windows-nt/Source/XPSP1/NT/sdktools/hsplit/hsparse.c
2020-09-26 16:20:57 +08:00

1404 lines
39 KiB
C

/****************************** Module Header ******************************\
* Module Name: hsparse.c
*
* Copyright (c) 1985-96, Microsoft Corporation
*
* 09/05/96 GerardoB Created
\***************************************************************************/
#include "hsplit.h"
/***************************************************************************\
* Globals
\***************************************************************************/
/*
* #if - #endif strings
* Compatibility: no space after #if and ( -- breaks wcshdr.exe
*/
static char gszIfStart [] = "\r\n#if(" ;
static char gszIfStop [] = ")";
static char gszDefCompOperator [] = ">=";
static char gszLessThan [] = "<";
static char gszEndStart [] = "\r\n#endif /* ";
static char gszEndStop [] = " */";
static char gszNewLine [] = "\r\n";
/*********************************************************************
* hsWriteNewLine
\***************************************************************************/
__inline BOOL hsWriteNewLine (DWORD dwMask)
{
return hsWriteHeaderFiles(gszNewLine, sizeof(gszNewLine)-1, dwMask);
}
/***************************************************************************\
* hsFindFirstSubTag
\***************************************************************************/
char * hsFindFirstSubTag(char * pmap)
{
/*
* pmap points to the beginning of the tag marker. So skip it
* and any spaces after it
*/
pmap += gdwTagMarkerSize;
while (pmap < gpmapEnd) {
if (*pmap == ' ') {
pmap++;
} else {
return pmap;
}
}
hsLogMsg(HSLM_EOFERROR, "hsFindFirstSubTag");
return NULL;
}
/*********************************************************************
* hsFindFirstCharInString
*
* Finds the first occurrence of any character in psz
\***************************************************************************/
char * hsFindFirstCharInString (char * pmap, char * psz)
{
char * pszNext;
while (pmap < gpmapEnd) {
/*
* Compare current char to all chars in psz
*/
pszNext = psz;
do {
if (*pmap == *pszNext++) {
return pmap;
}
} while (*pszNext != '\0');
pmap++;
}
return NULL;
}
/*********************************************************************
* hsFindEndOfString
\***************************************************************************/
__inline char * hsFindEndOfString (char * pmap)
{
return hsFindFirstCharInString(pmap, " " "\r");
}
/***************************************************************************\
* hsIsString
\***************************************************************************/
BOOL hsIsString (char * pmap, char * psz)
{
while (*psz != '\0') {
if (pmap >= gpmapEnd) {
return FALSE;
}
if (*pmap++ != *psz++) {
return FALSE;
}
}
return TRUE;
}
/***************************************************************************\
* hsFindTagMarker
\***************************************************************************/
char * hsFindTagMarker(char * pmap, char ** ppmapLineStart)
{
char * pmapMarker;
while (pmap < gpmapEnd) {
/*
* If this is the first character of the marker
*/
if (*pmap == *gpszTagMarker) {
/*
* If this is the marker, find the last one in this line
*/
if (hsIsString(pmap + 1, gpszTagMarker + 1)) {
pmapMarker = pmap++;
do {
/*
* Find the EOL or the first char of the next marker
*/
pmap = hsFindFirstCharInString(pmap, gszMarkerCharAndEOL);
/*
* If EOL or end of map, return
*/
if ((pmap == NULL) || (*pmap != *gpszTagMarker)) {
return pmapMarker;
}
/*
* If this is the marker, update pmapMarker
*/
if (hsIsString(pmap + 1, gpszTagMarker + 1)) {
pmapMarker = pmap;
}
/*
* It wasn't a marker, keep looking for EOL
*/
pmap++;
} while (TRUE);
} else {
/*
* This wasn't the marker, continue parsing
*/
pmap++;
continue;
}
} /* if (*pmap == *gpszTagMarker) */
/*
* If this is the end of a line, update *ppmapLineStart and
* gdwLineNumber. The line begins before the EOL
*/
if (*pmap++ == '\r') {
if (pmap >= gpmapEnd) {
hsLogMsg(HSLM_EOFERROR, "hsFindTagMarker");
return NULL;
}
if (*pmap++ != '\n') {
hsLogMsg(HSLM_ERROR, "Missing \\n after \\r");
return FALSE;
}
*ppmapLineStart = pmap - 2;
gdwLineNumber++;
continue;
}
} /* while (pmap < pmapEnd) */
return NULL;
}
/***************************************************************************\
* hsSkipTag
\***************************************************************************/
char * hsSkipTag(char * pmap)
{
while (pmap < gpmapEnd) {
switch (*pmap) {
case '_':
case ' ':
case '\r':
return pmap;
default:
pmap++;
}
}
hsLogMsg(HSLM_EOFERROR, "hsSkipTag");
return NULL;
}
/***************************************************************************\
* hsSkipEmptyLines
* If there are multiple empty lines, skip all but one
\***************************************************************************/
char * hsSkipEmptyLines(char * pmap)
{
char * pmapCurrentLine, *pmapLastEmptyLine;
pmapCurrentLine = pmapLastEmptyLine = pmap;
pmap++;
while (pmap < gpmapEnd) {
switch (*pmap) {
case '\r':
gdwLineNumber++;
pmapLastEmptyLine = pmapCurrentLine;
pmapCurrentLine = pmap;
case '\n':
case ' ':
pmap++;
break;
default:
/*
* If we've found more than one line,
* adjust line number since we're not skipping
* the last line we found
*/
if (pmapCurrentLine != pmapLastEmptyLine) {
gdwLineNumber--;
}
return pmapLastEmptyLine;
}
}
return gpmapEnd;
}
/***************************************************************************\
* hsIsEmpty
* Returns TRUE if there is nothing but spaces and \r\n
\***************************************************************************/
BOOL hsIsEmpty(char * pmap, char * pmapEnd)
{
while (pmap < pmapEnd) {
switch (*pmap++) {
case '\n':
case '\r':
case ' ':
break;
default:
return FALSE;
}
}
return TRUE;
}
/***************************************************************************\
* hsLastRealChar
* Returns a pointer past the last non-space non-line-break char.
* If there are multiple empty lines, returns a pointer past the last line break
\***************************************************************************/
char * hsLastRealChar(char * pmapLinesStart, char * pmap)
{
char * pmapCurrentLine, *pmapLastEmptyLine;
pmap--;
pmapCurrentLine = pmapLastEmptyLine = NULL;
while (pmapLinesStart < pmap) {
switch (*pmap) {
case '\n':
pmapLastEmptyLine = pmapCurrentLine;
pmapCurrentLine = pmap;
case '\r':
case ' ':
pmap--;
break;
default:
goto FoundIt;
}
}
FoundIt:
/*
* If we found multiple lines or spaces,
* then return a pointer to the last empty line
* else if we didn't reach pmapLinesStart, we're at the last real char
* else we're on an empty line
*/
if (pmapLastEmptyLine != pmapCurrentLine) {
if (pmapLastEmptyLine != NULL) {
return pmapLastEmptyLine + 1;
} else {
return pmapCurrentLine + 1;
}
} else if (pmap > pmapLinesStart) {
return pmap + 1;
} else {
return pmapLinesStart;
}
}
/***************************************************************************\
* hsFindEOL
*
\***************************************************************************/
char * hsFindEOL(char * pmap)
{
while (pmap < gpmapEnd) {
if (*pmap++ == '\r') {
if (pmap >= gpmapEnd) {
hsLogMsg(HSLM_EOFERROR, "hsFindEOL");
return NULL;
}
if (*pmap != '\n') {
hsLogMsg(HSLM_ERROR, "Missing \\n after \\r");
return NULL;
}
gdwLineNumber++;
return pmap - 1;
}
}
return NULL;
}
/***************************************************************************\
* hsFindTagInList
*
\***************************************************************************/
PHSTAG hsFindTagInList (PHSTAG phst, char * pmapTag, DWORD dwTagSize)
{
while (phst->dwLabelSize != 0) {
if ((phst->dwLabelSize == dwTagSize)
&& !_strnicmp(phst->pszLabel, pmapTag, dwTagSize)) {
return phst;
}
phst++;
}
return NULL;
}
/***************************************************************************\
* hsSkipBlockTagIfPresent
*
\***************************************************************************/
char * hsSkipBlockTagIfPresent (char * pmap, DWORD * pdwMask)
{
static char gszBegin [] = "begin";
static char gszEnd [] = "end";
char * pmapTag;
DWORD dwTagSize;
PHSTAG phst;
/*
* Remember the beginning of the tag
*/
pmapTag = pmap;
/*
* Compatibility. Deal with old lt? and bt? switches.
* If the whole tag was added to the tag list, get the flags
* and stop parsing.
*/
if (gdwOptions & (HSO_USERBLOCK | HSO_USERHEADERTAG)) {
pmap = hsFindEndOfString(pmap);
if ((pmap != NULL) && (pmap != pmapTag)) {
phst = hsFindTagInList (gphst, pmapTag, (DWORD)(pmap - pmapTag));
if (phst != NULL) {
*pdwMask |= phst->dwMask;
return pmap;
}
}
/*
* Didn't find the string in the table so restore pmap and continue
*/
pmap = pmapTag;
}
/*
* Find the end of the current tag
*/
pmap = hsSkipTag(pmap);
if ((pmap == NULL) || (pmap == pmapTag)) {
return pmap;
}
dwTagSize = (DWORD)(pmap - pmapTag);
/*
* If at separator, skip so the caller won't have to deal with it
*/
if (*pmap == '_') {
pmap++;
}
/*
* begin tag
*/
if ((HSCSZSIZE(gszBegin) == dwTagSize)
&& !_strnicmp(gszBegin, pmapTag, dwTagSize)) {
*pdwMask |= HST_BEGIN;
return pmap;
}
/*
* end tag
*/
if ((HSCSZSIZE(gszEnd) == dwTagSize)
&& !_strnicmp(gszEnd, pmapTag, dwTagSize)) {
*pdwMask |= HST_END;
return pmap;
}
return pmapTag;
}
/***************************************************************************\
* hsPopBlock
*
\***************************************************************************/
BOOL hsPopBlock (void)
{
/*
* Check for underflow
*/
if (gphsbStackTop <= ghsbStack) {
hsLogMsg(HSLM_ERROR, "Block stack underflow!");
return FALSE;
}
if (gphsbStackTop->pszifLabel != NULL) {
LocalFree(gphsbStackTop->pszifLabel);
}
gphsbStackTop--;
return TRUE;
}
/***************************************************************************\
* hsPushBlock
*
\***************************************************************************/
BOOL hsPushBlock(void)
{
/*
* Make sure we got room in the block stack
*/
if (gphsbStackTop >= HSBSTACKLIMIT) {
hsLogMsg(HSLM_ERROR, "Too many nested blocks. Artificial limit:%#lx", HSBSTACKSIZE);
return FALSE;
}
/*
* Grow the stack and initialize the new entry
*/
gphsbStackTop++;
ZeroMemory(gphsbStackTop, sizeof(*gphsbStackTop));
gphsbStackTop->dwLineNumber = gdwLineNumber;
/*
* propagate the mask
*/
gphsbStackTop->dwMask |= (gphsbStackTop - 1)->dwMask;
return TRUE;
}
/***************************************************************************\
* hsSkipBlock
*
\***************************************************************************/
char * hsSkipBlock(char * pmap)
{
char * pmapLineStart;
DWORD dwMask;
while (pmap < gpmapEnd) {
/*
* Find the next marker (; by default)
*/
pmap = hsFindTagMarker(pmap, &pmapLineStart);
if (pmap == NULL) {
return NULL;
}
/*
* Skip the marker and any spaces after it
*/
pmap = hsFindFirstSubTag(pmap);
if (pmap == NULL) {
return NULL;
}
/*
* Check if this is the beginning-end of a block
*/
dwMask = 0;
pmap = hsSkipBlockTagIfPresent(pmap, &dwMask);
if (pmap == NULL) {
return NULL;
}
/*
* If it found the beginning of another block, push it in the
* the stack and skip it.
*/
if (dwMask & HST_BEGIN) {
if (!hsPushBlock()) {
return NULL;
}
pmap = hsSkipBlock(pmap);
if (pmap == NULL) {
return NULL;
}
} else if (dwMask & HST_END) {
/*
* It found the end of the block; pop it out of the stack
* and return the beginning of the next line
*/
if (!hsPopBlock()) {
return NULL;
}
return hsFindEOL(pmap);
}
/*
* It wasn't a block tag so keep going
*/
pmap++;
}
return NULL;
}
/***************************************************************************\
* hsBuildifString
*
\***************************************************************************/
BOOL hsBuildifString(char * pString, DWORD dwStringSize, char * pCompOperator, DWORD dwCompOperatorSize)
{
char * psz;
/*
* Use default operator if none was provided.
*/
if (pCompOperator == NULL) {
pCompOperator = gszDefCompOperator;
dwCompOperatorSize = HSCSZSIZE(gszDefCompOperator);
}
/*
* Make a NULL terminated copy. Allocate enough space for the
* "label CompOperator version" string: 2 spaces + 10 digits (0xl#) +
* null termination
*/
psz = (char *) LocalAlloc(LPTR, dwStringSize + dwCompOperatorSize + 13);
if (psz == NULL) {
hsLogMsg(HSLM_APIERROR, "LocalAlloc");
hsLogMsg(HSLM_ERROR, "hsBuildifString allocation failed. Size:%#lx", dwStringSize+ dwCompOperatorSize + 13);
return FALSE;
}
/*
* Save it in the stack.
*/
gphsbStackTop->pszifLabel = psz;
/*
* Build the string (the right side of the comparison (version) will
* be added later when available.
*/
strncpy(psz, pString, dwStringSize);
psz += dwStringSize;
*psz++ = ' ';
strncpy(psz, pCompOperator, dwCompOperatorSize);
psz += dwCompOperatorSize;
*psz++ = ' ';
return TRUE;
}
/***************************************************************************\
* hsParseAndBuildifString
*
\***************************************************************************/
char * hsParseAndBuildifString(char * pmap, BOOL fSkip)
{
BOOL fEnclosed;
char * pmapTag, * pCompOperator;
DWORD dwTagSize, dwCompOperatorSize;
/*
* Skip the tag concatenator (_)
*/
if (*pmap++ != '_') {
hsLogMsg(HSLM_ERROR, "Expected '_' after if tag");
return NULL;
}
if (pmap >= gpmapEnd) {
hsLogMsg(HSLM_EOFERROR, "hsParseAndBuildifString");
return NULL;
}
/*
* Find the end of the string. If it starts wiht '(', then the string
* is enclosed in parens. This is for strings that use _ (like _WIN32_WINDOWS)
*/
pmapTag = pmap;
fEnclosed = (*pmap == '(');
if (fEnclosed) {
pmapTag = ++pmap;
pmap = hsFindFirstCharInString(pmap, ")" " " "\r");
if ((pmap == NULL) || (*pmap != ')')) {
hsLogMsg(HSLM_ERROR, "Expected ')' after if_(");
return NULL;
}
} else {
pmap = hsSkipTag(pmap);
if ((pmap == NULL) || (pmap == pmapTag)) {
hsLogMsg(HSLM_ERROR, "Expected string after if_");
return NULL;
}
}
dwTagSize = (DWORD)(pmap - pmapTag);
/*
* Skip the ')'
*/
if (fEnclosed) {
pmap++;
if (pmap >= gpmapEnd) {
hsLogMsg(HSLM_EOFERROR, "hsParseAndBuildifString");
return NULL;
}
}
/*
* If a comparison operator follows, use it
*/
if ((pmap + 1 < gpmapEnd) && (*pmap == '_')) {
switch (*(pmap + 1)) {
case '=':
case '>':
case '<':
pCompOperator = ++pmap;
pmap = hsSkipTag(pmap);
if ((pmap == NULL) || (pmap == pCompOperator)) {
hsLogMsg(HSLM_EOFERROR, "hsParseAndBuildifString");
return NULL;
}
dwCompOperatorSize = (DWORD)(pmap - pCompOperator);
break;
default:
pCompOperator = NULL;
break;
}
}
/*
* Build the stirng a copy it into the block stack
*/
if (!fSkip) {
if (!hsBuildifString(pmapTag, (DWORD)dwTagSize, pCompOperator, (DWORD)dwCompOperatorSize)) {
return NULL;
}
}
return pmap;
}
/***************************************************************************\
* hsMapOldTag
*
\***************************************************************************/
BOOL hsMapOldTag(char * pmapTag, DWORD dwTagSize, DWORD * pdwTagMask, DWORD * pdwVersion)
{
static char gszifWinver [] = "WINVER";
static char gszif_WIN32_WINDOWS [] = "_WIN32_WINDOWS";
static char gszif_WIN32_WINNT [] = "_WIN32_WINNT";
char * pszLabel;
UINT uSize;
/*
* Old tags must have a block or header bit set. Otherwise, they
* should be ignored
*/
if (!(*pdwTagMask & (HST_BOTH | HST_BLOCK))) {
*pdwTagMask |= HST_IGNORE;
return TRUE;
}
/*
* No mapping needed if at the end of a block or HST_SKIP is the only
* additional flag set.
*/
if ((*pdwTagMask & HST_END)
|| ((*pdwTagMask & ~(HST_BLOCK | HST_USERBLOCK | HST_BOTH | HST_USERHEADERTAG))
== (HST_SKIP | HST_MAPOLD))) {
return TRUE;
}
/*
* winver maps to if_winver
*/
if (*pdwTagMask & HST_WINVER) {
/*
* Compatibility
*/
if (!(gdwOptions & HSO_OLDPROJSW_4)
&& (*pdwTagMask & HST_INTERNAL)
&& !(gdwOptions & HSO_OLDPROJSW_E)) {
*pdwTagMask |= HST_SKIP;
return TRUE;
}
pszLabel = gszifWinver;
uSize = HSCSZSIZE(gszifWinver);
goto AddIf;
}
/*
* nashville maps to if_(_WIN32_WINDOWS)_40a
*/
if ((dwTagSize == HSCSZSIZE(gszNashville)) && !_strnicmp(pmapTag, gszNashville, dwTagSize)) {
*pdwVersion = 0x40a;
pszLabel = gszif_WIN32_WINDOWS;
uSize = HSCSZSIZE(gszif_WIN32_WINDOWS);
goto AddIf;
}
/*
* sur and surplus map to if_(_WIN32_WINNT)_400 if public
*/
if ((dwTagSize == HSCSZSIZE(gszSur)) && !_strnicmp(pmapTag, gszSur, dwTagSize)
|| (dwTagSize == HSCSZSIZE(gszSurplus)) && !_strnicmp(pmapTag, gszSurplus, dwTagSize)) {
if (*pdwTagMask & HST_INTERNAL) {
return TRUE;
}
*pdwVersion = 0x400;
pszLabel = gszif_WIN32_WINNT;
uSize = HSCSZSIZE(gszif_WIN32_WINNT);
goto AddIf;
}
/*
* 35 is excluded when building for old switch e and p
*/
if ((dwTagSize == HSCSZSIZE(gsz35)) && !_strnicmp(pmapTag, gsz35, dwTagSize)) {
*pdwTagMask |= HST_SKIP;
return TRUE;
}
return TRUE;
AddIf:
*pdwTagMask |= HST_IF;
/*
* If we're not in a block, push one to save the string
*/
if (!(*pdwTagMask & HST_BEGIN)) {
if (!hsPushBlock()) {
return FALSE;
}
}
if (!hsBuildifString(pszLabel, uSize, NULL, 0)) {
return FALSE;
}
return TRUE;
}
/***************************************************************************\
* hsParseTag
*
\***************************************************************************/
DWORD hsParseTag(char * pmap, DWORD * pdwVersion)
{
char * pmapTag;
DWORD dwTagMask = HST_DEFAULT;
DWORD dwTagSize;
PHSTAG phst;
*pdwVersion = 0;
/*
* Skip the marker and any spaces after it
*/
pmap = hsFindFirstSubTag(pmap);
if (pmap == NULL) {
return HST_DEFAULT;
}
/*
* Check for begin-end of block
*/
pmap = hsSkipBlockTagIfPresent(pmap, &dwTagMask);
if (pmap == NULL) {
return HST_DEFAULT;
}
/*
* If this the beginning of a block, push in the stack
* skip the tag concatenator (_)
*/
if (dwTagMask & HST_BEGIN) {
if (!hsPushBlock()) {
return HST_ERROR;
}
}
/*
* Build tag mask. Tags are concatenated by underscores (_); each
* iteration of this loop processes one "sub-tag"
*/
do {
/*
* Find current tag end. Bail if at last one.
*/
pmapTag = pmap;
pmap = hsSkipTag(pmap);
if ((pmap == NULL) || (pmap == pmapTag)) {
break;
}
/*
* Look up the tag
*/
dwTagSize = (DWORD)(pmap - pmapTag);
phst = hsFindTagInList (gphst, pmapTag, dwTagSize);
if (phst != NULL) {
dwTagMask |= phst->dwMask;
/*
* Compatibility
* If this is an old tag, map it.
* No mapping needed if doing split only (tag is going to be
* ignored)
*/
if ((dwTagMask & HST_MAPOLD)
&& !(gdwOptions & HSO_SPLITONLY)) {
if (!hsMapOldTag(pmapTag, dwTagSize, &dwTagMask, pdwVersion)) {
return HST_ERROR;
}
} else {
/*
* If this is an if tag, copy the block string
*/
if (phst->dwMask & HST_IF) {
BOOL fEndBlock;
/*
* If not in a block, push a fake one in to save the string
*/
if (!(dwTagMask & HST_BLOCK)) {
if (!hsPushBlock()) {
return HST_ERROR;
}
}
/*
* If we're at the end of a block, we want to skip
* the if string (already taken care of at begin tag)
*/
fEndBlock = (dwTagMask & HST_END);
if (fEndBlock) {
dwTagMask &= ~HST_IF;
}
pmap = hsParseAndBuildifString(pmap, fEndBlock);
if (pmap == NULL) {
return HST_ERROR;
}
}
} /* if ((dwTagMask & HST_MAPOLD)... */
} else {
/*
* If this is not the version number, then this is an unkown tag
*/
if (!hsVersionFromString (pmapTag, dwTagSize, pdwVersion)) {
dwTagMask |= HST_UNKNOWN;
}
} /* if (phst != NULL) */
} while (*pmap++ == '_');
/*
* Bail if we didn't find any tags
*/
if (dwTagMask == HST_DEFAULT) {
return HST_DEFAULT;
}
/*
* Unknown tags are to be skipped or ignored
*/
if (dwTagMask & HST_UNKNOWN) {
if (gdwOptions & HSO_SKIPUNKNOWN) {
dwTagMask |= HST_SKIP;
} else {
goto IgnoreTag;
}
}
/*
* Ignore the tag if marked as such
*/
if (dwTagMask & HST_IGNORE) {
goto IgnoreTag;
}
/*
* Compatibility hack. public_winver_40a is not included for old -n and
* it's internal for old -e. 400 is goes to both headers for -n
*/
if (dwTagMask & HST_WINVER) {
if (*pdwVersion == 0x40a) {
if (gdwOptions & HSO_OLDPROJSW_E) {
dwTagMask |= HST_INTERNAL;
dwTagMask &= ~HST_PUBLIC;
} else if (gdwOptions & HSO_OLDPROJSW_N) {
dwTagMask |= HST_SKIP;
}
} else if ((*pdwVersion == 0x400)
&& (gdwOptions & HSO_OLDPROJSW_N)) {
dwTagMask |= HST_INTERNALNOTCOMP | HST_BOTH;
}
}
/*
* if using old lt2, ltb, bt2 or btb switches,
* then both/internal tag/block must be skipped
*/
if ((gdwOptions & (HSO_USERBLOCK | HSO_USERHEADERTAG))
&& !(dwTagMask & ~(HST_BLOCK | HST_BOTH))) {
if ((gdwOptions & HSO_USERINTERNALBLOCK)
&& ((dwTagMask == (HST_BEGIN | HST_INTERNAL))
|| (dwTagMask == (HST_END | HST_INTERNAL)))) {
dwTagMask &= HST_BLOCK;
dwTagMask |= HST_SKIP;
} else if ((gdwOptions & HSO_USERBOTHBLOCK)
&& ((dwTagMask == (HST_BEGIN | HST_BOTH))
|| (dwTagMask == (HST_END | HST_BOTH)))) {
dwTagMask &= HST_BLOCK;
dwTagMask |= HST_SKIP;
} else if ((gdwOptions & HSO_USERINTERNALTAG)
&& (dwTagMask == HST_INTERNAL)) {
dwTagMask = HST_SKIP;
} else if ((gdwOptions & HSO_USERBOTHTAG)
&& (dwTagMask == HST_BOTH)) {
dwTagMask = HST_SKIP;
}
} /* if ((gdwOptions & (HSO_USERBLOCK | HSO_USERHEADERTAG))... */
/*
* If doing split only, anything other than both/internal is treated
* as untagged. If we pushed a block, pop it out as it will be ignored
*/
if (gdwOptions & HSO_SPLITONLY) {
if (dwTagMask & ~(HST_BLOCK | HST_USERBLOCK | HST_BOTH | HST_USERHEADERTAG)) {
goto IgnoreTag;
}
*pdwVersion = 0;
}
/*
* If this is the beginning of a block, save the mask in the block stack
*/
if (dwTagMask & HST_BEGIN) {
gphsbStackTop->dwMask |= dwTagMask;
}
return dwTagMask;
IgnoreTag:
/*
* If a block was pushed, pop it out.
*/
if (dwTagMask & HST_BEGIN) {
if (!hsPopBlock()) {
return HST_ERROR;
}
}
*pdwVersion = 0;
return HST_DEFAULT;
}
/***************************************************************************\
* hsBeginEndBlock
*
\***************************************************************************/
BOOL hsBeginEndBlock (DWORD dwMask, DWORD dwVersion)
{
char * psz;
UINT uPasses;
/*
* Compatibility. If writting this block to the internal header
* using the not comp (ie., from >= to <), then do two passes
* writing one header each time.
*/
if (dwMask & HST_INTERNALNOTCOMP) {
uPasses = 2;
if (dwMask & HST_BEGIN) {
/*
* Write public header first
*/
dwMask &= ~HST_INTERNAL;
} else {
/*
* Write internal header first
*/
dwMask &= ~HST_PUBLIC;
}
} else {
uPasses = 1;
}
/*
* Add version to the string
*/
if (dwMask & HST_BEGIN) {
/*
* Beginning of block or if
* If there is no if string, done
*/
if (gphsbStackTop->pszifLabel == NULL) {
return TRUE;
}
/*
* Something is fishy is dwVersion is 0
*/
if (dwVersion == 0) {
hsLogMsg(HSLM_ERROR, "if tag without version");
return FALSE;
}
sprintf(gphsbStackTop->pszifLabel + strlen(gphsbStackTop->pszifLabel),
"%#06lx", dwVersion);
}
/*
* Write headers
*/
do {
if (dwMask & HST_BEGIN) {
/*
* Write #if to output file
*/
if (!hsWriteHeaderFiles(gszIfStart, HSCSZSIZE(gszIfStart), dwMask)
|| !hsWriteHeaderFiles(gphsbStackTop->pszifLabel, lstrlen(gphsbStackTop->pszifLabel), dwMask)
|| !hsWriteHeaderFiles(gszIfStop, HSCSZSIZE(gszIfStop), dwMask)) {
return FALSE;
}
} else {
/*
* End of block or if
* If there is an if string, Write #endif to output file
*/
if (gphsbStackTop->pszifLabel != NULL) {
if (!hsWriteHeaderFiles(gszEndStart, HSCSZSIZE(gszEndStart), dwMask)
|| !hsWriteHeaderFiles(gphsbStackTop->pszifLabel, lstrlen(gphsbStackTop->pszifLabel), dwMask)
|| !hsWriteHeaderFiles(gszEndStop, HSCSZSIZE(gszEndStop), dwMask)) {
return FALSE;
}
}
}
/*
* If doing a second pass, fix the mask and the string
*/
if (uPasses > 1) {
psz = gphsbStackTop->pszifLabel;
if (dwMask & HST_BEGIN) {
/*
* Write internal header now
*/
dwMask &= ~HST_PUBLIC;
dwMask |= HST_INTERNAL;
/*
* From >= to <
*/
while (*psz != '>') {
psz++;
}
*psz++ = '<';
*psz = ' ';
} else {
/*
* Write public header now
*/
dwMask &= ~HST_INTERNAL;
dwMask |= HST_PUBLIC;
/*
* From < to >=
*/
while (*psz != '<') {
psz++;
}
*psz++ = '>';
*psz = '=';
}
}
} while (--uPasses != 0);
/*
* Clean up the block if at the end
*/
if (dwMask & HST_END) {
if (!hsPopBlock()) {
return FALSE;
}
}
return TRUE;
}
/***************************************************************************\
* hsSplit
*
\***************************************************************************/
BOOL hsSplit (void)
{
BOOL fSkip;
char * pmap, *pmapLineStart, *pmapLastLineStart, *pmapMarker, *pmapLastChar;
DWORD dwMask, dwVersion, dwPreviousMask, dwLastMask;
/*
* Initialize block stack top, map pointer, etc
*/
ZeroMemory(gphsbStackTop, sizeof(*gphsbStackTop));
dwLastMask = 0;
pmap = pmapLineStart = pmapLastLineStart = gpmapStart;
gdwLineNumber = 1;
while (pmap < gpmapEnd) {
/*
* Find the marker and the line it is on
*/
pmap = hsFindTagMarker(pmap, &pmapLineStart);
if (pmap == NULL) {
break;
}
/*
* Parse the tag
*/
dwMask = hsParseTag(pmap, &dwVersion);
if (dwMask & HST_ERROR) {
return FALSE;
}
/*
* If this wasn't a tag (just the tag marker), continue
*/
if ((dwMask == HST_DEFAULT) && (dwVersion == 0)) {
pmap++;
continue;
}
/*
* Write any previous non-empty (untagged) lines.
* If we're about to start a block, make sure to use the right mask.
*/
dwPreviousMask = ((dwMask & (HST_BEGIN | HST_IF)) ? (gphsbStackTop - 1)->dwMask : gphsbStackTop->dwMask);
pmapLastChar = hsLastRealChar(pmapLastLineStart, pmapLineStart);
if (pmapLastLineStart < pmapLastChar) {
/*
* Empty lines between internal (block) tags go to the internal file
*/
if (!(dwPreviousMask & HST_BOTH)
&& ((dwMask & HST_BOTH) == HST_INTERNAL)
&& ((dwLastMask & HST_BOTH) == HST_INTERNAL)
&& hsIsEmpty(pmapLastLineStart, pmapLastChar)) {
dwPreviousMask |= HST_INTERNAL;
}
if (!hsWriteHeaderFiles(pmapLastLineStart, (DWORD)(pmapLastChar - pmapLastLineStart), dwPreviousMask)) {
return FALSE;
}
}
/*
* Determine if this tag is to be skipped.
* If we're at the END tag, then we include it since the block was
* already included.
* If gdwFilterMask contains any user-defined tags, then they must
* be present or the block is to be skipped -- note that this only
* applies for not HST_SKIP | HST_IGNORE blocks.
*/
fSkip = (!(dwMask & HST_END)
&& ((dwMask & HST_SKIP)
|| (gdwVersion < dwVersion)
|| ((gdwFilterMask & HST_USERTAGSMASK)
&& ((gdwFilterMask & dwMask & HST_USERTAGSMASK) != (dwMask & HST_USERTAGSMASK)))));
/*
* If it is to be skipped, do it
*/
if (fSkip) {
/*
* If it's a block, skip the marker and the skip the block
* Otherwise, skip the current line
*/
if (dwMask & HST_BEGIN) {
pmap = hsSkipBlock(++pmap);
} else {
/*
* If this was an if tag with no begin-end block, pop
* the fake block out of the stack.
*/
if (dwMask & HST_IF) {
if (!hsPopBlock()) {
return FALSE;
}
}
/*
* Go to the beginning of the next line.
*/
pmap = hsFindEOL(pmap);
}
if (pmap == NULL) {
return TRUE;
}
goto SkipEmptyLines;
}
/*
* remember the marker position and the tag
*/
pmapMarker = pmap;
dwLastMask = dwMask;
/*
* For old switch 4, internal tags go into the public header
*/
if ((gdwOptions & HSO_INCINTERNAL) && ((dwMask & HST_BOTH) == HST_INTERNAL)) {
dwMask |= HST_INCINTERNAL;
if (dwMask & HST_BEGIN) {
gphsbStackTop->dwMask |= HST_INCINTERNAL;
}
}
/*
* If this is the end of a block, write the #endif statement
* else, if this is the beginning of a block or an if tag, add the
* #if statement.
*/
if (dwMask & HST_END) {
if (!hsBeginEndBlock(dwMask, dwVersion)) {
return FALSE;
}
} else if (dwMask & (HST_BEGIN | HST_IF)) {
if (!hsBeginEndBlock(dwMask | HST_BEGIN, dwVersion)) {
return FALSE;
}
}
//
// Later: If we're inside a block and find a tag the needs to go to a file
// that doesn't have the ifdef, then we might want to add it to that file.
// Few issues: more than one nesting. if add #if.. make sure to add #endif when
// block ends. Also hsBeginEnd doesn't expect to get called more than once
// per block. It would append the version twice.
//
// else if ((gphsbStackTop->pszifLabel != NULL)
// && ((gphsbStackTop->dwMask & HST_BOTH) != (dwMask & HST_BOTH))) {
//
// if ((gphsbStackTop->dwMask & HST_BOTH) == HST_INTERNAL) {
// hsLogMsg(HSLM_DEFAULT, "Public. Line:%d Block line:%d", gdwLineNumber, gphsbStackTop->dwLineNumber);
// } else if (!(gphsbStackTop->dwMask & HST_INTERNAL)
// && ((dwMask & HST_BOTH) == HST_INTERNAL)) {
// hsLogMsg(HSLM_DEFAULT, "Internal. Line:%d Block line:%d", gdwLineNumber, gphsbStackTop->dwLineNumber);
// }
// }
/*
* Write the line up to the tag marker
* If the line begins with the tag marker, then there is nothing to write
* Compatibility: Don't copy any trailing spaces (breaks mc.exe).
*/
if (pmapLineStart + 2 < pmapMarker) {
pmapLastChar = hsLastRealChar(pmapLineStart, pmapMarker);
if (pmapLineStart < pmapLastChar) {
if (!hsWriteHeaderFiles(pmapLineStart, (DWORD)(pmapLastChar - pmapLineStart), dwMask)) {
return FALSE;
}
}
}
/*
* If this is an if tag without a begin-end block,
* write the #endif statement
*/
if ((dwMask & HST_IF) && !(dwMask & HST_BLOCK)) {
if (!hsBeginEndBlock(dwMask | HST_END, dwVersion)) {
return FALSE;
}
}
/*
* Skip the tag (go to the beginning of the next line)
*/
pmap = hsFindEOL(pmapMarker);
if (pmap == NULL) {
return TRUE;
}
/*
* If including internal tags in the public header, add the tag
* as a comment.
*/
if (dwMask & HST_INCINTERNAL) {
/*
* Start a new line if at the end of a block
*/
if (dwMask & HST_END) {
if (!hsWriteNewLine(dwMask)) {
return FALSE;
}
}
if (!hsWriteHeaderFiles(" // ", 4, dwMask)
|| !hsWriteHeaderFiles(pmapMarker, (DWORD)(pmap - pmapMarker), dwMask)) {
return FALSE;
}
}
SkipEmptyLines:
/*
* Update line pointers and move past beginning of new line
*/
pmapLastLineStart = pmapLineStart = hsSkipEmptyLines(pmap);
pmap = pmapLastLineStart + 2;
} /* while (pmap < gpmapEnd) */
/*
* This is not good if we were inside a block
*/
if (gphsbStackTop > ghsbStack) {
hsLogMsg(HSLM_ERROR, "Missing end block");
hsLogMsg(HSLM_ERROR | HSLM_NOLINE, "Last block Line: %d. if Label:'%s'. Mask: %#lx",
gphsbStackTop->dwLineNumber, gphsbStackTop->pszifLabel, gphsbStackTop->dwMask);
return FALSE;
}
/*
* Write last (untagged) lines to public header.
*/
if (pmapLastLineStart < gpmapEnd) {
if (!hsWriteHeaderFiles(pmapLastLineStart, (DWORD)(gpmapEnd - pmapLastLineStart), HST_DEFAULT)) {
return FALSE;
}
}
/*
* Terminate the last line
*/
if (!hsWriteNewLine(HST_BOTH)) {
return FALSE;
}
return TRUE;
}