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