| /*++ | |
| 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 |