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.
28 #include "EfiUtilityMsgs.h"
29 #include "StrGather.h"
32 #define UTILITY_NAME "StrGather"
33 #define UTILITY_VERSION "v1.0"
38 #define MAX_NEST_DEPTH 20 // just in case we get in an endless loop.
39 #define MAX_STRING_IDENTIFIER_NAME 100 // 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 // We keep a linked list of these for the source files we process
54 typedef struct _SOURCE_FILE
{
59 INT8 FileName
[MAX_PATH
];
63 struct _SOURCE_FILE
*Previous
;
64 struct _SOURCE_FILE
*Next
;
65 WCHAR ControlCharacter
;
68 #define DEFAULT_CONTROL_CHARACTER UNICODE_SLASH
71 // Here's all our globals. We need a linked list of include paths, a linked
72 // list of source files, a linked list of subdirectories (appended to each
73 // include path when searching), and a couple other fields.
76 SOURCE_FILE SourceFiles
;
77 TEXT_STRING_LIST
*IncludePaths
; // all include paths to search
78 TEXT_STRING_LIST
*LastIncludePath
;
79 TEXT_STRING_LIST
*ScanFileName
;
80 TEXT_STRING_LIST
*LastScanFileName
;
81 TEXT_STRING_LIST
*SkipExt
; // if -skipext .uni
82 TEXT_STRING_LIST
*LastSkipExt
;
83 TEXT_STRING_LIST
*IndirectionFileName
;
84 TEXT_STRING_LIST
*LastIndirectionFileName
;
85 TEXT_STRING_LIST
*DatabaseFileName
;
86 TEXT_STRING_LIST
*LastDatabaseFileName
;
87 WCHAR_STRING_LIST
*Language
;
88 WCHAR_STRING_LIST
*LastLanguage
;
89 WCHAR_MATCHING_STRING_LIST
*IndirectionList
; // from indirection file(s)
90 WCHAR_MATCHING_STRING_LIST
*LastIndirectionList
;
91 BOOLEAN Verbose
; // for more detailed output
92 BOOLEAN VerboseDatabaseWrite
; // for more detailed output when writing database
93 BOOLEAN VerboseDatabaseRead
; // for more detailed output when reading database
94 BOOLEAN NewDatabase
; // to start from scratch
95 BOOLEAN IgnoreNotFound
; // when scanning
97 BOOLEAN UnquotedStrings
; // -uqs option
98 INT8 OutputDatabaseFileName
[MAX_PATH
];
99 INT8 StringHFileName
[MAX_PATH
];
100 INT8 StringCFileName
[MAX_PATH
]; // output .C filename
101 INT8 DumpUFileName
[MAX_PATH
]; // output unicode dump file name
102 INT8 HiiExportPackFileName
[MAX_PATH
]; // HII export pack file name
103 INT8 BaseName
[MAX_PATH
]; // base filename of the strings file
104 INT8 OutputDependencyFileName
[MAX_PATH
];
105 FILE *OutputDependencyFptr
;
111 IsValidIdentifierChar (
119 SOURCE_FILE
*SourceFile
125 SOURCE_FILE
*SourceFile
,
127 BOOLEAN StopAfterNewline
133 SOURCE_FILE
*SourceFile
139 SOURCE_FILE
*SourceFile
145 SOURCE_FILE
*SourceFile
151 SOURCE_FILE
*SourceFile
156 GetStringIdentifierName (
157 IN SOURCE_FILE
*SourceFile
,
158 IN OUT WCHAR
*StringIdentifierName
,
159 IN UINT32 StringIdentifierNameLen
164 GetLanguageIdentifierName (
165 IN SOURCE_FILE
*SourceFile
,
166 IN OUT WCHAR
*LanguageIdentifierName
,
167 IN UINT32 LanguageIdentifierNameLen
,
173 GetPrintableLanguageName (
174 IN SOURCE_FILE
*SourceFile
179 AddCommandLineLanguage (
186 SOURCE_FILE
*SourceFile
,
193 SOURCE_FILE
*SourceFile
,
194 SOURCE_FILE
*ParentSourceFile
200 SOURCE_FILE
*SourceFile
207 OUT INT8
*FoundFileName
,
208 IN UINT32 FoundFileNameLen
221 SOURCE_FILE
*SourceFile
246 SOURCE_FILE
*SourceFile
251 ProcessTokenInclude (
252 SOURCE_FILE
*SourceFile
258 SOURCE_FILE
*SourceFile
263 ProcessTokenLanguage (
264 SOURCE_FILE
*SourceFile
269 ProcessTokenLangDef (
270 SOURCE_FILE
*SourceFile
276 TEXT_STRING_LIST
*ScanFiles
281 ParseIndirectionFiles (
282 TEXT_STRING_LIST
*Files
294 Call the routine to parse the command-line options, then process the file.
298 Argc - Standard C main() argc and argv.
299 Argv - Standard C main() argc and argv.
310 SetUtilityName (UTILITY_NAME
);
312 // Process the command-line arguments
314 Status
= ProcessArgs (Argc
, Argv
);
315 if (Status
!= STATUS_SUCCESS
) {
319 // Initialize the database manager
321 StringDBConstructor ();
323 // We always try to read in an existing database file. It may not
324 // exist, which is ok usually.
326 if (mGlobals
.NewDatabase
== 0) {
328 // Read all databases specified.
330 for (mGlobals
.LastDatabaseFileName
= mGlobals
.DatabaseFileName
;
331 mGlobals
.LastDatabaseFileName
!= NULL
;
332 mGlobals
.LastDatabaseFileName
= mGlobals
.LastDatabaseFileName
->Next
334 Status
= StringDBReadDatabase (mGlobals
.LastDatabaseFileName
->Str
, TRUE
, mGlobals
.VerboseDatabaseRead
);
335 if (Status
!= STATUS_SUCCESS
) {
341 // Read indirection file(s) if specified
343 if (ParseIndirectionFiles (mGlobals
.IndirectionFileName
) != STATUS_SUCCESS
) {
347 // If scanning source files, do that now
349 if (mGlobals
.Mode
== MODE_SCAN
) {
350 ScanFiles (mGlobals
.ScanFileName
);
351 } else if (mGlobals
.Mode
== MODE_PARSE
) {
353 // Parsing a unicode strings file
355 mGlobals
.SourceFiles
.ControlCharacter
= DEFAULT_CONTROL_CHARACTER
;
356 if (mGlobals
.OutputDependencyFileName
[0] != 0) {
357 if ((mGlobals
.OutputDependencyFptr
= fopen (mGlobals
.OutputDependencyFileName
, "w")) == NULL
) {
358 Error (NULL
, 0, 0, mGlobals
.OutputDependencyFileName
, "failed to open output dependency file");
362 Status
= ProcessIncludeFile (&mGlobals
.SourceFiles
, NULL
);
363 if (mGlobals
.OutputDependencyFptr
!= NULL
) {
364 fclose (mGlobals
.OutputDependencyFptr
);
366 if (Status
!= STATUS_SUCCESS
) {
371 // Create the string defines header file if there have been no errors.
373 ParserSetPosition (NULL
, 0);
374 if ((mGlobals
.StringHFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
375 Status
= StringDBDumpStringDefines (mGlobals
.StringHFileName
, mGlobals
.BaseName
);
376 if (Status
!= EFI_SUCCESS
) {
381 // Dump the strings to a .c file if there have still been no errors.
383 if ((mGlobals
.StringCFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
384 Status
= StringDBDumpCStrings (
385 mGlobals
.StringCFileName
,
388 mGlobals
.IndirectionList
390 if (Status
!= EFI_SUCCESS
) {
395 // Dump the database if requested
397 if ((mGlobals
.DumpUFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
398 StringDBDumpDatabase (NULL
, mGlobals
.DumpUFileName
, FALSE
);
401 // Dump the string data as HII binary string pack if requested
403 if ((mGlobals
.HiiExportPackFileName
[0] != 0) && (GetUtilityStatus () < STATUS_ERROR
)) {
404 StringDBCreateHiiExportPack (mGlobals
.HiiExportPackFileName
, mGlobals
.Language
);
407 // Always update the database if no errors and not in dump mode. If they specified -od
408 // for an output database file name, then use that name. Otherwise use the name of
409 // the first database file specified with -db
411 if ((mGlobals
.Mode
!= MODE_DUMP
) && (GetUtilityStatus () < STATUS_ERROR
)) {
412 if (mGlobals
.OutputDatabaseFileName
[0]) {
413 Status
= StringDBWriteDatabase (mGlobals
.OutputDatabaseFileName
, mGlobals
.VerboseDatabaseWrite
);
415 Status
= StringDBWriteDatabase (mGlobals
.DatabaseFileName
->Str
, mGlobals
.VerboseDatabaseWrite
);
418 if (Status
!= EFI_SUCCESS
) {
428 StringDBDestructor ();
429 return GetUtilityStatus ();
435 SOURCE_FILE
*SourceFile
,
436 SOURCE_FILE
*ParentSourceFile
442 Given a source file, open the file and parse it
446 SourceFile - name of file to parse
447 ParentSourceFile - for error reporting purposes, the file that #included SourceFile.
455 static UINT32 NestDepth
= 0;
456 INT8 FoundFileName
[MAX_PATH
];
459 Status
= STATUS_SUCCESS
;
462 // Print the file being processed. Indent so you can tell the include nesting
465 if (mGlobals
.Verbose
) {
466 fprintf (stdout
, "%*cProcessing file '%s'\n", NestDepth
* 2, ' ', SourceFile
->FileName
);
470 // Make sure we didn't exceed our maximum nesting depth
472 if (NestDepth
> MAX_NEST_DEPTH
) {
473 Error (NULL
, 0, 0, SourceFile
->FileName
, "max nesting depth (%d) exceeded", NestDepth
);
474 Status
= STATUS_ERROR
;
478 // Try to open the file locally, and if that fails try along our include paths.
480 strcpy (FoundFileName
, SourceFile
->FileName
);
481 if ((SourceFile
->Fptr
= fopen (FoundFileName
, "rb")) == NULL
) {
483 // Try to find it among the paths if it has a parent (that is, it is included
486 if (ParentSourceFile
== NULL
) {
487 Error (NULL
, 0, 0, SourceFile
->FileName
, "file not found");
488 Status
= STATUS_ERROR
;
492 SourceFile
->Fptr
= FindFile (SourceFile
->FileName
, FoundFileName
, sizeof (FoundFileName
));
493 if (SourceFile
->Fptr
== NULL
) {
494 Error (ParentSourceFile
->FileName
, ParentSourceFile
->LineNum
, 0, SourceFile
->FileName
, "include file not found");
495 Status
= STATUS_ERROR
;
501 // Output the dependency
503 if (mGlobals
.OutputDependencyFptr
!= NULL
) {
504 fprintf (mGlobals
.OutputDependencyFptr
, "%s : %s\n", mGlobals
.DatabaseFileName
->Str
, FoundFileName
);
506 // Add pseudo target to avoid incremental build failure when the file is deleted
508 fprintf (mGlobals
.OutputDependencyFptr
, "%s : \n", FoundFileName
);
512 // Process the file found
514 ProcessFile (SourceFile
);
519 // Close open files and return status
521 if (SourceFile
->Fptr
!= NULL
) {
522 fclose (SourceFile
->Fptr
);
531 SOURCE_FILE
*SourceFile
535 // Get the file size, and then read the entire thing into memory.
536 // Allocate space for a terminator character.
538 fseek (SourceFile
->Fptr
, 0, SEEK_END
);
539 SourceFile
->FileSize
= ftell (SourceFile
->Fptr
);
540 fseek (SourceFile
->Fptr
, 0, SEEK_SET
);
541 SourceFile
->FileBuffer
= (WCHAR
*) malloc (SourceFile
->FileSize
+ sizeof (WCHAR
));
542 if (SourceFile
->FileBuffer
== NULL
) {
543 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
547 fread ((VOID
*) SourceFile
->FileBuffer
, SourceFile
->FileSize
, 1, SourceFile
->Fptr
);
548 SourceFile
->FileBuffer
[(SourceFile
->FileSize
/ sizeof (WCHAR
))] = UNICODE_NULL
;
550 // Pre-process the file to replace comments with spaces
552 PreprocessFile (SourceFile
);
556 ParseFile (SourceFile
);
557 free (SourceFile
->FileBuffer
);
558 return STATUS_SUCCESS
;
564 SOURCE_FILE
*SourceFile
571 // First character of a unicode file is special. Make sure
573 if (SourceFile
->FileBufferPtr
[0] != UNICODE_FILE_START
) {
574 Error (SourceFile
->FileName
, 1, 0, SourceFile
->FileName
, "file does not appear to be a unicode file");
578 SourceFile
->FileBufferPtr
++;
581 // Print the first line if in verbose mode
583 if (mGlobals
.Verbose
) {
584 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
587 // Since the syntax is relatively straightforward, just switch on the next char
589 while (!EndOfFile (SourceFile
)) {
591 // Check for whitespace
593 if (SourceFile
->FileBufferPtr
[0] == UNICODE_SPACE
) {
594 SourceFile
->FileBufferPtr
++;
595 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_TAB
) {
596 SourceFile
->FileBufferPtr
++;
597 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
598 SourceFile
->FileBufferPtr
++;
599 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
600 SourceFile
->FileBufferPtr
++;
601 SourceFile
->LineNum
++;
602 if (mGlobals
.Verbose
) {
603 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
607 } else if (SourceFile
->FileBufferPtr
[0] == 0) {
608 SourceFile
->FileBufferPtr
++;
609 } else if (InComment
) {
610 SourceFile
->FileBufferPtr
++;
611 } else if ((SourceFile
->FileBufferPtr
[0] == UNICODE_SLASH
) && (SourceFile
->FileBufferPtr
[1] == UNICODE_SLASH
)) {
612 SourceFile
->FileBufferPtr
+= 2;
614 } else if (SourceFile
->SkipToHash
&& (SourceFile
->FileBufferPtr
[0] != SourceFile
->ControlCharacter
)) {
615 SourceFile
->FileBufferPtr
++;
617 SourceFile
->SkipToHash
= FALSE
;
618 if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
619 ((Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"include")) > 0)
621 SourceFile
->FileBufferPtr
+= Len
+ 1;
622 ProcessTokenInclude (SourceFile
);
623 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
624 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"scope")) > 0
626 SourceFile
->FileBufferPtr
+= Len
+ 1;
627 ProcessTokenScope (SourceFile
);
628 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
629 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"language")) > 0
631 SourceFile
->FileBufferPtr
+= Len
+ 1;
632 ProcessTokenLanguage (SourceFile
);
633 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
634 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"langdef")) > 0
636 SourceFile
->FileBufferPtr
+= Len
+ 1;
637 ProcessTokenLangDef (SourceFile
);
638 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
639 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"string")) > 0
641 SourceFile
->FileBufferPtr
+= Len
+ 1;
642 ProcessTokenString (SourceFile
);
643 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
644 (Len
= wstrcmp (SourceFile
->FileBufferPtr
+ 1, L
"EFI_BREAKPOINT()")) > 0
646 SourceFile
->FileBufferPtr
+= Len
;
648 } else if ((SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
) &&
649 (SourceFile
->FileBufferPtr
[1] == UNICODE_EQUAL_SIGN
)
651 SourceFile
->ControlCharacter
= SourceFile
->FileBufferPtr
[2];
652 SourceFile
->FileBufferPtr
+= 3;
654 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "unrecognized token", "%S", SourceFile
->FileBufferPtr
);
656 // Treat rest of line as a comment.
663 return STATUS_SUCCESS
;
669 SOURCE_FILE
*SourceFile
674 Preprocess a file to replace all carriage returns with NULLs so
675 we can print lines from the file to the screen.
678 SourceFile - structure that we use to keep track of an input file.
687 RewindFile (SourceFile
);
689 while (!EndOfFile (SourceFile
)) {
691 // If a line-feed, then no longer in a comment
693 if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
694 SourceFile
->FileBufferPtr
++;
695 SourceFile
->LineNum
++;
697 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
699 // Replace all carriage returns with a NULL so we can print stuff
701 SourceFile
->FileBufferPtr
[0] = 0;
702 SourceFile
->FileBufferPtr
++;
703 } else if (InComment
) {
704 SourceFile
->FileBufferPtr
[0] = UNICODE_SPACE
;
705 SourceFile
->FileBufferPtr
++;
706 } else if ((SourceFile
->FileBufferPtr
[0] == UNICODE_SLASH
) && (SourceFile
->FileBufferPtr
[1] == UNICODE_SLASH
)) {
707 SourceFile
->FileBufferPtr
+= 2;
710 SourceFile
->FileBufferPtr
++;
714 // Could check for end-of-file and still in a comment, but
715 // should not be necessary. So just restore the file pointers.
717 RewindFile (SourceFile
);
722 GetPrintableLanguageName (
723 IN SOURCE_FILE
*SourceFile
731 SkipWhiteSpace (SourceFile
);
732 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
734 SourceFile
->FileName
,
737 "expected quoted printable language name",
739 SourceFile
->FileBufferPtr
741 SourceFile
->SkipToHash
= TRUE
;
746 SourceFile
->FileBufferPtr
++;
747 Start
= Ptr
= SourceFile
->FileBufferPtr
;
748 while (!EndOfFile (SourceFile
)) {
749 if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
750 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "carriage return found in quoted string", "%S", Start
);
752 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) {
756 SourceFile
->FileBufferPtr
++;
760 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
762 SourceFile
->FileName
,
765 "missing closing quote on printable language name string",
770 SourceFile
->FileBufferPtr
++;
773 // Now allocate memory for the string and save it off
775 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
776 if (String
== NULL
) {
777 Error (NULL
, 0, 0, "memory allocation failed", NULL
);
781 // Copy the string from the file buffer to the local copy.
782 // We do no reformatting of it whatsoever at this point.
794 // Now format the string to convert \wide and \narrow controls
796 StringDBFormatString (String
);
803 SOURCE_FILE
*SourceFile
,
811 BOOLEAN PreviousBackslash
;
813 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
815 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected quoted string", "%S", SourceFile
->FileBufferPtr
);
822 SourceFile
->FileBufferPtr
++;
823 Start
= Ptr
= SourceFile
->FileBufferPtr
;
824 PreviousBackslash
= FALSE
;
825 while (!EndOfFile (SourceFile
)) {
826 if ((SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) && (!PreviousBackslash
)) {
828 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) {
829 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "carriage return found in quoted string", "%S", Start
);
830 PreviousBackslash
= FALSE
;
831 } else if (SourceFile
->FileBufferPtr
[0] == UNICODE_BACKSLASH
) {
832 PreviousBackslash
= TRUE
;
834 PreviousBackslash
= FALSE
;
837 SourceFile
->FileBufferPtr
++;
841 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
842 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "missing closing quote on string", "%S", Start
);
844 SourceFile
->FileBufferPtr
++;
847 // Now allocate memory for the string and save it off
849 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
850 if (String
== NULL
) {
851 Error (NULL
, 0, 0, "memory allocation failed", NULL
);
855 // Copy the string from the file buffer to the local copy.
856 // We do no reformatting of it whatsoever at this point.
871 // #string STR_ID_NAME
873 // All we can do is call the string database to add the string identifier. Unfortunately
874 // he'll have to keep track of the last identifier we added.
879 SOURCE_FILE
*SourceFile
882 WCHAR StringIdentifier
[MAX_STRING_IDENTIFIER_NAME
];
885 // Extract the string identifier name and add it to the database.
887 if (GetStringIdentifierName (SourceFile
, StringIdentifier
, sizeof (StringIdentifier
)) > 0) {
888 StringId
= STRING_ID_INVALID
;
889 StringDBAddStringIdentifier (StringIdentifier
, &StringId
, 0);
892 // Error recovery -- skip to the next #
894 SourceFile
->SkipToHash
= TRUE
;
901 SOURCE_FILE
*SourceFile
905 // The file buffer pointer will typically get updated before the End-of-file flag in the
906 // source file structure, so check it first.
908 if (SourceFile
->FileBufferPtr
>= SourceFile
->FileBuffer
+ SourceFile
->FileSize
/ sizeof (WCHAR
)) {
909 SourceFile
->EndOfFile
= TRUE
;
913 if (SourceFile
->EndOfFile
) {
922 GetStringIdentifierName (
923 IN SOURCE_FILE
*SourceFile
,
924 IN OUT WCHAR
*StringIdentifierName
,
925 IN UINT32 StringIdentifierNameLen
935 SkipWhiteSpace (SourceFile
);
936 if (SourceFile
->EndOfFile
) {
937 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "end-of-file encountered", "expected string identifier");
941 // Verify first character of name is [A-Za-z]
944 StringIdentifierNameLen
/= 2;
945 From
= SourceFile
->FileBufferPtr
;
946 Start
= SourceFile
->FileBufferPtr
;
947 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
948 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_z
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
))
954 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid character in string identifier name", "%S", Start
);
958 while (!EndOfFile (SourceFile
)) {
959 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_A
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_Z
)) ||
960 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_z
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
)) ||
961 ((SourceFile
->FileBufferPtr
[0] >= UNICODE_0
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_9
)) ||
962 (SourceFile
->FileBufferPtr
[0] == UNICODE_UNDERSCORE
)
965 if (Len
>= StringIdentifierNameLen
) {
966 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "string identifier name too long", "%S", Start
);
970 *StringIdentifierName
= SourceFile
->FileBufferPtr
[0];
971 StringIdentifierName
++;
972 SourceFile
->FileBufferPtr
++;
973 } else if (SkipWhiteSpace (SourceFile
) == 0) {
974 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid string identifier name", "%S", Start
);
981 // Terminate the copy of the string.
983 *StringIdentifierName
= 0;
989 GetLanguageIdentifierName (
990 IN SOURCE_FILE
*SourceFile
,
991 IN OUT WCHAR
*LanguageIdentifierName
,
992 IN UINT32 LanguageIdentifierNameLen
,
1002 SkipWhiteSpace (SourceFile
);
1003 if (SourceFile
->EndOfFile
) {
1006 SourceFile
->FileName
,
1007 SourceFile
->LineNum
,
1009 "end-of-file encountered",
1010 "expected language identifier"
1017 // This function is called to optionally get a language identifier name in:
1018 // #string STR_ID eng "the string"
1019 // If it's optional, and we find a double-quote, then return now.
1022 if (*SourceFile
->FileBufferPtr
== UNICODE_DOUBLE_QUOTE
) {
1028 LanguageIdentifierNameLen
/= 2;
1030 // Internal error if we weren't given at least 4 WCHAR's to work with.
1032 if (LanguageIdentifierNameLen
< LANGUAGE_IDENTIFIER_NAME_LEN
+ 1) {
1034 SourceFile
->FileName
,
1035 SourceFile
->LineNum
,
1037 "app error -- language identifier name length is invalid",
1042 From
= SourceFile
->FileBufferPtr
;
1043 Start
= SourceFile
->FileBufferPtr
;
1044 while (!EndOfFile (SourceFile
)) {
1045 if (((SourceFile
->FileBufferPtr
[0] >= UNICODE_a
) && (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
))) {
1047 if (Len
> LANGUAGE_IDENTIFIER_NAME_LEN
) {
1048 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "language identifier name too long", "%S", Start
);
1052 *LanguageIdentifierName
= SourceFile
->FileBufferPtr
[0];
1053 SourceFile
->FileBufferPtr
++;
1054 LanguageIdentifierName
++;
1055 } else if (!IsWhiteSpace (SourceFile
)) {
1056 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid language identifier name", "%S", Start
);
1063 // Terminate the copy of the string.
1065 *LanguageIdentifierName
= 0;
1071 ProcessTokenInclude (
1072 SOURCE_FILE
*SourceFile
1075 INT8 IncludeFileName
[MAX_PATH
];
1078 BOOLEAN ReportedError
;
1079 SOURCE_FILE IncludedSourceFile
;
1081 ReportedError
= FALSE
;
1082 if (SkipWhiteSpace (SourceFile
) == 0) {
1083 Warning (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected whitespace following #include keyword", NULL
);
1086 // Should be quoted file name
1088 if (SourceFile
->FileBufferPtr
[0] != UNICODE_DOUBLE_QUOTE
) {
1089 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "expected quoted include file name", NULL
);
1093 SourceFile
->FileBufferPtr
++;
1095 // Copy the filename as ascii to our local string
1097 To
= IncludeFileName
;
1099 while (!EndOfFile (SourceFile
)) {
1100 if ((SourceFile
->FileBufferPtr
[0] == UNICODE_CR
) || (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
)) {
1101 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "end-of-line found in quoted include file name", NULL
);
1105 if (SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) {
1106 SourceFile
->FileBufferPtr
++;
1110 // If too long, then report the error once and process until the closing quote
1113 if (!ReportedError
&& (Len
>= sizeof (IncludeFileName
))) {
1114 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "length of include file name exceeds limit", NULL
);
1115 ReportedError
= TRUE
;
1118 if (!ReportedError
) {
1119 *To
= UNICODE_TO_ASCII (SourceFile
->FileBufferPtr
[0]);
1123 SourceFile
->FileBufferPtr
++;
1126 if (!ReportedError
) {
1128 memset ((char *) &IncludedSourceFile
, 0, sizeof (SOURCE_FILE
));
1129 strcpy (IncludedSourceFile
.FileName
, IncludeFileName
);
1130 IncludedSourceFile
.ControlCharacter
= DEFAULT_CONTROL_CHARACTER
;
1131 ProcessIncludeFile (&IncludedSourceFile
, SourceFile
);
1133 // printf ("including file '%s'\n", IncludeFileName);
1140 // Error recovery -- skip to next #
1142 SourceFile
->SkipToHash
= TRUE
;
1148 SOURCE_FILE
*SourceFile
1151 WCHAR StringIdentifier
[MAX_STRING_IDENTIFIER_NAME
];
1153 // Extract the scope name
1155 if (GetStringIdentifierName (SourceFile
, StringIdentifier
, sizeof (StringIdentifier
)) > 0) {
1156 StringDBSetScope (StringIdentifier
);
1160 // Parse: #langdef eng "English"
1161 // #langdef chn "\wideChinese"
1165 ProcessTokenLangDef (
1166 SOURCE_FILE
*SourceFile
1169 WCHAR LanguageIdentifier
[MAX_STRING_IDENTIFIER_NAME
];
1171 WCHAR
*PrintableName
;
1173 // Extract the 3-character language identifier
1175 Len
= GetLanguageIdentifierName (SourceFile
, LanguageIdentifier
, sizeof (LanguageIdentifier
), FALSE
);
1176 if (Len
!= LANGUAGE_IDENTIFIER_NAME_LEN
) {
1177 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid or missing language identifier", NULL
);
1180 // Extract the printable name
1182 PrintableName
= GetPrintableLanguageName (SourceFile
);
1183 if (PrintableName
!= NULL
) {
1184 ParserSetPosition (SourceFile
->FileName
, SourceFile
->LineNum
);
1185 StringDBAddLanguage (LanguageIdentifier
, PrintableName
);
1186 free (PrintableName
);
1191 // Error recovery -- skip to next #
1193 SourceFile
->SkipToHash
= TRUE
;
1198 ApparentQuotedString (
1199 SOURCE_FILE
*SourceFile
1204 // See if the first and last nonblank characters on the line are double quotes
1206 for (Ptr
= SourceFile
->FileBufferPtr
; *Ptr
&& (*Ptr
== UNICODE_SPACE
); Ptr
++)
1208 if (*Ptr
!= UNICODE_DOUBLE_QUOTE
) {
1217 for (; *Ptr
&& (*Ptr
== UNICODE_SPACE
); Ptr
--)
1219 if (*Ptr
!= UNICODE_DOUBLE_QUOTE
) {
1227 // #language eng "some string " "more string"
1231 ProcessTokenLanguage (
1232 SOURCE_FILE
*SourceFile
1236 WCHAR
*SecondString
;
1240 WCHAR Language
[LANGUAGE_IDENTIFIER_NAME_LEN
+ 1];
1242 BOOLEAN PreviousNewline
;
1244 // Get the language identifier
1247 Len
= GetLanguageIdentifierName (SourceFile
, Language
, sizeof (Language
), TRUE
);
1248 if (Len
!= LANGUAGE_IDENTIFIER_NAME_LEN
) {
1249 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid or missing language identifier", "%S", Language
);
1250 SourceFile
->SkipToHash
= TRUE
;
1254 // Extract the string value. It's either a quoted string that starts on the current line, or
1255 // an unquoted string that starts on the following line and continues until the next control
1256 // character in column 1.
1257 // Look ahead to find a quote or a newline
1259 if (SkipTo (SourceFile
, UNICODE_DOUBLE_QUOTE
, TRUE
)) {
1260 String
= GetQuotedString (SourceFile
, FALSE
);
1261 if (String
!= NULL
) {
1263 // Set the position in the file of where we are parsing for error
1264 // reporting purposes. Then start looking ahead for additional
1265 // quoted strings, and concatenate them until we get a failure
1266 // back from the string parser.
1268 Len
= wcslen (String
) + 1;
1269 ParserSetPosition (SourceFile
->FileName
, SourceFile
->LineNum
);
1271 SkipWhiteSpace (SourceFile
);
1272 SecondString
= GetQuotedString (SourceFile
, TRUE
);
1273 if (SecondString
!= NULL
) {
1274 Len
+= wcslen (SecondString
);
1275 TempString
= (WCHAR
*) malloc (Len
* sizeof (WCHAR
));
1276 if (TempString
== NULL
) {
1277 Error (NULL
, 0, 0, "application error", "failed to allocate memory");
1281 wcscpy (TempString
, String
);
1282 wcscat (TempString
, SecondString
);
1284 free (SecondString
);
1285 String
= TempString
;
1287 } while (SecondString
!= NULL
);
1288 StringDBAddString (Language
, NULL
, NULL
, String
, TRUE
, 0);
1292 // Error was reported at lower level. Error recovery mode.
1294 SourceFile
->SkipToHash
= TRUE
;
1297 if (!mGlobals
.UnquotedStrings
) {
1299 // They're using unquoted strings. If the next non-blank character is a double quote, and the
1300 // last non-blank character on the line is a double quote, then more than likely they're using
1301 // quotes, so they need to put the quoted string on the end of the previous line
1303 if (ApparentQuotedString (SourceFile
)) {
1305 SourceFile
->FileName
,
1306 SourceFile
->LineNum
,
1308 "unexpected quoted string on line",
1309 "specify -uqs option if necessary"
1314 // Found end-of-line (hopefully). Skip over it and start taking in characters
1315 // until we find a control character at the start of a line.
1318 From
= SourceFile
->FileBufferPtr
;
1319 PreviousNewline
= FALSE
;
1320 while (!EndOfFile (SourceFile
)) {
1321 if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
1322 PreviousNewline
= TRUE
;
1323 SourceFile
->LineNum
++;
1326 if (PreviousNewline
&& (SourceFile
->FileBufferPtr
[0] == SourceFile
->ControlCharacter
)) {
1330 PreviousNewline
= FALSE
;
1333 SourceFile
->FileBufferPtr
++;
1336 if ((Len
== 0) && EndOfFile (SourceFile
)) {
1337 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "unexpected end of file", NULL
);
1338 SourceFile
->SkipToHash
= TRUE
;
1342 // Now allocate a buffer, copy the characters, and add the string.
1344 String
= (WCHAR
*) malloc ((Len
+ 1) * sizeof (WCHAR
));
1345 if (String
== NULL
) {
1346 Error (NULL
, 0, 0, "application error", "failed to allocate memory");
1351 while (From
< SourceFile
->FileBufferPtr
) {
1370 StringDBAddString (Language
, NULL
, NULL
, String
, TRUE
, 0);
1377 SOURCE_FILE
*SourceFile
1380 switch (SourceFile
->FileBufferPtr
[0]) {
1396 SOURCE_FILE
*SourceFile
1402 while (!EndOfFile (SourceFile
)) {
1404 switch (*SourceFile
->FileBufferPtr
) {
1409 SourceFile
->FileBufferPtr
++;
1413 SourceFile
->FileBufferPtr
++;
1414 SourceFile
->LineNum
++;
1415 if (mGlobals
.Verbose
) {
1416 printf ("%d: %S\n", SourceFile
->LineNum
, SourceFile
->FileBufferPtr
);
1425 // Some tokens require trailing whitespace. If we're at the end of the
1426 // file, then we count that as well.
1428 if ((Count
== 0) && (EndOfFile (SourceFile
))) {
1445 while (*Str
== *Buffer
) {
1458 // Given a filename, try to find it along the include paths.
1464 OUT INT8
*FoundFileName
,
1465 IN UINT32 FoundFileNameLen
1469 TEXT_STRING_LIST
*List
;
1472 // Traverse the list of paths and try to find the file
1474 List
= mGlobals
.IncludePaths
;
1475 while (List
!= NULL
) {
1477 // Put the path and filename together
1479 if (strlen (List
->Str
) + strlen (FileName
) + 1 > FoundFileNameLen
) {
1480 Error (UTILITY_NAME
, 0, 0, NULL
, "internal error - cannot concatenate path+filename");
1484 // Append the filename to this include path and try to open the file.
1486 strcpy (FoundFileName
, List
->Str
);
1487 strcat (FoundFileName
, FileName
);
1488 if ((Fptr
= fopen (FoundFileName
, "rb")) != NULL
) {
1490 // Return the file pointer
1500 FoundFileName
[0] = 0;
1504 // Process the command-line arguments
1513 TEXT_STRING_LIST
*NewList
;
1515 // Clear our globals
1517 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
1518 strcpy (mGlobals
.BaseName
, DEFAULT_BASE_NAME
);
1520 // Skip program name
1527 return STATUS_ERROR
;
1530 mGlobals
.Mode
= MODE_UNKNOWN
;
1532 // Process until no more -args.
1534 while ((Argc
> 0) && (Argv
[0][0] == '-')) {
1538 if (_stricmp (Argv
[0], "-parse") == 0) {
1539 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1540 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1541 return STATUS_ERROR
;
1544 mGlobals
.Mode
= MODE_PARSE
;
1548 } else if (_stricmp (Argv
[0], "-scan") == 0) {
1549 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1550 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1551 return STATUS_ERROR
;
1554 mGlobals
.Mode
= MODE_SCAN
;
1556 // -vscan verbose scanning option
1558 } else if (_stricmp (Argv
[0], "-vscan") == 0) {
1559 mGlobals
.VerboseScan
= TRUE
;
1563 } else if (_stricmp (Argv
[0], "-dump") == 0) {
1564 if (mGlobals
.Mode
!= MODE_UNKNOWN
) {
1565 Error (NULL
, 0, 0, "only one of -parse/-scan/-dump allowed", NULL
);
1566 return STATUS_ERROR
;
1569 mGlobals
.Mode
= MODE_DUMP
;
1570 } else if (_stricmp (Argv
[0], "-uqs") == 0) {
1571 mGlobals
.UnquotedStrings
= TRUE
;
1573 // -i path add include search path when parsing
1575 } else if (_stricmp (Argv
[0], "-i") == 0) {
1577 // check for one more arg
1579 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1580 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing include path");
1581 return STATUS_ERROR
;
1584 // Allocate memory for a new list element, fill it in, and
1585 // add it to our list of include paths. Always make sure it
1586 // has a "\" on the end of it.
1588 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1589 if (NewList
== NULL
) {
1590 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1591 return STATUS_ERROR
;
1594 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1595 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1596 if (NewList
->Str
== NULL
) {
1598 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1599 return STATUS_ERROR
;
1602 strcpy (NewList
->Str
, Argv
[1]);
1603 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1604 strcat (NewList
->Str
, "\\");
1607 // Add it to our linked list
1609 if (mGlobals
.IncludePaths
== NULL
) {
1610 mGlobals
.IncludePaths
= NewList
;
1612 mGlobals
.LastIncludePath
->Next
= NewList
;
1615 mGlobals
.LastIncludePath
= NewList
;
1618 } else if (_stricmp (Argv
[0], "-if") == 0) {
1620 // Indirection file -- check for one more arg
1622 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1623 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing indirection file name");
1624 return STATUS_ERROR
;
1627 // Allocate memory for a new list element, fill it in, and
1628 // add it to our list of include paths. Always make sure it
1629 // has a "\" on the end of it.
1631 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1632 if (NewList
== NULL
) {
1633 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1634 return STATUS_ERROR
;
1637 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1638 NewList
->Str
= malloc (strlen (Argv
[1]) + 1);
1639 if (NewList
->Str
== NULL
) {
1641 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1642 return STATUS_ERROR
;
1645 strcpy (NewList
->Str
, Argv
[1]);
1647 // Add it to our linked list
1649 if (mGlobals
.IndirectionFileName
== NULL
) {
1650 mGlobals
.IndirectionFileName
= NewList
;
1652 mGlobals
.LastIndirectionFileName
->Next
= NewList
;
1655 mGlobals
.LastIndirectionFileName
= NewList
;
1658 } else if (_stricmp (Argv
[0], "-db") == 0) {
1660 // -db option to specify a database file.
1661 // Check for one more arg (the database file name)
1663 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1664 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing database file name");
1665 return STATUS_ERROR
;
1668 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1669 if (NewList
== NULL
) {
1670 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1671 return STATUS_ERROR
;
1674 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1675 NewList
->Str
= malloc (strlen (Argv
[1]) + 1);
1676 if (NewList
->Str
== NULL
) {
1678 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1679 return STATUS_ERROR
;
1682 strcpy (NewList
->Str
, Argv
[1]);
1684 // Add it to our linked list
1686 if (mGlobals
.DatabaseFileName
== NULL
) {
1687 mGlobals
.DatabaseFileName
= NewList
;
1689 mGlobals
.LastDatabaseFileName
->Next
= NewList
;
1692 mGlobals
.LastDatabaseFileName
= NewList
;
1695 } else if (_stricmp (Argv
[0], "-ou") == 0) {
1697 // -ou option to specify an output unicode file to
1698 // which we can dump our database.
1700 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1701 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing database dump output file name");
1702 return STATUS_ERROR
;
1705 if (mGlobals
.DumpUFileName
[0] == 0) {
1706 strcpy (mGlobals
.DumpUFileName
, Argv
[1]);
1708 Error (UTILITY_NAME
, 0, 0, Argv
[1], "-ou option already specified with '%s'", mGlobals
.DumpUFileName
);
1709 return STATUS_ERROR
;
1714 } else if (_stricmp (Argv
[0], "-hpk") == 0) {
1716 // -hpk option to create an HII export pack of the input database file
1718 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1719 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing raw string data dump output file name");
1720 return STATUS_ERROR
;
1723 if (mGlobals
.HiiExportPackFileName
[0] == 0) {
1724 strcpy (mGlobals
.HiiExportPackFileName
, Argv
[1]);
1726 Error (UTILITY_NAME
, 0, 0, Argv
[1], "-or option already specified with '%s'", mGlobals
.HiiExportPackFileName
);
1727 return STATUS_ERROR
;
1732 } else if ((_stricmp (Argv
[0], "-?") == 0) || (_stricmp (Argv
[0], "-h") == 0)) {
1734 return STATUS_ERROR
;
1735 } else if (_stricmp (Argv
[0], "-v") == 0) {
1736 mGlobals
.Verbose
= 1;
1737 } else if (_stricmp (Argv
[0], "-vdbw") == 0) {
1738 mGlobals
.VerboseDatabaseWrite
= 1;
1739 } else if (_stricmp (Argv
[0], "-vdbr") == 0) {
1740 mGlobals
.VerboseDatabaseRead
= 1;
1741 } else if (_stricmp (Argv
[0], "-newdb") == 0) {
1742 mGlobals
.NewDatabase
= 1;
1743 } else if (_stricmp (Argv
[0], "-ignorenotfound") == 0) {
1744 mGlobals
.IgnoreNotFound
= 1;
1745 } else if (_stricmp (Argv
[0], "-oc") == 0) {
1747 // check for one more arg
1749 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1750 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing output C filename");
1751 return STATUS_ERROR
;
1754 strcpy (mGlobals
.StringCFileName
, Argv
[1]);
1757 } else if (_stricmp (Argv
[0], "-bn") == 0) {
1759 // check for one more arg
1761 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1762 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing base name");
1764 return STATUS_ERROR
;
1767 strcpy (mGlobals
.BaseName
, Argv
[1]);
1770 } else if (_stricmp (Argv
[0], "-oh") == 0) {
1772 // -oh to specify output .h defines file name
1774 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1775 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing output .h filename");
1776 return STATUS_ERROR
;
1779 strcpy (mGlobals
.StringHFileName
, Argv
[1]);
1782 } else if (_stricmp (Argv
[0], "-dep") == 0) {
1784 // -dep to specify output dependency file name
1786 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1787 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing output dependency filename");
1788 return STATUS_ERROR
;
1791 strcpy (mGlobals
.OutputDependencyFileName
, Argv
[1]);
1794 } else if (_stricmp (Argv
[0], "-skipext") == 0) {
1796 // -skipext to skip scanning of files with certain filename extensions
1798 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1799 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing filename extension");
1800 return STATUS_ERROR
;
1803 // Allocate memory for a new list element, fill it in, and
1804 // add it to our list of excluded extensions. Always make sure it
1805 // has a "." as the first character.
1807 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1808 if (NewList
== NULL
) {
1809 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1810 return STATUS_ERROR
;
1813 memset ((char *) NewList
, 0, sizeof (TEXT_STRING_LIST
));
1814 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1815 if (NewList
->Str
== NULL
) {
1817 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1818 return STATUS_ERROR
;
1821 if (Argv
[1][0] == '.') {
1822 strcpy (NewList
->Str
, Argv
[1]);
1824 NewList
->Str
[0] = '.';
1825 strcpy (NewList
->Str
+ 1, Argv
[1]);
1828 // Add it to our linked list
1830 if (mGlobals
.SkipExt
== NULL
) {
1831 mGlobals
.SkipExt
= NewList
;
1833 mGlobals
.LastSkipExt
->Next
= NewList
;
1836 mGlobals
.LastSkipExt
= NewList
;
1839 } else if (_stricmp (Argv
[0], "-lang") == 0) {
1841 // "-lang eng" or "-lang spa+cat" to only output certain languages
1843 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1844 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing language name");
1846 return STATUS_ERROR
;
1849 if (AddCommandLineLanguage (Argv
[1]) != STATUS_SUCCESS
) {
1850 return STATUS_ERROR
;
1855 } else if (_stricmp (Argv
[0], "-od") == 0) {
1857 // Output database file name -- check for another arg
1859 if ((Argc
<= 1) || (Argv
[1][0] == '-')) {
1860 Error (UTILITY_NAME
, 0, 0, Argv
[0], "missing output database file name");
1861 return STATUS_ERROR
;
1864 strcpy (mGlobals
.OutputDatabaseFileName
, Argv
[1]);
1871 Error (UTILITY_NAME
, 0, 0, Argv
[0], "unrecognized option");
1873 return STATUS_ERROR
;
1880 // Make sure they specified the mode parse/scan/dump
1882 if (mGlobals
.Mode
== MODE_UNKNOWN
) {
1883 Error (NULL
, 0, 0, "must specify one of -parse/-scan/-dump", NULL
);
1884 return STATUS_ERROR
;
1887 // All modes require a database filename
1889 if (mGlobals
.DatabaseFileName
== 0) {
1890 Error (NULL
, 0, 0, "must specify a database filename using -db DbFileName", NULL
);
1892 return STATUS_ERROR
;
1895 // If dumping the database file, then return immediately if all
1896 // parameters check out.
1898 if (mGlobals
.Mode
== MODE_DUMP
) {
1900 // Not much use if they didn't specify -oh or -oc or -ou or -hpk
1902 if ((mGlobals
.DumpUFileName
[0] == 0) &&
1903 (mGlobals
.StringHFileName
[0] == 0) &&
1904 (mGlobals
.StringCFileName
[0] == 0) &&
1905 (mGlobals
.HiiExportPackFileName
[0] == 0)
1907 Error (NULL
, 0, 0, "-dump without -oc/-oh/-ou/-hpk is a NOP", NULL
);
1908 return STATUS_ERROR
;
1911 return STATUS_SUCCESS
;
1914 // Had to specify source string file and output string defines header filename.
1916 if (mGlobals
.Mode
== MODE_SCAN
) {
1918 Error (UTILITY_NAME
, 0, 0, NULL
, "must specify at least one source file to scan with -scan");
1920 return STATUS_ERROR
;
1923 // Get the list of filenames
1926 NewList
= malloc (sizeof (TEXT_STRING_LIST
));
1927 if (NewList
== NULL
) {
1928 Error (UTILITY_NAME
, 0, 0, "memory allocation failure", NULL
);
1929 return STATUS_ERROR
;
1932 memset (NewList
, 0, sizeof (TEXT_STRING_LIST
));
1933 NewList
->Str
= (UINT8
*) malloc (strlen (Argv
[0]) + 1);
1934 if (NewList
->Str
== NULL
) {
1935 Error (UTILITY_NAME
, 0, 0, "memory allocation failure", NULL
);
1936 return STATUS_ERROR
;
1939 strcpy (NewList
->Str
, Argv
[0]);
1940 if (mGlobals
.ScanFileName
== NULL
) {
1941 mGlobals
.ScanFileName
= NewList
;
1943 mGlobals
.LastScanFileName
->Next
= NewList
;
1946 mGlobals
.LastScanFileName
= NewList
;
1952 // Parse mode -- must specify an input unicode file name
1955 Error (UTILITY_NAME
, 0, 0, NULL
, "must specify input unicode string file name with -parse");
1957 return STATUS_ERROR
;
1960 strcpy (mGlobals
.SourceFiles
.FileName
, Argv
[0]);
1963 return STATUS_SUCCESS
;
1966 // Found "-lang eng,spa+cat" on the command line. Parse the
1967 // language list and save the setting for later processing.
1971 AddCommandLineLanguage (
1975 WCHAR_STRING_LIST
*WNewList
;
1979 // Keep processing the input string until we find the end.
1983 // Allocate memory for a new list element, fill it in, and
1984 // add it to our list.
1986 WNewList
= MALLOC (sizeof (WCHAR_STRING_LIST
));
1987 if (WNewList
== NULL
) {
1988 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1989 return STATUS_ERROR
;
1992 memset ((char *) WNewList
, 0, sizeof (WCHAR_STRING_LIST
));
1993 WNewList
->Str
= malloc ((strlen (Language
) + 1) * sizeof (WCHAR
));
1994 if (WNewList
->Str
== NULL
) {
1996 Error (UTILITY_NAME
, 0, 0, NULL
, "memory allocation failure");
1997 return STATUS_ERROR
;
2000 // Copy it as unicode to our new structure. Then remove the
2001 // plus signs in it, and verify each language name is 3 characters
2002 // long. If we find a comma, then we're done with this group, so
2006 swprintf (WNewList
->Str
, (strlen (Language
) + 1) * sizeof (WCHAR
), L
"%S", Language
);
2008 swprintf (WNewList
->Str
, L
"%S", Language
);
2010 From
= To
= WNewList
->Str
;
2012 if (*From
== L
',') {
2016 if ((wcslen (From
) < LANGUAGE_IDENTIFIER_NAME_LEN
) ||
2018 (From
[LANGUAGE_IDENTIFIER_NAME_LEN
] != 0) &&
2019 (From
[LANGUAGE_IDENTIFIER_NAME_LEN
] != UNICODE_PLUS_SIGN
) &&
2020 (From
[LANGUAGE_IDENTIFIER_NAME_LEN
] != L
',')
2023 Error (UTILITY_NAME
, 0, 0, Language
, "invalid format for language name on command line");
2024 FREE (WNewList
->Str
);
2026 return STATUS_ERROR
;
2029 wcsncpy (To
, From
, LANGUAGE_IDENTIFIER_NAME_LEN
);
2030 To
+= LANGUAGE_IDENTIFIER_NAME_LEN
;
2031 From
+= LANGUAGE_IDENTIFIER_NAME_LEN
;
2032 if (*From
== L
'+') {
2039 // Add it to our linked list
2041 if (mGlobals
.Language
== NULL
) {
2042 mGlobals
.Language
= WNewList
;
2044 mGlobals
.LastLanguage
->Next
= WNewList
;
2047 mGlobals
.LastLanguage
= WNewList
;
2049 // Skip to next entry (comma-separated list)
2052 if (*Language
== L
',') {
2061 return STATUS_SUCCESS
;
2064 // The contents of the text file are expected to be (one per line)
2065 // STRING_IDENTIFIER_NAME ScopeName
2067 // STR_ID_MY_FAVORITE_STRING IBM
2071 ParseIndirectionFiles (
2072 TEXT_STRING_LIST
*Files
2081 WCHAR_MATCHING_STRING_LIST
*NewList
;
2083 Line
[sizeof (Line
) - 1] = 0;
2085 while (Files
!= NULL
) {
2086 Fptr
= fopen (Files
->Str
, "r");
2089 Error (NULL
, 0, 0, Files
->Str
, "failed to open input indirection file for reading");
2090 return STATUS_ERROR
;
2093 while (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
2095 // remove terminating newline for error printing purposes.
2097 if (Line
[strlen (Line
) - 1] == '\n') {
2098 Line
[strlen (Line
) - 1] = 0;
2102 if (Line
[sizeof (Line
) - 1] != 0) {
2103 Error (Files
->Str
, LineCount
, 0, "line length exceeds maximum supported", NULL
);
2108 while (*StringName
&& (isspace (*StringName
))) {
2113 if ((*StringName
== '_') || isalpha (*StringName
)) {
2115 while ((*End
) && (*End
== '_') || (isalnum (*End
))) {
2119 if (isspace (*End
)) {
2122 while (isspace (*End
)) {
2128 while (*End
&& !isspace (*End
)) {
2134 // Add the string name/scope pair
2136 NewList
= malloc (sizeof (WCHAR_MATCHING_STRING_LIST
));
2137 if (NewList
== NULL
) {
2138 Error (NULL
, 0, 0, "memory allocation error", NULL
);
2142 memset (NewList
, 0, sizeof (WCHAR_MATCHING_STRING_LIST
));
2143 NewList
->Str1
= (WCHAR
*) malloc ((strlen (StringName
) + 1) * sizeof (WCHAR
));
2144 NewList
->Str2
= (WCHAR
*) malloc ((strlen (ScopeName
) + 1) * sizeof (WCHAR
));
2145 if ((NewList
->Str1
== NULL
) || (NewList
->Str2
== NULL
)) {
2146 Error (NULL
, 0, 0, "memory allocation error", NULL
);
2151 swprintf (NewList
->Str1
, (strlen (StringName
) + 1) * sizeof (WCHAR
), L
"%S", StringName
);
2152 swprintf (NewList
->Str2
, (strlen (ScopeName
) + 1) * sizeof (WCHAR
), L
"%S", ScopeName
);
2154 swprintf (NewList
->Str1
, L
"%S", StringName
);
2155 swprintf (NewList
->Str2
, L
"%S", ScopeName
);
2157 if (mGlobals
.IndirectionList
== NULL
) {
2158 mGlobals
.IndirectionList
= NewList
;
2160 mGlobals
.LastIndirectionList
->Next
= NewList
;
2163 mGlobals
.LastIndirectionList
= NewList
;
2165 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid line : expected 'StringIdentifier Scope'");
2169 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid line : expected 'StringIdentifier Scope'");
2173 Error (Files
->Str
, LineCount
, 0, StringName
, "invalid string identifier");
2181 Files
= Files
->Next
;
2187 return STATUS_ERROR
;
2190 return STATUS_SUCCESS
;
2196 TEXT_STRING_LIST
*ScanFiles
2199 char Line
[MAX_LINE_LEN
];
2205 char *StringTokenPos
;
2206 TEXT_STRING_LIST
*SList
;
2210 // Put a null-terminator at the end of the line. If we read in
2211 // a line longer than we support, then we can catch it.
2213 Line
[MAX_LINE_LEN
- 1] = 0;
2215 // Process each file. If they gave us a skip extension list, then
2216 // skip it if the extension matches.
2218 while (ScanFiles
!= NULL
) {
2220 for (SList
= mGlobals
.SkipExt
; SList
!= NULL
; SList
= SList
->Next
) {
2221 if ((strlen (ScanFiles
->Str
) > strlen (SList
->Str
)) &&
2222 (strcmp (ScanFiles
->Str
+ strlen (ScanFiles
->Str
) - strlen (SList
->Str
), SList
->Str
) == 0)
2226 // printf ("Match: %s : %s\n", ScanFiles->Str, SList->Str);
2233 if (mGlobals
.VerboseScan
) {
2234 printf ("Scanning %s\n", ScanFiles
->Str
);
2237 Fptr
= fopen (ScanFiles
->Str
, "r");
2239 Error (NULL
, 0, 0, ScanFiles
->Str
, "failed to open input file for scanning");
2240 return STATUS_ERROR
;
2244 while (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
2246 if (Line
[MAX_LINE_LEN
- 1] != 0) {
2247 Error (ScanFiles
->Str
, LineNum
, 0, "line length exceeds maximum supported by tool", NULL
);
2249 return STATUS_ERROR
;
2252 // Remove the newline from the input line so we can print a warning message
2254 if (Line
[strlen (Line
) - 1] == '\n') {
2255 Line
[strlen (Line
) - 1] = 0;
2258 // Terminate the line at // comments
2260 Cptr
= strstr (Line
, "//");
2266 while ((Cptr
= strstr (Cptr
, STRING_TOKEN
)) != NULL
) {
2268 // Found "STRING_TOKEN". Make sure we don't have NUM_STRING_TOKENS or
2269 // something like that. Then make sure it's followed by
2270 // an open parenthesis, a string identifier, and then a closing
2273 if (mGlobals
.VerboseScan
) {
2274 printf (" %d: %s", LineNum
, Cptr
);
2277 if (((Cptr
== Line
) || (!IsValidIdentifierChar (*(Cptr
- 1), FALSE
))) &&
2278 (!IsValidIdentifierChar (*(Cptr
+ sizeof (STRING_TOKEN
) - 1), FALSE
))
2280 StringTokenPos
= Cptr
;
2282 Cptr
+= strlen (STRING_TOKEN
);
2283 while (*Cptr
&& isspace (*Cptr
) && (*Cptr
!= '(')) {
2288 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected "STRING_TOKEN
"(identifier)");
2291 // Skip over the open-parenthesis and find the next non-blank character
2294 while (isspace (*Cptr
)) {
2299 if ((*Cptr
== '_') || isalpha (*Cptr
)) {
2300 while ((*Cptr
== '_') || (isalnum (*Cptr
))) {
2305 while (*Cptr
&& isspace (*Cptr
)) {
2310 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected "STRING_TOKEN
"(identifier)");
2320 // Add the string identifier to the list of used strings
2322 ParserSetPosition (ScanFiles
->Str
, LineNum
);
2323 StringDBSetStringReferenced (SavePtr
, mGlobals
.IgnoreNotFound
);
2324 if (mGlobals
.VerboseScan
) {
2325 printf ("...referenced %s", SavePtr
);
2328 Warning (ScanFiles
->Str
, LineNum
, 0, StringTokenPos
, "expected valid string identifier name");
2333 // Found it, but it's a substring of something else. Advance our pointer.
2338 if (mGlobals
.VerboseScan
) {
2347 // Skipping this file type
2349 if (mGlobals
.VerboseScan
) {
2350 printf ("Skip scanning of %s\n", ScanFiles
->Str
);
2354 ScanFiles
= ScanFiles
->Next
;
2357 return STATUS_SUCCESS
;
2360 // Free the global string lists we allocated memory for
2368 TEXT_STRING_LIST
*Temp
;
2369 WCHAR_STRING_LIST
*WTemp
;
2372 // Traverse the include paths, freeing each
2374 while (mGlobals
.IncludePaths
!= NULL
) {
2375 Temp
= mGlobals
.IncludePaths
->Next
;
2376 free (mGlobals
.IncludePaths
->Str
);
2377 free (mGlobals
.IncludePaths
);
2378 mGlobals
.IncludePaths
= Temp
;
2381 // If we did a scan, then free up our
2382 // list of files to scan.
2384 while (mGlobals
.ScanFileName
!= NULL
) {
2385 Temp
= mGlobals
.ScanFileName
->Next
;
2386 free (mGlobals
.ScanFileName
->Str
);
2387 free (mGlobals
.ScanFileName
);
2388 mGlobals
.ScanFileName
= Temp
;
2391 // If they gave us a list of filename extensions to
2392 // skip on scan, then free them up.
2394 while (mGlobals
.SkipExt
!= NULL
) {
2395 Temp
= mGlobals
.SkipExt
->Next
;
2396 free (mGlobals
.SkipExt
->Str
);
2397 free (mGlobals
.SkipExt
);
2398 mGlobals
.SkipExt
= Temp
;
2401 // Free up any languages specified
2403 while (mGlobals
.Language
!= NULL
) {
2404 WTemp
= mGlobals
.Language
->Next
;
2405 free (mGlobals
.Language
->Str
);
2406 free (mGlobals
.Language
);
2407 mGlobals
.Language
= WTemp
;
2410 // Free up our indirection list
2412 while (mGlobals
.IndirectionList
!= NULL
) {
2413 mGlobals
.LastIndirectionList
= mGlobals
.IndirectionList
->Next
;
2414 free (mGlobals
.IndirectionList
->Str1
);
2415 free (mGlobals
.IndirectionList
->Str2
);
2416 free (mGlobals
.IndirectionList
);
2417 mGlobals
.IndirectionList
= mGlobals
.LastIndirectionList
;
2420 while (mGlobals
.IndirectionFileName
!= NULL
) {
2421 mGlobals
.LastIndirectionFileName
= mGlobals
.IndirectionFileName
->Next
;
2422 free (mGlobals
.IndirectionFileName
->Str
);
2423 free (mGlobals
.IndirectionFileName
);
2424 mGlobals
.IndirectionFileName
= mGlobals
.LastIndirectionFileName
;
2430 IsValidIdentifierChar (
2436 // If it's the first character of an identifier, then
2437 // it must be one of [A-Za-z_].
2440 if (isalpha (Char
) || (Char
== '_')) {
2445 // If it's not the first character, then it can
2446 // be one of [A-Za-z_0-9]
2448 if (isalnum (Char
) || (Char
== '_')) {
2459 SOURCE_FILE
*SourceFile
2462 SourceFile
->LineNum
= 1;
2463 SourceFile
->FileBufferPtr
= SourceFile
->FileBuffer
;
2464 SourceFile
->EndOfFile
= 0;
2470 SOURCE_FILE
*SourceFile
,
2472 BOOLEAN StopAfterNewline
2475 while (!EndOfFile (SourceFile
)) {
2477 // Check for the character of interest
2479 if (SourceFile
->FileBufferPtr
[0] == WChar
) {
2482 if (SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) {
2483 SourceFile
->LineNum
++;
2484 if (StopAfterNewline
) {
2485 SourceFile
->FileBufferPtr
++;
2486 if (SourceFile
->FileBufferPtr
[0] == 0) {
2487 SourceFile
->FileBufferPtr
++;
2494 SourceFile
->FileBufferPtr
++;
2508 Routine Description:
2510 Print usage information for this utility.
2523 const char *Str
[] = {
2524 UTILITY_NAME
" "UTILITY_VERSION
" - Intel String Gather Utility",
2525 " Copyright (C), 2004 - 2008 Intel Corporation",
2527 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
2528 " Built from "UTILITY_BUILD
", project of "UTILITY_VENDOR
,
2532 " "UTILITY_NAME
" -parse [OPTION] FILE",
2533 " "UTILITY_NAME
" -scan [OPTION] FILE",
2534 " "UTILITY_NAME
" -dump [OPTION]",
2536 " Process unicode strings file.",
2537 "Common options include:",
2538 " -h or -? for this help information",
2539 " -db Database required name of output/input database file",
2540 " -bn BaseName for use in the .h and .c output files",
2541 " Default = "DEFAULT_BASE_NAME
,
2542 " -v for verbose output",
2543 " -vdbw for verbose output when writing database",
2544 " -vdbr for verbose output when reading database",
2545 " -od FileName to specify an output database file name",
2546 "Parse options include:",
2547 " -i IncludePath add IncludePath to list of search paths",
2548 " -dep FileName to specify an output dependency file name",
2549 " -newdb to not read in existing database file",
2550 " -uqs to indicate that unquoted strings are used",
2551 " FileNames name of one or more unicode files to parse",
2552 "Scan options include:",
2553 " -scan scan text file(s) for STRING_TOKEN() usage",
2554 " -skipext .ext to skip scan of files with .ext filename extension",
2555 " -ignorenotfound ignore if a given STRING_TOKEN(STR) is not ",
2556 " found in the database",
2557 " FileNames one or more files to scan",
2558 "Dump options include:",
2559 " -oc FileName write string data to FileName",
2560 " -oh FileName write string defines to FileName",
2561 " -ou FileName dump database to unicode file FileName",
2562 " -lang Lang only dump for the language 'Lang'",
2563 " -if FileName to specify an indirection file",
2564 " -hpk FileName to create an HII export pack of the strings",
2566 "The expected process is to parse a unicode string file to create an initial",
2567 "database of string identifier names and string definitions. Then text files",
2568 "should be scanned for STRING_TOKEN() usages, and the referenced",
2569 "strings will be tagged as used in the database. After all files have been",
2570 "scanned, then the database should be dumped to create the necessary output",
2575 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
2576 fprintf (stdout
, "%s\n", Str
[Index
]);