source: trunk/src/gui/common/hilite.c@ 2417

Last change on this file since 2417 was 2417, checked in by Andreas Schnellbacher, 14 years ago
  • Added svn keywords.
  • Property svn:keywords set to Date Revision Author HeadURL Id
File size: 52.8 KB
Line 
1/****************************** Module Header *******************************
2*
3* Module Name: hilite.c
4*
5* Generic routines to support extended keyword hilighting
6*
7* Copyright (c) Netlabs EPM Distribution Project 2002
8*
9* $Id: hilite.c 2417 2011-05-15 23:32:51Z aschn $
10*
11* ===========================================================================
12*
13* This file is part of the Netlabs EPM Distribution package and is free
14* software. You can redistribute it and/or modify it under the terms of the
15* GNU General Public License as published by the Free Software
16* Foundation, in version 2 as it comes in the "COPYING" file of the
17* Netlabs EPM Distribution. This library is distributed in the hope that it
18* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
19* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20* General Public License for more details.
21*
22****************************************************************************/
23
24#define INCL_DOS
25#define INCL_WIN
26#define INCL_ERRORS
27#include <os2.h>
28
29#include <stdlib.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdarg.h>
33#include <search.h>
34
35#include "macros.h"
36#include "nepmd.h"
37#include "libreg.h"
38#include "hilite.h"
39#include "init.h"
40#include "instval.h"
41#include "file.h"
42#include "mmf.h"
43#include "eas.h"
44
45// --- define to allow color value names in HIL files
46#define ALLOW_COLOR_VALUES 1
47
48// --- defines for detailed debug messages
49
50#define DEBUG_DUMPARRAYDETAILS 0
51
52// debug output on func entry and exit
53#define DEBUG_NOMESSAGE_ENTEREXIT 1
54
55#if DEBUG_NOMESSAGE_ENTEREXIT
56#undef FUNCENTER
57#undef FUNCEXIT
58#undef FUNCEXITRC
59#define FUNCENTER
60#define FUNCEXIT
61#define FUNCEXITRC
62#endif
63
64// ----- values for control files for creating hilite files -------------
65
66// definitions for file format for *.hil
67#define CHAR_HILCOMMENT ';'
68#define CHAR_SECTION_START '['
69#define CHAR_SECTION_END ']'
70
71// default values
72#define STR_KWDSCOMMENT "þ"
73#define STR_CASESENSITIVE "0"
74#define MAX_INI_LINE (_MAX_PATH)
75#define MAX_REG_PATH (_MAX_PATH)
76
77// global string vars
78static PSZ pszEnvnameEpmModepath = "EPMMODEPATH";
79static PSZ pszEnvnameEpmPath = "EPMPATH";
80
81static PSZ pszGlobalSection = "GLOBAL";
82static PSZ pszColorsSection = "COLORS";
83static PSZ pszSymbolsSection = "SYMBOLS";
84
85static PSZ pszFileInfoListEaName = "NEPMD.FileListInfo";
86
87static PSZ pszKeywordNone = "NONE:";
88
89// defines for strings used only once
90#define SEARCHMASK_HILITEFILES "%s\\%s\\*.hil"
91#define SEARCHMASK_TARGETFILES "%s.???"
92#define SEARCHMASK_MODEDIR "%s\\nepmd\\mode"
93#define SEARCHMASK_GLOBALINI "global.ini"
94#define SEARCHMASK_DEFAULTINI "%s\\default.ini"
95#define SEARCHMASK_CUSTOMINI "%s\\custom.ini"
96#define SEARCHMASK_EPMKWDS "epmkwds.%s"
97
98// --- keyword strings for the GLOBAL section of DEFAULT.INI and CUSTOM.INI
99
100// comment char for .hil files (undocumented)
101#define KEY_HILCOMMENTCHAR "HILCOMMENTCHAR"
102// used for mode determination and for building EPM highlighting files
103#define KEY_CHARSET "CHARSET"
104#define KEY_ADD_CHARSET "ADD_CHARSET"
105#define KEY_CASESENSITIVE "CASESENSITIVE"
106#define KEY_DEFEXTENSIONS "DEFEXTENSIONS"
107#define KEY_ADD_DEFEXTENSIONS "ADD_DEFEXTENSIONS"
108#define KEY_DEFNAMES "DEFNAMES"
109#define KEY_ADD_DEFNAMES "ADD_DEFNAMES"
110// the following keys can hold word list, not only single words
111#define KEY_LINECOMMENT "LINECOMMENT"
112#define KEY_LINECOMMENTPOS "LINECOMMENTPOS"
113#define KEY_LINECOMMENTNEEDSPACE "LINECOMMENTNEEDSPACE"
114#define KEY_LINECOMMENTOVERRIDEMULTI "LINECOMMENTOVERRIDEMULTI"
115#define KEY_MULTILINECOMMENTSTART "MULTILINECOMMENTSTART"
116#define KEY_MULTILINECOMMENTEND "MULTILINECOMMENTEND"
117#define KEY_MULTILINECOMMENTNESTED "MULTILINECOMMENTNESTED"
118// additional keys to support COMMENT.E
119#define KEY_LINECOMMENTADDSPACE "LINECOMMENTADDSPACE" // for defc comment
120// #define KEY_LINECOMMENTPREFERRED "LINECOMMENTPREFERRED" // for defc comment
121#define KEY_PREFERREDCOMMENT "PREFERREDCOMMENT" // for defc comment
122
123// --- keyword strings for NEPMD.INI (these settings are written to NEPMD.INI)
124
125// also used for mode determination and for building EPM highlighting files
126#define REGKEY_CHARSET "CharSet"
127#define REGKEY_CASESENSITIVE "CaseSensitive"
128#define REGKEY_DEFEXTENSIONS "DefExtensions"
129#define REGKEY_DEFNAMES "DefNames"
130// the following keys can hold word list, not only single words
131#define REGKEY_LINECOMMENT "LineComment"
132#define REGKEY_LINECOMMENTPOS "LineCommentPos"
133#define REGKEY_LINECOMMENTNEEDSPACE "LineCommentNeedSpace"
134#define REGKEY_LINECOMMENTOVERRIDEMULTI "LineCommentOverrideMulti"
135#define REGKEY_MULTILINECOMMENTSTART "MultiLineCommentStart"
136#define REGKEY_MULTILINECOMMENTEND "MultiLineCommentEnd"
137#define REGKEY_MULTILINECOMMENTNESTED "MultiLineCommentNested"
138// additional keys to support COMMENT.E
139#define REGKEY_LINECOMMENTADDSPACE "LineCommentAddSpace" // Word list
140// #define REGKEY_LINECOMMENTPREFERRED "LineCommentPreferred"
141#define REGKEY_PREFERREDCOMMENT "PreferredComment" // single "word"
142
143// ----------------------------------------------------------------------
144
145// some useful macros
146#define ALLOCATEMEMORYFILE(p,s) \
147rc = MmfAlloc( hmmf, (PVOID*)&p, MMF_FILE_INMEMORY, 0, s); \
148if (rc != NO_ERROR) \
149 break;
150
151#define FREEMEMORYFILE(p) MmfFree( hmmf, p)
152
153#define QUERYOPTINITVALUE(h,s,k,t,d) \
154InitQueryProfileString( h, s, k, d, t, sizeof( t));
155
156#define QUERYINITVALUE(h,s,k,t) \
157if (!InitQueryProfileString( h, s, k, NULL, t, sizeof( t))) \
158 { \
159 rc = ERROR_INVALID_DATA; \
160 break; \
161 }
162#define QUERYINITVALUESIZE(h,s,k) _queryInitValueSize( h, s, k)
163
164// ----------------------------------------------------------------------
165
166#ifdef DEBUG
167#if DEBUG_DUMPARRAYDETAILS
168#define DUMPINITVALUEARRAY(p) _dumpInitValueArray(p)
169#define DPRINTF_ARRAY(p) DPRINTF(p)
170#else
171#define DUMPINITVALUEARRAY(p)
172#define DPRINTF_ARRAY(p)
173#endif
174#else
175#define DUMPINITVALUEARRAY(p)
176#define DPRINTF_ARRAY(p)
177#endif
178
179// structure for an array of values
180// used by _maintainInitValueArray and _dumpInitValueArray
181typedef struct _VALUEARRAY
182 {
183 ULONG ulCount;
184 ULONG ulArraySize;
185 PSZ apszValue[ 1];
186 } VALUEARRAY, *PVALUEARRAY;
187
188// ----------------------------------------------------------------------
189
190static PSZ _stripblanks( PSZ string)
191{
192 PSZ p = string;
193 if (p != NULL)
194 {
195 while ((*p != 0) && (*p <= 32))
196 { p++;}
197 strcpy( string, p);
198
199 p = string;
200 if (*p != 0)
201 {
202 p += strlen(p) - 1;
203 while ((*p <= 32) && (p >= string))
204 {
205 *p = 0;
206 p--;
207 }
208 }
209 }
210
211return string;
212}
213
214// ######################################################################
215
216static APIRET _searchFile( PSZ pszSearchPathName, PSZ pszBuffer, ULONG ulBuflen, PSZ pszSearchMask, ...)
217{
218 APIRET rc = NO_ERROR;
219 CHAR szSourceName[ _MAX_PATH];
220 va_list arg_ptr;
221
222va_start (arg_ptr, pszSearchMask);
223vsprintf( szSourceName, pszSearchMask, arg_ptr);
224rc = DosSearchPath( SEARCH_IGNORENETERRS |
225 SEARCH_ENVIRONMENT |
226 SEARCH_CUR_DIRECTORY,
227 pszSearchPathName,
228 szSourceName,
229 pszBuffer,
230 ulBuflen);
231return rc;
232
233}
234
235// -----------------------------------------------------------------------------
236
237static APIRET _openInitFile( PHINIT phinit, PSZ pszSearchPathName, PSZ pszSearchMask, PSZ pszEpmMode,
238 PSZ pszBuffer, ULONG ulBuflen)
239{
240 APIRET rc = NO_ERROR;
241 CHAR szFile[ _MAX_PATH];
242
243do
244 {
245 // search init filefile
246 rc = _searchFile( pszSearchPathName, szFile, sizeof( szFile), pszSearchMask, pszEpmMode);
247 if (rc != NO_ERROR)
248 break;
249
250 rc = InitOpenProfile( szFile, phinit, INIT_OPEN_READONLY, 0, NULL);
251 if (rc != NO_ERROR)
252 break;
253
254 // hand over filename
255 if (pszBuffer)
256 {
257 if (strlen( szFile) + 1 > ulBuflen)
258 {
259 rc = ERROR_BUFFER_OVERFLOW;
260 break;
261 }
262 strcpy( pszBuffer, szFile);
263 strlwr( pszBuffer);
264 }
265
266 } while (FALSE);
267
268return rc;
269}
270
271// -----------------------------------------------------------------------------
272
273static APIRET _queryInitValueSize( HINIT hinit, PSZ pszSection, PSZ pszKey)
274{
275 ULONG ulDataLen = 0;
276
277InitQueryProfileSize( hinit, pszSection, pszKey, &ulDataLen);
278return ulDataLen;
279}
280
281// -----------------------------------------------------------------------------
282
283int _compareFilename( const void *pszKeyElement, const void *pszEntry)
284{
285pszKeyElement = (PVOID) Filespec( (PSZ) pszKeyElement, FILESPEC_NAME);
286pszEntry = (PVOID) Filespec( (PSZ) pszEntry, FILESPEC_NAME);
287return stricmp( pszKeyElement, pszEntry);
288}
289
290static APIRET _getDefFileList( HMMF hmmf, PSZ pszEpmMode, ULONG ulKeywordFileDate, PSZ *ppszFileList,
291 PULONG pulFileCount, PULONG pulTotalSize, PBOOL pfOutdated)
292{
293
294 APIRET rc = NO_ERROR;
295// PSZ pszTmp;
296
297 PSZ pszFileList = NULL;
298 ULONG ulListSize;
299 ULONG ulFileCount = 0;
300 ULONG ulTotalSize = 0;
301 BOOL fOutdated = FALSE;
302
303 PSZ pszKeywordPath = NULL;
304 PSZ pszKeywordDir;
305
306 CHAR szSearchMask[ _MAX_PATH];
307 CHAR szFile[ _MAX_PATH];
308 HDIR hdir;
309 PSZ pszEntry;
310
311do
312 {
313 // check parm
314 if ((!pszEpmMode) ||
315 (!*pszEpmMode) ||
316 (!ppszFileList) ||
317 (!pulFileCount) ||
318 (!pulTotalSize) ||
319 (!pfOutdated))
320 {
321 rc = ERROR_INVALID_PARAMETER;
322 break;
323 }
324
325
326 // create a strdup of the path, so that we can tokenize it
327 pszKeywordPath = getenv( pszEnvnameEpmModepath);
328 if (!pszKeywordPath)
329 {
330 rc = ERROR_ENVVAR_NOT_FOUND;
331 break;
332 }
333
334 pszKeywordPath = strdup( pszKeywordPath);
335 if (!pszKeywordPath)
336 {
337 rc = ERROR_NOT_ENOUGH_MEMORY;
338 break;
339 }
340
341 // allocate dynamic memory from file list
342 ALLOCATEMEMORYFILE( pszFileList, 16384);
343
344 // go through all keyword directories
345 pszKeywordDir = strtok( pszKeywordPath, ";");
346 while (pszKeywordDir)
347 {
348 // search all hilite files in that directory
349 sprintf( szSearchMask, SEARCHMASK_HILITEFILES, pszKeywordDir, pszEpmMode);
350
351 // store a filenames
352 hdir = HDIR_CREATE;
353
354 while (rc == NO_ERROR)
355 {
356 // search it
357 rc = GetNextFile( szSearchMask, &hdir,
358 szFile, sizeof( szFile));
359 if (rc != NO_ERROR)
360 break;
361
362 // check if file is already in
363 pszEntry = lfind( szFile, pszFileList, (PUINT) &ulFileCount, _MAX_PATH, _compareFilename);
364 if (pszEntry)
365 continue;
366
367// DPRINTF(( "HILITE: %u [%u] bytes (%u entries) (re)allocated for file list at 0x%08x\n",
368// ulListSize, _msize( pszTmp), ulListSize / _MAX_PATH, pszTmp));
369 pszEntry = pszFileList + (ulFileCount * _MAX_PATH);
370 strcpy( pszEntry, szFile);
371 strlwr( pszEntry );
372 ulFileCount++;
373 ulTotalSize += QueryFileSize( szFile);
374
375 // check filedate
376 if (FileDate( szFile) > ulKeywordFileDate)
377 fOutdated = TRUE;
378
379 }
380 DosFindClose( hdir);
381
382 // handle special errors
383 if (rc == ERROR_NOT_ENOUGH_MEMORY)
384 break;
385 else if (rc = ERROR_NO_MORE_FILES)
386 rc = NO_ERROR;
387
388 // next please
389 pszKeywordDir = strtok( NULL, ";");
390 }
391
392 if (rc != NO_ERROR)
393 break;
394
395 // hand over result
396 *ppszFileList = pszFileList;
397 *pulFileCount = ulFileCount;
398 *pulTotalSize = ulTotalSize;
399 *pfOutdated = fOutdated;
400
401 } while (FALSE);
402
403// cleanup
404if (rc)
405 {
406 if (pszFileList) FREEMEMORYFILE( pszFileList);
407 if (ppszFileList) *ppszFileList = NULL;
408 if (pulFileCount) *pulFileCount = 0;
409 }
410if (pszKeywordPath) free( pszKeywordPath);
411return rc;
412}
413
414// -----------------------------------------------------------------------------
415
416int _compareValue( const void *ppszKeyElement, const void *ppszEntry)
417{
418
419#ifdef DEBUG
420// for view in debugger only:
421 PSZ pszKey = *(PSZ*)ppszKeyElement;
422 PSZ pszEntry = *(PSZ*)ppszEntry;
423#endif
424return stricmp( *(PSZ*)ppszKeyElement, *(PSZ*)ppszEntry);
425}
426
427
428static PVALUEARRAY _maintainInitValueArray( HCONFIG hinit, PSZ pszSection, PVALUEARRAY pva)
429{
430 PVALUEARRAY pvaResult = pva;
431 APIRET rc = NO_ERROR;
432 ULONG i;
433 BOOL fSkip;
434
435 PSZ pszKey;
436 ULONG ulKeyCount;
437 PVALUEARRAY pvaNew = NULL;
438 ULONG ulBuflen;
439 CHAR szKeyList[ 1024];
440 CHAR szKeyValue[ 128];
441
442 PSZ *ppszAnchor;
443 PSZ pszEntry;
444
445 PSZ *ppszOldAnchor;
446 PSZ pszOldEntry;
447
448do
449 {
450 // read the key list
451 QUERYINITVALUE( hinit, pszSection, NULL, szKeyList);
452
453// if (pva)
454// DPRINTF_ARRAY(( "\nmaintaining symbols array at 0x%08x:\n", pva));
455
456 // count items and its size
457 ulBuflen = sizeof( VALUEARRAY);
458 ulKeyCount = 0;
459 pszKey = szKeyList;
460 while (*pszKey)
461 {
462 // does entry exist in the old array? then skip
463 fSkip = FALSE;
464 if (pva)
465 {
466 ppszOldAnchor = bsearch( &pszKey, pva->apszValue, pva->ulCount, sizeof( PSZ), _compareValue);
467 if (ppszOldAnchor)
468 fSkip = TRUE;
469 }
470
471 if (!fSkip)
472 {
473 // add appropriate space and count up
474 ulKeyCount++;
475 ulBuflen += sizeof( PSZ) +
476 strlen( pszKey) + 1 +
477 QUERYINITVALUESIZE( hinit, pszSection, pszKey) + 1;
478 }
479
480 // next key
481 pszKey = NEXTSTR( pszKey);
482 }
483
484 // add count and space of existing array
485 if (pva)
486 {
487 ulBuflen += pva->ulArraySize;
488 ulKeyCount += pva->ulCount;
489 }
490
491 // allocate memory
492 pvaNew = malloc( ulBuflen);
493 if (!pvaNew)
494 break;
495 memset( pvaNew, 0, ulBuflen);
496 pvaNew->ulArraySize = ulBuflen;
497 pvaNew->ulCount = ulKeyCount;
498 pvaResult = pvaNew;
499
500 // remove values from old array, that we want to readd
501 if (pva)
502 {
503 pszKey = szKeyList;
504 while (*pszKey)
505 {
506 // can entry be found in old array? if yes, mark it as deleted
507 ppszOldAnchor = (PVOID)lfind( (PSZ)&pszKey, (PSZ)pva->apszValue, (PUINT)&pva->ulCount, sizeof( PSZ), _compareValue);
508 if (ppszOldAnchor)
509 {
510// DPRINTF_ARRAY(( "HILITE: delete entry %s\n", *ppszOldAnchor));
511 **ppszOldAnchor = 0;
512 }
513
514 // next key
515 pszKey = NEXTSTR( pszKey);
516 }
517 } // if (pva)
518
519 // transfer existing entries
520 ppszAnchor = pvaNew->apszValue;
521 pszEntry = (PSZ) pvaNew->apszValue + (ulKeyCount * sizeof( PSZ));
522 if (pva)
523 {
524 for ( i = 0, ppszOldAnchor = pva->apszValue; i < pva->ulCount; i++, ppszOldAnchor++, ppszAnchor++)
525 {
526 // store entry
527 pszOldEntry = *ppszOldAnchor;
528 if (!*pszOldEntry)
529 {
530 // skip this entry, it has beeen deleted
531 ppszAnchor--;
532 continue;
533 }
534
535// DPRINTF_ARRAY(( "HILITE: transfer entry 0x%08x / 0x%08x: %s - %s\n",
536// pszOldEntry, NEXTSTR( pszOldEntry),
537// pszOldEntry, NEXTSTR( pszOldEntry)));
538
539 *ppszAnchor = pszEntry;
540 strcpy( pszEntry, pszOldEntry);
541
542// DPRINTF_ARRAY(( "HILITE: new entry 0x%08x / 0x%08x: %s - ",
543// pszEntry, NEXTSTR( pszEntry), pszEntry));
544
545 pszEntry = NEXTSTR( pszEntry);
546 pszOldEntry = NEXTSTR( pszOldEntry);
547
548 strcpy( pszEntry, pszOldEntry);
549// DPRINTF_ARRAY(( "%s\n", pszEntry));
550
551 pszEntry = NEXTSTR( pszEntry);
552 }
553 }
554
555 // add new values to array
556 // duplicates are now removed
557 pszKey = szKeyList;
558 while (*pszKey)
559 {
560 // store entry
561 *ppszAnchor = pszEntry;
562
563 strcpy( pszEntry, pszKey);
564 QUERYINITVALUE( hinit, pszSection, pszKey, szKeyValue);
565// DPRINTF_ARRAY(( "HILITE: add entry %s - %s\n", pszEntry, szKeyValue));
566 pszEntry = NEXTSTR( pszEntry);
567
568 strcpy( pszEntry, szKeyValue);
569 pszEntry = NEXTSTR( pszEntry);
570
571// DPRINTF_ARRAY(( "HILITE: array: store %s=%s\n", pszKey, szKeyValue));
572
573 // next key
574 ppszAnchor++;
575 pszKey = NEXTSTR( pszKey);
576 }
577
578 // sort the entries
579 qsort( pvaNew->apszValue, pvaNew->ulCount, sizeof( PSZ), _compareValue);
580
581 // throw away the old array
582 if (pva)
583 free( pva);
584
585 } while (FALSE);
586
587return pvaResult;
588
589}
590
591// -----------------------------------------------------------------------------
592
593static PSZ _queryInitValue( PVALUEARRAY pva, PSZ pszKey)
594{
595 PSZ pszResult = NULL;
596 PSZ *ppszEntry;
597
598do
599 {
600 // search the entry
601 ppszEntry = bsearch( &pszKey, pva->apszValue, pva->ulCount, sizeof( PSZ), _compareValue);
602 if (!ppszEntry)
603 break;
604
605 // report the value
606 pszResult = NEXTSTR( *ppszEntry);
607
608 } while (FALSE);
609
610return pszResult;
611
612}
613
614// -----------------------------------------------------------------------------
615
616static VOID _dumpInitValueArray( PVALUEARRAY pva)
617{
618
619
620 PSZ *ppszEntry = pva->apszValue;
621 PSZ pszEntry;
622 ULONG i;
623
624printf( "\nSymbols from array at 0x%08x:\n", pva);
625
626for (i = 0; i < pva->ulCount; i++)
627 {
628 pszEntry = *ppszEntry;
629 printf( "-> 0x%08x / 0x%08x: %s %s\n",
630 *ppszEntry, NEXTSTR( *ppszEntry),
631 *ppszEntry, NEXTSTR( *ppszEntry));
632 ppszEntry++;
633 }
634printf( "%u entries\n\n", i);
635}
636
637// #############################################################################
638// Determine the filename for a tmp EPM kwds file. Compare EA of the existing
639// EPM kwds file with the mode's INI and HIL file data. If outdated, rebuild it
640// using these files. The EPM kwds file is created in a tmp dir. Therefore
641// following env vars are queried, while one must exist: EPMKWDSTMP, TMP, TEMP.
642// A subdir "nepmd" is created in the tmp dir, holding the kwds files with the
643// filename = mode.
644//
645// Reads:
646// pszEpmMode mode
647// ulOptions 1 if checking for outdated files should be suppressed; also
648// used to control the 1st word of the parm for toggle_parse
649// Returns/alters via call by reference:
650// pfReload 1 if tmp EPM kwds file was rebuilt; used to determine the
651// 1st word of the parm for toggle_parse
652// pszBuffer fully qualified tmp EPM kwds filename
653// Returns:
654// rc 0 if no error
655//
656// Called by NepmdActivateHighlight (E proc):
657// NepmdQueryHighlightArgs (NEPMDLIB.C)
658// QueryHilightFile (HILITE.C)
659// _assembleKeywordFile (HILITE.C)
660//
661// E calls:
662// a_togl_hilit (SAMPACTN.E)
663// ActivateHighlighting (STDCMDS.E)
664// NepmdActivateHighlight (ACTIVATEHIGHLIGHT.E)
665// toggle_highlight, toggle_default_highlight (NEWMENU.E)
666// SetHighlight (MODEEXECUTE.E)
667// NepmdActivateHighlight (ACTIVATEHIGHLIGHT.E)
668// ProcessLoadSettings (MODEEXECUTE.E)
669// NepmdActivateHighlight (ACTIVATEHIGHLIGHT.E)
670//
671// NepmdActivateHighlight uses the toggle_parse command (STDCTRL.E) to execute
672// the highlighting. toggle_parse accepts 0, 1 or 2 as the first word of its
673// parm:
674// 0 unhighlight
675// 1 highlight, load the kwds file if not already loaded
676// 2 highlight and force reloading of the kwds file to reparse it
677
678static APIRET _assembleKeywordFile( PSZ pszEpmMode, ULONG ulOptions, PBOOL pfReload,
679 HCONFIG hconfig,
680 PSZ pszBuffer, ULONG ulBuflen)
681{
682 APIRET rc = NO_ERROR;
683 ULONG i;
684 HMMF hmmf = NULLHANDLE;
685
686 PSZ p;
687 PSZ pszTmpDir;
688
689 PSZ *ppszEntry;
690 PSZ pszEntry;
691 PSZ pszSymbol;
692 PSZ *ppszSymbolValue;
693 CHAR szValue[ MAX_INI_LINE] = "";
694 CHAR szCustomValue[ _MAX_PATH] = "";
695
696 // ----------------------------------
697
698 HINIT hinitGlobals = NULLHANDLE;
699 CHAR szInitGlobalFilename[ _MAX_PATH] = "";
700 HINIT hinitDefault = NULLHANDLE;
701 CHAR szInitDefaultFilename[ _MAX_PATH] = "";
702
703 // ----------------------------------
704
705 HINIT hinitCustom = NULLHANDLE;
706 CHAR szInitCustomFilename[ _MAX_PATH] = "";
707 BOOL fCustomLoaded = FALSE;
708
709 CHAR szCustomCharset[ _MAX_PATH] = "";
710 CHAR szCustomAddCharset[ _MAX_PATH] = "";
711
712 // ----------------------------------
713
714 ULONG ulInfoSize;
715 BOOL fCaseSensitive = FALSE;
716
717 // ----------------------------------
718
719 PVALUEARRAY pvaColors = NULL;
720 PVALUEARRAY pvaSymbols = NULL;
721
722 // ----------------------------------
723
724 CHAR szHilCommentChar[ 20] = "";
725
726 // ----------------------------------
727
728static PSZ pszRegPathTemplate = "\\NEPMD\\User\\Mode\\%s\\%s";
729 CHAR szRegPath[ MAX_REG_PATH] = "";
730 BOOL fImplicitOpen = FALSE;
731
732 // ----------------------------------
733
734 CHAR szKeywordFile[ _MAX_PATH] = "";
735 ULONG ulKeywordFileDate;
736 BOOL fOutdated = FALSE;
737
738 // ----------------------------------
739
740 PSZ pszFileList = NULL;
741 ULONG ulFileCount;
742 ULONG ulTotalSize;
743
744 PSZ pszOldFileInfoList = NULL;
745
746static PSZ pszFileInfoMask = "%s %s %u %u\r\n";
747 PSZ pszFileInfoList = NULL;
748 ULONG ulInfoListSize = 0;
749
750 // ----------------------------------
751
752 PSZ pszSectionDelimiter = NULL;
753 PSZ pszSectionDelimiteri = NULL;
754 PSZ pszSectionKeywords = NULL;
755 PSZ pszSectionSpecial = NULL;
756 PSZ pszSectionBreakChar = NULL;
757 PSZ pszSectionEndChar = NULL;
758
759 PSZ pszCurrentDelimiter;
760 PSZ pszCurrentDelimiteri;
761 PSZ pszCurrentKeywords;
762 PSZ pszCurrentSpecial;
763 PSZ pszCurrentBreakChar;
764 PSZ pszCurrentEndChar;
765
766static PSZ pszHeaderMask = "\r\n%s%s\r\n";
767
768 // ----------------------------------
769 ULONG ulCurrentFile;
770 PSZ pszSourceFile;
771 FILE *pfile = NULL;
772 ULONG ulLineCount;
773 CHAR szLine[ 1024] = "";
774 BOOL fSectionStart;
775 PSZ pszLine;
776 CHAR szCurrentSection[ 64] = "";
777 PSZ pszCurrentSectionColors;
778 CHAR szEntryColors[32];
779 BOOL fEntryColors;
780
781// keep these definitions in sync!!!
782 ULONG ulSectionIndex;
783 PSZ apszSpecialSections[] = {"", "COMMENT", "LITERAL", "SPECIAL", "OPERATOR", "BREAKCHAR", "ENDCHAR"};
784#define COUNT_SPECIALSECTION (sizeof( apszSpecialSections) / sizeof( PSZ))
785#define SECTION_DEFAULT 0
786#define SECTION_COMMENT 1
787#define SECTION_LITERAL 2
788#define SECTION_SPECIAL 3
789#define SECTION_OPERATOR 4
790#define SECTION_BREAKCHAR 5
791#define SECTION_ENDCHAR 6
792
793
794 PSZ pszStartStr;
795 PSZ pszStopStr;
796 PSZ pszBreakStr;
797 PSZ pszStartPos;
798 PSZ pszSymbolValue;
799 PSZ pszColorValue1;
800 PSZ pszColorValue2;
801 PSZ pszInvalid;
802 ULONG ulSelectIndex;
803
804 ULONG ulThisSectionIndex;
805
806 // ----------------------------------
807
808 PSZ pszHiliteContents = NULL;
809 ULONG ulHiliteContentsLen;
810 PSZ pszCurrent;
811
812 CHAR szCharset[ MAX_INI_LINE] = "";
813 CHAR szFileBuffer[ 2* MAX_INI_LINE + 1] = "";
814 CHAR szAddFileBuffer[ MAX_INI_LINE] = "";
815
816 PSZ apszKeys[] =
817 {
818 // used for mode determination and for building EPM highlighting files
819 // Each line is a set of 3 related keys:
820 // File key Registry key "ADD_" file key
821 KEY_CHARSET, REGKEY_CHARSET, KEY_ADD_CHARSET,
822 KEY_DEFEXTENSIONS, REGKEY_DEFEXTENSIONS, KEY_ADD_DEFEXTENSIONS,
823 KEY_DEFNAMES, REGKEY_DEFNAMES, KEY_ADD_DEFNAMES,
824 KEY_CASESENSITIVE, REGKEY_CASESENSITIVE, "",
825 // the following keys can hold word list, not only single words
826 KEY_LINECOMMENT, REGKEY_LINECOMMENT, "",
827 KEY_LINECOMMENTPOS, REGKEY_LINECOMMENTPOS, "",
828 KEY_LINECOMMENTNEEDSPACE, REGKEY_LINECOMMENTNEEDSPACE, "",
829 KEY_LINECOMMENTOVERRIDEMULTI, REGKEY_LINECOMMENTOVERRIDEMULTI, "",
830 KEY_MULTILINECOMMENTSTART, REGKEY_MULTILINECOMMENTSTART, "",
831 KEY_MULTILINECOMMENTEND, REGKEY_MULTILINECOMMENTEND, "",
832 KEY_MULTILINECOMMENTNESTED, REGKEY_MULTILINECOMMENTNESTED, "",
833 // additional keys to support COMMENT.E
834 KEY_LINECOMMENTADDSPACE, REGKEY_LINECOMMENTADDSPACE, "",
835 KEY_PREFERREDCOMMENT, REGKEY_PREFERREDCOMMENT, ""
836 };
837
838#define NUM_KEY_ADDRESSES (sizeof(apszKeys)/sizeof(PSZ))
839
840FUNCENTER;
841
842do
843 {
844 // check parms
845 if ((!pszEpmMode) ||
846 (!*pszEpmMode) ||
847 (!pfReload) ||
848 (!pszBuffer))
849 {
850 rc = ERROR_INVALID_PARAMETER;
851 break;
852 }
853
854 // check env
855 do
856 {
857 pszTmpDir = getenv( "EPMKWDSTMP");
858 if (pszTmpDir)
859 break;
860
861 pszTmpDir = getenv( "TMP");
862 if (pszTmpDir)
863 break;
864
865 pszTmpDir = getenv( "TEMP");
866
867 } while (FALSE);
868
869 if (!pszTmpDir)
870 {
871 rc = ERROR_ENVVAR_NOT_FOUND;
872 break;
873 }
874
875 // init target vars
876 *pfReload = TRUE;
877 memset( pszBuffer, 0, ulBuflen);
878
879 // -----------------------------------------------
880
881 // get the name and date of the temporary file
882
883 // get keywordfile
884 strupr( pszEpmMode);
885
886 // no keyword file yet, create a new one
887 // for that create subdirectory below TMP
888 sprintf( szKeywordFile, SEARCHMASK_MODEDIR, pszTmpDir);
889 rc = CreatePath( szKeywordFile);
890 if ((rc != NO_ERROR) && (rc != ERROR_ACCESS_DENIED))
891 break;
892 sprintf( _EOS( szKeywordFile), "\\%s", pszEpmMode);
893 strlwr( szKeywordFile);
894
895 // -----------------------------------------------
896
897 // --- hand over filename already here
898
899 // check result buffer
900 if (strlen( szKeywordFile) + 1 > ulBuflen)
901 {
902 rc = ERROR_BUFFER_OVERFLOW;
903 break;
904 }
905
906 // hand over result
907 strcpy( pszBuffer, szKeywordFile);
908
909 // if no update check, return filename if file exists
910 if ((ulOptions && HILITE_NOOUTDATECHECK) &&
911 (FileExists( szKeywordFile)))
912 {
913 rc = NO_ERROR;
914 break;
915 }
916
917 // -----------------------------------------------
918
919 // initialize support for memory mapped files
920
921 rc = MmfInitialize( &hmmf, 16);
922 if (rc != NO_ERROR)
923 break;
924
925 // -----------------------------------------------
926
927 // search and load values from INI files
928
929 // - read global values
930 rc = _openInitFile( &hinitGlobals, pszEnvnameEpmModepath, SEARCHMASK_GLOBALINI, NULL,
931 szInitGlobalFilename, sizeof( szInitGlobalFilename));
932 if (rc != NO_ERROR)
933 break;
934
935// DPRINTF(("Global Filename: '%s'\n", szInitGlobalFilename));
936 pvaColors = _maintainInitValueArray( hinitGlobals, pszColorsSection, NULL);
937 pvaSymbols = _maintainInitValueArray( hinitGlobals, pszSymbolsSection, NULL);
938
939
940 // - read defaults of the mode
941 rc = _openInitFile( &hinitDefault, pszEnvnameEpmModepath, SEARCHMASK_DEFAULTINI, pszEpmMode,
942 szInitDefaultFilename, sizeof( szInitDefaultFilename));
943 if (rc != NO_ERROR)
944 break;
945
946// DPRINTF(("Default Filename: '%s'\n", szInitDefaultFilename));
947 // - read customs of the mode - optional - so ignore errors here
948 rc = _openInitFile( &hinitCustom, pszEnvnameEpmModepath, SEARCHMASK_CUSTOMINI, pszEpmMode,
949 szInitCustomFilename, sizeof( szInitCustomFilename));
950 rc = NO_ERROR; // Disregard errors on custom file
951 for ( i = 0; i < NUM_KEY_ADDRESSES; i += 3)
952 {
953 PSZ pszDefaultValue;
954 szFileBuffer[0] = '\0';
955 if (hinitCustom)
956 {
957 QUERYOPTINITVALUE( hinitCustom, pszGlobalSection, apszKeys[i], szFileBuffer, "");
958// DPRINTF(( "Custom. File %s Key '%s' Value '%s'\n", szInitCustomFilename, apszKeys[i], szFileBuffer));
959 if (*(apszKeys[i+2]))
960 {
961 szAddFileBuffer[0] = '\0';
962 QUERYOPTINITVALUE( hinitCustom, pszGlobalSection, apszKeys[i+2], szAddFileBuffer, "");
963// DPRINTF(( "Custom addl. Key '%s' Value '%s'\n", apszKeys[i+2], szFileBuffer));
964 if (szAddFileBuffer[0])
965 {
966 if (apszKeys[i] == KEY_CHARSET)
967 {
968 strcat( szFileBuffer, szAddFileBuffer);
969 }
970 else // if not charset, must be "word" list
971 {
972 strcat( szFileBuffer, " ");
973 strcat( szFileBuffer, szAddFileBuffer);
974 strupr( szFileBuffer);
975 }
976 }
977 }
978 }
979 if (!szFileBuffer[0]) // If not set from custom, read from default.ini
980 {
981// DPRINTF(("Addr1 Addr2 string %08x %08x %s\n", apszKeys[i], KEY_CHARSET, apszKeys[i]));
982 if (!strcmp( apszKeys[i], KEY_CHARSET))
983 {
984 QUERYINITVALUE( hinitDefault, pszGlobalSection, apszKeys[i], szFileBuffer);
985 pszDefaultValue = STR_CASESENSITIVE;
986// DPRINTF(( "Default charset. Key '%s' Value '%s'\n", apszKeys[i], szFileBuffer));
987 }
988 else
989 {
990 if (!strcmp( apszKeys[i], KEY_CASESENSITIVE))
991 {
992 pszDefaultValue = STR_CASESENSITIVE;
993 }
994 else
995 {
996 pszDefaultValue = "";
997 }
998 QUERYOPTINITVALUE( hinitDefault, pszGlobalSection, apszKeys[i], szFileBuffer, pszDefaultValue);
999// DPRINTF(( "Default. Key '%s' Value '%s'\n", apszKeys[i], szFileBuffer));
1000 }
1001 }
1002 sprintf( szRegPath, pszRegPathTemplate, pszEpmMode, apszKeys[i+1]);
1003// DPRINTF(( "Regpath. Key '%s' Full path '%s'\n", apszKeys[i+1], szRegPath));
1004 rc = WriteConfigValue( hconfig, szRegPath, szFileBuffer);
1005// DPRINTF(( "Regupd rc %d Value '%s'\n", rc, szFileBuffer));
1006 if (!strcmp( apszKeys[i], KEY_CASESENSITIVE))
1007 {
1008 fCaseSensitive = atol( szFileBuffer);
1009// DPRINTF(( "Case sensitive: %d\n", fCaseSensitive));
1010 }
1011 else
1012 {
1013 if (!strcmp( apszKeys[i], KEY_CHARSET))
1014 {
1015 strcpy(szCharset, szFileBuffer);
1016// DPRINTF(( "Charset: %s\n", szCharset));
1017 }
1018 }
1019 }
1020
1021 // -----------------------------------------------
1022
1023 DUMPINITVALUEARRAY( pvaSymbols);
1024
1025 // add/replace with symbols from <mode>\default.ini
1026 pvaSymbols = _maintainInitValueArray( hinitDefault, pszSymbolsSection, pvaSymbols);
1027
1028 DUMPINITVALUEARRAY( pvaSymbols);
1029
1030 // add/replace with symbols from <mode>\custom.ini
1031 pvaSymbols = _maintainInitValueArray( hinitDefault, pszSymbolsSection, pvaSymbols);
1032
1033 DUMPINITVALUEARRAY( pvaSymbols);
1034
1035 if (hinitCustom)
1036 pvaSymbols = _maintainInitValueArray( hinitCustom, pszSymbolsSection, pvaSymbols);
1037
1038 // -----------------------------------------------
1039
1040 // replace color values in symbol defs
1041 ppszEntry = pvaSymbols->apszValue;
1042 for (i = 0; i < pvaSymbols->ulCount; i++)
1043 {
1044
1045 PSZ pszValueBuf;
1046 ULONG ulValueLen;
1047 PSZ pszValue;
1048
1049 // loop through all symbols
1050 pszEntry = *ppszEntry;
1051 szValue[ 0] = 0;
1052
1053 // replace color names with color values
1054 pszValueBuf = NEXTSTR( *ppszEntry);
1055 ulValueLen = strlen( pszValueBuf);
1056
1057 pszSymbol = strtok( pszValueBuf, " ");
1058 while (pszSymbol)
1059 {
1060 ppszSymbolValue = bsearch( &pszSymbol,
1061 pvaColors->apszValue,
1062 pvaColors->ulCount,
1063 sizeof( PSZ),
1064 _compareValue);
1065 if (ppszSymbolValue)
1066 {
1067 pszValue = NEXTSTR( *ppszSymbolValue);
1068 strcat( szValue, " ");
1069 strcat( szValue, pszValue);
1070// DPRINTF(( "HILITE: %s: %s -> %s\n", pszEntry, pszSymbol, pszValue));
1071 }
1072
1073 // next symbol
1074 pszSymbol = strtok( NULL, " ");
1075 }
1076
1077 // check buffer
1078 _stripblanks( szValue);
1079 if (strlen( szValue) <= ulValueLen)
1080 strcpy( pszValueBuf, szValue);
1081
1082 // next entry
1083 ppszEntry++;
1084 }
1085
1086 // -----------------------------------------------
1087
1088 // check for the file date - if not exists, will return -1,
1089 // then reset to zero to force a rebuild
1090 ulKeywordFileDate = FileDate( szKeywordFile);
1091 if (ulKeywordFileDate == - 1)
1092 ulKeywordFileDate = 0;
1093
1094 // get the list of files
1095 ulFileCount = 0;
1096 rc = _getDefFileList( hmmf, pszEpmMode, ulKeywordFileDate, &pszFileList, &ulFileCount, &ulTotalSize, &fOutdated);
1097 if (rc != NO_ERROR)
1098 break;
1099
1100 // if result file is not outdated, check the file list
1101 if (!fOutdated)
1102 {
1103 // check if file has an EA containing the old filelist
1104 rc = QueryStringEa( szKeywordFile, pszFileInfoListEaName, NULL, &ulInfoListSize);
1105 if (rc == ERROR_BUFFER_OVERFLOW)
1106 {
1107 pszOldFileInfoList = malloc( ulInfoListSize);
1108 if (!pszOldFileInfoList)
1109 {
1110 rc = ERROR_NOT_ENOUGH_MEMORY;
1111 break;
1112 }
1113 rc = QueryStringEa( szKeywordFile, pszFileInfoListEaName, pszOldFileInfoList, &ulInfoListSize);
1114 if (rc != NO_ERROR)
1115 break;
1116 }
1117 else
1118 // EA not found, just proceed!
1119 rc = NO_ERROR;
1120 }
1121
1122 // generate info list
1123 ulInfoListSize = ulFileCount * (MAX_INI_LINE + 32);
1124 ALLOCATEMEMORYFILE( pszFileInfoList, ulInfoListSize);
1125
1126 QUERYOPTINITVALUE( hinitDefault, pszGlobalSection, KEY_HILCOMMENTCHAR, szHilCommentChar, STR_KWDSCOMMENT); // first of all add info of init files to file list
1127 pszSourceFile = szInitGlobalFilename;
1128 sprintf( _EOS( pszFileInfoList), pszFileInfoMask, szHilCommentChar, pszSourceFile, QueryFileSize( pszSourceFile), FileDate( pszSourceFile));
1129 pszSourceFile = szInitDefaultFilename;
1130 sprintf( _EOS( pszFileInfoList), pszFileInfoMask, szHilCommentChar, pszSourceFile, QueryFileSize( pszSourceFile), FileDate( pszSourceFile));
1131 if (hinitCustom)
1132 {
1133 pszSourceFile = szInitCustomFilename;
1134 sprintf( _EOS( pszFileInfoList), pszFileInfoMask, szHilCommentChar, pszSourceFile, QueryFileSize( pszSourceFile), FileDate( pszSourceFile));
1135 }
1136
1137 // loop thru all files
1138 for (ulCurrentFile = 0, pszSourceFile = pszFileList;
1139 ulCurrentFile < ulFileCount;
1140 ulCurrentFile++, pszSourceFile += _MAX_PATH)
1141 {
1142 // add file to the info list
1143 sprintf( _EOS( pszFileInfoList), pszFileInfoMask, szHilCommentChar, pszSourceFile, QueryFileSize( pszSourceFile), FileDate( pszSourceFile));
1144 }
1145
1146 // now check the file list, if old one is present
1147 // if it is equal (including timestamps!)
1148 // break with no error
1149 if (pszOldFileInfoList)
1150 {
1151 if (!strcmp( pszOldFileInfoList, pszFileInfoList))
1152 {
1153// DPRINTF(( "HILITE: file has not changed!\n"
1154// "files used for last generation\n"
1155// "------------------------------\n"
1156// "%s\n", pszOldFileInfoList));
1157
1158 *pfReload = FALSE;
1159 break;
1160 }
1161 }
1162
1163 // -----------------------------------------------
1164
1165 // open up in-memory files for the six sections
1166 ALLOCATEMEMORYFILE( pszSectionDelimiter, ulTotalSize);
1167 ALLOCATEMEMORYFILE( pszSectionDelimiteri, ulTotalSize);
1168 ALLOCATEMEMORYFILE( pszSectionKeywords, ulTotalSize * 2);
1169 ALLOCATEMEMORYFILE( pszSectionSpecial, ulTotalSize);
1170 ALLOCATEMEMORYFILE( pszSectionBreakChar, ulTotalSize);
1171 ALLOCATEMEMORYFILE( pszSectionEndChar, ulTotalSize);
1172
1173 pszCurrentDelimiter = pszSectionDelimiter;
1174 pszCurrentDelimiteri = pszSectionDelimiteri;
1175 pszCurrentKeywords = pszSectionKeywords;
1176 pszCurrentSpecial = pszSectionSpecial;
1177 pszCurrentBreakChar = pszSectionBreakChar;
1178 pszCurrentEndChar = pszSectionEndChar;
1179
1180 // -----------------------------------------------
1181
1182 // loop thru all files
1183 for (ulCurrentFile = 0, pszSourceFile = pszFileList;
1184 ulCurrentFile < ulFileCount;
1185 ulCurrentFile++, pszSourceFile += _MAX_PATH)
1186 {
1187
1188 do
1189 {
1190 // open the file
1191// DPRINTF(( "HILITE: process file %s\n", pszSourceFile));
1192 pfile = fopen( pszSourceFile, "r");
1193 szCurrentSection[ 0] = 0;
1194 pszCurrentSectionColors = 0;
1195 pszLine = szLine;
1196 ulLineCount = 0;
1197
1198 while (!feof( pfile))
1199 {
1200 // read line
1201 if (!fgets( szLine, sizeof( szLine),pfile))
1202 break;
1203 pszLine = szLine;
1204 ulLineCount++;
1205
1206 // skip comments - the comment char must be on the first column!
1207 if ((*pszLine == CHAR_HILCOMMENT) ||
1208 (*pszLine == 0))
1209 continue;
1210
1211 // check for section start before stipping blanks!
1212 fSectionStart = (*pszLine == CHAR_SECTION_START);
1213
1214 // skip leading blanks anyway (also trailing newline)
1215 _stripblanks( pszLine);
1216
1217 // skip empty lines
1218 if (*pszLine == 0)
1219 continue;
1220
1221 // handle new section
1222 if (fSectionStart)
1223 {
1224 strcpy( pszLine, pszLine + 1);
1225 p = strchr( pszLine, CHAR_SECTION_END);
1226 if (!p)
1227 continue;
1228 *p = 0;
1229
1230 // if there exists a symbol, store values
1231 strupr( pszLine);
1232 pszCurrentSectionColors = _queryInitValue( pvaSymbols, pszLine);
1233 if (pszCurrentSectionColors)
1234 {
1235 strcpy( szCurrentSection, strupr( pszLine));
1236// DPRINTF(( "HILITE: - process section %s with colors: %s\n", szCurrentSection, pszCurrentSectionColors));
1237 }
1238 else
1239 DPRINTF(( "HILITE: - error: skipping invalid section = %s from line %u on, filename = %s\n", pszLine, ulLineCount, pszSourceFile));
1240
1241 // check if the values of the current symbol belong to a special section
1242 ulSectionIndex = 0;
1243 for (i = 1; i < COUNT_SPECIALSECTION; i++)
1244 {
1245 if (!strcmp( apszSpecialSections[ i], szCurrentSection))
1246 {
1247 ulSectionIndex = i;
1248// DPRINTF(( "HILITE: - special section recognized, index %u\n", ulSectionIndex));
1249 }
1250 }
1251
1252 continue;
1253 }
1254
1255 // from here, skip line if no valid section has been found
1256 if (!pszCurrentSectionColors)
1257 continue;
1258
1259 // tokenize line
1260 pszStartStr = NULL;
1261 pszStopStr = NULL;
1262 pszBreakStr = NULL;
1263 pszStartPos = NULL;
1264
1265 pszSymbolValue = NULL;
1266 pszColorValue1 = NULL;
1267 pszColorValue2 = NULL;
1268 pszInvalid = NULL;
1269
1270 pszStartStr = strtok( pszLine, " ");
1271 pszLine = strtok( NULL, " ");
1272 while (pszLine)
1273 {
1274 do
1275 {
1276
1277 // ------------------------------------
1278 // check if keyword is a symbol
1279 p = _queryInitValue( pvaSymbols, pszLine);
1280 if (p)
1281 {
1282 if ((!pszSymbolValue) &&
1283 (!pszColorValue1) &&
1284 (!pszColorValue2))
1285 pszSymbolValue = p;
1286 else
1287 pszInvalid = pszLine;
1288
1289 break;
1290 }
1291
1292 // ------------------------------------
1293
1294 // check if keyword is a color
1295 p = _queryInitValue( pvaColors, pszLine);
1296 if (p)
1297 {
1298#if ALLOW_COLOR_VALUES
1299 if ((!pszColorValue1) && (!pszSymbolValue))
1300 pszColorValue1 = p;
1301 else if ((!pszColorValue2) && (!pszSymbolValue))
1302 pszColorValue2 = p;
1303 else
1304 pszInvalid = pszLine;
1305#else
1306 pszInvalid = pszLine;
1307#endif
1308 break;
1309 }
1310
1311 // ------------------------------------
1312
1313 // use comment char if special keyword is specified
1314 if (!strcmp( pszKeywordNone, pszLine))
1315 pszLine = szHilCommentChar;
1316
1317 // store all other values
1318 if (!pszStopStr)
1319 pszStopStr = pszLine;
1320 else if (!pszBreakStr)
1321 pszBreakStr = pszLine;
1322 else if (!pszStartPos)
1323 pszStartPos = pszLine;
1324 else
1325 pszInvalid = pszLine;
1326
1327 } while (FALSE);
1328
1329 if (pszInvalid)
1330 break;
1331
1332 // next one
1333 pszLine = strtok( NULL, " ");
1334 }
1335
1336 // still invalid line?
1337 if (pszInvalid)
1338 {
1339 DPRINTF(( "HILITE: error: skipping invalid line %u, invalid token = %s, filename = %s\n", ulLineCount, pszInvalid, pszSourceFile));
1340 continue;
1341 }
1342
1343
1344 // check for color to be used
1345 fEntryColors = FALSE;
1346 if (pszSymbolValue)
1347 {
1348 strcpy( szEntryColors, pszSymbolValue);
1349 fEntryColors = TRUE;
1350 }
1351 else if ((pszColorValue1) && (pszColorValue2))
1352 {
1353 sprintf( szEntryColors, "%s %s", pszColorValue1, pszColorValue2);
1354 fEntryColors = TRUE;
1355 }
1356 else
1357 strcpy( szEntryColors, pszCurrentSectionColors);
1358
1359 // if a stop character is still available, make it a DELIM/DELIMI entry
1360 ulSelectIndex = ulSectionIndex;
1361 if (pszStopStr)
1362 ulSelectIndex = SECTION_COMMENT;
1363
1364 // handle different sections
1365 switch (ulSelectIndex)
1366 {
1367 case SECTION_DEFAULT:
1368 sprintf( pszCurrentKeywords, "%s %s\r\n", pszStartStr, szEntryColors);
1369 pszCurrentKeywords = _EOS( pszCurrentKeywords);
1370 break;
1371
1372 case SECTION_COMMENT:
1373 case SECTION_LITERAL:
1374 p = (fCaseSensitive) ?
1375 pszCurrentDelimiter : pszCurrentDelimiteri;
1376
1377 sprintf( p, "%s %s",
1378 pszStartStr, szEntryColors);
1379 if (pszStopStr)
1380 sprintf( _EOS( p), " %s", pszStopStr);
1381 if (pszBreakStr)
1382 sprintf( _EOS( p), " %s", pszBreakStr);
1383 if (pszStartPos)
1384 sprintf( _EOS( p), " %s", pszStartPos);
1385 strcat( p, "\r\n");
1386
1387 if (fCaseSensitive)
1388 pszCurrentDelimiter = _EOS( pszCurrentDelimiter);
1389 else
1390 pszCurrentDelimiteri = _EOS( pszCurrentDelimiteri);
1391 break;
1392
1393 case SECTION_SPECIAL:
1394 case SECTION_OPERATOR:
1395 sprintf( pszCurrentSpecial, "%s %s\r\n", pszStartStr, szEntryColors);
1396 pszCurrentSpecial = _EOS( pszCurrentSpecial);
1397 break;
1398
1399 case SECTION_BREAKCHAR:
1400 sprintf( pszCurrentBreakChar, "%s", pszStartStr);
1401 if (fEntryColors)
1402 sprintf( _EOS( pszCurrentBreakChar), " %s", szEntryColors);
1403 strcat( pszCurrentBreakChar, "\r\n");
1404 pszCurrentBreakChar = _EOS( pszCurrentBreakChar);
1405 break;
1406
1407 case SECTION_ENDCHAR:
1408 sprintf( pszCurrentEndChar, "%s", pszStartStr);
1409 if (fEntryColors)
1410 sprintf( _EOS( pszCurrentEndChar), " %s", szEntryColors);
1411 strcat( pszCurrentEndChar, "\r\n");
1412 pszCurrentEndChar = _EOS( pszCurrentEndChar);
1413 break;
1414
1415 } // switch (ulThisSectionIndex)
1416
1417 } // while (!feof( pinit->pfile))
1418
1419
1420 } while (FALSE);
1421
1422 // cleanup
1423 if (pfile) fclose( pfile);
1424
1425 } // for [all files]
1426
1427 // -----------------------------------------------
1428
1429
1430 // determine the length
1431 ulHiliteContentsLen = (pszCurrentDelimiter - pszSectionDelimiter) +
1432 (pszCurrentDelimiteri - pszSectionDelimiteri) +
1433 (pszCurrentKeywords - pszSectionKeywords) +
1434 (pszCurrentSpecial - pszSectionSpecial) +
1435 (pszCurrentBreakChar - pszSectionBreakChar) +
1436 (pszCurrentEndChar - pszSectionEndChar) +
1437 (strlen(szCharset) + 32);
1438
1439// DPRINTF(( "HILITE: assembling %u bytes to hilite file: %s\n", ulHiliteContentsLen, szKeywordFile));
1440
1441 rc = MmfAlloc( hmmf,
1442 (PVOID*)&pszHiliteContents,
1443 szKeywordFile,
1444 MMF_ACCESS_READWRITE |
1445 MMF_OPENMODE_RESETFILE,
1446 ulHiliteContentsLen + 4096);
1447 if (rc != NO_ERROR)
1448 break;
1449
1450// DPRINTF(( "- allocated buffer at 0x%08x, len %u, end address 0x%08x\n",
1451// pszHiliteContents, ulHiliteContentsLen, pszHiliteContents + ulHiliteContentsLen));
1452
1453 // write one line with the comment char only, followed by header and FileInfoList
1454 pszCurrent = pszHiliteContents;
1455 sprintf( pszCurrent, "%s\r\n"
1456 "%s NEPMD keyword highlighting definition - Files used\r\n"
1457 "%s ==================================================\r\n",
1458 szHilCommentChar, szHilCommentChar, szHilCommentChar);
1459 pszCurrent = _EOS( pszCurrent);
1460 strcat( pszCurrent, pszFileInfoList);
1461 pszCurrent = _EOS( pszCurrent);
1462
1463 // first of all write CHARSET
1464 sprintf( pszCurrent, pszHeaderMask, szHilCommentChar, "CHARSET");
1465// DPRINTF(( "- at 0x%08x adding header for %s\n", pszCurrent, pszCurrent));
1466 pszCurrent = _EOS( pszCurrent);
1467 sprintf( pszCurrent, "%s\r\n", szCharset);
1468 pszCurrent = _EOS( pszCurrent);
1469
1470 // add all sections, if something in it
1471 if (pszCurrentDelimiter - pszSectionDelimiter)
1472 {
1473 sprintf( pszCurrent, pszHeaderMask, szHilCommentChar, "DELIM");
1474// DPRINTF(( "- at 0x%08x adding header for %s\n", pszCurrent, pszCurrent));
1475 pszCurrent = _EOS( pszCurrent);
1476 strcpy( pszCurrent, pszSectionDelimiter);
1477 pszCurrent = _EOS( pszCurrent);
1478 }
1479
1480 if (pszCurrentDelimiteri - pszSectionDelimiteri)
1481 {
1482 sprintf( pszCurrent, pszHeaderMask, szHilCommentChar, "DELIMI");
1483// DPRINTF(( "- at 0x%08x adding header for %s\n", pszCurrent, pszCurrent));
1484 pszCurrent = _EOS( pszCurrent);
1485 strcpy( pszCurrent, pszSectionDelimiteri);
1486 pszCurrent = _EOS( pszCurrent);
1487 }
1488
1489 if (pszCurrentKeywords - pszSectionKeywords)
1490 {
1491 sprintf( pszCurrent, pszHeaderMask, szHilCommentChar, (fCaseSensitive) ? "KEYWORDS" : "INSENSITIVE");
1492// DPRINTF(( "- at 0x%08x adding header for %s\n", pszCurrent, pszCurrent));
1493 pszCurrent = _EOS( pszCurrent);
1494 strcpy( pszCurrent, pszSectionKeywords);
1495 pszCurrent = _EOS( pszCurrent);
1496 }
1497
1498 if (pszCurrentSpecial - pszSectionSpecial)
1499 {
1500 sprintf( pszCurrent, pszHeaderMask, szHilCommentChar, (fCaseSensitive) ? "SPECIAL" : "SPECIALI");
1501// DPRINTF(( "- at 0x%08x adding header for %s\n", pszCurrent, pszCurrent));
1502 pszCurrent = _EOS( pszCurrent);
1503 strcpy( pszCurrent, pszSectionSpecial);
1504 pszCurrent = _EOS( pszCurrent);
1505 }
1506
1507 if (pszCurrentBreakChar - pszSectionBreakChar)
1508 {
1509 sprintf( pszCurrent, pszHeaderMask, szHilCommentChar, "BREAK");
1510// DPRINTF(( "- at 0x%08x adding header for %s\n", pszCurrent, pszCurrent));
1511 pszCurrent = _EOS( pszCurrent);
1512 strcpy( pszCurrent, pszSectionBreakChar);
1513 pszCurrent = _EOS( pszCurrent);
1514 }
1515
1516 if (pszCurrentEndChar - pszSectionEndChar)
1517 {
1518 sprintf( pszCurrent, pszHeaderMask, szHilCommentChar, "ENDCHAR");
1519// DPRINTF(( "- at 0x%08x adding header for %s\n", pszCurrent, pszCurrent));
1520 pszCurrent = _EOS( pszCurrent);
1521 strcpy( pszCurrent, pszSectionEndChar);
1522 pszCurrent = _EOS( pszCurrent);
1523 }
1524
1525 // set filesize
1526 ulHiliteContentsLen = strlen( pszHiliteContents);
1527 rc = MmfSetSize( hmmf, pszHiliteContents, ulHiliteContentsLen);
1528// DPRINTF(( "- setting filesize to size of %u bytes, rc=%u\n", ulHiliteContentsLen, rc));
1529
1530 // write temporary file
1531 rc = MmfUpdate( hmmf, pszHiliteContents);
1532// DPRINTF(( "- update file, rc=%u\n", rc));
1533
1534
1535 // close target file first so that we can write the EA
1536 FREEMEMORYFILE( pszHiliteContents);
1537 pszHiliteContents = NULL;
1538
1539 // add file infolist as extended attribute
1540 rc = WriteStringEa( szKeywordFile, pszFileInfoListEaName, pszFileInfoList);
1541// DPRINTF(( "\n"
1542// "HILITE: used files for generation\n"
1543// "---------------------------------\n"
1544// "%s\n", pszFileInfoList));
1545
1546 } while (FALSE);
1547
1548// cleanup
1549
1550if (pvaColors) free( pvaColors);
1551if (pvaSymbols) free( pvaSymbols);
1552if (pszOldFileInfoList) free( pszOldFileInfoList);
1553
1554if (pszFileList) FREEMEMORYFILE( pszFileList);
1555if (pszFileInfoList) FREEMEMORYFILE( pszFileInfoList);
1556if (pszSectionDelimiter) FREEMEMORYFILE( pszSectionDelimiter);
1557if (pszSectionDelimiteri) FREEMEMORYFILE( pszSectionDelimiteri);
1558if (pszSectionKeywords) FREEMEMORYFILE( pszSectionKeywords);
1559if (pszSectionSpecial) FREEMEMORYFILE( pszSectionSpecial);
1560if (pszSectionBreakChar) FREEMEMORYFILE( pszSectionBreakChar);
1561if (pszSectionEndChar) FREEMEMORYFILE( pszSectionEndChar);
1562if (pszHiliteContents) FREEMEMORYFILE( pszHiliteContents);
1563
1564if (hinitCustom) InitCloseProfile( hinitCustom, FALSE);
1565if (hinitDefault) InitCloseProfile( hinitDefault, FALSE);
1566if (hinitGlobals) InitCloseProfile( hinitGlobals, FALSE);
1567if (hmmf) MmfTerminate( hmmf);
1568
1569FUNCEXITRC;
1570return rc;
1571}
1572
1573// #############################################################################
1574
1575APIRET QueryHilightFile( PSZ pszEpmMode, ULONG ulOptions, PBOOL pfReload,
1576 HCONFIG hconfig,
1577 PSZ pszBuffer, ULONG ulBuflen)
1578{
1579 APIRET rc = NO_ERROR;
1580 CHAR szValue[ _MAX_PATH];
1581// CHAR szDefaultsFile[ _MAX_PATH];
1582
1583
1584do
1585 {
1586 // init return value first
1587 if (pszBuffer)
1588 memset( pszBuffer, 0, ulBuflen);
1589
1590 // check parms
1591 if ((!pszEpmMode) ||
1592 (!*pszEpmMode) ||
1593 (!pfReload) ||
1594 (!pszBuffer))
1595 {
1596 rc = ERROR_INVALID_PARAMETER;
1597 break;
1598 }
1599
1600// DPRINTF(( "### HILITE: %s: options: %08x\n", pszEpmMode, ulOptions));
1601
1602 // search mode files
1603 rc = _assembleKeywordFile( pszEpmMode, ulOptions, pfReload, hconfig, szValue, sizeof( szValue));
1604 if (rc == NO_ERROR)
1605 {
1606 // disable reload if HighlightFlag <> 0
1607 if (ulOptions)
1608 *pfReload = FALSE;
1609 }
1610 else
1611 {
1612 // if no mode infos available; conventional search
1613 rc = _searchFile( pszEnvnameEpmPath, szValue, sizeof( szValue), SEARCHMASK_EPMKWDS, pszEpmMode);
1614 if (rc != NO_ERROR)
1615 break;
1616 // always do not reload this one (default EPM behaviour)
1617 *pfReload = FALSE;
1618 }
1619
1620 // check result buffer
1621 if (strlen( szValue) + 1 > ulBuflen)
1622 {
1623 rc = ERROR_BUFFER_OVERFLOW;
1624 break;
1625 }
1626
1627 // hand over result
1628 strcpy( pszBuffer, szValue);
1629
1630 } while (FALSE);
1631
1632return rc;
1633}
1634
Note: See TracBrowser for help on using the repository browser.