1404 lines
39 KiB
C
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;
|
|
}
|
|
|
|
|