|
|
Microsoft OS/2 SDK 03-01-1988
/****************************************************************************
PROGRAM: lqh.c
MODULE: lqhhelp.c
FUNCTIONS:
HelpSearch() - Retrieves a topic
PreLoad() - thread for preloading topics
****************************************************************************/
#include "lqh.h"
BOOL fStructList = FALSE, fStructRequest = FALSE;
/****************************************************************************
FUNCTION:
HelpSearch(NPSZ, BOOL, NC)
PURPOSE: Retrieves a topic from the database
COMMENTS:
The first parameter of HelpSearch() points to a null-terminated
string that contains the name of the topic to retrieve. The second
paramater contains a flag. When this flag is TRUE, and the topic is
not found, a warning box is displayed indicating that the topic was
not found. In other words, TRUE means display a warning, and FALSE
means do not. The third parameter is an optional context number. If
ncContext is a nonzero value, then it is used instead of the
pszTopic parameter.
The return value is TRUE if the topic was found.
****************************************************************************/
BOOL HelpSearch(npszTopic, bWarn, ncContext)
NPSZ npszTopic;
BOOL bWarn;
NC ncContext;
{
CHAR chBuf[256];
NPSZ npszTmpPtr;
NPCH npchBuf;
PCH pchPtr, pchCellString, pchTmpPtr;
USHORT cbLen, usLines, i;
SHORT cbLine;
SEL selDeCompress; /* selector for current decompressed data */
NC ncRequest;
TOPICHDR FAR *tphdr;
/* Call HelpNc to retrieve the context number of the topic requested
* in chBuf.
*/
if (!(ncRequest = ncContext))
if (!(ncRequest = HelpNc(npszTopic, ncHelp))) {
if (bWarn) {
Dstrcpy(chBuf, npszTopic);
Dstrcat(chBuf, " not found.");
BoxMessage(chBuf, atWARNING, THIN, hmou, TRUE);
}
fStructList = fBack = FALSE;
return FALSE;
}
pchCellString = MAKEP(selStringTable, 0);
if (!fBack)
HelpNcRecord(selTable[usCurrent].ncContext); /* Save for back-tracing */
else
fBack = fStructList = FALSE;
if (fStructList)
fStructRequest = TRUE;
for (i = 0; i < MAXPRELOAD; i++)
if (selTable[i].ncContext == ncRequest)
break;
/* If a selector is found that has been preloaded, then DosLockSeg is
* called to prevent the segment from being discarded. If DosLockSeg
* returns an error, then the memory was discarded. The entry in the
* selector table is then cleared and new memory is allocated.
*/
if (i < MAXPRELOAD)
if (DosLockSeg(selTable[i].sel)) { /* If it can't be locked, */
selTable[i].ncContext = (NC) 0; /* clears entry in table */
selTable[i].usHighLight = 0; /* no highlighting */
DosFreeSeg(selTable[i].sel); /* Frees the memory */
}
if (i >= MAXPRELOAD || !selTable[i].ncContext) {
/* Call HelpLook to place the compressed data into the StringTable
* buffer. This buffer will ultimately be used to store the
* character-attribute strings. HelpLook returns the amount of memory
* needed for the decompressed data.
*/
cbLen = HelpLook(ncRequest, MAKEP(selStringTable, 0));
if (DosAllocSeg(cbLen, &selDeCompress, SEG_DISCARDABLE)) {
BoxMessage(" Insufficient memory ", atWARNING,
THIN, hmou, TRUE);
return FALSE;
}
/* Convert the selector to a pointer */
pchPtr = MAKEP(selDeCompress, 0);
/* Decompress the data */
HelpDecomp(pchCellString, pchPtr, ncRequest);
if (selTable[usCurrent].sel) /* unlock current selector */
DosUnlockSeg(selTable[usCurrent].sel);
/* Find space in the table of selectors to store the current
* selector. Because the thread may be decompressing a file at the
* same time, the thread must be stopped until the usCurrent variable
* is set. The thread checks to make certain that it is not using the
* same usCurrent before writing data to the selTable strucutre.
*/
DosEnterCritSec();
usCurrent++;
if (usCurrent >= MAXPRELOAD)
usCurrent = 0;
DosExitCritSec();
/* If the current selector is preloaded, free that selector
* before assigning a new one to it.
*/
if (selTable[usCurrent].sel)
DosFreeSeg(selTable[usCurrent].sel);
selTable[usCurrent].sel = selDeCompress;
selTable[usCurrent].usTopLine = 1;
selTable[usCurrent].usHighLight = 0;
selTable[usCurrent].ncContext = ncRequest;
}
else
usCurrent = i;
pchPtr = MAKEP(selTable[usCurrent].sel, 0);
tphdr = MAKEP(selTable[usCurrent].sel, 0);
/* Databases are each allowed one special character that begins a line,
* and indicates it is a special line. QuickHelp specifies that lines
* beginning with a period are special lines and should be accepted.
*/
if (tphdr->appChar == '.') /* if control char is a period */
tphdr->lineChar = 0xFF; /* accept all lines */
else
tphdr->lineChar = tphdr->appChar; /* else accept none */
usStructLine = usRefCount = 0;
fListDisplay = FALSE;
/* It is necessary to keep two sets of line numbers. The variable
* usLines keeps track of the line number in the data file. This is used
* when requesting lines for pasting. The variable usTotalLines keeps
* track of the line numbers in the character-attribute string table.
*/
for (usLines = usTotalLines = 1;
(cbLine = HelpGetCells(usLines, 76,
pchCellString, pchPtr, bAttr)) != -1;
usLines++) {
if (*pchCellString == '.' && cbLine) {
/* Lines that begin with a dot are special flags for use with
* QuickHelp. The following flags are accepted in lqh:
*
* .category name position
* Contains the category name that the current function is in,
* and its position in the list of functions.
*
* .ref topics
* Contains a list of space- or comma-separated topics
* (functions, structures, etc.) that will appear in
* the Reference menu, and that the PreLoad
* thread will preload.
*
* .structure
* Marks the beginning of a structure section.
*
* .list
* Means that the current topic contains a list of topics.
* This will cause a highlighted line to be displayed.
* The user may select a topic by moving the highlighted
* line over the desired topic and pressing the ENTER key.
* The first word of the line is used as the topic string
* to search for.
*/
HelpGetLine(usLines, sizeof(chBuf), chBuf, pchPtr);
npchBuf = chBuf + 1;
/* .ref */
if (chBuf[1] == 'r' && chBuf[2] == 'e' &&
chBuf[3] == 'f') {
npchBuf += 4;
while (*npchBuf == ' ')
npchBuf++;
npszTmpPtr = chReference;
MoreRef:
do {
npszRefTable[usRefCount++] = npszTmpPtr;
while (isalpha(*npchBuf))
*npszTmpPtr++ = *npchBuf++;
*npszTmpPtr++ = 0;
while (!isalpha(*npchBuf) && *npchBuf)
npchBuf++;
}
while (*npchBuf && usRefCount < MAXREF);
*chBuf = 0;
HelpGetLine(usLines + 1, sizeof(chBuf), chBuf, pchPtr);
if (strncmp(chBuf, ".ref", 4) == 0) {
usLines++;
npchBuf = chBuf + 5;
while (*npchBuf == ' ')
npchBuf++;
goto MoreRef; /* second reference line */
}
}
/* .list */
else if (chBuf[1] == 'l' && chBuf[2] == 'i' &&
chBuf[3] == 's' && chBuf[4] == 't') {
fListDisplay = TRUE;
if (chBuf[6] == 's')
fStructList = TRUE;
}
/* .structure */
else if (chBuf[1] == 's' && chBuf[2] == 't' &&
chBuf[3] == 'r' && chBuf[4] == 'u' &&
chBuf[5] == 'c')
usStructLine = usLines - 3;
}
else {
strTable[usTotalLines].addr = pchCellString;
strTable[usTotalLines++].cb = cbLine;
pchCellString += cbLine;
}
}
/* Clear the semaphore to tell the thread to start preloading
* reference functions from the topic.
*/
usTotalLines--;
if (fListDisplay && !selTable[usCurrent].usHighLight)
selTable[usCurrent].usHighLight = 1;
if (usStructLine && fStructRequest) {
selTable[usCurrent].usTopLine = usStructLine;
fStructList = fStructRequest = FALSE;
}
DosSemClear((HSEM) &hsemNewRef);
return TRUE;
}
/****************************************************************************
THREAD: PreLoadThread
COMMENTS:
In order to maximize response time, this thread preloads any
reference functions specified by the current function. First, it
waits until the hsemNewRef semaphore is cleared, which indicates
that a new function has been loaded. It then goes through the
reference table and preloads all the functions. If the hsemNewRef
semaphore is set before the thread completes its loop, it breaks
out of the loop, goes to its begining and waits for the semaphore
to clear.
The thread is allowed to run only when the main process is waiting
for input. The Input function controls this by resuming thread
execution when it is called, and suspending thread execution before
it returns.
This thread maintains its own pointer into the table of preloaded
selectors, and cycles through all selectors in a continuous loop.
****************************************************************************/
USHORT usPreLoad = 10; /* Maintains preload position */
VOID FAR PreLoadThread() {
USHORT cbLen;
INT i;
register INT j;
NC ncRequest;
SEL selDeCompress, selCompress;
Loop:
for (;;) {
/* Do not begin processing until the semaphore is cleared, indicating
* that a new topic has been loaded.
*/
while (DosSemWait((HSEM) &hsemNewRef, -1L));
DosSemSet((HSEM) &hsemNewRef);
if (!usRefCount)
continue;
for (i = 0; i <= usRefCount; i++) { /* Preloads all references */
if (i == usRefCount)
ncRequest = HelpNcNext(selTable[usCurrent].ncContext);
else
ncRequest = HelpNc(npszRefTable[i], ncHelp);
if (ncRequest) {
for (j = 0; j < MAXPRELOAD; j++)
if (selTable[j].ncContext == ncRequest)
break; /* already preloaded */
if (j >= MAXPRELOAD) {
if (DosAllocSeg(HelpNcCb(ncRequest), &selCompress, 0))
break; /* Halts if allocation fails */
cbLen = HelpLook(ncRequest, MAKEP(selCompress, 0));
if (DosAllocSeg(cbLen, (PSEL) &selDeCompress,
SEG_DISCARDABLE)) {
DosFreeSeg(selCompress);
break; /* Halts if allocation fails */
}
if (HelpDecomp(MAKEP(selCompress, 0),
MAKEP(selDeCompress, 0), ncRequest)) {
DosFreeSeg(selCompress);
DosFreeSeg(selDeCompress);
continue;
}
DosFreeSeg(selCompress);
while (usPreLoad == usCurrent)
if (++usPreLoad >= MAXPRELOAD)
usPreLoad = 0;
/* It is crucial that the thread not change the
* selTable structure at the same time that HelpSearch is
* accessing it. The HelpSearch thread is suspended long
* enough to confirm that the table is safe, and
* is resumed only after writing to the table has
* been completed. The HelpSearch function has a
* similar critical section to prevent writing to the
* selTable structure at the same time as the thread.
*/
DosEnterCritSec(); /* Suspends other threads */
if (usPreLoad == usCurrent) {
DosExitCritSec();
goto Loop;
}
if (selTable[usPreLoad].sel)
DosFreeSeg(selTable[usPreLoad].sel);
selTable[usPreLoad].sel = selDeCompress;
selTable[usPreLoad].usTopLine = 1;
selTable[usPreLoad].usHighLight = 0;
selTable[usPreLoad].ncContext = ncRequest;
DosUnlockSeg(selTable[usPreLoad].sel);
DosExitCritSec();
if (++usPreLoad >= MAXPRELOAD)
usPreLoad = 0;
}
/* If the semaphore is cleared, a new topic was loaded,
* so the loop must start over again.
*/
if (!DosSemWait((HSEM) &hsemNewRef, 0L))
goto Loop;
}
}
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.