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