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