Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1590 lines
48 KiB

// Copyright (c) 1996-1999 Microsoft Corporation
/* token1.c - functions to create the tokenmap */
#include "gpdparse.h"
// ---- functions defined in token1.c ---- //
BOOL BcreateTokenMap(
PWSTR pwstrFileName,
PGLOBL pglobl ) ;
PARSTATE PARSTscanForKeyword(
PDWORD pdwTKMindex,
PGLOBL pglobl) ;
PARSTATE PARSTparseColon(
PDWORD pdwTKMindex,
PGLOBL pglobl) ;
PARSTATE PARSTparseValue(
PDWORD pdwTKMindex,
PGLOBL pglobl) ;
BOOL BparseKeyword(
DWORD dwTKMindex,
PGLOBL pglobl) ;
BOOL BisExternKeyword(
DWORD dwTKMindex,
PGLOBL pglobl) ;
BOOL BisColonNext(
PGLOBL pglobl) ;
BOOL BeatArbitraryWhite(
PGLOBL pglobl) ;
BOOL BeatComment(
PGLOBL pglobl) ;
BOOL BscanStringSegment(
PGLOBL pglobl) ;
BOOL BscanDelimitedString(
BYTE ubDelimiter,
PBOOL pbMacroDetected,
PGLOBL pglobl) ;
PARSTATE PARSTrestorePrevsFile(
PDWORD pdwTKMindex,
PGLOBL pglobl) ;
PWSTR
PwstrAnsiToUnicode(
IN PSTR pstrAnsiString,
PGLOBL pglobl
) ;
PARSTATE PARSTloadIncludeFile(
PDWORD pdwTKMindex,
PWSTR pwstrFileName, // root GPD file
PGLOBL pglobl);
BOOL BloadFile(
PWSTR pwstrFileName,
PGLOBL pglobl ) ;
BOOL BarchiveStrings(
DWORD dwTKMindex,
PGLOBL pglobl) ;
DWORD DWidentifyKeyword(
DWORD dwTKMindex,
PGLOBL pglobl) ;
BOOL BidentifyAttributeKeyword(
PTKMAP ptkmap, // pointer to tokenmap
PGLOBL pglobl
) ;
BOOL BcopyToTmpHeap(
PABSARRAYREF paarDest,
PABSARRAYREF paarSrc,
PGLOBL pglobl) ;
DWORD dwStoreFileName(PWSTR pwstrFileName,
PARRAYREF parDest,
PGLOBL pglobl) ;
VOID vFreeFileNames(
PGLOBL pglobl ) ;
VOID vIdentifySource(
PTKMAP ptkmap,
PGLOBL pglobl) ;
// functions defined in preproc1.c //
BOOL BPreProcess(
PGLOBL pglobl
) ; // from current file position, use file macros to access.
BOOL DefineSymbol(
PBYTE symbol,
PGLOBL pglobl
) ;
// ---------------------------------------------------- //
// define Local Macro to access info for current file:
#define mprngDictionary ((PRANGE)(gMasterTable \
[MTI_RNGDICTIONARY].pubStruct))
// static DWORD gdwLastIndex ; // leave this in this file only!
// Now is part of the GLOBL structure.
BOOL BcreateTokenMap(
PWSTR pwstrFileName, // root GPD file
PGLOBL pglobl)
/* some things that occur within this function:
Open and memory map initial file and any files specified
by *Include.
parse keyword, init aarKeyword field, set dwFlags,
set dwKeywordID, parse Value , init aarValue,
ArchiveStrings to tempHeap. During parsing of Values,
comments and continuation lines are replaced by whitespaces.
Assume each function in switch statement increments dwTKMindex
by at most by 1. Otherwise undetected TokenMap overflow may occur.
*/
{
PTKMAP ptkmap ; // start of tokenmap
DWORD dwTKMindex = 0, // current tokenKeyMap index
dwCnt ; // counts length of keyword or value string
PBYTE pubStart ; // start address of keyword or value string
PARSTATE parst = PARST_KEYWORD ;
// note in the case of the SOURCEBUFFERS, dwCurIndex is initialized
// to zero by loadIncludeFile(). Since we never append onto
// the existing source, dwCurIndex is used to track the current
// position within the file (streamptr).
// mCurFile initialized to 0 at buffer allocation time.
gdwLastIndex = 0 ; // ok, allow BarchiveStrings() of all entries.
gmrbd.rbd.dwSrcFileChecksum32 = 0 ;
{
PBYTE symbol ;
symbol = "WINNT_40" ; // newer OSs support older OS features unless otherwise specified.
if(! DefineSymbol(symbol, pglobl))
return(FALSE) ;
#ifndef WINNT_40
symbol = "WINNT_50" ;
if(! DefineSymbol(symbol, pglobl))
return(FALSE) ;
symbol = "WINNT_51" ;
if(! DefineSymbol(symbol, pglobl))
return(FALSE) ;
#endif
if(! DefineSymbol("PARSER_VER_1.0", pglobl)) // support multiple versions at once.
return(FALSE) ;
}
if(! BloadFile(pwstrFileName, pglobl) )
{
return(FALSE) ;
}
if(!BPreProcess(pglobl) )
return(FALSE) ;
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
while(parst != PARST_EXIT)
{
if(dwTKMindex >= gMasterTable[MTI_TOKENMAP].dwArraySize)
{
ERR(("Internal: no more tokenmap elements - restart.\n"));
if(ERRSEV_RESTART > geErrorSev)
{
geErrorSev = ERRSEV_RESTART ;
geErrorType = ERRTY_MEMORY_ALLOCATION ;
gdwMasterTabIndex = MTI_TOKENMAP ;
}
return(FALSE) ;
}
switch(parst)
{
case (PARST_KEYWORD):
{
parst = PARSTscanForKeyword(&dwTKMindex, pglobl) ;
break ;
}
case (PARST_COLON):
{
parst = PARSTparseColon(&dwTKMindex, pglobl) ;
break ;
}
case (PARST_VALUE):
{
parst = PARSTparseValue(&dwTKMindex, pglobl) ;
break ;
}
case (PARST_INCLUDEFILE):
{
parst = PARSTloadIncludeFile(&dwTKMindex, pwstrFileName, pglobl) ;
if(!BPreProcess(pglobl) )
return(FALSE) ;
break ;
}
case (PARST_EOF) :
{
parst = PARSTrestorePrevsFile(&dwTKMindex, pglobl) ;
if((parst != PARST_EXIT) && !BPreProcess(pglobl) )
return(FALSE) ;
if(parst == PARST_EXIT && mdwNestingLevel && geErrorSev != ERRSEV_FATAL)
{
ERR(("EOF reached before #Endif: was parsed!\n"));
geErrorType = ERRTY_SYNTAX ;
geErrorSev = ERRSEV_FATAL ;
return(FALSE) ;
}
break ;
}
case (PARST_ABORT) :
{
return(FALSE) ; // abnormal termination.
break ;
}
default:
{
ERR(("Internal error: no other PARST_ states exist!\n"));
if(ERRSEV_FATAL > geErrorSev)
{
geErrorSev = ERRSEV_FATAL ;
geErrorType = ERRTY_CODEBUG ;
}
return(FALSE) ;
}
}
}
return(TRUE) ;
}
PARSTATE PARSTscanForKeyword(
PDWORD pdwTKMindex,
PGLOBL pglobl)
/* this function exits with 2 possible codes:
PARST_EOF: end of source file encountered - return to parent file
PARST_COLON: a keyword or symbol keyword was parsed, now expecting
a colon delimiter.
*/
{
PTKMAP ptkmap ; // start of tokenmap
// these two vars are just for inspiration, they may
// never be used.
DWORD dwCnt ; // counts length of keyword or value string
PBYTE pubStart ; // start address of keyword or value string
BYTE ubSrc ; // a src byte
/* assume:
no field in ptkmap[*pdwTKMindex] is initialized.
pass all info by saving into ptkmap.
always clear flags field and consume remainder of
line up to first linebreak char in the event of
a parsing error.
we are looking for whichever occurs first:
a) arbitrary white space
c) { or }
d) line break chars
e) *keyword
f) symbol keyword (not beginning with *)
g) any other chars is a fatal error.
*/
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
// was the previous entry an *include ?
if(*pdwTKMindex)
{
DWORD dwKeywordID, dwSubType;
dwKeywordID = ptkmap[*pdwTKMindex - 1].dwKeywordID ;
if( (dwKeywordID < ID_SPECIAL) &&
(mMainKeywordTable[dwKeywordID].eType == TY_SPECIAL))
{
dwSubType = mMainKeywordTable[dwKeywordID].dwSubType ;
if( dwSubType == SPEC_INCLUDE )
{
(*pdwTKMindex)-- ; // make this the current entry again
return(PARST_INCLUDEFILE) ;
}
else if( (dwSubType == SPEC_MEM_CONFIG_KB) ||
( dwSubType == SPEC_MEM_CONFIG_MB) )
{
BexpandMemConfigShortcut(dwSubType) ;
// checks to make sure there are
// enough slots in the tokenmap before proceeding.
}
}
if(*pdwTKMindex > gdwLastIndex &&
! BarchiveStrings(*pdwTKMindex - 1, pglobl) )
return(PARST_ABORT) ;
gdwLastIndex = *pdwTKMindex ;
// strings from each entry will get saved only once.
}
ptkmap[*pdwTKMindex].dwFileNameIndex =
mpSourcebuffer[mCurFile - 1].dwFileNameIndex ;
while( mdwSrcInd < mdwSrcMax )
{
if(!BeatArbitraryWhite(pglobl) )
break ;
ptkmap[*pdwTKMindex].dwLineNumber =
mpSourcebuffer[mCurFile - 1].dwLineNumber ;
switch(ubSrc = mpubSrcRef[mdwSrcInd])
{
case '*':
{
if(mdwSrcInd + 1 >= mdwSrcMax)
{
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("Unexpected EOF encountered parsing Keyword.\n"));
mdwSrcInd++ ; // move past * this
// will trigger EOF detector.
break ;
}
// assume it must be a keyword since it wasn't
// consumed by eatArbitraryWhite().
mdwSrcInd++ ; // move past *
if(BparseKeyword(*pdwTKMindex, pglobl) )
{
ptkmap[*pdwTKMindex].dwKeywordID =
DWidentifyKeyword(*pdwTKMindex, pglobl) ;
return(PARST_COLON) ;
}
else
{
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("syntax error in Keyword: %0.*s.\n", ptkmap[*pdwTKMindex].aarKeyword.dw + 1,
ptkmap[*pdwTKMindex].aarKeyword.pub - 1));
ptkmap[*pdwTKMindex].dwFlags = 0 ;
// must clear the flags
mdwSrcInd-- ; // go back to *
BeatComment(pglobl) ; // may place cursor at EOF
}
break ;
}
case '{':
case '}':
{
ptkmap[*pdwTKMindex].aarKeyword.pub = mpubSrcRef +
mdwSrcInd ;
ptkmap[*pdwTKMindex].aarKeyword.dw = 1 ;
ptkmap[*pdwTKMindex].aarValue.pub = 0 ;
ptkmap[*pdwTKMindex].aarValue.dw = 0 ;
ptkmap[*pdwTKMindex].dwFlags |= TKMF_NOVALUE ;
ptkmap[*pdwTKMindex].dwKeywordID =
DWidentifyKeyword(*pdwTKMindex, pglobl) ;
(*pdwTKMindex)++ ; // this is the complete entry!
mdwSrcInd++ ;
return(PARST_KEYWORD); // re-enter this function
break ; // from the top.
}
case '\x1A': // ignore control Z
mdwSrcInd++ ;
break;
case '\n':
{
BYTE ubTmp ;
mdwSrcInd++ ;
if(mdwSrcInd < mdwSrcMax)
{
ubTmp = mpubSrcRef[mdwSrcInd] ;
if(ubTmp == '\r')
{
mdwSrcInd++ ;
}
}
mpSourcebuffer[mCurFile-1].dwLineNumber++ ;
break ; // eat 'em up yum!
}
case '\r':
{
BYTE ubTmp ;
mdwSrcInd++ ;
if(mdwSrcInd < mdwSrcMax)
{
ubTmp = mpubSrcRef[mdwSrcInd] ;
if(ubTmp == '\n')
{
mdwSrcInd++ ;
}
}
mpSourcebuffer[mCurFile-1].dwLineNumber++ ;
break ; // eat 'em up yum!
}
default:
{
if(BisExternKeyword(*pdwTKMindex, pglobl) )
/* if this token matches either EXTERN_GLOBAL
or EXTERN_FEATURE */
{
if(!BisColonNext(pglobl) )
{
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("syntax error: Colon expected but missing.\n"));
ptkmap[*pdwTKMindex].dwFlags = 0 ;
// must clear the flags
// if there is a syntax error.
BeatComment(pglobl) ; // may place cursor at EOF
}
// regardless of success or failure, we
// remain in this function waiting for a *keyword.
break ;
}
// parse token as a symbolkey.
if(BparseKeyword(*pdwTKMindex, pglobl) )
{
ptkmap[*pdwTKMindex].dwKeywordID = ID_SYMBOL ;
ptkmap[*pdwTKMindex].dwFlags |= TKMF_SYMBOL_KEYWORD ;
return (PARST_COLON) ;
}
else
{
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("syntax error: valid keyword token expected: %0.*s.\n", ptkmap[*pdwTKMindex].aarKeyword.dw,
ptkmap[*pdwTKMindex].aarKeyword.pub));
ptkmap[*pdwTKMindex].dwFlags = 0 ;
BeatComment(pglobl) ; // may place cursor at EOF
}
break ;
} // end default case
} // end switch
} // end while
return(PARST_EOF) ; // falls out of for loop.
}
PARSTATE PARSTparseColon(
PDWORD pdwTKMindex,
PGLOBL pglobl)
/* this function exits with 3 possible codes:
PARST_VALUE: a colon parsed, now expecting a value.
PARST_KEYWORD: a line termination, EOF or illegal char was parsed.
ready to parse a new entry.
what looks to be a keyword has been parsed.
attempt to look for a colon or line terminator.
always clear flags field and consume remainder of
line up to first linebreak char in the event of
a parsing error.
*/
{
PTKMAP ptkmap ; // start of tokenmap
BYTE ubSrc ; // a src byte
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
if(!BeatArbitraryWhite(pglobl) )
{
// encountered EOF and no value found.
ptkmap[*pdwTKMindex].dwFlags |= TKMF_NOVALUE ;
(*pdwTKMindex)++ ; // entry complete
return(PARST_KEYWORD) ;
}
if((ubSrc = mpubSrcRef[mdwSrcInd]) == ':')
{
mdwSrcInd++ ; // now expect a value
return(PARST_VALUE) ;
}
else if(ubSrc == '\n' || ubSrc == '\r')
{
// encountered linebreak and no value found.
ptkmap[*pdwTKMindex].dwFlags |= TKMF_NOVALUE ;
(*pdwTKMindex)++ ; // entry complete
return(PARST_KEYWORD) ;
}
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("Colon expected after keyword: *%0.*s.\n", ptkmap[*pdwTKMindex].aarKeyword.dw,
ptkmap[*pdwTKMindex].aarKeyword.pub));
BeatComment(pglobl) ; // may place cursor at EOF
ptkmap[*pdwTKMindex].dwFlags = 0 ;
return(PARST_KEYWORD) ;
}
PARSTATE PARSTparseValue(
PDWORD pdwTKMindex,
PGLOBL pglobl)
/* this function exits with 1 possible codes:
PARST_KEYWORD: correctly parsed value, a line termination, EOF
or illegal char was parsed. ready to parse a new entry.
Cursor is initially just past the colon delimiter, the purpose of
this function is to locate the end of the value construct. That
is parse up to the level 0 { or } or linebreak.
Replace any comments and continuation constructs that occur
within this value with spaces.
This function makes no assumptions about the type
of value, it only assumes the value may be comprised of none, one
of more tokens (separated by optional whitespace) of the form:
LIST(aaa, bbb, ccc)
POINT(), RECT()
integer: *, + - nnnn
Symbols, CONSTANTS
"strings%"" %{command params}
qualified.names
=macroname
We cannot simply stop scanning when { or } or non-continuation
linebreak is encountered because the chars { and } may occur
within comments, strings or command parameters. Each of these
constructs are governed by different parsing rules and hence
are parsed by their own specialized functions.
This function assumes all comments are preceeded by a
white character.
*/
{
PTKMAP ptkmap ; // start of tokenmap
BYTE ubSrc ; // a src byte
DWORD dwOrgInd; // holds index of start of value.
ptkmap = (PTKMAP) (gMasterTable[MTI_TOKENMAP].pubStruct) ;
if(!BeatArbitraryWhite(pglobl) )
{
ptkmap[*pdwTKMindex].dwFlags |= TKMF_NOVALUE ;
(*pdwTKMindex)++ ; // entry complete
return(PARST_KEYWORD) ;
}
ptkmap[*pdwTKMindex].aarValue.pub = mpubSrcRef +
mdwSrcInd ;
dwOrgInd = mdwSrcInd ;
while((ubSrc = mpubSrcRef[mdwSrcInd]) != '{' && ubSrc != '}' &&
ubSrc != '\n' && ubSrc != '\r')
{
switch(ubSrc)
{
case '*': // integer wildcard
case '-': // integer neg sign
case '+': // integer plus sign
case '.': // separator for qualified name
case '?': // valid char for symbolname
case '_': // valid char for symbolname
{
mdwSrcInd++ ; // go past this
break ;
}
case ':': // additional token in value - shortcut?
{
ptkmap[*pdwTKMindex].dwFlags |= TKMF_COLON ;
mdwSrcInd++ ; // go past this
break ;
}
case '=': // macroname indicator
{
ptkmap[*pdwTKMindex].dwFlags |= TKMF_MACROREF ;
mdwSrcInd++ ; // go past this
break ;
}
case '%': // command parameter
{
if(!BscanDelimitedString('}', NULL, pglobl) )
{
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("Expected closing '}'.\n"));
ptkmap[*pdwTKMindex].dwFlags = 0 ;
return(PARST_KEYWORD) ;
}
break ;
}
case '"' : // this is a string construct
{
mdwSrcInd++ ; // go past this
if(!BscanStringSegment(pglobl) )
{
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("Error parsing string segment: %0.*s.\n",
mdwSrcInd - dwOrgInd,
ptkmap[*pdwTKMindex].aarValue.pub));
ptkmap[*pdwTKMindex].dwFlags = 0 ;
return(PARST_KEYWORD) ;
}
break ;
}
case '(': // arg list for LIST, POINT or RECT
{
BOOL bMacroDetected ;
if(!BscanDelimitedString(')', &bMacroDetected, pglobl) )
{
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("Expected closing ')'.\n"));
ptkmap[*pdwTKMindex].dwFlags = 0 ;
return(PARST_KEYWORD) ;
}
if(bMacroDetected)
ptkmap[*pdwTKMindex].dwFlags |= TKMF_MACROREF ;
break ;
}
default:
{
if( (ubSrc >= 'a' && ubSrc <= 'z') ||
(ubSrc >= 'A' && ubSrc <= 'Z') ||
(ubSrc >= '0' && ubSrc <= '9') )
{
mdwSrcInd++ ; // looks legal, next char
break ;
}
else
{
vIdentifySource(ptkmap + *pdwTKMindex, pglobl) ;
ERR(("illegal char encountered parsing value: %0.*s.\n",
mdwSrcInd - dwOrgInd,
ptkmap[*pdwTKMindex].aarValue.pub));
ERR((" Line ignored.\n")) ;
ptkmap[*pdwTKMindex].dwFlags = 0 ;
BeatComment(pglobl) ;
ptkmap[*pdwTKMindex].dwKeywordID = gdwID_IgnoreBlock;
(*pdwTKMindex)++ ; // entry complete
return(PARST_KEYWORD) ;
}
}
}
if(!BeatArbitraryWhite(pglobl) )
{
ptkmap[*pdwTKMindex].aarValue.dw =
mdwSrcInd - dwOrgInd ;
if(!(mdwSrcInd - dwOrgInd))
ptkmap[*pdwTKMindex].dwFlags |= TKMF_NOVALUE ;
(*pdwTKMindex)++ ; // entry complete
return(PARST_KEYWORD) ; // end of file encountered.
}
}
ptkmap[*pdwTKMindex].aarValue.dw = mdwSrcInd - dwOrgInd ;
if(!(mdwSrcInd - dwOrgInd))
ptkmap[*pdwTKMindex].dwFlags |= TKMF_NOVALUE ;
(*pdwTKMindex)++ ; // entry complete
return(PARST_KEYWORD) ;
}
/* all of the following helper functions
leaves the cursor after the object being parsed
if successful, otherwise cursor is unchanged
except for consuming leading whitespace.
Return value means sucess in parsing or
simply that EOF was not encountered, see
specific function. */
BOOL BparseKeyword(
DWORD dwTKMindex,
PGLOBL pglobl)
/* assumes mdwSrcInd points to start of keyword (char
just after *). Determine end of keyword. mdwSrcInd advanced
past end of keyword. Initializes tokenmap entry aarKeyword.
*/
{
PTKMAP ptkmap ; // start of tokenmap
DWORD dwCnt ; // counts length of keyword or value string
BYTE ubSrc ; // a src byte
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
ptkmap[dwTKMindex].aarKeyword.pub = mpubSrcRef +
mdwSrcInd ;
for(dwCnt = 0 ; mdwSrcInd < mdwSrcMax ; mdwSrcInd++, dwCnt++)
{
ubSrc = mpubSrcRef[mdwSrcInd] ;
if(ubSrc == '?')
{
mdwSrcInd++ ;
dwCnt++ ;
break; // the ? char is permitted as a terminator only.
}
if( (ubSrc < 'a' || ubSrc > 'z') &&
(ubSrc < 'A' || ubSrc > 'Z') &&
(ubSrc < '0' || ubSrc > '9') &&
(ubSrc != '_') )
{
break ; // end of keyword token.
}
}
ptkmap[dwTKMindex].aarKeyword.dw = dwCnt ;
return(dwCnt != 0);
}
BOOL BisExternKeyword(
DWORD dwTKMindex,
PGLOBL pglobl)
/* if this token matches either EXTERN_GLOBAL
or EXTERN_FEATURE, this function sets the approp
flag in the tokenentry, advances mdwSrcInd past
qualifier and returns true. Else it leaves everything
undisturbed and returns false.
*/
{
PTKMAP ptkmap ; // start of tokenmap
DWORD dwCnt ; // counts length of keyword or value string
BYTE ubSrc ; // a src byte
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
if((dwCnt = strlen("EXTERN_GLOBAL"))
&& (mdwSrcInd + dwCnt <= mdwSrcMax)
&& !strncmp(mpubSrcRef + mdwSrcInd , "EXTERN_GLOBAL", dwCnt ))
{
ptkmap[dwTKMindex].dwFlags |= TKMF_EXTERN_GLOBAL ;
}
else if(dwCnt = strlen("EXTERN_FEATURE") &&
mdwSrcInd + dwCnt <= mdwSrcMax &&
!strncmp(mpubSrcRef + mdwSrcInd , "EXTERN_FEATURE", dwCnt ))
{
ptkmap[dwTKMindex].dwFlags |= TKMF_EXTERN_FEATURE ;
}
else
return(FALSE);
mdwSrcInd += dwCnt ; // skip past qualifier
return(TRUE);
}
BOOL BisColonNext(
PGLOBL pglobl)
{
if(BeatArbitraryWhite(pglobl) && mpubSrcRef[mdwSrcInd] == ':')
{
mdwSrcInd++ ; // advance past colon.
return(TRUE) ;
}
return(FALSE); // leave pointing to non-colon object.
}
BOOL BeatArbitraryWhite(
PGLOBL pglobl)
/* does nothing if not positioned
at arbitrary whitespace, returns FALSE
only if EOF is encountered.
Will replace comments and continuation constructs
with spaces.
*/
{
BYTE ubSrc ; // a src byte
while( mdwSrcInd < mdwSrcMax )
{
switch(ubSrc = mpubSrcRef[mdwSrcInd])
{
case '*': // a comment?
{
if(mdwSrcInd + 1 < mdwSrcMax &&
mpubSrcRef[mdwSrcInd + 1] == '%')
{
if(!BeatComment(pglobl) ) // leave pointing at linebreak.
return(FALSE) ; // reached EOF.
}
else
return(TRUE) ; // reached non-white.
break ;
}
case ' ':
case '\t':
{
mdwSrcInd++ ; // go to next char
break ;
}
case '\r': // eat continuation constructs
case '\n': // do not process normal EOL chars.
{
BYTE ubTmp ;
if(mdwSrcInd + 1 < mdwSrcMax)
{
ubTmp = mpubSrcRef[mdwSrcInd + 1] ;
if(ubTmp == '+')
{
mpubSrcRef[mdwSrcInd] = ' ' ;
mpubSrcRef[mdwSrcInd + 1] = ' ' ;
mdwSrcInd += 2 ; // skip past '+'
mpSourcebuffer[mCurFile-1].dwLineNumber++ ;
break ;
}
else if( ((ubTmp == '\n') || (ubTmp == '\r'))
&& (ubTmp != ubSrc)
&& (mdwSrcInd + 2 < mdwSrcMax)
&& (mpubSrcRef[mdwSrcInd + 2] == '+') )
{
mpubSrcRef[mdwSrcInd] = ' ' ;
mpubSrcRef[mdwSrcInd + 1] = ' ' ;
mpubSrcRef[mdwSrcInd + 2] = ' ' ;
mdwSrcInd += 3 ; // skip past '+'
mpSourcebuffer[mCurFile-1].dwLineNumber++ ;
break ;
}
}
return(TRUE) ; // reached logical linebreak.
}
default:
return(TRUE) ; // reached non-white.
}
}
return(FALSE) ; // reached EOF.
}
BOOL BeatComment(
PGLOBL pglobl)
// replaces entire comment with spaces until
// linebreak char or EOF is encountered.
{
BYTE ubSrc ; // a src byte
for( ; mdwSrcInd < mdwSrcMax ; mdwSrcInd++)
{
ubSrc = mpubSrcRef[mdwSrcInd] ;
if(ubSrc == '\n' || ubSrc == '\r' )
return(TRUE) ; // reached linebreak char.
mpubSrcRef[mdwSrcInd] = ' ' ; // replace with space.
}
return(FALSE) ; // reached EOF.
}
BOOL BscanStringSegment(
PGLOBL pglobl)
// cursor set just after first "
{
BYTE ubSrc = '\0', // a src byte
ubPrevs ;
while( mdwSrcInd < mdwSrcMax )
{
ubPrevs = ubSrc ;
ubSrc = mpubSrcRef[mdwSrcInd] ;
if(ubSrc == '<' && ubPrevs != '%')
{
mdwSrcInd++ ; // skip <
if(!BscanDelimitedString('>', NULL, pglobl) )
{
ERR(("\nMissing closing > in string segment.\n"));
return(FALSE) ;
}
continue ; // leaves cursor pointing after '>'
}
else if(ubSrc == '"' && ubPrevs != '%')
{
mdwSrcInd++ ; // end of literal string
return(TRUE) ;
}
else if(ubSrc == '\n' || ubSrc == '\r')
break ;
else
mdwSrcInd++ ; // scan through string
}
ERR(("\nLinebreak or EOF was encountered while parsing string segment.\n"));
return(FALSE) ;
}
BOOL BscanDelimitedString(
BYTE ubDelimiter, // the byte that signifies the end.
PBOOL pbMacroDetected, // set true if '=' was encountered.
PGLOBL pglobl)
// cursor set just after first <
{
BYTE ubSrc ; // a src byte
if(pbMacroDetected)
*pbMacroDetected = FALSE;
while( mdwSrcInd < mdwSrcMax )
{
ubSrc = mpubSrcRef[mdwSrcInd] ;
if(ubSrc == ubDelimiter)
{ // end of hex substring construct
mdwSrcInd++ ;
return(TRUE) ;
}
else if(ubSrc == ' ' || ubSrc == '\t' ||
ubSrc == '\n' || ubSrc == '\r')
{
if(!BeatArbitraryWhite(pglobl) )
break ;
ubSrc = mpubSrcRef[mdwSrcInd] ;
if(ubSrc == '\n' || ubSrc == '\r')
break ;
}
else
{
mdwSrcInd++ ; // keep parsing
if(ubSrc == '=' && pbMacroDetected)
*pbMacroDetected = TRUE ;
}
}
ERR(("unexpected linebreak or EOF.\n"));
return(FALSE) ; // BUG_BUG! unexpected linebreak or EOF
// in hex substring if delimiter was >
// LIST, POINT, etc if delimiter was ).
// command parameter if delimiter was }
}
PARSTATE PARSTrestorePrevsFile(
PDWORD pdwTKMindex,
PGLOBL pglobl)
/* this function exits with 2 possible codes:
PARST_EXIT: no more files left in stack !
PARST_KEYWORD: returned to prevs file. Ready to
resume parsing of new tokenmap entry.
The only function that issues PARST_EOF is parseKeyword().
It handles all processing for the previous keyword.
*/
{
PTKMAP ptkmap ; // start of tokenmap
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
mCurFile-- ; // pop stack
MemFree(mpSourcebuffer[mCurFile].pubSrcBuf) ;
if(mCurFile)
return(PARST_KEYWORD) ;
ptkmap[*pdwTKMindex].dwKeywordID = ID_EOF ;
(*pdwTKMindex)++ ;
// this is the last entry in the tokenmap.
return(PARST_EXIT) ; // reached end of rootfile.
}
PWSTR
PwstrAnsiToUnicode(
IN PSTR pstrAnsiString,
PGLOBL pglobl
)
/*++
Routine Description:
Make a Unicode copy of the input ANSI string
Warning: caller must delete Unicode copy when finished
Arguments:
pstrAnsiString - Pointer to the input ANSI string
Return Value:
Pointer to the resulting Unicode string
NULL if there is an error
--*/
{
PWSTR pwstr; // holds Unicode string
DWORD dwLen ;
ASSERT(pstrAnsiString != NULL);
dwLen = strlen(pstrAnsiString) + 1;
if (pwstr = (PWSTR)MemAlloc(dwLen * sizeof(WCHAR)))
{
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pstrAnsiString, dwLen,
pwstr, dwLen);
//
// Make sure the Unicode string is null-terminated
//
pwstr[dwLen - 1] = NUL;
}
else
{
ERR(("Fatal: unable to alloc requested memory: %d bytes.\n",
dwLen * sizeof(WCHAR)));
geErrorType = ERRTY_MEMORY_ALLOCATION ;
geErrorSev = ERRSEV_FATAL ;
}
return pwstr;
}
PARSTATE PARSTloadIncludeFile(
PDWORD pdwTKMindex,
PWSTR pwstrRootFileName, // root GPD file
PGLOBL pglobl)
/* this function exits with 2 possible codes:
PARST_ABORT: unable to read included file, force termination.
PARST_KEYWORD: opened file, updated SOURCEBUFFER stack,
ready to parse a new tokenmap entry which will overwrite the
*Include entry.
pdwTKMindex points to tokenmap entry containing the
*include keyword.
Each Memory Mapped file is referenced by a SOURCEBUFFER
structure.
typedef struct
{
PBYTE pubSrcBuf ; // start of file bytes.
DWORD dwCurIndex ; // stream ptr
DWORD dwArraySize ; // filesize
PWSTR pwstrFileName ;
HFILEMAP hFile ; // used to access/close file.
} SOURCEBUFFER, * PSOURCEBUFFER ;
// the tagname is 'sb'
*/
{
PTKMAP ptkmap ; // start of tokenmap
ARRAYREF arStrValue ; // dest for BparseString.
PWSTR pwstrFileName ; // , pwstrFullyQualifiedName = NULL;
WCHAR * pwDLLQualifiedName = NULL ;
PBYTE pubFileName ;
PARSTATE parst = PARST_KEYWORD;
PWSTR pwstrLastBackSlash ;
DWORD pathlen = 0 ;
DWORD namelen = 0 ;
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
// does a value exist?
if(ptkmap[*pdwTKMindex].dwFlags & TKMF_NOVALUE ||
!BparseString(&(ptkmap[*pdwTKMindex].aarValue), &arStrValue, pglobl) )
{
ERR(("syntax error in filename for *Include keyword.\n"));
// fatal error. override initial error code.
return(PARST_ABORT) ;
}
#if !defined(DEVSTUDIO)
// nothing here !
#endif
pubFileName = mpubOffRef + arStrValue.loOffset ;
pwstrFileName = PwstrAnsiToUnicode(pubFileName, pglobl) ;
if(!pwstrFileName)
{
parst = PARST_ABORT ;
goto FREE_MEM ;
}
#if !defined(DEVSTUDIO)
// how large should pwDLLQualifiedName be???
pathlen = wcslen(pwstrRootFileName) ;
namelen = pathlen + wcslen(pwstrFileName) + 1;
if (!(pwDLLQualifiedName =
(PWSTR)MemAlloc(namelen * sizeof(WCHAR)) ))
{
ERR(("Fatal: unable to alloc requested memory: %d WCHARs.\n",
namelen));
geErrorType = ERRTY_MEMORY_ALLOCATION ;
geErrorSev = ERRSEV_FATAL ;
return(PARST_ABORT) ;
}
wcsncpy(pwDLLQualifiedName, pwstrRootFileName , namelen);
if (pwstrLastBackSlash = wcsrchr(pwDLLQualifiedName,TEXT('\\')))
{
*(pwstrLastBackSlash + 1) = NUL;
// wcscat(pwDLLQualifiedName, pwstrFileName) ;
StringCchCatW(pwDLLQualifiedName, namelen, pwstrFileName);
}
else
{
ERR(("Internal Error: Must specify fully qualified path to Root GPD file.\n"));
// fatal error. override initial error code.
parst = PARST_ABORT ;
goto FREE_MEM ;
}
if(! BloadFile(pwDLLQualifiedName, pglobl) )
#else
if(! BloadFile(pwstrFileName, pglobl) )
#endif
parst = PARST_ABORT ;
else
parst = PARST_KEYWORD ;
FREE_MEM:
if(pwstrFileName)
MemFree(pwstrFileName) ;
if(pwDLLQualifiedName)
MemFree(pwDLLQualifiedName) ;
return(parst) ;
}
BOOL BloadFile(
PWSTR pwstrFileName,
PGLOBL pglobl)
{
PBYTE pub ;
PGPDFILEDATEINFO pfdi ;
DWORD dwNodeIndex ;
HANDLE hFile;
// mCurFile points to first uninitialized SOURCEBUFFER element
if(mCurFile >= mMaxFiles)
{
// nesting level too deep.
if(ERRSEV_RESTART > geErrorSev)
{
geErrorSev = ERRSEV_RESTART ;
geErrorType = ERRTY_MEMORY_ALLOCATION ;
gdwMasterTabIndex = MTI_SOURCEBUFFER ;
}
return(FALSE) ;
}
pfdi = (PGPDFILEDATEINFO) gMasterTable[MTI_GPDFILEDATEINFO].pubStruct ;
// address of first GPDFILEDATEINFO struct
if(! BallocElementFromMasterTable(MTI_GPDFILEDATEINFO , &dwNodeIndex, pglobl) )
{
return(FALSE) ;
}
mpSourcebuffer[mCurFile].dwFileNameIndex =
dwStoreFileName(pwstrFileName, &pfdi[dwNodeIndex].arFileName, pglobl) ;
// store Unicode representation of filename for diagnostic purposes.
if(mpSourcebuffer[mCurFile].dwFileNameIndex == INVALID_INDEX)
{
return(FALSE) ; // something failed
}
mpSourcebuffer[mCurFile].dwLineNumber = 1 ; // new rule: line 0 does not exist.
mpSourcebuffer[mCurFile].hFile = MapFileIntoMemory(
pwstrFileName, (PVOID *)&(pub),
&(mpSourcebuffer[mCurFile].dwArraySize)) ;
if(!mpSourcebuffer[mCurFile].hFile || !pub)
{
ERR(("unable to open GPD file: %S\n", pwstrFileName));
// set fatal error
geErrorSev = ERRSEV_FATAL ;
geErrorType = ERRTY_FILE_OPEN ;
return(FALSE) ;
}
// mapping successful. allocate writable buffer.
mpSourcebuffer[mCurFile].pubSrcBuf =
MemAlloc(mpSourcebuffer[mCurFile].dwArraySize) ;
if(!(mpSourcebuffer[mCurFile].pubSrcBuf))
{
ERR(("Fatal: unable to alloc requested memory: %d bytes.\n",
mpSourcebuffer[mCurFile].dwArraySize));
geErrorType = ERRTY_MEMORY_ALLOCATION ;
geErrorSev = ERRSEV_FATAL ;
gdwMasterTabIndex = MTI_SOURCEBUFFER ;
UnmapFileFromMemory(mpSourcebuffer[mCurFile].hFile) ;
return(FALSE) ; // This is unrecoverable
}
memcpy(mpSourcebuffer[mCurFile].pubSrcBuf,
pub, mpSourcebuffer[mCurFile].dwArraySize) ;
UnmapFileFromMemory(mpSourcebuffer[mCurFile].hFile) ;
// reopen to determine timestamp.
hFile = CreateFile(pwstrFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
if(!GetFileTime(hFile, NULL, NULL,
&pfdi[dwNodeIndex].FileTime) )
{
ERR(("GetFileTime '%S' failed.\n", pwstrFileName));
}
CloseHandle(hFile);
}
else
{
geErrorSev = ERRSEV_FATAL;
geErrorType = ERRTY_FILE_OPEN;
ERR(("CreateFile '%S' failed.\n", pwstrFileName));
}
gmrbd.rbd.dwSrcFileChecksum32 =
ComputeCrc32Checksum(
mpSourcebuffer[mCurFile].pubSrcBuf,
mpSourcebuffer[mCurFile].dwArraySize,
gmrbd.rbd.dwSrcFileChecksum32 ) ;
mCurFile++ ; // we now have an open file on the stack
mdwSrcInd = 0 ; // initialize stream ptr to start of file.
return(TRUE) ;
}
BOOL BarchiveStrings(
DWORD dwTKMindex,
PGLOBL pglobl)
/*
you see the Memory Mapped file only exists until
parsing reaches EOF. At that time its closed.
And all the aars stored in the tokenmap become useless.
So to extend their lifetime, we copy the strings to
a temporary heap. A heap that isn't going to be
saved as part of the GPD binary file.
*/
{
PTKMAP ptkmap ; // start of tokenmap
DWORD dwKeywordID ;
ABSARRAYREF aarDest ;
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
dwKeywordID = ptkmap[dwTKMindex].dwKeywordID ;
if((dwKeywordID != ID_NULLENTRY) && (dwKeywordID != ID_EOF) )
{
// copy keyword string over
if(!BcopyToTmpHeap(&aarDest, &(ptkmap[dwTKMindex].aarKeyword), pglobl))
return(FALSE) ;
ptkmap[dwTKMindex].aarKeyword.pub = aarDest.pub ;
ptkmap[dwTKMindex].aarKeyword.dw = aarDest.dw ;
if(!(ptkmap[dwTKMindex].dwFlags & TKMF_NOVALUE))
{
// copy value string over.
if(!BcopyToTmpHeap(&aarDest, &(ptkmap[dwTKMindex].aarValue), pglobl))
return(FALSE) ;
ptkmap[dwTKMindex].aarValue.pub = aarDest.pub ;
ptkmap[dwTKMindex].aarValue.dw = aarDest.dw ;
}
}
return(TRUE) ;
}
DWORD DWidentifyKeyword(
DWORD dwTKMindex,
PGLOBL pglobl)
/* assumes keywords are not symbol keywords.
if they are attribute keywords they will be labeled
as ID_UNRECOGNIZED.
returns (KeywordID) */
{
PTKMAP ptkmap ; // start of tokenmap
DWORD dwCnt ; // counts length of keyword or value string
DWORD dwKeyID ; // array index of MainKeywordTable
// also serves as the keywordID
PBYTE pubKey ;
DWORD dwStart, dwEnd ;
ptkmap = (PTKMAP) gMasterTable[MTI_TOKENMAP].pubStruct ;
if(ptkmap[dwTKMindex].dwFlags & TKMF_SYMBOL_KEYWORD)
{
return(ID_SYMBOL) ; // safety net.
}
dwStart = mprngDictionary[NON_ATTR].dwStart ;
dwEnd = mprngDictionary[NON_ATTR].dwEnd ;
for(dwKeyID = dwStart ; dwKeyID < dwEnd ; dwKeyID++ )
{
pubKey = mMainKeywordTable[dwKeyID].pstrKeyword ;
dwCnt = strlen(pubKey) ;
if(dwCnt != ptkmap[dwTKMindex].aarKeyword.dw)
continue ;
if(strncmp(ptkmap[dwTKMindex].aarKeyword.pub, pubKey, dwCnt))
continue ;
return(dwKeyID);
}
return(ID_UNRECOGNIZED) ; // does not attempt to identify
// attributes, this is done in BInterpretTokens().
}
BOOL BidentifyAttributeKeyword(
PTKMAP ptkmap, // pointer to tokenmap
PGLOBL pglobl
)
/*
// Assume this is an attribute keyword.
// If the flags TKMF_EXTERN_GLOBAL or _FEATURE
// the GPD author is explicitly identifying
// this as an attribute. Else look at the current
// state as an indication of which attribute dictionary
// to look at.
*/
{
DWORD dwKeywordID ;
STATE stOldState;
KEYWORD_SECTS eSection ;
DWORD dwStart, dwEnd , dwKeyID,
dwCnt ; // counts length of keyword or value string
PBYTE pubKey ;
if(ptkmap->dwFlags & TKMF_EXTERN_GLOBAL )
eSection = GLOBAL_ATTR ;
else if(ptkmap->dwFlags & TKMF_EXTERN_FEATURE )
eSection = FEATURE_ATTR ;
else
{
if(mdwCurStsPtr)
stOldState = mpstsStateStack[mdwCurStsPtr - 1].stState ;
else
stOldState = STATE_ROOT ;
switch(stOldState)
{
case (STATE_ROOT):
case (STATE_CASE_ROOT):
case (STATE_DEFAULT_ROOT):
{
eSection = GLOBAL_ATTR;
break ;
}
case (STATE_FEATURE):
case (STATE_CASE_FEATURE):
case (STATE_DEFAULT_FEATURE):
{
eSection = FEATURE_ATTR;
break ;
}
case (STATE_OPTIONS):
case (STATE_CASE_OPTION):
case (STATE_DEFAULT_OPTION):
{
eSection = OPTION_ATTR;
break ;
}
case (STATE_COMMAND):
{
eSection = COMMAND_ATTR;
break ;
}
case (STATE_FONTCART):
{
eSection = FONTCART_ATTR ;
break ;
}
case (STATE_TTFONTSUBS):
{
eSection = TTFONTSUBS_ATTR ;
break ;
}
case (STATE_OEM):
{
eSection = OEM_ATTR ;
break ;
}
default: // STATE_UIGROUP, STATE_SWITCH_anything etc.
{
return(FALSE); // no attributes allowed in this state.
}
}
}
dwStart = mprngDictionary[eSection].dwStart ;
dwEnd = mprngDictionary[eSection].dwEnd ;
for(dwKeyID = dwStart ; dwKeyID < dwEnd ; dwKeyID++ )
{
pubKey = mMainKeywordTable[dwKeyID].pstrKeyword ;
dwCnt = strlen(pubKey) ;
if(dwCnt != ptkmap->aarKeyword.dw)
continue ;
if(strncmp(ptkmap->aarKeyword.pub, pubKey, dwCnt))
continue ;
ptkmap->dwKeywordID = dwKeyID;
return(TRUE);
}
return(FALSE); // keyword not found in dictionary.
}
BOOL BcopyToTmpHeap(
PABSARRAYREF paarDest,
PABSARRAYREF paarSrc,
PGLOBL pglobl)
/* copy aarstring to the temp heap
does not create null terminated strings! */
{
#define mpubOffReft (gMasterTable[MTI_TMPHEAP].pubStruct)
#define mloCurHeapt (gMasterTable[MTI_TMPHEAP].dwCurIndex)
#define mdwMaxHeapt (gMasterTable[MTI_TMPHEAP].dwArraySize)
if(mloCurHeapt + paarSrc->dw >= mdwMaxHeapt)
{
ERR(("Out of heap space, restart.\n"));
if(ERRSEV_RESTART > geErrorSev)
{
geErrorSev = ERRSEV_RESTART ;
geErrorType = ERRTY_MEMORY_ALLOCATION ;
gdwMasterTabIndex = MTI_TMPHEAP ;
}
return(FALSE) ;
}
paarDest->dw = paarSrc->dw ;
paarDest->pub = mpubOffReft + mloCurHeapt ;
memcpy(paarDest->pub, paarSrc->pub, paarSrc->dw ) ;
mloCurHeapt += paarSrc->dw ;
return(TRUE) ;
#undef mpubOffReft
#undef mloCurHeapt
#undef mdwMaxHeapt
}
#define mCurFileName (gMasterTable[MTI_FILENAMES].dwCurIndex)
#define mpFileNamesArray ((PWSTR *)(gMasterTable \
[MTI_FILENAMES].pubStruct))
DWORD dwStoreFileName(PWSTR pwstrFileName,
PARRAYREF parDest,
PGLOBL pglobl)
// goes into a permanent
// stack of filenames - to be deleted at return buffers
// time. Returns index in array where name has been
// stored.
// also saves filename into heap. So we can access the GPD file
// and check its timestamp whenever we load the BUD file.
{
DWORD dwNodeIndex, dwLen ;
if(!BallocElementFromMasterTable(MTI_FILENAMES, &dwNodeIndex, pglobl))
return(INVALID_INDEX) ;
dwLen = wcslen(pwstrFileName) + 1 ; // need room for terminating null.
mpFileNamesArray[dwNodeIndex] = MemAlloc(dwLen * 2) ;
if(!mpFileNamesArray[dwNodeIndex])
{
ERR(("Fatal: unable to alloc requested memory: %d bytes.\n",
dwLen * 2));
geErrorType = ERRTY_MEMORY_ALLOCATION ;
geErrorSev = ERRSEV_FATAL ;
return(INVALID_INDEX) ;
}
// wcscpy(mpFileNamesArray[dwNodeIndex], pwstrFileName) ;
StringCchCopyW(mpFileNamesArray[dwNodeIndex], dwLen, pwstrFileName) ;
parDest->dwCount = (dwLen - 1) * 2 ; // doesn't include the NUL term.
if(!BwriteToHeap(&parDest->loOffset, (PBYTE)pwstrFileName, dwLen * 2, 2, pglobl) ) // includes Null termination
return(INVALID_INDEX) ;
return(dwNodeIndex) ;
}
VOID vFreeFileNames(
PGLOBL pglobl )
{
// free all buffers holding the filenames.
while(mCurFileName)
{
mCurFileName-- ; // pop stack
MemFree(mpFileNamesArray[mCurFileName]) ;
}
}
VOID vIdentifySource(
PTKMAP ptkmap,
PGLOBL pglobl )
{
PWSTR pwstrFileName ;
if(ptkmap->dwKeywordID == ID_EOF)
{
ERR(("\nEnd of File reached.\n")) ;
return;
}
pwstrFileName = mpFileNamesArray[ptkmap->dwFileNameIndex] ;
if(pwstrFileName)
#if defined(DEVSTUDIO) // Emit compiler-style line messages
ERR(("\n%S(%d): ", pwstrFileName, ptkmap->dwLineNumber)) ;
#else
ERR(("\n%S: line: %d ...\n", pwstrFileName, ptkmap->dwLineNumber)) ;
#endif
}
#undef mCurFileName
#undef mpFileNamesArray