mirror of https://github.com/acidanthera/audk.git
1438 lines
31 KiB
C
1438 lines
31 KiB
C
/** @file
|
|
Generic but simple file parsing routines.
|
|
|
|
Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
|
|
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.
|
|
|
|
--*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#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
|
|
);
|
|
|
|
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 ((int)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
|
|
|
|
--*/
|
|
{
|
|
unsigned 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;
|
|
}
|
|
}
|
|
|
|
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", (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 exceeeds 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;
|
|
}
|
|
|
|
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 = %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;
|
|
}
|
|
|
|
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 = %u (0x%X)\n", (unsigned)SourceFile->FileSize, (unsigned)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 ((int)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
|
|
|
|
--*/
|
|
{
|
|
unsigned 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;
|
|
}
|