mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
730 lines
19 KiB
730 lines
19 KiB
/*****************************************************************************
|
|
* *
|
|
* CTX.C *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1990. *
|
|
* All Rights reserved. *
|
|
* *
|
|
******************************************************************************
|
|
* *
|
|
* Module Intent *
|
|
* This module handles context strings, including footnote processing *
|
|
* and cross reference error checking. *
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "..\common\coutput.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
const char CTX_DEFINED = '0';
|
|
const char CTX_REFERENCED = '1';
|
|
const char CTX_SEPARATOR = '@';
|
|
const char txtSameCtx[] = ">";
|
|
|
|
extern COutput* pLogFile;
|
|
|
|
INLINE static BOOL STDCALL IsCtxPrefix(PCSTR pszContext);
|
|
|
|
/*
|
|
* Module Algorithms
|
|
*
|
|
* This module has three entry points: one when context strings
|
|
* are defined, one when they are referenced, and then one for error
|
|
* checking all the links at the end. When context strings are
|
|
* defined, the hash value and address pair is added to the context
|
|
* btree. When context strings are defined or referenced, the
|
|
* hash value, string, filename, and page number are all added to
|
|
* a file, as well as whether it is a definition or a reference. When
|
|
* error checking occurs, this file is sorted, and then entries are
|
|
* read in. An error is reported whenever a context string is
|
|
* referenced without being defined.
|
|
*
|
|
* Revision History
|
|
* This functionality is completely different from what this
|
|
* source file used to do.
|
|
*
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Defines *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
static char const txtCTXBtree[] = "|CONTEXT";
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Prototypes *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
BOOL STDCALL FCreateContextFiles(void)
|
|
{
|
|
BTREE_PARAMS bp;
|
|
|
|
// Create hash btree file
|
|
|
|
InitBtreeStruct(&bp, "L4", CB_CTX_BLOCK); // KT_LONG
|
|
|
|
fmsg.qbthrCtx = HbtCreateBtreeSz(txtCTXBtree, &bp);
|
|
|
|
// Create context info file. This may already have been done.
|
|
|
|
if (!ptblCtx)
|
|
ptblCtx = new CTable;
|
|
return TRUE;
|
|
}
|
|
|
|
void STDCALL CloseContextBtree(void)
|
|
{
|
|
if (fmsg.qbthrCtx != NULL) {
|
|
if (RcCloseBtreeHbt(fmsg.qbthrCtx) != RC_Success) {
|
|
fmsg.qbthrCtx = NULL;
|
|
}
|
|
else
|
|
fmsg.qbthrCtx = NULL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name FProcContextSz
|
|
-
|
|
* Purpose
|
|
* This function processes a context footnote. If it is given a
|
|
* valid context string, it puts the address into the context btree,
|
|
* indexed by a hash of the context string. It also enters a
|
|
* definition entry into the context string cross reference file.
|
|
*
|
|
* Arguments
|
|
* PSTR szContext: String found in context footnote
|
|
* ADDR addr: Address for context string
|
|
* PERR perr: Pointer to error information.
|
|
*
|
|
* Returns
|
|
* TRUE if context string was valid.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* Currently uses global fmsg.
|
|
*
|
|
***************************************************************************/
|
|
|
|
// BUGBUG: nobody uses this
|
|
// HASH hPrev; // REVIEW: who uses this?
|
|
|
|
BOOL STDCALL FProcContextSz(PSTR pszContext, IDFCP idfcp, UINT wObjrg,
|
|
PERR perr)
|
|
{
|
|
HASH hash;
|
|
PSTR szMaster;
|
|
|
|
SzTrimSz(pszContext);
|
|
if (*pszContext == '\0') {
|
|
VReportError(HCERR_MISSING_CTX, &errHpj);
|
|
return FALSE;
|
|
}
|
|
else if (!FValidContextSz(pszContext)) {
|
|
VReportError(HCERR_INVALID_CTX, &errHpj, pszContext);
|
|
return FALSE;
|
|
}
|
|
|
|
hash = HashFromSz(pszContext);
|
|
|
|
// Remap if the hash value is in the [ALIAS] section. Note that
|
|
// apparently, viewer 2.0 doesn't do this anymore. 14-Oct-1993 [ralphw]
|
|
|
|
szMaster = SzTranslateHash(&hash);
|
|
|
|
// Add hash value into btree
|
|
|
|
ASSERT(fmsg.qbthrCtx != NULL);
|
|
FDelayExecutionContext(hash, idfcp, wObjrg);
|
|
|
|
// Add context info to context info file
|
|
|
|
FRecordContext(hash, pszContext, szMaster, TRUE, perr);
|
|
curHash = hash; // save for possible use in FTS processing
|
|
fContextSeen = TRUE;
|
|
|
|
doGrind(); // update grinder bitmap
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: FRecordContext
|
|
-
|
|
* Purpose:
|
|
* Records a context string definition or reference, so that we
|
|
* may later check to see if it was undefined.
|
|
*
|
|
* Strings are written out as:
|
|
* hash szMaster fDefine pszContext pchFile iTopic
|
|
* If szMaster is nil, pszContext is used instead.
|
|
*
|
|
* Arguments:
|
|
* HASH hash: Translated hash value of context string.
|
|
* PSTR pszContext: Context string as it appears in the text.
|
|
* PSTR szMaster: Context string corresponding to given hash value,
|
|
* if different from pszContext.
|
|
* BOOL fDefine: TRUE for definition, FALSE for reference.
|
|
* PERR perr: Pointer to error information.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Globals Used:
|
|
* Writes out info to fmsg.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL STDCALL FRecordContext(HASH hash, PCSTR pszContext, PSTR pszMaster,
|
|
BOOL fDefine, PERR perr)
|
|
{
|
|
if (!ptblCtx)
|
|
ptblCtx = new CTable;
|
|
|
|
ASSERT(pszContext != NULL && pszContext[0] != '\0');
|
|
if (pszMaster == NULL)
|
|
pszMaster = (PSTR) pszContext;
|
|
ASSERT(pszMaster[0] != '\0');
|
|
ASSERT(perr->lpszFile != NULL && perr->lpszFile[0] != '\0');
|
|
|
|
char szBuf[1024];
|
|
ASSERT(strlen(pszMaster) < MAX_PATH);
|
|
|
|
// The CTX_SEPARATOR value must be used to separate strings. You can't
|
|
// use space because that would prevent using space for a Topic ID.
|
|
|
|
int iFile = ptblRtfFiles->IsStringInTable(perr->lpszFile);
|
|
|
|
if (iFile)
|
|
wsprintf(szBuf, "%8lX@%s@%c@%s@%u@%u",
|
|
hash, pszMaster, (char) (fDefine ? CTX_DEFINED : CTX_REFERENCED),
|
|
strcmp(pszMaster, pszContext) == 0 ? txtSameCtx : pszContext,
|
|
iFile, perr->iTopic);
|
|
else
|
|
wsprintf(szBuf, "%8lX@%s@%c@%s@%s@%u",
|
|
hash, pszMaster, (char) (fDefine ? CTX_DEFINED : CTX_REFERENCED),
|
|
strcmp(pszMaster, pszContext) == 0 ? txtSameCtx : pszContext,
|
|
perr->lpszFile, perr->iTopic);
|
|
|
|
ASSERT(strchr(szBuf, CTX_SEPARATOR)); // Make sure you used CTX_SEPARATOR!
|
|
|
|
if (!ptblCtx->AddString(hash, szBuf))
|
|
OOM();
|
|
|
|
if (fDefine)
|
|
hlpStats.cTopics++;
|
|
else
|
|
hlpStats.cJumps++;
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: FResolveContextErrors
|
|
-
|
|
* Purpose:
|
|
* This function goes through the list of context string definitions
|
|
* and references, looking for multiple definitions, hash value conflicts,
|
|
* and unresolved references.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Globals Used:
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
|
|
const char txtSpaceEol[] = " \n";
|
|
|
|
BOOL STDCALL FResolveContextErrors(void)
|
|
{
|
|
PSTR pszMasterLast;
|
|
PSTR pszHash, pszMaster, pszReference, pszContext, pszFile, pszTopic;
|
|
CTable* ptblErrors = NULL;
|
|
int pos;
|
|
|
|
ASSERT(ptblCtx != NULL);
|
|
|
|
if (!iflags.fTrusted) {
|
|
CMem mem(CB_SCRATCH); // create a scratch buffer
|
|
CMem master(MAX_FOOTNOTE);
|
|
|
|
ptblCtx->SetTableSortColumn(sizeof(HASH) + 1);
|
|
ptblCtx->SortTablei();
|
|
ptblCtx->RemoveDuplicateHashStrings();
|
|
|
|
#if 0 // Debugging code
|
|
{
|
|
COutput out("ctx.log");
|
|
|
|
int i = 1;
|
|
while (i < ptblCtx->CountStrings())
|
|
out.outstring_eol(ptblCtx->GetPointer(i++) + sizeof(HASH) + 1);
|
|
ptblCtx->SetPosition();
|
|
}
|
|
#endif
|
|
|
|
pszMasterLast = master.psz;
|
|
*pszMasterLast = '\0';
|
|
|
|
/*
|
|
* Note that we don't check for overflow of pszHash. This shouldn't
|
|
* happen. If it does, it will corrupt the heap which will be caught
|
|
* when the function terminates.
|
|
*/
|
|
|
|
// REVIEW: we now save the has number in the table...
|
|
|
|
HASH hash, hashLast = 0;
|
|
while(ptblCtx->GetHashAndString(&hash, mem.psz)) {
|
|
|
|
/*
|
|
* REVIEW: We still save the hash string in order to sort the
|
|
* hash strings. To avoid this we'd have to have a special sort
|
|
* table that sorted both the DWORD hash value and the ensuing
|
|
* string.
|
|
*/
|
|
|
|
pszHash = StrToken(mem.psz, CTX_SEPARATOR);
|
|
pszMaster = StrToken(NULL, CTX_SEPARATOR);
|
|
pszReference = StrToken(NULL, CTX_SEPARATOR);
|
|
pszContext = StrToken(NULL, CTX_SEPARATOR);
|
|
if (*pszContext == txtSameCtx[0])
|
|
pszContext = pszMaster;
|
|
pszFile = StrToken(NULL, CTX_SEPARATOR);
|
|
pszTopic = StrToken(NULL, CTX_SEPARATOR);
|
|
|
|
ASSERT(pszTopic != NULL);
|
|
errHpj.lpszFile = isdigit(*pszFile) ?
|
|
ptblRtfFiles->GetPointer(atoi(pszFile)) : pszFile;
|
|
errHpj.iTopic = atoi(pszTopic);
|
|
|
|
if (hash == hashLast) {
|
|
|
|
// Case insensitive comparison of aliased context strings:
|
|
|
|
CStr cszMaster(pszMaster);
|
|
CStr cszLast(pszMasterLast);
|
|
StrUpper(cszMaster);
|
|
StrUpper(cszLast);
|
|
|
|
if (strcmp(cszMaster, cszLast) != 0) {
|
|
VReportError(HCERR_HASH_CONFLICT, &errHpj,
|
|
pszMaster, pszMasterLast);
|
|
if (*pszReference == CTX_REFERENCED)
|
|
VReportError(HCERR_BAD_JUMP, &errHpj, pszContext);
|
|
}
|
|
else if (*pszReference == CTX_DEFINED) {
|
|
UINT curpos = ptblCtx->GetPosition();
|
|
pos = curpos - 2;
|
|
CMem memTmp(CB_SCRATCH);
|
|
|
|
// Find and whine about every duplicate
|
|
|
|
while (pos > 0) {
|
|
HASH hashTmp;
|
|
ptblCtx->GetHashAndString(&hashTmp, memTmp.psz, pos--);
|
|
PSTR pszTmpHash = StrToken(memTmp.psz, CTX_SEPARATOR);
|
|
|
|
// We're done when we hit a different hash number
|
|
|
|
if (hash != hashTmp)
|
|
break;
|
|
|
|
PSTR pszTmpMaster = StrToken(NULL, CTX_SEPARATOR);
|
|
PSTR pszTmpReference = StrToken(NULL, CTX_SEPARATOR);
|
|
|
|
// Only complain if its a definition, not if its a jump
|
|
|
|
if (*pszTmpReference == CTX_DEFINED &&
|
|
hash == hashTmp &&
|
|
strcmp(pszMaster, pszTmpMaster) == 0) {
|
|
PSTR pszTmpContext = StrToken(NULL, CTX_SEPARATOR);
|
|
PSTR pszTmpFile = StrToken(NULL, CTX_SEPARATOR);
|
|
PSTR pszTmpTopic = StrToken(NULL, CTX_SEPARATOR);
|
|
VReportError(HCERR_DUPLICATE_CTX, &errHpj, pszContext,
|
|
atoi(pszTmpTopic), pszTmpFile);
|
|
break;
|
|
}
|
|
}
|
|
ptblCtx->SetPosition(curpos);
|
|
}
|
|
}
|
|
else {
|
|
if (*pszReference == CTX_REFERENCED)
|
|
VReportError(HCERR_BAD_JUMP, &errHpj, pszContext);
|
|
else if (ptblMap && *pszContext == 'I' &&
|
|
*pszReference == CTX_DEFINED &&
|
|
strcmp(pszContext, pszMaster) == 0 &&
|
|
IsCtxPrefix(pszContext)) {
|
|
if (!ptblMap->IsHashInTable(HashFromSz(pszContext))) {
|
|
int ialias;
|
|
QALIAS qalias;
|
|
HASH hashMap = HashFromSz(pszContext);
|
|
if (pdrgAlias && pdrgAlias->Count() > 0) {
|
|
for (ialias = 0, qalias = (QALIAS) pdrgAlias->GetBasePtr();
|
|
ialias < pdrgAlias->Count();
|
|
ialias++, qalias++) {
|
|
|
|
// Look up address for alias in context btree
|
|
|
|
if (qalias->hashCtx == hashMap)
|
|
goto AliasedCtx;
|
|
}
|
|
if (ialias < pdrgAlias->Count())
|
|
continue; // aliased, so not an error
|
|
}
|
|
|
|
if (!ptblErrors)
|
|
ptblErrors = new CTable();
|
|
wsprintf(szParentString, "\t%s\tTopic %s of %s\r\n",
|
|
pszContext, pszTopic, ptblRtfFiles->GetPointer(atoi(pszFile)));
|
|
ptblErrors->AddString(szParentString);
|
|
}
|
|
}
|
|
}
|
|
AliasedCtx:
|
|
hashLast = hash;
|
|
strcpy(pszMasterLast, pszMaster);
|
|
}
|
|
}
|
|
|
|
delete ptblCtx;
|
|
ptblCtx = NULL;
|
|
|
|
if (ptblErrors) {
|
|
errHpj.ep = epNoFile;
|
|
VReportError(HCERR_NOT_IN_MAP, &errHpj);
|
|
ptblErrors->SortTable();
|
|
|
|
// Remove warning count from VReportError() and add real count
|
|
|
|
errcount.cWarnings--;
|
|
errcount.cWarnings += ptblErrors->CountStrings();
|
|
|
|
for (pos = 1; pos <= ptblErrors->CountStrings(); pos++) {
|
|
ptblErrors->GetString(szParentString, pos);
|
|
SendStringToParent(szParentString);
|
|
if (pLogFile)
|
|
pLogFile->outstring(szParentString);
|
|
if (pos % 10 == 0)
|
|
doGrind();
|
|
}
|
|
delete ptblErrors;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name AddrGetContents
|
|
-
|
|
* Purpose
|
|
* Gets the address of the contents topic.
|
|
*
|
|
* Arguments
|
|
* HASH hash: Hash value of index topic.
|
|
*
|
|
* Returns
|
|
* Address of contents topic.
|
|
*
|
|
* Globals Used:
|
|
* This function uses the fmsg.qbthrCtx global to look up the
|
|
* contents topic.
|
|
*
|
|
***************************************************************************/
|
|
|
|
ADDR STDCALL AddrGetContents(PSTR pszContents)
|
|
{
|
|
ADDR addr = 0; // Actually, default is sizeof(MBHD)
|
|
|
|
// Get address of contents
|
|
|
|
if (pszContents) {
|
|
ASSERT(fmsg.qbthrCtx != NULL);
|
|
HASH hash = HashFromSz(pszContents);
|
|
RC_TYPE rc = RcLookupByKey(fmsg.qbthrCtx,
|
|
(KEY) &hash, NULL, &addr);
|
|
if (rc == RC_NoExists) {
|
|
VReportError(HCERR_CONTENTS_CTX_MISSING, &errHpj,
|
|
pszContents);
|
|
addr = 0;
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
ASSERT(rc == RC_Success); // REVIEW: Is this true?
|
|
#endif
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: FOutAliasToCtxBtree
|
|
-
|
|
* Purpose:
|
|
* This function takes each entry in the alias table, looks up the
|
|
* address of the aliased topic, and enters this into the context
|
|
* btree.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
* Globals:
|
|
* This function reads and writes values to fmsg.qbthrCtx.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL STDCALL FOutAliasToCtxBtree(void)
|
|
{
|
|
RC_TYPE rc;
|
|
ADDR addr;
|
|
int ialias;
|
|
QALIAS qalias;
|
|
|
|
ASSERT(fmsg.qbthrCtx != NULL);
|
|
|
|
if (pdrgAlias && pdrgAlias->Count() > 0) {
|
|
for (ialias = 0, qalias = (QALIAS) pdrgAlias->GetBasePtr();
|
|
ialias < pdrgAlias->Count();
|
|
ialias++, qalias++) {
|
|
|
|
// Look up address for alias in context btree
|
|
|
|
rc = RcLookupByKey(fmsg.qbthrCtx, (KEY) &qalias->hashCtx,
|
|
NULL, &addr);
|
|
switch (rc) {
|
|
case RC_Success:
|
|
|
|
// Put context string and address of alias into context btree
|
|
|
|
// REVIEW: Error check?
|
|
|
|
ASSERT(fmsg.qbthrCtx != NULL);
|
|
RcInsertHbt(fmsg.qbthrCtx, (KEY) &qalias->hashAlias, &addr);
|
|
break;
|
|
|
|
case RC_NoExists:
|
|
|
|
// Context string was not defined -- not an error here?
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// REVIEW: Error message?
|
|
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* VOID VOutCtxOffsetTable()
|
|
*
|
|
* Description:
|
|
* This function outputs the Context-Offset table into the FS. It goes
|
|
* through every context string defined in the map section of the project
|
|
* file and finds the offset looking into the Topic-Offset Table. It
|
|
* outputs the offset against the hashed context string.
|
|
*
|
|
* Table layout:
|
|
* integer Count of Context strings present
|
|
* Context ID -- Address
|
|
* .....................
|
|
* .....................
|
|
* Context ID -- Address
|
|
*
|
|
* Returns;
|
|
* NOTHING
|
|
*-----------------------------------------------------------------------------*/
|
|
|
|
const char txtCTXOMAP[] = "|CTXOMAP"; // context map file name
|
|
|
|
void STDCALL VOutCtxOffsetTable(void)
|
|
{
|
|
QMAP qmap;
|
|
ADDR addr;
|
|
RC_TYPE rc;
|
|
BOOL fNagged = FALSE;
|
|
int count;
|
|
#ifdef _DEBUG
|
|
int actual = 0;
|
|
int cActualMap;
|
|
#endif
|
|
|
|
// create the context map file
|
|
|
|
fmsg.hfCtxOMap = HfCreateFileHfs(hfsOut, txtCTXOMAP, 0);
|
|
|
|
// Write out size of map table.
|
|
|
|
int cmap = pdrgMap ? pdrgMap->Count() : 0;
|
|
int imap;
|
|
|
|
/*
|
|
* If we're compressing, then we run the map entries first to get a
|
|
* count of valid entries. It sometimes happens that people will drop
|
|
* in .H files that contain not only map entries but a bunch of other
|
|
* #defines for their code -- such as dropping in ApStudio's resource.h
|
|
* file. Rather then put all of the non-valid entries into the help file,
|
|
* we make a pass here to calculate the number of real entries. Then when
|
|
* we're in the for() loop that writes the entry into the help file, we
|
|
* simply ignore non-valid entries.
|
|
*/
|
|
|
|
if (cmap && (options.fsCompress &
|
|
(COMPRESS_TEXT_PHRASE | COMPRESS_TEXT_HALL | COMPRESS_TEXT_ZECK))) {
|
|
int cRealMap = cmap;
|
|
#ifdef _DEBUG
|
|
cActualMap = cmap;
|
|
#endif
|
|
|
|
for (imap = 0, qmap = (QMAP) pdrgMap->GetBasePtr();
|
|
imap < cmap;
|
|
imap++, qmap++) {
|
|
|
|
// Get address of given hash value
|
|
|
|
rc = RcLookupByKey(fmsg.qbthrCtx, (KEY) &qmap->hash, NULL,
|
|
(LPVOID) &addr);
|
|
if (rc == RC_NoExists)
|
|
cRealMap--;
|
|
}
|
|
LcbWriteIntAsShort(fmsg.hfCtxOMap, cRealMap);
|
|
}
|
|
else {
|
|
LcbWriteIntAsShort(fmsg.hfCtxOMap, cmap);
|
|
#ifdef _DEBUG
|
|
cActualMap = cmap;
|
|
#endif
|
|
|
|
}
|
|
ASSERT(fmsg.qbthrCtx != NULL);
|
|
|
|
if (cmap > 0) {
|
|
ASSERT(ptblMap);
|
|
for (imap = 0, qmap = (QMAP) pdrgMap->GetBasePtr();
|
|
imap < cmap;
|
|
imap++, qmap++) {
|
|
|
|
// Get address of given hash value
|
|
|
|
rc = RcLookupByKey(fmsg.qbthrCtx, (KEY) &qmap->hash, NULL, (LPVOID) &addr);
|
|
if (rc == RC_NoExists) {
|
|
|
|
int ialias;
|
|
QALIAS qalias;
|
|
if (pdrgAlias && pdrgAlias->Count() > 0) {
|
|
for (ialias = 0, qalias = (QALIAS) pdrgAlias->GetBasePtr();
|
|
ialias < pdrgAlias->Count();
|
|
ialias++, qalias++) {
|
|
|
|
// Look up address for alias in context btree
|
|
|
|
if (qalias->hashAlias == qmap->hash)
|
|
break;
|
|
}
|
|
if (ialias < pdrgAlias->Count()) {
|
|
if (options.fsCompress &
|
|
(COMPRESS_TEXT_PHRASE | COMPRESS_TEXT_HALL |
|
|
COMPRESS_TEXT_ZECK))
|
|
continue; // aliased, so not an error
|
|
else
|
|
goto BadCtx; // non-compressed, have to add it anyway
|
|
}
|
|
}
|
|
|
|
if (!fNagged) {
|
|
errHpj.ep = epNoFile;
|
|
VReportError(HCERR_MAP_UNUSED, &errHpj);
|
|
fNagged = TRUE;
|
|
count = 0;
|
|
}
|
|
ASSERT(HCERR_MAP_UNUSED < HCERR_WARNINGS);
|
|
if (!options.fSupressNotes) {
|
|
strcpy(szParentString, "\t");
|
|
strcat(szParentString, ptblMap->GetPointer(qmap->pos) +
|
|
sizeof(HASH));
|
|
strcat(szParentString, txtEol);
|
|
SendStringToParent(szParentString);
|
|
if (pLogFile)
|
|
pLogFile->outstring(szParentString);
|
|
|
|
if (++count == 10) {
|
|
count = 0;
|
|
doGrind();
|
|
}
|
|
}
|
|
BadCtx:
|
|
addr = addrNil;
|
|
|
|
/*
|
|
* When we are compressing the help file, we already reduced
|
|
* the total map count to the number of entries actually
|
|
* used, so we can just ignore this not-found entry.
|
|
*/
|
|
|
|
if (options.fsCompress &
|
|
(COMPRESS_TEXT_PHRASE | COMPRESS_TEXT_HALL |
|
|
COMPRESS_TEXT_ZECK))
|
|
continue;
|
|
}
|
|
|
|
// Write out CTX
|
|
|
|
LcbWriteHf(fmsg.hfCtxOMap, &qmap->ctx, sizeof(CTX));
|
|
|
|
// Write out address
|
|
|
|
LcbWriteHf(fmsg.hfCtxOMap, &addr, sizeof(ADDR));
|
|
#ifdef _DEBUG
|
|
actual += sizeof(CTX) + sizeof(ADDR);
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef _DEBUG
|
|
{
|
|
int expected = cActualMap * (sizeof(CTX) + sizeof(ADDR));
|
|
ASSERT(expected == actual);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
INLINE static BOOL STDCALL IsCtxPrefix(PCSTR pszContext)
|
|
{
|
|
// BUGBUG: strnicmp won't be correct for DBCS
|
|
|
|
if (ptblCtxPrefixes) {
|
|
for (int pos = 1; pos <= ptblCtxPrefixes->CountStrings(); pos++) {
|
|
if (strnicmp(pszContext, ptblCtxPrefixes->GetPointer(pos),
|
|
strlen(ptblCtxPrefixes->GetPointer(pos))) == 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if (strnicmp(pszContext, "IDH_", 4) == 0)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|