audk/Tools/CCode/Source/FlashMap/Symbols.c

649 lines
13 KiB
C

/*++
Copyright (c) 2004-2006 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:
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;
}