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