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