/** @file Generic but simple file parsing routines. Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent --*/ #include #include #include #include #include "CommonLib.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 ); /** @retval STATUS_SUCCESS always **/ STATUS SFPInit ( VOID ) { memset ((VOID *) &mGlobals, 0, sizeof (mGlobals)); return STATUS_SUCCESS; } /** Return the line number of the file we're parsing. Used for error reporting purposes. @return The line number, or 0 if no file is being processed **/ UINTN SFPGetLineNumber ( VOID ) { return mGlobals.SourceFile.LineNum; } /** Return the name of the file we're parsing. Used for error reporting purposes. @return A pointer to the file name. Null if no file is being processed. **/ CHAR8 * SFPGetFileName ( VOID ) { if (mGlobals.SourceFile.FileName[0]) { return mGlobals.SourceFile.FileName; } return NULL; } /** Open a file for parsing. @param FileName name of the file to parse **/ STATUS SFPOpenFile ( CHAR8 *FileName ) { STATUS Status; t_strcpy (mGlobals.SourceFile.FileName, FileName); Status = ProcessIncludeFile (&mGlobals.SourceFile, NULL); return Status; } /** Check to see if the specified token is found at the current position in the input file. @note: 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. @param Str the token to look for @retval TRUE the token is next @retval FALSE the token is not next **/ BOOLEAN SFPIsToken ( CHAR8 *Str ) { 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; } /** Check to see if the specified keyword is found at the current position in the input file. @note: A keyword is defined as a "special" string that has a non-alphanumeric character following it. @param Str keyword to look for @retval TRUE the keyword is next @retval FALSE the keyword is not next **/ BOOLEAN SFPIsKeyword ( CHAR8 *Str ) { UINTN Len; SkipWhiteSpace (&mGlobals.SourceFile); if (EndOfFile (&mGlobals.SourceFile)) { return FALSE; } if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) { if (isalnum ((int)mGlobals.SourceFile.FileBufferPtr[Len])) { return FALSE; } mGlobals.SourceFile.FileBufferPtr += Len; if (mGlobals.VerboseToken) { printf ("Token: '%s'\n", Str); } return TRUE; } return FALSE; } /** Get the next token from the input stream. @note: Preceding white space is ignored. The parser's buffer pointer is advanced past the end of the token. @param Str pointer to a copy of the next token @param Len size of buffer pointed to by Str @retval TRUE next token successfully returned @retval FALSE otherwise **/ BOOLEAN SFPGetNextToken ( CHAR8 *Str, UINTN Len ) { 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; } /** Parse a GUID from the input stream. Stop when you discover white space. @param Str pointer to a copy of the next token @param Len size of buffer pointed to by Str @retval TRUE GUID string returned successfully @retval FALSE otherwise **/ BOOLEAN SFPGetGuidToken ( CHAR8 *Str, UINT32 Len ) { 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; } /** Check the token at the current file position for a numeric value. May be either decimal or hex. @param Value pointer where to store the value @retval FALSE current token is not a number @retval TRUE current token is a number **/ BOOLEAN SFPGetNumber ( UINTN *Value ) { int Val; SkipWhiteSpace (&mGlobals.SourceFile); if (EndOfFile (&mGlobals.SourceFile)) { return FALSE; } if (isdigit ((int)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 ((int)mGlobals.SourceFile.FileBufferPtr[2])) { return FALSE; } mGlobals.SourceFile.FileBufferPtr += 2; sscanf (mGlobals.SourceFile.FileBufferPtr, "%x", &Val); *Value = (UINT32) Val; while (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { mGlobals.SourceFile.FileBufferPtr++; } return TRUE; } else { *Value = atoi (mGlobals.SourceFile.FileBufferPtr); while (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { mGlobals.SourceFile.FileBufferPtr++; } return TRUE; } } else { return FALSE; } } /** Close the file being parsed. @retval STATUS_SUCCESS the file was closed @retval STATUS_ERROR no file is currently open **/ STATUS SFPCloseFile ( VOID ) { if (mGlobals.SourceFile.FileBuffer != NULL) { free (mGlobals.SourceFile.FileBuffer); memset (&mGlobals.SourceFile, 0, sizeof (mGlobals.SourceFile)); return STATUS_SUCCESS; } return STATUS_ERROR; } /** Given a source file, open the file and parse it @param SourceFile name of file to parse @param ParentSourceFile for error reporting purposes, the file that #included SourceFile. @return Standard status. **/ STATIC STATUS ProcessIncludeFile ( SOURCE_FILE *SourceFile, SOURCE_FILE *ParentSourceFile ) { 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", (int)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 exceeds max nesting depth (%u)", SourceFile->FileName, (unsigned) 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 (LongFilePath (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; } /** Given a source file that's been opened, read the contents into an internal buffer and pre-process it to remove comments. @param SourceFile structure containing info on the file to process @return Standard status. **/ STATIC STATUS ProcessFile ( SOURCE_FILE *SourceFile ) { // // 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 = %u (0x%X)\n", (unsigned) SourceFile->FileSize, (unsigned) 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; } /** 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. @param SourceFile structure that we use to keep track of an input file. **/ STATIC VOID PreprocessFile ( SOURCE_FILE *SourceFile ) { 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 = %u (0x%X)\n", (unsigned)SourceFile->FileSize, (unsigned)SourceFile->FileSize); RewindFile (SourceFile); } } /** Retrieve a quoted-string from the input file. @param Str pointer to a copy of the quoted string parsed @param Length size of buffer pointed to by Str @retval TRUE next token in input stream was a quoted string, and the string value was returned in Str @retval FALSE otherwise **/ BOOLEAN SFPGetQuotedString ( CHAR8 *Str, INTN Length ) { 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; } /** Return TRUE of FALSE to indicate whether or not we've reached the end of the file we're parsing. @retval TRUE EOF reached @retval FALSE otherwise **/ BOOLEAN SFPIsEOF ( VOID ) { 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; } /** 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. @param Buffer pointer to first (possibly not null-terminated) string @param Str pointer to null-terminated string to compare to Buffer @retval Number of bytes matched if exact match @retval 0 if Buffer does not start with Str **/ STATIC UINTN t_strcmp ( CHAR8 *Buffer, CHAR8 *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) && (Len < BufferLen)) { if (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { Buffer[Len] = mGlobals.SourceFile.FileBufferPtr[0]; Len++; mGlobals.SourceFile.FileBufferPtr++; } else { break; } } // // Null terminate if we can // if ((Len > 0) && (Len < BufferLen)) { Buffer[Len] = 0; } return Len; } /** Parse a GUID from the input stream. Stop when you discover white space. GUID styles Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD @param GuidStyle Style of the following GUID token @param Value pointer to EFI_GUID struct for output @retval TRUE GUID string parsed successfully @retval FALSE otherwise **/ BOOLEAN SFPGetGuid ( INTN GuidStyle, EFI_GUID *Value ) { INT32 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; }