]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkCompatibilityPkg/Sample/Tools/Source/GenFfsFile/GenFfsFile.c
1) Sync EdkCompatibilityPkg with EDK 1.04. The changes includes:
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / GenFfsFile / GenFfsFile.c
index 188ca77945ddf98691a3438ddbf22029f6e88382..2e065706331ed219c5527bffb34129d7bee05376 100644 (file)
@@ -24,6 +24,7 @@ Abstract:
 #include "EfiFirmwareFileSystem.h"\r
 #include "EfiFirmwareVolumeHeader.h"\r
 #include "EfiImageFormat.h"\r
+#include "EfiImage.h"\r
 #include "ParseInf.h"\r
 #include "Compress.h"\r
 #include "EfiCustomizedCompress.h"\r
@@ -82,6 +83,39 @@ PrintUsage (
   void\r
   );\r
 \r
+static\r
+void\r
+AddMacro (\r
+  UINT8   *MacroString\r
+  );\r
+\r
+static\r
+UINT8 *\r
+GetMacroValue (\r
+  UINT8   *MacroName\r
+  );\r
+    \r
+static\r
+void\r
+FreeMacros (\r
+  );\r
+\r
+static\r
+STATUS\r
+ReplaceMacros (\r
+  UINT8   *InputFile,\r
+  UINT8   *OutputFile\r
+  );\r
+    \r
+//\r
+// Linked list to keep track of all macros\r
+//\r
+typedef struct _MACRO {\r
+  struct _MACRO   *Next;\r
+  UINT8           *Name;\r
+  UINT8           *Value;\r
+} MACRO;\r
+\r
 //\r
 // Keep globals in this structure\r
 //\r
@@ -90,10 +124,13 @@ static struct {
   UINT8   PrimaryPackagePath[_MAX_PATH];\r
   UINT8   OverridePackagePath[_MAX_PATH];\r
   BOOLEAN Verbose;\r
+  MACRO   *MacroList;\r
 } mGlobals;\r
 \r
 static EFI_GUID mZeroGuid = { 0 };\r
 \r
+static UINT8  MinFfsDataAlignOverride = 0;\r
+\r
 static\r
 void\r
 StripQuotes (\r
@@ -151,8 +188,9 @@ Returns:
 --*/\r
 {\r
   printf ("Usage:\n");\r
-  printf (UTILITY_NAME " -b \"build directory\" -p1 \"package1.inf\" -p2 \"package2.inf\" -v\n");\r
-  printf ("   -b \"build directory\":\n ");\r
+  printf (UTILITY_NAME " -b \"build directory\" -p1 \"package1.inf\" -p2 \"package2.inf\"\n");\r
+  printf ("           -d \"name=value\" -v\n");\r
+  printf ("   -b \"build directory\":\n");\r
   printf ("       specifies the full path to the component build directory.\n");\r
   printf ("   -p1 \"P1_path\":\n");\r
   printf ("       specifies fully qualified file name to the primary package file.\n");\r
@@ -161,6 +199,10 @@ Returns:
   printf ("   -p2 \"P2_path\":\n");\r
   printf ("       specifies fully qualified file name to the override package file.\n");\r
   printf ("       This file will normally exist in the build tip. Optional.\n");\r
+  printf ("   -d \"name=value\":\n");\r
+  printf ("       add a macro definition for package file. Optional.\n");\r
+  printf ("   -v :\n");\r
+  printf ("       verbose. Optional.\n");\r
 }\r
 \r
 static\r
@@ -756,54 +798,6 @@ Returns:
   return ;\r
 }\r
 \r
