|
|
1.1 root 1: /****************************************************************************
2:
3: PROGRAM: lqh.c
4:
5: MODULE: lqhhelp.c
6:
7: FUNCTIONS:
8: HelpSearch() - Retrieves a topic
9: PreLoad() - thread for preloading topics
10:
11:
12: ****************************************************************************/
13:
14: #include "lqh.h"
15:
16: BOOL fStructList = FALSE, fStructRequest = FALSE;
17:
18: /****************************************************************************
19:
20: FUNCTION:
21: HelpSearch(NPSZ, BOOL, NC)
22:
23: PURPOSE: Retrieves a topic from the database
24:
25: COMMENTS:
26: The first parameter of HelpSearch() points to a null-terminated
27: string that contains the name of the topic to retrieve. The second
28: paramater contains a flag. When this flag is TRUE, and the topic is
29: not found, a warning box is displayed indicating that the topic was
30: not found. In other words, TRUE means display a warning, and FALSE
31: means do not. The third parameter is an optional context number. If
32: ncContext is a nonzero value, then it is used instead of the
33: pszTopic parameter.
34:
35: The return value is TRUE if the topic was found.
36:
37: ****************************************************************************/
38:
39: BOOL HelpSearch(npszTopic, bWarn, ncContext)
40: NPSZ npszTopic;
41: BOOL bWarn;
42: NC ncContext;
43: {
44: CHAR chBuf[256];
45: NPSZ npszTmpPtr;
46: NPCH npchBuf;
47: PCH pchPtr, pchCellString, pchTmpPtr;
48: USHORT cbLen, usLines, i;
49: SHORT cbLine;
50: SEL selDeCompress; /* selector for current decompressed data */
51: NC ncRequest;
52: TOPICHDR FAR *tphdr;
53:
54: /* Call HelpNc to retrieve the context number of the topic requested
55: * in chBuf.
56: */
57:
58: if (!(ncRequest = ncContext))
59: if (!(ncRequest = HelpNc(npszTopic, ncHelp))) {
60: if (bWarn) {
61: Dstrcpy(chBuf, npszTopic);
62: Dstrcat(chBuf, " not found.");
63: BoxMessage(chBuf, atWARNING, THIN, hmou, TRUE);
64: }
65: fStructList = fBack = FALSE;
66: return FALSE;
67: }
68:
69: pchCellString = MAKEP(selStringTable, 0);
70: if (!fBack)
71: HelpNcRecord(selTable[usCurrent].ncContext); /* Save for back-tracing */
72: else
73: fBack = fStructList = FALSE;
74: if (fStructList)
75: fStructRequest = TRUE;
76: for (i = 0; i < MAXPRELOAD; i++)
77: if (selTable[i].ncContext == ncRequest)
78: break;
79:
80: /* If a selector is found that has been preloaded, then DosLockSeg is
81: * called to prevent the segment from being discarded. If DosLockSeg
82: * returns an error, then the memory was discarded. The entry in the
83: * selector table is then cleared and new memory is allocated.
84: */
85:
86: if (i < MAXPRELOAD)
87: if (DosLockSeg(selTable[i].sel)) { /* If it can't be locked, */
88: selTable[i].ncContext = (NC) 0; /* clears entry in table */
89: selTable[i].usHighLight = 0; /* no highlighting */
90: DosFreeSeg(selTable[i].sel); /* Frees the memory */
91: }
92:
93: if (i >= MAXPRELOAD || !selTable[i].ncContext) {
94:
95: /* Call HelpLook to place the compressed data into the StringTable
96: * buffer. This buffer will ultimately be used to store the
97: * character-attribute strings. HelpLook returns the amount of memory
98: * needed for the decompressed data.
99: */
100:
101: cbLen = HelpLook(ncRequest, MAKEP(selStringTable, 0));
102: if (DosAllocSeg(cbLen, &selDeCompress, SEG_DISCARDABLE)) {
103: BoxMessage(" Insufficient memory ", atWARNING,
104: THIN, hmou, TRUE);
105: return FALSE;
106: }
107:
108: /* Convert the selector to a pointer */
109:
110: pchPtr = MAKEP(selDeCompress, 0);
111:
112: /* Decompress the data */
113:
114: HelpDecomp(pchCellString, pchPtr, ncRequest);
115:
116: if (selTable[usCurrent].sel) /* unlock current selector */
117: DosUnlockSeg(selTable[usCurrent].sel);
118:
119: /* Find space in the table of selectors to store the current
120: * selector. Because the thread may be decompressing a file at the
121: * same time, the thread must be stopped until the usCurrent variable
122: * is set. The thread checks to make certain that it is not using the
123: * same usCurrent before writing data to the selTable strucutre.
124: */
125:
126: DosEnterCritSec();
127: usCurrent++;
128: if (usCurrent >= MAXPRELOAD)
129: usCurrent = 0;
130: DosExitCritSec();
131:
132: /* If the current selector is preloaded, free that selector
133: * before assigning a new one to it.
134: */
135:
136: if (selTable[usCurrent].sel)
137: DosFreeSeg(selTable[usCurrent].sel);
138: selTable[usCurrent].sel = selDeCompress;
139: selTable[usCurrent].usTopLine = 1;
140: selTable[usCurrent].usHighLight = 0;
141: selTable[usCurrent].ncContext = ncRequest;
142: }
143: else
144: usCurrent = i;
145: pchPtr = MAKEP(selTable[usCurrent].sel, 0);
146: tphdr = MAKEP(selTable[usCurrent].sel, 0);
147:
148: /* Databases are each allowed one special character that begins a line,
149: * and indicates it is a special line. QuickHelp specifies that lines
150: * beginning with a period are special lines and should be accepted.
151: */
152:
153: if (tphdr->appChar == '.') /* if control char is a period */
154: tphdr->lineChar = 0xFF; /* accept all lines */
155: else
156: tphdr->lineChar = tphdr->appChar; /* else accept none */
157:
158: usStructLine = usRefCount = 0;
159: fListDisplay = FALSE;
160:
161: /* It is necessary to keep two sets of line numbers. The variable
162: * usLines keeps track of the line number in the data file. This is used
163: * when requesting lines for pasting. The variable usTotalLines keeps
164: * track of the line numbers in the character-attribute string table.
165: */
166:
167: for (usLines = usTotalLines = 1;
168: (cbLine = HelpGetCells(usLines, 76,
169: pchCellString, pchPtr, bAttr)) != -1;
170: usLines++) {
171: if (*pchCellString == '.' && cbLine) {
172:
173: /* Lines that begin with a dot are special flags for use with
174: * QuickHelp. The following flags are accepted in lqh:
175: *
176: * .category name position
177: * Contains the category name that the current function is in,
178: * and its position in the list of functions.
179: *
180: * .ref topics
181: * Contains a list of space- or comma-separated topics
182: * (functions, structures, etc.) that will appear in
183: * the Reference menu, and that the PreLoad
184: * thread will preload.
185: *
186: * .structure
187: * Marks the beginning of a structure section.
188: *
189: * .list
190: * Means that the current topic contains a list of topics.
191: * This will cause a highlighted line to be displayed.
192: * The user may select a topic by moving the highlighted
193: * line over the desired topic and pressing the ENTER key.
194: * The first word of the line is used as the topic string
195: * to search for.
196: */
197:
198: HelpGetLine(usLines, sizeof(chBuf), chBuf, pchPtr);
199: npchBuf = chBuf + 1;
200:
201: /* .ref */
202:
203: if (chBuf[1] == 'r' && chBuf[2] == 'e' &&
204: chBuf[3] == 'f') {
205: npchBuf += 4;
206: while (*npchBuf == ' ')
207: npchBuf++;
208: npszTmpPtr = chReference;
209: MoreRef:
210: do {
211: npszRefTable[usRefCount++] = npszTmpPtr;
212: while (isalpha(*npchBuf))
213: *npszTmpPtr++ = *npchBuf++;
214: *npszTmpPtr++ = 0;
215: while (!isalpha(*npchBuf) && *npchBuf)
216: npchBuf++;
217: }
218: while (*npchBuf && usRefCount < MAXREF);
219: *chBuf = 0;
220: HelpGetLine(usLines + 1, sizeof(chBuf), chBuf, pchPtr);
221: if (strncmp(chBuf, ".ref", 4) == 0) {
222: usLines++;
223: npchBuf = chBuf + 5;
224: while (*npchBuf == ' ')
225: npchBuf++;
226: goto MoreRef; /* second reference line */
227: }
228: }
229:
230: /* .list */
231:
232: else if (chBuf[1] == 'l' && chBuf[2] == 'i' &&
233: chBuf[3] == 's' && chBuf[4] == 't') {
234: fListDisplay = TRUE;
235: if (chBuf[6] == 's')
236: fStructList = TRUE;
237: }
238:
239: /* .structure */
240:
241: else if (chBuf[1] == 's' && chBuf[2] == 't' &&
242: chBuf[3] == 'r' && chBuf[4] == 'u' &&
243: chBuf[5] == 'c')
244: usStructLine = usLines - 3;
245: }
246: else {
247: strTable[usTotalLines].addr = pchCellString;
248: strTable[usTotalLines++].cb = cbLine;
249: pchCellString += cbLine;
250: }
251: }
252:
253: /* Clear the semaphore to tell the thread to start preloading
254: * reference functions from the topic.
255: */
256:
257: usTotalLines--;
258: if (fListDisplay && !selTable[usCurrent].usHighLight)
259: selTable[usCurrent].usHighLight = 1;
260: if (usStructLine && fStructRequest) {
261: selTable[usCurrent].usTopLine = usStructLine;
262: fStructList = fStructRequest = FALSE;
263: }
264: DosSemClear((HSEM) &hsemNewRef);
265: return TRUE;
266: }
267:
268: /****************************************************************************
269:
270: THREAD: PreLoadThread
271:
272: COMMENTS:
273: In order to maximize response time, this thread preloads any
274: reference functions specified by the current function. First, it
275: waits until the hsemNewRef semaphore is cleared, which indicates
276: that a new function has been loaded. It then goes through the
277: reference table and preloads all the functions. If the hsemNewRef
278: semaphore is set before the thread completes its loop, it breaks
279: out of the loop, goes to its begining and waits for the semaphore
280: to clear.
281:
282: The thread is allowed to run only when the main process is waiting
283: for input. The Input function controls this by resuming thread
284: execution when it is called, and suspending thread execution before
285: it returns.
286:
287: This thread maintains its own pointer into the table of preloaded
288: selectors, and cycles through all selectors in a continuous loop.
289:
290: ****************************************************************************/
291:
292: USHORT usPreLoad = 10; /* Maintains preload position */
293:
294: VOID FAR PreLoadThread() {
295: USHORT cbLen;
296: INT i;
297: register INT j;
298: NC ncRequest;
299: SEL selDeCompress, selCompress;
300:
301: Loop:
302: for (;;) {
303:
304: /* Do not begin processing until the semaphore is cleared, indicating
305: * that a new topic has been loaded.
306: */
307:
308: while (DosSemWait((HSEM) &hsemNewRef, -1L));
309: DosSemSet((HSEM) &hsemNewRef);
310: if (!usRefCount)
311: continue;
312:
313: for (i = 0; i <= usRefCount; i++) { /* Preloads all references */
314: if (i == usRefCount)
315: ncRequest = HelpNcNext(selTable[usCurrent].ncContext);
316: else
317: ncRequest = HelpNc(npszRefTable[i], ncHelp);
318: if (ncRequest) {
319: for (j = 0; j < MAXPRELOAD; j++)
320: if (selTable[j].ncContext == ncRequest)
321: break; /* already preloaded */
322: if (j >= MAXPRELOAD) {
323: if (DosAllocSeg(HelpNcCb(ncRequest), &selCompress, 0))
324: break; /* Halts if allocation fails */
325:
326: cbLen = HelpLook(ncRequest, MAKEP(selCompress, 0));
327: if (DosAllocSeg(cbLen, (PSEL) &selDeCompress,
328: SEG_DISCARDABLE)) {
329: DosFreeSeg(selCompress);
330: break; /* Halts if allocation fails */
331: }
332: if (HelpDecomp(MAKEP(selCompress, 0),
333: MAKEP(selDeCompress, 0), ncRequest)) {
334: DosFreeSeg(selCompress);
335: DosFreeSeg(selDeCompress);
336: continue;
337: }
338: DosFreeSeg(selCompress);
339: while (usPreLoad == usCurrent)
340: if (++usPreLoad >= MAXPRELOAD)
341: usPreLoad = 0;
342:
343: /* It is crucial that the thread not change the
344: * selTable structure at the same time that HelpSearch is
345: * accessing it. The HelpSearch thread is suspended long
346: * enough to confirm that the table is safe, and
347: * is resumed only after writing to the table has
348: * been completed. The HelpSearch function has a
349: * similar critical section to prevent writing to the
350: * selTable structure at the same time as the thread.
351: */
352:
353: DosEnterCritSec(); /* Suspends other threads */
354: if (usPreLoad == usCurrent) {
355: DosExitCritSec();
356: goto Loop;
357: }
358:
359: if (selTable[usPreLoad].sel)
360: DosFreeSeg(selTable[usPreLoad].sel);
361: selTable[usPreLoad].sel = selDeCompress;
362: selTable[usPreLoad].usTopLine = 1;
363: selTable[usPreLoad].usHighLight = 0;
364: selTable[usPreLoad].ncContext = ncRequest;
365: DosUnlockSeg(selTable[usPreLoad].sel);
366: DosExitCritSec();
367: if (++usPreLoad >= MAXPRELOAD)
368: usPreLoad = 0;
369: }
370:
371: /* If the semaphore is cleared, a new topic was loaded,
372: * so the loop must start over again.
373: */
374:
375: if (!DosSemWait((HSEM) &hsemNewRef, 0L))
376: goto Loop;
377: }
378: }
379: }
380: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.