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   FWVolume.c
     15 
     16 Abstract:
     17 
     18   This module contains functionality to keep track of files destined for
     19   multiple firmware volues. It saves them up, and when told to, dumps the
     20   file names out to some files used as input to other utilities that
     21   actually generate the FVs.
     22 
     23 --*/
     24 
     25 #include <windows.h>                        // for max_path definition
     26 #include <stdio.h>
     27 #include <string.h>
     28 #include <stdlib.h>                         // for malloc()
     29 #include "Common.h"
     30 #include "DSCFile.h"
     31 #include "FWVolume.h"
     32 
     33 #define FV_INF_DIR          "FV_INF_DIR"    // symbol for where we create the FV INF file
     34 #define FV_FILENAME         "FV_FILENAME"   // symbol for the current FV.INF filename
     35 #define EFI_BASE_ADDRESS    "EFI_BASE_ADDRESS"
     36 #define DEFAULT_FV_INF_DIR  "FV"            // default dir for where we create the FV INF file
     37 #define DEFAULT_FV_DIR      "$(BUILD_DIR)"  // where the FV file comes from
     38 
     39 typedef struct {
     40   char  *ComponentType;
     41   char  *Extension;
     42 } COMP_TYPE_EXTENSION;
     43 
     44 //
     45 // Use a linked list of these to keep track of all the FV names used
     46 //
     47 typedef struct _FV_LIST {
     48   struct _FV_LIST *Next;
     49   char            FVFileName[MAX_PATH];
     50   char            BaseAddress[MAX_LINE_LEN];
     51   SMART_FILE      *FVFilePtr;
     52   SMART_FILE      *AprioriFilePtr;
     53   char            *Processor;
     54   int             ComponentsInstance; // highest [components.n] section with a file for this FV
     55 } FV_LIST;
     56 
     57 //
     58 // Use a linked list of these to keep track of all FFS files built. When
     59 // we're done, we turn the info into the FV INF files used to build the
     60 // firmware volumes.
     61 //
     62 typedef struct _FILE_LIST {
     63   struct _FILE_LIST *Next;
     64   char              *FileName;
     65   char              *BaseFileName;
     66   char              *FVs;               // from FV=x,y,z
     67   char              *BaseName;          // only needed for duplicate basename check
     68   char              *Processor;         // only needed for duplicate basename check
     69   char              Apriori[100];       // of format "FVRecovery:1,FVMain:2" from APRIORI define
     70   char              *Guid;              // guid string
     71   int               ComponentsInstance; // which [components.n] section it's in
     72 } FILE_LIST;
     73 
     74 typedef struct _LINKED_LIST {
     75   struct _LINKED_LIST *Next;
     76   void                *Data;
     77 } LINKED_LIST;
     78 
     79 static FILE_LIST                  *mFileList;
     80 static FILE_LIST                  *mLastFile;
     81 static char                       *mXRefFileName  = NULL;
     82 static FV_LIST                    *mNonFfsFVList  = NULL;
     83 
     84 //
     85 // Whenever an FV name is referenced, then add it to our list of known
     86 // FV's using these.
     87 //
     88 static FV_LIST                    *mFVList      = NULL;
     89 static FV_LIST                    *mFVListLast  = NULL;
     90 
     91 //
     92 // We use this list so that from a given component type, we can determine
     93 // the name of the file on disk. For example, if we're given a file's
     94 // guid and base name, and we know it's a "bs_driver", then we can look
     95 // up "bs_driver" in this array and know that the file (after it's built)
     96 // name is GUID-BASENAME.DXE
     97 //
     98 static const COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
     99   {
    100     "bs_driver",
    101     ".dxe"
    102   },
    103   {
    104     "rt_driver",
    105     ".dxe"
    106   },
    107   {
    108     "sal_rt_driver",
    109     ".dxe"
    110   },
    111   {
    112     "security_core",
    113     ".sec"
    114   },
    115   {
    116     "pei_core",
    117     ".pei"
    118   },
    119   {
    120     "pic_peim",
    121     ".pei"
    122   },
    123   {
    124     "pe32_peim",
    125     ".pei"
    126   },
    127   {
    128     "relocatable_peim",
    129     ".pei"
    130   },
    131   {
    132     "binary",
    133     ".ffs"
    134   },
    135   {
    136     "application",
    137     ".app"
    138   },
    139   {
    140     "file",
    141     ".ffs"
    142   },
    143   {
    144     "fvimagefile",
    145     ".fvi"
    146   },
    147   {
    148     "rawfile",
    149     ".raw"
    150   },
    151   {
    152     "apriori",
    153     ".ffs"
    154   },
    155   {
    156     "combined_peim_driver",
    157     ".pei"
    158   },
    159   {
    160     NULL,
    161     NULL
    162   }
    163 };
    164 
    165 static
    166 void
    167 CFVFreeFileList (
    168   VOID
    169   );
    170 
    171 static
    172 char                              *
    173 UpperCaseString (
    174   char *Str
    175   );
    176 
    177 static
    178 BOOLEAN
    179 InSameFv (
    180   char  *FVs1,
    181   char  *FVs2
    182 );
    183 
    184 static
    185 void
    186 AddFirmwareVolumes (
    187   char          *FVs,
    188   int           ComponentsInstance
    189   );
    190 
    191 static
    192 BOOLEAN
    193 OrderInFvList (
    194   char    *FvList,
    195   char    *FvName,
    196   int     *Order
    197   );
    198 
    199 int
    200 GetBaseAddress (
    201   char *Name,
    202   char *BaseAddress
    203   )
    204 {
    205   char  *Start;
    206   char  *Cptr;
    207   char  CSave;
    208   char  *Value;
    209 
    210   Start = Name;
    211   while (*Name && isspace (*Name)) {
    212     Name++;
    213   }
    214 
    215   if (!*Name) {
    216     return STATUS_ERROR;
    217   }
    218   //
    219   // Find the end of the name. Either space or a '='.
    220   //
    221   for (Value = Name; *Value && !isspace (*Value) && (*Value != '='); Value++)
    222     ;
    223   if (!*Value) {
    224     return STATUS_ERROR;
    225   }
    226   //
    227   // Look for the '='
    228   //
    229   Cptr = Value;
    230   while (*Value && (*Value != '=')) {
    231     Value++;
    232   }
    233 
    234   if (!*Value) {
    235     return STATUS_ERROR;
    236   }
    237   //
    238   // Now truncate the name
    239   //
    240   CSave = *Cptr;
    241   *Cptr = 0;
    242   if (_stricmp (Name, EFI_BASE_ADDRESS) != 0) {
    243     return STATUS_ERROR;
    244   }
    245 
    246   *Cptr = CSave;
    247   //
    248   // Skip over the = and then any spaces
    249   //
    250   Value++;
    251   while (*Value && isspace (*Value)) {
    252     Value++;
    253   }
    254   //
    255   // Find end of string, checking for quoted string
    256   //
    257   if (*Value == '\"') {
    258     Value++;
    259     for (Cptr = Value; *Cptr && *Cptr != '\"'; Cptr++)
    260       ;
    261   } else {
    262     for (Cptr = Value; *Cptr && !isspace (*Cptr); Cptr++)
    263       ;
    264   }
    265   //
    266   // Null terminate the value string
    267   //
    268   CSave = *Cptr;
    269   *Cptr = 0;
    270   strcpy (BaseAddress, Value);
    271   *Cptr = CSave;
    272 
    273   return STATUS_SUCCESS;
    274 }
    275 
    276 int
    277 CFVAddFVFile (
    278   char  *Name,
    279   char  *ComponentType,
    280   char  *FVs,
    281   int   ComponentsInstance,
    282   char  *FFSExt,
    283   char  *Processor,
    284   char  *Apriori,
    285   char  *BaseName,
    286   char  *Guid
    287   )
    288 /*++
    289 
    290 Routine Description:
    291 
    292   Add a file to the list of files in one or more firmware volumes.
    293 
    294 Arguments:
    295 
    296   Name          - $(FILE_GUID)-$(BASE_NAME), or filename
    297   ComponentType - type of component being added. Required so we know the
    298                   resultant file name after it has been built
    299   FVs           - string of commma-separated FVs that the given file is
    300                   to be added to. For example, FVs="FV0001,FV0002"
    301   FFSExt        - FFS filename extension of the file after it has been built.
    302                   This is passed in to us in case we don't know the default
    303                   filename extension based on the component type.
    304   Processor     - the target processor which the FV is being built for
    305   Apriori       - pointer to the definition of APRIORI. For example APRIORI="FvRecovery:1,FvMain:4"
    306 
    307 Returns:
    308 
    309   STATUS_SUCCESS if successful
    310 
    311 --*/
    312 {
    313   FILE_LIST *Ptr;
    314   char      FileName[MAX_PATH];
    315   char      Str[MAX_PATH];
    316   int       i;
    317   char      *Sym;
    318 
    319   // If they provided a filename extension for this type of file, then use it.
    320   // If they did not provide a filename extension, search our list for a
    321   // matching component type and use the extension appropriate for this
    322   // component type.
    323   //
    324   if (FFSExt == NULL) {
    325     //
    326     // They didn't give us a filename extension. Figure it out from the
    327     // component type.
    328     //
    329     for (i = 0; mCompTypeExtension[i].ComponentType != NULL; i++) {
    330       if (_stricmp (ComponentType, mCompTypeExtension[i].ComponentType) == 0) {
    331         FFSExt = mCompTypeExtension[i].Extension;
    332         break;
    333       }
    334     }
    335     //
    336     // If we don't know the file extension, then error out. Just means
    337     // the need to define "FFS_EXT = raw" in the component INF file.
    338     //
    339     if (mCompTypeExtension[i].ComponentType == NULL) {
    340       Error (
    341         NULL,
    342         0,
    343         0,
    344         ComponentType,
    345         "unknown component type - must define FFS_EXT for built filename extension in component INF file"
    346         );
    347       return STATUS_ERROR;
    348     }
    349   }
    350   //
    351   // We now have all the parts to the FFS filename. Prepend the path to it if
    352   // it's not a full pathname.
    353   // See if they overrode the default base directory for the FV files.
    354   //
    355   if (!IsAbsolutePath (Name)) {
    356     Sym = GetSymbolValue (FV_DIR);
    357     if (Sym == NULL) {
    358       Sym = DEFAULT_FV_DIR;
    359     }
    360     //
    361     // Create the file path. Something like $(BUILD_DIR)\$(PROCESSOR)\$(GUID)-$(BASE_NAME).ext
    362     // If the extension is non-zero length, then make sure there's a dot in it.
    363     //
    364     if ((strlen (FFSExt) > 0) && (FFSExt[0] != '.')) {
    365       sprintf (Str, "%s\\%s\\%s.%s", Sym, Processor, Name, FFSExt);
    366     } else {
    367       sprintf (Str, "%s\\%s\\%s%s", Sym, Processor, Name, FFSExt);
    368     }
    369 
    370     ExpandSymbols (Str, FileName, sizeof (FileName), EXPANDMODE_NO_UNDEFS);
    371   } else {
    372     strcpy (FileName, Name);
    373   }
    374   //
    375   // Traverse the list of files we have so far and make sure we don't have
    376   // any duplicate basenames. If the base name and processor match, then we'll
    377   // have build issues, so don't allow it. We also don't allow the same file GUID
    378   // in the same FV which will cause boot time error if we allow this.
    379   //
    380   Ptr = mFileList;
    381   while (Ptr != NULL) {
    382     if ((Ptr->BaseName != NULL) && (BaseName != NULL) && (_stricmp (BaseName, Ptr->BaseName) == 0)) {
    383       if ((Ptr->Processor != NULL) && (Processor != NULL) && (_stricmp (Processor, Ptr->Processor) == 0)) {
    384         Error (NULL, 0, 0, BaseName, "duplicate base name specified");
    385         return STATUS_ERROR;
    386       }
    387     }
    388 
    389     if ((Ptr->Guid != NULL) && (Guid != NULL) && (_stricmp (Guid, Ptr->Guid) == 0)) {
    390       if ((Ptr->FVs != NULL) && (FVs != NULL) && (InSameFv (FVs, Ptr->FVs))) {
    391         Error (NULL, 0, 0, Guid, "duplicate Guid specified in the same FV for %s and %s",
    392                (Ptr->BaseName==NULL)?"Unknown":Ptr->BaseName,
    393                (BaseName==NULL)?"Unknown":BaseName);
    394         return STATUS_ERROR;
    395       }
    396     }
    397 
    398     Ptr = Ptr->Next;
    399   }
    400   //
    401   // Allocate a new structure so we can add this file to the list of
    402   // files.
    403   //
    404   Ptr = (FILE_LIST *) malloc (sizeof (FILE_LIST));
    405   if (Ptr == NULL) {
    406     Error (NULL, 0, 0, NULL, "failed to allocate memory");
    407     return STATUS_ERROR;
    408   }
    409 
    410   memset ((char *) Ptr, 0, sizeof (FILE_LIST));
    411   Ptr->FileName = (char *) malloc (strlen (FileName) + 1);
    412   if (Ptr->FileName == NULL) {
    413     Error (NULL, 0, 0, NULL, "failed to allocate memory");
    414     return STATUS_ERROR;
    415   }
    416 
    417   strcpy (Ptr->FileName, FileName);
    418   Ptr->ComponentsInstance = ComponentsInstance;
    419   //
    420   // Allocate memory to save the FV list if it's going into an FV.
    421   //
    422   if ((FVs != NULL) && (FVs[0] != 0)) {
    423     Ptr->FVs = (char *) malloc (strlen (FVs) + 1);
    424     if (Ptr->FVs == NULL) {
    425       Error (NULL, 0, 0, NULL, "failed to allocate memory");
    426       return STATUS_ERROR;
    427     }
    428 
    429     strcpy (Ptr->FVs, FVs);
    430   }
    431 
    432   Ptr->BaseFileName = (char *) malloc (strlen (Name) + 1);
    433   if (Ptr->BaseFileName == NULL) {
    434     Error (NULL, 0, 0, NULL, "failed to allocate memory");
    435     return STATUS_ERROR;
    436   }
    437 
    438   strcpy (Ptr->BaseFileName, Name);
    439   //
    440   // Allocate memory for the basename if they gave us one. May not have one
    441   // if the user is simply adding pre-existing binary files to the image.
    442   //
    443   if (BaseName != NULL) {
    444     Ptr->BaseName = (char *) malloc (strlen (BaseName) + 1);
    445     if (Ptr->BaseName == NULL) {
    446       Error (NULL, 0, 0, NULL, "failed to allocate memory");
    447       return STATUS_ERROR;
    448     }
    449 
    450     strcpy (Ptr->BaseName, BaseName);
    451   }
    452   //
    453   // Allocate memory for the processor name
    454   //
    455   if (Processor != NULL) {
    456     Ptr->Processor = (char *) malloc (strlen (Processor) + 1);
    457     if (Ptr->Processor == NULL) {
    458       Error (NULL, 0, 0, NULL, "failed to allocate memory");
    459       return STATUS_ERROR;
    460     }
    461 
    462     strcpy (Ptr->Processor, Processor);
    463   }
    464   //
    465   // Allocate memory for the guid name
    466   //
    467   if (Guid != NULL) {
    468     Ptr->Guid = (char *) malloc (strlen (Guid) + 1);
    469     if (Ptr->Guid == NULL) {
    470       Error (NULL, 0, 0, NULL, "failed to allocate memory");
    471       return STATUS_ERROR;
    472     }
    473 
    474     strcpy (Ptr->Guid, Guid);
    475   }
    476   //
    477   // If non-null apriori symbol, then save the apriori list for this file
    478   //
    479   if (Apriori != NULL) {
    480     strcpy (Ptr->Apriori, Apriori);
    481   }
    482 
    483   if (mFileList == NULL) {
    484     mFileList = Ptr;
    485   } else {
    486     mLastFile->Next = Ptr;
    487   }
    488 
    489   mLastFile = Ptr;
    490   //
    491   // Add these firmware volumes to the list of known firmware
    492   // volume names.
    493   //
    494   AddFirmwareVolumes (FVs, ComponentsInstance);
    495 
    496   return STATUS_SUCCESS;
    497 }
    498 
    499 void
    500 CFVConstructor (
    501   VOID
    502   )
    503 {
    504   mFileList = NULL;
    505   mLastFile = NULL;
    506 }
    507 
    508 void
    509 CFVDestructor (
    510   VOID
    511   )
    512 {
    513   CFVFreeFileList ();
    514   //
    515   // Free up our firmware volume list
    516   //
    517   while (mFVList != NULL) {
    518     mFVListLast = mFVList->Next;
    519     free (mFVList);
    520     mFVList = mFVListLast;
    521   }
    522 }
    523 
    524 static
    525 void
    526 CFVFreeFileList (
    527   VOID
    528   )
    529 {
    530   FILE_LIST *Next;
    531   while (mFileList != NULL) {
    532     if (mFileList->FileName != NULL) {
    533       free (mFileList->FileName);
    534     }
    535 
    536     if (mFileList->FVs != NULL) {
    537       free (mFileList->FVs);
    538     }
    539 
    540     free (mFileList->BaseFileName);
    541     if (mFileList->BaseName != NULL) {
    542       free (mFileList->BaseName);
    543     }
    544 
    545     if (mFileList->Processor != NULL) {
    546       free (mFileList->Processor);
    547     }
    548 
    549     if (mFileList->Guid != NULL) {
    550       free (mFileList->Guid);
    551     }
    552 
    553     Next = mFileList->Next;
    554     free (mFileList);
    555     mFileList = Next;
    556   }
    557 
    558   mFileList = NULL;
    559 }
    560 
    561 int
    562 CFVWriteInfFiles (
    563   DSC_FILE  *DSC,
    564   FILE      *MakeFptr
    565   )
    566 /*++
    567 
    568 Routine Description:
    569 
    570   After processing all components in a DSC file, create the firmware
    571   volume INF files. We actually do a lot more here.
    572 
    573   * Create the FVxxx.inf file that is used by GenFvImage
    574   * Create the Apriori files for each firmware volume that requires one
    575   * Create makefile.out macros for FVxxx_FILES = FVxxx_FILES AnotherFile
    576     so you can do incremental builds of firmware volumes.
    577   * For each FV, emit its build commands to makefile.out
    578 
    579 Arguments:
    580 
    581   DSC       - pointer to a DSC_FILE object to extract info from
    582   MakeFptr  - pointer to the output makefile
    583 
    584 Returns:
    585 
    586   0  if successful
    587   non-zero otherwise
    588 
    589 --*/
    590 {
    591   FILE_LIST *FileListPtr;
    592   FV_LIST   *FVList;
    593   FV_LIST   *LastFVList;
    594   FV_LIST   *FVPtr;
    595   SECTION   *Section;
    596   char      *StartCptr;
    597   char      *EndCptr;
    598   char      CSave;
    599   char      Str[MAX_PATH];
    600   char      Line[MAX_LINE_LEN];
    601   char      ExpandedLine[MAX_LINE_LEN];
    602   char      FVDir[MAX_PATH];
    603   FILE      *XRefFptr;
    604   int       AprioriCounter;
    605   int       AprioriCount;
    606   int       AprioriPosition;
    607   BOOLEAN   AprioriFound;
    608   int       ComponentsInstance;
    609   int       ComponentCount;
    610 
    611   //
    612   // Use this to keep track of all the firmware volume names
    613   //
    614   FVList      = NULL;
    615   LastFVList  = NULL;
    616   //
    617   // See if they specified a FV directory to dump the FV files out to. If not,
    618   // then use the default. Then create the output directory.
    619   //
    620   StartCptr = GetSymbolValue (FV_INF_DIR);
    621   if (StartCptr == NULL) {
    622     ExpandSymbols (DEFAULT_FV_INF_DIR, FVDir, sizeof (FVDir), EXPANDMODE_NO_UNDEFS);
    623   } else {
    624     strcpy (FVDir, StartCptr);
    625   }
    626   //
    627   // Make sure the fv directory path ends in /
    628   //
    629   CSave = FVDir[strlen (FVDir) - 1];
    630   if ((CSave != '\\') && (CSave != '/')) {
    631     strcat (FVDir, "\\");
    632   }
    633   //
    634   // Traverse the list of all files, determine which FV each is in, then
    635   // write out the file's name to the output FVxxx.inf file.
    636   //
    637   for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
    638     //
    639     // Parse all the "FV1,FV2..." in the FVs
    640     //
    641     if (FileListPtr->FVs != NULL) {
    642       //
    643       // Process each fv this file is in
    644       //
    645       StartCptr = FileListPtr->FVs;
    646       while (*StartCptr) {
    647         EndCptr = StartCptr;
    648         while (*EndCptr && (*EndCptr != ',')) {
    649           EndCptr++;
    650         }
    651 
    652         CSave     = *EndCptr;
    653         *EndCptr  = 0;
    654         //
    655         // Ok, we have a fv name, now see if we've already opened
    656         // an fv output file of this name.
    657         //
    658         for (FVPtr = FVList; FVPtr != NULL; FVPtr = FVPtr->Next) {
    659           if (_stricmp (FVPtr->FVFileName, StartCptr) == 0) {
    660             break;
    661           }
    662         }
    663         //
    664         // If we didn't find one, then create a new one
    665         //
    666         if (FVPtr == NULL) {
    667           //
    668           // Create a new one, add it to the list
    669           //
    670           FVPtr = (FV_LIST *) malloc (sizeof (FV_LIST));
    671           if (FVPtr == NULL) {
    672             Error (NULL, 0, 0, NULL, "failed to allocate memory for FV");
    673             return STATUS_ERROR;
    674           }
    675 
    676           memset ((char *) FVPtr, 0, sizeof (FV_LIST));
    677           //
    678           // Add it to the end of our list
    679           //
    680           if (FVList == NULL) {
    681             FVList = FVPtr;
    682           } else {
    683             LastFVList->Next = FVPtr;
    684           }
    685 
    686           LastFVList = FVPtr;
    687           //
    688           // Save the FV name in the FileName pointer so we can compare
    689           // for any future FV names specified.
    690           //
    691           strcpy (FVPtr->FVFileName, StartCptr);
    692 
    693           //
    694           // Add a symbol for the FV filename
    695           //
    696           UpperCaseString (FVPtr->FVFileName);
    697           AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);
    698           //
    699           // Now create the FVx.inf filename from the fv name and
    700           // default filename extension. Dump it in the FV directory
    701           // as well.
    702           //
    703           strcpy (Str, FVDir);
    704           strcat (Str, FVPtr->FVFileName);
    705           strcat (Str, ".inf");
    706           //
    707           // Create the directory path for our new fv.inf output file.
    708           //
    709           MakeFilePath (Str);
    710           if ((FVPtr->FVFilePtr = SmartOpen (Str)) == NULL) {
    711             Error (NULL, 0, 0, Str, "could not open FV output file");
    712             return STATUS_ERROR;
    713           }
    714           //
    715           // Now copy the [fv.$(FV).options] to the fv INF file
    716           //
    717           sprintf (Str, "fv.%s.options", StartCptr);
    718           Section = DSCFileFindSection (DSC, Str);
    719           if (Section != NULL) {
    720             SmartWrite (FVPtr->FVFilePtr, "[options]\n");
    721             while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
    722               ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
    723               SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
    724               GetBaseAddress (ExpandedLine, FVPtr->BaseAddress);
    725             }
    726           } else {
    727             Error (NULL, 0, 0, Str, "could not find FV section in description file");
    728           }
    729           //
    730           // Copy the [fv.$(FV).attributes] to the fv INF file
    731           //
    732           sprintf (Str, "fv.%s.attributes", StartCptr);
    733           Section = DSCFileFindSection (DSC, Str);
    734           if (Section != NULL) {
    735             SmartWrite (FVPtr->FVFilePtr, "[attributes]\n");
    736             while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
    737               ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
    738               SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
    739             }
    740           } else {
    741             Error (NULL, 0, 0, Str, "Could not find FV section in description file");
    742           }
    743           //
    744           // Start the files section
    745           //
    746           SmartWrite (FVPtr->FVFilePtr, "\n[files]\n");
    747         }
    748         //
    749         // Now write the FV filename to the FV.inf file. Prepend $(PROCESSOR) on
    750         // it.
    751         //
    752         sprintf (ExpandedLine, "EFI_FILE_NAME = %s\n", FileListPtr->FileName);
    753         SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
    754 
    755         //
    756         // Next FV on the FV list
    757         //
    758         *EndCptr  = CSave;
    759         StartCptr = EndCptr;
    760         if (*StartCptr) {
    761           StartCptr++;
    762         }
    763       }
    764     }
    765   }
    766   //
    767   // Now we walk the list of firmware volumes and create the APRIORI list
    768   // file for it .
    769   //
    770   for (FVPtr = FVList; FVPtr != NULL; FVPtr = FVPtr->Next) {
    771     //
    772     // Run through all the files and count up how many are to be
    773     // added to the apriori list for this FV. Then when we're done
    774     // we'll make sure we processed them all. We do this in case they
    775     // skipped an apriori index for a given FV.
    776     //
    777     AprioriCount = 0;
    778     for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
    779       if (OrderInFvList (FileListPtr->Apriori, FVPtr->FVFileName, &AprioriPosition)) {
    780         //
    781         // Emit an error if the index was 0, or they didn't give one.
    782         //
    783         if (AprioriPosition == 0) {
    784           Error (
    785             GetSymbolValue (DSC_FILENAME),
    786             1,
    787             0,
    788             "apriori indexes are 1-based",
    789             "component %s:APRIORI=%s",
    790             FileListPtr->BaseName,
    791             FileListPtr->Apriori
    792             );
    793         } else {
    794           AprioriCount++;
    795         }
    796 
    797       }
    798     }
    799     //
    800     // Now scan the files as we increment our apriori index
    801     //
    802     AprioriCounter = 0;
    803     do {
    804       AprioriFound = 0;
    805       AprioriCounter++;
    806       for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
    807         //
    808         // If in the apriori list for this fv, print the name. Open the
    809         // file first if we have to.
    810         //
    811         if ((FileListPtr->Apriori[0] != 0) &&
    812             (OrderInFvList (FileListPtr->Apriori, FVPtr->FVFileName, &AprioriPosition))
    813             ) {
    814           if (AprioriPosition == AprioriCounter) {
    815             //
    816             // If we've already found one for this index, emit an error. Decrement the
    817             // count of how files we are to process so we don't emit another error for
    818             // a miscount below.
    819             //
    820             if (AprioriFound) {
    821               Error (
    822                 GetSymbolValue (DSC_FILENAME),
    823                 1,
    824                 0,
    825                 "duplicate apriori index found",
    826                 "%s:%d",
    827                 FVPtr->FVFileName,
    828                 AprioriCounter
    829                 );
    830               AprioriCount--;
    831             }
    832 
    833             AprioriFound = 1;
    834             //
    835             // Open the apriori output file if we haven't already
    836             //
    837             if (FVPtr->AprioriFilePtr == NULL) {
    838               strcpy (Str, FVDir);
    839               strcat (Str, FVPtr->FVFileName);
    840               strcat (Str, ".apr");
    841               if ((FVPtr->AprioriFilePtr = SmartOpen (Str)) == NULL) {
    842                 Error (NULL, 0, 0, Str, "could not open output Apriori file for writing");
    843                 return STATUS_ERROR;
    844               }
    845             }
    846 
    847             sprintf (ExpandedLine, "%s\n", FileListPtr->BaseFileName);
    848             SmartWrite (FVPtr->AprioriFilePtr, ExpandedLine);
    849           }
    850         }
    851       }
    852     } while (AprioriFound);
    853     //
    854     // See if they skipped an apriori position for this FV
    855     //
    856     if (AprioriCount != (AprioriCounter - 1)) {
    857       Error (
    858         GetSymbolValue (DSC_FILENAME),
    859         1,
    860         0,
    861         "apriori index skipped",
    862         "%s:%d",
    863         FVPtr->FVFileName,
    864         AprioriCounter
    865         );
    866     }
    867   }
    868   //
    869   // Traverse the list of all files again, and create a macro in the output makefile
    870   // that defines all the files in each fv. For example, for each FV file, create a line:
    871   // FV0001_FILES = $(FV_0001_FILES) xxxx-yyy.dxe.
    872   // This can then be used as a dependency in their makefile.
    873   // Also if they wanted us to dump a cross-reference, do that now.
    874   //
    875   if (mXRefFileName != NULL) {
    876     if ((XRefFptr = fopen (mXRefFileName, "w")) == NULL) {
    877       Message (
    878         0,
    879         "Failed to open cross-reference file '%s' for writing\n",
    880         mXRefFileName
    881         );
    882     }
    883   } else {
    884     XRefFptr = NULL;
    885   }
    886 
    887   for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
    888     //
    889     // Parse all the "FV1,FV2..." in the FV field that came from FV=FVa,FVb,... on the
    890     // component line in the DSC file.
    891     //
    892     if (FileListPtr->FVs != NULL) {
    893       //
    894       // If generating a cross-reference file, dump the data
    895       //
    896       if (XRefFptr != NULL) {
    897         if ((FileListPtr->Guid != NULL) && (FileListPtr->BaseName != NULL) && (FileListPtr->Processor)) {
    898           fprintf (
    899             XRefFptr,
    900             "%s %s %s\n",
    901             FileListPtr->Guid,
    902             FileListPtr->BaseName,
    903             FileListPtr->Processor
    904             );
    905         }
    906       }
    907       //
    908       // Convert to uppercase since we're going to use the name as a macro variable name
    909       // in the makefile.
    910       //
    911       UpperCaseString (FileListPtr->FVs);
    912       //
    913       // Process each FV this file is in to write fvxxx_FILES = $(fvxxx_FILES) Guid-BaseName.ffs
    914       //
    915       StartCptr = FileListPtr->FVs;
    916       while (*StartCptr) {
    917         EndCptr = StartCptr;
    918         while (*EndCptr && (*EndCptr != ',')) {
    919           EndCptr++;
    920         }
    921 
    922         CSave     = *EndCptr;
    923         *EndCptr  = 0;
    924         fprintf (
    925           MakeFptr,
    926           "%s_FILES = $(%s_FILES) %s\n",
    927           StartCptr,
    928           StartCptr,
    929           FileListPtr->FileName
    930           );
    931         //
    932         // Next FV on the FV list
    933         //
    934         *EndCptr  = CSave;
    935         StartCptr = EndCptr;
    936         if (*StartCptr) {
    937           StartCptr++;
    938         }
    939       }
    940     }
    941   }
    942 
    943   fprintf (MakeFptr, "\n");
    944 
    945   //
    946   // Now go through the list of all NonFFS FVs they specified and search for
    947   // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the
    948   // output makefile. Add them to the "fvs_0" target as well.
    949   //
    950   if (mNonFfsFVList != NULL) {
    951     fprintf (MakeFptr, "fvs_0 ::");
    952     FVPtr = mNonFfsFVList;
    953     while (FVPtr != NULL) {
    954       fprintf (MakeFptr, " %s%s.fv", FVDir, FVPtr->FVFileName);
    955       FVPtr = FVPtr->Next;
    956     }
    957 
    958     fprintf (MakeFptr, "\n\n");
    959     FVPtr = mNonFfsFVList;
    960     while (FVPtr != NULL) {
    961       //
    962       // Save the position in the file
    963       //
    964       DSCFileSavePosition (DSC);
    965       //
    966       // first try to find a build section specific for this fv.
    967       //
    968       sprintf (Str, "build.fv.%s", FVPtr->FVFileName);
    969       Section = DSCFileFindSection (DSC, Str);
    970       if (Section == NULL) {
    971         sprintf (Str, "build.fv");
    972         Section = DSCFileFindSection (DSC, Str);
    973       }
    974 
    975       if (Section == NULL) {
    976         Warning (
    977           NULL,
    978           0,
    979           0,
    980           NULL,
    981           "No [build.fv.%s] nor [%s] section found in description file for building %s",
    982           FVPtr->FVFileName,
    983           Str,
    984           FVPtr->FVFileName
    985           );
    986       } else {
    987         //
    988         // Add a symbol for the FV filename
    989         //
    990         UpperCaseString (FVPtr->FVFileName);
    991         AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);
    992         AddSymbol (EFI_BASE_ADDRESS, FVPtr->BaseAddress, SYM_LOCAL | SYM_OVERWRITE);
    993 
    994         //
    995         // Now copy the build commands from the section to the makefile
    996         //
    997         while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
    998           ExpandSymbols (
    999             Line,
   1000             ExpandedLine,
   1001             sizeof (ExpandedLine),
   1002             EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
   1003             );
   1004 
   1005           fprintf (MakeFptr, ExpandedLine);
   1006         }
   1007       }
   1008 
   1009       FVPtr = FVPtr->Next;
   1010       DSCFileRestorePosition (DSC);
   1011     }
   1012   }
   1013 
   1014   //
   1015   // Get the components count
   1016   //
   1017   ComponentCount = -1;
   1018   for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
   1019     if (FileListPtr->ComponentsInstance > ComponentCount) {
   1020       ComponentCount = FileListPtr->ComponentsInstance;
   1021     }
   1022   }
   1023   ComponentCount++;
   1024 
   1025   //
   1026   // Now print firmware volumes build targets fvs_0, fvs_1 etc.
   1027   //
   1028   for (ComponentsInstance = 0; ComponentsInstance < ComponentCount; ComponentsInstance++) {
   1029     fprintf (MakeFptr, "fvs_%d ::", ComponentsInstance);
   1030     for (FVPtr = mFVList; FVPtr != NULL; FVPtr = FVPtr->Next) {
   1031       if (FVPtr->ComponentsInstance == ComponentsInstance) {
   1032         fprintf (MakeFptr, " %s%s.fv", FVDir, FVPtr->FVFileName);
   1033       }
   1034     }
   1035     fprintf (MakeFptr, "\n\n");
   1036   }
   1037 
   1038   //
   1039   // Create an "fvs" target that builds everything. It has to be a mix of
   1040   // components and FV's in order. For example:
   1041   // fvs :: components_0 fvs_0 components_1 fvs_1
   1042   //
   1043   fprintf (MakeFptr, "fvs ::");
   1044   for (ComponentsInstance = 0; ComponentsInstance < ComponentCount; ComponentsInstance++) {
   1045     fprintf (MakeFptr, " components_%d fvs_%d", ComponentsInstance, ComponentsInstance);
   1046   }
   1047   fprintf (MakeFptr, "\n\n");
   1048 
   1049   //
   1050   // Create a "components" target for build convenience. It should
   1051   // look something like:
   1052   // components : components_0 components_1...
   1053   //
   1054   if (ComponentCount > 0) {
   1055     fprintf (MakeFptr, "components :");
   1056     for (ComponentsInstance = 0; ComponentsInstance < ComponentCount; ComponentsInstance++) {
   1057       fprintf (MakeFptr, " components_%d", ComponentsInstance);
   1058     }
   1059 
   1060     fprintf (MakeFptr, "\n\n");
   1061   }
   1062   //
   1063   // Now go through the list of all FV's defined and search for
   1064   // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the
   1065   // output makefile.
   1066   //
   1067   FVPtr = mFVList;
   1068   while (FVPtr != NULL) {
   1069     if (FVPtr->FVFileName[0]) {
   1070       //
   1071       // Save the position in the file
   1072       //
   1073       DSCFileSavePosition (DSC);
   1074       //
   1075       // First try to find a build section specific for this FV.
   1076       //
   1077       sprintf (Str, "build.fv.%s", FVPtr->FVFileName);
   1078       Section = DSCFileFindSection (DSC, Str);
   1079       if (Section == NULL) {
   1080         sprintf (Str, "build.fv");
   1081         Section = DSCFileFindSection (DSC, Str);
   1082       }
   1083 
   1084       if (Section == NULL) {
   1085         Error (
   1086           NULL,
   1087           0,
   1088           0,
   1089           NULL,
   1090           "no [build.fv.%s] nor [%s] section found in description file for building %s",
   1091           FVPtr->FVFileName,
   1092           Str,
   1093           FVPtr->FVFileName
   1094           );
   1095       } else {
   1096         //
   1097         // Add a symbol for the FV filename
   1098         //
   1099         UpperCaseString (FVPtr->FVFileName);
   1100         AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);
   1101         AddSymbol (EFI_BASE_ADDRESS, FVPtr->BaseAddress, SYM_LOCAL | SYM_OVERWRITE);
   1102 
   1103         //
   1104         // Now copy the build commands from the section to the makefile
   1105         //
   1106         while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
   1107           ExpandSymbols (
   1108             Line,
   1109             ExpandedLine,
   1110             sizeof (ExpandedLine),
   1111             EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
   1112             );
   1113           fprintf (MakeFptr, ExpandedLine);
   1114         }
   1115       }
   1116 
   1117       DSCFileRestorePosition (DSC);
   1118     }
   1119 
   1120     FVPtr = FVPtr->Next;
   1121   }
   1122   //
   1123   // Close all the files and free up the memory
   1124   //
   1125   while (FVList != NULL) {
   1126     FVPtr = FVList->Next;
   1127     if (FVList->FVFilePtr != NULL) {
   1128       SmartClose (FVList->FVFilePtr);
   1129     }
   1130 
   1131     if (FVList->AprioriFilePtr != NULL) {
   1132       SmartClose (FVList->AprioriFilePtr);
   1133     }
   1134 
   1135     free (FVList);
   1136     FVList = FVPtr;
   1137   }
   1138 
   1139   while (mNonFfsFVList != NULL) {
   1140     FVPtr = mNonFfsFVList->Next;
   1141     free (mNonFfsFVList);
   1142     mNonFfsFVList = FVPtr;
   1143   }
   1144 
   1145   if (XRefFptr != NULL) {
   1146     fclose (XRefFptr);
   1147   }
   1148 
   1149   return STATUS_SUCCESS;
   1150 }
   1151 
   1152 int
   1153 NonFFSFVWriteInfFiles (
   1154   DSC_FILE  *DSC,
   1155   char      *FileName
   1156   )
   1157 /*++
   1158 
   1159 Routine Description:
   1160 
   1161   Generate a Non FFS fv file. It can only some variables,
   1162   or simply contains nothing except header.
   1163 
   1164 Arguments:
   1165 
   1166   DSC       - pointer to a DSC_FILE object to extract info from
   1167   FileName  - pointer to the fv file
   1168 
   1169 Returns:
   1170 
   1171   STATUS_SUCCESS  if successful
   1172   non-STATUS_SUCCESS  otherwise
   1173 
   1174 --*/
   1175 {
   1176   FV_LIST *FVPtr;
   1177   SECTION *Section;
   1178   char    *StartCptr;
   1179   char    *EndCptr;
   1180   char    CSave;
   1181   char    Str[MAX_PATH];
   1182   char    Line[MAX_LINE_LEN];
   1183   char    ExpandedLine[MAX_LINE_LEN];
   1184   char    FVDir[MAX_PATH];
   1185 
   1186   //
   1187   // See if they specified a FV directory to dump the FV files out to. If not,
   1188   // then use the default. Then create the output directory.
   1189   //
   1190   DSCFileSavePosition (DSC);
   1191   StartCptr = GetSymbolValue (FV_INF_DIR);
   1192   if (StartCptr == NULL) {
   1193     ExpandSymbols (DEFAULT_FV_INF_DIR, FVDir, sizeof (FVDir), EXPANDMODE_NO_UNDEFS);
   1194   } else {
   1195     strcpy (FVDir, StartCptr);
   1196   }
   1197 
   1198   //
   1199   // Make sure the fv directory path ends in /
   1200   //
   1201   CSave = FVDir[strlen (FVDir) - 1];
   1202   if ((CSave != '\\') && (CSave != '/')) {
   1203     strcat (FVDir, "\\");
   1204   }
   1205 
   1206   StartCptr = FileName;
   1207   while (*StartCptr) {
   1208     EndCptr = StartCptr;
   1209     while (*EndCptr && (*EndCptr != ',')) {
   1210       EndCptr++;
   1211     }
   1212 
   1213     CSave     = *EndCptr;
   1214     *EndCptr  = 0;
   1215     //
   1216     // Ok, we have a fv name, now see if we've already opened
   1217     // an fv output file of this name.
   1218     //
   1219     for (FVPtr = mNonFfsFVList; FVPtr != NULL; FVPtr = FVPtr->Next) {
   1220       if (_stricmp (FVPtr->FVFileName, StartCptr) == 0) {
   1221         break;
   1222       }
   1223     }
   1224     //
   1225     // If there is already one with the same name, wrong
   1226     //
   1227     if (FVPtr != NULL) {
   1228       DSCFileRestorePosition (DSC);
   1229       return STATUS_ERROR;
   1230     }
   1231     //
   1232     // Create a new one, add it to the list
   1233     //
   1234     FVPtr = (FV_LIST *) malloc (sizeof (FV_LIST));
   1235     if (FVPtr == NULL) {
   1236       Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL);
   1237       DSCFileRestorePosition (DSC);
   1238       return STATUS_ERROR;
   1239     }
   1240 
   1241     memset ((char *) FVPtr, 0, sizeof (FV_LIST));
   1242     FVPtr->Next   = mNonFfsFVList;
   1243     mNonFfsFVList = FVPtr;
   1244     //
   1245     // Save the FV name in the FileName pointer so we can compare
   1246     // for any future FV names specified.
   1247     //
   1248     strcpy (FVPtr->FVFileName, StartCptr);
   1249     //
   1250     // Add a symbol for the FV filename
   1251     //
   1252     UpperCaseString (FVPtr->FVFileName);
   1253     AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);
   1254 
   1255     //
   1256     // Now create the FVx.inf filename from the fv name and
   1257     // default filename extension. Dump it in the FV directory
   1258     // as well.
   1259     //
   1260     strcpy (Str, FVDir);
   1261     strcat (Str, FVPtr->FVFileName);
   1262     strcat (Str, ".inf");
   1263     //
   1264     // Create the directory path for our new fv.inf output file.
   1265     //
   1266     MakeFilePath (Str);
   1267     if ((FVPtr->FVFilePtr = SmartOpen (Str)) == NULL) {
   1268       Error (NULL, 0, 0, Str, "could not open FV output file");
   1269       DSCFileRestorePosition (DSC);
   1270       return STATUS_ERROR;
   1271     }
   1272     //
   1273     // Now copy the [fv.fvfile.options] to the fv file
   1274     //
   1275     sprintf (Str, "fv.%s.options", StartCptr);
   1276     Section = DSCFileFindSection (DSC, Str);
   1277     if (Section != NULL) {
   1278       SmartWrite (FVPtr->FVFilePtr, "[options]\n");
   1279       while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
   1280         ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
   1281         SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
   1282         GetBaseAddress (ExpandedLine, FVPtr->BaseAddress);
   1283       }
   1284     } else {
   1285       Warning (NULL, 0, 0, NULL, "Could not find FV section '%s' in description file", Str);
   1286     }
   1287     //
   1288     // Copy the [fv.fvfile.attributes] to the fv file
   1289     //
   1290     sprintf (Str, "fv.%s.attributes", StartCptr);
   1291     Section = DSCFileFindSection (DSC, Str);
   1292     if (Section != NULL) {
   1293       SmartWrite (FVPtr->FVFilePtr, "[attributes]\n");
   1294       while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
   1295         ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
   1296         SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
   1297       }
   1298     } else {
   1299       Warning (NULL, 0, 0, NULL, "Could not find FV section '%s' in description file", Str);
   1300     }
   1301     //
   1302     // Copy the [fv.fvfile.components] to the fv file
   1303     //
   1304     sprintf (Str, "fv.%s.components", StartCptr);
   1305     Section = DSCFileFindSection (DSC, Str);
   1306     if (Section != NULL) {
   1307       SmartWrite (FVPtr->FVFilePtr, "[components]\n");
   1308       while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
   1309         ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
   1310         SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
   1311       }
   1312     } else {
   1313       //
   1314       // An empty FV is allowed to contain nothing
   1315       //
   1316     }
   1317     //
   1318     // Close the file
   1319     //
   1320     SmartClose (FVPtr->FVFilePtr);
   1321     //
   1322     // Next FV in FileName
   1323     //
   1324     *EndCptr  = CSave;
   1325     StartCptr = EndCptr;
   1326     if (*StartCptr) {
   1327       StartCptr++;
   1328     }
   1329   }
   1330 
   1331   DSCFileRestorePosition (DSC);
   1332   return STATUS_SUCCESS;
   1333 }
   1334 
   1335 static
   1336 void
   1337 AddFirmwareVolumes (
   1338   char          *FVs,
   1339   int           ComponentsInstance
   1340   )
   1341 {
   1342   FV_LIST *FvPtr;
   1343   char    *StartPtr;
   1344   char    *EndPtr;
   1345   char    SaveChar;
   1346 
   1347   if ((FVs != NULL) && (FVs[0] != 0)) {
   1348     //
   1349     // Extract each FV name from the string. It's from the DSC file "FV=FvRecover,FvMain"
   1350     //
   1351     StartPtr = FVs;
   1352     while (*StartPtr != 0) {
   1353       EndPtr = StartPtr;
   1354       while (*EndPtr && (*EndPtr != ',')) {
   1355         EndPtr++;
   1356       }
   1357 
   1358       SaveChar  = *EndPtr;
   1359       *EndPtr   = 0;
   1360       //
   1361       // Look through our list of known firmware volumes and see if we've
   1362       // already added it.
   1363       //
   1364       for (FvPtr = mFVList; FvPtr != NULL; FvPtr = FvPtr->Next) {
   1365         if (_stricmp (FvPtr->FVFileName, StartPtr) == 0) {
   1366           break;
   1367         }
   1368       }
   1369       //
   1370       // If we didn't find a match, then create a new one
   1371       //
   1372       if (FvPtr == NULL) {
   1373         FvPtr = malloc (sizeof (FV_LIST));
   1374         if (FvPtr == NULL) {
   1375           Error (__FILE__, __LINE__, 0, "application error", "memory allocation failed");
   1376           return ;
   1377         }
   1378 
   1379         memset (FvPtr, 0, sizeof (FV_LIST));
   1380         strcpy (FvPtr->FVFileName, StartPtr);
   1381         if (mFVList == NULL) {
   1382           mFVList = FvPtr;
   1383         } else {
   1384           mFVListLast->Next = FvPtr;
   1385         }
   1386 
   1387         mFVListLast = FvPtr;
   1388       }
   1389       //
   1390       // If this component's section number is higher than that of this
   1391       // FV, then set the FV's to it.
   1392       //
   1393       if (FvPtr->ComponentsInstance < ComponentsInstance) {
   1394         FvPtr->ComponentsInstance = ComponentsInstance;
   1395       }
   1396       //
   1397       // If we found then end of the FVs in the string, then we're done.
   1398       // Always restore the original string's contents.
   1399       //
   1400       if (SaveChar != 0) {
   1401         *EndPtr   = SaveChar;
   1402         StartPtr  = EndPtr + 1;
   1403       } else {
   1404         StartPtr = EndPtr;
   1405       }
   1406     }
   1407   }
   1408 }
   1409 
   1410 static
   1411 BOOLEAN
   1412 OrderInFvList (
   1413   char    *FvList,
   1414   char    *FvName,
   1415   int     *Order
   1416   )
   1417 {
   1418   //
   1419   // Given FvList of format "FV_a,FV_b,FV_c" or "FV_a:1,FV_b:2" and
   1420   // FvName of format "FV_c", determine if FvName is in FvList. If
   1421   // FV_a:1 format, then return the value after the colon.
   1422   //
   1423   while (*FvList) {
   1424     //
   1425     // If it matches for the length of FvName...
   1426     //
   1427     if (_strnicmp (FvList, FvName, strlen (FvName)) == 0) {
   1428       //
   1429       // Then see if the match string in FvList is terminated at the
   1430       // same length.
   1431       //
   1432       if ((FvList[strlen (FvName)] == ',') || (FvList[strlen (FvName)] == 0)) {
   1433         *Order = 0;
   1434         return TRUE;
   1435       } else if (FvList[strlen (FvName)] == ':') {
   1436         *Order = atoi (FvList + strlen (FvName) + 1);
   1437         return TRUE;
   1438       }
   1439     }
   1440     //
   1441     // Skip to next FV in the comma-separated list
   1442     //
   1443     while ((*FvList != ',') && (*FvList != 0)) {
   1444       FvList++;
   1445     }
   1446     //
   1447     // Skip over comma
   1448     //
   1449     if (*FvList == ',') {
   1450       FvList++;
   1451     }
   1452   }
   1453 
   1454   return FALSE;
   1455 }
   1456 
   1457 static
   1458 char *
   1459 UpperCaseString (
   1460   char *Str
   1461   )
   1462 {
   1463   char  *Cptr;
   1464 
   1465   for (Cptr = Str; *Cptr; Cptr++) {
   1466     *Cptr = (char) toupper (*Cptr);
   1467   }
   1468 
   1469   return Str;
   1470 }
   1471 
   1472 static
   1473 BOOLEAN
   1474 InSameFv (
   1475   char  *FVs1,
   1476   char  *FVs2
   1477 )
   1478 {
   1479   char    *StartCptr1;
   1480   char    *StartCptr2;
   1481   char    *EndCptr1;
   1482   char    *EndCptr2;
   1483   char    CSave1;
   1484   char    CSave2;
   1485 
   1486   //
   1487   // Process each FV in first FV list
   1488   //
   1489   StartCptr1 = FVs1;
   1490   while (*StartCptr1) {
   1491     EndCptr1 = StartCptr1;
   1492     while (*EndCptr1 && (*EndCptr1 != ',')) {
   1493       EndCptr1++;
   1494     }
   1495 
   1496     CSave1     = *EndCptr1;
   1497     *EndCptr1  = 0;
   1498 
   1499     if (*StartCptr1) {
   1500       //
   1501       // Process each FV in second FV list
   1502       //
   1503       StartCptr2 = FVs2;
   1504       while (*StartCptr2) {
   1505         EndCptr2 = StartCptr2;
   1506         while (*EndCptr2 && (*EndCptr2 != ',')) {
   1507           EndCptr2++;
   1508         }
   1509 
   1510         CSave2     = *EndCptr2;
   1511         *EndCptr2  = 0;
   1512 
   1513         if (_stricmp (StartCptr1, StartCptr2) == 0) {
   1514           *EndCptr1  = CSave1;
   1515           *EndCptr2  = CSave2;
   1516           return TRUE;
   1517         }
   1518 
   1519         //
   1520         // Next FV on the second FV list
   1521         //
   1522         *EndCptr2  = CSave2;
   1523         StartCptr2 = EndCptr2;
   1524         if (*StartCptr2) {
   1525           StartCptr2++;
   1526         }
   1527       }
   1528     }
   1529 
   1530     //
   1531     // Next FV on the first FV list
   1532     //
   1533     *EndCptr1  = CSave1;
   1534     StartCptr1 = EndCptr1;
   1535     if (*StartCptr1) {
   1536       StartCptr1++;
   1537     }
   1538   }
   1539 
   1540   return FALSE;
   1541 }
   1542 
   1543 int
   1544 CFVSetXRefFileName (
   1545   char    *FileName
   1546   )
   1547 {
   1548   mXRefFileName = FileName;
   1549   return 0;
   1550 }
   1551