-static\r
-INT32\r
-ProcessEnvironmentVariable (\r
-  IN CHAR8  *Buffer,\r
-  OUT CHAR8 *NewBuffer\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Converts environment variables to values\r
-\r
-Arguments:\r
-\r
-  Buffer      - Buffer containing Environment Variable String\r
-\r
-  NewBuffer   - Buffer containing value of environment variable\r
-\r
-\r
-Returns:\r
-\r
-  Number of characters from Buffer used\r
-\r
---*/\r
-{\r
-  INT32 Index;\r
-  INT32 Index2;\r
-  CHAR8 VariableBuffer[_MAX_PATH];\r
-\r
-  Index   = 2;\r
-  Index2  = 0;\r
-\r
-  while (Buffer[Index] != ')') {\r
-    VariableBuffer[Index - 2] = Buffer[Index++];\r
-  }\r
-\r
-  VariableBuffer[Index - 2] = 0;\r
-  Index++;\r
-\r
-  if (getenv (VariableBuffer) != NULL) {\r
-    strcpy (NewBuffer, getenv (VariableBuffer));\r
-  } else {\r
-    printf ("Environment variable %s not found!\n", VariableBuffer);\r
-  }\r
-\r
-  return Index;\r
-}\r
-\r
 static\r
 void\r
 SplitAttributesField (\r
@@ -880,7 +874,6 @@ GetToolArguments (
   UINT32      Index2;\r
   UINT32      z;\r
   CHAR8       *CharBuffer;\r
-  INT32       Index;\r
   INT32       ReturnValue;\r
   EFI_STATUS  Status;\r
 \r
@@ -982,17 +975,7 @@ GetToolArguments (
 \r
       ToolArgumentsArray[argc] = CharBuffer;\r
 \r
-      if (Buffer[0] == '$') {\r
-        Index = ProcessEnvironmentVariable (&Buffer[0], ToolArgumentsArray[argc]);\r
-        //\r
-        // if there is string after the environment variable, cat it.\r
-        //\r
-        if ((UINT32) Index < strlen (Buffer)) {\r
-          strcat (ToolArgumentsArray[argc], &Buffer[Index]);\r
-        }\r
-      } else {\r
-        strcpy (ToolArgumentsArray[argc], Buffer);\r
-      }\r
+      strcpy (ToolArgumentsArray[argc], Buffer);\r
 \r
       argc += 1;\r
       ToolArgumentsArray[argc] = NULL;\r
@@ -1010,17 +993,7 @@ GetToolArguments (
 \r
       ZeroMem (InputFileName, sizeof (_MAX_PATH));\r
 \r
-      if (Buffer[0] == '$') {\r
-        Index = ProcessEnvironmentVariable (&Buffer[0], InputFileName);\r
-        //\r
-        // if there is string after the environment variable, cat it.\r
-        //\r
-        if ((UINT32) Index < strlen (Buffer)) {\r
-          strcat (InputFileName, &Buffer[Index]);\r
-        }\r
-      } else {\r
-        strcpy (InputFileName, Buffer);\r
-      }\r
+      strcpy (InputFileName, Buffer);\r
 \r
       InputFlag = FALSE;\r
       continue;\r
@@ -1037,17 +1010,7 @@ GetToolArguments (
 \r
       ZeroMem (OutputFileName, sizeof (_MAX_PATH));\r
 \r
-      if (Buffer[0] == '$') {\r
-        Index = ProcessEnvironmentVariable (&Buffer[0], OutputFileName);\r
-        //\r
-        // if there is string after the environment variable, cat it.\r
-        //\r
-        if ((UINT32) Index < strlen (Buffer)) {\r
-          strcat (OutputFileName, &Buffer[Index]);\r
-        }\r
-      } else {\r
-        strcpy (OutputFileName, Buffer);\r
-      }\r
+      strcpy (OutputFileName, Buffer);\r
 \r
       OutputFlag = FALSE;\r
       continue;\r
@@ -1139,10 +1102,12 @@ Returns:
 {\r
   EFI_STATUS  Status;\r
   UINT32      Size;\r
+  UINT32      OldSize;\r
+  UINT32      Adjust;\r
+  UINT16      TeStrippedSize;\r
   CHAR8       Buffer[_MAX_PATH];\r
   CHAR8       Type[_MAX_PATH];\r
   CHAR8       FileName[_MAX_PATH];\r
-  CHAR8       NewBuffer[_MAX_PATH];\r
   INT32       Index3;\r
   INT32       Index2;\r
   UINT32      ReturnValue;\r
@@ -1157,7 +1122,6 @@ Returns:
   FILE        *InputFile;\r
   UINT8       Temp;\r
   int         returnint;\r
-  INT32       Index;\r
   UINT32      LineNumber;\r
   BOOLEAN     IsError;\r
   EFI_GUID    SignGuid;\r
@@ -1200,11 +1164,7 @@ Returns:
       }\r
 \r
       StripParens (Buffer);\r
-      if (Buffer[0] == '$') {\r
-        ProcessEnvironmentVariable (&Buffer[0], Type);\r
-      } else {\r
-        strcpy (Type, Buffer);\r
-      }\r
+      strcpy (Type, Buffer);\r
       //\r
       // build buffer\r
       //\r
@@ -1275,19 +1235,7 @@ Returns:
       }\r
 \r
       StripParens (Buffer);\r
-\r
-      if (Buffer[0] == '$') {\r
-        Index = ProcessEnvironmentVariable (&Buffer[0], ToolName);\r
-        //\r
-        // if there is string after the environment variable, cat it.\r
-        //\r
-        if ((UINT32) Index < strlen (Buffer)) {\r
-          strcat (ToolName, &Buffer[Index]);\r
-        }\r
-      } else {\r
-        strcpy (ToolName, Buffer);\r
-      }\r
-\r
+      strcpy (ToolName, Buffer);\r
       ToolArgumentsArray[0] = ToolName;\r
 \r
       //\r
@@ -1397,13 +1345,8 @@ Returns:
       if (!isalpha (Buffer[0]) || (Buffer[1] != ':')) {\r
         sprintf (FileName, "%s\\", BuildDirectory);\r
       }\r
-\r
+      \r
       while (Buffer[Index3] != '\n') {\r
-        if (Buffer[Index3] == '$') {\r
-          Index3 += ProcessEnvironmentVariable (&Buffer[Index3], NewBuffer);\r
-          strcat (FileName, NewBuffer);\r
-        }\r
-\r
         if (Buffer[Index3] == 0) {\r
           break;\r
         } else {\r
@@ -1420,6 +1363,7 @@ Returns:
         goto Done;\r
       }\r
 \r
+      OldSize = Size;\r
       fread (&ByteBuffer, sizeof (UINT8), 1, InFile);\r
       while (!feof (InFile)) {\r
         FileBuffer[Size++] = ByteBuffer;\r
@@ -1429,6 +1373,29 @@ Returns:
       fclose (InFile);\r
       InFile = NULL;\r
 \r
+      //\r
+      // Adjust the TE Section for IPF so that the function entries are 16-byte aligned.\r
+      //\r
+      if (Size - OldSize >= sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER) &&\r
+          ((EFI_COMMON_SECTION_HEADER *) &FileBuffer[OldSize])->Type == EFI_SECTION_TE        &&\r
+          ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->Machine == EFI_IMAGE_MACHINE_IA64) {\r
+        TeStrippedSize = ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->StrippedSize;\r
+        Adjust = TeStrippedSize - (OldSize + sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER));\r
+        Adjust &= 15;\r
+        if (Adjust > 0) {\r
+          memmove (&FileBuffer[OldSize + Adjust], &FileBuffer[OldSize], Size - OldSize);\r
+          //\r
+          // Pad with RAW Section type\r
+          //\r
+          *(UINT32 *)&FileBuffer[OldSize] = 0x19000000 | Adjust;\r
+          Size += Adjust;\r
+          //\r
+          // Make sure the Data alignment in FFS header is no less than 1 (16-byte aligned)\r
+          //\r
+          MinFfsDataAlignOverride = 1;\r
+        }\r
+      }\r
+\r
       //\r
       // Make sure section ends on a DWORD boundary\r
       //\r
@@ -2252,6 +2219,9 @@ here:
     memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));\r
     memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));\r
     FileHeader.Type       = StringToType (FileType);\r
+    if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) {\r
+      FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3);\r
+    }\r
     FileHeader.Attributes = FfsAttrib;\r
     //\r
     // Now FileSize includes the EFI_FFS_FILE_HEADER\r
