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