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