@@ -2396,6 +2366,9 @@ here:
     memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));\r
     memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));\r
     FileHeader.Type       = StringToType (FileType);\r
+    if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) {\r
+      FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3);\r
+    }\r
     FileHeader.Attributes = FfsAttrib;\r
     //\r
     // From this point on FileSize includes the size of the EFI_FFS_FILE_HEADER\r
@@ -2540,6 +2513,7 @@ Returns:
   //\r
   SetUtilityName (UTILITY_NAME);\r
   Status = ProcessCommandLineArgs (argc, argv);\r
+  FreeMacros ();\r
   if (Status != STATUS_SUCCESS) {\r
     return Status;\r
   }\r
@@ -2577,6 +2551,11 @@ Returns:
 \r
 --*/\r
 {\r
+  STATUS       Status;\r
+  UINT8        *OriginalPrimaryPackagePath;\r
+  UINT8        *OriginalOverridePackagePath;\r
+  UINT8        *PackageName;\r
+  \r
   //\r
   // If no args, then print usage instructions and return an error\r
   //\r
@@ -2584,7 +2563,9 @@ Returns:
     PrintUsage ();\r
     return STATUS_ERROR;\r
   }\r
-\r
+  \r
+  OriginalPrimaryPackagePath = NULL;\r
+  OriginalOverridePackagePath = NULL;\r
   memset (&mGlobals, 0, sizeof (mGlobals));\r
   Argc--;\r
   Argv++;\r
