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
SFPInit(VOID)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
SFPGetLineNumber(VOID)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  *
SFPGetFileName(VOID)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
SFPOpenFile(CHAR8 * FileName)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
SFPIsToken(CHAR8 * Str)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
SFPIsKeyword(CHAR8 * Str)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
SFPGetNextToken(CHAR8 * Str,UINTN Len)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
SFPGetGuidToken(CHAR8 * Str,UINT32 Len)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
SFPSkipToToken(CHAR8 * Str)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
SFPGetNumber(UINTN * Value)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
SFPCloseFile(VOID)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
ProcessIncludeFile(SOURCE_FILE * SourceFile,SOURCE_FILE * ParentSourceFile)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
ProcessFile(SOURCE_FILE * SourceFile)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
PreprocessFile(SOURCE_FILE * SourceFile)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
SFPGetQuotedString(CHAR8 * Str,INTN Length)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
SFPIsEOF(VOID)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
EndOfFile(SOURCE_FILE * SourceFile)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
IsWhiteSpace(SOURCE_FILE * SourceFile)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
SkipWhiteSpace(SOURCE_FILE * SourceFile)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
t_strcmp(CHAR8 * Buffer,CHAR8 * Str)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
t_strlen(CHAR8 * Str)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
t_strncmp(CHAR8 * Str1,CHAR8 * Str2,INTN Len)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  *
t_strcpy(CHAR8 * Dest,CHAR8 * Src)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
RewindFile(SOURCE_FILE * SourceFile)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
GetHexChars(CHAR8 * Buffer,UINT32 BufferLen)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
SFPGetGuid(INTN GuidStyle,EFI_GUID * Value)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
GetFilePosition(FILE_POSITION * Fpos)1418 GetFilePosition (
1419   FILE_POSITION *Fpos
1420   )
1421 {
1422   Fpos->FileBufferPtr = mGlobals.SourceFile.FileBufferPtr;
1423   return STATUS_SUCCESS;
1424 }
1425 
1426 STATIC
1427 STATUS
SetFilePosition(FILE_POSITION * Fpos)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