EdkCompatibilityPkg: Fix some typos of "according"
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / UefiStrGather / StrGather.c
index 03b3cc6..e71b5e4 100644 (file)
@@ -1,7 +1,7 @@
 /*++\r
 \r
-Copyright (c) 2004 - 2007, Intel Corporation                                                         \r
-All rights reserved. This program and the accompanying materials                          \r
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
+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
@@ -11,7 +11,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 Module Name:\r
 \r
-  StrGather.c  \r
+  StrGather.c\r
 \r
 Abstract:\r
 \r
@@ -29,7 +29,8 @@ Abstract:
 #include "StrGather.h"\r
 #include "StringDB.h"\r
 \r
-#define TOOL_VERSION  "0.31"\r
+#define UTILITY_NAME     "StrGather"\r
+#define UTILITY_VERSION  "v1.2"\r
 \r
 typedef UINT16  WCHAR;\r
 \r
@@ -47,6 +48,15 @@ typedef UINT16  WCHAR;
 #define MODE_SCAN     2\r
 #define MODE_DUMP     3\r
 \r
+//\r
+// This is how we invoke the C preprocessor on the source file\r
+// to resolve #if, #else, etc.\r
+//\r
+#define PREPROCESSOR_COMMAND                "cl"\r
+#define PREPROCESSOR_OPTIONS                "/nologo /EP /TC /DSTRGATHER"\r
+#define PREPROCESS_TEMP_FILE_EXTENSION      ".ii"\r
+#define PREPROCESS_OUTPUT_FILE_EXTENSION    ".iii"\r
+\r
 //\r
 // We keep a linked list of these for the source files we process\r
 //\r
@@ -83,6 +93,8 @@ static struct {
   TEXT_STRING_LIST            *LastIndirectionFileName;\r
   TEXT_STRING_LIST            *DatabaseFileName;\r
   TEXT_STRING_LIST            *LastDatabaseFileName;\r
+  TEXT_STRING_LIST            *PreprocessFlags;\r
+  TEXT_STRING_LIST            *LastPreprocessFlags;\r
   WCHAR_STRING_LIST           *Language;\r
   WCHAR_STRING_LIST           *LastLanguage;\r
   WCHAR_MATCHING_STRING_LIST  *IndirectionList;                 // from indirection file(s)\r
@@ -94,6 +106,8 @@ static struct {
   BOOLEAN                     IgnoreNotFound;                   // when scanning\r
   BOOLEAN                     VerboseScan;\r
   BOOLEAN                     UnquotedStrings;                  // -uqs option\r
+  BOOLEAN                     Preprocess;                       // -ppflag option\r
+  INT8                        PreprocessFileName[MAX_PATH];\r
   INT8                        OutputDatabaseFileName[MAX_PATH];\r
   INT8                        StringHFileName[MAX_PATH];\r
   INT8                        StringCFileName[MAX_PATH];        // output .C filename\r
@@ -294,11 +308,6 @@ ParseIndirectionFiles (
   TEXT_STRING_LIST    *Files\r
   );\r
 \r
-STATUS\r
-StringDBCreateHiiExportPack (\r
-  INT8                *OutputFileName\r
-  );\r
-\r
 int\r
 main (\r
   int   Argc,\r
@@ -309,7 +318,7 @@ main (
 Routine Description:\r
 \r
   Call the routine to parse the command-line options, then process the file.\r
-  \r
+\r
 Arguments:\r
 \r
   Argc - Standard C main() argc and argv.\r
@@ -319,12 +328,12 @@ Returns:
 \r
   0       if successful\r
   nonzero otherwise\r
-  \r
+\r
 --*/\r
 {\r
   STATUS  Status;\r
 \r
-  SetUtilityName (PROGRAM_NAME);\r
+  SetUtilityName (UTILITY_NAME);\r
   //\r
   // Process the command-line arguments\r
   //\r
@@ -374,12 +383,12 @@ Returns:
       if ((mGlobals.OutputDependencyFptr = fopen (mGlobals.OutputDependencyFileName, "w")) == NULL) {\r
         Error (NULL, 0, 0, mGlobals.OutputDependencyFileName, "failed to open output dependency file");\r
         goto Finish;\r
-      }    \r
+      }\r
     }\r
     Status = ProcessIncludeFile (&mGlobals.SourceFiles, NULL);\r
     if (mGlobals.OutputDependencyFptr != NULL) {\r
       fclose (mGlobals.OutputDependencyFptr);\r
-    }    \r
+    }\r
     if (Status != STATUS_SUCCESS) {\r
       goto Finish;\r
     }\r
