371 lines
11 KiB
C
371 lines
11 KiB
C
#include "precomp.h"
|
|
#pragma hdrstop
|
|
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
infload1.c
|
|
|
|
Abstract:
|
|
|
|
Routines to load an INF file and proprocess it, eliminating
|
|
comments and line continuations, and collapsing adjacent WS
|
|
and NLs.
|
|
|
|
The result is a series of NUL-terminated lines, with no blank lines
|
|
or lines with only comments or whitespace, etc.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 9-Spetember-1991
|
|
|
|
--*/
|
|
|
|
/*
|
|
The purpose of the preprocessing step is to create a series of
|
|
significant lines, with comments stripped out.
|
|
|
|
The file is read from disk into a single large buffer. A destination
|
|
buffer is allocated to hold the preprocessed file. This buffer
|
|
is initially the size of the file image but will be reallocated
|
|
when proprocessing is completed.
|
|
|
|
The input image is considered to be a sequence of LF or CR/LF
|
|
separated lines. One line in the input file is equivalent to
|
|
one line in the output unless the lines are logically joined with
|
|
line continuation characters.
|
|
|
|
- A line continuation character is a non-quoted + which has no
|
|
non-space, non-tab, or non-comment text after it on the line.
|
|
Line continuation is accomplished by eliminating all characters
|
|
from the + through adjacent spaces, tabs, comments, and EOLs.
|
|
|
|
- Two consecutive double quote characters inside a quoted
|
|
string are replaced by a single double quote.
|
|
|
|
- Semantic double quuote chars (ie, those that begin and
|
|
end strings) are replaced by DQUOTE. Double quotes
|
|
that are actually part of the string (see first rule) are
|
|
emitted as actual double quote chars. This is so that later
|
|
steps can tell the difference between two adjacent quoted
|
|
strings and a string containing a quoted double quote.
|
|
|
|
- All strings of consecutive spaces and tabs are replaced
|
|
by a single space. A single space is in turn eliminated
|
|
if it occurs immediately adjacent to a comma.
|
|
|
|
- All comments are eliminated. A comment is an unquoted
|
|
semi-colon and consists of the rest of the line (to EOL).
|
|
|
|
- CR/LF or LF are replaced by NUL. The EOL does not result
|
|
in any implied actions being carried out -- ie, a terminating
|
|
double quote being supplied if none exists in the input.
|
|
|
|
- Adjacent NULs are never stored in the output. There will
|
|
be at most a single consecutive NUL character in the output.
|
|
Also, a space following a NUL is eliminated, as is a space
|
|
preceeding a NUL.
|
|
|
|
No syntax errors are reported from this step.
|
|
*/
|
|
|
|
|
|
PUCHAR CurrentOut; // points to next cell in output image
|
|
BOOL InsideQuotes; // self-explanatory flag
|
|
|
|
#define IsWS(x) (((x) == ' ') || ((x) == '\t'))
|
|
#define SkipWS(x) Preprocess_SkipChars(x," \t")
|
|
#define SkipWSEOL(x) Preprocess_SkipChars(x," \t\r\n");
|
|
#define SkipComment(x) Preprocess_SkipChars(x,"");
|
|
|
|
#define CtN 0 // Normal char; NOTE: same as ZERO!
|
|
#define CtS 1 // Space
|
|
#define CtE 2 // EOL
|
|
#define CtC 3 // Comma
|
|
#define CtF 4 // EOF
|
|
|
|
static BYTE charTypeTable [256] =
|
|
{
|
|
// 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
|
|
// 0 1 2 3 4 5 6 7 8 9 11 12 13 13 14 15
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
/* 00 */ CtE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CtF, 0, 0, 0, 0, 0,
|
|
/* 20 */ CtS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CtC, 0, 0, 0,
|
|
/* 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
|
|
/*
|
|
In: pointer to a char
|
|
list of chars to skip
|
|
Out: pointer to first char not in the skip list
|
|
|
|
Also: skips comments.
|
|
*/
|
|
|
|
VOID
|
|
Preprocess_SkipChars(
|
|
LPBYTE *StartingLoc,
|
|
LPSTR CharList
|
|
)
|
|
{
|
|
UCHAR c;
|
|
PUCHAR p = *StartingLoc;
|
|
PUCHAR pch;
|
|
BOOL InList;
|
|
|
|
while(1) {
|
|
|
|
c = *p;
|
|
|
|
InList = FALSE;
|
|
for(pch=CharList; *pch; pch++) {
|
|
if(*pch == c) {
|
|
InList = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!InList) {
|
|
|
|
/*
|
|
We don't need to bother with seeing if we're in quotes
|
|
because this routine is never called when we are.
|
|
*/
|
|
|
|
if(c == ';') {
|
|
|
|
while(*(++p) != NL) {
|
|
;
|
|
} // at loop exit, p points to NL
|
|
|
|
} else { // not in skip list and not a comment
|
|
|
|
*StartingLoc = p;
|
|
return;
|
|
}
|
|
|
|
} else { // c is in the list, so skip it
|
|
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Create a preprocessed in-memory version of an inf file as follows:
|
|
|
|
The result is a series of NUL-terminated lines, with no blank lines
|
|
or lines with only comments or whitespace, etc.
|
|
*/
|
|
|
|
GRC
|
|
PreprocessINFFile(
|
|
LPSTR FileName,
|
|
LPBYTE *ResultBuffer,
|
|
UINT *ResultBufferSize
|
|
)
|
|
{
|
|
HANDLE FileHandle;
|
|
LONG FileSize;
|
|
LPBYTE FileBuffer; // the input
|
|
LPBYTE INFBuffer; // the output
|
|
LPBYTE p,q; // current char in file image
|
|
UCHAR c;
|
|
register int iEmit ;
|
|
int iEmit2 ;
|
|
static UCHAR PreviousChar = EOL;
|
|
static PUCHAR PreviousPos;
|
|
|
|
|
|
if((FileHandle = (HANDLE)LongToHandle(_lopen(FileName,OF_READ))) == (HANDLE)(-1)) {
|
|
return(grcBadINF);
|
|
}
|
|
|
|
FileSize = _llseek(HandleToUlong(FileHandle),0,2); // move to end of file
|
|
_llseek(HandleToUlong(FileHandle),0,0); // move back to start of file
|
|
|
|
if((FileBuffer = SAlloc(FileSize+2)) == NULL) {
|
|
_lclose(HandleToUlong(FileHandle));
|
|
return(grcOutOfMemory);
|
|
}
|
|
|
|
if(_lread(HandleToUlong(FileHandle),FileBuffer,(UINT)FileSize) == -1) {
|
|
_lclose(HandleToUlong(FileHandle));
|
|
SFree(FileBuffer);
|
|
return(grcBadINF);
|
|
}
|
|
|
|
_lclose(HandleToUlong(FileHandle));
|
|
FileBuffer[FileSize] = NL; // in case last line is incomplete
|
|
FileBuffer[FileSize+1] = 0; // to terminate the image
|
|
|
|
if((INFBuffer = SAlloc(FileSize)) == NULL) {
|
|
SFree(FileBuffer);
|
|
return(grcOutOfMemory);
|
|
}
|
|
|
|
p = FileBuffer;
|
|
CurrentOut = INFBuffer;
|
|
|
|
InsideQuotes = FALSE;
|
|
|
|
iEmit = -1 ;
|
|
iEmit2 = -1 ;
|
|
|
|
while(c = *p)
|
|
{
|
|
if(c == CR) {
|
|
|
|
p++;
|
|
continue;
|
|
|
|
} else if(c == NL) {
|
|
|
|
iEmit = 0 ;
|
|
p++;
|
|
|
|
} else if(c == '"') {
|
|
|
|
if(InsideQuotes && (*(p+1) == '"')) {
|
|
// we've got a quoted quote
|
|
iEmit = '"' ;
|
|
p++; // skip first quote
|
|
} else {
|
|
InsideQuotes = !InsideQuotes;
|
|
iEmit = DQUOTE ;
|
|
}
|
|
p++;
|
|
|
|
} else if(InsideQuotes) {
|
|
|
|
// just spit out the character
|
|
|
|
iEmit = c ;
|
|
p++;
|
|
|
|
} else if (c == '+') { // line continuation
|
|
|
|
p++; // skip the +
|
|
|
|
q = p;
|
|
|
|
SkipWS(&p);
|
|
|
|
if((*p == CR) || (*p == NL)) { // line continuation
|
|
|
|
SkipWSEOL(&p);
|
|
|
|
} else { // ordinary character
|
|
|
|
iEmit = '+' ; // p already advanced (above)
|
|
|
|
if(p != q) { // preserve ws between + and
|
|
iEmit2 = ' ' ; // char that follows
|
|
}
|
|
}
|
|
|
|
} else if(IsWS(c)) {
|
|
|
|
iEmit = ' ' ;
|
|
SkipWS(&p);
|
|
|
|
} else if(c == ';') {
|
|
|
|
SkipComment(&p);
|
|
|
|
} else {
|
|
|
|
iEmit = c ; // plain old character
|
|
p++;
|
|
}
|
|
|
|
/*
|
|
Store a character in the output stream.
|
|
|
|
Control-z's are eliminated.
|
|
Consecutive NL's after the first are eliminated.
|
|
WS immediately following a NL is eliminated.
|
|
NL immediately following a WS is stored over the WS, eliminating it.
|
|
WS immediately before and after a comma is eliminated.
|
|
*/
|
|
|
|
if ( iEmit >= 0 )
|
|
{
|
|
switch ( charTypeTable[iEmit] )
|
|
{
|
|
case CtN: // Normal stuff
|
|
break ;
|
|
|
|
case CtS: // Space
|
|
if( PreviousChar == EOL
|
|
||(!InsideQuotes && (PreviousChar == ',')))
|
|
{ // don't store WS after NL's or ,'s
|
|
iEmit = -1 ;
|
|
}
|
|
break ;
|
|
|
|
case CtE: // EOL
|
|
if(PreviousChar == EOL) {
|
|
iEmit = -1 ; // don't store adjacent NL's
|
|
} else if(PreviousChar == ' ') { // WS/NL ==> collapse to NL
|
|
CurrentOut = PreviousPos; // back up over the space first
|
|
}
|
|
InsideQuotes = FALSE; // reset quotes status
|
|
break ;
|
|
|
|
case CtC: // Comma
|
|
if ( !InsideQuotes && (PreviousChar == ' ')) {
|
|
CurrentOut = PreviousPos;
|
|
}
|
|
break ;
|
|
|
|
case CtF: // 0x1a or Ctrl-Z
|
|
iEmit= -1 ;
|
|
break ;
|
|
}
|
|
|
|
if ( iEmit >= 0 )
|
|
{
|
|
PreviousChar = (UCHAR)iEmit ;
|
|
PreviousPos = CurrentOut;
|
|
*CurrentOut++ = (UCHAR)iEmit;
|
|
|
|
if ( iEmit2 >= 0 )
|
|
{
|
|
PreviousChar = (UCHAR)iEmit2 ;
|
|
PreviousPos = CurrentOut;
|
|
*CurrentOut++ = (UCHAR)iEmit2 ;
|
|
iEmit2 = -1 ;
|
|
}
|
|
iEmit = -1 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
SFree(FileBuffer);
|
|
|
|
*ResultBufferSize = (UINT)(CurrentOut - INFBuffer) ;
|
|
|
|
*ResultBuffer = SRealloc(INFBuffer,*ResultBufferSize);
|
|
Assert(*ResultBuffer); // it was shrinking!
|
|
|
|
return(grcOkay);
|
|
}
|
|
|