Back

1     //------------------------------------------------------------------------------
2     // Module: Language.cpp                                                       //
3     //                                                                            //
4     //    Class which encapsulates a programming language's definition            //
5     //                                                                            //
6     //    Copyright (c) 2004 by Lars Haendel                                      //
7     //    Home: http://www.newty.de                                               //
8     //                                                                            //
9     //    This program is free software and can be used under the terms of the    //
10    //    GNU licence. See header-file for further information and disclaimer.    //
11    //                                                                            //
12    //------------------------------------------------------------------------------
13
14    #include <iomanip>            // due to:  setw()
15
16
17    #include "Language.h"
18    #include "FileUtil.h"         //          file utilities
19    #include "NameUtil.h"         //          GetFileName()
20    #include "ErrText.h"          //          TErrText
21
22
23
24    //----------------------------------------------------------------------------------------------------------------------
25    // defines
26
27    // misc.
28    #define SZ_NAME                     "Name"                  // language's name
29    #define SZ_SYMBOLS                  "Symbols"
30    #define SZ_EXTENSION                "Extensions"            // common/typical file extensions
31    #define SZ_CASE_SENSITIVE           "CaseSensitive"         // do not ignore case when searching in word lists
32    #define SZ_ALLOW_WHITE_AFTER_FIRST  "AllowWhiteAfterFirst"  // allow white spaces after first character
33    #define SZ_CHARS_WITHIN_STRING      "CharsWithinString"     // chars that may be within strings
34    #define DEF_CASE_SENSITIVE          true                    // language is case sensitive
35    #define DEF_ALLOW_WHITE_AFTER_FIRST true
36
37    // regex and identifier type exchange info
38    #define SZ_REGEX                    "Regex"                 // regex string
39    #define SZ_TYPE                     "Type"                  // item type identified by regex
40    #define SZ_EXCH_TYPE                "ExchangeType"          // exchange identifier type after regex
41    #define SZ_END_SEQUENCE             "EndSequence"           // stop sequence for identifier type exchange
42
43
44    // strings
45    #define SZ_STRING                   "String"                // character that starts/ends a string
46    #define SZ_CHARACTER                "Character"             // character that starts/ends a character/string
47    #define SZ_ESCAPE_CHAR              "EscapeChar"            // escape character in strings
48    #define SZ_SILLY_STRING_HANDLING    "SillyStringHandling"   // the string is extended to the next line(s) until the
49                                                                // closing character is found
50
51    #define DEF_STRING                  '\0'
52    #define DEF_CHARACTER               '\0'
53    #define DEF_ESCAPE_CHAR             '\0'                    // escape character in strings
54    #define DEF_SILLY_STRING_HANDLING   false
55
56    // comments
57    #define SZ_SINGLE_LINE_COM          "SingleLineComment"     // start sequence for single line comments
58    #define SZ_MULTI_LINE_COM           "MultiLineComment"      // start and end sequence for multi line comments
59
60
61    // word lists
62    #define SZ_KEYWORDS                 "Keywords"              // keyword list
63    #define SZ_PREPROCESSOR             "Preprocessor"          // list with words that start a preprocessor directive
64    #define SZ_WORDLIST                 "Words"                 // user word list
65
66    #define WIDTH 20
67
68
69    //----------------------------------------------------------------------------------------------------------------------
70    // try to read type and identifier type exchange information (TInfo object)
71    void ReadTypeAndExchInfo(ifstream& file, TLanguage::TInfo* info, const char*const& szBaseKey)
72    {
73       char szKey[256], szText[256], szType[MAX_TYPE_LEN], szEndSeq[MAX_SEQUENCE_LEN];
74
75       // 1. if specified: read type and check it
76       // a) read
77       sprintf(szKey, "%s%s", szBaseKey, SZ_TYPE);                         // compose key
78       ReadKeyString(file, szKey, szType, MAX_TYPE_LEN, SEARCH_LINES);     // try to read
79       int typeId1 = IdentifyItemName(szType);
80
81       // b) check type and throw exception if no or invalid type was read ...
82       if(typeId1<0 || typeId1==TItemStyle::Bkgnd)
83       {
84          // compose text and throw exception
85          sprintf(szText, "Unknown or illegal item type defined for key '%s'!", szKey);
86          throw TErrText(szText);
87       }
88
89       // 2. try to read type for identifier type exchange and check it
90       sprintf(szKey, "%s%s", szBaseKey, SZ_EXCH_TYPE);                       // compose key
91       ReadKeyString(file, szKey, szType, MAX_TYPE_LEN, SEARCH_LINES);        // try to read
92       int typeId2 = IdentifyItemName(szType);
93
94       // check
95       if(szType[0]!='\0')
96       {
97          if(typeId2<0 || typeId2==TItemStyle::Bkgnd)
98          {
99             // compose text and throw exception
100            sprintf(szText, "Unknown or illegal item type defined for key '%s'!", szKey);
101            throw TErrText(szText);
102         }
103      }
104
105
106      // 3. try to read end sequence for identifier type exchange and check it
107      sprintf(szKey, "%s%s", szBaseKey, SZ_END_SEQUENCE);                    // compose key
108      ReadKeyString(file, szKey, szEndSeq, MAX_SEQUENCE_LEN, SEARCH_LINES);  // try to read
109
110      // check
111      if(szType[0]!='\0')        // if identifier type exchange was read ...
112         if(szEndSeq[0]=='\0')   // ... then throw excpetion if no end sequence was read
113         {
114            // ... compose text and throw exception
115            sprintf(szText, "No ending sequence defined! Use key '%s' to define one!", szKey);
116            throw TErrText(szText);
117         }
118
119      // insert regex type and identifier type exchange info in list ...
120      info->type1 = (TItemStyle::ItemType) typeId1;           // regex type
121      info->type2 = (TItemStyle::ItemType) typeId2;           // identifier type exchange type
122      strcpy(info->szEndSeq, szEndSeq);                       // identifier type exchange end sequence
123   }
124
125
126   //----------------------------------------------------------------------------------------------------------------------
127   // save type and identifier type exchange information (TInfo object)
128   void SaveTypeAndExchInfo(ofstream& file, const TLanguage::TInfo*const& info, const char*const& szBaseKey
129                           , const bool& f_SaveType=false)
130   {
131      char szKey[256];
132
133      // compose key for type and write it
134      if(f_SaveType)
135      {
136         sprintf(szKey, "%s%s", szBaseKey, SZ_TYPE);
137         file << setw(WIDTH) << szKey << " = " << GetItemName(info->type1) << endl;
138      }
139
140      // if identifier type exchange info exists: compose key write it
141      if(info->type2>=0)
142      {
143         // type for identifier type exchange
144         sprintf(szKey, "%s%s", szBaseKey, SZ_EXCH_TYPE);
145         file << setw(WIDTH) << szKey << " = " << GetItemName(info->type2) << endl;
146
147         // end sequence
148         sprintf(szKey, "%s%s", szBaseKey, SZ_END_SEQUENCE);
149         file << setw(WIDTH) << szKey << " = \"" << info->szEndSeq << "\"" << endl;
150      }
151   }
152
153
154   //----------------------------------------------------------------------------------------------------------------------
155   // symbols that can be in a number
156   // Note: '.', '+' and '-' are not inlcuded here as there is taken care of in Conv2Html.cpp
157   static const int  _nNumberEndingSymbols = 23;
158   static const char szNumberEndingSymbols[_nNumberEndingSymbols] =
159                        {  '^', '|', '~', '?', '&', '%', '!', ',', ';', ':', '"', '\'',
160                           '=', '*', '<', '>', '(', ')', '{', '}', '[', ']', '/' };
161
162
163   //----------------------------------------------------------------------------------------------------------------------
164   // constructor
165   TLanguage::TLanguage()
166   {
167      szSingleLineCommentStart = szMultiLineCommentStart = szMultiLineCommentEnd = NULL;
168      nSingleLineCommentStart = nMultiLineCommentStart = nMultiLineCommentEnd = 0;
169   }
170
171
172   //----------------------------------------------------------------------------------------------------------------------
173   // destructor
174   TLanguage::~TLanguage()
175   {
176      // clear memory
177      delete[] szSingleLineCommentStart;
178      delete[] szMultiLineCommentStart;
179      delete[] szMultiLineCommentEnd;
180      delete[] nSingleLineCommentStart;
181      delete[] nMultiLineCommentStart;
182      delete[] nMultiLineCommentEnd;
183   }
184
185
186   //----------------------------------------------------------------------------------------------------------------------
187   // parse single/multi line comment strings
188   void TLanguage::ParseCommentStrings()
189   {
190      // count number of comment starting/ending sequences
191      nSingleLineComments = CountWords(szSingleLineComment);
192      nMultiLineComments = CountWords(szMultiLineComment)/2;
193
194      // allocate memory for parsed comment start/end sequences
195      szSingleLineCommentStart = new ComSeq[nSingleLineComments];
196      szMultiLineCommentStart = new ComSeq[nMultiLineComments];
197      szMultiLineCommentEnd = new ComSeq[nMultiLineComments];
198      nSingleLineCommentStart = new int[nSingleLineComments];
199      nMultiLineCommentStart = new int[nMultiLineComments];
200      nMultiLineCommentEnd = new int[nMultiLineComments];
201
202      // extract single line comment starting sequences
203      int i=0;                                                                      // ini string position
204      for(int nSeq=0;nSeq<nSingleLineComments;nSeq++)
205      {
206         nSingleLineCommentStart[nSeq] = GetLengthOfFirstWord(&(szSingleLineComment[i])); // get length of sequence
207         int j=0;
208         for(;j<nSingleLineCommentStart[nSeq];j++)                                  // copy all characters of sequence
209            szSingleLineCommentStart[nSeq][j] = szSingleLineComment[i+j];
210         szSingleLineCommentStart[nSeq][j] = '\0';                                  // add terminating '\0'
211
212         i += j;                                                                    // increment string position
213         while(isspace(szSingleLineComment[i]))
214            i++;                                                                    // skip all whitespaces
215      }
216
217      // extract multi line comment starting/ending sequences
218      i=0;                                                                          // ini string position
219      for(int nSeq=0;nSeq<nMultiLineComments;nSeq++)
220      {
221         nMultiLineCommentStart[nSeq] = GetLengthOfFirstWord(&(szMultiLineComment[i])); // get length of sequence
222         int j=0;
223         for(;j<nMultiLineCommentStart[nSeq];j++)                                   // copy all characters of sequence
224            szMultiLineCommentStart[nSeq][j] = szMultiLineComment[i+j];
225         szMultiLineCommentStart[nSeq][j] = '\0';                                   // add terminating '\0'
226         i += j;                                                                    // increment string position
227         while(isspace(szMultiLineComment[i]))
228            i++;                                                                    // skip all whitespaces
229
230
231         nMultiLineCommentEnd[nSeq] = GetLengthOfFirstWord(&(szMultiLineComment[i])); // get length of sequence
232         j=0;
233         for(;j<nMultiLineCommentEnd[nSeq];j++)                                     // copy all characters of sequence
234            szMultiLineCommentEnd[nSeq][j] = szMultiLineComment[i+j];
235         szMultiLineCommentEnd[nSeq][j] = '\0';                                     // add terminating '\0'
236
237
238         i += j;                                                                    // increment string position
239         while(isspace(szMultiLineComment[i]))
240            i++;                                                                    // skip all whitespaces
241      }
242   }
243
244
245   //----------------------------------------------------------------------------------------------------------------------
246   // load language definition from file section
247   void TLanguage::Load(ifstream& file)
248   {
249      // read language definition
250      char szText[256];             // string used to compose error texts
251      try
252      {
253         //----------------------------------------------------------------------------------------------------------------
254         // a) read misc. settings
255
256         // language's name
257         ReadKeyString(file, SZ_NAME, szName, MAX_NAME_LEN, SEARCH_LINES);
258         if(szName[0]=='\0')
259         {
260            sprintf(szText, "Language name missing! Please specify it using key: '%s'", SZ_NAME);  // compose text
261            throw TErrText(szText);                                                                // throw exception
262         }
263
264         // flags
265         f_CaseSensitive = ReadKeyBool(file, SZ_CASE_SENSITIVE, DEF_CASE_SENSITIVE, SEARCH_LINES);
266         f_AllowWhiteAfterFirst = ReadKeyBool(file, SZ_ALLOW_WHITE_AFTER_FIRST, DEF_ALLOW_WHITE_AFTER_FIRST, SEARCH_LINES);
267
268
269         // read symbols, common file extensions and chars that are allowed to be within strings
270         ReadKeyString(file, SZ_SYMBOLS, szSymbols, MAX_SYMBOL_LEN, SEARCH_LINES);
271         ReadKeyString(file, SZ_EXTENSION, szExtensions, STS, SEARCH_LINES);
272         ReadKeyString(file, SZ_CHARS_WITHIN_STRING, szCharsWithinString, MAX_SYMBOL_LEN, SEARCH_LINES);
273
274         // determine # of symbols
275         _nSymbols = SizeOfString(szSymbols);
276         _nCharsWithinString = SizeOfString(szCharsWithinString);
277
278
279         //----------------------------------------------------------------------------------------------------------------
280         // b) try to read regular expression settings
281         char szRegex[MAX_REGEX_LEN];
282         do
283         {
284            char szRegexKey[256];
285            sprintf(szRegexKey, "%s%d", SZ_REGEX, (int) (regex.Size()+1));             // compose key and ...
286            ReadKeyString(file, szRegexKey, szRegex, MAX_REGEX_LEN, SEARCH_LINES);     // ... try to read regex string
287
288
289            // if regex string was read in ...
290            if(szRegex[0]!='\0')
291            {
292               // insert regex in regex list ...
293               try
294               {
295                  regex.Ins().SetRegex(szRegex);                                 // insert regex string
296               }
297               catch(TErrText err)                                               // ... and if an error occured
298               {
299                  sprintf(szText, "Key '%s': %s", szRegexKey, err.szErrText);    // compose text
300                  throw TErrText(szText);                                        // re-throw exception
301               }
302
303               // try to read corresponding regex type and identifier type exchange info
304               ReadTypeAndExchInfo(file, &regexInfo.Ins(), szRegexKey);
305            }
306         } while(szRegex[0]!='\0');     // repeat as long as regex was read
307
308
309
310         //----------------------------------------------------------------------------------------------------------------
311         // c) read string settings
312         cString = ReadKeyValue(file, SZ_STRING, DEF_STRING, SEARCH_LINES);
313         cCharacter = ReadKeyValue(file, SZ_CHARACTER, DEF_CHARACTER, SEARCH_LINES);
314         cEscapeChar = ReadKeyValue(file, SZ_ESCAPE_CHAR, DEF_ESCAPE_CHAR, SEARCH_LINES);
315         f_SillyStringHandling = ReadKeyBool (file, SZ_SILLY_STRING_HANDLING, DEF_SILLY_STRING_HANDLING, SEARCH_LINES);
316
317         //----------------------------------------------------------------------------------------------------------------
318         // d) read comment settings
319         ReadKeyString(file, SZ_SINGLE_LINE_COM, szSingleLineComment, STS, SEARCH_LINES);
320         ReadKeyString(file, SZ_MULTI_LINE_COM, szMultiLineComment, STS, SEARCH_LINES);
321
322         ParseCommentStrings();  // parse comment strings
323
324         //----------------------------------------------------------------------------------------------------------------
325         // e) read word lists
326         char szKey[256];
327         keywords.Load(file, SZ_KEYWORDS, f_CaseSensitive);         // keyword list
328         preproc.Load(file, SZ_PREPROCESSOR, f_CaseSensitive);      // list with words that start a preprocessor directive
329
330         bool f_ReadIn;
331         do
332         {
333            char szWordListKey[256];
334            sprintf(szWordListKey, "%s%d", SZ_WORDLIST, (int) (wordLists.Size()+1)); // compose key and ...
335            wordLists.Ins().Load(file, szWordListKey, f_CaseSensitive);              // ... try to read another word list
336
337            // if another word list was read in ... try to read identifier type exchange info
338            f_ReadIn = (wordLists.Get().nWords()>0);
339            if(f_ReadIn)
340               ReadTypeAndExchInfo(file, &wordListInfo.Ins(), szWordListKey);
341            else
342               wordLists.Del();                    // delete entry again
343
344         } while(f_ReadIn);                        // repeat as long another word list was read
345
346      }
347      catch(int errNo)     // exception handling
348      {
349         sprintf(szText, "Reading key '%s': %s", GetLastKey(), GetLastError(errNo));      // compose text
350         throw TErrText(szText);                                                          // propagate exception
351      }
352   }
353
354
355   //----------------------------------------------------------------------------------------------------------------------
356   // write language definition to file section
357   void TLanguage::Save(ofstream& file) const
358   {
359      // set left justified output
360      file << setiosflags(ios::left) << resetiosflags(ios::right);
361
362
363      //----------------------------------------------------------------------------------------------------------------
364      // a) misc. settings
365      file << endl;
366
367      // language's name
368      file << setw(WIDTH) << SZ_NAME << " = \"" << szName << "\"" << endl;
369
370      // symbols
371      if(szSymbols[0]!='\0')
372         file << setw(WIDTH) << SZ_SYMBOLS << " = \"" << szSymbols << "\"" << endl;
373
374      // common file extensions
375      if(szExtensions[0]!='\0')
376         file << setw(WIDTH) << SZ_EXTENSION << " = \"" << szExtensions << "\"" << endl;
377
378      // characters that may occur within keywords/names
379      if(szCharsWithinString[0]!='\0')
380         file << setw(WIDTH) << SZ_CHARS_WITHIN_STRING << " = \"" << szCharsWithinString << "\"" << endl;
381
382      // flags
383      file << setw(WIDTH) << SZ_CASE_SENSITIVE << " = " << FlagToString(f_CaseSensitive) << endl;
384      file << setw(WIDTH) << SZ_ALLOW_WHITE_AFTER_FIRST << " = " << FlagToString(f_AllowWhiteAfterFirst) << endl;
385
386
387      // regex
388      if(regex.Size()>0)
389         for(int i=0;i<regex.Size();i++)
390         {
391            // compose key for regex itself and write it
392            char szKey[256];
393            sprintf(szKey, "%s%d", SZ_REGEX, (int) (i+1));
394            file << setw(WIDTH) << szKey << " = \"" << regex.Get(i).GetRegexString() << "\"" << endl;
395
396            // save type and identifier type exchange info (TInfo object)
397            SaveTypeAndExchInfo(file, &regexInfo.Get(i), szKey, true);
398         }
399
400
401      //----------------------------------------------------------------------------------------------------------------
402      // b) string settings
403      if(cString!='\0')
404         file << setw(WIDTH) << SZ_STRING << " = " << cString << endl;
405      if(cCharacter!='\0')
406         file << setw(WIDTH) << SZ_CHARACTER << " = " << cCharacter << endl;
407      if(cEscapeChar!='\0')
408         file << setw(WIDTH) << SZ_ESCAPE_CHAR << " = " << cEscapeChar << endl;
409      file << setw(WIDTH) << SZ_SILLY_STRING_HANDLING << " = " << FlagToString(f_SillyStringHandling) << endl;
410
411
412      //----------------------------------------------------------------------------------------------------------------
413      // c) comment settings
414      if(szSingleLineComment[0]!='\0')
415         file << setw(WIDTH) << SZ_SINGLE_LINE_COM << " = \"" << szSingleLineComment << "\"" << endl;
416      if(szMultiLineComment[0]!='\0')
417         file << setw(WIDTH) << SZ_MULTI_LINE_COM << " = \"" << szMultiLineComment << "\"" << endl;
418
419
420      //----------------------------------------------------------------------------------------------------------------
421      // d) word lists
422      keywords.Save(file, SZ_KEYWORDS, WIDTH);             // keyword list
423      preproc.Save(file, SZ_PREPROCESSOR, WIDTH);          // list with words that start a preprocessor directive
424
425      // user word lists
426      if(wordLists.Size()>0)
427         for(int i=0;i<wordLists.Size();i++)
428         {
429            // compose key and write word list
430            char szKey[256];
431            sprintf(szKey, "%s%d", SZ_WORDLIST, (int) (i+1));
432            wordLists.Get(i).Save(file, szKey, WIDTH);
433
434            // save type and identifier type exchange info (TInfo object)
435            SaveTypeAndExchInfo(file, &wordListInfo.Get(i), szKey, true);
436         }
437
438      file << resetiosflags(ios::left) << setiosflags(ios::right);
439   }
440
441
442   //----------------------------------------------------------------------------------------------------------------------
443   // returns true if passed character is within passed string
444   bool TLanguage::IsWithinString(const char& cChar, const char*const& szString, const int& len)
445   {
446      for(int i=0;i<len;i++)
447         if(szString[i]==cChar)
448            return true;
449      return false;
450   }
451
452
453   //----------------------------------------------------------------------------------------------------------------------
454   // returns true if passed string starts with specified sequence
455   int TLanguage::SequenceStartsString(const char*const& szString, const char*const& szSequence, const int& nSeq)
456   {
457      for(int i=0;i<nSeq;i++)
458         if(szString[i]!=szSequence[i] || szString[i]=='\0')
459            return 0;                                             // does not match, return '0'
460
461      return nSeq;                                                // match: return # of characters in sequence
462   }
463
464
465   //----------------------------------------------------------------------------------------------------------------------
466   // returns true if passed character cannot be within a number
467   bool TLanguage::SymbolEndsNumber(const char& cChar) const
468   {
469      // check against hard coded symbols
470      return IsWithinString(cChar, szNumberEndingSymbols, _nNumberEndingSymbols);
471   }
472
473
474   //----------------------------------------------------------------------------------------------------------------------
475   // returns true if passed character string starts a preprocessor
476   int TLanguage::StartsPreproc(const char*const& szString, const int& nChar) const
477   {
478      char szWord[MAX_WORD_LEN];       // will be compared to preprocessor word list
479      int i=0, t;
480
481      // a) copy all characters to 'szWord'   note: 'nChar' is the # of characters of the first name in passed string
482      for(t=0;t<nChar;t++)
483         szWord[i++] = szString[t];
484
485
486      // b) if enabled and if only one character is copied to word so far ...
487      if(nChar==1 && f_AllowWhiteAfterFirst)
488      {
489         // skip all following white spaces
490         while(szString[t]!='\0')
491            if(szString[t]== ' ' || szString[t]== '\t')
492               t++;
493            else
494               break;
495
496         // and append following name to 'szWord'
497         while(szString[t]!='\0')
498         {
499            // accept '_', all numbers [0..9] and all characters [A..Z] and [a..z]
500            if(szString[t]!=95 && (szString[t]<48 || szString[t]>57) && (szString[t]<65 || szString[t]>90)
501               && (szString[t]<97 || szString[t]>122))
502               break;
503
504            szWord[i++] = szString[t++];   // copy to 'szWord'
505         }
506      }
507
508      szWord[i] = '\0';             // terminate
509      if(preproc.IsInList(szWord))  // return # of preprocessor characters or zero if no match was found
510         return i;
511      else
512         return 0;
513   }
514
515
516   //----------------------------------------------------------------------------------------------------------------------
517   // returns true if passed string is started with a sequence that starts a multi line comment
518   int TLanguage::StartsMultiLineComment(const char*const& szString) const
519   {
520      for(int i=0;i<nMultiLineComments;i++)
521      {
522         int nChar = SequenceStartsString(szString, szMultiLineCommentStart[i], nMultiLineCommentStart[i]);
523         if(nChar>0)
524            return nChar;     // match found, return number of matching characters
525      }
526      return 0;   // no match found
527   }
528
529
530   //----------------------------------------------------------------------------------------------------------------------
531   // returns true if passed string is started with a sequence that ends a multi line comment
532   int TLanguage::EndsMultiLineComment(const char*const& szString) const
533   {
534      for(int i=0;i<nMultiLineComments;i++)
535      {
536         int nChar = SequenceStartsString(szString, szMultiLineCommentEnd[i], nMultiLineCommentEnd[i]);
537         if(nChar>0)
538            return nChar;     // match found, return number of matching characters
539      }
540      return 0;   // no match found
541   }
542
543   //----------------------------------------------------------------------------------------------------------------------
544   // returns true if passed string is started with a sequence that starts a single line comment
545   int TLanguage::StartsSingleLineComment(const char*const& szString) const
546   {
547      for(int i=0;i<nSingleLineComments;i++)
548      {
549         int nChar = SequenceStartsString(szString, szSingleLineCommentStart[i], nSingleLineCommentStart[i]);
550         if(nChar>0)
551            return nChar;     // match found, return number of matching characters
552      }
553      return 0;   // no match found
554   }
555
556   //----------------------------------------------------------------------------------------------------------------------
557   // returns true if passed string is started with a sequence that matches one of the regexes
558   int TLanguage::StartsWithRegex(const char*const& szString) const
559   {
560      for(int i=0;i<regex.Size();i++)     // check all regular expressions
561      {
562         int nChar = regex.Get(i).StartsWithRegex(szString);
563         if(nChar>0)                                           // if match is found ...
564         {
565            lastRegexId = i;                                   // store regex id
566            return nChar;                                      // return # matching characters
567         }
568      }
569
570      return 0;
571   }
572
573
574   //----------------------------------------------------------------------------------------------------------------------
575   // returns true if passed word is found in one of the user word lists
576   bool TLanguage::IsUserWord(const char*const& szWord) const
577   {
578      for(int i=0;i<wordLists.Size();i++)                      // check all word lists
579      {
580         bool f_Found = wordLists.Get(i).IsInList(szWord);
581         if(f_Found)                                           // if match is found ...
582         {
583            lastWordId = i;                                    // store word id
584            return true;                                       // return true
585         }
586      }
587
588      return false;
589   }

Top