3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Parse a strings file and create or add to a string database file.
27 #include <EfiUtilityMsgs.h>
29 #include "StrGather.h"
32 #define UTILITY_NAME "StrGather"
33 #define UTILITY_VERSION "v1.2"
38 #define MAX_NEST_DEPTH 20 // just in case we get in an endless loop.
39 #define MAX_STRING_IDENTIFIER_NAME 128 // number of wchars
40 #define MAX_LINE_LEN 400
41 #define STRING_TOKEN "STRING_TOKEN"
42 #define DEFAULT_BASE_NAME "BaseName"
44 // Operational modes for this utility
46 #define MODE_UNKNOWN 0
52 // This is how we invoke the C preprocessor on the source file
53 // to resolve #if, #else, etc.
55 #define PREPROCESSOR_COMMAND "cl"
56 #define PREPROCESSOR_OPTIONS "/nologo /EP /TC /DSTRGATHER"
57 #define PREPROCESS_TEMP_FILE_EXTENSION ".ii"
58 #define PREPROCESS_OUTPUT_FILE_EXTENSION ".iii"
61 // We keep a linked list of these for the source files we process
63 typedef struct _SOURCE_FILE
{
68 INT8 FileName
[MAX_PATH
];
72 struct _SOURCE_FILE
*Previous
;
73 struct _SOURCE_FILE
*Next
;
74 WCHAR ControlCharacter
;
77 #define DEFAULT_CONTROL_CHARACTER UNICODE_SLASH
80 // Here's all our globals. We need a linked list of include paths, a linked
81 // list of source files, a linked list of subdirectories (appended to each
82 // include path when searching), and a couple other fields.
85 SOURCE_FILE SourceFiles
;
86 TEXT_STRING_LIST
*IncludePaths
; // all include paths to search
87 TEXT_STRING_LIST
*LastIncludePath
;
88 TEXT_STRING_LIST
*ScanFileName
;
89 TEXT_STRING_LIST
*LastScanFileName
;
90 TEXT_STRING_LIST
*SkipExt
; // if -skipext .uni
91 TEXT_STRING_LIST
*LastSkipExt
;
92 TEXT_STRING_LIST
*IndirectionFileName
;
93 TEXT_STRING_LIST
*LastIndirectionFileName
;
94 TEXT_STRING_LIST
*DatabaseFileName
;
95 TEXT_STRING_LIST
*LastDatabaseFileName
;
96 TEXT_STRING_LIST
*PreprocessFlags
;
97 TEXT_STRING_LIST
*LastPreprocessFlags
;
98 WCHAR_STRING_LIST
*Language
;
99 WCHAR_STRING_LIST
*LastLanguage
;
100 WCHAR_MATCHING_STRING_LIST
*IndirectionList
; // from indirection file(s)
101 WCHAR_MATCHING_STRING_LIST
*LastIndirectionList
;
102 BOOLEAN Verbose
; // for more detailed output
103 BOOLEAN VerboseDatabaseWrite
; // for more detailed output when writing database
104 BOOLEAN VerboseDatabaseRead
; // for more detailed output when reading database
105 BOOLEAN NewDatabase
; // to start from scratch
106 BOOLEAN IgnoreNotFound
; // when scanning
108 BOOLEAN UnquotedStrings
; // -uqs option
109 BOOLEAN Preprocess
; // -ppflag option
110 INT8 PreprocessFileName
[MAX_PATH
];
111 INT8 OutputDatabaseFileName
[MAX_PATH
];
112 INT8 StringHFileName
[MAX_PATH
];
113 INT8 StringCFileName
[MAX_PATH
]; // output .C filename
114 INT8 DumpUFileName
[MAX_PATH
]; // output unicode dump file name
115 INT8 HiiExportPackFileName
[MAX_PATH
]; // HII export pack file name
116 INT8 BaseName
[MAX_PATH
]; // base filename of the strings file
117 INT8 OutputDependencyFileName
[MAX_PATH
];
118 FILE *OutputDependencyFptr
;
124 IsValidIdentifierChar (
132 SOURCE_FILE
*SourceFile
138 SOURCE_FILE
*SourceFile
,
140 BOOLEAN StopAfterNewline
146 SOURCE_FILE
*SourceFile
152 SOURCE_FILE
*SourceFile
158 SOURCE_FILE
*SourceFile
164 SOURCE_FILE
*SourceFile
169 GetStringIdentifierName (
170 IN SOURCE_FILE
*SourceFile
,
171 IN OUT WCHAR
*StringIdentifierName
,
172 IN UINT32 StringIdentifierNameLen
177 GetLanguageIdentifierName (
178 IN SOURCE_FILE
*SourceFile
,
179 IN OUT WCHAR
*LanguageIdentifierName
,
180 IN UINT32 LanguageIdentifierNameLen
,
186 GetPrintableLanguageName (
187 IN SOURCE_FILE
*SourceFile
192 AddCommandLineLanguage (
199 SOURCE_FILE
*SourceFile
,
206 SOURCE_FILE
*SourceFile
,
207 SOURCE_FILE
*ParentSourceFile
213 SOURCE_FILE
*SourceFile
220 OUT INT8
*FoundFileName
,
221 IN UINT32 FoundFileNameLen
234 SOURCE_FILE
*SourceFile
266 SOURCE_FILE
*SourceFile
271 ProcessTokenInclude (
272 SOURCE_FILE
*SourceFile
278 SOURCE_FILE
*SourceFile
283 ProcessTokenLanguage (
284 SOURCE_FILE
*SourceFile
289 ProcessTokenLangDef (
290 SOURCE_FILE
*SourceFile
295 ProcessTokenSecondaryLangDef (
296 SOURCE_FILE
*SourceFile
302 TEXT_STRING_LIST
*ScanFiles
307 ParseIndirectionFiles (
308 TEXT_STRING_LIST
*Files
320 Call the routine to parse the command-line options, then process the file.
324 Argc - Standard C main() argc and argv.
325 Argv - Standard C main() argc and argv.
336 SetUtilityName (UTILITY_NAME
);
338 // Process the command-line arguments
340 Status
= ProcessArgs (Argc
, Argv
);
341 if (Status
!= STATUS_SUCCESS
) {
345 // Initialize the database manager
347 StringDBConstructor ();
349 // We always try to read in an existing database file. It may not
350 // exist, which is ok usually.
352 if (mGlobals
.NewDatabase
== 0) {
354 // Read all databases specified.
356 for (mGlobals
.LastDatabaseFileName
= mGlobals
.DatabaseFileName
;
357 mGlobals
.LastDatabaseFileName
!= NULL
;
358 mGlobals
.LastDatabaseFileName
= mGlobals
.LastDatabaseFileName
->Next
360 Status
= StringDBReadDatabase (mGlobals
.LastDatabaseFileName
->Str
, TRUE
, mGlobals
.VerboseDatabaseRead
);
361 if (Status
!= STATUS_SUCCESS
) {
367 // Read indirection file(s) if specified
369 if (ParseIndirectionFiles (mGlobals
.IndirectionFileName
) != STATUS_SUCCESS
) {
373 // If scanning source files, do that now
375 if (mGlobals
.Mode
== MODE_SCAN
) {
376 ScanFiles (mGlobals
.ScanFileName
);
377 } else if (mGlobals
.Mode
== MODE_PARSE
) {
379 // Parsing a unicode strings file
381 mGlobals
.SourceFiles
.ControlCharacter
= DEFAULT_CONTROL_CHARACTER
;
382 if (mGlobals
.OutputDependencyFileName
[0] != 0) {
383 if ((mGlobals
.OutputDependencyFptr
= fopen (mGlobals
.OutputDependencyFileName
, "w")) == NULL
) {
384 Error (NULL
, 0, 0, mGlobals
.OutputDependencyFileName
, "failed to open output dependency file");
388 Status
= ProcessIncludeFile (&mGlobals
.SourceFiles
, NULL
);
389 if (mGlobals
.OutputDependencyFptr
!= NULL
) {
390 fclose (mGlobals
.OutputDependencyFptr
);
392 if (Status
!= STATUS_SUCCESS
) {
397 // Create the string defines header file if there have been no errors.
399 ParserSetPosition (NULL
, 0);
400 if ((mGlobals
.StringHFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
401 Status
= StringDBDumpStringDefines (mGlobals
.StringHFileName
, mGlobals
.BaseName
);
402 if (Status
!= EFI_SUCCESS
) {
408 // Dump the strings to a .c file if there have still been no errors.
410 if ((mGlobals
.StringCFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
411 Status
= StringDBDumpCStrings (
413 mGlobals
.StringCFileName
,
416 if (Status
!= EFI_SUCCESS
) {
422 // Dump the database if requested
424 if ((mGlobals
.DumpUFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
425 StringDBDumpDatabase (NULL
, mGlobals
.DumpUFileName
, FALSE
);
428 // Dump the string data as HII binary string pack if requested
430 if ((mGlobals
.HiiExportPackFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
431 StringDBCreateHiiExportPack (mGlobals
.HiiExportPackFileName
, mGlobals
.Language
);
434 // Always update the database if no errors and not in dump mode. If they specified -od
435 // for an output database file name, then use that name. Otherwise use the name of
436 // the first database file specified with -db
438 if ((mGlobals
.Mode
!= MODE_DUMP
) && (GetUtilityStatus () < STATUS_ERROR
)) {
439 if (mGlobals
.OutputDatabaseFileName
[0]) {
440 Status
= StringDBWriteDatabase (mGlobals
.OutputDatabaseFileName
, mGlobals
.VerboseDatabaseWrite
);
442 Status
= StringDBWriteDatabase (mGlobals
.DatabaseFileName
->Str
, mGlobals
.VerboseDatabaseWrite
);
445 if (Status
!= EFI_SUCCESS
) {
455 StringDBDestructor ();
456 return GetUtilityStatus ();
462 SOURCE_FILE
*SourceFile
,
463 SOURCE_FILE
*ParentSourceFile
469 Given a source file, open the file and parse it
473 SourceFile - name of file to parse
474 ParentSourceFile - for error reporting purposes, the file that #included SourceFile.
482 static UINT32 NestDepth
= 0;
483 INT8 FoundFileName
[MAX_PATH
];
486 Status
= STATUS_SUCCESS
;
489 // Print the file being processed. Indent so you can tell the include nesting
492 if (mGlobals
.Verbose
) {
493 fprintf (stdout
, "%*cProcessing file '%s'\n", NestDepth
* 2, ' ', SourceFile
->FileName
);
497 // Make sure we didn't exceed our maximum nesting depth
499 if (NestDepth
> MAX_NEST_DEPTH
) {
500 Error (NULL
, 0, 0, SourceFile
->FileName
, "max nesting depth (%d) exceeded", NestDepth
);
501 Status
= STATUS_ERROR
;
505 // Try to open the file locally, and if that fails try along our include paths.
507 strcpy (FoundFileName
, SourceFile
->FileName
);
508 if ((SourceFile
->Fptr
= fopen (FoundFileName
, "rb")) == NULL
) {
510 // Try to find it among the paths if it has a parent (that is, it is included
513 if (ParentSourceFile
== NULL
) {
514 Error (NULL
, 0, 0, SourceFile
->FileName
, "file not found");
515 Status
= STATUS_ERROR
;
519 SourceFile
->Fptr
= FindFile (SourceFile
->FileName
, FoundFileName
, sizeof (FoundFileName
));
520 if (SourceFile
->Fptr
== NULL
) {
521 Error (ParentSourceFile
->FileName
, ParentSourceFile
->LineNum
, 0, SourceFile
->FileName
, "include file not found");
522 Status
= STATUS_ERROR
;
528 // Output the dependency
530 if (mGlobals
.OutputDependencyFptr
!= NULL
) {
531 fprintf (mGlobals
.OutputDependencyFptr
, "%s : %s\n", mGlobals
.DatabaseFileName
->Str
, FoundFileName
);
533 // Add pseudo target to avoid incremental build failure when the file is deleted
535 fprintf (mGlobals
.OutputDependencyFptr
, "%s : \n", FoundFileName
);
539 // Process the file found
541 ProcessFile (SourceFile
);
546 // Close open files and return status
548 if (SourceFile
->Fptr
!= NULL
) {
549 fclose (SourceFile
->Fptr
);
558 SOURCE_FILE
*SourceFile
562 // Get the file size, and then read the entire thing into memory.
563 // Allocate space for a terminator character.
565 fseek (SourceFile
->Fptr
, 0, SEEK_END
);
566 SourceFile
->FileSize
= ftell (SourceFile
->Fptr
);
567 fseek (SourceFile
->Fptr
, 0, SEEK_SET
);
568 SourceFile
->FileBuffer
= (WCHAR
*) malloc (SourceFile
->FileSize
+ sizeof (WCHAR
));
569 if (SourceFile
->FileBuffer
== NULL
) {
570 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
574 fread ((VOID
*) SourceFile
->FileBuffer
, SourceFile
->FileSize
, 1, SourceFile
->Fptr
);
575 SourceFile
->FileBuffer
[(SourceFile
->FileSize
/ sizeof (WCHAR
))] = UNICODE_NULL
;
577 // Pre-process the file to replace comments with spaces
579 PreprocessFile (SourceFile
);
583 ParseFile (SourceFile
);
584 free (SourceFile
->FileBuffer
);
585 return STATUS_SUCCESS
;
591 SOURCE_FILE
*SourceFile
598 // First character of a unicode file is special. Make sure
600 if (SourceFile
->FileBufferPtr
[0] != UNICODE_FILE_START
) {
601 Error (SourceFile
->FileName
, 1, 0, SourceFile
->FileName
, "file does not appear to be a unicode file");
605 SourceFile
->FileBufferPtr
++;
608 // Print the first line if in verbose mode
610 if (mGlobals
.Verbose
) {
611 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
614 // Since the syntax is relatively straightforward, just switch on the next char
616 while (!EndOfFile (SourceFile
)) {
618 // Check for whitespace
620 if (SourceFile
->FileBufferPtr
[0] == UNICODE_SPACE
) {
621 SourceFile
->FileBufferPtr
++;
622 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_TAB
) {
623 SourceFile
->FileBufferPtr
++;
624 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
625 SourceFile
->FileBufferPtr
++;
626 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
627 SourceFile
->FileBufferPtr
++;
628 SourceFile
->LineNum
++;
629 if (mGlobals
.Verbose
) {
630 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
634 } else if (SourceFile
->FileBufferPtr
[0] == 0) {
635 SourceFile
->FileBufferPtr
++;
636 } else if (InComment
) {
637 SourceFile
->FileBufferPtr
++;
638 } else if ((SourceFile
->FileBufferPtr
[0] == UNICODE_SLASH
) && (SourceFile
->FileBufferPtr
[1] == UNICODE_SLASH
)) {
639 SourceFile
->FileBufferPtr
+= 2;
641 } else if (SourceFile
->SkipToHash
&& (SourceFile
->FileBufferPtr
[0] != SourceFile
->ControlCharacter
)) {
642 SourceFile
->FileBufferPtr
++;
644 SourceFile
->SkipToHash
= FALSE
;
645 if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
646 ((Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"include")) > 0)
648 SourceFile
->FileBufferPtr
+= Len
+ 1;
649 ProcessTokenInclude (SourceFile
);
650 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
651 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"scope")) > 0
653 SourceFile
->FileBufferPtr
+= Len
+ 1;
654 ProcessTokenScope (SourceFile
);
655 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
656 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"language")) > 0
658 SourceFile
->FileBufferPtr
+= Len
+ 1;
659 ProcessTokenLanguage (SourceFile
);
660 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
661 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"langdef")) > 0
663 SourceFile
->FileBufferPtr
+= Len
+ 1;
664 ProcessTokenLangDef (SourceFile
);
665 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
666 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"secondarylang")) > 0
668 SourceFile
->FileBufferPtr
+= Len
+ 1;
669 ProcessTokenSecondaryLangDef (SourceFile
);
670 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
671 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"string")) > 0
673 SourceFile
->FileBufferPtr
+= Len
+ 1;
674 ProcessTokenString (SourceFile
);
675 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
676 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"EFI_BREAKPOINT()")) > 0
678 SourceFile
->FileBufferPtr
+= Len
;
680 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
681 (SourceFile
->FileBufferPtr
[1] == UNICODE_EQUAL_SIGN
)
683 SourceFile
->ControlCharacter
= SourceFile
->FileBufferPtr
[2];
684 SourceFile
->FileBufferPtr
+= 3;
686 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "unrecognized token", "%S", SourceFile
->FileBufferPtr
);
688 // Treat rest of line as a comment.
695 return STATUS_SUCCESS
;
701 SOURCE_FILE
*SourceFile
706 Preprocess a file to replace all carriage returns with NULLs so
707 we can print lines from the file to the screen.
710 SourceFile - structure that we use to keep track of an input file.
719 RewindFile (SourceFile
);
721 while (!EndOfFile (SourceFile
)) {
723 // If a line-feed, then no longer in a comment
725 if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
726 SourceFile
->FileBufferPtr
++;
727 SourceFile
->LineNum
++;
729 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
731 // Replace all carriage returns with a NULL so we can print stuff
733 SourceFile
->FileBufferPtr
[0] = 0;
734 SourceFile
->FileBufferPtr
++;
735 } else if (InComment
) {
736 SourceFile
->FileBufferPtr
[0] = UNICODE_SPACE
;
737 SourceFile
->FileBufferPtr
++;
738 } else if ((SourceFile
->FileBufferPtr
[0] == UNICODE_SLASH
) && (SourceFile
->FileBufferPtr
[1] == UNICODE_SLASH
)) {
739 SourceFile
->FileBufferPtr
+= 2;
742 SourceFile
->FileBufferPtr
++;
746 // Could check for end-of-file and still in a comment, but
747 // should not be necessary. So just restore the file pointers.
749 RewindFile (SourceFile
);
754 GetPrintableLanguageName (
755 IN SOURCE_FILE
*SourceFile
763 SkipWhiteSpace (SourceFile
);
764 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
765 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected quoted printable language name", "%S", SourceFile
->FileBufferPtr
);
766 SourceFile
->SkipToHash
= TRUE
;
771 SourceFile
->FileBufferPtr
++;
772 Start
= Ptr
= SourceFile
->FileBufferPtr
;
773 while (!EndOfFile (SourceFile
)) {
774 if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
775 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "carriage return found in quoted string", "%S", Start
);
777 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) {
781 SourceFile
->FileBufferPtr
++;
785 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
787 SourceFile
->FileName
,
790 "missing closing quote on printable language name string",
795 SourceFile
->FileBufferPtr
++;
798 // Now allocate memory for the string and save it off
800 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
801 if (String
== NULL
) {
802 Error (NULL
, 0, 0, "memory allocation failed", NULL
);
806 // Copy the string from the file buffer to the local copy.
807 // We do no reformatting of it whatsoever at this point.
819 // Now format the string to convert \wide and \narrow controls
821 StringDBFormatString (String
);
828 } LanguageConvertTable
[] = {
829 { L
"eng", L
"en-US" },
830 { L
"fra", L
"fr-FR" },
831 { L
"spa", L
"es-ES" },
846 // The Lang is xx-XX format and return.
848 if (wcschr (Lang
, L
'-') != NULL
) {
849 LangCode
= (WCHAR
*) malloc ((wcslen (Lang
) + 1) * sizeof(WCHAR
));
850 if (LangCode
!= NULL
) {
851 wcscpy (LangCode
, Lang
);
857 // Convert the language accoring to the table.
859 for (Index
= 0; LanguageConvertTable
[Index
].ISO639
!= NULL
; Index
++) {
860 if (wcscmp(LanguageConvertTable
[Index
].ISO639
, Lang
) == 0) {
861 LangCode
= (WCHAR
*) malloc ((wcslen (LanguageConvertTable
[Index
].RFC3066
) + 1) * sizeof (WCHAR
));
862 if (LangCode
!= NULL
) {
863 wcscpy (LangCode
, LanguageConvertTable
[Index
].RFC3066
);
874 IN WCHAR
*SecondaryLangList
877 WCHAR
*CodeBeg
, *CodeEnd
;
879 WCHAR
*LangCodeList
= NULL
;
880 WCHAR
*TempLangCodeList
= NULL
;
882 TempLangCodeList
= (WCHAR
*) malloc ((wcslen(SecondaryLangList
) + 1) * sizeof(WCHAR
));
883 if (TempLangCodeList
== NULL
) {
886 wcscpy (TempLangCodeList
, SecondaryLangList
);
887 CodeBeg
= TempLangCodeList
;
889 while (CodeBeg
!= NULL
) {
890 CodeEnd
= wcschr (CodeBeg
, L
';');
891 if (CodeEnd
!= NULL
) {
896 CodeRet
= GetLangCode (CodeBeg
);
897 if (CodeRet
!= NULL
) {
898 if (LangCodeList
!= NULL
) {
899 LangCodeList
= wstrcatenate (LangCodeList
, L
";");
901 LangCodeList
= wstrcatenate (LangCodeList
, CodeRet
);
908 free (TempLangCodeList
);
915 GetSecondaryLanguageList (
916 IN SOURCE_FILE
*SourceFile
919 WCHAR
*SecondaryLangList
= NULL
;
920 WCHAR SecondaryLang
[MAX_STRING_IDENTIFIER_NAME
+ 1];
926 SkipWhiteSpace (SourceFile
);
928 if (SourceFile
->FileBufferPtr
[0] != UNICODE_OPEN_PAREN
) {
929 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected open bracket", "%S", SourceFile
->FileBufferPtr
);
930 SourceFile
->SkipToHash
= TRUE
;
935 SecondaryLang
[0] = L
'\0';
936 SourceFile
->FileBufferPtr
++;
937 Start
= Ptr
= SourceFile
->FileBufferPtr
;
938 while (!EndOfFile (SourceFile
)) {
939 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_a
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
)) ||
940 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
941 (SourceFile
->FileBufferPtr
[0] == UNICODE_MINUS
)) {
942 if (Index
> MAX_STRING_IDENTIFIER_NAME
) {
943 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "secondary language length is too lang", "%S", SourceFile
->FileBufferPtr
);
946 SecondaryLang
[Index
] = SourceFile
->FileBufferPtr
[0];
948 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_SPACE
) {
949 SecondaryLang
[Index
] = L
'\0';
951 if (SecondaryLang
[0] != L
'\0') {
952 if (SecondaryLangList
!= NULL
) {
953 SecondaryLangList
= wstrcatenate (SecondaryLangList
, L
";");
955 SecondaryLangList
= wstrcatenate (SecondaryLangList
, SecondaryLang
);
957 SecondaryLang
[0] = L
'\0';
958 SourceFile
->FileBufferPtr
++;
961 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CLOSE_PAREN
) {
962 if (SecondaryLangList
!= NULL
) {
963 SecondaryLangList
= wstrcatenate (SecondaryLangList
, L
";");
965 SecondaryLangList
= wstrcatenate (SecondaryLangList
, SecondaryLang
);
968 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "can not recognize the secondary language", "%S", SourceFile
->FileBufferPtr
);
972 SourceFile
->FileBufferPtr
++;
975 if (SourceFile
->FileBufferPtr
[0] != UNICODE_CLOSE_PAREN
) {
976 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "missing closing bracket", "%S", Start
);
978 SourceFile
->FileBufferPtr
++;
981 LangCodeList
= GetLangCodeList (SecondaryLangList
);
982 FREE (SecondaryLangList
);
986 FREE(SecondaryLangList
);
993 SOURCE_FILE
*SourceFile
,
1001 BOOLEAN PreviousBackslash
;
1003 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
1005 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected quoted string", "%S", SourceFile
->FileBufferPtr
);
1012 SourceFile
->FileBufferPtr
++;
1013 Start
= Ptr
= SourceFile
->FileBufferPtr
;
1014 PreviousBackslash
= FALSE
;
1015 while (!EndOfFile (SourceFile
)) {
1016 if ((SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) && (!PreviousBackslash
)) {
1018 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
1019 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "carriage return found in quoted string", "%S", Start
);
1020 PreviousBackslash
= FALSE
;
1021 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_BACKSLASH
) {
1022 PreviousBackslash
= TRUE
;
1024 PreviousBackslash
= FALSE
;
1027 SourceFile
->FileBufferPtr
++;
1031 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
1032 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "missing closing quote on string", "%S", Start
);
1034 SourceFile
->FileBufferPtr
++;
1037 // Now allocate memory for the string and save it off
1039 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
1040 if (String
== NULL
) {
1041 Error (NULL
, 0, 0, "memory allocation failed", NULL
);
1045 // Copy the string from the file buffer to the local copy.
1046 // We do no reformatting of it whatsoever at this point.
1061 // #string STR_ID_NAME
1063 // All we can do is call the string database to add the string identifier. Unfortunately
1064 // he'll have to keep track of the last identifier we added.
1068 ProcessTokenString (
1069 SOURCE_FILE
*SourceFile
1072 WCHAR StringIdentifier
[MAX_STRING_IDENTIFIER_NAME
+ 1];
1075 // Extract the string identifier name and add it to the database.
1077 if (GetStringIdentifierName (SourceFile
, StringIdentifier
, sizeof (StringIdentifier
)) > 0) {
1078 StringId
= STRING_ID_INVALID
;
1079 StringDBAddStringIdentifier (StringIdentifier
, &StringId
, 0);
1082 // Error recovery -- skip to the next #
1084 SourceFile
->SkipToHash
= TRUE
;
1091 SOURCE_FILE
*SourceFile
1095 // The file buffer pointer will typically get updated before the End-of-file flag in the
1096 // source file structure, so check it first.
1098 if (SourceFile
->FileBufferPtr
>= SourceFile
->FileBuffer
+ SourceFile
->FileSize
/ sizeof (WCHAR
)) {
1099 SourceFile
->EndOfFile
= TRUE
;
1103 if (SourceFile
->EndOfFile
) {
1112 GetStringIdentifierName (
1113 IN SOURCE_FILE
*SourceFile
,
1114 IN OUT WCHAR
*StringIdentifierName
,
1115 IN UINT32 StringIdentifierNameLen
1125 SkipWhiteSpace (SourceFile
);
1126 if (SourceFile
->EndOfFile
) {
1127 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "end-of-file encountered", "expected string identifier");
1131 // Verify first character of name is [A-Za-z]
1134 StringIdentifierNameLen
/= 2;
1135 From
= SourceFile
->FileBufferPtr
;
1136 Start
= SourceFile
->FileBufferPtr
;
1137 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
1138 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_z
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
))
1144 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid character in string identifier name", "%S", Start
);
1148 while (!EndOfFile (SourceFile
)) {
1149 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
1150 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_z
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
)) ||
1151 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_0
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_9
)) ||
1152 (SourceFile
->FileBufferPtr
[0] == UNICODE_UNDERSCORE
)
1155 if (Len
>= StringIdentifierNameLen
) {
1156 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "string identifier name too long", "%S", Start
);
1160 *StringIdentifierName
= SourceFile
->FileBufferPtr
[0];
1161 StringIdentifierName
++;
1162 SourceFile
->FileBufferPtr
++;
1163 } else if (SkipWhiteSpace (SourceFile
) == 0) {
1164 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid string identifier name", "%S", Start
);
1171 // Terminate the copy of the string.
1173 *StringIdentifierName
= 0;
1179 GetLanguageIdentifierName (
1180 IN SOURCE_FILE
*SourceFile
,
1181 IN OUT WCHAR
*LanguageIdentifierName
,
1182 IN UINT32 LanguageIdentifierNameLen
,
1189 WCHAR
*LanguageIdentifier
;
1191 LanguageIdentifier
= LanguageIdentifierName
;
1196 SkipWhiteSpace (SourceFile
);
1197 if (SourceFile
->EndOfFile
) {
1199 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "end-of-file encountered", "expected language identifier");
1200 return STATUS_ERROR
;
1203 return STATUS_SUCCESS
;
1206 // This function is called to optionally get a language identifier name in:
1207 // #string STR_ID eng "the string"
1208 // If it's optional, and we find a double-quote, then return now.
1211 if (*SourceFile
->FileBufferPtr
== UNICODE_DOUBLE_QUOTE
) {
1212 return STATUS_SUCCESS
;
1216 LanguageIdentifierNameLen
/= 2;
1218 // Internal error if we weren't given at least 4 WCHAR's to work with.
1220 if (LanguageIdentifierNameLen
< LANGUAGE_IDENTIFIER_NAME_LEN
+ 1) {
1222 SourceFile
->FileName
,
1223 SourceFile
->LineNum
,
1225 "app error -- language identifier name length is invalid",
1231 Start
= SourceFile
->FileBufferPtr
;
1232 while (!EndOfFile (SourceFile
)) {
1233 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_a
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
)) ||
1234 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
1235 (SourceFile
->FileBufferPtr
[0] == UNICODE_MINUS
)) {
1237 if (Len
> LANGUAGE_IDENTIFIER_NAME_LEN
) {
1238 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "language identifier name too long", "%S", Start
);
1239 return STATUS_ERROR
;
1241 *LanguageIdentifierName
= SourceFile
->FileBufferPtr
[0];
1242 SourceFile
->FileBufferPtr
++;
1243 LanguageIdentifierName
++;
1244 } else if (!IsWhiteSpace (SourceFile
)) {
1245 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid language identifier name", "%S", Start
);
1246 return STATUS_ERROR
;
1252 // Terminate the copy of the string.
1254 *LanguageIdentifierName
= 0;
1255 LangCode
= GetLangCode (LanguageIdentifier
);
1256 if (LangCode
!= NULL
) {
1257 wcscpy (LanguageIdentifier
, LangCode
);
1260 return STATUS_SUCCESS
;
1265 ProcessTokenInclude (
1266 SOURCE_FILE
*SourceFile
1269 INT8 IncludeFileName
[MAX_PATH
];
1272 BOOLEAN ReportedError
;
1273 SOURCE_FILE IncludedSourceFile
;
1275 ReportedError
= FALSE
;
1276 if (SkipWhiteSpace (SourceFile
) == 0) {
1277 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected whitespace following #include keyword", NULL
);
1280 // Should be quoted file name
1282 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
1283 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected quoted include file name", NULL
);
1287 SourceFile
->FileBufferPtr
++;
1289 // Copy the filename as ascii to our local string
1291 To
= IncludeFileName
;
1293 while (!EndOfFile (SourceFile
)) {
1294 if ((SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) || (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
)) {
1295 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "end-of-line found in quoted include file name", NULL
);
1299 if (SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) {
1300 SourceFile
->FileBufferPtr
++;
1304 // If too long, then report the error once and process until the closing quote
1307 if (!ReportedError
&& (Len
>= sizeof (IncludeFileName
))) {
1308 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "length of include file name exceeds limit", NULL
);
1309 ReportedError
= TRUE
;
1312 if (!ReportedError
) {
1313 *To
= UNICODE_TO_ASCII (SourceFile
->FileBufferPtr
[0]);
1317 SourceFile
->FileBufferPtr
++;
1320 if (!ReportedError
) {
1322 memset ((char *) &IncludedSourceFile
, 0, sizeof (SOURCE_FILE
));
1323 strcpy (IncludedSourceFile
.FileName
, IncludeFileName
);
1324 IncludedSourceFile
.ControlCharacter
= DEFAULT_CONTROL_CHARACTER
;
1325 ProcessIncludeFile (&IncludedSourceFile
, SourceFile
);
1327 // printf ("including file '%s'\n", IncludeFileName);
1334 // Error recovery -- skip to next #
1336 SourceFile
->SkipToHash
= TRUE
;
1342 SOURCE_FILE
*SourceFile
1345 WCHAR StringIdentifier
[MAX_STRING_IDENTIFIER_NAME
+ 1];
1347 // Extract the scope name
1349 if (GetStringIdentifierName (SourceFile
, StringIdentifier
, sizeof (StringIdentifier
)) > 0) {
1350 StringDBSetScope (StringIdentifier
);
1355 // Parse: #langdef eng "English"
1356 // #langdef chn "\wideChinese"
1360 ProcessTokenLangDef (
1361 SOURCE_FILE
*SourceFile
1365 WCHAR LanguageIdentifier
[MAX_STRING_IDENTIFIER_NAME
+ 1];
1366 WCHAR
*PrintableName
;
1368 Status
= GetLanguageIdentifierName (SourceFile
, LanguageIdentifier
, sizeof (LanguageIdentifier
), FALSE
);
1369 if (Status
!= STATUS_SUCCESS
) {
1374 // Extract the printable name
1376 PrintableName
= GetPrintableLanguageName (SourceFile
);
1377 if (PrintableName
!= NULL
) {
1378 ParserSetPosition (SourceFile
->FileName
, SourceFile
->LineNum
);
1379 StringDBAddLanguage (LanguageIdentifier
, PrintableName
, NULL
);
1380 FREE (PrintableName
);
1384 // Error recovery -- skip to next #
1386 SourceFile
->SkipToHash
= TRUE
;
1391 ProcessTokenSecondaryLangDef (
1392 SOURCE_FILE
*SourceFile
1396 LANGUAGE_LIST
*Lang
;
1397 WCHAR LanguageIdentifier
[MAX_STRING_IDENTIFIER_NAME
+ 1];
1399 WCHAR
*SecondaryLangList
= NULL
;
1401 Status
= GetLanguageIdentifierName (SourceFile
, LanguageIdentifier
, sizeof (LanguageIdentifier
), FALSE
);
1402 if (Status
!= STATUS_SUCCESS
) {
1405 LangCode
= GetLangCode(LanguageIdentifier
);
1406 if (LangCode
== NULL
) {
1410 Lang
= StringDBFindLanguageList (LanguageIdentifier
);
1415 SecondaryLangList
= GetSecondaryLanguageList (SourceFile
);
1416 if (SecondaryLangList
!= NULL
) {
1417 ParserSetPosition (SourceFile
->FileName
, SourceFile
->LineNum
);
1418 Status
= StringDBAddSecondaryLanguage (LangCode
, GetLangCodeList(SecondaryLangList
));
1419 if (Status
!= STATUS_SUCCESS
) {
1420 SourceFile
->SkipToHash
= TRUE
;
1423 FREE (SecondaryLangList
);
1429 SourceFile
->SkipToHash
= TRUE
;
1434 ApparentQuotedString (
1435 SOURCE_FILE
*SourceFile
1440 // See if the first and last nonblank characters on the line are double quotes
1442 for (Ptr
= SourceFile
->FileBufferPtr
; *Ptr
&& (*Ptr
== UNICODE_SPACE
); Ptr
++)
1444 if (*Ptr
!= UNICODE_DOUBLE_QUOTE
) {
1453 for (; *Ptr
&& (*Ptr
== UNICODE_SPACE
); Ptr
--)
1455 if (*Ptr
!= UNICODE_DOUBLE_QUOTE
) {
1463 // #language eng "some string " "more string"
1467 ProcessTokenLanguage (
1468 SOURCE_FILE
*SourceFile
1473 WCHAR
*SecondString
;
1477 WCHAR Language
[LANGUAGE_IDENTIFIER_NAME_LEN
+ 1];
1479 BOOLEAN PreviousNewline
;
1481 // Get the language identifier
1484 Status
= GetLanguageIdentifierName (SourceFile
, Language
, sizeof (Language
), TRUE
);
1485 if (Status
!= STATUS_SUCCESS
) {
1490 // Extract the string value. It's either a quoted string that starts on the current line, or
1491 // an unquoted string that starts on the following line and continues until the next control
1492 // character in column 1.
1493 // Look ahead to find a quote or a newline
1495 if (SkipTo (SourceFile
, UNICODE_DOUBLE_QUOTE
, TRUE
)) {
1496 String
= GetQuotedString (SourceFile
, FALSE
);
1497 if (String
!= NULL
) {
1499 // Set the position in the file of where we are parsing for error
1500 // reporting purposes. Then start looking ahead for additional
1501 // quoted strings, and concatenate them until we get a failure
1502 // back from the string parser.
1504 Len
= wcslen (String
) + 1;
1505 ParserSetPosition (SourceFile
->FileName
, SourceFile
->LineNum
);
1507 SkipWhiteSpace (SourceFile
);
1508 SecondString
= GetQuotedString (SourceFile
, TRUE
);
1509 if (SecondString
!= NULL
) {
1510 Len
+= wcslen (SecondString
);
1511 TempString
= (WCHAR
*) malloc (Len
* sizeof (WCHAR
));
1512 if (TempString
== NULL
) {
1513 Error (NULL
, 0, 0, "application error", "failed to allocate memory");
1517 wcscpy (TempString
, String
);
1518 wcscat (TempString
, SecondString
);
1520 free (SecondString
);
1521 String
= TempString
;
1523 } while (SecondString
!= NULL
);
1524 StringDBAddString (Language
, NULL
, NULL
, String
, TRUE
, 0);
1528 // Error was reported at lower level. Error recovery mode.
1530 SourceFile
->SkipToHash
= TRUE
;
1533 if (!mGlobals
.UnquotedStrings
) {
1535 // They're using unquoted strings. If the next non-blank character is a double quote, and the
1536 // last non-blank character on the line is a double quote, then more than likely they're using
1537 // quotes, so they need to put the quoted string on the end of the previous line
1539 if (ApparentQuotedString (SourceFile
)) {
1541 SourceFile
->FileName
,
1542 SourceFile
->LineNum
,
1544 "unexpected quoted string on line",
1545 "specify -uqs option if necessary"
1550 // Found end-of-line (hopefully). Skip over it and start taking in characters
1551 // until we find a control character at the start of a line.
1554 From
= SourceFile
->FileBufferPtr
;
1555 PreviousNewline
= FALSE
;
1556 while (!EndOfFile (SourceFile
)) {
1557 if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
1558 PreviousNewline
= TRUE
;
1559 SourceFile
->LineNum
++;
1562 if (PreviousNewline
&& (SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
)) {
1566 PreviousNewline
= FALSE
;
1569 SourceFile
->FileBufferPtr
++;
1572 if ((Len
== 0) && EndOfFile (SourceFile
)) {
1573 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "unexpected end of file", NULL
);
1574 SourceFile
->SkipToHash
= TRUE
;
1578 // Now allocate a buffer, copy the characters, and add the string.
1580 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
1581 if (String
== NULL
) {
1582 Error (NULL
, 0, 0, "application error", "failed to allocate memory");
1587 while (From
< SourceFile
->FileBufferPtr
) {
1606 StringDBAddString (Language
, NULL
, NULL
, String
, TRUE
, 0);
1613 SOURCE_FILE
*SourceFile
1616 switch (SourceFile
->FileBufferPtr
[0]) {
1632 SOURCE_FILE
*SourceFile
1638 while (!EndOfFile (SourceFile
)) {
1640 switch (*SourceFile
->FileBufferPtr
) {
1645 SourceFile
->FileBufferPtr
++;
1649 SourceFile
->FileBufferPtr
++;
1650 SourceFile
->LineNum
++;
1651 if (mGlobals
.Verbose
) {
1652 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
1661 // Some tokens require trailing whitespace. If we're at the end of the
1662 // file, then we count that as well.
1664 if ((Count
== 0) && (EndOfFile (SourceFile
))) {
1681 while (*Str
== *Buffer
) {
1711 Len
+= wcslen (Src
);
1712 Dst
= (WCHAR
*) malloc ((Len
+ 1) * 2);
1727 // Given a filename, try to find it along the include paths.
1733 OUT INT8
*FoundFileName
,
1734 IN UINT32 FoundFileNameLen
1738 TEXT_STRING_LIST
*List
;
1741 // Traverse the list of paths and try to find the file
1743 List
= mGlobals
.IncludePaths
;
1744 while (List
!= NULL
) {
1746 // Put the path and filename together
1748 if (strlen (List
->Str
) + strlen (FileName
) + 1 > FoundFileNameLen
) {
1749 Error (UTILITY_NAME
, 0, 0, NULL
, "internal error - cannot concatenate path+filename");
1753 // Append the filename to this include path and try to open the file.
1755 strcpy (FoundFileName
, List
->Str
);
1756 strcat (FoundFileName
, FileName
);
1757 if ((Fptr
= fopen (FoundFileName
, "rb")) != NULL
) {
1759 // Return the file pointer
1769 FoundFileName
[0] = 0;
1773 // Process the command-line arguments
1782 TEXT_STRING_LIST
*NewList
;
1787 // Clear our globals
1789 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
1790 strcpy (mGlobals
.BaseName
, DEFAULT_BASE_NAME
);
1792 // Skip program name
1799 return STATUS_ERROR
;
1802 mGlobals
.Mode
= MODE_UNKNOWN
;
1804 // Process until no more -args.
1806 while ((Argc
> 0) && (Argv
[0][0] == '-')) {
1810 if (_stricmp (Argv
[0], "-parse") == 0) {
1811 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1812 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1813 return STATUS_ERROR
;
1816 mGlobals
.Mode
= MODE_PARSE
;
1820 } else if (_stricmp (Argv
[0], "-scan") == 0) {
1821 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1822 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1823 return STATUS_ERROR
;
1826 mGlobals
.Mode
= MODE_SCAN
;
1828 // -vscan verbose scanning option
1830 } else if (_stricmp (Argv
[0], "-vscan") == 0) {
1831 mGlobals
.VerboseScan
= TRUE
;
1835 } else if (_stricmp (Argv
[0], "-dump") == 0) {
1836 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1837 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1838 return STATUS_ERROR
;
1841 mGlobals
.Mode
= MODE_DUMP
;
1842 } else if (_stricmp (Argv
[0], "-uqs") == 0) {
1843 mGlobals
.UnquotedStrings
= TRUE
;
1845 // -i path add include search path when parsing
1847 } else if (_stricmp (Argv
[0], "-i") == 0) {
1849 // check for one more arg
1851 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1852 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing include path");
1853 return STATUS_ERROR
;
1856 // Allocate memory for a new list element, fill it in, and
1857 // add it to our list of include paths. Always make sure it
1858 // has a "\" on the end of it.
1860 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1861 if (NewList
== NULL
) {
1862 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1863 return STATUS_ERROR
;
1866 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1867 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1868 if (NewList
->Str
== NULL
) {
1870 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1871 return STATUS_ERROR
;
1874 strcpy (NewList
->Str
, Argv
[1]);
1875 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1876 strcat (NewList
->Str
, "\\");
1879 // Add it to our linked list
1881 if (mGlobals
.IncludePaths
== NULL
) {
1882 mGlobals
.IncludePaths
= NewList
;
1884 mGlobals
.LastIncludePath
->Next
= NewList
;
1887 mGlobals
.LastIncludePath
= NewList
;
1890 } else if (_stricmp (Argv
[0], "-if") == 0) {
1892 // Indirection file -- check for one more arg
1894 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1895 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing indirection file name");
1896 return STATUS_ERROR
;
1899 // Allocate memory for a new list element, fill it in, and
1900 // add it to our list of include paths. Always make sure it
1901 // has a "\" on the end of it.
1903 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1904 if (NewList
== NULL
) {
1905 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1906 return STATUS_ERROR
;
1909 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1910 NewList
->Str
= malloc (strlen (Argv
[1]) + 1);
1911 if (NewList
->Str
== NULL
) {
1913 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1914 return STATUS_ERROR
;
1917 strcpy (NewList
->Str
, Argv
[1]);
1919 // Add it to our linked list
1921 if (mGlobals
.IndirectionFileName
== NULL
) {
1922 mGlobals
.IndirectionFileName
= NewList
;
1924 mGlobals
.LastIndirectionFileName
->Next
= NewList
;
1927 mGlobals
.LastIndirectionFileName
= NewList
;
1930 } else if (_stricmp (Argv
[0], "-db") == 0) {
1932 // -db option to specify a database file.
1933 // Check for one more arg (the database file name)
1935 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1936 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing database file name");
1937 return STATUS_ERROR
;
1940 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1941 if (NewList
== NULL
) {
1942 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1943 return STATUS_ERROR
;
1946 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1947 NewList
->Str
= malloc (strlen (Argv
[1]) + 1);
1948 if (NewList
->Str
== NULL
) {
1950 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1951 return STATUS_ERROR
;
1954 strcpy (NewList
->Str
, Argv
[1]);
1956 // Add it to our linked list
1958 if (mGlobals
.DatabaseFileName
== NULL
) {
1959 mGlobals
.DatabaseFileName
= NewList
;
1961 mGlobals
.LastDatabaseFileName
->Next
= NewList
;
1964 mGlobals
.LastDatabaseFileName
= NewList
;
1967 } else if (_stricmp (Argv
[0], "-ou") == 0) {
1969 // -ou option to specify an output unicode file to
1970 // which we can dump our database.
1972 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1973 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing database dump output file name");
1974 return STATUS_ERROR
;
1977 if (mGlobals
.DumpUFileName
[0] == 0) {
1978 strcpy (mGlobals
.DumpUFileName
, Argv
[1]);
1980 Error (UTILITY_NAME
, 0, 0, Argv
[1], "-ou option already specified with '%s'", mGlobals
.DumpUFileName
);
1981 return STATUS_ERROR
;
1986 } else if (_stricmp (Argv
[0], "-hpk") == 0) {
1988 // -hpk option to create an HII export pack of the input database file
1990 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1991 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing raw string data dump output file name");
1992 return STATUS_ERROR
;
1995 if (mGlobals
.HiiExportPackFileName
[0] == 0) {
1996 strcpy (mGlobals
.HiiExportPackFileName
, Argv
[1]);
1998 Error (UTILITY_NAME
, 0, 0, Argv
[1], "-or option already specified with '%s'", mGlobals
.HiiExportPackFileName
);
1999 return STATUS_ERROR
;
2004 } else if ((_stricmp (Argv
[0], "-?") == 0) || (_stricmp (Argv
[0], "-h") == 0)) {
2006 return STATUS_ERROR
;
2007 } else if (_stricmp (Argv
[0], "-v") == 0) {
2008 mGlobals
.Verbose
= 1;
2009 } else if (_stricmp (Argv
[0], "-vdbw") == 0) {
2010 mGlobals
.VerboseDatabaseWrite
= 1;
2011 } else if (_stricmp (Argv
[0], "-vdbr") == 0) {
2012 mGlobals
.VerboseDatabaseRead
= 1;
2013 } else if (_stricmp (Argv
[0], "-newdb") == 0) {
2014 mGlobals
.NewDatabase
= 1;
2015 } else if (_stricmp (Argv
[0], "-ignorenotfound") == 0) {
2016 mGlobals
.IgnoreNotFound
= 1;
2017 } else if (_stricmp (Argv
[0], "-oc") == 0) {
2019 // check for one more arg
2021 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2022 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing output C filename");
2023 return STATUS_ERROR
;
2026 strcpy (mGlobals
.StringCFileName
, Argv
[1]);
2029 } else if (_stricmp (Argv
[0], "-bn") == 0) {
2031 // check for one more arg
2033 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2034 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing base name");
2036 return STATUS_ERROR
;
2039 strcpy (mGlobals
.BaseName
, Argv
[1]);
2042 } else if (_stricmp (Argv
[0], "-oh") == 0) {
2044 // -oh to specify output .h defines file name
2046 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2047 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing output .h filename");
2048 return STATUS_ERROR
;
2051 strcpy (mGlobals
.StringHFileName
, Argv
[1]);
2054 } else if (_stricmp (Argv
[0], "-dep") == 0) {
2056 // -dep to specify output dependency file name
2058 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2059 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing output dependency filename");
2060 return STATUS_ERROR
;
2063 strcpy (mGlobals
.OutputDependencyFileName
, Argv
[1]);
2066 } else if (_stricmp (Argv
[0], "-skipext") == 0) {
2068 // -skipext to skip scanning of files with certain filename extensions
2070 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2071 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing filename extension");
2072 return STATUS_ERROR
;
2075 // Allocate memory for a new list element, fill it in, and
2076 // add it to our list of excluded extensions. Always make sure it
2077 // has a "." as the first character.
2079 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
2080 if (NewList
== NULL
) {
2081 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
2082 return STATUS_ERROR
;
2085 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
2086 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
2087 if (NewList
->Str
== NULL
) {
2089 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
2090 return STATUS_ERROR
;
2093 if (Argv
[1][0] == '.') {
2094 strcpy (NewList
->Str
, Argv
[1]);
2096 NewList
->Str
[0] = '.';
2097 strcpy (NewList
->Str
+ 1, Argv
[1]);
2100 // Add it to our linked list
2102 if (mGlobals
.SkipExt
== NULL
) {
2103 mGlobals
.SkipExt
= NewList
;
2105 mGlobals
.LastSkipExt
->Next
= NewList
;
2108 mGlobals
.LastSkipExt
= NewList
;
2111 } else if (_stricmp (Argv
[0], "-lang") == 0) {
2113 // "-lang zh-Hans" or "-lang en-US" to only output certain languages
2115 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2116 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing language name");
2118 return STATUS_ERROR
;
2121 if (AddCommandLineLanguage (Argv
[1]) != STATUS_SUCCESS
) {
2122 return STATUS_ERROR
;
2127 } else if (_stricmp (Argv
[0], "-od") == 0) {
2129 // Output database file name -- check for another arg
2131 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2132 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing output database file name");
2133 return STATUS_ERROR
;
2136 strcpy (mGlobals
.OutputDatabaseFileName
, Argv
[1]);
2139 } else if (_stricmp (Argv
[0], "-ppflag") == 0) {
2141 // -ppflag "Preprocess flags" -- check for another arg
2143 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2144 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing preprocess flags");
2146 return STATUS_ERROR
;
2150 // Allocate memory for a new list element, fill it in, and
2151 // add it to our list of preprocess flag.
2153 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
2154 if (NewList
== NULL
) {
2155 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
2156 return STATUS_ERROR
;
2159 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
2160 NewList
->Str
= malloc (strlen (Argv
[1]) * 2 + 1);
2161 if (NewList
->Str
== NULL
) {
2163 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
2164 return STATUS_ERROR
;
2168 // Convert '"' to '\"' in preprocess flag
2171 Cptr2
= NewList
->Str
;
2177 while (*Cptr
!= '\0') {
2178 if ((*Cptr
== '"') && (*(Cptr
- 1) != '\\')) {
2186 // Add it to our linked list
2188 if (mGlobals
.PreprocessFlags
== NULL
) {
2189 mGlobals
.PreprocessFlags
= NewList
;
2191 mGlobals
.LastPreprocessFlags
->Next
= NewList
;
2193 mGlobals
.LastPreprocessFlags
= NewList
;
2195 mGlobals
.Preprocess
= TRUE
;
2203 Error (UTILITY_NAME
, 0, 0, Argv
[0], "unrecognized option");
2205 return STATUS_ERROR
;
2212 // Make sure they specified the mode parse/scan/dump
2214 if (mGlobals
.Mode
== MODE_UNKNOWN
) {
2215 Error (NULL
, 0, 0, "must specify one of -parse/-scan/-dump", NULL
);
2216 return STATUS_ERROR
;
2219 // All modes require a database filename
2221 if (mGlobals
.DatabaseFileName
== 0) {
2222 Error (NULL
, 0, 0, "must specify a database filename using -db DbFileName", NULL
);
2224 return STATUS_ERROR
;
2227 // If dumping the database file, then return immediately if all
2228 // parameters check out.
2230 if (mGlobals
.Mode
== MODE_DUMP
) {
2232 // Not much use if they didn't specify -oh or -oc or -ou or -hpk
2234 if ((mGlobals
.DumpUFileName
[0] == 0) &&
2235 (mGlobals
.StringHFileName
[0] == 0) &&
2236 (mGlobals
.StringCFileName
[0] == 0) &&
2237 (mGlobals
.HiiExportPackFileName
[0] == 0)
2239 Error (NULL
, 0, 0, "-dump without -oc/-oh/-ou/-hpk is a NOP", NULL
);
2240 return STATUS_ERROR
;
2243 return STATUS_SUCCESS
;
2246 // Had to specify source string file and output string defines header filename.
2248 if (mGlobals
.Mode
== MODE_SCAN
) {
2250 Error (UTILITY_NAME
, 0, 0, NULL
, "must specify at least one source file to scan with -scan");
2252 return STATUS_ERROR
;
2255 // If -ppflag is specified, -oh should also be specified for preprocess
2257 if (mGlobals
.Preprocess
&& (mGlobals
.StringHFileName
[0] == 0)) {
2258 Error (UTILITY_NAME
, 0, 0, NULL
, "must specify string defines file name to preprocess before scan");
2260 return STATUS_ERROR
;
2263 // Get the list of filenames
2266 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
2267 if (NewList
== NULL
) {
2268 Error (UTILITY_NAME
, 0, 0, "memory allocation failure", NULL
);
2269 return STATUS_ERROR
;
2272 memset (NewList
, 0, sizeof (TEXT_STRING_LIST
));
2273 NewList
->Str
= (UINT8
*) malloc (strlen (Argv
[0]) + 1);
2274 if (NewList
->Str
== NULL
) {
2275 Error (UTILITY_NAME
, 0, 0, "memory allocation failure", NULL
);
2276 return STATUS_ERROR
;
2279 strcpy (NewList
->Str
, Argv
[0]);
2280 if (mGlobals
.ScanFileName
== NULL
) {
2281 mGlobals
.ScanFileName
= NewList
;
2283 mGlobals
.LastScanFileName
->Next
= NewList
;
2286 mGlobals
.LastScanFileName
= NewList
;
2292 // Parse mode -- must specify an input unicode file name
2295 Error (UTILITY_NAME
, 0, 0, NULL
, "must specify input unicode string file name with -parse");
2297 return STATUS_ERROR
;
2300 strcpy (mGlobals
.SourceFiles
.FileName
, Argv
[0]);
2303 return STATUS_SUCCESS
;
2306 // Found "-lang zh-Hans;en-US" on the command line. Parse the
2307 // language list and save the setting for later processing.
2311 AddCommandLineLanguage (
2315 char Separator
[] = ";";
2317 WCHAR_STRING_LIST
*WNewList
;
2320 // Keep processing the input string until we find the end.
2322 Token
= strtok (Language
, Separator
);
2323 while (Token
!= NULL
) {
2324 WNewList
= MALLOC (sizeof (WCHAR_STRING_LIST
));
2325 if (WNewList
== NULL
) {
2326 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
2327 return STATUS_ERROR
;
2329 WNewList
->Next
= NULL
;
2330 WNewList
->Str
= MALLOC ((strlen (Token
) + 1) * sizeof (WCHAR
));
2331 if (WNewList
->Str
== NULL
) {
2333 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
2334 return STATUS_ERROR
;
2337 swprintf (WNewList
->Str
, (strlen (Token
) + 1) * sizeof (WCHAR
), L
"%S", Token
);
2339 swprintf (WNewList
->Str
, L
"%S", Token
);
2343 // Add it to our linked list
2345 if (mGlobals
.Language
== NULL
) {
2346 mGlobals
.Language
= WNewList
;
2348 mGlobals
.LastLanguage
->Next
= WNewList
;
2351 mGlobals
.LastLanguage
= WNewList
;
2352 Token
= strtok (NULL
, Separator
);
2355 return STATUS_SUCCESS
;
2358 // The contents of the text file are expected to be (one per line)
2359 // STRING_IDENTIFIER_NAME ScopeName
2361 // STR_ID_MY_FAVORITE_STRING IBM
2365 ParseIndirectionFiles (
2366 TEXT_STRING_LIST
*Files
2375 WCHAR_MATCHING_STRING_LIST
*NewList
;
2377 Line
[sizeof (Line
) - 1] = 0;
2379 while (Files
!= NULL
) {
2380 Fptr
= fopen (Files
->Str
, "r");
2383 Error (NULL
, 0, 0, Files
->Str
, "failed to open input indirection file for reading");
2384 return STATUS_ERROR
;
2387 while (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
2389 // remove terminating newline for error printing purposes.
2391 if (Line
[strlen (Line
) - 1] == '\n') {
2392 Line
[strlen (Line
) - 1] = 0;
2396 if (Line
[sizeof (Line
) - 1] != 0) {
2397 Error (Files
->Str
, LineCount
, 0, "line length exceeds maximum supported", NULL
);
2402 while (*StringName
&& (isspace (*StringName
))) {
2407 if ((*StringName
== '_') || isalpha (*StringName
)) {
2409 while ((*End
) && (*End
== '_') || (isalnum (*End
))) {
2413 if (isspace (*End
)) {
2416 while (isspace (*End
)) {
2422 while (*End
&& !isspace (*End
)) {
2428 // Add the string name/scope pair
2430 NewList
= malloc (sizeof (WCHAR_MATCHING_STRING_LIST
));
2431 if (NewList
== NULL
) {
2432 Error (NULL
, 0, 0, "memory allocation error", NULL
);
2436 memset (NewList
, 0, sizeof (WCHAR_MATCHING_STRING_LIST
));
2437 NewList
->Str1
= (WCHAR
*) malloc ((strlen (StringName
) + 1) * sizeof (WCHAR
));
2438 NewList
->Str2
= (WCHAR
*) malloc ((strlen (ScopeName
) + 1) * sizeof (WCHAR
));
2439 if ((NewList
->Str1
== NULL
) || (NewList
->Str2
== NULL
)) {
2440 Error (NULL
, 0, 0, "memory allocation error", NULL
);
2445 swprintf (NewList
->Str1
, (strlen (StringName
) + 1) * sizeof (WCHAR
), L
"%S", StringName
);
2446 swprintf (NewList
->Str2
, (strlen (ScopeName
) + 1) * sizeof (WCHAR
), L
"%S", ScopeName
);
2448 swprintf (NewList
->Str1
, L
"%S", StringName
);
2449 swprintf (NewList
->Str2
, L
"%S", ScopeName
);
2451 if (mGlobals
.IndirectionList
== NULL
) {
2452 mGlobals
.IndirectionList
= NewList
;
2454 mGlobals
.LastIndirectionList
->Next
= NewList
;
2457 mGlobals
.LastIndirectionList
= NewList
;
2459 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid line : expected 'StringIdentifier Scope'");
2463 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid line : expected 'StringIdentifier Scope'");
2467 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid string identifier");
2475 Files
= Files
->Next
;
2481 return STATUS_ERROR
;
2484 return STATUS_SUCCESS
;
2489 PreprocessSourceFile (
2490 UINT8
*SourceFileName
2497 char *PreProcessCmd
;
2498 char BaseName
[MAX_PATH
];
2499 char TempFileName
[MAX_PATH
];
2500 char SourceFileDir
[MAX_PATH
];
2501 char Line
[MAX_LINE_LEN
];
2502 TEXT_STRING_LIST
*List
;
2503 char InsertLine
[] = "#undef STRING_TOKEN\n";
2507 // Check whehter source file exist
2509 InFptr
= fopen (SourceFileName
, "r");
2510 if (InFptr
== NULL
) {
2511 Error (NULL
, 0, 0, SourceFileName
, "failed to open input file for scanning");
2512 return STATUS_ERROR
;
2516 // Get source file directory
2518 strcpy (SourceFileDir
, SourceFileName
);
2519 Cptr
= strrchr (SourceFileDir
, '\\');
2525 // Generate preprocess output file name
2527 strcpy (BaseName
, mGlobals
.OutputDatabaseFileName
);
2528 Cptr
= strrchr (BaseName
, '\\');
2533 Cptr
= strrchr (SourceFileName
, '\\');
2537 strcat (BaseName
, Cptr
);
2539 Cptr
= strrchr (BaseName
, '.');
2544 strcpy (mGlobals
.PreprocessFileName
, BaseName
);
2545 strcat (mGlobals
.PreprocessFileName
, PREPROCESS_OUTPUT_FILE_EXTENSION
);
2547 strcpy (TempFileName
, BaseName
);
2548 strcat (TempFileName
, PREPROCESS_TEMP_FILE_EXTENSION
);
2551 // Insert "#undef STRING_TOKEN" after each line of "#include ...", so as to
2552 // preserve the STRING_TOKEN() for scanning after preprocess
2554 OutFptr
= fopen (TempFileName
, "w");
2555 if (OutFptr
== NULL
) {
2556 Error (NULL
, 0, 0, TempFileName
, "failed to open file for write");
2558 return STATUS_ERROR
;
2560 while (fgets (Line
, MAX_LINE_LEN
, InFptr
) != NULL
) {
2561 fputs (Line
, OutFptr
);
2565 // Skip leading blank space
2567 while (*Cptr
== ' ' || *Cptr
== '\t') {
2571 if (*Cptr
== '#' && strncmp (Cptr
+ 1, "include", 7) == 0){
2572 fputs (InsertLine
, OutFptr
);
2579 // Prepare preprocess command
2582 CmdLen
+= strlen (PREPROCESSOR_COMMAND
);
2584 CmdLen
+= strlen (PREPROCESSOR_OPTIONS
);
2588 // "-I SourceFileDir "
2590 CmdLen
+= strlen (SourceFileDir
);
2593 List
= mGlobals
.PreprocessFlags
;
2594 while (List
!= NULL
) {
2595 CmdLen
+= strlen (List
->Str
);
2601 CmdLen
+= strlen (TempFileName
);
2603 CmdLen
+= strlen (mGlobals
.PreprocessFileName
);
2605 PreProcessCmd
= malloc (CmdLen
);
2606 if (PreProcessCmd
== NULL
) {
2607 Error (NULL
, 0, 0, UTILITY_NAME
, "memory allocation fail (%d bytes)\n", CmdLen
);
2608 return STATUS_ERROR
;
2611 strcpy (PreProcessCmd
, PREPROCESSOR_COMMAND
);
2612 strcat (PreProcessCmd
, " ");
2613 strcat (PreProcessCmd
, PREPROCESSOR_OPTIONS
);
2614 strcat (PreProcessCmd
, " ");
2617 strcat (PreProcessCmd
, "-I ");
2618 strcat (PreProcessCmd
, SourceFileDir
);
2619 strcat (PreProcessCmd
, " ");
2621 List
= mGlobals
.PreprocessFlags
;
2622 while (List
!= NULL
) {
2623 strcat (PreProcessCmd
, List
->Str
);
2624 strcat (PreProcessCmd
, " ");
2629 strcat (PreProcessCmd
, TempFileName
);
2630 strcat (PreProcessCmd
, " > ");
2631 strcat (PreProcessCmd
, mGlobals
.PreprocessFileName
);
2634 // Preprocess the source file
2636 Status
= system (PreProcessCmd
);
2638 Error (NULL
, 0, 0, PreProcessCmd
, "failed to spawn C preprocessor on source file\n");
2639 free (PreProcessCmd
);
2640 return STATUS_ERROR
;
2643 free (PreProcessCmd
);
2644 return STATUS_SUCCESS
;
2650 TEXT_STRING_LIST
*ScanFiles
2653 char Line
[MAX_LINE_LEN
];
2660 char *StringTokenPos
;
2661 TEXT_STRING_LIST
*SList
;
2666 // Put a null-terminator at the end of the line. If we read in
2667 // a line longer than we support, then we can catch it.
2669 Line
[MAX_LINE_LEN
- 1] = 0;
2671 // Process each file. If they gave us a skip extension list, then
2672 // skip it if the extension matches.
2675 while (ScanFiles
!= NULL
) {
2677 for (SList
= mGlobals
.SkipExt
; SList
!= NULL
; SList
= SList
->Next
) {
2678 if ((strlen (ScanFiles
->Str
) > strlen (SList
->Str
)) &&
2679 (strcmp (ScanFiles
->Str
+ strlen (ScanFiles
->Str
) - strlen (SList
->Str
), SList
->Str
) == 0)
2683 // printf ("Match: %s : %s\n", ScanFiles->Str, SList->Str);
2690 if (mGlobals
.VerboseScan
) {
2691 printf ("Scanning %s\n", ScanFiles
->Str
);
2694 if (mGlobals
.Preprocess
) {
2696 // Create an empty string defines file for preprocessor
2699 Fptr
= fopen (mGlobals
.StringHFileName
, "w");
2701 Error (NULL
, 0, 0, mGlobals
.StringHFileName
, "failed to open file for write");
2702 return STATUS_ERROR
;
2710 // Preprocess using C preprocessor
2712 if (PreprocessSourceFile (ScanFiles
->Str
) != STATUS_SUCCESS
) {
2713 return STATUS_ERROR
;
2716 FileName
= mGlobals
.PreprocessFileName
;
2718 FileName
= ScanFiles
->Str
;
2721 Fptr
= fopen (FileName
, "r");
2723 Error (NULL
, 0, 0, FileName
, "failed to open input file for scanning");
2724 return STATUS_ERROR
;
2728 while (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
2730 if (Line
[MAX_LINE_LEN
- 1] != 0) {
2731 Error (ScanFiles
->Str
, LineNum
, 0, "line length exceeds maximum supported by tool", NULL
);
2733 return STATUS_ERROR
;
2736 // Remove the newline from the input line so we can print a warning message
2738 if (Line
[strlen (Line
) - 1] == '\n') {
2739 Line
[strlen (Line
) - 1] = 0;
2742 // Terminate the line at // comments
2744 Cptr
= strstr (Line
, "//");
2750 while ((Cptr
= strstr (Cptr
, STRING_TOKEN
)) != NULL
) {
2752 // Found "STRING_TOKEN". Make sure we don't have NUM_STRING_TOKENS or
2753 // something like that. Then make sure it's followed by
2754 // an open parenthesis, a string identifier, and then a closing
2757 if (mGlobals
.VerboseScan
) {
2758 printf (" %d: %s", LineNum
, Cptr
);
2761 if (((Cptr
== Line
) || (!IsValidIdentifierChar (*(Cptr
- 1), FALSE
))) &&
2762 (!IsValidIdentifierChar (*(Cptr
+ sizeof (STRING_TOKEN
) - 1), FALSE
))
2764 StringTokenPos
= Cptr
;
2766 Cptr
+= strlen (STRING_TOKEN
);
2767 while (*Cptr
&& isspace (*Cptr
) && (*Cptr
!= '(')) {
2772 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected "STRING_TOKEN
"(identifier)");
2775 // Skip over the open-parenthesis and find the next non-blank character
2778 while (isspace (*Cptr
)) {
2783 if ((*Cptr
== '_') || isalpha (*Cptr
)) {
2784 while ((*Cptr
== '_') || (isalnum (*Cptr
))) {
2789 while (*Cptr
&& isspace (*Cptr
)) {
2794 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected "STRING_TOKEN
"(identifier)");
2804 // Add the string identifier to the list of used strings
2806 ParserSetPosition (ScanFiles
->Str
, LineNum
);
2807 StringDBSetStringReferenced (SavePtr
, mGlobals
.IgnoreNotFound
);
2808 if (mGlobals
.VerboseScan
) {
2809 printf ("...referenced %s", SavePtr
);
2812 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected valid string identifier name");
2817 // Found it, but it's a substring of something else. Advance our pointer.
2822 if (mGlobals
.VerboseScan
) {
2831 // Skipping this file type
2833 if (mGlobals
.VerboseScan
) {
2834 printf ("Skip scanning of %s\n", ScanFiles
->Str
);
2838 ScanFiles
= ScanFiles
->Next
;
2842 // Remove the empty string defines file
2845 remove (mGlobals
.StringHFileName
);
2848 return STATUS_SUCCESS
;
2851 // Free the global string lists we allocated memory for
2859 TEXT_STRING_LIST
*Temp
;
2860 WCHAR_STRING_LIST
*WTemp
;
2863 // Traverse the include paths, freeing each
2865 while (mGlobals
.IncludePaths
!= NULL
) {
2866 Temp
= mGlobals
.IncludePaths
->Next
;
2867 free (mGlobals
.IncludePaths
->Str
);
2868 free (mGlobals
.IncludePaths
);
2869 mGlobals
.IncludePaths
= Temp
;
2872 // If we did a scan, then free up our
2873 // list of files to scan.
2875 while (mGlobals
.ScanFileName
!= NULL
) {
2876 Temp
= mGlobals
.ScanFileName
->Next
;
2877 free (mGlobals
.ScanFileName
->Str
);
2878 free (mGlobals
.ScanFileName
);
2879 mGlobals
.ScanFileName
= Temp
;
2882 // Free up preprocess flags list
2884 while (mGlobals
.PreprocessFlags
!= NULL
) {
2885 Temp
= mGlobals
.PreprocessFlags
->Next
;
2886 free (mGlobals
.PreprocessFlags
->Str
);
2887 free (mGlobals
.PreprocessFlags
);
2888 mGlobals
.PreprocessFlags
= Temp
;
2891 // If they gave us a list of filename extensions to
2892 // skip on scan, then free them up.
2894 while (mGlobals
.SkipExt
!= NULL
) {
2895 Temp
= mGlobals
.SkipExt
->Next
;
2896 free (mGlobals
.SkipExt
->Str
);
2897 free (mGlobals
.SkipExt
);
2898 mGlobals
.SkipExt
= Temp
;
2901 // Free up any languages specified
2903 while (mGlobals
.Language
!= NULL
) {
2904 WTemp
= mGlobals
.Language
->Next
;
2905 free (mGlobals
.Language
->Str
);
2906 free (mGlobals
.Language
);
2907 mGlobals
.Language
= WTemp
;
2910 // Free up our indirection list
2912 while (mGlobals
.IndirectionList
!= NULL
) {
2913 mGlobals
.LastIndirectionList
= mGlobals
.IndirectionList
->Next
;
2914 free (mGlobals
.IndirectionList
->Str1
);