]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Sample/Tools/Source/StrGather/StrGather.c
Add in the 1st version of ECP.
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / StrGather / StrGather.c
CommitLineData
3eb9473e 1/*++\r
2\r
3Copyright (c) 2004 - 2007, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 StrGather.c \r
15\r
16Abstract:\r
17\r
18 Parse a strings file and create or add to a string database file.\r
19\r
20--*/\r
21\r
22#include <stdio.h>\r
23#include <string.h>\r
24#include <stdlib.h>\r
25#include <ctype.h>\r
26\r
27#include "Tiano.h"\r
28#include "EfiUtilityMsgs.h"\r
29#include "StrGather.h"\r
30#include "StringDB.h"\r
31\r
32#define TOOL_VERSION "0.31"\r
33\r
34typedef UINT16 WCHAR;\r
35\r
36#define MAX_PATH 1024\r
37#define MAX_NEST_DEPTH 20 // just in case we get in an endless loop.\r
38#define MAX_STRING_IDENTIFIER_NAME 100 // number of wchars\r
39#define MAX_LINE_LEN 400\r
40#define STRING_TOKEN "STRING_TOKEN"\r
41#define DEFAULT_BASE_NAME "BaseName"\r
42//\r
43// Operational modes for this utility\r
44//\r
45#define MODE_UNKNOWN 0\r
46#define MODE_PARSE 1\r
47#define MODE_SCAN 2\r
48#define MODE_DUMP 3\r
49\r
50//\r
51// We keep a linked list of these for the source files we process\r
52//\r
53typedef struct _SOURCE_FILE {\r
54 FILE *Fptr;\r
55 WCHAR *FileBuffer;\r
56 WCHAR *FileBufferPtr;\r
57 UINT32 FileSize;\r
58 INT8 FileName[MAX_PATH];\r
59 UINT32 LineNum;\r
60 BOOLEAN EndOfFile;\r
61 BOOLEAN SkipToHash;\r
62 struct _SOURCE_FILE *Previous;\r
63 struct _SOURCE_FILE *Next;\r
64 WCHAR ControlCharacter;\r
65} SOURCE_FILE;\r
66\r
67#define DEFAULT_CONTROL_CHARACTER UNICODE_SLASH\r
68\r
69//\r
70// Here's all our globals. We need a linked list of include paths, a linked\r
71// list of source files, a linked list of subdirectories (appended to each\r
72// include path when searching), and a couple other fields.\r
73//\r
74static struct {\r
75 SOURCE_FILE SourceFiles;\r
76 TEXT_STRING_LIST *IncludePaths; // all include paths to search\r
77 TEXT_STRING_LIST *LastIncludePath;\r
78 TEXT_STRING_LIST *ScanFileName;\r
79 TEXT_STRING_LIST *LastScanFileName;\r
80 TEXT_STRING_LIST *SkipExt; // if -skipext .uni\r
81 TEXT_STRING_LIST *LastSkipExt;\r
82 TEXT_STRING_LIST *IndirectionFileName;\r
83 TEXT_STRING_LIST *LastIndirectionFileName;\r
84 TEXT_STRING_LIST *DatabaseFileName;\r
85 TEXT_STRING_LIST *LastDatabaseFileName;\r
86 WCHAR_STRING_LIST *Language;\r
87 WCHAR_STRING_LIST *LastLanguage;\r
88 WCHAR_MATCHING_STRING_LIST *IndirectionList; // from indirection file(s)\r
89 WCHAR_MATCHING_STRING_LIST *LastIndirectionList;\r
90 BOOLEAN Verbose; // for more detailed output\r
91 BOOLEAN VerboseDatabaseWrite; // for more detailed output when writing database\r
92 BOOLEAN VerboseDatabaseRead; // for more detailed output when reading database\r
93 BOOLEAN NewDatabase; // to start from scratch\r
94 BOOLEAN IgnoreNotFound; // when scanning\r
95 BOOLEAN VerboseScan;\r
96 BOOLEAN UnquotedStrings; // -uqs option\r
97 INT8 OutputDatabaseFileName[MAX_PATH];\r
98 INT8 StringHFileName[MAX_PATH];\r
99 INT8 StringCFileName[MAX_PATH]; // output .C filename\r
100 INT8 DumpUFileName[MAX_PATH]; // output unicode dump file name\r
101 INT8 HiiExportPackFileName[MAX_PATH]; // HII export pack file name\r
102 INT8 BaseName[MAX_PATH]; // base filename of the strings file\r
103 INT8 OutputDependencyFileName[MAX_PATH];\r
104 FILE *OutputDependencyFptr;\r
105 UINT32 Mode;\r
106} mGlobals;\r
107\r
108static\r
109BOOLEAN\r
110IsValidIdentifierChar (\r
111 INT8 Char,\r
112 BOOLEAN FirstChar\r
113 );\r
114\r
115static\r
116void\r
117RewindFile (\r
118 SOURCE_FILE *SourceFile\r
119 );\r
120\r
121static\r
122BOOLEAN\r
123SkipTo (\r
124 SOURCE_FILE *SourceFile,\r
125 WCHAR WChar,\r
126 BOOLEAN StopAfterNewline\r
127 );\r
128\r
129static\r
130UINT32\r
131SkipWhiteSpace (\r
132 SOURCE_FILE *SourceFile\r
133 );\r
134\r
135static\r
136BOOLEAN\r
137IsWhiteSpace (\r
138 SOURCE_FILE *SourceFile\r
139 );\r
140\r
141static\r
142BOOLEAN\r
143EndOfFile (\r
144 SOURCE_FILE *SourceFile\r
145 );\r
146\r
147static\r
148void\r
149PreprocessFile (\r
150 SOURCE_FILE *SourceFile\r
151 );\r
152\r
153static\r
154UINT32\r
155GetStringIdentifierName (\r
156 IN SOURCE_FILE *SourceFile,\r
157 IN OUT WCHAR *StringIdentifierName,\r
158 IN UINT32 StringIdentifierNameLen\r
159 );\r
160\r
161static\r
162UINT32\r
163GetLanguageIdentifierName (\r
164 IN SOURCE_FILE *SourceFile,\r
165 IN OUT WCHAR *LanguageIdentifierName,\r
166 IN UINT32 LanguageIdentifierNameLen,\r
167 IN BOOLEAN Optional\r
168 );\r
169\r
170static\r
171WCHAR *\r
172GetPrintableLanguageName (\r
173 IN SOURCE_FILE *SourceFile\r
174 );\r
175\r
176static\r
177STATUS\r
178AddCommandLineLanguage (\r
179 IN INT8 *Language\r
180 );\r
181\r
182static\r
183WCHAR *\r
184GetQuotedString (\r
185 SOURCE_FILE *SourceFile,\r
186 BOOLEAN Optional\r
187 );\r
188\r
189static\r
190STATUS\r
191ProcessIncludeFile (\r
192 SOURCE_FILE *SourceFile,\r
193 SOURCE_FILE *ParentSourceFile\r
194 );\r
195\r
196static\r
197STATUS\r
198ParseFile (\r
199 SOURCE_FILE *SourceFile\r
200 );\r
201\r
202static\r
203FILE *\r
204FindFile (\r
205 IN INT8 *FileName,\r
206 OUT INT8 *FoundFileName,\r
207 IN UINT32 FoundFileNameLen\r
208 );\r
209\r
210static\r
211STATUS\r
212ProcessArgs (\r
213 int Argc,\r
214 char *Argv[]\r
215 );\r
216\r
217static\r
218STATUS\r
219ProcessFile (\r
220 SOURCE_FILE *SourceFile\r
221 );\r
222\r
223static\r
224UINT32\r
225wstrcmp (\r
226 WCHAR *Buffer,\r
227 WCHAR *Str\r
228 );\r
229\r
230static\r
231void\r
232Usage (\r
233 VOID\r
234 );\r
235\r
236static\r
237void\r
238FreeLists (\r
239 VOID\r
240 );\r
241\r
242static\r
243void\r
244ProcessTokenString (\r
245 SOURCE_FILE *SourceFile\r
246 );\r
247\r
248static\r
249void\r
250ProcessTokenInclude (\r
251 SOURCE_FILE *SourceFile\r
252 );\r
253\r
254static\r
255void\r
256ProcessTokenScope (\r
257 SOURCE_FILE *SourceFile\r
258 );\r
259\r
260static\r
261void\r
262ProcessTokenLanguage (\r
263 SOURCE_FILE *SourceFile\r
264 );\r
265\r
266static\r
267void\r
268ProcessTokenLangDef (\r
269 SOURCE_FILE *SourceFile\r
270 );\r
271\r
272static\r
273STATUS\r
274ScanFiles (\r
275 TEXT_STRING_LIST *ScanFiles\r
276 );\r
277\r
278static\r
279STATUS\r
280ParseIndirectionFiles (\r
281 TEXT_STRING_LIST *Files\r
282 );\r
283\r
284STATUS\r
285StringDBCreateHiiExportPack (\r
286 INT8 *OutputFileName\r
287 );\r
288\r
289int\r
290main (\r
291 int Argc,\r
292 char *Argv[]\r
293 )\r
294/*++\r
295\r
296Routine Description:\r
297\r
298 Call the routine to parse the command-line options, then process the file.\r
299 \r
300Arguments:\r
301\r
302 Argc - Standard C main() argc and argv.\r
303 Argv - Standard C main() argc and argv.\r
304\r
305Returns:\r
306\r
307 0 if successful\r
308 nonzero otherwise\r
309 \r
310--*/\r
311{\r
312 STATUS Status;\r
313\r
314 SetUtilityName (PROGRAM_NAME);\r
315 //\r
316 // Process the command-line arguments\r
317 //\r
318 Status = ProcessArgs (Argc, Argv);\r
319 if (Status != STATUS_SUCCESS) {\r
320 return Status;\r
321 }\r
322 //\r
323 // Initialize the database manager\r
324 //\r
325 StringDBConstructor ();\r
326 //\r
327 // We always try to read in an existing database file. It may not\r
328 // exist, which is ok usually.\r
329 //\r
330 if (mGlobals.NewDatabase == 0) {\r
331 //\r
332 // Read all databases specified.\r
333 //\r
334 for (mGlobals.LastDatabaseFileName = mGlobals.DatabaseFileName;\r
335 mGlobals.LastDatabaseFileName != NULL;\r
336 mGlobals.LastDatabaseFileName = mGlobals.LastDatabaseFileName->Next\r
337 ) {\r
338 Status = StringDBReadDatabase (mGlobals.LastDatabaseFileName->Str, TRUE, mGlobals.VerboseDatabaseRead);\r
339 if (Status != STATUS_SUCCESS) {\r
340 return Status;\r
341 }\r
342 }\r
343 }\r
344 //\r
345 // Read indirection file(s) if specified\r
346 //\r
347 if (ParseIndirectionFiles (mGlobals.IndirectionFileName) != STATUS_SUCCESS) {\r
348 goto Finish;\r
349 }\r
350 //\r
351 // If scanning source files, do that now\r
352 //\r
353 if (mGlobals.Mode == MODE_SCAN) {\r
354 ScanFiles (mGlobals.ScanFileName);\r
355 } else if (mGlobals.Mode == MODE_PARSE) {\r
356 //\r
357 // Parsing a unicode strings file\r
358 //\r
359 mGlobals.SourceFiles.ControlCharacter = DEFAULT_CONTROL_CHARACTER;\r
360 if (mGlobals.OutputDependencyFileName[0] != 0) {\r
361 if ((mGlobals.OutputDependencyFptr = fopen (mGlobals.OutputDependencyFileName, "w")) == NULL) {\r
362 Error (NULL, 0, 0, mGlobals.OutputDependencyFileName, "failed to open output dependency file");\r
363 goto Finish;\r
364 } \r
365 }\r
366 Status = ProcessIncludeFile (&mGlobals.SourceFiles, NULL);\r
367 if (mGlobals.OutputDependencyFptr != NULL) {\r
368 fclose (mGlobals.OutputDependencyFptr);\r
369 } \r
370 if (Status != STATUS_SUCCESS) {\r
371 goto Finish;\r
372 }\r
373 }\r
374 //\r
375 // Create the string defines header file if there have been no errors.\r
376 //\r
377 ParserSetPosition (NULL, 0);\r
378 if ((mGlobals.StringHFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
379 Status = StringDBDumpStringDefines (mGlobals.StringHFileName, mGlobals.BaseName);\r
380 if (Status != EFI_SUCCESS) {\r
381 goto Finish;\r
382 }\r
383 }\r
384 //\r
385 // Dump the strings to a .c file if there have still been no errors.\r
386 //\r
387 if ((mGlobals.StringCFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
388 Status = StringDBDumpCStrings (\r
389 mGlobals.StringCFileName,\r
390 mGlobals.BaseName,\r
391 mGlobals.Language,\r
392 mGlobals.IndirectionList\r
393 );\r
394 if (Status != EFI_SUCCESS) {\r
395 goto Finish;\r
396 }\r
397 }\r
398 //\r
399 // Dump the database if requested\r
400 //\r
401 if ((mGlobals.DumpUFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
402 StringDBDumpDatabase (NULL, mGlobals.DumpUFileName, FALSE);\r
403 }\r
404 //\r
405 // Dump the string data as HII binary string pack if requested\r
406 //\r
407 if ((mGlobals.HiiExportPackFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
408 StringDBCreateHiiExportPack (mGlobals.HiiExportPackFileName);\r
409 }\r
410 //\r
411 // Always update the database if no errors and not in dump mode. If they specified -od\r
412 // for an output database file name, then use that name. Otherwise use the name of\r
413 // the first database file specified with -db\r
414 //\r
415 if ((mGlobals.Mode != MODE_DUMP) && (GetUtilityStatus () < STATUS_ERROR)) {\r
416 if (mGlobals.OutputDatabaseFileName[0]) {\r
417 Status = StringDBWriteDatabase (mGlobals.OutputDatabaseFileName, mGlobals.VerboseDatabaseWrite);\r
418 } else {\r
419 Status = StringDBWriteDatabase (mGlobals.DatabaseFileName->Str, mGlobals.VerboseDatabaseWrite);\r
420 }\r
421\r
422 if (Status != EFI_SUCCESS) {\r
423 goto Finish;\r
424 }\r
425 }\r
426\r
427Finish:\r
428 //\r
429 // Free up memory\r
430 //\r
431 FreeLists ();\r
432 StringDBDestructor ();\r
433 return GetUtilityStatus ();\r
434}\r
435\r
436static\r
437STATUS\r
438ProcessIncludeFile (\r
439 SOURCE_FILE *SourceFile,\r
440 SOURCE_FILE *ParentSourceFile\r
441 )\r
442/*++\r
443\r
444Routine Description:\r
445\r
446 Given a source file, open the file and parse it\r
447 \r
448Arguments:\r
449\r
450 SourceFile - name of file to parse\r
451 ParentSourceFile - for error reporting purposes, the file that #included SourceFile.\r
452\r
453Returns:\r
454\r
455 Standard status.\r
456 \r
457--*/\r
458{\r
459 static UINT32 NestDepth = 0;\r
460 INT8 FoundFileName[MAX_PATH];\r
461 STATUS Status;\r
462\r
463 Status = STATUS_SUCCESS;\r
464 NestDepth++;\r
465 //\r
466 // Print the file being processed. Indent so you can tell the include nesting\r
467 // depth.\r
468 //\r
469 if (mGlobals.Verbose) {\r
470 fprintf (stdout, "%*cProcessing file '%s'\n", NestDepth * 2, ' ', SourceFile->FileName);\r
471 }\r
472\r
473 //\r
474 // Make sure we didn't exceed our maximum nesting depth\r
475 //\r
476 if (NestDepth > MAX_NEST_DEPTH) {\r
477 Error (NULL, 0, 0, SourceFile->FileName, "max nesting depth (%d) exceeded", NestDepth);\r
478 Status = STATUS_ERROR;\r
479 goto Finish;\r
480 }\r
481 //\r
482 // Try to open the file locally, and if that fails try along our include paths.\r
483 //\r
484 strcpy (FoundFileName, SourceFile->FileName);\r
485 if ((SourceFile->Fptr = fopen (FoundFileName, "rb")) == NULL) {\r
486 //\r
487 // Try to find it among the paths if it has a parent (that is, it is included\r
488 // by someone else).\r
489 //\r
490 if (ParentSourceFile == NULL) {\r
491 Error (NULL, 0, 0, SourceFile->FileName, "file not found");\r
492 Status = STATUS_ERROR;\r
493 goto Finish;\r
494 }\r
495\r
496 SourceFile->Fptr = FindFile (SourceFile->FileName, FoundFileName, sizeof (FoundFileName));\r
497 if (SourceFile->Fptr == NULL) {\r
498 Error (ParentSourceFile->FileName, ParentSourceFile->LineNum, 0, SourceFile->FileName, "include file not found");\r
499 Status = STATUS_ERROR;\r
500 goto Finish;\r
501 }\r
502 }\r
503 \r
504 //\r
505 // Output the dependency \r
506 //\r
507 if (mGlobals.OutputDependencyFptr != NULL) {\r
508 fprintf (mGlobals.OutputDependencyFptr, "%s : %s\n", mGlobals.DatabaseFileName->Str, FoundFileName); \r
509 //\r
510 // Add pseudo target to avoid incremental build failure when the file is deleted\r
511 //\r
512 fprintf (mGlobals.OutputDependencyFptr, "%s : \n", FoundFileName); \r
513 }\r
514 \r
515 //\r
516 // Process the file found\r
517 //\r
518 ProcessFile (SourceFile);\r
519\r
520Finish:\r
521 NestDepth--;\r
522 //\r
523 // Close open files and return status\r
524 //\r
525 if (SourceFile->Fptr != NULL) {\r
526 fclose (SourceFile->Fptr);\r
527 }\r
528\r
529 return Status;\r
530}\r
531\r
532static\r
533STATUS\r
534ProcessFile (\r
535 SOURCE_FILE *SourceFile\r
536 )\r
537{\r
538 //\r
539 // Get the file size, and then read the entire thing into memory.\r
540 // Allocate space for a terminator character.\r
541 //\r
542 fseek (SourceFile->Fptr, 0, SEEK_END);\r
543 SourceFile->FileSize = ftell (SourceFile->Fptr);\r
544 fseek (SourceFile->Fptr, 0, SEEK_SET);\r
545 SourceFile->FileBuffer = (WCHAR *) malloc (SourceFile->FileSize + sizeof (WCHAR));\r
546 if (SourceFile->FileBuffer == NULL) {\r
547 Error (NULL, 0, 0, "memory allocation failure", NULL);\r
548 return STATUS_ERROR;\r
549 }\r
550\r
551 fread ((VOID *) SourceFile->FileBuffer, SourceFile->FileSize, 1, SourceFile->Fptr);\r
552 SourceFile->FileBuffer[(SourceFile->FileSize / sizeof (WCHAR))] = UNICODE_NULL;\r
553 //\r
554 // Pre-process the file to replace comments with spaces\r
555 //\r
556 PreprocessFile (SourceFile);\r
557 //\r
558 // Parse the file\r
559 //\r
560 ParseFile (SourceFile);\r
561 free (SourceFile->FileBuffer);\r
562 return STATUS_SUCCESS;\r
563}\r
564\r
565static\r
566STATUS\r
567ParseFile (\r
568 SOURCE_FILE *SourceFile\r
569 )\r
570{\r
571 BOOLEAN InComment;\r
572 UINT32 Len;\r
573\r
574 //\r
575 // First character of a unicode file is special. Make sure\r
576 //\r
577 if (SourceFile->FileBufferPtr[0] != UNICODE_FILE_START) {\r
578 Error (SourceFile->FileName, 1, 0, SourceFile->FileName, "file does not appear to be a unicode file");\r
579 return STATUS_ERROR;\r
580 }\r
581\r
582 SourceFile->FileBufferPtr++;\r
583 InComment = FALSE;\r
584 //\r
585 // Print the first line if in verbose mode\r
586 //\r
587 if (mGlobals.Verbose) {\r
588 printf ("%d: %S\n", SourceFile->LineNum, SourceFile->FileBufferPtr);\r
589 }\r
590 //\r
591 // Since the syntax is relatively straightforward, just switch on the next char\r
592 //\r
593 while (!EndOfFile (SourceFile)) {\r
594 //\r
595 // Check for whitespace\r
596 //\r
597 if (SourceFile->FileBufferPtr[0] == UNICODE_SPACE) {\r
598 SourceFile->FileBufferPtr++;\r
599 } else if (SourceFile->FileBufferPtr[0] == UNICODE_TAB) {\r
600 SourceFile->FileBufferPtr++;\r
601 } else if (SourceFile->FileBufferPtr[0] == UNICODE_CR) {\r
602 SourceFile->FileBufferPtr++;\r
603 } else if (SourceFile->FileBufferPtr[0] == UNICODE_LF) {\r
604 SourceFile->FileBufferPtr++;\r
605 SourceFile->LineNum++;\r
606 if (mGlobals.Verbose) {\r
607 printf ("%d: %S\n", SourceFile->LineNum, SourceFile->FileBufferPtr);\r
608 }\r
609\r
610 InComment = FALSE;\r
611 } else if (SourceFile->FileBufferPtr[0] == 0) {\r
612 SourceFile->FileBufferPtr++;\r
613 } else if (InComment) {\r
614 SourceFile->FileBufferPtr++;\r
615 } else if ((SourceFile->FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile->FileBufferPtr[1] == UNICODE_SLASH)) {\r
616 SourceFile->FileBufferPtr += 2;\r
617 InComment = TRUE;\r
618 } else if (SourceFile->SkipToHash && (SourceFile->FileBufferPtr[0] != SourceFile->ControlCharacter)) {\r
619 SourceFile->FileBufferPtr++;\r
620 } else {\r
621 SourceFile->SkipToHash = FALSE;\r
622 if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
623 ((Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"include")) > 0)\r
624 ) {\r
625 SourceFile->FileBufferPtr += Len + 1;\r
626 ProcessTokenInclude (SourceFile);\r
627 } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
628 (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"scope")) > 0\r
629 ) {\r
630 SourceFile->FileBufferPtr += Len + 1;\r
631 ProcessTokenScope (SourceFile);\r
632 } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
633 (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"language")) > 0\r
634 ) {\r
635 SourceFile->FileBufferPtr += Len + 1;\r
636 ProcessTokenLanguage (SourceFile);\r
637 } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
638 (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"langdef")) > 0\r
639 ) {\r
640 SourceFile->FileBufferPtr += Len + 1;\r
641 ProcessTokenLangDef (SourceFile);\r
642 } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
643 (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"string")) > 0\r
644 ) {\r
645 SourceFile->FileBufferPtr += Len + 1;\r
646 ProcessTokenString (SourceFile);\r
647 } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
648 (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"EFI_BREAKPOINT()")) > 0\r
649 ) {\r
650 SourceFile->FileBufferPtr += Len;\r
651 EFI_BREAKPOINT ();\r
652 } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
653 (SourceFile->FileBufferPtr[1] == UNICODE_EQUAL_SIGN)\r
654 ) {\r
655 SourceFile->ControlCharacter = SourceFile->FileBufferPtr[2];\r
656 SourceFile->FileBufferPtr += 3;\r
657 } else {\r
658 Error (SourceFile->FileName, SourceFile->LineNum, 0, "unrecognized token", "%S", SourceFile->FileBufferPtr);\r
659 //\r
660 // Treat rest of line as a comment.\r
661 //\r
662 InComment = TRUE;\r
663 }\r
664 }\r
665 }\r
666\r
667 return STATUS_SUCCESS;\r
668}\r
669\r
670static\r
671void\r
672PreprocessFile (\r
673 SOURCE_FILE *SourceFile\r
674 )\r
675/*++\r
676\r
677Routine Description:\r
678 Preprocess a file to replace all carriage returns with NULLs so\r
679 we can print lines from the file to the screen.\r
680 \r
681Arguments:\r
682 SourceFile - structure that we use to keep track of an input file.\r
683\r
684Returns:\r
685 Nothing.\r
686 \r
687--*/\r
688{\r
689 BOOLEAN InComment;\r
690\r
691 RewindFile (SourceFile);\r
692 InComment = FALSE;\r
693 while (!EndOfFile (SourceFile)) {\r
694 //\r
695 // If a line-feed, then no longer in a comment\r
696 //\r
697 if (SourceFile->FileBufferPtr[0] == UNICODE_LF) {\r
698 SourceFile->FileBufferPtr++;\r
699 SourceFile->LineNum++;\r
700 InComment = 0;\r
701 } else if (SourceFile->FileBufferPtr[0] == UNICODE_CR) {\r
702 //\r
703 // Replace all carriage returns with a NULL so we can print stuff\r
704 //\r
705 SourceFile->FileBufferPtr[0] = 0;\r
706 SourceFile->FileBufferPtr++;\r
707 } else if (InComment) {\r
708 SourceFile->FileBufferPtr[0] = UNICODE_SPACE;\r
709 SourceFile->FileBufferPtr++;\r
710 } else if ((SourceFile->FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile->FileBufferPtr[1] == UNICODE_SLASH)) {\r
711 SourceFile->FileBufferPtr += 2;\r
712 InComment = TRUE;\r
713 } else {\r
714 SourceFile->FileBufferPtr++;\r
715 }\r
716 }\r
717 //\r
718 // Could check for end-of-file and still in a comment, but\r
719 // should not be necessary. So just restore the file pointers.\r
720 //\r
721 RewindFile (SourceFile);\r
722}\r
723\r
724static\r
725WCHAR *\r
726GetPrintableLanguageName (\r
727 IN SOURCE_FILE *SourceFile\r
728 )\r
729{\r
730 WCHAR *String;\r
731 WCHAR *Start;\r
732 WCHAR *Ptr;\r
733 UINT32 Len;\r
734\r
735 SkipWhiteSpace (SourceFile);\r
736 if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
737 Error (\r
738 SourceFile->FileName,\r
739 SourceFile->LineNum,\r
740 0,\r
741 "expected quoted printable language name",\r
742 "%S",\r
743 SourceFile->FileBufferPtr\r
744 );\r
745 SourceFile->SkipToHash = TRUE;\r
746 return NULL;\r
747 }\r
748\r
749 Len = 0;\r
750 SourceFile->FileBufferPtr++;\r
751 Start = Ptr = SourceFile->FileBufferPtr;\r
752 while (!EndOfFile (SourceFile)) {\r
753 if (SourceFile->FileBufferPtr[0] == UNICODE_CR) {\r
754 Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start);\r
755 break;\r
756 } else if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {\r
757 break;\r
758 }\r
759\r
760 SourceFile->FileBufferPtr++;\r
761 Len++;\r
762 }\r
763\r
764 if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
765 Warning (\r
766 SourceFile->FileName,\r
767 SourceFile->LineNum,\r
768 0,\r
769 "missing closing quote on printable language name string",\r
770 "%S",\r
771 Start\r
772 );\r
773 } else {\r
774 SourceFile->FileBufferPtr++;\r
775 }\r
776 //\r
777 // Now allocate memory for the string and save it off\r
778 //\r
779 String = (WCHAR *) malloc ((Len + 1) * sizeof (WCHAR));\r
780 if (String == NULL) {\r
781 Error (NULL, 0, 0, "memory allocation failed", NULL);\r
782 return NULL;\r
783 }\r
784 //\r
785 // Copy the string from the file buffer to the local copy.\r
786 // We do no reformatting of it whatsoever at this point.\r
787 //\r
788 Ptr = String;\r
789 while (Len > 0) {\r
790 *Ptr = *Start;\r
791 Start++;\r
792 Ptr++;\r
793 Len--;\r
794 }\r
795\r
796 *Ptr = 0;\r
797 //\r
798 // Now format the string to convert \wide and \narrow controls\r
799 //\r
800 StringDBFormatString (String);\r
801 return String;\r
802}\r
803\r
804static\r
805WCHAR *\r
806GetQuotedString (\r
807 SOURCE_FILE *SourceFile,\r
808 BOOLEAN Optional\r
809 )\r
810{\r
811 WCHAR *String;\r
812 WCHAR *Start;\r
813 WCHAR *Ptr;\r
814 UINT32 Len;\r
815 BOOLEAN PreviousBackslash;\r
816\r
817 if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
818 if (!Optional) {\r
819 Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted string", "%S", SourceFile->FileBufferPtr);\r
820 }\r
821\r
822 return NULL;\r
823 }\r
824\r
825 Len = 0;\r
826 SourceFile->FileBufferPtr++;\r
827 Start = Ptr = SourceFile->FileBufferPtr;\r
828 PreviousBackslash = FALSE;\r
829 while (!EndOfFile (SourceFile)) {\r
830 if ((SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) && (!PreviousBackslash)) {\r
831 break;\r
832 } else if (SourceFile->FileBufferPtr[0] == UNICODE_CR) {\r
833 Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start);\r
834 PreviousBackslash = FALSE;\r
835 } else if (SourceFile->FileBufferPtr[0] == UNICODE_BACKSLASH) {\r
836 PreviousBackslash = TRUE;\r
837 } else {\r
838 PreviousBackslash = FALSE;\r
839 }\r
840\r
841 SourceFile->FileBufferPtr++;\r
842 Len++;\r
843 }\r
844\r
845 if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
846 Warning (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", "%S", Start);\r
847 } else {\r
848 SourceFile->FileBufferPtr++;\r
849 }\r
850 //\r
851 // Now allocate memory for the string and save it off\r
852 //\r
853 String = (WCHAR *) malloc ((Len + 1) * sizeof (WCHAR));\r
854 if (String == NULL) {\r
855 Error (NULL, 0, 0, "memory allocation failed", NULL);\r
856 return NULL;\r
857 }\r
858 //\r
859 // Copy the string from the file buffer to the local copy.\r
860 // We do no reformatting of it whatsoever at this point.\r
861 //\r
862 Ptr = String;\r
863 while (Len > 0) {\r
864 *Ptr = *Start;\r
865 Start++;\r
866 Ptr++;\r
867 Len--;\r
868 }\r
869\r
870 *Ptr = 0;\r
871 return String;\r
872}\r
873//\r
874// Parse:\r
875// #string STR_ID_NAME\r
876//\r
877// All we can do is call the string database to add the string identifier. Unfortunately\r
878// he'll have to keep track of the last identifier we added.\r
879//\r
880static\r
881void\r
882ProcessTokenString (\r
883 SOURCE_FILE *SourceFile\r
884 )\r
885{\r
886 WCHAR StringIdentifier[MAX_STRING_IDENTIFIER_NAME];\r
887 UINT16 StringId;\r
888 //\r
889 // Extract the string identifier name and add it to the database.\r
890 //\r
891 if (GetStringIdentifierName (SourceFile, StringIdentifier, sizeof (StringIdentifier)) > 0) {\r
892 StringId = STRING_ID_INVALID;\r
893 StringDBAddStringIdentifier (StringIdentifier, &StringId, 0);\r
894 } else {\r
895 //\r
896 // Error recovery -- skip to the next #\r
897 //\r
898 SourceFile->SkipToHash = TRUE;\r
899 }\r
900}\r
901\r
902static\r
903BOOLEAN\r
904EndOfFile (\r
905 SOURCE_FILE *SourceFile\r
906 )\r
907{\r
908 //\r
909 // The file buffer pointer will typically get updated before the End-of-file flag in the\r
910 // source file structure, so check it first.\r
911 //\r
912 if (SourceFile->FileBufferPtr >= SourceFile->FileBuffer + SourceFile->FileSize / sizeof (WCHAR)) {\r
913 SourceFile->EndOfFile = TRUE;\r
914 return TRUE;\r
915 }\r
916\r
917 if (SourceFile->EndOfFile) {\r
918 return TRUE;\r
919 }\r
920\r
921 return FALSE;\r
922}\r
923\r
924static\r
925UINT32\r
926GetStringIdentifierName (\r
927 IN SOURCE_FILE *SourceFile,\r
928 IN OUT WCHAR *StringIdentifierName,\r
929 IN UINT32 StringIdentifierNameLen\r
930 )\r
931{\r
932 UINT32 Len;\r
933 WCHAR *From;\r
934 WCHAR *Start;\r
935\r
936 //\r
937 // Skip whitespace\r
938 //\r
939 SkipWhiteSpace (SourceFile);\r
940 if (SourceFile->EndOfFile) {\r
941 Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-file encountered", "expected string identifier");\r
942 return 0;\r
943 }\r
944 //\r
945 // Verify first character of name is [A-Za-z]\r
946 //\r
947 Len = 0;\r
948 StringIdentifierNameLen /= 2;\r
949 From = SourceFile->FileBufferPtr;\r
950 Start = SourceFile->FileBufferPtr;\r
951 if (((SourceFile->FileBufferPtr[0] >= UNICODE_A) && (SourceFile->FileBufferPtr[0] <= UNICODE_Z)) ||\r
952 ((SourceFile->FileBufferPtr[0] >= UNICODE_z) && (SourceFile->FileBufferPtr[0] <= UNICODE_z))\r
953 ) {\r
954 //\r
955 // Do nothing\r
956 //\r
957 } else {\r
958 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid character in string identifier name", "%S", Start);\r
959 return 0;\r
960 }\r
961\r
962 while (!EndOfFile (SourceFile)) {\r
963 if (((SourceFile->FileBufferPtr[0] >= UNICODE_A) && (SourceFile->FileBufferPtr[0] <= UNICODE_Z)) ||\r
964 ((SourceFile->FileBufferPtr[0] >= UNICODE_z) && (SourceFile->FileBufferPtr[0] <= UNICODE_z)) ||\r
965 ((SourceFile->FileBufferPtr[0] >= UNICODE_0) && (SourceFile->FileBufferPtr[0] <= UNICODE_9)) ||\r
966 (SourceFile->FileBufferPtr[0] == UNICODE_UNDERSCORE)\r
967 ) {\r
968 Len++;\r
969 if (Len >= StringIdentifierNameLen) {\r
970 Error (SourceFile->FileName, SourceFile->LineNum, 0, "string identifier name too long", "%S", Start);\r
971 return 0;\r
972 }\r
973\r
974 *StringIdentifierName = SourceFile->FileBufferPtr[0];\r
975 StringIdentifierName++;\r
976 SourceFile->FileBufferPtr++;\r
977 } else if (SkipWhiteSpace (SourceFile) == 0) {\r
978 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid string identifier name", "%S", Start);\r
979 return 0;\r
980 } else {\r
981 break;\r
982 }\r
983 }\r
984 //\r
985 // Terminate the copy of the string.\r
986 //\r
987 *StringIdentifierName = 0;\r
988 return Len;\r
989}\r
990\r
991static\r
992UINT32\r
993GetLanguageIdentifierName (\r
994 IN SOURCE_FILE *SourceFile,\r
995 IN OUT WCHAR *LanguageIdentifierName,\r
996 IN UINT32 LanguageIdentifierNameLen,\r
997 IN BOOLEAN Optional\r
998 )\r
999{\r
1000 UINT32 Len;\r
1001 WCHAR *From;\r
1002 WCHAR *Start;\r
1003 //\r
1004 // Skip whitespace\r
1005 //\r
1006 SkipWhiteSpace (SourceFile);\r
1007 if (SourceFile->EndOfFile) {\r
1008 if (!Optional) {\r
1009 Error (\r
1010 SourceFile->FileName,\r
1011 SourceFile->LineNum,\r
1012 0,\r
1013 "end-of-file encountered",\r
1014 "expected language identifier"\r
1015 );\r
1016 }\r
1017\r
1018 return 0;\r
1019 }\r
1020 //\r
1021 // This function is called to optionally get a language identifier name in:\r
1022 // #string STR_ID eng "the string"\r
1023 // If it's optional, and we find a double-quote, then return now.\r
1024 //\r
1025 if (Optional) {\r
1026 if (*SourceFile->FileBufferPtr == UNICODE_DOUBLE_QUOTE) {\r
1027 return 0;\r
1028 }\r
1029 }\r
1030\r
1031 Len = 0;\r
1032 LanguageIdentifierNameLen /= 2;\r
1033 //\r
1034 // Internal error if we weren't given at least 4 WCHAR's to work with.\r
1035 //\r
1036 if (LanguageIdentifierNameLen < LANGUAGE_IDENTIFIER_NAME_LEN + 1) {\r
1037 Error (\r
1038 SourceFile->FileName,\r
1039 SourceFile->LineNum,\r
1040 0,\r
1041 "app error -- language identifier name length is invalid",\r
1042 NULL\r
1043 );\r
1044 }\r
1045\r
1046 From = SourceFile->FileBufferPtr;\r
1047 Start = SourceFile->FileBufferPtr;\r
1048 while (!EndOfFile (SourceFile)) {\r
1049 if (((SourceFile->FileBufferPtr[0] >= UNICODE_a) && (SourceFile->FileBufferPtr[0] <= UNICODE_z))) {\r
1050 Len++;\r
1051 if (Len > LANGUAGE_IDENTIFIER_NAME_LEN) {\r
1052 Error (SourceFile->FileName, SourceFile->LineNum, 0, "language identifier name too long", "%S", Start);\r
1053 return 0;\r
1054 }\r
1055\r
1056 *LanguageIdentifierName = SourceFile->FileBufferPtr[0];\r
1057 SourceFile->FileBufferPtr++;\r
1058 LanguageIdentifierName++;\r
1059 } else if (!IsWhiteSpace (SourceFile)) {\r
1060 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid language identifier name", "%S", Start);\r
1061 return 0;\r
1062 } else {\r
1063 break;\r
1064 }\r
1065 }\r
1066 //\r
1067 // Terminate the copy of the string.\r
1068 //\r
1069 *LanguageIdentifierName = 0;\r
1070 return Len;\r
1071}\r
1072\r
1073static\r
1074void\r
1075ProcessTokenInclude (\r
1076 SOURCE_FILE *SourceFile\r
1077 )\r
1078{\r
1079 INT8 IncludeFileName[MAX_PATH];\r
1080 INT8 *To;\r
1081 UINT32 Len;\r
1082 BOOLEAN ReportedError;\r
1083 SOURCE_FILE IncludedSourceFile;\r
1084\r
1085 ReportedError = FALSE;\r
1086 if (SkipWhiteSpace (SourceFile) == 0) {\r
1087 Warning (SourceFile->FileName, SourceFile->LineNum, 0, "expected whitespace following #include keyword", NULL);\r
1088 }\r
1089 //\r
1090 // Should be quoted file name\r
1091 //\r
1092 if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
1093 Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted include file name", NULL);\r
1094 goto FailDone;\r
1095 }\r
1096\r
1097 SourceFile->FileBufferPtr++;\r
1098 //\r
1099 // Copy the filename as ascii to our local string\r
1100 //\r
1101 To = IncludeFileName;\r
1102 Len = 0;\r
1103 while (!EndOfFile (SourceFile)) {\r
1104 if ((SourceFile->FileBufferPtr[0] == UNICODE_CR) || (SourceFile->FileBufferPtr[0] == UNICODE_LF)) {\r
1105 Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-line found in quoted include file name", NULL);\r
1106 goto FailDone;\r
1107 }\r
1108\r
1109 if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {\r
1110 SourceFile->FileBufferPtr++;\r
1111 break;\r
1112 }\r
1113 //\r
1114 // If too long, then report the error once and process until the closing quote\r
1115 //\r
1116 Len++;\r
1117 if (!ReportedError && (Len >= sizeof (IncludeFileName))) {\r
1118 Error (SourceFile->FileName, SourceFile->LineNum, 0, "length of include file name exceeds limit", NULL);\r
1119 ReportedError = TRUE;\r
1120 }\r
1121\r
1122 if (!ReportedError) {\r
1123 *To = UNICODE_TO_ASCII (SourceFile->FileBufferPtr[0]);\r
1124 To++;\r
1125 }\r
1126\r
1127 SourceFile->FileBufferPtr++;\r
1128 }\r
1129\r
1130 if (!ReportedError) {\r
1131 *To = 0;\r
1132 memset ((char *) &IncludedSourceFile, 0, sizeof (SOURCE_FILE));\r
1133 strcpy (IncludedSourceFile.FileName, IncludeFileName);\r
1134 IncludedSourceFile.ControlCharacter = DEFAULT_CONTROL_CHARACTER;\r
1135 ProcessIncludeFile (&IncludedSourceFile, SourceFile);\r
1136 //\r
1137 // printf ("including file '%s'\n", IncludeFileName);\r
1138 //\r
1139 }\r
1140\r
1141 return ;\r
1142FailDone:\r
1143 //\r
1144 // Error recovery -- skip to next #\r
1145 //\r
1146 SourceFile->SkipToHash = TRUE;\r
1147}\r
1148\r
1149static\r
1150void\r
1151ProcessTokenScope (\r
1152 SOURCE_FILE *SourceFile\r
1153 )\r
1154{\r
1155 WCHAR StringIdentifier[MAX_STRING_IDENTIFIER_NAME];\r
1156 //\r
1157 // Extract the scope name\r
1158 //\r
1159 if (GetStringIdentifierName (SourceFile, StringIdentifier, sizeof (StringIdentifier)) > 0) {\r
1160 StringDBSetScope (StringIdentifier);\r
1161 }\r
1162}\r
1163//\r
1164// Parse: #langdef eng "English"\r
1165// #langdef chn "\wideChinese"\r
1166//\r
1167static\r
1168void\r
1169ProcessTokenLangDef (\r
1170 SOURCE_FILE *SourceFile\r
1171 )\r
1172{\r
1173 WCHAR LanguageIdentifier[MAX_STRING_IDENTIFIER_NAME];\r
1174 UINT32 Len;\r
1175 WCHAR *PrintableName;\r
1176 //\r
1177 // Extract the 3-character language identifier\r
1178 //\r
1179 Len = GetLanguageIdentifierName (SourceFile, LanguageIdentifier, sizeof (LanguageIdentifier), FALSE);\r
1180 if (Len != LANGUAGE_IDENTIFIER_NAME_LEN) {\r
1181 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid or missing language identifier", NULL);\r
1182 } else {\r
1183 //\r
1184 // Extract the printable name\r
1185 //\r
1186 PrintableName = GetPrintableLanguageName (SourceFile);\r
1187 if (PrintableName != NULL) {\r
1188 ParserSetPosition (SourceFile->FileName, SourceFile->LineNum);\r
1189 StringDBAddLanguage (LanguageIdentifier, PrintableName);\r
1190 free (PrintableName);\r
1191 return ;\r
1192 }\r
1193 }\r
1194 //\r
1195 // Error recovery -- skip to next #\r
1196 //\r
1197 SourceFile->SkipToHash = TRUE;\r
1198}\r
1199\r
1200static\r
1201BOOLEAN\r
1202ApparentQuotedString (\r
1203 SOURCE_FILE *SourceFile\r
1204 )\r
1205{\r
1206 WCHAR *Ptr;\r
1207 //\r
1208 // See if the first and last nonblank characters on the line are double quotes\r
1209 //\r
1210 for (Ptr = SourceFile->FileBufferPtr; *Ptr && (*Ptr == UNICODE_SPACE); Ptr++)\r
1211 ;\r
1212 if (*Ptr != UNICODE_DOUBLE_QUOTE) {\r
1213 return FALSE;\r
1214 }\r
1215\r
1216 while (*Ptr) {\r
1217 Ptr++;\r
1218 }\r
1219\r
1220 Ptr--;\r
1221 for (; *Ptr && (*Ptr == UNICODE_SPACE); Ptr--)\r
1222 ;\r
1223 if (*Ptr != UNICODE_DOUBLE_QUOTE) {\r
1224 return FALSE;\r
1225 }\r
1226\r
1227 return TRUE;\r
1228}\r
1229//\r
1230// Parse:\r
1231// #language eng "some string " "more string"\r
1232//\r
1233static\r
1234void\r
1235ProcessTokenLanguage (\r
1236 SOURCE_FILE *SourceFile\r
1237 )\r
1238{\r
1239 WCHAR *String;\r
1240 WCHAR *SecondString;\r
1241 WCHAR *TempString;\r
1242 WCHAR *From;\r
1243 WCHAR *To;\r
1244 WCHAR Language[LANGUAGE_IDENTIFIER_NAME_LEN + 1];\r
1245 UINT32 Len;\r
1246 BOOLEAN PreviousNewline;\r
1247 //\r
1248 // Get the language identifier\r
1249 //\r
1250 Language[0] = 0;\r
1251 Len = GetLanguageIdentifierName (SourceFile, Language, sizeof (Language), TRUE);\r
1252 if (Len != LANGUAGE_IDENTIFIER_NAME_LEN) {\r
1253 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid or missing language identifier", "%S", Language);\r
1254 SourceFile->SkipToHash = TRUE;\r
1255 return ;\r
1256 }\r
1257 //\r
1258 // Extract the string value. It's either a quoted string that starts on the current line, or\r
1259 // an unquoted string that starts on the following line and continues until the next control\r
1260 // character in column 1.\r
1261 // Look ahead to find a quote or a newline\r
1262 //\r
1263 if (SkipTo (SourceFile, UNICODE_DOUBLE_QUOTE, TRUE)) {\r
1264 String = GetQuotedString (SourceFile, FALSE);\r
1265 if (String != NULL) {\r
1266 //\r
1267 // Set the position in the file of where we are parsing for error\r
1268 // reporting purposes. Then start looking ahead for additional\r
1269 // quoted strings, and concatenate them until we get a failure\r
1270 // back from the string parser.\r
1271 //\r
1272 Len = wcslen (String) + 1;\r
1273 ParserSetPosition (SourceFile->FileName, SourceFile->LineNum);\r
1274 do {\r
1275 SkipWhiteSpace (SourceFile);\r
1276 SecondString = GetQuotedString (SourceFile, TRUE);\r
1277 if (SecondString != NULL) {\r
1278 Len += wcslen (SecondString);\r
1279 TempString = (WCHAR *) malloc (Len * sizeof (WCHAR));\r
1280 if (TempString == NULL) {\r
1281 Error (NULL, 0, 0, "application error", "failed to allocate memory");\r
1282 return ;\r
1283 }\r
1284\r
1285 wcscpy (TempString, String);\r
1286 wcscat (TempString, SecondString);\r
1287 free (String);\r
1288 free (SecondString);\r
1289 String = TempString;\r
1290 }\r
1291 } while (SecondString != NULL);\r
1292 StringDBAddString (Language, NULL, NULL, String, TRUE, 0);\r
1293 free (String);\r
1294 } else {\r
1295 //\r
1296 // Error was reported at lower level. Error recovery mode.\r
1297 //\r
1298 SourceFile->SkipToHash = TRUE;\r
1299 }\r
1300 } else {\r
1301 if (!mGlobals.UnquotedStrings) {\r
1302 //\r
1303 // They're using unquoted strings. If the next non-blank character is a double quote, and the\r
1304 // last non-blank character on the line is a double quote, then more than likely they're using\r
1305 // quotes, so they need to put the quoted string on the end of the previous line\r
1306 //\r
1307 if (ApparentQuotedString (SourceFile)) {\r
1308 Warning (\r
1309 SourceFile->FileName,\r
1310 SourceFile->LineNum,\r
1311 0,\r
1312 "unexpected quoted string on line",\r
1313 "specify -uqs option if necessary"\r
1314 );\r
1315 }\r
1316 }\r
1317 //\r
1318 // Found end-of-line (hopefully). Skip over it and start taking in characters\r
1319 // until we find a control character at the start of a line.\r
1320 //\r
1321 Len = 0;\r
1322 From = SourceFile->FileBufferPtr;\r
1323 PreviousNewline = FALSE;\r
1324 while (!EndOfFile (SourceFile)) {\r
1325 if (SourceFile->FileBufferPtr[0] == UNICODE_LF) {\r
1326 PreviousNewline = TRUE;\r
1327 SourceFile->LineNum++;\r
1328 } else {\r
1329 Len++;\r
1330 if (PreviousNewline && (SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter)) {\r
1331 break;\r
1332 }\r
1333\r
1334 PreviousNewline = FALSE;\r
1335 }\r
1336\r
1337 SourceFile->FileBufferPtr++;\r
1338 }\r
1339\r
1340 if ((Len == 0) && EndOfFile (SourceFile)) {\r
1341 Error (SourceFile->FileName, SourceFile->LineNum, 0, "unexpected end of file", NULL);\r
1342 SourceFile->SkipToHash = TRUE;\r
1343 return ;\r
1344 }\r
1345 //\r
1346 // Now allocate a buffer, copy the characters, and add the string.\r
1347 //\r
1348 String = (WCHAR *) malloc ((Len + 1) * sizeof (WCHAR));\r
1349 if (String == NULL) {\r
1350 Error (NULL, 0, 0, "application error", "failed to allocate memory");\r
1351 return ;\r
1352 }\r
1353\r
1354 To = String;\r
1355 while (From < SourceFile->FileBufferPtr) {\r
1356 switch (*From) {\r
1357 case UNICODE_LF:\r
1358 case 0:\r
1359 break;\r
1360\r
1361 default:\r
1362 *To = *From;\r
1363 To++;\r
1364 break;\r
1365 }\r
1366\r
1367 From++;\r
1368 }\r
1369\r
1370 //\r
1371 // String[Len] = 0;\r
1372 //\r
1373 *To = 0;\r
1374 StringDBAddString (Language, NULL, NULL, String, TRUE, 0);\r
1375 }\r
1376}\r
1377\r
1378static\r
1379BOOLEAN\r
1380IsWhiteSpace (\r
1381 SOURCE_FILE *SourceFile\r
1382 )\r
1383{\r
1384 switch (SourceFile->FileBufferPtr[0]) {\r
1385 case UNICODE_NULL:\r
1386 case UNICODE_CR:\r
1387 case UNICODE_SPACE:\r
1388 case UNICODE_TAB:\r
1389 case UNICODE_LF:\r
1390 return TRUE;\r
1391\r
1392 default:\r
1393 return FALSE;\r
1394 }\r
1395}\r
1396\r
1397static\r
1398UINT32\r
1399SkipWhiteSpace (\r
1400 SOURCE_FILE *SourceFile\r
1401 )\r
1402{\r
1403 UINT32 Count;\r
1404\r
1405 Count = 0;\r
1406 while (!EndOfFile (SourceFile)) {\r
1407 Count++;\r
1408 switch (*SourceFile->FileBufferPtr) {\r
1409 case UNICODE_NULL:\r
1410 case UNICODE_CR:\r
1411 case UNICODE_SPACE:\r
1412 case UNICODE_TAB:\r
1413 SourceFile->FileBufferPtr++;\r
1414 break;\r
1415\r
1416 case UNICODE_LF:\r
1417 SourceFile->FileBufferPtr++;\r
1418 SourceFile->LineNum++;\r
1419 if (mGlobals.Verbose) {\r
1420 printf ("%d: %S\n", SourceFile->LineNum, SourceFile->FileBufferPtr);\r
1421 }\r
1422 break;\r
1423\r
1424 default:\r
1425 return Count - 1;\r
1426 }\r
1427 }\r
1428 //\r
1429 // Some tokens require trailing whitespace. If we're at the end of the\r
1430 // file, then we count that as well.\r
1431 //\r
1432 if ((Count == 0) && (EndOfFile (SourceFile))) {\r
1433 Count++;\r
1434 }\r
1435\r
1436 return Count;\r
1437}\r
1438\r
1439static\r
1440UINT32\r
1441wstrcmp (\r
1442 WCHAR *Buffer,\r
1443 WCHAR *Str\r
1444 )\r
1445{\r
1446 UINT32 Len;\r
1447\r
1448 Len = 0;\r
1449 while (*Str == *Buffer) {\r
1450 Buffer++;\r
1451 Str++;\r
1452 Len++;\r
1453 }\r
1454\r
1455 if (*Str) {\r
1456 return 0;\r
1457 }\r
1458\r
1459 return Len;\r
1460}\r
1461//\r
1462// Given a filename, try to find it along the include paths.\r
1463//\r
1464static\r
1465FILE *\r
1466FindFile (\r
1467 IN INT8 *FileName,\r
1468 OUT INT8 *FoundFileName,\r
1469 IN UINT32 FoundFileNameLen\r
1470 )\r
1471{\r
1472 FILE *Fptr;\r
1473 TEXT_STRING_LIST *List;\r
1474\r
1475 //\r
1476 // Traverse the list of paths and try to find the file\r
1477 //\r
1478 List = mGlobals.IncludePaths;\r
1479 while (List != NULL) {\r
1480 //\r
1481 // Put the path and filename together\r
1482 //\r
1483 if (strlen (List->Str) + strlen (FileName) + 1 > FoundFileNameLen) {\r
1484 Error (PROGRAM_NAME, 0, 0, NULL, "internal error - cannot concatenate path+filename");\r
1485 return NULL;\r
1486 }\r
1487 //\r
1488 // Append the filename to this include path and try to open the file.\r
1489 //\r
1490 strcpy (FoundFileName, List->Str);\r
1491 strcat (FoundFileName, FileName);\r
1492 if ((Fptr = fopen (FoundFileName, "rb")) != NULL) {\r
1493 //\r
1494 // Return the file pointer\r
1495 //\r
1496 return Fptr;\r
1497 }\r
1498\r
1499 List = List->Next;\r
1500 }\r
1501 //\r
1502 // Not found\r
1503 //\r
1504 FoundFileName[0] = 0;\r
1505 return NULL;\r
1506}\r
1507//\r
1508// Process the command-line arguments\r
1509//\r
1510static\r
1511STATUS\r
1512ProcessArgs (\r
1513 int Argc,\r
1514 char *Argv[]\r
1515 )\r
1516{\r
1517 TEXT_STRING_LIST *NewList;\r
1518 //\r
1519 // Clear our globals\r
1520 //\r
1521 memset ((char *) &mGlobals, 0, sizeof (mGlobals));\r
1522 strcpy (mGlobals.BaseName, DEFAULT_BASE_NAME);\r
1523 //\r
1524 // Skip program name\r
1525 //\r
1526 Argc--;\r
1527 Argv++;\r
1528\r
1529 if (Argc == 0) {\r
1530 Usage ();\r
1531 return STATUS_ERROR;\r
1532 }\r
1533\r
1534 mGlobals.Mode = MODE_UNKNOWN;\r
1535 //\r
1536 // Process until no more -args.\r
1537 //\r
1538 while ((Argc > 0) && (Argv[0][0] == '-')) {\r
1539 //\r
1540 // -parse option\r
1541 //\r
1542 if (_stricmp (Argv[0], "-parse") == 0) {\r
1543 if (mGlobals.Mode != MODE_UNKNOWN) {\r
1544 Error (NULL, 0, 0, "only one of -parse/-scan/-dump allowed", NULL);\r
1545 return STATUS_ERROR;\r
1546 }\r
1547\r
1548 mGlobals.Mode = MODE_PARSE;\r
1549 //\r
1550 // -scan option\r
1551 //\r
1552 } else if (_stricmp (Argv[0], "-scan") == 0) {\r
1553 if (mGlobals.Mode != MODE_UNKNOWN) {\r
1554 Error (NULL, 0, 0, "only one of -parse/-scan/-dump allowed", NULL);\r
1555 return STATUS_ERROR;\r
1556 }\r
1557\r
1558 mGlobals.Mode = MODE_SCAN;\r
1559 //\r
1560 // -vscan verbose scanning option\r
1561 //\r
1562 } else if (_stricmp (Argv[0], "-vscan") == 0) {\r
1563 mGlobals.VerboseScan = TRUE;\r
1564 //\r
1565 // -dump option\r
1566 //\r
1567 } else if (_stricmp (Argv[0], "-dump") == 0) {\r
1568 if (mGlobals.Mode != MODE_UNKNOWN) {\r
1569 Error (NULL, 0, 0, "only one of -parse/-scan/-dump allowed", NULL);\r
1570 return STATUS_ERROR;\r
1571 }\r
1572\r
1573 mGlobals.Mode = MODE_DUMP;\r
1574 } else if (_stricmp (Argv[0], "-uqs") == 0) {\r
1575 mGlobals.UnquotedStrings = TRUE;\r
1576 //\r
1577 // -i path add include search path when parsing\r
1578 //\r
1579 } else if (_stricmp (Argv[0], "-i") == 0) {\r
1580 //\r
1581 // check for one more arg\r
1582 //\r
1583 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1584 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing include path");\r
1585 return STATUS_ERROR;\r
1586 }\r
1587 //\r
1588 // Allocate memory for a new list element, fill it in, and\r
1589 // add it to our list of include paths. Always make sure it\r
1590 // has a "\" on the end of it.\r
1591 //\r
1592 NewList = malloc (sizeof (TEXT_STRING_LIST));\r
1593 if (NewList == NULL) {\r
1594 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1595 return STATUS_ERROR;\r
1596 }\r
1597\r
1598 memset ((char *) NewList, 0, sizeof (TEXT_STRING_LIST));\r
1599 NewList->Str = malloc (strlen (Argv[1]) + 2);\r
1600 if (NewList->Str == NULL) {\r
1601 free (NewList);\r
1602 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1603 return STATUS_ERROR;\r
1604 }\r
1605\r
1606 strcpy (NewList->Str, Argv[1]);\r
1607 if (NewList->Str[strlen (NewList->Str) - 1] != '\\') {\r
1608 strcat (NewList->Str, "\\");\r
1609 }\r
1610 //\r
1611 // Add it to our linked list\r
1612 //\r
1613 if (mGlobals.IncludePaths == NULL) {\r
1614 mGlobals.IncludePaths = NewList;\r
1615 } else {\r
1616 mGlobals.LastIncludePath->Next = NewList;\r
1617 }\r
1618\r
1619 mGlobals.LastIncludePath = NewList;\r
1620 Argc--;\r
1621 Argv++;\r
1622 } else if (_stricmp (Argv[0], "-if") == 0) {\r
1623 //\r
1624 // Indirection file -- check for one more arg\r
1625 //\r
1626 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1627 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing indirection file name");\r
1628 return STATUS_ERROR;\r
1629 }\r
1630 //\r
1631 // Allocate memory for a new list element, fill it in, and\r
1632 // add it to our list of include paths. Always make sure it\r
1633 // has a "\" on the end of it.\r
1634 //\r
1635 NewList = malloc (sizeof (TEXT_STRING_LIST));\r
1636 if (NewList == NULL) {\r
1637 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1638 return STATUS_ERROR;\r
1639 }\r
1640\r
1641 memset ((char *) NewList, 0, sizeof (TEXT_STRING_LIST));\r
1642 NewList->Str = malloc (strlen (Argv[1]) + 1);\r
1643 if (NewList->Str == NULL) {\r
1644 free (NewList);\r
1645 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1646 return STATUS_ERROR;\r
1647 }\r
1648\r
1649 strcpy (NewList->Str, Argv[1]);\r
1650 //\r
1651 // Add it to our linked list\r
1652 //\r
1653 if (mGlobals.IndirectionFileName == NULL) {\r
1654 mGlobals.IndirectionFileName = NewList;\r
1655 } else {\r
1656 mGlobals.LastIndirectionFileName->Next = NewList;\r
1657 }\r
1658\r
1659 mGlobals.LastIndirectionFileName = NewList;\r
1660 Argc--;\r
1661 Argv++;\r
1662 } else if (_stricmp (Argv[0], "-db") == 0) {\r
1663 //\r
1664 // -db option to specify a database file.\r
1665 // Check for one more arg (the database file name)\r
1666 //\r
1667 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1668 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing database file name");\r
1669 return STATUS_ERROR;\r
1670 }\r
1671\r
1672 NewList = malloc (sizeof (TEXT_STRING_LIST));\r
1673 if (NewList == NULL) {\r
1674 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1675 return STATUS_ERROR;\r
1676 }\r
1677\r
1678 memset ((char *) NewList, 0, sizeof (TEXT_STRING_LIST));\r
1679 NewList->Str = malloc (strlen (Argv[1]) + 1);\r
1680 if (NewList->Str == NULL) {\r
1681 free (NewList);\r
1682 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1683 return STATUS_ERROR;\r
1684 }\r
1685\r
1686 strcpy (NewList->Str, Argv[1]);\r
1687 //\r
1688 // Add it to our linked list\r
1689 //\r
1690 if (mGlobals.DatabaseFileName == NULL) {\r
1691 mGlobals.DatabaseFileName = NewList;\r
1692 } else {\r
1693 mGlobals.LastDatabaseFileName->Next = NewList;\r
1694 }\r
1695\r
1696 mGlobals.LastDatabaseFileName = NewList;\r
1697 Argc--;\r
1698 Argv++;\r
1699 } else if (_stricmp (Argv[0], "-ou") == 0) {\r
1700 //\r
1701 // -ou option to specify an output unicode file to\r
1702 // which we can dump our database.\r
1703 //\r
1704 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1705 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing database dump output file name");\r
1706 return STATUS_ERROR;\r
1707 }\r
1708\r
1709 if (mGlobals.DumpUFileName[0] == 0) {\r
1710 strcpy (mGlobals.DumpUFileName, Argv[1]);\r
1711 } else {\r
1712 Error (PROGRAM_NAME, 0, 0, Argv[1], "-ou option already specified with '%s'", mGlobals.DumpUFileName);\r
1713 return STATUS_ERROR;\r
1714 }\r
1715\r
1716 Argc--;\r
1717 Argv++;\r
1718 } else if (_stricmp (Argv[0], "-hpk") == 0) {\r
1719 //\r
1720 // -hpk option to create an HII export pack of the input database file\r
1721 //\r
1722 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1723 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing raw string data dump output file name");\r
1724 return STATUS_ERROR;\r
1725 }\r
1726\r
1727 if (mGlobals.HiiExportPackFileName[0] == 0) {\r
1728 strcpy (mGlobals.HiiExportPackFileName, Argv[1]);\r
1729 } else {\r
1730 Error (PROGRAM_NAME, 0, 0, Argv[1], "-or option already specified with '%s'", mGlobals.HiiExportPackFileName);\r
1731 return STATUS_ERROR;\r
1732 }\r
1733\r
1734 Argc--;\r
1735 Argv++;\r
1736 } else if ((_stricmp (Argv[0], "-?") == 0) || (_stricmp (Argv[0], "-h") == 0)) {\r
1737 Usage ();\r
1738 return STATUS_ERROR;\r
1739 } else if (_stricmp (Argv[0], "-v") == 0) {\r
1740 mGlobals.Verbose = 1;\r
1741 } else if (_stricmp (Argv[0], "-vdbw") == 0) {\r
1742 mGlobals.VerboseDatabaseWrite = 1;\r
1743 } else if (_stricmp (Argv[0], "-vdbr") == 0) {\r
1744 mGlobals.VerboseDatabaseRead = 1;\r
1745 } else if (_stricmp (Argv[0], "-newdb") == 0) {\r
1746 mGlobals.NewDatabase = 1;\r
1747 } else if (_stricmp (Argv[0], "-ignorenotfound") == 0) {\r
1748 mGlobals.IgnoreNotFound = 1;\r
1749 } else if (_stricmp (Argv[0], "-oc") == 0) {\r
1750 //\r
1751 // check for one more arg\r
1752 //\r
1753 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1754 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output C filename");\r
1755 return STATUS_ERROR;\r
1756 }\r
1757\r
1758 strcpy (mGlobals.StringCFileName, Argv[1]);\r
1759 Argc--;\r
1760 Argv++;\r
1761 } else if (_stricmp (Argv[0], "-bn") == 0) {\r
1762 //\r
1763 // check for one more arg\r
1764 //\r
1765 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1766 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing base name");\r
1767 Usage ();\r
1768 return STATUS_ERROR;\r
1769 }\r
1770\r
1771 strcpy (mGlobals.BaseName, Argv[1]);\r
1772 Argc--;\r
1773 Argv++;\r
1774 } else if (_stricmp (Argv[0], "-oh") == 0) {\r
1775 //\r
1776 // -oh to specify output .h defines file name\r
1777 //\r
1778 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1779 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output .h filename");\r
1780 return STATUS_ERROR;\r
1781 }\r
1782\r
1783 strcpy (mGlobals.StringHFileName, Argv[1]);\r
1784 Argc--;\r
1785 Argv++;\r
1786 } else if (_stricmp (Argv[0], "-dep") == 0) {\r
1787 //\r
1788 // -dep to specify output dependency file name\r
1789 //\r
1790 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1791 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output dependency filename");\r
1792 return STATUS_ERROR;\r
1793 }\r
1794\r
1795 strcpy (mGlobals.OutputDependencyFileName, Argv[1]);\r
1796 Argc--;\r
1797 Argv++;\r
1798 } else if (_stricmp (Argv[0], "-skipext") == 0) {\r
1799 //\r
1800 // -skipext to skip scanning of files with certain filename extensions\r
1801 //\r
1802 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1803 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing filename extension");\r
1804 return STATUS_ERROR;\r
1805 }\r
1806 //\r
1807 // Allocate memory for a new list element, fill it in, and\r
1808 // add it to our list of excluded extensions. Always make sure it\r
1809 // has a "." as the first character.\r
1810 //\r
1811 NewList = malloc (sizeof (TEXT_STRING_LIST));\r
1812 if (NewList == NULL) {\r
1813 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1814 return STATUS_ERROR;\r
1815 }\r
1816\r
1817 memset ((char *) NewList, 0, sizeof (TEXT_STRING_LIST));\r
1818 NewList->Str = malloc (strlen (Argv[1]) + 2);\r
1819 if (NewList->Str == NULL) {\r
1820 free (NewList);\r
1821 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1822 return STATUS_ERROR;\r
1823 }\r
1824\r
1825 if (Argv[1][0] == '.') {\r
1826 strcpy (NewList->Str, Argv[1]);\r
1827 } else {\r
1828 NewList->Str[0] = '.';\r
1829 strcpy (NewList->Str + 1, Argv[1]);\r
1830 }\r
1831 //\r
1832 // Add it to our linked list\r
1833 //\r
1834 if (mGlobals.SkipExt == NULL) {\r
1835 mGlobals.SkipExt = NewList;\r
1836 } else {\r
1837 mGlobals.LastSkipExt->Next = NewList;\r
1838 }\r
1839\r
1840 mGlobals.LastSkipExt = NewList;\r
1841 Argc--;\r
1842 Argv++;\r
1843 } else if (_stricmp (Argv[0], "-lang") == 0) {\r
1844 //\r
1845 // "-lang eng" or "-lang spa+cat" to only output certain languages\r
1846 //\r
1847 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1848 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing language name");\r
1849 Usage ();\r
1850 return STATUS_ERROR;\r
1851 }\r
1852\r
1853 if (AddCommandLineLanguage (Argv[1]) != STATUS_SUCCESS) {\r
1854 return STATUS_ERROR;\r
1855 }\r
1856\r
1857 Argc--;\r
1858 Argv++;\r
1859 } else if (_stricmp (Argv[0], "-od") == 0) {\r
1860 //\r
1861 // Output database file name -- check for another arg\r
1862 //\r
1863 if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
1864 Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output database file name");\r
1865 return STATUS_ERROR;\r
1866 }\r
1867\r
1868 strcpy (mGlobals.OutputDatabaseFileName, Argv[1]);\r
1869 Argv++;\r
1870 Argc--;\r
1871 } else {\r
1872 //\r
1873 // Unrecognized arg\r
1874 //\r
1875 Error (PROGRAM_NAME, 0, 0, Argv[0], "unrecognized option");\r
1876 Usage ();\r
1877 return STATUS_ERROR;\r
1878 }\r
1879\r
1880 Argv++;\r
1881 Argc--;\r
1882 }\r
1883 //\r
1884 // Make sure they specified the mode parse/scan/dump\r
1885 //\r
1886 if (mGlobals.Mode == MODE_UNKNOWN) {\r
1887 Error (NULL, 0, 0, "must specify one of -parse/-scan/-dump", NULL);\r
1888 return STATUS_ERROR;\r
1889 }\r
1890 //\r
1891 // All modes require a database filename\r
1892 //\r
1893 if (mGlobals.DatabaseFileName == 0) {\r
1894 Error (NULL, 0, 0, "must specify a database filename using -db DbFileName", NULL);\r
1895 Usage ();\r
1896 return STATUS_ERROR;\r
1897 }\r
1898 //\r
1899 // If dumping the database file, then return immediately if all\r
1900 // parameters check out.\r
1901 //\r
1902 if (mGlobals.Mode == MODE_DUMP) {\r
1903 //\r
1904 // Not much use if they didn't specify -oh or -oc or -ou or -hpk\r
1905 //\r
1906 if ((mGlobals.DumpUFileName[0] == 0) &&\r
1907 (mGlobals.StringHFileName[0] == 0) &&\r
1908 (mGlobals.StringCFileName[0] == 0) &&\r
1909 (mGlobals.HiiExportPackFileName[0] == 0)\r
1910 ) {\r
1911 Error (NULL, 0, 0, "-dump without -oc/-oh/-ou/-hpk is a NOP", NULL);\r
1912 return STATUS_ERROR;\r
1913 }\r
1914\r
1915 return STATUS_SUCCESS;\r
1916 }\r
1917 //\r
1918 // Had to specify source string file and output string defines header filename.\r
1919 //\r
1920 if (mGlobals.Mode == MODE_SCAN) {\r
1921 if (Argc < 1) {\r
1922 Error (PROGRAM_NAME, 0, 0, NULL, "must specify at least one source file to scan with -scan");\r
1923 Usage ();\r
1924 return STATUS_ERROR;\r
1925 }\r
1926 //\r
1927 // Get the list of filenames\r
1928 //\r
1929 while (Argc > 0) {\r
1930 NewList = malloc (sizeof (TEXT_STRING_LIST));\r
1931 if (NewList == NULL) {\r
1932 Error (PROGRAM_NAME, 0, 0, "memory allocation failure", NULL);\r
1933 return STATUS_ERROR;\r
1934 }\r
1935\r
1936 memset (NewList, 0, sizeof (TEXT_STRING_LIST));\r
1937 NewList->Str = (UINT8 *) malloc (strlen (Argv[0]) + 1);\r
1938 if (NewList->Str == NULL) {\r
1939 Error (PROGRAM_NAME, 0, 0, "memory allocation failure", NULL);\r
1940 return STATUS_ERROR;\r
1941 }\r
1942\r
1943 strcpy (NewList->Str, Argv[0]);\r
1944 if (mGlobals.ScanFileName == NULL) {\r
1945 mGlobals.ScanFileName = NewList;\r
1946 } else {\r
1947 mGlobals.LastScanFileName->Next = NewList;\r
1948 }\r
1949\r
1950 mGlobals.LastScanFileName = NewList;\r
1951 Argc--;\r
1952 Argv++;\r
1953 }\r
1954 } else {\r
1955 //\r
1956 // Parse mode -- must specify an input unicode file name\r
1957 //\r
1958 if (Argc < 1) {\r
1959 Error (PROGRAM_NAME, 0, 0, NULL, "must specify input unicode string file name with -parse");\r
1960 Usage ();\r
1961 return STATUS_ERROR;\r
1962 }\r
1963\r
1964 strcpy (mGlobals.SourceFiles.FileName, Argv[0]);\r
1965 }\r
1966\r
1967 return STATUS_SUCCESS;\r
1968}\r
1969//\r
1970// Found "-lang eng,spa+cat" on the command line. Parse the\r
1971// language list and save the setting for later processing.\r
1972//\r
1973static\r
1974STATUS\r
1975AddCommandLineLanguage (\r
1976 IN INT8 *Language\r
1977 )\r
1978{\r
1979 WCHAR_STRING_LIST *WNewList;\r
1980 WCHAR *From;\r
1981 WCHAR *To;\r
1982 //\r
1983 // Keep processing the input string until we find the end.\r
1984 //\r
1985 while (*Language) {\r
1986 //\r
1987 // Allocate memory for a new list element, fill it in, and\r
1988 // add it to our list.\r
1989 //\r
1990 WNewList = MALLOC (sizeof (WCHAR_STRING_LIST));\r
1991 if (WNewList == NULL) {\r
1992 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
1993 return STATUS_ERROR;\r
1994 }\r
1995\r
1996 memset ((char *) WNewList, 0, sizeof (WCHAR_STRING_LIST));\r
1997 WNewList->Str = malloc ((strlen (Language) + 1) * sizeof (WCHAR));\r
1998 if (WNewList->Str == NULL) {\r
1999 free (WNewList);\r
2000 Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
2001 return STATUS_ERROR;\r
2002 }\r
2003 //\r
2004 // Copy it as unicode to our new structure. Then remove the\r
2005 // plus signs in it, and verify each language name is 3 characters\r
2006 // long. If we find a comma, then we're done with this group, so\r
2007 // break out.\r
2008 //\r
2009#ifdef USE_VC8\r
2010 swprintf (WNewList->Str, (strlen (Language) + 1) * sizeof (WCHAR), L"%S", Language);\r
2011#else\r
2012 swprintf (WNewList->Str, L"%S", Language);\r
2013#endif\r
2014 From = To = WNewList->Str;\r
2015 while (*From) {\r
2016 if (*From == L',') {\r
2017 break;\r
2018 }\r
2019\r
2020 if ((wcslen (From) < LANGUAGE_IDENTIFIER_NAME_LEN) ||\r
2021 (\r
2022 (From[LANGUAGE_IDENTIFIER_NAME_LEN] != 0) &&\r
2023 (From[LANGUAGE_IDENTIFIER_NAME_LEN] != UNICODE_PLUS_SIGN) &&\r
2024 (From[LANGUAGE_IDENTIFIER_NAME_LEN] != L',')\r
2025 )\r
2026 ) {\r
2027 Error (PROGRAM_NAME, 0, 0, Language, "invalid format for language name on command line");\r
2028 FREE (WNewList->Str);\r
2029 FREE (WNewList);\r
2030 return STATUS_ERROR;\r
2031 }\r
2032\r
2033 wcsncpy (To, From, LANGUAGE_IDENTIFIER_NAME_LEN);\r
2034 To += LANGUAGE_IDENTIFIER_NAME_LEN;\r
2035 From += LANGUAGE_IDENTIFIER_NAME_LEN;\r
2036 if (*From == L'+') {\r
2037 From++;\r
2038 }\r
2039 }\r
2040\r
2041 *To = 0;\r
2042 //\r
2043 // Add it to our linked list\r
2044 //\r
2045 if (mGlobals.Language == NULL) {\r
2046 mGlobals.Language = WNewList;\r
2047 } else {\r
2048 mGlobals.LastLanguage->Next = WNewList;\r
2049 }\r
2050\r
2051 mGlobals.LastLanguage = WNewList;\r
2052 //\r
2053 // Skip to next entry (comma-separated list)\r
2054 //\r
2055 while (*Language) {\r
2056 if (*Language == L',') {\r
2057 Language++;\r
2058 break;\r
2059 }\r
2060\r
2061 Language++;\r
2062 }\r
2063 }\r
2064\r
2065 return STATUS_SUCCESS;\r
2066}\r
2067//\r
2068// The contents of the text file are expected to be (one per line)\r
2069// STRING_IDENTIFIER_NAME ScopeName\r
2070// For example:\r
2071// STR_ID_MY_FAVORITE_STRING IBM\r
2072//\r
2073static\r
2074STATUS\r
2075ParseIndirectionFiles (\r
2076 TEXT_STRING_LIST *Files\r
2077 )\r
2078{\r
2079 FILE *Fptr;\r
2080 INT8 Line[200];\r
2081 INT8 *StringName;\r
2082 INT8 *ScopeName;\r
2083 INT8 *End;\r
2084 UINT32 LineCount;\r
2085 WCHAR_MATCHING_STRING_LIST *NewList;\r
2086\r
2087 Line[sizeof (Line) - 1] = 0;\r
2088 Fptr = NULL;\r
2089 while (Files != NULL) {\r
2090 Fptr = fopen (Files->Str, "r");\r
2091 LineCount = 0;\r
2092 if (Fptr == NULL) {\r
2093 Error (NULL, 0, 0, Files->Str, "failed to open input indirection file for reading");\r
2094 return STATUS_ERROR;\r
2095 }\r
2096\r
2097 while (fgets (Line, sizeof (Line), Fptr) != NULL) {\r
2098 //\r
2099 // remove terminating newline for error printing purposes.\r
2100 //\r
2101 if (Line[strlen (Line) - 1] == '\n') {\r
2102 Line[strlen (Line) - 1] = 0;\r
2103 }\r
2104\r
2105 LineCount++;\r
2106 if (Line[sizeof (Line) - 1] != 0) {\r
2107 Error (Files->Str, LineCount, 0, "line length exceeds maximum supported", NULL);\r
2108 goto Done;\r
2109 }\r
2110\r
2111 StringName = Line;\r
2112 while (*StringName && (isspace (*StringName))) {\r
2113 StringName++;\r
2114 }\r
2115\r
2116 if (*StringName) {\r
2117 if ((*StringName == '_') || isalpha (*StringName)) {\r
2118 End = StringName;\r
2119 while ((*End) && (*End == '_') || (isalnum (*End))) {\r
2120 End++;\r
2121 }\r
2122\r
2123 if (isspace (*End)) {\r
2124 *End = 0;\r
2125 End++;\r
2126 while (isspace (*End)) {\r
2127 End++;\r
2128 }\r
2129\r
2130 if (*End) {\r
2131 ScopeName = End;\r
2132 while (*End && !isspace (*End)) {\r
2133 End++;\r
2134 }\r
2135\r
2136 *End = 0;\r
2137 //\r
2138 // Add the string name/scope pair\r
2139 //\r
2140 NewList = malloc (sizeof (WCHAR_MATCHING_STRING_LIST));\r
2141 if (NewList == NULL) {\r
2142 Error (NULL, 0, 0, "memory allocation error", NULL);\r
2143 goto Done;\r
2144 }\r
2145\r
2146 memset (NewList, 0, sizeof (WCHAR_MATCHING_STRING_LIST));\r
2147 NewList->Str1 = (WCHAR *) malloc ((strlen (StringName) + 1) * sizeof (WCHAR));\r
2148 NewList->Str2 = (WCHAR *) malloc ((strlen (ScopeName) + 1) * sizeof (WCHAR));\r
2149 if ((NewList->Str1 == NULL) || (NewList->Str2 == NULL)) {\r
2150 Error (NULL, 0, 0, "memory allocation error", NULL);\r
2151 goto Done;\r
2152 }\r
2153\r
2154#ifdef USE_VC8\r
2155 swprintf (NewList->Str1, (strlen (StringName) + 1) * sizeof (WCHAR), L"%S", StringName);\r
2156 swprintf (NewList->Str2, (strlen (ScopeName) + 1) * sizeof (WCHAR), L"%S", ScopeName);\r
2157#else\r
2158 swprintf (NewList->Str1, L"%S", StringName);\r
2159 swprintf (NewList->Str2, L"%S", ScopeName);\r
2160#endif\r
2161 if (mGlobals.IndirectionList == NULL) {\r
2162 mGlobals.IndirectionList = NewList;\r
2163 } else {\r
2164 mGlobals.LastIndirectionList->Next = NewList;\r
2165 }\r
2166\r
2167 mGlobals.LastIndirectionList = NewList;\r
2168 } else {\r
2169 Error (Files->Str, LineCount, 0, StringName, "invalid line : expected 'StringIdentifier Scope'");\r
2170 goto Done;\r
2171 }\r
2172 } else {\r
2173 Error (Files->Str, LineCount, 0, StringName, "invalid line : expected 'StringIdentifier Scope'");\r
2174 goto Done;\r
2175 }\r
2176 } else {\r
2177 Error (Files->Str, LineCount, 0, StringName, "invalid string identifier");\r
2178 goto Done;\r
2179 }\r
2180 }\r
2181 }\r
2182\r
2183 fclose (Fptr);\r
2184 Fptr = NULL;\r
2185 Files = Files->Next;\r
2186 }\r
2187\r
2188Done:\r
2189 if (Fptr != NULL) {\r
2190 fclose (Fptr);\r
2191 return STATUS_ERROR;\r
2192 }\r
2193\r
2194 return STATUS_SUCCESS;\r
2195}\r
2196\r
2197static\r
2198STATUS\r
2199ScanFiles (\r
2200 TEXT_STRING_LIST *ScanFiles\r
2201 )\r
2202{\r
2203 char Line[MAX_LINE_LEN];\r
2204 FILE *Fptr;\r
2205 UINT32 LineNum;\r
2206 char *Cptr;\r
2207 char *SavePtr;\r
2208 char *TermPtr;\r
2209 char *StringTokenPos;\r
2210 TEXT_STRING_LIST *SList;\r
2211 BOOLEAN SkipIt;\r
2212\r
2213 //\r
2214 // Put a null-terminator at the end of the line. If we read in\r
2215 // a line longer than we support, then we can catch it.\r
2216 //\r
2217 Line[MAX_LINE_LEN - 1] = 0;\r
2218 //\r
2219 // Process each file. If they gave us a skip extension list, then\r
2220 // skip it if the extension matches.\r
2221 //\r
2222 while (ScanFiles != NULL) {\r
2223 SkipIt = FALSE;\r
2224 for (SList = mGlobals.SkipExt; SList != NULL; SList = SList->Next) {\r
2225 if ((strlen (ScanFiles->Str) > strlen (SList->Str)) &&\r
2226 (strcmp (ScanFiles->Str + strlen (ScanFiles->Str) - strlen (SList->Str), SList->Str) == 0)\r
2227 ) {\r
2228 SkipIt = TRUE;\r
2229 //\r
2230 // printf ("Match: %s : %s\n", ScanFiles->Str, SList->Str);\r
2231 //\r
2232 break;\r
2233 }\r
2234 }\r
2235\r
2236 if (!SkipIt) {\r
2237 if (mGlobals.VerboseScan) {\r
2238 printf ("Scanning %s\n", ScanFiles->Str);\r
2239 }\r
2240\r
2241 Fptr = fopen (ScanFiles->Str, "r");\r
2242 if (Fptr == NULL) {\r
2243 Error (NULL, 0, 0, ScanFiles->Str, "failed to open input file for scanning");\r
2244 return STATUS_ERROR;\r
2245 }\r
2246\r
2247 LineNum = 0;\r
2248 while (fgets (Line, sizeof (Line), Fptr) != NULL) {\r
2249 LineNum++;\r
2250 if (Line[MAX_LINE_LEN - 1] != 0) {\r
2251 Error (ScanFiles->Str, LineNum, 0, "line length exceeds maximum supported by tool", NULL);\r
2252 fclose (Fptr);\r
2253 return STATUS_ERROR;\r
2254 }\r
2255 //\r
2256 // Remove the newline from the input line so we can print a warning message\r
2257 //\r
2258 if (Line[strlen (Line) - 1] == '\n') {\r
2259 Line[strlen (Line) - 1] = 0;\r
2260 }\r
2261 //\r
2262 // Terminate the line at // comments\r
2263 //\r
2264 Cptr = strstr (Line, "//");\r
2265 if (Cptr != NULL) {\r
2266 *Cptr = 0;\r
2267 }\r
2268\r
2269 Cptr = Line;\r
2270 while ((Cptr = strstr (Cptr, STRING_TOKEN)) != NULL) {\r
2271 //\r
2272 // Found "STRING_TOKEN". Make sure we don't have NUM_STRING_TOKENS or\r
2273 // something like that. Then make sure it's followed by\r
2274 // an open parenthesis, a string identifier, and then a closing\r
2275 // parenthesis.\r
2276 //\r
2277 if (mGlobals.VerboseScan) {\r
2278 printf (" %d: %s", LineNum, Cptr);\r
2279 }\r
2280\r
2281 if (((Cptr == Line) || (!IsValidIdentifierChar (*(Cptr - 1), FALSE))) &&\r
2282 (!IsValidIdentifierChar (*(Cptr + sizeof (STRING_TOKEN) - 1), FALSE))\r
2283 ) {\r
2284 StringTokenPos = Cptr;\r
2285 SavePtr = Cptr;\r
2286 Cptr += strlen (STRING_TOKEN);\r
2287 while (*Cptr && isspace (*Cptr) && (*Cptr != '(')) {\r
2288 Cptr++;\r
2289 }\r
2290\r
2291 if (*Cptr != '(') {\r
2292 Warning (ScanFiles->Str, LineNum, 0, StringTokenPos, "expected "STRING_TOKEN "(identifier)");\r
2293 } else {\r
2294 //\r
2295 // Skip over the open-parenthesis and find the next non-blank character\r
2296 //\r
2297 Cptr++;\r
2298 while (isspace (*Cptr)) {\r
2299 Cptr++;\r
2300 }\r
2301\r
2302 SavePtr = Cptr;\r
2303 if ((*Cptr == '_') || isalpha (*Cptr)) {\r
2304 while ((*Cptr == '_') || (isalnum (*Cptr))) {\r
2305 Cptr++;\r
2306 }\r
2307\r
2308 TermPtr = Cptr;\r
2309 while (*Cptr && isspace (*Cptr)) {\r
2310 Cptr++;\r
2311 }\r
2312\r
2313 if (*Cptr != ')') {\r
2314 Warning (ScanFiles->Str, LineNum, 0, StringTokenPos, "expected "STRING_TOKEN "(identifier)");\r
2315 }\r
2316\r
2317 if (*TermPtr) {\r
2318 *TermPtr = 0;\r
2319 Cptr = TermPtr + 1;\r
2320 } else {\r
2321 Cptr = TermPtr;\r
2322 }\r
2323 //\r
2324 // Add the string identifier to the list of used strings\r
2325 //\r
2326 ParserSetPosition (ScanFiles->Str, LineNum);\r
2327 StringDBSetStringReferenced (SavePtr, mGlobals.IgnoreNotFound);\r
2328 if (mGlobals.VerboseScan) {\r
2329 printf ("...referenced %s", SavePtr);\r
2330 }\r
2331 } else {\r
2332 Warning (ScanFiles->Str, LineNum, 0, StringTokenPos, "expected valid string identifier name");\r
2333 }\r
2334 }\r
2335 } else {\r
2336 //\r
2337 // Found it, but it's a substring of something else. Advance our pointer.\r
2338 //\r
2339 Cptr++;\r
2340 }\r
2341\r
2342 if (mGlobals.VerboseScan) {\r
2343 printf ("\n");\r
2344 }\r
2345 }\r
2346 }\r
2347\r
2348 fclose (Fptr);\r
2349 } else {\r
2350 //\r
2351 // Skipping this file type\r
2352 //\r
2353 if (mGlobals.VerboseScan) {\r
2354 printf ("Skip scanning of %s\n", ScanFiles->Str);\r
2355 }\r
2356 }\r
2357\r
2358 ScanFiles = ScanFiles->Next;\r
2359 }\r
2360\r
2361 return STATUS_SUCCESS;\r
2362}\r
2363//\r
2364// Free the global string lists we allocated memory for\r
2365//\r
2366static\r
2367void\r
2368FreeLists (\r
2369 VOID\r
2370 )\r
2371{\r
2372 TEXT_STRING_LIST *Temp;\r
2373 WCHAR_STRING_LIST *WTemp;\r
2374\r
2375 //\r
2376 // Traverse the include paths, freeing each\r
2377 //\r
2378 while (mGlobals.IncludePaths != NULL) {\r
2379 Temp = mGlobals.IncludePaths->Next;\r
2380 free (mGlobals.IncludePaths->Str);\r
2381 free (mGlobals.IncludePaths);\r
2382 mGlobals.IncludePaths = Temp;\r
2383 }\r
2384 //\r
2385 // If we did a scan, then free up our\r
2386 // list of files to scan.\r
2387 //\r
2388 while (mGlobals.ScanFileName != NULL) {\r
2389 Temp = mGlobals.ScanFileName->Next;\r
2390 free (mGlobals.ScanFileName->Str);\r
2391 free (mGlobals.ScanFileName);\r
2392 mGlobals.ScanFileName = Temp;\r
2393 }\r
2394 //\r
2395 // If they gave us a list of filename extensions to\r
2396 // skip on scan, then free them up.\r
2397 //\r
2398 while (mGlobals.SkipExt != NULL) {\r
2399 Temp = mGlobals.SkipExt->Next;\r
2400 free (mGlobals.SkipExt->Str);\r
2401 free (mGlobals.SkipExt);\r
2402 mGlobals.SkipExt = Temp;\r
2403 }\r
2404 //\r
2405 // Free up any languages specified\r
2406 //\r
2407 while (mGlobals.Language != NULL) {\r
2408 WTemp = mGlobals.Language->Next;\r
2409 free (mGlobals.Language->Str);\r
2410 free (mGlobals.Language);\r
2411 mGlobals.Language = WTemp;\r
2412 }\r
2413 //\r
2414 // Free up our indirection list\r
2415 //\r
2416 while (mGlobals.IndirectionList != NULL) {\r
2417 mGlobals.LastIndirectionList = mGlobals.IndirectionList->Next;\r
2418 free (mGlobals.IndirectionList->Str1);\r
2419 free (mGlobals.IndirectionList->Str2);\r
2420 free (mGlobals.IndirectionList);\r
2421 mGlobals.IndirectionList = mGlobals.LastIndirectionList;\r
2422 }\r
2423\r
2424 while (mGlobals.IndirectionFileName != NULL) {\r
2425 mGlobals.LastIndirectionFileName = mGlobals.IndirectionFileName->Next;\r
2426 free (mGlobals.IndirectionFileName->Str);\r
2427 free (mGlobals.IndirectionFileName);\r
2428 mGlobals.IndirectionFileName = mGlobals.LastIndirectionFileName;\r
2429 }\r
2430}\r
2431\r
2432static\r
2433BOOLEAN\r
2434IsValidIdentifierChar (\r
2435 INT8 Char,\r
2436 BOOLEAN FirstChar\r
2437 )\r
2438{\r
2439 //\r
2440 // If it's the first character of an identifier, then\r
2441 // it must be one of [A-Za-z_].\r
2442 //\r
2443 if (FirstChar) {\r
2444 if (isalpha (Char) || (Char == '_')) {\r
2445 return TRUE;\r
2446 }\r
2447 } else {\r
2448 //\r
2449 // If it's not the first character, then it can\r
2450 // be one of [A-Za-z_0-9]\r
2451 //\r
2452 if (isalnum (Char) || (Char == '_')) {\r
2453 return TRUE;\r
2454 }\r
2455 }\r
2456\r
2457 return FALSE;\r
2458}\r
2459\r
2460static\r
2461void\r
2462RewindFile (\r
2463 SOURCE_FILE *SourceFile\r
2464 )\r
2465{\r
2466 SourceFile->LineNum = 1;\r
2467 SourceFile->FileBufferPtr = SourceFile->FileBuffer;\r
2468 SourceFile->EndOfFile = 0;\r
2469}\r
2470\r
2471static\r
2472BOOLEAN\r
2473SkipTo (\r
2474 SOURCE_FILE *SourceFile,\r
2475 WCHAR WChar,\r
2476 BOOLEAN StopAfterNewline\r
2477 )\r
2478{\r
2479 while (!EndOfFile (SourceFile)) {\r
2480 //\r
2481 // Check for the character of interest\r
2482 //\r
2483 if (SourceFile->FileBufferPtr[0] == WChar) {\r
2484 return TRUE;\r
2485 } else {\r
2486 if (SourceFile->FileBufferPtr[0] == UNICODE_LF) {\r
2487 SourceFile->LineNum++;\r
2488 if (StopAfterNewline) {\r
2489 SourceFile->FileBufferPtr++;\r
2490 if (SourceFile->FileBufferPtr[0] == 0) {\r
2491 SourceFile->FileBufferPtr++;\r
2492 }\r
2493\r
2494 return FALSE;\r
2495 }\r
2496 }\r
2497\r
2498 SourceFile->FileBufferPtr++;\r
2499 }\r
2500 }\r
2501\r
2502 return FALSE;\r
2503}\r
2504\r
2505static\r
2506void\r
2507Usage (\r
2508 VOID\r
2509 )\r
2510/*++\r
2511\r
2512Routine Description:\r
2513\r
2514 Print usage information for this utility.\r
2515 \r
2516Arguments:\r
2517\r
2518 None.\r
2519\r
2520Returns:\r
2521\r
2522 Nothing.\r
2523 \r
2524--*/\r
2525{\r
2526 int Index;\r
2527 static const char *Str[] = {\r
2528 "",\r
2529 PROGRAM_NAME " version "TOOL_VERSION " -- process unicode strings file",\r
2530 " Usage: "PROGRAM_NAME " -parse {parse options} [FileNames]",\r
2531 " "PROGRAM_NAME " -scan {scan options} [FileName]",\r
2532 " "PROGRAM_NAME " -dump {dump options}",\r
2533 " Common options include:",\r
2534 " -h or -? for this help information",\r
2535 " -db Database required name of output/input database file",\r
2536 " -bn BaseName for use in the .h and .c output files",\r
2537 " Default = "DEFAULT_BASE_NAME,\r
2538 " -v for verbose output",\r
2539 " -vdbw for verbose output when writing database",\r
2540 " -vdbr for verbose output when reading database",\r
2541 " -od FileName to specify an output database file name",\r
2542 " Parse options include:",\r
2543 " -i IncludePath add IncludePath to list of search paths",\r
2544 " -dep FileName to specify an output dependency file name",\r
2545 " -newdb to not read in existing database file",\r
2546 " -uqs to indicate that unquoted strings are used",\r
2547 " FileNames name of one or more unicode files to parse",\r
2548 " Scan options include:",\r
2549 " -scan scan text file(s) for STRING_TOKEN() usage",\r
2550 " -skipext .ext to skip scan of files with .ext filename extension",\r
2551 " -ignorenotfound ignore if a given STRING_TOKEN(STR) is not ",\r
2552 " found in the database",\r
2553 " FileNames one or more files to scan",\r
2554 " Dump options include:",\r
2555 " -oc FileName write string data to FileName",\r
2556 " -oh FileName write string defines to FileName",\r
2557 " -ou FileName dump database to unicode file FileName",\r
2558 " -lang Lang only dump for the language 'Lang'",\r
2559 " -if FileName to specify an indirection file",\r
2560 " -hpk FileName to create an HII export pack of the strings",\r
2561 "",\r
2562 " The expected process is to parse a unicode string file to create an initial",\r
2563 " database of string identifier names and string definitions. Then text files",\r
2564 " should be scanned for STRING_TOKEN() usages, and the referenced",\r
2565 " strings will be tagged as used in the database. After all files have been",\r
2566 " scanned, then the database should be dumped to create the necessary output",\r
2567 " files.",\r
2568 "",\r
2569 NULL\r
2570 };\r
2571 for (Index = 0; Str[Index] != NULL; Index++) {\r
2572 fprintf (stdout, "%s\n", Str[Index]);\r
2573 }\r
2574}\r