+++ /dev/null
-/*++\r
-\r
-Copyright (c) 2004, Intel Corporation \r
-All rights reserved. This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
-http://opensource.org/licenses/bsd-license.php \r
- \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
-\r
-Module Name:\r
-\r
- StrGather.c \r
-\r
-Abstract:\r
-\r
- Parse a strings file and create or add to a string database file.\r
-\r
---*/\r
-\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include <ctype.h>\r
-\r
-#include <Common/UefiBaseTypes.h>\r
-\r
-#include "CommonLib.h"\r
-#include "EfiUtilityMsgs.h"\r
-#include "StrGather.h"\r
-#include "StringDB.h"\r
-\r
-#define TOOL_VERSION "0.31"\r
-\r
-#ifndef MAX_PATH\r
-#define MAX_PATH 255\r
-#endif\r
-#define MAX_NEST_DEPTH 20 // just in case we get in an endless loop.\r
-#define MAX_STRING_IDENTIFIER_NAME 100 // number of wchars\r
-#define MAX_LINE_LEN 200\r
-#define STRING_TOKEN "STRING_TOKEN"\r
-#define DEFAULT_BASE_NAME "BaseName"\r
-//\r
-// Operational modes for this utility\r
-//\r
-#define MODE_UNKNOWN 0\r
-#define MODE_PARSE 1\r
-#define MODE_SCAN 2\r
-#define MODE_DUMP 3\r
-\r
-//\r
-// We keep a linked list of these for the source files we process\r
-//\r
-typedef struct _SOURCE_FILE {\r
- FILE *Fptr;\r
- WCHAR *FileBuffer;\r
- WCHAR *FileBufferPtr;\r
- UINT32 FileSize;\r
- CHAR8 FileName[MAX_PATH];\r
- UINT32 LineNum;\r
- BOOLEAN EndOfFile;\r
- BOOLEAN SkipToHash;\r
- struct _SOURCE_FILE *Previous;\r
- struct _SOURCE_FILE *Next;\r
- WCHAR ControlCharacter;\r
-} SOURCE_FILE;\r
-\r
-#define DEFAULT_CONTROL_CHARACTER UNICODE_SLASH\r
-\r
-//\r
-// Here's all our globals. We need a linked list of include paths, a linked\r
-// list of source files, a linked list of subdirectories (appended to each\r
-// include path when searching), and a couple other fields.\r
-//\r
-static struct {\r
- SOURCE_FILE SourceFiles;\r
- TEXT_STRING_LIST *IncludePaths; // all include paths to search\r
- TEXT_STRING_LIST *LastIncludePath;\r
- TEXT_STRING_LIST *ScanFileName;\r
- TEXT_STRING_LIST *LastScanFileName;\r
- TEXT_STRING_LIST *SkipExt; // if -skipext .uni\r
- TEXT_STRING_LIST *LastSkipExt;\r
- TEXT_STRING_LIST *IndirectionFileName;\r
- TEXT_STRING_LIST *LastIndirectionFileName;\r
- TEXT_STRING_LIST *DatabaseFileName;\r
- TEXT_STRING_LIST *LastDatabaseFileName;\r
- WCHAR_STRING_LIST *Language;\r
- WCHAR_STRING_LIST *LastLanguage;\r
- WCHAR_MATCHING_STRING_LIST *IndirectionList; // from indirection file(s)\r
- WCHAR_MATCHING_STRING_LIST *LastIndirectionList;\r
- BOOLEAN Verbose; // for more detailed output\r
- BOOLEAN VerboseDatabaseWrite; // for more detailed output when writing database\r
- BOOLEAN VerboseDatabaseRead; // for more detailed output when reading database\r
- BOOLEAN NewDatabase; // to start from scratch\r
- BOOLEAN IgnoreNotFound; // when scanning\r
- BOOLEAN VerboseScan;\r
- BOOLEAN UnquotedStrings; // -uqs option\r
- CHAR8 OutputDatabaseFileName[MAX_PATH];\r
- CHAR8 StringHFileName[MAX_PATH];\r
- CHAR8 StringCFileName[MAX_PATH]; // output .C filename\r
- CHAR8 DumpUFileName[MAX_PATH]; // output unicode dump file name\r
- CHAR8 HiiExportPackFileName[MAX_PATH]; // HII export pack file name\r
- CHAR8 BaseName[MAX_PATH]; // base filename of the strings file\r
- UINT32 Mode;\r
-} mGlobals;\r
-\r
-static\r
-BOOLEAN\r
-IsValidIdentifierChar (\r
- CHAR8 Char,\r
- BOOLEAN FirstChar\r
- );\r
-\r
-static\r
-void\r
-RewindFile (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-BOOLEAN\r
-SkipTo (\r
- SOURCE_FILE *SourceFile,\r
- WCHAR WChar,\r
- BOOLEAN StopAfterNewline\r
- );\r
-\r
-static\r
-UINT32\r
-SkipWhiteSpace (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-BOOLEAN\r
-IsWhiteSpace (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-BOOLEAN\r
-EndOfFile (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-void\r
-PreprocessFile (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-UINT32\r
-GetStringIdentifierName (\r
- IN SOURCE_FILE *SourceFile,\r
- IN OUT WCHAR *StringIdentifierName,\r
- IN UINT32 StringIdentifierNameLen\r
- );\r
-\r
-static\r
-UINT32\r
-GetLanguageIdentifierName (\r
- IN SOURCE_FILE *SourceFile,\r
- IN OUT WCHAR *LanguageIdentifierName,\r
- IN UINT32 LanguageIdentifierNameLen,\r
- IN BOOLEAN Optional\r
- );\r
-\r
-static\r
-WCHAR *\r
-GetPrintableLanguageName (\r
- IN SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-STATUS\r
-AddCommandLineLanguage (\r
- IN CHAR8 *Language\r
- );\r
-\r
-static\r
-WCHAR *\r
-GetQuotedString (\r
- SOURCE_FILE *SourceFile,\r
- BOOLEAN Optional\r
- );\r
-\r
-static\r
-STATUS\r
-ProcessIncludeFile (\r
- SOURCE_FILE *SourceFile,\r
- SOURCE_FILE *ParentSourceFile\r
- );\r
-\r
-static\r
-STATUS\r
-ParseFile (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-FILE *\r
-FindFile (\r
- IN CHAR8 *FileName,\r
- OUT CHAR8 *FoundFileName,\r
- IN UINT32 FoundFileNameLen\r
- );\r
-\r
-static\r
-STATUS\r
-ProcessArgs (\r
- int Argc,\r
- char *Argv[]\r
- );\r
-\r
-static\r
-STATUS\r
-ProcessFile (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-UINT32\r
-wstrcmp (\r
- WCHAR *Buffer,\r
- WCHAR *Str\r
- );\r
-\r
-static\r
-void\r
-Usage (\r
- VOID\r
- );\r
-\r
-static\r
-void\r
-FreeLists (\r
- VOID\r
- );\r
-\r
-static\r
-void\r
-ProcessTokenString (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-void\r
-ProcessTokenInclude (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-void\r
-ProcessTokenScope (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-void\r
-ProcessTokenLanguage (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-void\r
-ProcessTokenLangDef (\r
- SOURCE_FILE *SourceFile\r
- );\r
-\r
-static\r
-STATUS\r
-ScanFiles (\r
- TEXT_STRING_LIST *ScanFiles\r
- );\r
-\r
-static\r
-STATUS\r
-ParseIndirectionFiles (\r
- TEXT_STRING_LIST *Files\r
- );\r
-\r
-STATUS\r
-StringDBCreateHiiExportPack (\r
- CHAR8 *OutputFileName\r
- );\r
-\r
-int\r
-main (\r
- int Argc,\r
- char *Argv[]\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Call the routine to parse the command-line options, then process the file.\r
- \r
-Arguments:\r
-\r
- Argc - Standard C main() argc and argv.\r
- Argv - Standard C main() argc and argv.\r
-\r
-Returns:\r
-\r
- 0 if successful\r
- nonzero otherwise\r
- \r
---*/\r
-{\r
- STATUS Status;\r
-\r
- SetUtilityName (PROGRAM_NAME);\r
- //\r
- // Process the command-line arguments\r
- //\r
- Status = ProcessArgs (Argc, Argv);\r
- if (Status != STATUS_SUCCESS) {\r
- return Status;\r
- }\r
- //\r
- // Initialize the database manager\r
- //\r
- StringDBConstructor ();\r
- //\r
- // We always try to read in an existing database file. It may not\r
- // exist, which is ok usually.\r
- //\r
- if (mGlobals.NewDatabase == 0) {\r
- //\r
- // Read all databases specified.\r
- //\r
- for (mGlobals.LastDatabaseFileName = mGlobals.DatabaseFileName;\r
- mGlobals.LastDatabaseFileName != NULL;\r
- mGlobals.LastDatabaseFileName = mGlobals.LastDatabaseFileName->Next\r
- ) {\r
- Status = StringDBReadDatabase (mGlobals.LastDatabaseFileName->Str, TRUE, mGlobals.VerboseDatabaseRead);\r
- if (Status != STATUS_SUCCESS) {\r
- return Status;\r
- }\r
- }\r
- }\r
- //\r
- // Read indirection file(s) if specified\r
- //\r
- if (ParseIndirectionFiles (mGlobals.IndirectionFileName) != STATUS_SUCCESS) {\r
- goto Finish;\r
- }\r
- //\r
- // If scanning source files, do that now\r
- //\r
- if (mGlobals.Mode == MODE_SCAN) {\r
- ScanFiles (mGlobals.ScanFileName);\r
- } else if (mGlobals.Mode == MODE_PARSE) {\r
- //\r
- // Parsing a unicode strings file\r
- //\r
- mGlobals.SourceFiles.ControlCharacter = DEFAULT_CONTROL_CHARACTER;\r
- Status = ProcessIncludeFile (&mGlobals.SourceFiles, NULL);\r
- if (Status != STATUS_SUCCESS) {\r
- goto Finish;\r
- }\r
- }\r
- //\r
- // Create the string defines header file if there have been no errors.\r
- //\r
- ParserSetPosition (NULL, 0);\r
- if ((mGlobals.StringHFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
- Status = StringDBDumpStringDefines (mGlobals.StringHFileName, mGlobals.BaseName);\r
- if (Status != EFI_SUCCESS) {\r
- goto Finish;\r
- }\r
- }\r
- //\r
- // Dump the strings to a .c file if there have still been no errors.\r
- //\r
- if ((mGlobals.StringCFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
- Status = StringDBDumpCStrings (\r
- mGlobals.StringCFileName,\r
- mGlobals.BaseName,\r
- mGlobals.Language,\r
- mGlobals.IndirectionList\r
- );\r
- if (Status != EFI_SUCCESS) {\r
- goto Finish;\r
- }\r
- }\r
- //\r
- // Dump the database if requested\r
- //\r
- if ((mGlobals.DumpUFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
- StringDBDumpDatabase (NULL, mGlobals.DumpUFileName, FALSE);\r
- }\r
- //\r
- // Dump the string data as HII binary string pack if requested\r
- //\r
- if ((mGlobals.HiiExportPackFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
- StringDBCreateHiiExportPack (mGlobals.HiiExportPackFileName);\r
- }\r
- //\r
- // Always update the database if no errors and not in dump mode. If they specified -od\r
- // for an output database file name, then use that name. Otherwise use the name of\r
- // the first database file specified with -db\r
- //\r
- if ((mGlobals.Mode != MODE_DUMP) && (GetUtilityStatus () < STATUS_ERROR)) {\r
- if (mGlobals.OutputDatabaseFileName[0]) {\r
- Status = StringDBWriteDatabase (mGlobals.OutputDatabaseFileName, mGlobals.VerboseDatabaseWrite);\r
- } else {\r
- Status = StringDBWriteDatabase (mGlobals.DatabaseFileName->Str, mGlobals.VerboseDatabaseWrite);\r
- }\r
-\r
- if (Status != EFI_SUCCESS) {\r
- goto Finish;\r
- }\r
- }\r
-\r
-Finish:\r
- //\r
- // Free up memory\r
- //\r
- FreeLists ();\r
- StringDBDestructor ();\r
- return GetUtilityStatus ();\r
-}\r
-\r
-static\r
-STATUS\r
-ProcessIncludeFile (\r
- SOURCE_FILE *SourceFile,\r
- SOURCE_FILE *ParentSourceFile\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Given a source file, open the file and parse it\r
- \r
-Arguments:\r
-\r
- SourceFile - name of file to parse\r
- ParentSourceFile - for error reporting purposes, the file that #included SourceFile.\r
-\r
-Returns:\r
-\r
- Standard status.\r
- \r
---*/\r
-{\r
- static UINT32 NestDepth = 0;\r
- CHAR8 FoundFileName[MAX_PATH];\r
- STATUS Status;\r
-\r
- Status = STATUS_SUCCESS;\r
- NestDepth++;\r
- //\r
- // Print the file being processed. Indent so you can tell the include nesting\r
- // depth.\r
- //\r
- if (mGlobals.Verbose) {\r
- fprintf (stdout, "%*cProcessing file '%s'\n", NestDepth * 2, ' ', SourceFile->FileName);\r
- }\r
-\r
- //\r
- // Make sure we didn't exceed our maximum nesting depth\r
- //\r
- if (NestDepth > MAX_NEST_DEPTH) {\r
- Error (NULL, 0, 0, SourceFile->FileName, "max nesting depth (%d) exceeded", NestDepth);\r
- Status = STATUS_ERROR;\r
- goto Finish;\r
- }\r
- //\r
- // Try to open the file locally, and if that fails try along our include paths.\r
- //\r
- strcpy (FoundFileName, SourceFile->FileName);\r
- if ((SourceFile->Fptr = fopen (FoundFileName, "rb")) == NULL) {\r
- //\r
- // Try to find it among the paths if it has a parent (that is, it is included\r
- // by someone else).\r
- //\r
- if (ParentSourceFile == NULL) {\r
- Error (NULL, 0, 0, SourceFile->FileName, "file not found");\r
- return STATUS_ERROR;\r
- }\r
-\r
- SourceFile->Fptr = FindFile (SourceFile->FileName, FoundFileName, sizeof (FoundFileName));\r
- if (SourceFile->Fptr == NULL) {\r
- Error (ParentSourceFile->FileName, ParentSourceFile->LineNum, 0, SourceFile->FileName, "include file not found");\r
- return STATUS_ERROR;\r
- }\r
- }\r
- //\r
- // Process the file found\r
- //\r
- ProcessFile (SourceFile);\r
-Finish:\r
- //\r
- // Close open files and return status\r
- //\r
- if (SourceFile->Fptr != NULL) {\r
- fclose (SourceFile->Fptr);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-static\r
-STATUS\r
-ProcessFile (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- //\r
- // Get the file size, and then read the entire thing into memory.\r
- // Allocate space for a terminator character.\r
- //\r
- fseek (SourceFile->Fptr, 0, SEEK_END);\r
- SourceFile->FileSize = ftell (SourceFile->Fptr);\r
- fseek (SourceFile->Fptr, 0, SEEK_SET);\r
- SourceFile->FileBuffer = (WCHAR *) malloc (SourceFile->FileSize + sizeof (WCHAR));\r
- if (SourceFile->FileBuffer == NULL) {\r
- Error (NULL, 0, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- fread ((VOID *) SourceFile->FileBuffer, SourceFile->FileSize, 1, SourceFile->Fptr);\r
- SourceFile->FileBuffer[(SourceFile->FileSize / sizeof (WCHAR))] = UNICODE_NULL;\r
- //\r
- // Pre-process the file to replace comments with spaces\r
- //\r
- PreprocessFile (SourceFile);\r
- //\r
- // Parse the file\r
- //\r
- ParseFile (SourceFile);\r
- free (SourceFile->FileBuffer);\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-static\r
-STATUS\r
-ParseFile (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- BOOLEAN InComment;\r
- UINT32 Len;\r
-\r
- //\r
- // First character of a unicode file is special. Make sure\r
- //\r
- if (SourceFile->FileBufferPtr[0] != UNICODE_FILE_START) {\r
- Error (SourceFile->FileName, 1, 0, SourceFile->FileName, "file does not appear to be a unicode file");\r
- return STATUS_ERROR;\r
- }\r
-\r
- SourceFile->FileBufferPtr++;\r
- InComment = FALSE;\r
- //\r
- // Print the first line if in verbose mode\r
- //\r
- if (mGlobals.Verbose) {\r
- printf ("%d: %S\n", SourceFile->LineNum, SourceFile->FileBufferPtr);\r
- }\r
- //\r
- // Since the syntax is relatively straightforward, just switch on the next char\r
- //\r
- while (!EndOfFile (SourceFile)) {\r
- //\r
- // Check for whitespace\r
- //\r
- if (SourceFile->FileBufferPtr[0] == UNICODE_SPACE) {\r
- SourceFile->FileBufferPtr++;\r
- } else if (SourceFile->FileBufferPtr[0] == UNICODE_TAB) {\r
- SourceFile->FileBufferPtr++;\r
- } else if (SourceFile->FileBufferPtr[0] == UNICODE_CR) {\r
- SourceFile->FileBufferPtr++;\r
- } else if (SourceFile->FileBufferPtr[0] == UNICODE_LF) {\r
- SourceFile->FileBufferPtr++;\r
- SourceFile->LineNum++;\r
- if (mGlobals.Verbose) {\r
- printf ("%d: %S\n", SourceFile->LineNum, SourceFile->FileBufferPtr);\r
- }\r
-\r
- InComment = FALSE;\r
- } else if (SourceFile->FileBufferPtr[0] == 0) {\r
- SourceFile->FileBufferPtr++;\r
- } else if (InComment) {\r
- SourceFile->FileBufferPtr++;\r
- } else if ((SourceFile->FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile->FileBufferPtr[1] == UNICODE_SLASH)) {\r
- SourceFile->FileBufferPtr += 2;\r
- InComment = TRUE;\r
- } else if (SourceFile->SkipToHash && (SourceFile->FileBufferPtr[0] != SourceFile->ControlCharacter)) {\r
- SourceFile->FileBufferPtr++;\r
- } else {\r
- SourceFile->SkipToHash = FALSE;\r
- if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
- ((Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"include")) > 0)\r
- ) {\r
- SourceFile->FileBufferPtr += Len + 1;\r
- ProcessTokenInclude (SourceFile);\r
- } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
- (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"scope")) > 0\r
- ) {\r
- SourceFile->FileBufferPtr += Len + 1;\r
- ProcessTokenScope (SourceFile);\r
- } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
- (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"language")) > 0\r
- ) {\r
- SourceFile->FileBufferPtr += Len + 1;\r
- ProcessTokenLanguage (SourceFile);\r
- } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
- (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"langdef")) > 0\r
- ) {\r
- SourceFile->FileBufferPtr += Len + 1;\r
- ProcessTokenLangDef (SourceFile);\r
- } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
- (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"string")) > 0\r
- ) {\r
- SourceFile->FileBufferPtr += Len + 1;\r
- ProcessTokenString (SourceFile);\r
- } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
- (Len = wstrcmp (SourceFile->FileBufferPtr + 1, L"EFI_BREAKPOINT()")) > 0\r
- ) {\r
- SourceFile->FileBufferPtr += Len;\r
- //\r
- // BUGBUG: Caling EFI_BREAKOINT() is breaking the link. What is the proper action for this tool\r
- // in this condition?\r
- //\r
-// EFI_BREAKPOINT ();\r
- } else if ((SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter) &&\r
- (SourceFile->FileBufferPtr[1] == UNICODE_EQUAL_SIGN)\r
- ) {\r
- SourceFile->ControlCharacter = SourceFile->FileBufferPtr[2];\r
- SourceFile->FileBufferPtr += 3;\r
- } else {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "unrecognized token", "%S", SourceFile->FileBufferPtr);\r
- //\r
- // Treat rest of line as a comment.\r
- //\r
- InComment = TRUE;\r
- }\r
- }\r
- }\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-static\r
-void\r
-PreprocessFile (\r
- SOURCE_FILE *SourceFile\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Preprocess a file to replace all carriage returns with NULLs so\r
- we can print lines from the file to the screen.\r
- \r
-Arguments:\r
- SourceFile - structure that we use to keep track of an input file.\r
-\r
-Returns:\r
- Nothing.\r
- \r
---*/\r
-{\r
- BOOLEAN InComment;\r
-\r
- RewindFile (SourceFile);\r
- InComment = FALSE;\r
- while (!EndOfFile (SourceFile)) {\r
- //\r
- // If a line-feed, then no longer in a comment\r
- //\r
- if (SourceFile->FileBufferPtr[0] == UNICODE_LF) {\r
- SourceFile->FileBufferPtr++;\r
- SourceFile->LineNum++;\r
- InComment = 0;\r
- } else if (SourceFile->FileBufferPtr[0] == UNICODE_CR) {\r
- //\r
- // Replace all carriage returns with a NULL so we can print stuff\r
- //\r
- SourceFile->FileBufferPtr[0] = 0;\r
- SourceFile->FileBufferPtr++;\r
- } else if (InComment) {\r
- SourceFile->FileBufferPtr[0] = UNICODE_SPACE;\r
- SourceFile->FileBufferPtr++;\r
- } else if ((SourceFile->FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile->FileBufferPtr[1] == UNICODE_SLASH)) {\r
- SourceFile->FileBufferPtr += 2;\r
- InComment = TRUE;\r
- } else {\r
- SourceFile->FileBufferPtr++;\r
- }\r
- }\r
- //\r
- // Could check for end-of-file and still in a comment, but\r
- // should not be necessary. So just restore the file pointers.\r
- //\r
- RewindFile (SourceFile);\r
-}\r
-\r
-static\r
-WCHAR *\r
-GetPrintableLanguageName (\r
- IN SOURCE_FILE *SourceFile\r
- )\r
-{\r
- WCHAR *String;\r
- WCHAR *Start;\r
- WCHAR *Ptr;\r
- UINT32 Len;\r
-\r
- SkipWhiteSpace (SourceFile);\r
- if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
- Error (\r
- SourceFile->FileName,\r
- SourceFile->LineNum,\r
- 0,\r
- "expected quoted printable language name",\r
- "%S",\r
- SourceFile->FileBufferPtr\r
- );\r
- SourceFile->SkipToHash = TRUE;\r
- return NULL;\r
- }\r
-\r
- Len = 0;\r
- SourceFile->FileBufferPtr++;\r
- Start = Ptr = SourceFile->FileBufferPtr;\r
- while (!EndOfFile (SourceFile)) {\r
- if (SourceFile->FileBufferPtr[0] == UNICODE_CR) {\r
- Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start);\r
- break;\r
- } else if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {\r
- break;\r
- }\r
-\r
- SourceFile->FileBufferPtr++;\r
- Len++;\r
- }\r
-\r
- if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
- Warning (\r
- SourceFile->FileName,\r
- SourceFile->LineNum,\r
- 0,\r
- "missing closing quote on printable language name string",\r
- "%S",\r
- Start\r
- );\r
- } else {\r
- SourceFile->FileBufferPtr++;\r
- }\r
- //\r
- // Now allocate memory for the string and save it off\r
- //\r
- String = (WCHAR *) malloc ((Len + 1) * sizeof (WCHAR));\r
- if (String == NULL) {\r
- Error (NULL, 0, 0, "memory allocation failed", NULL);\r
- return NULL;\r
- }\r
- //\r
- // Copy the string from the file buffer to the local copy.\r
- // We do no reformatting of it whatsoever at this point.\r
- //\r
- Ptr = String;\r
- while (Len > 0) {\r
- *Ptr = *Start;\r
- Start++;\r
- Ptr++;\r
- Len--;\r
- }\r
-\r
- *Ptr = 0;\r
- //\r
- // Now format the string to convert \wide and \narrow controls\r
- //\r
- StringDBFormatString (String);\r
- return String;\r
-}\r
-\r
-static\r
-WCHAR *\r
-GetQuotedString (\r
- SOURCE_FILE *SourceFile,\r
- BOOLEAN Optional\r
- )\r
-{\r
- WCHAR *String;\r
- WCHAR *Start;\r
- WCHAR *Ptr;\r
- UINT32 Len;\r
- BOOLEAN PreviousBackslash;\r
-\r
- if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
- if (!Optional) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted string", "%S", SourceFile->FileBufferPtr);\r
- }\r
-\r
- return NULL;\r
- }\r
-\r
- Len = 0;\r
- SourceFile->FileBufferPtr++;\r
- Start = Ptr = SourceFile->FileBufferPtr;\r
- PreviousBackslash = FALSE;\r
- while (!EndOfFile (SourceFile)) {\r
- if ((SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) && (!PreviousBackslash)) {\r
- break;\r
- } else if (SourceFile->FileBufferPtr[0] == UNICODE_CR) {\r
- Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start);\r
- PreviousBackslash = FALSE;\r
- } else if (SourceFile->FileBufferPtr[0] == UNICODE_BACKSLASH) {\r
- PreviousBackslash = TRUE;\r
- } else {\r
- PreviousBackslash = FALSE;\r
- }\r
-\r
- SourceFile->FileBufferPtr++;\r
- Len++;\r
- }\r
-\r
- if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
- Warning (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", "%S", Start);\r
- } else {\r
- SourceFile->FileBufferPtr++;\r
- }\r
- //\r
- // Now allocate memory for the string and save it off\r
- //\r
- String = (WCHAR *) malloc ((Len + 1) * sizeof (WCHAR));\r
- if (String == NULL) {\r
- Error (NULL, 0, 0, "memory allocation failed", NULL);\r
- return NULL;\r
- }\r
- //\r
- // Copy the string from the file buffer to the local copy.\r
- // We do no reformatting of it whatsoever at this point.\r
- //\r
- Ptr = String;\r
- while (Len > 0) {\r
- *Ptr = *Start;\r
- Start++;\r
- Ptr++;\r
- Len--;\r
- }\r
-\r
- *Ptr = 0;\r
- return String;\r
-}\r
-//\r
-// Parse:\r
-// #string STR_ID_NAME\r
-//\r
-// All we can do is call the string database to add the string identifier. Unfortunately\r
-// he'll have to keep track of the last identifier we added.\r
-//\r
-static\r
-void\r
-ProcessTokenString (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- WCHAR StringIdentifier[MAX_STRING_IDENTIFIER_NAME];\r
- UINT16 StringId;\r
- //\r
- // Extract the string identifier name and add it to the database.\r
- //\r
- if (GetStringIdentifierName (SourceFile, StringIdentifier, sizeof (StringIdentifier)) > 0) {\r
- StringId = STRING_ID_INVALID;\r
- StringDBAddStringIdentifier (StringIdentifier, &StringId, 0);\r
- } else {\r
- //\r
- // Error recovery -- skip to the next #\r
- //\r
- SourceFile->SkipToHash = TRUE;\r
- }\r
-}\r
-\r
-static\r
-BOOLEAN\r
-EndOfFile (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- //\r
- // The file buffer pointer will typically get updated before the End-of-file flag in the\r
- // source file structure, so check it first.\r
- //\r
- if (SourceFile->FileBufferPtr >= SourceFile->FileBuffer + SourceFile->FileSize / sizeof (WCHAR)) {\r
- SourceFile->EndOfFile = TRUE;\r
- return TRUE;\r
- }\r
-\r
- if (SourceFile->EndOfFile) {\r
- return TRUE;\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-static\r
-UINT32\r
-GetStringIdentifierName (\r
- IN SOURCE_FILE *SourceFile,\r
- IN OUT WCHAR *StringIdentifierName,\r
- IN UINT32 StringIdentifierNameLen\r
- )\r
-{\r
- UINT32 Len;\r
- WCHAR *From;\r
- WCHAR *Start;\r
-\r
- //\r
- // Skip whitespace\r
- //\r
- SkipWhiteSpace (SourceFile);\r
- if (SourceFile->EndOfFile) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-file encountered", "expected string identifier");\r
- return 0;\r
- }\r
- //\r
- // Verify first character of name is [A-Za-z]\r
- //\r
- Len = 0;\r
- StringIdentifierNameLen /= 2;\r
- From = SourceFile->FileBufferPtr;\r
- Start = SourceFile->FileBufferPtr;\r
- if (((SourceFile->FileBufferPtr[0] >= UNICODE_A) && (SourceFile->FileBufferPtr[0] <= UNICODE_Z)) ||\r
- ((SourceFile->FileBufferPtr[0] >= UNICODE_z) && (SourceFile->FileBufferPtr[0] <= UNICODE_z))\r
- ) {\r
- //\r
- // Do nothing\r
- //\r
- } else {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid character in string identifier name", "%S", Start);\r
- return 0;\r
- }\r
-\r
- while (!EndOfFile (SourceFile)) {\r
- if (((SourceFile->FileBufferPtr[0] >= UNICODE_A) && (SourceFile->FileBufferPtr[0] <= UNICODE_Z)) ||\r
- ((SourceFile->FileBufferPtr[0] >= UNICODE_z) && (SourceFile->FileBufferPtr[0] <= UNICODE_z)) ||\r
- ((SourceFile->FileBufferPtr[0] >= UNICODE_0) && (SourceFile->FileBufferPtr[0] <= UNICODE_9)) ||\r
- (SourceFile->FileBufferPtr[0] == UNICODE_UNDERSCORE)\r
- ) {\r
- Len++;\r
- if (Len >= StringIdentifierNameLen) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "string identifier name too long", "%S", Start);\r
- return 0;\r
- }\r
-\r
- *StringIdentifierName = SourceFile->FileBufferPtr[0];\r
- StringIdentifierName++;\r
- SourceFile->FileBufferPtr++;\r
- } else if (SkipWhiteSpace (SourceFile) == 0) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid string identifier name", "%S", Start);\r
- return 0;\r
- } else {\r
- break;\r
- }\r
- }\r
- //\r
- // Terminate the copy of the string.\r
- //\r
- *StringIdentifierName = 0;\r
- return Len;\r
-}\r
-\r
-static\r
-UINT32\r
-GetLanguageIdentifierName (\r
- IN SOURCE_FILE *SourceFile,\r
- IN OUT WCHAR *LanguageIdentifierName,\r
- IN UINT32 LanguageIdentifierNameLen,\r
- IN BOOLEAN Optional\r
- )\r
-{\r
- UINT32 Len;\r
- WCHAR *From;\r
- WCHAR *Start;\r
- //\r
- // Skip whitespace\r
- //\r
- SkipWhiteSpace (SourceFile);\r
- if (SourceFile->EndOfFile) {\r
- if (!Optional) {\r
- Error (\r
- SourceFile->FileName,\r
- SourceFile->LineNum,\r
- 0,\r
- "end-of-file encountered",\r
- "expected language identifier"\r
- );\r
- }\r
-\r
- return 0;\r
- }\r
- //\r
- // This function is called to optionally get a language identifier name in:\r
- // #string STR_ID eng "the string"\r
- // If it's optional, and we find a double-quote, then return now.\r
- //\r
- if (Optional) {\r
- if (*SourceFile->FileBufferPtr == UNICODE_DOUBLE_QUOTE) {\r
- return 0;\r
- }\r
- }\r
-\r
- Len = 0;\r
- LanguageIdentifierNameLen /= 2;\r
- //\r
- // Internal error if we weren't given at least 4 WCHAR's to work with.\r
- //\r
- if (LanguageIdentifierNameLen < LANGUAGE_IDENTIFIER_NAME_LEN + 1) {\r
- Error (\r
- SourceFile->FileName,\r
- SourceFile->LineNum,\r
- 0,\r
- "app error -- language identifier name length is invalid",\r
- NULL\r
- );\r
- }\r
-\r
- From = SourceFile->FileBufferPtr;\r
- Start = SourceFile->FileBufferPtr;\r
- while (!EndOfFile (SourceFile)) {\r
- if (((SourceFile->FileBufferPtr[0] >= UNICODE_a) && (SourceFile->FileBufferPtr[0] <= UNICODE_z))) {\r
- Len++;\r
- if (Len > LANGUAGE_IDENTIFIER_NAME_LEN) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "language identifier name too long", "%S", Start);\r
- return 0;\r
- }\r
-\r
- *LanguageIdentifierName = SourceFile->FileBufferPtr[0];\r
- SourceFile->FileBufferPtr++;\r
- LanguageIdentifierName++;\r
- } else if (!IsWhiteSpace (SourceFile)) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid language identifier name", "%S", Start);\r
- return 0;\r
- } else {\r
- break;\r
- }\r
- }\r
- //\r
- // Terminate the copy of the string.\r
- //\r
- *LanguageIdentifierName = 0;\r
- return Len;\r
-}\r
-\r
-static\r
-void\r
-ProcessTokenInclude (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- CHAR8 IncludeFileName[MAX_PATH];\r
- CHAR8 *To;\r
- UINT32 Len;\r
- BOOLEAN ReportedError;\r
- SOURCE_FILE IncludedSourceFile;\r
-\r
- ReportedError = FALSE;\r
- if (SkipWhiteSpace (SourceFile) == 0) {\r
- Warning (SourceFile->FileName, SourceFile->LineNum, 0, "expected whitespace following #include keyword", NULL);\r
- }\r
- //\r
- // Should be quoted file name\r
- //\r
- if (SourceFile->FileBufferPtr[0] != UNICODE_DOUBLE_QUOTE) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted include file name", NULL);\r
- goto FailDone;\r
- }\r
-\r
- SourceFile->FileBufferPtr++;\r
- //\r
- // Copy the filename as ascii to our local string\r
- //\r
- To = IncludeFileName;\r
- Len = 0;\r
- while (!EndOfFile (SourceFile)) {\r
- if ((SourceFile->FileBufferPtr[0] == UNICODE_CR) || (SourceFile->FileBufferPtr[0] == UNICODE_LF)) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-line found in quoted include file name", NULL);\r
- goto FailDone;\r
- }\r
-\r
- if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {\r
- SourceFile->FileBufferPtr++;\r
- break;\r
- }\r
- //\r
- // If too long, then report the error once and process until the closing quote\r
- //\r
- Len++;\r
- if (!ReportedError && (Len >= sizeof (IncludeFileName))) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "length of include file name exceeds limit", NULL);\r
- ReportedError = TRUE;\r
- }\r
-\r
- if (!ReportedError) {\r
- *To = UNICODE_TO_ASCII (SourceFile->FileBufferPtr[0]);\r
- To++;\r
- }\r
-\r
- SourceFile->FileBufferPtr++;\r
- }\r
-\r
- if (!ReportedError) {\r
- *To = 0;\r
- memset ((char *) &IncludedSourceFile, 0, sizeof (SOURCE_FILE));\r
- strcpy (IncludedSourceFile.FileName, IncludeFileName);\r
- IncludedSourceFile.ControlCharacter = DEFAULT_CONTROL_CHARACTER;\r
- ProcessIncludeFile (&IncludedSourceFile, SourceFile);\r
- //\r
- // printf ("including file '%s'\n", IncludeFileName);\r
- //\r
- }\r
-\r
- return ;\r
-FailDone:\r
- //\r
- // Error recovery -- skip to next #\r
- //\r
- SourceFile->SkipToHash = TRUE;\r
-}\r
-\r
-static\r
-void\r
-ProcessTokenScope (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- WCHAR StringIdentifier[MAX_STRING_IDENTIFIER_NAME];\r
- //\r
- // Extract the scope name\r
- //\r
- if (GetStringIdentifierName (SourceFile, StringIdentifier, sizeof (StringIdentifier)) > 0) {\r
- StringDBSetScope (StringIdentifier);\r
- }\r
-}\r
-//\r
-// Parse: #langdef eng "English"\r
-// #langdef chn "\wideChinese"\r
-//\r
-static\r
-void\r
-ProcessTokenLangDef (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- WCHAR LanguageIdentifier[MAX_STRING_IDENTIFIER_NAME];\r
- UINT32 Len;\r
- WCHAR *PrintableName;\r
- //\r
- // Extract the 3-character language identifier\r
- //\r
- Len = GetLanguageIdentifierName (SourceFile, LanguageIdentifier, sizeof (LanguageIdentifier), FALSE);\r
- if (Len != LANGUAGE_IDENTIFIER_NAME_LEN) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid or missing language identifier", NULL);\r
- } else {\r
- //\r
- // Extract the printable name\r
- //\r
- PrintableName = GetPrintableLanguageName (SourceFile);\r
- if (PrintableName != NULL) {\r
- ParserSetPosition (SourceFile->FileName, SourceFile->LineNum);\r
- StringDBAddLanguage (LanguageIdentifier, PrintableName);\r
- free (PrintableName);\r
- return ;\r
- }\r
- }\r
- //\r
- // Error recovery -- skip to next #\r
- //\r
- SourceFile->SkipToHash = TRUE;\r
-}\r
-\r
-static\r
-BOOLEAN\r
-ApparentQuotedString (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- WCHAR *Ptr;\r
- //\r
- // See if the first and last nonblank characters on the line are double quotes\r
- //\r
- for (Ptr = SourceFile->FileBufferPtr; *Ptr && (*Ptr == UNICODE_SPACE); Ptr++)\r
- ;\r
- if (*Ptr != UNICODE_DOUBLE_QUOTE) {\r
- return FALSE;\r
- }\r
-\r
- while (*Ptr) {\r
- Ptr++;\r
- }\r
-\r
- Ptr--;\r
- for (; *Ptr && (*Ptr == UNICODE_SPACE); Ptr--)\r
- ;\r
- if (*Ptr != UNICODE_DOUBLE_QUOTE) {\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-//\r
-// Parse:\r
-// #language eng "some string " "more string"\r
-//\r
-static\r
-void\r
-ProcessTokenLanguage (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- WCHAR *String;\r
- WCHAR *SecondString;\r
- WCHAR *TempString;\r
- WCHAR *From;\r
- WCHAR *To;\r
- WCHAR Language[LANGUAGE_IDENTIFIER_NAME_LEN + 1];\r
- UINT32 Len;\r
- BOOLEAN PreviousNewline;\r
- //\r
- // Get the language identifier\r
- //\r
- Language[0] = 0;\r
- Len = GetLanguageIdentifierName (SourceFile, Language, sizeof (Language), TRUE);\r
- if (Len != LANGUAGE_IDENTIFIER_NAME_LEN) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid or missing language identifier", "%S", Language);\r
- SourceFile->SkipToHash = TRUE;\r
- return ;\r
- }\r
- //\r
- // Extract the string value. It's either a quoted string that starts on the current line, or\r
- // an unquoted string that starts on the following line and continues until the next control\r
- // character in column 1.\r
- // Look ahead to find a quote or a newline\r
- //\r
- if (SkipTo (SourceFile, UNICODE_DOUBLE_QUOTE, TRUE)) {\r
- String = GetQuotedString (SourceFile, FALSE);\r
- if (String != NULL) {\r
- //\r
- // Set the position in the file of where we are parsing for error\r
- // reporting purposes. Then start looking ahead for additional\r
- // quoted strings, and concatenate them until we get a failure\r
- // back from the string parser.\r
- //\r
- Len = StrLen (String) + 1;\r
- ParserSetPosition (SourceFile->FileName, SourceFile->LineNum);\r
- do {\r
- SkipWhiteSpace (SourceFile);\r
- SecondString = GetQuotedString (SourceFile, TRUE);\r
- if (SecondString != NULL) {\r
- Len += StrLen (SecondString);\r
- TempString = (WCHAR *) malloc (Len * sizeof (WCHAR));\r
- if (TempString == NULL) {\r
- Error (NULL, 0, 0, "application error", "failed to allocate memory");\r
- return ;\r
- }\r
-\r
- StrCpy (TempString, String);\r
- StrCat (TempString, SecondString);\r
- free (String);\r
- free (SecondString);\r
- String = TempString;\r
- }\r
- } while (SecondString != NULL);\r
- StringDBAddString (Language, NULL, NULL, String, TRUE, 0);\r
- free (String);\r
- } else {\r
- //\r
- // Error was reported at lower level. Error recovery mode.\r
- //\r
- SourceFile->SkipToHash = TRUE;\r
- }\r
- } else {\r
- if (!mGlobals.UnquotedStrings) {\r
- //\r
- // They're using unquoted strings. If the next non-blank character is a double quote, and the\r
- // last non-blank character on the line is a double quote, then more than likely they're using\r
- // quotes, so they need to put the quoted string on the end of the previous line\r
- //\r
- if (ApparentQuotedString (SourceFile)) {\r
- Warning (\r
- SourceFile->FileName,\r
- SourceFile->LineNum,\r
- 0,\r
- "unexpected quoted string on line",\r
- "specify -uqs option if necessary"\r
- );\r
- }\r
- }\r
- //\r
- // Found end-of-line (hopefully). Skip over it and start taking in characters\r
- // until we find a control character at the start of a line.\r
- //\r
- Len = 0;\r
- From = SourceFile->FileBufferPtr;\r
- PreviousNewline = FALSE;\r
- while (!EndOfFile (SourceFile)) {\r
- if (SourceFile->FileBufferPtr[0] == UNICODE_LF) {\r
- PreviousNewline = TRUE;\r
- SourceFile->LineNum++;\r
- } else {\r
- Len++;\r
- if (PreviousNewline && (SourceFile->FileBufferPtr[0] == SourceFile->ControlCharacter)) {\r
- break;\r
- }\r
-\r
- PreviousNewline = FALSE;\r
- }\r
-\r
- SourceFile->FileBufferPtr++;\r
- }\r
-\r
- if ((Len == 0) && EndOfFile (SourceFile)) {\r
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "unexpected end of file", NULL);\r
- SourceFile->SkipToHash = TRUE;\r
- return ;\r
- }\r
- //\r
- // Now allocate a buffer, copy the characters, and add the string.\r
- //\r
- String = (WCHAR *) malloc ((Len + 1) * sizeof (WCHAR));\r
- if (String == NULL) {\r
- Error (NULL, 0, 0, "application error", "failed to allocate memory");\r
- return ;\r
- }\r
-\r
- To = String;\r
- while (From < SourceFile->FileBufferPtr) {\r
- switch (*From) {\r
- case UNICODE_LF:\r
- case 0:\r
- break;\r
-\r
- default:\r
- *To = *From;\r
- To++;\r
- break;\r
- }\r
-\r
- From++;\r
- }\r
-\r
- //\r
- // String[Len] = 0;\r
- //\r
- *To = 0;\r
- StringDBAddString (Language, NULL, NULL, String, TRUE, 0);\r
- }\r
-}\r
-\r
-static\r
-BOOLEAN\r
-IsWhiteSpace (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- switch (SourceFile->FileBufferPtr[0]) {\r
- case UNICODE_NULL:\r
- case UNICODE_CR:\r
- case UNICODE_SPACE:\r
- case UNICODE_TAB:\r
- case UNICODE_LF:\r
- return TRUE;\r
-\r
- default:\r
- return FALSE;\r
- }\r
-}\r
-\r
-static\r
-UINT32\r
-SkipWhiteSpace (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- UINT32 Count;\r
-\r
- Count = 0;\r
- while (!EndOfFile (SourceFile)) {\r
- Count++;\r
- switch (*SourceFile->FileBufferPtr) {\r
- case UNICODE_NULL:\r
- case UNICODE_CR:\r
- case UNICODE_SPACE:\r
- case UNICODE_TAB:\r
- SourceFile->FileBufferPtr++;\r
- break;\r
-\r
- case UNICODE_LF:\r
- SourceFile->FileBufferPtr++;\r
- SourceFile->LineNum++;\r
- if (mGlobals.Verbose) {\r
- printf ("%d: %S\n", SourceFile->LineNum, SourceFile->FileBufferPtr);\r
- }\r
- break;\r
-\r
- default:\r
- return Count - 1;\r
- }\r
- }\r
- //\r
- // Some tokens require trailing whitespace. If we're at the end of the\r
- // file, then we count that as well.\r
- //\r
- if ((Count == 0) && (EndOfFile (SourceFile))) {\r
- Count++;\r
- }\r
-\r
- return Count;\r
-}\r
-\r
-static\r
-UINT32\r
-wstrcmp (\r
- WCHAR *Buffer,\r
- WCHAR *Str\r
- )\r
-{\r
- UINT32 Len;\r
-\r
- Len = 0;\r
- while (*Str == *Buffer) {\r
- Buffer++;\r
- Str++;\r
- Len++;\r
- }\r
-\r
- if (*Str) {\r
- return 0;\r
- }\r
-\r
- return Len;\r
-}\r
-//\r
-// Given a filename, try to find it along the include paths.\r
-//\r
-static\r
-FILE *\r
-FindFile (\r
- IN CHAR8 *FileName,\r
- OUT CHAR8 *FoundFileName,\r
- IN UINT32 FoundFileNameLen\r
- )\r
-{\r
- FILE *Fptr;\r
- TEXT_STRING_LIST *List;\r
-\r
- //\r
- // Traverse the list of paths and try to find the file\r
- //\r
- List = mGlobals.IncludePaths;\r
- while (List != NULL) {\r
- //\r
- // Put the path and filename together\r
- //\r
- if (strlen (List->Str) + strlen (FileName) + 1 > FoundFileNameLen) {\r
- Error (PROGRAM_NAME, 0, 0, NULL, "internal error - cannot concatenate path+filename");\r
- return NULL;\r
- }\r
- //\r
- // Append the filename to this include path and try to open the file.\r
- //\r
- strcpy (FoundFileName, List->Str);\r
- strcat (FoundFileName, FileName);\r
- if ((Fptr = fopen (FoundFileName, "rb")) != NULL) {\r
- //\r
- // Return the file pointer\r
- //\r
- return Fptr;\r
- }\r
-\r
- List = List->Next;\r
- }\r
- //\r
- // Not found\r
- //\r
- FoundFileName[0] = 0;\r
- return NULL;\r
-}\r
-//\r
-// Process the command-line arguments\r
-//\r
-static\r
-STATUS\r
-ProcessArgs (\r
- int Argc,\r
- char *Argv[]\r
- )\r
-{\r
- TEXT_STRING_LIST *NewList;\r
- //\r
- // Clear our globals\r
- //\r
- memset ((char *) &mGlobals, 0, sizeof (mGlobals));\r
- strcpy (mGlobals.BaseName, DEFAULT_BASE_NAME);\r
- //\r
- // Skip program name\r
- //\r
- Argc--;\r
- Argv++;\r
-\r
- if (Argc == 0) {\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- mGlobals.Mode = MODE_UNKNOWN;\r
- //\r
- // Process until no more -args.\r
- //\r
- while ((Argc > 0) && (Argv[0][0] == '-')) {\r
- //\r
- // -parse option\r
- //\r
- if (stricmp (Argv[0], "-parse") == 0) {\r
- if (mGlobals.Mode != MODE_UNKNOWN) {\r
- Error (NULL, 0, 0, "only one of -parse/-scan/-dump allowed", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- mGlobals.Mode = MODE_PARSE;\r
- //\r
- // -scan option\r
- //\r
- } else if (stricmp (Argv[0], "-scan") == 0) {\r
- if (mGlobals.Mode != MODE_UNKNOWN) {\r
- Error (NULL, 0, 0, "only one of -parse/-scan/-dump allowed", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- mGlobals.Mode = MODE_SCAN;\r
- //\r
- // -vscan verbose scanning option\r
- //\r
- } else if (stricmp (Argv[0], "-vscan") == 0) {\r
- mGlobals.VerboseScan = TRUE;\r
- //\r
- // -dump option\r
- //\r
- } else if (stricmp (Argv[0], "-dump") == 0) {\r
- if (mGlobals.Mode != MODE_UNKNOWN) {\r
- Error (NULL, 0, 0, "only one of -parse/-scan/-dump allowed", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- mGlobals.Mode = MODE_DUMP;\r
- } else if (stricmp (Argv[0], "-uqs") == 0) {\r
- mGlobals.UnquotedStrings = TRUE;\r
- //\r
- // -i path add include search path when parsing\r
- //\r
- } else if (stricmp (Argv[0], "-i") == 0) {\r
- //\r
- // check for one more arg\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing include path");\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Allocate memory for a new list element, fill it in, and\r
- // add it to our list of include paths. Always make sure it\r
- // has a "\" on the end of it.\r
- //\r
- NewList = malloc (sizeof (TEXT_STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- memset ((char *) NewList, 0, sizeof (TEXT_STRING_LIST));\r
- NewList->Str = malloc (strlen (Argv[1]) + 2);\r
- if (NewList->Str == NULL) {\r
- free (NewList);\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (NewList->Str, Argv[1]);\r
- if (NewList->Str[strlen (NewList->Str) - 1] != '\\') {\r
- strcat (NewList->Str, "\\");\r
- }\r
- //\r
- // Add it to our linked list\r
- //\r
- if (mGlobals.IncludePaths == NULL) {\r
- mGlobals.IncludePaths = NewList;\r
- } else {\r
- mGlobals.LastIncludePath->Next = NewList;\r
- }\r
-\r
- mGlobals.LastIncludePath = NewList;\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-if") == 0) {\r
- //\r
- // Indirection file -- check for one more arg\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing indirection file name");\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Allocate memory for a new list element, fill it in, and\r
- // add it to our list of include paths. Always make sure it\r
- // has a "\" on the end of it.\r
- //\r
- NewList = malloc (sizeof (TEXT_STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- memset ((char *) NewList, 0, sizeof (TEXT_STRING_LIST));\r
- NewList->Str = malloc (strlen (Argv[1]) + 1);\r
- if (NewList->Str == NULL) {\r
- free (NewList);\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (NewList->Str, Argv[1]);\r
- //\r
- // Add it to our linked list\r
- //\r
- if (mGlobals.IndirectionFileName == NULL) {\r
- mGlobals.IndirectionFileName = NewList;\r
- } else {\r
- mGlobals.LastIndirectionFileName->Next = NewList;\r
- }\r
-\r
- mGlobals.LastIndirectionFileName = NewList;\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-db") == 0) {\r
- //\r
- // -db option to specify a database file.\r
- // Check for one more arg (the database file name)\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing database file name");\r
- return STATUS_ERROR;\r
- }\r
-\r
- NewList = malloc (sizeof (TEXT_STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- memset ((char *) NewList, 0, sizeof (TEXT_STRING_LIST));\r
- NewList->Str = malloc (strlen (Argv[1]) + 1);\r
- if (NewList->Str == NULL) {\r
- free (NewList);\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (NewList->Str, Argv[1]);\r
- //\r
- // Add it to our linked list\r
- //\r
- if (mGlobals.DatabaseFileName == NULL) {\r
- mGlobals.DatabaseFileName = NewList;\r
- } else {\r
- mGlobals.LastDatabaseFileName->Next = NewList;\r
- }\r
-\r
- mGlobals.LastDatabaseFileName = NewList;\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-ou") == 0) {\r
- //\r
- // -ou option to specify an output unicode file to\r
- // which we can dump our database.\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing database dump output file name");\r
- return STATUS_ERROR;\r
- }\r
-\r
- if (mGlobals.DumpUFileName[0] == 0) {\r
- strcpy (mGlobals.DumpUFileName, Argv[1]);\r
- } else {\r
- Error (PROGRAM_NAME, 0, 0, Argv[1], "-ou option already specified with '%s'", mGlobals.DumpUFileName);\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-hpk") == 0) {\r
- //\r
- // -hpk option to create an HII export pack of the input database file\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing raw string data dump output file name");\r
- return STATUS_ERROR;\r
- }\r
-\r
- if (mGlobals.HiiExportPackFileName[0] == 0) {\r
- strcpy (mGlobals.HiiExportPackFileName, Argv[1]);\r
- } else {\r
- Error (PROGRAM_NAME, 0, 0, Argv[1], "-or option already specified with '%s'", mGlobals.HiiExportPackFileName);\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
- } else if ((stricmp (Argv[0], "-?") == 0) || (stricmp (Argv[0], "-h") == 0)) {\r
- Usage ();\r
- return STATUS_ERROR;\r
- } else if (stricmp (Argv[0], "-v") == 0) {\r
- mGlobals.Verbose = 1;\r
- } else if (stricmp (Argv[0], "-vdbw") == 0) {\r
- mGlobals.VerboseDatabaseWrite = 1;\r
- } else if (stricmp (Argv[0], "-vdbr") == 0) {\r
- mGlobals.VerboseDatabaseRead = 1;\r
- } else if (stricmp (Argv[0], "-newdb") == 0) {\r
- mGlobals.NewDatabase = 1;\r
- } else if (stricmp (Argv[0], "-ignorenotfound") == 0) {\r
- mGlobals.IgnoreNotFound = 1;\r
- } else if (stricmp (Argv[0], "-oc") == 0) {\r
- //\r
- // check for one more arg\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output C filename");\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (mGlobals.StringCFileName, Argv[1]);\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-bn") == 0) {\r
- //\r
- // check for one more arg\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing base name");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (mGlobals.BaseName, Argv[1]);\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-oh") == 0) {\r
- //\r
- // -oh to specify output .h defines file name\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output .h filename");\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (mGlobals.StringHFileName, Argv[1]);\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-skipext") == 0) {\r
- //\r
- // -skipext to skip scanning of files with certain filename extensions\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing filename extension");\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Allocate memory for a new list element, fill it in, and\r
- // add it to our list of excluded extensions. Always make sure it\r
- // has a "." as the first character.\r
- //\r
- NewList = malloc (sizeof (TEXT_STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- memset ((char *) NewList, 0, sizeof (TEXT_STRING_LIST));\r
- NewList->Str = malloc (strlen (Argv[1]) + 2);\r
- if (NewList->Str == NULL) {\r
- free (NewList);\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- if (Argv[1][0] == '.') {\r
- strcpy (NewList->Str, Argv[1]);\r
- } else {\r
- NewList->Str[0] = '.';\r
- strcpy (NewList->Str + 1, Argv[1]);\r
- }\r
- //\r
- // Add it to our linked list\r
- //\r
- if (mGlobals.SkipExt == NULL) {\r
- mGlobals.SkipExt = NewList;\r
- } else {\r
- mGlobals.LastSkipExt->Next = NewList;\r
- }\r
-\r
- mGlobals.LastSkipExt = NewList;\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-lang") == 0) {\r
- //\r
- // "-lang eng" or "-lang spa+cat" to only output certain languages\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing language name");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- if (AddCommandLineLanguage (Argv[1]) != STATUS_SUCCESS) {\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-od") == 0) {\r
- //\r
- // Output database file name -- check for another arg\r
- //\r
- if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output database file name");\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (mGlobals.OutputDatabaseFileName, Argv[1]);\r
- Argv++;\r
- Argc--;\r
- } else {\r
- //\r
- // Unrecognized arg\r
- //\r
- Error (PROGRAM_NAME, 0, 0, Argv[0], "unrecognized option");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argv++;\r
- Argc--;\r
- }\r
- //\r
- // Make sure they specified the mode parse/scan/dump\r
- //\r
- if (mGlobals.Mode == MODE_UNKNOWN) {\r
- Error (NULL, 0, 0, "must specify one of -parse/-scan/-dump", NULL);\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // All modes require a database filename\r
- //\r
- if (mGlobals.DatabaseFileName == 0) {\r
- Error (NULL, 0, 0, "must specify a database filename using -db DbFileName", NULL);\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // If dumping the database file, then return immediately if all\r
- // parameters check out.\r
- //\r
- if (mGlobals.Mode == MODE_DUMP) {\r
- //\r
- // Not much use if they didn't specify -oh or -oc or -ou or -hpk\r
- //\r
- if ((mGlobals.DumpUFileName[0] == 0) &&\r
- (mGlobals.StringHFileName[0] == 0) &&\r
- (mGlobals.StringCFileName[0] == 0) &&\r
- (mGlobals.HiiExportPackFileName[0] == 0)\r
- ) {\r
- Error (NULL, 0, 0, "-dump without -oc/-oh/-ou/-hpk is a NOP", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- return STATUS_SUCCESS;\r
- }\r
- //\r
- // Had to specify source string file and output string defines header filename.\r
- //\r
- if (mGlobals.Mode == MODE_SCAN) {\r
- if (Argc < 1) {\r
- Error (PROGRAM_NAME, 0, 0, NULL, "must specify at least one source file to scan with -scan");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Get the list of filenames\r
- //\r
- while (Argc > 0) {\r
- NewList = malloc (sizeof (TEXT_STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (PROGRAM_NAME, 0, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- memset (NewList, 0, sizeof (TEXT_STRING_LIST));\r
- NewList->Str = (CHAR8 *) malloc (strlen (Argv[0]) + 1);\r
- if (NewList->Str == NULL) {\r
- Error (PROGRAM_NAME, 0, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (NewList->Str, Argv[0]);\r
- if (mGlobals.ScanFileName == NULL) {\r
- mGlobals.ScanFileName = NewList;\r
- } else {\r
- mGlobals.LastScanFileName->Next = NewList;\r
- }\r
-\r
- mGlobals.LastScanFileName = NewList;\r
- Argc--;\r
- Argv++;\r
- }\r
- } else {\r
- //\r
- // Parse mode -- must specify an input unicode file name\r
- //\r
- if (Argc < 1) {\r
- Error (PROGRAM_NAME, 0, 0, NULL, "must specify input unicode string file name with -parse");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (mGlobals.SourceFiles.FileName, Argv[0]);\r
- }\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-//\r
-// Found "-lang eng,spa+cat" on the command line. Parse the\r
-// language list and save the setting for later processing.\r
-//\r
-static\r
-STATUS\r
-AddCommandLineLanguage (\r
- IN CHAR8 *Language\r
- )\r
-{\r
- WCHAR_STRING_LIST *WNewList;\r
- WCHAR *From;\r
- WCHAR *To;\r
- //\r
- // Keep processing the input string until we find the end.\r
- //\r
- while (*Language) {\r
- //\r
- // Allocate memory for a new list element, fill it in, and\r
- // add it to our list.\r
- //\r
- WNewList = MALLOC (sizeof (WCHAR_STRING_LIST));\r
- if (WNewList == NULL) {\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
-\r
- memset ((char *) WNewList, 0, sizeof (WCHAR_STRING_LIST));\r
- WNewList->Str = malloc ((strlen (Language) + 1) * sizeof (WCHAR));\r
- if (WNewList->Str == NULL) {\r
- free (WNewList);\r
- Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Copy it as unicode to our new structure. Then remove the\r
- // plus signs in it, and verify each language name is 3 characters\r
- // long. If we find a comma, then we're done with this group, so\r
- // break out.\r
- //\r
- UnicodeSPrint (WNewList->Str, (strlen (Language) + 1) * sizeof (WCHAR), L"%a", Language);\r
- From = To = WNewList->Str;\r
- while (*From) {\r
- if (*From == L',') {\r
- break;\r
- }\r
-\r
- if ((StrLen (From) < LANGUAGE_IDENTIFIER_NAME_LEN) ||\r
- (\r
- (From[LANGUAGE_IDENTIFIER_NAME_LEN] != 0) &&\r
- (From[LANGUAGE_IDENTIFIER_NAME_LEN] != UNICODE_PLUS_SIGN) &&\r
- (From[LANGUAGE_IDENTIFIER_NAME_LEN] != L',')\r
- )\r
- ) {\r
- Error (PROGRAM_NAME, 0, 0, Language, "invalid format for language name on command line");\r
- FREE (WNewList->Str);\r
- FREE (WNewList);\r
- return STATUS_ERROR;\r
- }\r
-\r
- StrnCpy (To, From, LANGUAGE_IDENTIFIER_NAME_LEN);\r
- To += LANGUAGE_IDENTIFIER_NAME_LEN;\r
- From += LANGUAGE_IDENTIFIER_NAME_LEN;\r
- if (*From == L'+') {\r
- From++;\r
- }\r
- }\r
-\r
- *To = 0;\r
- //\r
- // Add it to our linked list\r
- //\r
- if (mGlobals.Language == NULL) {\r
- mGlobals.Language = WNewList;\r
- } else {\r
- mGlobals.LastLanguage->Next = WNewList;\r
- }\r
-\r
- mGlobals.LastLanguage = WNewList;\r
- //\r
- // Skip to next entry (comma-separated list)\r
- //\r
- while (*Language) {\r
- if (*Language == L',') {\r
- Language++;\r
- break;\r
- }\r
-\r
- Language++;\r
- }\r
- }\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-//\r
-// The contents of the text file are expected to be (one per line)\r
-// STRING_IDENTIFIER_NAME ScopeName\r
-// For example:\r
-// STR_ID_MY_FAVORITE_STRING IBM\r
-//\r
-static\r
-STATUS\r
-ParseIndirectionFiles (\r
- TEXT_STRING_LIST *Files\r
- )\r
-{\r
- FILE *Fptr;\r
- CHAR8 Line[200];\r
- CHAR8 *StringName;\r
- CHAR8 *ScopeName;\r
- CHAR8 *End;\r
- UINT32 LineCount;\r
- WCHAR_MATCHING_STRING_LIST *NewList;\r
-\r
- Line[sizeof (Line) - 1] = 0;\r
- Fptr = NULL;\r
- while (Files != NULL) {\r
- Fptr = fopen (Files->Str, "r");\r
- LineCount = 0;\r
- if (Fptr == NULL) {\r
- Error (NULL, 0, 0, Files->Str, "failed to open input indirection file for reading");\r
- return STATUS_ERROR;\r
- }\r
-\r
- while (fgets (Line, sizeof (Line), Fptr) != NULL) {\r
- //\r
- // remove terminating newline for error printing purposes.\r
- //\r
- if (Line[strlen (Line) - 1] == '\n') {\r
- Line[strlen (Line) - 1] = 0;\r
- }\r
-\r
- LineCount++;\r
- if (Line[sizeof (Line) - 1] != 0) {\r
- Error (Files->Str, LineCount, 0, "line length exceeds maximum supported", NULL);\r
- goto Done;\r
- }\r
-\r
- StringName = Line;\r
- while (*StringName && (isspace (*StringName))) {\r
- StringName++;\r
- }\r
-\r
- if (*StringName) {\r
- if ((*StringName == '_') || isalpha (*StringName)) {\r
- End = StringName;\r
- while ((*End) && (*End == '_') || (isalnum (*End))) {\r
- End++;\r
- }\r
-\r
- if (isspace (*End)) {\r
- *End = 0;\r
- End++;\r
- while (isspace (*End)) {\r
- End++;\r
- }\r
-\r
- if (*End) {\r
- ScopeName = End;\r
- while (*End && !isspace (*End)) {\r
- End++;\r
- }\r
-\r
- *End = 0;\r
- //\r
- // Add the string name/scope pair\r
- //\r
- NewList = malloc (sizeof (WCHAR_MATCHING_STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (NULL, 0, 0, "memory allocation error", NULL);\r
- goto Done;\r
- }\r
-\r
- memset (NewList, 0, sizeof (WCHAR_MATCHING_STRING_LIST));\r
- NewList->Str1 = (WCHAR *) malloc ((strlen (StringName) + 1) * sizeof (WCHAR));\r
- NewList->Str2 = (WCHAR *) malloc ((strlen (ScopeName) + 1) * sizeof (WCHAR));\r
- if ((NewList->Str1 == NULL) || (NewList->Str2 == NULL)) {\r
- Error (NULL, 0, 0, "memory allocation error", NULL);\r
- goto Done;\r
- }\r
-\r
- UnicodeSPrint (NewList->Str1, strlen (StringName) + 1, L"%a", StringName);\r
- UnicodeSPrint (NewList->Str2, strlen (ScopeName) + 1, L"%a", ScopeName);\r
- if (mGlobals.IndirectionList == NULL) {\r
- mGlobals.IndirectionList = NewList;\r
- } else {\r
- mGlobals.LastIndirectionList->Next = NewList;\r
- }\r
-\r
- mGlobals.LastIndirectionList = NewList;\r
- } else {\r
- Error (Files->Str, LineCount, 0, StringName, "invalid line : expected 'StringIdentifier Scope'");\r
- goto Done;\r
- }\r
- } else {\r
- Error (Files->Str, LineCount, 0, StringName, "invalid line : expected 'StringIdentifier Scope'");\r
- goto Done;\r
- }\r
- } else {\r
- Error (Files->Str, LineCount, 0, StringName, "invalid string identifier");\r
- goto Done;\r
- }\r
- }\r
- }\r
-\r
- fclose (Fptr);\r
- Fptr = NULL;\r
- Files = Files->Next;\r
- }\r
-\r
-Done:\r
- if (Fptr != NULL) {\r
- fclose (Fptr);\r
- return STATUS_ERROR;\r
- }\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-static\r
-STATUS\r
-ScanFiles (\r
- TEXT_STRING_LIST *ScanFiles\r
- )\r
-{\r
- char Line[MAX_LINE_LEN];\r
- FILE *Fptr;\r
- UINT32 LineNum;\r
- char *Cptr;\r
- char *SavePtr;\r
- char *TermPtr;\r
- char *StringTokenPos;\r
- TEXT_STRING_LIST *SList;\r
- BOOLEAN SkipIt;\r
-\r
- //\r
- // Put a null-terminator at the end of the line. If we read in\r
- // a line longer than we support, then we can catch it.\r
- //\r
- Line[MAX_LINE_LEN - 1] = 0;\r
- //\r
- // Process each file. If they gave us a skip extension list, then\r
- // skip it if the extension matches.\r
- //\r
- while (ScanFiles != NULL) {\r
- SkipIt = FALSE;\r
- for (SList = mGlobals.SkipExt; SList != NULL; SList = SList->Next) {\r
- if ((strlen (ScanFiles->Str) > strlen (SList->Str)) &&\r
- (strcmp (ScanFiles->Str + strlen (ScanFiles->Str) - strlen (SList->Str), SList->Str) == 0)\r
- ) {\r
- SkipIt = TRUE;\r
- //\r
- // printf ("Match: %s : %s\n", ScanFiles->Str, SList->Str);\r
- //\r
- break;\r
- }\r
- }\r
-\r
- if (!SkipIt) {\r
- if (mGlobals.VerboseScan) {\r
- printf ("Scanning %s\n", ScanFiles->Str);\r
- }\r
-\r
- Fptr = fopen (ScanFiles->Str, "r");\r
- if (Fptr == NULL) {\r
- Error (NULL, 0, 0, ScanFiles->Str, "failed to open input file for scanning");\r
- return STATUS_ERROR;\r
- }\r
-\r
- LineNum = 0;\r
- while (fgets (Line, sizeof (Line), Fptr) != NULL) {\r
- LineNum++;\r
- if (Line[MAX_LINE_LEN - 1] != 0) {\r
- Error (ScanFiles->Str, LineNum, 0, "line length exceeds maximum supported by tool", NULL);\r
- fclose (Fptr);\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Remove the newline from the input line so we can print a warning message\r
- //\r
- if (Line[strlen (Line) - 1] == '\n') {\r
- Line[strlen (Line) - 1] = 0;\r
- }\r
- //\r
- // Terminate the line at // comments\r
- //\r
- Cptr = strstr (Line, "//");\r
- if (Cptr != NULL) {\r
- *Cptr = 0;\r
- }\r
-\r
- Cptr = Line;\r
- while ((Cptr = strstr (Cptr, STRING_TOKEN)) != NULL) {\r
- //\r
- // Found "STRING_TOKEN". Make sure we don't have NUM_STRING_TOKENS or\r
- // something like that. Then make sure it's followed by\r
- // an open parenthesis, a string identifier, and then a closing\r
- // parenthesis.\r
- //\r
- if (mGlobals.VerboseScan) {\r
- printf (" %d: %s", LineNum, Cptr);\r
- }\r
-\r
- if (((Cptr == Line) || (!IsValidIdentifierChar (*(Cptr - 1), FALSE))) &&\r
- (!IsValidIdentifierChar (*(Cptr + sizeof (STRING_TOKEN) - 1), FALSE))\r
- ) {\r
- StringTokenPos = Cptr;\r
- SavePtr = Cptr;\r
- Cptr += strlen (STRING_TOKEN);\r
- while (*Cptr && isspace (*Cptr) && (*Cptr != '(')) {\r
- Cptr++;\r
- }\r
-\r
- if (*Cptr != '(') {\r
- Warning (ScanFiles->Str, LineNum, 0, StringTokenPos, "expected "STRING_TOKEN "(identifier)");\r
- } else {\r
- //\r
- // Skip over the open-parenthesis and find the next non-blank character\r
- //\r
- Cptr++;\r
- while (isspace (*Cptr)) {\r
- Cptr++;\r
- }\r
-\r
- SavePtr = Cptr;\r
- if ((*Cptr == '_') || isalpha (*Cptr)) {\r
- while ((*Cptr == '_') || (isalnum (*Cptr))) {\r
- Cptr++;\r
- }\r
-\r
- TermPtr = Cptr;\r
- while (*Cptr && isspace (*Cptr)) {\r
- Cptr++;\r
- }\r
-\r
- if (*Cptr != ')') {\r
- Warning (ScanFiles->Str, LineNum, 0, StringTokenPos, "expected "STRING_TOKEN "(identifier)");\r
- }\r
-\r
- if (*TermPtr) {\r
- *TermPtr = 0;\r
- Cptr = TermPtr + 1;\r
- } else {\r
- Cptr = TermPtr;\r
- }\r
- //\r
- // Add the string identifier to the list of used strings\r
- //\r
- ParserSetPosition (ScanFiles->Str, LineNum);\r
- StringDBSetStringReferenced (SavePtr, mGlobals.IgnoreNotFound);\r
- if (mGlobals.VerboseScan) {\r
- printf ("...referenced %s", SavePtr);\r
- }\r
- } else {\r
- Warning (ScanFiles->Str, LineNum, 0, StringTokenPos, "expected valid string identifier name");\r
- }\r
- }\r
- } else {\r
- //\r
- // Found it, but it's a substring of something else. Advance our pointer.\r
- //\r
- Cptr++;\r
- }\r
-\r
- if (mGlobals.VerboseScan) {\r
- printf ("\n");\r
- }\r
- }\r
- }\r
-\r
- fclose (Fptr);\r
- } else {\r
- //\r
- // Skipping this file type\r
- //\r
- if (mGlobals.VerboseScan) {\r
- printf ("Skip scanning of %s\n", ScanFiles->Str);\r
- }\r
- }\r
-\r
- ScanFiles = ScanFiles->Next;\r
- }\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-//\r
-// Free the global string lists we allocated memory for\r
-//\r
-static\r
-void\r
-FreeLists (\r
- VOID\r
- )\r
-{\r
- TEXT_STRING_LIST *Temp;\r
- WCHAR_STRING_LIST *WTemp;\r
-\r
- //\r
- // Traverse the include paths, freeing each\r
- //\r
- while (mGlobals.IncludePaths != NULL) {\r
- Temp = mGlobals.IncludePaths->Next;\r
- free (mGlobals.IncludePaths->Str);\r
- free (mGlobals.IncludePaths);\r
- mGlobals.IncludePaths = Temp;\r
- }\r
- //\r
- // If we did a scan, then free up our\r
- // list of files to scan.\r
- //\r
- while (mGlobals.ScanFileName != NULL) {\r
- Temp = mGlobals.ScanFileName->Next;\r
- free (mGlobals.ScanFileName->Str);\r
- free (mGlobals.ScanFileName);\r
- mGlobals.ScanFileName = Temp;\r
- }\r
- //\r
- // If they gave us a list of filename extensions to\r
- // skip on scan, then free them up.\r
- //\r
- while (mGlobals.SkipExt != NULL) {\r
- Temp = mGlobals.SkipExt->Next;\r
- free (mGlobals.SkipExt->Str);\r
- free (mGlobals.SkipExt);\r
- mGlobals.SkipExt = Temp;\r
- }\r
- //\r
- // Free up any languages specified\r
- //\r
- while (mGlobals.Language != NULL) {\r
- WTemp = mGlobals.Language->Next;\r
- free (mGlobals.Language->Str);\r
- free (mGlobals.Language);\r
- mGlobals.Language = WTemp;\r
- }\r
- //\r
- // Free up our indirection list\r
- //\r
- while (mGlobals.IndirectionList != NULL) {\r
- mGlobals.LastIndirectionList = mGlobals.IndirectionList->Next;\r
- free (mGlobals.IndirectionList->Str1);\r
- free (mGlobals.IndirectionList->Str2);\r
- free (mGlobals.IndirectionList);\r
- mGlobals.IndirectionList = mGlobals.LastIndirectionList;\r
- }\r
-\r
- while (mGlobals.IndirectionFileName != NULL) {\r
- mGlobals.LastIndirectionFileName = mGlobals.IndirectionFileName->Next;\r
- free (mGlobals.IndirectionFileName->Str);\r
- free (mGlobals.IndirectionFileName);\r
- mGlobals.IndirectionFileName = mGlobals.LastIndirectionFileName;\r
- }\r
-}\r
-\r
-static\r
-BOOLEAN\r
-IsValidIdentifierChar (\r
- CHAR8 Char,\r
- BOOLEAN FirstChar\r
- )\r
-{\r
- //\r
- // If it's the first character of an identifier, then\r
- // it must be one of [A-Za-z_].\r
- //\r
- if (FirstChar) {\r
- if (isalpha (Char) || (Char == '_')) {\r
- return TRUE;\r
- }\r
- } else {\r
- //\r
- // If it's not the first character, then it can\r
- // be one of [A-Za-z_0-9]\r
- //\r
- if (isalnum (Char) || (Char == '_')) {\r
- return TRUE;\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-static\r
-void\r
-RewindFile (\r
- SOURCE_FILE *SourceFile\r
- )\r
-{\r
- SourceFile->LineNum = 1;\r
- SourceFile->FileBufferPtr = SourceFile->FileBuffer;\r
- SourceFile->EndOfFile = 0;\r
-}\r
-\r
-static\r
-BOOLEAN\r
-SkipTo (\r
- SOURCE_FILE *SourceFile,\r
- WCHAR WChar,\r
- BOOLEAN StopAfterNewline\r
- )\r
-{\r
- while (!EndOfFile (SourceFile)) {\r
- //\r
- // Check for the character of interest\r
- //\r
- if (SourceFile->FileBufferPtr[0] == WChar) {\r
- return TRUE;\r
- } else {\r
- if (SourceFile->FileBufferPtr[0] == UNICODE_LF) {\r
- SourceFile->LineNum++;\r
- if (StopAfterNewline) {\r
- SourceFile->FileBufferPtr++;\r
- if (SourceFile->FileBufferPtr[0] == 0) {\r
- SourceFile->FileBufferPtr++;\r
- }\r
-\r
- return FALSE;\r
- }\r
- }\r
-\r
- SourceFile->FileBufferPtr++;\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-static\r
-void\r
-Usage (\r
- VOID\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Print usage information for this utility.\r
- \r
-Arguments:\r
-\r
- None.\r
-\r
-Returns:\r
-\r
- Nothing.\r
- \r
---*/\r
-{\r
- int Index;\r
- static const char *Str[] = {\r
- "",\r
- PROGRAM_NAME " version "TOOL_VERSION " -- process unicode strings file",\r
- " Usage: "PROGRAM_NAME " -parse {parse options} [FileNames]",\r
- " "PROGRAM_NAME " -scan {scan options} [FileName]",\r
- " "PROGRAM_NAME " -dump {dump options}",\r
- " Common options include:",\r
- " -h or -? for this help information",\r
- " -db Database required name of output/input database file",\r
- " -bn BaseName for use in the .h and .c output files",\r
- " Default = "DEFAULT_BASE_NAME,\r
- " -v for verbose output",\r
- " -vdbw for verbose output when writing database",\r
- " -vdbr for verbose output when reading database",\r
- " -od FileName to specify an output database file name",\r
- " Parse options include:",\r
- " -i IncludePath add IncludePath to list of search paths",\r
- " -newdb to not read in existing database file",\r
- " -uqs to indicate that unquoted strings are used",\r
- " FileNames name of one or more unicode files to parse",\r
- " Scan options include:",\r
- " -scan scan text file(s) for STRING_TOKEN() usage",\r
- " -skipext .ext to skip scan of files with .ext filename extension",\r
- " -ignorenotfound ignore if a given STRING_TOKEN(STR) is not ",\r
- " found in the database",\r
- " FileNames one or more files to scan",\r
- " Dump options include:",\r
- " -oc FileName write string data to FileName",\r
- " -oh FileName write string defines to FileName",\r
- " -ou FileName dump database to unicode file FileName",\r
- " -lang Lang only dump for the language 'Lang'",\r
- " -if FileName to specify an indirection file",\r
- " -hpk FileName to create an HII export pack of the strings",\r
- "",\r
- " The expected process is to parse a unicode string file to create an initial",\r
- " database of string identifier names and string definitions. Then text files",\r
- " should be scanned for STRING_TOKEN() usages, and the referenced",\r
- " strings will be tagged as used in the database. After all files have been",\r
- " scanned, then the database should be dumped to create the necessary output",\r
- " files.",\r
- "",\r
- NULL\r
- };\r
- for (Index = 0; Str[Index] != NULL; Index++) {\r
- fprintf (stdout, "%s\n", Str[Index]);\r
- }\r
-}\r