Leaked source code of windows server 2003
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.

1745 lines
59 KiB

  1. /*** help.c - help library main
  2. *
  3. * Copyright <C> 1988-1990, Microsoft Corporation
  4. *
  5. * Definitions:
  6. *
  7. * Context Map: Mapping of context number to topic number.
  8. * Allows multiple contexts to be associated with a
  9. * single topic. Syncronized with the context
  10. * string table, each entry contains the topic
  11. * number associated with the corresponding context
  12. * string.
  13. *
  14. * Context String: String on which help can be "looked up".
  15. *
  16. * Context String Table: Table of all valid context strings in a
  17. * particular help file.
  18. *
  19. * Local Context: A type of context which bypasses the context
  20. * string and context numbers. In cross references,
  21. * encoded as a cross reference string of NULL,
  22. * followed by a topic number ored with 0x8000.
  23. *
  24. * nc: (Context Number) A long which uniquely
  25. * identifies a help file and context string, or
  26. * for local contexts, the helpfile and topic
  27. * number. Formatted as:
  28. *
  29. * +----------------+----------------+
  30. * | Fdb Mem Handle | context number |
  31. * +----------------+----------------+
  32. *
  33. * Where the upper word is the memory handle of the
  34. * allocated fdb for the help file. The lower word
  35. * is the either the "true" context number (see
  36. * below) if <= 0x7fff, or the actual topic number
  37. * or'ed with 0x8000.
  38. *
  39. * Topic: Actual help textual entry. May be compressed.
  40. *
  41. * Topic Index: Table of file positions of all topics contained
  42. * in a help file. Indexed by the topic number,
  43. * returns that topics physical position in the
  44. * file.
  45. *
  46. * Topic Number: Index to a particular topic. Topic numbers are
  47. * zero based, and reflect the physical ordering of
  48. * the topics in the file.
  49. *
  50. * "True" context number: is the zero based index or string number in the
  51. * <context string table>. I.E. the "n'th" string
  52. * has context number "n".
  53. *
  54. * The progression from string to true context number to topic number to file
  55. * position is:
  56. *
  57. * 1) Context String ==> "True" Context Number
  58. *
  59. * The string is searched for in the <context string table>, and
  60. * it's number becomes the "true" context number.
  61. *
  62. * 2) "True" Context Number ==> Topic Number
  63. *
  64. * The context number is an index into the <context map>, returing
  65. * the topic number associated with the context number.
  66. *
  67. * 3) Topic Number ==> File Position
  68. *
  69. * The topic number is used as an index into the Topic Index, from
  70. * which the physical file position is retrieved.
  71. *
  72. * Notes:
  73. * QuickPascal requires NO initialized data. In this case, CLEAR is defined,
  74. * and the HelpInit routine is included. We also play some pointer games to
  75. * simple variables, because the C compiler can generate CONST segment
  76. * entries for the SEG of various vars. (This enables it to load the segment
  77. * register directly, rather than by using SEG varname and another
  78. * register). Q/P cannot support this action by the compiler.
  79. *
  80. * QuickHelp for OS/2 is reentrant. This code should remain reentrant up to
  81. * but not including allocating and deallocating fdbs.
  82. *
  83. * Revision History:
  84. *
  85. * 17-Aug-1990 ln Don't blindly request 64k of an ascii file. Query
  86. * for size first, then read. Allocations based on
  87. * previous topic size requests may cause the OS to
  88. * GPFault for an out of range read.
  89. * 16-Jul-1990 ln Searching for "filename!" where filename is a QH
  90. * file, will now fail, rather than GP fault. Searching
  91. * for "!" will now succeed.
  92. * 08-Jun-1990 ln Remove HelpLock usage in HelpNcCmp
  93. * 13-Apr-1990 ln Try to get HelpSzContext to return strings in more
  94. * cases where it can.
  95. * 12-Mar-1990 ln Rename CloseFile -> HelpCloseFile
  96. * 08-Oct-1989 ln Changes to improve the previous change to work (allow
  97. * decompression) more often in low memory bases.
  98. * Deallocate table in OpenCore to reduce fragmentation
  99. * in non-moveable memory systems.
  100. * 19-May-1989 ln Correct bug in decompressing, where we would not
  101. * decompress if the tables didn;t exist.
  102. * 12-Apr-1989 ln Ensure that we handle Locks failing correctly. Also
  103. * remove TossPortion usage. Unlock handles directly.
  104. * 10-Mar-1989 ln Change MapTopicToContext to look forward. Changed
  105. * HelpNc to look begining at passed context string.
  106. * 17-Jan-1989 ln Correct creation of basename in HelpOpen to account
  107. * for environment syntax.
  108. * 09-Dec-1988 ln Add HelpNcUniq
  109. * 25-Oct-1988 ln Added minascii support to HelpNcPrev. Correct
  110. * minascii bug in HelpSzContext.
  111. * 14-Sep-1988 ln Improve doc. Remove ambiguity in MapContextToTopic
  112. * return value. Improve error checking in various
  113. * places.
  114. * 01-Sep-1988 ln Check ReadHelpFile return value in LoadPortion
  115. * 12-Aug-1988 ln Add check for memory discarded in alloc durring
  116. * HelpDecomp.
  117. * 08-Aug-1988 ln Ensure HelpClose closes ALL files. (Off by one error
  118. * in loop).
  119. * 14-Apr-1988 ln Modified to conform to QC (CW?) restriction that
  120. * prohibits any segments from being locked when an
  121. * allocation is performed.
  122. * [] 15-Dec-1987 ln Created, for design.
  123. *
  124. *************************************************************************/
  125. #include <assert.h> /* debugging assertions */
  126. #include <io.h> /* I/O function declarations */
  127. #include <stdlib.h> /* standard library */
  128. #include <stdio.h> /* standard I/O definitions */
  129. #if defined (OS2)
  130. #define INCL_BASE
  131. #include <os2.h>
  132. #else
  133. #include <windows.h>
  134. #endif
  135. #include "help.h" /* global (help & user) decl */
  136. #include "helpfile.h" /* help file format definition */
  137. #include "helpsys.h" /* internal (help sys only) decl*/
  138. #define MASIZE 512 /* size of ma input buffer */
  139. #define MAOVER 64 /* size of ma search overlap */
  140. #define ISERROR(x) (((x).mh == 0L) && ((x).cn <= HELPERR_MAX))
  141. #define SETERROR(x,y) { (x).mh = 0L; (x).cn = y; }
  142. /*************************************************************************
  143. **
  144. ** Forward definitions
  145. */
  146. void pascal near CloseShrink(nc, f);
  147. f pascal near LoadFdb (mh, fdb far *);
  148. mh pascal near LoadPortion (int, mh);
  149. ushort pascal near MapContexttoTopic (nc, fdb far *);
  150. nc pascal near MapTopictoContext(ushort, fdb far *, int);
  151. nc pascal near NextPrev(nc,int);
  152. nc pascal near OpenCore(FILE *, ulong, uchar far *, struct helpheader *, fdb far *);
  153. f pascal near PutFdb (mh, fdb far *);
  154. f pascal near SizePos (nc, ushort *,ulong *);
  155. ushort pascal near decomp (uchar far *, uchar far *, uchar far *, uchar far *);
  156. char far * pascal near hfmemzer(void far *, ushort);
  157. char far * pascal near hfstrchr(char far *, char);
  158. char far * pascal near hfstrcpy(char far *, char far *);
  159. ushort pascal near hfstrlen(char far *);
  160. f pascal far HelpCmp (uchar far *, uchar far *, ushort, f, f);
  161. f pascal near HelpCmpSz (uchar far *, uchar far *);
  162. void pascal near kwPtrBuild(uchar far *, ushort);
  163. #if ASCII
  164. long pascal near maLocate (fdb far *, uchar far *, ulong,
  165. f (pascal far *)(uchar far *, uchar far *, ushort, f, f));
  166. nc pascal near combineNc (ulong, mh);
  167. ulong pascal near NctoFo (ulong);
  168. #endif
  169. /*************************************************************************
  170. **
  171. ** External Global data
  172. ** BEWARE. The effects of global data on reentrancy should be VERY carefully
  173. ** considered.
  174. **
  175. *************************************************************************/
  176. extern mh tbmhFdb[MAXFILES+1];
  177. extern char szNil[1];
  178. extern ushort cBack;
  179. #ifdef CLEAR
  180. /*************************************************************************
  181. **
  182. ** HelpInit - One-time initialization
  183. **
  184. ** Purpose:
  185. ** Performs one-time initialization. Right now that's a zero fill of static
  186. ** memory for those environments which don't support pre-inited static
  187. ** memory.
  188. **
  189. ** Entry:
  190. ** none
  191. **
  192. ** Exit:
  193. ** none
  194. **
  195. */
  196. void far pascal LOADDS HelpInit () {
  197. hfmemzer (tbmhFdb, sizeof(tbmhFdb)); /* zero entire fdb handle table */
  198. hfmemzer (szNil, sizeof(szNil)); /* zero null string */
  199. hfmemzer (&cBack, sizeof(cBack)); /* zero back trace count */
  200. /* end HelpInit */}
  201. #endif
  202. /*************************************************************************
  203. **
  204. ** HelpOpen - Open help file & return help handle.
  205. **
  206. ** Purpose:
  207. ** Given the file basename, locate the associated help file on the path, and
  208. ** open it, initializing internal data structures as appropriate.
  209. **
  210. ** Entry:
  211. ** fpszName - base filename to be openned.
  212. **
  213. ** Exit:
  214. ** nc initial context for openned file.
  215. **
  216. ** Exceptions:
  217. ** Returns error code on failure to open for any reason.
  218. **
  219. */
  220. nc far pascal LOADDS HelpOpen (
  221. char far *fpszName
  222. ) {
  223. FILE *fhT; /* temp file handle */
  224. fdb fdbLocal; /* local copy of fdb to use */
  225. uchar far *fpszBase; /* base filename */
  226. void far *fpT;
  227. struct helpheader hdrLocal; /* for use by opencore */
  228. nc ncRet = {0,0}; /* first context */
  229. mh *ptbmhFdb; /* pointer into mh table */
  230. /*
  231. ** create basename by removing possible env variable, drive, and scanning
  232. ** for last path seperator
  233. */
  234. fpszBase = fpszName;
  235. if (fpT = hfstrchr(fpszBase,':'))
  236. fpszBase = (uchar far *)fpT+1;
  237. while (fpT = hfstrchr(fpszBase,'\\'))
  238. fpszBase = (uchar far *)fpT+1;
  239. /*
  240. ** Scan FDB's for an open file of the same base name. If we encounter the name,
  241. ** in either the true filename, or file header, just return that file's initial
  242. ** context. Otherwise fall below to try and open it.
  243. */
  244. for (ptbmhFdb=&tbmhFdb[1]; ptbmhFdb<=&tbmhFdb[MAXFILES]; ptbmhFdb++) {
  245. if (LoadFdb (*ptbmhFdb,&fdbLocal)) {
  246. if (HelpCmpSz(fpszBase,fdbLocal.fname) ||
  247. HelpCmpSz(fpszBase,fdbLocal.hdr.fname))
  248. ncRet = fdbLocal.ncInit;
  249. if (ncRet.mh && ncRet.cn)
  250. return ncRet;
  251. }
  252. }
  253. /*
  254. ** Open file. If we can, then call the core open routine to open the file (and
  255. ** any anything appended to it).
  256. **
  257. ** Warning: the app may callback HelpClose at this point.
  258. */
  259. if (fhT = OpenFileOnPath(fpszName,FALSE)) {
  260. ncRet = OpenCore (fhT,0L,fpszBase,&hdrLocal,&fdbLocal);
  261. if (ISERROR(ncRet))
  262. HelpCloseFile (fhT);
  263. return ncRet;
  264. }
  265. SETERROR(ncRet, HELPERR_FNF);
  266. return ncRet;
  267. // rjsa return HELPERR_FNF;
  268. /* end HelpOpen*/}
  269. /*************************************************************************
  270. **
  271. ** OpenCore - Recursive core of HelpOpen
  272. **
  273. ** Purpose:
  274. ** Given the open file handle, initialize internal data structures as
  275. ** appropriate. Attempt to open any file that is appended.
  276. **
  277. ** Entry:
  278. ** fhT - Open file handle
  279. ** offset - Offset from start of file of help file to open
  280. ** fpszBase - pointer to base filename
  281. **
  282. ** Exit:
  283. ** initial context, or NULL on failure.
  284. **
  285. ** Exceptions:
  286. ** Returns NULL on failure to open for any reason.
  287. **
  288. */
  289. nc pascal near OpenCore (
  290. FILE * fhHelp,
  291. ulong offset,
  292. uchar far *fpszBase, /* base filename */
  293. struct helpheader *phdrLocal,
  294. fdb far *pfdbLocal /* pointer to current FDB */
  295. ) {
  296. //void far *fpT;
  297. int ihFree; /* handle for free fdb (& index)*/
  298. mh mhCur; /* current memory handle */
  299. nc ncFirst = {0,0}; /* first context */
  300. nc ncInit; /* first context */
  301. mh *pmhT; /* pointer into mh table */
  302. /*
  303. ** Read in helpfile header
  304. */
  305. if (ReadHelpFile(fhHelp,
  306. offset,
  307. (char far *)phdrLocal,
  308. (ushort)sizeof(struct helpheader))) {
  309. /*
  310. ** search for available fdb
  311. */
  312. for (ihFree = MAXFILES, pmhT = &tbmhFdb[MAXFILES];
  313. ihFree && *pmhT;
  314. ihFree--, pmhT--);
  315. /*
  316. ** if an offset is present, and this is NOT a compressed file, or there is no
  317. ** available fdb, ignore the operation.
  318. */
  319. if ( offset
  320. && (phdrLocal->wMagic != wMagicHELP)
  321. && (phdrLocal->wMagic != wMagicHELPOld)
  322. ) {
  323. SETERROR(ncInit, HELPERR_BADAPPEND);
  324. return ncInit;
  325. // rjsa return HELPERR_BADAPPEND;
  326. }
  327. if (ihFree == 0) {
  328. SETERROR(ncInit, HELPERR_LIMIT);
  329. return ncInit;
  330. // rjsa return HELPERR_LIMIT;
  331. }
  332. /*
  333. ** allocate fdb. Again, if we can't, skip it all and return NULL.
  334. */
  335. if (mhCur = *pmhT = HelpAlloc((ushort)sizeof(fdb))) {
  336. /*
  337. ** Fill in helpfile header & appropriate fdb fields
  338. */
  339. hfmemzer(pfdbLocal,sizeof(fdb)); /* zero entire fdb */
  340. pfdbLocal->fhHelp = fhHelp; /* file handle */
  341. ncFirst.mh = pfdbLocal->ncInit.mh = mhCur;
  342. ncFirst.cn = pfdbLocal->ncInit.cn = 0L;
  343. // rjsa ncFirst = pfdbLocal->ncInit = ((long)mhCur) << 16; /* initial context */
  344. pfdbLocal->foff = offset; /* appended offset */
  345. hfstrcpy(pfdbLocal->fname,fpszBase); /* include base filename*/
  346. /*
  347. ** if this is a compressed file (signified by the first two bytes of the header
  348. ** we read in above), then note the file type in the fdb. We unlock the fdb, as
  349. ** MapTopicToContext and the recursion might cause memory allocation. We get a
  350. ** context number for the first topic, and recurse and attempt to open any
  351. ** appended file.
  352. */
  353. if ( (phdrLocal->wMagic == wMagicHELPOld)
  354. || (phdrLocal->wMagic == wMagicHELP)
  355. ) {
  356. if ((phdrLocal->wMagic == wMagicHELP)
  357. && (phdrLocal->wVersion > wHelpVers)) {
  358. SETERROR(ncInit, HELPERR_BADVERS);
  359. return ncInit;
  360. // rjsa return HELPERR_BADVERS;
  361. }
  362. pfdbLocal->hdr = *phdrLocal;
  363. pfdbLocal->ftype = FTCOMPRESSED | FTFORMATTED;
  364. if (PutFdb (mhCur, pfdbLocal)) {
  365. ncFirst = MapTopictoContext(0,pfdbLocal,0);
  366. // We free the context map (the only thing loaded by the
  367. // MapTopictoContext) in order to reduce fragmentation in
  368. // non-moveable memory based systems.
  369. //
  370. HelpDealloc (pfdbLocal->rgmhSections[HS_CONTEXTMAP]);
  371. pfdbLocal->rgmhSections[HS_CONTEXTMAP] = 0;
  372. ncInit = OpenCore(fhHelp,pfdbLocal->hdr.tbPos[HS_NEXT]+offset,szNil,phdrLocal,pfdbLocal);
  373. if (LoadFdb (mhCur, pfdbLocal)) {
  374. //if (ncInit.cn > HELPERR_MAX) {
  375. if ( !(ISERROR(ncInit)) ) {
  376. pfdbLocal->ncLink = ncInit;
  377. } else {
  378. pfdbLocal->ncLink.mh = (mh)0;
  379. pfdbLocal->ncLink.cn = 0L;
  380. }
  381. // rjsa pfdbLocal->ncLink = ncInit > HELPERR_MAX ? ncInit : 0;
  382. pfdbLocal->ncInit = ncFirst;
  383. }
  384. }
  385. }
  386. #if ASCII
  387. /*
  388. ** In the case of a minascii formatted file (signified by the first two bytes
  389. ** of the header being ">>") we just set up the filetype and "applications
  390. ** specific character". The default "ncFirst" is the context for the first
  391. ** topic.
  392. */
  393. else if (phdrLocal->wMagic == 0x3e3e) { /* minascii formatted? */
  394. pfdbLocal->ftype = FTFORMATTED;
  395. pfdbLocal->hdr.appChar = '>'; /* ignore lines with this*/
  396. }
  397. #endif
  398. else if ((phdrLocal->wMagic & 0x8080) == 0) { /* ascii unformatted? */
  399. pfdbLocal->ftype = 0;
  400. pfdbLocal->hdr.appChar = 0xff; /* ignore lines with this*/
  401. }
  402. else {
  403. SETERROR(ncInit, HELPERR_NOTHELP);
  404. return ncInit;
  405. // rjsa return HELPERR_NOTHELP;
  406. }
  407. if (!PutFdb (mhCur, pfdbLocal)) {
  408. ncFirst.mh = (mh)0;
  409. ncFirst.cn = 0L;
  410. }
  411. }
  412. else {
  413. SETERROR(ncFirst, HELPERR_MEMORY);
  414. // rjsa ncFirst = HELPERR_MEMORY; /* error reading file */
  415. }
  416. }
  417. else {
  418. SETERROR(ncFirst, HELPERR_READ);
  419. // rjsa ncFirst = HELPERR_READ; /* error reading file */
  420. }
  421. return ncFirst; /* return valid context */
  422. /* end OpenCore */}
  423. /*************************************************************************
  424. **
  425. ** HelpClose - Close Help file
  426. **
  427. ** Purpose:
  428. ** Close a help file, deallocate all memory associated with it, and free the
  429. ** handle.
  430. **
  431. ** Entry:
  432. ** ncClose - Context for file to be closed. If zero, close all.
  433. **
  434. ** Exit:
  435. ** None
  436. **
  437. ** Exceptions:
  438. ** All errors are ignored.
  439. **
  440. */
  441. void far pascal LOADDS HelpClose (
  442. nc ncClose
  443. ) {
  444. CloseShrink(ncClose,TRUE); /* close file(s) */
  445. /* end HelpClose */}
  446. /*************************************************************************
  447. **
  448. ** HelpShrink - Release all dynamic memory
  449. **
  450. ** Purpose:
  451. ** A call to this routines causes the help system to release all dynamic
  452. ** memory it may have in use.
  453. **
  454. ** Entry:
  455. ** None.
  456. **
  457. ** Exit:
  458. ** None.
  459. **
  460. ** Exceptions:
  461. ** None.
  462. **
  463. */
  464. void far pascal LOADDS HelpShrink(void) {
  465. nc ncTmp = {0,0};
  466. CloseShrink(ncTmp,0);
  467. // rjsa CloseShrink(0,0);
  468. /* end HelpShrink */}
  469. /*************************************************************************
  470. **
  471. ** CloseShrink - Deallocate memory and possibly Close Help file
  472. **
  473. ** Purpose:
  474. ** Deallocate all memory associated with a help file, and possibly close free
  475. ** it.
  476. **
  477. ** Entry:
  478. ** ncClose - Context for file. If zero, do all.
  479. ** fClose - TRUE if a close operation.
  480. **
  481. ** Exit:
  482. ** None
  483. **
  484. ** Exceptions:
  485. ** All errors are ignored.
  486. **
  487. */
  488. void pascal near CloseShrink (
  489. nc ncClose,
  490. f fClose
  491. ) {
  492. fdb fdbLocal; /* pointer to current FDB */
  493. int i;
  494. mh mhClose; /* fdb mem hdl to file to close */
  495. mh *pmhFdb; /* pointer to FDB's table entry */
  496. mhClose = ncClose.mh; /* get index */
  497. // rjsa mhClose = (mh)HIGH(ncClose); /* get index */
  498. for (pmhFdb = &tbmhFdb[0]; /* for each possible entry */
  499. pmhFdb <= &tbmhFdb[MAXFILES];
  500. pmhFdb++
  501. ) {
  502. if ((mhClose == 0) /* if all selected */
  503. || (mhClose == *pmhFdb)) { /* or this one selected */
  504. if (LoadFdb (*pmhFdb, &fdbLocal)) { /* if open file */
  505. /*
  506. * Recurse to close/shrink any appended files
  507. */
  508. if ((fdbLocal.ncLink.mh || fdbLocal.ncLink.cn) && mhClose)
  509. CloseShrink (fdbLocal.ncLink, fClose);
  510. for (i=HS_count-2; i>=0; i--) /* for dyn mem handles */
  511. HelpDealloc(fdbLocal.rgmhSections[i]); /* dealloc */
  512. hfmemzer(fdbLocal.rgmhSections,sizeof(fdbLocal.rgmhSections));
  513. if (fClose) {
  514. HelpCloseFile(fdbLocal.fhHelp); /* close file */
  515. HelpDealloc(*pmhFdb); /* deallocate fdb */
  516. *pmhFdb = 0;
  517. }
  518. else
  519. PutFdb (*pmhFdb, &fdbLocal); /* update FDB */
  520. }
  521. }
  522. }
  523. /* end CloseShrink */}
  524. /*** HelpNcCmp - Look up context string, provide comparison routine
  525. *
  526. * Given an ascii string, determine the context number of that string. Uses
  527. * user-supplied comparison routine.
  528. *
  529. * Entry:
  530. * lpszContext - Pointer to asciiz context string.
  531. * ncInital - Starting Context, used to locate file.
  532. * lpfnCmp - far pointer to comparison routine to use.
  533. *
  534. * Exit:
  535. * Context number, if found.
  536. *
  537. * Exceptions:
  538. * Returns NULL if context string not found.
  539. *
  540. *************************************************************************/
  541. nc far pascal LOADDS HelpNcCmp (
  542. char far *fpszContext,
  543. nc ncInitial,
  544. f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
  545. ) {
  546. f fFound = FALSE; // TRUE -> found
  547. f fOpened = FALSE; // TRUE -> file was openned here
  548. fdb fdbLocal; // pointer to current FDB
  549. char far *fpszT; // temp far pointer
  550. long i;
  551. long iStart; // nc to start looking at
  552. mh mhCur; // memory handle locked
  553. nc ncRet = {0,0}; // The return value
  554. char far *fpszContexts; // pointer to context strings
  555. // if the context string includes a "filename!", then open that as a help
  556. // file, and point to the context string which may follow.
  557. //
  558. if ((fpszT = hfstrchr(fpszContext,'!')) && (fpszT != fpszContext)) {
  559. *fpszT = 0;
  560. ncInitial = HelpOpen(fpszContext);
  561. *fpszT++ = '!';
  562. fpszContext = fpszT;
  563. fOpened = TRUE;
  564. }
  565. // if helpfile was not openned, just return the error
  566. //
  567. if (ISERROR(ncInitial)) {
  568. ncInitial.mh = (mh)0;
  569. ncInitial.cn = 0L;
  570. return ncInitial;
  571. }
  572. // For compressed files we scan the context strings in the file
  573. // (this turns out not to be that speed critical in
  574. // comparision with decompression, so I haven't bothered), to get the
  575. // context number.
  576. //
  577. // If not found, and there IS a linked (appended) file, we recurse to search
  578. // that file as well.
  579. //
  580. // The context number for compressed files is just the zero based string
  581. // number, plus the number of predefined contexts, with the fdb memory
  582. // handle in the upper word.
  583. //
  584. if (LoadFdb (ncInitial.mh, &fdbLocal)) {
  585. if (fdbLocal.ftype & FTCOMPRESSED) {
  586. // If not a local context look up, get the context strings, and
  587. // search
  588. //
  589. if (*fpszContext) {
  590. mhCur = LoadPortion (HS_CONTEXTSTRINGS, ncInitial.mh);
  591. if ( (mhCur == (mh)0)
  592. || (mhCur == (mh)(-1))
  593. || (!(fpszContexts = HelpLock(mhCur)))
  594. ) {
  595. ncRet.mh = (mh)0;
  596. ncRet.cn = 0L;
  597. return ncRet;
  598. }
  599. i=0;
  600. // iStart allows us to begin searching from the context string
  601. // passed, as opposed to from the begining each time. This
  602. // allows the application to "carry on" a search from othe last
  603. // place we found a match. This is usefull for multiple
  604. // duplicate context resolution, as well as inexact matching.
  605. //
  606. iStart = ncInitial.cn;
  607. if (iStart & 0x8000)
  608. iStart = 0;
  609. else
  610. iStart--; /* table index is 0 based */
  611. do {
  612. if (i >= iStart) {
  613. fFound = lpfnCmp ( fpszContext
  614. , fpszContexts
  615. , 0xffff
  616. , (f)(fdbLocal.hdr.wFlags & wfCase)
  617. , (f)FALSE);
  618. }
  619. while (*fpszContexts++); /* point to next string */
  620. i++;
  621. }
  622. while ((i < (int)fdbLocal.hdr.cContexts) && !fFound);
  623. HelpUnlock (mhCur);
  624. if (fFound) { /* if a match found */
  625. ncRet.mh = ncInitial.mh;
  626. ncRet.cn = i + fdbLocal.hdr.cPreDef;
  627. // rjsa ncRet = (i+fdbLocal.hdr.cPreDef) /* string # */
  628. // | HIGHONLY(ncInitial); /* & fdb handle */
  629. }
  630. else {
  631. ncInitial.mh = (mh)0;
  632. ncInitial.cn = 0L;
  633. ncRet = HelpNcCmp (fpszContext,fdbLocal.ncLink, lpfnCmp);
  634. }
  635. }
  636. else if (!fOpened) {
  637. ncRet.mh = ncInitial.mh;
  638. ncRet.cn = *(UNALIGNED ushort far *)(fpszContext + 1);
  639. // rjsa ncRet = *(ushort far *)(fpszContext + 1) /* word following*/
  640. // | HIGHONLY(ncInitial); /* & fdb handle */
  641. }
  642. }
  643. #if ASCII
  644. /*
  645. ** For minimally formatted ascii files, we sequentially scan the file itself
  646. ** for context string definitions until we find the string we care about.
  647. **
  648. ** The context number for minascii files is the the byte position/4 of the
  649. ** beginning of the associated topic, with the fdb memory handle in the upper
  650. ** word.
  651. */
  652. else if (fdbLocal.ftype & FTFORMATTED) {
  653. if (*fpszContext) {
  654. ncRet.cn = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
  655. if (ncRet.cn == -1L) {
  656. ncRet.mh = (mh)0;
  657. ncRet.cn = 0L;
  658. } else {
  659. ncRet = combineNc(ncRet.cn, fdbLocal.ncInit.mh);
  660. }
  661. // rjsa ncRet = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
  662. // ncRet = (ncRet == -1L)
  663. // ? 0
  664. // : combineNc(ncRet,HIGH(fdbLocal.ncInit));
  665. }
  666. }
  667. /*
  668. ** for unformatted ascii files, there must have been NO context string to be
  669. ** searched for. In that case, the context number is always 1, plus the fdb
  670. ** mem handle.
  671. */
  672. else if (*fpszContext == 0) { /* if null context string */
  673. ncRet.mh = ncInitial.mh;
  674. ncRet.cn = 1L;
  675. // rjsa ncRet = HIGHONLY(ncInitial) + 1;
  676. }
  677. #endif
  678. }
  679. return ncRet;
  680. /* end HelpNcCmp */}
  681. /*** HelpNc - Look up context string
  682. *
  683. * Given an ascii string, determine the context number of that string.
  684. *
  685. * Entry:
  686. * lpszContext - Pointer to asciiz context string.
  687. * ncInital - Starting Context, used to locate file.
  688. *
  689. * Exit:
  690. * Context number, if found.
  691. *
  692. * Exceptions:
  693. * Returns NULL if context string not found.
  694. *
  695. *************************************************************************/
  696. nc far pascal LOADDS HelpNc (
  697. char far *fpszContext,
  698. nc ncInitial
  699. ) {
  700. return HelpNcCmp (fpszContext, ncInitial, HelpCmp);
  701. /* end HelpNc */}
  702. /*************************************************************************
  703. **
  704. ** HelpNcCb - Return count of bytes in compressed topic
  705. **
  706. ** Purpose:
  707. ** Returns the size in bytes of the compressed topic. Provided for
  708. ** applications to determine how big a buffer to allocate.
  709. **
  710. ** Entry:
  711. ** ncCur - Context number to return info on.
  712. **
  713. ** Exit:
  714. ** Count of bytes in the compressed topic
  715. **
  716. ** Exceptions:
  717. ** Returns 0 on error.
  718. **
  719. */
  720. ushort far pascal LOADDS HelpNcCb (
  721. nc ncCur
  722. ) {
  723. ulong position;
  724. ushort size;
  725. return SizePos(ncCur,&size,&position) ? size+(ushort)4 : (ushort)0;
  726. /* end HelpNcCb */}
  727. /******************************************************************************
  728. **
  729. ** HelpLook - Return compressed topic text
  730. **
  731. ** Purpose:
  732. ** Places the compressed topic text referenced by a passed context number into
  733. ** a user supplied buffer.
  734. **
  735. ** Entry:
  736. ** ncCur - Context number for which to return text
  737. ** pbDest - Pointer to buffer in which to place the result.
  738. **
  739. ** Exit:
  740. ** Count of bytes in >uncompressed< topic. This is encoded based on file type.
  741. **
  742. ** Exceptions:
  743. ** Returns NULL on any error
  744. **
  745. */
  746. ushort far pascal LOADDS HelpLook (
  747. nc ncCur,
  748. PB pbDest
  749. ) {
  750. fdb fdbLocal; /* pointer to current FDB */
  751. char far *fpszDest;
  752. int i;
  753. ulong position = 0;
  754. ushort size = 0;
  755. if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb down */
  756. /*
  757. ** for both kinds of formatted files, we determine the position of the topic,
  758. ** and read it in.
  759. */
  760. if (fdbLocal.ftype) {
  761. if (SizePos (ncCur,&size,&position)) {
  762. if (fpszDest = (char far *)PBLOCK(pbDest)) {
  763. #ifdef BIGDEBUG
  764. {
  765. char DbgBuf[128];
  766. sprintf(DbgBuf, "HELP: Reading Topic for Context %d at %lX, size %d\n", ncCur.cn, position + fdbLocal.foff, size );
  767. OutputDebugString(DbgBuf);
  768. }
  769. #endif
  770. size = (ushort)ReadHelpFile(fdbLocal.fhHelp
  771. ,position + fdbLocal.foff
  772. ,fpszDest
  773. ,size);
  774. #ifdef BIGDEBUG
  775. {
  776. char DbgBuf[128];
  777. sprintf(DbgBuf, " Read %d bytes to address %lX\n", size, fpszDest );
  778. OutputDebugString(DbgBuf);
  779. }
  780. #endif
  781. /*
  782. ** for compressed files, if the read was sucessfull, we then return the
  783. ** uncompressed size which is the first word of the topic.
  784. */
  785. #if ASCII
  786. if (fdbLocal.ftype & FTCOMPRESSED) {
  787. #endif
  788. if (size)
  789. size = *(ushort far *)fpszDest+(ushort)1;
  790. #if ASCII
  791. }
  792. else {
  793. /*
  794. ** for minascii files, We also set up for the terminating NULL by scanning for
  795. ** the ">>" which begins the next topic, adjusting the size as well.
  796. */
  797. size -= 4;
  798. for (i=4; i; i--)
  799. if (fpszDest[++size] == '>') break;
  800. fpszDest[size++] = 0;
  801. }
  802. #endif
  803. }
  804. }
  805. }
  806. #if ASCII
  807. else { /* unformatted ascii */
  808. /*
  809. ** for unformatted ascii, we just read in (first 64k of) the file.
  810. */
  811. if (fpszDest = PBLOCK (pbDest)) {
  812. if (SizePos (ncCur,&size,&position)) {
  813. size = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,fpszDest,size);
  814. fpszDest[size++] = 0; /* terminate ascii text */
  815. }
  816. }
  817. }
  818. #endif
  819. PBUNLOCK (pbDest);
  820. }
  821. if (size) size += sizeof(topichdr); /* adjust for prepended topichdr*/
  822. return size;
  823. /* end HelpLook */}
  824. /******************************************************************************
  825. **
  826. ** HelpDecomp - Decompress Topic Text
  827. **
  828. ** Purpose:
  829. ** Fully decompress topic text. Decompresses based on current file, from one
  830. ** buffer to another.
  831. **
  832. ** Entry:
  833. ** pbTopic - Pointer to compressed topic text
  834. ** pbDest - Pointer to destination buffer
  835. **
  836. ** Exit:
  837. ** FALSE on successful completion
  838. **
  839. ** Exceptions:
  840. ** Returns TRUE on any error.
  841. **
  842. */
  843. f far pascal LOADDS HelpDecomp (
  844. PB pbTopic,
  845. PB pbDest,
  846. nc ncContext
  847. ) {
  848. fdb fdbLocal; // pointer to current FDB
  849. uchar far *fpszDest; // pointer to destination
  850. uchar far *fpTopic; // pointer to locked topic
  851. f fRv = TRUE; // return Value
  852. mh mhFdb; // handle to the fdb
  853. mh mhHuff;
  854. mh mhKey;
  855. mhFdb = ncContext.mh;
  856. if (LoadFdb (mhFdb, &fdbLocal)) { /* lock fdb down */
  857. if (fdbLocal.ftype & FTCOMPRESSED) {
  858. // This funky sequence of code attempts to ensure that both the
  859. // huffman and keyword decompression tables are loaded simultaneously
  860. // since we cannot decompress without both.
  861. //
  862. // We do things three times to cover the following cases:
  863. //
  864. // 1) huffman loaded ok
  865. // keyword loaded ok
  866. // huffman already loaded
  867. //
  868. // 2) huffman loaded ok
  869. // keyword loaded ok after HelpShrink (huffman discarded)
  870. // huffman re-loaded ok (HelpShrink freed enough for both)
  871. //
  872. // 3) huffman loaded ok after HelpShrink
  873. // keyword loaded ok after HelpShrink (huffman discarded)
  874. // huffman re-loaded ok (memory fragmentation allowed it)
  875. //
  876. // The other cases, where either the load fails immediatly after
  877. // any HelpShrink call, are the cases we cannot handle.
  878. //
  879. // Since handles can change due to the reallocation that can ocurr
  880. // in the HelpShrink-reload sequence, we simply do the three
  881. // loads, and then ensure that all the handles match what's in the
  882. // fdb. If they don't, we fail.
  883. //
  884. mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
  885. mhKey = LoadPortion (HS_KEYPHRASE,mhFdb);
  886. mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
  887. if ( LoadFdb (mhFdb, &fdbLocal)
  888. && (mhKey == fdbLocal.rgmhSections[HS_KEYPHRASE])
  889. && (mhHuff == fdbLocal.rgmhSections[HS_HUFFTREE])) {
  890. char far *fpHuff;
  891. char far *fpKey;
  892. // At this point we lock EVERYTHING and ensure that we have
  893. // valid pointers to it all. (Some swapped memory systems can
  894. // fail at this point, so we need to be sensitive).
  895. //
  896. fpHuff = HelpLock (mhHuff);
  897. fpKey = HelpLock (mhKey);
  898. fpTopic = PBLOCK (pbTopic);
  899. fpszDest = PBLOCK (pbDest);
  900. if ( fpTopic
  901. && fpszDest
  902. && (fpHuff || (mhHuff == 0))
  903. && (fpKey || (mhKey == 0))
  904. ) {
  905. decomp (fpHuff, fpKey, fpTopic, fpszDest+sizeof(topichdr));
  906. fRv = FALSE;
  907. }
  908. }
  909. // Unlock the handles, if they were valid.
  910. //
  911. if (mhKey != (mh)(-1))
  912. HelpUnlock (mhKey);
  913. if (mhHuff != (mh)(-1))
  914. HelpUnlock (mhHuff);
  915. }
  916. else {
  917. fpszDest = PBLOCK (pbDest);
  918. #if ASCII
  919. /*
  920. ** ascii, just copy
  921. */
  922. fpTopic = PBLOCK(pbTopic);
  923. if (fpTopic && fpszDest) {
  924. hfstrcpy(fpszDest+sizeof(topichdr),fpTopic);
  925. #else
  926. {
  927. #endif
  928. fRv = FALSE;
  929. }
  930. }
  931. if (!fRv) {
  932. ((topichdr far *)fpszDest)->ftype = fdbLocal.ftype;
  933. ((topichdr far *)fpszDest)->appChar = (uchar)fdbLocal.hdr.appChar;
  934. ((topichdr far *)fpszDest)->linChar = (uchar)fdbLocal.hdr.appChar;
  935. ((topichdr far *)fpszDest)->lnCur = 1;
  936. ((topichdr far *)fpszDest)->lnOff = sizeof(topichdr);
  937. }
  938. PBUNLOCK (pbTopic);
  939. PBUNLOCK (pbDest);
  940. }
  941. return fRv;
  942. /* end HelpDecomp */}
  943. /******************************************************************************
  944. **
  945. ** HelpNcNext - Return next context number
  946. **
  947. ** Purpose:
  948. ** Returns the context number corresponding to a physical "next" in the help
  949. ** file.
  950. **
  951. ** Entry:
  952. ** None
  953. **
  954. ** Exit:
  955. ** Returns context number
  956. **
  957. ** Exceptions:
  958. ** Returns NULL on any error
  959. **
  960. */
  961. nc far pascal LOADDS HelpNcNext (
  962. nc ncCur
  963. ) {
  964. return NextPrev(ncCur,1); /* get next */
  965. /* end HelpNcNext */}
  966. /******************************************************************************
  967. **
  968. ** HelpNcPrev - Return phyiscally previous context
  969. **
  970. ** Purpose:
  971. ** Returns the context number corresponding to the physically previous topic.
  972. **
  973. ** Entry:
  974. ** None
  975. **
  976. ** Exit:
  977. ** Returns context number
  978. **
  979. ** Exceptions:
  980. ** Returns NULL on any error
  981. **
  982. */
  983. nc far pascal LOADDS HelpNcPrev (
  984. nc ncCur
  985. ) {
  986. return NextPrev(ncCur,-1); /* get previous */
  987. /* end HelpNcPrev */}
  988. /******************************************************************************
  989. **
  990. ** HelpNcUniq - Return nc guaranteed unique for a given topic
  991. **
  992. ** Purpose:
  993. ** Maps a context number to a local context number. This is provided such
  994. ** that all context numbers which map to the same topic can be transformed
  995. ** into the same nc which maps to that topic. The information on the
  996. ** context string originally used is lost.
  997. **
  998. ** Entry:
  999. ** None
  1000. **
  1001. ** Exit:
  1002. ** Returns context number
  1003. **
  1004. ** Exceptions:
  1005. ** Returns NULL on any error
  1006. **
  1007. */
  1008. nc far pascal LOADDS HelpNcUniq (
  1009. nc ncCur
  1010. ) {
  1011. fdb fdbLocal; /* pointer to current FDB */
  1012. if (LoadFdb (ncCur.mh, &fdbLocal))
  1013. if (fdbLocal.ftype & FTCOMPRESSED) {
  1014. nc ncTmp;
  1015. ncTmp.mh = fdbLocal.ncInit.mh;
  1016. ncTmp.cn = MapContexttoTopic(ncCur, &fdbLocal);
  1017. ncTmp.cn |= 0x8000;
  1018. ncCur = ncTmp;
  1019. // rjsa return MapContexttoTopic (ncCur,&fdbLocal)
  1020. // | (fdbLocal.ncInit & 0xffff0000)
  1021. // | 0x8000;
  1022. }
  1023. return ncCur;
  1024. /* end HelpNcUniq */}
  1025. /******************************************************************************
  1026. **
  1027. ** NextPrev - Return phyiscally next or previous context
  1028. **
  1029. ** Purpose:
  1030. ** Returns the context number corresponding to the physically next or previous
  1031. ** topic.
  1032. **
  1033. ** Entry:
  1034. ** ncCur = Current Context
  1035. ** fNext = 1 for next, -1 for previous.
  1036. **
  1037. ** Exit:
  1038. ** Returns context number
  1039. **
  1040. ** Exceptions:
  1041. ** Returns NULL on any error
  1042. **
  1043. */
  1044. nc pascal near NextPrev (
  1045. nc ncCur,
  1046. int fNext
  1047. ) {
  1048. fdb fdbLocal; /* pointer to current FDB */
  1049. REGISTER nc ncNext = {0,0};
  1050. if (LoadFdb (ncCur.mh, &fdbLocal)) {
  1051. //
  1052. // For a compressed file the next/previous physical is computed by taking the
  1053. // context number, mapping it to its corresponding topic number, incrementing
  1054. // or decrementing the topic number (remember, topic numbers are in physical
  1055. // order), and then mapping that back to a context number.
  1056. //
  1057. // When nexting, we also support nexting into any appended file.
  1058. //
  1059. if (fdbLocal.ftype & FTCOMPRESSED) {
  1060. unsigned short cn;
  1061. cn = (ushort)(((ncCur.cn & 0x8000)
  1062. ? ncCur.cn & 0x7ffff
  1063. : MapContexttoTopic(ncCur, &fdbLocal))
  1064. + (ushort)fNext);
  1065. ncNext = MapTopictoContext(cn, (fdb far *)&fdbLocal, fNext);
  1066. // rjsa ncNext = MapTopictoContext((ushort)(((ncCur & 0x8000)
  1067. // ? ncCur & 0x7fff
  1068. // : MapContexttoTopic (ncCur,&fdbLocal))
  1069. // + fNext)
  1070. // ,(fdb far *)&fdbLocal);
  1071. //
  1072. // if we could not come up with a next, try to find a next using "local"
  1073. // context numbers. Map the context number to a topic number, and if that is
  1074. // not out of range, return it as a context.
  1075. //
  1076. if (!(ncNext.cn)) {
  1077. // rjsa if ((ncNext = MapContexttoTopic (ncCur,&fdbLocal)) == 0xffff)
  1078. // ncNext = 0;
  1079. ncNext.cn = MapContexttoTopic(ncCur, &fdbLocal);
  1080. if (ncNext.cn == 0xffff) {
  1081. ncNext.mh = (mh)0;
  1082. ncNext.cn = 0L;
  1083. } else {
  1084. ncNext.cn += fNext;
  1085. if (ncNext.cn >= fdbLocal.hdr.cTopics) {
  1086. ncNext.mh = (mh)0;
  1087. ncNext.cn = 0L;
  1088. } else {
  1089. // rjsa ncNext |= (fdbLocal.ncInit & 0xffff0000) | 0x8000;
  1090. ncNext.mh = fdbLocal.ncInit.mh;
  1091. ncNext.cn = 0x8000;
  1092. }
  1093. }
  1094. }
  1095. if (!(ncNext.cn & 0x7fff) && (fNext>0)) {
  1096. ncNext = fdbLocal.ncLink;
  1097. }
  1098. }
  1099. #if ASCII
  1100. //
  1101. // minascii files:
  1102. // next'ing: we just sequentially search the file for the first context to
  1103. // come along after that pointed to by our current context number.
  1104. //
  1105. else if (fdbLocal.ftype & FTFORMATTED) {
  1106. if (fNext > 0) {
  1107. ncNext.cn = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)+4, HelpCmp);
  1108. if (ncNext.cn == -1L) {
  1109. ncNext.mh = (mh)0;
  1110. ncNext.cn = 0L;
  1111. } else {
  1112. ncNext = combineNc(ncNext.cn, ncCur.mh);
  1113. }
  1114. // rjsa ncNext = (ncNext == -1L)
  1115. // ? 0
  1116. // : combineNc(ncNext,HIGH(ncCur));
  1117. } else {
  1118. nc ncTemp;
  1119. //
  1120. // prev'ing: start at the begining of the file, looking for the last context
  1121. // which is less than the current one.
  1122. //
  1123. ncNext = ncTemp = fdbLocal.ncInit;
  1124. while (NctoFo(ncTemp.cn) < NctoFo(ncCur.cn)) {
  1125. ncNext = ncTemp;
  1126. ncTemp.cn = maLocate(&fdbLocal,szNil,NctoFo(ncTemp.cn)+4, HelpCmp);
  1127. if (ncTemp.cn == -1L) {
  1128. ncTemp.mh = (mh)0;
  1129. ncTemp.cn = 0L;
  1130. } else {
  1131. ncTemp = combineNc(ncTemp.cn,fdbLocal.ncInit.mh);
  1132. }
  1133. // rjsa ncTemp = (ncTemp == -1L)
  1134. // ? 0
  1135. // : combineNc(ncTemp,HIGH(fdbLocal.ncInit));
  1136. }
  1137. }
  1138. }
  1139. #endif
  1140. }
  1141. return ncNext;
  1142. }
  1143. /*************************************************************************
  1144. **
  1145. ** HelpSzContext - Return string mapping to context number
  1146. **
  1147. ** Purpose:
  1148. ** Construct a string, which when looked-up, will return the passed context
  1149. ** number.
  1150. **
  1151. ** Entry:
  1152. ** pBuf = place to put the string
  1153. ** ncCur = The context number desired
  1154. **
  1155. ** Exit:
  1156. ** True on sucess.
  1157. **
  1158. */
  1159. f pascal far LOADDS HelpSzContext (
  1160. uchar far *pBuf,
  1161. nc ncCur
  1162. ) {
  1163. f fRet = FALSE; /* return value */
  1164. ulong i;
  1165. fdb fdbLocal; /* pointer to current FDB */
  1166. mh mhCur; /* handle we're dealing with */
  1167. char far *fpszContexts; /* pointer to context strings */
  1168. *pBuf = 0;
  1169. if (LoadFdb (ncCur.mh, &fdbLocal)) { /* lock fdb down */
  1170. /*
  1171. ** Everybody starts with a filename
  1172. */
  1173. if (*fdbLocal.hdr.fname)
  1174. pBuf = hfstrcpy(pBuf,fdbLocal.hdr.fname);
  1175. else
  1176. pBuf = hfstrcpy(pBuf,fdbLocal.fname);
  1177. *(ushort far *)pBuf = '!'; /* includes null term */
  1178. pBuf++;
  1179. fRet = TRUE;
  1180. // if we've been given a local context number, see if we can synthesize
  1181. // a context number from which we might get a string. If we can't get
  1182. // one, then return just the filename.
  1183. //
  1184. if ((i = ncCur.cn) & 0x8000) { /* context # */
  1185. ncCur = MapTopictoContext ((ushort)(ncCur.cn & 0x7fff),&fdbLocal,0);
  1186. if ((i = ncCur.cn) & 0x8000) /* context # */
  1187. return fRet;
  1188. }
  1189. /*
  1190. ** For compressed files (signified by being able to load context strings) we
  1191. ** just walk the context strings looking for string number "ncCur". Once found,
  1192. ** the returned string is just the concatenated filename, "!" and context
  1193. ** string.
  1194. */
  1195. mhCur = LoadPortion(HS_CONTEXTSTRINGS, ncCur.mh);
  1196. if (mhCur && (mhCur != (mh)(-1)) && (fpszContexts = HelpLock(mhCur))) {
  1197. if (i && (i <= fdbLocal.hdr.cContexts)) {
  1198. while (--i)
  1199. while (*fpszContexts++);/* point to next string */
  1200. hfstrcpy(pBuf,fpszContexts);/* copy over */
  1201. }
  1202. HelpUnlock (mhCur);
  1203. }
  1204. else if (fdbLocal.ftype & FTCOMPRESSED)
  1205. return FALSE;
  1206. #if ASCII
  1207. /*
  1208. ** for min ascii files, we search for the topic, and copy over the context
  1209. ** string directly from the file.
  1210. */
  1211. else if (fdbLocal.ftype & FTFORMATTED) {
  1212. long fpos;
  1213. if ((fpos = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)-1,HelpCmp)) != -1L) {
  1214. fpos = ReadHelpFile(fdbLocal.fhHelp,fpos+2,pBuf,80);
  1215. *(pBuf+fpos) = 0; /* ensure terminated */
  1216. if (pBuf = hfstrchr(pBuf,'\r'))
  1217. *pBuf = 0; /* terminate at CR */
  1218. }
  1219. }
  1220. #endif
  1221. }
  1222. return fRet;
  1223. /* end HelpSzContext */}
  1224. /******************************************************************************
  1225. **
  1226. ** LoadPortion - Load a section of the help file
  1227. **
  1228. ** Purpose:
  1229. ** If not loaded, allocates memory for and loads a section (as defined in
  1230. ** helpfile.h) of the current help file. Once loaded, or if already loaded,
  1231. ** locks it, and returns the the memory handle and pointer.
  1232. **
  1233. ** This routine must be far, since it is an entry point for HelpMake
  1234. **
  1235. ** Entry:
  1236. ** hsCur = Help section to be loaded.
  1237. ** mhfdb = memory handle for fdb
  1238. **
  1239. ** Exit:
  1240. ** returns handle for memory
  1241. **
  1242. ** Exceptions:
  1243. ** returns NULL on portion not existing, 0xffff on inability to allocate memory.
  1244. **
  1245. */
  1246. mh pascal near LoadPortion (
  1247. int hsCur,
  1248. mh mhfdb
  1249. ) {
  1250. fdb fdbLocal;
  1251. char far *fpDest = 0;
  1252. int i;
  1253. mh mhNew = 0; /* pointer to mh destination */
  1254. ushort osize; /* additional prepended size */
  1255. ushort size;
  1256. if (LoadFdb (mhfdb, &fdbLocal)) {
  1257. if (((mhNew = fdbLocal.rgmhSections[hsCur]) == 0)
  1258. && fdbLocal.hdr.tbPos[hsCur]) {
  1259. for (i=hsCur+1; i<HS_count; i++)
  1260. if (fdbLocal.hdr.tbPos[i]) {
  1261. size = (ushort)(fdbLocal.hdr.tbPos[i]-fdbLocal.hdr.tbPos[hsCur]);
  1262. break;
  1263. }
  1264. osize = (hsCur == HS_KEYPHRASE) ? 1024*sizeof(PVOID) : 0;
  1265. /*
  1266. ** Alloc the memory required. Re-read the FDB, incase intervening calls to
  1267. ** HelpShrink causes deallocs of other beasties.
  1268. */
  1269. if ( (mhNew = HelpAlloc(size + osize))
  1270. && LoadFdb (mhfdb, &fdbLocal)) {
  1271. fdbLocal.rgmhSections[hsCur] = mhNew;
  1272. if (PutFdb (mhfdb, &fdbLocal)) {
  1273. fpDest = (char far *)HelpLock(mhNew);
  1274. if (fpDest && ReadHelpFile(fdbLocal.fhHelp
  1275. ,(ulong)fdbLocal.hdr.tbPos[hsCur] + fdbLocal.foff
  1276. ,fpDest + osize
  1277. ,size)) {
  1278. if (hsCur == HS_KEYPHRASE)
  1279. kwPtrBuild(fpDest,size);/* build keyword pointers */
  1280. HelpUnlock (mhNew);
  1281. }
  1282. else {
  1283. fdbLocal.rgmhSections[hsCur] = 0;
  1284. HelpDealloc (mhNew);
  1285. PutFdb (mhfdb, &fdbLocal);
  1286. mhNew = (mh)(-1);
  1287. }
  1288. }
  1289. else
  1290. mhNew = (mh)0;
  1291. }
  1292. else
  1293. mhNew = (mh)(-1);
  1294. }
  1295. }
  1296. return mhNew;
  1297. /* end LoadPortion */}
  1298. /*************************************************************************
  1299. **
  1300. ** SizePos - Return count of bytes in compressed topic, and position
  1301. **
  1302. ** Purpose:
  1303. ** Returns the size in bytes of the compressed topic, and it's location in the
  1304. ** help file.
  1305. **
  1306. ** Entry:
  1307. ** ncCur - Context number to return info on.
  1308. ** psize - Pointer to place to put the size
  1309. ** ppos - Pointer to place to put the position
  1310. **
  1311. ** Exit:
  1312. ** Returns TRUE on success.
  1313. **
  1314. ** Exceptions:
  1315. ** Returns FALSE on all errors.
  1316. **
  1317. ** Algorithm:
  1318. **
  1319. ** If current help handle valid
  1320. ** If filetype is compressed
  1321. ** If context map not loaded, load it
  1322. ** Lock context map
  1323. ** Map context to topic number
  1324. ** Unlock context map
  1325. ** If topic index not loaded, load it
  1326. ** Lock topic index
  1327. ** size is difference in file positions
  1328. ** Unlock topic index
  1329. ** else if filetype is formatted ascii
  1330. ** seek to context file position
  1331. ** scan for next context definition
  1332. ** size is difference in file positions
  1333. ** else if filetype is unformatted ascii
  1334. ** size is filesize
  1335. */
  1336. f pascal near SizePos (
  1337. nc ncCur,
  1338. ushort *psize,
  1339. ulong *ppos
  1340. ) {
  1341. fdb fdbLocal; /* pointer to current FDB */
  1342. char far *fpT; /* temp pointer */
  1343. REGISTER f fRv = FALSE; /* return value */
  1344. ushort iTopic; /* topic index */
  1345. mh mhCur; /* handle being locked */
  1346. if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb copy */
  1347. if (fdbLocal.ftype & FTCOMPRESSED) {/* if a standard compressed file*/
  1348. if ((iTopic = MapContexttoTopic (ncCur,&fdbLocal)) != 0xffff) {
  1349. mhCur = LoadPortion(HS_INDEX,ncCur.mh);
  1350. if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
  1351. *ppos = ((long far *)fpT)[iTopic];
  1352. *psize = (ushort)(((long far *)fpT)[iTopic+1] - *ppos);
  1353. HelpUnlock (mhCur);
  1354. fRv = TRUE;
  1355. }
  1356. }
  1357. }
  1358. #if ASCII
  1359. else if (fdbLocal.ftype & FTFORMATTED) {/* if a formatted ascii file*/
  1360. if ((*psize = (ushort)(maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)+4, HelpCmp)))
  1361. == 0xffff)
  1362. *psize = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
  1363. else
  1364. *psize -= (ushort)NctoFo(ncCur.cn);
  1365. *ppos = (ulong) maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)-1, HelpCmp);
  1366. fRv = TRUE;
  1367. }
  1368. else { /* unformatted ascii */
  1369. *ppos = ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
  1370. *psize = (*ppos > (ulong)(65535-sizeof(topichdr)-4))
  1371. ? (ushort)(65535-sizeof(topichdr)-4)
  1372. : (ushort)*ppos;
  1373. *ppos = 0L; /* position is always zero. */
  1374. fRv = TRUE;
  1375. }
  1376. #endif
  1377. }
  1378. return fRv;
  1379. /* end SizePos */}
  1380. /************************************************************************
  1381. **
  1382. ** MapContexttoTopic
  1383. **
  1384. ** Purpose:
  1385. ** Given a context number, return the topic number which it maps to. This
  1386. ** is just a direct index of the context number into the context map.
  1387. **
  1388. ** Entry:
  1389. ** ncCur = context number to be mapped
  1390. ** fpfdbCur = pointer to associated fdb
  1391. **
  1392. ** Exit:
  1393. ** Returns zero based topic number, or 0xffff on error.
  1394. */
  1395. ushort pascal near MapContexttoTopic (
  1396. nc ncCur, /* context number to map */
  1397. fdb far *fpfdbCur /* pointer to current FDB */
  1398. ) {
  1399. REGISTER ushort topic = 0xffff; /* value to return */
  1400. ushort far *fpT; /* pointer to context map */
  1401. mh mhCur; /* handle being locked */
  1402. if (ncCur.cn) {
  1403. /*
  1404. ** Local contexts: the topic number is already encoded in the low word, if the
  1405. ** high bit of that word is set.
  1406. */
  1407. if (ncCur.cn & 0x8000)
  1408. topic = (ushort)(ncCur.cn & 0x7fff);
  1409. /*
  1410. ** Normal Contexts: low word of nc is an index into the context map which
  1411. ** returns the topic number
  1412. */
  1413. else {
  1414. mhCur = LoadPortion(HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
  1415. if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
  1416. topic = fpT[ncCur.cn-1];
  1417. HelpUnlock (mhCur);
  1418. }
  1419. }
  1420. }
  1421. return topic;
  1422. /* end MapContexttoTopic */}
  1423. /************************************************************************
  1424. **
  1425. ** MapTopictoContext
  1426. **
  1427. ** Purpose:
  1428. ** Given a topic number, return a context which maps to it.
  1429. **
  1430. ** This involves searching the context map for the first context entry that
  1431. ** maps to the desired topic number.
  1432. **
  1433. ** Entry:
  1434. ** iTopic = topic number to map back to a context number
  1435. ** fpfdbCur = pointer to associated fdb
  1436. **
  1437. ** Exit:
  1438. ** Returns a valid nc into the file.
  1439. **
  1440. ** Exceptions:
  1441. ** If the incoming iTopic is invalid, or a read error occurs, then the nc
  1442. ** returned refers to the topic number 0.
  1443. **
  1444. */
  1445. nc pascal near MapTopictoContext(
  1446. ushort iTopic, /* topic number to map */
  1447. fdb far *fpfdbCur, /* pointer to current FDB */
  1448. int Dir
  1449. ) {
  1450. ushort cTopics; /* number of topics to search */
  1451. ushort far *fpContextMap; /* pointer to the context map */
  1452. mh mhPortion; /* mem handle for the context map*/
  1453. nc ncMatch = {0,0}; /* return value */
  1454. mhPortion = LoadPortion (HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
  1455. if (mhPortion && (mhPortion != (mh)(-1))) {
  1456. if (fpContextMap = HelpLock(mhPortion)) {
  1457. if (iTopic >= fpfdbCur->hdr.cTopics) {
  1458. iTopic = 0;
  1459. }
  1460. ncMatch.mh = (mh)0L;
  1461. ncMatch.cn = 0x8000 | iTopic;
  1462. // rjsa ncMatch = 0x8000 | iTopic;
  1463. cTopics = 0;
  1464. while (cTopics < fpfdbCur->hdr.cContexts) {
  1465. if ( Dir == 0 ) {
  1466. if (iTopic == fpContextMap[cTopics++]) {
  1467. ncMatch.cn = cTopics; /* nc's are one based */
  1468. break;
  1469. }
  1470. } else if ( Dir > 0 ) {
  1471. if (iTopic <= fpContextMap[cTopics++]) {
  1472. ncMatch.cn = cTopics; /* nc's are one based */
  1473. break;
  1474. }
  1475. } else if ( Dir < 0 ) {
  1476. if (iTopic == fpContextMap[cTopics++]) {
  1477. ncMatch.cn = cTopics;
  1478. break;
  1479. } else if (iTopic < fpContextMap[cTopics-1]) {
  1480. ncMatch.cn = cTopics-1;
  1481. break;
  1482. }
  1483. }
  1484. }
  1485. //if ( iTopic != fpContextMap[cTopics-1] ) {
  1486. // ncMatch.cn = 0;
  1487. //}
  1488. if ( cTopics >= fpfdbCur->hdr.cContexts) {
  1489. ncMatch.cn = 0;
  1490. }
  1491. HelpUnlock (mhPortion);
  1492. }
  1493. }
  1494. ncMatch.mh = (fpfdbCur->ncInit).mh;
  1495. return ncMatch;
  1496. // rjsa return ncMatch | HIGHONLY(fpfdbCur->ncInit);
  1497. }
  1498. /************************************************************************
  1499. **
  1500. ** LoadFdb - make local copy of fdb.
  1501. **
  1502. ** Purpose:
  1503. ** Used to create a local copy of an FDB, so that we don't have to keep a
  1504. ** locked, far copy around.
  1505. **
  1506. ** Entry:
  1507. ** mhFdb - memory handle for the FDB
  1508. ** fpFdbDest - Pointer to destination for FDB copy
  1509. **
  1510. ** Exit:
  1511. ** returns TRUE if FDB copied.
  1512. */
  1513. f pascal near LoadFdb (
  1514. mh mhfdb,
  1515. fdb far *fpfdbDest
  1516. ) {
  1517. fdb far *fpfdbCur; /* pointer to current FDB */
  1518. if (fpfdbCur = HelpLock (mhfdb)) {
  1519. *fpfdbDest = *fpfdbCur;
  1520. HelpUnlock (mhfdb);
  1521. return TRUE;
  1522. }
  1523. return FALSE;
  1524. /* end LoadFdb */}
  1525. /************************************************************************
  1526. **
  1527. ** PutFdb - make local copy of fdb permanent.
  1528. **
  1529. ** Purpose:
  1530. ** Used to copy a local copy of an FDB to the "real" one, so that we don't
  1531. ** have to keep a locked, far copy around.
  1532. **
  1533. ** Entry:
  1534. ** mhFdb - memory handle for the FDB
  1535. ** fpfdbSrc - Pointer to source of FDB copy
  1536. **
  1537. ** Exit:
  1538. ** returns TRUE if FDB copied.
  1539. */
  1540. f pascal near PutFdb (
  1541. mh mhfdb,
  1542. fdb far *fpfdbSrc
  1543. ) {
  1544. fdb far *fpfdbCur; /* pointer to current FDB */
  1545. if (fpfdbCur = HelpLock (mhfdb)) {
  1546. *fpfdbCur = *fpfdbSrc;
  1547. HelpUnlock (mhfdb);
  1548. return TRUE;
  1549. }
  1550. return FALSE;
  1551. /* end PutFdb */}
  1552. #if ASCII
  1553. /************************************************************************
  1554. **
  1555. ** maLocate - Locate context in minimally formatted ascii file.
  1556. **
  1557. ** Purpose:
  1558. ** Performs sequential searches on mimimally formatted ascii files to locate
  1559. ** lines beginning with ">>" and a context string.
  1560. **
  1561. ** Entry:
  1562. ** fpfdbCur = Pointer to current fdb
  1563. ** fpszSrc = Pointer to context string to be found (or null for next
  1564. ** string)
  1565. ** offset = offset at which to begin search.
  1566. ** lpfnCMp = pointer to comparison routine to use
  1567. **
  1568. ** Exit:
  1569. ** returns file offset of ">>" of context string.
  1570. **
  1571. ** Exceptions:
  1572. ** returns -1 on error.
  1573. **
  1574. */
  1575. long pascal near maLocate (
  1576. fdb far *fpfdbCur,
  1577. uchar far *fpszSrc,
  1578. ulong offset,
  1579. f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
  1580. ) {
  1581. uchar buffer[MASIZE+1]; /* input buffer */
  1582. ushort cbBuf = 0; /* count of bytes in buffer */
  1583. ushort cbSrc; /* length of source string */
  1584. uchar far *pBuf; /* pointer into buffer */
  1585. uchar far *pBufT; /* temp pointer into buffer */
  1586. cbSrc = hfstrlen(fpszSrc)+1; /* get length of input */
  1587. if (offset == 0xffffffff) /* special case */
  1588. offset = 0;
  1589. while (cbBuf += (ushort)ReadHelpFile(fpfdbCur->fhHelp
  1590. , offset+cbBuf
  1591. , buffer+cbBuf
  1592. , MASIZE-cbBuf)) {
  1593. buffer[cbBuf] = 0; /* ensure strings terminated */
  1594. pBuf = &buffer[0];
  1595. while (pBuf = hfstrchr(pBuf,'>')) { /* look for start of context */
  1596. if ((*(pBuf+1) == '>') /* if >> found */
  1597. && ((*(pBuf-1) == '\n') /* at beginning of line */
  1598. || ((offset == 0) /* or beginning of file */
  1599. && (pBuf == (char far *)&buffer[0])))) {
  1600. pBufT = pBuf +2;
  1601. if (lpfnCmp (fpszSrc, pBufT, cbSrc, FALSE, TRUE))
  1602. return offset + (ulong)(pBuf - (uchar far *)&buffer[0]);
  1603. }
  1604. pBuf += 2;
  1605. }
  1606. if (cbBuf == MASIZE) { /* if buffer full */
  1607. hfstrcpy(buffer,buffer+MASIZE-MAOVER); /* copy down overlap */
  1608. cbBuf = MAOVER; /* and leave that in */
  1609. offset += MASIZE-MAOVER; /* file pos of buffer[0] */
  1610. }
  1611. else {
  1612. offset += cbBuf;
  1613. cbBuf = 0; /* else we're empty */
  1614. }
  1615. }
  1616. return -1;
  1617. /* end maLocate */}
  1618. #endif