diff options
author | qwang12 <qwang12@6f19259b-4bc3-4df7-8a09-765794883524> | 2007-06-28 07:00:39 +0000 |
---|---|---|
committer | qwang12 <qwang12@6f19259b-4bc3-4df7-8a09-765794883524> | 2007-06-28 07:00:39 +0000 |
commit | 3eb9473ea9a949badfe06ae61d2d3fcfa53651c7 (patch) | |
tree | e9d8c368dbb1e58794b2c00acefe4bbad270f8c4 /EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc | |
parent | 30d4a0c7ec19938196b1308006b990e0945150da (diff) | |
download | edk2-platforms-3eb9473ea9a949badfe06ae61d2d3fcfa53651c7.tar.xz |
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
Diffstat (limited to 'EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc')
9 files changed, 7434 insertions, 0 deletions
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 <stdio.h> // for file ops
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h> // 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h> // 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 <windows.h> // for max_path definition
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h> // 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 <windows.h> // for GetShortPathName()
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <direct.h> // for _mkdir()
+#include <errno.h>
+#include <stdlib.h> // 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).<extension>]
+ //
+ 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).<Extension>" 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;
+}
+
|