git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1006 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			649 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			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;
 | |
| }
 |