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.
2184 lines
39 KiB
2184 lines
39 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
alinf.c
|
|
|
|
Abstract:
|
|
|
|
This module implements functions to access the parsed INF.
|
|
|
|
Author:
|
|
|
|
Sunil Pai (sunilp) 13-Nov-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "winnt.h"
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <dos.h>
|
|
|
|
|
|
// 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,
|
|
unsigned Size,
|
|
unsigned *LineNumber
|
|
);
|
|
|
|
|
|
//
|
|
// 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
|
|
//
|
|
|
|
int
|
|
DnAppendSection(
|
|
IN PCHAR pSectionName
|
|
);
|
|
|
|
int
|
|
DnAppendLine(
|
|
IN PCHAR pLineKey
|
|
);
|
|
|
|
int
|
|
DnAppendValue(
|
|
IN PCHAR pValueString
|
|
);
|
|
|
|
TOKEN
|
|
DnGetToken(
|
|
IN OUT PCHAR *Stream,
|
|
IN PCHAR MaxStream
|
|
);
|
|
|
|
BOOLEAN
|
|
IsStringTerminator(
|
|
IN CHAR ch
|
|
);
|
|
|
|
BOOLEAN
|
|
IsQStringTerminator(
|
|
IN CHAR ch
|
|
);
|
|
|
|
// 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 unsigned ValueIndex
|
|
);
|
|
|
|
PLINE
|
|
SearchLineInSectionByKey(
|
|
IN PSECTION pSection,
|
|
IN PCHAR Key
|
|
);
|
|
|
|
PLINE
|
|
SearchLineInSectionByIndex(
|
|
IN PSECTION pSection,
|
|
IN unsigned LineIndex
|
|
);
|
|
|
|
PSECTION
|
|
SearchSectionByName(
|
|
IN PINF pINF,
|
|
IN PCHAR SectionName
|
|
);
|
|
|
|
//
|
|
// ROUTINE DEFINITIONS
|
|
//
|
|
|
|
//
|
|
// returns a handle to use for further inf parsing
|
|
//
|
|
|
|
int
|
|
DnInitINFBuffer (
|
|
IN int InfFileHandle,
|
|
OUT PVOID *pINFHandle,
|
|
OUT unsigned *LineNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
int Status;
|
|
PCHAR Buffer;
|
|
unsigned Siz,SizeRead;
|
|
|
|
*LineNumber = 0;
|
|
//
|
|
// find out size of INF file
|
|
//
|
|
|
|
_asm {
|
|
mov ax,0x4202 // func: move file ptr, method: end of file
|
|
mov bx,InfFileHandle
|
|
xor cx,cx // 0 bytes from the end
|
|
xor dx,dx
|
|
int 21h
|
|
jnc ok1
|
|
mov Status,EIO
|
|
jmp done
|
|
ok1:
|
|
or dx,dx // can't handle > 64K files.
|
|
jz sizeok
|
|
mov Status,E2BIG
|
|
jmp done
|
|
sizeok:
|
|
mov Siz,ax
|
|
mov ax,0x4200 // func: move file ptr, method: start of file
|
|
mov bx,InfFileHandle
|
|
xor cx,cx
|
|
xor dx,dx
|
|
int 21h
|
|
jnc ok2
|
|
mov Status,EIO
|
|
jmp done
|
|
ok2:
|
|
mov Status,EZERO
|
|
done:
|
|
}
|
|
|
|
if(Status) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// allocate this big a buffer
|
|
//
|
|
|
|
Buffer = MALLOC(Siz,TRUE);
|
|
|
|
//
|
|
// read the file in
|
|
//
|
|
|
|
if((Status = _dos_read(InfFileHandle, Buffer, Siz, &SizeRead))
|
|
|| (SizeRead != Siz))
|
|
{
|
|
FREE(Buffer);
|
|
if(SizeRead != Siz) {
|
|
Status = EIO;
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// parse the file
|
|
//
|
|
|
|
if((*pINFHandle = ParseInfBuffer(Buffer, SizeRead, LineNumber)) == NULL) {
|
|
Status = EBADF;
|
|
} else {
|
|
Status = EZERO;
|
|
}
|
|
|
|
//
|
|
// Clean up and return
|
|
//
|
|
|
|
FREE(Buffer);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// frees an INF Buffer
|
|
//
|
|
int
|
|
DnFreeINFBuffer (
|
|
IN PVOID INFHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PINF pINF;
|
|
|
|
//
|
|
// Valid INF Handle?
|
|
//
|
|
|
|
if (INFHandle == (PVOID)NULL) {
|
|
return EZERO;
|
|
}
|
|
|
|
//
|
|
// cast the buffer into an INF structure
|
|
//
|
|
|
|
pINF = (PINF)INFHandle;
|
|
|
|
FreeSectionList(pINF->pSection);
|
|
|
|
//
|
|
// free the inf structure too
|
|
//
|
|
|
|
FREE(pINF);
|
|
|
|
return( EZERO );
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeSectionList (
|
|
IN PSECTION pSection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECTION Next;
|
|
|
|
while(pSection) {
|
|
Next = pSection->pNext;
|
|
FreeLineList(pSection->pLine);
|
|
if(pSection->pName) {
|
|
FREE(pSection->pName);
|
|
}
|
|
FREE(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) {
|
|
FREE(pLine->pName);
|
|
}
|
|
FREE(pLine);
|
|
pLine = Next;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FreeValueList (
|
|
IN PVALUE pValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PVALUE Next;
|
|
|
|
while(pValue) {
|
|
Next = pValue->pNext;
|
|
if(pValue->pName) {
|
|
FREE(pValue->pName);
|
|
}
|
|
FREE(pValue);
|
|
pValue = Next;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// searches for the existance of a particular section
|
|
//
|
|
BOOLEAN
|
|
DnSearchINFSection (
|
|
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
|
|
DnGetSectionLineIndex (
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName,
|
|
IN unsigned LineIndex,
|
|
IN unsigned 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 (pValue->pName);
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
DnGetSectionKeyExists (
|
|
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) == (PLINE)NULL) {
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
PCHAR
|
|
DnGetKeyName(
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName,
|
|
IN unsigned 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, key and index return the value
|
|
//
|
|
PCHAR
|
|
DnGetSectionKeyIndex (
|
|
IN PVOID INFHandle,
|
|
IN PCHAR SectionName,
|
|
IN PCHAR Key,
|
|
IN unsigned 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
|
|
))
|
|
== (PLINE)NULL)
|
|
return((PCHAR)NULL);
|
|
|
|
if((pValue = SearchValueInLine(
|
|
pLine,
|
|
ValueIndex
|
|
))
|
|
== (PVALUE)NULL)
|
|
return((PCHAR)NULL);
|
|
|
|
return (pValue->pName);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PVALUE
|
|
SearchValueInLine(
|
|
IN PLINE pLine,
|
|
IN unsigned ValueIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PVALUE pValue;
|
|
unsigned 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
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PLINE pLine;
|
|
|
|
if (pSection == (PSECTION)NULL || Key == (PCHAR)NULL) {
|
|
return ((PLINE)NULL);
|
|
}
|
|
|
|
pLine = pSection->pLine;
|
|
while ((pLine != (PLINE)NULL) && (pLine->pName == NULL || stricmp(pLine->pName, Key))) {
|
|
pLine = pLine->pNext;
|
|
}
|
|
|
|
return pLine;
|
|
|
|
}
|
|
|
|
|
|
PLINE
|
|
SearchLineInSectionByIndex(
|
|
IN PSECTION pSection,
|
|
IN unsigned LineIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PLINE pLine;
|
|
unsigned 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) && stricmp(pSection->pName, SectionName)) {
|
|
pSection = pSection->pNext;
|
|
}
|
|
|
|
//
|
|
// return the section at which we stopped (either NULL or the section
|
|
// which was found
|
|
//
|
|
|
|
return pSection;
|
|
|
|
}
|
|
|
|
|
|
// 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','\032'};
|
|
unsigned NumberOfTerminators = sizeof (StringTerminators);
|
|
|
|
//
|
|
// quoted string terminators allow some of the regular terminators to
|
|
// appear as characters
|
|
|
|
CHAR QStringTerminators[] = {'\"', '\n','\f','\v', '\r','\032'};
|
|
unsigned QNumberOfTerminators = sizeof (QStringTerminators);
|
|
|
|
|
|
//
|
|
// Main parser routine
|
|
//
|
|
|
|
PVOID
|
|
ParseInfBuffer(
|
|
PCHAR Buffer,
|
|
unsigned Size,
|
|
unsigned *LineNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
LineNumber - In case of error, this variable will contain the line
|
|
in the file that contains a syntax error.
|
|
|
|
Return Value:
|
|
|
|
PVOID - INF handle ptr to be used in subsequent INF calls.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR Stream, MaxStream, pchSectionName, pchValue;
|
|
unsigned State, InfLine;
|
|
TOKEN Token;
|
|
BOOLEAN Done;
|
|
BOOLEAN Error;
|
|
int ErrorCode;
|
|
|
|
*LineNumber = 0;
|
|
//
|
|
// Initialise the globals
|
|
//
|
|
pINF = (PINF)NULL;
|
|
pSectionRecord = (PSECTION)NULL;
|
|
pLineRecord = (PLINE)NULL;
|
|
pValueRecord = (PVALUE)NULL;
|
|
|
|
//
|
|
// Get INF record
|
|
//
|
|
pINF = MALLOC(sizeof(INF),TRUE);
|
|
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 = DnGetToken(&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;
|
|
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;
|
|
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;
|
|
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 = DnAppendSection(pchSectionName)) != EZERO)
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchSectionName = NULL;
|
|
State = 5;
|
|
}
|
|
break;
|
|
|
|
case TOK_EOF:
|
|
if ((ErrorCode = DnAppendSection(pchSectionName)) != EZERO)
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchSectionName = NULL;
|
|
Done = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
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;
|
|
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 = DnAppendLine(NULL)) != EZERO ||
|
|
(ErrorCode = DnAppendValue(pchValue)) !=EZERO )
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchValue = NULL;
|
|
State = 5;
|
|
}
|
|
break;
|
|
|
|
case TOK_EOF:
|
|
if ( (ErrorCode = DnAppendLine(NULL)) != EZERO ||
|
|
(ErrorCode = DnAppendValue(pchValue)) !=EZERO )
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchValue = NULL;
|
|
Done = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TOK_COMMA:
|
|
if ( (ErrorCode = DnAppendLine(NULL)) != EZERO ||
|
|
(ErrorCode = DnAppendValue(pchValue)) !=EZERO )
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchValue = NULL;
|
|
State = 7;
|
|
}
|
|
break;
|
|
|
|
case TOK_EQUAL:
|
|
if ( (ErrorCode = DnAppendLine(pchValue)) !=EZERO)
|
|
Error = Done = TRUE;
|
|
else {
|
|
pchValue = NULL;
|
|
State = 8;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// STATE 7: Comma received, Expecting another string
|
|
//
|
|
// Valid Tokens: TOK_STRING
|
|
//
|
|
case 7:
|
|
switch (Token.Type) {
|
|
case TOK_STRING:
|
|
if ((ErrorCode = DnAppendValue(Token.pValue)) != EZERO)
|
|
Error = Done = TRUE;
|
|
else
|
|
State = 9;
|
|
|
|
break;
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
break;
|
|
}
|
|
break;
|
|
//
|
|
// STATE 8: Equal received, Expecting another string
|
|
//
|
|
// Valid Tokens: TOK_STRING
|
|
//
|
|
case 8:
|
|
switch (Token.Type) {
|
|
case TOK_STRING:
|
|
if ((ErrorCode = DnAppendValue(Token.pValue)) != EZERO)
|
|
Error = Done = TRUE;
|
|
else
|
|
State = 9;
|
|
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
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;
|
|
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;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Error = Done = TRUE;
|
|
ErrorCode = EINVAL;
|
|
break;
|
|
|
|
} // end switch(State)
|
|
|
|
|
|
if (Error) {
|
|
|
|
switch (ErrorCode) {
|
|
case ENOMEM:
|
|
DnFatalError(&DnsOutOfMemory);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ErrorCode = DnFreeINFBuffer((PVOID)pINF);
|
|
if (pchSectionName != (PCHAR)NULL) {
|
|
FREE(pchSectionName);
|
|
}
|
|
|
|
if (pchValue != (PCHAR)NULL) {
|
|
FREE(pchValue);
|
|
}
|
|
|
|
pINF = (PINF)NULL;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Keep track of line numbers so that we can display Errors
|
|
//
|
|
|
|
if (Token.Type == TOK_EOL)
|
|
InfLine++;
|
|
}
|
|
|
|
} // End while
|
|
|
|
if( pINF == NULL ) {
|
|
*LineNumber = InfLine;
|
|
}
|
|
return((PVOID)pINF);
|
|
}
|
|
|
|
|
|
|
|
int
|
|
DnAppendSection(
|
|
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:
|
|
|
|
EZERO - 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) {
|
|
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
|
|
//
|
|
|
|
pNewSection = MALLOC(sizeof(SECTION),TRUE);
|
|
|
|
//
|
|
// 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 EZERO;
|
|
}
|
|
|
|
|
|
int
|
|
DnAppendLine(
|
|
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:
|
|
|
|
EZERO - 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) {
|
|
return EINVAL;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the new Line
|
|
//
|
|
|
|
pNewLine = MALLOC(sizeof(LINE),TRUE);
|
|
|
|
//
|
|
// 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 EZERO;
|
|
}
|
|
|
|
|
|
|
|
int
|
|
DnAppendValue(
|
|
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:
|
|
|
|
EZERO - 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) {
|
|
return EINVAL;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the new value record
|
|
//
|
|
|
|
pNewValue = MALLOC(sizeof(VALUE),TRUE);
|
|
|
|
//
|
|
// Link it in.
|
|
//
|
|
|
|
pNewValue->pNext = (PVALUE)NULL;
|
|
pNewValue->pName = pValueString;
|
|
|
|
if (pValueRecord == (PVALUE)NULL)
|
|
pLineRecord->pValue = pNewValue;
|
|
else
|
|
pValueRecord->pNext = pNewValue;
|
|
|
|
pValueRecord = pNewValue;
|
|
return EZERO;
|
|
}
|
|
|
|
TOKEN
|
|
DnGetToken(
|
|
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;
|
|
unsigned Length;
|
|
TOKEN Token;
|
|
|
|
//
|
|
// Skip whitespace (except for eol)
|
|
//
|
|
|
|
pch = *Stream;
|
|
while (pch < MaxStream && *pch != '\n' && (isspace(*pch) || (*pch == '\032')))
|
|
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 ) {
|
|
*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 && !IsQStringTerminator(*pch)) {
|
|
pch++;
|
|
}
|
|
|
|
if (pch >=MaxStream || *pch != '\"') {
|
|
Token.Type = TOK_ERRPARSE;
|
|
Token.pValue = NULL;
|
|
}
|
|
else {
|
|
Length = pch - pchStart;
|
|
pchNew = MALLOC(Length + 1,TRUE);
|
|
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) && !IsStringTerminator(*pch)) {
|
|
pch++;
|
|
}
|
|
if (pch == pchStart) {
|
|
pch++;
|
|
Token.Type = TOK_ERRPARSE;
|
|
Token.pValue = NULL;
|
|
}
|
|
else {
|
|
Length = pch - pchStart;
|
|
pchNew = MALLOC(Length + 1,TRUE);
|
|
strncpy(pchNew, pchStart, Length);
|
|
pchNew[Length] = 0;
|
|
Token.Type = TOK_STRING;
|
|
Token.pValue = pchNew;
|
|
}
|
|
break;
|
|
}
|
|
|
|
*Stream = pch;
|
|
return (Token);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
IsStringTerminator(
|
|
CHAR ch
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tests whether the given character terminates a quoted
|
|
string.
|
|
|
|
Arguments:
|
|
|
|
ch - The current character.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the character is a quoted string terminator, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
unsigned i;
|
|
|
|
//
|
|
// one of the string terminator array
|
|
//
|
|
|
|
for (i = 0; i < NumberOfTerminators; i++) {
|
|
if (ch == StringTerminators[i]) {
|
|
return (TRUE);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
IsQStringTerminator(
|
|
CHAR ch
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tests whether the given character terminates a quoted
|
|
string.
|
|
|
|
Arguments:
|
|
|
|
ch - The current character.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the character is a quoted string terminator, FALSE otherwise.
|
|
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
unsigned i;
|
|
//
|
|
// one of quoted string terminators array
|
|
//
|
|
for (i = 0; i < QNumberOfTerminators; i++) {
|
|
|
|
if (ch == QStringTerminators[i]) {
|
|
return (TRUE);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
DnAddLineToSection(
|
|
IN PVOID Handle,
|
|
IN PCHAR SectionName,
|
|
IN PCHAR KeyName,
|
|
IN PCHAR Values[],
|
|
IN ULONG ValueCount
|
|
)
|
|
|
|
{
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
PVALUE pValue;
|
|
PVALUE pPrevVal;
|
|
PINF pFile;
|
|
ULONG v;
|
|
|
|
pFile = (PINF) Handle;
|
|
|
|
//
|
|
// If the section doesn't exist, create it
|
|
//
|
|
pSection = SearchSectionByName(pFile,SectionName);
|
|
if(!pSection) {
|
|
|
|
//
|
|
// Allocate and Zero space for the structure
|
|
//
|
|
pSection = MALLOC( sizeof(SECTION), TRUE );
|
|
memset( pSection, 0, sizeof(SECTION) );
|
|
|
|
//
|
|
// Link the section into the existing file pointer
|
|
//
|
|
pSection->pNext = pFile->pSection;
|
|
pFile->pSection = pSection;
|
|
|
|
//
|
|
// Set the Name of the Section
|
|
//
|
|
pSection->pName = DnDupString( SectionName );
|
|
|
|
}
|
|
|
|
//
|
|
// Create a structure for the line in the section
|
|
//
|
|
pLine = SearchLineInSectionByKey(pSection,KeyName);
|
|
|
|
//
|
|
// If we find a duplicate key, then we overwrite the previous
|
|
// contents and free them...
|
|
//
|
|
|
|
if (pLine) {
|
|
|
|
//
|
|
// We have to keep the keys unique, so we must
|
|
// free all the contents of this line
|
|
//
|
|
|
|
FreeValueList(pLine->pValue);
|
|
pLine->pValue = NULL;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Allocate and zero the space for the line entry
|
|
//
|
|
pLine = MALLOC( sizeof(LINE), TRUE );
|
|
memset( pLine, 0, sizeof (LINE) );
|
|
|
|
//
|
|
// Link the line into the section
|
|
//
|
|
pLine->pNext = pSection->pLine;
|
|
pSection->pLine = pLine;
|
|
|
|
//
|
|
// Set the Key Value of the Line
|
|
//
|
|
pLine->pName = DnDupString( KeyName );
|
|
|
|
}
|
|
|
|
//
|
|
// Create Value Entries for each specified value
|
|
// These must be kept in the order they were specified
|
|
//
|
|
for (v = 0; v<ValueCount; v++) {
|
|
|
|
//
|
|
// Allocate and zero the space for the value entry
|
|
//
|
|
pValue = MALLOC( sizeof(VALUE), TRUE);
|
|
memset( pValue, 0, sizeof(VALUE) );
|
|
|
|
//
|
|
// Set the Value for the entry
|
|
//
|
|
pValue->pName = DnDupString(Values[v]);
|
|
|
|
//
|
|
// Keep the entries in order
|
|
//
|
|
if (v==0) {
|
|
pLine->pValue = pValue;
|
|
} else {
|
|
pPrevVal->pNext = pValue;
|
|
}
|
|
pPrevVal = pValue;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
DnWriteSetupTextFile(
|
|
IN PVOID InfHandle,
|
|
IN PCHAR FileName
|
|
)
|
|
|
|
{
|
|
struct find_t FindData;
|
|
FILE *Handle;
|
|
PINF pFile;
|
|
PSECTION pSection;
|
|
PLINE pLine;
|
|
PVALUE pValue;
|
|
|
|
//
|
|
// See if the file exists and see if it is in read-only mode
|
|
//
|
|
if(!_dos_findfirst(FileName,_A_HIDDEN|_A_SUBDIR|_A_SYSTEM|_A_RDONLY,&FindData)) {
|
|
|
|
//
|
|
// The File Exists -- Perform some simple checks
|
|
//
|
|
if (FindData.attrib & _A_RDONLY) {
|
|
|
|
//
|
|
// Make it writeable
|
|
//
|
|
_dos_setfileattr(FileName,_A_NORMAL);
|
|
|
|
}
|
|
|
|
if (FindData.attrib & _A_SUBDIR) {
|
|
|
|
//
|
|
// This isn't a valid file that we can work with..
|
|
//
|
|
return (FALSE);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Obtain a handle to the file in write-only mode
|
|
//
|
|
Handle = fopen(FileName, "w+");
|
|
if (Handle == NULL) {
|
|
|
|
//
|
|
// We could not open the file
|
|
//
|
|
return (FALSE);
|
|
}
|
|
|
|
pFile = (PINF) InfHandle;
|
|
if (pFile == NULL) {
|
|
|
|
//
|
|
// There isn't anything in the file.
|
|
// That isn't an error since we can empty
|
|
// the file if we so desire, but this is a
|
|
// strange way todo that. However...
|
|
//
|
|
fclose(Handle);
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// BUGBUG - This can't handle > 64k buffers. Which may or may not be
|
|
// important
|
|
//
|
|
for(pSection=pFile->pSection; pSection; pSection=pSection->pNext) {
|
|
|
|
//
|
|
// Dump the section name
|
|
//
|
|
fprintf(Handle,"[%s]\n",pSection->pName);
|
|
|
|
for(pLine=pSection->pLine; pLine ; pLine=pLine->pNext) {
|
|
|
|
//
|
|
// Write the keyname
|
|
//
|
|
if(strchr( pLine->pName, ' ' ) == NULL) {
|
|
fprintf(Handle,"%s = ",pLine->pName);
|
|
} else {
|
|
fprintf(Handle,"\"%s\" = ",pLine->pName);
|
|
}
|
|
|
|
for(pValue=pLine->pValue; pValue; pValue=pValue->pNext) {
|
|
|
|
if (pValue != pLine->pValue) {
|
|
fprintf(Handle,",");
|
|
}
|
|
|
|
fprintf(Handle,"\"%s\"",pValue->pName);
|
|
}
|
|
|
|
//
|
|
// Finish off the line
|
|
//
|
|
fprintf(Handle,"\n");
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Flush and Close the file
|
|
//
|
|
fflush(Handle);
|
|
fclose(Handle);
|
|
return(TRUE);
|
|
}
|
|
|
|
PVOID
|
|
DnNewSetupTextFile(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
PINF pFile;
|
|
|
|
pFile = MALLOC( sizeof(INF), TRUE);
|
|
memset(pFile, 0, sizeof(INF) );
|
|
|
|
return (PVOID) pFile;
|
|
}
|
|
|
|
PCHAR
|
|
DnGetSectionName(
|
|
IN PVOID Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a handle to an inf file, return the string which identifies
|
|
a section in the inf, listing each section in turn
|
|
|
|
Arguments:
|
|
|
|
Handle - The current inf file
|
|
|
|
Return Value:
|
|
|
|
<String> - Name of current section
|
|
NULL - Listed all sections
|
|
|
|
|
|
--*/
|
|
{
|
|
static PINF CurrentInf = NULL;
|
|
static PSECTION CurrentSection = NULL;
|
|
|
|
if (CurrentInf != (PINF) Handle) {
|
|
|
|
//
|
|
// We have a new INF to examine, so reset
|
|
// our internal structures
|
|
//
|
|
CurrentInf = (PINF) Handle;
|
|
CurrentSection = NULL;
|
|
}
|
|
|
|
if (CurrentSection == NULL) {
|
|
|
|
//
|
|
// Start at the beginning of the INF
|
|
//
|
|
CurrentSection = CurrentInf->pSection;
|
|
|
|
//
|
|
// It is possible to have an empty INF file
|
|
//
|
|
if (!CurrentSection) {
|
|
return(NULL);
|
|
}
|
|
|
|
return (CurrentSection->pName);
|
|
}
|
|
|
|
//
|
|
// Point to the next section;
|
|
//
|
|
CurrentSection = CurrentSection->pNext;
|
|
|
|
if (!CurrentSection) {
|
|
return (NULL);
|
|
}
|
|
|
|
return (CurrentSection->pName);
|
|
}
|
|
|
|
VOID
|
|
DnCopySetupTextSection(
|
|
IN PVOID FromInf,
|
|
IN PVOID ToInf,
|
|
IN PCHAR SectionName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies section from one INF file to another
|
|
|
|
Arguments:
|
|
|
|
FromInf - The source inf
|
|
ToInf - The Destination inf
|
|
Section - The Section to Copy
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PINF From;
|
|
PINF To;
|
|
PSECTION FromSection;
|
|
PSECTION ToSection;
|
|
PLINE FromLine;
|
|
PLINE ToLine;
|
|
PLINE pTemp;
|
|
PVALUE FromValue;
|
|
PVALUE ToValue;
|
|
PVALUE PrevToValue;
|
|
|
|
From = (PINF) FromInf;
|
|
To = (PINF) ToInf;
|
|
|
|
//
|
|
// Find the section in the source inf
|
|
//
|
|
FromSection = SearchSectionByName(FromInf,SectionName);
|
|
if (FromSection == NULL) {
|
|
//
|
|
// Nothing todo
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// See if the section exists in the target
|
|
//
|
|
ToSection = SearchSectionByName(ToInf,SectionName);
|
|
if (ToSection == NULL) {
|
|
//
|
|
// Section doesn't exist -- add it
|
|
//
|
|
|
|
//
|
|
// Allocate and Zero space for the structure
|
|
//
|
|
ToSection = MALLOC( sizeof(SECTION), TRUE );
|
|
memset( ToSection, 0, sizeof(SECTION) );
|
|
|
|
//
|
|
// Link the section into the existing file pointer
|
|
//
|
|
ToSection->pNext = To->pSection;
|
|
To->pSection = ToSection;
|
|
|
|
//
|
|
// Set the Name of the Section
|
|
//
|
|
ToSection->pName = DnDupString( SectionName );
|
|
|
|
}
|
|
|
|
for(FromLine=SearchLineInSectionByIndex(FromSection,0); FromLine; FromLine=FromLine->pNext) {
|
|
|
|
#if 0
|
|
//
|
|
// Search for the line in the destination
|
|
//
|
|
ToLine = SearchLineInSectionByKey(ToSection,FromLine->pName);
|
|
#else
|
|
//
|
|
// Network stuff can have multiple values with the same name
|
|
// so we can't do duplicate elimination!
|
|
//
|
|
ToLine = NULL;
|
|
#endif
|
|
if (ToLine != NULL) {
|
|
|
|
//
|
|
// In this case the key in the destination exists, so we
|
|
// want to erase them
|
|
//
|
|
FreeValueList(ToLine->pValue);
|
|
|
|
} else {
|
|
|
|
//
|
|
// In this case the key doesn't exist and so we want to
|
|
// add it to the destination. Preserve line ordering.
|
|
//
|
|
|
|
//
|
|
// Allocate and zero the space for the line entry
|
|
//
|
|
ToLine = MALLOC( sizeof(LINE), TRUE );
|
|
memset( ToLine, 0, sizeof (LINE) );
|
|
|
|
//
|
|
// Link the line into the section
|
|
//
|
|
if(ToSection->pLine) {
|
|
for(pTemp=ToSection->pLine; pTemp->pNext; pTemp=pTemp->pNext) {
|
|
;
|
|
}
|
|
pTemp->pNext = ToLine;
|
|
} else {
|
|
ToSection->pLine = ToLine;
|
|
}
|
|
|
|
//
|
|
// Set the Key Value of the Line
|
|
//
|
|
ToLine->pName = DnDupString( FromLine->pName );
|
|
}
|
|
|
|
//
|
|
// Copy the value list
|
|
//
|
|
for(FromValue = FromLine->pValue, PrevToValue = NULL;
|
|
FromValue;
|
|
FromValue = FromValue->pNext) {
|
|
|
|
//
|
|
// Allocate and zero the space for the value entry
|
|
//
|
|
ToValue = MALLOC( sizeof(VALUE), TRUE);
|
|
memset( ToValue, 0, sizeof(VALUE) );
|
|
|
|
//
|
|
// Set the Value for the entry
|
|
//
|
|
ToValue->pName = DnDupString(FromValue->pName);
|
|
|
|
//
|
|
// Link the entry into the destination list
|
|
//
|
|
if (PrevToValue == NULL) {
|
|
ToLine->pValue = ToValue;
|
|
} else {
|
|
PrevToValue->pNext = ToValue;
|
|
}
|
|
|
|
//
|
|
// Remember the place to add the next value
|
|
//
|
|
PrevToValue = ToValue;
|
|
|
|
}
|
|
} // for
|
|
|
|
//
|
|
// do nothing more
|
|
//
|
|
return;
|
|
}
|