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