/*++ 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 #include #include // // for isspace() // #include #include #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; }