From 3eb9473ea9a949badfe06ae61d2d3fcfa53651c7 Mon Sep 17 00:00:00 2001 From: qwang12 Date: Thu, 28 Jun 2007 07:00:39 +0000 Subject: Add in the 1st version of ECP. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2832 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Sample/Tools/Source/ProcessDsc/Common.h | 123 + .../Sample/Tools/Source/ProcessDsc/DscFile.c | 534 +++ .../Sample/Tools/Source/ProcessDsc/DscFile.h | 109 + .../Sample/Tools/Source/ProcessDsc/Exceptions.c | 141 + .../Sample/Tools/Source/ProcessDsc/Exceptions.h | 57 + .../Sample/Tools/Source/ProcessDsc/FWVolume.c | 1566 +++++++ .../Sample/Tools/Source/ProcessDsc/FWVolume.h | 76 + .../Sample/Tools/Source/ProcessDsc/Makefile | 102 + .../Sample/Tools/Source/ProcessDsc/ProcessDsc.c | 4726 ++++++++++++++++++++ 9 files changed, 7434 insertions(+) create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Common.h create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/DscFile.c create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/DscFile.h create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Exceptions.c create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Exceptions.h create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.h create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Makefile create mode 100644 EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/ProcessDsc.c (limited to 'EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc') diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Common.h b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Common.h new file mode 100644 index 0000000000..b642d092cb --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Common.h @@ -0,0 +1,123 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Common.h + +Abstract: + + Common include file for the ProcessDsc utility. + +--*/ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +typedef char INT8; +typedef unsigned int UINT32; + +#include "EfiUtilityMsgs.h" + +#define MAX_LINE_LEN 1024 + +#ifdef MAX_PATH +#undef MAX_PATH +#define MAX_PATH 1024 +#endif + +// +// Defines for how to expand symbols +// +#define EXPANDMODE_NO_UNDEFS 0x01 +#define EXPANDMODE_NO_DESTDIR 0x02 +#define EXPANDMODE_NO_SOURCEDIR 0x04 +#define EXPANDMODE_RECURSIVE 0x08 + +// +// Defines for adding symbols +// +#define SYM_OVERWRITE 0x01 // overwrite existing assignments +#define SYM_GLOBAL 0x02 // global symbol (persistent) +#define SYM_LOCAL 0x04 // symbols at component level +#define SYM_FILE 0x08 // symbols at file level +#define SYM_FILEPATH 0x10 // symbol is a file path +#define SYM_FILENAME 0x20 // symbol is a file name +#define FV_DIR "FV_DIR" // symbol for base dir where FV files are +#define DSC_FILENAME "DSC_FILENAME" + +// +// Smart file for better incremental build support. +// Only re-create .pkg .inf or .apr files when it's content is changed. +// +// +typedef struct _SMART_FILE { + char *FileName; + char *FileContent; // Previous file content + int FileLength; // Previous file string length + int FilePosition; // The offset from FileContent for next comparison + FILE *FilePtr; // New file pointer if the file need to be re-created +} SMART_FILE; + +SMART_FILE * +SmartOpen ( + char *FileName + ); + +int +SmartWrite ( + SMART_FILE *SmartFile, + char *String + ); + +void +SmartClose ( + SMART_FILE *SmartFile + ); + +INT8 * +GetSymbolValue ( + INT8 *SymbolName + ); + +int +AddSymbol ( + INT8 *Name, + INT8 *Value, + int Mode + ); + +int +ExpandSymbols ( + INT8 *SourceLine, + INT8 *DestLine, + int LineLen, + int ExpandMode + ); + +void +Message ( + UINT32 PrintMask, + INT8 *Fmt, + ... + ); + +int +MakeFilePath ( + INT8 *FileName + ); + +int +IsAbsolutePath ( + INT8 *FileName + ); + +#endif // ifndef _COMMON_H_ diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/DscFile.c b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/DscFile.c new file mode 100644 index 0000000000..345e1a9e4a --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/DscFile.c @@ -0,0 +1,534 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + DscFile.c + + Abstract: + + This module is used to process description files at a high level. For the + most part, it pre-parses the file to find and save off positions of all + the sections ([section.subsection.subsection]) in a linked list, then + provides services to find the sections by name, and read the lines from + the section until you run into the next section. + + NOTE: DSC file is synonomous with section file. A DSC file is simply a file + containing bracketed section names [section.subsection.subsection...] + +--*/ + +#include // for file ops +#include +#include +#include // for malloc +#include "Common.h" +#include "DSCFile.h" + +#define MAX_INCLUDE_NEST_LEVEL 20 + +static +void +DSCFileFree ( + DSC_FILE *DSC + ); + +static +STATUS +DSCParseInclude ( + DSC_FILE *DSC, + char *FileName, + int NestLevel + ); + +// +// Constructor for a DSC file +// +int +DSCFileInit ( + DSC_FILE *DSC + ) +{ + memset ((char *) DSC, 0, sizeof (DSC_FILE)); + DSC->SavedPositionIndex = -1; + return STATUS_SUCCESS; +} +// +// Destructor for a DSC file +// +int +DSCFileDestroy ( + DSC_FILE *DSC + ) +{ + DSC->SavedPositionIndex = -1; + DSCFileFree (DSC); + return STATUS_SUCCESS; +} +// +// Get the next line from a DSC file. +// +char * +DSCFileGetLine ( + DSC_FILE *DSC, + char *Line, + int LineLen + ) +{ + char *Cptr; + + if (DSC->CurrentLine == NULL) { + return NULL; + } + // + // Check for running into next section + // + if (DSC->CurrentLine->Line[0] == '[') { + return NULL; + } + // + // Allow special case where the line starts with backslash-bracket. If we + // see this, then shift everything left one character. + // + if ((DSC->CurrentLine->Line[0] == '\\') && (DSC->CurrentLine->Line[1] == '[')) { + Cptr = DSC->CurrentLine->Line + 1; + } else { + Cptr = DSC->CurrentLine->Line; + } + + strncpy (Line, Cptr, LineLen); + ParserSetPosition (DSC->CurrentLine->FileName, DSC->CurrentLine->LineNum); + DSC->CurrentLine = DSC->CurrentLine->Next; + return Line; +} + +int +DSCFileSetFile ( + DSC_FILE *DSC, + char *FileName + ) +/*++ + +Routine Description: + + Pre-scan a section file to find all the sections. Then we can speed up + searching for the different sections. + +Arguments: + + DSC - pointer to a DSC structure (this pointer) + FileName - name of the file to process + +Returns: + + STATUS_SUCCESS if everything went well. + +--*/ +{ + STATUS Status; + + // + // Called to open a new sectioned file. + // + Status = DSCParseInclude (DSC, FileName, 1); + return Status; +} + +static +STATUS +DSCParseInclude ( + DSC_FILE *DSC, + char *FileName, + int NestLevel + ) +{ + SECTION *NewSect; + SECTION_LINE *NewLine; + DSC_FILE_NAME *NewDscFileName; + char Line[MAX_LINE_LEN]; + char *Start; + char *End; + char SaveChar; + char *TempCptr; + char ShortHandSectionName[MAX_LINE_LEN]; + char ThisSectionName[MAX_LINE_LEN]; + SECTION *CurrSect; + SECTION *TempSect; + FILE *FilePtr; + STATUS Status; + UINT32 LineNum; + + // + // Make sure we haven't exceeded our maximum nesting level + // + if (NestLevel > MAX_INCLUDE_NEST_LEVEL) { + Error (NULL, 0, 0, "application error", "maximum !include nesting level exceeded"); + return STATUS_ERROR; + } + // + // Try to open the file + // + if ((FilePtr = fopen (FileName, "r")) == NULL) { + // + // This function is called to handle the DSC file from the command line too, + // so differentiate whether this file is an include file or the main file + // by examining the nest level. + // + if (NestLevel == 1) { + Error (NULL, 0, 0, FileName, "could not open DSC file for reading"); + } else { + Error (NULL, 0, 0, FileName, "could not open !include DSC file for reading"); + } + + return STATUS_ERROR; + } + // + // We keep a linked list of files we parse for error reporting purposes. + // + NewDscFileName = malloc (sizeof (DSC_FILE_NAME)); + if (NewDscFileName == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL); + return STATUS_ERROR; + } + + memset (NewDscFileName, 0, sizeof (DSC_FILE_NAME)); + NewDscFileName->FileName = (INT8 *) malloc (strlen (FileName) + 1); + if (NewDscFileName->FileName == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL); + return STATUS_ERROR; + } + + strcpy (NewDscFileName->FileName, FileName); + if (DSC->FileName == NULL) { + DSC->FileName = NewDscFileName; + } else { + DSC->LastFileName->Next = NewDscFileName; + } + + DSC->LastFileName = NewDscFileName; + // + // Read lines and process until done + // + Status = STATUS_SUCCESS; + LineNum = 0; + for (;;) { + if (fgets (Line, sizeof (Line), FilePtr) == NULL) { + break; + } + + LineNum++; + ParserSetPosition (FileName, LineNum); + // + // Add the line to our list if it's not a !include line + // + if ((strncmp (Line, "!include", 8) == 0) && (isspace (Line[8]))) { + Start = Line + 9; + while (*Start && (*Start != '"')) { + Start++; + } + + if (*Start != '"') { + Error (FileName, LineNum, 0, NULL, "invalid format for !include"); + Status = STATUS_ERROR; + goto Done; + } + + Start++; + for (End = Start; *End && (*End != '"'); End++) + ; + if (*End != '"') { + Error (FileName, LineNum, 0, NULL, "invalid format for !include"); + Status = STATUS_ERROR; + goto Done; + } + + *End = 0; + // + // Expand symbols. Use 'ThisSectionName' as scratchpad + // + ExpandSymbols (Start, ThisSectionName, sizeof (ThisSectionName), EXPANDMODE_NO_UNDEFS); + Status = DSCParseInclude (DSC, ThisSectionName, NestLevel + 1); + if (Status != STATUS_SUCCESS) { + Error (FileName, LineNum, 0, NULL, "failed to parse !include file"); + goto Done; + } + } else { + NewLine = (SECTION_LINE *) malloc (sizeof (SECTION_LINE)); + if (NewLine == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + Status = STATUS_ERROR; + goto Done; + } + + memset ((char *) NewLine, 0, sizeof (SECTION_LINE)); + NewLine->LineNum = LineNum; + NewLine->FileName = NewDscFileName->FileName; + NewLine->Line = (char *) malloc (strlen (Line) + 1); + if (NewLine->Line == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + Status = STATUS_ERROR; + goto Done; + } + + strcpy (NewLine->Line, Line); + if (DSC->Lines == NULL) { + DSC->Lines = NewLine; + } else { + DSC->LastLine->Next = NewLine; + } + + DSC->LastLine = NewLine; + // + // Parse the line for []. Ignore [] and [----] delimiters. The + // line may have multiple definitions separated by commas, so + // take each separately + // + Start = Line; + if ((Line[0] == '[') && ((Line[1] != ']') && (Line[1] != '-'))) { + // + // Skip over open bracket and preceeding spaces + // + Start++; + ShortHandSectionName[0] = 0; + + while (*Start && (*Start != ']')) { + while (isspace (*Start)) { + Start++; + } + // + // Hack off closing bracket or trailing spaces or comma separator. + // Also allow things like [section.subsection1|subsection2], which + // is shorthand for [section.subsection1,section.subsection2] + // + End = Start; + while (*End && (*End != ']') && !isspace (*End) && (*End != ',') && (*End != '|')) { + End++; + } + // + // Save the character and null-terminate the string + // + SaveChar = *End; + *End = 0; + // + // Now allocate space for a new section and add it to the linked list. + // If the previous section ended with the shorthand indicator, then + // the section name was saved off. Append this section name to it. + // + strcpy (ThisSectionName, ShortHandSectionName); + if (*Start == '.') { + strcat (ThisSectionName, Start + 1); + } else { + strcat (ThisSectionName, Start); + } + // + // Allocate memory for the section. Then clear it out. + // + NewSect = (SECTION *) malloc (sizeof (SECTION)); + if (NewSect == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocation memory for sections"); + Status = STATUS_ERROR; + goto Done; + } + + memset ((char *) NewSect, 0, sizeof (SECTION)); + NewSect->FirstLine = NewLine; + NewSect->Name = (char *) malloc (strlen (ThisSectionName) + 1); + if (NewSect->Name == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocation memory for sections"); + Status = STATUS_ERROR; + goto Done; + } + + strcpy (NewSect->Name, ThisSectionName); + if (DSC->Sections == NULL) { + DSC->Sections = NewSect; + } else { + DSC->LastSection->Next = NewSect; + } + + DSC->LastSection = NewSect; + *End = SaveChar; + // + // If the name ended in a shorthand indicator, then save the + // section name and truncate it at the last dot. + // + if (SaveChar == '|') { + strcpy (ShortHandSectionName, ThisSectionName); + for (TempCptr = ShortHandSectionName + strlen (ShortHandSectionName) - 1; + (TempCptr != ShortHandSectionName) && (*TempCptr != '.'); + TempCptr-- + ) + ; + // + // If we didn't find a dot, then hopefully they have [name1|name2] + // instead of [name1,name2]. + // + if (TempCptr == ShortHandSectionName) { + ShortHandSectionName[0] = 0; + } else { + // + // Truncate after the dot + // + *(TempCptr + 1) = 0; + } + } else { + // + // Kill the shorthand string + // + ShortHandSectionName[0] = 0; + } + // + // Skip to next section name or closing bracket + // + while (*End && ((*End == ',') || isspace (*End) || (*End == '|'))) { + End++; + } + + Start = End; + } + } + } + } + // + // Look through all the sections to make sure we don't have any duplicates. + // Allow [----] and [====] section separators + // + CurrSect = DSC->Sections; + while (CurrSect != NULL) { + TempSect = CurrSect->Next; + while (TempSect != NULL) { + if (isalpha (CurrSect->Name[0]) && (_stricmp (CurrSect->Name, TempSect->Name) == 0)) { + Error ( + TempSect->FirstLine->FileName, + TempSect->FirstLine->LineNum, + 0, + TempSect->Name, + "duplicate section found" + ); + Error ( + CurrSect->FirstLine->FileName, + CurrSect->FirstLine->LineNum, + 0, + TempSect->Name, + "first definition of duplicate section" + ); + Status = STATUS_ERROR; + goto Done; + } + + TempSect = TempSect->Next; + } + + CurrSect = CurrSect->Next; + } + +Done: + fclose (FilePtr); + return Status; +} +// +// Free up memory allocated for DSC file handling. +// +static +void +DSCFileFree ( + DSC_FILE *DSC + ) +{ + SECTION *NextSection; + SECTION_LINE *NextLine; + DSC_FILE_NAME *NextName; + + while (DSC->Sections != NULL) { + NextSection = DSC->Sections->Next; + if (DSC->Sections->Name != NULL) { + free (DSC->Sections->Name); + } + + free (DSC->Sections); + DSC->Sections = NextSection; + } + + while (DSC->Lines != NULL) { + NextLine = DSC->Lines->Next; + free (DSC->Lines->Line); + free (DSC->Lines); + DSC->Lines = NextLine; + } + + while (DSC->FileName != NULL) { + NextName = DSC->FileName->Next; + free (DSC->FileName->FileName); + free (DSC->FileName); + DSC->FileName = NextName; + } +} + +SECTION * +DSCFileFindSection ( + DSC_FILE *DSC, + char *Name + ) +{ + SECTION *Sect; + + // + // Look through all the sections to find one with this name (case insensitive) + // + Sect = DSC->Sections; + while (Sect != NULL) { + if (_stricmp (Name, Sect->Name) == 0) { + // + // Position within file + // + DSC->CurrentLine = Sect->FirstLine->Next; + return Sect; + } + + Sect = Sect->Next; + } + + return NULL; +} + +int +DSCFileSavePosition ( + DSC_FILE *DSC + ) +{ + // + // Advance to next slot + // + DSC->SavedPositionIndex++; + if (DSC->SavedPositionIndex >= MAX_SAVES) { + DSC->SavedPositionIndex--; + Error (NULL, 0, 0, "APP ERROR", "max nesting of saved section file positions exceeded"); + return STATUS_ERROR; + } + + DSC->SavedPosition[DSC->SavedPositionIndex] = DSC->CurrentLine; + return STATUS_SUCCESS; +} + +int +DSCFileRestorePosition ( + DSC_FILE *DSC + ) +{ + if (DSC->SavedPositionIndex < 0) { + Error (NULL, 0, 0, "APP ERROR", "underflow of saved positions in section file"); + return STATUS_ERROR; + } + + DSC->CurrentLine = DSC->SavedPosition[DSC->SavedPositionIndex]; + DSC->SavedPositionIndex--; + return STATUS_SUCCESS; +} diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/DscFile.h b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/DscFile.h new file mode 100644 index 0000000000..4dcad547ec --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/DscFile.h @@ -0,0 +1,109 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DscFile.h + +Abstract: + + Defines and function prototypes for the ProcessDsc utility. + +--*/ + +#ifndef _DSC_FILE_H_ +#define _DSC_FILE_H_ + +typedef struct _SECTION_LINE { + struct _SECTION_LINE *Next; + char *Line; + char *FileName; + UINT32 LineNum; +} SECTION_LINE; + +// +// Use this structure to keep track of parsed file names. Then +// if we get a parse error we can figure out the file/line of +// the error and print a useful message. +// +typedef struct _DSC_FILE_NAME { + struct _DSC_FILE_NAME *Next; + char *FileName; +} DSC_FILE_NAME; + +// +// We create a list of section names when we pre-parse a description file. +// Use this structure. +// +typedef struct _SECTION { + struct _SECTION *Next; + char *Name; + SECTION_LINE *FirstLine; +} SECTION; + +#define MAX_SAVES 4 + +typedef struct { + SECTION_LINE *SavedPosition[MAX_SAVES]; + int SavedPositionIndex; + SECTION *Sections; + SECTION_LINE *Lines; + SECTION *LastSection; + SECTION_LINE *LastLine; + SECTION_LINE *CurrentLine; + DSC_FILE_NAME *FileName; + DSC_FILE_NAME *LastFileName; +} DSC_FILE; + +// +// Function prototypes +// +int +DSCFileSetFile ( + DSC_FILE *DSC, + char *FileName + ) +; +SECTION * +DSCFileFindSection ( + DSC_FILE *DSC, + char *Name + ) +; +int +DSCFileSavePosition ( + DSC_FILE *DSC + ) +; +int +DSCFileRestorePosition ( + DSC_FILE *DSC + ) +; +char * +DSCFileGetLine ( + DSC_FILE *DSC, + char *Line, + int LineLen + ) +; +int +DSCFileInit ( + DSC_FILE *DSC + ) +; +int +DSCFileDestroy ( + DSC_FILE *DSC + ) +; + +#endif // ifndef _DSC_FILE_H_ diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Exceptions.c b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Exceptions.c new file mode 100644 index 0000000000..bc50183ac3 --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Exceptions.c @@ -0,0 +1,141 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Exceptions.c + +Abstract: + + Exception logging routines. + +--*/ + +#include +#include +#include // for memset() +#include "Exceptions.h" + +// +// Max length of a saved exception message +// +#define MAX_EXCEPTION_MSG 200 + +// +// We use this structure to track exceptions thrown. We nest deeper on +// TryException() calls, and come back out on CatchException() calls. +// We save off the first exception message for a given exception level, +// but we save the count of how many were thrown. +// +typedef struct { + int ExceptionCount; + char ExceptionMsg[MAX_EXCEPTION_MSG]; +} EXCEPTION_LOG; + +static EXCEPTION_LOG ExceptionLog[MAX_EXCEPTION_NESTING + 1]; +static int ExceptionLevel; + +// +// Initialize our data and structures for tracking exceptions. +// +int +InitExceptions ( + VOID + ) +{ + ExceptionLevel = -1; + memset ((char *) &ExceptionLog, 0, sizeof (ExceptionLog)); + return 0; +} +// +// This function replaces the _try() exception macro. It sets the +// nesting level. +// +int +TryException ( + VOID + ) +{ + // + // Boost our exception level if we would not go out of range + // + ExceptionLevel++; + if (ExceptionLevel >= MAX_EXCEPTION_NESTING) { + fprintf (stderr, "ERROR: Max exception nesting level exceeded\n"); + ExceptionLevel--; + return 1; + } + + return 0; +} +// +// This function replaces the _catch() exception macro. It's used to decrement +// the nesting level and return any exeption error messages that were +// thrown at the current nesting level. +// +char * +CatchException ( + VOID + ) +{ + // + // Return a pointer to exception message. NULL if no exceptions at this level + // + if (ExceptionLevel >= 0) { + ExceptionLevel--; + if (ExceptionLog[ExceptionLevel + 1].ExceptionMsg[0]) { + return ExceptionLog[ExceptionLevel + 1].ExceptionMsg; + } else { + return NULL; + } + } else { + fprintf (stderr, "ERROR: Invalid nesting level call to CatchException()\n"); + return NULL; + } +} +// +// This function can be used to test for exceptions between the TryException() +// and CatchException() calls in a given function. +// +int +ExceptionThrown ( + VOID + ) +{ + return ExceptionLog[ExceptionLevel].ExceptionCount; +} +// +// This function replaces the _throw() exception macro. It saves off the +// given error message at the current exeption level nesting. +// +int +ThrowException ( + char *Msg + ) +{ + if (ExceptionLevel < 0) { + // + // fprintf (stderr, "ERROR: Exception thrown out of scope"); + // Haven't yet enabled handling of exceptions, so just emit the message. + // + fprintf (stderr, Msg); + return 1; + } + // + // Only log the first + // + if (ExceptionLog[ExceptionLevel].ExceptionMsg[0] == 0) { + strncpy (ExceptionLog[ExceptionLevel].ExceptionMsg, Msg, MAX_EXCEPTION_MSG); + } + + ExceptionLog[ExceptionLevel].ExceptionCount++; + return 0; +} diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Exceptions.h b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Exceptions.h new file mode 100644 index 0000000000..1425d4387a --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Exceptions.h @@ -0,0 +1,57 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Exceptions.h + +Abstract: + + Defines and function prototypes for the ProcessDsc utility. + +--*/ + +#ifndef _EXCEPTIONS_H_ +#define _EXCEPTIONS_H_ + +#define VOID void +#define MAX_EXCEPTION_NESTING 4 + +// +// Function prototypes +// +int +InitExceptions ( + VOID + ) +; +int +TryException ( + VOID + ) +; +char * +CatchException ( + VOID + ) +; +int +ExceptionThrown ( + VOID + ) +; +int +ThrowException ( + char *EMsg + ) +; + +#endif // ifndef _EXCEPTIONS_H_ diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c new file mode 100644 index 0000000000..28baf5551b --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c @@ -0,0 +1,1566 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FWVolume.c + +Abstract: + + This module contains functionality to keep track of files destined for + multiple firmware volues. It saves them up, and when told to, dumps the + file names out to some files used as input to other utilities that + actually generate the FVs. + +--*/ + +#include // for max_path definition +#include +#include +#include // for malloc() +#include "Common.h" +#include "DSCFile.h" +#include "FWVolume.h" + +#define FV_INF_DIR "FV_INF_DIR" // symbol for where we create the FV INF file +#define FV_FILENAME "FV_FILENAME" // symbol for the current FV.INF filename +#define EFI_BASE_ADDRESS "EFI_BASE_ADDRESS" +#define DEFAULT_FV_INF_DIR "FV" // default dir for where we create the FV INF file +#define DEFAULT_FV_DIR "$(BUILD_DIR)" // where the FV file comes from +#define MALLOC(size) malloc (size) +#define FREE(ptr) free (ptr) + +// +// Disable warning for unused function arguments +// +#pragma warning(disable : 4100) +// +// Disable warning for while(1) code +// +// #pragma warning (disable : 4127) +// +typedef struct { + char *ComponentType; + char *Extension; +} COMP_TYPE_EXTENSION; + +// +// Use a linked list of these to keep track of all the FV names used +// +typedef struct _FV_LIST { + struct _FV_LIST *Next; + char FVFileName[MAX_PATH]; + char BaseAddress[MAX_LINE_LEN]; + SMART_FILE *FVFilePtr; + SMART_FILE *AprioriFilePtr; + char *Processor; + int ComponentsInstance; // highest [components.n] section with a file for this FV +} FV_LIST; + +// +// Use a linked list of these to keep track of all FFS files built. When +// we're done, we turn the info into the FV INF files used to build the +// firmware volumes. +// +typedef struct _FILE_LIST { + struct _FILE_LIST *Next; + char *FileName; + char *BaseFileName; + char *FVs; // from FV=x,y,z + char *BaseName; // only needed for duplicate basename check + char *Processor; // only needed for duplicate basename check + char Apriori[100]; // of format "FVRecovery:1,FVMain:2" from APRIORI define + char *Guid; // guid string + int ComponentsInstance; // which [components.n] section it's in +} FILE_LIST; + +typedef struct _LINKED_LIST { + struct _LINKED_LIST *Next; + void *Data; +} LINKED_LIST; + +static FILE_LIST *mFileList; +static FILE_LIST *mLastFile; +static char *mXRefFileName = NULL; +static FV_LIST *mNonFfsFVList = NULL; + +// +// Whenever an FV name is referenced, then add it to our list of known +// FV's using these. +// +static FV_LIST *mFVList = NULL; +static FV_LIST *mFVListLast = NULL; + +// +// We use this list so that from a given component type, we can determine +// the name of the file on disk. For example, if we're given a file's +// guid and base name, and we know it's a "bs_driver", then we can look +// up "bs_driver" in this array and know that the file (after it's built) +// name is GUID-BASENAME.DXE +// +static const COMP_TYPE_EXTENSION mCompTypeExtension[] = { + { + "bs_driver", + ".dxe" + }, + { + "rt_driver", + ".dxe" + }, + { + "sal_rt_driver", + ".dxe" + }, + { + "security_core", + ".sec" + }, + { + "pei_core", + ".pei" + }, + { + "pic_peim", + ".pei" + }, + { + "pe32_peim", + ".pei" + }, + { + "relocatable_peim", + ".pei" + }, + { + "binary", + ".ffs" + }, + { + "application", + ".app" + }, + { + "file", + ".ffs" + }, + { + "fvimagefile", + ".fvi" + }, + { + "rawfile", + ".raw" + }, + { + "apriori", + ".ffs" + }, + { + "combined_peim_driver", + ".pei" + }, + { + NULL, + NULL + } +}; + +static +void +CFVFreeFileList ( + VOID + ); + +static +char * +UpperCaseString ( + char *Str + ); + +static +BOOLEAN +InSameFv ( + char *FVs1, + char *FVs2 +); + +static +void +AddFirmwareVolumes ( + char *FVs, + int ComponentsInstance, + FILE_LIST *FileListPtr + ); + +static +BOOLEAN +OrderInFvList ( + char *FvList, + char *FvName, + int *Order + ); + +int +GetBaseAddress ( + char *Name, + char *BaseAddress + ) +{ + char *Start; + char *Cptr; + char CSave; + char *Value; + + Start = Name; + while (*Name && isspace (*Name)) { + Name++; + } + + if (!*Name) { + return STATUS_ERROR; + } + // + // Find the end of the name. Either space or a '='. + // + for (Value = Name; *Value && !isspace (*Value) && (*Value != '='); Value++) + ; + if (!*Value) { + return STATUS_ERROR; + } + // + // Look for the '=' + // + Cptr = Value; + while (*Value && (*Value != '=')) { + Value++; + } + + if (!*Value) { + return STATUS_ERROR; + } + // + // Now truncate the name + // + CSave = *Cptr; + *Cptr = 0; + if (_stricmp (Name, EFI_BASE_ADDRESS) != 0) { + return STATUS_ERROR; + } + + *Cptr = CSave; + // + // Skip over the = and then any spaces + // + Value++; + while (*Value && isspace (*Value)) { + Value++; + } + // + // Find end of string, checking for quoted string + // + if (*Value == '\"') { + Value++; + for (Cptr = Value; *Cptr && *Cptr != '\"'; Cptr++) + ; + } else { + for (Cptr = Value; *Cptr && !isspace (*Cptr); Cptr++) + ; + } + // + // Null terminate the value string + // + CSave = *Cptr; + *Cptr = 0; + strcpy (BaseAddress, Value); + *Cptr = CSave; + + return STATUS_SUCCESS; +} + +int +CFVAddFVFile ( + char *Name, + char *ComponentType, + char *FVs, + int ComponentsInstance, + char *FFSExt, + char *Processor, + char *Apriori, + char *BaseName, + char *Guid + ) +/*++ + +Routine Description: + + Add a file to the list of files in one or more firmware volumes. + +Arguments: + + Name - $(FILE_GUID)-$(BASE_NAME), or filename + ComponentType - type of component being added. Required so we know the + resultant file name after it has been built + FVs - string of commma-separated FVs that the given file is + to be added to. For example, FVs="FV0001,FV0002" + FFSExt - FFS filename extension of the file after it has been built. + This is passed in to us in case we don't know the default + filename extension based on the component type. + Processor - the target processor which the FV is being built for + Apriori - pointer to the definition of APRIORI. For example APRIORI="FvRecovery:1,FvMain:4" + +Returns: + + STATUS_SUCCESS if successful + +--*/ +{ + FILE_LIST *Ptr; + char FileName[MAX_PATH]; + char Str[MAX_PATH]; + int i; + char *Sym; + + // If they provided a filename extension for this type of file, then use it. + // If they did not provide a filename extension, search our list for a + // matching component type and use the extension appropriate for this + // component type. + // + if (FFSExt == NULL) { + // + // They didn't give us a filename extension. Figure it out from the + // component type. + // + for (i = 0; mCompTypeExtension[i].ComponentType != NULL; i++) { + if (_stricmp (ComponentType, mCompTypeExtension[i].ComponentType) == 0) { + FFSExt = mCompTypeExtension[i].Extension; + break; + } + } + // + // If we don't know the file extension, then error out. Just means + // the need to define "FFS_EXT = raw" in the component INF file. + // + if (mCompTypeExtension[i].ComponentType == NULL) { + Error ( + NULL, + 0, + 0, + ComponentType, + "unknown component type - must define FFS_EXT for built filename extension in component INF file" + ); + return STATUS_ERROR; + } + } + // + // We now have all the parts to the FFS filename. Prepend the path to it if + // it's not a full pathname. + // See if they overrode the default base directory for the FV files. + // + if (!IsAbsolutePath (Name)) { + Sym = GetSymbolValue (FV_DIR); + if (Sym == NULL) { + Sym = DEFAULT_FV_DIR; + } + // + // Create the file path. Something like $(BUILD_DIR)\$(PROCESSOR)\$(GUID)-$(BASE_NAME).ext + // If the extension is non-zero length, then make sure there's a dot in it. + // + if ((strlen (FFSExt) > 0) && (FFSExt[0] != '.')) { + sprintf (Str, "%s\\%s\\%s.%s", Sym, Processor, Name, FFSExt); + } else { + sprintf (Str, "%s\\%s\\%s%s", Sym, Processor, Name, FFSExt); + } + + ExpandSymbols (Str, FileName, sizeof (FileName), EXPANDMODE_NO_UNDEFS); + } else { + strcpy (FileName, Name); + } + // + // Traverse the list of files we have so far and make sure we don't have + // any duplicate basenames. If the base name and processor match, then we'll + // have build issues, so don't allow it. We also don't allow the same file GUID + // in the same FV which will cause boot time error if we allow this. + // + Ptr = mFileList; + while (Ptr != NULL) { + if ((Ptr->BaseName != NULL) && (BaseName != NULL) && (_stricmp (BaseName, Ptr->BaseName) == 0)) { + if ((Ptr->Processor != NULL) && (Processor != NULL) && (_stricmp (Processor, Ptr->Processor) == 0)) { + Error (NULL, 0, 0, BaseName, "duplicate base name specified"); + return STATUS_ERROR; + } + } + + if ((Ptr->Guid != NULL) && (Guid != NULL) && (_stricmp (Guid, Ptr->Guid) == 0)) { + if ((Ptr->FVs != NULL) && (FVs != NULL) && (InSameFv (FVs, Ptr->FVs))) { + Error (NULL, 0, 0, Guid, "duplicate Guid specified in the same FV for %s and %s", + (Ptr->BaseName==NULL)?"Unknown":Ptr->BaseName, + (BaseName==NULL)?"Unknown":BaseName); + return STATUS_ERROR; + } + } + + Ptr = Ptr->Next; + } + // + // Allocate a new structure so we can add this file to the list of + // files. + // + Ptr = (FILE_LIST *) malloc (sizeof (FILE_LIST)); + if (Ptr == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + memset ((char *) Ptr, 0, sizeof (FILE_LIST)); + Ptr->FileName = (char *) malloc (strlen (FileName) + 1); + if (Ptr->FileName == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (Ptr->FileName, FileName); + Ptr->ComponentsInstance = ComponentsInstance; + // + // Allocate memory to save the FV list if it's going into an FV. + // + if ((FVs != NULL) && (FVs[0] != 0)) { + Ptr->FVs = (char *) malloc (strlen (FVs) + 1); + if (Ptr->FVs == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (Ptr->FVs, FVs); + } + + Ptr->BaseFileName = (char *) malloc (strlen (Name) + 1); + if (Ptr->BaseFileName == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (Ptr->BaseFileName, Name); + // + // Allocate memory for the basename if they gave us one. May not have one + // if the user is simply adding pre-existing binary files to the image. + // + if (BaseName != NULL) { + Ptr->BaseName = (char *) malloc (strlen (BaseName) + 1); + if (Ptr->BaseName == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (Ptr->BaseName, BaseName); + } + // + // Allocate memory for the processor name + // + if (Processor != NULL) { + Ptr->Processor = (char *) malloc (strlen (Processor) + 1); + if (Ptr->Processor == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (Ptr->Processor, Processor); + } + // + // Allocate memory for the guid name + // + if (Guid != NULL) { + Ptr->Guid = (char *) malloc (strlen (Guid) + 1); + if (Ptr->Guid == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (Ptr->Guid, Guid); + } + // + // If non-null apriori symbol, then save the apriori list for this file + // + if (Apriori != NULL) { + strcpy (Ptr->Apriori, Apriori); + } + + if (mFileList == NULL) { + mFileList = Ptr; + } else { + mLastFile->Next = Ptr; + } + + mLastFile = Ptr; + // + // Add these firmware volumes to the list of known firmware + // volume names. + // + AddFirmwareVolumes (FVs, ComponentsInstance, Ptr); + + return STATUS_SUCCESS; +} + +void +CFVConstructor ( + VOID + ) +{ + mFileList = NULL; + mLastFile = NULL; +} + +void +CFVDestructor ( + VOID + ) +{ + CFVFreeFileList (); + // + // Free up our firmware volume list + // + while (mFVList != NULL) { + mFVListLast = mFVList->Next; + FREE (mFVList); + mFVList = mFVListLast; + } +} + +static +void +CFVFreeFileList ( + VOID + ) +{ + FILE_LIST *Next; + while (mFileList != NULL) { + if (mFileList->FileName != NULL) { + free (mFileList->FileName); + } + + if (mFileList->FVs != NULL) { + free (mFileList->FVs); + } + + free (mFileList->BaseFileName); + if (mFileList->BaseName != NULL) { + free (mFileList->BaseName); + } + + if (mFileList->Processor != NULL) { + free (mFileList->Processor); + } + + if (mFileList->Guid != NULL) { + free (mFileList->Guid); + } + + Next = mFileList->Next; + free (mFileList); + mFileList = Next; + } + + mFileList = NULL; +} + +int +CFVWriteInfFiles ( + DSC_FILE *DSC, + FILE *MakeFptr + ) +/*++ + +Routine Description: + + After processing all components in a DSC file, create the firmware + volume INF files. We actually do a lot more here. + + * Create the FVxxx.inf file that is used by GenFvImage + * Create the Apriori files for each firmware volume that requires one + * Create makefile.out macros for FVxxx_FILES = FVxxx_FILES AnotherFile + so you can do incremental builds of firmware volumes. + * For each FV, emit its build commands to makefile.out + +Arguments: + + DSC - pointer to a DSC_FILE object to extract info from + MakeFptr - pointer to the output makefile + +Returns: + + 0 if successful + non-zero otherwise + +--*/ +{ + FILE_LIST *FileListPtr; + FV_LIST *FVList; + FV_LIST *LastFVList; + FV_LIST *FVPtr; + SECTION *Section; + char *StartCptr; + char *EndCptr; + char CSave; + char Str[MAX_PATH]; + char Line[MAX_LINE_LEN]; + char ExpandedLine[MAX_LINE_LEN]; + char FVDir[MAX_PATH]; + FILE *XRefFptr; + int AprioriCounter; + int AprioriCount; + int AprioriPosition; + BOOLEAN AprioriFound; + int ComponentsInstance; + int ComponentCount; + + // + // Use this to keep track of all the firmware volume names + // + FVList = NULL; + LastFVList = NULL; + // + // See if they specified a FV directory to dump the FV files out to. If not, + // then use the default. Then create the output directory. + // + StartCptr = GetSymbolValue (FV_INF_DIR); + if (StartCptr == NULL) { + ExpandSymbols (DEFAULT_FV_INF_DIR, FVDir, sizeof (FVDir), EXPANDMODE_NO_UNDEFS); + } else { + strcpy (FVDir, StartCptr); + } + // + // Make sure the fv directory path ends in / + // + CSave = FVDir[strlen (FVDir) - 1]; + if ((CSave != '\\') && (CSave != '/')) { + strcat (FVDir, "\\"); + } + // + // Traverse the list of all files, determine which FV each is in, then + // write out the file's name to the output FVxxx.inf file. + // + for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) { + // + // Parse all the "FV1,FV2..." in the FVs + // + if (FileListPtr->FVs != NULL) { + // + // Process each fv this file is in + // + StartCptr = FileListPtr->FVs; + while (*StartCptr) { + EndCptr = StartCptr; + while (*EndCptr && (*EndCptr != ',')) { + EndCptr++; + } + + CSave = *EndCptr; + *EndCptr = 0; + // + // Ok, we have a fv name, now see if we've already opened + // an fv output file of this name. + // + for (FVPtr = FVList; FVPtr != NULL; FVPtr = FVPtr->Next) { + if (_stricmp (FVPtr->FVFileName, StartCptr) == 0) { + break; + } + } + // + // If we didn't find one, then create a new one + // + if (FVPtr == NULL) { + // + // Create a new one, add it to the list + // + FVPtr = (FV_LIST *) malloc (sizeof (FV_LIST)); + if (FVPtr == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory for FV"); + return STATUS_ERROR; + } + + memset ((char *) FVPtr, 0, sizeof (FV_LIST)); + // + // Add it to the end of our list + // + if (FVList == NULL) { + FVList = FVPtr; + } else { + LastFVList->Next = FVPtr; + } + + LastFVList = FVPtr; + // + // Save the FV name in the FileName pointer so we can compare + // for any future FV names specified. + // + strcpy (FVPtr->FVFileName, StartCptr); + + // + // Add a symbol for the FV filename + // + UpperCaseString (FVPtr->FVFileName); + AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE); + // + // Now create the FVx.inf filename from the fv name and + // default filename extension. Dump it in the FV directory + // as well. + // + strcpy (Str, FVDir); + strcat (Str, FVPtr->FVFileName); + strcat (Str, ".inf"); + // + // Create the directory path for our new fv.inf output file. + // + MakeFilePath (Str); + if ((FVPtr->FVFilePtr = SmartOpen (Str)) == NULL) { + Error (NULL, 0, 0, Str, "could not open FV output file"); + return STATUS_ERROR; + } + // + // Now copy the [fv.$(FV).options] to the fv INF file + // + sprintf (Str, "fv.%s.options", StartCptr); + Section = DSCFileFindSection (DSC, Str); + if (Section != NULL) { + SmartWrite (FVPtr->FVFilePtr, "[options]\n"); + while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) { + ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0); + SmartWrite (FVPtr->FVFilePtr, ExpandedLine); + GetBaseAddress (ExpandedLine, FVPtr->BaseAddress); + } + } else { + Error (NULL, 0, 0, Str, "could not find FV section in description file"); + } + // + // Copy the [fv.$(FV).attributes] to the fv INF file + // + sprintf (Str, "fv.%s.attributes", StartCptr); + Section = DSCFileFindSection (DSC, Str); + if (Section != NULL) { + SmartWrite (FVPtr->FVFilePtr, "[attributes]\n"); + while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) { + ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0); + SmartWrite (FVPtr->FVFilePtr, ExpandedLine); + } + } else { + Error (NULL, 0, 0, Str, "Could not find FV section in description file"); + } + // + // Start the files section + // + SmartWrite (FVPtr->FVFilePtr, "\n[files]\n"); + } + // + // Now write the FV filename to the FV.inf file. Prepend $(PROCESSOR) on + // it. + // + sprintf (ExpandedLine, "EFI_FILE_NAME = %s\n", FileListPtr->FileName); + SmartWrite (FVPtr->FVFilePtr, ExpandedLine); + + // + // Next FV on the FV list + // + *EndCptr = CSave; + StartCptr = EndCptr; + if (*StartCptr) { + StartCptr++; + } + } + } + } + // + // Now we walk the list of firmware volumes and create the APRIORI list + // file for it . + // + for (FVPtr = FVList; FVPtr != NULL; FVPtr = FVPtr->Next) { + // + // Run through all the files and count up how many are to be + // added to the apriori list for this FV. Then when we're done + // we'll make sure we processed them all. We do this in case they + // skipped an apriori index for a given FV. + // + AprioriCount = 0; + for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) { + if (OrderInFvList (FileListPtr->Apriori, FVPtr->FVFileName, &AprioriPosition)) { + // + // Emit an error if the index was 0, or they didn't give one. + // + if (AprioriPosition == 0) { + Error ( + GetSymbolValue (DSC_FILENAME), + 1, + 0, + "apriori indexes are 1-based", + "component %s:APRIORI=%s", + FileListPtr->BaseName, + FileListPtr->Apriori + ); + } else { + AprioriCount++; + } + + } + } + // + // Now scan the files as we increment our apriori index + // + AprioriCounter = 0; + do { + AprioriFound = 0; + AprioriCounter++; + for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) { + // + // If in the apriori list for this fv, print the name. Open the + // file first if we have to. + // + if ((FileListPtr->Apriori[0] != 0) && + (OrderInFvList (FileListPtr->Apriori, FVPtr->FVFileName, &AprioriPosition)) + ) { + if (AprioriPosition == AprioriCounter) { + // + // If we've already found one for this index, emit an error. Decrement the + // count of how files we are to process so we don't emit another error for + // a miscount below. + // + if (AprioriFound) { + Error ( + GetSymbolValue (DSC_FILENAME), + 1, + 0, + "duplicate apriori index found", + "%s:%d", + FVPtr->FVFileName, + AprioriCounter + ); + AprioriCount--; + } + + AprioriFound = 1; + // + // Open the apriori output file if we haven't already + // + if (FVPtr->AprioriFilePtr == NULL) { + strcpy (Str, FVDir); + strcat (Str, FVPtr->FVFileName); + strcat (Str, ".apr"); + if ((FVPtr->AprioriFilePtr = SmartOpen (Str)) == NULL) { + Error (NULL, 0, 0, Str, "could not open output Apriori file for writing"); + return STATUS_ERROR; + } + } + + sprintf (ExpandedLine, "%s\n", FileListPtr->BaseFileName); + SmartWrite (FVPtr->AprioriFilePtr, ExpandedLine); + } + } + } + } while (AprioriFound); + // + // See if they skipped an apriori position for this FV + // + if (AprioriCount != (AprioriCounter - 1)) { + Error ( + GetSymbolValue (DSC_FILENAME), + 1, + 0, + "apriori index skipped", + "%s:%d", + FVPtr->FVFileName, + AprioriCounter + ); + } + } + // + // Traverse the list of all files again, and create a macro in the output makefile + // that defines all the files in each fv. For example, for each FV file, create a line: + // FV0001_FILES = $(FV_0001_FILES) xxxx-yyy.dxe. + // This can then be used as a dependency in their makefile. + // Also if they wanted us to dump a cross-reference, do that now. + // + if (mXRefFileName != NULL) { + if ((XRefFptr = fopen (mXRefFileName, "w")) == NULL) { + Message ( + 0, + "Failed to open cross-reference file '%s' for writing\n", + mXRefFileName + ); + } + } else { + XRefFptr = NULL; + } + + for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) { + // + // Parse all the "FV1,FV2..." in the FV field that came from FV=FVa,FVb,... on the + // component line in the DSC file. + // + if (FileListPtr->FVs != NULL) { + // + // If generating a cross-reference file, dump the data + // + if (XRefFptr != NULL) { + if ((FileListPtr->Guid != NULL) && (FileListPtr->BaseName != NULL) && (FileListPtr->Processor)) { + fprintf ( + XRefFptr, + "%s %s %s\n", + FileListPtr->Guid, + FileListPtr->BaseName, + FileListPtr->Processor + ); + } + } + // + // Convert to uppercase since we're going to use the name as a macro variable name + // in the makefile. + // + UpperCaseString (FileListPtr->FVs); + // + // Process each FV this file is in to write fvxxx_FILES = $(fvxxx_FILES) Guid-BaseName.ffs + // + StartCptr = FileListPtr->FVs; + while (*StartCptr) { + EndCptr = StartCptr; + while (*EndCptr && (*EndCptr != ',')) { + EndCptr++; + } + + CSave = *EndCptr; + *EndCptr = 0; + fprintf ( + MakeFptr, + "%s_FILES = $(%s_FILES) %s\n", + StartCptr, + StartCptr, + FileListPtr->FileName + ); + // + // Next FV on the FV list + // + *EndCptr = CSave; + StartCptr = EndCptr; + if (*StartCptr) { + StartCptr++; + } + } + } + } + + fprintf (MakeFptr, "\n"); + + // + // Now go through the list of all NonFFS FVs they specified and search for + // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the + // output makefile. Add them to the "fvs" target as well. + // + if (mNonFfsFVList != NULL) { + fprintf (MakeFptr, "fvs ::"); + FVPtr = mNonFfsFVList; + while (FVPtr != NULL) { + fprintf (MakeFptr, " %s%s.fv", FVDir, FVPtr->FVFileName); + FVPtr = FVPtr->Next; + } + + fprintf (MakeFptr, "\n\n"); + FVPtr = mNonFfsFVList; + while (FVPtr != NULL) { + // + // Save the position in the file + // + DSCFileSavePosition (DSC); + // + // first try to find a build section specific for this fv. + // + sprintf (Str, "build.fv.%s", FVPtr->FVFileName); + Section = DSCFileFindSection (DSC, Str); + if (Section == NULL) { + sprintf (Str, "build.fv"); + Section = DSCFileFindSection (DSC, Str); + } + + if (Section == NULL) { + Warning ( + NULL, + 0, + 0, + NULL, + "No [build.fv.%s] nor [%s] section found in description file for building %s", + FVPtr->FVFileName, + Str, + FVPtr->FVFileName + ); + } else { + // + // Add a symbol for the FV filename + // + UpperCaseString (FVPtr->FVFileName); + AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE); + AddSymbol (EFI_BASE_ADDRESS, FVPtr->BaseAddress, SYM_LOCAL | SYM_OVERWRITE); + + // + // Now copy the build commands from the section to the makefile + // + while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) { + ExpandSymbols ( + Line, + ExpandedLine, + sizeof (ExpandedLine), + EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR + ); + + fprintf (MakeFptr, ExpandedLine); + } + } + + FVPtr = FVPtr->Next; + DSCFileRestorePosition (DSC); + } + } + // + // Go through our list of firmware volumes and create an "fvs" target that + // builds everything. It has to be a mix of components and FV's in order. + // For example: fvs : components_0 fv\fv001.fv fv\fv002.fv components_1 fv\fv003.fv + // + ComponentsInstance = 0; + ComponentCount = 0; + fprintf (MakeFptr, "fvs ::"); + for (;;) { + // + // First see if we have any components for this section. If we don't, + // then we're done + // + for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) { + if (FileListPtr->ComponentsInstance == ComponentsInstance) { + break; + } + } + + if (FileListPtr == NULL) { + break; + } + + fprintf (MakeFptr, " components_%d", ComponentsInstance); + ComponentCount++; + // + // Now print any firmware volumes that match this components instance + // + for (FVPtr = mFVList; FVPtr != NULL; FVPtr = FVPtr->Next) { + if (FVPtr->ComponentsInstance == ComponentsInstance) { + fprintf (MakeFptr, " %s%s.fv", FVDir, FVPtr->FVFileName); + } + } + + ComponentsInstance++; + } + + fprintf (MakeFptr, "\n\n"); + + // + // Create a "components" target for build convenience. It should + // look something like: + // components : components_0 components_1... + // + if (ComponentCount > 0) { + fprintf (MakeFptr, "components :"); + for (ComponentsInstance = 0; ComponentsInstance < ComponentCount; ComponentsInstance++) { + fprintf (MakeFptr, " components_%d", ComponentsInstance); + } + + fprintf (MakeFptr, "\n\n"); + } + // + // Now go through the list of all FV's defined and search for + // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the + // output makefile. + // + FVPtr = mFVList; + while (FVPtr != NULL) { + if (FVPtr->FVFileName[0]) { + // + // Save the position in the file + // + DSCFileSavePosition (DSC); + // + // First try to find a build section specific for this FV. + // + sprintf (Str, "build.fv.%s", FVPtr->FVFileName); + Section = DSCFileFindSection (DSC, Str); + if (Section == NULL) { + sprintf (Str, "build.fv"); + Section = DSCFileFindSection (DSC, Str); + } + + if (Section == NULL) { + Error ( + NULL, + 0, + 0, + NULL, + "no [build.fv.%s] nor [%s] section found in description file for building %s", + FVPtr->FVFileName, + Str, + FVPtr->FVFileName + ); + } else { + // + // Add a symbol for the FV filename + // + UpperCaseString (FVPtr->FVFileName); + AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE); + AddSymbol (EFI_BASE_ADDRESS, FVPtr->BaseAddress, SYM_LOCAL | SYM_OVERWRITE); + + // + // Now copy the build commands from the section to the makefile + // + while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) { + ExpandSymbols ( + Line, + ExpandedLine, + sizeof (ExpandedLine), + EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR + ); + fprintf (MakeFptr, ExpandedLine); + } + } + + DSCFileRestorePosition (DSC); + } + + FVPtr = FVPtr->Next; + } + // + // Close all the files and free up the memory + // + while (FVList != NULL) { + FVPtr = FVList->Next; + if (FVList->FVFilePtr != NULL) { + SmartClose (FVList->FVFilePtr); + } + + if (FVList->AprioriFilePtr != NULL) { + SmartClose (FVList->AprioriFilePtr); + } + + free (FVList); + FVList = FVPtr; + } + + while (mNonFfsFVList != NULL) { + FVPtr = mNonFfsFVList->Next; + free (mNonFfsFVList); + mNonFfsFVList = FVPtr; + } + + if (XRefFptr != NULL) { + fclose (XRefFptr); + } + + return STATUS_SUCCESS; +} + +int +NonFFSFVWriteInfFiles ( + DSC_FILE *DSC, + char *FileName + ) +/*++ + +Routine Description: + + Generate a Non FFS fv file. It can only some variables, + or simply contains nothing except header. + +Arguments: + + DSC - pointer to a DSC_FILE object to extract info from + FileName - pointer to the fv file + +Returns: + + STATUS_SUCCESS if successful + non-STATUS_SUCCESS otherwise + +--*/ +{ + FV_LIST *FVPtr; + SECTION *Section; + char *StartCptr; + char *EndCptr; + char CSave; + char Str[MAX_PATH]; + char Line[MAX_LINE_LEN]; + char ExpandedLine[MAX_LINE_LEN]; + char FVDir[MAX_PATH]; + + // + // See if they specified a FV directory to dump the FV files out to. If not, + // then use the default. Then create the output directory. + // + DSCFileSavePosition (DSC); + StartCptr = GetSymbolValue (FV_INF_DIR); + if (StartCptr == NULL) { + ExpandSymbols (DEFAULT_FV_INF_DIR, FVDir, sizeof (FVDir), EXPANDMODE_NO_UNDEFS); + } else { + strcpy (FVDir, StartCptr); + } + + // + // Make sure the fv directory path ends in / + // + CSave = FVDir[strlen (FVDir) - 1]; + if ((CSave != '\\') && (CSave != '/')) { + strcat (FVDir, "\\"); + } + + StartCptr = FileName; + while (*StartCptr) { + EndCptr = StartCptr; + while (*EndCptr && (*EndCptr != ',')) { + EndCptr++; + } + + CSave = *EndCptr; + *EndCptr = 0; + // + // Ok, we have a fv name, now see if we've already opened + // an fv output file of this name. + // + for (FVPtr = mNonFfsFVList; FVPtr != NULL; FVPtr = FVPtr->Next) { + if (_stricmp (FVPtr->FVFileName, StartCptr) == 0) { + break; + } + } + // + // If there is already one with the same name, wrong + // + if (FVPtr != NULL) { + DSCFileRestorePosition (DSC); + return STATUS_ERROR; + } + // + // Create a new one, add it to the list + // + FVPtr = (FV_LIST *) malloc (sizeof (FV_LIST)); + if (FVPtr == NULL) { + Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL); + DSCFileRestorePosition (DSC); + return STATUS_ERROR; + } + + memset ((char *) FVPtr, 0, sizeof (FV_LIST)); + FVPtr->Next = mNonFfsFVList; + mNonFfsFVList = FVPtr; + // + // Save the FV name in the FileName pointer so we can compare + // for any future FV names specified. + // + strcpy (FVPtr->FVFileName, StartCptr); + // + // Add a symbol for the FV filename + // + UpperCaseString (FVPtr->FVFileName); + AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE); + + // + // Now create the FVx.inf filename from the fv name and + // default filename extension. Dump it in the FV directory + // as well. + // + strcpy (Str, FVDir); + strcat (Str, FVPtr->FVFileName); + strcat (Str, ".inf"); + // + // Create the directory path for our new fv.inf output file. + // + MakeFilePath (Str); + if ((FVPtr->FVFilePtr = SmartOpen (Str)) == NULL) { + Error (NULL, 0, 0, Str, "could not open FV output file"); + DSCFileRestorePosition (DSC); + return STATUS_ERROR; + } + // + // Now copy the [fv.fvfile.options] to the fv file + // + sprintf (Str, "fv.%s.options", StartCptr); + Section = DSCFileFindSection (DSC, Str); + if (Section != NULL) { + SmartWrite (FVPtr->FVFilePtr, "[options]\n"); + while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) { + ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0); + SmartWrite (FVPtr->FVFilePtr, ExpandedLine); + GetBaseAddress (ExpandedLine, FVPtr->BaseAddress); + } + } else { + Warning (NULL, 0, 0, NULL, "Could not find FV section '%s' in description file", Str); + } + // + // Copy the [fv.fvfile.attributes] to the fv file + // + sprintf (Str, "fv.%s.attributes", StartCptr); + Section = DSCFileFindSection (DSC, Str); + if (Section != NULL) { + SmartWrite (FVPtr->FVFilePtr, "[attributes]\n"); + while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) { + ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0); + SmartWrite (FVPtr->FVFilePtr, ExpandedLine); + } + } else { + Warning (NULL, 0, 0, NULL, "Could not find FV section '%s' in description file", Str); + } + // + // Copy the [fv.fvfile.components] to the fv file + // + sprintf (Str, "fv.%s.components", StartCptr); + Section = DSCFileFindSection (DSC, Str); + if (Section != NULL) { + SmartWrite (FVPtr->FVFilePtr, "[components]\n"); + while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) { + ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0); + SmartWrite (FVPtr->FVFilePtr, ExpandedLine); + } + } else { + // + // An empty FV is allowed to contain nothing + // + } + // + // Close the file + // + SmartClose (FVPtr->FVFilePtr); + // + // Next FV in FileName + // + *EndCptr = CSave; + StartCptr = EndCptr; + if (*StartCptr) { + StartCptr++; + } + } + + DSCFileRestorePosition (DSC); + return STATUS_SUCCESS; +} + +static +void +AddFirmwareVolumes ( + char *FVs, + int ComponentsInstance, + FILE_LIST *FileListPtr + ) +{ + FV_LIST *FvPtr; + char *StartPtr; + char *EndPtr; + char SaveChar; + + if ((FVs != NULL) && (FVs[0] != 0)) { + // + // Extract each FV name from the string. It's from the DSC file "FV=FvRecover,FvMain" + // + StartPtr = FVs; + while (*StartPtr != 0) { + EndPtr = StartPtr; + while (*EndPtr && (*EndPtr != ',')) { + EndPtr++; + } + + SaveChar = *EndPtr; + *EndPtr = 0; + // + // Look through our list of known firmware volumes and see if we've + // already added it. + // + for (FvPtr = mFVList; FvPtr != NULL; FvPtr = FvPtr->Next) { + if (_stricmp (FvPtr->FVFileName, StartPtr) == 0) { + break; + } + } + // + // If we didn't find a match, then create a new one + // + if (FvPtr == NULL) { + FvPtr = MALLOC (sizeof (FV_LIST)); + if (FvPtr == NULL) { + Error (__FILE__, __LINE__, 0, "application error", "memory allocation failed"); + return ; + } + + memset (FvPtr, 0, sizeof (FV_LIST)); + strcpy (FvPtr->FVFileName, StartPtr); + if (mFVList == NULL) { + mFVList = FvPtr; + } else { + mFVListLast->Next = FvPtr; + } + + mFVListLast = FvPtr; + } + // + // If this component's section number is higher than that of this + // FV, then set the FV's to it. + // + if (FvPtr->ComponentsInstance < ComponentsInstance) { + FvPtr->ComponentsInstance = ComponentsInstance; + } + // + // If we found then end of the FVs in the string, then we're done. + // Always restore the original string's contents. + // + if (SaveChar != 0) { + *EndPtr = SaveChar; + StartPtr = EndPtr + 1; + } else { + StartPtr = EndPtr; + } + } + } +} + +static +BOOLEAN +OrderInFvList ( + char *FvList, + char *FvName, + int *Order + ) +{ + // + // Given FvList of format "FV_a,FV_b,FV_c" or "FV_a:1,FV_b:2" and + // FvName of format "FV_c", determine if FvName is in FvList. If + // FV_a:1 format, then return the value after the colon. + // + while (*FvList) { + // + // If it matches for the length of FvName... + // + if (_strnicmp (FvList, FvName, strlen (FvName)) == 0) { + // + // Then see if the match string in FvList is terminated at the + // same length. + // + if ((FvList[strlen (FvName)] == ',') || (FvList[strlen (FvName)] == 0)) { + *Order = 0; + return TRUE; + } else if (FvList[strlen (FvName)] == ':') { + *Order = atoi (FvList + strlen (FvName) + 1); + return TRUE; + } + } + // + // Skip to next FV in the comma-separated list + // + while ((*FvList != ',') && (*FvList != 0)) { + FvList++; + } + // + // Skip over comma + // + if (*FvList == ',') { + FvList++; + } + } + + return FALSE; +} + +static +char * +UpperCaseString ( + char *Str + ) +{ + char *Cptr; + + for (Cptr = Str; *Cptr; Cptr++) { + *Cptr = (char) toupper (*Cptr); + } + + return Str; +} + +static +BOOLEAN +InSameFv ( + char *FVs1, + char *FVs2 +) +{ + char *StartCptr1; + char *StartCptr2; + char *EndCptr1; + char *EndCptr2; + char CSave1; + char CSave2; + + // + // Process each FV in first FV list + // + StartCptr1 = FVs1; + while (*StartCptr1) { + EndCptr1 = StartCptr1; + while (*EndCptr1 && (*EndCptr1 != ',')) { + EndCptr1++; + } + + CSave1 = *EndCptr1; + *EndCptr1 = 0; + + if (*StartCptr1) { + // + // Process each FV in second FV list + // + StartCptr2 = FVs2; + while (*StartCptr2) { + EndCptr2 = StartCptr2; + while (*EndCptr2 && (*EndCptr2 != ',')) { + EndCptr2++; + } + + CSave2 = *EndCptr2; + *EndCptr2 = 0; + + if (_stricmp (StartCptr1, StartCptr2) == 0) { + *EndCptr1 = CSave1; + *EndCptr2 = CSave2; + return TRUE; + } + + // + // Next FV on the second FV list + // + *EndCptr2 = CSave2; + StartCptr2 = EndCptr2; + if (*StartCptr2) { + StartCptr2++; + } + } + } + + // + // Next FV on the first FV list + // + *EndCptr1 = CSave1; + StartCptr1 = EndCptr1; + if (*StartCptr1) { + StartCptr1++; + } + } + + return FALSE; +} + +int +CFVSetXRefFileName ( + char *FileName + ) +{ + mXRefFileName = FileName; + return 0; +} diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.h b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.h new file mode 100644 index 0000000000..4a7af36e73 --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.h @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + FWVolume.h + +Abstract: + + Include file for the module that keeps track of files for the firmware + volumes. + +--*/ + +#ifndef _FW_VOLUME_H_ +#define _FW_VOLUME_H_ + +// +// class CFirmwareVolume +// { +// public: +// +void +CFVConstructor ( + VOID + ) +; +void +CFVDestructor ( + VOID + ) +; + +int +CFVAddFVFile ( + char *Name, + char *ComponentType, + char *FVs, + int ComponentsInstance, + char *FFSExt, + char *Processor, + char *Apriori, + char *BaseName, + char *Guid + ) +; + +int +CFVSetXRefFileName ( + char *FileName + ) +; + +int +CFVWriteInfFiles ( + DSC_FILE *DSC, + FILE *MakeFptr + ) +; + +int +NonFFSFVWriteInfFiles ( + DSC_FILE *DSC, + char *FileName + ) +; + +#endif // ifndef _FW_VOLUME_H_ diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Makefile b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Makefile new file mode 100644 index 0000000000..c835a80025 --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/Makefile @@ -0,0 +1,102 @@ +#/*++ +# +# Copyright (c) 2004 - 2007, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# Makefile +# +# Abstract: +# +# makefile for building the ProcessDsc utility. +# +#--*/ + +# +# Make sure environmental variable EDK_SOURCE is set +# +!IFNDEF EDK_SOURCE +!ERROR EDK_SOURCE environmental variable not set +!ENDIF + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE $(BUILD_DIR)\PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = ProcessDsc +TARGET_SRC_DIR = $(EDK_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(EDK_TOOLS_OUTPUT)\ProcessDsc.exe + +# +# Build targets +# + +all: $(TARGET_EXE) + +INC_DEPS = $(TARGET_SRC_DIR)\DSCFile.h $(INC_DEPS) +INC_DEPS = $(TARGET_SRC_DIR)\FWVolume.h $(INC_DEPS) +INC_DEPS = $(TARGET_SRC_DIR)\Exceptions.h $(INC_DEPS) +INC_DEPS = $(TARGET_SRC_DIR)\Common.h $(INC_DEPS) + +LIBS = $(LIBS) "$(EDK_TOOLS_OUTPUT)\Common.lib" + +OBJECTS = $(EDK_TOOLS_OUTPUT)\DSCFile.obj \ + $(EDK_TOOLS_OUTPUT)\FWVolume.obj \ + $(EDK_TOOLS_OUTPUT)\ProcessDsc.obj \ + $(EDK_TOOLS_OUTPUT)\Exceptions.obj + +# +# Compile each source file +# + +$(EDK_TOOLS_OUTPUT)\DSCFile.obj : $(TARGET_SRC_DIR)\DSCFile.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\DSCFile.c /Fo$@ + +$(EDK_TOOLS_OUTPUT)\FWVolume.obj : $(TARGET_SRC_DIR)\FWVolume.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\FWVolume.c /Fo$@ + +$(EDK_TOOLS_OUTPUT)\ProcessDsc.obj : $(TARGET_SRC_DIR)\ProcessDsc.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\ProcessDsc.c /Fo$@ + +$(EDK_TOOLS_OUTPUT)\Exceptions.obj : $(TARGET_SRC_DIR)\Exceptions.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\Exceptions.c /Fo$@ + +# +# Add Binary Build description for this tool. +# + +!IF (("$(EFI_BINARY_TOOLS)" == "YES") && EXIST($(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).exe)) +$(TARGET_EXE): $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).exe + copy $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).exe $(TARGET_EXE) /Y + if exist $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).pdb \ + copy $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).pdb $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).pdb /Y +!ELSE +$(TARGET_EXE) : $(OBJECTS) $(LIBS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) + if not exist $(EFI_PLATFORM_BIN)\Tools mkdir $(EFI_PLATFORM_BIN)\Tools + if exist $(TARGET_EXE) copy $(TARGET_EXE) $(EFI_PLATFORM_BIN)\tools\$(TARGET_NAME).exe /Y + if exist $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).pdb \ + copy $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).pdb $(EFI_PLATFORM_BIN)\Tools\$(TARGET_NAME).pdb /Y +!ENDIF + +clean: + @if exist $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL + @if exist $(EDK_TOOLS_OUTPUT)\DscFile.* del $(EDK_TOOLS_OUTPUT)\DscFile.* > NUL + @if exist $(EDK_TOOLS_OUTPUT)\Exceptions* del $(EDK_TOOLS_OUTPUT)\Exceptions.* > NUL + @if exist $(EDK_TOOLS_OUTPUT)\FwVolume.* del $(EDK_TOOLS_OUTPUT)\FwVolume.* > NUL diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/ProcessDsc.c b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/ProcessDsc.c new file mode 100644 index 0000000000..4833b78e0d --- /dev/null +++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/ProcessDsc.c @@ -0,0 +1,4726 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ProcessDsc.c + +Abstract: + + Main module for the ProcessDsc utility. + +--*/ + +#include // for GetShortPathName() +#include +#include +#include +#include +#include // for _mkdir() +#include +#include // for getenv() +#include "DSCFile.h" +#include "FWVolume.h" +#include "Exceptions.h" +#include "Common.h" + +#include "EfiUtilityMsgs.h" +#include "TianoBind.h" +// +// Disable warning for while(1) code +// +#pragma warning(disable : 4127) +// +// Disable warning for unreferenced function parameters +// +#pragma warning(disable : 4100) + +extern int errno; + +#define PROGRAM_NAME "ProcessDsc" + +// +// Common symbol name definitions. For example, the user can reference +// $(BUILD_DIR) in their DSC file and we will expand it for them (usually). +// I've defined the equivalents here in case we want to change the name the +// user references, in which case we just change the string value here and +// our code still works. +// +#define BUILD_DIR "BUILD_DIR" +#define EFI_SOURCE "EFI_SOURCE" +#define DEST_DIR "DEST_DIR" +#define SOURCE_DIR "SOURCE_DIR" +#define LIB_DIR "LIB_DIR" +#define BIN_DIR "BIN_DIR" +#define OUT_DIR "OUT_DIR" +#define INF_FILENAME "INF_FILENAME" +#define SOURCE_RELATIVE_PATH "SOURCE_RELATIVE_PATH" +#define SOURCE_BASE_NAME "SOURCE_BASE_NAME" +#define SOURCE_FILE_NAME "SOURCE_FILE_NAME" // c:\FullPath\File.c +#define PROCESSOR "PROCESSOR" +#define FV "FV" +#define BASE_NAME "BASE_NAME" +#define GUID "GUID" +#define FILE_GUID "FILE_GUID" +#define COMPONENT_TYPE_FILE "FILE" +#define BUILD_TYPE "BUILD_TYPE" +#define FFS_EXT "FFS_EXT" // FV_EXT is deprecated -- extension of FFS file +#define MAKEFILE_NAME "MAKEFILE_NAME" // name of component's output makefile +#define PLATFORM "PLATFORM" // for more granularity +#define PACKAGE_FILENAME "PACKAGE_FILENAME" +#define PACKAGE "PACKAGE" +#define PACKAGE_TAG "PACKAGE_TAG" // alternate name to PACKAGE +#define SHORT_NAMES "SHORT_NAMES" // for 8.3 names of symbols +#define APRIORI "APRIORI" // to add to apriori list +#define OPTIONAL_COMPONENT "OPTIONAL" // define as non-zero for optional INF files +#define SOURCE_SELECT "SOURCE_SELECT" // say SOURCE_SELECT=smm,common to select INF sources +#define NONFFS_FV "NONFFS_FV" // for non-FFS FV such as working & spare block FV +#define SKIP_FV_NULL "SKIP_FV_NULL" // define as nonzero to not build components with FV=NULL +#define SOURCE_COMPILE_TYPE "SOURCE_COMPILE_TYPE" // to build a source using a custom build section in the DSC file +#define SOURCE_FILE_EXTENSION "SOURCE_FILE_EXTENSION" +#define COMPILE_SELECT "COMPILE_SELECT" +#define SOURCE_OVERRIDE_PATH "SOURCE_OVERRIDE_PATH" // get source files from here first +#define MAKEFILE_OUT_SECTION_NAME "makefile.out" +#define COMMON_SECTION_NAME "common" // shared files or functionality +#define NMAKE_SECTION_NAME "nmake" +#define SOURCES_SECTION_NAME "sources" +#define COMPONENTS_SECTION_NAME "components" +#define INCLUDE_SECTION_NAME "includes" +#define DEFINES_SECTION_NAME "defines" +#define LIBRARIES_SECTION_NAME "libraries" +#define LIBRARIES_PLATFORM_SECTION_NAME "libraries.platform" +#define MAKEFILE_SECTION_NAME "makefile" +#define COMPONENT_TYPE "component_type" +#define PLATFORM_STR "\\platform\\" // to determine EFI_SOURCE +#define MAKEFILE_OUT_NAME "makefile.out" // if not specified on command line +#define MODULE_MAKEFILE_NAME "module.mak" // record all module makefile targets +#define MODULE_NAME_FILE "module.list" // record all module names defined in the dsc file +#define GLOBAL_LINK_LIB_NAME "CompilerStub" // Lib added in link option, maybe removed in the future +#define MODULE_BASE_NAME_WIDTH 25 // Width for module name output + +// +// When a symbol is defined as "NULL", it gets saved in the symbol table as a 0-length +// string. Use this macro to detect if a symbol has been defined this way. +// +#define IS_NULL_SYMBOL_VALUE(var) ((var != NULL) && (strlen (var) == 0)) + +// +// Defines for file types +// +#define FILETYPE_UNKNOWN 0 +#define FILETYPE_C 1 +#define FILETYPE_ASM 2 +#define FILETYPE_S 3 +#define FILETYPE_VFR 4 +#define FILETYPE_INC 5 +#define FILETYPE_H 6 +#define FILETYPE_I 7 + + +typedef struct { + INT8 *Extension; // file extension + INT8 *BuiltExtension; + INT8 FileFlags; + int FileType; +} FILETYPE; + +// +// Define masks for the FileFlags field +// +#define FILE_FLAG_INCLUDE 0x01 +#define FILE_FLAG_SOURCE 0x02 + +// +// This table describes a from-to list of files. For +// example, when a ".c" is built, it results in a ".obj" file. +// +static const FILETYPE mFileTypes[] = { + { + ".c", + ".obj", + FILE_FLAG_SOURCE, + FILETYPE_C + }, + { + ".asm", + ".obj", + FILE_FLAG_SOURCE, + FILETYPE_ASM + }, + { + ".s", + ".obj", + FILE_FLAG_SOURCE, + FILETYPE_S + }, + { + ".vfr", + ".obj", + FILE_FLAG_SOURCE, + FILETYPE_VFR + }, // actually *.vfr -> *.c -> *.obj + { + ".h", + NULL, + FILE_FLAG_INCLUDE, + FILETYPE_H + }, + { + ".inc", + NULL, + FILE_FLAG_INCLUDE, + FILETYPE_INC + }, + { + ".i", + NULL, + FILE_FLAG_INCLUDE, + FILETYPE_I + }, + { + NULL, + NULL, + 0, + 0 + } +}; + +// +// Structure to split up a file into its different parts. +// +typedef struct { + INT8 Drive[3]; + INT8 *Path; + INT8 *BaseName; + INT8 *Extension; + int ExtensionCode; +} FILE_NAME_PARTS; + +// +// Maximum length for any line in any file after symbol expansion +// +#define MAX_EXP_LINE_LEN (MAX_LINE_LEN * 2) + +// +// Linked list to keep track of all symbols +// +typedef struct _SYMBOL { + struct _SYMBOL *Next; + int Type; // local or global symbol + INT8 *Name; + INT8 *Value; +} SYMBOL; + +// +// Define new SYMBOL list to record all module name used in the platform.dsc file. +// +SYMBOL *gModuleList = NULL; + +// +// This structure is used to save globals +// +struct { + INT8 *DscFilename; + SYMBOL *Symbol; + INT8 MakefileName[MAX_PATH]; // output makefile name + INT8 XRefFileName[MAX_PATH]; + INT8 GuidDatabaseFileName[MAX_PATH]; + INT8 ModuleMakefileName[MAX_PATH]; + FILE *MakefileFptr; + FILE *ModuleMakefileFptr; + SYMBOL *ModuleList; + SYMBOL *OutdirList; + UINT32 Verbose; +} gGlobals; + +// +// This gets dumped to the head of makefile.out +// +static const INT8 *MakefileHeader[] = { + "#/*++", + "#", + "# DO NOT EDIT", + "# File auto-generated by build utility", + "#", + "# Module Name:", + "#", + "# makefile", + "#", + "# Abstract:", + "#", + "# Auto-generated makefile for building of EFI components/libraries", + "#", + "#--*/", + "", + NULL +}; + +// +// Function prototypes +// +static +int +ProcessOptions ( + int Argc, + INT8 *Argv[] + ); + +static +void +Usage ( + VOID + ); + +static +INT8 * +StripLine ( + INT8 *Line + ); + +static +STATUS +ParseGuidDatabaseFile ( + INT8 *FileName + ); + +#define DSC_SECTION_TYPE_COMPONENTS 0 +#define DSC_SECTION_TYPE_LIBRARIES 1 +#define DSC_SECTION_TYPE_PLATFORM_LIBRARIES 2 + +static +int +ProcessSectionComponents ( + DSC_FILE *DscFile, + int DscSectionType, + int Instance + ); +static +int +ProcessComponentFile ( + DSC_FILE *DscFile, + INT8 *Line, + int DscSectionType, + int Instance + ); +static +int +ProcessIncludeFiles ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ); +static + +int +ProcessIncludeFilesSingle ( + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName + ); + +// +// Mode flags for processing source files +// +#define SOURCE_MODE_BUILD_COMMANDS 0x01 +#define SOURCE_MODE_SOURCE_FILES 0x02 + +static +int +ProcessSourceFiles ( + DSC_FILE *DSCFile, + DSC_FILE *ComponentFile, + FILE *MakeFptr, + UINT32 Mode + ); + +static +int +ProcessSourceFilesSection ( + DSC_FILE *DSCFile, + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName, + UINT32 Mode + ); + +static +int +ProcessObjects ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ); + +static +int +ProcessObjectsSingle ( + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName + ); + +static +int +ProcessLibs ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ); + +static +int +ProcessLibsSingle ( + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName + ); + +static +int +ProcessIncludesSection ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ); + +static +int +ProcessIncludesSectionSingle ( + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName + ); + +static +int +ProcessINFNMakeSection ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ); + +static +int +ProcessINFDefinesSection ( + DSC_FILE *ComponentFile + ); + +static +int +ProcessINFDefinesSectionSingle ( + DSC_FILE *ComponentFile, + INT8 *SectionName + ); + +static +int +ProcessSectionLibraries ( + DSC_FILE *DscFile, + long Offset + ); + +static +int +ProcessDSCDefinesSection ( + DSC_FILE *DscFile + ); + +static +int +SetSymbolType ( + INT8 *SymbolName, + INT8 Type + ); + +static +int +RemoveLocalSymbols ( + VOID + ); + +static +int +RemoveFileSymbols ( + VOID + ); + +static +int +RemoveSymbol ( + INT8 *Name, + INT8 SymbolType + ); + +static +int +SetFileExtension ( + INT8 *FileName, + INT8 *Extension + ); + +static +int +GetSourceFileType ( + INT8 *FileName + ); + +static +int +IsIncludeFile ( + INT8 *FileName + ); + +static +int +WriteCompileCommands ( + DSC_FILE *DscFile, + FILE *MakeFptr, + INT8 *FileName, + INT8 *Processor + ); + +static +int +WriteCommonMakefile ( + DSC_FILE *DscFile, + FILE *MakeFptr, + INT8 *Processor + ); + +static +int +WriteComponentTypeBuildCommands ( + DSC_FILE *DscFile, + FILE *MakeFptr, + INT8 *SectionName + ); + +static +void +StripTrailingSpaces ( + INT8 *Str + ); + +static +void +FreeFileParts ( + FILE_NAME_PARTS *FP + ); + +static +FILE_NAME_PARTS * +GetFileParts ( + INT8 *FileName + ); + +static +SYMBOL * +FreeSymbols ( + SYMBOL *Syms + ); + +static +int +GetEfiSource ( + VOID + ); + +static +int +CreatePackageFile ( + DSC_FILE *DSCFile + ); + +static +INT8 * +BuiltFileExtension ( + INT8 *SourceFileName + ); + +static +void +SmartFree ( + SMART_FILE *SmartFile + ); + +static +int +AddModuleName ( + SYMBOL **SymbolList, + INT8 *ModuleName, + INT8 *InfName + ); + +/*****************************************************************************/ +int +main ( + int Argc, + INT8 *Argv[] + ) +/*++ + +Routine Description: + + Main utility entry point. + +Arguments: + + Argc - Standard app entry point args. + Argv - Standard app entry point args. + +Returns: + + 0 if successful + non-zero otherwise + +--*/ +{ + int i; + DSC_FILE DSCFile; + SECTION *Sect; + INT8 Line[MAX_LINE_LEN]; + INT8 ExpLine[MAX_LINE_LEN]; + INT8 *EMsg; + FILE *FpModule; + SYMBOL *TempSymbol; + + SetUtilityName (PROGRAM_NAME); + + InitExceptions (); + + DSCFileInit (&DSCFile); + // + // Initialize the firmware volume data + // + CFVConstructor (); + // + // Exception handling for this block of code. + // + TryException (); + // + // Process command-line options. + // + if (ProcessOptions (Argc, Argv)) { + EMsg = CatchException (); + if (EMsg != NULL) { + fprintf (stderr, "%s\n", EMsg); + } + + return STATUS_ERROR; + } + // + // Parse the GUID database file if specified + // + if (gGlobals.GuidDatabaseFileName[0] != 0) { + ParseGuidDatabaseFile (gGlobals.GuidDatabaseFileName); + } + // + // Set the output cross-reference file if applicable + // + if (gGlobals.XRefFileName[0]) { + CFVSetXRefFileName (gGlobals.XRefFileName); + } + + // + // Now get the EFI_SOURCE directory which we use everywhere. + // + if (GetEfiSource ()) { + return STATUS_ERROR; + } + + // + // Pre-process the DSC file to get section info. + // + if (DSCFileSetFile (&DSCFile, gGlobals.DscFilename) != 0) { + goto ProcessingError; + } + + // + // Set output makefile name for single module build + // + strcpy (gGlobals.ModuleMakefileName, MODULE_MAKEFILE_NAME); + + // + // Try to open all final output makefiles + // + if ((gGlobals.MakefileFptr = fopen (gGlobals.MakefileName, "w")) == NULL) { + Error (NULL, 0, 0, gGlobals.MakefileName, "failed to open output makefile for writing"); + goto ProcessingError; + } + if ((gGlobals.ModuleMakefileFptr = fopen (gGlobals.ModuleMakefileName, "w")) == NULL) { + Error (NULL, 0, 0, gGlobals.ModuleMakefileName, "failed to open output makefile for writing"); + goto ProcessingError; + } + + // + // Write the header out to the makefiles + // + for (i = 0; MakefileHeader[i] != NULL; i++) { + fprintf (gGlobals.MakefileFptr, "%s\n", MakefileHeader[i]); + fprintf (gGlobals.ModuleMakefileFptr, "%s\n", MakefileHeader[i]); + } + + // + // Init global potint = NULL + // + gGlobals.ModuleList = NULL; + gGlobals.OutdirList = NULL; + + // + // Process the [defines] section in the DSC file to get any defines we need + // elsewhere + // + ProcessDSCDefinesSection (&DSCFile); + if (ExceptionThrown ()) { + goto ProcessingError; + } + // + // Write out the [makefile.out] section data to the output makefiles + // + Sect = DSCFileFindSection (&DSCFile, MAKEFILE_OUT_SECTION_NAME); + if (Sect != NULL) { + while (DSCFileGetLine (&DSCFile, Line, sizeof (Line)) != NULL) { + ExpandSymbols (Line, ExpLine, sizeof (ExpLine), 0); + // + // Write the line to the output makefiles + // + fprintf (gGlobals.MakefileFptr, ExpLine); + fprintf (gGlobals.ModuleMakefileFptr, ExpLine); + } + } + + // + // Add a pseudo target for GLOBAL_LINK_LIB_NAME to avoid single module build + // failure when this lib is not used. + // + fprintf (gGlobals.ModuleMakefileFptr, "%sbuild ::\n\n", GLOBAL_LINK_LIB_NAME); + + fprintf (gGlobals.MakefileFptr, "libraries : \n"); + // + // Process [libraries] section in the DSC file + // + Sect = DSCFileFindSection (&DSCFile, LIBRARIES_SECTION_NAME); + if (Sect != NULL) { + ProcessSectionComponents (&DSCFile, DSC_SECTION_TYPE_LIBRARIES, 0); + } + + if (ExceptionThrown ()) { + goto ProcessingError; + } + // + // Process [libraries.platform] section in the DSC file + // + Sect = DSCFileFindSection (&DSCFile, LIBRARIES_PLATFORM_SECTION_NAME); + if (Sect != NULL) { + ProcessSectionComponents (&DSCFile, DSC_SECTION_TYPE_PLATFORM_LIBRARIES, 0); + } + + fprintf (gGlobals.MakefileFptr, "\n"); + if (ExceptionThrown ()) { + goto ProcessingError; + } + + // + // Process [components] section in the DSC file + // + Sect = DSCFileFindSection (&DSCFile, COMPONENTS_SECTION_NAME); + if (Sect != NULL) { + fprintf (gGlobals.MakefileFptr, "components_0 : \n"); + ProcessSectionComponents (&DSCFile, DSC_SECTION_TYPE_COMPONENTS, 0); + fprintf (gGlobals.MakefileFptr, "\n"); + } + + if (ExceptionThrown ()) { + goto ProcessingError; + } + // + // Now cycle through all [components.1], [components.2], ....[components.n]. + // This is necessary to support building of firmware volumes that may contain + // other encapsulated firmware volumes (ala capsules). + // + i = 1; + while (1) { + RemoveSymbol (FV, SYM_GLOBAL); + sprintf (Line, "%s.%d", COMPONENTS_SECTION_NAME, i); + Sect = DSCFileFindSection (&DSCFile, Line); + if (Sect != NULL) { + fprintf (gGlobals.MakefileFptr, "components_%d : \n", i); + ProcessSectionComponents (&DSCFile, DSC_SECTION_TYPE_COMPONENTS, i); + fprintf (gGlobals.MakefileFptr, "\n"); + } else { + break; + } + + if (ExceptionThrown ()) { + goto ProcessingError; + } + + i++; + } + +ProcessingError: + EMsg = CatchException (); + if (EMsg != NULL) { + fprintf (stderr, "%s\n", EMsg); + fprintf (stderr, "Processing aborted\n"); + } + + TryException (); + // + // Create the FV files if no fatal errors or errors + // + if (GetUtilityStatus () < STATUS_ERROR) { + CFVWriteInfFiles (&DSCFile, gGlobals.MakefileFptr); + } + + // + // Write all module name into MODULE_NAME_FILE file. + // + if ((FpModule = fopen (MODULE_NAME_FILE, "w")) != NULL) { + TempSymbol = gGlobals.ModuleList; + while (TempSymbol != NULL) { + fprintf (FpModule, " %-*s %s \n", MODULE_BASE_NAME_WIDTH, TempSymbol->Name, TempSymbol->Value); + TempSymbol = TempSymbol->Next; + } + fclose (FpModule); + FpModule = NULL; + } + + // + // Close the all the output makefiles + // + if (gGlobals.MakefileFptr != NULL) { + fclose (gGlobals.MakefileFptr); + gGlobals.MakefileFptr = NULL; + } + + if (gGlobals.ModuleMakefileFptr != NULL) { + fclose (gGlobals.ModuleMakefileFptr); + gGlobals.ModuleMakefileFptr = NULL; + } + + // + // Clean up + // + FreeSymbols (gGlobals.ModuleList); + FreeSymbols (gGlobals.OutdirList); + FreeSymbols (gGlobals.Symbol); + gGlobals.Symbol = NULL; + CFVDestructor (); + DSCFileDestroy (&DSCFile); + + EMsg = CatchException (); + if (EMsg != NULL) { + fprintf (stderr, "%s\n", EMsg); + fprintf (stderr, "Processing aborted\n"); + } + + return GetUtilityStatus (); +} + +static +int +ProcessSectionComponents ( + DSC_FILE *DSCFile, + int DscSectionType, + int Instance + ) +/*++ + +Routine Description: + + Process the [components] or [libraries] section in the description file. We + use this function for both since they're very similar. Here we just + read each line from the section, and if it's valid, call a function to + do the actual processing of the component description file. + +Arguments: + + DSCFile - structure containing section info on the description file + DscSectionType - type of description section + +Returns: + + 0 if successful + +--*/ +{ + INT8 Line[MAX_LINE_LEN]; + INT8 Line2[MAX_EXP_LINE_LEN]; + INT8 *Cptr; + + // + // Read lines while they're valid + // + while (DSCFileGetLine (DSCFile, Line, sizeof (Line)) != NULL) { + // + // Expand symbols on the line + // + if (ExpandSymbols (Line, Line2, sizeof (Line2), 0)) { + return STATUS_ERROR; + } + // + // Strip the line + // + Cptr = StripLine (Line2); + if (*Cptr) { + Message (2, "Processing component line: %s", Line2); + if (ProcessComponentFile (DSCFile, Line2, DscSectionType, Instance) != 0) { + return STATUS_ERROR; + } + } + } + + return 0; +} + +static +int +ProcessComponentFile ( + DSC_FILE *DSCFile, + INT8 *ArgLine, + int DscSectionType, + int Instance + ) +/*++ + +Routine Description: + + Given a line from the [components] or [libraries] section of the description + file, process the line to extract the component's INF filename and + parameters. Then open the INF file and process it to create a corresponding + makefile. + +Arguments: + + DSCFile The project DSC file info structure. + Libs Indicates whether we're processing the [components] + section or the [libraries] section. + ArgLine The actual line from the DSC file. Looks something like + one of the following: + + dxe\drivers\vm\vm.dsc PROCESSOR=IA32 DEST_DIR=$(DEST_DIR)\xxx FV=FV1,FV2 + $(BUILD_DIR).\FvVariable.ffs COMPONENT_TYPE=FILE + .\FvVariable.ffs COMPONENT_TYPE=FILE + define VAR1=value1 VAR2=value2 + +Returns: + + 0 if successful + +--*/ +{ + FILE *MakeFptr; + FILE *TempFptr; + INT8 *Cptr; + INT8 *name; + INT8 *End; + INT8 *TempCptr; + INT8 FileName[MAX_PATH]; + INT8 ComponentFilePath[MAX_PATH]; + INT8 InLine[MAX_LINE_LEN]; + INT8 Line[MAX_LINE_LEN]; + INT8 *Processor; + INT8 SymType; + int Len; + int ComponentCreated; + int ComponentFilePathAbsolute; + int DefineLine; + DSC_FILE ComponentFile; + INT8 ComponentMakefileName[MAX_PATH]; + BOOLEAN IsForFv; + + // + // Now remove all local symbols + // + RemoveLocalSymbols (); + // + // Null out the file pointer in case we take an exception somewhere + // and we need to close it only if we opened it. + // + MakeFptr = NULL; + ComponentFilePathAbsolute = 0; + ComponentCreated = 0; + // + // Skip preceeding spaces on the line + // + while (isspace (*ArgLine) && (*ArgLine)) { + ArgLine++; + } + // + // Find the end of the component's filename and truncate the line at that + // point. From here on out ArgLine is the name of the component filename. + // + Cptr = ArgLine; + while (!isspace (*Cptr) && *Cptr) { + Cptr++; + } + + End = Cptr; + if (*Cptr) { + End++; + *Cptr = 0; + } + // + // Exception-handle processing of this component description file + // + TryException (); + + // + // We also allow a component line format for defines of global symbols + // instead of a component filename. In this case, the line looks like: + // defines x=abc y=yyy. Be nice and accept "define" and "defines" in a + // case-insensitive manner. If it's defines, then make the symbols global. + // + if ((_stricmp (ArgLine, "define") == 0) || (_stricmp (ArgLine, "defines") == 0)) { + SymType = SYM_OVERWRITE | SYM_GLOBAL; + DefineLine = 1; + } else { + SymType = SYM_OVERWRITE | SYM_LOCAL; + DefineLine = 0; + } + // + // The rest of the component line from the DSC file should be defines + // + while (*End) { + End = StripLine (End); + if (*End) { + // + // If we're processing a "define abc=1 xyz=2" line, then set symbols + // as globals per the SymType set above. + // + Len = AddSymbol (End, NULL, SymType); + if (Len > 0) { + End += Len; + } else { + Warning (NULL, 0, 0, ArgLine, "unrecognized option in description file"); + break; + } + } + } + + // + // If DEBUG_BREAK or EFI_BREAKPOINT is defined, then do a debug breakpoint. + // + if ((GetSymbolValue ("DEBUG_BREAK") != NULL) || (GetSymbolValue ("EFI_BREAKPOINT") != NULL)) { + EFI_BREAKPOINT (); + } + + // + // If it's a define line, then we're done + // + if (DefineLine) { + // + // If there is NonFFS_FV, create the FVxxx.inf file + // and include it in makefile.out. Remove the symbol + // in order not to process it again next time + // + Cptr = GetSymbolValue (NONFFS_FV); + if (Cptr != NULL) { + NonFFSFVWriteInfFiles (DSCFile, Cptr); + RemoveSymbol (NONFFS_FV, SYM_GLOBAL); + } + + goto ComponentDone; + } + + // + // Expand symbols in the component description filename to expand the newly + // added local symbols + // + ExpandSymbols (ArgLine, Line, sizeof (Line), EXPANDMODE_NO_UNDEFS); + + // + // If we have "c:\path\filename" + // + if (IsAbsolutePath (Line)) { + ComponentFilePathAbsolute = 1; + } else if (Line[0] == '.') { + // + // or if the path starts with ".", then it's build-dir relative. + // Prepend $(BUILD_DIR) on the file name + // + sprintf (InLine, "%s\\%s", GetSymbolValue (BUILD_DIR), Line); + strcpy (Line, InLine); + ComponentFilePathAbsolute = 1; + } + + // + // Save the path from the component name for later. It may be relative or + // absolute. + // + strcpy (ComponentFilePath, Line); + Cptr = ComponentFilePath + strlen (ComponentFilePath) - 1; + while ((*Cptr != '\\') && (*Cptr != '/') && (Cptr != ComponentFilePath)) { + Cptr--; + } + // + // Terminate the path. + // + *Cptr = 0; + + // + // Typically the given line is a component description filename. However we + // also allow a FV filename (fvvariable.ffs COMPONENT_TYPE=FILE). If the + // component type is "FILE", then add it to the FV list, create a package + // file, and we're done. + // + Cptr = GetSymbolValue (COMPONENT_TYPE); + if ((Cptr != NULL) && (strncmp ( + Cptr, + COMPONENT_TYPE_FILE, + strlen (COMPONENT_TYPE_FILE) + ) == 0)) { + if (ComponentFilePathAbsolute) { + strcpy (InLine, Line); + } else { + sprintf (InLine, "%s\\%s", GetSymbolValue (EFI_SOURCE), Line); + } + CFVAddFVFile ( + InLine, + Cptr, + GetSymbolValue (FV), + Instance, + NULL, + NULL, + GetSymbolValue (APRIORI), + NULL, + NULL + ); + goto ComponentDone; + } + + // + // Better have defined processor by this point. + // + Processor = GetSymbolValue (PROCESSOR); + if (Processor == NULL) { + Error (NULL, 0, 0, NULL, "PROCESSOR not defined for component %s", Line); + return STATUS_ERROR; + } + + // + // The bin, out, and lib dirs are now = $(BUILD_DIR)/$(PROCESSOR). Set them. + // Don't flag them as file paths (required for short 8.3 filenames) since + // they're defined using the BUILD_DIR macro. + // + sprintf (InLine, "$(BUILD_DIR)\\%s", Processor); + AddSymbol (BIN_DIR, InLine, SYM_LOCAL); + AddSymbol (OUT_DIR, InLine, SYM_LOCAL); + AddSymbol (LIB_DIR, InLine, SYM_LOCAL); + // + // See if it's been destined for an FV. It's possible to not be in an + // FV if they just want to build it. + // + Cptr = GetSymbolValue (FV); + if ((Cptr != NULL) && !IS_NULL_SYMBOL_VALUE (Cptr)) { + IsForFv = TRUE; + } else { + IsForFv = FALSE; + } + // + // As an optimization, if they've defined SKIP_FV_NULL as non-zero, and + // the component is not destined for an FV, then skip it. + // Since libraries are never intended for firmware volumes, we have to + // build all of them. + // + if ((DscSectionType == DSC_SECTION_TYPE_COMPONENTS) && (IsForFv == FALSE)) { + if ((GetSymbolValue (SKIP_FV_NULL) != NULL) && (atoi (GetSymbolValue (SKIP_FV_NULL)) != 0)) { + Message (0, "%s not being built (FV=NULL)", FileName); + goto ComponentDone; + } + } + // + // Prepend EFI_SOURCE to the component description file to get the + // full path. Only do this if the path is not a full path already. + // + if (ComponentFilePathAbsolute == 0) { + name = GetSymbolValue (EFI_SOURCE); + sprintf (FileName, "%s\\%s", name, Line); + } else { + strcpy (FileName, Line); + } + // + // Print a message, depending on verbose level. + // + if (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) { + Message (1, "Processing component %s", FileName); + } else { + Message (1, "Processing library %s", FileName); + } + // + // Open the component's description file and get the sections. If we fail + // to open it, see if they defined "OPTIONAL=1, in which case we'll just + // ignore the component. + // + TempFptr = fopen (FileName, "r"); + if (TempFptr == NULL) { + // + // Better have defined OPTIONAL + // + if (GetSymbolValue (OPTIONAL_COMPONENT) != NULL) { + if (atoi (GetSymbolValue (OPTIONAL_COMPONENT)) != 0) { + Message (0, "Optional component '%s' not found", FileName); + goto ComponentDone; + } + } + + ParserError (0, FileName, "failed to open component file"); + return STATUS_ERROR; + } else { + fclose (TempFptr); + } + + DSCFileInit (&ComponentFile); + ComponentCreated = 1; + if (DSCFileSetFile (&ComponentFile, FileName)) { + Error (NULL, 0, 0, NULL, "failed to preprocess component file '%s'", FileName); + return STATUS_ERROR; + } + // + // Add a symbol for the INF filename so users can create dependencies + // in makefiles. + // + AddSymbol (INF_FILENAME, FileName, SYM_OVERWRITE | SYM_LOCAL | SYM_FILENAME); + // + // Process the [defines], [defines.$(PROCESSOR)], and [defines.$(PROCESSOR).$(PLATFORM)] + // sections in the INF file + // + ProcessINFDefinesSection (&ComponentFile); + // + // Better have defined FILE_GUID if not a library + // + if ((GetSymbolValue (GUID) == NULL) && + (GetSymbolValue (FILE_GUID) == NULL) && + (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) + ) { + Error (GetSymbolValue (INF_FILENAME), 1, 0, NULL, "missing FILE_GUID definition in component file"); + DSCFileDestroy (&ComponentFile); + return STATUS_ERROR; + } + // + // Better have defined base name + // + if (GetSymbolValue (BASE_NAME) == NULL) { + Error (GetSymbolValue (INF_FILENAME), 1, 0, NULL, "missing BASE_NAME definition in INF file"); + DSCFileDestroy (&ComponentFile); + return STATUS_ERROR; + } + // + // Better have defined COMPONENT_TYPE, since it's used to find named sections. + // + if (GetSymbolValue (COMPONENT_TYPE) == NULL) { + Error (GetSymbolValue (INF_FILENAME), 1, 0, NULL, "missing COMPONENT_TYPE definition in INF file"); + DSCFileDestroy (&ComponentFile); + return STATUS_ERROR; + } + + // + // Create the source directory path from the component file's path. If the component + // file's path is absolute, we may have problems here. Try to account for it though. + // + if (ComponentFilePathAbsolute == 0) { + sprintf ( + FileName, + "%s\\%s", + GetSymbolValue (EFI_SOURCE), + ComponentFilePath + ); + } else { + strcpy (FileName, ComponentFilePath); + } + AddSymbol (SOURCE_DIR, FileName, SYM_OVERWRITE | SYM_LOCAL | SYM_FILEPATH); + + // + // Create the destination path. + // They may have defined DEST_DIR on the component INF line, so it's already + // been defined, If that's the case, then don't set it to the path of this file. + // + if (GetSymbolValue (DEST_DIR) == NULL) { + if (ComponentFilePathAbsolute == 0) { + // + // The destination path is $(BUILD_DIR)\$(PROCESSOR)\component_path + // + sprintf ( + FileName, + "%s\\%s\\%s", + GetSymbolValue (BUILD_DIR), + Processor, + ComponentFilePath + ); + } else { + // + // The destination path is $(BUILD_DIR)\$(PROCESSOR)\$(BASE_NAME) + // + sprintf ( + FileName, + "%s\\%s\\%s", + GetSymbolValue (BUILD_DIR), + Processor, + GetSymbolValue (BASE_NAME) + ); + } + AddSymbol (DEST_DIR, FileName, SYM_OVERWRITE | SYM_LOCAL | SYM_FILEPATH); + } + + // + // Create the output directory, then open the output component's makefile + // we're going to create. Allow them to override the makefile name. + // + TempCptr = GetSymbolValue (MAKEFILE_NAME); + if (TempCptr != NULL) { + ExpandSymbols (TempCptr, ComponentMakefileName, sizeof (ComponentMakefileName), EXPANDMODE_NO_UNDEFS); + TempCptr = ComponentMakefileName; + } else { + TempCptr = "makefile"; + } + + sprintf (FileName, "%s\\%s", GetSymbolValue (DEST_DIR), TempCptr); + // + // Save it now with path info + // + AddSymbol (MAKEFILE_NAME, FileName, SYM_OVERWRITE | SYM_LOCAL | SYM_FILENAME); + + if (MakeFilePath (FileName)) { + return STATUS_ERROR; + } + + if ((MakeFptr = fopen (FileName, "w")) == NULL) { + Error (NULL, 0, 0, FileName, "could not create makefile"); + return STATUS_ERROR; + } + // + // At this point we should have all the info we need to create a package + // file if setup to do so. Libraries don't use package files, so + // don't do this for libs. + // + if (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) { + CreatePackageFile (DSCFile); + } + + // + // Add Module name to the global module list + // + AddModuleName (&gGlobals.ModuleList, GetSymbolValue (BASE_NAME), GetSymbolValue (INF_FILENAME)); + // + // Write an nmake line to makefile.out + // + fprintf (gGlobals.MakefileFptr, " @cd %s\n", Processor); + fprintf (gGlobals.MakefileFptr, " $(MAKE) -f %s all\n", FileName); + fprintf (gGlobals.MakefileFptr, " @cd ..\n"); + + // + // Copy the common makefile section from the description file to + // the component's makefile + // + WriteCommonMakefile (DSCFile, MakeFptr, Processor); + // + // Process the component's [nmake.common] and [nmake.$(PROCESSOR)] sections + // + ProcessINFNMakeSection (&ComponentFile, MakeFptr); + // + // Create the SOURCE_FILES macro that includes the names of all source + // files in this component. This macro can then be used elsewhere to + // process all the files making up the component. Required for scanning + // files for string localization. + // + ProcessSourceFiles (DSCFile, &ComponentFile, MakeFptr, SOURCE_MODE_SOURCE_FILES); + // + // Create the include paths. Process [includes.common] and + // [includes.$(PROCESSOR)] and [includes.$(PROCESSOR).$(PLATFORM)] sections. + // + ProcessIncludesSection (&ComponentFile, MakeFptr); + // + // Process all include source files to create a dependency list that can + // be used in the makefile. + // + ProcessIncludeFiles (&ComponentFile, MakeFptr); + // + // Process the [sources.common], [sources.$(PROCESSOR)], and + // [sources.$(PROCESSOR).$(PLATFORM)] files and emit their build commands + // + ProcessSourceFiles (DSCFile, &ComponentFile, MakeFptr, SOURCE_MODE_BUILD_COMMANDS); + // + // Process sources again to create an OBJECTS macro + // + ProcessObjects (&ComponentFile, MakeFptr); + + // + // Add Single Module target : build and clean in top level makefile + // + fprintf (gGlobals.ModuleMakefileFptr, "%sbuild ::", GetSymbolValue (BASE_NAME)); + if (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) { + fprintf (gGlobals.ModuleMakefileFptr, " %sbuild", GLOBAL_LINK_LIB_NAME); + } + + // + // Process all the libraries to define "LIBS = x.lib y.lib..." + // Be generous and append ".lib" if they forgot. + // Make a macro definition: LIBS = $(LIBS) xlib.lib ylib.lib... + // Also add libs dependency for single module build: basenamebuild :: xlibbuild ylibbuild ... + // + ProcessLibs (&ComponentFile, MakeFptr); + + fprintf (gGlobals.ModuleMakefileFptr, "\n"); + + fprintf (gGlobals.ModuleMakefileFptr, " @cd %s\n", Processor); + fprintf (gGlobals.ModuleMakefileFptr, " $(MAKE) -f %s all\n", FileName); + fprintf (gGlobals.ModuleMakefileFptr, " @cd ..\n\n"); + + fprintf (gGlobals.ModuleMakefileFptr, "%sclean ::\n", GetSymbolValue (BASE_NAME)); + fprintf (gGlobals.ModuleMakefileFptr, " $(MAKE) -f %s clean\n\n", FileName); + + // + // Emit commands to create the component. These are simply copied from + // the description file to the component's makefile. First look for + // [build.$(PROCESSOR).$(BUILD_TYPE)]. If not found, then look for if + // find a [build.$(PROCESSOR).$(COMPONENT_TYPE)] line. + // + Cptr = GetSymbolValue (BUILD_TYPE); + if (Cptr != NULL) { + sprintf (InLine, "build.%s.%s", Processor, Cptr); + WriteComponentTypeBuildCommands (DSCFile, MakeFptr, InLine); + } else { + sprintf (InLine, "build.%s.%s", Processor, GetSymbolValue (COMPONENT_TYPE)); + WriteComponentTypeBuildCommands (DSCFile, MakeFptr, InLine); + } + // + // Add it to the FV if not a library + // + if (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) { + // + // Create the FV filename and add it to the FV. + // By this point we know it's in FV. + // + Cptr = GetSymbolValue (FILE_GUID); + if (Cptr == NULL) { + Cptr = GetSymbolValue (GUID); + } + + sprintf (InLine, "%s-%s", Cptr, GetSymbolValue (BASE_NAME)); + // + // We've deprecated FV_EXT, which should be FFS_EXT, the extension + // of the FFS file generated by GenFFSFile. + // + TempCptr = GetSymbolValue (FFS_EXT); + if (TempCptr == NULL) { + TempCptr = GetSymbolValue ("FV_EXT"); + } + + CFVAddFVFile ( + InLine, + GetSymbolValue (COMPONENT_TYPE), + GetSymbolValue (FV), + Instance, + TempCptr, + Processor, + GetSymbolValue (APRIORI), + GetSymbolValue (BASE_NAME), + Cptr + ); + } + // + // Catch any failures and print the name of the component file + // being processed to assist debugging. + // +ComponentDone: + + Cptr = CatchException (); + if (Cptr != NULL) { + fprintf (stderr, "%s\n", Cptr); + sprintf (InLine, "Processing of component %s failed", ArgLine); + ThrowException (InLine); + } + + if (MakeFptr != NULL) { + fclose (MakeFptr); + } + + if (ComponentCreated) { + DSCFileDestroy (&ComponentFile); + } + + return STATUS_SUCCESS; +} + +static +int +CreatePackageFile ( + DSC_FILE *DSCFile + ) +{ + INT8 *Package; + SECTION *TempSect; + INT8 Str[MAX_LINE_LEN]; + INT8 StrExpanded[MAX_LINE_LEN]; + SMART_FILE *PkgFptr; + int Status; + + PkgFptr = NULL; + + // + // First find out if PACKAGE_FILENAME or PACKAGE is defined. PACKAGE_FILENAME + // is used to specify the exact package file to use. PACKAGE is used to + // specify the package section name. + // + Package = GetSymbolValue (PACKAGE_FILENAME); + if (Package != NULL) { + // + // Use existing file. We're done. + // + return STATUS_SUCCESS; + } + // + // See if PACKAGE or PACKAGE_TAG is defined + // + Package = GetSymbolValue (PACKAGE); + if (Package == NULL) { + Package = GetSymbolValue (PACKAGE_TAG); + } + + if (Package == NULL) { + // + // Not defined either. Assume they are not using the package functionality + // of this utility. However define the PACKAGE_FILENAME macro to the + // best-guess value. + // + sprintf ( + Str, + "%s\\%s.pkg", + GetSymbolValue (SOURCE_DIR), + GetSymbolValue (BASE_NAME) + ); + + // + // Expand symbols in the package filename + // + ExpandSymbols (Str, StrExpanded, sizeof (StrExpanded), EXPANDMODE_NO_UNDEFS); + + AddSymbol (PACKAGE_FILENAME, StrExpanded, SYM_LOCAL | SYM_FILENAME); + return STATUS_SUCCESS; + } + // + // Save the position in the DSC file. + // Find the [package.$(COMPONENT_TYPE).$(PACKAGE)] section in the DSC file + // + Status = STATUS_SUCCESS; + DSCFileSavePosition (DSCFile); + sprintf (Str, "%s.%s.%s", PACKAGE, GetSymbolValue (COMPONENT_TYPE), Package); + TempSect = DSCFileFindSection (DSCFile, Str); + if (TempSect != NULL) { + // + // So far so good. Create the name of the package file, then open it up + // for writing. File name is c:\...\oem\platform\nt32\ia32\...\BaseName.pkg. + // + sprintf ( + Str, + "%s\\%s.pkg", + GetSymbolValue (DEST_DIR), + GetSymbolValue (BASE_NAME) + ); + + // + // Expand symbols in the package filename + // + ExpandSymbols (Str, StrExpanded, sizeof (StrExpanded), EXPANDMODE_NO_UNDEFS); + + // + // Try to open the file, then save the file name as the PACKAGE_FILENAME + // symbol for use elsewhere. + // + if ((PkgFptr = SmartOpen (StrExpanded)) == NULL) { + Error (NULL, 0, 0, Str, "could not open package file for writing"); + Status = STATUS_ERROR; + goto Finish; + } + + AddSymbol (PACKAGE_FILENAME, StrExpanded, SYM_LOCAL | SYM_FILENAME); + // + // Now read lines in from the DSC file and write them back out to the + // package file (with string substitution). + // + while (DSCFileGetLine (DSCFile, Str, sizeof (Str)) != NULL) { + // + // Expand symbols, then write the line out to the package file + // + ExpandSymbols (Str, StrExpanded, sizeof (StrExpanded), EXPANDMODE_RECURSIVE); + SmartWrite (PkgFptr, StrExpanded); + } + } else { + Warning ( + NULL, + 0, + 0, + NULL, + "cannot locate package section [%s] in DSC file for %s", + Str, + GetSymbolValue (INF_FILENAME) + ); + Status = STATUS_WARNING; + goto Finish; + } + + if (PkgFptr != NULL) { + SmartClose (PkgFptr); + } + +Finish: + // + // Restore the position in the DSC file + // + DSCFileRestorePosition (DSCFile); + + return STATUS_SUCCESS; +} + +static +int +ProcessINFDefinesSection ( + DSC_FILE *ComponentFile + ) +/*++ + +Routine Description: + + Process the [defines.xxx] sections of the component description file. Process + platform first, then processor. In this way, if a platform wants and override, + that one gets parsed first, and later assignments do not overwrite the value. + +Arguments: + + ComponentFile - section info on the component file being processed + +Returns: + + +--*/ +{ + INT8 *Cptr; + INT8 Str[MAX_LINE_LEN]; + + // + // Find a [defines.$(PROCESSOR).$(PLATFORM)] section and process it + // + Cptr = GetSymbolValue (PLATFORM); + if (Cptr != NULL) { + sprintf ( + Str, + "%s.%s.%s", + DEFINES_SECTION_NAME, + GetSymbolValue (PROCESSOR), + Cptr + ); + ProcessINFDefinesSectionSingle (ComponentFile, Str); + } + // + // Find a [defines.$(PROCESSOR)] section and process it + // + sprintf (Str, "%s.%s", DEFINES_SECTION_NAME, GetSymbolValue (PROCESSOR)); + ProcessINFDefinesSectionSingle (ComponentFile, Str); + + // + // Find a [defines] section and process it + // + if (ProcessINFDefinesSectionSingle (ComponentFile, DEFINES_SECTION_NAME) != STATUS_SUCCESS) { + Error (NULL, 0, 0, NULL, "missing [defines] section in component file %s", GetSymbolValue (INF_FILENAME)); + return STATUS_ERROR; + } + + return STATUS_SUCCESS; +} + +static +int +ProcessINFDefinesSectionSingle ( + DSC_FILE *ComponentFile, + INT8 *SectionName + ) +{ + INT8 *Cptr; + INT8 Str[MAX_LINE_LEN]; + INT8 ExpandedLine[MAX_LINE_LEN]; + SECTION *TempSect; + + TempSect = DSCFileFindSection (ComponentFile, SectionName); + if (TempSect != NULL) { + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + ExpandSymbols (Str, ExpandedLine, sizeof (ExpandedLine), 0); + Cptr = StripLine (ExpandedLine); + // + // Don't process blank lines. + // + if (*Cptr) { + // + // Add without overwriting macros specified on the component line + // in the description file + // + AddSymbol (Cptr, NULL, SYM_LOCAL); + } + } + } else { + return STATUS_WARNING; + } + + return STATUS_SUCCESS; +} + +static +int +ProcessINFNMakeSection ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ) +/*++ + +Routine Description: + + Process the [nmake.common] and [nmake.$(PROCESSOR)] sections of the component + description file and write and copy them to the component's makefile. + +Arguments: + + ComponentFile - section info on the component file being processed + MakeFptr - file pointer to the component' makefile we're creating + +Returns: + + Always STATUS_SUCCESS right now, since the sections are optional. + +--*/ +{ + INT8 *Cptr; + INT8 Str[MAX_LINE_LEN]; + INT8 ExpandedLine[MAX_LINE_LEN]; + SECTION *TempSect; + + // + // Copy the [nmake.common] and [nmake.$(PROCESSOR)] sections from the + // component file directly to the output file. + // The line will be stripped and don't print blank lines + // + sprintf (Str, "%s.%s", NMAKE_SECTION_NAME, COMMON_SECTION_NAME); + TempSect = DSCFileFindSection (ComponentFile, Str); + if (TempSect != NULL) { + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + ExpandSymbols ( + Str, + ExpandedLine, + sizeof (ExpandedLine), + EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR + ); + Cptr = StripLine (ExpandedLine); + if (*Cptr) { + fprintf (MakeFptr, "%s\n", Cptr); + } + } + + fprintf (MakeFptr, "\n"); + } else { + Error (GetSymbolValue (INF_FILENAME), 1, 0, Str, "section not found in component INF file"); + } + + sprintf (Str, "%s.%s", NMAKE_SECTION_NAME, GetSymbolValue (PROCESSOR)); + TempSect = DSCFileFindSection (ComponentFile, Str); + if (TempSect != NULL) { + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + ExpandSymbols ( + Str, + ExpandedLine, + sizeof (ExpandedLine), + EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR + ); + Cptr = StripLine (ExpandedLine); + if (*Cptr) { + fprintf (MakeFptr, "%s\n", Cptr); + } + } + + fprintf (MakeFptr, "\n"); + } + // + // Do the same for [nmake.$(PROCESSOR).$(PLATFORM)] + // + Cptr = GetSymbolValue (PLATFORM); + if (Cptr != NULL) { + sprintf (Str, "%s.%s.%s", NMAKE_SECTION_NAME, GetSymbolValue (PROCESSOR), Cptr); + TempSect = DSCFileFindSection (ComponentFile, Str); + if (TempSect != NULL) { + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + ExpandSymbols ( + Str, + ExpandedLine, + sizeof (ExpandedLine), + EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR + ); + Cptr = StripLine (ExpandedLine); + if (*Cptr) { + fprintf (MakeFptr, "%s\n", Cptr); + } + } + + fprintf (MakeFptr, "\n"); + } + } + + return STATUS_SUCCESS; +} + +static +int +ProcessIncludesSection ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ) +/*++ + +Routine Description: + + Process the [includes.common], [includes.processor], and + [includes.processor.platform] section of the component description file + and write the appropriate macros to the component's makefile. + + Process in reverse order to allow overrides on platform basis. + +Arguments: + + ComponentFile - section info on the component file being processed + MakeFptr - file pointer to the component' makefile we're creating + +Returns: + + Always STATUS_SUCCESS right now, since the sections are optional. + +--*/ +{ + INT8 *Cptr; + INT8 Str[MAX_LINE_LEN]; + INT8 *Processor; + INT8 *OverridePath; + + // + // Write a useful comment to the output makefile so the user knows where + // the data came from. + // + fprintf (MakeFptr, "#\n# Tool-generated list of include paths that are created\n"); + fprintf (MakeFptr, "# from the list of include paths in the [includes.*] sections\n"); + fprintf (MakeFptr, "# of the component INF file.\n#\n"); + + // + // We use this a lot here, so get the value only once. + // + Processor = GetSymbolValue (PROCESSOR); + // + // If they're using an override source path, then add OverridePath and + // OverridePath\$(PROCESSOR) to the list of include paths. + // + OverridePath = GetSymbolValue (SOURCE_OVERRIDE_PATH); + if (OverridePath != NULL) { + fprintf (MakeFptr, "INC = $(INC) -I %s\n", OverridePath); + fprintf (MakeFptr, "INC = $(INC) -I %s\\%s \n", OverridePath, Processor); + } + // + // Try for an [includes.$(PROCESSOR).$(PLATFORM)] + // + Cptr = GetSymbolValue (PLATFORM); + if (Cptr != NULL) { + sprintf (Str, "%s.%s.%s", INCLUDE_SECTION_NAME, Processor, Cptr); + ProcessIncludesSectionSingle (ComponentFile, MakeFptr, Str); + } + // + // Now the [includes.$(PROCESSOR)] section + // + sprintf (Str, "%s.%s", INCLUDE_SECTION_NAME, Processor); + ProcessIncludesSectionSingle (ComponentFile, MakeFptr, Str); + + // + // Now the [includes.common] section + // + sprintf (Str, "%s.%s", INCLUDE_SECTION_NAME, COMMON_SECTION_NAME); + ProcessIncludesSectionSingle (ComponentFile, MakeFptr, Str); + + // + // Done + // + fprintf (MakeFptr, "\n"); + return STATUS_SUCCESS; +} +// +// Process one of the [includes.xxx] sections to create a list of all +// the include paths. +// +static +int +ProcessIncludesSectionSingle ( + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName + ) +{ + INT8 *Cptr; + SECTION *TempSect; + INT8 Str[MAX_LINE_LEN]; + INT8 ExpandedLine[MAX_LINE_LEN]; + INT8 *Processor; + + TempSect = DSCFileFindSection (ComponentFile, SectionName); + if (TempSect != NULL) { + // + // Add processor subdirectory on every include path + // + Processor = GetSymbolValue (PROCESSOR); + // + // Copy lines directly + // + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + ExpandSymbols (Str, ExpandedLine, sizeof (ExpandedLine), 0); + Cptr = StripLine (ExpandedLine); + // + // Don't process blank lines + // + if (*Cptr) { + // + // Strip off trailing slash + // + if (Cptr[strlen (Cptr) - 1] == '\\') { + Cptr[strlen (Cptr) - 1] = 0; + } + // + // Special case of ".". Replace it with source path + // and the rest of the line (for .\$(PROCESSOR)) + // + if (*Cptr == '.') { + // + // Handle case of just a "." + // + if (Cptr[1] == 0) { + fprintf (MakeFptr, "INC = $(INC) -I $(SOURCE_DIR)\n"); + fprintf ( + MakeFptr, + "INC = $(INC) -I $(SOURCE_DIR)\\%s \n", + Processor + ); + } else { + // + // Handle case of ".\path\path\path" or "..\path\path\path" + // + fprintf ( + MakeFptr, + "INC = $(INC) -I $(SOURCE_DIR)\\%s \n", + Cptr + ); + fprintf ( + MakeFptr, + "INC = $(INC) -I $(SOURCE_DIR)\\%s\\%s \n", + Cptr, + Processor + ); + } + } else if ((Cptr[1] != ':') && isalpha (*Cptr)) { + fprintf (MakeFptr, "INC = $(INC) -I $(EFI_SOURCE)\\%s \n", Cptr); + fprintf ( + MakeFptr, + "INC = $(INC) -I $(EFI_SOURCE)\\%s\\%s \n", + Cptr, + Processor + ); + } else { + // + // The line is something like: $(EFI_SOURCE)\dxe\include. Add it to + // the existing $(INC) definition. Add user includes before any + // other existing paths. + // + fprintf (MakeFptr, "INC = $(INC) -I %s \n", Cptr); + fprintf (MakeFptr, "INC = $(INC) -I %s\\%s \n", Cptr, Processor); + } + } + } + } + + return STATUS_SUCCESS; +} + +static +int +ProcessSourceFiles ( + DSC_FILE *DSCFile, + DSC_FILE *ComponentFile, + FILE *MakeFptr, + UINT32 Mode + ) +/*++ + +Routine Description: + + Process the [sources.common], [sources.$(PROCESSOR)], and + [sources.$(PROCESSOR).$(PLATFORM] sections of the component + description file and write the appropriate build commands out to the + component's makefile. If $(SOURCE_SELECT) is defined, then it overrides + the source selections. We use this functionality for SMM. + +Arguments: + + ComponentFile - section info on the component file being processed + MakeFptr - file pointer to the component' makefile we're creating + DSCFile - section info on the description file we're processing + Mode - to write build commands, or just create a list + of sources. + +Returns: + + Always STATUS_SUCCESS right now, since the sections are optional. + +--*/ +{ + INT8 Str[MAX_LINE_LEN]; + INT8 *Processor; + INT8 *Platform; + INT8 *SourceSelect; + INT8 *CStart; + INT8 *CEnd; + INT8 CSave; + INT8 *CopySourceSelect; + + if (Mode & SOURCE_MODE_SOURCE_FILES) { + // + // Write a useful comment to the output makefile so the user knows where + // the data came from. + // + fprintf (MakeFptr, "#\n# Tool-generated list of source files that are created\n"); + fprintf (MakeFptr, "# from the list of source files in the [sources.*] sections\n"); + fprintf (MakeFptr, "# of the component INF file.\n#\n"); + } + + // + // We use this a lot here, so get the value only once. + // + Processor = GetSymbolValue (PROCESSOR); + // + // See if they defined SOURCE_SELECT=xxx,yyy in which case we'll + // select each [sources.xxx] and [sources.yyy] files and process + // them. + // + SourceSelect = GetSymbolValue (SOURCE_SELECT); + + if (SourceSelect != NULL) { + // + // Make a copy of the string and break it up (comma-separated) and + // select each [sources.*] file from the INF. + // + CopySourceSelect = (INT8 *) malloc (strlen (SourceSelect) + 1); + if (CopySourceSelect == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (CopySourceSelect, SourceSelect); + CStart = CopySourceSelect; + CEnd = CStart; + while (*CStart) { + CEnd = CStart + 1; + while (*CEnd && *CEnd != ',') { + CEnd++; + } + + CSave = *CEnd; + *CEnd = 0; + sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, CStart); + ProcessSourceFilesSection (DSCFile, ComponentFile, MakeFptr, Str, Mode); + // + // Restore the terminator and advance + // + *CEnd = CSave; + CStart = CEnd; + if (*CStart) { + CStart++; + } + } + + free (CopySourceSelect); + + } else { + // + // Process all the [sources.common] source files to make them build + // + sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, COMMON_SECTION_NAME); + ProcessSourceFilesSection (DSCFile, ComponentFile, MakeFptr, Str, Mode); + // + // Now process the [sources.$(PROCESSOR)] files. + // + sprintf (Str, "sources.%s", Processor); + ProcessSourceFilesSection (DSCFile, ComponentFile, MakeFptr, Str, Mode); + // + // Now process the [sources.$(PROCESSOR).$(PLATFORM)] files. + // + Platform = GetSymbolValue (PLATFORM); + if (Platform != NULL) { + sprintf (Str, "sources.%s.%s", Processor, Platform); + ProcessSourceFilesSection (DSCFile, ComponentFile, MakeFptr, Str, Mode); + } + } + + fprintf (MakeFptr, "\n"); + return STATUS_SUCCESS; +} + +/*++ + +Routine Description: + Given a source file line from an INF file, parse it to see if there are + any defines on it. If so, then add them to the symbol table. + Also, terminate the line after the file name. + +Arguments: + SourceFileLine - a line from a [sources.?] section of the INF file. Likely + something like: + + MySourceFile.c BUILT_NAME=$(BUILD_DIR)\MySourceFile.obj + +Returns: + Nothing. + +--*/ +static +void +AddFileSymbols ( + INT8 *SourceFileLine + ) +{ + int Len; + // + // Skip spaces + // + for (; *SourceFileLine && isspace (*SourceFileLine); SourceFileLine++) + ; + for (; *SourceFileLine && !isspace (*SourceFileLine); SourceFileLine++) + ; + if (*SourceFileLine) { + *SourceFileLine = 0; + SourceFileLine++; + // + // AddSymbol() will parse it for us, and return the length. Keep calling + // it until it reports an error or is done. + // + do { + Len = AddSymbol (SourceFileLine, NULL, SYM_FILE); + SourceFileLine += Len; + } while (Len > 0); + } +} +// +// Process a single section of source files in the component INF file +// +static +int +ProcessSourceFilesSection ( + DSC_FILE *DSCFile, + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName, + UINT32 Mode + ) +{ + INT8 *Cptr; + INT8 FileName[MAX_EXP_LINE_LEN]; + INT8 FilePath[MAX_PATH]; + INT8 TempFileName[MAX_PATH]; + SECTION *TempSect; + INT8 Str[MAX_LINE_LEN]; + INT8 *Processor; + INT8 *OverridePath; + FILE *FPtr; + + TempSect = DSCFileFindSection (ComponentFile, SectionName); + if (TempSect != NULL) { + Processor = GetSymbolValue (PROCESSOR); + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + Cptr = StripLine (Str); + // + // Don't process blank lines + // + if (*Cptr) { + // + // Expand symbols in the filename, then parse the line for symbol + // definitions. AddFileSymbols() will null-terminate the line + // after the file name. Save a copy for override purposes, in which + // case we'll need to know the file name and path (in case it's in + // a subdirectory). + // + ExpandSymbols (Cptr, FileName, sizeof (FileName), 0); + AddFileSymbols (FileName); + // + // Set the SOURCE_FILE_NAME symbol. What we have now is the name of + // the file, relative to the location of the INF file. So prepend + // $(SOURCE_DIR) to it first. + // + if (IsAbsolutePath (FileName)) { + strcpy (TempFileName, FileName); + } else { + strcpy (TempFileName, "$(SOURCE_DIR)\\"); + strcat (TempFileName, FileName); + } + AddSymbol (SOURCE_FILE_NAME, TempFileName, SYM_FILE | SYM_OVERWRITE); + // + // Extract path information from the source file and set internal + // variable SOURCE_RELATIVE_PATH. Only do this if the path + // contains a backslash. + // + strcpy (FilePath, FileName); + for (Cptr = FilePath + strlen (FilePath) - 1; (Cptr > FilePath) && (*Cptr != '\\'); Cptr--) + ; + if (*Cptr == '\\') { + *(Cptr + 1) = 0; + AddSymbol (SOURCE_RELATIVE_PATH, FilePath, SYM_FILE); + } + // + // Define another internal symbol for the name of the file without + // the path and extension. + // + for (Cptr = FileName + strlen (FileName) - 1; (Cptr > FileName) && (*Cptr != '\\'); Cptr--) + ; + if (*Cptr == '\\') { + Cptr++; + } + + strcpy (FilePath, Cptr); + // + // We now have a file name with no path information. Before we do anything else, + // see if OVERRIDE_PATH is set, and if so, see if file $(OVERRIDE_PATH)FileName + // exists. If it does, then recursive call this function to use the override file + // instead of the one from the INF file. + // + if (IsAbsolutePath (FileName)) { + OverridePath = NULL; + } else { + OverridePath = GetSymbolValue (SOURCE_OVERRIDE_PATH); + } + if (OverridePath != NULL) { + // + // See if the file exists. If it does, reset the SOURCE_FILE_NAME symbol. + // + strcpy (TempFileName, OverridePath); + strcat (TempFileName, "\\"); + strcat (TempFileName, FileName); + if ((FPtr = fopen (TempFileName, "rb")) != NULL) { + fclose (FPtr); + AddSymbol (SOURCE_FILE_NAME, TempFileName, SYM_FILE | SYM_OVERWRITE); + // + // Print a message. This function is called to create build commands + // for source files, and to create a macro of all source files. Therefore + // do this check so we don't print the override message multiple times. + // + if (Mode & SOURCE_MODE_BUILD_COMMANDS) { + fprintf (stdout, "Override: %s\n", TempFileName); + } + } else { + // + // Set override path to null to use as a flag below + // + OverridePath = NULL; + } + } + + // + // Start at the end and work back + // + for (Cptr = FilePath + strlen (FilePath) - 1; (Cptr > FilePath) && (*Cptr != '\\') && (*Cptr != '.'); Cptr--) + ; + if (*Cptr == '.') { + *Cptr = 0; + AddSymbol (SOURCE_FILE_EXTENSION, Cptr + 1, SYM_FILE); + } + + AddSymbol (SOURCE_BASE_NAME, FilePath, SYM_FILE); + // + // If we're just creating the SOURCE_FILES macro, then write the + // file name out to the makefile. + // + if (Mode & SOURCE_MODE_SOURCE_FILES) { + // + // If we're processing an override file, then use the file name as-is + // + if (OverridePath != NULL) { + // + // SOURCE_FILES = $(SOURCE_FILES) c:\Path\ThisFile.c + // + fprintf (MakeFptr, "SOURCE_FILES = $(SOURCE_FILES) %s\n", TempFileName); + } else if (IsAbsolutePath (FileName)) { + // + // For Absolute path, don't print $(SOURCE_FILE) directory. + // + fprintf (MakeFptr, "SOURCE_FILES = $(SOURCE_FILES) %s\n", FileName); + } else { + // + // SOURCE_FILES = $(SOURCE_FILES) $(SOURCE_DIR)\ThisFile.c + // + fprintf (MakeFptr, "SOURCE_FILES = $(SOURCE_FILES) $(SOURCE_DIR)\\%s\n", FileName); + } + } else if (Mode & SOURCE_MODE_BUILD_COMMANDS) { + // + // Write the build commands for this file per the build commands + // for this file type as defined in the description file. + // Also create the directory for it in the build path. + // + WriteCompileCommands (DSCFile, MakeFptr, FileName, Processor); + if (!IsAbsolutePath (FileName)) { + sprintf (Str, "%s\\%s", GetSymbolValue (DEST_DIR), FileName); + MakeFilePath (Str); + // + // Get all output directory for build output files. + // + Cptr = FileName + strlen (FileName) - 1; + for (; (Cptr > FileName) && (*Cptr != '\\'); Cptr--); + if (*Cptr == '\\') { + *Cptr = '\0'; + AddModuleName (&gGlobals.OutdirList, FileName, NULL); + } + } + } + // + // Remove file-level symbols + // + RemoveFileSymbols (); + } + } + } + + return STATUS_SUCCESS; +} +// +// Process the INF [sources.*] sections and emit the OBJECTS = ..... +// lines to the component's makefile. +// +static +int +ProcessObjects ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ) +{ + INT8 Str[MAX_LINE_LEN]; + INT8 *Processor; + INT8 *Platform; + INT8 *SourceSelect; + INT8 *CStart; + INT8 *CEnd; + INT8 CSave; + INT8 *CopySourceSelect; + SYMBOL *TempSymbol; + + // + // Write a useful comment to the output makefile so the user knows where + // the data came from. + // + fprintf (MakeFptr, "#\n# Tool-generated list of object files that are created\n"); + fprintf (MakeFptr, "# from the list of source files in the [sources.*] sections\n"); + fprintf (MakeFptr, "# of the component INF file.\n#\n"); + // + // We use this a lot here, so get the value only once. + // + Processor = GetSymbolValue (PROCESSOR); + // + // Now define the OBJECTS variable and assign it to be all the object files we're going + // to create. Afterwards create a pseudo-target objects to let the user quickly just compile + // the source files. This means we need to process all the common objects and + // processor-specific objects again. + // + fprintf (MakeFptr, "OBJECTS = $(OBJECTS) "); + // + // See if they defined SOURCE_SELECT=xxx,yyy in which case well + // select each [sources.xxx] and [sources.yyy] files and process + // them. + // + SourceSelect = GetSymbolValue (SOURCE_SELECT); + + if (SourceSelect != NULL) { + // + // Make a copy of the string and break it up (comma-separated) and + // select each [sources.*] file from the INF. + // + CopySourceSelect = (INT8 *) malloc (strlen (SourceSelect) + 1); + if (CopySourceSelect == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (CopySourceSelect, SourceSelect); + CStart = CopySourceSelect; + CEnd = CStart; + while (*CStart) { + CEnd = CStart + 1; + while (*CEnd && *CEnd != ',') { + CEnd++; + } + + CSave = *CEnd; + *CEnd = 0; + sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, CStart); + ProcessObjectsSingle (ComponentFile, MakeFptr, Str); + // + // Restore the terminator and advance + // + *CEnd = CSave; + CStart = CEnd; + if (*CStart) { + CStart++; + } + } + + free (CopySourceSelect); + + } else { + // + // Now process all the [sources.common] files and emit build commands for them + // + sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, COMMON_SECTION_NAME); + if (ProcessObjectsSingle (ComponentFile, MakeFptr, Str) != STATUS_SUCCESS) { + Warning (GetSymbolValue (INF_FILENAME), 1, 0, NULL, "no [%s] section found in component description", Str); + } + // + // Now process any processor-specific source files in [sources.$(PROCESSOR)] + // + sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, Processor); + ProcessObjectsSingle (ComponentFile, MakeFptr, Str); + + // + // Now process any [sources.$(PROCESSOR).$(PLATFORM)] files + // + Platform = GetSymbolValue (PLATFORM); + if (Platform != NULL) { + sprintf (Str, "sources.%s.%s", Processor, Platform); + ProcessObjectsSingle (ComponentFile, MakeFptr, Str); + } + } + + fprintf (MakeFptr, "\n\n"); + + // + // Write a useful comment to the output makefile so the user knows where + // the data came from. + // + fprintf (MakeFptr, "#\n# Tool-generated list of dest output dirs that are created\n"); + fprintf (MakeFptr, "# from the list of source files in the [sources.*] sections\n"); + fprintf (MakeFptr, "# of the component INF file.\n#\n"); + // + // Create output directory list + // for clean target to delete all build output files. + // + fprintf (MakeFptr, "DEST_OUTPUT_DIRS = $(%s) ", DEST_DIR); + + TempSymbol = gGlobals.OutdirList; + while (TempSymbol != NULL) { + fprintf (MakeFptr, "\\\n $(%s)\\%s ", + DEST_DIR, TempSymbol->Name); + TempSymbol = TempSymbol->Next; + } + fprintf (MakeFptr, "\n\n"); + + // + // clean up for the next module + // + FreeSymbols (gGlobals.OutdirList); + gGlobals.OutdirList = NULL; + + return STATUS_SUCCESS; +} + +static +INT8 * +BuiltFileExtension ( + INT8 *SourceFileName + ) +{ + int i; + INT8 *Cptr; + // + // Find the dot in the filename extension + // + for (Cptr = SourceFileName + strlen (SourceFileName) - 1; + (Cptr > SourceFileName) && (*Cptr != '\\') && (*Cptr != '.'); + Cptr-- + ) { + // + // Do nothing + // + } + + if (*Cptr != '.') { + return NULL; + } + // + // Look through our list of known file types and return a pointer to + // its built file extension. + // + for (i = 0; mFileTypes[i].Extension != NULL; i++) { + if (_stricmp (Cptr, mFileTypes[i].Extension) == 0) { + return mFileTypes[i].BuiltExtension; + } + } + + return NULL; +} + +int +ProcessObjectsSingle ( + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName + ) +{ + INT8 *Cptr; + INT8 *Cptr2; + INT8 Str[MAX_LINE_LEN]; + INT8 FileName[MAX_EXP_LINE_LEN]; + SECTION *TempSect; + + TempSect = DSCFileFindSection (ComponentFile, SectionName); + if (TempSect != NULL) { + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + Cptr = StripLine (Str); + // + // Don't process blank lines + // + if (*Cptr) { + // + // Expand symbols then create the output filename. We'll do a lookup + // on the source file's extension to determine what the extension of + // the built version of the file is. For example, .c -> .obj. + // + if (!IsIncludeFile (Cptr)) { + ExpandSymbols (Cptr, FileName, sizeof (FileName), 0); + Cptr2 = BuiltFileExtension (FileName); + if (Cptr2 != NULL) { + SetFileExtension (FileName, Cptr2); + if (!IsAbsolutePath (FileName)) { + fprintf (MakeFptr, "\\\n $(%s)\\%s ", DEST_DIR, FileName); + } else { + fprintf (MakeFptr, "\\\n %s ", FileName); + } + } + } + } + } + } else { + return STATUS_WARNING; + } + + return STATUS_SUCCESS; +} +// +// Process all [libraries.*] sections in the component INF file to create a +// macro to the component's output makefile: LIBS = Lib1 Lib2, ... +// +static +int +ProcessLibs ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ) +{ + INT8 Str[MAX_LINE_LEN]; + INT8 *Processor; + INT8 *Platform; + + // + // Print a useful comment to the component's makefile so the user knows + // where the data came from. + // + fprintf (MakeFptr, "#\n# Tool-generated list of libraries that are generated\n"); + fprintf (MakeFptr, "# from the list of libraries listed in the [libraries.*] sections\n"); + fprintf (MakeFptr, "# of the component INF file.\n#\n"); + + fprintf (MakeFptr, "LIBS = $(LIBS) "); + + Processor = GetSymbolValue (PROCESSOR); + // + // Process [libraries.common] files + // + sprintf (Str, "%s.%s", LIBRARIES_SECTION_NAME, COMMON_SECTION_NAME); + ProcessLibsSingle (ComponentFile, MakeFptr, Str); + // + // Process the [libraries.$(PROCESSOR)] libraries to define "LIBS = x.lib y.lib..." + // + sprintf (Str, "%s.%s", LIBRARIES_SECTION_NAME, Processor); + ProcessLibsSingle (ComponentFile, MakeFptr, Str); + // + // Now process any [libraries.$(PROCESSOR).$(PLATFORM)] files + // + Platform = GetSymbolValue (PLATFORM); + if (Platform != NULL) { + sprintf (Str, "%s.%s.%s", LIBRARIES_SECTION_NAME, Processor, Platform); + ProcessLibsSingle (ComponentFile, MakeFptr, Str); + } + // + // Process any [libraries.platform] files + // + ProcessLibsSingle (ComponentFile, MakeFptr, LIBRARIES_PLATFORM_SECTION_NAME); + + fprintf (MakeFptr, "\n\n"); + return STATUS_SUCCESS; +} + +static +int +ProcessLibsSingle ( + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName + ) +{ + INT8 *Cptr; + INT8 Str[MAX_LINE_LEN]; + INT8 ExpandedLine[MAX_LINE_LEN]; + SECTION *TempSect; + + TempSect = DSCFileFindSection (ComponentFile, SectionName); + if (TempSect != NULL) { + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + ExpandSymbols (Str, ExpandedLine, sizeof (ExpandedLine), 0); + Cptr = StripLine (ExpandedLine); + // + // Don't process blank lines + // + if (*Cptr) { + if (Cptr[strlen (Cptr) - 4] != '.') { + fprintf (MakeFptr, " \\\n $(LIB_DIR)\\%s.lib", Cptr); + // + // Add lib dependency for single module build + // + fprintf (gGlobals.ModuleMakefileFptr, " %sbuild", Cptr); + } else { + fprintf (MakeFptr, " \\\n $(LIB_DIR)\\%s", Cptr); + // + // Add lib dependency for single module build + // + Cptr[strlen (Cptr) - 4] = 0; + fprintf (gGlobals.ModuleMakefileFptr, " %sbuild", Cptr); + } + } + } + } + + return STATUS_SUCCESS; +} + +static +int +ProcessIncludeFiles ( + DSC_FILE *ComponentFile, + FILE *MakeFptr + ) +{ + INT8 Str[MAX_LINE_LEN]; + INT8 *Processor; + INT8 *Platform; + INT8 *SourceSelect; + INT8 *CStart; + INT8 *CEnd; + INT8 CSave; + INT8 *CopySourceSelect; + + // + // Print a useful comment to the output makefile so the user knows where + // the info came from + // + //fprintf (MakeFptr, "#\n# Tool-generated include dependencies from any include files in the\n"); + //fprintf (MakeFptr, "# [sources.*] sections of the component INF file\n#\n"); + + Processor = GetSymbolValue (PROCESSOR); + + // + // See if they defined SOURCE_SELECT=xxx,yyy in which case we'll + // select each [sources.xxx] and [sources.yyy] files and process + // them. + // + SourceSelect = GetSymbolValue (SOURCE_SELECT); + + if (SourceSelect != NULL) { + // + // Make a copy of the string and break it up (comma-separated) and + // select each [sources.*] file from the INF. + // + CopySourceSelect = (INT8 *) malloc (strlen (SourceSelect) + 1); + if (CopySourceSelect == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return STATUS_ERROR; + } + + strcpy (CopySourceSelect, SourceSelect); + CStart = CopySourceSelect; + CEnd = CStart; + while (*CStart) { + CEnd = CStart + 1; + while (*CEnd && *CEnd != ',') { + CEnd++; + } + + CSave = *CEnd; + *CEnd = 0; + sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, CStart); + ProcessIncludeFilesSingle (ComponentFile, MakeFptr, Str); + // + // Restore the terminator and advance + // + *CEnd = CSave; + CStart = CEnd; + if (*CStart) { + CStart++; + } + } + + free (CopySourceSelect); + + } else { + // + // Find all the include files in the [sources.common] sections. + // + sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, COMMON_SECTION_NAME); + ProcessIncludeFilesSingle (ComponentFile, MakeFptr, Str); + // + // Now process the [sources.$(PROCESSOR)] files. + // + sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, Processor); + ProcessIncludeFilesSingle (ComponentFile, MakeFptr, Str); + // + // Now process the [sources.$(PROCESSOR).$(PLATFORM)] files. + // + Platform = GetSymbolValue (PLATFORM); + if (Platform != NULL) { + sprintf (Str, "sources.%s.%s", Processor, Platform); + ProcessIncludeFilesSingle (ComponentFile, MakeFptr, Str); + } + } + + fprintf (MakeFptr, "\n"); + return STATUS_SUCCESS; +} + +int +ProcessIncludeFilesSingle ( + DSC_FILE *ComponentFile, + FILE *MakeFptr, + INT8 *SectionName + ) +{ + INT8 *Cptr; + INT8 FileName[MAX_EXP_LINE_LEN]; + INT8 TempFileName[MAX_PATH]; + SECTION *TempSect; + INT8 Str[MAX_LINE_LEN]; + INT8 *OverridePath; + FILE *FPtr; + + TempSect = DSCFileFindSection (ComponentFile, SectionName); + if (TempSect != NULL) { + // + // See if the SOURCE_OVERRIDE_PATH has been set. If it has, and + // they have an include file that is overridden, then add the path + // to it to the list of include paths (prepend). + // + OverridePath = GetSymbolValue (SOURCE_OVERRIDE_PATH); + while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) { + Cptr = StripLine (Str); + // + // Don't process blank lines + // + if (*Cptr) { + // + // Expand symbols in the filename, then get its parts + // + ExpandSymbols (Cptr, FileName, sizeof (FileName), 0); + AddFileSymbols (FileName); + if (IsIncludeFile (FileName)) { + if ((OverridePath != NULL) && (!IsAbsolutePath (FileName))) { + strcpy (TempFileName, OverridePath); + strcat (TempFileName, "\\"); + strcat (TempFileName, FileName); + if ((FPtr = fopen (TempFileName, "rb")) != NULL) { + fclose (FPtr); + // + // Null-terminate the file name at the last backslash and add that + // to the beginning of the list of include paths. + // + for (Cptr = TempFileName + strlen (TempFileName) - 1; + (Cptr >= TempFileName) && (*Cptr != '\\') && (*Cptr != '/'); + Cptr-- + ) + ; + if (Cptr >= TempFileName) { + *Cptr = 0; + } + + fprintf (MakeFptr, "INC = -I %s $(INC)\n", TempFileName); + } + } + // + // If absolute path already, don't prepend source directory + // + // if (IsAbsolutePath (FileName)) { + // fprintf (MakeFptr, "INC_DEPS = $(INC_DEPS) %s\n", FileName); + // } else { + // fprintf (MakeFptr, "INC_DEPS = $(INC_DEPS) $(SOURCE_DIR)\\%s\n", FileName); + // } + } + + RemoveFileSymbols (); + } + } + } + + return STATUS_SUCCESS; +} + +static +void +FreeFileParts ( + FILE_NAME_PARTS *FP + ) +{ + if (FP != NULL) { + if (FP->Path != NULL) { + free (FP->Path); + } + + if (FP->BaseName != NULL) { + free (FP->BaseName); + } + + if (FP->Extension != NULL) { + free (FP->Extension); + } + } +} + +static +FILE_NAME_PARTS * +GetFileParts ( + INT8 *FileName + ) +{ + FILE_NAME_PARTS *FP; + INT8 *Cptr; + INT8 CopyFileName[MAX_PATH]; + INT8 *FileNamePtr; + + strcpy (CopyFileName, FileName); + FP = (FILE_NAME_PARTS *) malloc (sizeof (FILE_NAME_PARTS)); + if (FP == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return NULL; + } + + memset ((INT8 *) FP, 0, sizeof (FILE_NAME_PARTS)); + // + // Get extension code + // + FP->ExtensionCode = GetSourceFileType (CopyFileName); + // + // Get drive if there + // + FileNamePtr = CopyFileName; + if (FileNamePtr[1] == ':') { + FP->Drive[0] = FileNamePtr[0]; + FP->Drive[1] = ':'; + FileNamePtr += 2; + } + // + // Start at the end and work back + // + for (Cptr = FileNamePtr + strlen (FileNamePtr) - 1; (Cptr > FileNamePtr) && (*Cptr != '.'); Cptr--) + ; + + if (*Cptr == '.') { + // + // Don't copy the dot + // + FP->Extension = (char *) malloc (strlen (Cptr)); + strcpy (FP->Extension, Cptr + 1); + *Cptr = 0; + Cptr--; + StripTrailingSpaces (FP->Extension); + } else { + // + // Create empty string for extension + // + FP->Extension = (char *) malloc (1); + FP->Extension[0] = 0; + } + // + // Now back up and get the base name (include the preceding '\' or '/') + // + for (; (Cptr > FileNamePtr) && (*Cptr != '\\') && (*Cptr != '/'); Cptr--) + ; + FP->BaseName = (char *) malloc (strlen (Cptr) + 1); + strcpy (FP->BaseName, Cptr); + *Cptr = 0; + Cptr--; + // + // Rest is path + // + if (Cptr >= FileNamePtr) { + Cptr = FileNamePtr; + FP->Path = (char *) malloc (strlen (Cptr) + 1); + strcpy (FP->Path, Cptr); + } else { + FP->Path = (char *) malloc (1); + FP->Path[0] = 0; + } + + return FP; +} + +/***************************************************************************** +******************************************************************************/ +static +int +WriteCommonMakefile ( + DSC_FILE *DSCFile, + FILE *MakeFptr, + INT8 *Processor + ) +{ + INT8 InLine[MAX_LINE_LEN]; + INT8 OutLine[MAX_EXP_LINE_LEN]; + SECTION *Sect; + INT8 *Sym; + int i; + // + // Don't mess up the original file pointer, since we're processing it at a higher + // level. + // + DSCFileSavePosition (DSCFile); + // + // Write the header to the file + // + for (i = 0; MakefileHeader[i] != NULL; i++) { + fprintf (MakeFptr, "%s\n", MakefileHeader[i]); + } + + fprintf (MakeFptr, "#\n# Hard-coded defines output by the tool\n#\n"); + // + // First write the basics to the component's makefile. These includes + // EFI_SOURCE, BIN_DIR, OUT_DIR, LIB_DIR, SOURCE_DIR, DEST_DIR. + // + Sym = GetSymbolValue (EFI_SOURCE); + fprintf (MakeFptr, "%s = %s\n", EFI_SOURCE, Sym); + Sym = GetSymbolValue (BUILD_DIR); + fprintf (MakeFptr, "%s = %s\n", BUILD_DIR, Sym); + Sym = GetSymbolValue (BIN_DIR); + fprintf (MakeFptr, "%s = %s\n", BIN_DIR, Sym); + Sym = GetSymbolValue (OUT_DIR); + fprintf (MakeFptr, "%s = %s\n", OUT_DIR, Sym); + Sym = GetSymbolValue (LIB_DIR); + fprintf (MakeFptr, "%s = %s\n", LIB_DIR, Sym); + Sym = GetSymbolValue (SOURCE_DIR); + fprintf (MakeFptr, "%s = %s\n", SOURCE_DIR, Sym); + Sym = GetSymbolValue (DEST_DIR); + fprintf (MakeFptr, "%s = %s\n", DEST_DIR, Sym); + fprintf (MakeFptr, "\n"); + // + // If there was a [makefile.common] section in the description file, + // copy it (after symbol expansion) to the output file. + // + sprintf (InLine, "%s.%s", MAKEFILE_SECTION_NAME, COMMON_SECTION_NAME); + Sect = DSCFileFindSection (DSCFile, InLine); + if (Sect != NULL) { + // + // fprintf (MakeFptr, "# From the [makefile.common] section of the DSC file\n"); + // Read lines, expand, then dump out + // + while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) { + // + // Replace symbols + // + ExpandSymbols (InLine, OutLine, sizeof (OutLine), EXPANDMODE_RECURSIVE); + fprintf (MakeFptr, OutLine); + } + } + // + // If there was a [makefile.platform] section in the description file, + // copy it (after symbol expansion) to the output file. + // + sprintf (InLine, "%s.%s", MAKEFILE_SECTION_NAME, "Platform"); + Sect = DSCFileFindSection (DSCFile, InLine); + if (Sect != NULL) { + // + // Read lines, expand, then dump out + // + while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) { + // + // Replace symbols + // + ExpandSymbols (InLine, OutLine, sizeof (OutLine), EXPANDMODE_RECURSIVE); + fprintf (MakeFptr, OutLine); + } + } + // + // Do the same for any [makefile.$(PROCESSOR)] + // + sprintf (InLine, "%s.%s", MAKEFILE_SECTION_NAME, Processor); + Sect = DSCFileFindSection (DSCFile, InLine); + if (Sect != NULL) { + // + // Read lines, expand, then dump out + // + while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) { + ExpandSymbols (InLine, OutLine, sizeof (OutLine), EXPANDMODE_RECURSIVE); + fprintf (MakeFptr, OutLine); + } + } + // + // Same thing for [makefile.$(PROCESSOR).$(PLATFORM)] + // + Sym = GetSymbolValue (PLATFORM); + if (Sym != NULL) { + sprintf (InLine, "%s.%s.%s", MAKEFILE_SECTION_NAME, Processor, Sym); + Sect = DSCFileFindSection (DSCFile, InLine); + if (Sect != NULL) { + // + // Read lines, expand, then dump out + // + while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) { + ExpandSymbols (InLine, OutLine, sizeof (OutLine), EXPANDMODE_RECURSIVE); + fprintf (MakeFptr, OutLine); + } + } + } + + fprintf (MakeFptr, "\n"); + DSCFileRestorePosition (DSCFile); + return 0; +} + +static +int +WriteComponentTypeBuildCommands ( + DSC_FILE *DSCFile, + FILE *MakeFptr, + INT8 *SectionName + ) +/*++ + +Routine Description: + + Given a section name such as [build.ia32.library], find the section in + the description file and copy the build commands. + +Arguments: + + DSCFile - section information on the main description file + MakeFptr - file pointer to the makefile we're writing to + SectionName - name of the section we're to copy out to the makefile. + +Returns: + + Always successful, since the section may be optional. + +--*/ +{ + SECTION *Sect; + INT8 InLine[MAX_LINE_LEN]; + INT8 OutLine[MAX_EXP_LINE_LEN]; + + // + // Don't mess up the original file pointer, since we're processing it at a higher + // level. + // + DSCFileSavePosition (DSCFile); + Sect = DSCFileFindSection (DSCFile, SectionName); + if (Sect != NULL) { + // + // Read lines, expand, then dump out + // + while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) { + ExpandSymbols ( + InLine, + OutLine, + sizeof(OutLine), + EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR + ); + fprintf (MakeFptr, OutLine); + } + } else { + Warning ( + NULL, + 0, + 0, + GetSymbolValue (INF_FILENAME), + "no [%s] build commands found in DSC file for component", + SectionName + ); + } + + DSCFileRestorePosition (DSCFile); + return STATUS_SUCCESS; +} + +/***************************************************************************** + +******************************************************************************/ +static +int +WriteCompileCommands ( + DSC_FILE *DscFile, + FILE *MakeFptr, + INT8 *FileName, + INT8 *Processor + ) +{ + FILE_NAME_PARTS *File; + SECTION *Sect; + INT8 BuildSectionName[40]; + INT8 InLine[MAX_LINE_LEN]; + INT8 OutLine[MAX_EXP_LINE_LEN]; + INT8 *SourceCompileType; + char *CPtr; + char *CPtr2; + // + // Determine the filename, then chop it up into its parts + // + File = GetFileParts (FileName); + if (File != NULL) { + // + // Don't mess up the original file pointer, since we're processing it at a higher + // level. + // + DSCFileSavePosition (DscFile); + // + // Option 1: SOURCE_COMPILE_TYPE=MyCompileSection + // Find a section of that name from which to get the compile + // commands for this source file. + // Look for [compile.$(PROCESSOR).$(SOURCE_COMPILE_TYPE] + // Option 2: COMPILE_SELECT=.c=MyCCompile,.asm=MyAsm + // Find a [compile.$(PROCESSOR).MyCompile] section from which to + // get the compile commands for this source file. + // Look for [compile.$(PROCESSOR).MyCompile] + // Option 3: Look for standard section types to compile the file by extension. + // Look for [compile.$(PROCESSOR).] + // + Sect = NULL; + // + // Option 1 - use SOURCE_COMPILE_TYPE variable + // + SourceCompileType = GetSymbolValue (SOURCE_COMPILE_TYPE); + if (SourceCompileType != NULL) { + sprintf (BuildSectionName, "compile.%s.%s", Processor, SourceCompileType); + Sect = DSCFileFindSection (DscFile, BuildSectionName); + } + // + // Option 2 - use COMPILE_SELECT variable + // + if (Sect == NULL) { + SourceCompileType = GetSymbolValue (COMPILE_SELECT); + if (SourceCompileType != NULL) { + // + // Parse the variable, which looks like COMPILE_SELECT=.c=MyCCompiler;.asm=MyAsm; + // to find an entry with a matching file name extension. If you find one, + // then use that name to find the section name. + // + CPtr = SourceCompileType; + while (*CPtr && (Sect == NULL)) { + // + // See if we found a match with this source file name extension. File->Extension + // does not include the dot, so skip the dot in the COMPILE_SELECT variable if there + // is one. + // + if (*CPtr == '.') { + CPtr++; + } + + if (_strnicmp (CPtr, File->Extension, strlen (File->Extension)) == 0) { + // + // Found a file name extension match -- extract the name from the variable, for + // example "MyCCompiler" + // + while (*CPtr && (*CPtr != '=')) { + CPtr++; + } + + if ((*CPtr != '=') || (CPtr[1] == 0)) { + Error (NULL, 0, 0, SourceCompileType, "malformed COMPILE_SELECT variable"); + break; + } + + CPtr++; + sprintf (BuildSectionName, "compile.%s.", Processor); + for (CPtr2 = BuildSectionName + strlen (BuildSectionName); + *CPtr && (*CPtr != ',') && (*CPtr != ';'); + CPtr++ + ) { + *CPtr2 = *CPtr; + CPtr2++; + } + + *CPtr2 = 0; + Sect = DSCFileFindSection (DscFile, BuildSectionName); + if (Sect == NULL) { + ParserError ( + 0, + BuildSectionName, + "could not find section in DSC file - selected by COMPILE_SELECT variable" + ); + } + } + + // + // Skip to next file name extension in the COMPILE_SELECT variable + // + while (*CPtr && (*CPtr != ';') && (*CPtr != ',')) { + CPtr++; + } + + if (*CPtr) { + CPtr++; + } + } + } + } + // + // Option 3 - use "Compile.$(PROCESSOR)." section + // + if (Sect == NULL) { + sprintf (BuildSectionName, "compile.%s.%s", Processor, File->Extension); + Sect = DSCFileFindSection (DscFile, BuildSectionName); + } + // + // Should have found something by now unless it's an include (.h) file + // + if (Sect != NULL) { + // + // Temporarily add a FILE variable to the global symbol table. Omit the + // extension. + // + sprintf (InLine, "%s%s%s", File->Drive, File->Path, File->BaseName); + AddSymbol ("FILE", InLine, SYM_OVERWRITE | SYM_LOCAL | SYM_FILENAME); + // + // Read lines, expand (except SOURCE_DIR and DEST_DIR), then dump out + // + while (DSCFileGetLine (DscFile, InLine, sizeof (InLine)) != NULL) { + ExpandSymbols ( + InLine, + OutLine, + sizeof (OutLine), + EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR + ); + fprintf (MakeFptr, OutLine); + } + fprintf (MakeFptr, "\n"); + } else { + // + // Be nice and ignore include files + // + if (!IsIncludeFile (FileName)) { + Error ( + NULL, + 0, + 0, + NULL, + "no compile commands section [%s] found in DSC file for %s", + BuildSectionName, + FileName + ); + } + } + + DSCFileRestorePosition (DscFile); + FreeFileParts (File); + } + + return STATUS_SUCCESS; +} + +/***************************************************************************** +******************************************************************************/ +static +int +SetFileExtension ( + INT8 *FileName, + INT8 *Extension + ) +{ + INT8 *Cptr; + + Cptr = FileName + strlen (FileName) - 1; + while ((Cptr > FileName) && (*Cptr != '.')) { + Cptr--; + + } + // + // Better be a dot + // + if (*Cptr != '.') { + Message (2, "Missing filename extension: %s", FileName); + return STATUS_WARNING; + } + + Cptr++; + if (*Extension == '.') { + Extension++; + } + + strcpy (Cptr, Extension); + return STATUS_SUCCESS; +} + +/***************************************************************************** +******************************************************************************/ +int +MakeFilePath ( + INT8 *FileName + ) +{ + INT8 *Cptr; + INT8 SavedChar; + INT8 BuildDir[MAX_PATH]; + INT8 CopyFileName[MAX_PATH]; + + // + // Expand symbols in the filename + // + if (ExpandSymbols (FileName, CopyFileName, sizeof (CopyFileName), EXPANDMODE_NO_UNDEFS)) { + Error (NULL, 0, 0, NULL, "undefined symbols in file path: %s", FileName); + return STATUS_ERROR; + } + // + // Copy it back + // + strcpy (FileName, CopyFileName); + // + // To avoid creating $(BUILD_DIR) path, see if this path is the same as + // $(BUILD_DIR), and if it is, see if build dir exists and skip over that + // portion if it does + // + Cptr = GetSymbolValue (BUILD_DIR); + if (Cptr != NULL) { + if (_strnicmp (Cptr, FileName, strlen (Cptr)) == 0) { + // + // BUILD_DIR path. See if it exists + // + strcpy (BuildDir, FileName); + BuildDir[strlen (Cptr)] = 0; + if ((_mkdir (BuildDir) != 0) && (errno != EEXIST)) { + Cptr = FileName; + } else { + // + // Already done. Shortcut. Skip to next path so that we don't create + // the BUILD_DIR as well. + // + Cptr = FileName + strlen (Cptr); + if (*Cptr == '\\') { + Cptr++; + } + } + } else { + // + // Not build dir + // + Cptr = FileName; + } + } else { + Cptr = FileName; + } + // + // Create directories until done. Skip over "c:\" in the path if it exists + // + if (*Cptr && (*(Cptr + 1) == ':') && (*(Cptr + 2) == '\\')) { + Cptr += 3; + } + + for (;;) { + for (; *Cptr && (*Cptr != '/') && (*Cptr != '\\'); Cptr++) + ; + if (*Cptr) { + SavedChar = *Cptr; + *Cptr = 0; + if ((_mkdir (FileName) != 0)) { + // + // Error (NULL, 0, 0, FileName, "failed to create directory"); + // return 1; + // + } + + *Cptr = SavedChar; + Cptr++; + } else { + break; + } + } + + return STATUS_SUCCESS; +} + +/***************************************************************************** +******************************************************************************/ +int +ExpandSymbols ( + INT8 *SourceLine, + INT8 *DestLine, + int LineLen, + int ExpandMode + ) +{ + static int NestDepth = 0; + INT8 *FromPtr; + INT8 *ToPtr; + INT8 *SaveStart; + INT8 *Cptr; + INT8 *value; + int Expanded; + int ExpandedCount; + INT8 *LocalDestLine; + STATUS Status; + int LocalLineLen; + + NestDepth++; + Status = STATUS_SUCCESS; + LocalDestLine = (INT8 *) malloc (LineLen); + if (LocalDestLine == NULL) { + Error (__FILE__, __LINE__, 0, "application error", "memory allocation failed"); + NestDepth = 0; + return STATUS_ERROR; + } + + FromPtr = SourceLine; + ToPtr = LocalDestLine; + // + // Walk the entire line, replacing $(SYMBOL_NAME). + // + LocalLineLen = LineLen; + ExpandedCount = 0; + while (*FromPtr && (LocalLineLen > 0)) { + if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) { + // + // Save the start in case it's undefined, in which case we copy it as-is. + // + SaveStart = FromPtr; + Expanded = 0; + // + // Symbol expansion time. Find the end (no spaces allowed) + // + FromPtr += 2; + for (Cptr = FromPtr; *Cptr && (*Cptr != ')'); Cptr++) + ; + if (*Cptr) { + // + // Truncate the string at the closing parenthesis for ease-of-use. + // Then copy the string directly to the destination line in case we don't find + // a definition for it. + // + *Cptr = 0; + strcpy (ToPtr, SaveStart); + if ((_stricmp (SOURCE_DIR, FromPtr) == 0) && (ExpandMode & EXPANDMODE_NO_SOURCEDIR)) { + // + // excluded this expansion + // + } else if ((_stricmp (DEST_DIR, FromPtr) == 0) && (ExpandMode & EXPANDMODE_NO_DESTDIR)) { + // + // excluded this expansion + // + } else if ((value = GetSymbolValue (FromPtr)) != NULL) { + strcpy (ToPtr, value); + LocalLineLen -= strlen (value); + ToPtr += strlen (value); + Expanded = 1; + ExpandedCount++; + } else if (ExpandMode & EXPANDMODE_NO_UNDEFS) { + Error (NULL, 0, 0, "undefined symbol", "$(%s)", FromPtr); + Status = STATUS_ERROR; + goto Done; + } + + // + // Restore closing parenthesis, and advance to next character + // + *Cptr = ')'; + if (!Expanded) { + FromPtr = SaveStart + 1; + ToPtr++; + } else { + FromPtr = Cptr + 1; + } + } else { + Error (NULL, 0, 0, SourceLine, "missing closing parenthesis on symbol"); + strcpy (ToPtr, FromPtr); + Status = STATUS_WARNING; + goto Done; + } + } else { + *ToPtr = *FromPtr; + FromPtr++; + ToPtr++; + LocalLineLen--; + } + } + + if (*FromPtr == 0) { + *ToPtr = 0; + } + + // + // If we're in recursive mode, and we expanded at least one string successfully, + // then make a recursive call to try again. + // + if ((ExpandedCount != 0) && (Status == STATUS_SUCCESS) && (ExpandMode & EXPANDMODE_RECURSIVE) && (NestDepth < 2)) { + Status = ExpandSymbols (LocalDestLine, DestLine, LineLen, ExpandMode); + free (LocalDestLine); + NestDepth = 0; + return Status; + } + +Done: + if (Status != STATUS_ERROR) { + strcpy (DestLine, LocalDestLine); + } + + NestDepth = 0; + free (LocalDestLine); + return Status; +} + +INT8 * +GetSymbolValue ( + INT8 *SymbolName + ) +/*++ + +Routine Description: + + Look up a symbol in our symbol table. + +Arguments: + + SymbolName - The name of symbol. + +Returns: + + Pointer to the value of the symbol if found + NULL if the symbol is not found + +--*/ +{ + SYMBOL *Symbol; + + // + // Scan once for file-level symbols + // + Symbol = gGlobals.Symbol; + while (Symbol) { + if ((_stricmp (SymbolName, Symbol->Name) == 0) && (Symbol->Type & SYM_FILE)) { + return Symbol->Value; + } + + Symbol = Symbol->Next; + } + // + // Scan once for local symbols + // + Symbol = gGlobals.Symbol; + while (Symbol) { + if ((_stricmp (SymbolName, Symbol->Name) == 0) && (Symbol->Type & SYM_LOCAL)) { + return Symbol->Value; + } + + Symbol = Symbol->Next; + } + // + // No local value found. Scan for globals. + // + Symbol = gGlobals.Symbol; + while (Symbol) { + if ((_stricmp (SymbolName, Symbol->Name) == 0) && (Symbol->Type & SYM_GLOBAL)) { + return Symbol->Value; + } + + Symbol = Symbol->Next; + } + // + // For backwards-compatibility, if it's "GUID", return FILE_GUID value + // + if (_stricmp (SymbolName, GUID) == 0) { + return GetSymbolValue (FILE_GUID); + } + + return NULL; +} + +static +int +RemoveLocalSymbols ( + VOID + ) +/*++ + +Routine Description: + + Remove all local symbols from the symbol table. Local symbols are those + that are defined typically by the component's INF file. + +Arguments: + + None. + +Returns: + + Right now, never fails. + +--*/ +{ + SYMBOL *Sym; + int FoundOne; + + do { + FoundOne = 0; + Sym = gGlobals.Symbol; + while (Sym) { + if (Sym->Type & SYM_LOCAL) { + // + // Going to delete it out from under ourselves, so break and restart + // + FoundOne = 1; + RemoveSymbol (Sym->Name, SYM_LOCAL); + break; + } + + Sym = Sym->Next; + } + } while (FoundOne); + return STATUS_SUCCESS; +} + +static +int +RemoveFileSymbols ( + VOID + ) +/*++ + +Routine Description: + + Remove all file-level symbols from the symbol table. File-level symbols are + those that are defined on a source file line in an INF file. + +Arguments: + + None. + +Returns: + + Right now, never fails. + +--*/ +{ + SYMBOL *Sym; + int FoundOne; + + do { + FoundOne = 0; + Sym = gGlobals.Symbol; + while (Sym) { + if (Sym->Type & SYM_FILE) { + // + // Going to delete it out from under ourselves, so break and restart + // + FoundOne = 1; + RemoveSymbol (Sym->Name, SYM_FILE); + break; + } + + Sym = Sym->Next; + } + } while (FoundOne); + return STATUS_SUCCESS; +} + +static +STATUS +ParseGuidDatabaseFile ( + INT8 *FileName + ) +/*++ + +Routine Description: + This function parses a GUID-to-basename text file (perhaps output by + the GuidChk utility) to define additional symbols. The format of the + file should be: + + 7BB28B99-61BB-11D5-9A5D-0090273FC14D EFI_DEFAULT_BMP_LOGO_GUID gEfiDefaultBmpLogoGuid + + This function parses the line and defines global symbol: + + EFI_DEFAULT_BMP_LOGO_GUID=7BB28B99-61BB-11D5-9A5D-0090273FC14D + + This symbol (rather than the actual GUID) can then be used in INF files to + fix duplicate GUIDs + +Arguments: + FileName - the name of the file to parse. + +Returns: + STATUS_ERROR - could not open FileName + STATUS_SUCCESS - we opened the file + +--*/ +{ + FILE *Fptr; + INT8 Line[100]; + INT8 Guid[100]; + INT8 DefineName[80]; + + Fptr = fopen (FileName, "r"); + if (Fptr == NULL) { + Error (NULL, 0, 0, FileName, "failed to open input GUID database input file"); + return STATUS_ERROR; + } + + while (fgets (Line, sizeof (Line), Fptr) != NULL) { + // + // Get the GUID string, skip the defined name (EFI_XXX_GUID), and get the + // variable name (gWhateverProtocolGuid) + // + if (sscanf (Line, "%s %s %*s", Guid, DefineName) == 2) { + AddSymbol (DefineName, Guid, SYM_GLOBAL); + } + } + + fclose (Fptr); + return STATUS_SUCCESS; +} + +/***************************************************************************** + + Returns: + 0 if successful standard add + length of the parsed string if passed in " name = value " + < 0 on error + +******************************************************************************/ +int +AddSymbol ( + INT8 *Name, + INT8 *Value, + int Mode + ) +{ + SYMBOL *Symbol; + SYMBOL *NewSymbol; + int Len; + INT8 *Start; + INT8 *Cptr; + INT8 CSave1; + INT8 *SaveCptr1; + INT8 CSave2; + INT8 *SaveCptr2; + INT8 ShortName[MAX_PATH]; + + Len = 0; + SaveCptr1 = NULL; + CSave1 = 0; + SaveCptr2 = NULL; + CSave2 = 0; + + ShortName[0] = 0; + // + // Mode better be local or global symbol + // + if ((Mode & (SYM_LOCAL | SYM_GLOBAL | SYM_FILE)) == 0) { + Error (NULL, 0, 0, "APP ERROR", "adding symbol '%s' that is not local, global, nor file level", Name); + return -1; + } + // + // If value pointer is null, then they passed us a line something like: + // varname = value, or simply var = + // + if (Value == NULL) { + Start = Name; + while (*Name && isspace (*Name)) { + Name++; + + } + + if (!*Name) { + return -1; + } + // + // Find the end of the name. Either space or a '='. + // + for (Value = Name; *Value && !isspace (*Value) && (*Value != '='); Value++) + ; + if (!*Value) { + return -1; + } + // + // Look for the '=' + // + Cptr = Value; + while (*Value && (*Value != '=')) { + Value++; + } + + if (!*Value) { + return -1; + } + + // + // Now truncate the name + // + CSave1 = *Cptr; + SaveCptr1 = Cptr; + *Cptr = 0; + + // + // Skip over the = and then any spaces + // + Value++; + while (*Value && isspace (*Value)) { + Value++; + + } + // + // Find end of string, checking for quoted string + // + if (*Value == '\"') { + Value++; + for (Cptr = Value; *Cptr && *Cptr != '\"'; Cptr++) + ; + } else { + for (Cptr = Value; *Cptr && !isspace (*Cptr); Cptr++) + ; + } + // + // Null terminate the value string + // + if (*Cptr) { + Len = (int) (Cptr - Start) + 1; + CSave2 = *Cptr; + SaveCptr2 = Cptr; + *Cptr = 0; + } else { + Len = (int) (Cptr - Start); + } + } + + // + // If file name or file path, and we're shortening, then print it + // + if ((Mode & (SYM_FILEPATH | SYM_FILENAME)) && (GetSymbolValue (SHORT_NAMES) != NULL)) { + if (GetShortPathName (Value, ShortName, sizeof (ShortName)) > 0) { + // + // fprintf (stdout, "String value '%s' shortened to '%s'\n", + // Value, ShortName); + // + Value = ShortName; + } else { + // + // fprintf (stdout, "WARNING: Failed to get short name for %s\n", Value); + // + } + } + // + // We now have a symbol name and a value. Look for an existing variable of + // the same type (global or local) and overwrite it. + // + Symbol = gGlobals.Symbol; + while (Symbol) { + // + // Check for symbol name match + // + if (_stricmp (Name, Symbol->Name) == 0) { + // + // See if this symbol is of the same type (global or local) as what + // they're requesting + // + if ((Symbol->Type & (SYM_LOCAL | SYM_GLOBAL)) == (Mode & (SYM_LOCAL | SYM_GLOBAL))) { + // + // Did they say we could overwrite it? + // + if (Mode & SYM_OVERWRITE) { + free (Symbol->Value); + Symbol->Value = (INT8 *) malloc (strlen (Value) + 1); + if (Symbol->Value == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return -1; + } + + strcpy (Symbol->Value, Value); + // + // If value == "NULL", then make it a 0-length string + // + if (_stricmp (Symbol->Value, "NULL") == 0) { + Symbol->Value[0] = 0; + } + + return Len; + } else { + return STATUS_ERROR; + } + } + } + + Symbol = Symbol->Next; + } + // + // Does not exist, create a new one + // + NewSymbol = (SYMBOL *) malloc (sizeof (SYMBOL)); + if (NewSymbol == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return -1; + } + + memset ((INT8 *) NewSymbol, 0, sizeof (SYMBOL)); + NewSymbol->Name = (INT8 *) malloc (strlen (Name) + 1); + NewSymbol->Value = (INT8 *) malloc (strlen (Value) + 1); + // + // Simply use the mode bits as the type. + // + NewSymbol->Type = Mode; + if ((NewSymbol->Name == NULL) || (NewSymbol->Value == NULL)) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return -1; + } + + strcpy (NewSymbol->Name, Name); + strcpy (NewSymbol->Value, Value); + // + // Remove trailing spaces + // + Cptr = NewSymbol->Value + strlen (NewSymbol->Value) - 1; + while (Cptr > NewSymbol->Value) { + if (isspace (*Cptr)) { + *Cptr = 0; + Cptr--; + } else { + break; + } + } + // + // Add it to the head of the list. + // + NewSymbol->Next = gGlobals.Symbol; + gGlobals.Symbol = NewSymbol; + // + // If value == "NULL", then make it a 0-length string + // + if (_stricmp (NewSymbol->Value, "NULL") == 0) { + NewSymbol->Value[0] = 0; + } + // + // Restore the terminator we inserted if they passed in var=value + // + if (SaveCptr1 != NULL) { + *SaveCptr1 = CSave1; + } + if (SaveCptr2 != NULL) { + *SaveCptr2 = CSave2; + } + + return Len; +} + +/***************************************************************************** +******************************************************************************/ +static +int +RemoveSymbol ( + INT8 *Name, + INT8 SymbolType + ) +{ + SYMBOL *Symbol; + SYMBOL *PrevSymbol; + + PrevSymbol = NULL; + Symbol = gGlobals.Symbol; + while (Symbol) { + if ((_stricmp (Name, Symbol->Name) == 0) && (Symbol->Type & SymbolType)) { + if (Symbol->Value) { + free (Symbol->Value); + } + + free (Symbol->Name); + if (PrevSymbol) { + PrevSymbol->Next = Symbol->Next; + } else { + gGlobals.Symbol = Symbol->Next; + } + + free (Symbol); + return STATUS_SUCCESS; + } + + PrevSymbol = Symbol; + Symbol = Symbol->Next; + } + + return STATUS_WARNING; +} + +#if 0 + +/***************************************************************************** +******************************************************************************/ +static +void +FreeSections ( + SECTION *Sect + ) +{ + SECTION *Next; + + while (Sect != NULL) { + Next = Sect->Next; + if (Sect->Name != NULL) { + delete[] Sect->Name; + } + + delete Sect; + Sect = Next; + } +} +#endif + +/***************************************************************************** +******************************************************************************/ +static +INT8 * +StripLine ( + INT8 *Line + ) +{ + INT8 *Cptr; + int Len; + + Cptr = Line; + // + // Look for '#' comments in first character of line + // + if (*Cptr == '#') { + *Cptr = 0; + return Cptr; + } + + while (isspace (*Cptr)) { + Cptr++; + } + // + // Hack off newlines + // + Len = strlen (Cptr); + if ((Len > 0) && (Cptr[Len - 1] == '\n')) { + Cptr[Len - 1] = 0; + } + // + // Hack off trailing spaces + // + StripTrailingSpaces (Cptr); + return Cptr; +} + +/***************************************************************************** + FUNCTION: ProcessOptions() + + DESCRIPTION: Process the command-line options. +******************************************************************************/ +static +int +ProcessOptions ( + int Argc, + INT8 *Argv[] + ) +/*++ + +Routine Description: + + Process the command line options to this utility. + +Arguments: + + Argc - Standard Argc. + Argv[] - Standard Argv. + +Returns: + +--*/ +{ + INT8 *Cptr; + int FreeCwd; + + // + // Clear out the options + // + memset ((INT8 *) &gGlobals, 0, sizeof (gGlobals)); + + Argc--; + Argv++; + + if (Argc == 0) { + Usage (); + return STATUS_ERROR; + } + // + // Now process the arguments + // + while (Argc > 0) { + + if ((Argv[0][0] == '-') || (Argv[0][0] == '/')) { + switch (Argv[0][1]) { + // + // -? or -h help option + // + case '?': + case 'h': + case 'H': + Usage (); + return STATUS_ERROR; + + // + // /d symbol=name + // + case 'd': + case 'D': + // + // Skip to next arg + // + Argc--; + Argv++; + if (Argc == 0) { + Argv--; + Error (NULL, 0, 0, NULL, "missing symbol definition with %c%c", Argv[0][0], Argv[0][1]); + return STATUS_ERROR; + } else { + if (AddSymbol (Argv[0], NULL, SYM_OVERWRITE | SYM_GLOBAL) <= 0) { + Warning (NULL, 0, 0, Argv[0], "failed to add symbol: %s"); + } + } + break; + + // + // output makefile name + // + case 'm': + case 'M': + // + // Skip to next arg + // + Argc--; + Argv++; + if (Argc == 0) { + Argv--; + Error (NULL, 0, 0, Argv[0], "missing output makefile name with option"); + Usage (); + return STATUS_ERROR; + } else { + strcpy (gGlobals.MakefileName, Argv[0]); + } + break; + + // + // Print a cross-reference file containing guid/basename/processor + // + case 'x': + case 'X': + // + // Skip to next arg + // + Argc--; + Argv++; + if (Argc == 0) { + Argv--; + Error (NULL, 0, 0, Argv[0], "missing cross-reference output filename with option"); + Usage (); + return STATUS_ERROR; + } else { + strcpy (gGlobals.XRefFileName, Argv[0]); + } + break; + + // + // GUID database file to preparse + // + case 'g': + case 'G': + // + // Skip to next arg + // + Argc--; + Argv++; + if (Argc == 0) { + Argv--; + Error (NULL, 0, 0, Argv[0], "missing input GUID database filename with option"); + Usage (); + return STATUS_ERROR; + } else { + strcpy (gGlobals.GuidDatabaseFileName, Argv[0]); + } + break; + + case 'v': + case 'V': + gGlobals.Verbose = 1; + break; + + default: + Error (NULL, 0, 0, Argv[0], "unrecognized option"); + return STATUS_ERROR; + } + } else { + break; + } + + Argc--; + Argv++; + } + // + // Must be at least one arg left + // + if (Argc > 0) { + gGlobals.DscFilename = Argv[0]; + } + + if (gGlobals.DscFilename == NULL) { + Error (NULL, 0, 0, NULL, "must specify DSC filename on command line"); + return STATUS_ERROR; + } + // + // Make a global symbol for the DSC filename + // + AddSymbol (DSC_FILENAME, gGlobals.DscFilename, SYM_GLOBAL | SYM_FILENAME); + // + // If no output makefile specified, take the default + // + if (gGlobals.MakefileName[0] == 0) { + strcpy (gGlobals.MakefileName, MAKEFILE_OUT_NAME); + } + // + // Get the current working directory and use it for the build directory. + // Only do this if they have not defined it on the command line. Do the + // same for the bin dir, output dir, and library directory. + // + Cptr = GetSymbolValue (BUILD_DIR); + if (Cptr == NULL) { + Cptr = _getcwd (NULL, 0); + FreeCwd = 1; + AddSymbol (BUILD_DIR, Cptr, SYM_OVERWRITE | SYM_GLOBAL | SYM_FILEPATH); + } else { + FreeCwd = 0; + } + + if (FreeCwd) { + free (Cptr); + } + + return 0; +} + +/***************************************************************************** +******************************************************************************/ +static +SYMBOL * +FreeSymbols ( + SYMBOL *Syms + ) +{ + SYMBOL *Next; + while (Syms) { + + if (Syms->Name != NULL) { + free (Syms->Name); + } + + if (Syms->Value != NULL) { + free (Syms->Value); + } + + Next = Syms->Next; + free (Syms); + Syms = Next; + } + + return Syms; +} + +/***************************************************************************** +******************************************************************************/ +static +int +GetSourceFileType ( + INT8 *FileName + ) +{ + INT8 *Cptr; + int len; + int i; + + len = strlen (FileName); + if (len == 0) { + return FILETYPE_UNKNOWN; + + } + + Cptr = FileName + len - 1; + while ((*Cptr != '.') && (Cptr >= FileName)) { + Cptr--; + + } + + if (*Cptr == '.') { + + for (i = 0; mFileTypes[i].Extension != NULL; i++) { + len = strlen (mFileTypes[i].Extension); + if (_strnicmp (mFileTypes[i].Extension, Cptr, len) == 0) { + if ((*(Cptr + len) == 0) || isspace (*(Cptr + len))) { + return mFileTypes[i].FileType; + } + } + } + } + + return FILETYPE_UNKNOWN; +} +// +// Determine if a given file is a standard include file. If we don't know, +// then assume it's not. +// +static +int +IsIncludeFile ( + INT8 *FileName + ) +{ + INT8 *Cptr; + int len; + int i; + + len = strlen (FileName); + if (len == 0) { + return 0; + } + + Cptr = FileName + len - 1; + while ((*Cptr != '.') && (Cptr >= FileName)) { + Cptr--; + } + + if (*Cptr == '.') { + // + // Now go through the list of filename extensions and try to find + // a match for this file extension. + // + for (i = 0; mFileTypes[i].Extension != NULL; i++) { + len = strlen (mFileTypes[i].Extension); + if (_strnicmp (mFileTypes[i].Extension, Cptr, len) == 0) { + // + // Make sure that's all there is to the filename extension. + // + if ((*(Cptr + len) == 0) || isspace (*(Cptr + len))) { + return mFileTypes[i].FileFlags & FILE_FLAG_INCLUDE; + } + } + } + } + + return 0; +} + +/***************************************************************************** +******************************************************************************/ +static +void +StripTrailingSpaces ( + INT8 *Str + ) +{ + INT8 *Cptr; + Cptr = Str + strlen (Str) - 1; + while (Cptr > Str) { + if (isspace (*Cptr)) { + *Cptr = 0; + Cptr--; + } else { + break; + } + } +} + +/***************************************************************************** +******************************************************************************/ +static +int +GetEfiSource ( + VOID + ) +{ + INT8 *EfiSource; + + // + // Don't set it if the user specified it on the command line. + // + EfiSource = GetSymbolValue (EFI_SOURCE); + if ( EfiSource != NULL) { + if (EfiSource[strlen (EfiSource) - 1] == '\\') { + EfiSource[strlen (EfiSource) - 1] = 0; + } + return STATUS_SUCCESS; + } + + // + // Get the environmental variable setting of EFI_SOURCE. + // + EfiSource = getenv (EFI_SOURCE); + if (EfiSource != NULL) { + if (EfiSource[strlen (EfiSource) - 1] == '\\') { + EfiSource[strlen (EfiSource) - 1] = 0; + } + AddSymbol (EFI_SOURCE, EfiSource, SYM_GLOBAL | SYM_FILEPATH); + return STATUS_SUCCESS; + } + + Error (NULL, 0, 0, NULL, "could not determine EFI_SOURCE"); + return STATUS_ERROR; +} + +void +Message ( + UINT32 PrintMask, + INT8 *Fmt, + ... + ) +{ + INT8 Line[MAX_LINE_LEN]; + va_list List; + + va_start (List, Fmt); + vsprintf (Line, Fmt, List); + if (PrintMask & gGlobals.Verbose) { + fprintf (stdout, "%s\n", Line); + } + + va_end (List); +} + +static +void +Usage ( + VOID + ) +{ + int i; + static const INT8 *Help[] = { + "Usage: ProcessDsc {options} [Dsc Filename]", + " Options:", + " -d var=value to define symbol 'var' to 'value'", + " -v for verbose mode", + " -g filename to preparse GUID listing file", + " -x filename to create a cross-reference file", + NULL + }; + for (i = 0; Help[i] != NULL; i++) { + fprintf (stdout, "%s\n", Help[i]); + } +} + +/*++ + +Routine Description: + + Process the [defines] section in the DSC file. + +Arguments: + + DscFile - pointer to the DSCFile class that contains the relevant info. + +Returns: + + 0 if not necessarily an absolute path + 1 otherwise + +--*/ +static +int +ProcessDSCDefinesSection ( + DSC_FILE *DscFile + ) +{ + INT8 Line[MAX_LINE_LEN]; + INT8 Line2[MAX_EXP_LINE_LEN]; + INT8 *Cptr; + SECTION *Sect; + + // + // Look for a [defines] section and process it + // + Sect = DSCFileFindSection (DscFile, DEFINES_SECTION_NAME); + if (Sect == NULL) { + return STATUS_ERROR; + } + // + // Read lines while they're valid + // + while (DSCFileGetLine (DscFile, Line, sizeof (Line)) != NULL) { + // + // Expand symbols on the line + // + if (ExpandSymbols (Line, Line2, sizeof (Line2), 0)) { + return STATUS_ERROR; + } + // + // Strip the line + // + Cptr = StripLine (Line2); + if (*Cptr) { + // + // Make the assignment + // + AddSymbol (Line2, NULL, SYM_OVERWRITE | SYM_GLOBAL); + } + } + + return STATUS_SUCCESS; +} + +int +IsAbsolutePath ( + char *FileName + ) +/*++ + +Routine Description: + + Determine if a given filename contains the full path information. + +Arguments: + + FileName - the name of the file, with symbol expanded. + +Returns: + + 0 if not necessarily an absolute path + 1 otherwise + +--*/ +{ + // + // If the first character is a-z, and the second character is a colon, then + // it is an absolute path. + // + if (isalpha (FileName[0]) && (FileName[1] == ':')) { + return 1; + } + + return 0; +} + +SMART_FILE * +SmartOpen ( + char *FileName + ) +{ + SMART_FILE *SmartFile; + FILE *Fptr; + int FileSize; + + SmartFile = malloc (sizeof (SMART_FILE)); + if (SmartFile == NULL) { + return NULL; + } + memset (SmartFile, 0, sizeof (SMART_FILE)); + + SmartFile->FileName = malloc (strlen (FileName) + 1); + if (SmartFile->FileName == NULL){ + SmartFree (SmartFile); + return NULL; + } + strcpy (SmartFile->FileName, FileName); + + if ((Fptr = fopen (FileName, "r")) != NULL) { + fseek (Fptr, 0, SEEK_END); + FileSize = ftell (Fptr); + fseek (Fptr, 0, SEEK_SET); + SmartFile->FileContent = malloc (FileSize + 1); + if (SmartFile->FileContent != NULL) { + memset (SmartFile->FileContent, 0, FileSize + 1); + // + // Usually FileLength < FileSize, because in text mode, carriage return¨Clinefeed + // combinations are translated into single linefeeds on input + // + SmartFile->FileLength = fread (SmartFile->FileContent, sizeof(char), FileSize, Fptr); + } + fclose (Fptr); + } + + // + // No previous output file content, re-create the file + // + if (SmartFile->FileContent == NULL) { + if ((SmartFile->FilePtr = fopen (FileName, "w")) == NULL) { + SmartFree (SmartFile); + return NULL; + } + } + + return SmartFile; +} + +int +SmartWrite ( + SMART_FILE *SmartFile, + char *String + ) +{ + int StrLen; + + if (SmartFile->FilePtr != NULL) { + return fprintf (SmartFile->FilePtr, "%s", String); + } else { + StrLen = strlen (String); + if ((StrLen > SmartFile->FileLength - SmartFile->FilePosition) || + (_strnicmp (&SmartFile->FileContent[SmartFile->FilePosition], String, StrLen) != 0)) { + // + // file changed, need to re-create. + // + if ((SmartFile->FilePtr = fopen (SmartFile->FileName, "w")) == NULL) { + Error (NULL, 0, 0, SmartFile->FileName, "could not open file for writing when SmartWrite"); + return -1; + } else { + SmartFile->FileContent[SmartFile->FilePosition] = 0; + fprintf (SmartFile->FilePtr, "%s%s", SmartFile->FileContent, String); + return StrLen; + } + } else { + SmartFile->FilePosition += StrLen; + return StrLen; + } + } +} + +void +SmartClose ( + SMART_FILE *SmartFile + ) +{ + if ((SmartFile->FilePtr == NULL) && (SmartFile->FilePosition < SmartFile->FileLength)) { + // + // The new file is smaller than before, re-create it. + // + if ((SmartFile->FilePtr = fopen (SmartFile->FileName, "w")) == NULL) { + Error (NULL, 0, 0, SmartFile->FileName, "could not open file for writing when SmartClose"); + } else { + SmartFile->FileContent[SmartFile->FilePosition] = 0; + fprintf (SmartFile->FilePtr, "%s", SmartFile->FileContent); + } + } + + SmartFree(SmartFile); +} + +static +void +SmartFree ( + SMART_FILE *SmartFile + ) +{ + if (SmartFile == NULL) { + return; + } + + if (SmartFile->FileName != NULL ) { + free (SmartFile->FileName); + } + + if (SmartFile->FileContent != NULL ) { + free (SmartFile->FileContent); + } + + if (SmartFile->FilePtr != NULL ) { + fclose (SmartFile->FilePtr); + } + + free (SmartFile); + + return; +} + +static +int +AddModuleName ( + SYMBOL **SymbolList, + INT8 *ModuleName, + INT8 *InfName + ) +/*++ + +Routine Description: + + Add module name in the global module list. + For the same module names, it is only added once. + +Arguments: + SymbolList : add name into this list + ModuleName : point to one module name char string. + InfName : point to this module inf file name with path. + +Returns: + + 0 : Successfully add input name into the global list. + other value : allocate memory failed. + +--*/ +{ + SYMBOL *CurrentSymbol; + SYMBOL *LastSymbol; + + // + // Get the global module list. + // + CurrentSymbol = *SymbolList; + LastSymbol = *SymbolList; + + // + // Search whether this module name has been added into the global list. + // + while (CurrentSymbol != NULL) { + if (_stricmp (CurrentSymbol->Name, ModuleName) == 0) { + if ((CurrentSymbol->Value == NULL) && (InfName == NULL)) { + break; + } else if ((CurrentSymbol->Value != NULL) && (InfName != NULL) && \ + (_stricmp (CurrentSymbol->Value, InfName) == 0)) { + break; + } + } + LastSymbol = CurrentSymbol; + CurrentSymbol = CurrentSymbol->Next; + } + + // + // Add new module name in list. + // + if (CurrentSymbol == NULL) { + CurrentSymbol = (SYMBOL *) malloc (sizeof (SYMBOL)); + if (CurrentSymbol == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return -1; + } + memset ((INT8 *) CurrentSymbol, 0, sizeof (SYMBOL)); + + if (ModuleName != NULL) { + CurrentSymbol->Name = (INT8 *) malloc (strlen (ModuleName) + 1); + strcpy (CurrentSymbol->Name, ModuleName); + } + + if (InfName != NULL) { + CurrentSymbol->Value = (INT8 *) malloc (strlen (InfName) + 1); + strcpy (CurrentSymbol->Value, InfName); + } + + if (LastSymbol == NULL) { + *SymbolList = CurrentSymbol; + } else { + LastSymbol->Next = CurrentSymbol; + } + } + + return 0; +} + -- cgit v1.2.3