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