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
 |