mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1973 lines
37 KiB
1973 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
parseini.c
|
|
|
|
Abstract:
|
|
|
|
This module implements functions to parse a .INI file
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 7-Oct-1993
|
|
|
|
Revision History:
|
|
|
|
John Vert (jvert) 7-Oct-1993 - largely lifted from splib\spinf.c
|
|
|
|
--*/
|
|
|
|
#include "setupldr.h"
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
|
|
#define SpFree(x)
|
|
|
|
// what follows was alpar.h
|
|
|
|
//
|
|
// EXPORTED BY THE PARSER AND USED BY BOTH THE PARSER AND
|
|
// THE INF HANDLING COMPONENTS
|
|
//
|
|
|
|
// typedefs exported
|
|
//
|
|
|
|
typedef struct _value {
|
|
struct _value *pNext;
|
|
PCHAR pName;
|
|
} VALUE, *PVALUE;
|
|
|
|
typedef struct _line {
|
|
struct _line *pNext;
|
|
PCHAR pName;
|
|
PVALUE pValue;
|
|
} LINE, *PLINE;
|
|
|
|
typedef struct _section {
|
|
struct _section *pNext;
|
|
PCHAR pName;
|
|
PLINE pLine;
|
|
} SECTION, *PSECTION;
|
|
|
|
typedef struct _inf {
|
|
PSECTION pSection;
|
|
} INF, *PINF;
|
|
|
|
//
|
|
// Routines exported
|
|
//
|
|
|
|
PVOID
|
|
ParseInfBuffer(
|
|
PCHAR Buffer,
|
|
ULONG Size,
|
|
PULONG ErrorLine
|
|
);
|
|
|
|
//
|
|
// DEFINES USED FOR THE PARSER INTERNALLY
|
|
//
|
|
//
|
|
// typedefs used
|
|
//
|
|
|
|
typedef enum _tokentype {
|
|
TOK_EOF,
|
|
TOK_EOL,
|
|
TOK_LBRACE,
|
|
TOK_RBRACE,
|
|
TOK_STRING,
|
|
TOK_EQUAL,
|
|
TOK_COMMA,
|
|
TOK_ERRPARSE,
|
|
TOK_ERRNOMEM
|
|
} TOKENTYPE, *PTOKENTTYPE;
|
|
|
|
|
|
typedef struct _token {
|
|
TOKENTYPE Type;
|
|
PCHAR pValue;
|
|
} TOKEN, *PTOKEN;
|
|
|
|
|
|
//
|
|
// Routine defines
|
|
//
|
|
|
|
ARC_STATUS
|
|
SpAppendSection(
|
|
IN PCHAR pSectionName
|
|
);
|
|
|
|
ARC_STATUS
|
|
SpAppendLine(
|
|
IN PCHAR pLineKey
|
|
);
|
|
|
|
ARC_STATUS
|
|
SpAppendValue(
|
|
IN PCHAR pValueString
|
|
);
|
|
|
|
TOKEN
|
|
SpGetToken(
|
|
IN OUT PCHAR *Stream,
|
|
IN PCHAR MaxStream
|
|
);
|
|
|
|
// Global added to provide INF filename for friendly error messages.
|
|
PCHAR pchINFName = NULL;
|
|
|
|
// what follows was alinf.c
|
|
|
|
//
|
|
// Internal Routine Declarations for freeing inf structure members
|
|
//
|
|
|
|
VOID
|
|
FreeSectionList (
|
|
IN PSECTION pSection
|
|
);
|
|
|
|
VOID
|
|
FreeLineList (
|
|
IN PLINE pLine
|
|
);
|
|
|
|
VOID
|
|
FreeValueList (
|
|
IN PVALUE pValue
|
|
);
|
|
|
|
|
|
//
|
|
// Internal Routine declarations for searching in the INF structures
|
|
//
|
|
|
|
|
|
PVALUE
|
|
SearchValueInLine(
|
|
IN PLINE pLine,
|
|
IN ULONG ValueIndex
|
|
);
|
|
|
|
PLINE
|
|
SearchLineInSectionByKey(
|
|
IN PSECTION pSection,
|
|
IN PCHAR Key,
|
|
OUT PULONG pOrdinal OPTIONAL
|
|
);
|
|
|
|
PLINE
|
|
SearchLineInSectionByIndex(
|
|
IN PSECTION pSection,
|
|
IN ULONG LineIndex
|
|
);
|
|
|
|
PSECTION
|
|
SearchSectionByName(
|
|
IN PINF pINF,
|
|
IN PCHAR SectionName
|
|
);
|
|
|
|
PCHAR
|
|
ProcessForStringSubs(
|
|
IN PINF pInf,
|
|
IN PCHAR String
|
|
);
|
|
|
|
|
|
//
|
|
// ROUTINE DEFINITIONS
|
|
//
|
|
|
|
|
|
PCHAR
|
|
SlGetIniValue(
|
|
IN PVOID InfHandle,
|
|
IN PCHAR SectionName,
|
|
IN PCHAR KeyName,
|
|
IN PCHAR Default
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches an INF handle for a given section/key value.
|
|
|
|
Arguments:
|
|
|
|
InfHandle - Supplies a handle returned by SlInitIniFile.
|
|
|
|
SectionName - Supplies the name of the section to search
|
|
|
|
KeyName - Supplies the name of the key whose value should be returned.
|
|
|
|
Default - Supplies the default setting, returned if the specified key
|
|
is not found.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the value of the key, if the key is found
|
|
|
|
Default, if the key is not found.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR Value;
|
|
|
|
Value = SlGetSectionKeyIndex(InfHandle,
|
|
SectionName,
|
|
KeyName,
|
|
0);
|
|
if (Value==NULL) {
|
|
Value = Default;
|
|
}
|
|
|
|
return(Value);
|
|
|
|
}
|
|
|
|
//
|
|
// returns a handle to use for further inf parsing
|
|
//
|
|
|
|
ARC_STATUS
|
|
SlInitIniFile(
|
|
IN PCHAR DevicePath,
|
|
IN ULONG DeviceId,
|
|
IN PCHAR INFFile,
|
|
OUT PVOID *pINFHandle,
|
|
OUT PULONG ErrorLine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ARC_STATUS Status;
|
|
ULONG DeviceID,FileID;
|
|
PCHAR Buffer;
|
|
ULONG Size, SizeRead;
|
|
FILE_INFORMATION FileInfo;
|
|
ULONG PageCount;
|
|
ULONG ActualBase;
|
|
|
|
*ErrorLine = (ULONG)(-1);
|
|
|
|
//
|
|
// If required, open the device
|
|
//
|
|
|
|
if(DevicePath) {
|
|
Status = ArcOpen(DevicePath,ArcOpenReadOnly,&DeviceID);
|
|
if (Status != ESUCCESS) {
|
|
return( Status );
|
|
}
|
|
} else {
|
|
DeviceID = DeviceId;
|
|
}
|
|
|
|
//
|
|
// Open the file
|
|
//
|
|
|
|
Status = BlOpen(DeviceID,INFFile,ArcOpenReadOnly,&FileID);
|
|
if (Status != ESUCCESS) {
|
|
// We report better error messages elsewhere
|
|
// SlMessageBox(SL_FILE_LOAD_FAILED,INFFile,Status);
|
|
pchINFName = NULL;
|
|
goto xx0;
|
|
} else {
|
|
pchINFName = INFFile;
|
|
}
|
|
|
|
//
|
|
// find out size of INF file
|
|
//
|
|
|
|
Status = BlGetFileInformation(FileID, &FileInfo);
|
|
if (Status != ESUCCESS) {
|
|
BlClose(FileID);
|
|
goto xx0;
|
|
}
|
|
Size = FileInfo.EndingAddress.LowPart;
|
|
|
|
//
|
|
// allocate a descriptor large enough to hold the entire file.
|
|
// On x86 this has an unfortunate tendency to slam txtsetup.sif
|
|
// into a free block at 1MB, which means the kernel can't be
|
|
// loaded (it's linked for 0x100000 without relocations).
|
|
//
|
|
#ifdef _X86_
|
|
{
|
|
extern ALLOCATION_POLICY BlMemoryAllocationPolicy;
|
|
ALLOCATION_POLICY policy;
|
|
|
|
policy = BlMemoryAllocationPolicy;
|
|
BlMemoryAllocationPolicy = BlAllocateHighestFit;
|
|
#endif
|
|
|
|
PageCount = ROUND_TO_PAGES(Size) >> PAGE_SHIFT;
|
|
|
|
Status = BlAllocateDescriptor(LoaderOsloaderHeap,
|
|
0,
|
|
PageCount,
|
|
&ActualBase);
|
|
#ifdef _X86_
|
|
BlMemoryAllocationPolicy = policy;
|
|
}
|
|
#endif
|
|
|
|
if (Status != ESUCCESS) {
|
|
BlClose(FileID);
|
|
goto xx0;
|
|
}
|
|
|
|
Buffer = (PCHAR)(KSEG0_BASE | (ActualBase << PAGE_SHIFT));
|
|
|
|
//
|
|
// read the file in
|
|
//
|
|
|
|
Status = BlRead(FileID, Buffer, Size, &SizeRead);
|
|
if (Status != ESUCCESS) {
|
|
BlClose(FileID);
|
|
SpFree(Buffer);
|
|
goto xx0;
|
|
}
|
|
|
|
if (BlLoaderBlock->SetupLoaderBlock->IniFile == NULL) {
|
|
BlLoaderBlock->SetupLoaderBlock->IniFile = Buffer;
|
|
BlLoaderBlock->SetupLoaderBlock->IniFileLength = Size;
|
|
}
|
|
|
|
//
|
|
// parse the file
|
|
//
|
|
if((*pINFHandle = ParseInfBuffer(Buffer, SizeRead, ErrorLine)) == (PVOID)NULL) {
|
|
Status = EBADF;
|
|
} else {
|
|
Status = ESUCCESS;
|
|
}
|
|
|
|
//
|
|
// Clean up and return
|
|
//
|
|
SpFree(Buffer);
|
|
BlClose(FileID);
|
|
|
|
#if 0
|
|
if((Status == ESUCCESS)
|
|
&& SlGetSectionKeyIndex(*pINFHandle,"debug","DumpInf",0)
|
|
&& atoi(SlGetSectionKeyIndex(*pINFHandle,"debug","DumpInf",0)))
|
|
{
|
|
PINF pInf = *pINFHandle;
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
PVALUE pValue;
|
|
|
|
for(pSection = pInf->pSection; pSection; pSection = pSection->pNext) {
|
|
|
|
SpxClearClientArea();
|
|
SpxPositionCursor(0,4);
|
|
|
|
SpMsg(FALSE,"Section: [%s]\r\n",pSection->pName);
|
|
|
|
for(pLine = pSection->pLine; pLine; pLine = pLine->pNext) {
|
|
|
|
SpMsg(FALSE," [%s] = ",pLine->pName ? pLine->pName : "(none)");
|
|
|
|
for(pValue = pLine->pValue; pValue; pValue = pValue->pNext) {
|
|
|
|
SpMsg(FALSE,"[%s]",pValue->pName);
|
|
}
|
|
SpMsg(FALSE,"\r\n");
|
|
}
|
|
SpMsg(TRUE,"");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
xx0:
|
|
|
|
if(DevicePath) {
|
|
ArcClose(DeviceID);
|
|
}
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
//
|
|
// frees an INF Buffer
|
|
//
|
|
ARC_STATUS
|
|
SpFreeINFBuffer (
|
|
IN PVOID INFHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PINF pINF;
|
|
|
|
//
|
|
// Valid INF Handle?
|
|
//
|
|
|
|
if (INFHandle == (PVOID)NULL) {
|
|
return ESUCCESS;
|
|
}
|
|
|
|
//
|
|
// cast the buffer into an INF structure
|
|
//
|
|
|
|
pINF = (PINF)INFHandle;
|
|
|
|
FreeSectionList(pINF->pSection);
|
|
|
|
//
|
|
// free the inf structure too
|
|
//
|
|
|
|
SpFree(pINF);
|
|
|
|
return( ESUCCESS );
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeSectionList (
|
|
IN PSECTION pSection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECTION Next;
|
|
|
|
while(pSection) {
|
|
Next = pSection->pNext;
|
|
FreeLineList(pSection->pLine);
|
|
if(pSection->pName) {
|
|
SpFree(pSection->pName);
|
|
}
|
|
SpFree(pSection);
|
|
pSection = Next;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeLineList (
|
|
IN PLINE pLine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PLINE Next;
|
|
|
|
while(pLine) {
|
|
Next = pLine->pNext;
|
|
FreeValueList(pLine->pValue);
|
|
if(pLine->pName) {
|
|
SpFree(pLine->pName);
|
|
}
|
|
SpFree(pLine);
|
|
pLine = Next;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FreeValueList (
|
|
IN PVALUE pValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PVALUE Next;
|
|
|
|
while(pValue) {
|
|
Next = pValue->pNext;
|
|
if(pValue->pName) {
|
|
SpFree(pValue->pName);
|
|
}
|
|
SpFree(pValue);
|
|
pValue = Next;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// searches for the existance of a particular section
|
|
//
|
|
BOOLEAN
|
|
SpSearchINFSection (
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECTION pSection;
|
|
|
|
//
|
|
// if search for section fails return false
|
|
//
|
|
|
|
if ((pSection = SearchSectionByName(
|
|
(PINF)INFHandle,
|
|
SectionName
|
|
)) == (PSECTION)NULL) {
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// else return true
|
|
//
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// given section name, line number and index return the value.
|
|
//
|
|
PCHAR
|
|
SlGetSectionLineIndex (
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName,
|
|
IN ULONG LineIndex,
|
|
IN ULONG ValueIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
PVALUE pValue;
|
|
|
|
if((pSection = SearchSectionByName(
|
|
(PINF)INFHandle,
|
|
SectionName
|
|
))
|
|
== (PSECTION)NULL)
|
|
return((PCHAR)NULL);
|
|
|
|
if((pLine = SearchLineInSectionByIndex(
|
|
pSection,
|
|
LineIndex
|
|
))
|
|
== (PLINE)NULL)
|
|
return((PCHAR)NULL);
|
|
|
|
if((pValue = SearchValueInLine(
|
|
pLine,
|
|
ValueIndex
|
|
))
|
|
== (PVALUE)NULL)
|
|
return((PCHAR)NULL);
|
|
|
|
return(ProcessForStringSubs(INFHandle,pValue->pName));
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpGetSectionKeyExists (
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName,
|
|
IN PCHAR Key
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECTION pSection;
|
|
|
|
if((pSection = SearchSectionByName(
|
|
(PINF)INFHandle,
|
|
SectionName
|
|
))
|
|
== (PSECTION)NULL) {
|
|
return( FALSE );
|
|
}
|
|
|
|
if (SearchLineInSectionByKey(pSection, Key, NULL) == (PLINE)NULL) {
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
PCHAR
|
|
SlGetKeyName(
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName,
|
|
IN ULONG LineIndex
|
|
)
|
|
{
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
|
|
pSection = SearchSectionByName((PINF)INFHandle,SectionName);
|
|
if(pSection == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
pLine = SearchLineInSectionByIndex(pSection,LineIndex);
|
|
if(pLine == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
return(pLine->pName);
|
|
}
|
|
|
|
|
|
//
|
|
// given section name and key, return (0-based) ordinal for this entry
|
|
// (returns -1 on error)
|
|
//
|
|
ULONG
|
|
SlGetSectionKeyOrdinal(
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName,
|
|
IN PCHAR Key
|
|
)
|
|
{
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
ULONG Ordinal;
|
|
|
|
|
|
pSection = SearchSectionByName(
|
|
(PINF)INFHandle,
|
|
SectionName
|
|
);
|
|
|
|
pLine = SearchLineInSectionByKey(
|
|
pSection,
|
|
Key,
|
|
&Ordinal
|
|
);
|
|
|
|
if(pLine == (PLINE)NULL) {
|
|
return (ULONG)-1;
|
|
} else {
|
|
return Ordinal;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// given section name, key and index return the value
|
|
//
|
|
PCHAR
|
|
SlGetSectionKeyIndex (
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName,
|
|
IN PCHAR Key,
|
|
IN ULONG ValueIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
PVALUE pValue;
|
|
|
|
if((pSection = SearchSectionByName(
|
|
(PINF)INFHandle,
|
|
SectionName
|
|
))
|
|
== (PSECTION)NULL)
|
|
return((PCHAR)NULL);
|
|
|
|
if((pLine = SearchLineInSectionByKey(
|
|
pSection,
|
|
Key,
|
|
NULL
|
|
))
|
|
== (PLINE)NULL)
|
|
return((PCHAR)NULL);
|
|
|
|
if((pValue = SearchValueInLine(
|
|
pLine,
|
|
ValueIndex
|
|
))
|
|
== (PVALUE)NULL)
|
|
return((PCHAR)NULL);
|
|
|
|
return(ProcessForStringSubs(INFHandle,pValue->pName));
|
|
}
|
|
|
|
|
|
ULONG
|
|
SlCountLinesInSection(
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName
|
|
)
|
|
{
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
ULONG Count;
|
|
|
|
if((pSection = SearchSectionByName((PINF)INFHandle,SectionName)) == NULL) {
|
|
return((ULONG)(-1));
|
|
}
|
|
|
|
for(pLine = pSection->pLine, Count = 0;
|
|
pLine;
|
|
pLine = pLine->pNext, Count++
|
|
);
|
|
|
|
return(Count);
|
|
}
|
|
|
|
|
|
PVALUE
|
|
SearchValueInLine(
|
|
IN PLINE pLine,
|
|
IN ULONG ValueIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PVALUE pValue;
|
|
ULONG i;
|
|
|
|
if (pLine == (PLINE)NULL)
|
|
return ((PVALUE)NULL);
|
|
|
|
pValue = pLine->pValue;
|
|
for (i = 0; i < ValueIndex && ((pValue = pValue->pNext) != (PVALUE)NULL); i++)
|
|
;
|
|
|
|
return pValue;
|
|
|
|
}
|
|
|
|
PLINE
|
|
SearchLineInSectionByKey(
|
|
IN PSECTION pSection,
|
|
IN PCHAR Key,
|
|
OUT PULONG pOrdinal OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PLINE pLine;
|
|
ULONG LineOrdinal;
|
|
|
|
if (pSection == (PSECTION)NULL || Key == (PCHAR)NULL) {
|
|
return ((PLINE)NULL);
|
|
}
|
|
|
|
pLine = pSection->pLine;
|
|
LineOrdinal = 0;
|
|
while ((pLine != (PLINE)NULL) && (pLine->pName == NULL || _strcmpi(pLine->pName, Key))) {
|
|
pLine = pLine->pNext;
|
|
LineOrdinal++;
|
|
}
|
|
|
|
if(pLine && pOrdinal) {
|
|
*pOrdinal = LineOrdinal;
|
|
}
|
|
|
|
return pLine;
|
|
|
|
}
|
|
|
|
|
|
PLINE
|
|
SearchLineInSectionByIndex(
|
|
IN PSECTION pSection,
|
|
IN ULONG LineIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PLINE pLine;
|
|
ULONG i;
|
|
|
|
//
|
|
// Validate the parameters passed in
|
|
//
|
|
|
|
if (pSection == (PSECTION)NULL) {
|
|
return ((PLINE)NULL);
|
|
}
|
|
|
|
//
|
|
// find the start of the line list in the section passed in
|
|
//
|
|
|
|
pLine = pSection->pLine;
|
|
|
|
//
|
|
// traverse down the current line list to the LineIndex th line
|
|
//
|
|
|
|
for (i = 0; i < LineIndex && ((pLine = pLine->pNext) != (PLINE)NULL); i++) {
|
|
;
|
|
}
|
|
|
|
//
|
|
// return the Line found
|
|
//
|
|
|
|
return pLine;
|
|
|
|
}
|
|
|
|
|
|
PSECTION
|
|
SearchSectionByName(
|
|
IN PINF pINF,
|
|
IN PCHAR SectionName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECTION pSection;
|
|
|
|
//
|
|
// validate the parameters passed in
|
|
//
|
|
|
|
if (pINF == (PINF)NULL || SectionName == (PCHAR)NULL) {
|
|
return ((PSECTION)NULL);
|
|
}
|
|
|
|
//
|
|
// find the section list
|
|
//
|
|
pSection = pINF->pSection;
|
|
|
|
//
|
|
// traverse down the section list searching each section for the section
|
|
// name mentioned
|
|
//
|
|
|
|
while ((pSection != (PSECTION)NULL) && _strcmpi(pSection->pName, SectionName)) {
|
|
pSection = pSection->pNext;
|
|
}
|
|
|
|
//
|
|
// return the section at which we stopped (either NULL or the section
|
|
// which was found
|
|
//
|
|
|
|
return pSection;
|
|
|
|
}
|
|
|
|
|
|
PCHAR
|
|
ProcessForStringSubs(
|
|
IN PINF pInf,
|
|
IN PCHAR String
|
|
)
|
|
{
|
|
unsigned Len;
|
|
PCHAR ReturnString;
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
|
|
//
|
|
// Assume no substitution necessary.
|
|
//
|
|
ReturnString = String;
|
|
|
|
//
|
|
// If it starts and ends with % then look it up in the
|
|
// strings section. Note the initial check before doing a
|
|
// strlen, to preserve performance in the 99% case where
|
|
// there is no substitution.
|
|
//
|
|
if((String[0] == '%') && ((Len = strlen(String)) > 2) && (String[Len-1] == '%')) {
|
|
|
|
for(pSection = pInf->pSection; pSection; pSection=pSection->pNext) {
|
|
if(pSection->pName && !_stricmp(pSection->pName,"Strings")) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(pSection) {
|
|
|
|
for(pLine = pSection->pLine; pLine; pLine=pLine->pNext) {
|
|
if(pLine->pName
|
|
&& !_strnicmp(pLine->pName,String+1,Len-2)
|
|
&& (pLine->pName[Len-2] == 0))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(pLine && pLine->pValue && pLine->pValue->pName) {
|
|
ReturnString = pLine->pValue->pName;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(ReturnString);
|
|
}
|
|
|
|
|
|
|
|
// what follows was alparse.c
|
|
|
|
|
|
//
|
|
// Globals used to make building the lists easier
|
|
//
|
|
|
|
PINF pINF;
|
|
PSECTION pSectionRecord;
|
|
PLINE pLineRecord;
|
|
PVALUE pValueRecord;
|
|
|
|
|
|
//
|
|
// Globals used by the token parser
|
|
//
|
|
|
|
// string terminators are the whitespace characters (isspace: space, tab,
|
|
// linefeed, formfeed, vertical tab, carriage return) or the chars given below
|
|
|
|
CHAR StringTerminators[] = "[]=,\t \"\n\f\v\r";
|
|
|
|
PCHAR QStringTerminators = StringTerminators+6;
|
|
|
|
|
|
//
|
|
// Main parser routine
|
|
//
|
|
|
|
PVOID
|
|
ParseInfBuffer(
|
|
PCHAR Buffer,
|
|
ULONG Size,
|
|
PULONG ErrorLine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a character buffer containing the INF file, this routine parses
|
|
the INF into an internal form with Section records, Line records and
|
|
Value records.
|
|
|
|
Arguments:
|
|
|
|
Buffer - contains to ptr to a buffer containing the INF file
|
|
|
|
Size - contains the size of the buffer.
|
|
|
|
ErrorLine - if a parse error occurs, this variable receives the line
|
|
number of the line containing the error.
|
|
|
|
|
|
Return Value:
|
|
|
|
PVOID - INF handle ptr to be used in subsequent INF calls.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR Stream, MaxStream, pchSectionName = NULL, pchValue = NULL;
|
|
ULONG State, InfLine;
|
|
TOKEN Token;
|
|
BOOLEAN Done;
|
|
BOOLEAN Error;
|
|
ARC_STATUS ErrorCode;
|
|
|
|
//
|
|
// Initialise the globals
|
|
//
|
|
pINF = (PINF)NULL;
|
|
pSectionRecord = (PSECTION)NULL;
|
|
pLineRecord = (PLINE)NULL;
|
|
pValueRecord = (PVALUE)NULL;
|
|
|
|
//
|
|
// Get INF record
|
|
//
|
|
if ((pINF = (PINF)BlAllocateHeap(sizeof(INF))) == NULL) {
|
|
SlNoMemoryError();
|
|
return NULL;
|
|
}
|
|
pINF->pSection = NULL;
|
|
|
|
//
|
|
// Set initial state
|
|
//
|
|
State = 1;
|
|
InfLine = 1;
|
|
Stream = Buffer;
|
|
MaxStream = Buffer + Size;
|
|
Done = FALSE;
|
|
Error = FALSE;
|
|
|
|
//
|
|
// Enter token processing loop
|
|
//
|
|
|
|
while (!Done) {
|
|
|
|
Token = SpGetToken(&Stream, MaxStream);
|
|
|
|
switch (State) {
|
|
//
|
|
// STATE1: Start of file, this state remains till first
|
|
// section is found
|
|
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_LBRACE
|
|
case 1:
|
|
switch (Token.Type) {
|
|
case TOK_EOL:
|
|
break;
|
|
case TOK_EOF:
|
|
Done = TRUE;
|
|
break;
|
|
case TOK_LBRACE:
|
|
State = 2;
|
|
break;
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// STATE 2: Section LBRACE has been received, expecting STRING
|
|
//
|
|
// Valid Tokens: TOK_STRING
|
|
//
|
|
case 2:
|
|
switch (Token.Type) {
|
|
case TOK_STRING:
|
|
State = 3;
|
|
pchSectionName = Token.pValue;
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
//
|
|
// STATE 3: Section Name received, expecting RBRACE
|
|
//
|
|
// Valid Tokens: TOK_RBRACE
|
|
//
|
|
case 3:
|
|
switch (Token.Type) {
|
|
case TOK_RBRACE:
|
|
State = 4;
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
//
|
|
// STATE 4: Section Definition Complete, expecting EOL
|
|
//
|
|
// Valid Tokens: TOK_EOL, TOK_EOF
|
|
//
|
|
case 4:
|
|
switch (Token.Type) {
|
|
case TOK_EOL:
|
|
if ((ErrorCode = SpAppendSection(pchSectionName)) != ESUCCESS) {
|
|
|
|
Error = Done = TRUE;
|
|
} else {
|
|
pchSectionName = NULL;
|
|
State = 5;
|
|
}
|
|
break;
|
|
|
|
case TOK_EOF:
|
|
if ((ErrorCode = SpAppendSection(pchSectionName)) != ESUCCESS)
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchSectionName = NULL;
|
|
Done = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// STATE 5: Expecting Section Lines
|
|
//
|
|
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_STRING, TOK_LBRACE
|
|
//
|
|
case 5:
|
|
switch (Token.Type) {
|
|
case TOK_EOL:
|
|
break;
|
|
case TOK_EOF:
|
|
Done = TRUE;
|
|
break;
|
|
case TOK_STRING:
|
|
pchValue = Token.pValue;
|
|
State = 6;
|
|
break;
|
|
case TOK_LBRACE:
|
|
State = 2;
|
|
break;
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE, InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// STATE 6: String returned, not sure whether it is key or value
|
|
//
|
|
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA, TOK_EQUAL
|
|
//
|
|
case 6:
|
|
switch (Token.Type) {
|
|
case TOK_EOL:
|
|
if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
|
|
(ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchValue = NULL;
|
|
State = 5;
|
|
}
|
|
break;
|
|
|
|
case TOK_EOF:
|
|
if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
|
|
(ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchValue = NULL;
|
|
Done = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TOK_COMMA:
|
|
if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
|
|
(ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchValue = NULL;
|
|
State = 7;
|
|
}
|
|
break;
|
|
|
|
case TOK_EQUAL:
|
|
if ( (ErrorCode = SpAppendLine(pchValue)) !=ESUCCESS)
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchValue = NULL;
|
|
State = 8;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// STATE 7: Comma received, Expecting another string
|
|
//
|
|
// Valid Tokens: TOK_STRING TOK_COMMA
|
|
// A comma means we have an empty value.
|
|
//
|
|
case 7:
|
|
switch (Token.Type) {
|
|
case TOK_COMMA:
|
|
Token.pValue = BlAllocateHeap(1);
|
|
if(Token.pValue == NULL) {
|
|
Error = Done = TRUE;
|
|
ErrorCode = ENOMEM;
|
|
break;
|
|
}
|
|
Token.pValue[0] = 0;
|
|
if ((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS) {
|
|
Error = Done = TRUE;
|
|
}
|
|
//
|
|
// State stays at 7 because we are expecting a string
|
|
//
|
|
break;
|
|
|
|
case TOK_STRING:
|
|
if ((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS)
|
|
Error = Done = TRUE;
|
|
else
|
|
State = 9;
|
|
|
|
break;
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
//
|
|
// STATE 8: Equal received, Expecting another string
|
|
// If none, assume there is a single empty string on the RHS
|
|
//
|
|
// Valid Tokens: TOK_STRING, TOK_EOL, TOK_EOF
|
|
//
|
|
case 8:
|
|
switch (Token.Type) {
|
|
case TOK_EOF:
|
|
Token.pValue = BlAllocateHeap(1);
|
|
if(Token.pValue == NULL) {
|
|
Error = Done = TRUE;
|
|
ErrorCode = ENOMEM;
|
|
break;
|
|
}
|
|
Token.pValue[0] = 0;
|
|
if((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS) {
|
|
Error = TRUE;
|
|
}
|
|
Done = TRUE;
|
|
break;
|
|
|
|
case TOK_EOL:
|
|
Token.pValue = BlAllocateHeap(1);
|
|
if(Token.pValue == NULL) {
|
|
Error = Done = TRUE;
|
|
ErrorCode = ENOMEM;
|
|
break;
|
|
}
|
|
Token.pValue[0] = 0;
|
|
if((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS) {
|
|
Error = TRUE;
|
|
Done = TRUE;
|
|
} else {
|
|
State = 5;
|
|
}
|
|
break;
|
|
|
|
case TOK_STRING:
|
|
if ((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS)
|
|
Error = Done = TRUE;
|
|
else
|
|
State = 9;
|
|
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
//
|
|
// STATE 9: String received after equal, value string
|
|
//
|
|
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
|
|
//
|
|
case 9:
|
|
switch (Token.Type) {
|
|
case TOK_EOL:
|
|
State = 5;
|
|
break;
|
|
|
|
case TOK_EOF:
|
|
Done = TRUE;
|
|
break;
|
|
|
|
case TOK_COMMA:
|
|
State = 7;
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
//
|
|
// STATE 10: Value string definitely received
|
|
//
|
|
// Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
|
|
//
|
|
case 10:
|
|
switch (Token.Type) {
|
|
case TOK_EOL:
|
|
State =5;
|
|
break;
|
|
|
|
case TOK_EOF:
|
|
Done = TRUE;
|
|
break;
|
|
|
|
case TOK_COMMA:
|
|
State = 7;
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
break;
|
|
|
|
} // end switch(State)
|
|
|
|
|
|
if (Error) {
|
|
|
|
switch (ErrorCode) {
|
|
case EINVAL:
|
|
*ErrorLine = InfLine;
|
|
break;
|
|
case ENOMEM:
|
|
SlFatalError(SL_BAD_INF_LINE,InfLine);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ErrorCode = SpFreeINFBuffer((PVOID)pINF);
|
|
if (pchSectionName != (PCHAR)NULL) {
|
|
SpFree(pchSectionName);
|
|
}
|
|
|
|
if (pchValue != (PCHAR)NULL) {
|
|
SpFree(pchValue);
|
|
}
|
|
|
|
pINF = (PINF)NULL;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Keep track of line numbers so that we can display Errors
|
|
//
|
|
|
|
if (Token.Type == TOK_EOL)
|
|
InfLine++;
|
|
}
|
|
|
|
} // End while
|
|
|
|
return((PVOID)pINF);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
SpAppendSection(
|
|
IN PCHAR pSectionName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This appends a new section to the section list in the current INF.
|
|
All further lines and values pertain to this new section, so it resets
|
|
the line list and value lists too.
|
|
|
|
Arguments:
|
|
|
|
pSectionName - Name of the new section. ( [SectionName] )
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - if successful.
|
|
ENOMEM - if memory allocation failed.
|
|
EINVAL - if invalid parameters passed in or the INF buffer not
|
|
initialised
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECTION pNewSection;
|
|
|
|
//
|
|
// Check to see if INF initialised and the parameter passed in is valid
|
|
//
|
|
|
|
if (pINF == (PINF)NULL || pSectionName == (PCHAR)NULL) {
|
|
if(pchINFName) {
|
|
SlFriendlyError(
|
|
EINVAL,
|
|
pchINFName,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
} else {
|
|
SlError(EINVAL);
|
|
}
|
|
return EINVAL;
|
|
}
|
|
|
|
//
|
|
// See if we already have a section by this name. If so we want
|
|
// to merge sections.
|
|
//
|
|
for(pNewSection=pINF->pSection; pNewSection; pNewSection=pNewSection->pNext) {
|
|
if(pNewSection->pName && !_stricmp(pNewSection->pName,pSectionName)) {
|
|
break;
|
|
}
|
|
}
|
|
if(pNewSection) {
|
|
//
|
|
// Set pLineRecord to point to the list line currently in the section.
|
|
//
|
|
for(pLineRecord = pNewSection->pLine;
|
|
pLineRecord && pLineRecord->pNext;
|
|
pLineRecord = pLineRecord->pNext)
|
|
;
|
|
|
|
} else {
|
|
//
|
|
// Allocate memory for the new section
|
|
//
|
|
|
|
if ((pNewSection = (PSECTION)BlAllocateHeap(sizeof(SECTION))) == (PSECTION)NULL) {
|
|
SlNoMemoryError();
|
|
return ENOMEM;
|
|
}
|
|
|
|
//
|
|
// initialise the new section
|
|
//
|
|
pNewSection->pNext = NULL;
|
|
pNewSection->pLine = NULL;
|
|
pNewSection->pName = pSectionName;
|
|
|
|
//
|
|
// link it in
|
|
//
|
|
pNewSection->pNext = pINF->pSection;
|
|
pINF->pSection = pNewSection;
|
|
|
|
//
|
|
// reset the current line record
|
|
//
|
|
pLineRecord = NULL;
|
|
}
|
|
|
|
pSectionRecord = pNewSection;
|
|
pValueRecord = NULL;
|
|
|
|
return ESUCCESS;
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
SpAppendLine(
|
|
IN PCHAR pLineKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This appends a new line to the line list in the current section.
|
|
All further values pertain to this new line, so it resets
|
|
the value list too.
|
|
|
|
Arguments:
|
|
|
|
pLineKey - Key to be used for the current line, this could be NULL.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - if successful.
|
|
ENOMEM - if memory allocation failed.
|
|
EINVAL - if invalid parameters passed in or current section not
|
|
initialised
|
|
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
PLINE pNewLine;
|
|
|
|
//
|
|
// Check to see if current section initialised
|
|
//
|
|
|
|
if (pSectionRecord == (PSECTION)NULL) {
|
|
if(pchINFName) {
|
|
SlFriendlyError(
|
|
EINVAL,
|
|
pchINFName,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
} else {
|
|
SlError(EINVAL);
|
|
}
|
|
return EINVAL;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the new Line
|
|
//
|
|
|
|
if ((pNewLine = (PLINE)BlAllocateHeap(sizeof(LINE))) == (PLINE)NULL) {
|
|
SlNoMemoryError();
|
|
return ENOMEM;
|
|
}
|
|
|
|
//
|
|
// Link it in
|
|
//
|
|
pNewLine->pNext = (PLINE)NULL;
|
|
pNewLine->pValue = (PVALUE)NULL;
|
|
pNewLine->pName = pLineKey;
|
|
|
|
if (pLineRecord == (PLINE)NULL) {
|
|
pSectionRecord->pLine = pNewLine;
|
|
}
|
|
else {
|
|
pLineRecord->pNext = pNewLine;
|
|
}
|
|
|
|
pLineRecord = pNewLine;
|
|
|
|
//
|
|
// Reset the current value record
|
|
//
|
|
|
|
pValueRecord = (PVALUE)NULL;
|
|
|
|
return ESUCCESS;
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
SpAppendValue(
|
|
IN PCHAR pValueString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This appends a new value to the value list in the current line.
|
|
|
|
Arguments:
|
|
|
|
pValueString - The value string to be added.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - if successful.
|
|
ENOMEM - if memory allocation failed.
|
|
EINVAL - if invalid parameters passed in or current line not
|
|
initialised.
|
|
|
|
--*/
|
|
|
|
{
|
|
PVALUE pNewValue;
|
|
|
|
//
|
|
// Check to see if current line record has been initialised and
|
|
// the parameter passed in is valid
|
|
//
|
|
|
|
if (pLineRecord == (PLINE)NULL || pValueString == (PCHAR)NULL) {
|
|
if(pchINFName) {
|
|
SlFriendlyError(
|
|
EINVAL,
|
|
pchINFName,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
} else {
|
|
SlError(EINVAL);
|
|
}
|
|
return EINVAL;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the new value record
|
|
//
|
|
|
|
if ((pNewValue = (PVALUE)BlAllocateHeap(sizeof(VALUE))) == (PVALUE)NULL) {
|
|
SlNoMemoryError();
|
|
return ENOMEM;
|
|
}
|
|
|
|
//
|
|
// Link it in.
|
|
//
|
|
|
|
pNewValue->pNext = (PVALUE)NULL;
|
|
pNewValue->pName = pValueString;
|
|
|
|
if (pValueRecord == (PVALUE)NULL)
|
|
pLineRecord->pValue = pNewValue;
|
|
else
|
|
pValueRecord->pNext = pNewValue;
|
|
|
|
pValueRecord = pNewValue;
|
|
return ESUCCESS;
|
|
}
|
|
|
|
TOKEN
|
|
SpGetToken(
|
|
IN OUT PCHAR *Stream,
|
|
IN PCHAR MaxStream
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the Next token from the configuration stream.
|
|
|
|
Arguments:
|
|
|
|
Stream - Supplies the address of the configuration stream. Returns
|
|
the address of where to start looking for tokens within the
|
|
stream.
|
|
|
|
MaxStream - Supplies the address of the last character in the stream.
|
|
|
|
|
|
Return Value:
|
|
|
|
TOKEN - Returns the next token
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCHAR pch, pchStart, pchNew;
|
|
ULONG Length;
|
|
TOKEN Token;
|
|
|
|
//
|
|
// Skip whitespace (except for eol)
|
|
//
|
|
|
|
pch = *Stream;
|
|
while (pch < MaxStream && *pch != '\n' && isspace(*pch))
|
|
pch++;
|
|
|
|
|
|
//
|
|
// Check for comments and remove them
|
|
//
|
|
|
|
if (pch < MaxStream &&
|
|
((*pch == '#') ||
|
|
(*pch == ';') ||
|
|
(*pch == '/' && pch+1 < MaxStream && *(pch+1) =='/')))
|
|
while (pch < MaxStream && *pch != '\n')
|
|
pch++;
|
|
|
|
//
|
|
// Check to see if EOF has been reached, set the token to the right
|
|
// value
|
|
//
|
|
|
|
if ((pch >= MaxStream) || (*pch == 26)) {
|
|
*Stream = pch;
|
|
Token.Type = TOK_EOF;
|
|
Token.pValue = NULL;
|
|
return Token;
|
|
}
|
|
|
|
|
|
switch (*pch) {
|
|
|
|
case '[' :
|
|
pch++;
|
|
Token.Type = TOK_LBRACE;
|
|
Token.pValue = NULL;
|
|
break;
|
|
|
|
case ']' :
|
|
pch++;
|
|
Token.Type = TOK_RBRACE;
|
|
Token.pValue = NULL;
|
|
break;
|
|
|
|
case '=' :
|
|
pch++;
|
|
Token.Type = TOK_EQUAL;
|
|
Token.pValue = NULL;
|
|
break;
|
|
|
|
case ',' :
|
|
pch++;
|
|
Token.Type = TOK_COMMA;
|
|
Token.pValue = NULL;
|
|
break;
|
|
|
|
case '\n' :
|
|
pch++;
|
|
Token.Type = TOK_EOL;
|
|
Token.pValue = NULL;
|
|
break;
|
|
|
|
case '\"':
|
|
pch++;
|
|
//
|
|
// determine quoted string
|
|
//
|
|
pchStart = pch;
|
|
while (pch < MaxStream && (strchr(QStringTerminators,*pch) == NULL)) {
|
|
pch++;
|
|
}
|
|
|
|
if (pch >=MaxStream || *pch != '\"') {
|
|
Token.Type = TOK_ERRPARSE;
|
|
Token.pValue = NULL;
|
|
}
|
|
else {
|
|
Length = pch - pchStart;
|
|
if ((pchNew = BlAllocateHeap(Length + 1)) == NULL) {
|
|
Token.Type = TOK_ERRNOMEM;
|
|
Token.pValue = NULL;
|
|
}
|
|
else {
|
|
if (Length != 0) { // Null quoted strings are allowed
|
|
strncpy(pchNew, pchStart, Length);
|
|
}
|
|
pchNew[Length] = 0;
|
|
Token.Type = TOK_STRING;
|
|
Token.pValue = pchNew;
|
|
}
|
|
pch++; // advance past the quote
|
|
}
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// determine regular string
|
|
//
|
|
pchStart = pch;
|
|
while (pch < MaxStream && (strchr(StringTerminators,*pch) == NULL)) {
|
|
pch++;
|
|
}
|
|
|
|
if (pch == pchStart) {
|
|
pch++;
|
|
Token.Type = TOK_ERRPARSE;
|
|
Token.pValue = NULL;
|
|
}
|
|
else {
|
|
Length = pch - pchStart;
|
|
if ((pchNew = BlAllocateHeap(Length + 1)) == NULL) {
|
|
Token.Type = TOK_ERRNOMEM;
|
|
Token.pValue = NULL;
|
|
}
|
|
else {
|
|
strncpy(pchNew, pchStart, Length);
|
|
pchNew[Length] = 0;
|
|
Token.Type = TOK_STRING;
|
|
Token.pValue = pchNew;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
*Stream = pch;
|
|
return (Token);
|
|
}
|