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