|
|
/****************************** 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; }
|