Home | History | Annotate | Download | only in Common
      1 /** @file
      2 Generic but simple file parsing routines.
      3 
      4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 --*/
     14 
     15 #include <stdio.h>
     16 #include <string.h>
     17 #include <stdlib.h>
     18 #include <ctype.h>
     19 
     20 #include "CommonLib.h"
     21 #include "EfiUtilityMsgs.h"
     22 #include "SimpleFileParsing.h"
     23 
     24 #ifndef MAX_PATH
     25 #define MAX_PATH  255
     26 #endif
     27 //
     28 // just in case we get in an endless loop.
     29 //
     30 #define MAX_NEST_DEPTH  20
     31 //
     32 // number of wchars
     33 //
     34 #define MAX_STRING_IDENTIFIER_NAME  100
     35 
     36 #define T_CHAR_SPACE                ' '
     37 #define T_CHAR_NULL                 0
     38 #define T_CHAR_CR                   '\r'
     39 #define T_CHAR_TAB                  '\t'
     40 #define T_CHAR_LF                   '\n'
     41 #define T_CHAR_SLASH                '/'
     42 #define T_CHAR_BACKSLASH            '\\'
     43 #define T_CHAR_DOUBLE_QUOTE         '"'
     44 #define T_CHAR_LC_X                 'x'
     45 #define T_CHAR_0                    '0'
     46 #define T_CHAR_STAR                 '*'
     47 
     48 //
     49 // We keep a linked list of these for the source files we process
     50 //
     51 typedef struct _SOURCE_FILE {
     52   FILE                *Fptr;
     53   CHAR8               *FileBuffer;
     54   CHAR8               *FileBufferPtr;
     55   UINTN               FileSize;
     56   CHAR8               FileName[MAX_PATH];
     57   UINTN               LineNum;
     58   BOOLEAN             EndOfFile;
     59   BOOLEAN             SkipToHash;
     60   struct _SOURCE_FILE *Previous;
     61   struct _SOURCE_FILE *Next;
     62   CHAR8               ControlCharacter;
     63 } SOURCE_FILE;
     64 
     65 typedef struct {
     66   CHAR8   *FileBufferPtr;
     67 } FILE_POSITION;
     68 
     69 //
     70 // Keep all our module globals in this structure
     71 //
     72 STATIC struct {
     73   SOURCE_FILE SourceFile;
     74   BOOLEAN     VerboseFile;
     75   BOOLEAN     VerboseToken;
     76 } mGlobals;
     77 
     78 STATIC
     79 UINTN
     80 t_strcmp (
     81   CHAR8  *Buffer,
     82   CHAR8  *Str
     83   );
     84 
     85 STATIC
     86 UINTN
     87 t_strncmp (
     88   CHAR8  *Str1,
     89   CHAR8  *Str2,
     90   INTN    Len
     91   );
     92 
     93 STATIC
     94 UINTN
     95 t_strlen (
     96   CHAR8  *Str
     97   );
     98 
     99 STATIC
    100 VOID
    101 RewindFile (
    102   SOURCE_FILE *SourceFile
    103   );
    104 
    105 STATIC
    106 BOOLEAN
    107 IsWhiteSpace (
    108   SOURCE_FILE *SourceFile
    109   );
    110 
    111 STATIC
    112 UINTN
    113 SkipWhiteSpace (
    114   SOURCE_FILE *SourceFile
    115   );
    116 
    117 STATIC
    118 BOOLEAN
    119 EndOfFile (
    120   SOURCE_FILE *SourceFile
    121   );
    122 
    123 STATIC
    124 VOID
    125 PreprocessFile (
    126   SOURCE_FILE *SourceFile
    127   );
    128 
    129 STATIC
    130 CHAR8   *
    131 t_strcpy (
    132   CHAR8  *Dest,
    133   CHAR8  *Src
    134   );
    135 
    136 STATIC
    137 STATUS
    138 ProcessIncludeFile (
    139   SOURCE_FILE *SourceFile,
    140   SOURCE_FILE *ParentSourceFile
    141   );
    142 
    143 STATIC
    144 STATUS
    145 ProcessFile (
    146   SOURCE_FILE *SourceFile
    147   );
    148 
    149 STATIC
    150 STATUS
    151 GetFilePosition (
    152   FILE_POSITION *Fpos
    153   );
    154 
    155 STATIC
    156 STATUS
    157 SetFilePosition (
    158   FILE_POSITION *Fpos
    159   );
    160 
    161 STATUS
    162 SFPInit (
    163   VOID
    164   )
    165 /*++
    166 
    167 Routine Description:
    168 
    169 Arguments:
    170   None.
    171 
    172 Returns:
    173   STATUS_SUCCESS always
    174 
    175 --*/
    176 {
    177   memset ((VOID *) &mGlobals, 0, sizeof (mGlobals));
    178   return STATUS_SUCCESS;
    179 }
    180 
    181 UINTN
    182 SFPGetLineNumber (
    183   VOID
    184   )
    185 /*++
    186 
    187 Routine Description:
    188   Return the line number of the file we're parsing. Used
    189   for error reporting purposes.
    190 
    191 Arguments:
    192   None.
    193 
    194 Returns:
    195   The line number, or 0 if no file is being processed
    196 
    197 --*/
    198 {
    199   return mGlobals.SourceFile.LineNum;
    200 }
    201 
    202 CHAR8  *
    203 SFPGetFileName (
    204   VOID
    205   )
    206 /*++
    207 
    208 Routine Description:
    209   Return the name of the file we're parsing. Used
    210   for error reporting purposes.
    211 
    212 Arguments:
    213   None.
    214 
    215 Returns:
    216   A pointer to the file name. Null if no file is being
    217   processed.
    218 
    219 --*/
    220 {
    221   if (mGlobals.SourceFile.FileName[0]) {
    222     return mGlobals.SourceFile.FileName;
    223   }
    224 
    225   return NULL;
    226 }
    227 
    228 STATUS
    229 SFPOpenFile (
    230   CHAR8      *FileName
    231   )
    232 /*++
    233 
    234 Routine Description:
    235   Open a file for parsing.
    236 
    237 Arguments:
    238   FileName  - name of the file to parse
    239 
    240 Returns:
    241 
    242 
    243 --*/
    244 {
    245   STATUS  Status;
    246   t_strcpy (mGlobals.SourceFile.FileName, FileName);
    247   Status = ProcessIncludeFile (&mGlobals.SourceFile, NULL);
    248   return Status;
    249 }
    250 
    251 BOOLEAN
    252 SFPIsToken (
    253   CHAR8  *Str
    254   )
    255 /*++
    256 
    257 Routine Description:
    258   Check to see if the specified token is found at
    259   the current position in the input file.
    260 
    261 Arguments:
    262   Str - the token to look for
    263 
    264 Returns:
    265   TRUE - the token is next
    266   FALSE - the token is not next
    267 
    268 Notes:
    269   We do a simple string comparison on this function. It is
    270   the responsibility of the caller to ensure that the token
    271   is not a subset of some other token.
    272 
    273   The file pointer is advanced past the token in the input file.
    274 
    275 --*/
    276 {
    277   UINTN  Len;
    278   SkipWhiteSpace (&mGlobals.SourceFile);
    279   if (EndOfFile (&mGlobals.SourceFile)) {
    280     return FALSE;
    281   }
    282 
    283   if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) {
    284     mGlobals.SourceFile.FileBufferPtr += Len;
    285     if (mGlobals.VerboseToken) {
    286       printf ("Token: '%s'\n", Str);
    287     }
    288 
    289     return TRUE;
    290   }
    291 
    292   return FALSE;
    293 }
    294 
    295 BOOLEAN
    296 SFPIsKeyword (
    297   CHAR8  *Str
    298   )
    299 /*++
    300 
    301 Routine Description:
    302   Check to see if the specified keyword is found at
    303   the current position in the input file.
    304 
    305 Arguments:
    306   Str - keyword to look for
    307 
    308 Returns:
    309   TRUE - the keyword is next
    310   FALSE - the keyword is not next
    311 
    312 Notes:
    313   A keyword is defined as a "special" string that has a non-alphanumeric
    314   character following it.
    315 
    316 --*/
    317 {
    318   UINTN  Len;
    319   SkipWhiteSpace (&mGlobals.SourceFile);
    320   if (EndOfFile (&mGlobals.SourceFile)) {
    321     return FALSE;
    322   }
    323 
    324   if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) {
    325     if (isalnum ((int)mGlobals.SourceFile.FileBufferPtr[Len])) {
    326       return FALSE;
    327     }
    328 
    329     mGlobals.SourceFile.FileBufferPtr += Len;
    330     if (mGlobals.VerboseToken) {
    331       printf ("Token: '%s'\n", Str);
    332     }
    333 
    334     return TRUE;
    335   }
    336 
    337   return FALSE;
    338 }
    339 
    340 BOOLEAN
    341 SFPGetNextToken (
    342   CHAR8  *Str,
    343   UINTN  Len
    344   )
    345 /*++
    346 
    347 Routine Description:
    348   Get the next token from the input stream.
    349 
    350 Arguments:
    351   Str - pointer to a copy of the next token
    352   Len - size of buffer pointed to by Str
    353 
    354 Returns:
    355   TRUE  - next token successfully returned
    356   FALSE - otherwise
    357 
    358 Notes:
    359   Preceeding white space is ignored.
    360   The parser's buffer pointer is advanced past the end of the
    361   token.
    362 
    363 --*/
    364 {
    365   UINTN  Index;
    366   CHAR8  TempChar;
    367 
    368   SkipWhiteSpace (&mGlobals.SourceFile);
    369   if (EndOfFile (&mGlobals.SourceFile)) {
    370     return FALSE;
    371   }
    372   //
    373   // Have to have enough string for at least one char and a null-terminator
    374   //
    375   if (Len < 2) {
    376     return FALSE;
    377   }
    378   //
    379   // Look at the first character. If it's an identifier, then treat it
    380   // as such
    381   //
    382   TempChar = mGlobals.SourceFile.FileBufferPtr[0];
    383   if (((TempChar >= 'a') && (TempChar <= 'z')) || ((TempChar >= 'A') && (TempChar <= 'Z')) || (TempChar == '_')) {
    384     Str[0] = TempChar;
    385     mGlobals.SourceFile.FileBufferPtr++;
    386     Index = 1;
    387     while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) {
    388       TempChar = mGlobals.SourceFile.FileBufferPtr[0];
    389       if (((TempChar >= 'a') && (TempChar <= 'z')) ||
    390           ((TempChar >= 'A') && (TempChar <= 'Z')) ||
    391           ((TempChar >= '0') && (TempChar <= '9')) ||
    392           (TempChar == '_')
    393           ) {
    394         Str[Index] = mGlobals.SourceFile.FileBufferPtr[0];
    395         mGlobals.SourceFile.FileBufferPtr++;
    396         Index++;
    397       } else {
    398         //
    399         // Invalid character for symbol name, so break out
    400         //
    401         break;
    402       }
    403     }
    404     //
    405     // Null terminate and return success
    406     //
    407     Str[Index] = 0;
    408     return TRUE;
    409   } else if ((TempChar == ')') || (TempChar == '(') || (TempChar == '*')) {
    410     Str[0] = mGlobals.SourceFile.FileBufferPtr[0];
    411     mGlobals.SourceFile.FileBufferPtr++;
    412     Str[1] = 0;
    413     return TRUE;
    414   } else {
    415     //
    416     // Everything else is white-space (or EOF) separated
    417     //
    418     Index = 0;
    419     while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) {
    420       if (IsWhiteSpace (&mGlobals.SourceFile)) {
    421         if (Index > 0) {
    422           Str[Index] = 0;
    423           return TRUE;
    424         }
    425 
    426         return FALSE;
    427       } else {
    428         Str[Index] = mGlobals.SourceFile.FileBufferPtr[0];
    429         mGlobals.SourceFile.FileBufferPtr++;
    430         Index++;
    431       }
    432     }
    433     //
    434     // See if we just ran out of file contents, but did find a token
    435     //
    436     if ((Index > 0) && EndOfFile (&mGlobals.SourceFile)) {
    437       Str[Index] = 0;
    438       return TRUE;
    439     }
    440   }
    441 
    442   return FALSE;
    443 }
    444 
    445 BOOLEAN
    446 SFPGetGuidToken (
    447   CHAR8  *Str,
    448   UINT32 Len
    449   )
    450 /*++
    451 
    452 Routine Description:
    453   Parse a GUID from the input stream. Stop when you discover white space.
    454 
    455 Arguments:
    456   Str - pointer to a copy of the next token
    457   Len - size of buffer pointed to by Str
    458 
    459 Returns:
    460   TRUE  - GUID string returned successfully
    461   FALSE - otherwise
    462 
    463 --*/
    464 {
    465   UINT32  Index;
    466   SkipWhiteSpace (&mGlobals.SourceFile);
    467   if (EndOfFile (&mGlobals.SourceFile)) {
    468     return FALSE;
    469   }
    470 
    471   Index = 0;
    472   while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) {
    473     if (IsWhiteSpace (&mGlobals.SourceFile)) {
    474       if (Index > 0) {
    475         Str[Index] = 0;
    476         return TRUE;
    477       }
    478 
    479       return FALSE;
    480     } else {
    481       Str[Index] = mGlobals.SourceFile.FileBufferPtr[0];
    482       mGlobals.SourceFile.FileBufferPtr++;
    483       Index++;
    484     }
    485   }
    486 
    487   return FALSE;
    488 }
    489 
    490 BOOLEAN
    491 SFPSkipToToken (
    492   CHAR8  *Str
    493   )
    494 {
    495   UINTN  Len;
    496   CHAR8         *SavePos;
    497   Len     = t_strlen (Str);
    498   SavePos = mGlobals.SourceFile.FileBufferPtr;
    499   SkipWhiteSpace (&mGlobals.SourceFile);
    500   while (!EndOfFile (&mGlobals.SourceFile)) {
    501     if (t_strncmp (Str, mGlobals.SourceFile.FileBufferPtr, Len) == 0) {
    502       mGlobals.SourceFile.FileBufferPtr += Len;
    503       return TRUE;
    504     }
    505 
    506     mGlobals.SourceFile.FileBufferPtr++;
    507     SkipWhiteSpace (&mGlobals.SourceFile);
    508   }
    509 
    510   mGlobals.SourceFile.FileBufferPtr = SavePos;
    511   return FALSE;
    512 }
    513 
    514 BOOLEAN
    515 SFPGetNumber (
    516   UINTN *Value
    517   )
    518 /*++
    519 
    520 Routine Description:
    521   Check the token at the current file position for a numeric value.
    522   May be either decimal or hex.
    523 
    524 Arguments:
    525   Value  - pointer where to store the value
    526 
    527 Returns:
    528   FALSE    - current token is not a number
    529   TRUE     - current token is a number
    530 
    531 --*/
    532 {
    533   unsigned Val;
    534 
    535   SkipWhiteSpace (&mGlobals.SourceFile);
    536   if (EndOfFile (&mGlobals.SourceFile)) {
    537     return FALSE;
    538   }
    539 
    540   if (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) {
    541     //
    542     // Check for hex value
    543     //
    544     if ((mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_0) && (mGlobals.SourceFile.FileBufferPtr[1] == T_CHAR_LC_X)) {
    545       if (!isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[2])) {
    546         return FALSE;
    547       }
    548 
    549       mGlobals.SourceFile.FileBufferPtr += 2;
    550       sscanf (mGlobals.SourceFile.FileBufferPtr, "%x", &Val);
    551       *Value = (UINT32) Val;
    552       while (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) {
    553         mGlobals.SourceFile.FileBufferPtr++;
    554       }
    555 
    556       return TRUE;
    557     } else {
    558       *Value = atoi (mGlobals.SourceFile.FileBufferPtr);
    559       while (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) {
    560         mGlobals.SourceFile.FileBufferPtr++;
    561       }
    562 
    563       return TRUE;
    564     }
    565   } else {
    566     return FALSE;
    567   }
    568 }
    569 
    570 STATUS
    571 SFPCloseFile (
    572   VOID
    573   )
    574 /*++
    575 
    576 Routine Description:
    577   Close the file being parsed.
    578 
    579 Arguments:
    580   None.
    581 
    582 Returns:
    583   STATUS_SUCCESS - the file was closed
    584   STATUS_ERROR   - no file is currently open
    585 
    586 --*/
    587 {
    588   if (mGlobals.SourceFile.FileBuffer != NULL) {
    589     free (mGlobals.SourceFile.FileBuffer);
    590     memset (&mGlobals.SourceFile, 0, sizeof (mGlobals.SourceFile));
    591     return STATUS_SUCCESS;
    592   }
    593 
    594   return STATUS_ERROR;
    595 }
    596 
    597 STATIC
    598 STATUS
    599 ProcessIncludeFile (
    600   SOURCE_FILE *SourceFile,
    601   SOURCE_FILE *ParentSourceFile
    602   )
    603 /*++
    604 
    605 Routine Description:
    606 
    607   Given a source file, open the file and parse it
    608 
    609 Arguments:
    610 
    611   SourceFile        - name of file to parse
    612   ParentSourceFile  - for error reporting purposes, the file that #included SourceFile.
    613 
    614 Returns:
    615 
    616   Standard status.
    617 
    618 --*/
    619 {
    620   STATIC UINTN NestDepth = 0;
    621   CHAR8               FoundFileName[MAX_PATH];
    622   STATUS              Status;
    623 
    624   Status = STATUS_SUCCESS;
    625   NestDepth++;
    626   //
    627   // Print the file being processed. Indent so you can tell the include nesting
    628   // depth.
    629   //
    630   if (mGlobals.VerboseFile) {
    631     fprintf (stdout, "%*cProcessing file '%s'\n", (int)NestDepth * 2, ' ', SourceFile->FileName);
    632     fprintf (stdout, "Parent source file = '%s'\n", ParentSourceFile->FileName);
    633   }
    634 
    635   //
    636   // Make sure we didn't exceed our maximum nesting depth
    637   //
    638   if (NestDepth > MAX_NEST_DEPTH) {
    639     Error (NULL, 0, 3001, "Not Supported", "%s exceeeds max nesting depth (%u)", SourceFile->FileName, (unsigned) NestDepth);
    640     Status = STATUS_ERROR;
    641     goto Finish;
    642   }
    643   //
    644   // Try to open the file locally, and if that fails try along our include paths.
    645   //
    646   strcpy (FoundFileName, SourceFile->FileName);
    647   if ((SourceFile->Fptr = fopen (LongFilePath (FoundFileName), "rb")) == NULL) {
    648     return STATUS_ERROR;
    649   }
    650   //
    651   // Process the file found
    652   //
    653   ProcessFile (SourceFile);
    654 Finish:
    655   //
    656   // Close open files and return status
    657   //
    658   if (SourceFile->Fptr != NULL) {
    659     fclose (SourceFile->Fptr);
    660     SourceFile->Fptr = NULL;
    661   }
    662 
    663   return Status;
    664 }
    665 
    666 STATIC
    667 STATUS
    668 ProcessFile (
    669   SOURCE_FILE *SourceFile
    670   )
    671 /*++
    672 
    673 Routine Description:
    674 
    675   Given a source file that's been opened, read the contents into an internal
    676   buffer and pre-process it to remove comments.
    677 
    678 Arguments:
    679 
    680   SourceFile        - structure containing info on the file to process
    681 
    682 Returns:
    683 
    684   Standard status.
    685 
    686 --*/
    687 {
    688   //
    689   // Get the file size, and then read the entire thing into memory.
    690   // Allocate extra space for a terminator character.
    691   //
    692   fseek (SourceFile->Fptr, 0, SEEK_END);
    693   SourceFile->FileSize = ftell (SourceFile->Fptr);
    694   if (mGlobals.VerboseFile) {
    695     printf ("FileSize = %u (0x%X)\n", (unsigned) SourceFile->FileSize, (unsigned) SourceFile->FileSize);
    696   }
    697 
    698   fseek (SourceFile->Fptr, 0, SEEK_SET);
    699   SourceFile->FileBuffer = (CHAR8  *) malloc (SourceFile->FileSize + sizeof (CHAR8 ));
    700   if (SourceFile->FileBuffer == NULL) {
    701     Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL);
    702     return STATUS_ERROR;
    703   }
    704 
    705   fread ((VOID *) SourceFile->FileBuffer, SourceFile->FileSize, 1, SourceFile->Fptr);
    706   SourceFile->FileBuffer[(SourceFile->FileSize / sizeof (CHAR8 ))] = T_CHAR_NULL;
    707   //
    708   // Pre-process the file to replace comments with spaces
    709   //
    710   PreprocessFile (SourceFile);
    711   SourceFile->LineNum = 1;
    712   return STATUS_SUCCESS;
    713 }
    714 
    715 STATIC
    716 VOID
    717 PreprocessFile (
    718   SOURCE_FILE *SourceFile
    719   )
    720 /*++
    721 
    722 Routine Description:
    723   Preprocess a file to replace all carriage returns with NULLs so
    724   we can print lines (as part of error messages) from the file to the screen.
    725 
    726 Arguments:
    727   SourceFile - structure that we use to keep track of an input file.
    728 
    729 Returns:
    730   Nothing.
    731 
    732 --*/
    733 {
    734   BOOLEAN InComment;
    735   BOOLEAN SlashSlashComment;
    736   int     LineNum;
    737 
    738   RewindFile (SourceFile);
    739   InComment         = FALSE;
    740   SlashSlashComment = FALSE;
    741   while (!EndOfFile (SourceFile)) {
    742     //
    743     // If a line-feed, then no longer in a comment if we're in a // comment
    744     //
    745     if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) {
    746       SourceFile->FileBufferPtr++;
    747       SourceFile->LineNum++;
    748       if (InComment && SlashSlashComment) {
    749         InComment         = FALSE;
    750         SlashSlashComment = FALSE;
    751       }
    752     } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) {
    753       //
    754       // Replace all carriage returns with a NULL so we can print stuff
    755       //
    756       SourceFile->FileBufferPtr[0] = 0;
    757       SourceFile->FileBufferPtr++;
    758       //
    759       // Check for */ comment end
    760       //
    761     } else if (InComment &&
    762              !SlashSlashComment &&
    763              (SourceFile->FileBufferPtr[0] == T_CHAR_STAR) &&
    764              (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH)
    765             ) {
    766       SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
    767       SourceFile->FileBufferPtr++;
    768       SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
    769       SourceFile->FileBufferPtr++;
    770       InComment = FALSE;
    771     } else if (InComment) {
    772       SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
    773       SourceFile->FileBufferPtr++;
    774       //
    775       // Check for // comments
    776       //
    777     } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH)) {
    778       InComment         = TRUE;
    779       SlashSlashComment = TRUE;
    780       //
    781       // Check for /* comment start
    782       //
    783     } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_STAR)) {
    784       SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
    785       SourceFile->FileBufferPtr++;
    786       SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
    787       SourceFile->FileBufferPtr++;
    788       SlashSlashComment = FALSE;
    789       InComment         = TRUE;
    790     } else {
    791       SourceFile->FileBufferPtr++;
    792     }
    793   }
    794   //
    795   // Could check for end-of-file and still in a comment, but
    796   // should not be necessary. So just restore the file pointers.
    797   //
    798   RewindFile (SourceFile);
    799   //
    800   // Dump the reformatted file if verbose mode
    801   //
    802   if (mGlobals.VerboseFile) {
    803     LineNum = 1;
    804     printf ("%04d: ", LineNum);
    805     while (!EndOfFile (SourceFile)) {
    806       if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) {
    807         printf ("'\n%04d: '", ++LineNum);
    808       } else {
    809         printf ("%c", SourceFile->FileBufferPtr[0]);
    810       }
    811 
    812       SourceFile->FileBufferPtr++;
    813     }
    814 
    815     printf ("'\n");
    816     printf ("FileSize = %u (0x%X)\n", (unsigned)SourceFile->FileSize, (unsigned)SourceFile->FileSize);
    817     RewindFile (SourceFile);
    818   }
    819 }
    820 
    821 BOOLEAN
    822 SFPGetQuotedString (
    823   CHAR8       *Str,
    824   INTN         Length
    825   )
    826 /*++
    827 
    828 Routine Description:
    829   Retrieve a quoted-string from the input file.
    830 
    831 Arguments:
    832   Str    - pointer to a copy of the quoted string parsed
    833   Length - size of buffer pointed to by Str
    834 
    835 Returns:
    836   TRUE    - next token in input stream was a quoted string, and
    837             the string value was returned in Str
    838   FALSE   - otherwise
    839 
    840 --*/
    841 {
    842   SkipWhiteSpace (&mGlobals.SourceFile);
    843   if (EndOfFile (&mGlobals.SourceFile)) {
    844     return FALSE;
    845   }
    846 
    847   if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) {
    848     mGlobals.SourceFile.FileBufferPtr++;
    849     while (Length > 0) {
    850       if (EndOfFile (&mGlobals.SourceFile)) {
    851         return FALSE;
    852       }
    853       //
    854       // Check for closing quote
    855       //
    856       if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) {
    857         mGlobals.SourceFile.FileBufferPtr++;
    858         *Str = 0;
    859         return TRUE;
    860       }
    861 
    862       *Str = mGlobals.SourceFile.FileBufferPtr[0];
    863       Str++;
    864       Length--;
    865       mGlobals.SourceFile.FileBufferPtr++;
    866     }
    867   }
    868   //
    869   // First character was not a quote, or the input string length was
    870   // insufficient to contain the quoted string, so return failure code.
    871   //
    872   return FALSE;
    873 }
    874 
    875 BOOLEAN
    876 SFPIsEOF (
    877   VOID
    878   )
    879 /*++
    880 
    881 Routine Description:
    882   Return TRUE of FALSE to indicate whether or not we've reached the end of the
    883   file we're parsing.
    884 
    885 Arguments:
    886   NA
    887 
    888 Returns:
    889   TRUE    - EOF reached
    890   FALSE   - otherwise
    891 
    892 --*/
    893 {
    894   SkipWhiteSpace (&mGlobals.SourceFile);
    895   return EndOfFile (&mGlobals.SourceFile);
    896 }
    897 
    898 #if 0
    899 STATIC
    900 CHAR8  *
    901 GetQuotedString (
    902   SOURCE_FILE *SourceFile,
    903   BOOLEAN     Optional
    904   )
    905 {
    906   CHAR8         *String;
    907   CHAR8         *Start;
    908   CHAR8         *Ptr;
    909   UINTN         Len;
    910   BOOLEAN       PreviousBackslash;
    911 
    912   if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) {
    913     if (Optional == FALSE) {
    914       Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted string", "%S", SourceFile->FileBufferPtr);
    915     }
    916 
    917     return NULL;
    918   }
    919 
    920   Len = 0;
    921   SourceFile->FileBufferPtr++;
    922   Start             = Ptr = SourceFile->FileBufferPtr;
    923   PreviousBackslash = FALSE;
    924   while (!EndOfFile (SourceFile)) {
    925     if ((SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) && (PreviousBackslash == FALSE)) {
    926       break;
    927     } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) {
    928       Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start);
    929       PreviousBackslash = FALSE;
    930     } else if (SourceFile->FileBufferPtr[0] == T_CHAR_BACKSLASH) {
    931       PreviousBackslash = TRUE;
    932     } else {
    933       PreviousBackslash = FALSE;
    934     }
    935 
    936     SourceFile->FileBufferPtr++;
    937     Len++;
    938   }
    939 
    940   if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) {
    941     Warning (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", "%S", Start);
    942   } else {
    943     SourceFile->FileBufferPtr++;
    944   }
    945   //
    946   // Now allocate memory for the string and save it off
    947   //
    948   String = (CHAR8  *) malloc ((Len + 1) * sizeof (CHAR8 ));
    949   if (String == NULL) {
    950     Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL);
    951     return NULL;
    952   }
    953   //
    954   // Copy the string from the file buffer to the local copy.
    955   // We do no reformatting of it whatsoever at this point.
    956   //
    957   Ptr = String;
    958   while (Len > 0) {
    959     *Ptr = *Start;
    960     Start++;
    961     Ptr++;
    962     Len--;
    963   }
    964 
    965   *Ptr = 0;
    966   return String;
    967 }
    968 #endif
    969 STATIC
    970 BOOLEAN
    971 EndOfFile (
    972   SOURCE_FILE *SourceFile
    973   )
    974 {
    975   //
    976   // The file buffer pointer will typically get updated before the End-of-file flag in the
    977   // source file structure, so check it first.
    978   //
    979   if (SourceFile->FileBufferPtr >= SourceFile->FileBuffer + SourceFile->FileSize / sizeof (CHAR8 )) {
    980     SourceFile->EndOfFile = TRUE;
    981     return TRUE;
    982   }
    983 
    984   if (SourceFile->EndOfFile) {
    985     return TRUE;
    986   }
    987 
    988   return FALSE;
    989 }
    990 
    991 #if 0
    992 STATIC
    993 VOID
    994 ProcessTokenInclude (
    995   SOURCE_FILE *SourceFile
    996   )
    997 {
    998   CHAR8          IncludeFileName[MAX_PATH];
    999   CHAR8          *To;
   1000   UINTN  Len;
   1001   BOOLEAN       ReportedError;
   1002   SOURCE_FILE   IncludedSourceFile;
   1003 
   1004   ReportedError = FALSE;
   1005   if (SkipWhiteSpace (SourceFile) == 0) {
   1006     Warning (SourceFile->FileName, SourceFile->LineNum, 0, "expected whitespace following #include keyword", NULL);
   1007   }
   1008   //
   1009   // Should be quoted file name
   1010   //
   1011   if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) {
   1012     Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted include file name", NULL);
   1013     goto FailDone;
   1014   }
   1015 
   1016   SourceFile->FileBufferPtr++;
   1017   //
   1018   // Copy the filename as ascii to our local string
   1019   //
   1020   To  = IncludeFileName;
   1021   Len = 0;
   1022   while (!EndOfFile (SourceFile)) {
   1023     if ((SourceFile->FileBufferPtr[0] == T_CHAR_CR) || (SourceFile->FileBufferPtr[0] == T_CHAR_LF)) {
   1024       Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-line found in quoted include file name", NULL);
   1025       goto FailDone;
   1026     }
   1027 
   1028     if (SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) {
   1029       SourceFile->FileBufferPtr++;
   1030       break;
   1031     }
   1032     //
   1033     // If too long, then report the error once and process until the closing quote
   1034     //
   1035     Len++;
   1036     if (!ReportedError && (Len >= sizeof (IncludeFileName))) {
   1037       Error (SourceFile->FileName, SourceFile->LineNum, 0, "length of include file name exceeds limit", NULL);
   1038       ReportedError = TRUE;
   1039     }
   1040 
   1041     if (!ReportedError) {
   1042       *To = (CHAR8 ) SourceFile->FileBufferPtr[0];
   1043       To++;
   1044     }
   1045 
   1046     SourceFile->FileBufferPtr++;
   1047   }
   1048 
   1049   if (!ReportedError) {
   1050     *To = 0;
   1051     memset ((CHAR8 *) &IncludedSourceFile, 0, sizeof (SOURCE_FILE));
   1052     strcpy (IncludedSourceFile.FileName, IncludeFileName);
   1053     ProcessIncludeFile (&IncludedSourceFile, SourceFile);
   1054   }
   1055 
   1056   return ;
   1057 FailDone:
   1058   //
   1059   // Error recovery -- skip to next #
   1060   //
   1061   SourceFile->SkipToHash = TRUE;
   1062 }
   1063 #endif
   1064 STATIC
   1065 BOOLEAN
   1066 IsWhiteSpace (
   1067   SOURCE_FILE *SourceFile
   1068   )
   1069 {
   1070   switch (*SourceFile->FileBufferPtr) {
   1071   case T_CHAR_NULL:
   1072   case T_CHAR_CR:
   1073   case T_CHAR_SPACE:
   1074   case T_CHAR_TAB:
   1075   case T_CHAR_LF:
   1076     return TRUE;
   1077 
   1078   default:
   1079     return FALSE;
   1080   }
   1081 }
   1082 
   1083 UINTN
   1084 SkipWhiteSpace (
   1085   SOURCE_FILE *SourceFile
   1086   )
   1087 {
   1088   UINTN  Count;
   1089 
   1090   Count = 0;
   1091   while (!EndOfFile (SourceFile)) {
   1092     Count++;
   1093     switch (*SourceFile->FileBufferPtr) {
   1094     case T_CHAR_NULL:
   1095     case T_CHAR_CR:
   1096     case T_CHAR_SPACE:
   1097     case T_CHAR_TAB:
   1098       SourceFile->FileBufferPtr++;
   1099       break;
   1100 
   1101     case T_CHAR_LF:
   1102       SourceFile->FileBufferPtr++;
   1103       SourceFile->LineNum++;
   1104       break;
   1105 
   1106     default:
   1107       return Count - 1;
   1108     }
   1109   }
   1110   //
   1111   // Some tokens require trailing whitespace. If we're at the end of the
   1112   // file, then we count that as well.
   1113   //
   1114   if ((Count == 0) && (EndOfFile (SourceFile))) {
   1115     Count++;
   1116   }
   1117 
   1118   return Count;
   1119 }
   1120 
   1121 STATIC
   1122 UINTN
   1123 t_strcmp (
   1124   CHAR8  *Buffer,
   1125   CHAR8  *Str
   1126   )
   1127 /*++
   1128 
   1129 Routine Description:
   1130   Compare two strings for equality. The string pointed to by 'Buffer' may or may not be null-terminated,
   1131   so only compare up to the length of Str.
   1132 
   1133 Arguments:
   1134   Buffer  - pointer to first (possibly not null-terminated) string
   1135   Str     - pointer to null-terminated string to compare to Buffer
   1136 
   1137 Returns:
   1138   Number of bytes matched if exact match
   1139   0 if Buffer does not start with Str
   1140 
   1141 --*/
   1142 {
   1143   UINTN  Len;
   1144 
   1145   Len = 0;
   1146   while (*Str && (*Str == *Buffer)) {
   1147     Buffer++;
   1148     Str++;
   1149     Len++;
   1150   }
   1151 
   1152   if (*Str) {
   1153     return 0;
   1154   }
   1155 
   1156   return Len;
   1157 }
   1158 
   1159 STATIC
   1160 UINTN
   1161 t_strlen (
   1162   CHAR8  *Str
   1163   )
   1164 {
   1165   UINTN  Len;
   1166   Len = 0;
   1167   while (*Str) {
   1168     Len++;
   1169     Str++;
   1170   }
   1171 
   1172   return Len;
   1173 }
   1174 
   1175 STATIC
   1176 UINTN
   1177 t_strncmp (
   1178   CHAR8  *Str1,
   1179   CHAR8  *Str2,
   1180   INTN    Len
   1181   )
   1182 {
   1183   while (Len > 0) {
   1184     if (*Str1 != *Str2) {
   1185       return Len;
   1186     }
   1187 
   1188     Len--;
   1189     Str1++;
   1190     Str2++;
   1191   }
   1192 
   1193   return 0;
   1194 }
   1195 
   1196 STATIC
   1197 CHAR8  *
   1198 t_strcpy (
   1199   CHAR8  *Dest,
   1200   CHAR8  *Src
   1201   )
   1202 {
   1203   CHAR8   *SaveDest;
   1204   SaveDest = Dest;
   1205   while (*Src) {
   1206     *Dest = *Src;
   1207     Dest++;
   1208     Src++;
   1209   }
   1210 
   1211   *Dest = 0;
   1212   return SaveDest;
   1213 }
   1214 
   1215 STATIC
   1216 VOID
   1217 RewindFile (
   1218   SOURCE_FILE *SourceFile
   1219   )
   1220 {
   1221   SourceFile->LineNum       = 1;
   1222   SourceFile->FileBufferPtr = SourceFile->FileBuffer;
   1223   SourceFile->EndOfFile     = 0;
   1224 }
   1225 
   1226 STATIC
   1227 UINT32
   1228 GetHexChars (
   1229   CHAR8       *Buffer,
   1230   UINT32      BufferLen
   1231   )
   1232 {
   1233   UINT32  Len;
   1234   Len = 0;
   1235   while (!EndOfFile (&mGlobals.SourceFile) && (BufferLen > 0)) {
   1236     if (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) {
   1237       *Buffer = mGlobals.SourceFile.FileBufferPtr[0];
   1238       Buffer++;
   1239       Len++;
   1240       BufferLen--;
   1241       mGlobals.SourceFile.FileBufferPtr++;
   1242     } else {
   1243       break;
   1244     }
   1245   }
   1246   //
   1247   // Null terminate if we can
   1248   //
   1249   if ((Len > 0) && (BufferLen > 0)) {
   1250     *Buffer = 0;
   1251   }
   1252 
   1253   return Len;
   1254 }
   1255 
   1256 BOOLEAN
   1257 SFPGetGuid (
   1258   INTN         GuidStyle,
   1259   EFI_GUID    *Value
   1260   )
   1261 /*++
   1262 
   1263 Routine Description:
   1264   Parse a GUID from the input stream. Stop when you discover white space.
   1265 
   1266 Arguments:
   1267   GuidStyle - Style of the following GUID token
   1268   Value     - pointer to EFI_GUID struct for output
   1269 
   1270 Returns:
   1271   TRUE  - GUID string parsed successfully
   1272   FALSE - otherwise
   1273 
   1274   GUID styles
   1275     Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD
   1276 
   1277 --*/
   1278 {
   1279   unsigned      Value32;
   1280   UINT32        Index;
   1281   FILE_POSITION FPos;
   1282   CHAR8         TempString[20];
   1283   CHAR8         TempString2[3];
   1284   CHAR8         *From;
   1285   CHAR8         *To;
   1286   UINT32        Len;
   1287   BOOLEAN       Status;
   1288 
   1289   Status = FALSE;
   1290   //
   1291   // Skip white space, then start parsing
   1292   //
   1293   SkipWhiteSpace (&mGlobals.SourceFile);
   1294   GetFilePosition (&FPos);
   1295   if (EndOfFile (&mGlobals.SourceFile)) {
   1296     return FALSE;
   1297   }
   1298 
   1299   if (GuidStyle == PARSE_GUID_STYLE_5_FIELDS) {
   1300     //
   1301     // Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD
   1302     //
   1303     Len = GetHexChars (TempString, sizeof (TempString));
   1304     if ((Len == 0) || (Len > 8)) {
   1305       goto Done;
   1306     }
   1307 
   1308     sscanf (TempString, "%x", &Value32);
   1309     Value->Data1 = Value32;
   1310     //
   1311     // Next two UINT16 fields
   1312     //
   1313     if (mGlobals.SourceFile.FileBufferPtr[0] != '-') {
   1314       goto Done;
   1315     }
   1316 
   1317     mGlobals.SourceFile.FileBufferPtr++;
   1318     Len = GetHexChars (TempString, sizeof (TempString));
   1319     if ((Len == 0) || (Len > 4)) {
   1320       goto Done;
   1321     }
   1322 
   1323     sscanf (TempString, "%x", &Value32);
   1324     Value->Data2 = (UINT16) Value32;
   1325 
   1326     if (mGlobals.SourceFile.FileBufferPtr[0] != '-') {
   1327       goto Done;
   1328     }
   1329 
   1330     mGlobals.SourceFile.FileBufferPtr++;
   1331     Len = GetHexChars (TempString, sizeof (TempString));
   1332     if ((Len == 0) || (Len > 4)) {
   1333       goto Done;
   1334     }
   1335 
   1336     sscanf (TempString, "%x", &Value32);
   1337     Value->Data3 = (UINT16) Value32;
   1338     //
   1339     // Parse the "AAAA" as two bytes
   1340     //
   1341     if (mGlobals.SourceFile.FileBufferPtr[0] != '-') {
   1342       goto Done;
   1343     }
   1344 
   1345     mGlobals.SourceFile.FileBufferPtr++;
   1346     Len = GetHexChars (TempString, sizeof (TempString));
   1347     if ((Len == 0) || (Len > 4)) {
   1348       goto Done;
   1349     }
   1350 
   1351     sscanf (TempString, "%x", &Value32);
   1352     Value->Data4[0] = (UINT8) (Value32 >> 8);
   1353     Value->Data4[1] = (UINT8) Value32;
   1354     if (mGlobals.SourceFile.FileBufferPtr[0] != '-') {
   1355       goto Done;
   1356     }
   1357 
   1358     mGlobals.SourceFile.FileBufferPtr++;
   1359     //
   1360     // Read the last 6 bytes of the GUID
   1361     //
   1362     //
   1363     Len = GetHexChars (TempString, sizeof (TempString));
   1364     if ((Len == 0) || (Len > 12)) {
   1365       goto Done;
   1366     }
   1367     //
   1368     // Insert leading 0's to make life easier
   1369     //
   1370     if (Len != 12) {
   1371       From            = TempString + Len - 1;
   1372       To              = TempString + 11;
   1373       TempString[12]  = 0;
   1374       while (From >= TempString) {
   1375         *To = *From;
   1376         To--;
   1377         From--;
   1378       }
   1379 
   1380       while (To >= TempString) {
   1381         *To = '0';
   1382         To--;
   1383       }
   1384     }
   1385     //
   1386     // Now parse each byte
   1387     //
   1388     TempString2[2] = 0;
   1389     for (Index = 0; Index < 6; Index++) {
   1390       //
   1391       // Copy the two characters from the input string to something
   1392       // we can parse.
   1393       //
   1394       TempString2[0]  = TempString[Index * 2];
   1395       TempString2[1]  = TempString[Index * 2 + 1];
   1396       sscanf (TempString2, "%x", &Value32);
   1397       Value->Data4[Index + 2] = (UINT8) Value32;
   1398     }
   1399 
   1400     Status = TRUE;
   1401   } else {
   1402     //
   1403     // Unsupported GUID style
   1404     //
   1405     return FALSE;
   1406   }
   1407 
   1408 Done:
   1409   if (Status == FALSE) {
   1410     SetFilePosition (&FPos);
   1411   }
   1412 
   1413   return Status;
   1414 }
   1415 
   1416 STATIC
   1417 STATUS
   1418 GetFilePosition (
   1419   FILE_POSITION *Fpos
   1420   )
   1421 {
   1422   Fpos->FileBufferPtr = mGlobals.SourceFile.FileBufferPtr;
   1423   return STATUS_SUCCESS;
   1424 }
   1425 
   1426 STATIC
   1427 STATUS
   1428 SetFilePosition (
   1429   FILE_POSITION *Fpos
   1430   )
   1431 {
   1432   //
   1433   // Should check range of pointer
   1434   //
   1435   mGlobals.SourceFile.FileBufferPtr = Fpos->FileBufferPtr;
   1436   return STATUS_SUCCESS;
   1437 }
   1438