1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxHtmlHelpData
4 // Notes: Based on htmlhelp.cpp, implementing a monolithic
5 // HTML Help controller class, by Vaclav Slavik
6 // Author: Harm van der Heijden and Vaclav Slavik
8 // Copyright: (c) Harm van der Heijden and Vaclav Slavik
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
25 #if wxUSE_HTML && wxUSE_STREAMS
32 #include "wx/html/helpdata.h"
33 #include "wx/tokenzr.h"
34 #include "wx/wfstream.h"
35 #include "wx/busyinfo.h"
36 #include "wx/encconv.h"
37 #include "wx/fontmap.h"
39 #include "wx/html/htmlpars.h"
40 #include "wx/html/htmldefs.h"
41 #include "wx/filename.h"
43 #include "wx/arrimpl.cpp"
44 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
)
46 //-----------------------------------------------------------------------------
47 // static helper functions
48 //-----------------------------------------------------------------------------
50 // Reads one line, stores it into buf and returns pointer to new line or NULL.
51 static char* ReadLine(char *line
, char *buf
, size_t bufsize
)
54 char *endptr
= buf
+ bufsize
- 1;
57 while (*readptr
!= 0 && *readptr
!= '\r' && *readptr
!= '\n' &&
59 *(writeptr
++) = *(readptr
++);
61 while (*readptr
== '\r' || *readptr
== '\n')
71 extern "C" int LINKAGEMODE
72 wxHtmlHelpIndexCompareFunc(const void *a
, const void *b
)
74 return wxStricmp(((wxHtmlContentsItem
*)a
)->m_Name
, ((wxHtmlContentsItem
*)b
)->m_Name
);
78 //-----------------------------------------------------------------------------
80 //-----------------------------------------------------------------------------
82 class HP_Parser
: public wxHtmlParser
85 wxObject
* GetProduct() { return NULL
; }
87 virtual void AddText(const wxChar
* WXUNUSED(txt
)) {}
91 //-----------------------------------------------------------------------------
93 //-----------------------------------------------------------------------------
95 class HP_TagHandler
: public wxHtmlTagHandler
98 wxString m_Name
, m_Page
;
102 wxHtmlContentsItem
*m_Items
;
104 wxHtmlBookRecord
*m_Book
;
107 HP_TagHandler(wxHtmlBookRecord
*b
) : wxHtmlTagHandler()
108 { m_Book
= b
; m_Items
= NULL
; m_ItemsCnt
= 0; m_Name
= m_Page
= wxEmptyString
;
109 m_Level
= 0; m_ID
= -1; }
110 wxString
GetSupportedTags() { return wxT("UL,OBJECT,PARAM"); }
111 bool HandleTag(const wxHtmlTag
& tag
);
112 void WriteOut(wxHtmlContentsItem
*& array
, int& size
);
113 void ReadIn(wxHtmlContentsItem
* array
, int size
);
117 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
)
119 if (tag
.GetName() == wxT("UL"))
126 else if (tag
.GetName() == wxT("OBJECT"))
128 m_Name
= m_Page
= wxEmptyString
;
132 if (!m_Page
.IsEmpty())
133 /* Valid HHW's file may contain only two object tags:
135 <OBJECT type="text/site properties">
136 <param name="ImageType" value="Folder">
141 <OBJECT type="text/sitemap">
142 <param name="Name" value="main page">
143 <param name="Local" value="another.htm">
146 We're interested in the latter. !m_Page.IsEmpty() is valid
147 condition because text/site properties does not contain Local param
150 if (tag
.GetParam(wxT("TYPE")) == wxT("text/sitemap"))
152 if (m_ItemsCnt
% wxHTML_REALLOC_STEP
== 0)
153 m_Items
= (wxHtmlContentsItem
*) realloc(m_Items
,
154 (m_ItemsCnt
+ wxHTML_REALLOC_STEP
) *
155 sizeof(wxHtmlContentsItem
));
157 m_Items
[m_ItemsCnt
].m_Level
= m_Level
;
158 m_Items
[m_ItemsCnt
].m_ID
= m_ID
;
159 m_Items
[m_ItemsCnt
].m_Page
= new wxChar
[m_Page
.Length() + 1];
160 wxStrcpy(m_Items
[m_ItemsCnt
].m_Page
, m_Page
.c_str());
161 m_Items
[m_ItemsCnt
].m_Name
= new wxChar
[m_Name
.Length() + 1];
162 wxStrcpy(m_Items
[m_ItemsCnt
].m_Name
, m_Name
.c_str());
163 m_Items
[m_ItemsCnt
].m_Book
= m_Book
;
171 if (m_Name
== wxEmptyString
&& tag
.GetParam(wxT("NAME")) == wxT("Name"))
172 m_Name
= tag
.GetParam(wxT("VALUE"));
173 if (tag
.GetParam(wxT("NAME")) == wxT("Local"))
174 m_Page
= tag
.GetParam(wxT("VALUE"));
175 if (tag
.GetParam(wxT("NAME")) == wxT("ID"))
176 tag
.GetParamAsInt(wxT("VALUE"), &m_ID
);
183 void HP_TagHandler::WriteOut(wxHtmlContentsItem
*& array
, int& size
)
191 void HP_TagHandler::ReadIn(wxHtmlContentsItem
* array
, int size
)
200 //-----------------------------------------------------------------------------
202 //-----------------------------------------------------------------------------
204 wxString
wxHtmlBookRecord::GetFullPath(const wxString
&page
) const
206 if (wxIsAbsolutePath(page
))
209 return m_BasePath
+ page
;
214 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
)
216 wxHtmlHelpData::wxHtmlHelpData()
218 m_TempPath
= wxEmptyString
;
226 wxHtmlHelpData::~wxHtmlHelpData()
230 m_BookRecords
.Empty();
233 for (i
= 0; i
< m_ContentsCnt
; i
++)
235 delete[] m_Contents
[i
].m_Page
;
236 delete[] m_Contents
[i
].m_Name
;
242 for (i
= 0; i
< m_IndexCnt
; i
++)
244 delete[] m_Index
[i
].m_Page
;
245 delete[] m_Index
[i
].m_Name
;
251 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord
*book
, wxFileSystem
& fsys
, const wxString
& indexfile
, const wxString
& contentsfile
)
259 HP_TagHandler
*handler
= new HP_TagHandler(book
);
260 parser
.AddTagHandler(handler
);
262 f
= ( contentsfile
.IsEmpty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(contentsfile
) );
265 sz
= f
->GetStream()->GetSize();
266 buf
= new char[sz
+ 1];
268 f
->GetStream()->Read(buf
, sz
);
270 handler
->ReadIn(m_Contents
, m_ContentsCnt
);
272 handler
->WriteOut(m_Contents
, m_ContentsCnt
);
276 wxLogError(_("Cannot open contents file: %s"), contentsfile
.c_str());
278 f
= ( indexfile
.IsEmpty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(indexfile
) );
281 sz
= f
->GetStream()->GetSize();
282 buf
= new char[sz
+ 1];
284 f
->GetStream()->Read(buf
, sz
);
286 handler
->ReadIn(m_Index
, m_IndexCnt
);
288 handler
->WriteOut(m_Index
, m_IndexCnt
);
291 else if (!indexfile
.IsEmpty())
292 wxLogError(_("Cannot open index file: %s"), indexfile
.c_str());
298 inline static void CacheWriteInt32(wxOutputStream
*f
, wxInt32 value
)
300 wxInt32 x
= wxINT32_SWAP_ON_BE(value
);
301 f
->Write(&x
, sizeof(x
));
304 inline static wxInt32
CacheReadInt32(wxInputStream
*f
)
307 f
->Read(&x
, sizeof(x
));
308 return wxINT32_SWAP_ON_BE(x
);
311 inline static void CacheWriteString(wxOutputStream
*f
, const wxChar
*str
)
313 size_t len
= wxStrlen(str
)+1;
314 CacheWriteInt32(f
, len
);
315 f
->Write(str
, len
* sizeof(wxChar
));
318 inline static wxChar
*CacheReadString(wxInputStream
*f
)
321 size_t len
= (size_t)CacheReadInt32(f
);
322 str
= new wxChar
[len
];
323 f
->Read(str
, len
* sizeof(wxChar
));
327 #define CURRENT_CACHED_BOOK_VERSION 2
329 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord
*book
, wxInputStream
*f
)
334 /* load header - version info : */
335 version
= CacheReadInt32(f
);
337 if (version
!= CURRENT_CACHED_BOOK_VERSION
)
339 // NB: We can just silently return FALSE here and don't worry about
340 // it anymore, because AddBookParam will load the MS project in
341 // absence of (properly versioned) .cached file and automatically
342 // create new .cached file immediately afterward.
346 /* load contents : */
348 m_ContentsCnt
+= CacheReadInt32(f
);
349 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
,
350 (m_ContentsCnt
/ wxHTML_REALLOC_STEP
+ 1) *
351 wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
352 for (i
= st
; i
< m_ContentsCnt
; i
++)
354 m_Contents
[i
].m_Level
= CacheReadInt32(f
);
355 m_Contents
[i
].m_ID
= CacheReadInt32(f
);
356 m_Contents
[i
].m_Name
= CacheReadString(f
);
357 m_Contents
[i
].m_Page
= CacheReadString(f
);
358 m_Contents
[i
].m_Book
= book
;
363 m_IndexCnt
+= CacheReadInt32(f
);
364 m_Index
= (wxHtmlContentsItem
*) realloc(m_Index
, (m_IndexCnt
/ wxHTML_REALLOC_STEP
+ 1) *
365 wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
366 for (i
= st
; i
< m_IndexCnt
; i
++)
368 m_Index
[i
].m_Name
= CacheReadString(f
);
369 m_Index
[i
].m_Page
= CacheReadString(f
);
370 m_Index
[i
].m_Book
= book
;
376 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord
*book
, wxOutputStream
*f
)
381 /* save header - version info : */
382 CacheWriteInt32(f
, CURRENT_CACHED_BOOK_VERSION
);
384 /* save contents : */
385 for (cnt
= 0, i
= 0; i
< m_ContentsCnt
; i
++)
386 if (m_Contents
[i
].m_Book
== book
&& m_Contents
[i
].m_Level
> 0)
388 CacheWriteInt32(f
, cnt
);
390 for (i
= 0; i
< m_ContentsCnt
; i
++)
392 if (m_Contents
[i
].m_Book
!= book
|| m_Contents
[i
].m_Level
== 0)
394 CacheWriteInt32(f
, m_Contents
[i
].m_Level
);
395 CacheWriteInt32(f
, m_Contents
[i
].m_ID
);
396 CacheWriteString(f
, m_Contents
[i
].m_Name
);
397 CacheWriteString(f
, m_Contents
[i
].m_Page
);
401 for (cnt
= 0, i
= 0; i
< m_IndexCnt
; i
++)
402 if (m_Index
[i
].m_Book
== book
&& m_Index
[i
].m_Level
> 0)
404 CacheWriteInt32(f
, cnt
);
406 for (i
= 0; i
< m_IndexCnt
; i
++)
408 if (m_Index
[i
].m_Book
!= book
|| m_Index
[i
].m_Level
== 0)
410 CacheWriteString(f
, m_Index
[i
].m_Name
);
411 CacheWriteString(f
, m_Index
[i
].m_Page
);
417 void wxHtmlHelpData::SetTempDir(const wxString
& path
)
419 if (path
== wxEmptyString
) m_TempPath
= path
;
422 if (wxIsAbsolutePath(path
)) m_TempPath
= path
;
423 else m_TempPath
= wxGetCwd() + _T("/") + path
;
425 if (m_TempPath
[m_TempPath
.Length() - 1] != _T('/'))
426 m_TempPath
<< _T('/');
432 static wxString
SafeFileName(const wxString
& s
)
435 res
.Replace(wxT("#"), wxT("_"));
436 res
.Replace(wxT(":"), wxT("_"));
437 res
.Replace(wxT("\\"), wxT("_"));
438 res
.Replace(wxT("/"), wxT("_"));
442 bool wxHtmlHelpData::AlreadyHasBook(wxHtmlBookRecord
* bookr
)
444 size_t bookCount
= m_BookRecords
.GetCount();
445 if (bookCount
== 0) return FALSE
;
447 wxHtmlBookRecord
currentBook(wxEmptyString
,wxEmptyString
,wxEmptyString
);
449 for (i
=0; i
<bookCount
; i
++)
451 currentBook
= m_BookRecords
.Item(i
) ;
452 if (currentBook
.GetBasePath().IsSameAs(bookr
->GetBasePath()) &&
453 currentBook
.GetTitle().IsSameAs(bookr
->GetTitle()) &&
454 currentBook
.GetStart().IsSameAs(bookr
->GetStart()) )
461 bool wxHtmlHelpData::AddBookParam(const wxFSFile
& bookfile
,
462 wxFontEncoding encoding
,
463 const wxString
& title
, const wxString
& contfile
,
464 const wxString
& indexfile
, const wxString
& deftopic
,
465 const wxString
& path
)
469 wxHtmlBookRecord
*bookr
;
471 int IndexOld
= m_IndexCnt
,
472 ContentsOld
= m_ContentsCnt
;
474 if (! path
.IsEmpty())
475 fsys
.ChangePathTo(path
, TRUE
);
477 bookr
= new wxHtmlBookRecord(fsys
.GetPath(), title
, deftopic
);
478 // return TRUE to indicate book is loaded
479 if (AlreadyHasBook(bookr
)) return TRUE
;
481 if (m_ContentsCnt
% wxHTML_REALLOC_STEP
== 0)
482 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
, (m_ContentsCnt
+ wxHTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
));
483 m_Contents
[m_ContentsCnt
].m_Level
= 0;
484 m_Contents
[m_ContentsCnt
].m_ID
= 0;
485 m_Contents
[m_ContentsCnt
].m_Page
= new wxChar
[deftopic
.Length() + 1];
486 wxStrcpy(m_Contents
[m_ContentsCnt
].m_Page
, deftopic
.c_str());
487 m_Contents
[m_ContentsCnt
].m_Name
= new wxChar
[title
.Length() + 1];
488 wxStrcpy(m_Contents
[m_ContentsCnt
].m_Name
, title
.c_str());
489 m_Contents
[m_ContentsCnt
].m_Book
= bookr
;
491 // store the contents index for later
492 int cont_start
= m_ContentsCnt
++;
494 // Try to find cached binary versions:
495 // 1. save file as book, but with .hhp.cached extension
496 // 2. same as 1. but in temp path
497 // 3. otherwise or if cache load failed, load it from MS.
499 fi
= fsys
.OpenFile(bookfile
.GetLocation() + wxT(".cached"));
502 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
503 !LoadCachedBook(bookr
, fi
->GetStream()))
505 if (fi
!= NULL
) delete fi
;
506 fi
= fsys
.OpenFile(m_TempPath
+ wxFileNameFromPath(bookfile
.GetLocation()) + wxT(".cached"));
507 if (m_TempPath
== wxEmptyString
|| fi
== NULL
||
508 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
509 !LoadCachedBook(bookr
, fi
->GetStream()))
511 LoadMSProject(bookr
, fsys
, indexfile
, contfile
);
512 if (m_TempPath
!= wxEmptyString
)
514 wxFileOutputStream
*outs
= new wxFileOutputStream(m_TempPath
+
515 SafeFileName(wxFileNameFromPath(bookfile
.GetLocation())) + wxT(".cached"));
516 SaveCachedBook(bookr
, outs
);
522 if (fi
!= NULL
) delete fi
;
524 // Now store the contents range
525 bookr
->SetContentsRange(cont_start
, m_ContentsCnt
);
527 // Convert encoding, if neccessary:
528 if (encoding
!= wxFONTENCODING_SYSTEM
)
530 wxFontEncodingArray a
= wxEncodingConverter::GetPlatformEquivalents(encoding
);
531 if (a
.GetCount() != 0 && a
[0] != encoding
)
534 wxEncodingConverter conv
;
535 conv
.Init(encoding
, a
[0]);
537 for (i
= IndexOld
; i
< m_IndexCnt
; i
++)
538 conv
.Convert(m_Index
[i
].m_Name
);
539 for (i
= ContentsOld
; i
< m_ContentsCnt
; i
++)
540 conv
.Convert(m_Contents
[i
].m_Name
);
544 m_BookRecords
.Add(bookr
);
546 qsort(m_Index
, m_IndexCnt
, sizeof(wxHtmlContentsItem
), wxHtmlHelpIndexCompareFunc
);
552 bool wxHtmlHelpData::AddBook(const wxString
& book
)
554 if (book
.Right(4).Lower() == wxT(".zip") ||
555 book
.Right(4).Lower() == wxT(".htb") /*html book*/)
561 s
= fsys
.FindFirst(book
+ wxT("#zip:") + wxT("*.hhp"), wxFILE
);
564 if (AddBook(s
)) rt
= TRUE
;
577 wxString title
= _("noname"),
579 start
= wxEmptyString
,
580 contents
= wxEmptyString
,
581 index
= wxEmptyString
,
582 charset
= wxEmptyString
;
584 #if defined(__WXMAC__) && !defined(__DARWIN__)
585 if (wxIsAbsolutePath(book
)) bookFull
= book
;
586 else bookFull
= wxGetCwd() + book
; // no slash or dot
587 wxFileName
fn( bookFull
);
588 bookFull
= fn
.GetFullPath( wxPATH_UNIX
);
590 if (wxIsAbsolutePath(book
)) bookFull
= book
;
591 else bookFull
= wxGetCwd() + "/" + book
;
594 fi
= fsys
.OpenFile(bookFull
);
597 wxLogError(_("Cannot open HTML help book: %s"), bookFull
.c_str());
600 fsys
.ChangePathTo(bookFull
);
604 char *buff
, *lineptr
;
608 buff
= new char[sz
+ 1];
615 lineptr
= ReadLine(lineptr
, linebuf
, 300);
617 for (char *ch
= linebuf
; *ch
!= '\0' && *ch
!= '='; ch
++)
620 if (strstr(linebuf
, "title=") == linebuf
)
621 title
= linebuf
+ strlen("title=");
622 if (strstr(linebuf
, "default topic=") == linebuf
)
623 start
= linebuf
+ strlen("default topic=");
624 if (strstr(linebuf
, "index file=") == linebuf
)
625 index
= linebuf
+ strlen("index file=");
626 if (strstr(linebuf
, "contents file=") == linebuf
)
627 contents
= linebuf
+ strlen("contents file=");
628 if (strstr(linebuf
, "charset=") == linebuf
)
629 charset
= linebuf
+ strlen("charset=");
630 } while (lineptr
!= NULL
);
634 if (charset
== wxEmptyString
) enc
= wxFONTENCODING_SYSTEM
;
635 else enc
= wxTheFontMapper
->CharsetToEncoding(charset
);
636 bool rtval
= AddBookParam(*fi
, enc
,
637 title
, contents
, index
, start
, fsys
.GetPath());
643 wxString
wxHtmlHelpData::FindPageByName(const wxString
& x
)
649 wxString
url(wxEmptyString
);
651 /* 1. try to open given file: */
653 cnt
= m_BookRecords
.GetCount();
654 for (i
= 0; i
< cnt
; i
++)
656 f
= fsys
.OpenFile(m_BookRecords
[i
].GetFullPath(x
));
659 url
= m_BookRecords
[i
].GetFullPath(x
);
666 /* 2. try to find a book: */
668 for (i
= 0; i
< cnt
; i
++)
670 if (m_BookRecords
[i
].GetTitle() == x
)
672 url
= m_BookRecords
[i
].GetFullPath(m_BookRecords
[i
].GetStart());
677 /* 3. try to find in contents: */
680 for (i
= 0; i
< cnt
; i
++)
682 if (wxStrcmp(m_Contents
[i
].m_Name
, x
) == 0)
684 url
= m_Contents
[i
].GetFullPath();
690 /* 4. try to find in index: */
693 for (i
= 0; i
< cnt
; i
++)
695 if (wxStrcmp(m_Index
[i
].m_Name
, x
) == 0)
697 url
= m_Index
[i
].GetFullPath();
705 wxString
wxHtmlHelpData::FindPageById(int id
)
708 wxString
url(wxEmptyString
);
710 for (i
= 0; i
< m_ContentsCnt
; i
++)
712 if (m_Contents
[i
].m_ID
== id
)
714 url
= m_Contents
[i
].GetFullPath();
722 //----------------------------------------------------------------------------------
723 // wxHtmlSearchStatus functions
724 //----------------------------------------------------------------------------------
726 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
,
727 bool case_sensitive
, bool whole_words_only
,
728 const wxString
& book
)
732 wxHtmlBookRecord
* bookr
= NULL
;
733 if (book
!= wxEmptyString
)
735 // we have to search in a specific book. Find it first
736 int i
, cnt
= data
->m_BookRecords
.GetCount();
737 for (i
= 0; i
< cnt
; i
++)
738 if (data
->m_BookRecords
[i
].GetTitle() == book
)
740 bookr
= &(data
->m_BookRecords
[i
]);
741 m_CurIndex
= bookr
->GetContentsStart();
742 m_MaxIndex
= bookr
->GetContentsEnd();
745 // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
750 // no book specified; search all books
752 m_MaxIndex
= m_Data
->m_ContentsCnt
;
754 m_Engine
.LookFor(keyword
, case_sensitive
, whole_words_only
);
755 m_Active
= (m_CurIndex
< m_MaxIndex
);
759 bool wxHtmlSearchStatus::Search()
762 int i
= m_CurIndex
; // shortcut
768 // sanity check. Illegal use, but we'll try to prevent a crash anyway
773 m_Name
= wxEmptyString
;
774 m_ContentsItem
= NULL
;
775 thepage
= m_Data
->m_Contents
[i
].m_Page
;
777 m_Active
= (++m_CurIndex
< m_MaxIndex
);
778 // check if it is same page with different anchor:
779 if (m_LastPage
!= NULL
)
782 for (p1
= thepage
, p2
= m_LastPage
;
783 *p1
!= 0 && *p1
!= _T('#') && *p1
== *p2
; p1
++, p2
++) {}
785 m_LastPage
= thepage
;
787 if (*p1
== 0 || *p1
== _T('#'))
790 else m_LastPage
= thepage
;
793 file
= fsys
.OpenFile(m_Data
->m_Contents
[i
].m_Book
->GetFullPath(thepage
));
796 if (m_Engine
.Scan(file
->GetStream()))
798 m_Name
= m_Data
->m_Contents
[i
].m_Name
;
799 m_ContentsItem
= m_Data
->m_Contents
+ i
;
814 //--------------------------------------------------------------------------------
816 //--------------------------------------------------------------------------------
818 void wxSearchEngine::LookFor(const wxString
& keyword
, bool case_sensitive
, bool whole_words_only
)
820 m_CaseSensitive
= case_sensitive
;
821 m_WholeWords
= whole_words_only
;
822 if (m_Keyword
) delete[] m_Keyword
;
823 m_Keyword
= new wxChar
[keyword
.Length() + 1];
824 wxStrcpy(m_Keyword
, keyword
.c_str());
826 if (!m_CaseSensitive
)
828 for (int i
= wxStrlen(m_Keyword
) - 1; i
>= 0; i
--)
830 if ((m_Keyword
[i
] >= wxT('A')) && (m_Keyword
[i
] <= wxT('Z')))
831 m_Keyword
[i
] += wxT('a') - wxT('A');
838 #define WHITESPACE(c) (c == ' ' || c == '\n' || c == '\r' || c == '\t')
840 bool wxSearchEngine::Scan(wxInputStream
*stream
)
842 wxASSERT_MSG(m_Keyword
!= NULL
, wxT("wxSearchEngine::LookFor must be called before scanning!"));
845 int lng
= stream
->GetSize();
846 int wrd
= wxStrlen(m_Keyword
);
848 char *buf
= new char[lng
+ 1];
849 stream
->Read(buf
, lng
);
852 if (!m_CaseSensitive
)
853 for (i
= 0; i
< lng
; i
++)
854 if ((buf
[i
] >= 'A') && (buf
[i
] <= 'Z')) buf
[i
] += 'a' - 'A';
858 for (i
= 0; i
< lng
- wrd
; i
++)
860 if (WHITESPACE(buf
[i
])) continue;
862 while ((j
< wrd
) && (buf
[i
+ j
] == m_Keyword
[j
])) j
++;
863 if (j
== wrd
&& WHITESPACE(buf
[i
+ j
])) { found
= TRUE
; break; }
869 for (i
= 0; i
< lng
- wrd
; i
++)
872 while ((j
< wrd
) && (buf
[i
+ j
] == m_Keyword
[j
])) j
++;
873 if (j
== wrd
) { found
= TRUE
; break; }