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