/*++ | |
Copyright (c) 2004, 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 <Common/UefiBaseTypes.h> | |
#include "EfiUtilityMsgs.h" | |
#include "SimpleFileParsing.h" | |
#define MAX_PATH 255 | |
#define MAX_NEST_DEPTH 20 // just in case we get in an endless loop. | |
#define MAX_STRING_IDENTIFIER_NAME 100 // number of wchars | |
#define MAX_LINE_LEN 400 | |
#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' | |
// | |
// We keep a linked list of these for the source files we process | |
// | |
typedef struct _SOURCE_FILE { | |
FILE *Fptr; | |
T_CHAR *FileBuffer; | |
T_CHAR *FileBufferPtr; | |
UINT32 FileSize; | |
INT8 FileName[MAX_PATH]; | |
UINT32 LineNum; | |
BOOLEAN EndOfFile; | |
BOOLEAN SkipToHash; | |
struct _SOURCE_FILE *Previous; | |
struct _SOURCE_FILE *Next; | |
T_CHAR ControlCharacter; | |
} SOURCE_FILE; | |
// | |
// Here's all our module globals. | |
// | |
static struct { | |
SOURCE_FILE SourceFile; | |
BOOLEAN Verbose; | |
} mGlobals; | |
static | |
UINT32 | |
t_strcmp ( | |
T_CHAR *Buffer, | |
T_CHAR *Str | |
); | |
static | |
UINT32 | |
t_strncmp ( | |
T_CHAR *Str1, | |
T_CHAR *Str2, | |
UINT32 Len | |
); | |
static | |
UINT32 | |
t_strlen ( | |
T_CHAR *Str | |
); | |
static | |
void | |
RewindFile ( | |
SOURCE_FILE *SourceFile | |
); | |
static | |
BOOLEAN | |
SkipTo ( | |
SOURCE_FILE *SourceFile, | |
T_CHAR TChar, | |
BOOLEAN StopAfterNewline | |
); | |
static | |
BOOLEAN | |
IsWhiteSpace ( | |
SOURCE_FILE *SourceFile | |
); | |
static | |
UINT32 | |
SkipWhiteSpace ( | |
SOURCE_FILE *SourceFile | |
); | |
static | |
BOOLEAN | |
EndOfFile ( | |
SOURCE_FILE *SourceFile | |
); | |
static | |
void | |
PreprocessFile ( | |
SOURCE_FILE *SourceFile | |
); | |
// | |
// static | |
// T_CHAR * | |
// GetQuotedString ( | |
// SOURCE_FILE *SourceFile, | |
// BOOLEAN Optional | |
// ); | |
// | |
static | |
T_CHAR * | |
t_strcpy ( | |
T_CHAR *Dest, | |
T_CHAR *Src | |
); | |
static | |
STATUS | |
ProcessIncludeFile ( | |
SOURCE_FILE *SourceFile, | |
SOURCE_FILE *ParentSourceFile | |
); | |
static | |
STATUS | |
ParseFile ( | |
SOURCE_FILE *SourceFile | |
); | |
static | |
FILE * | |
FindFile ( | |
IN INT8 *FileName, | |
OUT INT8 *FoundFileName, | |
IN UINT32 FoundFileNameLen | |
); | |
static | |
STATUS | |
ProcessFile ( | |
SOURCE_FILE *SourceFile | |
); | |
STATUS | |
SFPInit ( | |
VOID | |
) | |
{ | |
memset ((void *) &mGlobals, 0, sizeof (mGlobals)); | |
return STATUS_SUCCESS; | |
} | |
UINT32 | |
SFPGetLineNumber ( | |
VOID | |
) | |
{ | |
return mGlobals.SourceFile.LineNum; | |
} | |
/*++ | |
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 | |
--*/ | |
T_CHAR * | |
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 ( | |
IN INT8 *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 ( | |
T_CHAR *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. | |
--*/ | |
{ | |
UINT32 Len; | |
SkipWhiteSpace (&mGlobals.SourceFile); | |
if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) { | |
mGlobals.SourceFile.FileBufferPtr += Len; | |
return TRUE; | |
} | |
return FALSE; | |
} | |
BOOLEAN | |
SFPGetNextToken ( | |
T_CHAR *Str, | |
UINT32 Len | |
) | |
{ | |
UINT32 Index; | |
SkipWhiteSpace (&mGlobals.SourceFile); | |
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 ( | |
T_CHAR *Str | |
) | |
{ | |
UINT32 Len; | |
T_CHAR *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 ( | |
UINT32 *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 Len; | |
// | |
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", Value); | |
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 UINT32 NestDepth = 0; | |
INT8 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.Verbose) { | |
fprintf (stdout, "%*cProcessing file '%s'\n", NestDepth * 2, ' ', SourceFile->FileName); | |
} | |
// | |
// Make sure we didn't exceed our maximum nesting depth | |
// | |
if (NestDepth > MAX_NEST_DEPTH) { | |
Error (NULL, 0, 0, SourceFile->FileName, "max nesting depth (%d) exceeded", 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, "r")) == NULL) { | |
// | |
// Try to find it among the paths if it has a parent (that is, it is included | |
// by someone else). | |
// | |
Error (NULL, 0, 0, SourceFile->FileName, "file not found"); | |
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 | |
) | |
{ | |
// | |
// Get the file size, and then read the entire thing into memory. | |
// Allocate space for a terminator character. | |
// | |
fseek (SourceFile->Fptr, 0, SEEK_END); | |
SourceFile->FileSize = ftell (SourceFile->Fptr); | |
fseek (SourceFile->Fptr, 0, SEEK_SET); | |
SourceFile->FileBuffer = (T_CHAR *) malloc (SourceFile->FileSize + sizeof (T_CHAR)); | |
if (SourceFile->FileBuffer == NULL) { | |
Error (NULL, 0, 0, "memory allocation failure", NULL); | |
return STATUS_ERROR; | |
} | |
fread ((VOID *) SourceFile->FileBuffer, SourceFile->FileSize, 1, SourceFile->Fptr); | |
SourceFile->FileBuffer[(SourceFile->FileSize / sizeof (T_CHAR))] = 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 from the file to the screen. | |
Arguments: | |
SourceFile - structure that we use to keep track of an input file. | |
Returns: | |
Nothing. | |
--*/ | |
{ | |
BOOLEAN InComment; | |
RewindFile (SourceFile); | |
InComment = FALSE; | |
while (!EndOfFile (SourceFile)) { | |
// | |
// If a line-feed, then no longer in a comment | |
// | |
if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) { | |
SourceFile->FileBufferPtr++; | |
SourceFile->LineNum++; | |
InComment = 0; | |
} 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++; | |
} else if (InComment) { | |
SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; | |
SourceFile->FileBufferPtr++; | |
} else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH)) { | |
SourceFile->FileBufferPtr += 2; | |
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); | |
} | |
#if 0 | |
static | |
T_CHAR * | |
GetQuotedString ( | |
SOURCE_FILE *SourceFile, | |
BOOLEAN Optional | |
) | |
{ | |
T_CHAR *String; | |
T_CHAR *Start; | |
T_CHAR *Ptr; | |
UINT32 Len; | |
BOOLEAN PreviousBackslash; | |
if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { | |
if (!Optional) { | |
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)) { | |
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 = (T_CHAR *) malloc ((Len + 1) * sizeof (T_CHAR)); | |
if (String == NULL) { | |
Error (NULL, 0, 0, "memory allocation failed", 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 (T_CHAR)) { | |
SourceFile->EndOfFile = TRUE; | |
return TRUE; | |
} | |
if (SourceFile->EndOfFile) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
#if 0 | |
static | |
void | |
ProcessTokenInclude ( | |
SOURCE_FILE *SourceFile | |
) | |
{ | |
INT8 IncludeFileName[MAX_PATH]; | |
INT8 *To; | |
UINT32 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 = UNICODE_TO_ASCII(SourceFile->FileBufferPtr[0]); | |
// | |
*To = (T_CHAR) SourceFile->FileBufferPtr[0]; | |
To++; | |
} | |
SourceFile->FileBufferPtr++; | |
} | |
if (!ReportedError) { | |
*To = 0; | |
memset ((char *) &IncludedSourceFile, 0, sizeof (SOURCE_FILE)); | |
strcpy (IncludedSourceFile.FileName, IncludeFileName); | |
// | |
// IncludedSourceFile.ControlCharacter = DEFAULT_CONTROL_CHARACTER; | |
// | |
ProcessIncludeFile (&IncludedSourceFile, SourceFile); | |
// | |
// printf ("including file '%s'\n", IncludeFileName); | |
// | |
} | |
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; | |
} | |
} | |
UINT32 | |
SkipWhiteSpace ( | |
SOURCE_FILE *SourceFile | |
) | |
{ | |
UINT32 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++; | |
if (mGlobals.Verbose) { | |
printf ("%d: %S\n", SourceFile->LineNum, SourceFile->FileBufferPtr); | |
} | |
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 | |
UINT32 | |
t_strcmp ( | |
T_CHAR *Buffer, | |
T_CHAR *Str | |
) | |
{ | |
UINT32 Len; | |
Len = 0; | |
while (*Str == *Buffer) { | |
Buffer++; | |
Str++; | |
Len++; | |
} | |
if (*Str) { | |
return 0; | |
} | |
return Len; | |
} | |
static | |
UINT32 | |
t_strlen ( | |
T_CHAR *Str | |
) | |
{ | |
UINT32 Len; | |
Len = 0; | |
while (*Str) { | |
Len++; | |
Str++; | |
} | |
return Len; | |
} | |
static | |
UINT32 | |
t_strncmp ( | |
T_CHAR *Str1, | |
T_CHAR *Str2, | |
UINT32 Len | |
) | |
{ | |
while (Len > 0) { | |
if (*Str1 != *Str2) { | |
return Len; | |
} | |
Len--; | |
Str1++; | |
Str2++; | |
} | |
return 0; | |
} | |
static | |
T_CHAR * | |
t_strcpy ( | |
T_CHAR *Dest, | |
T_CHAR *Src | |
) | |
{ | |
T_CHAR *SaveDest; | |
SaveDest = Dest; | |
while (*Src) { | |
*Dest = *Src; | |
Dest++; | |
Src++; | |
} | |
*Dest = 0; | |
return SaveDest; | |
} | |
#if 0 | |
static | |
BOOLEAN | |
IsValidIdentifierChar ( | |
INT8 Char, | |
BOOLEAN FirstChar | |
) | |
{ | |
// | |
// If it's the first character of an identifier, then | |
// it must be one of [A-Za-z_]. | |
// | |
if (FirstChar) { | |
if (isalpha (Char) || (Char == '_')) { | |
return TRUE; | |
} | |
} else { | |
// | |
// If it's not the first character, then it can | |
// be one of [A-Za-z_0-9] | |
// | |
if (isalnum (Char) || (Char == '_')) { | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
#endif | |
static | |
void | |
RewindFile ( | |
SOURCE_FILE *SourceFile | |
) | |
{ | |
SourceFile->LineNum = 1; | |
SourceFile->FileBufferPtr = SourceFile->FileBuffer; | |
SourceFile->EndOfFile = 0; | |
} | |
#if 0 | |
static | |
BOOLEAN | |
SkipTo ( | |
SOURCE_FILE *SourceFile, | |
T_CHAR TChar, | |
BOOLEAN StopAfterNewline | |
) | |
{ | |
while (!EndOfFile (SourceFile)) { | |
// | |
// Check for the character of interest | |
// | |
if (SourceFile->FileBufferPtr[0] == TChar) { | |
return TRUE; | |
} else { | |
if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) { | |
SourceFile->LineNum++; | |
if (StopAfterNewline) { | |
SourceFile->FileBufferPtr++; | |
if (SourceFile->FileBufferPtr[0] == 0) { | |
SourceFile->FileBufferPtr++; | |
} | |
return FALSE; | |
} | |
} | |
SourceFile->FileBufferPtr++; | |
} | |
} | |
return FALSE; | |
} | |
#endif |