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