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