@@ -2617,12 +2598,12 @@ Returns:
         return STATUS_ERROR;\r
       }\r
 \r
-      if (mGlobals.PrimaryPackagePath[0]) {\r
+      if (OriginalPrimaryPackagePath) {\r
         Error (NULL, 0, 0, Argv[0], "option can only be specified once");\r
         return STATUS_ERROR;\r
       }\r
-\r
-      strcpy (mGlobals.PrimaryPackagePath, Argv[1]);\r
+      \r
+      OriginalPrimaryPackagePath = Argv[1];\r
       Argc--;\r
       Argv++;\r
     } else if (_strcmpi (Argv[0], "-p2") == 0) {\r
@@ -2635,12 +2616,12 @@ Returns:
         return STATUS_ERROR;\r
       }\r
 \r
-      if (mGlobals.OverridePackagePath[0]) {\r
+      if (OriginalOverridePackagePath) {\r
         Error (NULL, 0, 0, Argv[0], "option can only be specified once");\r
         return STATUS_ERROR;\r
       }\r
-\r
-      strcpy (mGlobals.OverridePackagePath, Argv[1]);\r
+      \r
+      OriginalOverridePackagePath = Argv[1];\r
       Argc--;\r
       Argv++;\r
     } else if (_strcmpi (Argv[0], "-v") == 0) {\r
@@ -2648,6 +2629,19 @@ Returns:
       // OPTION: -v       verbose\r
       //\r
       mGlobals.Verbose = TRUE;\r
+    } else if (_strcmpi (Argv[0], "-d") == 0) {\r
+      //\r
+      // OPTION: -d  name=value\r
+      // Make sure there is another argument, then add it to our macro list.\r
+      //\r
+      if (Argc < 2) {\r
+        Error (NULL, 0, 0, Argv[0], "option requires the macro definition");\r
+        return STATUS_ERROR;\r
+      }\r
+      \r
+      AddMacro (Argv[1]);\r
+      Argc--;\r
+      Argv++;\r
     } else if (_strcmpi (Argv[0], "-h") == 0) {\r
       //\r
       // OPTION: -h      help\r
@@ -2669,13 +2663,324 @@ Returns:
     Argv++;\r
     Argc--;\r
   }\r
