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