mirror of https://github.com/acidanthera/audk.git
651 lines
13 KiB
C
651 lines
13 KiB
C
/*++
|
|
|
|
Copyright (c) 2004 Intel Corporation. All rights reserved
|
|
This software and associated documentation (if any) is furnished
|
|
under a license and may only be used or copied in accordance
|
|
with the terms of the license. Except as permitted by such
|
|
license, no part of this software or documentation may be
|
|
reproduced, stored in a retrieval system, or transmitted in any
|
|
form or by any means without the express written consent of
|
|
Intel Corporation.
|
|
|
|
|
|
Module Name:
|
|
|
|
Symbol.c
|
|
|
|
Abstract:
|
|
|
|
Class-like implementation for a symbol table.
|
|
|
|
--*/
|
|
|
|
// GC_TODO: fix comment to set correct module name: Symbols.c
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
//
|
|
// for isspace()
|
|
//
|
|
#include <ctype.h>
|
|
|
|
#include <UefiBaseTypes.h>
|
|
#include <Base.h>
|
|
#include <CommonLib.h>
|
|
|
|
#include "EfiUtilityMsgs.h"
|
|
#include "Symbols.h"
|
|
|
|
#define MAX_LINE_LEN 512
|
|
|
|
//
|
|
// Linked list to keep track of all symbols
|
|
//
|
|
typedef struct _SYMBOL {
|
|
struct _SYMBOL *Next;
|
|
int Type;
|
|
char *Name;
|
|
char *Value;
|
|
} SYMBOL;
|
|
|
|
static
|
|
SYMBOL *
|
|
FreeSymbols (
|
|
SYMBOL *Syms
|
|
);
|
|
|
|
static
|
|
int
|
|
ExpandMacros (
|
|
char *SourceLine,
|
|
char *DestLine,
|
|
int LineLen
|
|
);
|
|
|
|
static SYMBOL *mSymbolTable = NULL;
|
|
|
|
void
|
|
SymbolsConstructor (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GC_TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
GC_TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
SymbolsDestructor ();
|
|
}
|
|
|
|
void
|
|
SymbolsDestructor (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GC_TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
GC_TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
mSymbolTable = FreeSymbols (mSymbolTable);
|
|
}
|
|
|
|
char *
|
|
GetSymbolValue (
|
|
char *SymbolName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look up a symbol in our symbol table.
|
|
|
|
Arguments:
|
|
|
|
SymbolName
|
|
|
|
Returns:
|
|
|
|
Pointer to the value of the symbol if found
|
|
NULL if the symbol is not found
|
|
|
|
--*/
|
|
// GC_TODO: SymbolName - add argument and description to function comment
|
|
{
|
|
SYMBOL *Symbol;
|
|
//
|
|
// Walk the symbol table
|
|
//
|
|
Symbol = mSymbolTable;
|
|
while (Symbol) {
|
|
if (stricmp (SymbolName, Symbol->Name) == 0) {
|
|
return Symbol->Value;
|
|
}
|
|
|
|
Symbol = Symbol->Next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
SymbolAdd (
|
|
char *Name,
|
|
char *Value,
|
|
int Mode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a symbol name/value to the symbol table
|
|
|
|
Arguments:
|
|
|
|
Name - name of symbol to add
|
|
Value - value of symbol to add
|
|
Mode - currrently unused
|
|
|
|
Returns:
|
|
|
|
Length of symbol added.
|
|
|
|
Notes:
|
|
If Value == NULL, then this routine will assume that the Name field
|
|
looks something like "MySymName = MySymValue", and will try to parse
|
|
it that way and add the symbol name/pair from the string.
|
|
|
|
--*/
|
|
{
|
|
SYMBOL *Symbol;
|
|
|
|
SYMBOL *NewSymbol;
|
|
int Len;
|
|
char *Start;
|
|
char *Cptr;
|
|
char CSave;
|
|
char *SaveCptr;
|
|
|
|
Len = 0;
|
|
SaveCptr = NULL;
|
|
CSave = 0;
|
|
//
|
|
// If value pointer is null, then they passed us a line something like:
|
|
// varname = value, or simply var =
|
|
//
|
|
if (Value == NULL) {
|
|
Start = Name;
|
|
while (*Name && isspace (*Name)) {
|
|
Name++;
|
|
}
|
|
|
|
if (Name == NULL) {
|
|
return -1;
|
|
}
|
|
//
|
|
// Find the end of the name. Either space or a '='.
|
|
//
|
|
for (Value = Name; *Value && !isspace (*Value) && (*Value != '='); Value++)
|
|
;
|
|
if (Value == NULL) {
|
|
return -1;
|
|
}
|
|
//
|
|
// Look for the '='
|
|
//
|
|
Cptr = Value;
|
|
while (*Value && (*Value != '=')) {
|
|
Value++;
|
|
}
|
|
|
|
if (Value == NULL) {
|
|
return -1;
|
|
}
|
|
//
|
|
// Now truncate the name
|
|
//
|
|
*Cptr = 0;
|
|
//
|
|
// Skip over the = and then any spaces
|
|
//
|
|
Value++;
|
|
while (*Value && isspace (*Value)) {
|
|
Value++;
|
|
|
|
}
|
|
//
|
|
// Find end of string, checking for quoted string
|
|
//
|
|
if (*Value == '\"') {
|
|
Value++;
|
|
for (Cptr = Value; *Cptr && *Cptr != '\"'; Cptr++)
|
|
;
|
|
} else {
|
|
for (Cptr = Value; *Cptr && !isspace (*Cptr); Cptr++)
|
|
;
|
|
}
|
|
//
|
|
// Null terminate the value string
|
|
//
|
|
CSave = *Cptr;
|
|
SaveCptr = Cptr;
|
|
*Cptr = 0;
|
|
Len = (int) (Cptr - Start);
|
|
}
|
|
//
|
|
// We now have a symbol name and a value. Look for an existing variable
|
|
// and overwrite it.
|
|
//
|
|
Symbol = mSymbolTable;
|
|
while (Symbol) {
|
|
//
|
|
// Check for symbol name match
|
|
//
|
|
if (stricmp (Name, Symbol->Name) == 0) {
|
|
_free (Symbol->Value);
|
|
Symbol->Value = (char *) _malloc (strlen (Value) + 1);
|
|
if (Symbol->Value == NULL) {
|
|
Error (NULL, 0, 0, NULL, "failed to allocate memory");
|
|
return -1;
|
|
}
|
|
|
|
strcpy (Symbol->Value, Value);
|
|
//
|
|
// If value == "NULL", then make it a 0-length string
|
|
//
|
|
if (stricmp (Symbol->Value, "NULL") == 0) {
|
|
Symbol->Value[0] = 0;
|
|
}
|
|
|
|
return Len;
|
|
}
|
|
|
|
Symbol = Symbol->Next;
|
|
}
|
|
//
|
|
// Does not exist, create a new one
|
|
//
|
|
NewSymbol = (SYMBOL *) _malloc (sizeof (SYMBOL));
|
|
if (NewSymbol == NULL) {
|
|
Error (NULL, 0, 0, NULL, "memory allocation failure");
|
|
return -1;
|
|
}
|
|
|
|
memset ((char *) NewSymbol, 0, sizeof (SYMBOL));
|
|
NewSymbol->Name = (char *) _malloc (strlen (Name) + 1);
|
|
if (NewSymbol->Name == NULL) {
|
|
Error (NULL, 0, 0, NULL, "memory allocation failure");
|
|
_free (NewSymbol);
|
|
return -1;
|
|
}
|
|
|
|
NewSymbol->Value = (char *) _malloc (strlen (Value) + 1);
|
|
if (NewSymbol->Value == NULL) {
|
|
Error (NULL, 0, 0, NULL, "memory allocation failure");
|
|
_free (NewSymbol->Name);
|
|
_free (NewSymbol);
|
|
return -1;
|
|
}
|
|
|
|
strcpy (NewSymbol->Name, Name);
|
|
strcpy (NewSymbol->Value, Value);
|
|
//
|
|
// Remove trailing spaces
|
|
//
|
|
Cptr = NewSymbol->Value + strlen (NewSymbol->Value) - 1;
|
|
while (Cptr > NewSymbol->Value) {
|
|
if (isspace (*Cptr)) {
|
|
*Cptr = 0;
|
|
Cptr--;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// Add it to the head of the list.
|
|
//
|
|
NewSymbol->Next = mSymbolTable;
|
|
mSymbolTable = NewSymbol;
|
|
//
|
|
// If value == "NULL", then make it a 0-length string
|
|
//
|
|
if (stricmp (NewSymbol->Value, "NULL") == 0) {
|
|
NewSymbol->Value[0] = 0;
|
|
}
|
|
//
|
|
// Restore the terminator we inserted if they passed in var=value
|
|
//
|
|
if (SaveCptr != NULL) {
|
|
*SaveCptr = CSave;
|
|
}
|
|
_free (NewSymbol->Value);
|
|
_free (NewSymbol->Name);
|
|
_free (NewSymbol);
|
|
return Len;
|
|
}
|
|
|
|
static
|
|
STATUS
|
|
RemoveSymbol (
|
|
char *Name,
|
|
char SymbolType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove a symbol name/value from the symbol table
|
|
|
|
Arguments:
|
|
|
|
Name - name of symbol to remove
|
|
SymbolType - type of symbol to remove
|
|
|
|
Returns:
|
|
|
|
STATUS_SUCCESS - matching symbol found and removed
|
|
STATUS_ERROR - matching symbol not found in symbol table
|
|
|
|
--*/
|
|
{
|
|
SYMBOL *Symbol;
|
|
|
|
SYMBOL *PrevSymbol;
|
|
|
|
PrevSymbol = NULL;
|
|
Symbol = mSymbolTable;
|
|
//
|
|
// Walk the linked list of symbols in the symbol table looking
|
|
// for a match of both symbol name and type.
|
|
//
|
|
while (Symbol) {
|
|
if ((stricmp (Name, Symbol->Name) == 0) && (Symbol->Type & SymbolType)) {
|
|
//
|
|
// If the symbol has a value associated with it, free the memory
|
|
// allocated for the value.
|
|
// Then free the memory allocated for the symbols string name.
|
|
//
|
|
if (Symbol->Value) {
|
|
_free (Symbol->Value);
|
|
}
|
|
|
|
_free (Symbol->Name);
|
|
//
|
|
// Link the previous symbol to the next symbol to effectively
|
|
// remove this symbol from the linked list.
|
|
//
|
|
if (PrevSymbol) {
|
|
PrevSymbol->Next = Symbol->Next;
|
|
} else {
|
|
mSymbolTable = Symbol->Next;
|
|
}
|
|
|
|
_free (Symbol);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
PrevSymbol = Symbol;
|
|
Symbol = Symbol->Next;
|
|
}
|
|
|
|
return STATUS_WARNING;
|
|
}
|
|
|
|
static
|
|
SYMBOL *
|
|
FreeSymbols (
|
|
SYMBOL *Syms
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GC_TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Syms - GC_TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
GC_TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
SYMBOL *Next;
|
|
while (Syms) {
|
|
if (Syms->Name != NULL) {
|
|
_free (Syms->Name);
|
|
}
|
|
|
|
if (Syms->Value != NULL) {
|
|
_free (Syms->Value);
|
|
}
|
|
|
|
Next = Syms->Next;
|
|
_free (Syms);
|
|
Syms = Next;
|
|
}
|
|
|
|
return Syms;
|
|
}
|
|
|
|
static
|
|
int
|
|
ExpandMacros (
|
|
char *SourceLine,
|
|
char *DestLine,
|
|
int LineLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a line of text, replace all variables of format $(NAME) with values
|
|
from our symbol table.
|
|
|
|
Arguments:
|
|
|
|
SourceLine - input line of text to do symbol replacements on
|
|
DestLine - on output, SourceLine with symbols replaced
|
|
LineLen - length of DestLine, so we don't exceed its allocated length
|
|
|
|
Returns:
|
|
|
|
STATUS_SUCCESS - no problems encountered
|
|
STATUS_WARNING - missing closing parenthesis on a symbol reference in SourceLine
|
|
STATUS_ERROR - memory allocation failure
|
|
|
|
--*/
|
|
{
|
|
static int NestDepth = 0;
|
|
char *FromPtr;
|
|
char *ToPtr;
|
|
char *SaveStart;
|
|
char *Cptr;
|
|
char *value;
|
|
int Expanded;
|
|
int ExpandedCount;
|
|
INT8 *LocalDestLine;
|
|
STATUS Status;
|
|
int LocalLineLen;
|
|
|
|
NestDepth++;
|
|
Status = STATUS_SUCCESS;
|
|
LocalDestLine = (char *) _malloc (LineLen);
|
|
if (LocalDestLine == NULL) {
|
|
Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
FromPtr = SourceLine;
|
|
ToPtr = LocalDestLine;
|
|
//
|
|
// Walk the entire line, replacing $(MACRO_NAME).
|
|
//
|
|
LocalLineLen = LineLen;
|
|
ExpandedCount = 0;
|
|
while (*FromPtr && (LocalLineLen > 0)) {
|
|
if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) {
|
|
//
|
|
// Save the start in case it's undefined, in which case we copy it as-is.
|
|
//
|
|
SaveStart = FromPtr;
|
|
Expanded = 0;
|
|
//
|
|
// Macro expansion time. Find the end (no spaces allowed)
|
|
//
|
|
FromPtr += 2;
|
|
for (Cptr = FromPtr; *Cptr && (*Cptr != ')'); Cptr++)
|
|
;
|
|
if (*Cptr) {
|
|
//
|
|
// Truncate the string at the closing parenthesis for ease-of-use.
|
|
// Then copy the string directly to the destination line in case we don't find
|
|
// a definition for it.
|
|
//
|
|
*Cptr = 0;
|
|
strcpy (ToPtr, SaveStart);
|
|
if ((value = GetSymbolValue (FromPtr)) != NULL) {
|
|
strcpy (ToPtr, value);
|
|
LocalLineLen -= strlen (value);
|
|
ToPtr += strlen (value);
|
|
Expanded = 1;
|
|
ExpandedCount++;
|
|
}
|
|
|
|
if (!Expanded) {
|
|
//
|
|
// Restore closing parenthesis, and advance to next character
|
|
//
|
|
*Cptr = ')';
|
|
FromPtr = SaveStart + 1;
|
|
ToPtr++;
|
|
} else {
|
|
FromPtr = Cptr + 1;
|
|
}
|
|
} else {
|
|
Error (NULL, 0, 0, SourceLine, "missing closing parenthesis on macro");
|
|
strcpy (ToPtr, FromPtr);
|
|
Status = STATUS_WARNING;
|
|
goto Done;
|
|
}
|
|
} else {
|
|
*ToPtr = *FromPtr;
|
|
FromPtr++;
|
|
ToPtr++;
|
|
LocalLineLen--;
|
|
}
|
|
}
|
|
|
|
if (*FromPtr == 0) {
|
|
*ToPtr = 0;
|
|
}
|
|
|
|
//
|
|
// If we expanded at least one string successfully, then make a recursive call to try again.
|
|
//
|
|
if ((ExpandedCount != 0) && (Status == STATUS_SUCCESS) && (NestDepth < 10)) {
|
|
Status = ExpandMacros (LocalDestLine, DestLine, LineLen);
|
|
_free (LocalDestLine);
|
|
NestDepth = 0;
|
|
return Status;
|
|
}
|
|
|
|
Done:
|
|
if (Status != STATUS_ERROR) {
|
|
strcpy (DestLine, LocalDestLine);
|
|
}
|
|
|
|
NestDepth = 0;
|
|
_free (LocalDestLine);
|
|
return Status;
|
|
}
|
|
|
|
STATUS
|
|
SymbolsFileStringsReplace (
|
|
char *InFileName,
|
|
char *OutFileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given input and output file names, read in the input file, replace variable
|
|
references of format $(NAME) with appropriate values from our symbol table,
|
|
and write the result out to the output file.
|
|
|
|
Arguments:
|
|
|
|
InFileName - name of input text file to replace variable references
|
|
OutFileName - name of output text file to write results to
|
|
|
|
Returns:
|
|
|
|
STATUS_SUCCESS - no problems encountered
|
|
STATUS_ERROR - failed to open input or output file
|
|
|
|
--*/
|
|
{
|
|
STATUS Status;
|
|
FILE *InFptr;
|
|
FILE *OutFptr;
|
|
char Line[MAX_LINE_LEN];
|
|
char OutLine[MAX_LINE_LEN];
|
|
|
|
Status = STATUS_ERROR;
|
|
//
|
|
// Open input and output files
|
|
//
|
|
InFptr = NULL;
|
|
OutFptr = NULL;
|
|
if ((InFptr = fopen (InFileName, "r")) == NULL) {
|
|
Error (NULL, 0, 0, InFileName, "failed to open input file for reading");
|
|
goto Done;
|
|
}
|
|
|
|
if ((OutFptr = fopen (OutFileName, "w")) == NULL) {
|
|
Error (NULL, 0, 0, OutFileName, "failed to open output file for writing");
|
|
goto Done;
|
|
}
|
|
//
|
|
// Read lines from input file until done
|
|
//
|
|
while (fgets (Line, sizeof (Line), InFptr) != NULL) {
|
|
ExpandMacros (Line, OutLine, sizeof (OutLine));
|
|
fprintf (OutFptr, OutLine);
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Done:
|
|
if (InFptr != NULL) {
|
|
fclose (InFptr);
|
|
}
|
|
|
|
if (OutFptr != NULL) {
|
|
fclose (OutFptr);
|
|
}
|
|
|
|
return Status;
|
|
}
|