--- /dev/null
+/*++\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation \r
+All rights reserved. This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+ Module Name:\r
+\r
+ DscFile.c\r
+\r
+ Abstract:\r
+\r
+ This module is used to process description files at a high level. For the\r
+ most part, it pre-parses the file to find and save off positions of all\r
+ the sections ([section.subsection.subsection]) in a linked list, then\r
+ provides services to find the sections by name, and read the lines from\r
+ the section until you run into the next section.\r
+\r
+ NOTE: DSC file is synonomous with section file. A DSC file is simply a file\r
+ containing bracketed section names [section.subsection.subsection...]\r
+\r
+--*/\r
+\r
+#include <stdio.h> // for file ops\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <stdlib.h> // for malloc\r
+#include "Common.h"\r
+#include "DSCFile.h"\r
+\r
+#define MAX_INCLUDE_NEST_LEVEL 20\r
+\r
+static\r
+void\r
+DSCFileFree (\r
+ DSC_FILE *DSC\r
+ );\r
+\r
+static\r
+STATUS\r
+DSCParseInclude (\r
+ DSC_FILE *DSC,\r
+ char *FileName,\r
+ int NestLevel\r
+ );\r
+\r
+//\r
+// Constructor for a DSC file\r
+//\r
+int\r
+DSCFileInit (\r
+ DSC_FILE *DSC\r
+ )\r
+{\r
+ memset ((char *) DSC, 0, sizeof (DSC_FILE));\r
+ DSC->SavedPositionIndex = -1;\r
+ return STATUS_SUCCESS;\r
+}\r
+//\r
+// Destructor for a DSC file\r
+//\r
+int\r
+DSCFileDestroy (\r
+ DSC_FILE *DSC\r
+ )\r
+{\r
+ DSC->SavedPositionIndex = -1;\r
+ DSCFileFree (DSC);\r
+ return STATUS_SUCCESS;\r
+}\r
+//\r
+// Get the next line from a DSC file.\r
+//\r
+char *\r
+DSCFileGetLine (\r
+ DSC_FILE *DSC,\r
+ char *Line,\r
+ int LineLen\r
+ )\r
+{\r
+ char *Cptr;\r
+\r
+ if (DSC->CurrentLine == NULL) {\r
+ return NULL;\r
+ }\r
+ //\r
+ // Check for running into next section\r
+ //\r
+ if (DSC->CurrentLine->Line[0] == '[') {\r
+ return NULL;\r
+ }\r
+ //\r
+ // Allow special case where the line starts with backslash-bracket. If we\r
+ // see this, then shift everything left one character.\r
+ //\r
+ if ((DSC->CurrentLine->Line[0] == '\\') && (DSC->CurrentLine->Line[1] == '[')) {\r
+ Cptr = DSC->CurrentLine->Line + 1;\r
+ } else {\r
+ Cptr = DSC->CurrentLine->Line;\r
+ }\r
+\r
+ strncpy (Line, Cptr, LineLen);\r
+ ParserSetPosition (DSC->CurrentLine->FileName, DSC->CurrentLine->LineNum);\r
+ DSC->CurrentLine = DSC->CurrentLine->Next;\r
+ return Line;\r
+}\r
+\r
+int\r
+DSCFileSetFile (\r
+ DSC_FILE *DSC,\r
+ char *FileName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Pre-scan a section file to find all the sections. Then we can speed up\r
+ searching for the different sections.\r
+\r
+Arguments:\r
+\r
+ DSC - pointer to a DSC structure (this pointer)\r
+ FileName - name of the file to process\r
+\r
+Returns:\r
+\r
+ STATUS_SUCCESS if everything went well.\r
+\r
+--*/\r
+{\r
+ STATUS Status;\r
+\r
+ //\r
+ // Called to open a new sectioned file.\r
+ //\r
+ Status = DSCParseInclude (DSC, FileName, 1);\r
+ return Status;\r
+}\r
+\r
+static\r
+STATUS\r
+DSCParseInclude (\r
+ DSC_FILE *DSC,\r
+ char *FileName,\r
+ int NestLevel\r
+ )\r
+{\r
+ SECTION *NewSect;\r
+ SECTION_LINE *NewLine;\r
+ DSC_FILE_NAME *NewDscFileName;\r
+ char Line[MAX_LINE_LEN];\r
+ char *Start;\r
+ char *End;\r
+ char SaveChar;\r
+ char *TempCptr;\r
+ char ShortHandSectionName[MAX_LINE_LEN];\r
+ char ThisSectionName[MAX_LINE_LEN];\r
+ SECTION *CurrSect;\r
+ SECTION *TempSect;\r
+ FILE *FilePtr;\r
+ STATUS Status;\r
+ UINT32 LineNum;\r
+\r
+ //\r
+ // Make sure we haven't exceeded our maximum nesting level\r
+ //\r
+ if (NestLevel > MAX_INCLUDE_NEST_LEVEL) {\r
+ Error (NULL, 0, 0, "application error", "maximum !include nesting level exceeded");\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Try to open the file\r
+ //\r
+ if ((FilePtr = fopen (FileName, "r")) == NULL) {\r
+ //\r
+ // This function is called to handle the DSC file from the command line too,\r
+ // so differentiate whether this file is an include file or the main file\r
+ // by examining the nest level.\r
+ //\r
+ if (NestLevel == 1) {\r
+ Error (NULL, 0, 0, FileName, "could not open DSC file for reading");\r
+ } else {\r
+ Error (NULL, 0, 0, FileName, "could not open !include DSC file for reading");\r
+ }\r
+\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // We keep a linked list of files we parse for error reporting purposes.\r
+ //\r
+ NewDscFileName = malloc (sizeof (DSC_FILE_NAME));\r
+ if (NewDscFileName == NULL) {\r
+ Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ memset (NewDscFileName, 0, sizeof (DSC_FILE_NAME));\r
+ NewDscFileName->FileName = (INT8 *) malloc (strlen (FileName) + 1);\r
+ if (NewDscFileName->FileName == NULL) {\r
+ Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ strcpy (NewDscFileName->FileName, FileName);\r
+ if (DSC->FileName == NULL) {\r
+ DSC->FileName = NewDscFileName;\r
+ } else {\r
+ DSC->LastFileName->Next = NewDscFileName;\r
+ }\r
+\r
+ DSC->LastFileName = NewDscFileName;\r
+ //\r
+ // Read lines and process until done\r
+ //\r
+ Status = STATUS_SUCCESS;\r
+ LineNum = 0;\r
+ for (;;) {\r
+ if (fgets (Line, sizeof (Line), FilePtr) == NULL) {\r
+ break;\r
+ }\r
+\r
+ LineNum++;\r
+ ParserSetPosition (FileName, LineNum);\r
+ //\r
+ // Add the line to our list if it's not a !include line\r
+ //\r
+ if ((strncmp (Line, "!include", 8) == 0) && (isspace (Line[8]))) {\r
+ Start = Line + 9;\r
+ while (*Start && (*Start != '"')) {\r
+ Start++;\r
+ }\r
+\r
+ if (*Start != '"') {\r
+ Error (FileName, LineNum, 0, NULL, "invalid format for !include");\r
+ Status = STATUS_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ Start++;\r
+ for (End = Start; *End && (*End != '"'); End++)\r
+ ;\r
+ if (*End != '"') {\r
+ Error (FileName, LineNum, 0, NULL, "invalid format for !include");\r
+ Status = STATUS_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ *End = 0;\r
+ //\r
+ // Expand symbols. Use 'ThisSectionName' as scratchpad\r
+ //\r
+ ExpandSymbols (Start, ThisSectionName, sizeof (ThisSectionName), EXPANDMODE_NO_UNDEFS);\r
+ Status = DSCParseInclude (DSC, ThisSectionName, NestLevel + 1);\r
+ if (Status != STATUS_SUCCESS) {\r
+ Error (FileName, LineNum, 0, NULL, "failed to parse !include file");\r
+ goto Done;\r
+ }\r
+ } else {\r
+ NewLine = (SECTION_LINE *) malloc (sizeof (SECTION_LINE));\r
+ if (NewLine == NULL) {\r
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");\r
+ Status = STATUS_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ memset ((char *) NewLine, 0, sizeof (SECTION_LINE));\r
+ NewLine->LineNum = LineNum;\r
+ NewLine->FileName = NewDscFileName->FileName;\r
+ NewLine->Line = (char *) malloc (strlen (Line) + 1);\r
+ if (NewLine->Line == NULL) {\r
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");\r
+ Status = STATUS_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ strcpy (NewLine->Line, Line);\r
+ if (DSC->Lines == NULL) {\r
+ DSC->Lines = NewLine;\r
+ } else {\r
+ DSC->LastLine->Next = NewLine;\r
+ }\r
+\r
+ DSC->LastLine = NewLine;\r
+ //\r
+ // Parse the line for []. Ignore [] and [----] delimiters. The\r
+ // line may have multiple definitions separated by commas, so\r
+ // take each separately\r
+ //\r
+ Start = Line;\r
+ if ((Line[0] == '[') && ((Line[1] != ']') && (Line[1] != '-'))) {\r
+ //\r
+ // Skip over open bracket and preceeding spaces\r
+ //\r
+ Start++;\r
+ ShortHandSectionName[0] = 0;\r
+\r
+ while (*Start && (*Start != ']')) {\r
+ while (isspace (*Start)) {\r
+ Start++;\r
+ }\r
+ //\r
+ // Hack off closing bracket or trailing spaces or comma separator.\r
+ // Also allow things like [section.subsection1|subsection2], which\r
+ // is shorthand for [section.subsection1,section.subsection2]\r
+ //\r
+ End = Start;\r
+ while (*End && (*End != ']') && !isspace (*End) && (*End != ',') && (*End != '|')) {\r
+ End++;\r
+ }\r
+ //\r
+ // Save the character and null-terminate the string\r
+ //\r
+ SaveChar = *End;\r
+ *End = 0;\r
+ //\r
+ // Now allocate space for a new section and add it to the linked list.\r
+ // If the previous section ended with the shorthand indicator, then\r
+ // the section name was saved off. Append this section name to it.\r
+ //\r
+ strcpy (ThisSectionName, ShortHandSectionName);\r
+ if (*Start == '.') {\r
+ strcat (ThisSectionName, Start + 1);\r
+ } else {\r
+ strcat (ThisSectionName, Start);\r
+ }\r
+ //\r
+ // Allocate memory for the section. Then clear it out.\r
+ //\r
+ NewSect = (SECTION *) malloc (sizeof (SECTION));\r
+ if (NewSect == NULL) {\r
+ Error (NULL, 0, 0, NULL, "failed to allocation memory for sections");\r
+ Status = STATUS_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ memset ((char *) NewSect, 0, sizeof (SECTION));\r
+ NewSect->FirstLine = NewLine;\r
+ NewSect->Name = (char *) malloc (strlen (ThisSectionName) + 1);\r
+ if (NewSect->Name == NULL) {\r
+ Error (NULL, 0, 0, NULL, "failed to allocation memory for sections");\r
+ Status = STATUS_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ strcpy (NewSect->Name, ThisSectionName);\r
+ if (DSC->Sections == NULL) {\r
+ DSC->Sections = NewSect;\r
+ } else {\r
+ DSC->LastSection->Next = NewSect;\r
+ }\r
+\r
+ DSC->LastSection = NewSect;\r
+ *End = SaveChar;\r
+ //\r
+ // If the name ended in a shorthand indicator, then save the\r
+ // section name and truncate it at the last dot.\r
+ //\r
+ if (SaveChar == '|') {\r
+ strcpy (ShortHandSectionName, ThisSectionName);\r
+ for (TempCptr = ShortHandSectionName + strlen (ShortHandSectionName) - 1;\r
+ (TempCptr != ShortHandSectionName) && (*TempCptr != '.');\r
+ TempCptr--\r
+ )\r
+ ;\r
+ //\r
+ // If we didn't find a dot, then hopefully they have [name1|name2]\r
+ // instead of [name1,name2].\r
+ //\r
+ if (TempCptr == ShortHandSectionName) {\r
+ ShortHandSectionName[0] = 0;\r
+ } else {\r
+ //\r
+ // Truncate after the dot\r
+ //\r
+ *(TempCptr + 1) = 0;\r
+ }\r
+ } else {\r
+ //\r
+ // Kill the shorthand string\r
+ //\r
+ ShortHandSectionName[0] = 0;\r
+ }\r
+ //\r
+ // Skip to next section name or closing bracket\r
+ //\r
+ while (*End && ((*End == ',') || isspace (*End) || (*End == '|'))) {\r
+ End++;\r
+ }\r
+\r
+ Start = End;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Look through all the sections to make sure we don't have any duplicates.\r
+ // Allow [----] and [====] section separators\r
+ //\r
+ CurrSect = DSC->Sections;\r
+ while (CurrSect != NULL) {\r
+ TempSect = CurrSect->Next;\r
+ while (TempSect != NULL) {\r
+ if (isalpha (CurrSect->Name[0]) && (_stricmp (CurrSect->Name, TempSect->Name) == 0)) {\r
+ Error (\r
+ TempSect->FirstLine->FileName,\r
+ TempSect->FirstLine->LineNum,\r
+ 0,\r
+ TempSect->Name,\r
+ "duplicate section found"\r
+ );\r
+ Error (\r
+ CurrSect->FirstLine->FileName,\r
+ CurrSect->FirstLine->LineNum,\r
+ 0,\r
+ TempSect->Name,\r
+ "first definition of duplicate section"\r
+ );\r
+ Status = STATUS_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ TempSect = TempSect->Next;\r
+ }\r
+\r
+ CurrSect = CurrSect->Next;\r
+ }\r
+\r
+Done:\r
+ fclose (FilePtr);\r
+ return Status;\r
+}\r
+//\r
+// Free up memory allocated for DSC file handling.\r
+//\r
+static\r
+void\r
+DSCFileFree (\r
+ DSC_FILE *DSC\r
+ )\r
+{\r
+ SECTION *NextSection;\r
+ SECTION_LINE *NextLine;\r
+ DSC_FILE_NAME *NextName;\r
+\r
+ while (DSC->Sections != NULL) {\r
+ NextSection = DSC->Sections->Next;\r
+ if (DSC->Sections->Name != NULL) {\r
+ free (DSC->Sections->Name);\r
+ }\r
+\r
+ free (DSC->Sections);\r
+ DSC->Sections = NextSection;\r
+ }\r
+\r
+ while (DSC->Lines != NULL) {\r
+ NextLine = DSC->Lines->Next;\r
+ free (DSC->Lines->Line);\r
+ free (DSC->Lines);\r
+ DSC->Lines = NextLine;\r
+ }\r
+\r
+ while (DSC->FileName != NULL) {\r
+ NextName = DSC->FileName->Next;\r
+ free (DSC->FileName->FileName);\r
+ free (DSC->FileName);\r
+ DSC->FileName = NextName;\r
+ }\r
+}\r
+\r
+SECTION *\r
+DSCFileFindSection (\r
+ DSC_FILE *DSC,\r
+ char *Name\r
+ )\r
+{\r
+ SECTION *Sect;\r
+\r
+ //\r
+ // Look through all the sections to find one with this name (case insensitive)\r
+ //\r
+ Sect = DSC->Sections;\r
+ while (Sect != NULL) {\r
+ if (_stricmp (Name, Sect->Name) == 0) {\r
+ //\r
+ // Position within file\r
+ //\r
+ DSC->CurrentLine = Sect->FirstLine->Next;\r
+ return Sect;\r
+ }\r
+\r
+ Sect = Sect->Next;\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+int\r
+DSCFileSavePosition (\r
+ DSC_FILE *DSC\r
+ )\r
+{\r
+ //\r
+ // Advance to next slot\r
+ //\r
+ DSC->SavedPositionIndex++;\r
+ if (DSC->SavedPositionIndex >= MAX_SAVES) {\r
+ DSC->SavedPositionIndex--;\r
+ Error (NULL, 0, 0, "APP ERROR", "max nesting of saved section file positions exceeded");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ DSC->SavedPosition[DSC->SavedPositionIndex] = DSC->CurrentLine;\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+int\r
+DSCFileRestorePosition (\r
+ DSC_FILE *DSC\r
+ )\r
+{\r
+ if (DSC->SavedPositionIndex < 0) {\r
+ Error (NULL, 0, 0, "APP ERROR", "underflow of saved positions in section file");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ DSC->CurrentLine = DSC->SavedPosition[DSC->SavedPositionIndex];\r
+ DSC->SavedPositionIndex--;\r
+ return STATUS_SUCCESS;\r
+}\r