#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); }