/*++ | |
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 <Common/UefiBaseTypes.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; | |
} |