|
|
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.