| /** @file | |
| Copyright (c) 2004 - 2008, Intel Corporation | |
| All rights reserved. This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| SimpleFileParsing.c | |
| Abstract: | |
| Generic but simple file parsing routines. | |
| --*/ | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include <ctype.h> | |
| #include "EfiUtilityMsgs.h" | |
| #include "SimpleFileParsing.h" | |
| #ifndef MAX_PATH | |
| #define MAX_PATH 255 | |
| #endif | |
| // | |
| // just in case we get in an endless loop. | |
| // | |
| #define MAX_NEST_DEPTH 20 | |
| // | |
| // number of wchars | |
| // | |
| #define MAX_STRING_IDENTIFIER_NAME 100 | |
| #define T_CHAR_SPACE ' ' | |
| #define T_CHAR_NULL 0 | |
| #define T_CHAR_CR '\r' | |
| #define T_CHAR_TAB '\t' | |
| #define T_CHAR_LF '\n' | |
| #define T_CHAR_SLASH '/' | |
| #define T_CHAR_BACKSLASH '\\' | |
| #define T_CHAR_DOUBLE_QUOTE '"' | |
| #define T_CHAR_LC_X 'x' | |
| #define T_CHAR_0 '0' | |
| #define T_CHAR_STAR '*' | |
| // | |
| // We keep a linked list of these for the source files we process | |
| // | |
| typedef struct _SOURCE_FILE { | |
| FILE *Fptr; | |
| CHAR8 *FileBuffer; | |
| CHAR8 *FileBufferPtr; | |
| UINTN FileSize; | |
| CHAR8 FileName[MAX_PATH]; | |
| UINTN LineNum; | |
| BOOLEAN EndOfFile; | |
| BOOLEAN SkipToHash; | |
| struct _SOURCE_FILE *Previous; | |
| struct _SOURCE_FILE *Next; | |
| CHAR8 ControlCharacter; | |
| } SOURCE_FILE; | |
| typedef struct { | |
| CHAR8 *FileBufferPtr; | |
| } FILE_POSITION; | |
| // | |
| // Keep all our module globals in this structure | |
| // | |
| STATIC struct { | |
| SOURCE_FILE SourceFile; | |
| BOOLEAN VerboseFile; | |
| BOOLEAN VerboseToken; | |
| } mGlobals; | |
| STATIC | |
| UINTN | |
| t_strcmp ( | |
| CHAR8 *Buffer, | |
| CHAR8 *Str | |
| ); | |
| STATIC | |
| UINTN | |
| t_strncmp ( | |
| CHAR8 *Str1, | |
| CHAR8 *Str2, | |
| INTN Len | |
| ); | |
| STATIC | |
| UINTN | |
| t_strlen ( | |
| CHAR8 *Str | |
| ); | |
| STATIC | |
| VOID | |
| RewindFile ( | |
| SOURCE_FILE *SourceFile | |
| ); | |
| STATIC | |
| BOOLEAN | |
| IsWhiteSpace ( | |
| SOURCE_FILE *SourceFile | |
| ); | |
| STATIC | |
| UINTN | |
| SkipWhiteSpace ( | |
| SOURCE_FILE *SourceFile | |
| ); | |
| STATIC | |
| BOOLEAN | |
| EndOfFile ( | |
| SOURCE_FILE *SourceFile | |
| ); | |
| STATIC | |
| VOID | |
| PreprocessFile ( | |
| SOURCE_FILE *SourceFile | |
| ); | |
| STATIC | |
| CHAR8 * | |
| t_strcpy ( | |
| CHAR8 *Dest, | |
| CHAR8 *Src | |
| ); | |
| STATIC | |
| STATUS | |
| ProcessIncludeFile ( | |
| SOURCE_FILE *SourceFile, | |
| SOURCE_FILE *ParentSourceFile | |
| ); | |
| STATIC | |
| STATUS | |
| ProcessFile ( | |
| SOURCE_FILE *SourceFile | |
| ); | |
| STATIC | |
| STATUS | |
| GetFilePosition ( | |
| FILE_POSITION *Fpos | |
| ); | |
| STATIC | |
| STATUS | |
| SetFilePosition ( | |
| FILE_POSITION *Fpos | |
| ); | |
| STATUS | |
| SFPInit ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| None. | |
| Returns: | |
| STATUS_SUCCESS always | |
| --*/ | |
| { | |
| memset ((VOID *) &mGlobals, 0, sizeof (mGlobals)); | |
| return STATUS_SUCCESS; | |
| } | |
| UINTN | |
| SFPGetLineNumber ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Return the line number of the file we're parsing. Used | |
| for error reporting purposes. | |
| Arguments: | |
| None. | |
| Returns: | |
| The line number, or 0 if no file is being processed | |
| --*/ | |
| { | |
| return mGlobals.SourceFile.LineNum; | |
| } | |
| CHAR8 * | |
| SFPGetFileName ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Return the name of the file we're parsing. Used | |
| for error reporting purposes. | |
| Arguments: | |
| None. | |
| Returns: | |
| A pointer to the file name. Null if no file is being | |
| processed. | |
| --*/ | |
| { | |
| if (mGlobals.SourceFile.FileName[0]) { | |
| return mGlobals.SourceFile.FileName; | |
| } | |
| return NULL; | |
| } | |
| STATUS | |
| SFPOpenFile ( | |
| CHAR8 *FileName | |
| ) | |
| /*++ | |
| Routine Description: | |
| Open a file for parsing. | |
| Arguments: | |
| FileName - name of the file to parse | |
| Returns: | |
| --*/ | |
| { | |
| STATUS Status; | |
| t_strcpy (mGlobals.SourceFile.FileName, FileName); | |
| Status = ProcessIncludeFile (&mGlobals.SourceFile, NULL); | |
| return Status; | |
| } | |
| BOOLEAN | |
| SFPIsToken ( | |
| CHAR8 *Str | |
| ) | |
| /*++ | |
| Routine Description: | |
| Check to see if the specified token is found at | |
| the current position in the input file. | |
| Arguments: | |
| Str - the token to look for | |
| Returns: | |
| TRUE - the token is next | |
| FALSE - the token is not next | |
| Notes: | |
| We do a simple string comparison on this function. It is | |
| the responsibility of the caller to ensure that the token | |
| is not a subset of some other token. | |
| The file pointer is advanced past the token in the input file. | |
| --*/ | |
| { | |
| UINTN Len; | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| if (EndOfFile (&mGlobals.SourceFile)) { | |
| return FALSE; | |
| } | |
| if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) { | |
| mGlobals.SourceFile.FileBufferPtr += Len; | |
| if (mGlobals.VerboseToken) { | |
| printf ("Token: '%s'\n", Str); | |
| } | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| BOOLEAN | |
| SFPIsKeyword ( | |
| CHAR8 *Str | |
| ) | |
| /*++ | |
| Routine Description: | |
| Check to see if the specified keyword is found at | |
| the current position in the input file. | |
| Arguments: | |
| Str - keyword to look for | |
| Returns: | |
| TRUE - the keyword is next | |
| FALSE - the keyword is not next | |
| Notes: | |
| A keyword is defined as a "special" string that has a non-alphanumeric | |
| character following it. | |
| --*/ | |
| { | |
| UINTN Len; | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| if (EndOfFile (&mGlobals.SourceFile)) { | |
| return FALSE; | |
| } | |
| if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) { | |
| if (isalnum (mGlobals.SourceFile.FileBufferPtr[Len])) { | |
| return FALSE; | |
| } | |
| mGlobals.SourceFile.FileBufferPtr += Len; | |
| if (mGlobals.VerboseToken) { | |
| printf ("Token: '%s'\n", Str); | |
| } | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| BOOLEAN | |
| SFPGetNextToken ( | |
| CHAR8 *Str, | |
| UINTN Len | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get the next token from the input stream. | |
| Arguments: | |
| Str - pointer to a copy of the next token | |
| Len - size of buffer pointed to by Str | |
| Returns: | |
| TRUE - next token successfully returned | |
| FALSE - otherwise | |
| Notes: | |
| Preceeding white space is ignored. | |
| The parser's buffer pointer is advanced past the end of the | |
| token. | |
| --*/ | |
| { | |
| UINTN Index; | |
| CHAR8 TempChar; | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| if (EndOfFile (&mGlobals.SourceFile)) { | |
| return FALSE; | |
| } | |
| // | |
| // Have to have enough string for at least one char and a null-terminator | |
| // | |
| if (Len < 2) { | |
| return FALSE; | |
| } | |
| // | |
| // Look at the first character. If it's an identifier, then treat it | |
| // as such | |
| // | |
| TempChar = mGlobals.SourceFile.FileBufferPtr[0]; | |
| if (((TempChar >= 'a') && (TempChar <= 'z')) || ((TempChar >= 'A') && (TempChar <= 'Z')) || (TempChar == '_')) { | |
| Str[0] = TempChar; | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| Index = 1; | |
| while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { | |
| TempChar = mGlobals.SourceFile.FileBufferPtr[0]; | |
| if (((TempChar >= 'a') && (TempChar <= 'z')) || | |
| ((TempChar >= 'A') && (TempChar <= 'Z')) || | |
| ((TempChar >= '0') && (TempChar <= '9')) || | |
| (TempChar == '_') | |
| ) { | |
| Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| Index++; | |
| } else { | |
| // | |
| // Invalid character for symbol name, so break out | |
| // | |
| break; | |
| } | |
| } | |
| // | |
| // Null terminate and return success | |
| // | |
| Str[Index] = 0; | |
| return TRUE; | |
| } else if ((TempChar == ')') || (TempChar == '(') || (TempChar == '*')) { | |
| Str[0] = mGlobals.SourceFile.FileBufferPtr[0]; | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| Str[1] = 0; | |
| return TRUE; | |
| } else { | |
| // | |
| // Everything else is white-space (or EOF) separated | |
| // | |
| Index = 0; | |
| while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { | |
| if (IsWhiteSpace (&mGlobals.SourceFile)) { | |
| if (Index > 0) { | |
| Str[Index] = 0; | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } else { | |
| Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| Index++; | |
| } | |
| } | |
| // | |
| // See if we just ran out of file contents, but did find a token | |
| // | |
| if ((Index > 0) && EndOfFile (&mGlobals.SourceFile)) { | |
| Str[Index] = 0; | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| BOOLEAN | |
| SFPGetGuidToken ( | |
| CHAR8 *Str, | |
| UINT32 Len | |
| ) | |
| /*++ | |
| Routine Description: | |
| Parse a GUID from the input stream. Stop when you discover white space. | |
| Arguments: | |
| Str - pointer to a copy of the next token | |
| Len - size of buffer pointed to by Str | |
| Returns: | |
| TRUE - GUID string returned successfully | |
| FALSE - otherwise | |
| --*/ | |
| { | |
| UINT32 Index; | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| if (EndOfFile (&mGlobals.SourceFile)) { | |
| return FALSE; | |
| } | |
| Index = 0; | |
| while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { | |
| if (IsWhiteSpace (&mGlobals.SourceFile)) { | |
| if (Index > 0) { | |
| Str[Index] = 0; | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } else { | |
| Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| Index++; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| BOOLEAN | |
| SFPSkipToToken ( | |
| CHAR8 *Str | |
| ) | |
| { | |
| UINTN Len; | |
| CHAR8 *SavePos; | |
| Len = t_strlen (Str); | |
| SavePos = mGlobals.SourceFile.FileBufferPtr; | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| while (!EndOfFile (&mGlobals.SourceFile)) { | |
| if (t_strncmp (Str, mGlobals.SourceFile.FileBufferPtr, Len) == 0) { | |
| mGlobals.SourceFile.FileBufferPtr += Len; | |
| return TRUE; | |
| } | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| } | |
| mGlobals.SourceFile.FileBufferPtr = SavePos; | |
| return FALSE; | |
| } | |
| BOOLEAN | |
| SFPGetNumber ( | |
| UINTN *Value | |
| ) | |
| /*++ | |
| Routine Description: | |
| Check the token at the current file position for a numeric value. | |
| May be either decimal or hex. | |
| Arguments: | |
| Value - pointer where to store the value | |
| Returns: | |
| FALSE - current token is not a number | |
| TRUE - current token is a number | |
| --*/ | |
| { | |
| UINT32 Val; | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| if (EndOfFile (&mGlobals.SourceFile)) { | |
| return FALSE; | |
| } | |
| if (isdigit (mGlobals.SourceFile.FileBufferPtr[0])) { | |
| // | |
| // Check for hex value | |
| // | |
| if ((mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_0) && (mGlobals.SourceFile.FileBufferPtr[1] == T_CHAR_LC_X)) { | |
| if (!isxdigit (mGlobals.SourceFile.FileBufferPtr[2])) { | |
| return FALSE; | |
| } | |
| mGlobals.SourceFile.FileBufferPtr += 2; | |
| sscanf (mGlobals.SourceFile.FileBufferPtr, "%x", &Val); | |
| *Value = Val; | |
| while (isxdigit (mGlobals.SourceFile.FileBufferPtr[0])) { | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| } | |
| return TRUE; | |
| } else { | |
| *Value = atoi (mGlobals.SourceFile.FileBufferPtr); | |
| while (isdigit (mGlobals.SourceFile.FileBufferPtr[0])) { | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| } | |
| return TRUE; | |
| } | |
| } else { | |
| return FALSE; | |
| } | |
| } | |
| STATUS | |
| SFPCloseFile ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Close the file being parsed. | |
| Arguments: | |
| None. | |
| Returns: | |
| STATUS_SUCCESS - the file was closed | |
| STATUS_ERROR - no file is currently open | |
| --*/ | |
| { | |
| if (mGlobals.SourceFile.FileBuffer != NULL) { | |
| free (mGlobals.SourceFile.FileBuffer); | |
| memset (&mGlobals.SourceFile, 0, sizeof (mGlobals.SourceFile)); | |
| return STATUS_SUCCESS; | |
| } | |
| return STATUS_ERROR; | |
| } | |
| STATIC | |
| STATUS | |
| ProcessIncludeFile ( | |
| SOURCE_FILE *SourceFile, | |
| SOURCE_FILE *ParentSourceFile | |
| ) | |
| /*++ | |
| Routine Description: | |
| Given a source file, open the file and parse it | |
| Arguments: | |
| SourceFile - name of file to parse | |
| ParentSourceFile - for error reporting purposes, the file that #included SourceFile. | |
| Returns: | |
| Standard status. | |
| --*/ | |
| { | |
| STATIC UINTN NestDepth = 0; | |
| CHAR8 FoundFileName[MAX_PATH]; | |
| STATUS Status; | |
| Status = STATUS_SUCCESS; | |
| NestDepth++; | |
| // | |
| // Print the file being processed. Indent so you can tell the include nesting | |
| // depth. | |
| // | |
| if (mGlobals.VerboseFile) { | |
| fprintf (stdout, "%*cProcessing file '%s'\n", (INT32)NestDepth * 2, ' ', SourceFile->FileName); | |
| fprintf (stdout, "Parent source file = '%s'\n", ParentSourceFile->FileName); | |
| } | |
| // | |
| // Make sure we didn't exceed our maximum nesting depth | |
| // | |
| if (NestDepth > MAX_NEST_DEPTH) { | |
| Error (NULL, 0, 3001, "Not Supported", "%s exceeeds max nesting depth (%d)", SourceFile->FileName, NestDepth); | |
| Status = STATUS_ERROR; | |
| goto Finish; | |
| } | |
| // | |
| // Try to open the file locally, and if that fails try along our include paths. | |
| // | |
| strcpy (FoundFileName, SourceFile->FileName); | |
| if ((SourceFile->Fptr = fopen (FoundFileName, "rb")) == NULL) { | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Process the file found | |
| // | |
| ProcessFile (SourceFile); | |
| Finish: | |
| // | |
| // Close open files and return status | |
| // | |
| if (SourceFile->Fptr != NULL) { | |
| fclose (SourceFile->Fptr); | |
| SourceFile->Fptr = NULL; | |
| } | |
| return Status; | |
| } | |
| STATIC | |
| STATUS | |
| ProcessFile ( | |
| SOURCE_FILE *SourceFile | |
| ) | |
| /*++ | |
| Routine Description: | |
| Given a source file that's been opened, read the contents into an internal | |
| buffer and pre-process it to remove comments. | |
| Arguments: | |
| SourceFile - structure containing info on the file to process | |
| Returns: | |
| Standard status. | |
| --*/ | |
| { | |
| // | |
| // Get the file size, and then read the entire thing into memory. | |
| // Allocate extra space for a terminator character. | |
| // | |
| fseek (SourceFile->Fptr, 0, SEEK_END); | |
| SourceFile->FileSize = ftell (SourceFile->Fptr); | |
| if (mGlobals.VerboseFile) { | |
| printf ("FileSize = %d (0x%X)\n", (INT32)SourceFile->FileSize, (UINT32)SourceFile->FileSize); | |
| } | |
| fseek (SourceFile->Fptr, 0, SEEK_SET); | |
| SourceFile->FileBuffer = (CHAR8 *) malloc (SourceFile->FileSize + sizeof (CHAR8 )); | |
| if (SourceFile->FileBuffer == NULL) { | |
| Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL); | |
| return STATUS_ERROR; | |
| } | |
| fread ((VOID *) SourceFile->FileBuffer, SourceFile->FileSize, 1, SourceFile->Fptr); | |
| SourceFile->FileBuffer[(SourceFile->FileSize / sizeof (CHAR8 ))] = T_CHAR_NULL; | |
| // | |
| // Pre-process the file to replace comments with spaces | |
| // | |
| PreprocessFile (SourceFile); | |
| SourceFile->LineNum = 1; | |
| return STATUS_SUCCESS; | |
| } | |
| STATIC | |
| VOID | |
| PreprocessFile ( | |
| SOURCE_FILE *SourceFile | |
| ) | |
| /*++ | |
| Routine Description: | |
| Preprocess a file to replace all carriage returns with NULLs so | |
| we can print lines (as part of error messages) from the file to the screen. | |
| Arguments: | |
| SourceFile - structure that we use to keep track of an input file. | |
| Returns: | |
| Nothing. | |
| --*/ | |
| { | |
| BOOLEAN InComment; | |
| BOOLEAN SlashSlashComment; | |
| int LineNum; | |
| RewindFile (SourceFile); | |
| InComment = FALSE; | |
| SlashSlashComment = FALSE; | |
| while (!EndOfFile (SourceFile)) { | |
| // | |
| // If a line-feed, then no longer in a comment if we're in a // comment | |
| // | |
| if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) { | |
| SourceFile->FileBufferPtr++; | |
| SourceFile->LineNum++; | |
| if (InComment && SlashSlashComment) { | |
| InComment = FALSE; | |
| SlashSlashComment = FALSE; | |
| } | |
| } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) { | |
| // | |
| // Replace all carriage returns with a NULL so we can print stuff | |
| // | |
| SourceFile->FileBufferPtr[0] = 0; | |
| SourceFile->FileBufferPtr++; | |
| // | |
| // Check for */ comment end | |
| // | |
| } else if (InComment && | |
| !SlashSlashComment && | |
| (SourceFile->FileBufferPtr[0] == T_CHAR_STAR) && | |
| (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH) | |
| ) { | |
| SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; | |
| SourceFile->FileBufferPtr++; | |
| SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; | |
| SourceFile->FileBufferPtr++; | |
| InComment = FALSE; | |
| } else if (InComment) { | |
| SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; | |
| SourceFile->FileBufferPtr++; | |
| // | |
| // Check for // comments | |
| // | |
| } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH)) { | |
| InComment = TRUE; | |
| SlashSlashComment = TRUE; | |
| // | |
| // Check for /* comment start | |
| // | |
| } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_STAR)) { | |
| SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; | |
| SourceFile->FileBufferPtr++; | |
| SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; | |
| SourceFile->FileBufferPtr++; | |
| SlashSlashComment = FALSE; | |
| InComment = TRUE; | |
| } else { | |
| SourceFile->FileBufferPtr++; | |
| } | |
| } | |
| // | |
| // Could check for end-of-file and still in a comment, but | |
| // should not be necessary. So just restore the file pointers. | |
| // | |
| RewindFile (SourceFile); | |
| // | |
| // Dump the reformatted file if verbose mode | |
| // | |
| if (mGlobals.VerboseFile) { | |
| LineNum = 1; | |
| printf ("%04d: ", LineNum); | |
| while (!EndOfFile (SourceFile)) { | |
| if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) { | |
| printf ("'\n%04d: '", ++LineNum); | |
| } else { | |
| printf ("%c", SourceFile->FileBufferPtr[0]); | |
| } | |
| SourceFile->FileBufferPtr++; | |
| } | |
| printf ("'\n"); | |
| printf ("FileSize = %d (0x%X)\n", (INT32)SourceFile->FileSize, (UINT32)SourceFile->FileSize); | |
| RewindFile (SourceFile); | |
| } | |
| } | |
| BOOLEAN | |
| SFPGetQuotedString ( | |
| CHAR8 *Str, | |
| INTN Length | |
| ) | |
| /*++ | |
| Routine Description: | |
| Retrieve a quoted-string from the input file. | |
| Arguments: | |
| Str - pointer to a copy of the quoted string parsed | |
| Length - size of buffer pointed to by Str | |
| Returns: | |
| TRUE - next token in input stream was a quoted string, and | |
| the string value was returned in Str | |
| FALSE - otherwise | |
| --*/ | |
| { | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| if (EndOfFile (&mGlobals.SourceFile)) { | |
| return FALSE; | |
| } | |
| if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| while (Length > 0) { | |
| if (EndOfFile (&mGlobals.SourceFile)) { | |
| return FALSE; | |
| } | |
| // | |
| // Check for closing quote | |
| // | |
| if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| *Str = 0; | |
| return TRUE; | |
| } | |
| *Str = mGlobals.SourceFile.FileBufferPtr[0]; | |
| Str++; | |
| Length--; | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| } | |
| } | |
| // | |
| // First character was not a quote, or the input string length was | |
| // insufficient to contain the quoted string, so return failure code. | |
| // | |
| return FALSE; | |
| } | |
| BOOLEAN | |
| SFPIsEOF ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Return TRUE of FALSE to indicate whether or not we've reached the end of the | |
| file we're parsing. | |
| Arguments: | |
| NA | |
| Returns: | |
| TRUE - EOF reached | |
| FALSE - otherwise | |
| --*/ | |
| { | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| return EndOfFile (&mGlobals.SourceFile); | |
| } | |
| #if 0 | |
| STATIC | |
| CHAR8 * | |
| GetQuotedString ( | |
| SOURCE_FILE *SourceFile, | |
| BOOLEAN Optional | |
| ) | |
| { | |
| CHAR8 *String; | |
| CHAR8 *Start; | |
| CHAR8 *Ptr; | |
| UINTN Len; | |
| BOOLEAN PreviousBackslash; | |
| if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { | |
| if (Optional == FALSE) { | |
| Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted string", "%S", SourceFile->FileBufferPtr); | |
| } | |
| return NULL; | |
| } | |
| Len = 0; | |
| SourceFile->FileBufferPtr++; | |
| Start = Ptr = SourceFile->FileBufferPtr; | |
| PreviousBackslash = FALSE; | |
| while (!EndOfFile (SourceFile)) { | |
| if ((SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) && (PreviousBackslash == FALSE)) { | |
| break; | |
| } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) { | |
| Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start); | |
| PreviousBackslash = FALSE; | |
| } else if (SourceFile->FileBufferPtr[0] == T_CHAR_BACKSLASH) { | |
| PreviousBackslash = TRUE; | |
| } else { | |
| PreviousBackslash = FALSE; | |
| } | |
| SourceFile->FileBufferPtr++; | |
| Len++; | |
| } | |
| if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { | |
| Warning (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", "%S", Start); | |
| } else { | |
| SourceFile->FileBufferPtr++; | |
| } | |
| // | |
| // Now allocate memory for the string and save it off | |
| // | |
| String = (CHAR8 *) malloc ((Len + 1) * sizeof (CHAR8 )); | |
| if (String == NULL) { | |
| Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL); | |
| return NULL; | |
| } | |
| // | |
| // Copy the string from the file buffer to the local copy. | |
| // We do no reformatting of it whatsoever at this point. | |
| // | |
| Ptr = String; | |
| while (Len > 0) { | |
| *Ptr = *Start; | |
| Start++; | |
| Ptr++; | |
| Len--; | |
| } | |
| *Ptr = 0; | |
| return String; | |
| } | |
| #endif | |
| STATIC | |
| BOOLEAN | |
| EndOfFile ( | |
| SOURCE_FILE *SourceFile | |
| ) | |
| { | |
| // | |
| // The file buffer pointer will typically get updated before the End-of-file flag in the | |
| // source file structure, so check it first. | |
| // | |
| if (SourceFile->FileBufferPtr >= SourceFile->FileBuffer + SourceFile->FileSize / sizeof (CHAR8 )) { | |
| SourceFile->EndOfFile = TRUE; | |
| return TRUE; | |
| } | |
| if (SourceFile->EndOfFile) { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| #if 0 | |
| STATIC | |
| VOID | |
| ProcessTokenInclude ( | |
| SOURCE_FILE *SourceFile | |
| ) | |
| { | |
| CHAR8 IncludeFileName[MAX_PATH]; | |
| CHAR8 *To; | |
| UINTN Len; | |
| BOOLEAN ReportedError; | |
| SOURCE_FILE IncludedSourceFile; | |
| ReportedError = FALSE; | |
| if (SkipWhiteSpace (SourceFile) == 0) { | |
| Warning (SourceFile->FileName, SourceFile->LineNum, 0, "expected whitespace following #include keyword", NULL); | |
| } | |
| // | |
| // Should be quoted file name | |
| // | |
| if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { | |
| Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted include file name", NULL); | |
| goto FailDone; | |
| } | |
| SourceFile->FileBufferPtr++; | |
| // | |
| // Copy the filename as ascii to our local string | |
| // | |
| To = IncludeFileName; | |
| Len = 0; | |
| while (!EndOfFile (SourceFile)) { | |
| if ((SourceFile->FileBufferPtr[0] == T_CHAR_CR) || (SourceFile->FileBufferPtr[0] == T_CHAR_LF)) { | |
| Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-line found in quoted include file name", NULL); | |
| goto FailDone; | |
| } | |
| if (SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { | |
| SourceFile->FileBufferPtr++; | |
| break; | |
| } | |
| // | |
| // If too long, then report the error once and process until the closing quote | |
| // | |
| Len++; | |
| if (!ReportedError && (Len >= sizeof (IncludeFileName))) { | |
| Error (SourceFile->FileName, SourceFile->LineNum, 0, "length of include file name exceeds limit", NULL); | |
| ReportedError = TRUE; | |
| } | |
| if (!ReportedError) { | |
| *To = (CHAR8 ) SourceFile->FileBufferPtr[0]; | |
| To++; | |
| } | |
| SourceFile->FileBufferPtr++; | |
| } | |
| if (!ReportedError) { | |
| *To = 0; | |
| memset ((CHAR8 *) &IncludedSourceFile, 0, sizeof (SOURCE_FILE)); | |
| strcpy (IncludedSourceFile.FileName, IncludeFileName); | |
| ProcessIncludeFile (&IncludedSourceFile, SourceFile); | |
| } | |
| return ; | |
| FailDone: | |
| // | |
| // Error recovery -- skip to next # | |
| // | |
| SourceFile->SkipToHash = TRUE; | |
| } | |
| #endif | |
| STATIC | |
| BOOLEAN | |
| IsWhiteSpace ( | |
| SOURCE_FILE *SourceFile | |
| ) | |
| { | |
| switch (*SourceFile->FileBufferPtr) { | |
| case T_CHAR_NULL: | |
| case T_CHAR_CR: | |
| case T_CHAR_SPACE: | |
| case T_CHAR_TAB: | |
| case T_CHAR_LF: | |
| return TRUE; | |
| default: | |
| return FALSE; | |
| } | |
| } | |
| UINTN | |
| SkipWhiteSpace ( | |
| SOURCE_FILE *SourceFile | |
| ) | |
| { | |
| UINTN Count; | |
| Count = 0; | |
| while (!EndOfFile (SourceFile)) { | |
| Count++; | |
| switch (*SourceFile->FileBufferPtr) { | |
| case T_CHAR_NULL: | |
| case T_CHAR_CR: | |
| case T_CHAR_SPACE: | |
| case T_CHAR_TAB: | |
| SourceFile->FileBufferPtr++; | |
| break; | |
| case T_CHAR_LF: | |
| SourceFile->FileBufferPtr++; | |
| SourceFile->LineNum++; | |
| break; | |
| default: | |
| return Count - 1; | |
| } | |
| } | |
| // | |
| // Some tokens require trailing whitespace. If we're at the end of the | |
| // file, then we count that as well. | |
| // | |
| if ((Count == 0) && (EndOfFile (SourceFile))) { | |
| Count++; | |
| } | |
| return Count; | |
| } | |
| STATIC | |
| UINTN | |
| t_strcmp ( | |
| CHAR8 *Buffer, | |
| CHAR8 *Str | |
| ) | |
| /*++ | |
| Routine Description: | |
| Compare two strings for equality. The string pointed to by 'Buffer' may or may not be null-terminated, | |
| so only compare up to the length of Str. | |
| Arguments: | |
| Buffer - pointer to first (possibly not null-terminated) string | |
| Str - pointer to null-terminated string to compare to Buffer | |
| Returns: | |
| Number of bytes matched if exact match | |
| 0 if Buffer does not start with Str | |
| --*/ | |
| { | |
| UINTN Len; | |
| Len = 0; | |
| while (*Str && (*Str == *Buffer)) { | |
| Buffer++; | |
| Str++; | |
| Len++; | |
| } | |
| if (*Str) { | |
| return 0; | |
| } | |
| return Len; | |
| } | |
| STATIC | |
| UINTN | |
| t_strlen ( | |
| CHAR8 *Str | |
| ) | |
| { | |
| UINTN Len; | |
| Len = 0; | |
| while (*Str) { | |
| Len++; | |
| Str++; | |
| } | |
| return Len; | |
| } | |
| STATIC | |
| UINTN | |
| t_strncmp ( | |
| CHAR8 *Str1, | |
| CHAR8 *Str2, | |
| INTN Len | |
| ) | |
| { | |
| while (Len > 0) { | |
| if (*Str1 != *Str2) { | |
| return Len; | |
| } | |
| Len--; | |
| Str1++; | |
| Str2++; | |
| } | |
| return 0; | |
| } | |
| STATIC | |
| CHAR8 * | |
| t_strcpy ( | |
| CHAR8 *Dest, | |
| CHAR8 *Src | |
| ) | |
| { | |
| CHAR8 *SaveDest; | |
| SaveDest = Dest; | |
| while (*Src) { | |
| *Dest = *Src; | |
| Dest++; | |
| Src++; | |
| } | |
| *Dest = 0; | |
| return SaveDest; | |
| } | |
| STATIC | |
| VOID | |
| RewindFile ( | |
| SOURCE_FILE *SourceFile | |
| ) | |
| { | |
| SourceFile->LineNum = 1; | |
| SourceFile->FileBufferPtr = SourceFile->FileBuffer; | |
| SourceFile->EndOfFile = 0; | |
| } | |
| STATIC | |
| UINT32 | |
| GetHexChars ( | |
| CHAR8 *Buffer, | |
| UINT32 BufferLen | |
| ) | |
| { | |
| UINT32 Len; | |
| Len = 0; | |
| while (!EndOfFile (&mGlobals.SourceFile) && (BufferLen > 0)) { | |
| if (isxdigit (mGlobals.SourceFile.FileBufferPtr[0])) { | |
| *Buffer = mGlobals.SourceFile.FileBufferPtr[0]; | |
| Buffer++; | |
| Len++; | |
| BufferLen--; | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| } else { | |
| break; | |
| } | |
| } | |
| // | |
| // Null terminate if we can | |
| // | |
| if ((Len > 0) && (BufferLen > 0)) { | |
| *Buffer = 0; | |
| } | |
| return Len; | |
| } | |
| BOOLEAN | |
| SFPGetGuid ( | |
| INTN GuidStyle, | |
| EFI_GUID *Value | |
| ) | |
| /*++ | |
| Routine Description: | |
| Parse a GUID from the input stream. Stop when you discover white space. | |
| Arguments: | |
| GuidStyle - Style of the following GUID token | |
| Value - pointer to EFI_GUID struct for output | |
| Returns: | |
| TRUE - GUID string parsed successfully | |
| FALSE - otherwise | |
| GUID styles | |
| Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD | |
| --*/ | |
| { | |
| UINT32 Value32; | |
| UINT32 Index; | |
| FILE_POSITION FPos; | |
| CHAR8 TempString[20]; | |
| CHAR8 TempString2[3]; | |
| CHAR8 *From; | |
| CHAR8 *To; | |
| UINT32 Len; | |
| BOOLEAN Status; | |
| Status = FALSE; | |
| // | |
| // Skip white space, then start parsing | |
| // | |
| SkipWhiteSpace (&mGlobals.SourceFile); | |
| GetFilePosition (&FPos); | |
| if (EndOfFile (&mGlobals.SourceFile)) { | |
| return FALSE; | |
| } | |
| if (GuidStyle == PARSE_GUID_STYLE_5_FIELDS) { | |
| // | |
| // Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD | |
| // | |
| Len = GetHexChars (TempString, sizeof (TempString)); | |
| if ((Len == 0) || (Len > 8)) { | |
| goto Done; | |
| } | |
| sscanf (TempString, "%x", &Value32); | |
| Value->Data1 = Value32; | |
| // | |
| // Next two UINT16 fields | |
| // | |
| if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { | |
| goto Done; | |
| } | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| Len = GetHexChars (TempString, sizeof (TempString)); | |
| if ((Len == 0) || (Len > 4)) { | |
| goto Done; | |
| } | |
| sscanf (TempString, "%x", &Value32); | |
| Value->Data2 = (UINT16) Value32; | |
| if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { | |
| goto Done; | |
| } | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| Len = GetHexChars (TempString, sizeof (TempString)); | |
| if ((Len == 0) || (Len > 4)) { | |
| goto Done; | |
| } | |
| sscanf (TempString, "%x", &Value32); | |
| Value->Data3 = (UINT16) Value32; | |
| // | |
| // Parse the "AAAA" as two bytes | |
| // | |
| if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { | |
| goto Done; | |
| } | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| Len = GetHexChars (TempString, sizeof (TempString)); | |
| if ((Len == 0) || (Len > 4)) { | |
| goto Done; | |
| } | |
| sscanf (TempString, "%x", &Value32); | |
| Value->Data4[0] = (UINT8) (Value32 >> 8); | |
| Value->Data4[1] = (UINT8) Value32; | |
| if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { | |
| goto Done; | |
| } | |
| mGlobals.SourceFile.FileBufferPtr++; | |
| // | |
| // Read the last 6 bytes of the GUID | |
| // | |
| // | |
| Len = GetHexChars (TempString, sizeof (TempString)); | |
| if ((Len == 0) || (Len > 12)) { | |
| goto Done; | |
| } | |
| // | |
| // Insert leading 0's to make life easier | |
| // | |
| if (Len != 12) { | |
| From = TempString + Len - 1; | |
| To = TempString + 11; | |
| TempString[12] = 0; | |
| while (From >= TempString) { | |
| *To = *From; | |
| To--; | |
| From--; | |
| } | |
| while (To >= TempString) { | |
| *To = '0'; | |
| To--; | |
| } | |
| } | |
| // | |
| // Now parse each byte | |
| // | |
| TempString2[2] = 0; | |
| for (Index = 0; Index < 6; Index++) { | |
| // | |
| // Copy the two characters from the input string to something | |
| // we can parse. | |
| // | |
| TempString2[0] = TempString[Index * 2]; | |
| TempString2[1] = TempString[Index * 2 + 1]; | |
| sscanf (TempString2, "%x", &Value32); | |
| Value->Data4[Index + 2] = (UINT8) Value32; | |
| } | |
| Status = TRUE; | |
| } else { | |
| // | |
| // Unsupported GUID style | |
| // | |
| return FALSE; | |
| } | |
| Done: | |
| if (Status == FALSE) { | |
| SetFilePosition (&FPos); | |
| } | |
| return Status; | |
| } | |
| STATIC | |
| STATUS | |
| GetFilePosition ( | |
| FILE_POSITION *Fpos | |
| ) | |
| { | |
| Fpos->FileBufferPtr = mGlobals.SourceFile.FileBufferPtr; | |
| return STATUS_SUCCESS; | |
| } | |
| STATIC | |
| STATUS | |
| SetFilePosition ( | |
| FILE_POSITION *Fpos | |
| ) | |
| { | |
| // | |
| // Should check range of pointer | |
| // | |
| mGlobals.SourceFile.FileBufferPtr = Fpos->FileBufferPtr; | |
| return STATUS_SUCCESS; | |
| } |