Home | History | Annotate | Download | only in ProcessDsc
      1 /*++
      2 
      3 Copyright (c) 2004 - 2007, 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     DscFile.c
     15 
     16   Abstract:
     17 
     18     This module is used to process description files at a high level. For the
     19     most part, it pre-parses the file to find and save off positions of all
     20     the sections ([section.subsection.subsection]) in a linked list, then
     21     provides services to find the sections by name, and read the lines from
     22     the section until you run into the next section.
     23 
     24   NOTE: DSC file is synonomous with section file. A DSC file is simply a file
     25     containing bracketed section names [section.subsection.subsection...]
     26 
     27 --*/
     28 
     29 #include <stdio.h>  // for file ops
     30 #include <string.h>
     31 #include <ctype.h>
     32 #include <stdlib.h> // for malloc
     33 #include "Common.h"
     34 #include "DSCFile.h"
     35 
     36 #define MAX_INCLUDE_NEST_LEVEL  20
     37 
     38 static
     39 void
     40 DSCFileFree (
     41   DSC_FILE *DSC
     42   );
     43 
     44 static
     45 STATUS
     46 DSCParseInclude (
     47   DSC_FILE  *DSC,
     48   char      *FileName,
     49   int       NestLevel
     50   );
     51 
     52 //
     53 // Constructor for a DSC file
     54 //
     55 int
     56 DSCFileInit (
     57   DSC_FILE *DSC
     58   )
     59 {
     60   memset ((char *) DSC, 0, sizeof (DSC_FILE));
     61   DSC->SavedPositionIndex = -1;
     62   return STATUS_SUCCESS;
     63 }
     64 //
     65 // Destructor for a DSC file
     66 //
     67 int
     68 DSCFileDestroy (
     69   DSC_FILE *DSC
     70   )
     71 {
     72   DSC->SavedPositionIndex = -1;
     73   DSCFileFree (DSC);
     74   return STATUS_SUCCESS;
     75 }
     76 //
     77 // Get the next line from a DSC file.
     78 //
     79 char *
     80 DSCFileGetLine (
     81   DSC_FILE  *DSC,
     82   char      *Line,
     83   int       LineLen
     84   )
     85 {
     86   char  *Cptr;
     87 
     88   if (DSC->CurrentLine == NULL) {
     89     return NULL;
     90   }
     91   //
     92   // Check for running into next section
     93   //
     94   if (DSC->CurrentLine->Line[0] == '[') {
     95     return NULL;
     96   }
     97   //
     98   // Allow special case where the line starts with backslash-bracket. If we
     99   // see this, then shift everything left one character.
    100   //
    101   if ((DSC->CurrentLine->Line[0] == '\\') && (DSC->CurrentLine->Line[1] == '[')) {
    102     Cptr = DSC->CurrentLine->Line + 1;
    103   } else {
    104     Cptr = DSC->CurrentLine->Line;
    105   }
    106 
    107   strncpy (Line, Cptr, LineLen);
    108   ParserSetPosition (DSC->CurrentLine->FileName, DSC->CurrentLine->LineNum);
    109   DSC->CurrentLine = DSC->CurrentLine->Next;
    110   return Line;
    111 }
    112 
    113 int
    114 DSCFileSetFile (
    115   DSC_FILE  *DSC,
    116   char      *FileName
    117   )
    118 /*++
    119 
    120 Routine Description:
    121 
    122   Pre-scan a section file to find all the sections. Then we can speed up
    123   searching for the different sections.
    124 
    125 Arguments:
    126 
    127   DSC       - pointer to a DSC structure (this pointer)
    128   FileName  - name of the file to process
    129 
    130 Returns:
    131 
    132   STATUS_SUCCESS if everything went well.
    133 
    134 --*/
    135 {
    136   STATUS  Status;
    137 
    138   //
    139   // Called to open a new sectioned file.
    140   //
    141   Status = DSCParseInclude (DSC, FileName, 1);
    142   return Status;
    143 }
    144 
    145 static
    146 STATUS
    147 DSCParseInclude (
    148   DSC_FILE    *DSC,
    149   char        *FileName,
    150   int         NestLevel
    151   )
    152 {
    153   SECTION       *NewSect;
    154   SECTION_LINE  *NewLine;
    155   DSC_FILE_NAME *NewDscFileName;
    156   char          Line[MAX_LINE_LEN];
    157   char          *Start;
    158   char          *End;
    159   char          SaveChar;
    160   char          *TempCptr;
    161   char          ShortHandSectionName[MAX_LINE_LEN];
    162   char          ThisSectionName[MAX_LINE_LEN];
    163   SECTION       *CurrSect;
    164   SECTION       *TempSect;
    165   FILE          *FilePtr;
    166   STATUS        Status;
    167   UINT32        LineNum;
    168 
    169   //
    170   // Make sure we haven't exceeded our maximum nesting level
    171   //
    172   if (NestLevel > MAX_INCLUDE_NEST_LEVEL) {
    173     Error (NULL, 0, 0, "application error", "maximum !include nesting level exceeded");
    174     return STATUS_ERROR;
    175   }
    176   //
    177   // Try to open the file
    178   //
    179   if ((FilePtr = fopen (FileName, "r")) == NULL) {
    180     //
    181     // This function is called to handle the DSC file from the command line too,
    182     // so differentiate whether this file is an include file or the main file
    183     // by examining the nest level.
    184     //
    185     if (NestLevel == 1) {
    186       Error (NULL, 0, 0, FileName, "could not open DSC file for reading");
    187     } else {
    188       Error (NULL, 0, 0, FileName, "could not open !include DSC file for reading");
    189     }
    190 
    191     return STATUS_ERROR;
    192   }
    193   //
    194   // We keep a linked list of files we parse for error reporting purposes.
    195   //
    196   NewDscFileName = malloc (sizeof (DSC_FILE_NAME));
    197   if (NewDscFileName == NULL) {
    198     Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);
    199     return STATUS_ERROR;
    200   }
    201 
    202   memset (NewDscFileName, 0, sizeof (DSC_FILE_NAME));
    203   NewDscFileName->FileName = (INT8 *) malloc (strlen (FileName) + 1);
    204   if (NewDscFileName->FileName == NULL) {
    205     Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);
    206     return STATUS_ERROR;
    207   }
    208 
    209   strcpy (NewDscFileName->FileName, FileName);
    210   if (DSC->FileName == NULL) {
    211     DSC->FileName = NewDscFileName;
    212   } else {
    213     DSC->LastFileName->Next = NewDscFileName;
    214   }
    215 
    216   DSC->LastFileName = NewDscFileName;
    217   //
    218   // Read lines and process until done
    219   //
    220   Status  = STATUS_SUCCESS;
    221   LineNum = 0;
    222   for (;;) {
    223     if (fgets (Line, sizeof (Line), FilePtr) == NULL) {
    224       break;
    225     }
    226 
    227     LineNum++;
    228     ParserSetPosition (FileName, LineNum);
    229     //
    230     // Add the line to our list if it's not a !include line
    231     //
    232     if ((strncmp (Line, "!include", 8) == 0) && (isspace (Line[8]))) {
    233       Start = Line + 9;
    234       while (*Start && (*Start != '"')) {
    235         Start++;
    236       }
    237 
    238       if (*Start != '"') {
    239         Error (FileName, LineNum, 0, NULL, "invalid format for !include");
    240         Status = STATUS_ERROR;
    241         goto Done;
    242       }
    243 
    244       Start++;
    245       for (End = Start; *End && (*End != '"'); End++)
    246         ;
    247       if (*End != '"') {
    248         Error (FileName, LineNum, 0, NULL, "invalid format for !include");
    249         Status = STATUS_ERROR;
    250         goto Done;
    251       }
    252 
    253       *End = 0;
    254       //
    255       // Expand symbols. Use 'ThisSectionName' as scratchpad
    256       //
    257       ExpandSymbols (Start, ThisSectionName, sizeof (ThisSectionName), EXPANDMODE_NO_UNDEFS);
    258       Status = DSCParseInclude (DSC, ThisSectionName, NestLevel + 1);
    259       if (Status != STATUS_SUCCESS) {
    260         Error (FileName, LineNum, 0, NULL, "failed to parse !include file");
    261         goto Done;
    262       }
    263     } else {
    264       NewLine = (SECTION_LINE *) malloc (sizeof (SECTION_LINE));
    265       if (NewLine == NULL) {
    266         Error (NULL, 0, 0, NULL, "failed to allocate memory");
    267         Status = STATUS_ERROR;
    268         goto Done;
    269       }
    270 
    271       memset ((char *) NewLine, 0, sizeof (SECTION_LINE));
    272       NewLine->LineNum  = LineNum;
    273       NewLine->FileName = NewDscFileName->FileName;
    274       NewLine->Line     = (char *) malloc (strlen (Line) + 1);
    275       if (NewLine->Line == NULL) {
    276         Error (NULL, 0, 0, NULL, "failed to allocate memory");
    277         Status = STATUS_ERROR;
    278         goto Done;
    279       }
    280 
    281       strcpy (NewLine->Line, Line);
    282       if (DSC->Lines == NULL) {
    283         DSC->Lines = NewLine;
    284       } else {
    285         DSC->LastLine->Next = NewLine;
    286       }
    287 
    288       DSC->LastLine = NewLine;
    289       //
    290       // Parse the line for []. Ignore [] and [----] delimiters. The
    291       // line may have multiple definitions separated by commas, so
    292       // take each separately
    293       //
    294       Start = Line;
    295       if ((Line[0] == '[') && ((Line[1] != ']') && (Line[1] != '-'))) {
    296         //
    297         // Skip over open bracket and preceeding spaces
    298         //
    299         Start++;
    300         ShortHandSectionName[0] = 0;
    301 
    302         while (*Start && (*Start != ']')) {
    303           while (isspace (*Start)) {
    304             Start++;
    305           }
    306           //
    307           // Hack off closing bracket or trailing spaces or comma separator.
    308           // Also allow things like [section.subsection1|subsection2], which
    309           // is shorthand for [section.subsection1,section.subsection2]
    310           //
    311           End = Start;
    312           while (*End && (*End != ']') && !isspace (*End) && (*End != ',') && (*End != '|')) {
    313             End++;
    314           }
    315           //
    316           // Save the character and null-terminate the string
    317           //
    318           SaveChar  = *End;
    319           *End      = 0;
    320           //
    321           // Now allocate space for a new section and add it to the linked list.
    322           // If the previous section ended with the shorthand indicator, then
    323           // the section name was saved off. Append this section name to it.
    324           //
    325           strcpy (ThisSectionName, ShortHandSectionName);
    326           if (*Start == '.') {
    327             strcat (ThisSectionName, Start + 1);
    328           } else {
    329             strcat (ThisSectionName, Start);
    330           }
    331           //
    332           // Allocate memory for the section. Then clear it out.
    333           //
    334           NewSect = (SECTION *) malloc (sizeof (SECTION));
    335           if (NewSect == NULL) {
    336             Error (NULL, 0, 0, NULL, "failed to allocation memory for sections");
    337             Status = STATUS_ERROR;
    338             goto Done;
    339           }
    340 
    341           memset ((char *) NewSect, 0, sizeof (SECTION));
    342           NewSect->FirstLine  = NewLine;
    343           NewSect->Name       = (char *) malloc (strlen (ThisSectionName) + 1);
    344           if (NewSect->Name == NULL) {
    345             Error (NULL, 0, 0, NULL, "failed to allocation memory for sections");
    346             Status = STATUS_ERROR;
    347             goto Done;
    348           }
    349 
    350           strcpy (NewSect->Name, ThisSectionName);
    351           if (DSC->Sections == NULL) {
    352             DSC->Sections = NewSect;
    353           } else {
    354             DSC->LastSection->Next = NewSect;
    355           }
    356 
    357           DSC->LastSection  = NewSect;
    358           *End              = SaveChar;
    359           //
    360           // If the name ended in a shorthand indicator, then save the
    361           // section name and truncate it at the last dot.
    362           //
    363           if (SaveChar == '|') {
    364             strcpy (ShortHandSectionName, ThisSectionName);
    365             for (TempCptr = ShortHandSectionName + strlen (ShortHandSectionName) - 1;
    366                  (TempCptr != ShortHandSectionName) && (*TempCptr != '.');
    367                  TempCptr--
    368                 )
    369               ;
    370             //
    371             // If we didn't find a dot, then hopefully they have [name1|name2]
    372             // instead of [name1,name2].
    373             //
    374             if (TempCptr == ShortHandSectionName) {
    375               ShortHandSectionName[0] = 0;
    376             } else {
    377               //
    378               // Truncate after the dot
    379               //
    380               *(TempCptr + 1) = 0;
    381             }
    382           } else {
    383             //
    384             // Kill the shorthand string
    385             //
    386             ShortHandSectionName[0] = 0;
    387           }
    388           //
    389           // Skip to next section name or closing bracket
    390           //
    391           while (*End && ((*End == ',') || isspace (*End) || (*End == '|'))) {
    392             End++;
    393           }
    394 
    395           Start = End;
    396         }
    397       }
    398     }
    399   }
    400   //
    401   // Look through all the sections to make sure we don't have any duplicates.
    402   // Allow [----] and [====] section separators
    403   //
    404   CurrSect = DSC->Sections;
    405   while (CurrSect != NULL) {
    406     TempSect = CurrSect->Next;
    407     while (TempSect != NULL) {
    408       if (isalpha (CurrSect->Name[0]) && (_stricmp (CurrSect->Name, TempSect->Name) == 0)) {
    409         Error (
    410           TempSect->FirstLine->FileName,
    411           TempSect->FirstLine->LineNum,
    412           0,
    413           TempSect->Name,
    414           "duplicate section found"
    415           );
    416         Error (
    417           CurrSect->FirstLine->FileName,
    418           CurrSect->FirstLine->LineNum,
    419           0,
    420           TempSect->Name,
    421           "first definition of duplicate section"
    422           );
    423         Status = STATUS_ERROR;
    424         goto Done;
    425       }
    426 
    427       TempSect = TempSect->Next;
    428     }
    429 
    430     CurrSect = CurrSect->Next;
    431   }
    432 
    433 Done:
    434   fclose (FilePtr);
    435   return Status;
    436 }
    437 //
    438 // Free up memory allocated for DSC file handling.
    439 //
    440 static
    441 void
    442 DSCFileFree (
    443   DSC_FILE *DSC
    444   )
    445 {
    446   SECTION       *NextSection;
    447   SECTION_LINE  *NextLine;
    448   DSC_FILE_NAME *NextName;
    449 
    450   while (DSC->Sections != NULL) {
    451     NextSection = DSC->Sections->Next;
    452     if (DSC->Sections->Name != NULL) {
    453       free (DSC->Sections->Name);
    454     }
    455 
    456     free (DSC->Sections);
    457     DSC->Sections = NextSection;
    458   }
    459 
    460   while (DSC->Lines != NULL) {
    461     NextLine = DSC->Lines->Next;
    462     free (DSC->Lines->Line);
    463     free (DSC->Lines);
    464     DSC->Lines = NextLine;
    465   }
    466 
    467   while (DSC->FileName != NULL) {
    468     NextName = DSC->FileName->Next;
    469     free (DSC->FileName->FileName);
    470     free (DSC->FileName);
    471     DSC->FileName = NextName;
    472   }
    473 }
    474 
    475 SECTION *
    476 DSCFileFindSection (
    477   DSC_FILE  *DSC,
    478   char      *Name
    479   )
    480 {
    481   SECTION *Sect;
    482 
    483   //
    484   // Look through all the sections to find one with this name (case insensitive)
    485   //
    486   Sect = DSC->Sections;
    487   while (Sect != NULL) {
    488     if (_stricmp (Name, Sect->Name) == 0) {
    489       //
    490       // Position within file
    491       //
    492       DSC->CurrentLine = Sect->FirstLine->Next;
    493       return Sect;
    494     }
    495 
    496     Sect = Sect->Next;
    497   }
    498 
    499   return NULL;
    500 }
    501 
    502 int
    503 DSCFileSavePosition (
    504   DSC_FILE *DSC
    505   )
    506 {
    507   //
    508   // Advance to next slot
    509   //
    510   DSC->SavedPositionIndex++;
    511   if (DSC->SavedPositionIndex >= MAX_SAVES) {
    512     DSC->SavedPositionIndex--;
    513     Error (NULL, 0, 0, "APP ERROR", "max nesting of saved section file positions exceeded");
    514     return STATUS_ERROR;
    515   }
    516 
    517   DSC->SavedPosition[DSC->SavedPositionIndex] = DSC->CurrentLine;
    518   return STATUS_SUCCESS;
    519 }
    520 
    521 int
    522 DSCFileRestorePosition (
    523   DSC_FILE *DSC
    524   )
    525 {
    526   if (DSC->SavedPositionIndex < 0) {
    527     Error (NULL, 0, 0, "APP ERROR", "underflow of saved positions in section file");
    528     return STATUS_ERROR;
    529   }
    530 
    531   DSC->CurrentLine = DSC->SavedPosition[DSC->SavedPositionIndex];
    532   DSC->SavedPositionIndex--;
    533   return STATUS_SUCCESS;
    534 }
    535