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