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