+\r
+  //\r
+  // Must have at least specified the build directory\r
+  //\r
+  if (!mGlobals.BuildDirectory[0]) {\r
+    Error (NULL, 0, 0, "must specify build directory", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  \r
   //\r
   // Must have at least specified the package file name\r
   //\r
-  if (mGlobals.PrimaryPackagePath[0] == 0) {\r
+  if (OriginalPrimaryPackagePath == NULL) {\r
     Error (NULL, 0, 0, "must specify primary package file", NULL);\r
     return STATUS_ERROR;\r
   }\r
 \r
+  PackageName = OriginalPrimaryPackagePath + strlen (OriginalPrimaryPackagePath);\r
+  while ((*PackageName != '\\') && (*PackageName != '/') && \r
+         (PackageName != OriginalPrimaryPackagePath)) {\r
+    PackageName--;\r
+  }\r
+  //\r
+  // Skip the '\' or '/'\r
+  //\r
+  if (PackageName != OriginalPrimaryPackagePath) {\r
+    PackageName++;\r
+  }\r
+  sprintf (mGlobals.PrimaryPackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName);\r
+  Status = ReplaceMacros (OriginalPrimaryPackagePath, mGlobals.PrimaryPackagePath);\r
+  if (Status == STATUS_WARNING) {\r
+    //\r
+    // No macro replacement, use the previous package file\r
+    //\r
+    strcpy (mGlobals.PrimaryPackagePath, OriginalPrimaryPackagePath);\r
+  } else if (Status != STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+  \r
+  if (OriginalOverridePackagePath != NULL) {\r
+    PackageName = OriginalOverridePackagePath + strlen (OriginalOverridePackagePath);\r
+    while ((*PackageName != '\\') && (*PackageName != '/') && \r
+           (PackageName != OriginalOverridePackagePath)) {\r
+      PackageName--;\r
+    }\r
+    //\r
+    // Skip the '\' or '/'\r
+    //\r
+    if (PackageName != OriginalOverridePackagePath) {\r
+      PackageName++;\r
+    }    \r
+    sprintf (mGlobals.OverridePackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName);\r
+    Status = ReplaceMacros (OriginalOverridePackagePath, mGlobals.OverridePackagePath);\r
+    if (Status == STATUS_WARNING) {\r
+      //\r
+      // No macro replacement, use the previous package file\r
+      //\r
+      strcpy (mGlobals.OverridePackagePath, OriginalOverridePackagePath);\r
+    } else if (Status != STATUS_SUCCESS) {\r
+        return Status;\r
+    }    \r
+  }\r
+\r
   return STATUS_SUCCESS;\r
 }\r
+\r
+static\r
+void\r
+AddMacro (\r
+  UINT8   *MacroString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Add or override a macro definition.\r
+\r
+Arguments:\r
+\r
+  MacroString  - macro definition string: name=value\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/  \r
+{\r
+  MACRO    *Macro;\r
+  MACRO    *NewMacro;\r
+  UINT8    *Value;\r
+  \r
+  //\r
+  // Seperate macro name and value by '\0'\r
+  //\r
+  for (Value = MacroString; *Value && (*Value != '='); Value++);\r
+  \r
+  if (*Value == '=') {\r
+    *Value = '\0';\r
+    Value ++;\r
+  }\r
+  \r
+  //\r
+  // We now have a macro name and value. \r
+  // Look for an existing macro and overwrite it.\r
+  //\r
+  Macro = mGlobals.MacroList;\r
+  while (Macro) {\r
+    if (_strcmpi (MacroString, Macro->Name) == 0) {\r
+      Macro->Value = Value;\r
+      return;\r
+    }\r
+\r
+    Macro = Macro->Next;\r
+  }\r
+  \r
+  //\r
+  // Does not exist, create a new one\r
+  //\r
+  NewMacro = (MACRO *) malloc (sizeof (MACRO));\r
+  memset ((UINT8 *) NewMacro, 0, sizeof (MACRO));\r
+  NewMacro->Name   = MacroString;\r
+  NewMacro->Value  = Value;\r
+\r
+  //\r
+  // Add it to the head of the list.\r
+  //\r
+  NewMacro->Next = mGlobals.MacroList;\r
+  mGlobals.MacroList = NewMacro;\r
+  \r
+  return;\r
+}\r
+\r
+static\r
+UINT8 *\r
+GetMacroValue (\r
+  UINT8   *MacroName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Look up a macro.\r
+\r
+Arguments:\r
+\r
+  MacroName  - The name of macro\r
+\r
+Returns:\r
+\r
+  Pointer to the value of the macro if found\r
+  NULL if the macro is not found\r
+\r
+--*/   \r
+{\r
+\r
+  MACRO  *Macro;\r
+  UINT8  *Value;\r
+\r
+  //\r
+  // Scan for macro\r
+  //\r
+  Macro = mGlobals.MacroList;\r
+  while (Macro) {\r
+    if (_strcmpi (MacroName, Macro->Name) == 0) {\r
+      return Macro->Value;\r
+    }\r
+    Macro = Macro->Next;\r
+  }\r
+  \r
+  //\r
+  // Try environment variable\r
+  //\r
+  Value = getenv (MacroName);\r
+  if (Value == NULL) {\r
+    printf ("Environment variable %s not found!\n", MacroName);\r
+  }   \r
+  return Value;\r
+}\r
+  \r
+static\r
+void\r
+FreeMacros (\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Free the macro list.\r
+\r
+Arguments:\r
+\r
+  None\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/    \r
+{\r
+  MACRO    *Macro;\r
+  MACRO    *NextMacro;\r
+  \r
+  Macro = mGlobals.MacroList;\r
+  while (Macro) {\r
+    NextMacro = Macro->Next;\r
+    free (Macro);\r
+    Macro = NextMacro;\r
+  }\r
+  mGlobals.MacroList = NULL;\r
+  \r
+  return;\r
+}\r
+\r
+static\r
+STATUS\r
+ReplaceMacros (\r
+  UINT8   *InputFile,\r
+  UINT8   *OutputFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Replace all the macros in InputFile to create the OutputFile.\r
+\r
+Arguments:\r
+\r
+  InputFile         - Input package file for macro replacement\r
+  OutputFile        - Output package file after macro replacement\r
+\r
+Returns:\r
+\r
+  STATUS_SUCCESS    - Output package file is created successfully after the macro replacement.\r
+  STATUS_WARNING    - Output package file is not created because of no macro replacement.\r
+  STATUS_ERROR      - Some error occurred during execution.\r
+\r
+--*/    \r
+{\r
+  FILE   *Fptr;\r
+  UINT8  *SaveStart;\r
+  UINT8  *FromPtr;\r
+  UINT8  *ToPtr;\r
+  UINT8  *Value;\r
+  UINT8  *FileBuffer;\r
+  UINTN  FileSize;\r
+  \r
+  //\r
+  // Get the file size, and then read the entire thing into memory.\r
+  // Allocate extra space for a terminator character.\r
+  //\r
+  if ((Fptr = fopen (InputFile, "r")) == NULL) {\r
+    Error (NULL, 0, 0, InputFile, "can't open input file");\r
+    return STATUS_ERROR;    \r
+  }\r
+  fseek (Fptr, 0, SEEK_END);\r
+  FileSize = ftell (Fptr);\r
+  fseek (Fptr, 0, SEEK_SET);\r
+  FileBuffer = malloc (FileSize + 1);\r
+  if (FileBuffer == NULL) {\r
+    fclose (Fptr);\r
+    Error (NULL, 0, 0, InputFile, "file buffer memory allocation failure");\r
+    return STATUS_ERROR;\r
+  }\r
+  fread (FileBuffer, FileSize, 1, Fptr);\r
+  FileBuffer[FileSize] = '\0';\r
+  fclose (Fptr);\r
+    \r
+  //\r
+  // Walk the entire file, replacing $(MACRO_NAME).\r
+  //\r
+  Fptr = NULL;\r
+  FromPtr = FileBuffer;\r
+  SaveStart = FromPtr;\r
+  while (*FromPtr) {\r
+    if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) {\r
+      FromPtr += 2;\r
+      for (ToPtr = FromPtr; *ToPtr && (*ToPtr != ')'); ToPtr++);\r
+      if (*ToPtr) {\r
+        //\r
+        // Find an $(MACRO_NAME), replace it\r
+        //\r
+        *ToPtr = '\0';\r
+        Value = GetMacroValue (FromPtr);\r
+        *(FromPtr-2)= '\0';\r
+        if (Fptr == NULL) {\r
+          if ((Fptr = fopen (OutputFile, "w")) == NULL) {\r
+            free (FileBuffer);\r
+            Error (NULL, 0, 0, OutputFile, "can't open output file");\r
+            return STATUS_ERROR;    \r
+          }\r
+        }\r
+        if (Value != NULL) {\r
+          fprintf (Fptr, "%s%s", SaveStart, Value);\r
+        } else {\r
+          fprintf (Fptr, "%s", SaveStart);\r
+        }\r
+        //\r
+        // Continue macro replacement for the remaining string line\r
+        //\r
+        FromPtr = ToPtr+1;\r
+        SaveStart = FromPtr;\r
+        continue;\r
+      } else {\r
+        break;\r
+      }\r
+    } else {\r
+      FromPtr++;\r
+    }\r
+  }\r
+  if (Fptr != NULL) {\r
+    fprintf (Fptr, "%s", SaveStart);\r
+  }\r
+  \r
+  free (FileBuffer);\r
+  if (Fptr != NULL) {\r
+    fclose (Fptr);\r
+    return STATUS_SUCCESS;\r
+  } else {\r
+    return STATUS_WARNING;\r
+  }\r
+}\r