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.
893 lines
19 KiB
893 lines
19 KiB
// Hilite.c -- Code to drive the FTSrch hilite APIs
|
|
|
|
#include "help.h"
|
|
|
|
// #include "FrTypes.h"
|
|
#include "FrStuff.h"
|
|
// #include "FrParagp.h"
|
|
#include "FcPriv.h"
|
|
|
|
// Variables to support hilites from the Find tab:
|
|
|
|
static CHAR achMemberHilite[cchWindowMemberMax];
|
|
static char szFNameHilite[MAX_PATH];
|
|
|
|
|
|
static VA vaHilite= { vaNil }; // vaNil for no hilites;
|
|
// == vaNSR or vaSR when hilites exist
|
|
|
|
static HANDLE haHilites; // handle for results from HILITER
|
|
static HANDLE haHelpHilites; // handle for results mapped into HELPHILITE form
|
|
|
|
static HILITE *paHilites; // address of results from HILITER
|
|
static HELPHILITE *paHelpHilites; // address of results mapped into HELPHILITE form
|
|
static UINT cHilites; // number of hilites
|
|
|
|
// Variables used to map the HILITE array into the HELPHILITE array:
|
|
|
|
static HILITE *pHilite; // Points to the current HILITE item
|
|
static HELPHILITE *pHelpHilite; // Points to the current HELPHILITE item
|
|
static UINT cHilitesLeft; // Number of HILITE items left to map
|
|
static BOOL fScanningForStart; // True when we're looking for a text
|
|
// segment containing the base offset
|
|
// of a HILITE. False when we're looking
|
|
// for the limit offset.
|
|
|
|
#ifdef _DEBUG
|
|
#define HeapChecker() lcHeapCheck()
|
|
#else // _DEBUG
|
|
#define HeapChecker()
|
|
#endif // _DEBUG
|
|
|
|
BOOL STDCALL HilitesDefined()
|
|
{
|
|
return vaHilite.dword != vaNil;
|
|
}
|
|
|
|
BOOL IsHiliteWindow(QDE qde)
|
|
{
|
|
PSTR pszMemberName;
|
|
int iWnd;
|
|
|
|
if (!HilitesDefined()) return FALSE;
|
|
|
|
if (hwndNote) return FALSE; // If hwndNote is non-null, we're in a popup window
|
|
|
|
for (iWnd= 0; iWnd < MAX_WINDOWS; ++iWnd)
|
|
if ( ahwnd[iWnd].hwndTopic == qde->hwnd
|
|
|| ahwnd[iWnd].hwndTitle == qde->hwnd
|
|
)
|
|
{
|
|
pszMemberName= ahwnd[iWnd].pszMemberName;
|
|
|
|
if (!pszMemberName) return FALSE;
|
|
|
|
return !WCmpiSz(achMemberHilite, pszMemberName);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL STDCALL HasTopicChanged(QDE qde)
|
|
{
|
|
VA vaDE;
|
|
|
|
if (!IsHiliteWindow(qde)) return FALSE;
|
|
|
|
if (WCmpiSz(szFNameHilite, PszFromGh(QDE_FM(qde)))) return TRUE; // Same HLP file?
|
|
|
|
ASSERT(qde->top.mtop.vaNSR.dword != vaNil || qde->top.mtop.vaSR.dword != vaNil);
|
|
|
|
vaDE= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
|
|
: qde->top.mtop.vaSR;
|
|
|
|
return vaDE.dword != vaHilite.dword; // Same address within the HLP file?
|
|
}
|
|
|
|
void STDCALL CheckForTopicChanges(QDE qde)
|
|
{
|
|
if (vaHilite.dword == vaNil) return;
|
|
|
|
if (HasTopicChanged(qde))
|
|
DiscardHiliteInformation();
|
|
}
|
|
|
|
static BOOL STDCALL ScanThisTopic(QDE qde);
|
|
static void STDCALL InitScanBuffer(BOOL fSendToScanner);
|
|
static void STDCALL DisconnectScanBuffer();
|
|
|
|
void STDCALL CreateHiliteInformation(QDE qde)
|
|
{
|
|
int c;
|
|
PHILITE phlSrc, phlDest;
|
|
BOOL fScanned;
|
|
|
|
HeapChecker();
|
|
|
|
if (vaHilite.dword != vaNil) DiscardHiliteInformation();
|
|
|
|
HeapChecker();
|
|
|
|
InitScanBuffer(TRUE);
|
|
|
|
HeapChecker();
|
|
|
|
fScanned= ScanThisTopic(qde);
|
|
|
|
HeapChecker();
|
|
|
|
DisconnectScanBuffer();
|
|
|
|
HeapChecker();
|
|
|
|
if (!fScanned) return;
|
|
|
|
ASSERT(!cHilites);
|
|
ASSERT(!haHilites);
|
|
ASSERT(!haHelpHilites);
|
|
|
|
cHilites= pCountHilites(GetHiliter(), 0, -1);
|
|
|
|
if (!cHilites) return;
|
|
|
|
haHilites= GhAlloc(LMEM_FIXED, cHilites * sizeof(HILITE));
|
|
|
|
HeapChecker();
|
|
|
|
if (!haHilites) goto resource_limited;
|
|
|
|
paHilites= (PHILITE) PtrFromGh(haHilites);
|
|
|
|
if (0 > pQueryHilites(GetHiliter(), 0, -1, cHilites, paHilites))
|
|
goto resource_limited;
|
|
|
|
HeapChecker();
|
|
|
|
if (cHilites > 1)
|
|
{
|
|
// The hilite array may contain overlapping hilites.
|
|
// The loop below looks for overlaps and consolidates
|
|
// them.
|
|
|
|
for (c= cHilites, phlDest= paHilites, phlSrc= paHilites + 1;
|
|
--c;
|
|
)
|
|
{
|
|
ASSERT(phlSrc->base >= phlDest->base);
|
|
|
|
if (phlDest->limit > phlSrc->base)
|
|
{
|
|
ASSERT(phlSrc->limit >= phlDest->limit);
|
|
|
|
phlDest->limit = (phlSrc++)->limit;
|
|
}
|
|
else *(++phlDest)= *phlSrc++;
|
|
}
|
|
|
|
cHilites= 1 + (phlDest - paHilites);
|
|
|
|
HeapChecker();
|
|
}
|
|
|
|
cHilitesLeft= cHilites;
|
|
|
|
haHelpHilites= GhAlloc(GMEM_FIXED, cHilites * sizeof(HELPHILITE));
|
|
|
|
HeapChecker();
|
|
|
|
if (!haHelpHilites) goto resource_limited;
|
|
|
|
paHelpHilites= (PHELPHILITE) PtrFromGh(haHelpHilites);
|
|
|
|
HeapChecker();
|
|
|
|
InitScanBuffer(FALSE);
|
|
|
|
HeapChecker();
|
|
|
|
fScanned= ScanThisTopic(qde);
|
|
|
|
HeapChecker();
|
|
|
|
FreeGh(haHilites); haHilites= NULL; pHelpHilite= NULL; pHilite= paHilites= NULL;
|
|
|
|
HeapChecker();
|
|
|
|
if (!fScanned) goto resource_limited;
|
|
|
|
lstrcpy(achMemberHilite, ahwnd[iCurWindow].pszMemberName);
|
|
lstrcpy(szFNameHilite, PszFromGh(QDE_FM(qde)));
|
|
|
|
vaHilite= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
|
|
: qde->top.mtop.vaSR;
|
|
|
|
return;
|
|
|
|
resource_limited:
|
|
|
|
// If we don't have enough memory to construct the highlight structures
|
|
// we just deallocate the partial results and set the hilite count to
|
|
// zero.
|
|
|
|
HeapChecker();
|
|
|
|
if (haHelpHilites) { FreeGh(haHelpHilites); haHelpHilites = NULL; }
|
|
if (haHilites ) { FreeGh(haHilites ); haHilites = NULL; }
|
|
|
|
HeapChecker();
|
|
|
|
pHilite = paHilites = NULL;
|
|
pHelpHilite = paHelpHilites = NULL;
|
|
cHilitesLeft = cHilites = 0;
|
|
}
|
|
|
|
void STDCALL DiscardHiliteInformation()
|
|
{
|
|
int iWnd;
|
|
|
|
ASSERT(HilitesDefined());
|
|
|
|
for (iWnd= 0; iWnd < MAX_WINDOWS; ++iWnd)
|
|
if ( ahwnd[iWnd].pszMemberName
|
|
&& !WCmpiSz(achMemberHilite, ahwnd[iWnd].pszMemberName)
|
|
)
|
|
{
|
|
ASSERT(ahwnd[iWnd].hwndTopic);
|
|
|
|
if (ahwnd[iWnd].hwndTopic)
|
|
InvalidateRect(ahwnd[iWnd].hwndTopic, NULL, TRUE);
|
|
|
|
if (ahwnd[iWnd].hwndTitle)
|
|
InvalidateRect(ahwnd[iWnd].hwndTitle, NULL, TRUE);
|
|
|
|
break;
|
|
}
|
|
|
|
achMemberHilite[0] = 0;
|
|
szFNameHilite[0] = 0;
|
|
|
|
vaHilite.dword= vaNil;
|
|
|
|
ASSERT(!haHilites && !paHilites && !pHilite && !pHelpHilite);
|
|
|
|
HeapChecker();
|
|
|
|
if (haHelpHilites)
|
|
{
|
|
FreeGh(haHelpHilites);
|
|
|
|
haHelpHilites = NULL;
|
|
paHelpHilites = NULL;
|
|
cHilites = 0;
|
|
}
|
|
|
|
HeapChecker();
|
|
}
|
|
|
|
UINT STDCALL GetHilites(QDE qde, PHELPHILITE *ppHelpHilites)
|
|
{
|
|
if (!paHelpHilites || !cHilites) return 0;
|
|
|
|
if (!IsHiliteWindow(qde)) return 0;
|
|
|
|
if (HasTopicChanged(qde))
|
|
{
|
|
DiscardHiliteInformation();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
*ppHelpHilites= paHelpHilites;
|
|
|
|
return cHilites;
|
|
}
|
|
|
|
#define COLLECT_BUFFER 4096
|
|
|
|
static BYTE ScanBuffer[COLLECT_BUFFER];
|
|
static PSTR pszCollect;
|
|
static UINT iCharSet;
|
|
static BOOL fPendingSpace;
|
|
static int cbScanned;
|
|
static int cbCollect;
|
|
|
|
static void STDCALL InitScanBuffer(BOOL fSendToScanner)
|
|
{
|
|
if (pszCollect) DisconnectScanBuffer();
|
|
|
|
pszCollect = fSendToScanner? ScanBuffer : NULL;
|
|
cbCollect = 0;
|
|
cbScanned = 0;
|
|
iCharSet = 0;
|
|
fPendingSpace = FALSE;
|
|
|
|
ASSERT(pClearDisplayText);
|
|
|
|
if (fSendToScanner) pClearDisplayText(GetHiliter());
|
|
else
|
|
{
|
|
pHilite = paHilites;
|
|
pHelpHilite = paHelpHilites;
|
|
cHilitesLeft = cHilites;
|
|
fScanningForStart = TRUE;
|
|
}
|
|
}
|
|
|
|
static void STDCALL FlushToScanner();
|
|
|
|
static void STDCALL DisconnectScanBuffer()
|
|
{
|
|
FlushToScanner();
|
|
|
|
pszCollect = NULL;
|
|
}
|
|
|
|
static void STDCALL FlushToScanner()
|
|
{
|
|
if (cbCollect)
|
|
pScanDisplayText(GetHiliter(), pszCollect, cbCollect, iCharSet, lcid);
|
|
|
|
cbCollect= 0;
|
|
}
|
|
|
|
// The QueueForScanner routine processes text from the display environment.
|
|
// Processing happens in two phases. During the first phase the text is passed
|
|
// to the HILITER. In that phase the explicit result from QueueForScanner is
|
|
// ignored. During the second phase we scan the text again to map an array of
|
|
// HILITES into an array of HELPHILITES. In the second phase the explicit result
|
|
// from QueueForScanner is TRUE when all the elements of the HILITES array have
|
|
// been mapped into the HELPHILITES array.
|
|
|
|
static BOOL STDCALL QueueForScanner(PSTR *ppszText, UINT charset, VA vaBase, int ichBase)
|
|
{
|
|
int cbBase;
|
|
PSZ pszText= *ppszText;
|
|
UINT cbText = strlen(pszText);
|
|
|
|
*ppszText = pszText + cbText;
|
|
|
|
if (fPendingSpace) cbScanned++;
|
|
|
|
cbBase= cbScanned;
|
|
|
|
cbScanned += cbText;
|
|
|
|
// This routine is used for two purposes. When pszCollect is non-NULL
|
|
// we're passing the topic text along to the Hiliter. When it's NULL,
|
|
// we're remapping the HILITE array into the HELPHILITE array.
|
|
|
|
if (!pszCollect)
|
|
{
|
|
fPendingSpace= FALSE;
|
|
|
|
for (;;)
|
|
{
|
|
if (!cHilitesLeft) return TRUE;
|
|
|
|
if (fScanningForStart)
|
|
{
|
|
if (pHilite->base >= cbScanned) return FALSE;
|
|
|
|
// ASSERT(pHilite->base >= cbBase);
|
|
|
|
pHelpHilite->vaBase = vaBase;
|
|
pHelpHilite->ichBase = ichBase + pHilite->base - cbBase;
|
|
|
|
if (pHilite->limit > cbScanned)
|
|
{
|
|
fScanningForStart= FALSE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pHelpHilite->vaLimit = vaBase;
|
|
pHelpHilite->ichLimit = ichBase + pHilite->limit - cbBase;
|
|
|
|
++pHelpHilite;
|
|
++pHilite;
|
|
|
|
--cHilitesLeft;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (pHilite->limit > cbScanned) return FALSE;
|
|
|
|
pHelpHilite->vaLimit = vaBase;
|
|
pHelpHilite->ichLimit = ichBase + pHilite->limit - cbBase;
|
|
|
|
fScanningForStart = TRUE;
|
|
|
|
++pHelpHilite;
|
|
++pHilite;
|
|
|
|
--cHilitesLeft;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (charset != iCharSet)
|
|
{
|
|
FlushToScanner();
|
|
|
|
iCharSet= charset;
|
|
}
|
|
|
|
if (cbText + cbCollect + (fPendingSpace? 1 : 0) > COLLECT_BUFFER)
|
|
FlushToScanner();
|
|
|
|
if (fPendingSpace)
|
|
{
|
|
pszCollect[cbCollect++] = ' ';
|
|
|
|
fPendingSpace= FALSE;
|
|
}
|
|
|
|
while (cbText)
|
|
{
|
|
int cbChunk= cbText;
|
|
|
|
if (cbChunk > COLLECT_BUFFER - cbCollect)
|
|
cbChunk = COLLECT_BUFFER - cbCollect;
|
|
|
|
cbText -= cbChunk;
|
|
|
|
CopyMemory(pszCollect + cbCollect, pszText, cbChunk);
|
|
|
|
cbCollect += cbChunk;
|
|
pszText += cbChunk;
|
|
|
|
if (cbCollect == COLLECT_BUFFER)
|
|
FlushToScanner();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL fTitleSeen;
|
|
|
|
static BOOL bSYS;
|
|
static BOOL bSYSFirst;
|
|
|
|
static BOOL STDCALL NextFTSString(QDE qde, LPSTR pszText, LPSTR *ppCmd,
|
|
int* pCharSet, VA vaBase, PCSTR pszEnd)
|
|
{
|
|
char chCmd;
|
|
MOBJ mobj;
|
|
MOPG mopg;
|
|
BOOL bProcessCell = FALSE;
|
|
short int iCell;
|
|
BYTE CharSetNew;
|
|
LPSTR pszBase= pszText;
|
|
|
|
if (*pszText)
|
|
QueueForScanner(&pszText, *pCharSet, vaBase, pszText - pszBase);
|
|
|
|
ASSERT(*pszText == 0x00);
|
|
|
|
while (pszText < pszEnd) {
|
|
while (*pszText == chCommand) {
|
|
|
|
// Side by side paragraph has the following embedded structure:
|
|
// INT16 cell number;
|
|
// MOBJ;
|
|
// MOPG;
|
|
|
|
if (bSYS && bSYSFirst)
|
|
{
|
|
bSYSFirst = FALSE;
|
|
bProcessCell = TRUE;
|
|
#ifdef _X86_
|
|
iCell = *((short int *) *ppCmd);
|
|
#else
|
|
{
|
|
UNALIGNED short int *pTemp;
|
|
pTemp = (short int *)*ppCmd;
|
|
iCell = *pTemp;
|
|
}
|
|
#endif
|
|
(*ppCmd) += 2;
|
|
if (iCell < 0)
|
|
return TRUE;
|
|
|
|
#ifdef _X86_
|
|
(*ppCmd) += CbUnpackMOBJ(&mobj, *ppCmd);
|
|
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd);
|
|
#else
|
|
(*ppCmd) += CbUnpackMOBJ(&mobj, (void *) *ppCmd, QDE_ISDFFTOPIC(qde));
|
|
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd, QDE_ISDFFTOPIC(qde));
|
|
#endif
|
|
}
|
|
|
|
// do
|
|
// {
|
|
chCmd = **ppCmd;
|
|
switch((0x00FF & chCmd))
|
|
{
|
|
case bNewLine:
|
|
fPendingSpace = TRUE;
|
|
(*ppCmd)++;
|
|
break;
|
|
|
|
case bNewPara:
|
|
fPendingSpace = TRUE;
|
|
(*ppCmd)++;
|
|
break;
|
|
|
|
case bTab:
|
|
fPendingSpace = TRUE;
|
|
(*ppCmd)++;
|
|
break;
|
|
|
|
case bEndHotspot:
|
|
(*ppCmd)++;
|
|
break;
|
|
|
|
case bBlankLine:
|
|
fPendingSpace = TRUE;
|
|
*ppCmd += 3;
|
|
break;
|
|
|
|
case bWordFormat:
|
|
(*ppCmd)++;
|
|
|
|
#ifdef _X86_
|
|
CharSetNew = GetCharset(qde, (*((INT16*)*ppCmd))) & 0x000000ff;
|
|
#else
|
|
{
|
|
UNALIGNED INT16 *pTemp;
|
|
pTemp = (INT16*) *ppCmd;
|
|
CharSetNew = GetCharset(qde, *pTemp) & 0x000000ff;
|
|
}
|
|
#endif
|
|
if (CharSetNew != *pCharSet)
|
|
{
|
|
FlushToScanner();
|
|
*pCharSet= CharSetNew;
|
|
}
|
|
|
|
*ppCmd += 2;
|
|
break;
|
|
|
|
case bWrapObjLeft:
|
|
case bWrapObjRight:
|
|
case bInlineObject:
|
|
|
|
fPendingSpace = TRUE;
|
|
|
|
(*ppCmd)++;
|
|
#ifdef _X86_
|
|
*ppCmd += CbUnpackMOBJ(&mobj, (void *) *ppCmd);
|
|
#else
|
|
*ppCmd += CbUnpackMOBJ(&mobj, (void *) *ppCmd,
|
|
QDE_ISDFFTOPIC(qde));
|
|
#endif
|
|
*ppCmd += (INT16) mobj.lcbSize;
|
|
break;
|
|
|
|
case bEnd:
|
|
|
|
(*ppCmd)++;
|
|
|
|
// fPendingSpace= TRUE;
|
|
|
|
if (bSYS)
|
|
{
|
|
bProcessCell = TRUE;
|
|
#ifdef _X86_
|
|
iCell = *((short int *) *ppCmd);
|
|
#else
|
|
{
|
|
UNALIGNED short int *pTemp;
|
|
pTemp = (short int *)*ppCmd;
|
|
iCell = *pTemp;
|
|
}
|
|
#endif
|
|
(*ppCmd) += 2;
|
|
|
|
if (iCell < 0)
|
|
return TRUE;
|
|
|
|
#ifdef _X86_
|
|
(*ppCmd) += CbUnpackMOBJ(&mobj, *ppCmd);
|
|
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd);
|
|
#else
|
|
(*ppCmd) += CbUnpackMOBJ(&mobj, (void *) *ppCmd, QDE_ISDFFTOPIC(qde));
|
|
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd, QDE_ISDFFTOPIC(qde));
|
|
#endif
|
|
}
|
|
|
|
|
|
if (bProcessCell)
|
|
bProcessCell = FALSE;
|
|
else
|
|
return TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
if (FShortHotspot(**ppCmd))
|
|
{
|
|
*ppCmd += 5;
|
|
}
|
|
else if (FLongHotspot(**ppCmd))
|
|
{
|
|
(*ppCmd)++;
|
|
#ifdef _X86_
|
|
*ppCmd += 2 + *((INT16*)*ppCmd);
|
|
#else
|
|
{UNALIGNED INT16 *pTemp;
|
|
pTemp = (INT16*)*ppCmd;
|
|
*ppCmd += 2 + *pTemp;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// } while (bProcessCell);
|
|
|
|
pszText++;
|
|
|
|
}
|
|
|
|
if (pszText) QueueForScanner(&pszText, *pCharSet, vaBase, pszText - pszBase);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
enum {
|
|
TABTYPELEFT,
|
|
TABTYPERIGHT,
|
|
TABTYPECENTER,
|
|
TABTYPEDECIMAL
|
|
};
|
|
|
|
#ifdef _X86_
|
|
static PBYTE STDCALL ScanTopic(LPSTR lpData, QFCINFO qfcinfo, MTOP* pmtop)
|
|
#else
|
|
static PBYTE STDCALL ScanTopic(LPSTR lpData, QFCINFO qfcinfo, MTOP* pmtop, QDE qde)
|
|
#endif
|
|
{
|
|
MOBJ mobj;
|
|
int iTopic;
|
|
QMSBS qmsbs;
|
|
#ifndef _X86_
|
|
MTOP mtop;
|
|
#endif
|
|
|
|
for(;;) {
|
|
#ifdef _X86_
|
|
lpData += CbUnpackMOBJ(&mobj, (QV) lpData);
|
|
#else
|
|
lpData += CbUnpackMOBJ(&mobj, (QV) lpData,QDE_ISDFFTOPIC(qde));
|
|
#endif
|
|
|
|
iTopic = 0x00FF & mobj.bType;
|
|
|
|
bSYS = FALSE;
|
|
bSYSFirst = FALSE;
|
|
switch (iTopic)
|
|
{
|
|
case bTypeSbys:
|
|
case bTypeSbysCounted:
|
|
if (pmtop)
|
|
return lpData;
|
|
bSYS = TRUE;
|
|
bSYSFirst = TRUE;
|
|
|
|
qmsbs = (QMSBS) lpData;
|
|
lpData += 2;
|
|
|
|
if (!qmsbs->fAbsolute)
|
|
{
|
|
lpData += 2;
|
|
}
|
|
lpData += qmsbs->bcCol * sizeof(MCOL);
|
|
return(lpData);
|
|
|
|
default:
|
|
if (pmtop)
|
|
ZeroMemory(pmtop, sizeof(MTOP));
|
|
return(NULL);
|
|
break;
|
|
|
|
case bTypeParaGroup:
|
|
case bTypeParaGroupCounted:
|
|
{
|
|
MOPG mopg;
|
|
MPFG mpfg;
|
|
LPSTR lpStart = lpData;
|
|
int iTab;
|
|
|
|
if (pmtop)
|
|
return lpData;
|
|
|
|
lpData = QVSkipQGE(lpData, (QL) &(mopg.libText));
|
|
#ifdef _X86_
|
|
mpfg = *((QMPFG) lpData);
|
|
#else
|
|
MoveMemory(&mpfg, lpData, sizeof(MPFG));
|
|
#endif
|
|
lpData = (LPSTR) (((QMPFG) lpData) + 1);
|
|
|
|
|
|
if (mpfg.rgf.fMoreFlags)
|
|
{
|
|
lpData = QVSkipQGE(lpData, (QL) &(mopg.lMoreFlags));
|
|
}
|
|
|
|
if (mpfg.rgf.fSpaceOver)
|
|
{
|
|
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.ySpaceOver));
|
|
}
|
|
|
|
if (mpfg.rgf.fSpaceUnder)
|
|
{
|
|
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.ySpaceUnder));
|
|
}
|
|
|
|
if (mpfg.rgf.fLineSpacing)
|
|
{
|
|
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.yLineSpacing));
|
|
}
|
|
|
|
if (mpfg.rgf.fLeftIndent)
|
|
{
|
|
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &mopg.xLeftIndent);
|
|
}
|
|
|
|
if (mpfg.rgf.fRightIndent)
|
|
{
|
|
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xRightIndent);
|
|
}
|
|
|
|
if (mpfg.rgf.fFirstIndent)
|
|
{
|
|
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xFirstIndent);
|
|
}
|
|
|
|
mopg.xTabSpacing = 72;
|
|
if (mpfg.rgf.fTabSpacing)
|
|
{
|
|
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xTabSpacing);
|
|
}
|
|
|
|
if (mpfg.rgf.fBoxed)
|
|
{
|
|
mopg.mbox = *((UNALIGNED MBOX *)lpData);
|
|
#ifdef _X86_
|
|
lpData = (LPSTR) (((QMBOX)lpData) + 1);
|
|
#else
|
|
lpData = (QB)lpData + 3;
|
|
#endif
|
|
}
|
|
|
|
if (mpfg.rgf.fTabs)
|
|
{
|
|
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &mopg.cTabs);
|
|
}
|
|
else
|
|
mopg.cTabs = 0;
|
|
|
|
for (iTab = 0; iTab < mopg.cTabs; iTab++)
|
|
{
|
|
lpData = QVSkipQGA(lpData, (QI) &mopg.rgtab[iTab].x);
|
|
if (mopg.rgtab[iTab].x & 0x4000)
|
|
lpData = QVSkipQGA(lpData, (QI) &mopg.rgtab[iTab].wType);
|
|
else
|
|
mopg.rgtab[iTab].wType = TABTYPELEFT;
|
|
mopg.rgtab[iTab].x = mopg.rgtab[iTab].x & 0xBFFF;
|
|
}
|
|
}
|
|
|
|
return(lpData);
|
|
break;
|
|
|
|
case bTypeTopic:
|
|
if (pmtop) { // all we wanted was MTOP structure
|
|
MoveMemory(pmtop, lpData, sizeof(MTOP));
|
|
return NULL;
|
|
}
|
|
else
|
|
#ifdef _X86_
|
|
pmtop = (MTOP*) lpData;
|
|
#else
|
|
{
|
|
MoveMemory(&mtop, lpData, sizeof(MTOP));
|
|
pmtop = & mtop;
|
|
}
|
|
#endif
|
|
|
|
lpData += sizeof(MTOP);
|
|
|
|
fTitleSeen = TRUE;
|
|
|
|
return(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
static BOOL STDCALL ForageTopic(QDE qde, VA vaNext)
|
|
{
|
|
static DB db;
|
|
int wErr;
|
|
HFC hfc = NULL;
|
|
LPSTR lpCmd;
|
|
LPSTR lpText;
|
|
DWORD dwCmd;
|
|
int cbAnimate = 0;
|
|
QFCINFO qfcinfo;
|
|
|
|
iCharSet = defcharset;
|
|
|
|
fTitleSeen = FALSE;
|
|
|
|
while (!fTitleSeen && (hfc = GetQFCINFO(qde, vaNext, &wErr)) != NULL)
|
|
{
|
|
qfcinfo = (QFCINFO) PtrFromGh(hfc);
|
|
|
|
/*
|
|
* In order for WinHelp to be able to jump to this topic,
|
|
* vaCurrent must be set to vaNext. Don't ask me why -- but it works.
|
|
* Same VA is used in History and Bookmark jumps. [ralphw]
|
|
*/
|
|
|
|
vaNext = qfcinfo->vaNext;
|
|
|
|
#ifdef _X86_
|
|
lpCmd = ScanTopic(((LPSTR) qfcinfo) + sizeof(FCINFO), qfcinfo, NULL);
|
|
#else
|
|
lpCmd = ScanTopic(((LPSTR) qfcinfo) + sizeof(FCINFO), qfcinfo, NULL, qde);
|
|
#endif
|
|
|
|
if (lpCmd)
|
|
{
|
|
lpText = ((LPSTR) qfcinfo) + qfcinfo->ichText;
|
|
dwCmd = lpText - lpCmd;
|
|
|
|
if (!NextFTSString(qde, lpText, &lpCmd, &iCharSet, qfcinfo->vaCurr,
|
|
lpText + qfcinfo->lcbText
|
|
)
|
|
)
|
|
{
|
|
FreeGh(hfc); hfc= NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
FreeGh(hfc); hfc= NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL STDCALL ScanThisTopic(QDE qde)
|
|
{
|
|
HDE hde = NULL;
|
|
VA vaHilite;
|
|
BOOL fRet;
|
|
|
|
hde = HdeCreate(NULL, qde, deTopic);
|
|
|
|
if (!hde) return FALSE;
|
|
|
|
vaHilite= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
|
|
: qde->top.mtop.vaSR;
|
|
fRet = ForageTopic(QdeFromGh(hde), vaHilite);
|
|
|
|
ASSERT(hde);
|
|
|
|
DestroyHde(hde);
|
|
|
|
return fRet;
|
|
}
|
|
|