mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-27 01:03:45 +01:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1676 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			970 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			970 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| 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
 |