Annotation of os2sdk/demos/apps/lqh/lqhhelp.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.