3 Copyright (c) 2004 - 2007, 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 TOOL_VERSION "0.31"
37 #define MAX_NEST_DEPTH 20 // just in case we get in an endless loop.
38 #define MAX_STRING_IDENTIFIER_NAME 128 // number of wchars
39 #define MAX_LINE_LEN 400
40 #define STRING_TOKEN "STRING_TOKEN"
41 #define DEFAULT_BASE_NAME "BaseName"
43 // Operational modes for this utility
45 #define MODE_UNKNOWN 0
51 // We keep a linked list of these for the source files we process
53 typedef struct _SOURCE_FILE
{
58 INT8 FileName
[MAX_PATH
];
62 struct _SOURCE_FILE
*Previous
;
63 struct _SOURCE_FILE
*Next
;
64 WCHAR ControlCharacter
;
67 #define DEFAULT_CONTROL_CHARACTER UNICODE_SLASH
70 // Here's all our globals. We need a linked list of include paths, a linked
71 // list of source files, a linked list of subdirectories (appended to each
72 // include path when searching), and a couple other fields.
75 SOURCE_FILE SourceFiles
;
76 TEXT_STRING_LIST
*IncludePaths
; // all include paths to search
77 TEXT_STRING_LIST
*LastIncludePath
;
78 TEXT_STRING_LIST
*ScanFileName
;
79 TEXT_STRING_LIST
*LastScanFileName
;
80 TEXT_STRING_LIST
*SkipExt
; // if -skipext .uni
81 TEXT_STRING_LIST
*LastSkipExt
;
82 TEXT_STRING_LIST
*IndirectionFileName
;
83 TEXT_STRING_LIST
*LastIndirectionFileName
;
84 TEXT_STRING_LIST
*DatabaseFileName
;
85 TEXT_STRING_LIST
*LastDatabaseFileName
;
86 WCHAR_STRING_LIST
*Language
;
87 WCHAR_STRING_LIST
*LastLanguage
;
88 WCHAR_MATCHING_STRING_LIST
*IndirectionList
; // from indirection file(s)
89 WCHAR_MATCHING_STRING_LIST
*LastIndirectionList
;
90 BOOLEAN Verbose
; // for more detailed output
91 BOOLEAN VerboseDatabaseWrite
; // for more detailed output when writing database
92 BOOLEAN VerboseDatabaseRead
; // for more detailed output when reading database
93 BOOLEAN NewDatabase
; // to start from scratch
94 BOOLEAN IgnoreNotFound
; // when scanning
96 BOOLEAN UnquotedStrings
; // -uqs option
97 INT8 OutputDatabaseFileName
[MAX_PATH
];
98 INT8 StringHFileName
[MAX_PATH
];
99 INT8 StringCFileName
[MAX_PATH
]; // output .C filename
100 INT8 DumpUFileName
[MAX_PATH
]; // output unicode dump file name
101 INT8 HiiExportPackFileName
[MAX_PATH
]; // HII export pack file name
102 INT8 BaseName
[MAX_PATH
]; // base filename of the strings file
103 INT8 OutputDependencyFileName
[MAX_PATH
];
104 FILE *OutputDependencyFptr
;
110 IsValidIdentifierChar (
118 SOURCE_FILE
*SourceFile
124 SOURCE_FILE
*SourceFile
,
126 BOOLEAN StopAfterNewline
132 SOURCE_FILE
*SourceFile
138 SOURCE_FILE
*SourceFile
144 SOURCE_FILE
*SourceFile
150 SOURCE_FILE
*SourceFile
155 GetStringIdentifierName (
156 IN SOURCE_FILE
*SourceFile
,
157 IN OUT WCHAR
*StringIdentifierName
,
158 IN UINT32 StringIdentifierNameLen
163 GetLanguageIdentifierName (
164 IN SOURCE_FILE
*SourceFile
,
165 IN OUT WCHAR
*LanguageIdentifierName
,
166 IN UINT32 LanguageIdentifierNameLen
,
172 GetPrintableLanguageName (
173 IN SOURCE_FILE
*SourceFile
178 AddCommandLineLanguage (
185 SOURCE_FILE
*SourceFile
,
192 SOURCE_FILE
*SourceFile
,
193 SOURCE_FILE
*ParentSourceFile
199 SOURCE_FILE
*SourceFile
206 OUT INT8
*FoundFileName
,
207 IN UINT32 FoundFileNameLen
220 SOURCE_FILE
*SourceFile
252 SOURCE_FILE
*SourceFile
257 ProcessTokenInclude (
258 SOURCE_FILE
*SourceFile
264 SOURCE_FILE
*SourceFile
269 ProcessTokenLanguage (
270 SOURCE_FILE
*SourceFile
275 ProcessTokenLangDef (
276 SOURCE_FILE
*SourceFile
281 ProcessTokenSecondaryLangDef (
282 SOURCE_FILE
*SourceFile
288 TEXT_STRING_LIST
*ScanFiles
293 ParseIndirectionFiles (
294 TEXT_STRING_LIST
*Files
298 StringDBCreateHiiExportPack (
311 Call the routine to parse the command-line options, then process the file.
315 Argc - Standard C main() argc and argv.
316 Argv - Standard C main() argc and argv.
327 SetUtilityName (PROGRAM_NAME
);
329 // Process the command-line arguments
331 Status
= ProcessArgs (Argc
, Argv
);
332 if (Status
!= STATUS_SUCCESS
) {
336 // Initialize the database manager
338 StringDBConstructor ();
340 // We always try to read in an existing database file. It may not
341 // exist, which is ok usually.
343 if (mGlobals
.NewDatabase
== 0) {
345 // Read all databases specified.
347 for (mGlobals
.LastDatabaseFileName
= mGlobals
.DatabaseFileName
;
348 mGlobals
.LastDatabaseFileName
!= NULL
;
349 mGlobals
.LastDatabaseFileName
= mGlobals
.LastDatabaseFileName
->Next
351 Status
= StringDBReadDatabase (mGlobals
.LastDatabaseFileName
->Str
, TRUE
, mGlobals
.VerboseDatabaseRead
);
352 if (Status
!= STATUS_SUCCESS
) {
358 // Read indirection file(s) if specified
360 if (ParseIndirectionFiles (mGlobals
.IndirectionFileName
) != STATUS_SUCCESS
) {
364 // If scanning source files, do that now
366 if (mGlobals
.Mode
== MODE_SCAN
) {
367 ScanFiles (mGlobals
.ScanFileName
);
368 } else if (mGlobals
.Mode
== MODE_PARSE
) {
370 // Parsing a unicode strings file
372 mGlobals
.SourceFiles
.ControlCharacter
= DEFAULT_CONTROL_CHARACTER
;
373 if (mGlobals
.OutputDependencyFileName
[0] != 0) {
374 if ((mGlobals
.OutputDependencyFptr
= fopen (mGlobals
.OutputDependencyFileName
, "w")) == NULL
) {
375 Error (NULL
, 0, 0, mGlobals
.OutputDependencyFileName
, "failed to open output dependency file");
379 Status
= ProcessIncludeFile (&mGlobals
.SourceFiles
, NULL
);
380 if (mGlobals
.OutputDependencyFptr
!= NULL
) {
381 fclose (mGlobals
.OutputDependencyFptr
);
383 if (Status
!= STATUS_SUCCESS
) {
388 // Create the string defines header file if there have been no errors.
390 ParserSetPosition (NULL
, 0);
391 if ((mGlobals
.StringHFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
392 Status
= StringDBDumpStringDefines (mGlobals
.StringHFileName
, mGlobals
.BaseName
);
393 if (Status
!= EFI_SUCCESS
) {
399 // Dump the strings to a .c file if there have still been no errors.
401 if ((mGlobals
.StringCFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
402 Status
= StringDBDumpCStrings (
404 mGlobals
.StringCFileName
406 if (Status
!= EFI_SUCCESS
) {
412 // Dump the database if requested
414 if ((mGlobals
.DumpUFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
415 StringDBDumpDatabase (NULL
, mGlobals
.DumpUFileName
, FALSE
);
418 // Dump the string data as HII binary string pack if requested
420 if ((mGlobals
.HiiExportPackFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
421 StringDBCreateHiiExportPack (mGlobals
.HiiExportPackFileName
);
424 // Always update the database if no errors and not in dump mode. If they specified -od
425 // for an output database file name, then use that name. Otherwise use the name of
426 // the first database file specified with -db
428 if ((mGlobals
.Mode
!= MODE_DUMP
) && (GetUtilityStatus () < STATUS_ERROR
)) {
429 if (mGlobals
.OutputDatabaseFileName
[0]) {
430 Status
= StringDBWriteDatabase (mGlobals
.OutputDatabaseFileName
, mGlobals
.VerboseDatabaseWrite
);
432 Status
= StringDBWriteDatabase (mGlobals
.DatabaseFileName
->Str
, mGlobals
.VerboseDatabaseWrite
);
435 if (Status
!= EFI_SUCCESS
) {
445 StringDBDestructor ();
446 return GetUtilityStatus ();
452 SOURCE_FILE
*SourceFile
,
453 SOURCE_FILE
*ParentSourceFile
459 Given a source file, open the file and parse it
463 SourceFile - name of file to parse
464 ParentSourceFile - for error reporting purposes, the file that #included SourceFile.
472 static UINT32 NestDepth
= 0;
473 INT8 FoundFileName
[MAX_PATH
];
476 Status
= STATUS_SUCCESS
;
479 // Print the file being processed. Indent so you can tell the include nesting
482 if (mGlobals
.Verbose
) {
483 fprintf (stdout
, "%*cProcessing file '%s'\n", NestDepth
* 2, ' ', SourceFile
->FileName
);
487 // Make sure we didn't exceed our maximum nesting depth
489 if (NestDepth
> MAX_NEST_DEPTH
) {
490 Error (NULL
, 0, 0, SourceFile
->FileName
, "max nesting depth (%d) exceeded", NestDepth
);
491 Status
= STATUS_ERROR
;
495 // Try to open the file locally, and if that fails try along our include paths.
497 strcpy (FoundFileName
, SourceFile
->FileName
);
498 if ((SourceFile
->Fptr
= fopen (FoundFileName
, "rb")) == NULL
) {
500 // Try to find it among the paths if it has a parent (that is, it is included
503 if (ParentSourceFile
== NULL
) {
504 Error (NULL
, 0, 0, SourceFile
->FileName
, "file not found");
505 Status
= STATUS_ERROR
;
509 SourceFile
->Fptr
= FindFile (SourceFile
->FileName
, FoundFileName
, sizeof (FoundFileName
));
510 if (SourceFile
->Fptr
== NULL
) {
511 Error (ParentSourceFile
->FileName
, ParentSourceFile
->LineNum
, 0, SourceFile
->FileName
, "include file not found");
512 Status
= STATUS_ERROR
;
518 // Output the dependency
520 if (mGlobals
.OutputDependencyFptr
!= NULL
) {
521 fprintf (mGlobals
.OutputDependencyFptr
, "%s : %s\n", mGlobals
.DatabaseFileName
->Str
, FoundFileName
);
523 // Add pseudo target to avoid incremental build failure when the file is deleted
525 fprintf (mGlobals
.OutputDependencyFptr
, "%s : \n", FoundFileName
);
529 // Process the file found
531 ProcessFile (SourceFile
);
536 // Close open files and return status
538 if (SourceFile
->Fptr
!= NULL
) {
539 fclose (SourceFile
->Fptr
);
548 SOURCE_FILE
*SourceFile
552 // Get the file size, and then read the entire thing into memory.
553 // Allocate space for a terminator character.
555 fseek (SourceFile
->Fptr
, 0, SEEK_END
);
556 SourceFile
->FileSize
= ftell (SourceFile
->Fptr
);
557 fseek (SourceFile
->Fptr
, 0, SEEK_SET
);
558 SourceFile
->FileBuffer
= (WCHAR
*) malloc (SourceFile
->FileSize
+ sizeof (WCHAR
));
559 if (SourceFile
->FileBuffer
== NULL
) {
560 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
564 fread ((VOID
*) SourceFile
->FileBuffer
, SourceFile
->FileSize
, 1, SourceFile
->Fptr
);
565 SourceFile
->FileBuffer
[(SourceFile
->FileSize
/ sizeof (WCHAR
))] = UNICODE_NULL
;
567 // Pre-process the file to replace comments with spaces
569 PreprocessFile (SourceFile
);
573 ParseFile (SourceFile
);
574 free (SourceFile
->FileBuffer
);
575 return STATUS_SUCCESS
;
581 SOURCE_FILE
*SourceFile
588 // First character of a unicode file is special. Make sure
590 if (SourceFile
->FileBufferPtr
[0] != UNICODE_FILE_START
) {
591 Error (SourceFile
->FileName
, 1, 0, SourceFile
->FileName
, "file does not appear to be a unicode file");
595 SourceFile
->FileBufferPtr
++;
598 // Print the first line if in verbose mode
600 if (mGlobals
.Verbose
) {
601 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
604 // Since the syntax is relatively straightforward, just switch on the next char
606 while (!EndOfFile (SourceFile
)) {
608 // Check for whitespace
610 if (SourceFile
->FileBufferPtr
[0] == UNICODE_SPACE
) {
611 SourceFile
->FileBufferPtr
++;
612 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_TAB
) {
613 SourceFile
->FileBufferPtr
++;
614 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
615 SourceFile
->FileBufferPtr
++;
616 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
617 SourceFile
->FileBufferPtr
++;
618 SourceFile
->LineNum
++;
619 if (mGlobals
.Verbose
) {
620 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
624 } else if (SourceFile
->FileBufferPtr
[0] == 0) {
625 SourceFile
->FileBufferPtr
++;
626 } else if (InComment
) {
627 SourceFile
->FileBufferPtr
++;
628 } else if ((SourceFile
->FileBufferPtr
[0] == UNICODE_SLASH
) && (SourceFile
->FileBufferPtr
[1] == UNICODE_SLASH
)) {
629 SourceFile
->FileBufferPtr
+= 2;
631 } else if (SourceFile
->SkipToHash
&& (SourceFile
->FileBufferPtr
[0] != SourceFile
->ControlCharacter
)) {
632 SourceFile
->FileBufferPtr
++;
634 SourceFile
->SkipToHash
= FALSE
;
635 if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
636 ((Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"include")) > 0)
638 SourceFile
->FileBufferPtr
+= Len
+ 1;
639 ProcessTokenInclude (SourceFile
);
640 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
641 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"scope")) > 0
643 SourceFile
->FileBufferPtr
+= Len
+ 1;
644 ProcessTokenScope (SourceFile
);
645 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
646 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"language")) > 0
648 SourceFile
->FileBufferPtr
+= Len
+ 1;
649 ProcessTokenLanguage (SourceFile
);
650 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
651 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"langdef")) > 0
653 SourceFile
->FileBufferPtr
+= Len
+ 1;
654 ProcessTokenLangDef (SourceFile
);
655 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
656 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"secondarylang")) > 0
658 SourceFile
->FileBufferPtr
+= Len
+ 1;
659 ProcessTokenSecondaryLangDef (SourceFile
);
660 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
661 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"string")) > 0
663 SourceFile
->FileBufferPtr
+= Len
+ 1;
664 ProcessTokenString (SourceFile
);
665 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
666 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"EFI_BREAKPOINT()")) > 0
668 SourceFile
->FileBufferPtr
+= Len
;
670 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
671 (SourceFile
->FileBufferPtr
[1] == UNICODE_EQUAL_SIGN
)
673 SourceFile
->ControlCharacter
= SourceFile
->FileBufferPtr
[2];
674 SourceFile
->FileBufferPtr
+= 3;
676 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "unrecognized token", "%S", SourceFile
->FileBufferPtr
);
678 // Treat rest of line as a comment.
685 return STATUS_SUCCESS
;
691 SOURCE_FILE
*SourceFile
696 Preprocess a file to replace all carriage returns with NULLs so
697 we can print lines from the file to the screen.
700 SourceFile - structure that we use to keep track of an input file.
709 RewindFile (SourceFile
);
711 while (!EndOfFile (SourceFile
)) {
713 // If a line-feed, then no longer in a comment
715 if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
716 SourceFile
->FileBufferPtr
++;
717 SourceFile
->LineNum
++;
719 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
721 // Replace all carriage returns with a NULL so we can print stuff
723 SourceFile
->FileBufferPtr
[0] = 0;
724 SourceFile
->FileBufferPtr
++;
725 } else if (InComment
) {
726 SourceFile
->FileBufferPtr
[0] = UNICODE_SPACE
;
727 SourceFile
->FileBufferPtr
++;
728 } else if ((SourceFile
->FileBufferPtr
[0] == UNICODE_SLASH
) && (SourceFile
->FileBufferPtr
[1] == UNICODE_SLASH
)) {
729 SourceFile
->FileBufferPtr
+= 2;
732 SourceFile
->FileBufferPtr
++;
736 // Could check for end-of-file and still in a comment, but
737 // should not be necessary. So just restore the file pointers.
739 RewindFile (SourceFile
);
744 GetPrintableLanguageName (
745 IN SOURCE_FILE
*SourceFile
753 SkipWhiteSpace (SourceFile
);
754 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
755 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected quoted printable language name", "%S", SourceFile
->FileBufferPtr
);
756 SourceFile
->SkipToHash
= TRUE
;
761 SourceFile
->FileBufferPtr
++;
762 Start
= Ptr
= SourceFile
->FileBufferPtr
;
763 while (!EndOfFile (SourceFile
)) {
764 if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
765 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "carriage return found in quoted string", "%S", Start
);
767 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) {
771 SourceFile
->FileBufferPtr
++;
775 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
777 SourceFile
->FileName
,
780 "missing closing quote on printable language name string",
785 SourceFile
->FileBufferPtr
++;
788 // Now allocate memory for the string and save it off
790 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
791 if (String
== NULL
) {
792 Error (NULL
, 0, 0, "memory allocation failed", NULL
);
796 // Copy the string from the file buffer to the local copy.
797 // We do no reformatting of it whatsoever at this point.
809 // Now format the string to convert \wide and \narrow controls
811 StringDBFormatString (String
);
818 } LanguageConvertTable
[] = {
819 { L
"eng", L
"en-US" },
820 { L
"fra", L
"fr-FR" },
821 { L
"spa", L
"es-ES" },
836 // The Lang is xx-XX format and return.
838 if (wcschr (Lang
, L
'-') != NULL
) {
839 LangCode
= (WCHAR
*) malloc ((wcslen (Lang
) + 1) * sizeof(WCHAR
));
840 if (LangCode
!= NULL
) {
841 wcscpy (LangCode
, Lang
);
847 // Convert the language accoring to the table.
849 for (Index
= 0; LanguageConvertTable
[Index
].ISO639
!= NULL
; Index
++) {
850 if (wcscmp(LanguageConvertTable
[Index
].ISO639
, Lang
) == 0) {
851 LangCode
= (WCHAR
*) malloc ((wcslen (LanguageConvertTable
[Index
].RFC3066
) + 1) * sizeof (WCHAR
));
852 if (LangCode
!= NULL
) {
853 wcscpy (LangCode
, LanguageConvertTable
[Index
].RFC3066
);
864 IN WCHAR
*SecondaryLangList
867 WCHAR
*CodeBeg
, *CodeEnd
;
869 WCHAR
*LangCodeList
= NULL
;
870 WCHAR
*TempLangCodeList
= NULL
;
872 TempLangCodeList
= (WCHAR
*) malloc ((wcslen(SecondaryLangList
) + 1) * sizeof(WCHAR
));
873 if (TempLangCodeList
== NULL
) {
876 wcscpy (TempLangCodeList
, SecondaryLangList
);
877 CodeBeg
= TempLangCodeList
;
879 while (CodeBeg
!= NULL
) {
880 CodeEnd
= wcschr (CodeBeg
, L
';');
881 if (CodeEnd
!= NULL
) {
886 CodeRet
= GetLangCode (CodeBeg
);
887 if (CodeRet
!= NULL
) {
888 if (LangCodeList
!= NULL
) {
889 LangCodeList
= wstrcatenate (LangCodeList
, L
";");
891 LangCodeList
= wstrcatenate (LangCodeList
, CodeRet
);
898 free (TempLangCodeList
);
905 GetSecondaryLanguageList (
906 IN SOURCE_FILE
*SourceFile
909 WCHAR
*SecondaryLangList
= NULL
;
910 WCHAR SecondaryLang
[MAX_STRING_IDENTIFIER_NAME
+ 1];
916 SkipWhiteSpace (SourceFile
);
918 if (SourceFile
->FileBufferPtr
[0] != UNICODE_OPEN_PAREN
) {
919 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected open bracket", "%S", SourceFile
->FileBufferPtr
);
920 SourceFile
->SkipToHash
= TRUE
;
925 SecondaryLang
[0] = L
'\0';
926 SourceFile
->FileBufferPtr
++;
927 Start
= Ptr
= SourceFile
->FileBufferPtr
;
928 while (!EndOfFile (SourceFile
)) {
929 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_a
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
)) ||
930 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
931 (SourceFile
->FileBufferPtr
[0] == UNICODE_MINUS
)) {
932 if (Index
> MAX_STRING_IDENTIFIER_NAME
) {
933 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "secondary language length is too lang", "%S", SourceFile
->FileBufferPtr
);
936 SecondaryLang
[Index
] = SourceFile
->FileBufferPtr
[0];
938 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_SPACE
) {
939 SecondaryLang
[Index
] = L
'\0';
941 if (SecondaryLang
[0] != L
'\0') {
942 if (SecondaryLangList
!= NULL
) {
943 SecondaryLangList
= wstrcatenate (SecondaryLangList
, L
";");
945 SecondaryLangList
= wstrcatenate (SecondaryLangList
, SecondaryLang
);
947 SecondaryLang
[0] = L
'\0';
948 SourceFile
->FileBufferPtr
++;
951 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CLOSE_PAREN
) {
952 if (SecondaryLangList
!= NULL
) {
953 SecondaryLangList
= wstrcatenate (SecondaryLangList
, L
";");
955 SecondaryLangList
= wstrcatenate (SecondaryLangList
, SecondaryLang
);
958 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "can not recognize the secondary language", "%S", SourceFile
->FileBufferPtr
);
962 SourceFile
->FileBufferPtr
++;
965 if (SourceFile
->FileBufferPtr
[0] != UNICODE_CLOSE_PAREN
) {
966 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "missing closing bracket", "%S", Start
);
968 SourceFile
->FileBufferPtr
++;
971 LangCodeList
= GetLangCodeList (SecondaryLangList
);
972 FREE (SecondaryLangList
);
976 FREE(SecondaryLangList
);
983 SOURCE_FILE
*SourceFile
,
991 BOOLEAN PreviousBackslash
;
993 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
995 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected quoted string", "%S", SourceFile
->FileBufferPtr
);
1002 SourceFile
->FileBufferPtr
++;
1003 Start
= Ptr
= SourceFile
->FileBufferPtr
;
1004 PreviousBackslash
= FALSE
;
1005 while (!EndOfFile (SourceFile
)) {
1006 if ((SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) && (!PreviousBackslash
)) {
1008 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
1009 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "carriage return found in quoted string", "%S", Start
);
1010 PreviousBackslash
= FALSE
;
1011 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_BACKSLASH
) {
1012 PreviousBackslash
= TRUE
;
1014 PreviousBackslash
= FALSE
;
1017 SourceFile
->FileBufferPtr
++;
1021 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
1022 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "missing closing quote on string", "%S", Start
);
1024 SourceFile
->FileBufferPtr
++;
1027 // Now allocate memory for the string and save it off
1029 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
1030 if (String
== NULL
) {
1031 Error (NULL
, 0, 0, "memory allocation failed", NULL
);
1035 // Copy the string from the file buffer to the local copy.
1036 // We do no reformatting of it whatsoever at this point.
1051 // #string STR_ID_NAME
1053 // All we can do is call the string database to add the string identifier. Unfortunately
1054 // he'll have to keep track of the last identifier we added.
1058 ProcessTokenString (
1059 SOURCE_FILE
*SourceFile
1062 WCHAR StringIdentifier
[MAX_STRING_IDENTIFIER_NAME
+ 1];
1065 // Extract the string identifier name and add it to the database.
1067 if (GetStringIdentifierName (SourceFile
, StringIdentifier
, sizeof (StringIdentifier
)) > 0) {
1068 StringId
= STRING_ID_INVALID
;
1069 StringDBAddStringIdentifier (StringIdentifier
, &StringId
, 0);
1072 // Error recovery -- skip to the next #
1074 SourceFile
->SkipToHash
= TRUE
;
1081 SOURCE_FILE
*SourceFile
1085 // The file buffer pointer will typically get updated before the End-of-file flag in the
1086 // source file structure, so check it first.
1088 if (SourceFile
->FileBufferPtr
>= SourceFile
->FileBuffer
+ SourceFile
->FileSize
/ sizeof (WCHAR
)) {
1089 SourceFile
->EndOfFile
= TRUE
;
1093 if (SourceFile
->EndOfFile
) {
1102 GetStringIdentifierName (
1103 IN SOURCE_FILE
*SourceFile
,
1104 IN OUT WCHAR
*StringIdentifierName
,
1105 IN UINT32 StringIdentifierNameLen
1115 SkipWhiteSpace (SourceFile
);
1116 if (SourceFile
->EndOfFile
) {
1117 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "end-of-file encountered", "expected string identifier");
1121 // Verify first character of name is [A-Za-z]
1124 StringIdentifierNameLen
/= 2;
1125 From
= SourceFile
->FileBufferPtr
;
1126 Start
= SourceFile
->FileBufferPtr
;
1127 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
1128 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_z
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
))
1134 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid character in string identifier name", "%S", Start
);
1138 while (!EndOfFile (SourceFile
)) {
1139 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
1140 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_z
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
)) ||
1141 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_0
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_9
)) ||
1142 (SourceFile
->FileBufferPtr
[0] == UNICODE_UNDERSCORE
)
1145 if (Len
>= StringIdentifierNameLen
) {
1146 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "string identifier name too long", "%S", Start
);
1150 *StringIdentifierName
= SourceFile
->FileBufferPtr
[0];
1151 StringIdentifierName
++;
1152 SourceFile
->FileBufferPtr
++;
1153 } else if (SkipWhiteSpace (SourceFile
) == 0) {
1154 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid string identifier name", "%S", Start
);
1161 // Terminate the copy of the string.
1163 *StringIdentifierName
= 0;
1169 GetLanguageIdentifierName (
1170 IN SOURCE_FILE
*SourceFile
,
1171 IN OUT WCHAR
*LanguageIdentifierName
,
1172 IN UINT32 LanguageIdentifierNameLen
,
1179 WCHAR
*LanguageIdentifier
;
1181 LanguageIdentifier
= LanguageIdentifierName
;
1186 SkipWhiteSpace (SourceFile
);
1187 if (SourceFile
->EndOfFile
) {
1189 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "end-of-file encountered", "expected language identifier");
1190 return STATUS_ERROR
;
1193 return STATUS_SUCCESS
;
1196 // This function is called to optionally get a language identifier name in:
1197 // #string STR_ID eng "the string"
1198 // If it's optional, and we find a double-quote, then return now.
1201 if (*SourceFile
->FileBufferPtr
== UNICODE_DOUBLE_QUOTE
) {
1202 return STATUS_SUCCESS
;
1206 LanguageIdentifierNameLen
/= 2;
1208 // Internal error if we weren't given at least 4 WCHAR's to work with.
1210 if (LanguageIdentifierNameLen
< LANGUAGE_IDENTIFIER_NAME_LEN
+ 1) {
1212 SourceFile
->FileName
,
1213 SourceFile
->LineNum
,
1215 "app error -- language identifier name length is invalid",
1221 Start
= SourceFile
->FileBufferPtr
;
1222 while (!EndOfFile (SourceFile
)) {
1223 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_a
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
)) ||
1224 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
1225 (SourceFile
->FileBufferPtr
[0] == UNICODE_MINUS
)) {
1227 if (Len
> LANGUAGE_IDENTIFIER_NAME_LEN
) {
1228 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "language identifier name too long", "%S", Start
);
1229 return STATUS_ERROR
;
1231 *LanguageIdentifierName
= SourceFile
->FileBufferPtr
[0];
1232 SourceFile
->FileBufferPtr
++;
1233 LanguageIdentifierName
++;
1234 } else if (!IsWhiteSpace (SourceFile
)) {
1235 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid language identifier name", "%S", Start
);
1236 return STATUS_ERROR
;
1242 // Terminate the copy of the string.
1244 *LanguageIdentifierName
= 0;
1245 LangCode
= GetLangCode (LanguageIdentifier
);
1246 if (LangCode
!= NULL
) {
1247 wcscpy (LanguageIdentifier
, LangCode
);
1250 return STATUS_SUCCESS
;
1255 ProcessTokenInclude (
1256 SOURCE_FILE
*SourceFile
1259 INT8 IncludeFileName
[MAX_PATH
];
1262 BOOLEAN ReportedError
;
1263 SOURCE_FILE IncludedSourceFile
;
1265 ReportedError
= FALSE
;
1266 if (SkipWhiteSpace (SourceFile
) == 0) {
1267 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected whitespace following #include keyword", NULL
);
1270 // Should be quoted file name
1272 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
1273 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected quoted include file name", NULL
);
1277 SourceFile
->FileBufferPtr
++;
1279 // Copy the filename as ascii to our local string
1281 To
= IncludeFileName
;
1283 while (!EndOfFile (SourceFile
)) {
1284 if ((SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) || (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
)) {
1285 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "end-of-line found in quoted include file name", NULL
);
1289 if (SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) {
1290 SourceFile
->FileBufferPtr
++;
1294 // If too long, then report the error once and process until the closing quote
1297 if (!ReportedError
&& (Len
>= sizeof (IncludeFileName
))) {
1298 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "length of include file name exceeds limit", NULL
);
1299 ReportedError
= TRUE
;
1302 if (!ReportedError
) {
1303 *To
= UNICODE_TO_ASCII (SourceFile
->FileBufferPtr
[0]);
1307 SourceFile
->FileBufferPtr
++;
1310 if (!ReportedError
) {
1312 memset ((char *) &IncludedSourceFile
, 0, sizeof (SOURCE_FILE
));
1313 strcpy (IncludedSourceFile
.FileName
, IncludeFileName
);
1314 IncludedSourceFile
.ControlCharacter
= DEFAULT_CONTROL_CHARACTER
;
1315 ProcessIncludeFile (&IncludedSourceFile
, SourceFile
);
1317 // printf ("including file '%s'\n", IncludeFileName);
1324 // Error recovery -- skip to next #
1326 SourceFile
->SkipToHash
= TRUE
;
1332 SOURCE_FILE
*SourceFile
1335 WCHAR StringIdentifier
[MAX_STRING_IDENTIFIER_NAME
+ 1];
1337 // Extract the scope name
1339 if (GetStringIdentifierName (SourceFile
, StringIdentifier
, sizeof (StringIdentifier
)) > 0) {
1340 StringDBSetScope (StringIdentifier
);
1345 // Parse: #langdef eng "English"
1346 // #langdef chn "\wideChinese"
1350 ProcessTokenLangDef (
1351 SOURCE_FILE
*SourceFile
1355 WCHAR LanguageIdentifier
[MAX_STRING_IDENTIFIER_NAME
+ 1];
1356 WCHAR
*PrintableName
;
1358 Status
= GetLanguageIdentifierName (SourceFile
, LanguageIdentifier
, sizeof (LanguageIdentifier
), FALSE
);
1359 if (Status
!= STATUS_SUCCESS
) {
1364 // Extract the printable name
1366 PrintableName
= GetPrintableLanguageName (SourceFile
);
1367 if (PrintableName
!= NULL
) {
1368 ParserSetPosition (SourceFile
->FileName
, SourceFile
->LineNum
);
1369 StringDBAddLanguage (LanguageIdentifier
, PrintableName
, NULL
);
1370 FREE (PrintableName
);
1374 // Error recovery -- skip to next #
1376 SourceFile
->SkipToHash
= TRUE
;
1381 ProcessTokenSecondaryLangDef (
1382 SOURCE_FILE
*SourceFile
1386 LANGUAGE_LIST
*Lang
;
1387 WCHAR LanguageIdentifier
[MAX_STRING_IDENTIFIER_NAME
+ 1];
1389 WCHAR
*SecondaryLangList
= NULL
;
1391 Status
= GetLanguageIdentifierName (SourceFile
, LanguageIdentifier
, sizeof (LanguageIdentifier
), FALSE
);
1392 if (Status
!= STATUS_SUCCESS
) {
1395 LangCode
= GetLangCode(LanguageIdentifier
);
1396 if (LangCode
== NULL
) {
1400 Lang
= StringDBFindLanguageList (LanguageIdentifier
);
1405 SecondaryLangList
= GetSecondaryLanguageList (SourceFile
);
1406 if (SecondaryLangList
!= NULL
) {
1407 ParserSetPosition (SourceFile
->FileName
, SourceFile
->LineNum
);
1408 Status
= StringDBAddSecondaryLanguage (LangCode
, GetLangCodeList(SecondaryLangList
));
1409 if (Status
!= STATUS_SUCCESS
) {
1410 SourceFile
->SkipToHash
= TRUE
;
1413 FREE (SecondaryLangList
);
1419 SourceFile
->SkipToHash
= TRUE
;
1424 ApparentQuotedString (
1425 SOURCE_FILE
*SourceFile
1430 // See if the first and last nonblank characters on the line are double quotes
1432 for (Ptr
= SourceFile
->FileBufferPtr
; *Ptr
&& (*Ptr
== UNICODE_SPACE
); Ptr
++)
1434 if (*Ptr
!= UNICODE_DOUBLE_QUOTE
) {
1443 for (; *Ptr
&& (*Ptr
== UNICODE_SPACE
); Ptr
--)
1445 if (*Ptr
!= UNICODE_DOUBLE_QUOTE
) {
1453 // #language eng "some string " "more string"
1457 ProcessTokenLanguage (
1458 SOURCE_FILE
*SourceFile
1463 WCHAR
*SecondString
;
1467 WCHAR Language
[LANGUAGE_IDENTIFIER_NAME_LEN
+ 1];
1469 BOOLEAN PreviousNewline
;
1471 // Get the language identifier
1474 Status
= GetLanguageIdentifierName (SourceFile
, Language
, sizeof (Language
), TRUE
);
1475 if (Status
!= STATUS_SUCCESS
) {
1480 // Extract the string value. It's either a quoted string that starts on the current line, or
1481 // an unquoted string that starts on the following line and continues until the next control
1482 // character in column 1.
1483 // Look ahead to find a quote or a newline
1485 if (SkipTo (SourceFile
, UNICODE_DOUBLE_QUOTE
, TRUE
)) {
1486 String
= GetQuotedString (SourceFile
, FALSE
);
1487 if (String
!= NULL
) {
1489 // Set the position in the file of where we are parsing for error
1490 // reporting purposes. Then start looking ahead for additional
1491 // quoted strings, and concatenate them until we get a failure
1492 // back from the string parser.
1494 Len
= wcslen (String
) + 1;
1495 ParserSetPosition (SourceFile
->FileName
, SourceFile
->LineNum
);
1497 SkipWhiteSpace (SourceFile
);
1498 SecondString
= GetQuotedString (SourceFile
, TRUE
);
1499 if (SecondString
!= NULL
) {
1500 Len
+= wcslen (SecondString
);
1501 TempString
= (WCHAR
*) malloc (Len
* sizeof (WCHAR
));
1502 if (TempString
== NULL
) {
1503 Error (NULL
, 0, 0, "application error", "failed to allocate memory");
1507 wcscpy (TempString
, String
);
1508 wcscat (TempString
, SecondString
);
1510 free (SecondString
);
1511 String
= TempString
;
1513 } while (SecondString
!= NULL
);
1514 StringDBAddString (Language
, NULL
, NULL
, String
, TRUE
, 0);
1518 // Error was reported at lower level. Error recovery mode.
1520 SourceFile
->SkipToHash
= TRUE
;
1523 if (!mGlobals
.UnquotedStrings
) {
1525 // They're using unquoted strings. If the next non-blank character is a double quote, and the
1526 // last non-blank character on the line is a double quote, then more than likely they're using
1527 // quotes, so they need to put the quoted string on the end of the previous line
1529 if (ApparentQuotedString (SourceFile
)) {
1531 SourceFile
->FileName
,
1532 SourceFile
->LineNum
,
1534 "unexpected quoted string on line",
1535 "specify -uqs option if necessary"
1540 // Found end-of-line (hopefully). Skip over it and start taking in characters
1541 // until we find a control character at the start of a line.
1544 From
= SourceFile
->FileBufferPtr
;
1545 PreviousNewline
= FALSE
;
1546 while (!EndOfFile (SourceFile
)) {
1547 if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
1548 PreviousNewline
= TRUE
;
1549 SourceFile
->LineNum
++;
1552 if (PreviousNewline
&& (SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
)) {
1556 PreviousNewline
= FALSE
;
1559 SourceFile
->FileBufferPtr
++;
1562 if ((Len
== 0) && EndOfFile (SourceFile
)) {
1563 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "unexpected end of file", NULL
);
1564 SourceFile
->SkipToHash
= TRUE
;
1568 // Now allocate a buffer, copy the characters, and add the string.
1570 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
1571 if (String
== NULL
) {
1572 Error (NULL
, 0, 0, "application error", "failed to allocate memory");
1577 while (From
< SourceFile
->FileBufferPtr
) {
1596 StringDBAddString (Language
, NULL
, NULL
, String
, TRUE
, 0);
1603 SOURCE_FILE
*SourceFile
1606 switch (SourceFile
->FileBufferPtr
[0]) {
1622 SOURCE_FILE
*SourceFile
1628 while (!EndOfFile (SourceFile
)) {
1630 switch (*SourceFile
->FileBufferPtr
) {
1635 SourceFile
->FileBufferPtr
++;
1639 SourceFile
->FileBufferPtr
++;
1640 SourceFile
->LineNum
++;
1641 if (mGlobals
.Verbose
) {
1642 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
1651 // Some tokens require trailing whitespace. If we're at the end of the
1652 // file, then we count that as well.
1654 if ((Count
== 0) && (EndOfFile (SourceFile
))) {
1671 while (*Str
== *Buffer
) {
1701 Len
+= wcslen (Src
);
1702 Dst
= (WCHAR
*) malloc ((Len
+ 1) * 2);
1717 // Given a filename, try to find it along the include paths.
1723 OUT INT8
*FoundFileName
,
1724 IN UINT32 FoundFileNameLen
1728 TEXT_STRING_LIST
*List
;
1731 // Traverse the list of paths and try to find the file
1733 List
= mGlobals
.IncludePaths
;
1734 while (List
!= NULL
) {
1736 // Put the path and filename together
1738 if (strlen (List
->Str
) + strlen (FileName
) + 1 > FoundFileNameLen
) {
1739 Error (PROGRAM_NAME
, 0, 0, NULL
, "internal error - cannot concatenate path+filename");
1743 // Append the filename to this include path and try to open the file.
1745 strcpy (FoundFileName
, List
->Str
);
1746 strcat (FoundFileName
, FileName
);
1747 if ((Fptr
= fopen (FoundFileName
, "rb")) != NULL
) {
1749 // Return the file pointer
1759 FoundFileName
[0] = 0;
1763 // Process the command-line arguments
1772 TEXT_STRING_LIST
*NewList
;
1774 // Clear our globals
1776 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
1777 strcpy (mGlobals
.BaseName
, DEFAULT_BASE_NAME
);
1779 // Skip program name
1786 return STATUS_ERROR
;
1789 mGlobals
.Mode
= MODE_UNKNOWN
;
1791 // Process until no more -args.
1793 while ((Argc
> 0) && (Argv
[0][0] == '-')) {
1797 if (_stricmp (Argv
[0], "-parse") == 0) {
1798 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1799 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1800 return STATUS_ERROR
;
1803 mGlobals
.Mode
= MODE_PARSE
;
1807 } else if (_stricmp (Argv
[0], "-scan") == 0) {
1808 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1809 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1810 return STATUS_ERROR
;
1813 mGlobals
.Mode
= MODE_SCAN
;
1815 // -vscan verbose scanning option
1817 } else if (_stricmp (Argv
[0], "-vscan") == 0) {
1818 mGlobals
.VerboseScan
= TRUE
;
1822 } else if (_stricmp (Argv
[0], "-dump") == 0) {
1823 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1824 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1825 return STATUS_ERROR
;
1828 mGlobals
.Mode
= MODE_DUMP
;
1829 } else if (_stricmp (Argv
[0], "-uqs") == 0) {
1830 mGlobals
.UnquotedStrings
= TRUE
;
1832 // -i path add include search path when parsing
1834 } else if (_stricmp (Argv
[0], "-i") == 0) {
1836 // check for one more arg
1838 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1839 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing include path");
1840 return STATUS_ERROR
;
1843 // Allocate memory for a new list element, fill it in, and
1844 // add it to our list of include paths. Always make sure it
1845 // has a "\" on the end of it.
1847 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1848 if (NewList
== NULL
) {
1849 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
1850 return STATUS_ERROR
;
1853 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1854 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1855 if (NewList
->Str
== NULL
) {
1857 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
1858 return STATUS_ERROR
;
1861 strcpy (NewList
->Str
, Argv
[1]);
1862 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1863 strcat (NewList
->Str
, "\\");
1866 // Add it to our linked list
1868 if (mGlobals
.IncludePaths
== NULL
) {
1869 mGlobals
.IncludePaths
= NewList
;
1871 mGlobals
.LastIncludePath
->Next
= NewList
;
1874 mGlobals
.LastIncludePath
= NewList
;
1877 } else if (_stricmp (Argv
[0], "-if") == 0) {
1879 // Indirection file -- check for one more arg
1881 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1882 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing indirection file name");
1883 return STATUS_ERROR
;
1886 // Allocate memory for a new list element, fill it in, and
1887 // add it to our list of include paths. Always make sure it
1888 // has a "\" on the end of it.
1890 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1891 if (NewList
== NULL
) {
1892 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
1893 return STATUS_ERROR
;
1896 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1897 NewList
->Str
= malloc (strlen (Argv
[1]) + 1);
1898 if (NewList
->Str
== NULL
) {
1900 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
1901 return STATUS_ERROR
;
1904 strcpy (NewList
->Str
, Argv
[1]);
1906 // Add it to our linked list
1908 if (mGlobals
.IndirectionFileName
== NULL
) {
1909 mGlobals
.IndirectionFileName
= NewList
;
1911 mGlobals
.LastIndirectionFileName
->Next
= NewList
;
1914 mGlobals
.LastIndirectionFileName
= NewList
;
1917 } else if (_stricmp (Argv
[0], "-db") == 0) {
1919 // -db option to specify a database file.
1920 // Check for one more arg (the database file name)
1922 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1923 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing database file name");
1924 return STATUS_ERROR
;
1927 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1928 if (NewList
== NULL
) {
1929 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
1930 return STATUS_ERROR
;
1933 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1934 NewList
->Str
= malloc (strlen (Argv
[1]) + 1);
1935 if (NewList
->Str
== NULL
) {
1937 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
1938 return STATUS_ERROR
;
1941 strcpy (NewList
->Str
, Argv
[1]);
1943 // Add it to our linked list
1945 if (mGlobals
.DatabaseFileName
== NULL
) {
1946 mGlobals
.DatabaseFileName
= NewList
;
1948 mGlobals
.LastDatabaseFileName
->Next
= NewList
;
1951 mGlobals
.LastDatabaseFileName
= NewList
;
1954 } else if (_stricmp (Argv
[0], "-ou") == 0) {
1956 // -ou option to specify an output unicode file to
1957 // which we can dump our database.
1959 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1960 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing database dump output file name");
1961 return STATUS_ERROR
;
1964 if (mGlobals
.DumpUFileName
[0] == 0) {
1965 strcpy (mGlobals
.DumpUFileName
, Argv
[1]);
1967 Error (PROGRAM_NAME
, 0, 0, Argv
[1], "-ou option already specified with '%s'", mGlobals
.DumpUFileName
);
1968 return STATUS_ERROR
;
1973 } else if (_stricmp (Argv
[0], "-hpk") == 0) {
1975 // -hpk option to create an HII export pack of the input database file
1977 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1978 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing raw string data dump output file name");
1979 return STATUS_ERROR
;
1982 if (mGlobals
.HiiExportPackFileName
[0] == 0) {
1983 strcpy (mGlobals
.HiiExportPackFileName
, Argv
[1]);
1985 Error (PROGRAM_NAME
, 0, 0, Argv
[1], "-or option already specified with '%s'", mGlobals
.HiiExportPackFileName
);
1986 return STATUS_ERROR
;
1991 } else if ((_stricmp (Argv
[0], "-?") == 0) || (_stricmp (Argv
[0], "-h") == 0)) {
1993 return STATUS_ERROR
;
1994 } else if (_stricmp (Argv
[0], "-v") == 0) {
1995 mGlobals
.Verbose
= 1;
1996 } else if (_stricmp (Argv
[0], "-vdbw") == 0) {
1997 mGlobals
.VerboseDatabaseWrite
= 1;
1998 } else if (_stricmp (Argv
[0], "-vdbr") == 0) {
1999 mGlobals
.VerboseDatabaseRead
= 1;
2000 } else if (_stricmp (Argv
[0], "-newdb") == 0) {
2001 mGlobals
.NewDatabase
= 1;
2002 } else if (_stricmp (Argv
[0], "-ignorenotfound") == 0) {
2003 mGlobals
.IgnoreNotFound
= 1;
2004 } else if (_stricmp (Argv
[0], "-oc") == 0) {
2006 // check for one more arg
2008 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2009 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing output C filename");
2010 return STATUS_ERROR
;
2013 strcpy (mGlobals
.StringCFileName
, Argv
[1]);
2016 } else if (_stricmp (Argv
[0], "-bn") == 0) {
2018 // check for one more arg
2020 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2021 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing base name");
2023 return STATUS_ERROR
;
2026 strcpy (mGlobals
.BaseName
, Argv
[1]);
2029 } else if (_stricmp (Argv
[0], "-oh") == 0) {
2031 // -oh to specify output .h defines file name
2033 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2034 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing output .h filename");
2035 return STATUS_ERROR
;
2038 strcpy (mGlobals
.StringHFileName
, Argv
[1]);
2041 } else if (_stricmp (Argv
[0], "-dep") == 0) {
2043 // -dep to specify output dependency file name
2045 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2046 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing output dependency filename");
2047 return STATUS_ERROR
;
2050 strcpy (mGlobals
.OutputDependencyFileName
, Argv
[1]);
2053 } else if (_stricmp (Argv
[0], "-skipext") == 0) {
2055 // -skipext to skip scanning of files with certain filename extensions
2057 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2058 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing filename extension");
2059 return STATUS_ERROR
;
2062 // Allocate memory for a new list element, fill it in, and
2063 // add it to our list of excluded extensions. Always make sure it
2064 // has a "." as the first character.
2066 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
2067 if (NewList
== NULL
) {
2068 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
2069 return STATUS_ERROR
;
2072 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
2073 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
2074 if (NewList
->Str
== NULL
) {
2076 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
2077 return STATUS_ERROR
;
2080 if (Argv
[1][0] == '.') {
2081 strcpy (NewList
->Str
, Argv
[1]);
2083 NewList
->Str
[0] = '.';
2084 strcpy (NewList
->Str
+ 1, Argv
[1]);
2087 // Add it to our linked list
2089 if (mGlobals
.SkipExt
== NULL
) {
2090 mGlobals
.SkipExt
= NewList
;
2092 mGlobals
.LastSkipExt
->Next
= NewList
;
2095 mGlobals
.LastSkipExt
= NewList
;
2098 } else if (_stricmp (Argv
[0], "-lang") == 0) {
2100 // "-lang eng" or "-lang spa+cat" to only output certain languages
2102 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2103 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing language name");
2105 return STATUS_ERROR
;
2108 if (AddCommandLineLanguage (Argv
[1]) != STATUS_SUCCESS
) {
2109 return STATUS_ERROR
;
2114 } else if (_stricmp (Argv
[0], "-od") == 0) {
2116 // Output database file name -- check for another arg
2118 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
2119 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "missing output database file name");
2120 return STATUS_ERROR
;
2123 strcpy (mGlobals
.OutputDatabaseFileName
, Argv
[1]);
2130 Error (PROGRAM_NAME
, 0, 0, Argv
[0], "unrecognized option");
2132 return STATUS_ERROR
;
2139 // Make sure they specified the mode parse/scan/dump
2141 if (mGlobals
.Mode
== MODE_UNKNOWN
) {
2142 Error (NULL
, 0, 0, "must specify one of -parse/-scan/-dump", NULL
);
2143 return STATUS_ERROR
;
2146 // All modes require a database filename
2148 if (mGlobals
.DatabaseFileName
== 0) {
2149 Error (NULL
, 0, 0, "must specify a database filename using -db DbFileName", NULL
);
2151 return STATUS_ERROR
;
2154 // If dumping the database file, then return immediately if all
2155 // parameters check out.
2157 if (mGlobals
.Mode
== MODE_DUMP
) {
2159 // Not much use if they didn't specify -oh or -oc or -ou or -hpk
2161 if ((mGlobals
.DumpUFileName
[0] == 0) &&
2162 (mGlobals
.StringHFileName
[0] == 0) &&
2163 (mGlobals
.StringCFileName
[0] == 0) &&
2164 (mGlobals
.HiiExportPackFileName
[0] == 0)
2166 Error (NULL
, 0, 0, "-dump without -oc/-oh/-ou/-hpk is a NOP", NULL
);
2167 return STATUS_ERROR
;
2170 return STATUS_SUCCESS
;
2173 // Had to specify source string file and output string defines header filename.
2175 if (mGlobals
.Mode
== MODE_SCAN
) {
2177 Error (PROGRAM_NAME
, 0, 0, NULL
, "must specify at least one source file to scan with -scan");
2179 return STATUS_ERROR
;
2182 // Get the list of filenames
2185 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
2186 if (NewList
== NULL
) {
2187 Error (PROGRAM_NAME
, 0, 0, "memory allocation failure", NULL
);
2188 return STATUS_ERROR
;
2191 memset (NewList
, 0, sizeof (TEXT_STRING_LIST
));
2192 NewList
->Str
= (UINT8
*) malloc (strlen (Argv
[0]) + 1);
2193 if (NewList
->Str
== NULL
) {
2194 Error (PROGRAM_NAME
, 0, 0, "memory allocation failure", NULL
);
2195 return STATUS_ERROR
;
2198 strcpy (NewList
->Str
, Argv
[0]);
2199 if (mGlobals
.ScanFileName
== NULL
) {
2200 mGlobals
.ScanFileName
= NewList
;
2202 mGlobals
.LastScanFileName
->Next
= NewList
;
2205 mGlobals
.LastScanFileName
= NewList
;
2211 // Parse mode -- must specify an input unicode file name
2214 Error (PROGRAM_NAME
, 0, 0, NULL
, "must specify input unicode string file name with -parse");
2216 return STATUS_ERROR
;
2219 strcpy (mGlobals
.SourceFiles
.FileName
, Argv
[0]);
2222 return STATUS_SUCCESS
;
2225 // Found "-lang eng,spa+cat" on the command line. Parse the
2226 // language list and save the setting for later processing.
2230 AddCommandLineLanguage (
2234 WCHAR_STRING_LIST
*WNewList
;
2238 // Keep processing the input string until we find the end.
2242 // Allocate memory for a new list element, fill it in, and
2243 // add it to our list.
2245 WNewList
= MALLOC (sizeof (WCHAR_STRING_LIST
));
2246 if (WNewList
== NULL
) {
2247 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
2248 return STATUS_ERROR
;
2251 memset ((char *) WNewList
, 0, sizeof (WCHAR_STRING_LIST
));
2252 WNewList
->Str
= malloc ((strlen (Language
) + 1) * sizeof (WCHAR
));
2253 if (WNewList
->Str
== NULL
) {
2255 Error (PROGRAM_NAME
, 0, 0, NULL
, "memory allocation failure");
2256 return STATUS_ERROR
;
2259 // Copy it as unicode to our new structure. Then remove the
2260 // plus signs in it, and verify each language name is 3 characters
2261 // long. If we find a comma, then we're done with this group, so
2265 swprintf (WNewList
->Str
, (strlen (Language
) + 1) * sizeof (WCHAR
), L
"%S", Language
);
2267 swprintf (WNewList
->Str
, L
"%S", Language
);
2269 From
= To
= WNewList
->Str
;
2271 if (*From
== L
',') {
2275 if ((wcslen (From
) < LANGUAGE_IDENTIFIER_NAME_LEN
) ||
2277 (From
[LANGUAGE_IDENTIFIER_NAME_LEN
] != 0) &&
2278 (From
[LANGUAGE_IDENTIFIER_NAME_LEN
] != UNICODE_PLUS_SIGN
) &&
2279 (From
[LANGUAGE_IDENTIFIER_NAME_LEN
] != L
',')
2282 Error (PROGRAM_NAME
, 0, 0, Language
, "invalid format for language name on command line");
2283 FREE (WNewList
->Str
);
2285 return STATUS_ERROR
;
2288 wcsncpy (To
, From
, LANGUAGE_IDENTIFIER_NAME_LEN
);
2289 To
+= LANGUAGE_IDENTIFIER_NAME_LEN
;
2290 From
+= LANGUAGE_IDENTIFIER_NAME_LEN
;
2291 if (*From
== L
'+') {
2298 // Add it to our linked list
2300 if (mGlobals
.Language
== NULL
) {
2301 mGlobals
.Language
= WNewList
;
2303 mGlobals
.LastLanguage
->Next
= WNewList
;
2306 mGlobals
.LastLanguage
= WNewList
;
2308 // Skip to next entry (comma-separated list)
2311 if (*Language
== L
',') {
2320 return STATUS_SUCCESS
;
2323 // The contents of the text file are expected to be (one per line)
2324 // STRING_IDENTIFIER_NAME ScopeName
2326 // STR_ID_MY_FAVORITE_STRING IBM
2330 ParseIndirectionFiles (
2331 TEXT_STRING_LIST
*Files
2340 WCHAR_MATCHING_STRING_LIST
*NewList
;
2342 Line
[sizeof (Line
) - 1] = 0;
2344 while (Files
!= NULL
) {
2345 Fptr
= fopen (Files
->Str
, "r");
2348 Error (NULL
, 0, 0, Files
->Str
, "failed to open input indirection file for reading");
2349 return STATUS_ERROR
;
2352 while (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
2354 // remove terminating newline for error printing purposes.
2356 if (Line
[strlen (Line
) - 1] == '\n') {
2357 Line
[strlen (Line
) - 1] = 0;
2361 if (Line
[sizeof (Line
) - 1] != 0) {
2362 Error (Files
->Str
, LineCount
, 0, "line length exceeds maximum supported", NULL
);
2367 while (*StringName
&& (isspace (*StringName
))) {
2372 if ((*StringName
== '_') || isalpha (*StringName
)) {
2374 while ((*End
) && (*End
== '_') || (isalnum (*End
))) {
2378 if (isspace (*End
)) {
2381 while (isspace (*End
)) {
2387 while (*End
&& !isspace (*End
)) {
2393 // Add the string name/scope pair
2395 NewList
= malloc (sizeof (WCHAR_MATCHING_STRING_LIST
));
2396 if (NewList
== NULL
) {
2397 Error (NULL
, 0, 0, "memory allocation error", NULL
);
2401 memset (NewList
, 0, sizeof (WCHAR_MATCHING_STRING_LIST
));
2402 NewList
->Str1
= (WCHAR
*) malloc ((strlen (StringName
) + 1) * sizeof (WCHAR
));
2403 NewList
->Str2
= (WCHAR
*) malloc ((strlen (ScopeName
) + 1) * sizeof (WCHAR
));
2404 if ((NewList
->Str1
== NULL
) || (NewList
->Str2
== NULL
)) {
2405 Error (NULL
, 0, 0, "memory allocation error", NULL
);
2410 swprintf (NewList
->Str1
, (strlen (StringName
) + 1) * sizeof (WCHAR
), L
"%S", StringName
);
2411 swprintf (NewList
->Str2
, (strlen (ScopeName
) + 1) * sizeof (WCHAR
), L
"%S", ScopeName
);
2413 swprintf (NewList
->Str1
, L
"%S", StringName
);
2414 swprintf (NewList
->Str2
, L
"%S", ScopeName
);
2416 if (mGlobals
.IndirectionList
== NULL
) {
2417 mGlobals
.IndirectionList
= NewList
;
2419 mGlobals
.LastIndirectionList
->Next
= NewList
;
2422 mGlobals
.LastIndirectionList
= NewList
;
2424 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid line : expected 'StringIdentifier Scope'");
2428 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid line : expected 'StringIdentifier Scope'");
2432 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid string identifier");
2440 Files
= Files
->Next
;
2446 return STATUS_ERROR
;
2449 return STATUS_SUCCESS
;
2455 TEXT_STRING_LIST
*ScanFiles
2458 char Line
[MAX_LINE_LEN
];
2464 char *StringTokenPos
;
2465 TEXT_STRING_LIST
*SList
;
2469 // Put a null-terminator at the end of the line. If we read in
2470 // a line longer than we support, then we can catch it.
2472 Line
[MAX_LINE_LEN
- 1] = 0;
2474 // Process each file. If they gave us a skip extension list, then
2475 // skip it if the extension matches.
2477 while (ScanFiles
!= NULL
) {
2479 for (SList
= mGlobals
.SkipExt
; SList
!= NULL
; SList
= SList
->Next
) {
2480 if ((strlen (ScanFiles
->Str
) > strlen (SList
->Str
)) &&
2481 (strcmp (ScanFiles
->Str
+ strlen (ScanFiles
->Str
) - strlen (SList
->Str
), SList
->Str
) == 0)
2485 // printf ("Match: %s : %s\n", ScanFiles->Str, SList->Str);
2492 if (mGlobals
.VerboseScan
) {
2493 printf ("Scanning %s\n", ScanFiles
->Str
);
2496 Fptr
= fopen (ScanFiles
->Str
, "r");
2498 Error (NULL
, 0, 0, ScanFiles
->Str
, "failed to open input file for scanning");
2499 return STATUS_ERROR
;
2503 while (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
2505 if (Line
[MAX_LINE_LEN
- 1] != 0) {
2506 Error (ScanFiles
->Str
, LineNum
, 0, "line length exceeds maximum supported by tool", NULL
);
2508 return STATUS_ERROR
;
2511 // Remove the newline from the input line so we can print a warning message
2513 if (Line
[strlen (Line
) - 1] == '\n') {
2514 Line
[strlen (Line
) - 1] = 0;
2517 // Terminate the line at // comments
2519 Cptr
= strstr (Line
, "//");
2525 while ((Cptr
= strstr (Cptr
, STRING_TOKEN
)) != NULL
) {
2527 // Found "STRING_TOKEN". Make sure we don't have NUM_STRING_TOKENS or
2528 // something like that. Then make sure it's followed by
2529 // an open parenthesis, a string identifier, and then a closing
2532 if (mGlobals
.VerboseScan
) {
2533 printf (" %d: %s", LineNum
, Cptr
);
2536 if (((Cptr
== Line
) || (!IsValidIdentifierChar (*(Cptr
- 1), FALSE
))) &&
2537 (!IsValidIdentifierChar (*(Cptr
+ sizeof (STRING_TOKEN
) - 1), FALSE
))
2539 StringTokenPos
= Cptr
;
2541 Cptr
+= strlen (STRING_TOKEN
);
2542 while (*Cptr
&& isspace (*Cptr
) && (*Cptr
!= '(')) {
2547 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected "STRING_TOKEN
"(identifier)");
2550 // Skip over the open-parenthesis and find the next non-blank character
2553 while (isspace (*Cptr
)) {
2558 if ((*Cptr
== '_') || isalpha (*Cptr
)) {
2559 while ((*Cptr
== '_') || (isalnum (*Cptr
))) {
2564 while (*Cptr
&& isspace (*Cptr
)) {
2569 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected "STRING_TOKEN
"(identifier)");
2579 // Add the string identifier to the list of used strings
2581 ParserSetPosition (ScanFiles
->Str
, LineNum
);
2582 StringDBSetStringReferenced (SavePtr
, mGlobals
.IgnoreNotFound
);
2583 if (mGlobals
.VerboseScan
) {
2584 printf ("...referenced %s", SavePtr
);
2587 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected valid string identifier name");
2592 // Found it, but it's a substring of something else. Advance our pointer.
2597 if (mGlobals
.VerboseScan
) {
2606 // Skipping this file type
2608 if (mGlobals
.VerboseScan
) {
2609 printf ("Skip scanning of %s\n", ScanFiles
->Str
);
2613 ScanFiles
= ScanFiles
->Next
;
2616 return STATUS_SUCCESS
;
2619 // Free the global string lists we allocated memory for
2627 TEXT_STRING_LIST
*Temp
;
2628 WCHAR_STRING_LIST
*WTemp
;
2631 // Traverse the include paths, freeing each
2633 while (mGlobals
.IncludePaths
!= NULL
) {
2634 Temp
= mGlobals
.IncludePaths
->Next
;
2635 free (mGlobals
.IncludePaths
->Str
);
2636 free (mGlobals
.IncludePaths
);
2637 mGlobals
.IncludePaths
= Temp
;
2640 // If we did a scan, then free up our
2641 // list of files to scan.
2643 while (mGlobals
.ScanFileName
!= NULL
) {
2644 Temp
= mGlobals
.ScanFileName
->Next
;
2645 free (mGlobals
.ScanFileName
->Str
);
2646 free (mGlobals
.ScanFileName
);
2647 mGlobals
.ScanFileName
= Temp
;
2650 // If they gave us a list of filename extensions to
2651 // skip on scan, then free them up.
2653 while (mGlobals
.SkipExt
!= NULL
) {
2654 Temp
= mGlobals
.SkipExt
->Next
;
2655 free (mGlobals
.SkipExt
->Str
);
2656 free (mGlobals
.SkipExt
);
2657 mGlobals
.SkipExt
= Temp
;
2660 // Free up any languages specified
2662 while (mGlobals
.Language
!= NULL
) {
2663 WTemp
= mGlobals
.Language
->Next
;
2664 free (mGlobals
.Language
->Str
);
2665 free (mGlobals
.Language
);
2666 mGlobals
.Language
= WTemp
;
2669 // Free up our indirection list
2671 while (mGlobals
.IndirectionList
!= NULL
) {
2672 mGlobals
.LastIndirectionList
= mGlobals
.IndirectionList
->Next
;
2673 free (mGlobals
.IndirectionList
->Str1
);
2674 free (mGlobals
.IndirectionList
->Str2
);
2675 free (mGlobals
.IndirectionList
);
2676 mGlobals
.IndirectionList
= mGlobals
.LastIndirectionList
;
2679 while (mGlobals
.IndirectionFileName
!= NULL
) {
2680 mGlobals
.LastIndirectionFileName
= mGlobals
.IndirectionFileName
->Next
;
2681 free (mGlobals
.IndirectionFileName
->Str
);
2682 free (mGlobals
.IndirectionFileName
);
2683 mGlobals
.IndirectionFileName
= mGlobals
.LastIndirectionFileName
;
2689 IsValidIdentifierChar (
2695 // If it's the first character of an identifier, then
2696 // it must be one of [A-Za-z_].
2699 if (isalpha (Char
) || (Char
== '_')) {
2704 // If it's not the first character, then it can
2705 // be one of [A-Za-z_0-9]
2707 if (isalnum (Char
) || (Char
== '_')) {
2718 SOURCE_FILE
*SourceFile
2721 SourceFile
->LineNum
= 1;
2722 SourceFile
->FileBufferPtr
= SourceFile
->FileBuffer
;
2723 SourceFile
->EndOfFile
= FALSE
;
2729 SOURCE_FILE
*SourceFile
,
2731 BOOLEAN StopAfterNewline
2734 while (!EndOfFile (SourceFile
)) {
2736 // Check for the character of interest
2738 if (SourceFile
->FileBufferPtr
[0] == WChar
) {
2741 if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
2742 SourceFile
->LineNum
++;
2743 if (StopAfterNewline
) {
2744 SourceFile
->FileBufferPtr
++;
2745 if (SourceFile
->FileBufferPtr
[0] == 0) {
2746 SourceFile
->FileBufferPtr
++;
2753 SourceFile
->FileBufferPtr
++;
2767 Routine Description:
2769 Print usage information for this utility.
2782 static const char *Str
[] = {
2784 PROGRAM_NAME
" version "TOOL_VERSION
" -- process unicode strings file",
2785 " Usage: "PROGRAM_NAME
" -parse {parse options} [FileNames]",
2786 " "PROGRAM_NAME
" -scan {scan options} [FileName]",
2787 " "PROGRAM_NAME
" -dump {dump options}",
2788 " Common options include:",
2789 " -h or -? for this help information",
2790 " -db Database required name of output/input database file",
2791 " -bn BaseName for use in the .h and .c output files",
2792 " Default = "DEFAULT_BASE_NAME
,
2793 " -v for verbose output",
2794 " -vdbw for verbose output when writing database",
2795 " -vdbr for verbose output when reading database",
2796 " -od FileName to specify an output database file name",
2797 " Parse options include:",
2798 " -i IncludePath add IncludePath to list of search paths",
2799 " -dep FileName to specify an output dependency file name",
2800 " -newdb to not read in existing database file",
2801 " -uqs to indicate that unquoted strings are used",
2802 " FileNames name of one or more unicode files to parse",
2803 " Scan options include:",
2804 " -scan scan text file(s) for STRING_TOKEN() usage",
2805 " -skipext .ext to skip scan of files with .ext filename extension",
2806 " -ignorenotfound ignore if a given STRING_TOKEN(STR) is not ",
2807 " found in the database",
2808 " FileNames one or more files to scan",
2809 " Dump options include:",
2810 " -oc FileName write string data to FileName",
2811 " -oh FileName write string defines to FileName",
2812 " -ou FileName dump database to unicode file FileName",
2813 " -lang Lang only dump for the language 'Lang'",
2814 " -if FileName to specify an indirection file",
2815 " -hpk FileName to create an HII export pack of the strings",
2817 " The expected process is to parse a unicode string file to create an initial",
2818 " database of string identifier names and string definitions. Then text files",
2819 " should be scanned for STRING_TOKEN() usages, and the referenced",
2820 " strings will be tagged as used in the database. After all files have been",
2821 " scanned, then the database should be dumped to create the necessary output",
2826 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
2827 fprintf (stdout
, "%s\n", Str
[Index
]);