/************************************************************************ * * * MAPREAD.CPP * * * * Copyright (C) Microsoft Corporation 1995 * * All Rights reserved. * * * ************************************************************************/ #include "stdafx.h" #include "mapread.h" #include "..\hwdll\waitcur.h" const int MAX_MAP_TABLES = 10; static CTable* aMapTables[MAX_MAP_TABLES + 1]; static CTable* aAliasTables[MAX_MAP_TABLES + 1]; static CTable* ptblMapNames; const char txtDBCSOption[] = "DBCS="; extern const char txtMAP[]; static PSTR FASTCALL SkipToEndOfWord(PSTR psz); /*************************************************************************** FUNCTION: CReadMapFile::CReadMapFile PURPOSE: Read the [MAP] section of a project file into a double-table PARAMETERS: pszFile -- either help file or project file fHelpFile -- TRUE (default) if it pszFile is a help file RETURNS: m_ptblMap is non-NULL is a map table is available COMMENTS: Numbers are stored in the primary string, Topic IDs are stored in the secondary string. MODIFICATION DATES: 07-Mar-1995 [ralphw] ***************************************************************************/ CReadMapFile::CReadMapFile(PCSTR pszFile, BOOL fHelpFile) { m_ptblMap = NULL; m_ptblAlias = NULL; PCSTR pszProjectFile; if (!ptblMapNames) ptblMapNames = new CTable; if (fHelpFile) { ASSERT(pMapFile); char szDummy[MAX_PATH]; PSTR pszFilePortion; if (GetFullPathName(pszFile, sizeof(szDummy), szDummy, &pszFilePortion) == 0) pszFilePortion = (PSTR) pszFile; int pos = pMapFile->ctbl.IsPrimaryStringInTable(pszFilePortion) + 1; if (pos < 2) return; // we don't have a project file for this help file else pszProjectFile = pMapFile->ctbl.GetPointer(pos); } else pszProjectFile = pszFile; int pos = ptblMapNames->IsStringInTable(pszProjectFile); if (pos) { m_ptblMap = aMapTables[pos]; m_ptblAlias = aAliasTables[pos]; return; } CHourGlass cwait; /* * Note that by adding the name here, we will never attempt to read * this project file again if it can't be opened, or if it doesn't contain * a [MAP] section. */ if (ptblMapNames->CountStrings() > MAX_MAP_TABLES) { /* * We overflowed, which means we probably have a lot of unused * map tables hanging out. So we throw out the whole batch and * start over. */ for (int i = 1; i <= ptblMapNames->CountStrings(); i++) { if (aMapTables[i]) { delete aMapTables[i]; aMapTables[i] = NULL; } if (aAliasTables[i]) { delete aAliasTables[i]; aAliasTables[i] = NULL; } } delete ptblMapNames; ptblMapNames = new CTable; } pos = ptblMapNames->AddString(pszProjectFile); iTop = 0; if (!FPushFilePfs(pszProjectFile)) return; char szOldDir[MAX_PATH]; GetCurrentDirectory(sizeof(szOldDir), szOldDir); ChangeDirectory(pszProjectFile); m_ptblDefine = new CTable; fDBCSSystem = _fDBCSSystem; CStr cszDst; RC_TYPE rc = RC_Success; CInput* pin = PfTopPfs(); while (rc == RC_Success) { if (!pin->getline(&cszDst)) { // Close current file, continue with nested file if there is one FPopPfs(); if (!(pin = PfTopPfs())) { rc = RC_EOF; break; } continue; } LineRead: if (rc != RC_Success) break; if (nstrsubcmp(cszDst, txtDBCSOption)) { char szValue[256]; GetArg(szValue, FirstNonSpace(cszDst.psz + strlen(txtDBCSOption))); fDBCSSystem = YesNo(szValue); } // REVIEW: we should handle DBCS=, ROOT=, and REPLACE= else if (nstrisubcmp(cszDst, txtMAP)) { if (!aMapTables[pos]) aMapTables[pos] = new CTable; m_ptblMap = aMapTables[pos]; rc = CReadMapSection(&cszDst); goto LineRead; } else if (nstrisubcmp(cszDst, "[ALIAS]")) { if (!aAliasTables[pos]) aAliasTables[pos] = new CTable; m_ptblAlias = aAliasTables[pos]; rc = CReadAliasSection(&cszDst); goto LineRead; } } if (rc != RC_Success) { // Happens if there is no map section SetCurrentDirectory(szOldDir); return; } if (m_ptblDefine) { delete m_ptblDefine; m_ptblDefine = NULL; } SetCurrentDirectory(szOldDir); } RC_TYPE CReadMapFile::CReadMapSection(CStr* pcszDst) { RC_TYPE rc = RC_Success; while (rc == RC_Success) { rc = RcGetLogicalLine(pcszDst); if (rc != RC_Success) return rc; if (*pcszDst->psz == '[') return RC_Success; if (nstrisubcmp(pcszDst->psz, txtDefine) && m_ptblDefine->IsStringInTable( FirstNonSpace(pcszDst->psz + strlen(txtDefine) + 1, fDBCSSystem))) continue; PSTR pszTmp; if (!(pszTmp = StrChr(pcszDst->psz, CH_EQUAL, fDBCSSystem))) pszTmp = SkipToEndOfWord(pcszDst->psz); if (!pszTmp || !*pszTmp) continue; if (nstrisubcmp(pcszDst->psz, txtDefine)) { strcpy(pcszDst->psz, FirstNonSpace(pcszDst->psz + strlen(txtDefine), fDBCSSystem)); if (*pszTmp != CH_EQUAL) pszTmp = SkipToEndOfWord(pcszDst->psz); if (!*pszTmp) { continue; } } *pszTmp = '\0'; SzTrimSz(pcszDst->psz); // Special case no-help constant if (nstrsubcmp(FirstNonSpace(pszTmp + 1, fDBCSSystem), "((DWORD) -1)")) continue; PSTR pszSave = pcszDst->psz; PSTR pszLine = SzTrimSz(pszTmp + 1); int val; if (!FGetUnsigned(pszLine, &pszTmp, &val)) continue; char szNum[20]; _itoa(val, szNum, 10); m_ptblMap->AddString(szNum, pszSave); } return rc; } RC_TYPE CReadMapFile::CReadAliasSection(CStr* pcszDst) { RC_TYPE rc = RC_Success; while (rc == RC_Success) { rc = RcGetLogicalLine(pcszDst); if (rc != RC_Success) return rc; if (*pcszDst->psz == '[') return RC_Success; PSTR pszAlias; if (!(pszAlias = StrChr(pcszDst->psz, CH_EQUAL, fDBCSSystem))) continue; *pszAlias++ = '\0'; SzTrimSz(pcszDst->psz); SzTrimSz(pszAlias); m_ptblAlias->AddString(pcszDst->psz, pszAlias); } return rc; } // Stolen shamelessly from hpj.cpp in hcrtf static const char txtInclude[] = "#include"; static const char txtIfDef[] = "#ifdef"; static const char txtIfnDef[] = "#ifndef"; #define IsQuote(ch) ((ch) == CH_QUOTE || (ch) == CH_START_QUOTE || (ch) == CH_END_QUOTE) RC_TYPE STDCALL CReadMapFile::RcGetLogicalLine(CStr* pcszDst) { PSTR pszDst = pcszDst->psz; // purely for our notational convenience CInput* pin = PfTopPfs(); if (!pin) return RC_EOF; for (;;) { if (!pin->getline(pcszDst)) { // Close current file, continue with nested file if there is one FPopPfs(); if (!(pin = PfTopPfs())) return RC_EOF; continue; } if (*pszDst == CH_SPACE || *pszDst == CH_TAB) strcpy(pszDst, FirstNonSpace(pszDst, fDBCSSystem)); PSTR psz = pszDst; switch (*psz) { case 0: case ';': continue; case '#': if (nstrisubcmp(psz, txtInclude)) { // process #include psz = FirstNonSpace(pszDst + strlen(txtInclude), fDBCSSystem); if (!psz) { continue; } if (*psz == CH_QUOTE || *psz == '<') { char ch = (*psz == CH_QUOTE) ? CH_QUOTE : '>'; psz++; PSTR pszEnd = StrChr(psz, ch, fDBCSSystem); if (*pszEnd) *pszEnd = '\0'; } FPushFilePfs(psz); if (!(pin = PfTopPfs())) return RC_EOF; continue; } else if (nstrisubcmp(psz, txtDefine)) goto ValidString; else if (nstrisubcmp(psz, txtIfDef)) m_ptblDefine->AddString( FirstNonSpace(psz + strlen(txtIfDef) + 1, fDBCSSystem)); else if (nstrisubcmp(psz, txtIfnDef)) m_ptblDefine->AddString( FirstNonSpace(psz + strlen(txtIfnDef) + 1, fDBCSSystem)); // REVIEW: process #ifdef, #ifndef, #else, #endif continue; default: // We have a valid string. if (psz != pszDst) strcpy(pszDst, psz); // Remove any comments ValidString: // Usually there are no comments, so the strchr/strstr checks // are faster then stepping through every character in the line if (strchr(pszDst, ';') || strstr(pszDst, "//")) { for (psz = pszDst; *psz; psz++) { if (IsQuote(*psz)) { psz++; while (!IsQuote(*psz) && *psz) psz++; } if (*psz == ';') { *psz = '\0'; break; } else if (*psz == '/' && psz[1] == '/') { *psz = '\0'; break; } } } while ((psz = strstr(pszDst, "/*"))) { PSTR pszTmp = strstr(psz, "*/"); if (pszTmp) strcpy(psz, FirstNonSpace(pszTmp + 2, fDBCSSystem)); else { char szBuf[512]; do { if (!pin->getline(szBuf)) { /* * Close current file, continue with nested * file if there is one */ FPopPfs(); if (!(pin = PfTopPfs())) return RC_EOF; continue; } } while (!(pszTmp = strstr(szBuf, "*/"))); strcpy(psz, FirstNonSpace(pszTmp + 2, fDBCSSystem)); // New line could have comments, so start all over goto ValidString; } } SzTrimSz(pszDst); if (!*pszDst) continue; return RC_Success; } } } BOOL STDCALL CReadMapFile::FPushFilePfs(PCSTR szFile) { CInput* pin = new CInput(szFile); if (!pin->fInitialized) return FALSE; apin[iTop++] = pin; return TRUE; } BOOL CReadMapFile::FPopPfs(void) { if (iTop >= 0) { ASSERT(PfTopPfs() != NULL); delete PfTopPfs(); --iTop; return TRUE; } return FALSE; } static PSTR FASTCALL SkipToEndOfWord(PSTR psz) { while (*psz != ' ' && *psz != '\t' && *psz) psz++; return psz; }