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