Home | History | Annotate | Download | only in ProcessDsc
      1 /*++
      2 
      3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   ProcessDsc.c
     15 
     16 Abstract:
     17 
     18   Main module for the ProcessDsc utility.
     19 
     20 --*/
     21 
     22 #include <windows.h>  // for GetShortPathName()
     23 #include <stdio.h>
     24 #include <string.h>
     25 #include <ctype.h>
     26 #include <stdarg.h>
     27 #include <direct.h>   // for _mkdir()
     28 #include <errno.h>
     29 #include <stdlib.h>   // for getenv()
     30 #include <shlwapi.h>  // for PathCanonicalize()
     31 #include "DSCFile.h"
     32 #include "MultiThread.h"
     33 #include "FWVolume.h"
     34 #include "Exceptions.h"
     35 #include "Common.h"
     36 
     37 #include "EfiUtilityMsgs.h"
     38 #include "TianoBind.h"
     39 
     40 #define UTILITY_NAME    "ProcessDsc"
     41 #define UTILITY_VERSION "v1.0"
     42 
     43 //
     44 // Common symbol name definitions. For example, the user can reference
     45 // $(BUILD_DIR) in their DSC file and we will expand it for them (usually).
     46 // I've defined the equivalents here in case we want to change the name the
     47 // user references, in which case we just change the string value here and
     48 // our code still works.
     49 //
     50 #define BUILD_DIR                       "BUILD_DIR"
     51 #define EFI_SOURCE                      "EFI_SOURCE"
     52 #define DEST_DIR                        "DEST_DIR"
     53 #define SOURCE_DIR                      "SOURCE_DIR"
     54 #define LIB_DIR                         "LIB_DIR"
     55 #define BIN_DIR                         "BIN_DIR"
     56 #define OUT_DIR                         "OUT_DIR"
     57 #define INF_FILENAME                    "INF_FILENAME"
     58 #define SOURCE_RELATIVE_PATH            "SOURCE_RELATIVE_PATH"
     59 #define SOURCE_BASE_NAME                "SOURCE_BASE_NAME"
     60 #define SOURCE_FILE_NAME                "SOURCE_FILE_NAME"    // c:\FullPath\File.c
     61 #define PROCESSOR                       "PROCESSOR"
     62 #define FV                              "FV"
     63 #define BASE_NAME                       "BASE_NAME"
     64 #define GUID                            "GUID"
     65 #define FILE_GUID                       "FILE_GUID"
     66 #define COMPONENT_TYPE_FILE             "FILE"
     67 #define BUILD_TYPE                      "BUILD_TYPE"
     68 #define FFS_EXT                         "FFS_EXT"             // FV_EXT is deprecated -- extension of FFS file
     69 #define MAKEFILE_NAME                   "MAKEFILE_NAME"       // name of component's output makefile
     70 #define PLATFORM                        "PLATFORM"            // for more granularity
     71 #define PACKAGE_FILENAME                "PACKAGE_FILENAME"
     72 #define PACKAGE                         "PACKAGE"
     73 #define PACKAGE_TAG                     "PACKAGE_TAG"         // alternate name to PACKAGE
     74 #define SHORT_NAMES                     "SHORT_NAMES"         // for 8.3 names of symbols
     75 #define APRIORI                         "APRIORI"             // to add to apriori list
     76 #define OPTIONAL_COMPONENT              "OPTIONAL"            // define as non-zero for optional INF files
     77 #define SOURCE_SELECT                   "SOURCE_SELECT"       // say SOURCE_SELECT=smm,common to select INF sources
     78 #define NONFFS_FV                       "NONFFS_FV"           // for non-FFS FV such as working & spare block FV
     79 #define SKIP_FV_NULL                    "SKIP_FV_NULL"        // define as nonzero to not build components with FV=NULL
     80 #define SOURCE_COMPILE_TYPE             "SOURCE_COMPILE_TYPE" // to build a source using a custom build section in the DSC file
     81 #define SOURCE_FILE_EXTENSION           "SOURCE_FILE_EXTENSION"
     82 #define COMPILE_SELECT                  "COMPILE_SELECT"
     83 #define SOURCE_OVERRIDE_PATH            "SOURCE_OVERRIDE_PATH"  // get source files from here first
     84 #define MAKEFILE_OUT_SECTION_NAME       "makefile.out"
     85 #define COMMON_SECTION_NAME             "common"                // shared files or functionality
     86 #define NMAKE_SECTION_NAME              "nmake"
     87 #define SOURCES_SECTION_NAME            "sources"
     88 #define COMPONENTS_SECTION_NAME         "components"
     89 #define INCLUDE_SECTION_NAME            "includes"
     90 #define DEFINES_SECTION_NAME            "defines"
     91 #define LIBRARIES_SECTION_NAME          "libraries"
     92 #define LIBRARIES_PLATFORM_SECTION_NAME "libraries.platform"
     93 #define MAKEFILE_SECTION_NAME           "makefile"
     94 #define COMPONENT_TYPE                  "component_type"
     95 #define PLATFORM_STR                    "\\platform\\"          // to determine EFI_SOURCE
     96 #define MAKEFILE_OUT_NAME               "makefile.out"          // if not specified on command line
     97 #define MODULE_MAKEFILE_NAME            "module.mak"            // record all module makefile targets
     98 #define MODULE_NAME_FILE                "module.list"           // record all module names defined in the dsc file
     99 #define GLOBAL_LINK_LIB_NAME            "CompilerStub"          // Lib added in link option, maybe removed in the future
    100 #define MODULE_BASE_NAME_WIDTH          25                      // Width for module name output
    101 
    102 //
    103 // When a symbol is defined as "NULL", it gets saved in the symbol table as a 0-length
    104 // string. Use this macro to detect if a symbol has been defined this way.
    105 //
    106 #define IS_NULL_SYMBOL_VALUE(var) ((var != NULL) && (strlen (var) == 0))
    107 
    108 //
    109 // Defines for file types
    110 //
    111 #define FILETYPE_UNKNOWN  0
    112 #define FILETYPE_C        1
    113 #define FILETYPE_ASM      2
    114 #define FILETYPE_S        3
    115 #define FILETYPE_VFR      4
    116 #define FILETYPE_INC      5
    117 #define FILETYPE_H        6
    118 #define FILETYPE_I        7
    119 
    120 
    121 typedef struct {
    122   INT8  *Extension;         // file extension
    123   INT8  *BuiltExtension;
    124   INT8  FileFlags;
    125   int   FileType;
    126 } FILETYPE;
    127 
    128 //
    129 // Define masks for the FileFlags field
    130 //
    131 #define FILE_FLAG_INCLUDE 0x01
    132 #define FILE_FLAG_SOURCE  0x02
    133 
    134 //
    135 // This table describes a from-to list of files. For
    136 // example, when a ".c" is built, it results in a ".obj" file.
    137 //
    138 static const FILETYPE mFileTypes[] = {
    139   {
    140     ".c",
    141     ".obj",
    142     FILE_FLAG_SOURCE,
    143     FILETYPE_C
    144   },
    145   {
    146     ".asm",
    147     ".obj",
    148     FILE_FLAG_SOURCE,
    149     FILETYPE_ASM
    150   },
    151   {
    152     ".s",
    153     ".obj",
    154     FILE_FLAG_SOURCE,
    155     FILETYPE_S
    156   },
    157   {
    158     ".vfr",
    159     ".obj",
    160     FILE_FLAG_SOURCE,
    161     FILETYPE_VFR
    162   },  // actually *.vfr -> *.c -> *.obj
    163   {
    164     ".h",
    165     NULL,
    166     FILE_FLAG_INCLUDE,
    167     FILETYPE_H
    168   },
    169   {
    170     ".inc",
    171     NULL,
    172     FILE_FLAG_INCLUDE,
    173     FILETYPE_INC
    174   },
    175   {
    176     ".i",
    177     NULL,
    178     FILE_FLAG_INCLUDE,
    179     FILETYPE_I
    180   },
    181   {
    182     NULL,
    183     NULL,
    184     0,
    185     0
    186   }
    187 };
    188 
    189 //
    190 // Structure to split up a file into its different parts.
    191 //
    192 typedef struct {
    193   INT8  Drive[3];
    194   INT8  *Path;
    195   INT8  *BaseName;
    196   INT8  *Extension;
    197   int   ExtensionCode;
    198 } FILE_NAME_PARTS;
    199 
    200 //
    201 // Maximum length for any line in any file after symbol expansion
    202 //
    203 #define MAX_EXP_LINE_LEN  (MAX_LINE_LEN * 2)
    204 
    205 //
    206 // Linked list to keep track of all symbols
    207 //
    208 typedef struct _SYMBOL {
    209   struct _SYMBOL  *Next;
    210   int             Type; // local or global symbol
    211   INT8            *Name;
    212   INT8            *Value;
    213 } SYMBOL;
    214 
    215 //
    216 // Module globals for multi-thread build
    217 //
    218 static BUILD_ITEM  **mCurrentBuildList;          // build list currently handling
    219 static BUILD_ITEM  *mCurrentBuildItem;           // build item currently handling
    220 
    221 //
    222 // Define masks for the build targets
    223 //
    224 #define BUILD_TARGET_COMPONENTS 0x01
    225 #define BUILD_TARGET_LIBRARIES  0x02
    226 #define BUILD_TARGET_FVS        0x04
    227 #define BUILD_TARGET_ALL        0xff
    228 
    229 
    230 //
    231 // This structure is used to save globals
    232 //
    233 struct {
    234   INT8                *DscFilename;
    235   SYMBOL              *Symbol;
    236   INT8                MakefileName[MAX_PATH]; // output makefile name
    237   INT8                XRefFileName[MAX_PATH];
    238   INT8                GuidDatabaseFileName[MAX_PATH];
    239   INT8                ModuleMakefileName[MAX_PATH];
    240   FILE                *MakefileFptr;
    241   FILE                *ModuleMakefileFptr;
    242   SYMBOL              *ModuleList;
    243   SYMBOL              *OutdirList;
    244   UINT32              Verbose;
    245   UINT32              ThreadNumber;
    246   UINT32              BuildTarget;
    247   BUILD_ITEM          *LibraryList;
    248   COMPONENTS_ITEM     *ComponentsList;
    249 } gGlobals;
    250 
    251 //
    252 // This gets dumped to the head of makefile.out
    253 //
    254 static const INT8 *MakefileHeader[] = {
    255   "#/*++",
    256   "#",
    257   "#  DO NOT EDIT",
    258   "#  File auto-generated by build utility",
    259   "#",
    260   "#  Module Name:",
    261   "#",
    262   "#    makefile",
    263   "#",
    264   "#  Abstract:",
    265   "#",
    266   "#    Auto-generated makefile for building of EFI components/libraries",
    267   "#",
    268   "#--*/",
    269   "",
    270   NULL
    271 };
    272 
    273 //
    274 // Function prototypes
    275 //
    276 static
    277 int
    278 ProcessOptions (
    279   int  Argc,
    280   INT8 *Argv[]
    281   );
    282 
    283 static
    284 void
    285 Usage (
    286   VOID
    287   );
    288 
    289 static
    290 INT8              *
    291 StripLine (
    292   INT8 *Line
    293   );
    294 
    295 static
    296 STATUS
    297 ParseGuidDatabaseFile (
    298   INT8 *FileName
    299   );
    300 
    301 #define DSC_SECTION_TYPE_COMPONENTS         0
    302 #define DSC_SECTION_TYPE_LIBRARIES          1
    303 #define DSC_SECTION_TYPE_PLATFORM_LIBRARIES 2
    304 
    305 static
    306 int
    307 ProcessSectionComponents (
    308   DSC_FILE *DscFile,
    309   int      DscSectionType,
    310   int      Instance
    311   );
    312 static
    313 int
    314 ProcessComponentFile (
    315   DSC_FILE  *DscFile,
    316   INT8      *Line,
    317   int       DscSectionType,
    318   int       Instance
    319   );
    320 static
    321 int
    322 ProcessIncludeFiles (
    323   DSC_FILE  *ComponentFile,
    324   FILE      *MakeFptr
    325   );
    326 static
    327 
    328 int
    329 ProcessIncludeFilesSingle (
    330   DSC_FILE  *ComponentFile,
    331   FILE      *MakeFptr,
    332   INT8      *SectionName
    333   );
    334 
    335 //
    336 // Mode flags for processing source files
    337 //
    338 #define SOURCE_MODE_BUILD_COMMANDS  0x01
    339 #define SOURCE_MODE_SOURCE_FILES    0x02
    340 
    341 static
    342 int
    343 ProcessSourceFiles (
    344   DSC_FILE  *DSCFile,
    345   DSC_FILE  *ComponentFile,
    346   FILE      *MakeFptr,
    347   UINT32    Mode
    348   );
    349 
    350 static
    351 int
    352 ProcessSourceFilesSection (
    353   DSC_FILE  *DSCFile,
    354   DSC_FILE  *ComponentFile,
    355   FILE      *MakeFptr,
    356   INT8      *SectionName,
    357   UINT32    Mode
    358   );
    359 
    360 static
    361 int
    362 ProcessObjects (
    363   DSC_FILE  *ComponentFile,
    364   FILE      *MakeFptr
    365   );
    366 
    367 static
    368 int
    369 ProcessObjectsSingle (
    370   DSC_FILE  *ComponentFile,
    371   FILE      *MakeFptr,
    372   INT8      *SectionName
    373   );
    374 
    375 static
    376 int
    377 ProcessLibs (
    378   DSC_FILE  *ComponentFile,
    379   FILE      *MakeFptr
    380   );
    381 
    382 static
    383 int
    384 ProcessLibsSingle (
    385   DSC_FILE  *ComponentFile,
    386   FILE      *MakeFptr,
    387   INT8      *SectionName
    388   );
    389 
    390 static
    391 int
    392 ProcessIncludesSection (
    393   DSC_FILE  *ComponentFile,
    394   FILE      *MakeFptr
    395   );
    396 
    397 static
    398 int
    399 ProcessIncludesSectionSingle (
    400   DSC_FILE  *ComponentFile,
    401   FILE      *MakeFptr,
    402   INT8      *SectionName
    403   );
    404 
    405 static
    406 int
    407 ProcessINFNMakeSection (
    408   DSC_FILE  *ComponentFile,
    409   FILE      *MakeFptr
    410   );
    411 
    412 static
    413 int
    414 ProcessINFDefinesSection (
    415   DSC_FILE  *ComponentFile
    416   );
    417 
    418 static
    419 int
    420 ProcessINFDefinesSectionSingle (
    421   DSC_FILE  *ComponentFile,
    422   INT8      *SectionName
    423   );
    424 
    425 static
    426 int
    427 ProcessSectionLibraries (
    428   DSC_FILE  *DscFile,
    429   long      Offset
    430   );
    431 
    432 static
    433 int
    434 ProcessDSCDefinesSection (
    435   DSC_FILE *DscFile
    436   );
    437 
    438 static
    439 int
    440 SetSymbolType (
    441   INT8  *SymbolName,
    442   INT8  Type
    443   );
    444 
    445 static
    446 int
    447 RemoveLocalSymbols (
    448   VOID
    449   );
    450 
    451 static
    452 int
    453 RemoveFileSymbols (
    454   VOID
    455   );
    456 
    457 static
    458 int
    459 RemoveSymbol (
    460   INT8   *Name,
    461   INT8   SymbolType
    462   );
    463 
    464 static
    465 int
    466 SetFileExtension (
    467   INT8 *FileName,
    468   INT8 *Extension
    469   );
    470 
    471 static
    472 int
    473 GetSourceFileType (
    474   INT8 *FileName
    475   );
    476 
    477 static
    478 int
    479 IsIncludeFile (
    480   INT8 *FileName
    481   );
    482 
    483 static
    484 int
    485 WriteCompileCommands (
    486   DSC_FILE *DscFile,
    487   FILE     *MakeFptr,
    488   INT8     *FileName,
    489   INT8     *Processor
    490   );
    491 
    492 static
    493 int
    494 WriteCommonMakefile (
    495   DSC_FILE *DscFile,
    496   FILE     *MakeFptr,
    497   INT8     *Processor
    498   );
    499 
    500 static
    501 int
    502 WriteComponentTypeBuildCommands (
    503   DSC_FILE *DscFile,
    504   FILE     *MakeFptr,
    505   INT8     *SectionName
    506   );
    507 
    508 static
    509 void
    510 StripTrailingSpaces (
    511   INT8 *Str
    512   );
    513 
    514 static
    515 void
    516 FreeFileParts (
    517   FILE_NAME_PARTS *FP
    518   );
    519 
    520 static
    521 FILE_NAME_PARTS   *
    522 GetFileParts (
    523   INT8 *FileName
    524   );
    525 
    526 static
    527 SYMBOL            *
    528 FreeSymbols (
    529   SYMBOL *Syms
    530   );
    531 
    532 static
    533 int
    534 GetEfiSource (
    535   VOID
    536   );
    537 
    538 static
    539 int
    540 CreatePackageFile (
    541   DSC_FILE          *DSCFile
    542   );
    543 
    544 static
    545 INT8              *
    546 BuiltFileExtension (
    547   INT8      *SourceFileName
    548   );
    549 
    550 static
    551 void
    552 SmartFree (
    553   SMART_FILE  *SmartFile
    554   );
    555 
    556 static
    557 int
    558 AddModuleName (
    559   SYMBOL  **SymbolList,
    560   INT8    *ModuleName,
    561   INT8    *InfName
    562   );
    563 
    564 static
    565 void
    566 ReplaceSlash (
    567   INT8    *Path
    568   );
    569 
    570 /*****************************************************************************/
    571 int
    572 main (
    573   int   Argc,
    574   INT8  *Argv[]
    575   )
    576 /*++
    577 
    578 Routine Description:
    579 
    580   Main utility entry point.
    581 
    582 Arguments:
    583 
    584   Argc - Standard app entry point args.
    585   Argv - Standard app entry point args.
    586 
    587 Returns:
    588 
    589   0  if successful
    590   non-zero otherwise
    591 
    592 --*/
    593 {
    594   int                   i;
    595   DSC_FILE              DSCFile;
    596   SECTION               *Sect;
    597   INT8                  Line[MAX_LINE_LEN];
    598   INT8                  ExpLine[MAX_LINE_LEN];
    599   INT8                  *BuildDir;
    600   INT8                  *EMsg;
    601   FILE                  *FpModule;
    602   SYMBOL                *TempSymbol;
    603   COMPONENTS_ITEM       *TempComponents;
    604 
    605   SetUtilityName (UTILITY_NAME);
    606 
    607   InitExceptions ();
    608 
    609   DSCFileInit (&DSCFile);
    610   //
    611   // Initialize the firmware volume data
    612   //
    613   CFVConstructor ();
    614   //
    615   // Exception handling for this block of code.
    616   //
    617   TryException ();
    618   //
    619   // Process command-line options.
    620   //
    621   if (ProcessOptions (Argc, Argv)) {
    622     EMsg = CatchException ();
    623     if (EMsg != NULL) {
    624       fprintf (stderr, "%s\n", EMsg);
    625     }
    626 
    627     return STATUS_ERROR;
    628   }
    629   //
    630   // Parse the GUID database file if specified
    631   //
    632   if (gGlobals.GuidDatabaseFileName[0] != 0) {
    633     ParseGuidDatabaseFile (gGlobals.GuidDatabaseFileName);
    634   }
    635   //
    636   // Set the output cross-reference file if applicable
    637   //
    638   if (gGlobals.XRefFileName[0]) {
    639     CFVSetXRefFileName (gGlobals.XRefFileName);
    640   }
    641 
    642   //
    643   // Now get the EFI_SOURCE directory which we use everywhere.
    644   //
    645   if (GetEfiSource ()) {
    646     return STATUS_ERROR;
    647   }
    648 
    649   //
    650   // Pre-process the DSC file to get section info.
    651   //
    652   if (DSCFileSetFile (&DSCFile, gGlobals.DscFilename) != 0) {
    653     goto ProcessingError;
    654   }
    655 
    656   //
    657   // Set output makefile name for single module build
    658   //
    659   strcpy (gGlobals.ModuleMakefileName, MODULE_MAKEFILE_NAME);
    660 
    661   //
    662   // Try to open all final output makefiles
    663   //
    664   if ((gGlobals.MakefileFptr = fopen (gGlobals.MakefileName, "w")) == NULL) {
    665     Error (NULL, 0, 0, gGlobals.MakefileName, "failed to open output makefile for writing");
    666     goto ProcessingError;
    667   }
    668   if ((gGlobals.ModuleMakefileFptr = fopen (gGlobals.ModuleMakefileName, "w")) == NULL) {
    669     Error (NULL, 0, 0, gGlobals.ModuleMakefileName, "failed to open output makefile for writing");
    670     goto ProcessingError;
    671   }
    672 
    673   //
    674   // Write the header out to the makefiles
    675   //
    676   for (i = 0; MakefileHeader[i] != NULL; i++) {
    677     fprintf (gGlobals.MakefileFptr, "%s\n", MakefileHeader[i]);
    678     fprintf (gGlobals.ModuleMakefileFptr, "%s\n", MakefileHeader[i]);
    679   }
    680 
    681   //
    682   // Init global potint = NULL
    683   //
    684   gGlobals.ModuleList = NULL;
    685   gGlobals.OutdirList = NULL;
    686 
    687   //
    688   // Process the [defines] section in the DSC file to get any defines we need
    689   // elsewhere
    690   //
    691   ProcessDSCDefinesSection (&DSCFile);
    692   if (ExceptionThrown ()) {
    693     goto ProcessingError;
    694   }
    695   //
    696   // Write out the [makefile.out] section data to the output makefiles
    697   //
    698   Sect = DSCFileFindSection (&DSCFile, MAKEFILE_OUT_SECTION_NAME);
    699   if (Sect != NULL) {
    700     while (DSCFileGetLine (&DSCFile, Line, sizeof (Line)) != NULL) {
    701       ExpandSymbols (Line, ExpLine, sizeof (ExpLine), 0);
    702       //
    703       // Write the line to the output makefiles
    704       //
    705       fprintf (gGlobals.MakefileFptr, ExpLine);
    706       fprintf (gGlobals.ModuleMakefileFptr, ExpLine);
    707     }
    708   }
    709 
    710   //
    711   // Add a pseudo target for GLOBAL_LINK_LIB_NAME to avoid single module build
    712   // failure when this lib is not used.
    713   //
    714   fprintf (gGlobals.ModuleMakefileFptr, "%sbuild ::\n\n", GLOBAL_LINK_LIB_NAME);
    715 
    716   fprintf (gGlobals.MakefileFptr, "libraries : \n");
    717   //
    718   // Process [libraries] section in the DSC file
    719   //
    720   Sect = DSCFileFindSection (&DSCFile, LIBRARIES_SECTION_NAME);
    721   if (Sect != NULL) {
    722     mCurrentBuildList = &gGlobals.LibraryList;
    723     ProcessSectionComponents (&DSCFile, DSC_SECTION_TYPE_LIBRARIES, 0);
    724   }
    725 
    726   if (ExceptionThrown ()) {
    727     goto ProcessingError;
    728   }
    729   //
    730   // Process [libraries.platform] section in the DSC file
    731   //
    732   Sect = DSCFileFindSection (&DSCFile, LIBRARIES_PLATFORM_SECTION_NAME);
    733   if (Sect != NULL) {
    734     mCurrentBuildList = &gGlobals.LibraryList;
    735     ProcessSectionComponents (&DSCFile, DSC_SECTION_TYPE_PLATFORM_LIBRARIES, 0);
    736   }
    737 
    738   fprintf (gGlobals.MakefileFptr, "\n");
    739   if (ExceptionThrown ()) {
    740     goto ProcessingError;
    741   }
    742 
    743   //
    744   // Process [components] section in the DSC file
    745   //
    746   Sect = DSCFileFindSection (&DSCFile, COMPONENTS_SECTION_NAME);
    747   if (Sect != NULL) {
    748     fprintf (gGlobals.MakefileFptr, "components_0 : \n");
    749     TempComponents    = AddComponentsItem (&gGlobals.ComponentsList);
    750     mCurrentBuildList = &TempComponents->BuildList;
    751     ProcessSectionComponents (&DSCFile, DSC_SECTION_TYPE_COMPONENTS, 0);
    752     fprintf (gGlobals.MakefileFptr, "\n");
    753   }
    754 
    755   if (ExceptionThrown ()) {
    756     goto ProcessingError;
    757   }
    758   //
    759   // Now cycle through all [components.1], [components.2], ....[components.n].
    760   // This is necessary to support building of firmware volumes that may contain
    761   // other encapsulated firmware volumes (ala capsules).
    762   //
    763   i = 1;
    764   while (1) {
    765     RemoveSymbol (FV, SYM_GLOBAL);
    766     sprintf (Line, "%s.%d", COMPONENTS_SECTION_NAME, i);
    767     Sect = DSCFileFindSection (&DSCFile, Line);
    768     if (Sect != NULL) {
    769       fprintf (gGlobals.MakefileFptr, "components_%d : \n", i);
    770       TempComponents    = AddComponentsItem (&gGlobals.ComponentsList);
    771       mCurrentBuildList = &TempComponents->BuildList;
    772       ProcessSectionComponents (&DSCFile, DSC_SECTION_TYPE_COMPONENTS, i);
    773       fprintf (gGlobals.MakefileFptr, "\n");
    774     } else {
    775       break;
    776     }
    777 
    778     if (ExceptionThrown ()) {
    779       goto ProcessingError;
    780     }
    781 
    782     i++;
    783   }
    784 
    785 ProcessingError:
    786   EMsg = CatchException ();
    787   if (EMsg != NULL) {
    788     fprintf (stderr, "%s\n", EMsg);
    789     fprintf (stderr, "Processing aborted\n");
    790   }
    791 
    792   TryException ();
    793   //
    794   // Create the FV files if no fatal errors or errors
    795   //
    796   if (GetUtilityStatus () < STATUS_ERROR) {
    797     CFVWriteInfFiles (&DSCFile, gGlobals.MakefileFptr);
    798   }
    799 
    800   //
    801   // Write all module name into MODULE_NAME_FILE file.
    802   //
    803   if ((FpModule = fopen (MODULE_NAME_FILE, "w")) != NULL) {
    804     TempSymbol = gGlobals.ModuleList;
    805     while (TempSymbol != NULL) {
    806       fprintf (FpModule, " %-*s %s \n", MODULE_BASE_NAME_WIDTH, TempSymbol->Name, TempSymbol->Value);
    807       TempSymbol = TempSymbol->Next;
    808     }
    809     fclose (FpModule);
    810     FpModule = NULL;
    811   }
    812 
    813   //
    814   // Close the all the output makefiles
    815   //
    816   if (gGlobals.MakefileFptr != NULL) {
    817     fclose (gGlobals.MakefileFptr);
    818     gGlobals.MakefileFptr = NULL;
    819   }
    820 
    821   if (gGlobals.ModuleMakefileFptr != NULL) {
    822     fclose (gGlobals.ModuleMakefileFptr);
    823     gGlobals.ModuleMakefileFptr = NULL;
    824   }
    825 
    826   //
    827   // Start multi-thread build if ThreadNumber is specified and no error status
    828   //
    829   if ((gGlobals.ThreadNumber != 0) && (GetUtilityStatus () < STATUS_ERROR)) {
    830     BuildDir = GetSymbolValue (BUILD_DIR);
    831     if (gGlobals.BuildTarget & BUILD_TARGET_LIBRARIES) {
    832       if (StartMultiThreadBuild (&gGlobals.LibraryList, gGlobals.ThreadNumber, BuildDir) != 0) {
    833         Error (NULL, 0, 0, NULL, "Multi-thread build libraries failure");
    834         goto Cleanup;
    835       }
    836     }
    837     i = 0;
    838     TempComponents = gGlobals.ComponentsList;
    839     while (TempComponents != NULL) {
    840       if (gGlobals.BuildTarget & BUILD_TARGET_COMPONENTS) {
    841         if (StartMultiThreadBuild (&TempComponents->BuildList, gGlobals.ThreadNumber, BuildDir) != 0) {
    842           Error (NULL, 0, 0, NULL, "Multi-thread build components %d failure", i);
    843           goto Cleanup;
    844         }
    845       }
    846       if (gGlobals.BuildTarget & BUILD_TARGET_FVS) {
    847         sprintf (ExpLine, "nmake -nologo -f %s fvs_%d", gGlobals.MakefileName, i);
    848         _flushall ();
    849         if (system (ExpLine)) {
    850           Error (NULL, 0, 0, NULL, "Build FVs for components %d failure", i);
    851           goto Cleanup;
    852         }
    853       }
    854       i++;
    855       TempComponents = TempComponents->Next;
    856     }
    857   }
    858 
    859 Cleanup:
    860   //
    861   // Clean up
    862   //
    863   FreeBuildList (gGlobals.LibraryList);
    864   gGlobals.LibraryList = NULL;
    865   FreeComponentsList (gGlobals.ComponentsList);
    866   gGlobals.ComponentsList = NULL;
    867   FreeSymbols (gGlobals.ModuleList);
    868   gGlobals.ModuleList = NULL;
    869   FreeSymbols (gGlobals.OutdirList);
    870   gGlobals.OutdirList = NULL;
    871   FreeSymbols (gGlobals.Symbol);
    872   gGlobals.Symbol = NULL;
    873   CFVDestructor ();
    874   DSCFileDestroy (&DSCFile);
    875 
    876   EMsg = CatchException ();
    877   if (EMsg != NULL) {
    878     fprintf (stderr, "%s\n", EMsg);
    879     fprintf (stderr, "Processing aborted\n");
    880   }
    881 
    882   return GetUtilityStatus ();
    883 }
    884 
    885 static
    886 int
    887 ProcessSectionComponents (
    888   DSC_FILE  *DSCFile,
    889   int       DscSectionType,
    890   int       Instance
    891   )
    892 /*++
    893 
    894 Routine Description:
    895 
    896   Process the [components] or [libraries] section in the description file. We
    897   use this function for both since they're very similar. Here we just
    898   read each line from the section, and if it's valid, call a function to
    899   do the actual processing of the component description file.
    900 
    901 Arguments:
    902 
    903   DSCFile        - structure containing section info on the description file
    904   DscSectionType - type of description section
    905 
    906 Returns:
    907 
    908   0     if successful
    909 
    910 --*/
    911 {
    912   INT8  Line[MAX_LINE_LEN];
    913   INT8  Line2[MAX_EXP_LINE_LEN];
    914   INT8  *Cptr;
    915 
    916   //
    917   // Read lines while they're valid
    918   //
    919   while (DSCFileGetLine (DSCFile, Line, sizeof (Line)) != NULL) {
    920     //
    921     // Expand symbols on the line
    922     //
    923     if (ExpandSymbols (Line, Line2, sizeof (Line2), 0)) {
    924       return STATUS_ERROR;
    925     }
    926     //
    927     // Strip the line
    928     //
    929     Cptr = StripLine (Line2);
    930     if (*Cptr) {
    931       Message (2, "Processing component line: %s", Line2);
    932       if (ProcessComponentFile (DSCFile, Line2, DscSectionType, Instance) != 0) {
    933         return STATUS_ERROR;
    934       }
    935     }
    936   }
    937 
    938   return 0;
    939 }
    940 
    941 static
    942 int
    943 ProcessComponentFile (
    944   DSC_FILE  *DSCFile,
    945   INT8      *ArgLine,
    946   int       DscSectionType,
    947   int       Instance
    948   )
    949 /*++
    950 
    951 Routine Description:
    952 
    953   Given a line from the [components] or [libraries] section of the description
    954   file, process the line to extract the component's INF filename and
    955   parameters. Then open the INF file and process it to create a corresponding
    956   makefile.
    957 
    958 Arguments:
    959 
    960   DSCFile               The project DSC file info structure.
    961   Libs                  Indicates whether we're processing the [components]
    962                         section or the [libraries] section.
    963   ArgLine               The actual line from the DSC file. Looks something like
    964                         one of the following:
    965 
    966    dxe\drivers\vm\vm.dsc PROCESSOR=IA32 DEST_DIR=$(DEST_DIR)\xxx FV=FV1,FV2
    967    $(BUILD_DIR).\FvVariable.ffs COMPONENT_TYPE=FILE
    968    .\FvVariable.ffs COMPONENT_TYPE=FILE
    969    define  VAR1=value1 VAR2=value2
    970 
    971 Returns:
    972 
    973   0 if successful
    974 
    975 --*/
    976 {
    977   FILE      *MakeFptr;
    978   FILE      *TempFptr;
    979   INT8      *Cptr;
    980   INT8      *name;
    981   INT8      *End;
    982   INT8      *TempCptr;
    983   INT8      FileName[MAX_PATH];
    984   INT8      ComponentFilePath[MAX_PATH];
    985   INT8      InLine[MAX_LINE_LEN];
    986   INT8      Line[MAX_LINE_LEN];
    987   INT8      *Processor;
    988   INT8      SymType;
    989   int       Len;
    990   int       ComponentCreated;
    991   int       ComponentFilePathAbsolute;
    992   int       DefineLine;
    993   DSC_FILE  ComponentFile;
    994   INT8      ComponentMakefileName[MAX_PATH];
    995   BOOLEAN   IsForFv;
    996 
    997   //
    998   // Now remove all local symbols
    999   //
   1000   RemoveLocalSymbols ();
   1001   //
   1002   // Null out the file pointer in case we take an exception somewhere
   1003   // and we need to close it only if we opened it.
   1004   //
   1005   MakeFptr                  = NULL;
   1006   ComponentFilePathAbsolute = 0;
   1007   ComponentCreated          = 0;
   1008   //
   1009   // Skip preceeding spaces on the line
   1010   //
   1011   while (isspace (*ArgLine) && (*ArgLine)) {
   1012     ArgLine++;
   1013   }
   1014   //
   1015   // Find the end of the component's filename and truncate the line at that
   1016   // point. From here on out ArgLine is the name of the component filename.
   1017   //
   1018   Cptr = ArgLine;
   1019   while (!isspace (*Cptr) && *Cptr) {
   1020     Cptr++;
   1021   }
   1022 
   1023   End = Cptr;
   1024   if (*Cptr) {
   1025     End++;
   1026     *Cptr = 0;
   1027   }
   1028   //
   1029   // Exception-handle processing of this component description file
   1030   //
   1031   TryException ();
   1032 
   1033   //
   1034   // We also allow a component line format for defines of global symbols
   1035   // instead of a component filename. In this case, the line looks like:
   1036   // defines  x=abc y=yyy. Be nice and accept "define" and "defines" in a
   1037   // case-insensitive manner. If it's defines, then make the symbols global.
   1038   //
   1039   if ((_stricmp (ArgLine, "define") == 0) || (_stricmp (ArgLine, "defines") == 0)) {
   1040     SymType     = SYM_OVERWRITE | SYM_GLOBAL;
   1041     DefineLine  = 1;
   1042   } else {
   1043     SymType     = SYM_OVERWRITE | SYM_LOCAL;
   1044     DefineLine  = 0;
   1045   }
   1046   //
   1047   // The rest of the component line from the DSC file should be defines
   1048   //
   1049   while (*End) {
   1050     End = StripLine (End);
   1051     if (*End) {
   1052       //
   1053       // If we're processing a "define abc=1 xyz=2" line, then set symbols
   1054       // as globals per the SymType set above.
   1055       //
   1056       Len = AddSymbol (End, NULL, SymType);
   1057       if (Len > 0) {
   1058         End += Len;
   1059       } else {
   1060         Warning (NULL, 0, 0, ArgLine, "unrecognized option in description file");
   1061         break;
   1062       }
   1063     }
   1064   }
   1065 
   1066   //
   1067   // If DEBUG_BREAK or EFI_BREAKPOINT is defined, then do a debug breakpoint.
   1068   //
   1069   if ((GetSymbolValue ("DEBUG_BREAK") != NULL) || (GetSymbolValue ("EFI_BREAKPOINT") != NULL)) {
   1070     EFI_BREAKPOINT ();
   1071   }
   1072 
   1073   //
   1074   // If it's a define line, then we're done
   1075   //
   1076   if (DefineLine) {
   1077     //
   1078     // If there is NonFFS_FV, create the FVxxx.inf file
   1079     // and include it in makefile.out. Remove the symbol
   1080     // in order not to process it again next time
   1081     //
   1082     Cptr = GetSymbolValue (NONFFS_FV);
   1083     if (Cptr != NULL) {
   1084       NonFFSFVWriteInfFiles (DSCFile, Cptr);
   1085       RemoveSymbol (NONFFS_FV, SYM_GLOBAL);
   1086     }
   1087 
   1088     goto ComponentDone;
   1089   }
   1090 
   1091   //
   1092   // Expand symbols in the component description filename to expand the newly
   1093   // added local symbols
   1094   //
   1095   ExpandSymbols (ArgLine, Line, sizeof (Line), EXPANDMODE_NO_UNDEFS);
   1096 
   1097   //
   1098   // If we have "c:\path\filename"
   1099   //
   1100   ReplaceSlash (Line);
   1101   if (IsAbsolutePath (Line)) {
   1102     ComponentFilePathAbsolute = 1;
   1103   } else if (Line[0] == '.') {
   1104     //
   1105     // or if the path starts with ".", then it's build-dir relative.
   1106     // Prepend $(BUILD_DIR) on the file name
   1107     //
   1108     sprintf (InLine, "%s\\%s", GetSymbolValue (BUILD_DIR), Line);
   1109     strcpy (Line, InLine);
   1110     ComponentFilePathAbsolute = 1;
   1111   }
   1112 
   1113   //
   1114   // Save the path from the component name for later. It may be relative or
   1115   // absolute.
   1116   //
   1117   strcpy (ComponentFilePath, Line);
   1118   Cptr = ComponentFilePath + strlen (ComponentFilePath) - 1;
   1119   while ((*Cptr != '\\') && (Cptr != ComponentFilePath)) {
   1120     Cptr--;
   1121   }
   1122   //
   1123   // Terminate the path.
   1124   //
   1125   *Cptr = 0;
   1126 
   1127   //
   1128   // Typically the given line is a component description filename. However we
   1129   // also allow a FV filename (fvvariable.ffs COMPONENT_TYPE=FILE). If the
   1130   // component type is "FILE", then add it to the FV list, create a package
   1131   // file, and we're done.
   1132   //
   1133   Cptr = GetSymbolValue (COMPONENT_TYPE);
   1134   if ((Cptr != NULL) && (strncmp (
   1135                           Cptr,
   1136                           COMPONENT_TYPE_FILE,
   1137                           strlen (COMPONENT_TYPE_FILE)
   1138                           ) == 0)) {
   1139     if (ComponentFilePathAbsolute) {
   1140       strcpy (InLine, Line);
   1141     } else {
   1142       sprintf (InLine, "%s\\%s", GetSymbolValue (EFI_SOURCE), Line);
   1143     }
   1144     CFVAddFVFile (
   1145       InLine,
   1146       Cptr,
   1147       GetSymbolValue (FV),
   1148       Instance,
   1149       NULL,
   1150       NULL,
   1151       GetSymbolValue (APRIORI),
   1152       NULL,
   1153       NULL
   1154       );
   1155     goto ComponentDone;
   1156   }
   1157 
   1158   //
   1159   // Better have defined processor by this point.
   1160   //
   1161   Processor = GetSymbolValue (PROCESSOR);
   1162   if (Processor == NULL) {
   1163     Error (NULL, 0, 0, NULL, "PROCESSOR not defined for component %s", Line);
   1164     return STATUS_ERROR;
   1165   }
   1166 
   1167   //
   1168   // The bin, out, and lib dirs are now = $(BUILD_DIR)/$(PROCESSOR). Set them.
   1169   // Don't flag them as file paths (required for short 8.3 filenames) since
   1170   // they're defined using the BUILD_DIR macro.
   1171   //
   1172   sprintf (InLine, "$(BUILD_DIR)\\%s", Processor);
   1173   AddSymbol (BIN_DIR, InLine, SYM_LOCAL);
   1174   AddSymbol (OUT_DIR, InLine, SYM_LOCAL);
   1175   AddSymbol (LIB_DIR, InLine, SYM_LOCAL);
   1176   //
   1177   // See if it's been destined for an FV. It's possible to not be in an
   1178   // FV if they just want to build it.
   1179   //
   1180   Cptr = GetSymbolValue (FV);
   1181   if ((Cptr != NULL) && !IS_NULL_SYMBOL_VALUE (Cptr)) {
   1182     IsForFv = TRUE;
   1183   } else {
   1184     IsForFv = FALSE;
   1185   }
   1186   //
   1187   // As an optimization, if they've defined SKIP_FV_NULL as non-zero, and
   1188   // the component is not destined for an FV, then skip it.
   1189   // Since libraries are never intended for firmware volumes, we have to
   1190   // build all of them.
   1191   //
   1192   if ((DscSectionType == DSC_SECTION_TYPE_COMPONENTS) && (IsForFv == FALSE)) {
   1193     if ((GetSymbolValue (SKIP_FV_NULL) != NULL) && (atoi (GetSymbolValue (SKIP_FV_NULL)) != 0)) {
   1194       Message (0, "%s not being built (FV=NULL)", FileName);
   1195       goto ComponentDone;
   1196     }
   1197   }
   1198   //
   1199   // Prepend EFI_SOURCE to the component description file to get the
   1200   // full path. Only do this if the path is not a full path already.
   1201   //
   1202   if (ComponentFilePathAbsolute == 0) {
   1203     name = GetSymbolValue (EFI_SOURCE);
   1204     sprintf (FileName, "%s\\%s", name, Line);
   1205   } else {
   1206     strcpy (FileName, Line);
   1207   }
   1208   //
   1209   // Print a message, depending on verbose level.
   1210   //
   1211   if (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) {
   1212     Message (1, "Processing component         %s", FileName);
   1213   } else {
   1214     Message (1, "Processing library           %s", FileName);
   1215   }
   1216   //
   1217   // Open the component's description file and get the sections. If we fail
   1218   // to open it, see if they defined "OPTIONAL=1, in which case we'll just
   1219   // ignore the component.
   1220   //
   1221   TempFptr = fopen (FileName, "r");
   1222   if (TempFptr == NULL) {
   1223     //
   1224     // Better have defined OPTIONAL
   1225     //
   1226     if (GetSymbolValue (OPTIONAL_COMPONENT) != NULL) {
   1227       if (atoi (GetSymbolValue (OPTIONAL_COMPONENT)) != 0) {
   1228         Message (0, "Optional component '%s' not found", FileName);
   1229         goto ComponentDone;
   1230       }
   1231     }
   1232 
   1233     ParserError (0, FileName, "failed to open component file");
   1234     return STATUS_ERROR;
   1235   } else {
   1236     fclose (TempFptr);
   1237   }
   1238 
   1239   DSCFileInit (&ComponentFile);
   1240   ComponentCreated = 1;
   1241   if (DSCFileSetFile (&ComponentFile, FileName)) {
   1242     Error (NULL, 0, 0, NULL, "failed to preprocess component file '%s'", FileName);
   1243     return STATUS_ERROR;
   1244   }
   1245   //
   1246   // Add a symbol for the INF filename so users can create dependencies
   1247   // in makefiles.
   1248   //
   1249   AddSymbol (INF_FILENAME, FileName, SYM_OVERWRITE | SYM_LOCAL | SYM_FILENAME);
   1250   //
   1251   // Process the [defines], [defines.$(PROCESSOR)], and [defines.$(PROCESSOR).$(PLATFORM)]
   1252   // sections in the INF file
   1253   //
   1254   ProcessINFDefinesSection (&ComponentFile);
   1255   //
   1256   // Better have defined FILE_GUID if not a library
   1257   //
   1258   if ((GetSymbolValue (GUID) == NULL) &&
   1259       (GetSymbolValue (FILE_GUID) == NULL) &&
   1260       (DscSectionType == DSC_SECTION_TYPE_COMPONENTS)
   1261       ) {
   1262     Error (GetSymbolValue (INF_FILENAME), 1, 0, NULL, "missing FILE_GUID definition in component file");
   1263     DSCFileDestroy (&ComponentFile);
   1264     return STATUS_ERROR;
   1265   }
   1266   //
   1267   // Better have defined base name
   1268   //
   1269   if (GetSymbolValue (BASE_NAME) == NULL) {
   1270     Error (GetSymbolValue (INF_FILENAME), 1, 0, NULL, "missing BASE_NAME definition in INF file");
   1271     DSCFileDestroy (&ComponentFile);
   1272     return STATUS_ERROR;
   1273   }
   1274   //
   1275   // Better have defined COMPONENT_TYPE, since it's used to find named sections.
   1276   //
   1277   if (GetSymbolValue (COMPONENT_TYPE) == NULL) {
   1278     Error (GetSymbolValue (INF_FILENAME), 1, 0, NULL, "missing COMPONENT_TYPE definition in INF file");
   1279     DSCFileDestroy (&ComponentFile);
   1280     return STATUS_ERROR;
   1281   }
   1282 
   1283   //
   1284   // Create the source directory path from the component file's path. If the component
   1285   // file's path is absolute, we may have problems here. Try to account for it though.
   1286   //
   1287   if (ComponentFilePathAbsolute == 0) {
   1288     sprintf (
   1289       FileName,
   1290       "%s\\%s",
   1291       GetSymbolValue (EFI_SOURCE),
   1292       ComponentFilePath
   1293       );
   1294   } else {
   1295     strcpy (FileName, ComponentFilePath);
   1296   }
   1297   AddSymbol (SOURCE_DIR, FileName, SYM_OVERWRITE | SYM_LOCAL | SYM_FILEPATH);
   1298 
   1299   //
   1300   // Create the destination path.
   1301   // They may have defined DEST_DIR on the component INF line, so it's already
   1302   // been defined, If that's the case, then don't set it to the path of this file.
   1303   //
   1304   TempCptr = GetSymbolValue (DEST_DIR);
   1305   if (TempCptr == NULL) {
   1306     if (ComponentFilePathAbsolute == 0) {
   1307       //
   1308       // The destination path is $(BUILD_DIR)\$(PROCESSOR)\component_path
   1309       //
   1310       sprintf (
   1311         FileName,
   1312         "%s\\%s\\%s",
   1313         GetSymbolValue (BUILD_DIR),
   1314         Processor,
   1315         ComponentFilePath
   1316         );
   1317     } else {
   1318       //
   1319       // The destination path is $(BUILD_DIR)\$(PROCESSOR)\$(BASE_NAME)
   1320       //
   1321       sprintf (
   1322         FileName,
   1323         "%s\\%s\\%s",
   1324         GetSymbolValue (BUILD_DIR),
   1325         Processor,
   1326         GetSymbolValue (BASE_NAME)
   1327         );
   1328     }
   1329     AddSymbol (DEST_DIR, FileName, SYM_OVERWRITE | SYM_LOCAL | SYM_FILEPATH);
   1330   } else {
   1331     ReplaceSlash (TempCptr);
   1332   }
   1333 
   1334   //
   1335   // Create the output directory, then open the output component's makefile
   1336   // we're going to create. Allow them to override the makefile name.
   1337   //
   1338   TempCptr = GetSymbolValue (MAKEFILE_NAME);
   1339   if (TempCptr != NULL) {
   1340     ExpandSymbols (TempCptr, ComponentMakefileName, sizeof (ComponentMakefileName), EXPANDMODE_NO_UNDEFS);
   1341     TempCptr = ComponentMakefileName;
   1342   } else {
   1343     TempCptr = "makefile";
   1344   }
   1345 
   1346   sprintf (FileName, "%s\\%s", GetSymbolValue (DEST_DIR), TempCptr);
   1347   //
   1348   // Save it now with path info
   1349   //
   1350   AddSymbol (MAKEFILE_NAME, FileName, SYM_OVERWRITE | SYM_LOCAL | SYM_FILENAME);
   1351 
   1352   if (MakeFilePath (FileName)) {
   1353     return STATUS_ERROR;
   1354   }
   1355 
   1356   if ((MakeFptr = fopen (FileName, "w")) == NULL) {
   1357     Error (NULL, 0, 0, FileName, "could not create makefile");
   1358     return STATUS_ERROR;
   1359   }
   1360   //
   1361   // At this point we should have all the info we need to create a package
   1362   // file if setup to do so. Libraries don't use package files, so
   1363   // don't do this for libs.
   1364   //
   1365   if (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) {
   1366     CreatePackageFile (DSCFile);
   1367   }
   1368 
   1369   //
   1370   // Add a new build item to mCurrentBuildList
   1371   //
   1372   mCurrentBuildItem = AddBuildItem (mCurrentBuildList, GetSymbolValue (BASE_NAME), Processor, FileName);
   1373   //
   1374   // ProcessDsc allows duplicate base name libraries. Make sure the duplicate
   1375   // base name libraries will be built in the same order as listed in DSC file.
   1376   //
   1377   AddDependency (*mCurrentBuildList, mCurrentBuildItem, mCurrentBuildItem->BaseName, 1);
   1378 
   1379   //
   1380   // Add Module name to the global module list
   1381   //
   1382   AddModuleName (&gGlobals.ModuleList, GetSymbolValue (BASE_NAME), GetSymbolValue (INF_FILENAME));
   1383   //
   1384   // Write an nmake line to makefile.out
   1385   //
   1386   fprintf (gGlobals.MakefileFptr, "  @cd %s\n", Processor);
   1387   fprintf (gGlobals.MakefileFptr, "  $(MAKE) -f %s all\n", FileName);
   1388   fprintf (gGlobals.MakefileFptr, "  @cd ..\n");
   1389 
   1390   //
   1391   // Copy the common makefile section from the description file to
   1392   // the component's makefile
   1393   //
   1394   WriteCommonMakefile (DSCFile, MakeFptr, Processor);
   1395   //
   1396   // Process the component's [nmake.common] and [nmake.$(PROCESSOR)] sections
   1397   //
   1398   ProcessINFNMakeSection (&ComponentFile, MakeFptr);
   1399   //
   1400   // Create the SOURCE_FILES macro that includes the names of all source
   1401   // files in this component. This macro can then be used elsewhere to
   1402   // process all the files making up the component. Required for scanning
   1403   // files for string localization.
   1404   // Also add source files to mCurrentBuildItem.
   1405   //
   1406   ProcessSourceFiles (DSCFile, &ComponentFile, MakeFptr, SOURCE_MODE_SOURCE_FILES);
   1407   //
   1408   // Create the include paths. Process [includes.common] and
   1409   // [includes.$(PROCESSOR)] and [includes.$(PROCESSOR).$(PLATFORM)] sections.
   1410   //
   1411   ProcessIncludesSection (&ComponentFile, MakeFptr);
   1412   //
   1413   // Process all include source files to create a dependency list that can
   1414   // be used in the makefile.
   1415   //
   1416   ProcessIncludeFiles (&ComponentFile, MakeFptr);
   1417   //
   1418   // Process the [sources.common], [sources.$(PROCESSOR)], and
   1419   // [sources.$(PROCESSOR).$(PLATFORM)] files and emit their build commands
   1420   //
   1421   ProcessSourceFiles (DSCFile, &ComponentFile, MakeFptr, SOURCE_MODE_BUILD_COMMANDS);
   1422   //
   1423   // Process sources again to create an OBJECTS macro
   1424   //
   1425   ProcessObjects (&ComponentFile, MakeFptr);
   1426 
   1427   //
   1428   // Add Single Module target : build and clean in top level makefile
   1429   //
   1430   fprintf (gGlobals.ModuleMakefileFptr, "%sbuild ::", GetSymbolValue (BASE_NAME));
   1431   if (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) {
   1432     fprintf (gGlobals.ModuleMakefileFptr, " %sbuild", GLOBAL_LINK_LIB_NAME);
   1433   }
   1434 
   1435   //
   1436   // Process all the libraries to define "LIBS = x.lib y.lib..."
   1437   // Be generous and append ".lib" if they forgot.
   1438   // Make a macro definition: LIBS = $(LIBS) xlib.lib ylib.lib...
   1439   // Add libs dependency for single module build: basenamebuild :: xlibbuild ylibbuild ...
   1440   // Also add libs dependency to mCurrentBuildItem.
   1441   //
   1442   ProcessLibs (&ComponentFile, MakeFptr);
   1443 
   1444   fprintf (gGlobals.ModuleMakefileFptr, "\n");
   1445 
   1446   fprintf (gGlobals.ModuleMakefileFptr, "  @cd %s\n", Processor);
   1447   fprintf (gGlobals.ModuleMakefileFptr, "  $(MAKE) -f %s all\n", FileName);
   1448   fprintf (gGlobals.ModuleMakefileFptr, "  @cd ..\n\n");
   1449 
   1450   fprintf (gGlobals.ModuleMakefileFptr, "%sclean ::\n", GetSymbolValue (BASE_NAME));
   1451   fprintf (gGlobals.ModuleMakefileFptr, "  $(MAKE) -f %s clean\n\n", FileName);
   1452 
   1453   //
   1454   // Emit commands to create the component. These are simply copied from
   1455   // the description file to the component's makefile. First look for
   1456   // [build.$(PROCESSOR).$(BUILD_TYPE)]. If not found, then look for if
   1457   // find a [build.$(PROCESSOR).$(COMPONENT_TYPE)] line.
   1458   //
   1459   Cptr = GetSymbolValue (BUILD_TYPE);
   1460   if (Cptr != NULL) {
   1461     sprintf (InLine, "build.%s.%s", Processor, Cptr);
   1462     WriteComponentTypeBuildCommands (DSCFile, MakeFptr, InLine);
   1463   } else {
   1464     sprintf (InLine, "build.%s.%s", Processor, GetSymbolValue (COMPONENT_TYPE));
   1465     WriteComponentTypeBuildCommands (DSCFile, MakeFptr, InLine);
   1466   }
   1467   //
   1468   // Add it to the FV if not a library
   1469   //
   1470   if (DscSectionType == DSC_SECTION_TYPE_COMPONENTS) {
   1471     //
   1472     // Create the FV filename and add it to the FV.
   1473     // By this point we know it's in FV.
   1474     //
   1475     Cptr = GetSymbolValue (FILE_GUID);
   1476     if (Cptr == NULL) {
   1477       Cptr = GetSymbolValue (GUID);
   1478     }
   1479 
   1480     sprintf (InLine, "%s-%s", Cptr, GetSymbolValue (BASE_NAME));
   1481     //
   1482     // We've deprecated FV_EXT, which should be FFS_EXT, the extension
   1483     // of the FFS file generated by GenFFSFile.
   1484     //
   1485     TempCptr = GetSymbolValue (FFS_EXT);
   1486     if (TempCptr == NULL) {
   1487       TempCptr = GetSymbolValue ("FV_EXT");
   1488     }
   1489 
   1490     CFVAddFVFile (
   1491       InLine,
   1492       GetSymbolValue (COMPONENT_TYPE),
   1493       GetSymbolValue (FV),
   1494       Instance,
   1495       TempCptr,
   1496       Processor,
   1497       GetSymbolValue (APRIORI),
   1498       GetSymbolValue (BASE_NAME),
   1499       Cptr
   1500       );
   1501   }
   1502   //
   1503   // Catch any failures and print the name of the component file
   1504   // being processed to assist debugging.
   1505   //
   1506 ComponentDone:
   1507 
   1508   Cptr = CatchException ();
   1509   if (Cptr != NULL) {
   1510     fprintf (stderr, "%s\n", Cptr);
   1511     sprintf (InLine, "Processing of component %s failed", ArgLine);
   1512     ThrowException (InLine);
   1513   }
   1514 
   1515   if (MakeFptr != NULL) {
   1516     fclose (MakeFptr);
   1517   }
   1518 
   1519   if (ComponentCreated) {
   1520     DSCFileDestroy (&ComponentFile);
   1521   }
   1522 
   1523   return STATUS_SUCCESS;
   1524 }
   1525 
   1526 static
   1527 int
   1528 CreatePackageFile (
   1529   DSC_FILE          *DSCFile
   1530   )
   1531 {
   1532   INT8       *Package;
   1533   SECTION    *TempSect;
   1534   INT8       Str[MAX_LINE_LEN];
   1535   INT8       StrExpanded[MAX_LINE_LEN];
   1536   SMART_FILE *PkgFptr;
   1537   int        Status;
   1538 
   1539   PkgFptr = NULL;
   1540 
   1541   //
   1542   // First find out if PACKAGE_FILENAME or PACKAGE is defined. PACKAGE_FILENAME
   1543   // is used to specify the exact package file to use. PACKAGE is used to
   1544   // specify the package section name.
   1545   //
   1546   Package = GetSymbolValue (PACKAGE_FILENAME);
   1547   if (Package != NULL) {
   1548     //
   1549     // Use existing file. We're done.
   1550     //
   1551     return STATUS_SUCCESS;
   1552   }
   1553   //
   1554   // See if PACKAGE or PACKAGE_TAG is defined
   1555   //
   1556   Package = GetSymbolValue (PACKAGE);
   1557   if (Package == NULL) {
   1558     Package = GetSymbolValue (PACKAGE_TAG);
   1559   }
   1560 
   1561   if (Package == NULL) {
   1562     //
   1563     // Not defined either. Assume they are not using the package functionality
   1564     // of this utility. However define the PACKAGE_FILENAME macro to the
   1565     // best-guess value.
   1566     //
   1567     sprintf (
   1568       Str,
   1569       "%s\\%s.pkg",
   1570       GetSymbolValue (SOURCE_DIR),
   1571       GetSymbolValue (BASE_NAME)
   1572       );
   1573 
   1574     //
   1575     // Expand symbols in the package filename
   1576     //
   1577     ExpandSymbols (Str, StrExpanded, sizeof (StrExpanded), EXPANDMODE_NO_UNDEFS);
   1578 
   1579     AddSymbol (PACKAGE_FILENAME, StrExpanded, SYM_LOCAL | SYM_FILENAME);
   1580     return STATUS_SUCCESS;
   1581   }
   1582   //
   1583   // Save the position in the DSC file.
   1584   // Find the [package.$(COMPONENT_TYPE).$(PACKAGE)] section in the DSC file
   1585   //
   1586   Status = STATUS_SUCCESS;
   1587   DSCFileSavePosition (DSCFile);
   1588   sprintf (Str, "%s.%s.%s", PACKAGE, GetSymbolValue (COMPONENT_TYPE), Package);
   1589   TempSect = DSCFileFindSection (DSCFile, Str);
   1590   if (TempSect != NULL) {
   1591     //
   1592     // So far so good. Create the name of the package file, then open it up
   1593     // for writing. File name is c:\...\oem\platform\nt32\ia32\...\BaseName.pkg.
   1594     //
   1595     sprintf (
   1596       Str,
   1597       "%s\\%s.pkg",
   1598       GetSymbolValue (DEST_DIR),
   1599       GetSymbolValue (BASE_NAME)
   1600       );
   1601 
   1602     //
   1603     // Expand symbols in the package filename
   1604     //
   1605     ExpandSymbols (Str, StrExpanded, sizeof (StrExpanded), EXPANDMODE_NO_UNDEFS);
   1606 
   1607     //
   1608     // Try to open the file, then save the file name as the PACKAGE_FILENAME
   1609     // symbol for use elsewhere.
   1610     //
   1611     if ((PkgFptr = SmartOpen (StrExpanded)) == NULL) {
   1612       Error (NULL, 0, 0, Str, "could not open package file for writing");
   1613       Status = STATUS_ERROR;
   1614       goto Finish;
   1615     }
   1616 
   1617     AddSymbol (PACKAGE_FILENAME, StrExpanded, SYM_LOCAL | SYM_FILENAME);
   1618     //
   1619     // Now read lines in from the DSC file and write them back out to the
   1620     // package file (with string substitution).
   1621     //
   1622     while (DSCFileGetLine (DSCFile, Str, sizeof (Str)) != NULL) {
   1623       //
   1624       // Expand symbols, then write the line out to the package file
   1625       //
   1626       ExpandSymbols (Str, StrExpanded, sizeof (StrExpanded), EXPANDMODE_RECURSIVE);
   1627       SmartWrite (PkgFptr, StrExpanded);
   1628     }
   1629   } else {
   1630     Warning (
   1631       NULL,
   1632       0,
   1633       0,
   1634       NULL,
   1635       "cannot locate package section [%s] in DSC file for %s",
   1636       Str,
   1637       GetSymbolValue (INF_FILENAME)
   1638       );
   1639     Status = STATUS_WARNING;
   1640     goto Finish;
   1641   }
   1642 
   1643   if (PkgFptr != NULL) {
   1644     SmartClose (PkgFptr);
   1645   }
   1646 
   1647 Finish:
   1648   //
   1649   // Restore the position in the DSC file
   1650   //
   1651   DSCFileRestorePosition (DSCFile);
   1652 
   1653   return STATUS_SUCCESS;
   1654 }
   1655 
   1656 static
   1657 int
   1658 ProcessINFDefinesSection (
   1659   DSC_FILE   *ComponentFile
   1660   )
   1661 /*++
   1662 
   1663 Routine Description:
   1664 
   1665   Process the [defines.xxx] sections of the component description file. Process
   1666   platform first, then processor. In this way, if a platform wants and override,
   1667   that one gets parsed first, and later assignments do not overwrite the value.
   1668 
   1669 Arguments:
   1670 
   1671   ComponentFile     - section info on the component file being processed
   1672 
   1673 Returns:
   1674 
   1675 
   1676 --*/
   1677 {
   1678   INT8  *Cptr;
   1679   INT8  Str[MAX_LINE_LEN];
   1680 
   1681   //
   1682   // Find a [defines.$(PROCESSOR).$(PLATFORM)] section and process it
   1683   //
   1684   Cptr = GetSymbolValue (PLATFORM);
   1685   if (Cptr != NULL) {
   1686     sprintf (
   1687       Str,
   1688       "%s.%s.%s",
   1689       DEFINES_SECTION_NAME,
   1690       GetSymbolValue (PROCESSOR),
   1691       Cptr
   1692       );
   1693     ProcessINFDefinesSectionSingle (ComponentFile, Str);
   1694   }
   1695   //
   1696   // Find a [defines.$(PROCESSOR)] section and process it
   1697   //
   1698   sprintf (Str, "%s.%s", DEFINES_SECTION_NAME, GetSymbolValue (PROCESSOR));
   1699   ProcessINFDefinesSectionSingle (ComponentFile, Str);
   1700 
   1701   //
   1702   // Find a [defines] section and process it
   1703   //
   1704   if (ProcessINFDefinesSectionSingle (ComponentFile, DEFINES_SECTION_NAME) != STATUS_SUCCESS) {
   1705     Error (NULL, 0, 0, NULL, "missing [defines] section in component file %s", GetSymbolValue (INF_FILENAME));
   1706     return STATUS_ERROR;
   1707   }
   1708 
   1709   return STATUS_SUCCESS;
   1710 }
   1711 
   1712 static
   1713 int
   1714 ProcessINFDefinesSectionSingle (
   1715   DSC_FILE  *ComponentFile,
   1716   INT8      *SectionName
   1717   )
   1718 {
   1719   INT8    *Cptr;
   1720   INT8    Str[MAX_LINE_LEN];
   1721   INT8    ExpandedLine[MAX_LINE_LEN];
   1722   SECTION *TempSect;
   1723 
   1724   TempSect = DSCFileFindSection (ComponentFile, SectionName);
   1725   if (TempSect != NULL) {
   1726     while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   1727       ExpandSymbols (Str, ExpandedLine, sizeof (ExpandedLine), 0);
   1728       Cptr = StripLine (ExpandedLine);
   1729       //
   1730       // Don't process blank lines.
   1731       //
   1732       if (*Cptr) {
   1733         //
   1734         // Add without overwriting macros specified on the component line
   1735         // in the description file
   1736         //
   1737         AddSymbol (Cptr, NULL, SYM_LOCAL);
   1738       }
   1739     }
   1740   } else {
   1741     return STATUS_WARNING;
   1742   }
   1743 
   1744   return STATUS_SUCCESS;
   1745 }
   1746 
   1747 static
   1748 int
   1749 ProcessINFNMakeSection (
   1750   DSC_FILE  *ComponentFile,
   1751   FILE      *MakeFptr
   1752   )
   1753 /*++
   1754 
   1755 Routine Description:
   1756 
   1757   Process the [nmake.common] and [nmake.$(PROCESSOR)] sections of the component
   1758   description file and write and copy them to the component's makefile.
   1759 
   1760 Arguments:
   1761 
   1762   ComponentFile     - section info on the component file being processed
   1763   MakeFptr          - file pointer to the component' makefile we're creating
   1764 
   1765 Returns:
   1766 
   1767   Always STATUS_SUCCESS right now, since the sections are optional.
   1768 
   1769 --*/
   1770 {
   1771   INT8    *Cptr;
   1772   INT8    Str[MAX_LINE_LEN];
   1773   INT8    ExpandedLine[MAX_LINE_LEN];
   1774   SECTION *TempSect;
   1775 
   1776   //
   1777   // Copy the [nmake.common] and [nmake.$(PROCESSOR)] sections from the
   1778   // component file directly to the output file.
   1779   // The line will be stripped and don't print blank lines
   1780   //
   1781   sprintf (Str, "%s.%s", NMAKE_SECTION_NAME, COMMON_SECTION_NAME);
   1782   TempSect = DSCFileFindSection (ComponentFile, Str);
   1783   if (TempSect != NULL) {
   1784     while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   1785       ExpandSymbols (
   1786         Str,
   1787         ExpandedLine,
   1788         sizeof (ExpandedLine),
   1789         EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
   1790         );
   1791       Cptr = StripLine (ExpandedLine);
   1792       if (*Cptr) {
   1793         fprintf (MakeFptr, "%s\n", Cptr);
   1794       }
   1795     }
   1796 
   1797     fprintf (MakeFptr, "\n");
   1798   } else {
   1799     Error (GetSymbolValue (INF_FILENAME), 1, 0, Str, "section not found in component INF file");
   1800   }
   1801 
   1802   sprintf (Str, "%s.%s", NMAKE_SECTION_NAME, GetSymbolValue (PROCESSOR));
   1803   TempSect = DSCFileFindSection (ComponentFile, Str);
   1804   if (TempSect != NULL) {
   1805     while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   1806       ExpandSymbols (
   1807         Str,
   1808         ExpandedLine,
   1809         sizeof (ExpandedLine),
   1810         EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
   1811         );
   1812       Cptr = StripLine (ExpandedLine);
   1813       if (*Cptr) {
   1814         fprintf (MakeFptr, "%s\n", Cptr);
   1815       }
   1816     }
   1817 
   1818     fprintf (MakeFptr, "\n");
   1819   }
   1820   //
   1821   // Do the same for [nmake.$(PROCESSOR).$(PLATFORM)]
   1822   //
   1823   Cptr = GetSymbolValue (PLATFORM);
   1824   if (Cptr != NULL) {
   1825     sprintf (Str, "%s.%s.%s", NMAKE_SECTION_NAME, GetSymbolValue (PROCESSOR), Cptr);
   1826     TempSect = DSCFileFindSection (ComponentFile, Str);
   1827     if (TempSect != NULL) {
   1828       while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   1829         ExpandSymbols (
   1830           Str,
   1831           ExpandedLine,
   1832           sizeof (ExpandedLine),
   1833           EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
   1834           );
   1835         Cptr = StripLine (ExpandedLine);
   1836         if (*Cptr) {
   1837           fprintf (MakeFptr, "%s\n", Cptr);
   1838         }
   1839       }
   1840 
   1841       fprintf (MakeFptr, "\n");
   1842     }
   1843   }
   1844 
   1845   return STATUS_SUCCESS;
   1846 }
   1847 
   1848 static
   1849 int
   1850 ProcessIncludesSection (
   1851   DSC_FILE  *ComponentFile,
   1852   FILE      *MakeFptr
   1853   )
   1854 /*++
   1855 
   1856 Routine Description:
   1857 
   1858   Process the [includes.common], [includes.processor], and
   1859   [includes.processor.platform] section of the component description file
   1860   and write the appropriate macros to the component's makefile.
   1861 
   1862   Process in reverse order to allow overrides on platform basis.
   1863 
   1864 Arguments:
   1865 
   1866   ComponentFile     - section info on the component file being processed
   1867   MakeFptr          - file pointer to the component' makefile we're creating
   1868 
   1869 Returns:
   1870 
   1871   Always STATUS_SUCCESS right now, since the sections are optional.
   1872 
   1873 --*/
   1874 {
   1875   INT8  *Cptr;
   1876   INT8  Str[MAX_LINE_LEN];
   1877   INT8  *Processor;
   1878   INT8  *OverridePath;
   1879 
   1880   //
   1881   // Write a useful comment to the output makefile so the user knows where
   1882   // the data came from.
   1883   //
   1884   fprintf (MakeFptr, "#\n# Tool-generated list of include paths that are created\n");
   1885   fprintf (MakeFptr, "# from the list of include paths in the [includes.*] sections\n");
   1886   fprintf (MakeFptr, "# of the component INF file.\n#\n");
   1887 
   1888   //
   1889   // We use this a lot here, so get the value only once.
   1890   //
   1891   Processor = GetSymbolValue (PROCESSOR);
   1892   //
   1893   // If they're using an override source path, then add OverridePath and
   1894   // OverridePath\$(PROCESSOR) to the list of include paths.
   1895   //
   1896   OverridePath = GetSymbolValue (SOURCE_OVERRIDE_PATH);
   1897   if (OverridePath != NULL) {
   1898     ReplaceSlash (OverridePath);
   1899     fprintf (MakeFptr, "!IF EXIST(%s)\n", OverridePath);
   1900     fprintf (MakeFptr, "INC = $(INC) -I %s\n", OverridePath);
   1901     fprintf (MakeFptr, "!IF EXIST(%s\\%s)\n", OverridePath, Processor);
   1902     fprintf (MakeFptr, "INC = $(INC) -I %s\\%s\n", OverridePath, Processor);
   1903     fprintf (MakeFptr, "!ENDIF\n");
   1904     fprintf (MakeFptr, "!ELSE\n");
   1905     fprintf (MakeFptr, "!MESSAGE Warning: include dir %s does not exist\n", OverridePath);
   1906     fprintf (MakeFptr, "!ENDIF\n");
   1907   }
   1908   //
   1909   // Try for an [includes.$(PROCESSOR).$(PLATFORM)]
   1910   //
   1911   Cptr = GetSymbolValue (PLATFORM);
   1912   if (Cptr != NULL) {
   1913     sprintf (Str, "%s.%s.%s", INCLUDE_SECTION_NAME, Processor, Cptr);
   1914     ProcessIncludesSectionSingle (ComponentFile, MakeFptr, Str);
   1915   }
   1916   //
   1917   // Now the [includes.$(PROCESSOR)] section
   1918   //
   1919   sprintf (Str, "%s.%s", INCLUDE_SECTION_NAME, Processor);
   1920   ProcessIncludesSectionSingle (ComponentFile, MakeFptr, Str);
   1921 
   1922   //
   1923   // Now the [includes.common] section
   1924   //
   1925   sprintf (Str, "%s.%s", INCLUDE_SECTION_NAME, COMMON_SECTION_NAME);
   1926   ProcessIncludesSectionSingle (ComponentFile, MakeFptr, Str);
   1927 
   1928   //
   1929   // Done
   1930   //
   1931   fprintf (MakeFptr, "\n");
   1932   return STATUS_SUCCESS;
   1933 }
   1934 //
   1935 // Process one of the [includes.xxx] sections to create a list of all
   1936 // the include paths.
   1937 //
   1938 static
   1939 int
   1940 ProcessIncludesSectionSingle (
   1941   DSC_FILE  *ComponentFile,
   1942   FILE      *MakeFptr,
   1943   INT8      *SectionName
   1944   )
   1945 {
   1946   INT8    *Cptr;
   1947   SECTION *TempSect;
   1948   INT8    Str[MAX_LINE_LEN];
   1949   INT8    ExpandedLine[MAX_LINE_LEN];
   1950   INT8    *Processor;
   1951 
   1952   TempSect = DSCFileFindSection (ComponentFile, SectionName);
   1953   if (TempSect != NULL) {
   1954     //
   1955     // Add processor subdirectory on every include path
   1956     //
   1957     Processor = GetSymbolValue (PROCESSOR);
   1958     //
   1959     // Copy lines directly
   1960     //
   1961     while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   1962       ExpandSymbols (Str, ExpandedLine, sizeof (ExpandedLine), 0);
   1963       Cptr = StripLine (ExpandedLine);
   1964       //
   1965       // Don't process blank lines
   1966       //
   1967       if (*Cptr) {
   1968         ReplaceSlash (Cptr);
   1969         //
   1970         // Strip off trailing slash
   1971         //
   1972         if (Cptr[strlen (Cptr) - 1] == '\\') {
   1973           Cptr[strlen (Cptr) - 1] = 0;
   1974         }
   1975         //
   1976         // Special case of ".". Replace it with source path
   1977         // and the rest of the line (for .\$(PROCESSOR))
   1978         //
   1979         if (*Cptr == '.') {
   1980           //
   1981           // Handle case of just a "."
   1982           //
   1983           if (Cptr[1] == 0) {
   1984             fprintf (MakeFptr, "INC = $(INC) -I $(SOURCE_DIR)\n");
   1985             fprintf (MakeFptr, "!IF EXIST($(SOURCE_DIR)\\%s)\n", Processor);
   1986             fprintf (MakeFptr, "INC = $(INC) -I $(SOURCE_DIR)\\%s\n", Processor);
   1987             fprintf (MakeFptr, "!ENDIF\n");
   1988           } else {
   1989             //
   1990             // Handle case of ".\path\path\path" or "..\path\path\path"
   1991             //
   1992             fprintf (MakeFptr, "!IF EXIST($(SOURCE_DIR)\\%s)\n", Cptr);
   1993             fprintf (MakeFptr, "INC = $(INC) -I $(SOURCE_DIR)\\%s\n", Cptr);
   1994             fprintf (MakeFptr, "!IF EXIST($(SOURCE_DIR)\\%s\\%s)\n", Cptr, Processor);
   1995             fprintf (MakeFptr, "INC = $(INC) -I $(SOURCE_DIR)\\%s\\%s\n", Cptr, Processor);
   1996             fprintf (MakeFptr, "!ENDIF\n");
   1997             fprintf (MakeFptr, "!ELSE\n");
   1998             fprintf (MakeFptr, "!MESSAGE Warning: include dir $(SOURCE_DIR)\\%s does not exist\n", Cptr);
   1999             fprintf (MakeFptr, "!ENDIF\n");
   2000           }
   2001         } else if ((Cptr[1] != ':') && isalpha (*Cptr)) {
   2002           fprintf (MakeFptr, "!IF EXIST($(EFI_SOURCE)\\%s)\n", Cptr);
   2003           fprintf (MakeFptr, "INC = $(INC) -I $(EFI_SOURCE)\\%s\n", Cptr);
   2004           fprintf (MakeFptr, "!IF EXIST($(EFI_SOURCE)\\%s\\%s)\n", Cptr, Processor);
   2005           fprintf (MakeFptr, "INC = $(INC) -I $(EFI_SOURCE)\\%s\\%s\n", Cptr, Processor);
   2006           fprintf (MakeFptr, "!ENDIF\n");
   2007           fprintf (MakeFptr, "!ELSE\n");
   2008           fprintf (MakeFptr, "!MESSAGE Warning: include dir $(EFI_SOURCE)\\%s does not exist\n", Cptr);
   2009           fprintf (MakeFptr, "!ENDIF\n");
   2010         } else {
   2011           //
   2012           // The line is something like: $(EFI_SOURCE)\dxe\include. Add it to
   2013           // the existing $(INC) definition. Add user includes before any
   2014           // other existing paths.
   2015           //
   2016           fprintf (MakeFptr, "!IF EXIST(%s)\n", Cptr);
   2017           fprintf (MakeFptr, "INC = $(INC) -I %s\n", Cptr);
   2018           fprintf (MakeFptr, "!IF EXIST(%s\\%s)\n", Cptr, Processor);
   2019           fprintf (MakeFptr, "INC = $(INC) -I %s\\%s\n", Cptr, Processor);
   2020           fprintf (MakeFptr, "!ENDIF\n");
   2021           fprintf (MakeFptr, "!ELSE\n");
   2022           fprintf (MakeFptr, "!MESSAGE Warning: include dir %s does not exist\n", Cptr);
   2023           fprintf (MakeFptr, "!ENDIF\n");
   2024         }
   2025       }
   2026     }
   2027   }
   2028 
   2029   return STATUS_SUCCESS;
   2030 }
   2031 
   2032 static
   2033 int
   2034 ProcessSourceFiles (
   2035   DSC_FILE  *DSCFile,
   2036   DSC_FILE  *ComponentFile,
   2037   FILE      *MakeFptr,
   2038   UINT32    Mode
   2039   )
   2040 /*++
   2041 
   2042 Routine Description:
   2043 
   2044   Process the [sources.common], [sources.$(PROCESSOR)], and
   2045   [sources.$(PROCESSOR).$(PLATFORM] sections of the component
   2046   description file and write the appropriate build commands out to the
   2047   component's makefile. If $(SOURCE_SELECT) is defined, then it overrides
   2048   the source selections. We use this functionality for SMM.
   2049 
   2050 Arguments:
   2051 
   2052   ComponentFile     - section info on the component file being processed
   2053   MakeFptr          - file pointer to the component' makefile we're creating
   2054   DSCFile           - section info on the description file we're processing
   2055   Mode              - to write build commands, or just create a list
   2056                       of sources.
   2057 
   2058 Returns:
   2059 
   2060   Always STATUS_SUCCESS right now, since the sections are optional.
   2061 
   2062 --*/
   2063 {
   2064   INT8  Str[MAX_LINE_LEN];
   2065   INT8  *Processor;
   2066   INT8  *Platform;
   2067   INT8  *SourceSelect;
   2068   INT8  *CStart;
   2069   INT8  *CEnd;
   2070   INT8  CSave;
   2071   INT8  *CopySourceSelect;
   2072 
   2073   if (Mode & SOURCE_MODE_SOURCE_FILES) {
   2074     //
   2075     // Write a useful comment to the output makefile so the user knows where
   2076     // the data came from.
   2077     //
   2078     fprintf (MakeFptr, "#\n# Tool-generated list of source files that are created\n");
   2079     fprintf (MakeFptr, "# from the list of source files in the [sources.*] sections\n");
   2080     fprintf (MakeFptr, "# of the component INF file.\n#\n");
   2081   }
   2082 
   2083   //
   2084   // We use this a lot here, so get the value only once.
   2085   //
   2086   Processor = GetSymbolValue (PROCESSOR);
   2087   //
   2088   // See if they defined SOURCE_SELECT=xxx,yyy in which case we'll
   2089   // select each [sources.xxx] and [sources.yyy] files and process
   2090   // them.
   2091   //
   2092   SourceSelect = GetSymbolValue (SOURCE_SELECT);
   2093 
   2094   if (SourceSelect != NULL) {
   2095     //
   2096     // Make a copy of the string and break it up (comma-separated) and
   2097     // select each [sources.*] file from the INF.
   2098     //
   2099     CopySourceSelect = (INT8 *) malloc (strlen (SourceSelect) + 1);
   2100     if (CopySourceSelect == NULL) {
   2101       Error (NULL, 0, 0, NULL, "failed to allocate memory");
   2102       return STATUS_ERROR;
   2103     }
   2104 
   2105     strcpy (CopySourceSelect, SourceSelect);
   2106     CStart  = CopySourceSelect;
   2107     CEnd    = CStart;
   2108     while (*CStart) {
   2109       CEnd = CStart + 1;
   2110       while (*CEnd && *CEnd != ',') {
   2111         CEnd++;
   2112       }
   2113 
   2114       CSave = *CEnd;
   2115       *CEnd = 0;
   2116       sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, CStart);
   2117       ProcessSourceFilesSection (DSCFile, ComponentFile, MakeFptr, Str, Mode);
   2118       //
   2119       // Restore the terminator and advance
   2120       //
   2121       *CEnd   = CSave;
   2122       CStart  = CEnd;
   2123       if (*CStart) {
   2124         CStart++;
   2125       }
   2126     }
   2127 
   2128     free (CopySourceSelect);
   2129 
   2130   } else {
   2131     //
   2132     // Process all the [sources.common] source files to make them build
   2133     //
   2134     sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, COMMON_SECTION_NAME);
   2135     ProcessSourceFilesSection (DSCFile, ComponentFile, MakeFptr, Str, Mode);
   2136     //
   2137     // Now process the [sources.$(PROCESSOR)] files.
   2138     //
   2139     sprintf (Str, "sources.%s", Processor);
   2140     ProcessSourceFilesSection (DSCFile, ComponentFile, MakeFptr, Str, Mode);
   2141     //
   2142     // Now process the [sources.$(PROCESSOR).$(PLATFORM)] files.
   2143     //
   2144     Platform = GetSymbolValue (PLATFORM);
   2145     if (Platform != NULL) {
   2146       sprintf (Str, "sources.%s.%s", Processor, Platform);
   2147       ProcessSourceFilesSection (DSCFile, ComponentFile, MakeFptr, Str, Mode);
   2148     }
   2149   }
   2150 
   2151   fprintf (MakeFptr, "\n");
   2152   return STATUS_SUCCESS;
   2153 }
   2154 
   2155 /*++
   2156 
   2157 Routine Description:
   2158   Given a source file line from an INF file, parse it to see if there are
   2159   any defines on it. If so, then add them to the symbol table.
   2160   Also, terminate the line after the file name.
   2161 
   2162 Arguments:
   2163   SourceFileLine - a line from a [sources.?] section of the INF file. Likely
   2164   something like:
   2165 
   2166   MySourceFile.c   BUILT_NAME=$(BUILD_DIR)\MySourceFile.obj
   2167 
   2168 Returns:
   2169   Nothing.
   2170 
   2171 --*/
   2172 static
   2173 void
   2174 AddFileSymbols (
   2175   INT8    *SourceFileLine
   2176   )
   2177 {
   2178   int Len;
   2179   //
   2180   // Skip spaces
   2181   //
   2182   for (; *SourceFileLine && isspace (*SourceFileLine); SourceFileLine++)
   2183     ;
   2184   for (; *SourceFileLine && !isspace (*SourceFileLine); SourceFileLine++)
   2185     ;
   2186   if (*SourceFileLine) {
   2187     *SourceFileLine = 0;
   2188     SourceFileLine++;
   2189     //
   2190     // AddSymbol() will parse it for us, and return the length. Keep calling
   2191     // it until it reports an error or is done.
   2192     //
   2193     do {
   2194       Len = AddSymbol (SourceFileLine, NULL, SYM_FILE);
   2195       SourceFileLine += Len;
   2196     } while (Len > 0);
   2197   }
   2198 }
   2199 //
   2200 // Process a single section of source files in the component INF file
   2201 //
   2202 static
   2203 int
   2204 ProcessSourceFilesSection (
   2205   DSC_FILE  *DSCFile,
   2206   DSC_FILE  *ComponentFile,
   2207   FILE      *MakeFptr,
   2208   INT8      *SectionName,
   2209   UINT32    Mode
   2210   )
   2211 {
   2212   INT8    *Cptr;
   2213   INT8    FileName[MAX_EXP_LINE_LEN];
   2214   INT8    FilePath[MAX_PATH];
   2215   INT8    TempFileName[MAX_PATH];
   2216   SECTION *TempSect;
   2217   INT8    Str[MAX_LINE_LEN];
   2218   INT8    *Processor;
   2219   INT8    *OverridePath;
   2220   FILE    *FPtr;
   2221 
   2222   TempSect = DSCFileFindSection (ComponentFile, SectionName);
   2223   if (TempSect != NULL) {
   2224     Processor = GetSymbolValue (PROCESSOR);
   2225     while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   2226       Cptr = StripLine (Str);
   2227       //
   2228       // Don't process blank lines
   2229       //
   2230       if (*Cptr) {
   2231         //
   2232         // Expand symbols in the filename, then parse the line for symbol
   2233         // definitions. AddFileSymbols() will null-terminate the line
   2234         // after the file name. Save a copy for override purposes, in which
   2235         // case we'll need to know the file name and path (in case it's in
   2236         // a subdirectory).
   2237         //
   2238         ExpandSymbols (Cptr, FileName, sizeof (FileName), 0);
   2239         AddFileSymbols (FileName);
   2240         ReplaceSlash (FileName);
   2241         //
   2242         // Set the SOURCE_FILE_NAME symbol. What we have now is the name of
   2243         // the file, relative to the location of the INF file. So prepend
   2244         // $(SOURCE_DIR) to it first.
   2245         //
   2246         if (IsAbsolutePath (FileName)) {
   2247           strcpy (TempFileName, FileName);
   2248         } else {
   2249           strcpy (TempFileName, "$(SOURCE_DIR)\\");
   2250           strcat (TempFileName, FileName);
   2251         }
   2252         AddSymbol (SOURCE_FILE_NAME, TempFileName, SYM_FILE | SYM_OVERWRITE);
   2253         //
   2254         // Extract path information from the source file and set internal
   2255         // variable SOURCE_RELATIVE_PATH. Only do this if the path
   2256         // contains a backslash.
   2257         //
   2258         strcpy (FilePath, FileName);
   2259         for (Cptr = FilePath + strlen (FilePath) - 1; (Cptr > FilePath) && (*Cptr != '\\'); Cptr--)
   2260           ;
   2261         if (*Cptr == '\\') {
   2262           *(Cptr + 1) = 0;
   2263           AddSymbol (SOURCE_RELATIVE_PATH, FilePath, SYM_FILE);
   2264         }
   2265         //
   2266         // Define another internal symbol for the name of the file without
   2267         // the path and extension.
   2268         //
   2269         for (Cptr = FileName + strlen (FileName) - 1; (Cptr > FileName) && (*Cptr != '\\'); Cptr--)
   2270           ;
   2271         if (*Cptr == '\\') {
   2272           Cptr++;
   2273         }
   2274 
   2275         strcpy (FilePath, Cptr);
   2276         //
   2277         // We now have a file name with no path information. Before we do anything else,
   2278         // see if OVERRIDE_PATH is set, and if so, see if file $(OVERRIDE_PATH)FileName
   2279         // exists. If it does, then recursive call this function to use the override file
   2280         // instead of the one from the INF file.
   2281         //
   2282         if (IsAbsolutePath (FileName)) {
   2283           OverridePath = NULL;
   2284         } else {
   2285           OverridePath = GetSymbolValue (SOURCE_OVERRIDE_PATH);
   2286         }
   2287         if (OverridePath != NULL) {
   2288           ReplaceSlash (OverridePath);
   2289           //
   2290           // See if the file exists. If it does, reset the SOURCE_FILE_NAME symbol.
   2291           //
   2292           strcpy (TempFileName, OverridePath);
   2293           strcat (TempFileName, "\\");
   2294           strcat (TempFileName, FileName);
   2295           if ((FPtr = fopen (TempFileName, "rb")) != NULL) {
   2296             fclose (FPtr);
   2297             AddSymbol (SOURCE_FILE_NAME, TempFileName, SYM_FILE | SYM_OVERWRITE);
   2298             //
   2299             // Print a message. This function is called to create build commands
   2300             // for source files, and to create a macro of all source files. Therefore
   2301             // do this check so we don't print the override message multiple times.
   2302             //
   2303             if (Mode & SOURCE_MODE_BUILD_COMMANDS) {
   2304               fprintf (stdout, "Override: %s\n", TempFileName);
   2305             }
   2306           } else {
   2307             //
   2308             // Set override path to null to use as a flag below
   2309             //
   2310             OverridePath = NULL;
   2311           }
   2312         }
   2313 
   2314         //
   2315         // Start at the end and work back
   2316         //
   2317         for (Cptr = FilePath + strlen (FilePath) - 1; (Cptr > FilePath) && (*Cptr != '\\') && (*Cptr != '.'); Cptr--)
   2318           ;
   2319         if (*Cptr == '.') {
   2320           *Cptr = 0;
   2321           AddSymbol (SOURCE_FILE_EXTENSION, Cptr + 1, SYM_FILE);
   2322         }
   2323 
   2324         AddSymbol (SOURCE_BASE_NAME, FilePath, SYM_FILE);
   2325         //
   2326         // If we're just creating the SOURCE_FILES macro, then write the
   2327         // file name out to the makefile.
   2328         //
   2329         if (Mode & SOURCE_MODE_SOURCE_FILES) {
   2330           //
   2331           // If we're processing an override file, then use the file name as-is
   2332           //
   2333           if (OverridePath != NULL) {
   2334             //
   2335             // SOURCE_FILES = $(SOURCE_FILES) c:\Path\ThisFile.c
   2336             //
   2337             fprintf (MakeFptr, "SOURCE_FILES = $(SOURCE_FILES) %s\n", TempFileName);
   2338             //
   2339             // Save the source absolute path
   2340             //
   2341             if (PathCanonicalize (FilePath, TempFileName)) {
   2342               AddSourceFile (mCurrentBuildItem, FilePath);
   2343             }
   2344           } else if (IsAbsolutePath (FileName)) {
   2345             //
   2346             // For Absolute path, don't print $(SOURCE_FILE) directory.
   2347             //
   2348             fprintf (MakeFptr, "SOURCE_FILES = $(SOURCE_FILES) %s\n", FileName);
   2349             //
   2350             // Save the source absolute path
   2351             //
   2352             if (PathCanonicalize (FilePath, FileName)) {
   2353               AddSourceFile (mCurrentBuildItem, FilePath);
   2354             }
   2355           } else {
   2356             //
   2357             // SOURCE_FILES = $(SOURCE_FILES) $(SOURCE_DIR)\ThisFile.c
   2358             //
   2359             fprintf (MakeFptr, "SOURCE_FILES = $(SOURCE_FILES) $(SOURCE_DIR)\\%s\n", FileName);
   2360             //
   2361             // Save the source absolute path
   2362             //
   2363             sprintf (Str, "%s\\%s", GetSymbolValue (SOURCE_DIR), FileName);
   2364             if (PathCanonicalize (FilePath, Str)) {
   2365               AddSourceFile (mCurrentBuildItem, FilePath);
   2366             }
   2367           }
   2368         } else if (Mode & SOURCE_MODE_BUILD_COMMANDS) {
   2369           //
   2370           // Write the build commands for this file per the build commands
   2371           // for this file type as defined in the description file.
   2372           // Also create the directory for it in the build path.
   2373           //
   2374           WriteCompileCommands (DSCFile, MakeFptr, FileName, Processor);
   2375           if (!IsAbsolutePath (FileName)) {
   2376             sprintf (Str, "%s\\%s", GetSymbolValue (DEST_DIR), FileName);
   2377             MakeFilePath (Str);
   2378             //
   2379             // Get all output directory for build output files.
   2380             //
   2381             Cptr = FileName + strlen (FileName) - 1;
   2382             for (; (Cptr > FileName) && (*Cptr != '\\'); Cptr--);
   2383             if (*Cptr == '\\') {
   2384               *Cptr = '\0';
   2385               AddModuleName (&gGlobals.OutdirList, FileName, NULL);
   2386             }
   2387           }
   2388         }
   2389         //
   2390         // Remove file-level symbols
   2391         //
   2392         RemoveFileSymbols ();
   2393       }
   2394     }
   2395   }
   2396 
   2397   return STATUS_SUCCESS;
   2398 }
   2399 //
   2400 // Process the INF [sources.*] sections and emit the OBJECTS = .....
   2401 // lines to the component's makefile.
   2402 //
   2403 static
   2404 int
   2405 ProcessObjects (
   2406   DSC_FILE  *ComponentFile,
   2407   FILE      *MakeFptr
   2408   )
   2409 {
   2410   INT8  Str[MAX_LINE_LEN];
   2411   INT8  *Processor;
   2412   INT8  *Platform;
   2413   INT8  *SourceSelect;
   2414   INT8  *CStart;
   2415   INT8  *CEnd;
   2416   INT8  CSave;
   2417   INT8  *CopySourceSelect;
   2418   SYMBOL *TempSymbol;
   2419 
   2420   //
   2421   // Write a useful comment to the output makefile so the user knows where
   2422   // the data came from.
   2423   //
   2424   fprintf (MakeFptr, "#\n# Tool-generated list of object files that are created\n");
   2425   fprintf (MakeFptr, "# from the list of source files in the [sources.*] sections\n");
   2426   fprintf (MakeFptr, "# of the component INF file.\n#\n");
   2427   //
   2428   // We use this a lot here, so get the value only once.
   2429   //
   2430   Processor = GetSymbolValue (PROCESSOR);
   2431   //
   2432   // Now define the OBJECTS variable and assign it to be all the object files we're going
   2433   // to create. Afterwards create a pseudo-target objects to let the user quickly just compile
   2434   // the source files. This means we need to process all the common objects and
   2435   // processor-specific objects again.
   2436   //
   2437   fprintf (MakeFptr, "OBJECTS = $(OBJECTS) ");
   2438   //
   2439   // See if they defined SOURCE_SELECT=xxx,yyy in which case well
   2440   // select each [sources.xxx] and [sources.yyy] files and process
   2441   // them.
   2442   //
   2443   SourceSelect = GetSymbolValue (SOURCE_SELECT);
   2444 
   2445   if (SourceSelect != NULL) {
   2446     //
   2447     // Make a copy of the string and break it up (comma-separated) and
   2448     // select each [sources.*] file from the INF.
   2449     //
   2450     CopySourceSelect = (INT8 *) malloc (strlen (SourceSelect) + 1);
   2451     if (CopySourceSelect == NULL) {
   2452       Error (NULL, 0, 0, NULL, "failed to allocate memory");
   2453       return STATUS_ERROR;
   2454     }
   2455 
   2456     strcpy (CopySourceSelect, SourceSelect);
   2457     CStart  = CopySourceSelect;
   2458     CEnd    = CStart;
   2459     while (*CStart) {
   2460       CEnd = CStart + 1;
   2461       while (*CEnd && *CEnd != ',') {
   2462         CEnd++;
   2463       }
   2464 
   2465       CSave = *CEnd;
   2466       *CEnd = 0;
   2467       sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, CStart);
   2468       ProcessObjectsSingle (ComponentFile, MakeFptr, Str);
   2469       //
   2470       // Restore the terminator and advance
   2471       //
   2472       *CEnd   = CSave;
   2473       CStart  = CEnd;
   2474       if (*CStart) {
   2475         CStart++;
   2476       }
   2477     }
   2478 
   2479     free (CopySourceSelect);
   2480 
   2481   } else {
   2482     //
   2483     // Now process all the [sources.common] files and emit build commands for them
   2484     //
   2485     sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, COMMON_SECTION_NAME);
   2486     if (ProcessObjectsSingle (ComponentFile, MakeFptr, Str) != STATUS_SUCCESS) {
   2487       Warning (GetSymbolValue (INF_FILENAME), 1, 0, NULL, "no [%s] section found in component description", Str);
   2488     }
   2489     //
   2490     // Now process any processor-specific source files in [sources.$(PROCESSOR)]
   2491     //
   2492     sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, Processor);
   2493     ProcessObjectsSingle (ComponentFile, MakeFptr, Str);
   2494 
   2495     //
   2496     // Now process any [sources.$(PROCESSOR).$(PLATFORM)] files
   2497     //
   2498     Platform = GetSymbolValue (PLATFORM);
   2499     if (Platform != NULL) {
   2500       sprintf (Str, "sources.%s.%s", Processor, Platform);
   2501       ProcessObjectsSingle (ComponentFile, MakeFptr, Str);
   2502     }
   2503   }
   2504 
   2505   fprintf (MakeFptr, "\n\n");
   2506 
   2507   //
   2508   // Write a useful comment to the output makefile so the user knows where
   2509   // the data came from.
   2510   //
   2511   fprintf (MakeFptr, "#\n# Tool-generated list of dest output dirs that are created\n");
   2512   fprintf (MakeFptr, "# from the list of source files in the [sources.*] sections\n");
   2513   fprintf (MakeFptr, "# of the component INF file.\n#\n");
   2514   //
   2515   // Create output directory list
   2516   // for clean target to delete all build output files.
   2517   //
   2518   fprintf (MakeFptr, "DEST_OUTPUT_DIRS = $(%s) ", DEST_DIR);
   2519 
   2520   TempSymbol = gGlobals.OutdirList;
   2521   while (TempSymbol != NULL) {
   2522     fprintf (MakeFptr, "\\\n                   $(%s)\\%s   ",
   2523              DEST_DIR, TempSymbol->Name);
   2524     TempSymbol = TempSymbol->Next;
   2525   }
   2526   fprintf (MakeFptr, "\n\n");
   2527 
   2528   //
   2529   // clean up for the next module
   2530   //
   2531   FreeSymbols (gGlobals.OutdirList);
   2532   gGlobals.OutdirList = NULL;
   2533 
   2534   return STATUS_SUCCESS;
   2535 }
   2536 
   2537 static
   2538 INT8 *
   2539 BuiltFileExtension (
   2540   INT8      *SourceFileName
   2541   )
   2542 {
   2543   int   i;
   2544   INT8  *Cptr;
   2545   //
   2546   // Find the dot in the filename extension
   2547   //
   2548   for (Cptr = SourceFileName + strlen (SourceFileName) - 1;
   2549        (Cptr > SourceFileName) && (*Cptr != '\\') && (*Cptr != '.');
   2550        Cptr--
   2551       ) {
   2552     //
   2553     // Do nothing
   2554     //
   2555   }
   2556 
   2557   if (*Cptr != '.') {
   2558     return NULL;
   2559   }
   2560   //
   2561   // Look through our list of known file types and return a pointer to
   2562   // its built file extension.
   2563   //
   2564   for (i = 0; mFileTypes[i].Extension != NULL; i++) {
   2565     if (_stricmp (Cptr, mFileTypes[i].Extension) == 0) {
   2566       return mFileTypes[i].BuiltExtension;
   2567     }
   2568   }
   2569 
   2570   return NULL;
   2571 }
   2572 
   2573 int
   2574 ProcessObjectsSingle (
   2575   DSC_FILE  *ComponentFile,
   2576   FILE      *MakeFptr,
   2577   INT8      *SectionName
   2578   )
   2579 {
   2580   INT8    *Cptr;
   2581   INT8    *Cptr2;
   2582   INT8    Str[MAX_LINE_LEN];
   2583   INT8    FileName[MAX_EXP_LINE_LEN];
   2584   SECTION *TempSect;
   2585 
   2586   TempSect = DSCFileFindSection (ComponentFile, SectionName);
   2587   if (TempSect != NULL) {
   2588     while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   2589       Cptr = StripLine (Str);
   2590       //
   2591       // Don't process blank lines
   2592       //
   2593       if (*Cptr) {
   2594         //
   2595         // Expand symbols then create the output filename. We'll do a lookup
   2596         // on the source file's extension to determine what the extension of
   2597         // the built version of the file is. For example, .c -> .obj.
   2598         //
   2599         if (!IsIncludeFile (Cptr)) {
   2600           ExpandSymbols (Cptr, FileName, sizeof (FileName), 0);
   2601           ReplaceSlash (FileName);
   2602           Cptr2 = BuiltFileExtension (FileName);
   2603           if (Cptr2 != NULL) {
   2604             SetFileExtension (FileName, Cptr2);
   2605             if (!IsAbsolutePath (FileName)) {
   2606               fprintf (MakeFptr, "\\\n          $(%s)\\%s   ", DEST_DIR, FileName);
   2607             } else {
   2608               fprintf (MakeFptr, "\\\n          %s   ", FileName);
   2609             }
   2610           }
   2611         }
   2612       }
   2613     }
   2614   } else {
   2615     return STATUS_WARNING;
   2616   }
   2617 
   2618   return STATUS_SUCCESS;
   2619 }
   2620 //
   2621 // Process all [libraries.*] sections in the component INF file to create a
   2622 // macro to the component's output makefile: LIBS = Lib1 Lib2, ...
   2623 //
   2624 static
   2625 int
   2626 ProcessLibs (
   2627   DSC_FILE  *ComponentFile,
   2628   FILE      *MakeFptr
   2629   )
   2630 {
   2631   INT8  Str[MAX_LINE_LEN];
   2632   INT8  *Processor;
   2633   INT8  *Platform;
   2634 
   2635   //
   2636   // Print a useful comment to the component's makefile so the user knows
   2637   // where the data came from.
   2638   //
   2639   fprintf (MakeFptr, "#\n# Tool-generated list of libraries that are generated\n");
   2640   fprintf (MakeFptr, "# from the list of libraries listed in the [libraries.*] sections\n");
   2641   fprintf (MakeFptr, "# of the component INF file.\n#\n");
   2642 
   2643   fprintf (MakeFptr, "LIBS = $(LIBS) ");
   2644 
   2645   Processor = GetSymbolValue (PROCESSOR);
   2646   //
   2647   // Process [libraries.common] files
   2648   //
   2649   sprintf (Str, "%s.%s", LIBRARIES_SECTION_NAME, COMMON_SECTION_NAME);
   2650   ProcessLibsSingle (ComponentFile, MakeFptr, Str);
   2651   //
   2652   // Process the [libraries.$(PROCESSOR)] libraries to define "LIBS = x.lib y.lib..."
   2653   //
   2654   sprintf (Str, "%s.%s", LIBRARIES_SECTION_NAME, Processor);
   2655   ProcessLibsSingle (ComponentFile, MakeFptr, Str);
   2656   //
   2657   // Now process any [libraries.$(PROCESSOR).$(PLATFORM)] files
   2658   //
   2659   Platform = GetSymbolValue (PLATFORM);
   2660   if (Platform != NULL) {
   2661     sprintf (Str, "%s.%s.%s", LIBRARIES_SECTION_NAME, Processor, Platform);
   2662     ProcessLibsSingle (ComponentFile, MakeFptr, Str);
   2663   }
   2664   //
   2665   // Process any [libraries.platform] files
   2666   //
   2667   ProcessLibsSingle (ComponentFile, MakeFptr, LIBRARIES_PLATFORM_SECTION_NAME);
   2668 
   2669   fprintf (MakeFptr, "\n\n");
   2670   return STATUS_SUCCESS;
   2671 }
   2672 
   2673 static
   2674 int
   2675 ProcessLibsSingle (
   2676   DSC_FILE  *ComponentFile,
   2677   FILE      *MakeFptr,
   2678   INT8      *SectionName
   2679   )
   2680 {
   2681   INT8    *Cptr;
   2682   INT8    Str[MAX_LINE_LEN];
   2683   INT8    ExpandedLine[MAX_LINE_LEN];
   2684   SECTION *TempSect;
   2685 
   2686   TempSect = DSCFileFindSection (ComponentFile, SectionName);
   2687   if (TempSect != NULL) {
   2688     while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   2689       ExpandSymbols (Str, ExpandedLine, sizeof (ExpandedLine), 0);
   2690       Cptr = StripLine (ExpandedLine);
   2691       //
   2692       // Don't process blank lines
   2693       //
   2694       if (*Cptr) {
   2695         if (Cptr[strlen (Cptr) - 4] != '.') {
   2696           fprintf (MakeFptr, "    \\\n       $(LIB_DIR)\\%s.lib", Cptr);
   2697           //
   2698           // Add lib dependency for single module build
   2699           //
   2700           fprintf (gGlobals.ModuleMakefileFptr, " %sbuild", Cptr);
   2701         } else {
   2702           fprintf (MakeFptr, "    \\\n       $(LIB_DIR)\\%s", Cptr);
   2703           //
   2704           // Add lib dependency for single module build
   2705           //
   2706           Cptr[strlen (Cptr) - 4] = 0;
   2707           fprintf (gGlobals.ModuleMakefileFptr, " %sbuild", Cptr);
   2708         }
   2709         //
   2710         // Add libs dependency for mCurrentBuildItem
   2711         //
   2712         AddDependency (*mCurrentBuildList, mCurrentBuildItem, Cptr, 0);
   2713       }
   2714     }
   2715   }
   2716 
   2717   return STATUS_SUCCESS;
   2718 }
   2719 
   2720 static
   2721 int
   2722 ProcessIncludeFiles (
   2723   DSC_FILE *ComponentFile,
   2724   FILE     *MakeFptr
   2725   )
   2726 {
   2727   INT8  Str[MAX_LINE_LEN];
   2728   INT8  *Processor;
   2729   INT8  *Platform;
   2730   INT8  *SourceSelect;
   2731   INT8  *CStart;
   2732   INT8  *CEnd;
   2733   INT8  CSave;
   2734   INT8  *CopySourceSelect;
   2735 
   2736   //
   2737   // Print a useful comment to the output makefile so the user knows where
   2738   // the info came from
   2739   //
   2740   //fprintf (MakeFptr, "#\n# Tool-generated include dependencies from any include files in the\n");
   2741   //fprintf (MakeFptr, "# [sources.*] sections of the component INF file\n#\n");
   2742 
   2743   Processor = GetSymbolValue (PROCESSOR);
   2744 
   2745   //
   2746   // See if they defined SOURCE_SELECT=xxx,yyy in which case we'll
   2747   // select each [sources.xxx] and [sources.yyy] files and process
   2748   // them.
   2749   //
   2750   SourceSelect = GetSymbolValue (SOURCE_SELECT);
   2751 
   2752   if (SourceSelect != NULL) {
   2753     //
   2754     // Make a copy of the string and break it up (comma-separated) and
   2755     // select each [sources.*] file from the INF.
   2756     //
   2757     CopySourceSelect = (INT8 *) malloc (strlen (SourceSelect) + 1);
   2758     if (CopySourceSelect == NULL) {
   2759       Error (NULL, 0, 0, NULL, "failed to allocate memory");
   2760       return STATUS_ERROR;
   2761     }
   2762 
   2763     strcpy (CopySourceSelect, SourceSelect);
   2764     CStart  = CopySourceSelect;
   2765     CEnd    = CStart;
   2766     while (*CStart) {
   2767       CEnd = CStart + 1;
   2768       while (*CEnd && *CEnd != ',') {
   2769         CEnd++;
   2770       }
   2771 
   2772       CSave = *CEnd;
   2773       *CEnd = 0;
   2774       sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, CStart);
   2775       ProcessIncludeFilesSingle (ComponentFile, MakeFptr, Str);
   2776       //
   2777       // Restore the terminator and advance
   2778       //
   2779       *CEnd   = CSave;
   2780       CStart  = CEnd;
   2781       if (*CStart) {
   2782         CStart++;
   2783       }
   2784     }
   2785 
   2786     free (CopySourceSelect);
   2787 
   2788   } else {
   2789     //
   2790     // Find all the include files in the [sources.common] sections.
   2791     //
   2792     sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, COMMON_SECTION_NAME);
   2793     ProcessIncludeFilesSingle (ComponentFile, MakeFptr, Str);
   2794     //
   2795     // Now process the [sources.$(PROCESSOR)] files.
   2796     //
   2797     sprintf (Str, "%s.%s", SOURCES_SECTION_NAME, Processor);
   2798     ProcessIncludeFilesSingle (ComponentFile, MakeFptr, Str);
   2799     //
   2800     // Now process the [sources.$(PROCESSOR).$(PLATFORM)] files.
   2801     //
   2802     Platform = GetSymbolValue (PLATFORM);
   2803     if (Platform != NULL) {
   2804       sprintf (Str, "sources.%s.%s", Processor, Platform);
   2805       ProcessIncludeFilesSingle (ComponentFile, MakeFptr, Str);
   2806     }
   2807   }
   2808 
   2809   fprintf (MakeFptr, "\n");
   2810   return STATUS_SUCCESS;
   2811 }
   2812 
   2813 int
   2814 ProcessIncludeFilesSingle (
   2815   DSC_FILE  *ComponentFile,
   2816   FILE      *MakeFptr,
   2817   INT8      *SectionName
   2818   )
   2819 {
   2820   INT8            *Cptr;
   2821   INT8            FileName[MAX_EXP_LINE_LEN];
   2822   INT8            TempFileName[MAX_PATH];
   2823   SECTION         *TempSect;
   2824   INT8            Str[MAX_LINE_LEN];
   2825   INT8            *OverridePath;
   2826   FILE            *FPtr;
   2827 
   2828   TempSect = DSCFileFindSection (ComponentFile, SectionName);
   2829   if (TempSect != NULL) {
   2830     //
   2831     // See if the SOURCE_OVERRIDE_PATH has been set. If it has, and
   2832     // they have an include file that is overridden, then add the path
   2833     // to it to the list of include paths (prepend).
   2834     //
   2835     OverridePath = GetSymbolValue (SOURCE_OVERRIDE_PATH);
   2836     while (DSCFileGetLine (ComponentFile, Str, sizeof (Str)) != NULL) {
   2837       Cptr = StripLine (Str);
   2838       //
   2839       // Don't process blank lines
   2840       //
   2841       if (*Cptr) {
   2842         //
   2843         // Expand symbols in the filename, then get its parts
   2844         //
   2845         ExpandSymbols (Cptr, FileName, sizeof (FileName), 0);
   2846         AddFileSymbols (FileName);
   2847         ReplaceSlash (FileName);
   2848         if (IsIncludeFile (FileName)) {
   2849           if ((OverridePath != NULL) && (!IsAbsolutePath (FileName))) {
   2850             ReplaceSlash (OverridePath);
   2851             strcpy (TempFileName, OverridePath);
   2852             strcat (TempFileName, "\\");
   2853             strcat (TempFileName, FileName);
   2854             if ((FPtr = fopen (TempFileName, "rb")) != NULL) {
   2855               fclose (FPtr);
   2856               //
   2857               // Null-terminate the file name at the last backslash and add that
   2858               // to the beginning of the list of include paths.
   2859               //
   2860               for (Cptr = TempFileName + strlen (TempFileName) - 1;
   2861                    (Cptr >= TempFileName) && (*Cptr != '\\');
   2862                    Cptr--
   2863                   )
   2864                 ;
   2865               if (Cptr >= TempFileName) {
   2866                 *Cptr = 0;
   2867               }
   2868               fprintf (MakeFptr, "!IF EXIST(%s)\n", TempFileName);
   2869               fprintf (MakeFptr, "INC = -I %s $(INC)\n", TempFileName);
   2870               fprintf (MakeFptr, "!ENDIF\n");
   2871             }
   2872           }
   2873           //
   2874           // If absolute path already, don't prepend source directory
   2875           //
   2876           // if (IsAbsolutePath (FileName)) {
   2877           //   fprintf (MakeFptr, "INC_DEPS = $(INC_DEPS) %s\n", FileName);
   2878           // } else {
   2879           //   fprintf (MakeFptr, "INC_DEPS = $(INC_DEPS) $(SOURCE_DIR)\\%s\n", FileName);
   2880           // }
   2881         }
   2882 
   2883         RemoveFileSymbols ();
   2884       }
   2885     }
   2886   }
   2887 
   2888   return STATUS_SUCCESS;
   2889 }
   2890 
   2891 static
   2892 void
   2893 FreeFileParts (
   2894   FILE_NAME_PARTS *FP
   2895   )
   2896 {
   2897   if (FP != NULL) {
   2898     if (FP->Path != NULL) {
   2899       free (FP->Path);
   2900     }
   2901 
   2902     if (FP->BaseName != NULL) {
   2903       free (FP->BaseName);
   2904     }
   2905 
   2906     if (FP->Extension != NULL) {
   2907       free (FP->Extension);
   2908     }
   2909   }
   2910 }
   2911 
   2912 static
   2913 FILE_NAME_PARTS *
   2914 GetFileParts (
   2915   INT8 *FileName
   2916   )
   2917 {
   2918   FILE_NAME_PARTS *FP;
   2919   INT8            *Cptr;
   2920   INT8            CopyFileName[MAX_PATH];
   2921   INT8            *FileNamePtr;
   2922 
   2923   strcpy (CopyFileName, FileName);
   2924   FP = (FILE_NAME_PARTS *) malloc (sizeof (FILE_NAME_PARTS));
   2925   if (FP == NULL) {
   2926     Error (NULL, 0, 0, NULL, "failed to allocate memory");
   2927     return NULL;
   2928   }
   2929 
   2930   memset ((INT8 *) FP, 0, sizeof (FILE_NAME_PARTS));
   2931   //
   2932   // Get extension code
   2933   //
   2934   FP->ExtensionCode = GetSourceFileType (CopyFileName);
   2935   //
   2936   // Get drive if there
   2937   //
   2938   FileNamePtr = CopyFileName;
   2939   if (FileNamePtr[1] == ':') {
   2940     FP->Drive[0]  = FileNamePtr[0];
   2941     FP->Drive[1]  = ':';
   2942     FileNamePtr += 2;
   2943   }
   2944   //
   2945   // Start at the end and work back
   2946   //
   2947   for (Cptr = FileNamePtr + strlen (FileNamePtr) - 1; (Cptr > FileNamePtr) && (*Cptr != '.'); Cptr--)
   2948     ;
   2949 
   2950   if (*Cptr == '.') {
   2951     //
   2952     // Don't copy the dot
   2953     //
   2954     FP->Extension = (char *) malloc (strlen (Cptr));
   2955     strcpy (FP->Extension, Cptr + 1);
   2956     *Cptr = 0;
   2957     Cptr--;
   2958     StripTrailingSpaces (FP->Extension);
   2959   } else {
   2960     //
   2961     // Create empty string for extension
   2962     //
   2963     FP->Extension     = (char *) malloc (1);
   2964     FP->Extension[0]  = 0;
   2965   }
   2966   //
   2967   // Now back up and get the base name (include the preceding '\')
   2968   //
   2969   for (; (Cptr > FileNamePtr) && (*Cptr != '\\'); Cptr--)
   2970     ;
   2971   FP->BaseName = (char *) malloc (strlen (Cptr) + 1);
   2972   strcpy (FP->BaseName, Cptr);
   2973   *Cptr = 0;
   2974   Cptr--;
   2975   //
   2976   // Rest is path
   2977   //
   2978   if (Cptr >= FileNamePtr) {
   2979     Cptr      = FileNamePtr;
   2980     FP->Path  = (char *) malloc (strlen (Cptr) + 1);
   2981     strcpy (FP->Path, Cptr);
   2982   } else {
   2983     FP->Path    = (char *) malloc (1);
   2984     FP->Path[0] = 0;
   2985   }
   2986 
   2987   return FP;
   2988 }
   2989 
   2990 /*****************************************************************************
   2991 ******************************************************************************/
   2992 static
   2993 int
   2994 WriteCommonMakefile (
   2995   DSC_FILE  *DSCFile,
   2996   FILE      *MakeFptr,
   2997   INT8      *Processor
   2998   )
   2999 {
   3000   INT8    InLine[MAX_LINE_LEN];
   3001   INT8    OutLine[MAX_EXP_LINE_LEN];
   3002   SECTION *Sect;
   3003   INT8    *Sym;
   3004   int     i;
   3005   //
   3006   // Don't mess up the original file pointer, since we're processing it at a higher
   3007   // level.
   3008   //
   3009   DSCFileSavePosition (DSCFile);
   3010   //
   3011   // Write the header to the file
   3012   //
   3013   for (i = 0; MakefileHeader[i] != NULL; i++) {
   3014     fprintf (MakeFptr, "%s\n", MakefileHeader[i]);
   3015   }
   3016 
   3017   fprintf (MakeFptr, "#\n# Hard-coded defines output by the tool\n#\n");
   3018   //
   3019   // First write the basics to the component's makefile. These includes
   3020   // EFI_SOURCE, BIN_DIR, OUT_DIR, LIB_DIR, SOURCE_DIR, DEST_DIR.
   3021   //
   3022   Sym = GetSymbolValue (EFI_SOURCE);
   3023   fprintf (MakeFptr, "%s       = %s\n", EFI_SOURCE, Sym);
   3024   Sym = GetSymbolValue (BUILD_DIR);
   3025   fprintf (MakeFptr, "%s        = %s\n", BUILD_DIR, Sym);
   3026   Sym = GetSymbolValue (BIN_DIR);
   3027   fprintf (MakeFptr, "%s          = %s\n", BIN_DIR, Sym);
   3028   Sym = GetSymbolValue (OUT_DIR);
   3029   fprintf (MakeFptr, "%s          = %s\n", OUT_DIR, Sym);
   3030   Sym = GetSymbolValue (LIB_DIR);
   3031   fprintf (MakeFptr, "%s          = %s\n", LIB_DIR, Sym);
   3032   Sym = GetSymbolValue (SOURCE_DIR);
   3033   fprintf (MakeFptr, "%s       = %s\n", SOURCE_DIR, Sym);
   3034   Sym = GetSymbolValue (DEST_DIR);
   3035   fprintf (MakeFptr, "%s         = %s\n", DEST_DIR, Sym);
   3036   fprintf (MakeFptr, "\n");
   3037   //
   3038   // If there was a [makefile.common] section in the description file,
   3039   // copy it (after symbol expansion) to the output file.
   3040   //
   3041   sprintf (InLine, "%s.%s", MAKEFILE_SECTION_NAME, COMMON_SECTION_NAME);
   3042   Sect = DSCFileFindSection (DSCFile, InLine);
   3043   if (Sect != NULL) {
   3044     //
   3045     // fprintf (MakeFptr, "# From the [makefile.common] section of the DSC file\n");
   3046     // Read lines, expand, then dump out
   3047     //
   3048     while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) {
   3049       //
   3050       // Replace symbols
   3051       //
   3052       ExpandSymbols (InLine, OutLine, sizeof (OutLine), EXPANDMODE_RECURSIVE);
   3053       fprintf (MakeFptr, OutLine);
   3054     }
   3055   }
   3056   //
   3057   // If there was a [makefile.platform] section in the description file,
   3058   // copy it (after symbol expansion) to the output file.
   3059   //
   3060   sprintf (InLine, "%s.%s", MAKEFILE_SECTION_NAME, "Platform");
   3061   Sect = DSCFileFindSection (DSCFile, InLine);
   3062   if (Sect != NULL) {
   3063     //
   3064     // Read lines, expand, then dump out
   3065     //
   3066     while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) {
   3067       //
   3068       // Replace symbols
   3069       //
   3070       ExpandSymbols (InLine, OutLine, sizeof (OutLine), EXPANDMODE_RECURSIVE);
   3071       fprintf (MakeFptr, OutLine);
   3072     }
   3073   }
   3074   //
   3075   // Do the same for any [makefile.$(PROCESSOR)]
   3076   //
   3077   sprintf (InLine, "%s.%s", MAKEFILE_SECTION_NAME, Processor);
   3078   Sect = DSCFileFindSection (DSCFile, InLine);
   3079   if (Sect != NULL) {
   3080     //
   3081     // Read lines, expand, then dump out
   3082     //
   3083     while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) {
   3084       ExpandSymbols (InLine, OutLine, sizeof (OutLine), EXPANDMODE_RECURSIVE);
   3085       fprintf (MakeFptr, OutLine);
   3086     }
   3087   }
   3088   //
   3089   // Same thing for [makefile.$(PROCESSOR).$(PLATFORM)]
   3090   //
   3091   Sym = GetSymbolValue (PLATFORM);
   3092   if (Sym != NULL) {
   3093     sprintf (InLine, "%s.%s.%s", MAKEFILE_SECTION_NAME, Processor, Sym);
   3094     Sect = DSCFileFindSection (DSCFile, InLine);
   3095     if (Sect != NULL) {
   3096       //
   3097       // Read lines, expand, then dump out
   3098       //
   3099       while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) {
   3100         ExpandSymbols (InLine, OutLine, sizeof (OutLine), EXPANDMODE_RECURSIVE);
   3101         fprintf (MakeFptr, OutLine);
   3102       }
   3103     }
   3104   }
   3105 
   3106   fprintf (MakeFptr, "\n");
   3107   DSCFileRestorePosition (DSCFile);
   3108   return 0;
   3109 }
   3110 
   3111 static
   3112 int
   3113 WriteComponentTypeBuildCommands (
   3114   DSC_FILE *DSCFile,
   3115   FILE     *MakeFptr,
   3116   INT8     *SectionName
   3117   )
   3118 /*++
   3119 
   3120 Routine Description:
   3121 
   3122    Given a section name such as [build.ia32.library], find the section in
   3123    the description file and copy the build commands.
   3124 
   3125 Arguments:
   3126 
   3127   DSCFile     - section information on the main description file
   3128   MakeFptr    - file pointer to the makefile we're writing to
   3129   SectionName - name of the section we're to copy out to the makefile.
   3130 
   3131 Returns:
   3132 
   3133   Always successful, since the section may be optional.
   3134 
   3135 --*/
   3136 {
   3137   SECTION *Sect;
   3138   INT8    InLine[MAX_LINE_LEN];
   3139   INT8    OutLine[MAX_EXP_LINE_LEN];
   3140 
   3141   //
   3142   // Don't mess up the original file pointer, since we're processing it at a higher
   3143   // level.
   3144   //
   3145   DSCFileSavePosition (DSCFile);
   3146   Sect = DSCFileFindSection (DSCFile, SectionName);
   3147   if (Sect != NULL) {
   3148     //
   3149     // Read lines, expand, then dump out
   3150     //
   3151     while (DSCFileGetLine (DSCFile, InLine, sizeof (InLine)) != NULL) {
   3152       ExpandSymbols (
   3153         InLine,
   3154         OutLine,
   3155         sizeof(OutLine),
   3156         EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
   3157         );
   3158       fprintf (MakeFptr, OutLine);
   3159     }
   3160   } else {
   3161     Warning (
   3162       NULL,
   3163       0,
   3164       0,
   3165       GetSymbolValue (INF_FILENAME),
   3166       "no [%s] build commands found in DSC file for component",
   3167       SectionName
   3168       );
   3169   }
   3170 
   3171   DSCFileRestorePosition (DSCFile);
   3172   return STATUS_SUCCESS;
   3173 }
   3174 
   3175 /*****************************************************************************
   3176 
   3177 ******************************************************************************/
   3178 static
   3179 int
   3180 WriteCompileCommands (
   3181   DSC_FILE  *DscFile,
   3182   FILE      *MakeFptr,
   3183   INT8      *FileName,
   3184   INT8      *Processor
   3185   )
   3186 {
   3187   FILE_NAME_PARTS *File;
   3188   SECTION         *Sect;
   3189   INT8            BuildSectionName[40];
   3190   INT8            InLine[MAX_LINE_LEN];
   3191   INT8            OutLine[MAX_EXP_LINE_LEN];
   3192   INT8            *SourceCompileType;
   3193   char            *CPtr;
   3194   char            *CPtr2;
   3195   //
   3196   // Determine the filename, then chop it up into its parts
   3197   //
   3198   File = GetFileParts (FileName);
   3199   if (File != NULL) {
   3200     //
   3201     // Don't mess up the original file pointer, since we're processing it at a higher
   3202     // level.
   3203     //
   3204     DSCFileSavePosition (DscFile);
   3205     //
   3206     // Option 1: SOURCE_COMPILE_TYPE=MyCompileSection
   3207     //           Find a section of that name from which to get the compile
   3208     //           commands for this source file.
   3209     //           Look for [compile.$(PROCESSOR).$(SOURCE_COMPILE_TYPE]
   3210     // Option 2: COMPILE_SELECT=.c=MyCCompile,.asm=MyAsm
   3211     //           Find a [compile.$(PROCESSOR).MyCompile] section from which to
   3212     //           get the compile commands for this source file.
   3213     //           Look for [compile.$(PROCESSOR).MyCompile]
   3214     // Option 3: Look for standard section types to compile the file by extension.
   3215     //           Look for [compile.$(PROCESSOR).<extension>]
   3216     //
   3217     Sect = NULL;
   3218     //
   3219     // Option 1 - use SOURCE_COMPILE_TYPE variable
   3220     //
   3221     SourceCompileType = GetSymbolValue (SOURCE_COMPILE_TYPE);
   3222     if (SourceCompileType != NULL) {
   3223       sprintf (BuildSectionName, "compile.%s.%s", Processor, SourceCompileType);
   3224       Sect = DSCFileFindSection (DscFile, BuildSectionName);
   3225     }
   3226     //
   3227     // Option 2 - use COMPILE_SELECT variable
   3228     //
   3229     if (Sect == NULL) {
   3230       SourceCompileType = GetSymbolValue (COMPILE_SELECT);
   3231       if (SourceCompileType != NULL) {
   3232         //
   3233         // Parse the variable, which looks like COMPILE_SELECT=.c=MyCCompiler;.asm=MyAsm;
   3234         // to find an entry with a matching file name extension. If you find one,
   3235         // then use that name to find the section name.
   3236         //
   3237         CPtr = SourceCompileType;
   3238         while (*CPtr && (Sect == NULL)) {
   3239           //
   3240           // See if we found a match with this source file name extension. File->Extension
   3241           // does not include the dot, so skip the dot in the COMPILE_SELECT variable if there
   3242           // is one.
   3243           //
   3244           if (*CPtr == '.') {
   3245             CPtr++;
   3246           }
   3247 
   3248           if (_strnicmp (CPtr, File->Extension, strlen (File->Extension)) == 0) {
   3249             //
   3250             // Found a file name extension match -- extract the name from the variable, for
   3251             // example "MyCCompiler"
   3252             //
   3253             while (*CPtr && (*CPtr != '=')) {
   3254               CPtr++;
   3255             }
   3256 
   3257             if ((*CPtr != '=') || (CPtr[1] == 0)) {
   3258               Error (NULL, 0, 0, SourceCompileType, "malformed COMPILE_SELECT variable");
   3259               break;
   3260             }
   3261 
   3262             CPtr++;
   3263             sprintf (BuildSectionName, "compile.%s.", Processor);
   3264             for (CPtr2 = BuildSectionName + strlen (BuildSectionName);
   3265                  *CPtr && (*CPtr != ',') && (*CPtr != ';');
   3266                  CPtr++
   3267                 ) {
   3268               *CPtr2 = *CPtr;
   3269               CPtr2++;
   3270             }
   3271 
   3272             *CPtr2  = 0;
   3273             Sect    = DSCFileFindSection (DscFile, BuildSectionName);
   3274             if (Sect == NULL) {
   3275               ParserError (
   3276                 0,
   3277                 BuildSectionName,
   3278                 "could not find section in DSC file - selected by COMPILE_SELECT variable"
   3279                 );
   3280             }
   3281           }
   3282 
   3283           //
   3284           // Skip to next file name extension in the COMPILE_SELECT variable
   3285           //
   3286           while (*CPtr && (*CPtr != ';') && (*CPtr != ',')) {
   3287             CPtr++;
   3288           }
   3289 
   3290           if (*CPtr) {
   3291             CPtr++;
   3292           }
   3293         }
   3294       }
   3295     }
   3296     //
   3297     // Option 3 - use "Compile.$(PROCESSOR).<Extension>" section
   3298     //
   3299     if (Sect == NULL) {
   3300       sprintf (BuildSectionName, "compile.%s.%s", Processor, File->Extension);
   3301       Sect = DSCFileFindSection (DscFile, BuildSectionName);
   3302     }
   3303     //
   3304     // Should have found something by now unless it's an include (.h) file
   3305     //
   3306     if (Sect != NULL) {
   3307       //
   3308       // Temporarily add a FILE variable to the global symbol table. Omit the
   3309       // extension.
   3310       //
   3311       sprintf (InLine, "%s%s%s", File->Drive, File->Path, File->BaseName);
   3312       AddSymbol ("FILE", InLine, SYM_OVERWRITE | SYM_LOCAL | SYM_FILENAME);
   3313       //
   3314       // Read lines, expand (except SOURCE_DIR and DEST_DIR), then dump out
   3315       //
   3316       while (DSCFileGetLine (DscFile, InLine, sizeof (InLine)) != NULL) {
   3317         ExpandSymbols (
   3318           InLine,
   3319           OutLine,
   3320           sizeof (OutLine),
   3321           EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
   3322           );
   3323         fprintf (MakeFptr, OutLine);
   3324       }
   3325       fprintf (MakeFptr, "\n");
   3326     } else {
   3327       //
   3328       // Be nice and ignore include files
   3329       //
   3330       if (!IsIncludeFile (FileName)) {
   3331         Error (
   3332           NULL,
   3333           0,
   3334           0,
   3335           NULL,
   3336           "no compile commands section [%s] found in DSC file for %s",
   3337           BuildSectionName,
   3338           FileName
   3339           );
   3340       }
   3341     }
   3342 
   3343     DSCFileRestorePosition (DscFile);
   3344     FreeFileParts (File);
   3345   }
   3346 
   3347   return STATUS_SUCCESS;
   3348 }
   3349 
   3350 /*****************************************************************************
   3351 ******************************************************************************/
   3352 static
   3353 int
   3354 SetFileExtension (
   3355   INT8 *FileName,
   3356   INT8 *Extension
   3357   )
   3358 {
   3359   INT8  *Cptr;
   3360 
   3361   Cptr = FileName + strlen (FileName) - 1;
   3362   while ((Cptr > FileName) && (*Cptr != '.')) {
   3363     Cptr--;
   3364 
   3365   }
   3366   //
   3367   // Better be a dot
   3368   //
   3369   if (*Cptr != '.') {
   3370     Message (2, "Missing filename extension: %s", FileName);
   3371     return STATUS_WARNING;
   3372   }
   3373 
   3374   Cptr++;
   3375   if (*Extension == '.') {
   3376     Extension++;
   3377   }
   3378 
   3379   strcpy (Cptr, Extension);
   3380   return STATUS_SUCCESS;
   3381 }
   3382 
   3383 /*****************************************************************************
   3384 ******************************************************************************/
   3385 int
   3386 MakeFilePath (
   3387   INT8 *FileName
   3388   )
   3389 {
   3390   INT8  *Cptr;
   3391   INT8  SavedChar;
   3392   INT8  BuildDir[MAX_PATH];
   3393   INT8  CopyFileName[MAX_PATH];
   3394 
   3395   //
   3396   // Expand symbols in the filename
   3397   //
   3398   if (ExpandSymbols (FileName, CopyFileName, sizeof (CopyFileName), EXPANDMODE_NO_UNDEFS)) {
   3399     Error (NULL, 0, 0, NULL, "undefined symbols in file path: %s", FileName);
   3400     return STATUS_ERROR;
   3401   }
   3402   //
   3403   // Copy it back
   3404   //
   3405   strcpy (FileName, CopyFileName);
   3406   //
   3407   // To avoid creating $(BUILD_DIR) path, see if this path is the same as
   3408   // $(BUILD_DIR), and if it is, see if build dir exists and skip over that
   3409   // portion if it does
   3410   //
   3411   Cptr = GetSymbolValue (BUILD_DIR);
   3412   if (Cptr != NULL) {
   3413     if (_strnicmp (Cptr, FileName, strlen (Cptr)) == 0) {
   3414       //
   3415       // BUILD_DIR path. See if it exists
   3416       //
   3417       strcpy (BuildDir, FileName);
   3418       BuildDir[strlen (Cptr)] = 0;
   3419       if ((_mkdir (BuildDir) != 0) && (errno != EEXIST)) {
   3420         Cptr = FileName;
   3421       } else {
   3422         //
   3423         // Already done. Shortcut. Skip to next path so that we don't create
   3424         // the BUILD_DIR as well.
   3425         //
   3426         Cptr = FileName + strlen (Cptr);
   3427         if (*Cptr == '\\') {
   3428           Cptr++;
   3429         }
   3430       }
   3431     } else {
   3432       //
   3433       // Not build dir
   3434       //
   3435       Cptr = FileName;
   3436     }
   3437   } else {
   3438     Cptr = FileName;
   3439   }
   3440   //
   3441   // Create directories until done. Skip over "c:\" in the path if it exists
   3442   //
   3443   if (*Cptr && (*(Cptr + 1) == ':') && (*(Cptr + 2) == '\\')) {
   3444     Cptr += 3;
   3445   }
   3446 
   3447   for (;;) {
   3448     for (; *Cptr && (*Cptr != '\\'); Cptr++)
   3449       ;
   3450     if (*Cptr) {
   3451       SavedChar = *Cptr;
   3452       *Cptr     = 0;
   3453       if ((_mkdir (FileName) != 0)) {
   3454         //
   3455         //        Error (NULL, 0, 0, FileName, "failed to create directory");
   3456         //        return 1;
   3457         //
   3458       }
   3459 
   3460       *Cptr = SavedChar;
   3461       Cptr++;
   3462     } else {
   3463       break;
   3464     }
   3465   }
   3466 
   3467   return STATUS_SUCCESS;
   3468 }
   3469 
   3470 /*****************************************************************************
   3471 ******************************************************************************/
   3472 int
   3473 ExpandSymbols (
   3474   INT8  *SourceLine,
   3475   INT8  *DestLine,
   3476   int   LineLen,
   3477   int   ExpandMode
   3478   )
   3479 {
   3480   static int  NestDepth = 0;
   3481   INT8        *FromPtr;
   3482   INT8        *ToPtr;
   3483   INT8        *SaveStart;
   3484   INT8        *Cptr;
   3485   INT8        *value;
   3486   int         Expanded;
   3487   int         ExpandedCount;
   3488   INT8        *LocalDestLine;
   3489   STATUS      Status;
   3490   int         LocalLineLen;
   3491 
   3492   NestDepth++;
   3493   Status        = STATUS_SUCCESS;
   3494   LocalDestLine = (INT8 *) malloc (LineLen);
   3495   if (LocalDestLine == NULL) {
   3496     Error (__FILE__, __LINE__, 0, "application error", "memory allocation failed");
   3497     NestDepth = 0;
   3498     return STATUS_ERROR;
   3499   }
   3500 
   3501   FromPtr = SourceLine;
   3502   ToPtr   = LocalDestLine;
   3503   //
   3504   // Walk the entire line, replacing $(SYMBOL_NAME).
   3505   //
   3506   LocalLineLen  = LineLen;
   3507   ExpandedCount = 0;
   3508   while (*FromPtr && (LocalLineLen > 0)) {
   3509     if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) {
   3510       //
   3511       // Save the start in case it's undefined, in which case we copy it as-is.
   3512       //
   3513       SaveStart = FromPtr;
   3514       Expanded  = 0;
   3515       //
   3516       // Symbol expansion time. Find the end (no spaces allowed)
   3517       //
   3518       FromPtr += 2;
   3519       for (Cptr = FromPtr; *Cptr && (*Cptr != ')'); Cptr++)
   3520         ;
   3521       if (*Cptr) {
   3522         //
   3523         // Truncate the string at the closing parenthesis for ease-of-use.
   3524         // Then copy the string directly to the destination line in case we don't find
   3525         // a definition for it.
   3526         //
   3527         *Cptr = 0;
   3528         strcpy (ToPtr, SaveStart);
   3529         if ((_stricmp (SOURCE_DIR, FromPtr) == 0) && (ExpandMode & EXPANDMODE_NO_SOURCEDIR)) {
   3530           //
   3531           // excluded this expansion
   3532           //
   3533         } else if ((_stricmp (DEST_DIR, FromPtr) == 0) && (ExpandMode & EXPANDMODE_NO_DESTDIR)) {
   3534           //
   3535           // excluded this expansion
   3536           //
   3537         } else if ((value = GetSymbolValue (FromPtr)) != NULL) {
   3538           strcpy (ToPtr, value);
   3539           LocalLineLen -= strlen (value);
   3540           ToPtr += strlen (value);
   3541           Expanded = 1;
   3542           ExpandedCount++;
   3543         } else if (ExpandMode & EXPANDMODE_NO_UNDEFS) {
   3544           Error (NULL, 0, 0, "undefined symbol", "$(%s)", FromPtr);
   3545           Status = STATUS_ERROR;
   3546           goto Done;
   3547         }
   3548 
   3549         //
   3550         // Restore closing parenthesis, and advance to next character
   3551         //
   3552         *Cptr   = ')';
   3553         if (!Expanded) {
   3554           FromPtr = SaveStart + 1;
   3555           ToPtr++;
   3556         } else {
   3557           FromPtr = Cptr + 1;
   3558         }
   3559       } else {
   3560         Error (NULL, 0, 0, SourceLine, "missing closing parenthesis on symbol");
   3561         strcpy (ToPtr, FromPtr);
   3562         Status = STATUS_WARNING;
   3563         goto Done;
   3564       }
   3565     } else {
   3566       *ToPtr = *FromPtr;
   3567       FromPtr++;
   3568       ToPtr++;
   3569       LocalLineLen--;
   3570     }
   3571   }
   3572 
   3573   if (*FromPtr == 0) {
   3574     *ToPtr = 0;
   3575   }
   3576 
   3577   //
   3578   // If we're in recursive mode, and we expanded at least one string successfully,
   3579   // then make a recursive call to try again.
   3580   //
   3581   if ((ExpandedCount != 0) && (Status == STATUS_SUCCESS) && (ExpandMode & EXPANDMODE_RECURSIVE) && (NestDepth < 2)) {
   3582     Status = ExpandSymbols (LocalDestLine, DestLine, LineLen, ExpandMode);
   3583     free (LocalDestLine);
   3584     NestDepth = 0;
   3585     return Status;
   3586   }
   3587 
   3588 Done:
   3589   if (Status != STATUS_ERROR) {
   3590     strcpy (DestLine, LocalDestLine);
   3591   }
   3592 
   3593   NestDepth = 0;
   3594   free (LocalDestLine);
   3595   return Status;
   3596 }
   3597 
   3598 INT8 *
   3599 GetSymbolValue (
   3600   INT8 *SymbolName
   3601   )
   3602 /*++
   3603 
   3604 Routine Description:
   3605 
   3606   Look up a symbol in our symbol table.
   3607 
   3608 Arguments:
   3609 
   3610   SymbolName - The name of symbol.
   3611 
   3612 Returns:
   3613 
   3614   Pointer to the value of the symbol if found
   3615   NULL if the symbol is not found
   3616 
   3617 --*/
   3618 {
   3619   SYMBOL  *Symbol;
   3620 
   3621   //
   3622   // Scan once for file-level symbols
   3623   //
   3624   Symbol = gGlobals.Symbol;
   3625   while (Symbol) {
   3626     if ((_stricmp (SymbolName, Symbol->Name) == 0) && (Symbol->Type & SYM_FILE)) {
   3627       return Symbol->Value;
   3628     }
   3629 
   3630     Symbol = Symbol->Next;
   3631   }
   3632   //
   3633   // Scan once for local symbols
   3634   //
   3635   Symbol = gGlobals.Symbol;
   3636   while (Symbol) {
   3637     if ((_stricmp (SymbolName, Symbol->Name) == 0) && (Symbol->Type & SYM_LOCAL)) {
   3638       return Symbol->Value;
   3639     }
   3640 
   3641     Symbol = Symbol->Next;
   3642   }
   3643   //
   3644   // No local value found. Scan for globals.
   3645   //
   3646   Symbol = gGlobals.Symbol;
   3647   while (Symbol) {
   3648     if ((_stricmp (SymbolName, Symbol->Name) == 0) && (Symbol->Type & SYM_GLOBAL)) {
   3649       return Symbol->Value;
   3650     }
   3651 
   3652     Symbol = Symbol->Next;
   3653   }
   3654   //
   3655   // For backwards-compatibility, if it's "GUID", return FILE_GUID value
   3656   //
   3657   if (_stricmp (SymbolName, GUID) == 0) {
   3658     return GetSymbolValue (FILE_GUID);
   3659   }
   3660 
   3661   return NULL;
   3662 }
   3663 
   3664 static
   3665 int
   3666 RemoveLocalSymbols (
   3667   VOID
   3668   )
   3669 /*++
   3670 
   3671 Routine Description:
   3672 
   3673   Remove all local symbols from the symbol table. Local symbols are those
   3674   that are defined typically by the component's INF file.
   3675 
   3676 Arguments:
   3677 
   3678   None.
   3679 
   3680 Returns:
   3681 
   3682   Right now, never fails.
   3683 
   3684 --*/
   3685 {
   3686   SYMBOL  *Sym;
   3687   int     FoundOne;
   3688 
   3689   do {
   3690     FoundOne  = 0;
   3691     Sym       = gGlobals.Symbol;
   3692     while (Sym) {
   3693       if (Sym->Type & SYM_LOCAL) {
   3694         //
   3695         // Going to delete it out from under ourselves, so break and restart
   3696         //
   3697         FoundOne = 1;
   3698         RemoveSymbol (Sym->Name, SYM_LOCAL);
   3699         break;
   3700       }
   3701 
   3702       Sym = Sym->Next;
   3703     }
   3704   } while (FoundOne);
   3705   return STATUS_SUCCESS;
   3706 }
   3707 
   3708 static
   3709 int
   3710 RemoveFileSymbols (
   3711   VOID
   3712   )
   3713 /*++
   3714 
   3715 Routine Description:
   3716 
   3717   Remove all file-level symbols from the symbol table. File-level symbols are
   3718   those that are defined on a source file line in an INF file.
   3719 
   3720 Arguments:
   3721 
   3722   None.
   3723 
   3724 Returns:
   3725 
   3726   Right now, never fails.
   3727 
   3728 --*/
   3729 {
   3730   SYMBOL  *Sym;
   3731   int     FoundOne;
   3732 
   3733   do {
   3734     FoundOne  = 0;
   3735     Sym       = gGlobals.Symbol;
   3736     while (Sym) {
   3737       if (Sym->Type & SYM_FILE) {
   3738         //
   3739         // Going to delete it out from under ourselves, so break and restart
   3740         //
   3741         FoundOne = 1;
   3742         RemoveSymbol (Sym->Name, SYM_FILE);
   3743         break;
   3744       }
   3745 
   3746       Sym = Sym->Next;
   3747     }
   3748   } while (FoundOne);
   3749   return STATUS_SUCCESS;
   3750 }
   3751 
   3752 static
   3753 STATUS
   3754 ParseGuidDatabaseFile (
   3755   INT8 *FileName
   3756   )
   3757 /*++
   3758 
   3759 Routine Description:
   3760   This function parses a GUID-to-basename text file (perhaps output by
   3761   the GuidChk utility) to define additional symbols. The format of the
   3762   file should be:
   3763 
   3764   7BB28B99-61BB-11D5-9A5D-0090273FC14D EFI_DEFAULT_BMP_LOGO_GUID gEfiDefaultBmpLogoGuid
   3765 
   3766   This function parses the line and defines global symbol:
   3767 
   3768     EFI_DEFAULT_BMP_LOGO_GUID=7BB28B99-61BB-11D5-9A5D-0090273FC14D
   3769 
   3770   This symbol (rather than the actual GUID) can then be used in INF files to
   3771   fix duplicate GUIDs
   3772 
   3773 Arguments:
   3774   FileName  - the name of the file to parse.
   3775 
   3776 Returns:
   3777   STATUS_ERROR    - could not open FileName
   3778   STATUS_SUCCESS  - we opened the file
   3779 
   3780 --*/
   3781 {
   3782   FILE  *Fptr;
   3783   INT8  Line[100];
   3784   INT8  Guid[100];
   3785   INT8  DefineName[80];
   3786 
   3787   Fptr = fopen (FileName, "r");
   3788   if (Fptr == NULL) {
   3789     Error (NULL, 0, 0, FileName, "failed to open input GUID database input file");
   3790     return STATUS_ERROR;
   3791   }
   3792 
   3793   while (fgets (Line, sizeof (Line), Fptr) != NULL) {
   3794     //
   3795     // Get the GUID string, skip the defined name (EFI_XXX_GUID), and get the
   3796     // variable name (gWhateverProtocolGuid)
   3797     //
   3798     if (sscanf (Line, "%s %s %*s", Guid, DefineName) == 2) {
   3799       AddSymbol (DefineName, Guid, SYM_GLOBAL);
   3800     }
   3801   }
   3802 
   3803   fclose (Fptr);
   3804   return STATUS_SUCCESS;
   3805 }
   3806 
   3807 /*****************************************************************************
   3808 
   3809   Returns:
   3810      0 if successful standard add
   3811     length of the parsed string if passed in " name = value  "
   3812     < 0 on error
   3813 
   3814 ******************************************************************************/
   3815 int
   3816 AddSymbol (
   3817   INT8    *Name,
   3818   INT8    *Value,
   3819   int     Mode
   3820   )
   3821 {
   3822   SYMBOL  *Symbol;
   3823   SYMBOL  *NewSymbol;
   3824   int     Len;
   3825   INT8    *Start;
   3826   INT8    *Cptr;
   3827   INT8    CSave1;
   3828   INT8    *SaveCptr1;
   3829   INT8    CSave2;
   3830   INT8    *SaveCptr2;
   3831   INT8    ShortName[MAX_PATH];
   3832 
   3833   Len           = 0;
   3834   SaveCptr1     = NULL;
   3835   CSave1        = 0;
   3836   SaveCptr2     = NULL;
   3837   CSave2        = 0;
   3838 
   3839   ShortName[0]  = 0;
   3840   //
   3841   // Mode better be local or global symbol
   3842   //
   3843   if ((Mode & (SYM_LOCAL | SYM_GLOBAL | SYM_FILE)) == 0) {
   3844     Error (NULL, 0, 0, "APP ERROR", "adding symbol '%s' that is not local, global, nor file level", Name);
   3845     return -1;
   3846   }
   3847   //
   3848   // If value pointer is null, then they passed us a line something like:
   3849   //    varname = value, or simply var =
   3850   //
   3851   if (Value == NULL) {
   3852     Start = Name;
   3853     while (*Name && isspace (*Name)) {
   3854       Name++;
   3855 
   3856     }
   3857 
   3858     if (!*Name) {
   3859       return -1;
   3860     }
   3861     //
   3862     // Find the end of the name. Either space or a '='.
   3863     //
   3864     for (Value = Name; *Value && !isspace (*Value) && (*Value != '='); Value++)
   3865       ;
   3866     if (!*Value) {
   3867       return -1;
   3868     }
   3869     //
   3870     // Look for the '='
   3871     //
   3872     Cptr = Value;
   3873     while (*Value && (*Value != '=')) {
   3874       Value++;
   3875     }
   3876 
   3877     if (!*Value) {
   3878       return -1;
   3879     }
   3880 
   3881     //
   3882     // Now truncate the name
   3883     //
   3884     CSave1    = *Cptr;
   3885     SaveCptr1 = Cptr;
   3886     *Cptr     = 0;
   3887 
   3888     //
   3889     // Skip over the = and then any spaces
   3890     //
   3891     Value++;
   3892     while (*Value && isspace (*Value)) {
   3893       Value++;
   3894 
   3895     }
   3896     //
   3897     // Find end of string, checking for quoted string
   3898     //
   3899     if (*Value == '\"') {
   3900       Value++;
   3901       for (Cptr = Value; *Cptr && *Cptr != '\"'; Cptr++)
   3902         ;
   3903     } else {
   3904       for (Cptr = Value; *Cptr && !isspace (*Cptr); Cptr++)
   3905         ;
   3906     }
   3907     //
   3908     // Null terminate the value string
   3909     //
   3910     if (*Cptr) {
   3911       Len = (int) (Cptr - Start) + 1;
   3912       CSave2    = *Cptr;
   3913       SaveCptr2 = Cptr;
   3914       *Cptr     = 0;
   3915     } else {
   3916       Len = (int) (Cptr - Start);
   3917     }
   3918   }
   3919 
   3920   //
   3921   // If file name or file path, and we're shortening, then print it
   3922   //
   3923   if ((Mode & (SYM_FILEPATH | SYM_FILENAME)) && (GetSymbolValue (SHORT_NAMES) != NULL)) {
   3924     if (GetShortPathName (Value, ShortName, sizeof (ShortName)) > 0) {
   3925       //
   3926       // fprintf (stdout, "String value '%s' shortened to '%s'\n",
   3927       //    Value, ShortName);
   3928       //
   3929       Value = ShortName;
   3930     } else {
   3931       //
   3932       // fprintf (stdout, "WARNING: Failed to get short name for %s\n", Value);
   3933       //
   3934     }
   3935   }
   3936   //
   3937   // We now have a symbol name and a value. Look for an existing variable of
   3938   // the same type (global or local) and overwrite it.
   3939   //
   3940   Symbol = gGlobals.Symbol;
   3941   while (Symbol) {
   3942     //
   3943     // Check for symbol name match
   3944     //
   3945     if (_stricmp (Name, Symbol->Name) == 0) {
   3946       //
   3947       // See if this symbol is of the same type (global or local) as what
   3948       // they're requesting
   3949       //
   3950       if ((Symbol->Type & (SYM_LOCAL | SYM_GLOBAL)) == (Mode & (SYM_LOCAL | SYM_GLOBAL))) {
   3951         //
   3952         // Did they say we could overwrite it?
   3953         //
   3954         if (Mode & SYM_OVERWRITE) {
   3955           free (Symbol->Value);
   3956           Symbol->Value = (INT8 *) malloc (strlen (Value) + 1);
   3957           if (Symbol->Value == NULL) {
   3958             Error (NULL, 0, 0, NULL, "failed to allocate memory");
   3959             return -1;
   3960           }
   3961 
   3962           strcpy (Symbol->Value, Value);
   3963           //
   3964           // If value == "NULL", then make it a 0-length string
   3965           //
   3966           if (_stricmp (Symbol->Value, "NULL") == 0) {
   3967             Symbol->Value[0] = 0;
   3968           }
   3969 
   3970           return Len;
   3971         } else {
   3972           return STATUS_ERROR;
   3973         }
   3974       }
   3975     }
   3976 
   3977     Symbol = Symbol->Next;
   3978   }
   3979   //
   3980   // Does not exist, create a new one
   3981   //
   3982   NewSymbol = (SYMBOL *) malloc (sizeof (SYMBOL));
   3983   if (NewSymbol == NULL) {
   3984     Error (NULL, 0, 0, NULL, "failed to allocate memory");
   3985     return -1;
   3986   }
   3987 
   3988   memset ((INT8 *) NewSymbol, 0, sizeof (SYMBOL));
   3989   NewSymbol->Name   = (INT8 *) malloc (strlen (Name) + 1);
   3990   NewSymbol->Value  = (INT8 *) malloc (strlen (Value) + 1);
   3991   //
   3992   // Simply use the mode bits as the type.
   3993   //
   3994   NewSymbol->Type = Mode;
   3995   if ((NewSymbol->Name == NULL) || (NewSymbol->Value == NULL)) {
   3996     Error (NULL, 0, 0, NULL, "failed to allocate memory");
   3997     return -1;
   3998   }
   3999 
   4000   strcpy (NewSymbol->Name, Name);
   4001   strcpy (NewSymbol->Value, Value);
   4002   //
   4003   // Remove trailing spaces
   4004   //
   4005   Cptr = NewSymbol->Value + strlen (NewSymbol->Value) - 1;
   4006   while (Cptr > NewSymbol->Value) {
   4007     if (isspace (*Cptr)) {
   4008       *Cptr = 0;
   4009       Cptr--;
   4010     } else {
   4011       break;
   4012     }
   4013   }
   4014   //
   4015   // Add it to the head of the list.
   4016   //
   4017   NewSymbol->Next = gGlobals.Symbol;
   4018   gGlobals.Symbol = NewSymbol;
   4019   //
   4020   // If value == "NULL", then make it a 0-length string
   4021   //
   4022   if (_stricmp (NewSymbol->Value, "NULL") == 0) {
   4023     NewSymbol->Value[0] = 0;
   4024   }
   4025   //
   4026   // Restore the terminator we inserted if they passed in var=value
   4027   //
   4028   if (SaveCptr1 != NULL) {
   4029     *SaveCptr1 = CSave1;
   4030   }
   4031   if (SaveCptr2 != NULL) {
   4032     *SaveCptr2 = CSave2;
   4033   }
   4034 
   4035   return Len;
   4036 }
   4037 
   4038 /*****************************************************************************
   4039 ******************************************************************************/
   4040 static
   4041 int
   4042 RemoveSymbol (
   4043   INT8 *Name,
   4044   INT8 SymbolType
   4045   )
   4046 {
   4047   SYMBOL  *Symbol;
   4048   SYMBOL  *PrevSymbol;
   4049 
   4050   PrevSymbol  = NULL;
   4051   Symbol      = gGlobals.Symbol;
   4052   while (Symbol) {
   4053     if ((_stricmp (Name, Symbol->Name) == 0) && (Symbol->Type & SymbolType)) {
   4054       if (Symbol->Value) {
   4055         free (Symbol->Value);
   4056       }
   4057 
   4058       free (Symbol->Name);
   4059       if (PrevSymbol) {
   4060         PrevSymbol->Next = Symbol->Next;
   4061       } else {
   4062         gGlobals.Symbol = Symbol->Next;
   4063       }
   4064 
   4065       free (Symbol);
   4066       return STATUS_SUCCESS;
   4067     }
   4068 
   4069     PrevSymbol  = Symbol;
   4070     Symbol      = Symbol->Next;
   4071   }
   4072 
   4073   return STATUS_WARNING;
   4074 }
   4075 
   4076 #if 0
   4077 
   4078 /*****************************************************************************
   4079 ******************************************************************************/
   4080 static
   4081 void
   4082 FreeSections (
   4083   SECTION *Sect
   4084   )
   4085 {
   4086   SECTION *Next;
   4087 
   4088   while (Sect != NULL) {
   4089     Next = Sect->Next;
   4090     if (Sect->Name != NULL) {
   4091       delete[] Sect->Name;
   4092     }
   4093 
   4094     delete Sect;
   4095     Sect = Next;
   4096   }
   4097 }
   4098 #endif
   4099 
   4100 /*****************************************************************************
   4101 ******************************************************************************/
   4102 static
   4103 INT8 *
   4104 StripLine (
   4105   INT8 *Line
   4106   )
   4107 {
   4108   INT8  *Cptr;
   4109   int   Len;
   4110 
   4111   Cptr = Line;
   4112   //
   4113   // Look for '#' comments in first character of line
   4114   //
   4115   if (*Cptr == '#') {
   4116     *Cptr = 0;
   4117     return Cptr;
   4118   }
   4119 
   4120   while (isspace (*Cptr)) {
   4121     Cptr++;
   4122   }
   4123   //
   4124   // Hack off newlines
   4125   //
   4126   Len = strlen (Cptr);
   4127   if ((Len > 0) && (Cptr[Len - 1] == '\n')) {
   4128     Cptr[Len - 1] = 0;
   4129   }
   4130   //
   4131   // Hack off trailing spaces
   4132   //
   4133   StripTrailingSpaces (Cptr);
   4134   return Cptr;
   4135 }
   4136 
   4137 /*****************************************************************************
   4138   FUNCTION:  ProcessOptions()
   4139 
   4140   DESCRIPTION: Process the command-line options.
   4141 ******************************************************************************/
   4142 static
   4143 int
   4144 ProcessOptions (
   4145   int   Argc,
   4146   INT8  *Argv[]
   4147   )
   4148 /*++
   4149 
   4150 Routine Description:
   4151 
   4152   Process the command line options to this utility.
   4153 
   4154 Arguments:
   4155 
   4156   Argc   - Standard Argc.
   4157   Argv[] - Standard Argv.
   4158 
   4159 Returns:
   4160 
   4161 --*/
   4162 {
   4163   INT8  *Cptr;
   4164   int   FreeCwd;
   4165 
   4166   //
   4167   // Clear out the options
   4168   //
   4169   memset ((INT8 *) &gGlobals, 0, sizeof (gGlobals));
   4170 
   4171   Argc--;
   4172   Argv++;
   4173 
   4174   if (Argc == 0) {
   4175     Usage ();
   4176     return STATUS_ERROR;
   4177   }
   4178   //
   4179   // Now process the arguments
   4180   //
   4181   while (Argc > 0) {
   4182 
   4183     if ((Argv[0][0] == '-') || (Argv[0][0] == '/')) {
   4184       switch (Argv[0][1]) {
   4185       //
   4186       // -? or -h help option
   4187       //
   4188       case '?':
   4189       case 'h':
   4190       case 'H':
   4191         Usage ();
   4192         return STATUS_ERROR;
   4193 
   4194       //
   4195       // /d symbol=name
   4196       //
   4197       case 'd':
   4198       case 'D':
   4199         //
   4200         // Skip to next arg
   4201         //
   4202         Argc--;
   4203         Argv++;
   4204         if (Argc == 0) {
   4205           Argv--;
   4206           Error (NULL, 0, 0, NULL, "missing symbol definition with %c%c", Argv[0][0], Argv[0][1]);
   4207           return STATUS_ERROR;
   4208         } else {
   4209           if (AddSymbol (Argv[0], NULL, SYM_OVERWRITE | SYM_GLOBAL) <= 0) {
   4210             Warning (NULL, 0, 0, Argv[0], "failed to add symbol: %s");
   4211           }
   4212         }
   4213         break;
   4214 
   4215       //
   4216       // output makefile name
   4217       //
   4218       case 'm':
   4219       case 'M':
   4220         //
   4221         // Skip to next arg
   4222         //
   4223         Argc--;
   4224         Argv++;
   4225         if (Argc == 0) {
   4226           Argv--;
   4227           Error (NULL, 0, 0, Argv[0], "missing output makefile name with option");
   4228           Usage ();
   4229           return STATUS_ERROR;
   4230         } else {
   4231           strcpy (gGlobals.MakefileName, Argv[0]);
   4232         }
   4233         break;
   4234 
   4235       //
   4236       // Print a cross-reference file containing guid/basename/processor
   4237       //
   4238       case 'x':
   4239       case 'X':
   4240         //
   4241         // Skip to next arg
   4242         //
   4243         Argc--;
   4244         Argv++;
   4245         if (Argc == 0) {
   4246           Argv--;
   4247           Error (NULL, 0, 0, Argv[0], "missing cross-reference output filename with option");
   4248           Usage ();
   4249           return STATUS_ERROR;
   4250         } else {
   4251           strcpy (gGlobals.XRefFileName, Argv[0]);
   4252         }
   4253         break;
   4254 
   4255       //
   4256       // GUID database file to preparse
   4257       //
   4258       case 'g':
   4259       case 'G':
   4260         //
   4261         // Skip to next arg
   4262         //
   4263         Argc--;
   4264         Argv++;
   4265         if (Argc == 0) {
   4266           Argv--;
   4267           Error (NULL, 0, 0, Argv[0], "missing input GUID database filename with option");
   4268           Usage ();
   4269           return STATUS_ERROR;
   4270         } else {
   4271           strcpy (gGlobals.GuidDatabaseFileName, Argv[0]);
   4272         }
   4273         break;
   4274 
   4275       //
   4276       // Enable multi-thread build and specify the thread number
   4277       //
   4278       case 'n':
   4279       case 'N':
   4280         //
   4281         // Skip to next arg
   4282         //
   4283         Argc--;
   4284         Argv++;
   4285         if (Argc == 0) {
   4286           Argv--;
   4287           Error (NULL, 0, 0, Argv[0], "missing input thread number with option");
   4288           Usage ();
   4289           return STATUS_ERROR;
   4290         } else {
   4291           gGlobals.ThreadNumber = atoi (Argv[0]);
   4292           if (gGlobals.ThreadNumber == 0) {
   4293             Argv--;
   4294             Error (NULL, 0, 0, Argv[0], "input thread number should not be %s", Argv[1]);
   4295             return STATUS_ERROR;
   4296           } else if (gGlobals.ThreadNumber > MAXIMUM_WAIT_OBJECTS) {
   4297             Argv--;
   4298             Error (NULL, 0, 0, Argv[0], "input thread number should not greater than %d", MAXIMUM_WAIT_OBJECTS);
   4299             return STATUS_ERROR;
   4300           }
   4301         }
   4302         break;
   4303 
   4304       //
   4305       // Specify the multi-thread build target
   4306       //
   4307       case 't':
   4308       case 'T':
   4309         //
   4310         // Skip to next arg
   4311         //
   4312         Argc--;
   4313         Argv++;
   4314         if (Argc == 0) {
   4315           Argv--;
   4316           Error (NULL, 0, 0, Argv[0], "missing input build target with option");
   4317           Usage ();
   4318           return STATUS_ERROR;
   4319         } else if (_stricmp (Argv[0], "all") == 0) {
   4320           gGlobals.BuildTarget |= BUILD_TARGET_ALL;
   4321         } else if (_stricmp (Argv[0], "libraries") == 0) {
   4322           gGlobals.BuildTarget |= BUILD_TARGET_LIBRARIES;
   4323         } else if (_stricmp (Argv[0], "components") == 0) {
   4324           gGlobals.BuildTarget |= BUILD_TARGET_COMPONENTS;
   4325         } else {
   4326           Argv--;
   4327           Error (NULL, 0, 0, Argv[0], "input build target not supported");
   4328           Usage ();
   4329         }
   4330         break;
   4331 
   4332       case 'v':
   4333       case 'V':
   4334         gGlobals.Verbose = 1;
   4335         break;
   4336 
   4337       default:
   4338         Error (NULL, 0, 0, Argv[0], "unrecognized option");
   4339         return STATUS_ERROR;
   4340       }
   4341     } else {
   4342       break;
   4343     }
   4344 
   4345     Argc--;
   4346     Argv++;
   4347   }
   4348   //
   4349   // Must be at least one arg left
   4350   //
   4351   if (Argc > 0) {
   4352     gGlobals.DscFilename = Argv[0];
   4353   }
   4354 
   4355   if (gGlobals.DscFilename == NULL) {
   4356     Error (NULL, 0, 0, NULL, "must specify DSC filename on command line");
   4357     return STATUS_ERROR;
   4358   }
   4359   //
   4360   // Make a global symbol for the DSC filename
   4361   //
   4362   AddSymbol (DSC_FILENAME, gGlobals.DscFilename, SYM_GLOBAL | SYM_FILENAME);
   4363   //
   4364   // If no output makefile specified, take the default
   4365   //
   4366   if (gGlobals.MakefileName[0] == 0) {
   4367     strcpy (gGlobals.MakefileName, MAKEFILE_OUT_NAME);
   4368   }
   4369   //
   4370   // Get the current working directory and use it for the build directory.
   4371   // Only do this if they have not defined it on the command line. Do the
   4372   // same for the bin dir, output dir, and library directory.
   4373   //
   4374   Cptr = GetSymbolValue (BUILD_DIR);
   4375   if (Cptr == NULL) {
   4376     Cptr    = _getcwd (NULL, 0);
   4377     FreeCwd = 1;
   4378     AddSymbol (BUILD_DIR, Cptr, SYM_OVERWRITE | SYM_GLOBAL | SYM_FILEPATH);
   4379   } else {
   4380     ReplaceSlash (Cptr);
   4381     FreeCwd = 0;
   4382   }
   4383 
   4384   if (FreeCwd) {
   4385     free (Cptr);
   4386   }
   4387 
   4388   //
   4389   // Default build target is all
   4390   //
   4391   if (gGlobals.BuildTarget == 0) {
   4392     gGlobals.BuildTarget = BUILD_TARGET_ALL;
   4393   }
   4394 
   4395   return 0;
   4396 }
   4397 
   4398 /*****************************************************************************
   4399 ******************************************************************************/
   4400 static
   4401 SYMBOL *
   4402 FreeSymbols (
   4403   SYMBOL *Syms
   4404   )
   4405 {
   4406   SYMBOL  *Next;
   4407   while (Syms) {
   4408 
   4409     if (Syms->Name != NULL) {
   4410       free (Syms->Name);
   4411     }
   4412 
   4413     if (Syms->Value != NULL) {
   4414       free (Syms->Value);
   4415     }
   4416 
   4417     Next = Syms->Next;
   4418     free (Syms);
   4419     Syms = Next;
   4420   }
   4421 
   4422   return Syms;
   4423 }
   4424 
   4425 /*****************************************************************************
   4426 ******************************************************************************/
   4427 static
   4428 int
   4429 GetSourceFileType (
   4430   INT8 *FileName
   4431   )
   4432 {
   4433   INT8  *Cptr;
   4434   int   len;
   4435   int   i;
   4436 
   4437   len = strlen (FileName);
   4438   if (len == 0) {
   4439     return FILETYPE_UNKNOWN;
   4440 
   4441   }
   4442 
   4443   Cptr = FileName + len - 1;
   4444   while ((*Cptr != '.') && (Cptr >= FileName)) {
   4445     Cptr--;
   4446 
   4447   }
   4448 
   4449   if (*Cptr == '.') {
   4450 
   4451     for (i = 0; mFileTypes[i].Extension != NULL; i++) {
   4452       len = strlen (mFileTypes[i].Extension);
   4453       if (_strnicmp (mFileTypes[i].Extension, Cptr, len) == 0) {
   4454         if ((*(Cptr + len) == 0) || isspace (*(Cptr + len))) {
   4455           return mFileTypes[i].FileType;
   4456         }
   4457       }
   4458     }
   4459   }
   4460 
   4461   return FILETYPE_UNKNOWN;
   4462 }
   4463 //
   4464 // Determine if a given file is a standard include file. If we don't know,
   4465 // then assume it's not.
   4466 //
   4467 static
   4468 int
   4469 IsIncludeFile (
   4470   INT8 *FileName
   4471   )
   4472 {
   4473   INT8  *Cptr;
   4474   int   len;
   4475   int   i;
   4476 
   4477   len = strlen (FileName);
   4478   if (len == 0) {
   4479     return 0;
   4480   }
   4481 
   4482   Cptr = FileName + len - 1;
   4483   while ((*Cptr != '.') && (Cptr >= FileName)) {
   4484     Cptr--;
   4485   }
   4486 
   4487   if (*Cptr == '.') {
   4488     //
   4489     // Now go through the list of filename extensions and try to find
   4490     // a match for this file extension.
   4491     //
   4492     for (i = 0; mFileTypes[i].Extension != NULL; i++) {
   4493       len = strlen (mFileTypes[i].Extension);
   4494       if (_strnicmp (mFileTypes[i].Extension, Cptr, len) == 0) {
   4495         //
   4496         // Make sure that's all there is to the filename extension.
   4497         //
   4498         if ((*(Cptr + len) == 0) || isspace (*(Cptr + len))) {
   4499           return mFileTypes[i].FileFlags & FILE_FLAG_INCLUDE;
   4500         }
   4501       }
   4502     }
   4503   }
   4504 
   4505   return 0;
   4506 }
   4507 
   4508 /*****************************************************************************
   4509 ******************************************************************************/
   4510 static
   4511 void
   4512 StripTrailingSpaces (
   4513   INT8 *Str
   4514   )
   4515 {
   4516   INT8  *Cptr;
   4517   Cptr = Str + strlen (Str) - 1;
   4518   while (Cptr > Str) {
   4519     if (isspace (*Cptr)) {
   4520       *Cptr = 0;
   4521       Cptr--;
   4522     } else {
   4523       break;
   4524     }
   4525   }
   4526 }
   4527 
   4528 /*****************************************************************************
   4529 ******************************************************************************/
   4530 static
   4531 int
   4532 GetEfiSource (
   4533   VOID
   4534   )
   4535 {
   4536   INT8  *EfiSource;
   4537 
   4538   //
   4539   // Don't set it if the user specified it on the command line.
   4540   //
   4541   EfiSource = GetSymbolValue (EFI_SOURCE);
   4542   if ( EfiSource != NULL) {
   4543     ReplaceSlash (EfiSource);
   4544     if (EfiSource[strlen (EfiSource) - 1] == '\\') {
   4545       EfiSource[strlen (EfiSource) - 1] = 0;
   4546     }
   4547     return STATUS_SUCCESS;
   4548   }
   4549 
   4550   //
   4551   // Get the environmental variable setting of EFI_SOURCE.
   4552   //
   4553   EfiSource = getenv (EFI_SOURCE);
   4554   if (EfiSource != NULL) {
   4555     ReplaceSlash (EfiSource);
   4556     if (EfiSource[strlen (EfiSource) - 1] == '\\') {
   4557       EfiSource[strlen (EfiSource) - 1] = 0;
   4558     }
   4559     AddSymbol (EFI_SOURCE, EfiSource, SYM_GLOBAL | SYM_FILEPATH);
   4560     return STATUS_SUCCESS;
   4561   }
   4562 
   4563   Error (NULL, 0, 0, NULL, "could not determine EFI_SOURCE");
   4564   return STATUS_ERROR;
   4565 }
   4566 
   4567 void
   4568 Message (
   4569   UINT32  PrintMask,
   4570   INT8    *Fmt,
   4571   ...
   4572   )
   4573 {
   4574   INT8    Line[MAX_LINE_LEN];
   4575   va_list List;
   4576 
   4577   va_start (List, Fmt);
   4578   vsprintf (Line, Fmt, List);
   4579   if (PrintMask & gGlobals.Verbose) {
   4580     fprintf (stdout, "%s\n", Line);
   4581   }
   4582 
   4583   va_end (List);
   4584 }
   4585 
   4586 static
   4587 void
   4588 Usage (
   4589   VOID
   4590   )
   4591 {
   4592   int         Index;
   4593   const char  *Str[] = {
   4594     UTILITY_NAME" "UTILITY_VERSION" - Intel Process DSC File Utility",
   4595     "  Copyright (C), 2004 - 2008 Intel Corporation",
   4596 
   4597 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
   4598     "  Built from "UTILITY_BUILD", project of "UTILITY_VENDOR,
   4599 #endif
   4600     "",
   4601     "Usage:",
   4602     "  "UTILITY_NAME" [OPTION]... DSCFILE",
   4603     "Options:",
   4604     "  -d var=value        to define symbol 'var' to 'value'",
   4605     "  -v                  for verbose mode",
   4606     "  -g filename         to preparse GUID listing file",
   4607     "  -x filename         to create a cross-reference file",
   4608     "  -n threadnumber     to build with multi-thread",
   4609     "  -t target           to build the specified target:",
   4610     "                      all, libraries or components",
   4611     NULL
   4612   };
   4613   for (Index = 0; Str[Index] != NULL; Index++) {
   4614     fprintf (stdout, "%s\n", Str[Index]);
   4615   }
   4616 }
   4617 
   4618 /*++
   4619 
   4620 Routine Description:
   4621 
   4622   Process the [defines] section in the DSC file.
   4623 
   4624 Arguments:
   4625 
   4626   DscFile - pointer to the DSCFile class that contains the relevant info.
   4627 
   4628 Returns:
   4629 
   4630   0 if not necessarily an absolute path
   4631   1 otherwise
   4632 
   4633 --*/
   4634 static
   4635 int
   4636 ProcessDSCDefinesSection (
   4637   DSC_FILE *DscFile
   4638   )
   4639 {
   4640   INT8    Line[MAX_LINE_LEN];
   4641   INT8    Line2[MAX_EXP_LINE_LEN];
   4642   INT8    *Cptr;
   4643   SECTION *Sect;
   4644 
   4645   //
   4646   // Look for a [defines] section and process it
   4647   //
   4648   Sect = DSCFileFindSection (DscFile, DEFINES_SECTION_NAME);
   4649   if (Sect == NULL) {
   4650     return STATUS_ERROR;
   4651   }
   4652   //
   4653   // Read lines while they're valid
   4654   //
   4655   while (DSCFileGetLine (DscFile, Line, sizeof (Line)) != NULL) {
   4656     //
   4657     // Expand symbols on the line
   4658     //
   4659     if (ExpandSymbols (Line, Line2, sizeof (Line2), 0)) {
   4660       return STATUS_ERROR;
   4661     }
   4662     //
   4663     // Strip the line
   4664     //
   4665     Cptr = StripLine (Line2);
   4666     if (*Cptr) {
   4667       //
   4668       // Make the assignment
   4669       //
   4670       AddSymbol (Line2, NULL, SYM_OVERWRITE | SYM_GLOBAL);
   4671     }
   4672   }
   4673 
   4674   return STATUS_SUCCESS;
   4675 }
   4676 
   4677 int
   4678 IsAbsolutePath (
   4679   char    *FileName
   4680   )
   4681 /*++
   4682 
   4683 Routine Description:
   4684 
   4685   Determine if a given filename contains the full path information.
   4686 
   4687 Arguments:
   4688 
   4689   FileName - the name of the file, with symbol expanded.
   4690 
   4691 Returns:
   4692 
   4693   0 if not necessarily an absolute path
   4694   1 otherwise
   4695 
   4696 --*/
   4697 {
   4698   //
   4699   // If the first character is a-z, and the second character is a colon, then
   4700   // it is an absolute path.
   4701   //
   4702   if (isalpha (FileName[0]) && (FileName[1] == ':')) {
   4703     return 1;
   4704   }
   4705 
   4706   return 0;
   4707 }
   4708 
   4709 SMART_FILE *
   4710 SmartOpen (
   4711   char        *FileName
   4712   )
   4713 {
   4714   SMART_FILE     *SmartFile;
   4715   FILE           *Fptr;
   4716   int            FileSize;
   4717 
   4718   SmartFile = malloc (sizeof (SMART_FILE));
   4719   if (SmartFile == NULL) {
   4720     return NULL;
   4721   }
   4722   memset (SmartFile, 0, sizeof (SMART_FILE));
   4723 
   4724   SmartFile->FileName = malloc (strlen (FileName) + 1);
   4725   if (SmartFile->FileName == NULL){
   4726     SmartFree (SmartFile);
   4727     return NULL;
   4728   }
   4729   strcpy (SmartFile->FileName, FileName);
   4730 
   4731   if ((Fptr = fopen (FileName, "r")) != NULL) {
   4732     fseek (Fptr, 0, SEEK_END);
   4733     FileSize = ftell (Fptr);
   4734     fseek (Fptr, 0, SEEK_SET);
   4735     SmartFile->FileContent = malloc (FileSize + 1);
   4736     if (SmartFile->FileContent != NULL) {
   4737       memset (SmartFile->FileContent, 0, FileSize + 1);
   4738       //
   4739       // Usually FileLength < FileSize, because in text mode, carriage return-linefeed
   4740       // combinations are translated into single linefeeds on input
   4741       //
   4742       SmartFile->FileLength = fread (SmartFile->FileContent, sizeof(char), FileSize, Fptr);
   4743     }
   4744     fclose (Fptr);
   4745   }
   4746 
   4747   //
   4748   // No previous output file content, re-create the file
   4749   //
   4750   if (SmartFile->FileContent == NULL) {
   4751     if ((SmartFile->FilePtr = fopen (FileName, "w")) == NULL) {
   4752       SmartFree (SmartFile);
   4753       return NULL;
   4754     }
   4755   }
   4756 
   4757   return SmartFile;
   4758 }
   4759 
   4760 int
   4761 SmartWrite (
   4762   SMART_FILE  *SmartFile,
   4763   char        *String
   4764   )
   4765 {
   4766   int  StrLen;
   4767 
   4768   if (SmartFile->FilePtr != NULL) {
   4769     return fprintf (SmartFile->FilePtr, "%s", String);
   4770   } else {
   4771     StrLen = strlen (String);
   4772     if ((StrLen > SmartFile->FileLength - SmartFile->FilePosition) ||
   4773        (_strnicmp (&SmartFile->FileContent[SmartFile->FilePosition], String, StrLen) != 0)) {
   4774       //
   4775       // file changed, need to re-create.
   4776       //
   4777       if ((SmartFile->FilePtr = fopen (SmartFile->FileName, "w")) == NULL) {
   4778         Error (NULL, 0, 0, SmartFile->FileName, "could not open file for writing when SmartWrite");
   4779         return -1;
   4780       } else {
   4781         SmartFile->FileContent[SmartFile->FilePosition] = 0;
   4782         fprintf (SmartFile->FilePtr, "%s%s", SmartFile->FileContent, String);
   4783         return StrLen;
   4784       }
   4785     } else {
   4786       SmartFile->FilePosition += StrLen;
   4787       return StrLen;
   4788     }
   4789   }
   4790 }
   4791 
   4792 void
   4793 SmartClose (
   4794   SMART_FILE  *SmartFile
   4795   )
   4796 {
   4797   if ((SmartFile->FilePtr == NULL) && (SmartFile->FilePosition < SmartFile->FileLength)) {
   4798     //
   4799     // The new file is smaller than before, re-create it.
   4800     //
   4801     if ((SmartFile->FilePtr = fopen (SmartFile->FileName, "w")) == NULL) {
   4802       Error (NULL, 0, 0, SmartFile->FileName, "could not open file for writing when SmartClose");
   4803     } else {
   4804       SmartFile->FileContent[SmartFile->FilePosition] = 0;
   4805       fprintf (SmartFile->FilePtr, "%s", SmartFile->FileContent);
   4806     }
   4807   }
   4808 
   4809   SmartFree(SmartFile);
   4810 }
   4811 
   4812 static
   4813 void
   4814 SmartFree (
   4815   SMART_FILE  *SmartFile
   4816   )
   4817 {
   4818   if (SmartFile == NULL) {
   4819     return;
   4820   }
   4821 
   4822   if (SmartFile->FileName != NULL ) {
   4823     free (SmartFile->FileName);
   4824   }
   4825 
   4826   if (SmartFile->FileContent != NULL ) {
   4827     free (SmartFile->FileContent);
   4828   }
   4829 
   4830   if (SmartFile->FilePtr != NULL ) {
   4831     fclose (SmartFile->FilePtr);
   4832   }
   4833 
   4834   free (SmartFile);
   4835 
   4836   return;
   4837 }
   4838 
   4839 static
   4840 int
   4841 AddModuleName (
   4842   SYMBOL  **SymbolList,
   4843   INT8    *ModuleName,
   4844   INT8    *InfName
   4845   )
   4846 /*++
   4847 
   4848 Routine Description:
   4849 
   4850   Add module name in the global module list.
   4851   For the same module names, it is only added once.
   4852 
   4853 Arguments:
   4854   SymbolList : add name into this list
   4855   ModuleName : point to one module name char string.
   4856   InfName    : point to this module inf file name with path.
   4857 
   4858 Returns:
   4859 
   4860   0 : Successfully add input name into the global list.
   4861   other value : allocate memory failed.
   4862 
   4863 --*/
   4864 {
   4865   SYMBOL *CurrentSymbol;
   4866   SYMBOL *LastSymbol;
   4867 
   4868   //
   4869   // Get the global module list.
   4870   //
   4871   CurrentSymbol = *SymbolList;
   4872   LastSymbol    = *SymbolList;
   4873 
   4874   //
   4875   // Search whether this module name has been added into the global list.
   4876   //
   4877   while (CurrentSymbol != NULL) {
   4878     if (_stricmp (CurrentSymbol->Name, ModuleName) == 0) {
   4879       if ((CurrentSymbol->Value == NULL) && (InfName == NULL)) {
   4880         break;
   4881       } else if ((CurrentSymbol->Value != NULL) && (InfName != NULL) && \
   4882         (_stricmp (CurrentSymbol->Value, InfName) == 0)) {
   4883         break;
   4884       }
   4885     }
   4886     LastSymbol    = CurrentSymbol;
   4887     CurrentSymbol = CurrentSymbol->Next;
   4888   }
   4889 
   4890   //
   4891   // Add new module name in list.
   4892   //
   4893   if (CurrentSymbol == NULL) {
   4894     CurrentSymbol = (SYMBOL *) malloc (sizeof (SYMBOL));
   4895     if (CurrentSymbol == NULL) {
   4896       Error (NULL, 0, 0, NULL, "failed to allocate memory");
   4897       return -1;
   4898     }
   4899     memset ((INT8 *) CurrentSymbol, 0, sizeof (SYMBOL));
   4900 
   4901     if (ModuleName != NULL) {
   4902       CurrentSymbol->Name   = (INT8 *) malloc (strlen (ModuleName) + 1);
   4903       strcpy (CurrentSymbol->Name, ModuleName);
   4904     }
   4905 
   4906     if (InfName != NULL) {
   4907       CurrentSymbol->Value  = (INT8 *) malloc (strlen (InfName) + 1);
   4908       strcpy (CurrentSymbol->Value, InfName);
   4909     }
   4910 
   4911     if (LastSymbol == NULL) {
   4912       *SymbolList      = CurrentSymbol;
   4913     } else {
   4914       LastSymbol->Next = CurrentSymbol;
   4915     }
   4916   }
   4917 
   4918   return 0;
   4919 }
   4920 
   4921 
   4922 static
   4923 void
   4924 ReplaceSlash (
   4925   INT8    *Path
   4926   )
   4927 /*++
   4928 
   4929 Routine Description:
   4930 
   4931   Replace '/' with '\\'
   4932 
   4933 Returns:
   4934 
   4935 --*/
   4936 {
   4937   while (*Path) {
   4938     if (*Path == '/') {
   4939       *Path = '\\';
   4940     }
   4941     Path++;
   4942   }
   4943 }
   4944