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