@@ -401,7 +410,8 @@ Returns:
   if ((mGlobals.StringCFileName[0] != 0) && (GetUtilityStatus () < STATUS_ERROR)) {\r
     Status = StringDBDumpCStrings (\r
               mGlobals.BaseName,\r
-              mGlobals.StringCFileName\r
+              mGlobals.StringCFileName,\r
+              mGlobals.Language\r
               );\r
     if (Status != EFI_SUCCESS) {\r
       goto Finish;\r
@@ -418,7 +428,7 @@ Returns:
   // 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
+    StringDBCreateHiiExportPack (mGlobals.HiiExportPackFileName, mGlobals.Language);\r
   }\r
   //\r
   // Always update the database if no errors and not in dump mode. If they specified -od\r
@@ -457,7 +467,7 @@ ProcessIncludeFile (
 Routine Description:\r
 \r
   Given a source file, open the file and parse it\r
-  \r
+\r
 Arguments:\r
 \r
   SourceFile        - name of file to parse\r
@@ -466,7 +476,7 @@ Arguments:
 Returns:\r
 \r
   Standard status.\r
-  \r
+\r
 --*/\r
 {\r
   static UINT32 NestDepth = 0;\r
@@ -513,18 +523,18 @@ Returns:
       goto Finish;\r
     }\r
   }\r
-  \r
+\r
   //\r
-  // Output the dependency \r
+  // Output the dependency\r
   //\r
   if (mGlobals.OutputDependencyFptr != NULL) {\r
-    fprintf (mGlobals.OutputDependencyFptr, "%s : %s\n", mGlobals.DatabaseFileName->Str, FoundFileName);    \r
+    fprintf (mGlobals.OutputDependencyFptr, "%s : %s\n", mGlobals.DatabaseFileName->Str, FoundFileName);\r
     //\r
     // Add pseudo target to avoid incremental build failure when the file is deleted\r
     //\r
-    fprintf (mGlobals.OutputDependencyFptr, "%s : \n", FoundFileName); \r
+    fprintf (mGlobals.OutputDependencyFptr, "%s : \n", FoundFileName);\r
   }\r
-   \r
+\r
   //\r
   // Process the file found\r
   //\r
@@ -695,13 +705,13 @@ PreprocessFile (
 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
+\r
 Arguments:\r
   SourceFile - structure that we use to keep track of an input file.\r
 \r
 Returns:\r
   Nothing.\r
-  \r
+\r
 --*/\r
 {\r
   BOOLEAN InComment;\r
@@ -844,7 +854,7 @@ GetLangCode (
   }\r
 \r
   //\r
-  // Convert the language accoring to the table.\r
+  // Convert the language according to the table.\r
   //\r
   for (Index = 0; LanguageConvertTable[Index].ISO639 != NULL; Index++) {\r
     if (wcscmp(LanguageConvertTable[Index].ISO639, Lang) == 0) {\r
@@ -1736,7 +1746,7 @@ FindFile (
     // 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
+      Error (UTILITY_NAME, 0, 0, NULL, "internal error - cannot concatenate path+filename");\r
       return NULL;\r
     }\r
     //\r
@@ -1770,6 +1780,9 @@ ProcessArgs (
   )\r
 {\r
   TEXT_STRING_LIST  *NewList;\r
+  char              *Cptr;\r
+  char              *Cptr2;\r
+\r
   //\r
   // Clear our globals\r
   //\r
@@ -1836,7 +1849,7 @@ ProcessArgs (
       // 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
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing include path");\r
         return STATUS_ERROR;\r
       }\r
       //\r
@@ -1846,7 +1859,7 @@ ProcessArgs (
       //\r
       NewList = malloc (sizeof (TEXT_STRING_LIST));\r
       if (NewList == NULL) {\r
-        Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -1854,7 +1867,7 @@ ProcessArgs (
       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
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -1879,7 +1892,7 @@ ProcessArgs (
       // 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
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing indirection file name");\r
         return STATUS_ERROR;\r
       }\r
       //\r
@@ -1889,7 +1902,7 @@ ProcessArgs (
       //\r
       NewList = malloc (sizeof (TEXT_STRING_LIST));\r
       if (NewList == NULL) {\r
-        Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -1897,7 +1910,7 @@ ProcessArgs (
       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
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -1920,13 +1933,13 @@ ProcessArgs (
       // 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
+        Error (UTILITY_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
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -1934,7 +1947,7 @@ ProcessArgs (
       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
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -1957,14 +1970,14 @@ ProcessArgs (
       // 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
+        Error (UTILITY_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
+        Error (UTILITY_NAME, 0, 0, Argv[1], "-ou option already specified with '%s'", mGlobals.DumpUFileName);\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -1975,14 +1988,14 @@ ProcessArgs (
       // -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
+        Error (UTILITY_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
+        Error (UTILITY_NAME, 0, 0, Argv[1], "-or option already specified with '%s'", mGlobals.HiiExportPackFileName);\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -2006,7 +2019,7 @@ ProcessArgs (
       // 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
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing output C filename");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -2018,7 +2031,7 @@ ProcessArgs (
       // 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
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing base name");\r
         Usage ();\r
         return STATUS_ERROR;\r
       }\r
@@ -2031,7 +2044,7 @@ ProcessArgs (
       // -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
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing output .h filename");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -2043,7 +2056,7 @@ ProcessArgs (
       // -dep to specify output dependency file name\r
       //\r
       if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
-        Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output dependency filename");\r
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing output dependency filename");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -2055,7 +2068,7 @@ ProcessArgs (
       // -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
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing filename extension");\r
         return STATUS_ERROR;\r
       }\r
       //\r
@@ -2065,7 +2078,7 @@ ProcessArgs (
       //\r
       NewList = malloc (sizeof (TEXT_STRING_LIST));\r
       if (NewList == NULL) {\r
-        Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -2073,7 +2086,7 @@ ProcessArgs (
       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
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -2097,10 +2110,10 @@ ProcessArgs (
       Argv++;\r
     } else if (_stricmp (Argv[0], "-lang") == 0) {\r
       //\r
-      // "-lang eng" or "-lang spa+cat" to only output certain languages\r
+      // "-lang zh-Hans" or "-lang en-US" 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
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing language name");\r
         Usage ();\r
         return STATUS_ERROR;\r
       }\r
@@ -2116,18 +2129,78 @@ ProcessArgs (
       // 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
+        Error (UTILITY_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 if (_stricmp (Argv[0], "-ppflag") == 0) {\r
+      //\r
+      // -ppflag "Preprocess flags" -- check for another arg\r
+      //\r
+      if ((Argc <= 1) || (Argv[1][0] == '-')) {\r
+        Error (UTILITY_NAME, 0, 0, Argv[0], "missing preprocess flags");\r
+        Usage ();\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      //\r
+      // Allocate memory for a new list element, fill it in, and\r
+      // add it to our list of preprocess flag.\r
+      //\r
+      NewList = malloc (sizeof (TEXT_STRING_LIST));\r
+      if (NewList == NULL) {\r
+        Error (UTILITY_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 + 1);\r
+      if (NewList->Str == NULL) {\r
+        free (NewList);\r
+        Error (UTILITY_NAME, 0, 0, NULL, "memory allocation failure");\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      //\r
+      // Convert '"' to '\"' in preprocess flag\r
+      //\r
+      Cptr = Argv[1];\r
+      Cptr2 = NewList->Str;\r
+      if (*Cptr == '"') {\r
+        *Cptr2++ = '\\';\r
+        *Cptr2++ = '"';\r
+        Cptr++;\r
+      }\r
+      while (*Cptr != '\0') {\r
+        if ((*Cptr == '"') && (*(Cptr - 1) != '\\')) {\r
+          *Cptr2++ = '\\';\r
+        }\r
+        *Cptr2++ = *Cptr++;\r
+      }\r
+      *Cptr2 = '\0';\r
+\r
+      //\r
+      // Add it to our linked list\r
+      //\r
+      if (mGlobals.PreprocessFlags == NULL) {\r
+        mGlobals.PreprocessFlags = NewList;\r
+      } else {\r
+        mGlobals.LastPreprocessFlags->Next = NewList;\r
+      }\r
+      mGlobals.LastPreprocessFlags = NewList;\r
+\r
+      mGlobals.Preprocess = TRUE;\r
+\r
       Argv++;\r
       Argc--;\r
     } else {\r
       //\r
       // Unrecognized arg\r
       //\r
-      Error (PROGRAM_NAME, 0, 0, Argv[0], "unrecognized option");\r
+      Error (UTILITY_NAME, 0, 0, Argv[0], "unrecognized option");\r
       Usage ();\r
       return STATUS_ERROR;\r
     }\r
@@ -2174,7 +2247,15 @@ ProcessArgs (
   //\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
+      Error (UTILITY_NAME, 0, 0, NULL, "must specify at least one source file to scan with -scan");\r
+      Usage ();\r
+      return STATUS_ERROR;\r
+    }\r
+    //\r
+    // If -ppflag is specified, -oh should also be specified for preprocess\r
+    //\r
+    if (mGlobals.Preprocess && (mGlobals.StringHFileName[0] == 0)) {\r
+      Error (UTILITY_NAME, 0, 0, NULL, "must specify string defines file name to preprocess before scan");\r
       Usage ();\r
       return STATUS_ERROR;\r
     }\r
@@ -2184,14 +2265,14 @@ ProcessArgs (
     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
+        Error (UTILITY_NAME, 0, 0, "memory allocation failure", NULL);\r
         return STATUS_ERROR;\r
       }\r
 \r
       memset (NewList, 0, sizeof (TEXT_STRING_LIST));\r
       NewList->Str = (UINT8 *) malloc (strlen (Argv[0]) + 1);\r
       if (NewList->Str == NULL) {\r
-        Error (PROGRAM_NAME, 0, 0, "memory allocation failure", NULL);\r
+        Error (UTILITY_NAME, 0, 0, "memory allocation failure", NULL);\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -2211,7 +2292,7 @@ ProcessArgs (
     // 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
+      Error (UTILITY_NAME, 0, 0, NULL, "must specify input unicode string file name with -parse");\r
       Usage ();\r
       return STATUS_ERROR;\r
     }\r
@@ -2222,7 +2303,7 @@ ProcessArgs (
   return STATUS_SUCCESS;\r
 }\r
 //\r
-// Found "-lang eng,spa+cat" on the command line. Parse the\r
+// Found "-lang zh-Hans;en-US" on the command line. Parse the\r
 // language list and save the setting for later processing.\r
 //\r
 static\r
@@ -2231,69 +2312,33 @@ AddCommandLineLanguage (
   IN INT8          *Language\r
   )\r
 {\r
+  char              Separator[] = ";";\r
+  char              *Token;\r
   WCHAR_STRING_LIST *WNewList;\r
-  WCHAR             *From;\r
-  WCHAR             *To;\r
+\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
+  Token = strtok (Language, Separator);\r
+  while (Token != NULL) {\r
     WNewList = MALLOC (sizeof (WCHAR_STRING_LIST));\r
     if (WNewList == NULL) {\r
-      Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
+      Error (UTILITY_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
+    WNewList->Next = NULL;\r
+    WNewList->Str  = MALLOC ((strlen (Token) + 1) * sizeof (WCHAR));\r
     if (WNewList->Str == NULL) {\r
       free (WNewList);\r
-      Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");\r
+      Error (UTILITY_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
 #ifdef USE_VC8\r
-    swprintf (WNewList->Str, (strlen (Language) + 1) * sizeof (WCHAR), L"%S", Language);\r
+    swprintf (WNewList->Str, (strlen (Token) + 1) * sizeof (WCHAR), L"%S", Token);\r
 #else\r
-    swprintf (WNewList->Str, L"%S", Language);\r
+    swprintf (WNewList->Str, L"%S", Token);\r
 #endif\r
-    From = To = WNewList->Str;\r
-    while (*From) {\r
-      if (*From == L',') {\r
-        break;\r
-      }\r
 \r
-      if ((wcslen (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
-      wcsncpy (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
@@ -2304,17 +2349,7 @@ AddCommandLineLanguage (
     }\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
+    Token = strtok (NULL, Separator);\r
   }\r
 \r
   return STATUS_SUCCESS;\r
@@ -2449,6 +2484,166 @@ Done:
   return STATUS_SUCCESS;\r
 }\r
 \r
+static\r
+INTN\r
+PreprocessSourceFile (\r
+  UINT8 *SourceFileName\r
+  )\r
+{\r
+  char              *Cptr;\r
+  FILE              *InFptr;\r
+  FILE              *OutFptr;\r
+  UINT32            CmdLen;\r
+  char              *PreProcessCmd;\r
+  char              BaseName[MAX_PATH];\r
+  char              TempFileName[MAX_PATH];\r
+  char              SourceFileDir[MAX_PATH];\r
+  char              Line[MAX_LINE_LEN];\r
+  TEXT_STRING_LIST  *List;\r
+  char              InsertLine[] = "#undef STRING_TOKEN\n";\r
+  int               Status;\r
+\r
+  //\r
+  // Check whehter source file exist\r
+  //\r
+  InFptr = fopen (SourceFileName, "r");\r
+  if (InFptr == NULL) {\r
+    Error (NULL, 0, 0, SourceFileName, "failed to open input file for scanning");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  //\r
+  // Get source file directory\r
+  //\r
+  strcpy (SourceFileDir, SourceFileName);\r
+  Cptr = strrchr (SourceFileDir, '\\');\r
+  if (Cptr != NULL) {\r
+    *Cptr = '\0';\r
+  }\r
+\r
+  //\r
+  // Generate preprocess output file name\r
+  //\r
+  strcpy (BaseName, mGlobals.OutputDatabaseFileName);\r
+  Cptr = strrchr (BaseName, '\\');\r
+  if (Cptr != NULL) {\r
+    *++Cptr = '\0';\r
+  }\r
+\r
+  Cptr = strrchr (SourceFileName, '\\');\r
+  if (Cptr != NULL) {\r
+    Cptr++;\r
+  }\r
+  strcat (BaseName, Cptr);\r
+\r
+  Cptr = strrchr (BaseName, '.');\r
+  if (Cptr != NULL) {\r
+    *Cptr = '\0';\r
+  }\r
+\r
+  strcpy (mGlobals.PreprocessFileName, BaseName);\r
+  strcat (mGlobals.PreprocessFileName, PREPROCESS_OUTPUT_FILE_EXTENSION);\r
+\r
+  strcpy (TempFileName, BaseName);\r
+  strcat (TempFileName, PREPROCESS_TEMP_FILE_EXTENSION);\r
+\r
+  //\r
+  // Insert "#undef STRING_TOKEN" after each line of "#include ...", so as to\r
+  // preserve the STRING_TOKEN() for scanning after preprocess\r
+  //\r
+  OutFptr = fopen (TempFileName, "w");\r
+  if (OutFptr == NULL) {\r
+    Error (NULL, 0, 0, TempFileName, "failed to open file for write");\r
+    fclose (InFptr);\r
+    return STATUS_ERROR;\r
+  }\r
+  while (fgets (Line, MAX_LINE_LEN, InFptr) != NULL) {\r
+    fputs (Line, OutFptr);\r
+    Cptr = Line;\r
+\r
+    //\r
+    // Skip leading blank space\r
+    //\r
+    while (*Cptr == ' ' || *Cptr == '\t') {\r
+      Cptr++;\r
+    }\r
+\r
+    if (*Cptr == '#' && strncmp (Cptr + 1, "include", 7) == 0){\r
+      fputs (InsertLine, OutFptr);\r
+    }\r
+  }\r
+  fclose (InFptr);\r
+  fclose (OutFptr);\r
+\r
+  //\r
+  // Prepare preprocess command\r
+  //\r
+  CmdLen = 1;\r
+  CmdLen += strlen (PREPROCESSOR_COMMAND);\r
+  CmdLen++;\r
+  CmdLen += strlen (PREPROCESSOR_OPTIONS);\r
+  CmdLen++;\r
+\r
+  //\r
+  // "-I SourceFileDir "\r
+  //\r
+  CmdLen += strlen (SourceFileDir);\r
+  CmdLen += 4;\r
+\r
+  List = mGlobals.PreprocessFlags;\r
+  while (List != NULL) {\r
+    CmdLen += strlen (List->Str);\r
+    CmdLen++;\r
+\r
+    List = List->Next;\r
+  }\r
+\r
+  CmdLen += strlen (TempFileName);\r
+  CmdLen += 3;\r
+  CmdLen += strlen (mGlobals.PreprocessFileName);\r
+\r
+  PreProcessCmd = malloc (CmdLen);\r
+  if (PreProcessCmd == NULL) {\r
+    Error (NULL, 0, 0, UTILITY_NAME, "memory allocation fail (%d bytes)\n", CmdLen);\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  strcpy (PreProcessCmd, PREPROCESSOR_COMMAND);\r
+  strcat (PreProcessCmd, " ");\r
+  strcat (PreProcessCmd, PREPROCESSOR_OPTIONS);\r
+  strcat (PreProcessCmd, " ");\r
+\r
+\r
+  strcat (PreProcessCmd, "-I ");\r
+  strcat (PreProcessCmd, SourceFileDir);\r
+  strcat (PreProcessCmd, " ");\r
+\r
+  List = mGlobals.PreprocessFlags;\r
+  while (List != NULL) {\r
+    strcat (PreProcessCmd, List->Str);\r
+    strcat (PreProcessCmd, " ");\r
+\r
+    List = List->Next;\r
+  }\r
+\r
+  strcat (PreProcessCmd, TempFileName);\r
+  strcat (PreProcessCmd, " > ");\r
+  strcat (PreProcessCmd, mGlobals.PreprocessFileName);\r
+\r
+  //\r
+  // Preprocess the source file\r
+  //\r
+  Status = system (PreProcessCmd);\r
+  if (Status != 0) {\r
+    Error (NULL, 0, 0, PreProcessCmd, "failed to spawn C preprocessor on source file\n");\r
+    free (PreProcessCmd);\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  free (PreProcessCmd);\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
 static\r
 STATUS\r
 ScanFiles (\r
@@ -2457,6 +2652,7 @@ ScanFiles (
 {\r
   char              Line[MAX_LINE_LEN];\r
   FILE              *Fptr;\r
+  char              *FileName;\r
   UINT32            LineNum;\r
   char              *Cptr;\r
   char              *SavePtr;\r
@@ -2464,6 +2660,7 @@ ScanFiles (
   char              *StringTokenPos;\r
   TEXT_STRING_LIST  *SList;\r
   BOOLEAN           SkipIt;\r
+  BOOLEAN           FileExist;\r
 \r
   //\r
   // Put a null-terminator at the end of the line. If we read in\r
@@ -2474,6 +2671,7 @@ ScanFiles (
   // Process each file. If they gave us a skip extension list, then\r
   // skip it if the extension matches.\r
   //\r
+  FileExist = FALSE;\r
   while (ScanFiles != NULL) {\r
     SkipIt = FALSE;\r
     for (SList = mGlobals.SkipExt; SList != NULL; SList = SList->Next) {\r
@@ -2493,9 +2691,36 @@ ScanFiles (
         printf ("Scanning %s\n", ScanFiles->Str);\r
       }\r
 \r
-      Fptr = fopen (ScanFiles->Str, "r");\r
+      if (mGlobals.Preprocess) {\r
+        //\r
+        // Create an empty string defines file for preprocessor\r
+        //\r
+        if (!FileExist) {\r
+          Fptr = fopen (mGlobals.StringHFileName, "w");\r
+          if (Fptr == NULL) {\r
+            Error (NULL, 0, 0, mGlobals.StringHFileName, "failed to open file for write");\r
+            return STATUS_ERROR;\r
+          }\r
+\r
+          fclose (Fptr);\r
+          FileExist = TRUE;\r
+        }\r
+\r
+        //\r
+        // Preprocess using C preprocessor\r
+        //\r
+        if (PreprocessSourceFile (ScanFiles->Str) != STATUS_SUCCESS) {\r
+          return STATUS_ERROR;\r
+        }\r
+\r
+        FileName = mGlobals.PreprocessFileName;\r
+      } else {\r
+        FileName = ScanFiles->Str;\r
+      }\r
+\r
+      Fptr = fopen (FileName, "r");\r
       if (Fptr == NULL) {\r
-        Error (NULL, 0, 0, ScanFiles->Str, "failed to open input file for scanning");\r
+        Error (NULL, 0, 0, FileName, "failed to open input file for scanning");\r
         return STATUS_ERROR;\r
       }\r
 \r
@@ -2613,6 +2838,13 @@ ScanFiles (
     ScanFiles = ScanFiles->Next;\r
   }\r
 \r
+  //\r
+  // Remove the empty string defines file\r
+  //\r
+  if (FileExist) {\r
+    remove (mGlobals.StringHFileName);\r
+  }\r
+\r
   return STATUS_SUCCESS;\r
 }\r
 //\r
@@ -2647,6 +2879,15 @@ FreeLists (
     mGlobals.ScanFileName = Temp;\r
   }\r
   //\r
+  // Free up preprocess flags list\r
+  //\r
+  while (mGlobals.PreprocessFlags != NULL) {\r
+    Temp = mGlobals.PreprocessFlags->Next;\r
+    free (mGlobals.PreprocessFlags->Str);\r
+    free (mGlobals.PreprocessFlags);\r
+    mGlobals.PreprocessFlags = Temp;\r
+  }\r
+  //\r
   // If they gave us a list of filename extensions to\r
   // skip on scan, then free them up.\r
   //\r
@@ -2767,7 +3008,7 @@ Usage (
 Routine Description:\r
 \r
   Print usage information for this utility.\r
-  \r
+\r
 Arguments:\r
 \r
   None.\r
@@ -2775,51 +3016,62 @@ Arguments:
 Returns:\r
 \r
   Nothing.\r
-  \r
+\r
 --*/\r
 {\r
-  int               Index;\r
-  static const char *Str[] = {\r
+  int         Index;\r
+  const char  *Str[] = {\r
+    UTILITY_NAME" "UTILITY_VERSION" - Intel UEFI String Gather Utility",\r
+    "  Copyright (C), 2004 - 2008 Intel Corporation",\r
+\r
+#if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )\r
+    "  Built from "UTILITY_BUILD", project of "UTILITY_VENDOR,\r
+#endif\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
-    "      -dep FileName    to specify an output dependency file name",\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
+    "Usage:",\r
+    "  "UTILITY_NAME" -parse [OPTION] FILE",\r
+    "  "UTILITY_NAME" -scan  [OPTION] FILE",\r
+    "  "UTILITY_NAME" -dump  [OPTION]",\r
+    "Description:",\r
+    "  Process unicode strings file.",\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
+    "  -dep FileName    to specify an output dependency file name",\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
+    "  -ppflag \"Flags\"  to specify the C preprocessor flags",\r
+    "  -oh FileName     to specify string defines file name for preprocessor",\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
+    "                   use ';' to separate multiple languages",\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
+    "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