summaryrefslogtreecommitdiffstats
path: root/private/utils/mep/help
diff options
context:
space:
mode:
Diffstat (limited to 'private/utils/mep/help')
-rw-r--r--private/utils/mep/help/dirs24
-rw-r--r--private/utils/mep/help/enginlib/hback.c105
-rw-r--r--private/utils/mep/help/enginlib/hctl.c72
-rw-r--r--private/utils/mep/help/enginlib/hdata.c46
-rw-r--r--private/utils/mep/help/enginlib/help.c1745
-rw-r--r--private/utils/mep/help/enginlib/helpcell.c138
-rw-r--r--private/utils/mep/help/enginlib/helpcnt.c54
-rw-r--r--private/utils/mep/help/enginlib/helpdec.c722
-rw-r--r--private/utils/mep/help/enginlib/helpdll.c190
-rw-r--r--private/utils/mep/help/enginlib/helpif.c308
-rw-r--r--private/utils/mep/help/enginlib/hinfo.c57
-rw-r--r--private/utils/mep/help/enginlib/hline.c139
-rw-r--r--private/utils/mep/help/enginlib/hloc.c146
-rw-r--r--private/utils/mep/help/enginlib/makefile6
-rw-r--r--private/utils/mep/help/enginlib/mshelp.def29
-rw-r--r--private/utils/mep/help/enginlib/mshelp.rc10
-rw-r--r--private/utils/mep/help/enginlib/mshelp1.def29
-rw-r--r--private/utils/mep/help/enginlib/sources35
-rw-r--r--private/utils/mep/help/htest/cons.c2200
-rw-r--r--private/utils/mep/help/htest/cons.h253
-rw-r--r--private/utils/mep/help/htest/htest.c1441
-rw-r--r--private/utils/mep/help/htest/makefile6
-rw-r--r--private/utils/mep/help/htest/sources18
-rw-r--r--private/utils/mep/help/inc/farutil.h30
-rw-r--r--private/utils/mep/help/inc/help.h235
-rw-r--r--private/utils/mep/help/inc/helpfile.h95
-rw-r--r--private/utils/mep/help/inc/helpmake.h195
-rw-r--r--private/utils/mep/help/inc/helpsys.h92
-rw-r--r--private/utils/mep/help/inc/huffman.h8
-rw-r--r--private/utils/mep/help/inc/rtf.h94
-rw-r--r--private/utils/mep/help/inc/vm.h46
-rw-r--r--private/utils/mep/help/inc/zlib.h9
-rw-r--r--private/utils/mep/help/mshelp/help.c1745
-rw-r--r--private/utils/mep/help/mshelp/makefile6
-rw-r--r--private/utils/mep/help/mshelp/mshelp.def29
-rw-r--r--private/utils/mep/help/mshelp/mshelp.rc10
-rw-r--r--private/utils/mep/help/mshelp/mshelp1.def29
-rw-r--r--private/utils/mep/help/mshelp/sources24
38 files changed, 10420 insertions, 0 deletions
diff --git a/private/utils/mep/help/dirs b/private/utils/mep/help/dirs
new file mode 100644
index 000000000..129a62c4a
--- /dev/null
+++ b/private/utils/mep/help/dirs
@@ -0,0 +1,24 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+
+!ENDIF
+
+DIRS=enginlib
+
+OPTIONAL_DIRS=
diff --git a/private/utils/mep/help/enginlib/hback.c b/private/utils/mep/help/enginlib/hback.c
new file mode 100644
index 000000000..68242e0c3
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hback.c
@@ -0,0 +1,105 @@
+/*** hlback.c - help library historical back-trace routines & data
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* 02-Aug-1988 ln Correct HelpNcBack
+* 19-May-1988 LN Split off from help.c
+*
+*************************************************************************/
+#include <assert.h> /* debugging assertions */
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+/*************************************************************************
+**
+** cBack, iBackLast, rgncBack
+** System context back-trace list.
+**
+** cBack - Number of entries in back-trace list
+** iBackLast - Index to last back trace entry
+** rgncBack - Array of back-trace entries
+*/
+extern ushort cBack; /* Number of Back-List entries */
+static ushort iBackLast; /* Back-List Last entry index */
+static nc rgncBack[MAXBACK+1]; /* Back-List */
+
+/************************************************************************
+**
+** HelpNcRecord - Remember context for back-trace
+**
+** Purpose:
+** records a context number for back-trace.
+**
+** Entry:
+** ncCur = context number to record.
+**
+** Exit:
+** none
+**
+** Exceptions:
+** none
+*/
+void far pascal LOADDS HelpNcRecord(ncCur)
+nc ncCur;
+{
+ushort *pcBack = &cBack;
+
+if ((ncCur.mh || ncCur.cn) &&
+ ((ncCur.mh != rgncBack[iBackLast].mh) ||
+ (ncCur.cn != rgncBack[iBackLast].cn))) {
+ iBackLast = (ushort)(((int)iBackLast + 1) % MAXBACK);
+ rgncBack[iBackLast] = ncCur;
+ if (*pcBack < MAXBACK)
+ (*pcBack)++;
+}
+/* end HelpNcRecord */}
+
+/******************************************************************************
+**
+** HelpNcBack - Return previously viewed context
+**
+** Purpose:
+** Returns the context number corresponding to the historically previously
+** viewed topic.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on backup list exhuasted
+**
+** Algorithm:
+**
+** If backlist not empty
+** context is last entry in back list
+** remove last entry
+** else
+** return NULL
+*/
+nc far pascal LOADDS HelpNcBack(void) {
+nc ncLast = {0,0}; /* return value */
+ushort *pcBack = &cBack;
+
+if (*pcBack) {
+ ncLast = rgncBack[iBackLast];
+ iBackLast = iBackLast == 0 ? (ushort)MAXBACK-1 : (ushort)iBackLast-1;
+ (*pcBack)--;
+ }
+return ncLast;
+/* end HelpNcBack */}
diff --git a/private/utils/mep/help/enginlib/hctl.c b/private/utils/mep/help/enginlib/hctl.c
new file mode 100644
index 000000000..a0d3797c1
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hctl.c
@@ -0,0 +1,72 @@
+/**************************************************************************
+ *hctl - enable/disable retrieval of control lines
+ *
+ * Copyright <C> 1989, Microsoft Corporation
+ *
+ * Purpose:
+ *
+ * Revision History:
+ *
+ * 10-Oct-1990 RJSA Translated to C
+ * 13-May-1990 LN Unlock topic text when through with it.
+ * [] 22-Feb-1989 LN Created
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <help.h>
+#include <helpfile.h>
+#include <helpsys.h>
+
+
+
+/**** helpctl - enable/disable retrieval of control lines
+ * void far pascal helpctl(
+ * uchar far *pTopic,
+ * f fEnable
+ * )
+ *
+ * Purpose:
+ * Enables or disables retrieval of embedded help control lines
+ *
+ * Entry:
+ * pTopic = Topic text
+ * fEnable = TRUE=> allow lookups of control lines, else disable
+ *
+ * Exit:
+ * returns nothing
+ *
+ **************************************************************************/
+
+void pascal
+HelpCtl (
+ PB pTopic,
+ f fEnable
+ ) {
+
+ struct topichdr UNALIGNED *pT;
+
+
+ pT = PBLOCK(pTopic);
+
+ if (pT) {
+
+ pT->lnCur = 1;
+ pT->lnOff = sizeof(struct topichdr);
+ pT->linChar = pT->appChar;
+
+ if (fEnable) {
+ pT->linChar = 0xFF;
+ }
+
+ PBUNLOCK(pTopic);
+ }
+
+}
diff --git a/private/utils/mep/help/enginlib/hdata.c b/private/utils/mep/help/enginlib/hdata.c
new file mode 100644
index 000000000..bffddefa5
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hdata.c
@@ -0,0 +1,46 @@
+/*** hdata.c - global help engine data definitions.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* [] 01-Mar-1989 LN Created
+*
+*************************************************************************/
+
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+/*************************************************************************
+**
+** Global data
+** BEWARE. The effects of global data on reentrancy should be VERY carefully
+** considered.
+**
+**************************************************************************
+**
+** tbmhFdb[]
+** Table of FDB handles. Non-zero value indicates allocated to open help file.
+** We make this table one larger than it needs to be to save code later on.
+*/
+mh tbmhFdb[MAXFILES+1] = {0};
+/*
+** szNil
+** Null string.
+*/
+char szNil[1] = "";
+/*
+** cBack
+** count of entries in the help back-trace list
+*/
+ushort cBack = 0; /* Number of Back-List entries */
diff --git a/private/utils/mep/help/enginlib/help.c b/private/utils/mep/help/enginlib/help.c
new file mode 100644
index 000000000..f520d0a0b
--- /dev/null
+++ b/private/utils/mep/help/enginlib/help.c
@@ -0,0 +1,1745 @@
+/*** help.c - help library main
+*
+* Copyright <C> 1988-1990, Microsoft Corporation
+*
+* Definitions:
+*
+* Context Map: Mapping of context number to topic number.
+* Allows multiple contexts to be associated with a
+* single topic. Syncronized with the context
+* string table, each entry contains the topic
+* number associated with the corresponding context
+* string.
+*
+* Context String: String on which help can be "looked up".
+*
+* Context String Table: Table of all valid context strings in a
+* particular help file.
+*
+* Local Context: A type of context which bypasses the context
+* string and context numbers. In cross references,
+* encoded as a cross reference string of NULL,
+* followed by a topic number ored with 0x8000.
+*
+* nc: (Context Number) A long which uniquely
+* identifies a help file and context string, or
+* for local contexts, the helpfile and topic
+* number. Formatted as:
+*
+* +----------------+----------------+
+* | Fdb Mem Handle | context number |
+* +----------------+----------------+
+*
+* Where the upper word is the memory handle of the
+* allocated fdb for the help file. The lower word
+* is the either the "true" context number (see
+* below) if <= 0x7fff, or the actual topic number
+* or'ed with 0x8000.
+*
+* Topic: Actual help textual entry. May be compressed.
+*
+* Topic Index: Table of file positions of all topics contained
+* in a help file. Indexed by the topic number,
+* returns that topics physical position in the
+* file.
+*
+* Topic Number: Index to a particular topic. Topic numbers are
+* zero based, and reflect the physical ordering of
+* the topics in the file.
+*
+* "True" context number: is the zero based index or string number in the
+* <context string table>. I.E. the "n'th" string
+* has context number "n".
+*
+* The progression from string to true context number to topic number to file
+* position is:
+*
+* 1) Context String ==> "True" Context Number
+*
+* The string is searched for in the <context string table>, and
+* it's number becomes the "true" context number.
+*
+* 2) "True" Context Number ==> Topic Number
+*
+* The context number is an index into the <context map>, returing
+* the topic number associated with the context number.
+*
+* 3) Topic Number ==> File Position
+*
+* The topic number is used as an index into the Topic Index, from
+* which the physical file position is retrieved.
+*
+* Notes:
+* QuickPascal requires NO initialized data. In this case, CLEAR is defined,
+* and the HelpInit routine is included. We also play some pointer games to
+* simple variables, because the C compiler can generate CONST segment
+* entries for the SEG of various vars. (This enables it to load the segment
+* register directly, rather than by using SEG varname and another
+* register). Q/P cannot support this action by the compiler.
+*
+* QuickHelp for OS/2 is reentrant. This code should remain reentrant up to
+* but not including allocating and deallocating fdbs.
+*
+* Revision History:
+*
+* 17-Aug-1990 ln Don't blindly request 64k of an ascii file. Query
+* for size first, then read. Allocations based on
+* previous topic size requests may cause the OS to
+* GPFault for an out of range read.
+* 16-Jul-1990 ln Searching for "filename!" where filename is a QH
+* file, will now fail, rather than GP fault. Searching
+* for "!" will now succeed.
+* 08-Jun-1990 ln Remove HelpLock usage in HelpNcCmp
+* 13-Apr-1990 ln Try to get HelpSzContext to return strings in more
+* cases where it can.
+* 12-Mar-1990 ln Rename CloseFile -> HelpCloseFile
+* 08-Oct-1989 ln Changes to improve the previous change to work (allow
+* decompression) more often in low memory bases.
+* Deallocate table in OpenCore to reduce fragmentation
+* in non-moveable memory systems.
+* 19-May-1989 ln Correct bug in decompressing, where we would not
+* decompress if the tables didn;t exist.
+* 12-Apr-1989 ln Ensure that we handle Locks failing correctly. Also
+* remove TossPortion usage. Unlock handles directly.
+* 10-Mar-1989 ln Change MapTopicToContext to look forward. Changed
+* HelpNc to look begining at passed context string.
+* 17-Jan-1989 ln Correct creation of basename in HelpOpen to account
+* for environment syntax.
+* 09-Dec-1988 ln Add HelpNcUniq
+* 25-Oct-1988 ln Added minascii support to HelpNcPrev. Correct
+* minascii bug in HelpSzContext.
+* 14-Sep-1988 ln Improve doc. Remove ambiguity in MapContextToTopic
+* return value. Improve error checking in various
+* places.
+* 01-Sep-1988 ln Check ReadHelpFile return value in LoadPortion
+* 12-Aug-1988 ln Add check for memory discarded in alloc durring
+* HelpDecomp.
+* 08-Aug-1988 ln Ensure HelpClose closes ALL files. (Off by one error
+* in loop).
+* 14-Apr-1988 ln Modified to conform to QC (CW?) restriction that
+* prohibits any segments from being locked when an
+* allocation is performed.
+* [] 15-Dec-1987 ln Created, for design.
+*
+*************************************************************************/
+
+#include <assert.h> /* debugging assertions */
+#include <io.h> /* I/O function declarations */
+#include <stdlib.h> /* standard library */
+
+#include <stdio.h> /* standard I/O definitions */
+
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+#define MASIZE 512 /* size of ma input buffer */
+#define MAOVER 64 /* size of ma search overlap */
+
+#define ISERROR(x) (((x).mh == 0L) && ((x).cn <= HELPERR_MAX))
+#define SETERROR(x,y) { (x).mh = 0L; (x).cn = y; }
+
+/*************************************************************************
+**
+** Forward definitions
+*/
+void pascal near CloseShrink(nc, f);
+f pascal near LoadFdb (mh, fdb far *);
+mh pascal near LoadPortion (int, mh);
+ushort pascal near MapContexttoTopic (nc, fdb far *);
+nc pascal near MapTopictoContext(ushort, fdb far *, int);
+nc pascal near NextPrev(nc,int);
+nc pascal near OpenCore(FILE *, ulong, uchar far *, struct helpheader *, fdb far *);
+f pascal near PutFdb (mh, fdb far *);
+f pascal near SizePos (nc, ushort *,ulong *);
+
+ushort pascal near decomp (uchar far *, uchar far *, uchar far *, uchar far *);
+char far * pascal near hfmemzer(void far *, ushort);
+char far * pascal near hfstrchr(char far *, char);
+char far * pascal near hfstrcpy(char far *, char far *);
+ushort pascal near hfstrlen(char far *);
+f pascal far HelpCmp (uchar far *, uchar far *, ushort, f, f);
+f pascal near HelpCmpSz (uchar far *, uchar far *);
+void pascal near kwPtrBuild(uchar far *, ushort);
+
+#if ASCII
+long pascal near maLocate (fdb far *, uchar far *, ulong,
+ f (pascal far *)(uchar far *, uchar far *, ushort, f, f));
+
+nc pascal near combineNc (ulong, mh);
+ulong pascal near NctoFo (ulong);
+#endif
+
+/*************************************************************************
+**
+** External Global data
+** BEWARE. The effects of global data on reentrancy should be VERY carefully
+** considered.
+**
+*************************************************************************/
+extern mh tbmhFdb[MAXFILES+1];
+extern char szNil[1];
+extern ushort cBack;
+
+#ifdef CLEAR
+/*************************************************************************
+**
+** HelpInit - One-time initialization
+**
+** Purpose:
+** Performs one-time initialization. Right now that's a zero fill of static
+** memory for those environments which don't support pre-inited static
+** memory.
+**
+** Entry:
+** none
+**
+** Exit:
+** none
+**
+*/
+void far pascal LOADDS HelpInit () {
+
+hfmemzer (tbmhFdb, sizeof(tbmhFdb)); /* zero entire fdb handle table */
+hfmemzer (szNil, sizeof(szNil)); /* zero null string */
+hfmemzer (&cBack, sizeof(cBack)); /* zero back trace count */
+
+/* end HelpInit */}
+#endif
+
+/*************************************************************************
+**
+** HelpOpen - Open help file & return help handle.
+**
+** Purpose:
+** Given the file basename, locate the associated help file on the path, and
+** open it, initializing internal data structures as appropriate.
+**
+** Entry:
+** fpszName - base filename to be openned.
+**
+** Exit:
+** nc initial context for openned file.
+**
+** Exceptions:
+** Returns error code on failure to open for any reason.
+**
+*/
+nc far pascal LOADDS HelpOpen (
+char far *fpszName
+) {
+FILE *fhT; /* temp file handle */
+fdb fdbLocal; /* local copy of fdb to use */
+uchar far *fpszBase; /* base filename */
+void far *fpT;
+struct helpheader hdrLocal; /* for use by opencore */
+nc ncRet = {0,0}; /* first context */
+mh *ptbmhFdb; /* pointer into mh table */
+
+/*
+** create basename by removing possible env variable, drive, and scanning
+** for last path seperator
+*/
+fpszBase = fpszName;
+if (fpT = hfstrchr(fpszBase,':'))
+ fpszBase = (uchar far *)fpT+1;
+while (fpT = hfstrchr(fpszBase,'\\'))
+ fpszBase = (uchar far *)fpT+1;
+/*
+** Scan FDB's for an open file of the same base name. If we encounter the name,
+** in either the true filename, or file header, just return that file's initial
+** context. Otherwise fall below to try and open it.
+*/
+for (ptbmhFdb=&tbmhFdb[1]; ptbmhFdb<=&tbmhFdb[MAXFILES]; ptbmhFdb++) {
+ if (LoadFdb (*ptbmhFdb,&fdbLocal)) {
+ if (HelpCmpSz(fpszBase,fdbLocal.fname) ||
+ HelpCmpSz(fpszBase,fdbLocal.hdr.fname))
+ ncRet = fdbLocal.ncInit;
+ if (ncRet.mh && ncRet.cn)
+ return ncRet;
+ }
+ }
+/*
+** Open file. If we can, then call the core open routine to open the file (and
+** any anything appended to it).
+**
+** Warning: the app may callback HelpClose at this point.
+*/
+if (fhT = OpenFileOnPath(fpszName,FALSE)) {
+ ncRet = OpenCore (fhT,0L,fpszBase,&hdrLocal,&fdbLocal);
+ if (ISERROR(ncRet))
+ HelpCloseFile (fhT);
+ return ncRet;
+ }
+
+SETERROR(ncRet, HELPERR_FNF);
+return ncRet;
+// rjsa return HELPERR_FNF;
+
+/* end HelpOpen*/}
+
+/*************************************************************************
+**
+** OpenCore - Recursive core of HelpOpen
+**
+** Purpose:
+** Given the open file handle, initialize internal data structures as
+** appropriate. Attempt to open any file that is appended.
+**
+** Entry:
+** fhT - Open file handle
+** offset - Offset from start of file of help file to open
+** fpszBase - pointer to base filename
+**
+** Exit:
+** initial context, or NULL on failure.
+**
+** Exceptions:
+** Returns NULL on failure to open for any reason.
+**
+*/
+nc pascal near OpenCore (
+FILE * fhHelp,
+ulong offset,
+uchar far *fpszBase, /* base filename */
+struct helpheader *phdrLocal,
+fdb far *pfdbLocal /* pointer to current FDB */
+) {
+//void far *fpT;
+int ihFree; /* handle for free fdb (& index)*/
+mh mhCur; /* current memory handle */
+nc ncFirst = {0,0}; /* first context */
+nc ncInit; /* first context */
+mh *pmhT; /* pointer into mh table */
+
+/*
+** Read in helpfile header
+*/
+if (ReadHelpFile(fhHelp,
+ offset,
+ (char far *)phdrLocal,
+ (ushort)sizeof(struct helpheader))) {
+/*
+** search for available fdb
+*/
+ for (ihFree = MAXFILES, pmhT = &tbmhFdb[MAXFILES];
+ ihFree && *pmhT;
+ ihFree--, pmhT--);
+/*
+** if an offset is present, and this is NOT a compressed file, or there is no
+** available fdb, ignore the operation.
+*/
+ if ( offset
+ && (phdrLocal->wMagic != wMagicHELP)
+ && (phdrLocal->wMagic != wMagicHELPOld)
+ ) {
+ SETERROR(ncInit, HELPERR_BADAPPEND);
+ return ncInit;
+ // rjsa return HELPERR_BADAPPEND;
+ }
+ if (ihFree == 0) {
+ SETERROR(ncInit, HELPERR_LIMIT);
+ return ncInit;
+ // rjsa return HELPERR_LIMIT;
+ }
+/*
+** allocate fdb. Again, if we can't, skip it all and return NULL.
+*/
+ if (mhCur = *pmhT = HelpAlloc((ushort)sizeof(fdb))) {
+/*
+** Fill in helpfile header & appropriate fdb fields
+*/
+ hfmemzer(pfdbLocal,sizeof(fdb)); /* zero entire fdb */
+ pfdbLocal->fhHelp = fhHelp; /* file handle */
+ ncFirst.mh = pfdbLocal->ncInit.mh = mhCur;
+ ncFirst.cn = pfdbLocal->ncInit.cn = 0L;
+ // rjsa ncFirst = pfdbLocal->ncInit = ((long)mhCur) << 16; /* initial context */
+ pfdbLocal->foff = offset; /* appended offset */
+ hfstrcpy(pfdbLocal->fname,fpszBase); /* include base filename*/
+/*
+** if this is a compressed file (signified by the first two bytes of the header
+** we read in above), then note the file type in the fdb. We unlock the fdb, as
+** MapTopicToContext and the recursion might cause memory allocation. We get a
+** context number for the first topic, and recurse and attempt to open any
+** appended file.
+*/
+ if ( (phdrLocal->wMagic == wMagicHELPOld)
+ || (phdrLocal->wMagic == wMagicHELP)
+ ) {
+ if ((phdrLocal->wMagic == wMagicHELP)
+ && (phdrLocal->wVersion > wHelpVers)) {
+ SETERROR(ncInit, HELPERR_BADVERS);
+ return ncInit;
+ // rjsa return HELPERR_BADVERS;
+ }
+ pfdbLocal->hdr = *phdrLocal;
+ pfdbLocal->ftype = FTCOMPRESSED | FTFORMATTED;
+ if (PutFdb (mhCur, pfdbLocal)) {
+ ncFirst = MapTopictoContext(0,pfdbLocal,0);
+
+ // We free the context map (the only thing loaded by the
+ // MapTopictoContext) in order to reduce fragmentation in
+ // non-moveable memory based systems.
+ //
+ HelpDealloc (pfdbLocal->rgmhSections[HS_CONTEXTMAP]);
+ pfdbLocal->rgmhSections[HS_CONTEXTMAP] = 0;
+
+ ncInit = OpenCore(fhHelp,pfdbLocal->hdr.tbPos[HS_NEXT]+offset,szNil,phdrLocal,pfdbLocal);
+ if (LoadFdb (mhCur, pfdbLocal)) {
+ //if (ncInit.cn > HELPERR_MAX) {
+ if ( !(ISERROR(ncInit)) ) {
+ pfdbLocal->ncLink = ncInit;
+ } else {
+ pfdbLocal->ncLink.mh = (mh)0;
+ pfdbLocal->ncLink.cn = 0L;
+ }
+ // rjsa pfdbLocal->ncLink = ncInit > HELPERR_MAX ? ncInit : 0;
+ pfdbLocal->ncInit = ncFirst;
+ }
+ }
+ }
+#if ASCII
+/*
+** In the case of a minascii formatted file (signified by the first two bytes
+** of the header being ">>") we just set up the filetype and "applications
+** specific character". The default "ncFirst" is the context for the first
+** topic.
+*/
+ else if (phdrLocal->wMagic == 0x3e3e) { /* minascii formatted? */
+ pfdbLocal->ftype = FTFORMATTED;
+ pfdbLocal->hdr.appChar = '>'; /* ignore lines with this*/
+ }
+#endif
+ else if ((phdrLocal->wMagic & 0x8080) == 0) { /* ascii unformatted? */
+ pfdbLocal->ftype = 0;
+ pfdbLocal->hdr.appChar = 0xff; /* ignore lines with this*/
+ }
+ else {
+ SETERROR(ncInit, HELPERR_NOTHELP);
+ return ncInit;
+ // rjsa return HELPERR_NOTHELP;
+ }
+
+ if (!PutFdb (mhCur, pfdbLocal)) {
+ ncFirst.mh = (mh)0;
+ ncFirst.cn = 0L;
+ }
+ }
+ else {
+ SETERROR(ncFirst, HELPERR_MEMORY);
+ // rjsa ncFirst = HELPERR_MEMORY; /* error reading file */
+ }
+}
+else {
+ SETERROR(ncFirst, HELPERR_READ);
+ // rjsa ncFirst = HELPERR_READ; /* error reading file */
+}
+
+return ncFirst; /* return valid context */
+
+/* end OpenCore */}
+
+
+/*************************************************************************
+**
+** HelpClose - Close Help file
+**
+** Purpose:
+** Close a help file, deallocate all memory associated with it, and free the
+** handle.
+**
+** Entry:
+** ncClose - Context for file to be closed. If zero, close all.
+**
+** Exit:
+** None
+**
+** Exceptions:
+** All errors are ignored.
+**
+*/
+void far pascal LOADDS HelpClose (
+nc ncClose
+) {
+CloseShrink(ncClose,TRUE); /* close file(s) */
+/* end HelpClose */}
+
+/*************************************************************************
+**
+** HelpShrink - Release all dynamic memory
+**
+** Purpose:
+** A call to this routines causes the help system to release all dynamic
+** memory it may have in use.
+**
+** Entry:
+** None.
+**
+** Exit:
+** None.
+**
+** Exceptions:
+** None.
+**
+*/
+void far pascal LOADDS HelpShrink(void) {
+ nc ncTmp = {0,0};
+CloseShrink(ncTmp,0);
+// rjsa CloseShrink(0,0);
+/* end HelpShrink */}
+
+/*************************************************************************
+**
+** CloseShrink - Deallocate memory and possibly Close Help file
+**
+** Purpose:
+** Deallocate all memory associated with a help file, and possibly close free
+** it.
+**
+** Entry:
+** ncClose - Context for file. If zero, do all.
+** fClose - TRUE if a close operation.
+**
+** Exit:
+** None
+**
+** Exceptions:
+** All errors are ignored.
+**
+*/
+void pascal near CloseShrink (
+nc ncClose,
+f fClose
+) {
+fdb fdbLocal; /* pointer to current FDB */
+int i;
+mh mhClose; /* fdb mem hdl to file to close */
+mh *pmhFdb; /* pointer to FDB's table entry */
+
+
+mhClose = ncClose.mh; /* get index */
+// rjsa mhClose = (mh)HIGH(ncClose); /* get index */
+for (pmhFdb = &tbmhFdb[0]; /* for each possible entry */
+ pmhFdb <= &tbmhFdb[MAXFILES];
+ pmhFdb++
+ ) {
+ if ((mhClose == 0) /* if all selected */
+ || (mhClose == *pmhFdb)) { /* or this one selected */
+
+ if (LoadFdb (*pmhFdb, &fdbLocal)) { /* if open file */
+/*
+ * Recurse to close/shrink any appended files
+ */
+ if ((fdbLocal.ncLink.mh || fdbLocal.ncLink.cn) && mhClose)
+ CloseShrink (fdbLocal.ncLink, fClose);
+
+ for (i=HS_count-2; i>=0; i--) /* for dyn mem handles */
+ HelpDealloc(fdbLocal.rgmhSections[i]); /* dealloc */
+ hfmemzer(fdbLocal.rgmhSections,sizeof(fdbLocal.rgmhSections));
+
+ if (fClose) {
+ HelpCloseFile(fdbLocal.fhHelp); /* close file */
+ HelpDealloc(*pmhFdb); /* deallocate fdb */
+ *pmhFdb = 0;
+ }
+ else
+ PutFdb (*pmhFdb, &fdbLocal); /* update FDB */
+ }
+ }
+ }
+/* end CloseShrink */}
+
+/*** HelpNcCmp - Look up context string, provide comparison routine
+*
+* Given an ascii string, determine the context number of that string. Uses
+* user-supplied comparison routine.
+*
+* Entry:
+* lpszContext - Pointer to asciiz context string.
+* ncInital - Starting Context, used to locate file.
+* lpfnCmp - far pointer to comparison routine to use.
+*
+* Exit:
+* Context number, if found.
+*
+* Exceptions:
+* Returns NULL if context string not found.
+*
+*************************************************************************/
+nc far pascal LOADDS HelpNcCmp (
+char far *fpszContext,
+nc ncInitial,
+f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
+) {
+f fFound = FALSE; // TRUE -> found
+f fOpened = FALSE; // TRUE -> file was openned here
+fdb fdbLocal; // pointer to current FDB
+char far *fpszT; // temp far pointer
+long i;
+long iStart; // nc to start looking at
+mh mhCur; // memory handle locked
+nc ncRet = {0,0}; // The return value
+char far *fpszContexts; // pointer to context strings
+
+
+// if the context string includes a "filename!", then open that as a help
+// file, and point to the context string which may follow.
+//
+if ((fpszT = hfstrchr(fpszContext,'!')) && (fpszT != fpszContext)) {
+ *fpszT = 0;
+ ncInitial = HelpOpen(fpszContext);
+ *fpszT++ = '!';
+ fpszContext = fpszT;
+ fOpened = TRUE;
+}
+
+// if helpfile was not openned, just return the error
+//
+if (ISERROR(ncInitial)) {
+ ncInitial.mh = (mh)0;
+ ncInitial.cn = 0L;
+ return ncInitial;
+}
+
+// For compressed files we scan the context strings in the file (I know,
+// it's stupid code, but this turns out not to be that speed critical in
+// comparision with decompression, so I haven't bothered), to get the
+// context number.
+//
+// If not found, and there IS a linked (appended) file, we recurse to search
+// that file as well.
+//
+// The context number for compressed files is just the zero based string
+// number, plus the number of predefined contexts, with the fdb memory
+// handle in the upper word.
+//
+if (LoadFdb (ncInitial.mh, &fdbLocal)) {
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+
+ // If not a local context look up, get the context strings, and
+ // search
+ //
+ if (*fpszContext) {
+ mhCur = LoadPortion (HS_CONTEXTSTRINGS, ncInitial.mh);
+ if ( (mhCur == (mh)0)
+ || (mhCur == (mh)(-1))
+ || (!(fpszContexts = HelpLock(mhCur)))
+ ) {
+ ncRet.mh = (mh)0;
+ ncRet.cn = 0L;
+ return ncRet;
+ }
+ i=0;
+
+ // iStart allows us to begin searching from the context string
+ // passed, as opposed to from the begining each time. This
+ // allows the application to "carry on" a search from othe last
+ // place we found a match. This is usefull for multiple
+ // duplicate context resolution, as well as inexact matching.
+ //
+ iStart = ncInitial.cn;
+ if (iStart & 0x8000)
+ iStart = 0;
+ else
+ iStart--; /* table index is 0 based */
+
+ do {
+ if (i >= iStart) {
+ fFound = lpfnCmp ( fpszContext
+ , fpszContexts
+ , 0xffff
+ , (f)(fdbLocal.hdr.wFlags & wfCase)
+ , (f)FALSE);
+ }
+ while (*fpszContexts++); /* point to next string */
+ i++;
+ }
+ while ((i < (int)fdbLocal.hdr.cContexts) && !fFound);
+ HelpUnlock (mhCur);
+
+ if (fFound) { /* if a match found */
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = i + fdbLocal.hdr.cPreDef;
+ // rjsa ncRet = (i+fdbLocal.hdr.cPreDef) /* string # */
+ // | HIGHONLY(ncInitial); /* & fdb handle */
+ }
+ else {
+ ncInitial.mh = (mh)0;
+ ncInitial.cn = 0L;
+ ncRet = HelpNcCmp (fpszContext,fdbLocal.ncLink, lpfnCmp);
+ }
+ }
+ else if (!fOpened) {
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = *(UNALIGNED ushort far *)(fpszContext + 1);
+ // rjsa ncRet = *(ushort far *)(fpszContext + 1) /* word following*/
+ // | HIGHONLY(ncInitial); /* & fdb handle */
+ }
+ }
+#if ASCII
+/*
+** For minimally formatted ascii files, we sequentially scan the file itself
+** for context string definitions until we find the string we care about.
+**
+** The context number for minascii files is the the byte position/4 of the
+** beginning of the associated topic, with the fdb memory handle in the upper
+** word.
+*/
+ else if (fdbLocal.ftype & FTFORMATTED) {
+ if (*fpszContext) {
+ ncRet.cn = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
+ if (ncRet.cn == -1L) {
+ ncRet.mh = (mh)0;
+ ncRet.cn = 0L;
+ } else {
+ ncRet = combineNc(ncRet.cn, fdbLocal.ncInit.mh);
+ }
+ // rjsa ncRet = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
+ // ncRet = (ncRet == -1L)
+ // ? 0
+ // : combineNc(ncRet,HIGH(fdbLocal.ncInit));
+ }
+ }
+/*
+** for unformatted ascii files, there must have been NO context string to be
+** searched for. In that case, the context number is always 1, plus the fdb
+** mem handle.
+*/
+ else if (*fpszContext == 0) { /* if null context string */
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = 1L;
+ // rjsa ncRet = HIGHONLY(ncInitial) + 1;
+ }
+#endif
+}
+
+return ncRet;
+
+/* end HelpNcCmp */}
+
+/*** HelpNc - Look up context string
+*
+* Given an ascii string, determine the context number of that string.
+*
+* Entry:
+* lpszContext - Pointer to asciiz context string.
+* ncInital - Starting Context, used to locate file.
+*
+* Exit:
+* Context number, if found.
+*
+* Exceptions:
+* Returns NULL if context string not found.
+*
+*************************************************************************/
+nc far pascal LOADDS HelpNc (
+char far *fpszContext,
+nc ncInitial
+) {
+return HelpNcCmp (fpszContext, ncInitial, HelpCmp);
+/* end HelpNc */}
+
+
+/*************************************************************************
+**
+** HelpNcCb - Return count of bytes in compressed topic
+**
+** Purpose:
+** Returns the size in bytes of the compressed topic. Provided for
+** applications to determine how big a buffer to allocate.
+**
+** Entry:
+** ncCur - Context number to return info on.
+**
+** Exit:
+** Count of bytes in the compressed topic
+**
+** Exceptions:
+** Returns 0 on error.
+**
+*/
+ushort far pascal LOADDS HelpNcCb (
+nc ncCur
+) {
+ulong position;
+ushort size;
+
+return SizePos(ncCur,&size,&position) ? size+(ushort)4 : (ushort)0;
+
+/* end HelpNcCb */}
+
+/******************************************************************************
+**
+** HelpLook - Return compressed topic text
+**
+** Purpose:
+** Places the compressed topic text referenced by a passed context number into
+** a user supplied buffer.
+**
+** Entry:
+** ncCur - Context number for which to return text
+** pbDest - Pointer to buffer in which to place the result.
+**
+** Exit:
+** Count of bytes in >uncompressed< topic. This is encoded based on file type.
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+ushort far pascal LOADDS HelpLook (
+nc ncCur,
+PB pbDest
+) {
+fdb fdbLocal; /* pointer to current FDB */
+char far *fpszDest;
+int i;
+ulong position = 0;
+ushort size = 0;
+
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb down */
+/*
+** for both kinds of formatted files, we determine the position of the topic,
+** and read it in.
+*/
+ if (fdbLocal.ftype) {
+ if (SizePos (ncCur,&size,&position)) {
+ if (fpszDest = (char far *)PBLOCK(pbDest)) {
+
+#ifdef BIGDEBUG
+ {
+ char DbgBuf[128];
+ sprintf(DbgBuf, "HELP: Reading Topic for Context %d at %lX, size %d\n", ncCur.cn, position + fdbLocal.foff, size );
+ OutputDebugString(DbgBuf);
+ }
+#endif
+
+ size = (ushort)ReadHelpFile(fdbLocal.fhHelp
+ ,position + fdbLocal.foff
+ ,fpszDest
+ ,size);
+
+#ifdef BIGDEBUG
+ {
+ char DbgBuf[128];
+ sprintf(DbgBuf, " Read %d bytes to address %lX\n", size, fpszDest );
+ OutputDebugString(DbgBuf);
+ }
+#endif
+/*
+** for compressed files, if the read was sucessfull, we then return the
+** uncompressed size which is the first word of the topic.
+*/
+#if ASCII
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+#endif
+ if (size)
+ size = *(ushort far *)fpszDest+(ushort)1;
+#if ASCII
+ }
+ else {
+/*
+** for minascii files, We also set up for the terminating NULL by scanning for
+** the ">>" which begins the next topic, adjusting the size as well.
+*/
+ size -= 4;
+ for (i=4; i; i--)
+ if (fpszDest[++size] == '>') break;
+ fpszDest[size++] = 0;
+ }
+#endif
+ }
+ }
+ }
+#if ASCII
+ else { /* unformatted ascii */
+/*
+** for unformatted ascii, we just read in (first 64k of) the file.
+*/
+ if (fpszDest = PBLOCK (pbDest)) {
+ if (SizePos (ncCur,&size,&position)) {
+ size = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,fpszDest,size);
+ fpszDest[size++] = 0; /* terminate ascii text */
+ }
+ }
+ }
+#endif
+ PBUNLOCK (pbDest);
+ }
+if (size) size += sizeof(topichdr); /* adjust for prepended topichdr*/
+return size;
+/* end HelpLook */}
+
+/******************************************************************************
+**
+** HelpDecomp - Decompress Topic Text
+**
+** Purpose:
+** Fully decompress topic text. Decompresses based on current file, from one
+** buffer to another.
+**
+** Entry:
+** pbTopic - Pointer to compressed topic text
+** pbDest - Pointer to destination buffer
+**
+** Exit:
+** FALSE on successful completion
+**
+** Exceptions:
+** Returns TRUE on any error.
+**
+*/
+f far pascal LOADDS HelpDecomp (
+PB pbTopic,
+PB pbDest,
+nc ncContext
+) {
+fdb fdbLocal; // pointer to current FDB
+uchar far *fpszDest; // pointer to destination
+uchar far *fpTopic; // pointer to locked topic
+f fRv = TRUE; // return Value
+mh mhFdb; // handle to the fdb
+mh mhHuff;
+mh mhKey;
+
+mhFdb = ncContext.mh;
+if (LoadFdb (mhFdb, &fdbLocal)) { /* lock fdb down */
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+
+ // This funky sequence of code attempts to ensure that both the
+ // huffman and keyword decompression tables are loaded simultaneously
+ // since we cannot decompress without both.
+ //
+ // We do things three times to cover the following cases:
+ //
+ // 1) huffman loaded ok
+ // keyword loaded ok
+ // huffman already loaded
+ //
+ // 2) huffman loaded ok
+ // keyword loaded ok after HelpShrink (huffman discarded)
+ // huffman re-loaded ok (HelpShrink freed enough for both)
+ //
+ // 3) huffman loaded ok after HelpShrink
+ // keyword loaded ok after HelpShrink (huffman discarded)
+ // huffman re-loaded ok (memory fragmentation allowed it)
+ //
+ // The other cases, where either the load fails immediatly after
+ // any HelpShrink call, are the cases we cannot handle.
+ //
+ // Since handles can change due to the reallocation that can ocurr
+ // in the HelpShrink-reload sequence, we simply do the three
+ // loads, and then ensure that all the handles match what's in the
+ // fdb. If they don't, we fail.
+ //
+ mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
+ mhKey = LoadPortion (HS_KEYPHRASE,mhFdb);
+ mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
+
+ if ( LoadFdb (mhFdb, &fdbLocal)
+ && (mhKey == fdbLocal.rgmhSections[HS_KEYPHRASE])
+ && (mhHuff == fdbLocal.rgmhSections[HS_HUFFTREE])) {
+
+ char far *fpHuff;
+ char far *fpKey;
+
+ // At this point we lock EVERYTHING and ensure that we have
+ // valid pointers to it all. (Some swapped memory systems can
+ // fail at this point, so we need to be sensitive).
+ //
+ fpHuff = HelpLock (mhHuff);
+ fpKey = HelpLock (mhKey);
+ fpTopic = PBLOCK (pbTopic);
+ fpszDest = PBLOCK (pbDest);
+
+ if ( fpTopic
+ && fpszDest
+ && (fpHuff || (mhHuff == 0))
+ && (fpKey || (mhKey == 0))
+ ) {
+ decomp (fpHuff, fpKey, fpTopic, fpszDest+sizeof(topichdr));
+ fRv = FALSE;
+ }
+ }
+
+ // Unlock the handles, if they were valid.
+ //
+ if (mhKey != (mh)(-1))
+ HelpUnlock (mhKey);
+ if (mhHuff != (mh)(-1))
+ HelpUnlock (mhHuff);
+ }
+ else {
+ fpszDest = PBLOCK (pbDest);
+#if ASCII
+/*
+** ascii, just copy
+*/
+ fpTopic = PBLOCK(pbTopic);
+ if (fpTopic && fpszDest) {
+ hfstrcpy(fpszDest+sizeof(topichdr),fpTopic);
+#else
+ {
+#endif
+ fRv = FALSE;
+ }
+ }
+ if (!fRv) {
+ ((topichdr far *)fpszDest)->ftype = fdbLocal.ftype;
+ ((topichdr far *)fpszDest)->appChar = (uchar)fdbLocal.hdr.appChar;
+ ((topichdr far *)fpszDest)->linChar = (uchar)fdbLocal.hdr.appChar;
+ ((topichdr far *)fpszDest)->lnCur = 1;
+ ((topichdr far *)fpszDest)->lnOff = sizeof(topichdr);
+ }
+ PBUNLOCK (pbTopic);
+ PBUNLOCK (pbDest);
+ }
+return fRv;
+/* end HelpDecomp */}
+
+/******************************************************************************
+**
+** HelpNcNext - Return next context number
+**
+** Purpose:
+** Returns the context number corresponding to a physical "next" in the help
+** file.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcNext (
+nc ncCur
+) {
+return NextPrev(ncCur,1); /* get next */
+/* end HelpNcNext */}
+
+/******************************************************************************
+**
+** HelpNcPrev - Return phyiscally previous context
+**
+** Purpose:
+** Returns the context number corresponding to the physically previous topic.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcPrev (
+nc ncCur
+) {
+return NextPrev(ncCur,-1); /* get previous */
+/* end HelpNcPrev */}
+
+/******************************************************************************
+**
+** HelpNcUniq - Return nc guaranteed unique for a given topic
+**
+** Purpose:
+** Maps a context number to a local context number. This is provided such
+** that all context numbers which map to the same topic can be transformed
+** into the same nc which maps to that topic. The information on the
+** context string originally used is lost.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcUniq (
+nc ncCur
+) {
+fdb fdbLocal; /* pointer to current FDB */
+
+if (LoadFdb (ncCur.mh, &fdbLocal))
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+ nc ncTmp;
+
+ ncTmp.mh = fdbLocal.ncInit.mh;
+ ncTmp.cn = MapContexttoTopic(ncCur, &fdbLocal);
+ ncTmp.cn |= 0x8000;
+
+ ncCur = ncTmp;
+
+ // rjsa return MapContexttoTopic (ncCur,&fdbLocal)
+ // | (fdbLocal.ncInit & 0xffff0000)
+ // | 0x8000;
+
+ }
+return ncCur;
+/* end HelpNcUniq */}
+
+/******************************************************************************
+**
+** NextPrev - Return phyiscally next or previous context
+**
+** Purpose:
+** Returns the context number corresponding to the physically next or previous
+** topic.
+**
+** Entry:
+** ncCur = Current Context
+** fNext = 1 for next, -1 for previous.
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc pascal near NextPrev (
+ nc ncCur,
+ int fNext
+ ) {
+
+ fdb fdbLocal; /* pointer to current FDB */
+ REGISTER nc ncNext = {0,0};
+
+ if (LoadFdb (ncCur.mh, &fdbLocal)) {
+
+ //
+ // For a compressed file the next/previous physical is computed by taking the
+ // context number, mapping it to its corresponding topic number, incrementing
+ // or decrementing the topic number (remember, topic numbers are in physical
+ // order), and then mapping that back to a context number.
+ //
+ // When nexting, we also support nexting into any appended file.
+ //
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+ unsigned short cn;
+
+ cn = (ushort)(((ncCur.cn & 0x8000)
+ ? ncCur.cn & 0x7ffff
+ : MapContexttoTopic(ncCur, &fdbLocal))
+ + (ushort)fNext);
+
+ ncNext = MapTopictoContext(cn, (fdb far *)&fdbLocal, fNext);
+
+ // rjsa ncNext = MapTopictoContext((ushort)(((ncCur & 0x8000)
+ // ? ncCur & 0x7fff
+ // : MapContexttoTopic (ncCur,&fdbLocal))
+ // + fNext)
+ // ,(fdb far *)&fdbLocal);
+
+ //
+ // if we could not come up with a next, try to find a next using "local"
+ // context numbers. Map the context number to a topic number, and if that is
+ // not out of range, return it as a context.
+ //
+ if (!(ncNext.cn)) {
+
+ // rjsa if ((ncNext = MapContexttoTopic (ncCur,&fdbLocal)) == 0xffff)
+ // ncNext = 0;
+ ncNext.cn = MapContexttoTopic(ncCur, &fdbLocal);
+
+ if (ncNext.cn == 0xffff) {
+
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+
+ } else {
+
+ ncNext.cn += fNext;
+
+ if (ncNext.cn >= fdbLocal.hdr.cTopics) {
+
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+
+ } else {
+
+ // rjsa ncNext |= (fdbLocal.ncInit & 0xffff0000) | 0x8000;
+ ncNext.mh = fdbLocal.ncInit.mh;
+ ncNext.cn = 0x8000;
+ }
+ }
+ }
+
+ if (!(ncNext.cn & 0x7fff) && (fNext>0)) {
+ ncNext = fdbLocal.ncLink;
+ }
+ }
+
+#if ASCII
+
+ //
+ // minascii files:
+ // next'ing: we just sequentially search the file for the first context to
+ // come along after that pointed to by our current context number.
+ //
+ else if (fdbLocal.ftype & FTFORMATTED) {
+
+ if (fNext > 0) {
+
+ ncNext.cn = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)+4, HelpCmp);
+ if (ncNext.cn == -1L) {
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+ } else {
+ ncNext = combineNc(ncNext.cn, ncCur.mh);
+ }
+ // rjsa ncNext = (ncNext == -1L)
+ // ? 0
+ // : combineNc(ncNext,HIGH(ncCur));
+
+ } else {
+
+ nc ncTemp;
+
+ //
+ // prev'ing: start at the begining of the file, looking for the last context
+ // which is less than the current one.
+ //
+
+ ncNext = ncTemp = fdbLocal.ncInit;
+ while (NctoFo(ncTemp.cn) < NctoFo(ncCur.cn)) {
+ ncNext = ncTemp;
+ ncTemp.cn = maLocate(&fdbLocal,szNil,NctoFo(ncTemp.cn)+4, HelpCmp);
+
+ if (ncTemp.cn == -1L) {
+ ncTemp.mh = (mh)0;
+ ncTemp.cn = 0L;
+ } else {
+ ncTemp = combineNc(ncTemp.cn,fdbLocal.ncInit.mh);
+ }
+ // rjsa ncTemp = (ncTemp == -1L)
+ // ? 0
+ // : combineNc(ncTemp,HIGH(fdbLocal.ncInit));
+ }
+ }
+ }
+#endif
+ }
+ return ncNext;
+}
+
+/*************************************************************************
+**
+** HelpSzContext - Return string mapping to context number
+**
+** Purpose:
+** Construct a string, which when looked-up, will return the passed context
+** number.
+**
+** Entry:
+** pBuf = place to put the string
+** ncCur = The context number desired
+**
+** Exit:
+** True on sucess.
+**
+*/
+f pascal far LOADDS HelpSzContext (
+uchar far *pBuf,
+nc ncCur
+) {
+f fRet = FALSE; /* return value */
+ulong i;
+fdb fdbLocal; /* pointer to current FDB */
+mh mhCur; /* handle we're dealing with */
+char far *fpszContexts; /* pointer to context strings */
+
+*pBuf = 0;
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* lock fdb down */
+/*
+** Everybody starts with a filename
+*/
+ if (*fdbLocal.hdr.fname)
+ pBuf = hfstrcpy(pBuf,fdbLocal.hdr.fname);
+ else
+ pBuf = hfstrcpy(pBuf,fdbLocal.fname);
+ *(ushort far *)pBuf = '!'; /* includes null term */
+ pBuf++;
+ fRet = TRUE;
+
+ // if we've been given a local context number, see if we can synthesize
+ // a context number from which we might get a string. If we can't get
+ // one, then return just the filename.
+ //
+ if ((i = ncCur.cn) & 0x8000) { /* context # */
+ ncCur = MapTopictoContext ((ushort)(ncCur.cn & 0x7fff),&fdbLocal,0);
+ if ((i = ncCur.cn) & 0x8000) /* context # */
+ return fRet;
+ }
+/*
+** For compressed files (signified by being able to load context strings) we
+** just walk the context strings looking for string number "ncCur". Once found,
+** the returned string is just the concatenated filename, "!" and context
+** string.
+*/
+ mhCur = LoadPortion(HS_CONTEXTSTRINGS, ncCur.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpszContexts = HelpLock(mhCur))) {
+ if (i && (i <= fdbLocal.hdr.cContexts)) {
+ while (--i)
+ while (*fpszContexts++);/* point to next string */
+ hfstrcpy(pBuf,fpszContexts);/* copy over */
+ }
+ HelpUnlock (mhCur);
+ }
+ else if (fdbLocal.ftype & FTCOMPRESSED)
+ return FALSE;
+#if ASCII
+/*
+** for min ascii files, we search for the topic, and copy over the context
+** string directly from the file.
+*/
+ else if (fdbLocal.ftype & FTFORMATTED) {
+ long fpos;
+
+ if ((fpos = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)-1,HelpCmp)) != -1L) {
+ fpos = ReadHelpFile(fdbLocal.fhHelp,fpos+2,pBuf,80);
+ *(pBuf+fpos) = 0; /* ensure terminated */
+ if (pBuf = hfstrchr(pBuf,'\r'))
+ *pBuf = 0; /* terminate at CR */
+ }
+ }
+#endif
+ }
+return fRet;
+/* end HelpSzContext */}
+
+/******************************************************************************
+**
+** LoadPortion - Load a section of the help file
+**
+** Purpose:
+** If not loaded, allocates memory for and loads a section (as defined in
+** helpfile.h) of the current help file. Once loaded, or if already loaded,
+** locks it, and returns the the memory handle and pointer.
+**
+** This routine must be far, since it is an entry point for HelpMake
+**
+** Entry:
+** hsCur = Help section to be loaded.
+** mhfdb = memory handle for fdb
+**
+** Exit:
+** returns handle for memory
+**
+** Exceptions:
+** returns NULL on portion not existing, 0xffff on inability to allocate memory.
+**
+*/
+mh pascal near LoadPortion (
+int hsCur,
+mh mhfdb
+) {
+fdb fdbLocal;
+char far *fpDest = 0;
+int i;
+mh mhNew = 0; /* pointer to mh destination */
+ushort osize; /* additional prepended size */
+ushort size;
+
+if (LoadFdb (mhfdb, &fdbLocal)) {
+ if (((mhNew = fdbLocal.rgmhSections[hsCur]) == 0)
+ && fdbLocal.hdr.tbPos[hsCur]) {
+
+ for (i=hsCur+1; i<HS_count; i++)
+ if (fdbLocal.hdr.tbPos[i]) {
+ size = (ushort)(fdbLocal.hdr.tbPos[i]-fdbLocal.hdr.tbPos[hsCur]);
+ break;
+ }
+
+ osize = (hsCur == HS_KEYPHRASE) ? 1024*sizeof(PVOID) : 0;
+/*
+** Alloc the memory required. Re-read the FDB, incase intervening calls to
+** HelpShrink causes deallocs of other beasties.
+*/
+ if ( (mhNew = HelpAlloc(size + osize))
+ && LoadFdb (mhfdb, &fdbLocal)) {
+ fdbLocal.rgmhSections[hsCur] = mhNew;
+ if (PutFdb (mhfdb, &fdbLocal)) {
+ fpDest = (char far *)HelpLock(mhNew);
+ if (fpDest && ReadHelpFile(fdbLocal.fhHelp
+ ,(ulong)fdbLocal.hdr.tbPos[hsCur] + fdbLocal.foff
+ ,fpDest + osize
+ ,size)) {
+
+ if (hsCur == HS_KEYPHRASE)
+ kwPtrBuild(fpDest,size);/* build keyword pointers */
+ HelpUnlock (mhNew);
+ }
+ else {
+ fdbLocal.rgmhSections[hsCur] = 0;
+ HelpDealloc (mhNew);
+ PutFdb (mhfdb, &fdbLocal);
+ mhNew = (mh)(-1);
+ }
+ }
+ else
+ mhNew = (mh)0;
+ }
+ else
+ mhNew = (mh)(-1);
+ }
+ }
+
+return mhNew;
+
+/* end LoadPortion */}
+
+/*************************************************************************
+**
+** SizePos - Return count of bytes in compressed topic, and position
+**
+** Purpose:
+** Returns the size in bytes of the compressed topic, and it's location in the
+** help file.
+**
+** Entry:
+** ncCur - Context number to return info on.
+** psize - Pointer to place to put the size
+** ppos - Pointer to place to put the position
+**
+** Exit:
+** Returns TRUE on success.
+**
+** Exceptions:
+** Returns FALSE on all errors.
+**
+** Algorithm:
+**
+** If current help handle valid
+** If filetype is compressed
+** If context map not loaded, load it
+** Lock context map
+** Map context to topic number
+** Unlock context map
+** If topic index not loaded, load it
+** Lock topic index
+** size is difference in file positions
+** Unlock topic index
+** else if filetype is formatted ascii
+** seek to context file position
+** scan for next context definition
+** size is difference in file positions
+** else if filetype is unformatted ascii
+** size is filesize
+*/
+f pascal near SizePos (
+nc ncCur,
+ushort *psize,
+ulong *ppos
+) {
+fdb fdbLocal; /* pointer to current FDB */
+char far *fpT; /* temp pointer */
+REGISTER f fRv = FALSE; /* return value */
+ushort iTopic; /* topic index */
+mh mhCur; /* handle being locked */
+
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb copy */
+ if (fdbLocal.ftype & FTCOMPRESSED) {/* if a standard compressed file*/
+ if ((iTopic = MapContexttoTopic (ncCur,&fdbLocal)) != 0xffff) {
+ mhCur = LoadPortion(HS_INDEX,ncCur.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
+ *ppos = ((long far *)fpT)[iTopic];
+ *psize = (ushort)(((long far *)fpT)[iTopic+1] - *ppos);
+ HelpUnlock (mhCur);
+ fRv = TRUE;
+ }
+ }
+ }
+
+#if ASCII
+ else if (fdbLocal.ftype & FTFORMATTED) {/* if a formatted ascii file*/
+ if ((*psize = (ushort)(maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)+4, HelpCmp)))
+ == 0xffff)
+ *psize = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
+ else
+ *psize -= (ushort)NctoFo(ncCur.cn);
+ *ppos = (ulong) maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)-1, HelpCmp);
+ fRv = TRUE;
+ }
+ else { /* unformatted ascii */
+ *ppos = ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
+ *psize = (*ppos > (ulong)(65535-sizeof(topichdr)-4))
+ ? (ushort)(65535-sizeof(topichdr)-4)
+ : (ushort)*ppos;
+ *ppos = 0L; /* position is always zero. */
+ fRv = TRUE;
+ }
+#endif
+ }
+
+return fRv;
+/* end SizePos */}
+
+/************************************************************************
+**
+** MapContexttoTopic
+**
+** Purpose:
+** Given a context number, return the topic number which it maps to. This
+** is just a direct index of the context number into the context map.
+**
+** Entry:
+** ncCur = context number to be mapped
+** fpfdbCur = pointer to associated fdb
+**
+** Exit:
+** Returns zero based topic number, or 0xffff on error.
+*/
+ushort pascal near MapContexttoTopic (
+nc ncCur, /* context number to map */
+fdb far *fpfdbCur /* pointer to current FDB */
+) {
+REGISTER ushort topic = 0xffff; /* value to return */
+ushort far *fpT; /* pointer to context map */
+mh mhCur; /* handle being locked */
+
+if (ncCur.cn) {
+/*
+** Local contexts: the topic number is already encoded in the low word, if the
+** high bit of that word is set.
+*/
+ if (ncCur.cn & 0x8000)
+ topic = (ushort)(ncCur.cn & 0x7fff);
+/*
+** Normal Contexts: low word of nc is an index into the context map which
+** returns the topic number
+*/
+ else {
+ mhCur = LoadPortion(HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
+ topic = fpT[ncCur.cn-1];
+ HelpUnlock (mhCur);
+ }
+ }
+ }
+return topic;
+/* end MapContexttoTopic */}
+
+/************************************************************************
+**
+** MapTopictoContext
+**
+** Purpose:
+** Given a topic number, return a context which maps to it.
+**
+** This involves searching the context map for the first context entry that
+** maps to the desired topic number.
+**
+** Entry:
+** iTopic = topic number to map back to a context number
+** fpfdbCur = pointer to associated fdb
+**
+** Exit:
+** Returns a valid nc into the file.
+**
+** Exceptions:
+** If the incoming iTopic is invalid, or a read error occurs, then the nc
+** returned refers to the topic number 0.
+**
+*/
+nc pascal near MapTopictoContext(
+ushort iTopic, /* topic number to map */
+fdb far *fpfdbCur, /* pointer to current FDB */
+int Dir
+) {
+ ushort cTopics; /* number of topics to search */
+ ushort far *fpContextMap; /* pointer to the context map */
+ mh mhPortion; /* mem handle for the context map*/
+ nc ncMatch = {0,0}; /* return value */
+
+ mhPortion = LoadPortion (HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
+ if (mhPortion && (mhPortion != (mh)(-1))) {
+ if (fpContextMap = HelpLock(mhPortion)) {
+ if (iTopic >= fpfdbCur->hdr.cTopics) {
+ iTopic = 0;
+ }
+ ncMatch.mh = (mh)0L;
+ ncMatch.cn = 0x8000 | iTopic;
+ // rjsa ncMatch = 0x8000 | iTopic;
+ cTopics = 0;
+ while (cTopics < fpfdbCur->hdr.cContexts) {
+ if ( Dir == 0 ) {
+ if (iTopic == fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics; /* nc's are one based */
+ break;
+ }
+ } else if ( Dir > 0 ) {
+ if (iTopic <= fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics; /* nc's are one based */
+ break;
+ }
+
+ } else if ( Dir < 0 ) {
+
+ if (iTopic == fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics;
+ break;
+ } else if (iTopic < fpContextMap[cTopics-1]) {
+ ncMatch.cn = cTopics-1;
+ break;
+ }
+ }
+ }
+ //if ( iTopic != fpContextMap[cTopics-1] ) {
+ // ncMatch.cn = 0;
+ //}
+ if ( cTopics >= fpfdbCur->hdr.cContexts) {
+ ncMatch.cn = 0;
+ }
+ HelpUnlock (mhPortion);
+ }
+ }
+ ncMatch.mh = (fpfdbCur->ncInit).mh;
+ return ncMatch;
+ // rjsa return ncMatch | HIGHONLY(fpfdbCur->ncInit);
+}
+
+/************************************************************************
+**
+** LoadFdb - make local copy of fdb.
+**
+** Purpose:
+** Used to create a local copy of an FDB, so that we don't have to keep a
+** locked, far copy around.
+**
+** Entry:
+** mhFdb - memory handle for the FDB
+** fpFdbDest - Pointer to destination for FDB copy
+**
+** Exit:
+** returns TRUE if FDB copied.
+*/
+f pascal near LoadFdb (
+mh mhfdb,
+fdb far *fpfdbDest
+) {
+fdb far *fpfdbCur; /* pointer to current FDB */
+
+if (fpfdbCur = HelpLock (mhfdb)) {
+ *fpfdbDest = *fpfdbCur;
+ HelpUnlock (mhfdb);
+ return TRUE;
+ }
+return FALSE;
+/* end LoadFdb */}
+
+/************************************************************************
+**
+** PutFdb - make local copy of fdb permanent.
+**
+** Purpose:
+** Used to copy a local copy of an FDB to the "real" one, so that we don't
+** have to keep a locked, far copy around.
+**
+** Entry:
+** mhFdb - memory handle for the FDB
+** fpfdbSrc - Pointer to source of FDB copy
+**
+** Exit:
+** returns TRUE if FDB copied.
+*/
+f pascal near PutFdb (
+mh mhfdb,
+fdb far *fpfdbSrc
+) {
+fdb far *fpfdbCur; /* pointer to current FDB */
+
+if (fpfdbCur = HelpLock (mhfdb)) {
+ *fpfdbCur = *fpfdbSrc;
+ HelpUnlock (mhfdb);
+ return TRUE;
+ }
+return FALSE;
+/* end PutFdb */}
+
+#if ASCII
+/************************************************************************
+**
+** maLocate - Locate context in minimally formatted ascii file.
+**
+** Purpose:
+** Performs sequential searches on mimimally formatted ascii files to locate
+** lines beginning with ">>" and a context string.
+**
+** Entry:
+** fpfdbCur = Pointer to current fdb
+** fpszSrc = Pointer to context string to be found (or null for next
+** string)
+** offset = offset at which to begin search.
+** lpfnCMp = pointer to comparison routine to use
+**
+** Exit:
+** returns file offset of ">>" of context string.
+**
+** Exceptions:
+** returns -1 on error.
+**
+*/
+long pascal near maLocate (
+fdb far *fpfdbCur,
+uchar far *fpszSrc,
+ulong offset,
+f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
+) {
+uchar buffer[MASIZE+1]; /* input buffer */
+ushort cbBuf = 0; /* count of bytes in buffer */
+ushort cbSrc; /* length of source string */
+uchar far *pBuf; /* pointer into buffer */
+uchar far *pBufT; /* temp pointer into buffer */
+
+cbSrc = hfstrlen(fpszSrc)+1; /* get length of input */
+if (offset == 0xffffffff) /* special case */
+ offset = 0;
+while (cbBuf += (ushort)ReadHelpFile(fpfdbCur->fhHelp
+ , offset+cbBuf
+ , buffer+cbBuf
+ , MASIZE-cbBuf)) {
+
+ buffer[cbBuf] = 0; /* ensure strings terminated */
+ pBuf = &buffer[0];
+ while (pBuf = hfstrchr(pBuf,'>')) { /* look for start of context */
+ if ((*(pBuf+1) == '>') /* if >> found */
+ && ((*(pBuf-1) == '\n') /* at beginning of line */
+ || ((offset == 0) /* or beginning of file */
+ && (pBuf == (char far *)&buffer[0])))) {
+ pBufT = pBuf +2;
+ if (lpfnCmp (fpszSrc, pBufT, cbSrc, FALSE, TRUE))
+ return offset + (ulong)(pBuf - (uchar far *)&buffer[0]);
+ }
+ pBuf += 2;
+ }
+ if (cbBuf == MASIZE) { /* if buffer full */
+ hfstrcpy(buffer,buffer+MASIZE-MAOVER); /* copy down overlap */
+ cbBuf = MAOVER; /* and leave that in */
+ offset += MASIZE-MAOVER; /* file pos of buffer[0] */
+ }
+ else {
+ offset += cbBuf;
+ cbBuf = 0; /* else we're empty */
+ }
+ }
+return -1;
+
+/* end maLocate */}
+#endif
diff --git a/private/utils/mep/help/enginlib/helpcell.c b/private/utils/mep/help/enginlib/helpcell.c
new file mode 100644
index 000000000..cb1d64900
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpcell.c
@@ -0,0 +1,138 @@
+/*** helpcell.c - HelpGetCells routine.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* 25-Jan-1990 ln locate -> hlp_locate
+* [] 04-Aug-1988 LN Created...split from helpif.c. Added auto-fill.
+*
+*************************************************************************/
+
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h"
+#include "helpfile.h"
+#include "helpsys.h"
+
+/************************************************************************
+**
+** Foward Declarations
+*/
+uchar near pascal toupr(uchar);
+
+/************************************************************************
+**
+** HelpGetCells - Return a string of character / attribute pairs from helpfile
+**
+** Purpose:
+** Interpret the help files stored format and return a line at a time of
+** character & attribute information.
+**
+** Entry:
+** ln = 1 based line number to return
+** cbMax = Max number of characters to transfer
+** pbDst = pointer to destination
+** pbTopic = pointer to topic text
+** prgAttr = pointer to array of character attributes
+**
+** Exit:
+** returns number of bytes transfered, or -1 if that line does not exist.
+** DOES blank fill to the cbMax width.
+**
+** Exceptions:
+**
+*/
+int far pascal LOADDS HelpGetCells(ln,cbMax,pbDst,pbTopic,prgAttr)
+int ln;
+int cbMax;
+char far *pbDst;
+PB pbTopic;
+uchar far *prgAttr;
+{
+ushort cbAttr; /* length of current attribute */
+ushort cbAttrCur = 0; /* length of current attribute */
+ushort cbSrc; /* count of source characters */
+uchar cAttrCur; /* current attribute */
+uchar iAttrCur; /* index to current attribute */
+uchar far *pTopic; /* pointer to topic */
+uchar far *pchSrc; /* pointer to source characters */
+topichdr far *pHdr; /* pointer to topic header */
+
+pTopic = PBLOCK (pbTopic);
+pHdr = (topichdr far *)pTopic;
+if ((pTopic = hlp_locate(ln,pTopic)) == NULL)/* locate line */
+ ln = -1;
+
+else if (pHdr->ftype & FTCOMPRESSED) {
+ ln=0;
+ pchSrc = pTopic; /* point to character data */
+ pTopic += (*pTopic); /* point to attribute data */
+ cbAttr = *((ushort far UNALIGNED *)pTopic)++ - (ushort)sizeof(ushort);/* count of attribute bytes */
+ cbSrc = (ushort)((*pchSrc++) -1); /* get count of characters */
+
+ while (cbSrc-- && cbMax--) { /* while characters to get */
+/*
+ * Time for a new attribute. If there are attributes left (cbAttr > 0) then
+ * just get the next one (length & index). If there weren't any left, or the
+ * last one had an index of 0xff (indicating end), then we'll use the index
+ * zero attribute byte, else pick up the current attribute byte and move on
+ * in the attribute string.
+ */
+ if (cbAttrCur == 0) {
+ if (cbAttr > 0) {
+ cbAttrCur = ((intlineattr far UNALIGNED *)pTopic)->cb;
+ iAttrCur = ((intlineattr far UNALIGNED *)pTopic)->attr;
+ }
+ if ((cbAttr <= 0) || (iAttrCur == 0xff))
+ cAttrCur = prgAttr[0];
+ else {
+ cAttrCur = prgAttr[iAttrCur];
+ ((intlineattr far *)pTopic)++;
+ cbAttr -= 2;
+ }
+ }
+ *((ushort far UNALIGNED *)pbDst)++ = (ushort)((cAttrCur << 8) | *pchSrc++); /* stuff char & attr*/
+ cbAttrCur--;
+ ln += 2;
+ }
+ }
+#if ASCII
+else {
+/*
+** For ascii files, just copy line over with attr[0]
+*/
+ ln=0;
+ while (*pTopic && (*pTopic != '\r') && cbMax--) {
+ if (*pTopic == '\t') {
+ pTopic++;
+ do {
+ *((ushort far UNALIGNED *)pbDst)++ = (ushort)((prgAttr[0] << 8) | ' ');
+ ln += 2;
+ }
+ while ((ln % 16) && cbMax--);
+ }
+ else {
+ *((ushort far UNALIGNED *)pbDst)++ = (ushort)((prgAttr[0] << 8) | *pTopic++);
+ ln += 2;
+ }
+ }
+ }
+#endif
+#if 0
+/*
+ * blank fill the rest of the line
+ */
+while (cbMax--)
+ *((ushort far UNALIGNED *)pbDst)++ = (prgAttr[0] << 8) | ' '; /* stuff char & attr*/
+#endif
+PBUNLOCK (pbTopic);
+return ln;
+/* end HelpGetCells */}
diff --git a/private/utils/mep/help/enginlib/helpcnt.c b/private/utils/mep/help/enginlib/helpcnt.c
new file mode 100644
index 000000000..8e64feb6a
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpcnt.c
@@ -0,0 +1,54 @@
+/*** helpcnt.c - HelpcLines routine.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 25-Jan-1990 ln locate -> hlp_locate
+* 19-Aug-1988 ln Changed to use new locate routine.
+* [] 10-Aug-1988 LN Created
+*
+*************************************************************************/
+
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h"
+#include "helpfile.h"
+#include "helpsys.h"
+
+
+/*** HelpcLines - Return number of lines in topic
+*
+* Purpose:
+* Interpret the help files stored format and return the number of lines
+* contained therein.
+*
+* It *is* sensitive to the applications control character, again just like
+* HelpGetLine, and will return total number of lines if the header.linChar
+* is set to 0xff, or the number of lines that do NOT begin with
+* header.linChar.
+*
+* Input:
+* pbTopic = pointer to topic text
+*
+* Output:
+* Returns number of lines in topic.
+*
+*************************************************************************/
+int far pascal LOADDS HelpcLines(
+PB pbTopic
+) {
+REGISTER ushort cLines; /* count of lines */
+uchar far *pTopic; /* pointer to topic */
+
+pTopic = PBLOCK (pbTopic);
+cLines = (ushort)hlp_locate (-1,pTopic);
+PBUNLOCK (pbTopic);
+
+return cLines;
+/* end HelpcLines */}
diff --git a/private/utils/mep/help/enginlib/helpdec.c b/private/utils/mep/help/enginlib/helpdec.c
new file mode 100644
index 000000000..0f6324a52
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpdec.c
@@ -0,0 +1,722 @@
+/*************************************************************************
+ * helpdec - HelpDecomp routine and Other ASM code
+ *
+ * Copyright <C> 1988, Microsoft Corporation
+ *
+ * Purpose:
+ *
+ * Revision History:
+ *
+ * 08-Oct-1990 RJSA Converted to C
+ * 22-Dec-1988 LN Removed MASM High Level Lang support (Need
+ * to control segments better than that will
+ * let me)
+ * 08-Dec-1988 LN CSEG
+ * 16-Feb-1988 LN Rewrite for (some) speed
+ * [] 17-Jan-1988 LN Created
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+
+#include <help.h>
+#include <helpfile.h>
+
+#pragma function( memset, memcpy, memcmp, strcpy, strcmp, strcat )
+
+// In order to increase performance, and because of the functions
+// decomp and NextChar being tightly coupled, global variables are
+// used instead of passing parameters.
+//
+
+PBYTE pHuffmanRoot; // Root of Huffman Tree
+PBYTE pCompTopic; // Current pointer to text (compressed)
+BYTE BitMask; // Rotating bit mask
+BOOL IsCompressed; // True if text is compressed
+
+
+BYTE NextChar (void);
+BOOL pascal HelpCmp (PCHAR fpsz1, PCHAR fpsz2, USHORT cbCmp, BOOL fCase, BOOL fTerm);
+
+
+/**************************************************************************
+ *
+ * Decomp - Decompress Topic Text
+ * f near pascal Decomp(fpHuffmanRoot, fpKeyphrase, fpTopic, fpDest)
+ * uchar far *fpHuffmanRoot
+ * uchar far *fpKeyphrase
+ * uchar far *fpTopic
+ * uchar far *fpDest
+ *
+ * Purpose:
+ * Fully decompress topic text. Decompresses based on current file, from one
+ * buffer to another.
+ *
+ * Entry:
+ * fpHuffmanRoot - Pointer to root of huffman tree (or NULL if no huffman)
+ * fpKeyphrase - Pointer to keyphrase table (or NULL if no keyphrase)
+ * fpTopic - Pointer to compressed topic text
+ * fpDest - Pointer to destination buffer
+ *
+ * Exit:
+ * FALSE on successful completion
+ *
+ * Exceptions:
+ * Returns TRUE on any error.
+ *
+ **************************************************************************/
+BOOL pascal decomp (
+ PCHAR fpHuffmanRoot,
+ PCHAR fpKeyphrase,
+ PCHAR fpTopic,
+ PCHAR fpDest
+ ){
+
+ int cDecomp; /* count of totally decompressed */
+ BYTE c; /* byte read */
+
+#ifdef BIGDEBUG
+ char DbgB[128];
+ char *DbgP = fpDest;
+#endif
+
+
+ // Initialize global variables.
+
+ pHuffmanRoot = (PBYTE)fpHuffmanRoot;
+ pCompTopic = (PBYTE)fpTopic + sizeof(USHORT);
+ BitMask = 0x01;
+ IsCompressed = fpHuffmanRoot
+ ? ((*(USHORT UNALIGNED *)((PBYTE)fpHuffmanRoot + 2)) != 0xFFFF)
+ : FALSE;
+
+ cDecomp = *((USHORT UNALIGNED *)fpTopic);
+
+#ifdef BIGDEBUG
+ sprintf(DbgB, "DECOMPRESSING: HuffmanRoot: %lx, Keyphrase: %lx\n", fpHuffmanRoot, fpKeyphrase );
+ OutputDebugString(DbgB);
+ sprintf(DbgB, " Topic: %lx, Dest: %lx\n", fpTopic, fpDest );
+ OutputDebugString(DbgB);
+ if ( IsCompressed ) {
+ OutputDebugString(" The Topic IS Compressed\n");
+ }
+#endif
+
+ while ( cDecomp > 0 ) {
+
+ c = NextChar();
+
+ //
+ // At this point a valid character has been found and huffman decoded. We must
+ // now perform any other decoding on it that is required.
+ //
+ // Variables are:
+ // c = character
+ // cDecomp = Output count remaining
+ // BitMask = bit mask for interpreting input stream
+ //
+ // "Magic Cookie" decompression.
+ // The chararacter stream after huffman encoding is "cookie" encoded, in that
+ // certain characters are flags which when encountered mean something other than
+ // themselves. All characters which are NOT such flags (or cookies, as they seem
+ // to be called), are simply copied to the output stream.
+ //
+ // We first check the character to see if it IS a cookie. If it is NOT, we just
+ // store it, and get the next input byte
+ //
+
+ if ((c >= C_MIN) && (c <= C_MAX)) {
+
+ BYTE Cookie = c ;
+
+#ifdef BIGDEBUG
+ OutputDebugString("Cookie\n");
+#endif
+ // c is a cookie of some sort, jump to the appropriate
+ // cookie eater.
+
+ c = NextChar();
+
+ switch (Cookie) {
+ case C_KEYPHRASE0:
+ case C_KEYPHRASE1:
+ case C_KEYPHRASE2:
+ case C_KEYPHRASE3:
+ case C_KEYPHRASE_SPACE0:
+ case C_KEYPHRASE_SPACE1:
+ case C_KEYPHRASE_SPACE2:
+ case C_KEYPHRASE_SPACE3:
+ {
+ ULONG Index; /* Keyword index */
+ PBYTE pKey; /* Keyword */
+ BYTE Size; /* Keyword size */
+
+ if ((Cookie >= C_KEYPHRASE_SPACE0) && (Cookie <= C_KEYPHRASE_SPACE3)) {
+ Index = (ULONG)((int)Cookie - C_MIN - 4);
+ } else {
+ Index = (ULONG)((int)Cookie - C_MIN);
+ }
+ Index = (ULONG)(((Index * 0x100) + c) * sizeof(PVOID));
+
+ pKey = *(PBYTE *)(((PBYTE)fpKeyphrase) + Index);
+
+ // pKey = *(PBYTE *)(fpKeyphrase + Index);
+
+ Size = *pKey++;
+
+ {
+ BYTE i = Size;
+
+ while (i--) {
+ *fpDest++ = *pKey++;
+ }
+ cDecomp -=Size;
+ }
+ if ((Cookie >= C_KEYPHRASE_SPACE0) && (Cookie <= C_KEYPHRASE_SPACE3)) {
+ *fpDest++ = ' ';
+ cDecomp--;
+ }
+ break;
+ }
+
+ case C_RUNSPACE:
+ {
+ BYTE Count = c;
+
+ while (Count--) {
+ *fpDest++ = ' ';
+ }
+ cDecomp -= c;
+ break;
+ }
+
+ case C_RUN:
+ {
+ BYTE b = c;
+ BYTE Cnt;
+
+ Cnt = c = NextChar();
+
+ while (Cnt--) {
+ *fpDest++ = b;
+ }
+ cDecomp -= c;
+ break;
+ }
+
+ case C_QUOTE:
+ *fpDest++ = c;
+ cDecomp--;
+ break;
+
+ }
+
+ } else {
+
+ // c is not a cookie
+
+ *fpDest++ = c;
+ cDecomp--;
+ }
+ }
+
+ *fpDest++ = '\00'; // Null terminate string
+
+#ifdef BIGDEBUG
+ sprintf( DbgB, "Decompressed topic: [%s]\n", DbgP );
+ OutputDebugString( DbgB );
+
+ if ( cDecomp < 0 ) {
+ sprintf( DbgB, "DECOMPRESSION ERROR: cDecomp = %d!\n", cDecomp );
+ OutputDebugString(DbgB);
+ }
+#endif
+
+ return FALSE;
+}
+
+
+
+
+/**************************************************************************
+ *
+ * NextChar - Return next character from input stream
+ *
+ * Purpose:
+ * Returns next character from input stream, performing huffman decompression
+ * if enabled.
+ *
+ * Entry:
+ * fpHuffmanRoot = pointer to root of huffman tree
+ * pfpTopic = pointer to pointer to Topic
+ * pBitmask = pointer to bit mask of current bit
+ *
+ * Exit:
+ * Returns character
+ * *pfpTopic and *pBitMask updated.
+ *
+ **************************************************************************
+ *
+ * Format of Huffman decode tree:
+ * The Huffman decode tree is a binary tree used to decode a bitstream into a
+ * character stream. The tree consists of nodes (internal nodes and leaves).
+ * Each node is represented by a word. If the high bit in the word is set then
+ * the node is a leaf. If the node is an internal node, then the value of the
+ * node is the index of the right branch in the binary tree. The left branch is
+ * the node following the current node (in memory). If the node is a leaf, then
+ * the low byte of the node is a character.
+ *
+ * e.g.
+ * 0: 0004 0
+ * 1: 0003 / \
+ * 2: 8020 / \
+ * 3: 8065 1 \------4
+ * 4: 0006 / \ / \
+ * 5: 806C / \ / \
+ * 6: 8040 2 3 5 6
+ * ' ' 'e' 'l' '@'
+ *
+ * Using the Huffman decode tree:
+ * The huffman decode tree is used to decode a bitstream into a character
+ * string. The bitstream is used to traverse the decode tree. Whenever a zero
+ * is detected in the bit stream we take the right branch, when one is detected
+ * we take the left branch. When a leaf is reached in the tree, the value of
+ * the leaf (a character) is output, and the current node is set back to the
+ *
+ ********************************************************************/
+
+BYTE
+NextChar (
+ void
+ ) {
+
+ BYTE b; // current source byte
+
+#ifdef BIGDEBUG
+ char DbgB[128];
+ OutputDebugString("NextChar:\n");
+#endif
+
+ if (IsCompressed) {
+
+ USHORT HuffmanNode; // curent node in the huffman tree
+ USHORT UNALIGNED *pHuffmanNext; // next node in the huffman tree
+
+ //
+ // Huffman decoding.
+ // This first part of the decode loop performs the actual huffman decode. This
+ // code is very speed critical. We walk the tree, as defined by the bit pattern
+ // coming in, and exit this portion of the code when we reach a leaf which
+ // contains the character that the bit pattern represented.
+ //
+
+ pHuffmanNext = (USHORT UNALIGNED *)pHuffmanRoot;
+ HuffmanNode = *pHuffmanNext;
+
+ b = *(pCompTopic - 1); // get last byte read
+
+ while (!(HuffmanNode & 0x8000)) { // while not leaf
+
+ BitMask >>= 1;
+
+ if (!(BitMask)) {
+ //
+ // Get new byte from input
+ //
+ b = *pCompTopic++;
+ BitMask = 0x80;
+#ifdef BIGDEBUG
+ sprintf(DbgB, "\tb=%02x Mask=%02x Node=%04x", b, BitMask, HuffmanNode );
+ OutputDebugString(DbgB);
+#endif
+ } else {
+#ifdef BIGDEBUG
+ sprintf(DbgB, "\tb=%02x Mask=%02x Node=%04x", b, BitMask, HuffmanNode );
+ OutputDebugString(DbgB);
+#endif
+ }
+
+ if (b & BitMask) {
+ //
+ // one: take left branch
+ //
+ pHuffmanNext++;
+ } else {
+ //
+ // zero: take right branch
+ //
+ pHuffmanNext = (PUSHORT)((PBYTE)pHuffmanRoot + HuffmanNode);
+#ifdef BIGDEBUG
+ sprintf(DbgB, " <%04x+%02x=%04x (%04x)>", pHuffmanRoot, HuffmanNode,
+ pHuffmanNext, *pHuffmanNext );
+ OutputDebugString( DbgB );
+#endif
+ }
+
+ HuffmanNode = *pHuffmanNext;
+
+#ifdef BIGDEBUG
+ sprintf(DbgB, " Next=%04x\n", HuffmanNode );
+ OutputDebugString(DbgB);
+#endif
+
+ }
+
+ b = (BYTE)HuffmanNode; // character is low byte of leaf node
+
+ } else {
+ b = *pCompTopic++; // not compressed, simply return byte
+ }
+
+#ifdef BIGDEBUG
+ sprintf(DbgB, "\t---->%2x [%c]\n", b,b);
+ OutputDebugString(DbgB);
+#endif
+
+ return b;
+}
+
+
+/**************************************************************************
+ *
+ * HelpCmpSz - help system string comparison routine.
+ * f near pascal HelpCmpSz (fpsz1, fpsz2)
+ * uchar far *fpsz1*
+ * uchar far *fpsz2*
+ *
+ * Purpose:
+ * Perform string comparisons for help system look-up.
+ * Default case of HelpCmp below.
+ *
+ * Entry:
+ * fpsz1 = Far pointer to string 1. (Usually the constant string
+ * being "looked-up".
+ * fpsz2 = Far pointer to string 2. This is usually the string table
+ * being searched.
+ *
+ * Exit:
+ * TRUE on match
+ *
+ ********************************************************************/
+BOOL pascal
+HelpCmpSz (
+ PCHAR fpsz1,
+ PCHAR fpsz2
+ ){
+ return HelpCmp(fpsz1, fpsz2, (USHORT)0xFFFF, TRUE, FALSE); // fcase, fTerm
+}
+
+
+/**************************************************************************
+ *
+ * HelpCmp - help system string comparison routine.
+ * f near pascal HelpCmp (fpsz1, fpsz2, cbCmp, fCase, fTerm)
+ * uchar far *fpsz1
+ * uchar far *fpsz2
+ * ushort cbCmp
+ * f fCase
+ * f fTerm
+ *
+ * Purpose:
+ * Perform string comparisons for help system look-up.
+ *
+ * Entry:
+ * fpsz1 = Far pointer to string 1. (Usually the constant string being
+ * "looked-up"). NOTE THAT IF THIS STRING IS NULL, WE RETURN
+ * TRUE!
+ * fpsz2 = Far pointer to string 2. This is usually the string table
+ * being searched.
+ * cbCmp = Max number of bytes to compare.
+ * fCase = TRUE if search is to be case sensitive.
+ * fTerm = TRUE if we allow special termination processing.
+ *
+ * Exit:
+ * TRUE on match
+ *
+ ********************************************************************/
+
+BOOL pascal
+HelpCmp (
+ PCHAR fpsz1,
+ PCHAR fpsz2,
+ USHORT cbCmp,
+ BOOL fCase,
+ BOOL fTerm
+ ){
+
+ register PBYTE p1 = (PBYTE)fpsz1;
+ register PBYTE p2 = (PBYTE)fpsz2;
+
+ while (cbCmp--) {
+
+ if ((!*p1) && (!*p2)) {
+ //
+ // Got a match
+ //
+ return TRUE;
+ }
+
+ if (!fCase) {
+ if (toupper((char)*p1) != toupper((char)*p2)) {
+ break;
+ }
+ p1++;
+ p2++;
+ } else {
+ if (*p1++ != *p2++) {
+ break;
+ }
+ }
+ }
+
+ if (!cbCmp) {
+ return TRUE;
+ }
+
+
+ // At this point, we have terminated the comparison. Termination conditions
+ // were:
+ //
+ // character count exausted: CX == zero. (Complete match, return TRUE)
+ // Null terminator found: CX != zero, & Zero flag set. (Complete match,
+ // return TRUE)
+ // non-match found CX != zero, & Zero flag clear.
+ //
+ // In the later case, if special termination processing is NOT selected, we
+ // return FALSE, having found a mis-match.
+ //
+ // If special termination processing is TRUE, then if the mismatched character
+ // from string 1 is a null, and the mismatched character from string 2 is any
+ // whitespace or CR, we declare a match. (This is used in minascii processing).
+ //
+
+ if (fTerm) {
+ p1--; p2--;
+ if ((! *p1) &&
+ ((*p2 == '\n') || (*p2 == '\t') || (*p2 == ' '))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*************************************************************************
+ *
+ * hfstrlen - far string length
+ *
+ * Purpose:
+ * return length of null terminated string.
+ *
+ * Entry:
+ * fpszSrc = pointer to source
+ *
+ * Exit:
+ * returns length
+ *
+ *************************************************************************/
+USHORT
+hfstrlen (
+ PCHAR fpszSrc
+ ){
+ return (USHORT)strlen(fpszSrc);
+}
+
+
+/*************************************************************************
+ *
+ * hfstrcpy - far string copy
+ *
+ * Purpose:
+ * copy strings
+ *
+ * Entry:
+ * fpszDst = pointer to destination
+ * fpszSrc = pointer to source
+ *
+ * Exit:
+ * pointer to terminating null in destination
+ *
+ *************************************************************************/
+PCHAR
+hfstrcpy (
+ PCHAR fpszDst,
+ PCHAR fpszSrc
+ ) {
+ return (PCHAR)strcpy(fpszDst, fpszSrc);
+}
+
+
+
+/*************************************************************************
+ *
+ * hfstrchr - search for character in far string
+ *
+ * Purpose:
+ * a near, pascal routine (for size/speed) to search for a character in
+ * a far string.
+ *
+ * Entry:
+ * fpsz = far pointer to string
+ * c = character to locate
+ *
+ * Exit:
+ * returns far pointer into string
+ *
+ * Exceptions:
+ * returns NULL on character not in string
+ *
+ *************************************************************************/
+PCHAR
+hfstrchr (
+ PCHAR fpsz,
+ char c
+ ){
+ return (PCHAR)strchr(fpsz, c);
+}
+
+
+
+/*************************************************************************
+ *
+ * hfmemzer - zero out memory area.
+ *
+ * Purpose:
+ * a near, pascal routine (for size/speed) to fill an area with zero
+ *
+ * Entry:
+ * fpb = far pointer to buffer
+ * cb = count of zeros to store
+ *
+ * Exit:
+ *
+ *************************************************************************/
+void
+hfmemzer (
+ PVOID fpb,
+ ULONG cb
+ ) {
+ memset(fpb, '\00', cb);
+}
+
+
+
+
+/*************************************************************************
+ *
+ * NctoFo - extract file offset from NC
+ *
+ * Purpose:
+ * Extracts the file offset for a minascii file, and returns it as a long.
+ *
+ * Entry:
+ * nc = context number
+ *
+ * Exit:
+ * returns file offset
+ *
+ *************************************************************************/
+ULONG
+NctoFo (
+ ULONG nc
+ ) {
+ nc = nc & 0x0000FFFF;
+ nc *= 4;
+ return nc;
+}
+
+
+
+/*************************************************************************
+ *
+ * combineNc - combine a minascii file offset and fdb handle into nc.
+ *
+ * Purpose:
+ * Combines a minascii file offset and fdb memory handle into an NC. If the
+ * file offset is 0xffffffff, we return zero.
+ *
+ * Entry:
+ * offset = long file offset
+ * mh = fdb mem handle
+ *
+ * Exit:
+ * returns NC (DX = mem handle, AX = filepos/4), or 0L if offset==FFFFFFFF
+ *
+ *************************************************************************/
+nc pascal
+combineNc (
+ ULONG offset,
+ mh mh
+ ){
+ nc ncRet = {0,0};
+ if (offset = 0xFFFFFFFF) {
+ return ncRet;
+ }
+ ncRet.mh = mh;
+ ncRet.cn = offset/4;
+ return ncRet;
+}
+
+
+/*************************************************************************
+ *
+ * toupr - convert char to upper case
+ *
+ * Purpose:
+ *
+ * Entry:
+ * chr = character
+ *
+ * Exit:
+ * returns upper case character
+ *
+ *************************************************************************/
+char
+toupr (
+ char chr
+ ){
+ return (char)toupper(chr);
+}
+
+
+
+/*************************************************************************
+ *kwPtrBuild - Build table of pointers to keywords.
+ *void pascal near kwPtrBuild(uchar far *fpTable, ushort tsize)
+ *
+ *Purpose:
+ * Builds a table of pointers to the keyword strings in the passed string array.
+ * The table is built in the first 4k of the passed buffer. The strings are
+ * assummed to start immediately thereafter.
+ *
+ *Entry:
+ * fpTable - pointer to string table
+ * tsize - size, in bytes, of strings
+ *
+ *Exit:
+ * none
+ *
+ *******************************************************************************/
+void
+kwPtrBuild (
+ PVOID fpTable,
+ USHORT tsize
+ ) {
+ PBYTE fpStr = (PBYTE)fpTable + 1024 * sizeof (PVOID);
+ PBYTE *fpTbl = fpTable;
+ while (tsize > 0) {
+ UCHAR sSize = (UCHAR)(*fpStr) + (UCHAR)1;
+ *fpTbl++ = fpStr;
+ tsize -= sSize;
+ fpStr += sSize;
+ }
+}
diff --git a/private/utils/mep/help/enginlib/helpdll.c b/private/utils/mep/help/enginlib/helpdll.c
new file mode 100644
index 000000000..4f9a28754
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpdll.c
@@ -0,0 +1,190 @@
+/*************************************************************************
+**
+** helpdll - stubs for call-back routines when used as dll.
+**
+** Copyright <C> 1987, Microsoft Corporation
+**
+** Purpose:
+**
+** Revision History:
+**
+** 12-Mar-1990 ln CloseFile -> HelpCloseFile
+** [] 22-Jan-1988 LN Created
+**
+*************************************************************************/
+
+#include <stdio.h>
+#include <malloc.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+
+#ifdef OS2
+int _acrtused; /* define to disable crt0 */
+#endif
+
+char far * pascal near hfstrchr(char far *, char);
+
+/************************************************************************
+ *
+ * OpenFileOnPath - Open a file located somewhere on the PATH
+ *
+ * Purpose:
+ *
+ * Entry:
+ * pszName - far pointer to filename to open
+ * mode - read/write mode
+ *
+ * Exit:
+ * returns file handle
+ *
+ * Exceptions:
+ * return 0 on error.
+ *
+ */
+FILE *
+pascal
+far
+OpenFileOnPath(
+ char far *pszName,
+ int mode
+ )
+{
+ FILE *fh;
+ char szNameFull[260];
+ char szNameFull1[260];
+
+ fh = (FILE *)pathopen(pszName, szNameFull, "rb");
+
+ if (!fh) {
+
+ char *pszPath;
+ char *pT;
+
+ if (*pszName == '$') {
+ if (pT = hfstrchr(pszName,':')) { /* if properly terminated */
+ *pT = 0; /* terminate env variable */
+ pszPath = pszName+1; /* get path name */
+ pszName = pT+1; /* and point to filename part */
+ }
+ } else {
+ pszPath = "PATH";
+ }
+ sprintf(szNameFull, "$%s:%s", pszPath, pszName);
+ fh = (FILE *)pathopen(szNameFull, szNameFull1, "rb");
+
+ }
+
+ return fh;
+}
+
+
+
+/************************************************************************
+ *
+ * HelpCloseFile - Close a file
+ *
+ * Purpose:
+ *
+ * Entry:
+ * fh = file handle
+ *
+ * Exit:
+ * none
+ *
+ */
+void
+pascal
+far
+HelpCloseFile(
+ FILE* fh
+ )
+{
+ fclose(fh);
+}
+
+
+
+
+/************************************************************************
+ *
+ * ReadHelpFile - locate and read data from help file
+ *
+ * Purpose:
+ * reads cb bytes from the file fh, at file position fpos, placing them in
+ * pdest. Special case of pdest==0, returns file size of fh.
+ *
+ * Entry:
+ * fh = File handle
+ * fpos = position to seek to first
+ * pdest = location to place it
+ * cb = count of bytes to read
+ *
+ * Exit:
+ * returns length of data read
+ *
+ * Exceptions:
+ * returns 0 on errors.
+ *
+ */
+unsigned long
+pascal
+far
+ReadHelpFile (
+ FILE *fh,
+ unsigned long fpos,
+ char far *pdest,
+ unsigned short cb
+ )
+{
+ unsigned long cRet = 0;
+
+
+ if (pdest) {
+ //
+ // Read cb bytes
+ //
+ if (!fseek(fh, fpos, SEEK_SET)) {
+ cRet = fread(pdest, 1, cb, fh);
+ }
+
+ } else {
+ //
+ // Return size of file (yuck!)
+ //
+ fseek(fh, 0, SEEK_END);
+ fgetpos(fh, (fpos_t *) &cRet);
+ }
+
+ return cRet;
+}
+
+
+
+
+/************************************************************************
+**
+** HelpAlloc - Allocate a segment of memory for help
+**
+** Purpose:
+**
+** Entry:
+** size = size of memory segment desired
+**
+** Exit:
+** returns handle on success
+**
+** Exceptions:
+** returns NULL on failure
+*/
+mh pascal far HelpAlloc(ushort size)
+{
+ return (mh)malloc(size);
+/* end HelpAlloc */}
diff --git a/private/utils/mep/help/enginlib/helpif.c b/private/utils/mep/help/enginlib/helpif.c
new file mode 100644
index 000000000..9f04366dc
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpif.c
@@ -0,0 +1,308 @@
+/*** helpif.c - help routines for user interface assistance.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+* These routines aid in the interpretation of help text by applications.
+* After decompression, the help text is encoded into a line oriented format
+* which includes text, highlighting and cross reference information.
+*
+* Each line of text is formatted in the database as:
+*
+* +--------+----------------+--------+---------------+------+---------------+
+* | cbText | - Ascii Text - | cbAttr | - Attr info - | 0xff | - Xref Info - |
+* +--------+----------------+--------+---------------+------+---------------+
+*
+* Where:
+*
+* cbText - a BYTE which contains the length of the ascii text plus
+* one (for itself).
+* Ascii Text - Just that, the ascii text to be displayed
+* cbAttr - a WORD which contains the length of the attribute
+* information *plus* the cross reference information.
+* Attr info - attribute/length pairs of highlighting information plus
+* two (for itself).
+* 0xff - Attr info terminator byte (present ONLY IF Xref
+* information follows)
+* Xref Info - Cross Referencing information.
+*
+* Notes:
+* If the LAST attributes on a line are "plain", then the attribute/length
+* pair is omitted, and the rest of the line is assumed plain.
+*
+* Given a pointer to a line, a pointer to the next line is:
+*
+* Pointer + cbText + cbAttr
+*
+* A line which has no cross-reference or highlighting will have a cbAttr of
+* 2, and nothing else.
+*
+* Revision History:
+*
+* 25-Jan-1990 ln locate -> hlp_locate
+* 19-Aug-1988 ln Move "locate" to assembly language hloc.asm
+* [] 26-Jan-1988 LN Created
+*
+*************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h"
+#include "helpfile.h"
+#include "helpsys.h"
+
+/************************************************************************
+**
+** Foward Declarations
+*/
+uchar near pascal toupr(uchar);
+
+/*** HelpGetLineAttr - Return attributes associated with a line of ascii text
+*
+* Interprets the help files stored format and return a line at a time of
+* attribute information.
+*
+* Input:
+* ln = 1 based line number to return
+* cbMax = Max number of bytes to transfer
+* pbDst = pointer to destination
+* pbTopic = PB pointer to topic text
+*
+* Output:
+* Returns number of characters transfered (not including terminating 0xffff
+* attribute), or 0 if that line does not exist.
+*
+*************************************************************************/
+ushort far pascal LOADDS HelpGetLineAttr(
+ushort ln,
+int cbMax,
+lineattr far *pbDst,
+PB pbTopic
+) {
+lineattr far *pbDstBegin;
+uchar far *pTopic;
+/*
+** Form valid (locked) pointer to topic text & working pointer to detination
+*/
+pTopic = PBLOCK (pbTopic);
+pbDstBegin = pbDst;
+/*
+** Information is on present in compressed files. Locate the line in the text,
+** and then point at the attribute information therein.
+*/
+#if ASCII
+if (((topichdr far *)pTopic)->ftype & FTCOMPRESSED) {
+#endif
+ if (pTopic = hlp_locate(ln,pTopic)) {
+ pTopic += *pTopic;
+/*
+** Start by giving ln the count of encoded bytes. Then while there are
+** bytes, and we have enough room in the destination, AND we haven't reached
+** the end of the attribute information, then for each cb/attr pair, copy
+** them over, converting from our internal byte-per format to the external
+** word-per format.
+*/
+ ln = *((ushort far UNALIGNED *)pTopic)++ - (ushort)2;
+ while ( ln
+ && (cbMax >= sizeof(lineattr))
+ && (((intlineattr far *)pTopic)->attr != (uchar)0xff)
+ ) {
+ *(ushort UNALIGNED *)&(pbDst->cb) = ((intlineattr far UNALIGNED *)pTopic)->cb;
+ *(ushort UNALIGNED *)&(pbDst->attr) = ((intlineattr far UNALIGNED *)pTopic)->attr;
+ pbDst++;
+ ((intlineattr *)pTopic)++;
+ cbMax -= sizeof(lineattr);
+ ln -= sizeof(intlineattr);
+ }
+ }
+#if ASCII
+ }
+#endif
+PBUNLOCK (pbTopic);
+/*
+** Finally, if there is room in the destination buffer, terminate the
+** attributes with "default attributes to the end of line", and then
+** attribute ffff, signalling the end of the buffer.
+*/
+if (cbMax >= sizeof(lineattr)) {
+ pbDst->cb = 0xffff;
+ pbDst->attr = 0;
+ cbMax -= sizeof(lineattr);
+ pbDst++;
+ }
+if (cbMax >= sizeof(pbDst->attr))
+ pbDst->attr = 0xffff;
+/*
+** return the number of bytes transferred, not including the terminating
+** word.
+*/
+return (ushort)((uchar far *)pbDst - (uchar far *)pbDstBegin);
+
+/* end HelpGetLineAttr */}
+
+/************************************************************************
+**
+** HelpHlNext - Locate next cross reference
+**
+** Purpose:
+** Locates the next cross reference in the help topic. Locates either the
+** next physical cross reference, or the next referece beginning with a
+** particular character (case insensitive!). Locates either forward or
+** backward.
+**
+** Entry:
+** cLead = leading character, or flag, indicating direction and type
+** of search. May be:
+** NULL: Get next sequential cross reference
+** -1: Get previous sequential cross reference
+** char: Get next cross reference beginning with 'char'
+** -char: Get previous cross reference beginning with
+** 'char'
+** pbTopic = pointer to topic text.
+** photspot = pointer to hotspot structure to recive info. (line and col
+** indicate starting point)
+**
+** Exit:
+** returns TRUE if cross reference found, hotspot structure updated.
+**
+** Exceptions:
+** returns 0 if no such cross reference.
+*/
+f pascal far LOADDS HelpHlNext(cLead,pbTopic, photspot)
+int cLead;
+PB pbTopic;
+hotspot far *photspot;
+{
+ushort cbAttr;
+ushort col;
+ushort ln;
+uchar far *pbEnd; /* pointer to next line */
+uchar far *pbLineCur; /* pointer to current line */
+uchar far *pbFound = 0; /* found entry, perhaps */
+uchar far *pText;
+uchar far *pTopic;
+
+pTopic = PBLOCK (pbTopic);
+col = photspot->col; /* save these */
+ln = photspot->line;
+if (((topichdr far *)pTopic)->ftype & FTCOMPRESSED) {
+ while (1) {
+ if (ln == 0) break; /* if not found, ret */
+ pbLineCur = hlp_locate(ln,pTopic); /* find line */
+ if (pbLineCur == 0) break; /* if not found, ret */
+ pText = pbLineCur; /* point at topic text */
+ pbLineCur += *pbLineCur; /* skip the topic text */
+ cbAttr = *((ushort far UNALIGNED *)pbLineCur)++ - (ushort)sizeof(ushort);
+ pbEnd = pbLineCur + cbAttr; /* next line */
+ while (cbAttr && (((intlineattr far UNALIGNED *)pbLineCur)->attr != 0xff)) {
+ pbLineCur += sizeof(intlineattr);
+ cbAttr -=sizeof(intlineattr);
+ }
+ if (cbAttr)
+ pbLineCur += sizeof(uchar); /* skip (0xff) attr */
+
+ while (pbLineCur < pbEnd) { /* scan rest for data */
+/*
+** in a forward scan, the first cross reference (with appropriate char) that is
+** greater than our current position, is the correct one.
+*/
+ if (cLead >= 0) { /* forward scan */
+ if (col <= *(pbLineCur+1)) /* if found */
+ if ((cLead == 0) /* and criteria met */
+ || (toupr(*(pText + *pbLineCur)) == (uchar)cLead)) {
+ pbFound = pbLineCur;
+ break;
+ }
+ }
+/*
+** in a backward scan, we accept the LAST item we find which is less than
+** the current position.
+*/
+ else {
+ if (col > *(pbLineCur)) /* if a candidate found */
+ if ((cLead == -1) /* and criteria met */
+ || (toupr(*(pText + *pbLineCur)) == (uchar)-cLead))
+ pbFound = pbLineCur;/* remember it */
+ }
+ pbLineCur += 2; /* skip column spec */
+ if (*pbLineCur)
+ while (*pbLineCur++); /* skip string */
+ else
+ pbLineCur += 3;
+ }
+
+ if (pbFound) { /* if we found one */
+ *(ushort UNALIGNED *)&(photspot->line) = ln;
+ *(ushort UNALIGNED *)&(photspot->col) = (ushort)*pbFound++;
+ *(ushort UNALIGNED *)&(photspot->ecol) = (ushort)*pbFound++;
+ *(uchar *UNALIGNED *)&(photspot->pXref) = pbFound;
+ PBUNLOCK (pbTopic);
+ return TRUE;
+ }
+/*
+** move on to next line.
+*/
+ if (cLead >= 0) {
+ ln++;
+ col = 0;
+ }
+ else {
+ ln--;
+ col = 127;
+ }
+ }
+ }
+
+PBUNLOCK (pbTopic);
+return FALSE;
+/* end HelpHlNext */}
+
+/************************************************************************
+**
+** HelpXRef - Return pointer to Xref String
+**
+** Purpose:
+** Given a row, column (in a hotspot structure) and topic, return a pointer
+** to a cross reference string.
+**
+** Entry:
+** pbTopic = Pointer to topic text
+** photspot = Pointer to hotspot structure to update
+**
+** Exit:
+** returns far pointer into topic text of cross reference string & updates
+** hotspot structure.
+**
+** Exceptions:
+** returns NULL if no cross reference for that line.
+**
+*/
+char far * pascal far LOADDS HelpXRef(pbTopic, photspot)
+PB pbTopic;
+hotspot far *photspot;
+{
+uchar far *pTopic;
+ushort col; /* column requested */
+ushort ln; /* line requested */
+
+pTopic = PBLOCK (pbTopic);
+col = photspot->col; /* save these */
+ln = photspot->line;
+if (((topichdr far *)pTopic)->ftype & FTCOMPRESSED)
+ if (HelpHlNext(0,pbTopic,photspot)) /* if xref found */
+ if ( (photspot->line == ln) /* & our req. in range */
+ && ( (col >= photspot->col)
+ && (col <= photspot->ecol))) {
+ PBUNLOCK (pbTopic);
+ return photspot->pXref; /* return ptr */
+ }
+
+PBUNLOCK (pbTopic);
+return 0;
+
+/* end HelpXRef */}
diff --git a/private/utils/mep/help/enginlib/hinfo.c b/private/utils/mep/help/enginlib/hinfo.c
new file mode 100644
index 000000000..c34fa9376
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hinfo.c
@@ -0,0 +1,57 @@
+/*** hinfo.c - helpgetinfo support
+*
+* Copyright <C> 1989, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* [] 09-Mar-1989 LN Created
+*
+*************************************************************************/
+
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+/*
+** external definitions
+*/
+f pascal near LoadFdb (mh, fdb far *);
+
+/*** HelpGetInfo - Return public info to caller
+*
+* Returns a data structure to the caller which allows him into some of
+* our internal data.
+*
+* Input:
+* ncInfo = nc requesting info on
+* fpDest = pointer to location to place into
+* cbDest = size of destination
+*
+* Output:
+* Returns NULL on success, count of bytes required if cbDest too small,
+* or -1 on any other error
+*
+*************************************************************************/
+int far pascal LOADDS HelpGetInfo (
+nc ncInfo,
+helpinfo far *fpDest,
+int cbDest
+) {
+if (cbDest < sizeof (helpinfo))
+ return sizeof (helpinfo);
+if (LoadFdb (ncInfo.mh, &(fpDest->fileinfo))) {
+ fpDest->filename[0] = 0;
+ return 0;
+ }
+return -1;
+
+/* end HelpGetInfo */}
diff --git a/private/utils/mep/help/enginlib/hline.c b/private/utils/mep/help/enginlib/hline.c
new file mode 100644
index 000000000..a9376f361
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hline.c
@@ -0,0 +1,139 @@
+/**************************************************************************
+ *HelpGetLine - Return a line of ascii text
+ *
+ * Copyright <C> 1988, Microsoft Corporation
+ *
+ * Revision History:
+ *
+ * 25-Jan-1990 ln LOCATE -> HLP_LOCATE
+ * 22-Feb-1989 ln Check correctly for end of topic while copying
+ * line.
+ * 22-Dec-1988 LN Removed MASM High Level Lang support (Need
+ * to control segments better than that will
+ * let me)
+ * 08-Dec-1988 LN CSEG
+ * 11-Nov-1988 ln Adjust cbMax on entry
+ * 03-Nov-1988 ln Added GQ sensitivity
+ * [] 22-Sep-1988 LN Created
+ *
+ * Notes:
+ *
+ * Sensitive to the following switches:
+ *
+ * HOFFSET - If defined, handle/offset version
+ * OS2 - If defined, OS/2 protect mode version
+ * DSLOAD - If defined, causes DS to be reloaded, if needed
+ * ASCII - If TRUE, includes ASCII support code
+ * GQ - If defined, INC BP before saving & DEC before restore
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <help.h>
+#include <helpfile.h>
+#include <helpsys.h>
+
+
+
+/**** HelpGetLine - Return a line of ascii text
+ *
+ * Interpret the help files stored format and return a line at a time of
+ * ascii text.
+ *
+ * ushort far pascal LOADDS HelpGetLine (
+ * ushort ln, = 1 based line number to return
+ * ushort cbMax, = Max number of bytes to transfer
+ * uchar far *pszDst, = pointer to destination
+ * PB pbTopic = PB pointer to topic text
+ *
+ * Output:
+ * Returns number of characters transfered, or 0 if that line does not exist.
+ *
+ *************************************************************************/
+USHORT pascal
+HelpGetLine (
+ USHORT ln,
+ USHORT cbMax,
+ PUCHAR pszDst,
+ PB pbTopic
+ ) {
+
+ struct topichdr *pT;
+ USHORT cbTransfered = 0;
+ PUCHAR pszDstOrg = pszDst;
+
+ cbMax--; //adjust to account for terminating zero
+
+ pT = PBLOCK(pbTopic);
+
+ if (pT) {
+
+ PCHAR pLine = hlp_locate(ln, (PCHAR)pT);
+
+ if (pLine) {
+
+ *pszDst = ' ';
+ *(pszDst +1) = '\00'; // initialize dest.
+
+
+ if (pT->ftype & FTCOMPRESSED) {
+
+ // For compressed files, get the length of the line from the
+ // first byte, and of course skip that byte. Form the
+ // maximum byte count ot be transfered as the lesser of the
+ // actual length of the line or caller cbMax.
+
+ USHORT Len = (USHORT)*pLine++ - 1;
+
+ if (Len) {
+ ULONG LongLen;
+ Len = (Len > cbMax) ? cbMax : Len;
+
+ LongLen = Len/sizeof(ULONG);
+ Len = (USHORT)(Len % sizeof(ULONG));
+
+
+ while (LongLen--) {
+ *((ULONG *UNALIGNED)pszDst)++ = *((ULONG UNALIGNED *)pLine)++;
+ }
+ while (Len--) {
+ *pszDst++ = *pLine++;
+ }
+ *pszDst++ = '\00'; // Null terminate it
+ cbTransfered = (USHORT)(pszDst - pszDstOrg);
+ } else {
+ cbTransfered = 2;
+ }
+
+ } else {
+
+ // For non-compressed files, copy one line
+
+ PCHAR pSrc = pLine;
+ CHAR c = *pLine;
+
+ if (c == '\n') {
+ cbTransfered = 2;
+ } else {
+ while (c != '\00' && c != '\n') {
+ c = *pszDst++ = *pLine++;
+ }
+ *(pszDst-1) = '\00'; // null terminate it
+
+ cbTransfered = (USHORT)(pszDst - pszDstOrg);
+ }
+ }
+ }
+
+ PBUNLOCK(pbTopic);
+ }
+
+ return cbTransfered;
+}
diff --git a/private/utils/mep/help/enginlib/hloc.c b/private/utils/mep/help/enginlib/hloc.c
new file mode 100644
index 000000000..273303a67
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hloc.c
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *hlp_locate - locate line in help text
+ *
+ * Copyright <C> 1988, Microsoft Corporation
+ *
+ * Purpose:
+ *
+ * Revision History:
+ *
+ * 17-OCt-1990 RJSA translated to C
+ * 25-Jan-1990 LN renamed to hlp_locate
+ * 22-Dec-1988 LN Removed MASM High Level Lang support (Need
+ * to control segments better than that will
+ * let me)
+ * 08-Dec-1988 LN CSEG
+ * [] 18-Aug-1988 LN Created
+ *
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <help.h>
+#include <helpfile.h>
+#include <helpsys.h>
+
+
+
+/**** hlp_locate - locate a line in the buffer
+ * uchar far * near pascal hlp_locate(
+ * ushort ln,
+ * uchar far *pTopic
+ * )
+ *
+ * Purpose:
+ * commonly used routine to find a line in the topic text.
+ *
+ * Entry:
+ * ln = 1 based line number to look for (-1 means return number
+ * of lines in topic)
+ * pTopic = Topic text to look for it in
+ *
+ * Exit:
+ * returns pointer to start of line
+ *
+ * Exceptions:
+ * returns NULL on not found
+ *
+ **************************************************************************/
+
+PCHAR pascal
+hlp_locate (
+ SHORT ln,
+ PCHAR pTopic
+ ){
+
+ struct topichdr UNALIGNED *pT = (struct topichdr *)pTopic;
+ PBYTE pSrc = (PBYTE)pTopic;
+ SHORT lnOrig = ln;
+
+ if (pT->lnCur <= (USHORT)ln) {
+
+ // Use last past position calculated
+
+ ln -= (pT->lnCur );
+ pSrc += pT->lnOff;
+
+ } else {
+
+ // Start from beginning
+
+ pSrc += sizeof(struct topichdr);
+ }
+
+ if (pT->ftype & FTCOMPRESSED) {
+
+ // Compressed file. Walk over each text\attribute pair
+ // until the desired line is found.
+
+ while ( *pSrc && ln) {
+
+ pSrc += *pSrc;
+ pSrc += *(USHORT UNALIGNED *)pSrc;
+
+ if ( *pSrc && *(pSrc+1) != pT->linChar ) {
+ ln--;
+ }
+ }
+
+ //while (*pSrc && ln) {
+ //
+ // if (*(pSrc + 1) != pT->linChar) {
+ // ln--;
+ // }
+ // pSrc += *pSrc;
+ // pSrc += *(PUSHORT)pSrc;
+ //}
+
+ } else {
+
+ // ASCII file
+
+ while (*pSrc && ln) {
+ if (*pSrc != pT->linChar) {
+ ln--;
+ }
+
+ while (*pSrc && *pSrc != 0x0A) {
+ pSrc++;
+ }
+ if (*pSrc)
+ pSrc++;
+ }
+ }
+
+ if (*pSrc) {
+
+ // Line found. Update the topic hdr with the pointers to the text
+ // and line number that we just found, to help speed us up next time.
+
+ pT->lnOff = (USHORT)((PBYTE)pSrc - (PBYTE)pT);
+ pT->lnCur = lnOrig;
+
+ } else {
+
+ //
+ // Line not found. Update nothing and return NULL
+ // (Side Effect: line requested (ln) - line count left (ln) is the
+ // number of lines in the topic! If original ln is -1, we'll return
+ // that instead!
+
+ if (lnOrig == -1)
+ pSrc = (PBYTE)(lnOrig - ln);
+ else
+ pSrc = (PBYTE)0L;
+ }
+
+ return pSrc;
+
+}
diff --git a/private/utils/mep/help/enginlib/makefile b/private/utils/mep/help/enginlib/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/help/enginlib/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/help/enginlib/mshelp.def b/private/utils/mep/help/enginlib/mshelp.def
new file mode 100644
index 000000000..8686b0eaa
--- /dev/null
+++ b/private/utils/mep/help/enginlib/mshelp.def
@@ -0,0 +1,29 @@
+LIBRARY MSHELP
+
+DESCRIPTION 'Help engine'
+
+EXPORTS
+ HelpcLines
+ HelpClose
+ HelpCtl
+ HelpDecomp
+ HelpGetCells
+ HelpGetInfo
+ HelpGetLine
+ HelpGetLineAttr
+ HelpHlNext
+ HelpLook
+ HelpNc
+ HelpNcBack
+ HelpNcCb
+ HelpNcCmp
+ HelpNcNext
+ HelpNcPrev
+ HelpNcRecord
+ HelpNcUniq
+ HelpOpen
+ HelpShrink
+ HelpSzContext
+ HelpXRef
+ LoadFdb
+ LoadPortion
diff --git a/private/utils/mep/help/enginlib/mshelp.rc b/private/utils/mep/help/enginlib/mshelp.rc
new file mode 100644
index 000000000..039e42627
--- /dev/null
+++ b/private/utils/mep/help/enginlib/mshelp.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "MS Help Utility DLL"
+#define VER_INTERNALNAME_STR "mshelp"
+#define VER_ORIGINALNAME_STR "MSHELP.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/help/enginlib/mshelp1.def b/private/utils/mep/help/enginlib/mshelp1.def
new file mode 100644
index 000000000..d06263f3a
--- /dev/null
+++ b/private/utils/mep/help/enginlib/mshelp1.def
@@ -0,0 +1,29 @@
+LIBRARY MSHELP1
+
+DESCRIPTION 'Help engine'
+
+EXPORTS
+ _HelpcLines
+ _HelpClose
+ _HelpCtl
+ _HelpDecomp
+ _HelpGetCells
+ _HelpGetInfo
+ _HelpGetLine
+ _HelpGetLineAttr
+ _HelpHlNext
+ _HelpLook
+ _HelpNc
+ _HelpNcBack
+ _HelpNcCb
+ _HelpNcCmp
+ _HelpNcNext
+ _HelpNcPrev
+ _HelpNcRecord
+ _HelpNcUniq
+ _HelpOpen
+ _HelpShrink
+ _HelpSzContext
+ _HelpXRef
+ _LoadFdb
+ _LoadPortion
diff --git a/private/utils/mep/help/enginlib/sources b/private/utils/mep/help/enginlib/sources
new file mode 100644
index 000000000..177480707
--- /dev/null
+++ b/private/utils/mep/help/enginlib/sources
@@ -0,0 +1,35 @@
+MAJORCOMP=sdktools
+MINORCOMP=engine
+
+TARGETNAME=mshelp
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib \
+ \nt\private\sdktools\ztools\src\obj\*\ztools.lib \
+ \nt\public\sdk\lib\*\user32.lib
+
+INCLUDES=.;..\inc;
+
+SOURCES= hback.c \
+ hctl.c \
+ hdata.c \
+ helpcell.c \
+ helpcnt.c \
+ helpdec.c \
+ helpdll.c \
+ helpif.c \
+ hinfo.c \
+ hline.c \
+ hloc.c \
+ help.c \
+ mshelp.rc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT -DDEBUG
+!ELSE
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+!ENDIF
+UMTYPE=console
+UMRES=obj\*\mshelp.res
+USE_CRTDLL=1
diff --git a/private/utils/mep/help/htest/cons.c b/private/utils/mep/help/htest/cons.c
new file mode 100644
index 000000000..894a78325
--- /dev/null
+++ b/private/utils/mep/help/htest/cons.c
@@ -0,0 +1,2200 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ console.c
+
+Abstract:
+
+ Interface to the console for Win32 applications.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 30-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+#include <string.h>
+#include <malloc.h>
+#include <assert.h>
+#include <windows.h>
+
+#define FREE(x) free(x)
+#define MALLOC(x) malloc(x)
+#define REALLOC(x,y) realloc(x,y)
+
+#include "cons.h"
+
+
+
+//
+// EVENT BUFFER
+//
+// The event buffer is used to store event records from the input
+// queue.
+//
+#define INITIAL_EVENTS 32
+#define MAX_EVENTS 64
+#define EVENT_INCREMENT 4
+
+#define ADVANCE TRUE
+#define NOADVANCE FALSE
+#define WAIT TRUE
+#define NOWAIT FALSE
+
+//
+// For accessing fields of an event record
+//
+#define EVENT_TYPE(p) ((p)->EventType)
+#define EVENT_DATA(p) ((p)->Event)
+
+//
+// For casting event records
+//
+#define PMOUSE_EVT(p) (&(EVENT_DATA(p).MouseEvent))
+#define PWINDOW_EVT(p) (&(EVENT_DATA(p).WindowBufferSizeEvent))
+#define PKEY_EVT(p) (&(EVENT_DATA(p).KeyEvent))
+
+//
+// The event buffer structure
+//
+typedef struct EVENT_BUFFER {
+ DWORD MaxEvents; // Max number of events in buffer
+ DWORD NumberOfEvents; // Number of events in buffer
+ DWORD EventIndex; // Event Index
+ BOOL BusyFlag; // Busy flag
+ CRITICAL_SECTION CriticalSection; // To maintain integrity
+ CRITICAL_SECTION PeekCriticalSection; // While peeking
+ PINPUT_RECORD EventBuffer; // Event Buffer
+} EVENT_BUFFER, *PEVENT_BUFFER;
+
+
+
+
+
+//
+// Screen attributes
+//
+#define BLACK_FGD 0
+#define BLUE_FGD FOREGROUND_BLUE
+#define GREEN_FGD FOREGROUND_GREEN
+#define CYAN_FGD (FOREGROUND_BLUE | FOREGROUND_GREEN)
+#define RED_FGD FOREGROUND_RED
+#define MAGENTA_FGD (FOREGROUND_BLUE | FOREGROUND_RED)
+#define YELLOW_FGD (FOREGROUND_GREEN | FOREGROUND_RED)
+#define WHITE_FGD (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
+
+#define BLACK_BGD 0
+#define BLUE_BGD BACKGROUND_BLUE
+#define GREEN_BGD BACKGROUND_GREEN
+#define CYAN_BGD (BACKGROUND_BLUE | BACKGROUND_GREEN)
+#define RED_BGD BACKGROUND_RED
+#define MAGENTA_BGD (BACKGROUND_BLUE | BACKGROUND_RED)
+#define YELLOW_BGD (BACKGROUND_GREEN | BACKGROUND_RED)
+#define WHITE_BGD (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
+
+
+
+//
+// The AttrBg and AttrFg arrays are used for mapping DOS attributes
+// to the new attributes.
+//
+WORD AttrBg[ ] = {
+ BLACK_BGD, // black
+ BLUE_BGD, // blue
+ GREEN_BGD, // green
+ CYAN_BGD, // cyan
+ RED_BGD, // red
+ MAGENTA_BGD, // magenta
+ YELLOW_BGD, // brown
+ WHITE_BGD, // light gray
+ BACKGROUND_INTENSITY | BLACK_BGD, // dark gray
+ BACKGROUND_INTENSITY | BLUE_BGD, // light blue
+ BACKGROUND_INTENSITY | GREEN_BGD, // light green
+ BACKGROUND_INTENSITY | CYAN_BGD, // light cyan
+ BACKGROUND_INTENSITY | RED_BGD, // light red
+ BACKGROUND_INTENSITY | MAGENTA_BGD, // light magenta
+ BACKGROUND_INTENSITY | YELLOW_BGD, // light yellow
+ BACKGROUND_INTENSITY | WHITE_BGD // white
+};
+
+WORD AttrFg[ ] = {
+ BLACK_FGD, // black
+ BLUE_FGD, // blue
+ GREEN_FGD, // green
+ CYAN_FGD, // cyan
+ RED_FGD, // red
+ MAGENTA_FGD, // magenta
+ YELLOW_FGD, // brown
+ WHITE_FGD, // light gray
+ FOREGROUND_INTENSITY | BLACK_FGD, // dark gray
+ FOREGROUND_INTENSITY | BLUE_FGD, // light blue
+ FOREGROUND_INTENSITY | GREEN_FGD, // light green
+ FOREGROUND_INTENSITY | CYAN_FGD, // light cyan
+ FOREGROUND_INTENSITY | RED_FGD, // light red
+ FOREGROUND_INTENSITY | MAGENTA_FGD, // light magenta
+ FOREGROUND_INTENSITY | YELLOW_FGD, // light yellow
+ FOREGROUND_INTENSITY | WHITE_FGD // white
+};
+
+//
+// GET_ATTRIBUTE performs the mapping from old attributes to new attributes
+//
+#define GET_ATTRIBUTE(x) (AttrFg[x & 0x000F ] | AttrBg[( x & 0x00F0 ) >> 4])
+
+
+//
+// The LINE_INFO structure contains information about each line in the
+// screen buffer.
+//
+typedef struct _LINE_INFO {
+
+ BOOL Dirty; // True if has not been displayed
+ int colMinChanged; // if dirty, smallest col changed
+ int colMaxChanged; // if dirty, biggest col changed
+ PCHAR_INFO Line; // Pointer to the line.
+
+} LINE_INFO, *PLINE_INFO;
+
+#define ResetLineInfo(pli) \
+ { pli->Dirty = 0; \
+ pli->colMinChanged = 1000; \
+ pli->colMaxChanged = -1; \
+ }
+
+//
+// The SCREEN_DATA structure contains the information about individual
+// screens.
+//
+typedef struct SCREEN_DATA {
+ HANDLE ScreenHandle; // Handle to screen
+ PLINE_INFO LineInfo; // Array of line info.
+ PCHAR_INFO ScreenBuffer; // Screen buffer
+ ULONG MaxBufferSize; // Max. buffer size
+ ATTRIBUTE AttributeOld; // Attribute - original
+ WORD AttributeNew; // Attribute - converted
+ ROW FirstRow; // First row to update
+ ROW LastRow; // Last row to update
+ CRITICAL_SECTION CriticalSection; // To maintain integrity
+ DWORD CursorSize; // Cursor Size
+ SCREEN_INFORMATION ScreenInformation; // Screen information
+} SCREEN_DATA, *PSCREEN_DATA;
+
+
+//
+// Static global data
+//
+static EVENT_BUFFER EventBuffer; // Event buffer
+static HANDLE hInput; // handle to stdin
+static HANDLE hOutput; // handle to stdout
+static HANDLE hError; // handle to stderr
+static PSCREEN_DATA OutputScreenData; // Screen data for hOutput
+static PSCREEN_DATA ActiveScreenData; // Points to current screen data
+static BOOL Initialized = FALSE; // Initialized flag
+
+
+#if defined (DEBUG)
+ static char DbgBuffer[128];
+#endif
+
+
+//
+// Local Prototypes
+//
+BOOL
+InitializeGlobalState (
+ void
+ );
+
+
+PSCREEN_DATA
+MakeScreenData (
+ HANDLE ScreenHandle
+ );
+
+BOOL
+InitLineInfo (
+ PSCREEN_DATA ScreenData
+ );
+
+PINPUT_RECORD
+NextEvent (
+ BOOL fAdvance,
+ BOOL fWait
+ );
+
+void
+MouseEvent (
+ PMOUSE_EVENT_RECORD pEvent
+ );
+
+BOOL
+WindowEvent (
+ PWINDOW_BUFFER_SIZE_RECORD pEvent
+ );
+
+BOOL
+KeyEvent (
+ PKEY_EVENT_RECORD pEvent,
+ PKBDKEY pKey
+ );
+
+
+BOOL
+PutEvent (
+ PINPUT_RECORD InputRecord
+ );
+
+
+BOOL
+InitializeGlobalState (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Initializes our global state data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success
+ FALSE otherwise.
+
+--*/
+{
+
+
+ //
+ // Initialize the event buffer
+ //
+ InitializeCriticalSection( &(EventBuffer.CriticalSection) );
+ InitializeCriticalSection( &(EventBuffer.PeekCriticalSection) );
+ EventBuffer.NumberOfEvents = 0;
+ EventBuffer.EventIndex = 0;
+ EventBuffer.BusyFlag = FALSE;
+ EventBuffer.EventBuffer = MALLOC( INITIAL_EVENTS * sizeof(INPUT_RECORD) );
+
+ if ( !EventBuffer.EventBuffer ) {
+ return FALSE;
+ }
+
+ EventBuffer.MaxEvents = INITIAL_EVENTS;
+
+
+ //
+ // Get handles to stdin, stdout and stderr
+ //
+ hInput = GetStdHandle( STD_INPUT_HANDLE );
+ hOutput = GetStdHandle( STD_OUTPUT_HANDLE );
+ hError = GetStdHandle( STD_ERROR_HANDLE );
+
+
+ //
+ // Initialize the screen data for hOutput
+ //
+ if ( !(OutputScreenData = MakeScreenData( hOutput )) ) {
+ return FALSE;
+ }
+
+
+ //
+ // Current screen is hOutput
+ //
+ ActiveScreenData = OutputScreenData;
+
+
+ return (Initialized = TRUE);
+
+}
+
+
+
+
+
+PSCREEN_DATA
+MakeScreenData (
+ HANDLE ScreenHandle
+ )
+/*++
+
+Routine Description:
+
+ Allocates memory for a SCREEN_DATA information and initializes it.
+
+Arguments:
+
+ ScreenHandle - Supplies handle of screen.
+
+Return Value:
+
+ POINTER to allocated SCREEN_DATA structure
+
+--*/
+{
+ PSCREEN_DATA ScreenData; // Pointer to screen data
+ CONSOLE_SCREEN_BUFFER_INFO ScrInfo; // Screen buffer info.
+
+
+ //
+ // Allocate space for the screen data.
+ //
+ if ( !(ScreenData = (PSCREEN_DATA)MALLOC(sizeof(SCREEN_DATA))) ) {
+ return NULL;
+ }
+
+ //
+ // Allocate space for our copy of the screen buffer.
+ //
+ GetConsoleScreenBufferInfo( ScreenHandle,
+ &ScrInfo );
+
+ ScreenData->MaxBufferSize = ScrInfo.dwSize.Y *
+ ScrInfo.dwSize.X;
+
+ ScreenData->ScreenBuffer = (PCHAR_INFO)MALLOC( ScreenData->MaxBufferSize *
+ sizeof(CHAR_INFO));
+
+ if ( !ScreenData->ScreenBuffer ) {
+ FREE( ScreenData );
+ return NULL;
+ }
+
+ //
+ // Allocate space for the LineInfo array
+ //
+ ScreenData->LineInfo = (PLINE_INFO)MALLOC( ScrInfo.dwSize.Y * sizeof( LINE_INFO ) );
+ if ( !ScreenData->LineInfo ) {
+ FREE( ScreenData->ScreenBuffer );
+ FREE( ScreenData );
+ return NULL;
+ }
+
+
+ //
+ // Memory has been allocated, now initialize the structure
+ //
+ ScreenData->ScreenHandle = ScreenHandle;
+
+ ScreenData->ScreenInformation.NumberOfRows = ScrInfo.dwSize.Y;
+ ScreenData->ScreenInformation.NumberOfCols = ScrInfo.dwSize.X;
+
+ ScreenData->ScreenInformation.CursorRow = ScrInfo.dwCursorPosition.Y;
+ ScreenData->ScreenInformation.CursorCol = ScrInfo.dwCursorPosition.X;
+
+ ScreenData->AttributeNew = ScrInfo.wAttributes;
+ ScreenData->AttributeOld = 0x00;
+
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+ ScreenData->LastRow = 0;
+
+ InitializeCriticalSection( &(ScreenData->CriticalSection) );
+
+ InitLineInfo( ScreenData );
+
+ return ScreenData;
+}
+
+
+
+
+
+BOOL
+InitLineInfo (
+ PSCREEN_DATA ScreenData
+ )
+/*++
+
+Routine Description:
+
+ Initializes the LineInfo array.
+
+Arguments:
+
+ ScreenData - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if initialized, false otherwise.
+
+--*/
+{
+
+ ROW Row;
+ COLUMN Cols;
+ PLINE_INFO LineInfo;
+ PCHAR_INFO CharInfo;
+
+
+ LineInfo = ScreenData->LineInfo;
+ CharInfo = ScreenData->ScreenBuffer;
+ Row = ScreenData->ScreenInformation.NumberOfRows;
+ Cols = ScreenData->ScreenInformation.NumberOfCols;
+
+ while ( Row-- ) {
+
+ //
+ // BUGBUG Temporary
+ //
+ // assert( LineInfo < (ScreenData->LineInfo + ScreenData->ScreenInformation.NumberOfRows));
+ // assert( (CharInfo + Cols) <= (ScreenData->ScreenBuffer + ScreenData->MaxBufferSize) );
+
+ ResetLineInfo (LineInfo);
+
+ LineInfo->Line = CharInfo;
+
+ LineInfo++;
+ CharInfo += Cols;
+
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+PSCREEN
+consoleNewScreen (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Creates a new screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to screen data.
+
+--*/
+{
+ PSCREEN_DATA ScreenData; // Screen data
+ HANDLE NewScreenHandle;
+ SMALL_RECT NewSize;
+ CONSOLE_SCREEN_BUFFER_INFO ScrInfo; // Screen buffer info.
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ if ( !Initialized ) {
+
+ //
+ // We have to initialize our global state.
+ //
+ if ( !InitializeGlobalState() ) {
+ return NULL;
+ }
+ }
+
+ //
+ // Create a new screen buffer
+ //
+ NewScreenHandle = CreateConsoleScreenBuffer(GENERIC_WRITE | GENERIC_READ,
+ 0,
+ NULL,
+ CONSOLE_TEXTMODE_BUFFER,
+ NULL );
+
+ if (NewScreenHandle == INVALID_HANDLE_VALUE) {
+ //
+ // No luck
+ //
+ return NULL;
+ }
+
+ //
+ // We want the new window to be the same size as the current one, so
+ // we resize it.
+ //
+ GetConsoleScreenBufferInfo( ActiveScreenData->ScreenHandle,
+ &ScrInfo );
+
+ NewSize.Left = 0;
+ NewSize.Top = 0;
+ NewSize.Right = ScrInfo.srWindow.Right - ScrInfo.srWindow.Left;
+ NewSize.Bottom = ScrInfo.srWindow.Bottom - ScrInfo.srWindow.Top;
+
+ SetConsoleWindowInfo( NewScreenHandle, TRUE, &NewSize );
+
+ //
+ // Now we create a screen data structure for it.
+ //
+ if ( !(ScreenData = MakeScreenData(NewScreenHandle)) ) {
+ CloseHandle(NewScreenHandle);
+ return NULL;
+ }
+
+
+ CursorInfo.bVisible = TRUE;
+ ScreenData->CursorSize = CursorInfo.dwSize = 25;
+
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ //
+ // We are all set. We return a pointer to the
+ // screen data.
+ //
+ return (PSCREEN)ScreenData;
+}
+
+
+
+
+
+BOOL
+consoleCloseScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Closes a screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if screen closed.
+ FALSE otherwise
+
+--*/
+{
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ //
+ // We cannot close the active screen
+ //
+ if ( !ScreenData || (ScreenData == ActiveScreenData) ) {
+ return FALSE;
+ }
+
+ if (ScreenData->ScreenHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(ScreenData->ScreenHandle);
+ }
+
+ FREE( ScreenData->LineInfo );
+ FREE( ScreenData->ScreenBuffer );
+ FREE( ScreenData );
+
+ return TRUE;
+}
+
+
+
+
+
+PSCREEN
+consoleGetCurrentScreen (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Returns the current screen.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ Pointer to currently active screen data.
+
+--*/
+{
+ if ( !Initialized ) {
+
+ //
+ // We have to initialize our global state.
+ //
+ if (!InitializeGlobalState()) {
+ return NULL;
+ }
+ }
+
+ return (PSCREEN)ActiveScreenData;
+}
+
+
+
+
+
+BOOL
+consoleSetCurrentScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Sets the active screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if the active screen set
+ FALSE otherwise.
+
+--*/
+{
+ BOOL ScreenSet = TRUE;
+ PSCREEN_DATA CurrentScreen = ActiveScreenData;
+
+
+ EnterCriticalSection( &(CurrentScreen->CriticalSection) );
+
+ ScreenSet = SetConsoleActiveScreenBuffer( ((PSCREEN_DATA)pScreen)->ScreenHandle);
+
+ if (ScreenSet) {
+ ActiveScreenData = (PSCREEN_DATA)pScreen;
+ }
+
+ LeaveCriticalSection( &(CurrentScreen->CriticalSection) );
+
+ return ScreenSet;
+}
+
+
+
+
+
+BOOL
+consoleGetScreenInformation (
+ PSCREEN pScreen,
+ PSCREEN_INFORMATION pScreenInfo
+ )
+/*++
+
+Routine Description:
+
+ Sets the active screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+ pScreenInfo - Supplies pointer to screen info buffer
+
+Return Value:
+
+ TRUE if the screen info returned
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ if (!ScreenData) {
+ return FALSE;
+ }
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ memcpy(pScreenInfo, &(ScreenData->ScreenInformation), sizeof(SCREEN_INFORMATION));
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return TRUE;
+}
+
+
+
+BOOL
+consoleSetScreenSize (
+ PSCREEN pScreen,
+ ROW Rows,
+ COLUMN Cols
+ )
+/*++
+
+Routine Description:
+
+ Sets the screen size
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+ Rows - Number of rows
+ Cols - Number of columns
+
+Return Value:
+
+ TRUE if screen size changed successfully
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+ SMALL_RECT ScreenRect;
+ COORD ScreenSize;
+ USHORT MinRows;
+ USHORT MinCols;
+ ULONG NewBufferSize;
+ BOOL WindowSet = FALSE;
+ BOOL Status = FALSE;
+
+ //
+ // Won't attempt to resize larger than the largest window size
+ //
+ ScreenSize = GetLargestConsoleWindowSize( ScreenData->ScreenHandle );
+
+ if ( (Rows > (ROW)ScreenSize.Y) || (Cols > (COLUMN)ScreenSize.X) ) {
+ return FALSE;
+ }
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ //
+ // Obtain the current screen information.
+ //
+ if ( GetConsoleScreenBufferInfo( ScreenData->ScreenHandle, &ScreenBufferInfo ) ) {
+
+ //
+ // If the desired buffer size is smaller than the current window
+ // size, we have to resize the current window first.
+ //
+ if ( ( Rows < (ROW)
+ (ScreenBufferInfo.srWindow.Bottom -
+ ScreenBufferInfo.srWindow.Top + 1) ) ||
+ ( Cols < (COLUMN)
+ (ScreenBufferInfo.srWindow.Right -
+ ScreenBufferInfo.srWindow.Left + 1) ) ) {
+
+ //
+ // Set the window to a size that will fit in the current
+ // screen buffer and that is no bigger than the size to
+ // which we want to grow the screen buffer.
+ //
+ MinRows = (USHORT)min( (int)Rows, (int)(ScreenBufferInfo.dwSize.Y) );
+ MinCols = (USHORT)min( (int)Cols, (int)(ScreenBufferInfo.dwSize.X) );
+
+ ScreenRect.Top = 0;
+ ScreenRect.Left = 0;
+ ScreenRect.Right = (SHORT)MinCols - (SHORT)1;
+ ScreenRect.Bottom = (SHORT)MinRows - (SHORT)1;
+
+ WindowSet = (BOOL)SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &ScreenRect );
+
+ if ( !WindowSet ) {
+ //
+ // ERROR
+ //
+ goto Done;
+ }
+ }
+
+ //
+ // Set the screen buffer size to the desired size.
+ //
+ ScreenSize.X = (WORD)Cols;
+ ScreenSize.Y = (WORD)Rows;
+
+ if ( !SetConsoleScreenBufferSize( ScreenData->ScreenHandle, ScreenSize ) ) {
+
+ //
+ // ERROR
+ //
+ //
+ // Return the window to its original size. We ignore the return
+ // code because there is nothing we can do about it.
+ //
+ SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &(ScreenBufferInfo.srWindow) );
+
+ goto Done;
+ }
+
+ //
+ // resize the screen buffer. Note that the contents of the screen
+ // buffer are not valid anymore. Someone else will have to update
+ // them.
+ //
+ NewBufferSize = Rows * Cols;
+
+ if (ScreenData->MaxBufferSize < NewBufferSize ) {
+ ScreenData->ScreenBuffer = REALLOC( ScreenData->ScreenBuffer, NewBufferSize * sizeof(CHAR_INFO));
+ ScreenData->MaxBufferSize = NewBufferSize;
+ ScreenData->LineInfo = REALLOC( ScreenData->LineInfo, Rows * sizeof( LINE_INFO ) );
+ }
+
+ //
+ // Set the Window Size. We know that we can grow the window to this size
+ // because we tested the size against the largest window size at the
+ // beginning of the function.
+ //
+ ScreenRect.Top = 0;
+ ScreenRect.Left = 0;
+ ScreenRect.Right = (SHORT)Cols - (SHORT)1;
+ ScreenRect.Bottom = (SHORT)Rows - (SHORT)1;
+
+ WindowSet = (BOOL)SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &ScreenRect );
+
+ if ( !WindowSet ) {
+ //
+ // We could not resize the window. We will leave the
+ // resized screen buffer.
+ //
+ // ERROR
+ //
+ goto Done;
+ }
+
+ //
+ // Update the screen size
+ //
+ ScreenData->ScreenInformation.NumberOfRows = Rows;
+ ScreenData->ScreenInformation.NumberOfCols = Cols;
+
+ InitLineInfo( ScreenData );
+
+ //
+ // Done
+ //
+ Status = TRUE;
+
+ } else {
+
+ //
+ // ERROR
+ //
+ }
+
+Done:
+ //
+ // Invalidate the entire screen buffer
+ //
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+ ScreenData->LastRow = 0;
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+ return Status;
+
+}
+
+
+
+
+BOOL
+consoleSetCursor (
+ PSCREEN pScreen,
+ ROW Row,
+ COLUMN Col
+ )
+/*++
+
+Routine Description:
+
+ Moves the cursor to a certain position.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ Row - Supplies row coordinate
+ Col - Supplies column coordinate
+
+Return Value:
+
+ TRUE if moved
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ COORD Position;
+ BOOL Moved = FALSE;
+
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if ((Row != ScreenData->ScreenInformation.CursorRow) ||
+ (Col != ScreenData->ScreenInformation.CursorCol) ) {
+
+ assert( Row < ScreenData->ScreenInformation.NumberOfRows);
+ assert( Col < ScreenData->ScreenInformation.NumberOfCols);
+
+ Position.Y = (SHORT)Row;
+ Position.X = (SHORT)Col;
+
+ if ( SetConsoleCursorPosition( ScreenData->ScreenHandle,
+ Position )) {
+ //
+ // Cursor moved, update the data
+ //
+ ScreenData->ScreenInformation.CursorRow = Row;
+ ScreenData->ScreenInformation.CursorCol = Col;
+
+ Moved = TRUE;
+ }
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Moved;
+}
+
+
+
+
+BOOL
+consoleSetCursorStyle (
+ PSCREEN pScreen,
+ ULONG Style
+ )
+
+/*++
+
+Routine Description7:
+
+ Sets the cursor style. The two available styles are: underscrore and
+ box
+
+Arguments:
+
+ Style - New cursor style
+
+Return Value:
+
+ True if cursor style set
+
+--*/
+
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ CursorInfo.bVisible = TRUE;
+
+ if ( Style == CURSOR_STYLE_UNDERSCORE ) {
+
+ CursorInfo.dwSize = 25;
+
+ } else if ( Style == CURSOR_STYLE_BOX ) {
+
+ CursorInfo.dwSize = 100;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ ScreenData->CursorSize = CursorInfo.dwSize;
+
+ return SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+}
+
+
+
+
+
+ULONG
+consoleWriteLine (
+ PSCREEN pScreen,
+ PVOID pBuffer,
+ ULONG BufferSize,
+ ROW Row,
+ COLUMN Col,
+ ATTRIBUTE Attribute,
+ BOOL Blank
+ )
+/*++
+
+Routine Description7:
+
+ Writes a buffer to the screen with the specified attribute and blanks
+ to end of row.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ pBuffer - Supplies pointer to buffer
+ BufferSize - Supplies the size of the buffer
+ Row - Supplies row coordinate
+ Col - Supplies column coordinate
+ Attr - Supplies the attribute
+ Blank - TRUE if we should blank to end of last row written.
+
+Return Value:
+
+ Number of bytes written
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ PLINE_INFO LineInfo;
+ PCHAR_INFO CharInfo;
+ CHAR_INFO Char;
+ WORD Attr;
+
+ char * p = (char *)pBuffer;
+
+ COLUMN ColsLeft; // Available columns
+ COLUMN InfoCols; // Columns taken from buffer
+ COLUMN BlankCols; // Columns to be blanked
+ COLUMN Column; // Counter;
+
+ //
+ // We will ignore writes outside of the screen buffer
+ //
+ if ( ( Row >= ScreenData->ScreenInformation.NumberOfRows ) ||
+ ( Col >= ScreenData->ScreenInformation.NumberOfCols ) ) {
+ return TRUE;
+ }
+
+ //
+ // Ignore trivial writes
+ //
+
+ if (BufferSize == 0 && !Blank)
+ return TRUE;
+
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ //
+ // We will truncate writes that are too long
+ //
+ if ( (Col + BufferSize) >= ScreenData->ScreenInformation.NumberOfCols ) {
+ BufferSize = ScreenData->ScreenInformation.NumberOfCols - Col;
+ }
+
+ LineInfo = ScreenData->LineInfo + Row;
+ CharInfo = LineInfo->Line + Col;
+
+ ColsLeft = ScreenData->ScreenInformation.NumberOfCols - Col;
+ InfoCols = min( BufferSize, ColsLeft );
+ BlankCols = Blank ? (ColsLeft - InfoCols) : 0;
+
+ //
+ // Set the attribute
+ //
+ if ( Attribute != ScreenData->AttributeOld ) {
+ ScreenData->AttributeOld = Attribute;
+ ScreenData->AttributeNew = GET_ATTRIBUTE(Attribute);
+ }
+ Attr = ScreenData->AttributeNew;
+
+ //
+ // set up default attribute
+ //
+
+ Char.Attributes = Attr;
+
+ //
+ // set up number of columns to draw
+ //
+
+ Column = InfoCols;
+
+ //
+ // draw chars in all specified columns
+ //
+
+ while ( Column-- ) {
+
+ //
+ // use character from input string
+ //
+
+ Char.Char.AsciiChar = *p++;
+
+ //
+ // update change portions of line info
+ //
+
+ if (CharInfo->Attributes != Char.Attributes ||
+ CharInfo->Char.AsciiChar != Char.Char.AsciiChar) {
+
+ LineInfo->colMinChanged = min (LineInfo->colMinChanged, CharInfo - LineInfo->Line);
+ LineInfo->colMaxChanged = max (LineInfo->colMaxChanged, CharInfo - LineInfo->Line);
+ LineInfo->Dirty = TRUE;
+ }
+
+ //
+ // set up new character
+ //
+
+ *CharInfo++ = Char;
+ }
+
+
+ //
+ // Blank to end of line
+ //
+ Char.Attributes = Attr;
+ Char.Char.AsciiChar = ' ';
+ Column = BlankCols;
+ while ( Column-- ) {
+ //
+ // update change portions of line info
+ //
+
+ if (CharInfo->Attributes != Char.Attributes ||
+ CharInfo->Char.AsciiChar != Char.Char.AsciiChar) {
+
+ LineInfo->colMinChanged = min (LineInfo->colMinChanged, CharInfo - LineInfo->Line);
+ LineInfo->colMaxChanged = max (LineInfo->colMaxChanged, CharInfo - LineInfo->Line);
+ LineInfo->Dirty = TRUE;
+ }
+
+ *CharInfo++ = Char;
+ }
+
+ //
+ // Update row information
+ //
+ if ( Row < ScreenData->FirstRow ) {
+ ScreenData->FirstRow = Row;
+ }
+ if ( Row > ScreenData->LastRow ) {
+ ScreenData->LastRow = Row;
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return (ULONG)(InfoCols + BlankCols);
+}
+
+
+
+
+
+BOOL
+consoleShowScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Moves data from our screen buffer to the console screen buffer.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+
+Return Value:
+
+ TRUE if done
+ FALSE otherwise
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_CURSOR_INFO CursorInfo;
+ PLINE_INFO LineInfo;
+ BOOL Shown = FALSE;
+ ROW FirstRow;
+ ROW LastRow;
+ COLUMN LastCol;
+
+ COORD Position;
+ COORD Size;
+ SMALL_RECT Rectangle;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if ( ScreenData->FirstRow <= ScreenData->LastRow ) {
+
+ Size.X = (SHORT)(ScreenData->ScreenInformation.NumberOfCols);
+ Size.Y = (SHORT)(ScreenData->ScreenInformation.NumberOfRows);
+
+ FirstRow = ScreenData->FirstRow;
+ LineInfo = ScreenData->LineInfo + FirstRow;
+
+ LastCol = ScreenData->ScreenInformation.NumberOfCols-1;
+
+ //
+ // Find next dirty block
+ //
+ while ( (FirstRow <= ScreenData->LastRow) && !LineInfo->Dirty ) {
+ FirstRow++;
+ LineInfo++;
+ }
+
+ while ( FirstRow <= ScreenData->LastRow ) {
+
+ int colLeft, colRight;
+
+ //
+ // Get the block
+ //
+
+ LastRow = FirstRow;
+
+ //
+ // set up for left/right boundary accrual
+ //
+
+ colLeft = LastCol + 1;
+ colRight = -1;
+
+ while ( (LastRow <= ScreenData->LastRow) && LineInfo->Dirty ) {
+
+ //
+ // accrue smallest bounding right/left margins
+ //
+
+ colLeft = min (colLeft, LineInfo->colMinChanged);
+ colRight = max (colRight, LineInfo->colMaxChanged);
+
+ //
+ // reset line information
+ //
+
+ ResetLineInfo (LineInfo);
+
+ //
+ // advance to next row
+ //
+
+ LastRow++;
+ LineInfo++;
+ }
+ LastRow--;
+
+
+ //
+ // Write the block
+ //
+ assert( FirstRow <= LastRow );
+
+ Position.X = (SHORT)colLeft;
+ Position.Y = (SHORT)FirstRow;
+
+ Rectangle.Top = (SHORT)FirstRow;
+ Rectangle.Bottom = (SHORT)LastRow;
+ Rectangle.Left = (SHORT) colLeft;
+ Rectangle.Right = (SHORT) colRight;
+
+ //
+ // Performance hack: making the cursor invisible speeds
+ // screen updates.
+ //
+ CursorInfo.bVisible = FALSE;
+ CursorInfo.dwSize = ScreenData->CursorSize;
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ Shown = WriteConsoleOutput( ScreenData->ScreenHandle,
+ ScreenData->ScreenBuffer,
+ Size,
+ Position,
+ &Rectangle );
+
+#if defined (DEBUG)
+ if ( !Shown ) {
+ char DbgB[128];
+ sprintf(DbgB, "MEP: WriteConsoleOutput Error %d\n", GetLastError() );
+ OutputDebugString( DbgB );
+ }
+#endif
+ assert( Shown );
+
+ CursorInfo.bVisible = TRUE;
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ FirstRow = LastRow + 1;
+
+ //
+ // Find next dirty block
+ //
+ while ( (FirstRow <= ScreenData->LastRow) && !LineInfo->Dirty ) {
+ FirstRow++;
+ LineInfo++;
+ }
+ }
+
+ ScreenData->LastRow = 0;
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Shown;
+
+}
+
+
+
+
+
+BOOL
+consoleClearScreen (
+ PSCREEN pScreen,
+ BOOL ShowScreen
+ )
+/*++
+
+Routine Description:
+
+ Clears the screen
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+
+Return Value:
+
+ TRUE if screen cleared
+ FALSE otherwise
+
+--*/
+{
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ ROW Rows;
+ BOOL Status = TRUE;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ Rows = ScreenData->ScreenInformation.NumberOfRows;
+
+ while ( Rows-- ) {
+ consoleWriteLine( pScreen, NULL, 0, Rows, 0, ScreenData->AttributeOld, TRUE );
+ }
+
+ if (ShowScreen) {
+ Status = consoleShowScreen( pScreen );
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Status;
+}
+
+
+
+
+
+
+
+BOOL
+consoleSetAttribute (
+ PSCREEN pScreen,
+ ATTRIBUTE Attribute
+ )
+/*++
+
+Routine Description:
+
+ Sets the console attribute
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ Attribute - Supplies the attribute
+
+Return Value:
+
+ TRUE if Attribute set
+ FALSE otherwise
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if (Attribute != ScreenData->AttributeOld) {
+ ScreenData->AttributeOld = Attribute;
+ ScreenData->AttributeNew = GET_ATTRIBUTE(Attribute);
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+
+BOOL
+consoleFlushInput (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Flushes input events.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success, FALSE otherwise
+
+--*/
+{
+ EventBuffer.NumberOfEvents = 0;
+
+ return FlushConsoleInputBuffer( hInput );
+}
+
+
+
+
+
+
+
+BOOL
+consoleGetMode (
+ PKBDMODE pMode
+ )
+/*++
+
+Routine Description:
+
+ Get current console mode.
+
+Arguments:
+
+ pMode - Supplies a pointer to the mode flag variable
+
+Return Value:
+
+ TRUE if success, FALSE otherwise.
+
+--*/
+{
+ return GetConsoleMode( hInput,
+ pMode );
+}
+
+
+
+
+
+
+BOOL
+consoleSetMode (
+ KBDMODE Mode
+ )
+/*++
+
+Routine Description:
+
+ Sets the console mode.
+
+Arguments:
+
+ Mode - Supplies the mode flags.
+
+Return Value:
+
+ TRUE if success, FALSE otherwise
+
+--*/
+{
+ return SetConsoleMode( hInput,
+ Mode );
+}
+
+
+BOOL
+consoleIsKeyAvailable (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Returns TRUE if a key is available in the event buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if a key is available in the event buffer
+ FALSE otherwise
+
+--*/
+
+{
+ BOOL IsKey = FALSE;
+ PINPUT_RECORD pEvent;
+ DWORD Index;
+
+ EnterCriticalSection( &(EventBuffer.CriticalSection) );
+
+ for ( Index = EventBuffer.EventIndex; Index < EventBuffer.NumberOfEvents; Index++ ) {
+
+ pEvent = EventBuffer.EventBuffer + EventBuffer.EventIndex;
+
+ if ( ((EVENT_TYPE(pEvent)) == KEY_EVENT) &&
+ (PKEY_EVT(pEvent))->bKeyDown ) {
+ IsKey = TRUE;
+ break;
+ }
+ }
+
+ LeaveCriticalSection( &(EventBuffer.CriticalSection) );
+
+ return IsKey;
+}
+
+
+
+
+BOOL
+consoleDoWindow (
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Responds to a window event
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if window changed
+ FALSE otherwise
+
+--*/
+
+{
+
+ PINPUT_RECORD pEvent;
+
+ pEvent = NextEvent( NOADVANCE, NOWAIT );
+
+ if (( EVENT_TYPE(pEvent) ) == WINDOW_BUFFER_SIZE_EVENT) {
+
+ pEvent = NextEvent( ADVANCE, WAIT );
+ WindowEvent(PWINDOW_EVT(pEvent));
+ }
+
+ return FALSE;
+
+}
+
+
+
+
+
+BOOL
+consolePeekKey (
+ PKBDKEY Key
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the next key from the input buffer if the buffer is not empty.
+
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+
+Return Value:
+
+ TRUE if keystroke read, FALSE otherwise.
+
+--*/
+
+{
+
+ PINPUT_RECORD pEvent;
+ BOOL Done = FALSE;
+ BOOL IsKey = FALSE;
+
+ EnterCriticalSection(&(EventBuffer.PeekCriticalSection));
+
+ do {
+
+ pEvent = NextEvent( NOADVANCE, NOWAIT );
+
+ if ( pEvent ) {
+
+ switch ( EVENT_TYPE(pEvent) ) {
+
+ case KEY_EVENT:
+ if (KeyEvent(PKEY_EVT(pEvent), Key)){
+ IsKey = TRUE;
+ Done = TRUE;
+ }
+ break;
+
+ case MOUSE_EVENT:
+ Done = TRUE;
+ break;
+
+
+ case WINDOW_BUFFER_SIZE_EVENT:
+ Done = TRUE;
+ break;
+
+ default:
+ assert( FALSE );
+ break;
+ }
+
+ if ( !Done ) {
+ NextEvent( ADVANCE, NOWAIT );
+ }
+
+ } else {
+ Done = TRUE;
+ }
+
+ } while ( !Done );
+
+ LeaveCriticalSection(&(EventBuffer.PeekCriticalSection));
+
+ return IsKey;
+
+}
+
+
+
+
+
+
+BOOL
+consoleGetKey (
+ PKBDKEY Key,
+ BOOL fWait
+ )
+/*++
+
+Routine Description:
+
+ Gets the next key from the input buffer.
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+ fWait - Supplies a flag:
+ if TRUE, the function blocks until a key is ready.
+ if FALSE, the function returns immediately.
+
+Return Value:
+
+ TRUE if keystroke read, FALSE otherwise.
+
+--*/
+{
+
+ PINPUT_RECORD pEvent;
+
+ do {
+ pEvent = NextEvent( ADVANCE, fWait );
+
+ if (pEvent) {
+
+ switch ( EVENT_TYPE(pEvent) ) {
+
+ case KEY_EVENT:
+ if (KeyEvent(PKEY_EVT(pEvent), Key)) {
+ return TRUE;
+ }
+ break;
+
+ case MOUSE_EVENT:
+ MouseEvent(PMOUSE_EVT(pEvent));
+ break;
+
+ case WINDOW_BUFFER_SIZE_EVENT:
+ WindowEvent(PWINDOW_EVT(pEvent));
+ break;
+
+ default:
+ break;
+ }
+ }
+ } while (fWait);
+
+ return FALSE;
+}
+
+
+BOOL
+consolePutKey (
+ PKBDKEY Key
+ )
+/*++
+
+Routine Description:
+
+ Puts a key in the console's input buffer
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+
+Return Value:
+
+ TRUE if key put, false otherwise
+
+--*/
+{
+
+ INPUT_RECORD InputRecord;
+
+ InputRecord.EventType = KEY_EVENT;
+
+ InputRecord.Event.KeyEvent.bKeyDown = FALSE;
+ InputRecord.Event.KeyEvent.wRepeatCount = 0;
+ InputRecord.Event.KeyEvent.wVirtualKeyCode = Key->Scancode;
+ InputRecord.Event.KeyEvent.wVirtualScanCode = 0;
+ InputRecord.Event.KeyEvent.uChar.UnicodeChar = Key->Unicode;
+ InputRecord.Event.KeyEvent.dwControlKeyState = Key->Flags;
+
+ if ( PutEvent( &InputRecord )) {
+ InputRecord.Event.KeyEvent.bKeyDown = TRUE;
+ return PutEvent( &InputRecord );
+ }
+ return FALSE;
+}
+
+
+BOOL
+consolePutMouse(
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ )
+/*++
+
+Routine Description:
+
+ Puts a mose event in the console's input buffer
+
+Arguments:
+
+ Row - Supplies the row
+ Col - Supplies the column
+ MouseFlags - Supplies the flags
+
+Return Value:
+
+ TRUE if key put, false otherwise
+
+--*/
+{
+
+ INPUT_RECORD InputRecord;
+ COORD Position;
+ DWORD Flags;
+
+ InputRecord.EventType = MOUSE_EVENT;
+
+ Position.Y = (WORD)(Row - 1);
+ Position.X = (WORD)(Col - 1);
+
+ Flags = 0;
+
+
+ InputRecord.Event.MouseEvent.dwMousePosition = Position;
+ InputRecord.Event.MouseEvent.dwButtonState = Flags;
+ InputRecord.Event.MouseEvent.dwControlKeyState = 0;
+ InputRecord.Event.MouseEvent.dwEventFlags = 0;
+
+ return PutEvent( &InputRecord );
+}
+
+
+
+BOOL
+consoleIsBusyReadingKeyboard (
+ )
+/*++
+
+Routine Description:
+
+ Determines if the console is busy reading the keyboard
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if console is busy reading the keyboard.
+
+--*/
+{
+ BOOL Busy;
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+ Busy = EventBuffer.BusyFlag;
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return Busy;
+}
+
+
+
+BOOL
+consoleEnterCancelEvent (
+ )
+{
+
+ INPUT_RECORD Record;
+
+ Record.EventType = KEY_EVENT;
+ Record.Event.KeyEvent.bKeyDown = TRUE;
+ Record.Event.KeyEvent.wRepeatCount = 0;
+ Record.Event.KeyEvent.wVirtualKeyCode = VK_CANCEL;
+ Record.Event.KeyEvent.wVirtualScanCode = 0;
+ Record.Event.KeyEvent.uChar.AsciiChar = 0;
+ Record.Event.KeyEvent.dwControlKeyState = 0;
+
+ return PutEvent( &Record );
+}
+
+
+PINPUT_RECORD
+NextEvent (
+ BOOL fAdvance,
+ BOOL fWait
+ )
+/*++
+
+Routine Description:
+
+ Returns pointer to next event record.
+
+Arguments:
+
+ fAdvance - Supplies a flag:
+ if TRUE: Advance to next event record
+ if FALSE: Do not advance to next event record
+
+ fWait - Supplies a flag:
+ if TRUE, the blocks until an event is ready.
+ if FALSE, return immediately.
+
+Return Value:
+
+ Pointer to event record, or NULL.
+
+--*/
+{
+ PINPUT_RECORD pEvent;
+ BOOL Success;
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ //
+ // If the busy flag is set, then the buffer is in the process of
+ // being read. Only one thread should want to wait, so it is
+ // safe to simply return.
+ //
+ if ( EventBuffer.BusyFlag ) {
+ assert( !fWait );
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+ return NULL;
+ }
+
+ if (EventBuffer.NumberOfEvents == 0) {
+
+ //
+ // No events in buffer, read as many as we can
+ //
+ DWORD NumberOfEvents;
+
+ //
+ // If the buffer is too big, resize it
+ //
+ if ( EventBuffer.MaxEvents > MAX_EVENTS ) {
+
+ EventBuffer.EventBuffer = REALLOC( EventBuffer.EventBuffer,
+ MAX_EVENTS * sizeof( INPUT_RECORD ) );
+
+ EventBuffer.MaxEvents = MAX_EVENTS;
+ assert( EventBuffer.EventBuffer );
+
+ //CleanExit( 1, 0 );
+ }
+
+ Success = PeekConsoleInput( hInput,
+ EventBuffer.EventBuffer,
+ EventBuffer.MaxEvents,
+ &NumberOfEvents);
+
+ if ((!Success || (NumberOfEvents == 0)) && (!fWait)) {
+ //
+ // No events available and don't want to wait,
+ // return.
+ //
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+ return NULL;
+ }
+
+ //
+ // Since we will block, we have to leave the critical section.
+ // We set the Busy flag to indicate that the buffer is being
+ // read.
+ //
+ EventBuffer.BusyFlag = TRUE;
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ Success = ReadConsoleInput (hInput,
+ EventBuffer.EventBuffer,
+ EventBuffer.MaxEvents,
+ &EventBuffer.NumberOfEvents);
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ EventBuffer.BusyFlag = FALSE;
+
+ if (!Success) {
+#if defined( DEBUG )
+ OutputDebugString(" Error: Cannot read console events\n");
+ assert( Success );
+#endif
+ EventBuffer.NumberOfEvents = 0;
+ }
+ EventBuffer.EventIndex = 0;
+ }
+
+ pEvent = EventBuffer.EventBuffer + EventBuffer.EventIndex;
+
+ //
+ // If Advance flag is set, we advance the pointer to the next
+ // record.
+ //
+ if (fAdvance) {
+ if (--(EventBuffer.NumberOfEvents)) {
+
+ switch (EVENT_TYPE(pEvent)) {
+
+ case KEY_EVENT:
+ case MOUSE_EVENT:
+ case WINDOW_BUFFER_SIZE_EVENT:
+ (EventBuffer.EventIndex)++;
+ break;
+
+ default:
+#if defined( DEBUG)
+ sprintf(DbgBuffer, "WARNING: unknown event type %X\n", EVENT_TYPE(pEvent));
+ OutputDebugString(DbgBuffer);
+#endif
+ (EventBuffer.EventIndex)++;
+ break;
+ }
+ }
+ }
+
+
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return pEvent;
+}
+
+
+
+
+
+void
+MouseEvent (
+ PMOUSE_EVENT_RECORD pEvent
+ )
+/*++
+
+Routine Description:
+
+ Processes mouse events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+
+Return Value:
+
+ None..
+
+--*/
+{
+
+}
+
+
+
+
+
+BOOL
+WindowEvent (
+ PWINDOW_BUFFER_SIZE_RECORD pEvent
+ )
+/*++
+
+Routine Description:
+
+ Processes window size change events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+
+Return Value:
+
+ None
+
+--*/
+{
+ return TRUE;
+}
+
+
+
+
+
+BOOL
+KeyEvent (
+ PKEY_EVENT_RECORD pEvent,
+ PKBDKEY pKey
+ )
+/*++
+
+Routine Description:
+
+ Processes key events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+ pKey - Supplies pointer to key structure to fill out.
+
+Return Value:
+
+ TRUE if key structured filled out, FALSE otherwise.
+
+--*/
+{
+ // static BOOL AltPressed = FALSE;
+
+ if (pEvent->bKeyDown) {
+
+ WORD Scan = pEvent->wVirtualKeyCode;
+
+ //
+ // Pressing the ALT key generates an event, but we filter this
+ // out.
+ //
+ if (Scan == VK_MENU) {
+ return FALSE;
+ }
+
+
+ if (Scan != VK_NUMLOCK && // NumLock
+ Scan != VK_CAPITAL && // Caps Lock
+ Scan != VK_SHIFT && // Shift
+ Scan != VK_CONTROL ) { // Ctrl
+
+ pKey->Unicode = pEvent->uChar.UnicodeChar;
+ pKey->Scancode = pEvent->wVirtualKeyCode;
+ pKey->Flags = pEvent->dwControlKeyState;
+
+//#if defined (DEBUG)
+// sprintf(DbgBuffer, " KEY: Scan %d '%c'\n", pKey->Scancode, pKey->Unicode );
+// OutputDebugString(DbgBuffer);
+//#endif
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ return FALSE;
+
+ }
+}
+
+
+BOOL
+PutEvent (
+ PINPUT_RECORD InputRecord
+ )
+{
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ //
+ // If no space at beginning of buffer, resize and shift right
+ //
+ if ( EventBuffer.EventIndex == 0 ) {
+
+ EventBuffer.EventBuffer = REALLOC( EventBuffer.EventBuffer,
+ (EventBuffer.MaxEvents + EVENT_INCREMENT) * sizeof(INPUT_RECORD));
+
+ if ( !EventBuffer.EventBuffer ) {
+ //CleanExit(1, 0);
+ }
+
+ memmove( EventBuffer.EventBuffer + EVENT_INCREMENT,
+ EventBuffer.EventBuffer ,
+ EventBuffer.NumberOfEvents * sizeof(INPUT_RECORD) );
+
+ EventBuffer.EventIndex = EVENT_INCREMENT;
+ }
+
+ //
+ // Add event
+ //
+ EventBuffer.EventIndex--;
+ EventBuffer.NumberOfEvents++;
+
+ memcpy( EventBuffer.EventBuffer + EventBuffer.EventIndex,
+ InputRecord,
+ sizeof(INPUT_RECORD ));
+
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return TRUE;
+}
diff --git a/private/utils/mep/help/htest/cons.h b/private/utils/mep/help/htest/cons.h
new file mode 100644
index 000000000..8dd1846e5
--- /dev/null
+++ b/private/utils/mep/help/htest/cons.h
@@ -0,0 +1,253 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ console.h
+
+Abstract:
+
+ Interface to the console-management functions for Win32 applications.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 30-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+
+
+
+//
+// Some common typedefs...
+//
+typedef ULONG ROW, *PROW; // row
+typedef ULONG COLUMN, *PCOLUMN; // column
+typedef DWORD KBDMODE, *PKBDMODE; // Keyboard mode
+typedef DWORD ATTRIBUTE, *PATTRIBUTE; // Screen Attribute
+typedef PVOID PSCREEN; // The screen
+
+
+
+//
+// Console Input Mode flags. They are the same as the NT flags
+//
+#define CONS_ENABLE_LINE_INPUT ENABLE_LINE_INPUT
+#define CONS_ENABLE_PROCESSED_INPUT ENABLE_PROCESSED_INPUT
+#define CONS_ENABLE_ECHO_INPUT ENABLE_ECHO_INPUT
+#define CONS_ENABLE_WINDOW_INPUT ENABLE_WINDOW_INPUT
+#define CONS_ENABLE_MOUSE_INPUT ENABLE_MOUSE_INPUT
+
+//
+// Cursor styles
+//
+#define CURSOR_STYLE_UNDERSCORE 0
+#define CURSOR_STYLE_BOX 1
+
+
+//
+// The information about a screen is retrieved in the following
+// structure:
+//
+typedef struct SCREEN_INFORMATION {
+ ROW NumberOfRows; // Number of rows
+ COLUMN NumberOfCols; // Number of columns
+ ROW CursorRow; // Cursor row position
+ COLUMN CursorCol; // Cursor column position
+} SCREEN_INFORMATION, *PSCREEN_INFORMATION;
+
+
+
+
+//
+// The information about each keystroke is returned in
+// the KBDKEY structure.
+//
+typedef struct KBDKEY {
+ WORD Unicode; // character unicode
+ WORD Scancode; // key scan code
+ DWORD Flags; // keyboard state flags
+} KBDKEY, *PKBDKEY;
+
+//
+// The following macros access particular fields within the
+// KBDKEY structure. They exist to facilitate porting of OS/2
+// programs.
+//
+#define KBDKEY_ASCII(k) (UCHAR)((k).Unicode)
+#define KBDKEY_SCAN(k) ((k).Scancode)
+#define KBDKEY_FLAGS(k) ((k).Flags)
+
+
+#define NEXT_EVENT_NONE 0
+#define NEXT_EVENT_KEY 1
+#define NEXT_EVENT_WINDOW 2
+
+//
+// ControlKeyState flags. They are the same as the NT status flags.
+//
+#define CONS_RIGHT_ALT_PRESSED RIGHT_ALT_PRESSED
+#define CONS_LEFT_ALT_PRESSED LEFT_ALT_PRESSED
+#define CONS_RIGHT_CTRL_PRESSED RIGHT_CTRL_PRESSED
+#define CONS_LEFT_CTRL_PRESSED LEFT_CTRL_PRESSED
+#define CONS_SHIFT_PRESSED SHIFT_PRESSED
+#define CONS_NUMLOCK_PRESSED NUMLOCK_ON
+#define CONS_SCROLLLOCK_PRESSED SCROLLLOCK_ON
+#define CONS_CAPSLOCK_PRESSED CAPSLOCK_ON
+#define CONS_ENHANCED_KEY ENHANCED_KEY
+
+
+
+
+
+//
+// Screen Management functions
+//
+PSCREEN
+consoleNewScreen (
+ void
+ );
+
+BOOL
+consoleCloseScreen (
+ PSCREEN pScreen
+ );
+
+PSCREEN
+consoleGetCurrentScreen (
+ void
+ );
+
+BOOL
+consoleSetCurrentScreen (
+ PSCREEN pScreen
+ );
+
+BOOL
+consoleGetScreenInformation (
+ PSCREEN pScreen,
+ PSCREEN_INFORMATION pScreenInformation
+ );
+
+BOOL
+consoleSetScreenSize (
+ PSCREEN Screen,
+ ROW Rows,
+ COLUMN Cols
+ );
+
+
+
+//
+// Cursor management
+//
+BOOL
+consoleSetCursor (
+ PSCREEN pScreen,
+ ROW Row,
+ COLUMN Col
+ );
+
+//
+// Cursor style
+//
+BOOL
+consoleSetCursorStyle (
+ PSCREEN pScreen,
+ ULONG Style
+ );
+
+
+
+//
+// Screen output functions
+//
+ULONG
+consoleWriteLine (
+ PSCREEN pScreen,
+ PVOID pBuffer,
+ ULONG BufferSize,
+ ROW Row,
+ COLUMN Col,
+ ATTRIBUTE Attribute,
+ BOOL Blank
+ );
+
+BOOL
+consoleShowScreen (
+ PSCREEN pScreen
+ );
+
+BOOL
+consoleClearScreen (
+ PSCREEN pScreen,
+ BOOL ShowScreen
+ );
+
+BOOL
+consoleSetAttribute (
+ PSCREEN pScreen,
+ ATTRIBUTE Attribute
+ );
+
+
+
+
+
+
+
+//
+// Input functions
+//
+BOOL
+consoleFlushInput (
+ void
+ );
+
+BOOL
+consoleIsKeyAvailable (
+ void
+ );
+
+BOOL
+consoleDoWindow (
+ void
+ );
+
+BOOL
+consoleGetKey (
+ PKBDKEY pKey,
+ BOOL fWait
+ );
+
+BOOL
+consolePutKey (
+ PKBDKEY pKey
+ );
+
+BOOL
+consolePutMouse (
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ );
+
+BOOL
+consolePeekKey (
+ PKBDKEY pKey
+ );
+
+BOOL
+consoleGetMode (
+ PKBDMODE Mode
+ );
+
+BOOL
+consoleSetMode (
+ KBDMODE Mode
+ );
diff --git a/private/utils/mep/help/htest/htest.c b/private/utils/mep/help/htest/htest.c
new file mode 100644
index 000000000..76b4d8dce
--- /dev/null
+++ b/private/utils/mep/help/htest/htest.c
@@ -0,0 +1,1441 @@
+/*** htest - help engine test harness
+*
+* Copyright <C> 1987, Microsoft Corporation
+*
+* Revision History:
+*
+* 15-Dec-1988 ln Added dump command
+* [] 21-Oct-1988 LN New Version
+*
+*************************************************************************/
+
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined (OS2)
+#define INCL_SUB
+#define INCL_DOSMODULEMGR
+#define INCL_DOSFILEMGR
+#define INCL_DOSMISC
+#include <ctype.h>
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include "cons.h"
+
+#include "help.h"
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+#if defined (OS2)
+#define HELPDLL_NAME "mshelp1.dll"
+#define HELPDLL_BASE "mshelp1"
+#else
+#define HELPDLL_NAME "mshelp.dll"
+#define HELPDLL_BASE "mshelp"
+#endif
+/*
+ * text color values
+ */
+#define BLACK 0
+#define BLUE 1
+#define GREEN 2
+#define CYAN 3
+#define RED 4
+#define MAGENTA 5
+#define BROWN 6
+#define WHITE 7
+#define GREY 8
+#define LIGHTBLUE 9
+#define LIGHTGREEN 10
+#define LIGHTCYAN 11
+#define LIGHTRED 12
+#define LIGHTMAGENTA 13
+#define YELLOW 14
+#define BRIGHTWHITE 15
+
+#define BUFSIZE 128 /* text buffer size */
+
+#define ISERROR(x) (((x).mh == 0L) && ((x).cn <= HELPERR_MAX))
+#define SETERROR(x,y) { (x).mh = 0L; (x).cn = y;}
+
+typedef void pascal (*void_F) (void);
+typedef int pascal (*int_F) (void);
+typedef ushort pascal (*ushort_F) (void);
+typedef f pascal (*f_F) (void);
+typedef char * pascal (*pchar_F) (void);
+typedef nc pascal (*nc_F) (void);
+typedef mh pascal (*mh_F) (void);
+
+#if !defined (HELP_HACK)
+
+#define HelpcLines ((int_F) (pEntry[P_HelpcLines ]))
+#define HelpClose ((void_F) (pEntry[P_HelpClose ]))
+#define HelpCtl ((void_F) (pEntry[P_HelpCtl ]))
+#define HelpDecomp ((f_F) (pEntry[P_HelpDecomp ]))
+#define HelpGetCells ((int_F) (pEntry[P_HelpGetCells ]))
+#define HelpGetInfo ((inf_F) (pEntry[P_HelpGetInfo ]))
+#define HelpGetLine ((ushort_F) (pEntry[P_HelpGetLine ]))
+#define HelpGetLineAttr ((ushort_F) (pEntry[P_HelpGetLineAttr]))
+#define HelpHlNext ((f_F) (pEntry[P_HelpHlNext ]))
+#define HelpLook ((ushort_F) (pEntry[P_HelpLook ]))
+#define HelpNc ((nc_F) (pEntry[P_HelpNc ]))
+#define HelpNcBack ((nc_F) (pEntry[P_HelpNcBack ]))
+#define HelpNcCb ((ushort_F) (pEntry[P_HelpNcCb ]))
+#define HelpNcCmp ((nc_F) (pEntry[P_HelpNcCmp ]))
+#define HelpNcNext ((nc_F) (pEntry[P_HelpNcNext ]))
+#define HelpNcPrev ((nc_F) (pEntry[P_HelpNcPrev ]))
+#define HelpNcRecord ((void_F) (pEntry[P_HelpNcRecord ]))
+#define HelpNcUniq ((nc_F) (pEntry[P_HelpNcUniq ]))
+#define HelpOpen ((nc_F) (pEntry[P_HelpOpen ]))
+#define HelpShrink ((void_F) (pEntry[P_HelpShrink ]))
+#define HelpSzContext ((f_F) (pEntry[P_HelpSzContext ]))
+#define HelpXRef ((pchar_F) (pEntry[P_HelpXRef ]))
+#define LoadFdb ((f_F) (pEntry[P_LoadFdb ]))
+#define LoadPortion ((mh_F) (pEntry[P_LoadPortion ]))
+
+#endif
+
+enum {
+ P_HelpcLines,
+ P_HelpClose,
+ P_HelpCtl,
+ P_HelpDecomp,
+ P_HelpGetCells,
+ P_HelpGetInfo,
+ P_HelpGetLine,
+ P_HelpGetLineAttr,
+ P_HelpHlNext,
+ P_HelpLook,
+ P_HelpNc,
+ P_HelpNcBack,
+ P_HelpNcCb,
+ P_HelpNcCmp,
+ P_HelpNcNext,
+ P_HelpNcPrev,
+ P_HelpNcRecord,
+ P_HelpNcUniq,
+ P_HelpOpen,
+ P_HelpShrink,
+ P_HelpSzContext,
+ P_HelpXRef,
+ P_LoadFdb,
+ P_LoadPortion,
+ LASTENTRYPOINT
+ } ENTRYPOINTS;
+
+#define NUM_ENTRYPOINTS (LASTENTRYPOINT - P_HelpcLines)
+
+
+typedef nc pascal (*PHF) (void);
+
+
+/*
+ * Global Data
+ */
+char buf[BUFSIZ]; /* text buffer */
+char cell[2] = {' ',0x1f}; /* background clearing cell */
+#define ColorByte cell[1]
+int curline; /* current line output */
+char *errTbl[] = {
+ "",
+ "help file not found",
+ "ReadHelpFile failed on header",
+ "to many open helpfiles",
+ "bad appeneded file",
+ "Not a help file",
+ "newer or incompatible help file",
+ "memory allocation failed"
+ };
+f fBoth = FALSE; /* both stdout & screen */
+f fEnable = FALSE; /* enable control lines in disp */
+int iNcCur; /* current index in ncTbl */
+int lastline;
+int lLast; /* last starting line number disp*/
+mh mhTopicCur; /* mem handle for most recent */
+uchar mpAttr[] = { /* on-screen color map */
+ 0x1f, /* 0: normal text */
+ 0x1c, /* 1: bold */
+ 0x1a, /* 2: italics */
+ 0x1e, /* 3: bold italics */
+ 0x7f, /* 4: underline */
+ 0x7c, /* 5: bold ul */
+ 0x7a, /* 6: italics ul */
+ 0x7e /* 7: bold italics ul */
+ };
+nc ncCur; /* most recently read in topic */
+nc ncTbl[MAXFILES]; /* table of open nc's */
+char far * pTopicCur; /* ptr to most recent topic */
+char *spaces = " \r\n";
+
+#if defined (OS2)
+HMODULE hModule;
+#else
+HANDLE hModule;
+#endif
+
+PHF pEntry[NUM_ENTRYPOINTS] = {0};
+#if defined (OS2)
+char * szEntryName[NUM_ENTRYPOINTS] = {
+ "_HelpcLines",
+ "_HelpClose",
+ "_HelpCtl",
+ "_HelpDecomp",
+ "_HelpGetCells",
+ "_HelpGetInfo",
+ "_HelpGetLine",
+ "_HelpGetLineAttr",
+ "_HelpHlNext",
+ "_HelpLook",
+ "_HelpNc",
+ "_HelpNcBack",
+ "_HelpNcCb",
+ "_HelpNcCmp",
+ "_HelpNcNext",
+ "_HelpNcPrev",
+ "_HelpNcRecord",
+ "_HelpNcUniq",
+ "_HelpOpen",
+ "_HelpShrink",
+ "_HelpSzContext",
+ "_HelpXRef",
+ "_LoadFdb",
+ "_LoadPortion",
+ };
+
+#else
+char * szEntryName[NUM_ENTRYPOINTS] = {
+ "HelpcLines",
+ "HelpClose",
+ "HelpCtl",
+ "HelpDecomp",
+ "HelpGetCells",
+ "HelpGetInfo",
+ "HelpGetLine",
+ "HelpGetLineAttr",
+ "HelpHlNext",
+ "HelpLook",
+ "HelpNc",
+ "HelpNcBack",
+ "HelpNcCb",
+ "HelpNcCmp",
+ "HelpNcNext",
+ "HelpNcPrev",
+ "HelpNcRecord",
+ "HelpNcUniq",
+ "HelpOpen",
+ "HelpShrink",
+ "HelpSzContext",
+ "HelpXRef",
+ "LoadFdb",
+ "LoadPortion",
+ };
+
+#endif
+
+// rjsa VIOMODEINFO screen;
+
+/*
+ * Forward declarations
+ */
+#define ASSERTDOS(x) assertDos(x, __FILE__, __LINE__)
+void pascal near assertDos (USHORT, CHAR *, USHORT);
+void pascal near cls (void);
+void pascal near dispCmd (int, int);
+void pascal near dumpCmd ();
+void pascal near dumpfileCmd ( char *);
+void pascal near fileCmd (char *);
+void pascal near helpCmd (void);
+void pascal near lookupCmd (char *, int);
+void pascal near outtext (char *, BYTE);
+void pascal near outtextat (char *, int, int, BYTE);
+uchar far * pascal near phrasecopy (uchar *, uchar far *);
+void pascal near xrefCmd (char *);
+
+#undef HelpDealloc
+#undef HelpLock
+#undef HelpUnlock
+
+void pascal far HelpDealloc (mh);
+void far * pascal far HelpLock (mh);
+void pascal far HelpUnlock (mh);
+
+f pascal near LoadFdb (mh, fdb far *);
+mh pascal near LoadPortion (USHORT, mh);
+//char far * pascal near hfstrcpy(char far *, char far *);
+//ushort pascal near hfstrlen(char far *);
+
+
+void LoadTheDll(void);
+USHORT WrtCellStr (PBYTE buf, int cb, int row, int col);
+USHORT WrtLineAttr( PBYTE buf, lineattr* rgAttr, int cb, int row, int col );
+USHORT WrtCharStrAtt (PBYTE pText, int cb, int row, int col, PBYTE pcolor);
+
+
+PSCREEN Scr;
+
+/*** main - main program
+*
+* Input:
+* Standard C main, all ignored
+*
+* Output:
+* Returns via exit()
+*
+*************************************************************************/
+void main(
+USHORT argc,
+char **argv
+) {
+char c;
+nc ncNull = {0,0};
+SCREEN_INFORMATION ScrInfo;
+/*
+ * parse any options
+ */
+if (argc > 1)
+ while ((** ++argv) == '-') {
+ c = *(++(*argv));
+ switch (toupper(c)) {
+ case 'B': /* -b: both screen and stdout */
+ fBoth = TRUE;
+ break;
+ default:
+ fputs ("Unknown switch ignored", stderr);
+ break;
+ }
+ }
+
+// InitializeGlobalState();
+Scr = consoleGetCurrentScreen();
+
+// Load help engine DLL and initialize pointers to entry
+// points.
+//
+LoadTheDll();
+
+#if defined(CLEAR)
+HelpInit();
+#endif
+
+/*
+ * Start by getting the current config & clearing screen.
+ */
+// rjsa screen.cb = sizeof(screen);
+// rjsa assertDos (VioGetMode (&screen, 0));
+// rjsa lastline = screen.row-1;
+consoleGetScreenInformation( Scr, &ScrInfo );
+lastline = ScrInfo.NumberOfRows-2;
+// lastline = 22;
+cls();
+helpCmd();
+/*
+ * main loop. Position at bottom of screen, and accept one command at at time
+ * from there. Interpret commands until done.
+ */
+do {
+ outtextat ("\r\n", lastline, 0, BRIGHTWHITE);
+ outtextat (spaces, lastline, 0, BRIGHTWHITE);
+ outtextat ("HTEST Command> ", lastline, 0, BRIGHTWHITE);
+ // rjsa VioSetCurPos (lastline, 15, 0);
+ consoleSetCursor(Scr, lastline, 16);
+ gets (buf);
+ cls ();
+ outtextat ("\r\n", lastline, 0, BRIGHTWHITE);
+ outtextat ("Processing: ", lastline, 0, LIGHTRED);
+ outtextat (buf, lastline, 12, BRIGHTWHITE);
+ outtextat ("\r\n", lastline, 0, BRIGHTWHITE);
+/*
+ * ctrl on/off
+ */
+ if (!strcmp (buf,"ctrl on")) {
+ fEnable = TRUE;
+ cls ();
+ outtextat ("Control Lines Displayed", 0, 0, BRIGHTWHITE);
+ }
+ else if (!strcmp (buf,"ctrl off")) {
+ fEnable = FALSE;
+ cls ();
+ outtextat ("Control Lines NOT Displayed", 0, 0, BRIGHTWHITE);
+ }
+/*
+ * disp
+ */
+ else if (!strcmp (buf,"disp"))
+ dispCmd (1,lastline);
+/*
+ * down
+ */
+ else if (!strcmp (buf,"down"))
+ dispCmd (lLast+1,lLast + lastline);
+/*
+ * dump
+ */
+ else if (!strncmp (buf, "dump ", 5))
+ dumpfileCmd(buf+5);
+ else if (!strcmp (buf,"dump"))
+ dumpCmd ();
+/*
+ * file newhelpfilename
+ */
+ else if (!strncmp (buf,"file ", 5))
+ fileCmd (buf+5);
+/*
+ * help
+ */
+ else if (!strcmp (buf,"help"))
+ helpCmd ();
+/*
+ * look helpstring
+ */
+ else if (!strncmp (buf,"look ", 5))
+ lookupCmd (buf+5,0);
+/*
+ * look
+ */
+ else if (!strcmp (buf,"look"))
+ lookupCmd (NULL,0);
+/*
+ * next
+ */
+ else if (!strcmp (buf,"next"))
+ lookupCmd (NULL,1);
+/*
+ * prev
+ */
+ else if (!strcmp (buf,"prev"))
+ lookupCmd (NULL,-1);
+/*
+ * up
+ */
+ else if (!strcmp (buf,"up")) {
+ lLast = max (1, lLast-1);
+ dispCmd (lLast,lLast + lastline);
+ }
+/*
+ * xref xrefnumber
+ */
+ else if (!strncmp (buf,"xref", 4))
+ xrefCmd (buf+4);
+/*
+ * + page down
+ */
+ else if (!strcmp (buf,"+")) {
+ lLast += lastline;
+ dispCmd (lLast,lLast + lastline);
+ }
+/*
+ * - page up
+ */
+ else if (!strcmp (buf,"-")) {
+ lLast = max (1, lLast - (lastline));
+ dispCmd (lLast,lLast + lastline);
+ }
+ }
+/*
+ * exit
+ */
+while (strncmp(buf,"exit",4));
+outtextat (spaces, lastline, 0, BRIGHTWHITE);
+HelpClose (ncNull);
+
+/* end main */}
+
+
+
+
+
+
+/*** dispCmd - display topic text
+*
+* displays the topic text on the screen.
+*
+* Input:
+* lStart - starting line
+* lEnd - ending line
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near dispCmd (
+int lStart,
+int lEnd
+) {
+char buf[BUFSIZ*2];
+lineattr rgAttr[BUFSIZ];
+int cb;
+int lineCur = 0;
+
+ HelpCtl (pTopicCur, fEnable);
+ cls ();
+ lLast = lStart;
+ while (lStart<lEnd) {
+ if (!isatty(_fileno(stdout)) || fBoth) {
+ cb = (int)HelpGetLine (lStart, BUFSIZ*2, (char far *)buf, pTopicCur);
+ if (cb == 0)
+ lStart = lEnd;
+ buf[cb-1] = '\r';
+ buf[cb] = '\n';
+ buf[cb+1] = 0;
+ outtext (buf, BLACK);
+ buf[cb-1] = 0;
+ }
+ if (isatty(_fileno(stdout)) || fBoth) {
+ cb = HelpGetLine(lStart, BUFSIZ*2, (char far*)buf, pTopicCur );
+ HelpGetLineAttr( lStart, BUFSIZ*sizeof(lineattr), rgAttr, pTopicCur );
+ WrtLineAttr(buf, rgAttr, cb, lineCur++, 0 );
+ }
+
+ //if (isatty(fileno(stdout)) || fBoth) {
+ // cb = HelpGetCells (lStart, BUFSIZ*2, buf, pTopicCur, mpAttr);
+ // if (cb == -1)
+ // lStart = lEnd;
+ // else
+ // ASSERTDOS (WrtCellStr (buf, cb, lineCur++, 0));
+ // }
+
+ lStart++;
+ }
+
+/* end dispCmd */}
+
+static char *szHS[] = { "HS_INDEX",
+ "HS_CONTEXTSTRINGS",
+ "HS_CONTEXTMAP",
+ "HS_KEYPHRASE",
+ "HS_HUFFTREE",
+ "HS_TOPICS",
+ "unused (6)",
+ "unused (7)",
+ "HS_NEXT" };
+
+/*** dumpCmd - process dump command
+*
+* Dumps the contents of the current help file
+*
+* NOTE:
+* This function uses all sorts of "internal" knowledge and calls to
+* do it's job.
+*
+* Input:
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near dumpCmd () {
+char buf[BUFSIZ];
+int cbKeyPhrase;
+fdb fdbLocal; /* local copy of fdb to use */
+uchar far *fpT;
+ushort far *fpW;
+int i;
+nc ncNext; /* nc init of appended file */
+//uchar uc;
+
+cls();
+ncNext = ncCur;
+while (ncNext.cn) {
+ if (LoadFdb (ncNext.mh, &fdbLocal)) {
+ sprintf (buf,"fhHelp %u\r\n", fdbLocal.fhHelp);
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"ncInit %08lx\r\n", fdbLocal.ncInit);
+ outtext (buf, BRIGHTWHITE);
+ for (i=0; i<HS_count; i++) {
+ sprintf (buf,"rgmhSections[%18s] %04x\r\n", szHS[i], fdbLocal.rgmhSections[i]);
+ outtext (buf, BRIGHTWHITE);
+ }
+ sprintf (buf,"ftype %02x\r\n", fdbLocal.ftype );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"fname %14s\r\n", fdbLocal.fname );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"foff %08lx\r\n", fdbLocal.foff );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"ncLink %08lx\r\n", fdbLocal.ncLink);
+ outtext (buf, BRIGHTWHITE);
+
+ sprintf (buf,"hdr.wMagic %04x\r\n", fdbLocal.hdr.wMagic );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.wVersion %04x\r\n", fdbLocal.hdr.wVersion );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.wFlags %04x\r\n", fdbLocal.hdr.wFlags );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.appChar %04x\r\n", fdbLocal.hdr.appChar );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.cTopics %04x\r\n", fdbLocal.hdr.cTopics );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.cContexts %04x\r\n", fdbLocal.hdr.cContexts );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.cbWidth %04x\r\n", fdbLocal.hdr.cbWidth );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.cPreDef %04x\r\n", fdbLocal.hdr.cPreDef );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.fname %s\r\n", fdbLocal.hdr.fname );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.reserved[0] %04x\r\n", fdbLocal.hdr.reserved[0]);
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.reserved[1] %04x\r\n", fdbLocal.hdr.reserved[1]);
+
+ for (i=0; i<HS_count; i++) {
+ sprintf (buf,"hdr.tbPos[%18s] %08lx\r\n", szHS[i], fdbLocal.hdr.tbPos[i]);
+ outtext (buf, BRIGHTWHITE);
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+/*
+ * Topic Index
+ * This is just a table of (long) offsets within the current file. We just
+ * report the values, and also calculate the size of each entry by looking
+ * at the position of the entry following.
+ */
+ fpT = HelpLock (LoadPortion( HS_INDEX ,ncNext.mh));
+ if (fpT) {
+ outtext ("Topic Index:\r\n", LIGHTRED);
+ for (i = 0; i < (int)fdbLocal.hdr.cTopics; i++) {
+ sprintf (buf, " %2d: %08lx, %ld bytes\r\n", i, ((long far *)fpT)[i], ((long far *)fpT)[i+1]-((long far *)fpT)[i]);
+ outtext (buf, BRIGHTWHITE);
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+ }
+/*
+ * context strings
+ * This is just a table of null terminated strings, in no particular order.
+ * We just list them out sequentially.
+ */
+ fpT = HelpLock (LoadPortion( HS_CONTEXTSTRINGS ,ncNext.mh));
+ if (fpT) {
+ outtext ("Context strings:\r\n", LIGHTRED);
+ for (i=0; i<(int)fdbLocal.hdr.cContexts; i++) {
+
+ sprintf (buf, " %03d: ", i);
+ // rjsa hfstrcpy ((char far *)buf+7, fpT);
+ strcpy ((char far *)buf+7, fpT);
+ strcat (buf, "\r\n");
+ outtext (buf, BRIGHTWHITE);
+
+ // rjsa fpT += hfstrlen(fpT) +1;
+ fpT += strlen(fpT) +1;
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+ }
+/*
+ * Context Map
+ * This is the mapping of context strings to actual topic numbers. The context
+ * strings map one to one to the entries in this table, which in turn contains
+ * indexes into the topic index at the head of the file. We just dump this
+ * table sequentially.
+ */
+ fpT = HelpLock (LoadPortion( HS_CONTEXTMAP ,ncNext.mh));
+ if (fpT) {
+ outtext ("Context map:\r\n", LIGHTRED);
+ outtext (" Ctx Topic\r\n",BRIGHTWHITE);
+ outtext (" --- -----\r\n",BRIGHTWHITE);
+ for (i=0; i<(int)fdbLocal.hdr.cContexts; i++) {
+ sprintf (buf, " %03d: %04d\r\n", i, ((ushort far *)fpT)[i]);
+ outtext (buf, BRIGHTWHITE);
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+ }
+/*
+ * keyword table
+ * This is a table of byte-prefixed strings, which we output in order,
+ * synthesizing the tokens that they would be in the text as well.
+ */
+ fpT = HelpLock (LoadPortion( HS_KEYPHRASE, ncNext.mh));
+ if (fpT) {
+ cbKeyPhrase = 0;
+ for (i=HS_HUFFTREE; i<HS_count; i++)
+ if (fdbLocal.hdr.tbPos[i]) {
+ cbKeyPhrase = (ushort)(fdbLocal.hdr.tbPos[i] - fdbLocal.hdr.tbPos[HS_KEYPHRASE]);
+ break;
+ }
+
+ outtext ("Keyphrase Table:\r\n", LIGHTRED);
+ outtext (" Token Phrase\r\n",BRIGHTWHITE);
+ outtext (" ----- ------\r\n",BRIGHTWHITE);
+ i = 0;
+ fpT += 1024 * sizeof (PVOID);
+ fpW = (ushort far *)(fpT + cbKeyPhrase);
+ while (fpT < (uchar far *)fpW) {
+ sprintf (buf, " %04x: ", i+(C_KEYPHRASE0 << 8));
+ fpT = phrasecopy (buf+8, fpT);
+ strcat (buf, "\r\n");
+ outtext (buf, BRIGHTWHITE);
+ i++;
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+ }
+/*
+ * huffman table
+ * here we try to get fancy and output some information about the table format
+ */
+ fpW = HelpLock (LoadPortion( HS_HUFFTREE, ncNext.mh));
+ if (fpW) {
+ outtext ("Huffman Tree:\r\n", LIGHTRED);
+ i = 0;
+ while (*fpW) {
+ sprintf (buf, " 0x%03x: 0x%04x, %s\r\n", i++, *fpW, *fpW & 0x8000 ? "Leaf" : "Node");
+ fpW++;
+ outtext (buf, BRIGHTWHITE);
+ }
+ }
+ outtext ("===== ===== =====\r\n", YELLOW);
+ ncNext = fdbLocal.ncLink;
+ }
+ else {
+ sprintf(buf, "Cannot load fdb for %08lx\r\n",ncCur);
+ outtext (buf, LIGHTRED);
+ return;
+ }
+ }
+/* end dumpCmd */}
+
+/*** dumpfileCmd - process dump command
+*
+* Dumps the contents of the current help file
+*
+* NOTE:
+* This function uses all sorts of "internal" knowledge and calls to
+* do it's job.
+*
+* Input:
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near dumpfileCmd (char *fname) {
+char buf[BUFSIZ];
+int cbKeyPhrase;
+fdb fdbLocal; /* local copy of fdb to use */
+uchar far *fpT;
+ushort far *fpW;
+int i;
+nc ncNext; /* nc init of appended file */
+//uchar uc;
+
+FILE* fh = fopen(fname, "w");
+if (!fh) {
+ return;
+}
+ncNext = ncCur;
+while (ncNext.cn) {
+ if (LoadFdb (ncNext.mh, &fdbLocal)) {
+ sprintf (buf,"fhHelp %u\r\n", fdbLocal.fhHelp);
+ fprintf( fh, buf );
+ sprintf (buf,"ncInit %08lx\r\n", fdbLocal.ncInit);
+ fprintf( fh, buf );
+ for (i=0; i<HS_count; i++) {
+ sprintf (buf,"rgmhSections[%18s] %04x\r\n", szHS[i], fdbLocal.rgmhSections[i]);
+ fprintf( fh, buf );
+ }
+ sprintf (buf,"ftype %02x\r\n", fdbLocal.ftype );
+ fprintf( fh, buf );
+ sprintf (buf,"fname %14s\r\n", fdbLocal.fname );
+ fprintf( fh, buf );
+ fprintf( fh, buf );
+ sprintf (buf,"foff %08lx\r\n", fdbLocal.foff );
+ fprintf( fh, buf );
+ sprintf (buf,"ncLink %08lx\r\n", fdbLocal.ncLink);
+ fprintf( fh, buf );
+
+ sprintf (buf,"hdr.wMagic %04x\r\n", fdbLocal.hdr.wMagic );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.wVersion %04x\r\n", fdbLocal.hdr.wVersion );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.wFlags %04x\r\n", fdbLocal.hdr.wFlags );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.appChar %04x\r\n", fdbLocal.hdr.appChar );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.cTopics %04x\r\n", fdbLocal.hdr.cTopics );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.cContexts %04x\r\n", fdbLocal.hdr.cContexts );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.cbWidth %04x\r\n", fdbLocal.hdr.cbWidth );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.cPreDef %04x\r\n", fdbLocal.hdr.cPreDef );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.fname %s\r\n", fdbLocal.hdr.fname );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.reserved[0] %04x\r\n", fdbLocal.hdr.reserved[0]);
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.reserved[1] %04x\r\n", fdbLocal.hdr.reserved[1]);
+
+ for (i=0; i<HS_count; i++) {
+ sprintf (buf,"hdr.tbPos[%18s] %08lx\r\n", szHS[i], fdbLocal.hdr.tbPos[i]);
+ fprintf( fh, buf );
+ }
+ fprintf( fh,"----- ----- -----\r\n" );
+/*
+ * Topic Index
+ * This is just a table of (long) offsets within the current file. We just
+ * report the values, and also calculate the size of each entry by looking
+ * at the position of the entry following.
+ */
+ fpT = HelpLock (LoadPortion( HS_INDEX ,ncNext.mh));
+ if (fpT) {
+ fprintf( fh,"Topic Index:\r\n" );
+ for (i = 0; i < (int)fdbLocal.hdr.cTopics; i++) {
+ sprintf (buf, " %2d: %08lx, %ld bytes\r\n", i, ((long far *)fpT)[i], ((long far *)fpT)[i+1]-((long far *)fpT)[i]);
+ fprintf( fh, buf );
+ }
+ fprintf( fh,"----- ----- -----\r\n" );
+ }
+/*
+ * context strings
+ * This is just a table of null terminated strings, in no particular order.
+ * We just list them out sequentially.
+ */
+ fpT = HelpLock (LoadPortion( HS_CONTEXTSTRINGS ,ncNext.mh));
+ if (fpT) {
+ fprintf( fh, "Context strings:\r\n" );
+ for (i=0; i<(int)fdbLocal.hdr.cContexts; i++) {
+
+ sprintf (buf, " %03d: ", i);
+ // rjsa hfstrcpy ((char far *)buf+7, fpT);
+ strcpy ((char far *)buf+7, fpT);
+ strcat (buf, "\r\n");
+ fprintf( fh, buf );
+
+ // rjsa fpT += hfstrlen(fpT) +1;
+ fpT += strlen(fpT) +1;
+ }
+ fprintf( fh,"----- ----- -----\r\n" );
+ }
+/*
+ * Context Map
+ * This is the mapping of context strings to actual topic numbers. The context
+ * strings map one to one to the entries in this table, which in turn contains
+ * indexes into the topic index at the head of the file. We just dump this
+ * table sequentially.
+ */
+ fpT = HelpLock (LoadPortion( HS_CONTEXTMAP ,ncNext.mh));
+ if (fpT) {
+ fprintf( fh, "Context map:\r\n" );
+ fprintf( fh, " Ctx Topic\r\n" );
+ fprintf( fh, " --- -----\r\n" );
+ for (i=0; i<(int)fdbLocal.hdr.cContexts; i++) {
+ sprintf (buf, " %03d: %04d\r\n", i, ((ushort far *)fpT)[i]);
+ fprintf( fh, buf );
+ }
+ fprintf( fh, "----- ----- -----\r\n" );
+ }
+/*
+ * keyword table
+ * This is a table of byte-prefixed strings, which we output in order,
+ * synthesizing the tokens that they would be in the text as well.
+ */
+ fpT = HelpLock (LoadPortion( HS_KEYPHRASE, ncNext.mh));
+ if (fpT) {
+ cbKeyPhrase = 0;
+ for (i=HS_HUFFTREE; i<HS_count; i++)
+ if (fdbLocal.hdr.tbPos[i]) {
+ cbKeyPhrase = (ushort)(fdbLocal.hdr.tbPos[i] - fdbLocal.hdr.tbPos[HS_KEYPHRASE]);
+ break;
+ }
+
+ fprintf( fh, "Keyphrase Table:\r\n" );
+ fprintf( fh, " Token Phrase\r\n" );
+ fprintf( fh, " ----- ------\r\n" );
+ i = 0;
+ fpT += 1024 * sizeof (PVOID);
+ fpW = (ushort far *)(fpT + cbKeyPhrase);
+ while (fpT < (uchar far *)fpW) {
+ sprintf (buf, " %04x: ", i+(C_KEYPHRASE0 << 8));
+ fpT = phrasecopy (buf+8, fpT);
+ strcat (buf, "\r\n");
+ fprintf( fh, buf );
+ i++;
+ }
+ fprintf( fh,"----- ----- -----\r\n" );
+ }
+/*
+ * huffman table
+ * here we try to get fancy and output some information about the table format
+ */
+ fpW = HelpLock (LoadPortion( HS_HUFFTREE, ncNext.mh));
+ if (fpW) {
+ fprintf( fh, "Huffman Tree:\r\n" );
+ i = 0;
+ while (*fpW) {
+ sprintf (buf, " 0x%03x: 0x%04x, %s\r\n", i++, *fpW, *fpW & 0x8000 ? "Leaf" : "Node");
+ fpW++;
+ fprintf( fh, buf );
+ }
+ }
+ fprintf( fh, "===== ===== =====\r\n" );
+ ncNext = fdbLocal.ncLink;
+ }
+ else {
+ sprintf(buf, "Cannot load fdb for %08lx\r\n",ncCur);
+ fprintf( fh, buf );
+ fclose(fh);
+ return;
+ }
+ }
+/* end dumpCmd */}
+
+
+/*** fileCmd - process file command
+*
+* Opens the help file specified.
+*
+* Input:
+* pName = name of help file to be added
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near fileCmd (
+char *pName
+) {
+char buf[BUFSIZ];
+int i;
+nc ncInit;
+
+sprintf (buf,"Opening %s...\r\n",pName);
+outtext (buf, BRIGHTWHITE);
+/*
+ * search file table for available slot
+ */
+for (i=0; i<MAXFILES; i++)
+ if (!ncTbl[i].cn)
+ break;
+if (i >= MAXFILES) {
+ sprintf(buf, "Cannot open %s: htest's open file limit exceeded\r\n",pName);
+ outtext (buf, LIGHTRED);
+ return;
+ }
+
+iNcCur = i;
+
+ncInit = HelpOpen(pName);
+
+for (i=0; i<MAXFILES; i++)
+ if ((ncTbl[i].mh == ncInit.mh) && (ncTbl[i].cn == ncInit.cn)) {
+ iNcCur = i;
+ sprintf (buf, "File #%d; Initial Context: 0x%04lx (file already open)\r\n",iNcCur,ncInit);
+ outtext (buf, BRIGHTWHITE);
+ return;
+ }
+
+if (ISERROR(ncInit)) {
+ sprintf(buf, "Cannot open %s: 0x%04lx, %s\r\n",pName,ncInit, errTbl[ncInit.cn]);
+ outtext (buf, LIGHTRED);
+ return;
+ }
+/*
+ * output initial context, and the available memory
+ */
+ncCur = ncTbl[iNcCur] = ncInit;
+sprintf (buf, "File #%d; Initial Context: 0x%04lx\r\n",iNcCur,ncInit.cn);
+outtext (buf, BRIGHTWHITE);
+
+lookupCmd(NULL, 0);
+/* end fileCmd */}
+
+/*** helpCmd - display help on commands
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near helpCmd () {
+
+outtext ("HTEST - Help Engine Test Harness\r\n", BRIGHTWHITE);
+outtext ("\r\n", BRIGHTWHITE);
+outtext ("Comands:\r\n", BRIGHTWHITE);
+outtext ("\r\n", BRIGHTWHITE);
+outtext ("ctrl on/off - turn on/off display of control lines\r\n", BRIGHTWHITE);
+outtext ("disp - display first screen of most recently read topic\r\n", BRIGHTWHITE);
+outtext ("down - move ahead one line in topic and display\r\n", BRIGHTWHITE);
+outtext ("dump - dump file info (very large)\r\n", BRIGHTWHITE);
+outtext ("exit - exit htest\r\n", BRIGHTWHITE);
+outtext ("file x - open new help file, or make help file current\r\n", BRIGHTWHITE);
+outtext ("help - display this screen\r\n", BRIGHTWHITE);
+outtext ("look x - loop up context string & fetch topic\r\n", BRIGHTWHITE);
+outtext ("next - fetch next physical topic\r\n", BRIGHTWHITE);
+outtext ("prev - fetch previous physical topic\r\n", BRIGHTWHITE);
+outtext ("up - move back one line in topic and display\r\n", BRIGHTWHITE);
+outtext ("xref x - display all xrefs in current topic, or look up #x\r\n", BRIGHTWHITE);
+outtext ("+ - move & redisplay one page down\r\n", BRIGHTWHITE);
+outtext ("- - move & redisplay one page up\r\n", BRIGHTWHITE);
+/* end helpCmd */}
+
+/*** lookupCmd - process file command
+*
+* Looks up the specified string in the current helpfile, or the next help
+* topic.
+*
+* Input:
+* pString = help string to look up
+* dir = direction: 0= look up string, 1=get next, -1= get previous
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near lookupCmd (
+char *pString,
+int dir
+) {
+char buf[BUFSIZ];
+unsigned cbCompressed;
+unsigned cbUncompressed;
+char far *pCompressed;
+/*
+ * Start with the simple look up of the conetxt to get an nc. Report on
+ * failure.
+ */
+if (pString)
+ ncCur = HelpNc(pString,ncTbl[iNcCur]);
+else if (dir>0) {
+ if (!ncCur.cn)
+ ncCur = ncTbl[iNcCur];
+ else
+ ncCur = HelpNcNext(ncCur);
+ }
+else if (dir<0) {
+ if (!ncCur.cn)
+ ncCur = ncTbl[iNcCur];
+ else if (ncCur.cn != ncTbl[iNcCur].cn)
+ ncCur = HelpNcPrev(ncCur);
+ }
+else
+ ncCur = ncTbl[iNcCur];
+
+if (!ncCur.cn) {
+ outtext ("Lookup Failed: HelpNc/HelpNcNext/HelpNcPrev returned 0", LIGHTRED);
+ return;
+ }
+/*
+ * It exists. Indicate what file we're looking in, what we found, and the
+ * nc that was returned
+ */
+sprintf (buf, "File #%d; Looking up:%s\r\n",iNcCur,
+ pString ? (*pString ? pString : "local context")
+ : (dir ? ((dir>0) ? "**NEXT**" : "**PREV**")
+ : "current"));
+outtext (buf, BRIGHTWHITE);
+sprintf (buf, "nc returned = %08lx\r\n",ncCur.cn);
+outtext (buf, BRIGHTWHITE);
+/*
+ * Free up memory for previously current topic
+ */
+if (mhTopicCur)
+ free(mhTopicCur);
+/*
+ * Get the compressed memory size required, and report it. Alloc it.
+ */
+cbCompressed = HelpNcCb(ncCur);
+sprintf (buf, "size of compressed topic = %d\r\n",cbCompressed);
+outtext (buf, BRIGHTWHITE);
+pCompressed = malloc(cbCompressed);
+/*
+ * read in the compressed topic, getting the size required for the
+ * uncompressed results. Report that, and allocate it.
+ */
+cbUncompressed = HelpLook(ncCur,pCompressed);
+sprintf (buf, "size of UNcompressed topic = %d\r\n",cbUncompressed);
+outtext (buf, BRIGHTWHITE);
+mhTopicCur = malloc(cbUncompressed);
+//pTopicCur = MAKEP (mhTopicCur, 0);
+pTopicCur = mhTopicCur;
+/*
+ * Decompress the topic.
+ */
+HelpDecomp(pCompressed,pTopicCur,ncCur);
+outtext ("Decompressed\r\n", BRIGHTWHITE);
+/*
+ * exercise SzContext and cLines routines, reporting results
+ */
+HelpSzContext(buf,ncCur);
+strcat (buf, "\r\n");
+outtext (buf, BRIGHTWHITE);
+sprintf(buf,"%d lines\r\n", HelpcLines(pTopicCur));
+outtext (buf, BRIGHTWHITE);
+/*
+ * Report the amount of available memory at this point, and then free up the
+ * compressed text
+ */
+free(pCompressed);
+
+/* end lookupCmd */}
+
+/*** xrefCmd - process xref command
+*
+* Display or execute cross reference
+*
+* Input:
+* pText = pointer to ascii text which, if a non-zero number, indicates the
+* xref to execute. If zero, display all
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near xrefCmd (
+char *pText
+) {
+hotspot hsCur; /* hot spot definition */
+int i; /* working counter */
+int iReq; /* request value */
+char *pT; /* temp pointer */
+
+iReq = atoi (pText);
+hsCur.line = hsCur.col = 1;
+i = 1;
+while (HelpHlNext(0,pTopicCur,&hsCur)) {
+/*
+ * if not explicit request, then list as much as we can
+ */
+ if (!iReq) {
+ sprintf (buf, "Xref [%d] @ line: %05d columns %02d to %02d = "
+ ,i
+ ,hsCur.line
+ ,hsCur.col
+ ,hsCur.ecol);
+ pT = buf + strlen(buf);
+ if (*hsCur.pXref)
+ while (*pT++ = *hsCur.pXref++);
+ else
+ sprintf(pT, "Local >> topic # 0x%04x ",*(ushort far *)(hsCur.pXref+1));
+ strcat (buf, "\r\n");
+ outtext (buf, LIGHTGREEN);
+ }
+ else if (i == iReq) {
+ pT = buf;
+ if (*hsCur.pXref)
+ while (*pT++ = *hsCur.pXref++);
+ else {
+ *pT++ = *hsCur.pXref++;
+ *pT++ = *hsCur.pXref++;
+ *pT++ = *hsCur.pXref++;
+ }
+ lookupCmd (buf, 0);
+ return;
+ }
+ ++i;
+ hsCur.col = hsCur.ecol+(ushort)1;
+ }
+/* end xrefCmd */}
+
+/*** outtext - output text with specific colors
+*
+* sets the forground color and location as appropriate, and displays the
+* desired text. Checks for redirection, and if redirected, just outputs the
+* text to stdout.
+*
+* Input:
+* ptext = pointer to text to output
+* color = color to use
+*
+* Output:
+* Returns
+*
+*************************************************************************/
+void pascal near outtext (
+char *pText,
+BYTE color
+) {
+outtextat (pText, curline++, 0, color);
+if (curline >= lastline) {
+ if (isatty(_fileno(stdout))
+ && !fBoth) {
+
+ outtextat ("More...", lastline, 0, BRIGHTWHITE);
+ // rjsa VioSetCurPos (lastline, 8, 0);
+#if defined (OS2)
+ consoleSetCursor(lastline,8);
+#else
+ consoleSetCursor(Scr,lastline,8);
+#endif
+ gets (buf);
+ }
+ curline = 0;
+ cls ();
+ }
+
+/* end outtext */}
+
+/*** outtextat - put text with specific colors at a specific place
+*
+* sets the forground color and location as appropriate, and displays the
+* desired text. Checks for redirection, and if redirected, just outputs the
+* text to stdout.
+*
+* Input:
+* ptext = pointer to text to output
+* col = column to put into
+* color = color to use
+*
+* Output:
+* Returns
+*
+*************************************************************************/
+void pascal near outtextat (
+char *pText,
+int line,
+int col,
+BYTE color
+) {
+char *pEol; /* ptr to nl, if present */
+int len;
+
+color |= (ColorByte & 0xf0);
+if ((isatty(_fileno(stdout)) || fBoth) && (line <= lastline)) {
+ len = strlen(pText);
+ if (pEol = strchr (pText, '\r'))
+ *pEol = 0;
+ // rjsa VioWrtCharStrAtt (pText, strlen(pText), line, col, (PBYTE)&color, 0);
+ WrtCharStrAtt (pText, strlen(pText), line, col, (PBYTE)&color);
+
+ if (pEol)
+ *pEol = '\r';
+ }
+if (!isatty(_fileno(stdout)) || fBoth)
+ printf ("%s",pText);
+/* end outtextat */}
+
+/*** assertDos - asserts that a dos call returned a zero
+*
+* Just prints the number passed it if non-zero, and quits
+*
+* Input:
+* Return code from a dos call
+*
+* Output:
+* Returns only if zero passed in
+*
+*************************************************************************/
+void pascal near assertDos (
+USHORT rv,
+CHAR * pFile,
+USHORT LineNo
+) {
+if (rv) {
+ printf ("assertDos: %u (0x%04x) File %s, line %u\n", rv, rv, pFile, LineNo);
+ exit (1);
+ }
+/* end assertDos*/}
+
+/*** cls - clear screen
+*
+* Clear screen to current backround color
+*
+* Input:
+* none
+*
+* Output:
+* Returns screen clear
+*
+*************************************************************************/
+void pascal near cls () {
+curline = 0;
+// rjsa VioScrollUp (0, 0, 0xffff, 0xffff, 0xffff, cell, 0);
+consoleSetAttribute( Scr, 0x1f );
+consoleClearScreen(Scr, TRUE);
+/* end cls */}
+
+/*** phrasecopy - copy a keyword phrase from the table
+*
+* Copies a byte-length-prefixed string from far memory to a null terminated
+* string in near memory.
+*
+* Input:
+* dst - near pointer to destination
+* src - far pointer to source
+*
+* Output:
+* Returns far pointer to byte following source string
+*
+*************************************************************************/
+uchar far * pascal near phrasecopy (
+uchar *dst,
+uchar far *src
+) {
+register int i;
+
+if (i = (int)*src++)
+ while (i--)
+ *dst++ = *src++;
+*dst = 0;
+return src;
+/* end phrasecopy */}
+
+
+
+void far * pascal HelpLock(mhCur)
+mh mhCur;
+{
+//return MAKEP(mhCur,0);
+return mhCur;
+}
+
+void pascal HelpUnlock(mhCur)
+mh mhCur;
+{
+ mhCur;
+}
+
+void pascal HelpDealloc(mhCur)
+mh mhCur;
+{
+if (mhCur)
+ free(mhCur);
+}
+
+
+
+
+USHORT WrtCellStr (PBYTE buf, int cb, int row, int col) {
+ int cl = col;
+ //consoleSetCursor(Scr,row,col);
+ while (cb) {
+ UCHAR c;
+ UCHAR attr;
+
+ c = *buf++;
+ attr = *buf++;
+
+ //consoleSetAttribute(Scr,attr);
+ //consoleWrite(Scr,&c,1);
+
+ consoleWriteLine( Scr, &c, 1, row, cl, attr, FALSE );
+ cl++;
+
+ cb -= 2;
+ }
+ consoleShowScreen(Scr);
+ return 0;
+}
+
+
+USHORT WrtLineAttr ( PBYTE pText,
+ lineattr *rgAttr,
+ int cb,
+ int row,
+ int col
+ ) {
+
+ lineattr *Attr = rgAttr;
+ char *p = pText;
+ int l = cb;
+ int len;
+
+ consoleSetCursor(Scr, row, col );
+
+ while (cb > 0) {
+
+ if ( Attr->cb == 0xFFFF || Attr->attr == 0xFFFF ) {
+ len = cb;
+ } else {
+ len = Attr->cb;
+ }
+
+ outtextat (p, row, col, mpAttr[Attr->attr] );
+ col += len;
+ p += len;
+ cb -= len;
+ Attr++;
+
+ }
+ return (USHORT)l;
+}
+
+
+
+USHORT WrtCharStrAtt (PBYTE pText, int cb, int row, int col, PBYTE pcolor) {
+ //consoleSetCursor(Scr,row,col);
+ //consoleSetAttribute(Scr,*pcolor);
+ //consoleWrite( Scr,pText, cb );
+ consoleWriteLine( Scr, pText, cb, row, col, *pcolor, FALSE );
+ consoleShowScreen(Scr);
+ return 0;
+}
+
+/**********************************************************************
+ *
+ * LoadTheDll
+ *
+ * Loads the help engine dll (mshelp.dll) and initializes the
+ * pointers to the dll's entry points.
+ *
+ **********************************************************************/
+
+void
+LoadTheDll (
+ void) {
+
+
+#if defined (OS2)
+ USHORT rc;
+ CHAR szFullName[256];
+ CHAR szErrorName[256];
+ USHORT i;
+
+
+ strcpy(szFullName, HELPDLL_BASE);
+ strcpy(szErrorName, HELPDLL_NAME);
+
+ ASSERTDOS(rc = DosLoadModule(szErrorName,
+ 256,
+ szFullName,
+ &hModule));
+
+
+ for (i=0; i<LASTENTRYPOINT; i++) {
+ ASSERTDOS (rc = DosQueryProcAddr(hModule,
+ 0L,
+ szEntryName[i],
+ (PFN*)&(pEntry[i])));
+ }
+#else
+
+#if defined (HELP_HACK)
+
+ //pEntry[0] = (PHF)HelpcLines;
+ //pEntry[1] = (PHF)HelpClose;
+ //pEntry[2] = (PHF)HelpCtl;
+ //pEntry[3] = (PHF)HelpDecomp;
+ //pEntry[4] = (PHF)HelpGetCells;
+ //pEntry[5] = (PHF)HelpGetInfo;
+ //pEntry[6] = (PHF)HelpGetLine;
+ //pEntry[7] = (PHF)HelpGetLineAttr;
+ //pEntry[8] = (PHF)HelpHlNext;
+ //pEntry[9] = (PHF)HelpLook;
+ //pEntry[10] = (PHF)HelpNc;
+ //pEntry[11] = (PHF)HelpNcBack;
+ //pEntry[12] = (PHF)HelpNcCb;
+ //pEntry[13] = (PHF)HelpNcCmp;
+ //pEntry[14] = (PHF)HelpNcNext;
+ //pEntry[15] = (PHF)HelpNcPrev;
+ //pEntry[16] = (PHF)HelpNcRecord;
+ //pEntry[17] = (PHF)HelpNcUniq;
+ //pEntry[18] = (PHF)HelpOpen;
+ //pEntry[19] = (PHF)HelpShrink;
+ //pEntry[20] = (PHF)HelpSzContext;
+ //pEntry[21] = (PHF)HelpXRef;
+ //pEntry[22] = (PHF)LoadFdb;
+ //pEntry[23] = (PHF)LoadPortion;
+
+
+
+#else
+ USHORT i;
+ hModule = LoadLibrary(HELPDLL_NAME);
+ for (i=0; i<LASTENTRYPOINT; i++) {
+ pEntry[i] = (PHF)GetProcAddress(hModule, (LPSTR)szEntryName[i]);
+ }
+#endif
+
+#endif
+}
diff --git a/private/utils/mep/help/htest/makefile b/private/utils/mep/help/htest/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/help/htest/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/help/htest/sources b/private/utils/mep/help/htest/sources
new file mode 100644
index 000000000..dbc302203
--- /dev/null
+++ b/private/utils/mep/help/htest/sources
@@ -0,0 +1,18 @@
+MAJORCOMP=sdktools
+MINORCOMP=htest
+
+TARGETNAME=cons
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=.;..\inc;..\..\inc;\nt\private\sdktools\ztools\inc
+
+
+SOURCES=cons.c
+
+
+UMAPPL=htest
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT -DHELP_HACK
+UMTYPE=console
+UMLIBS= obj\*\cons.lib ..\mshelp\obj\*\mshelp.lib ..\enginlib\obj\*\engine.lib \nt\private\sdktools\ztools\src\obj\*\ztools.lib
diff --git a/private/utils/mep/help/inc/farutil.h b/private/utils/mep/help/inc/farutil.h
new file mode 100644
index 000000000..ff41ac36e
--- /dev/null
+++ b/private/utils/mep/help/inc/farutil.h
@@ -0,0 +1,30 @@
+/*************************************************************************
+**
+** farutil.h - procedure definitions for farutil package
+**
+** Copyright <C> 1988, Microsoft Corporation
+**
+** Purpose:
+**
+** Revision History:
+**
+** [] 08-May-1988 LN Created
+**
+*************************************************************************/
+typedef char f;
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+
+char far * pascal far farAlloc(ulong);
+void pascal far farFree (char far *);
+uchar far * pascal far farMemset(uchar far *, uchar, ushort);
+uchar far * pascal far farMove (uchar far *, uchar far *, ushort);
+uchar far * pascal far farMoveDn (uchar far *, uchar far *, ushort);
+uchar far * pascal far farMoveUp (uchar far *, uchar far *, ushort);
+int pascal far farRead (int, uchar far *, int);
+int pascal far farStrcmp (uchar far *, uchar far *);
+int pascal far farStrncmp (uchar far *, uchar far *, int);
+uchar far * pascal far farStrcpy (uchar far *, uchar far *);
+int pascal far farStrlen (uchar far *);
+int pascal far farWrite (int, uchar far *, int);
diff --git a/private/utils/mep/help/inc/help.h b/private/utils/mep/help/inc/help.h
new file mode 100644
index 000000000..4ba09bf2e
--- /dev/null
+++ b/private/utils/mep/help/inc/help.h
@@ -0,0 +1,235 @@
+/*
+** help.h
+**
+** typedefs & definitions used in the help system and by those who use it.
+**
+** define:
+** HOFFSET - to define buffer pointers (PB's) as handle/offset, else
+** they are defined as void far *.
+*/
+typedef char f; /* boolean */
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+
+/*
+** lineattr
+** external representation of line attributes, as returned by HelpGetLineAttr
+*/
+typedef struct lineattr { /* LA */
+ ushort attr; /* attribute index */
+ ushort cb; /* count of bytes */
+ } lineattr;
+/*
+** mh
+** a memory handle is defined for use with systems that use dynamic, moveable
+** memory. It is long, so that in simple cases where memory is NOT moveable,
+** the handle can contain the far pointer to the base.
+*/
+typedef void * mh; /* dynamic memory handle */
+/*
+** nc
+** a context number is a unique id associated with each context string.
+**
+** fhnc returns the file memory handle from the nc
+** fLocal returns TRUE if the context is a uniq context number (local, or
+** result of explicit uniq call.
+*/
+typedef struct _nc {
+ mh mh;
+ ulong cn;
+ } nc ; /* context number */
+// rjsa #define fmhnc(x) ((unsigned)(((unsigned long)x & 0xffff0000L) >> 16))
+#define fmhnc(x) ((x).mh)
+#define fUniq(x) ((x).cn & 0x8000)
+
+/*
+** topichdr
+** header placed (by HelpDecomp) at the begining of every decompressed topic
+*/
+typedef struct topichdr { /* TH */
+ uchar appChar; /* app-specific character const */
+ uchar linChar; /* character for line removal */
+ uchar ftype; /* source file type */
+ ushort lnCur; /* line number last accessed */
+ ushort lnOff; /* offset into topic for that line*/
+ } topichdr;
+
+/*
+** hotspot
+** defines the position of an embedded cross reference, or "hotspot". Used by
+** HelpHlNext and HelpXRef
+*/
+typedef struct hotspot { /* HS */
+ ushort line; /* the topic line with an xref */
+ ushort col; /* the starting column of xref */
+ ushort ecol; /* the ending columng of xref */
+ uchar far *pXref; /* pointer to xref string */
+ } hotspot;
+/*
+** helpheader
+** This defines the actual structure of a help file header. Provided here
+** for HelpGetInfo
+*/
+#define HS_count 9 /* number-1 of sections defined */
+
+#pragma pack(1)
+typedef struct helpheader { /* HH */
+ ushort wMagic; /* word indicating help file */
+ ushort wVersion; /* helpfile version */
+ ushort wFlags; /* flags */
+ ushort appChar; /* application specific char */
+ ushort cTopics; /* count of topics */
+ ushort cContexts; /* count of context strings */
+ ushort cbWidth; /* fixed width */
+ ushort cPreDef; /* count of pre-defined contexts*/
+ uchar fname[14]; /* base file name */
+ ushort reserved[2]; /* unused */
+ ulong tbPos[HS_count]; /* positions for file sections */
+ } helpheader;
+#pragma pack()
+/*
+** fdb
+** Dynamically allocated structure which is created for each open help file.
+** Remains allocated for the life of the file.
+**
+** rgmhSections contains dynamic memory handles. Each open file has various
+** dynamic memory buffers associated with it. Each can be present or discarded,
+** as memory constrictions determine. If needed and not present, they are
+** reloaded from the associated help file. All may be discarded when memory
+** gets tight. An entry is defined for each help file section, except for the
+** Topics themselves.
+**
+*/
+typedef struct fdb { /* FDB */
+ FILE * fhHelp; /* OS file handle */
+ nc ncInit; /* initial context (includes mh)*/
+ mh rgmhSections[HS_count-1]; /* dynamic memory handles */
+ uchar ftype; /* file type */
+ uchar fname[14]; /* base file name */
+ ulong foff; /* our file offset, if appended */
+ nc ncLink; /* nc linking any appended file */
+ helpheader hdr; /* file header */
+ } fdb;
+/*
+** helpinfo
+** structure of information relating to a help file and/or context returned
+** by HelpGetInfo
+*/
+typedef struct helpinfo { /* HI */
+ fdb fileinfo; /* entire fdb copied out */
+ char filename[1]; /* filename appended to data */
+ } helpinfo;
+/*
+** Macros for accessing helpinfo data
+*/
+#define FHHELP(x) ((x)->fileinfo.fhHelp)
+#define NCINIT(x) ((x)->fileinfo.ncInit)
+#define FTYPE(x) ((x)->fileinfo.ftype)
+#define FNAME(x) ((x)->fileinfo.fname)
+#define FOFF(x) ((x)->fileinfo.foff)
+#define NCLINK(x) ((x)->fileinfo.ncLink)
+#define WMAGIC(x) ((x)->fileinfo.hdr.wMagic)
+#define WVERSION(x) ((x)->fileinfo.hdr.wVersion)
+#define WFLAGS(x) ((x)->fileinfo.hdr.wFlags)
+#define APPCHAR(x) ((x)->fileinfo.hdr.appChar)
+#define CTOPICS(x) ((x)->fileinfo.hdr.cTopics)
+#define CCONTEXTS(x) ((x)->fileinfo.hdr.cContexts)
+#define CBWIDTH(x) ((x)->fileinfo.hdr.cbWidth)
+#define CPREDEF(x) ((x)->fileinfo.hdr.cPreDef)
+#define HFNAME(x) ((x)->fileinfo.hdr.fname)
+#define TBPOS(x) ((x)->fileinfo.hdr.tbPos)
+
+/******************************************************************************
+**
+** Some versions of the help engine run with SS!=DS, and thus require the
+** _loadds attribute on function calls.
+*/
+#ifdef DSLOAD
+#define LOADDS _loadds
+#else
+#define LOADDS
+#endif
+
+/******************************************************************************
+**
+** PB
+** pointer to a buffer. Based on the switch HOFFSET, it is either a
+** handle-offset or a far pointer. In the handle/offset case, the high word
+** contains a memory handle which must be locked, to get a "real" address, to
+** which the offset is added.
+*/
+#ifdef HOFFSET
+#define PB ulong
+#else
+#define PB void far *
+#endif
+
+typedef PB pb;
+
+/******************************************************************************
+**
+** Forward declarations
+*/
+void far pascal LOADDS HelpInit (void);
+
+void far pascal LOADDS HelpClose(nc);
+nc far pascal LOADDS HelpOpen(char far *);
+
+nc far pascal LOADDS HelpNc(char far *, nc);
+nc far pascal LOADDS HelpNcCmp (char far *, nc,
+ f (pascal far *)(uchar far *, uchar far *, ushort, f, f));
+ushort far pascal LOADDS HelpNcCb(nc);
+ushort far pascal LOADDS HelpLook(nc, PB);
+f far pascal LOADDS HelpDecomp(PB, PB, nc);
+void far pascal LOADDS HelpCtl(PB, f);
+
+nc far pascal LOADDS HelpNcNext(nc);
+nc far pascal LOADDS HelpNcPrev(nc);
+nc far pascal LOADDS HelpNcUniq(nc);
+
+void far pascal LOADDS HelpNcRecord(nc);
+nc far pascal LOADDS HelpNcBack(void);
+
+f far pascal LOADDS HelpSzContext(uchar far *, nc);
+int far pascal LOADDS HelpGetInfo (nc, helpinfo far *, int);
+
+void far pascal LOADDS HelpShrink(void);
+
+int far pascal LOADDS HelpGetCells(int, int, char far *, PB, uchar far *);
+ushort far pascal LOADDS HelpGetLine(ushort, ushort, uchar far *, PB);
+ushort far pascal LOADDS HelpGetLineAttr(ushort, int, lineattr far *, PB);
+int far pascal LOADDS HelpcLines(PB);
+
+f far pascal LOADDS HelpHlNext(int, PB, hotspot far *);
+char far * pascal far LOADDS HelpXRef(PB, hotspot far *);
+
+/******************************************************************************
+**
+** constant declarations
+**
+** Character attribute bits. These bits are order together to form attribute
+** indecies. Data in the help file has associated with it attribute information
+** encoded in length/index pairs. Each index is simply a constant which
+** indicates which of several attributes should be applied to the characters in
+** that portion of the line.
+*/
+#define A_PLAIN 0 /* plain, "normal" text */
+#define A_BOLD 1 /* emboldened text */
+#define A_ITALICS 2 /* italicised text */
+#define A_UNDERLINE 4 /* underlined text */
+
+/******************************************************************************
+**
+** Help Error Codes.
+**
+** Return values greater than HELPERR_MAX are valid nc's.
+*/
+#define HELPERR_FNF 1 /* OpenFileOnPath failed */
+#define HELPERR_READ 2 /* ReadHelpFile failed on header*/
+#define HELPERR_LIMIT 3 /* to many open helpfiles */
+#define HELPERR_BADAPPEND 4 /* bad appeneded file */
+#define HELPERR_NOTHELP 5 /* Not a help file */
+#define HELPERR_BADVERS 6 /* newer or incompatible help file */
+#define HELPERR_MEMORY 7 /* memory allocation failed */
+#define HELPERR_MAX 10 /* max help error */
diff --git a/private/utils/mep/help/inc/helpfile.h b/private/utils/mep/help/inc/helpfile.h
new file mode 100644
index 000000000..6dd159bc1
--- /dev/null
+++ b/private/utils/mep/help/inc/helpfile.h
@@ -0,0 +1,95 @@
+/*
+** helpfile.h
+**
+** This file defines the help file format.
+**
+**
+** +---------------------+
+** | Header |
+** +---------------------+
+** | Topic index |
+** +---------------------+
+** | Context strings |
+** +---------------------+
+** | Context map |
+** +---------------------+
+** | Keyphrase table |
+** +---------------------+
+** | Huffman decode tree |
+** +---------------------+
+** | Filename Map |
+** +---------------------+
+** | Compressed topics |
+** +---------------------+
+**
+** Header: described by the structure below.
+**
+** Topic index: an array of dwords indexed by topic number that gives the file
+** position of the topic. Note: topic n+1 follows topic n so the index can be
+** used to compute the size of a topic as well.
+**
+** Context Strings: An array of (null terminated) strings which map to context
+** numbers in the following Context Map. These strings are used to for topic
+** look-up when no predefined Context Number has been assigned.
+**
+** Context map: an array of words which maps a context to a topic. This allows
+** the order of context numbers to differ from the order of topics in the help
+** file, and allows more than one context to map to the same topic.
+**
+** Keyphrase table: table of strings used to compress the topic text.
+**
+** Huffman decode tree: tree representing the character mapping used in huffman
+** copression of the help text.
+**
+** Filename Map: Table of filenames and Topic Index ranges used to redirect
+** certain topics to other help files. Used in combined help files.
+**
+** Compressed Topics: The compressed text for all topics. When the help file is
+** built, the topics are first keyphrase and runlength compressed, and are the
+** Huffman encoded. So to decode a topic, it must first be Huffman decoded, and
+** then keyphrase and runlength expanded. Keyphrase and runlength encoding
+** cookies are described below. Huffman decoding is discussed in dehuff.asm.
+*/
+
+/*
+** Numbers for each of the sections of the help file
+*/
+#define HS_INDEX 0 /* topic index */
+#define HS_CONTEXTSTRINGS 1 /* Context Strings */
+#define HS_CONTEXTMAP 2 /* context to topic map */
+#define HS_KEYPHRASE 3 /* keyphrase table */
+#define HS_HUFFTREE 4 /* huffman decode tree */
+#define HS_TOPICS 5 /* compressed topic text */
+#define HS_NEXT 8 /* position of cat'ed helpfile */
+
+#define wMagicHELP 0x4e4c /* New Help file magic word */
+#define wMagicHELPOld 0x928b /* Old Help file magic word */
+#define wHelpVers 2 /* helpfile version */
+
+
+#define wfCase 0x0001 /* set= Preserve case */
+#define wfLock 0x0002 /* set= file locked */
+
+/*
+** Keyphrase and run length encoding cookies. Each compressed keyphrase or
+** character run is replaced by one of these cookies with appropriate
+** parameters.
+**
+** Keyphrase cookies are followed by a one byte keyphrase index.
+** Runspace is followed by a one byte count of spaces.
+** Run is followed by a character and a count of repititions.
+** Quote is followed by a character.
+*/
+#define C_MIN 0x10 /* Bottom of cookie range */
+#define C_KEYPHRASE0 0x10 /* 1st keyphrase cookie */
+#define C_KEYPHRASE1 0x11 /* 2nd keyphrase cookie */
+#define C_KEYPHRASE2 0x12 /* 3rd keyphrase cookie */
+#define C_KEYPHRASE3 0x13 /* 3rd keyphrase cookie */
+#define C_KEYPHRASE_SPACE0 0x14 /* 1st keyphrase + space cookie */
+#define C_KEYPHRASE_SPACE1 0x15 /* 2nd keyphrase + space cookie */
+#define C_KEYPHRASE_SPACE2 0x16 /* 3rd keyphrase + space cookie */
+#define C_KEYPHRASE_SPACE3 0x17 /* 3rd keyphrase + space cookie */
+#define C_RUNSPACE 0x18 /* Cookie for runs of spaces */
+#define C_RUN 0x19 /* Cookie for runs of non-space */
+#define C_QUOTE 0x1a /* Cookie to quote non-cookies */
+#define C_MAX 0x1a /* top of cookie range */
diff --git a/private/utils/mep/help/inc/helpmake.h b/private/utils/mep/help/inc/helpmake.h
new file mode 100644
index 000000000..c41fdfa0e
--- /dev/null
+++ b/private/utils/mep/help/inc/helpmake.h
@@ -0,0 +1,195 @@
+/*************************************************************************
+**
+** helpmake.h - misc definitions common to helpmake
+**
+** Copyright <C> 1987, Microsoft Corporation
+**
+** Revision History:
+**
+** 31-Jul-1990 ln csVal takes a param.
+** 04-Jul-1990 JCK Add F_LOCALCONTEXT to allow escaped @
+** 28-Oct-1988 ln Add parameter to rlCompress
+** 12-Aug-1988 ln Add COLMAX, local context routines & pass1a
+** [] 18-Dec-1987 LN Created
+**
+*************************************************************************/
+
+/************************************************************************
+**
+** Includes required for subsequent definitions in this file.
+*/
+#include "help.h" // structires & constants
+#include "helpfile.h" // help file structure
+#include "helpsys.h" // misc commn defs
+#include "hmmsg.h" // error message numbers
+#include "farutil.h" // far memory utils
+#include "vm.h" // virtual memory management
+
+/*************************************************************************
+**
+** definitions
+**
+*/
+#define TRUE 1
+#define FALSE 0
+
+#define ASTACKSIZE 50 // size of attribute stack
+#define BUFSIZE 512 // size of line buffers
+#define CBFBUF 64000 // size of far buffer(s)
+#define CBIOBUF 16000 // file buffer size (60k)
+#define CBRTFMAX 40 // max length of RTF keyword
+#define CBSZCONTEXT 60000 // context string buffer size
+#define CCONTEXTMAX 10000 // max number of contexts
+#define CTOPICSMAX 10000 // max number of topics
+#define COLMAX 250 // max column we can run into
+#define FBUFSIZE 2048 // size of buffers used
+#define MAXBACKC 128 // max number of back-up characters
+
+#define F_RTF 1 // RTF file type
+#define F_QH 2 // QuickHelp format
+#define F_MINASCII 3 // minimal ascii
+#define F_MAX 3 // maximum
+
+#define F_LOCALCONTEXT 0xff // marker for local context
+
+#define CMP_RUNLENGTH 0x01 // runlength encoding
+#define CMP_KEYWORD 0x02 // base keyword encoding
+#define CMP_KEYWORD2 0x04 // "agressive" keyword
+#define CMP_HUFFMAN 0x08 // huffman encoding
+#define CMP_MAX 0x0f // maximum
+
+/*
+** formatting tokens. Embedded in non-rtf text, and converter from (longer)
+** rtf equivalents by the RTF stripper.
+*/
+#define FM_ANCHOR 'a' | 0xff00 // anchor cross reference
+#define FM_PLAIN 'p' | 0xff00 // plain text
+#define FM_BOLD 'b' | 0xff00 // bold text
+#define FM_ITALIC 'i' | 0xff00 // italic
+#define FM_HIDDEN 'v' | 0xff00 // hidden text
+#define FM_UNDERLINE 'u' | 0xff00 // underline
+#define FM_DEFAULT 'd' | 0xff00 // paragraph defaults
+#define FM_FINDENT 'f' | 0xff00 // first line indent
+#define FM_LINDENT 'l' | 0xff00 // paragraph left indent
+#define FM_TAB 't' | 0xff00 // tab character
+#define FM_LINE 'n' | 0xff00 // exlicit line break
+#define FM_BLOCKBEG '{' | 0xff00 // block begin
+#define FM_BLOCKEND '}' | 0xff00 // block begin
+
+typedef char buffer[256]; // line buffer
+typedef char f; // boolean
+
+struct kwi { // keyword info structure
+ char far *fpszKw; // pointer to the actual keyword
+ int cbKw; // length of keyword
+ ushort cKwInst; // count of keyword instances
+ ushort cKwSpInst; // count of keyword-space instances
+ int savings; // computed savings for this word
+ };
+
+/*
+** transitem
+** dotcommand translation item
+*/
+struct transitem {
+ char *pdotcmd; // original dot command
+ int cbdotcmd; // length of said dot command
+ char *pnewcmd; // replacement command
+ char cbnewcmd; // length of said new cmd
+ };
+
+// context string
+// context string item in a linked list
+//
+typedef struct _cshdr {
+ va vaNext; // next item in list or NULL
+ va vaTopic; // va of topic
+ uchar cbszCs; // length of context string + null
+ } cshdr;
+
+typedef struct _cs {
+ cshdr cshdr; // header info
+ buffer szCs; // context string + terminating null
+ } cs;
+
+/*
+** verbosity level definitions.
+*/
+#define V_BANNER (verbose >= 1) // (default) print banner
+#define V_PASSES (verbose >= 2) // print pass names
+#define V_CONTEXTS (verbose >= 3) // print contexts on 1st pass
+#define V_CONTEXTS2 (verbose >= 4) // print contexts on each pass
+#define V_STEPS (verbose >= 5) // print intermediate steps
+#define V_STATS (verbose >= 6) // print statistics
+#define V_DSTATS (verbose >= 10) // print debug statistics
+#define V_ARGS (verbose >= 20) // print prog arguments
+#define V_KEYWORD (verbose >= 30) // print keyword table
+#define V_HUFFMAN (verbose >= 40) // print huffman table
+
+/************************************************************************
+**
+** HelpMake function forward definitions
+*/
+void pascal AddContextString (char *);
+va pascal AddKw (uchar far *);
+void pascal addXref (uchar *, uchar *, ushort, ushort);
+void pascal BackUp (int);
+void pascal BackUpToken (int);
+uchar * pascal basename (uchar *);
+void pascal ContextVA (va);
+ushort pascal counttab (struct hnode *, int, ulong);
+void pascal decode (int, char **, int, f);
+int pascal DofarWrite (int, uchar far *, int);
+void pascal DumpRtf (uchar far *, nc, int, f);
+void pascal encode (int, char **, int);
+f pascal fControlLine (void);
+va pascal FindKw (uchar far *, f);
+int pascal getcProc (void);
+int pascal getcQH (void);
+int pascal getcRTF (void);
+void pascal help ();
+void pascal hmerror (ushort, uchar *, ulong);
+f pascal hmmsg (ushort);
+int hnodecomp (struct hnode **, struct hnode **);
+void pascal HuffBuild (void);
+void pascal HuffCompress (uchar far *, uchar far *);
+ushort pascal HuffDump (void);
+void pascal HuffInit (void);
+void pascal HuffFreq (uchar far *, ushort);
+void pascal HuffStats (void);
+uchar * pascal getFarMsg (ushort, uchar *);
+void pascal InitOutput (int);
+void pascal kwAnal (uchar far *, int);
+void pascal kwCompress (uchar far *);
+f pascal kwSepar (char);
+mh pascal LoadPortion (int, mh);
+ushort pascal LocalContext (uchar *, ushort);
+void pascal LocalContextFix (uchar far *);
+ushort pascal MapLocalContext (ushort);
+int pascal NextChar (void);
+char * pascal NextContext (f);
+uchar * pascal NextLine (void);
+long pascal NextNum (void);
+void pascal parserefs (uchar *, uchar *);
+void pascal pass1 (int, char **);
+void pascal pass1a (void);
+void pascal pass2 (void);
+void pascal pass3 (void);
+void pascal passfa (void);
+void pascal passfb (int);
+uchar pascal PopAttr (void);
+f pascal procRTF (char *, char *);
+void pascal PushAttr (uchar);
+void pascal rlCompress (uchar far *, ushort);
+int pascal SkipDest (int,char **);
+void pascal SkipSpace (void);
+void pascal SkipVal (char **);
+void pascal SortKw (void);
+void pascal split (int, char **);
+uchar * pascal trim (uchar *, f);
+
+#ifdef DEBUG
+void pascal csVal (va);
+#else
+#define csVal(x)
+#endif
diff --git a/private/utils/mep/help/inc/helpsys.h b/private/utils/mep/help/inc/helpsys.h
new file mode 100644
index 000000000..2997b6d6a
--- /dev/null
+++ b/private/utils/mep/help/inc/helpsys.h
@@ -0,0 +1,92 @@
+/*
+** helpsys.h - Help system internal definitions
+**
+** Copyright <C> 1987, Microsoft Corporation
+**
+** Purpose:
+** Contains definitions used within the help system.
+**
+** Revision History:
+**
+** 12-Mar-1990 CloseFile -> HelpCloseFile
+** 22-Jan-1990 MAXFILES from 50 to 100
+** [] 14-Dec-1987 Created
+**
+*/
+
+/*
+** definitions
+*/
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define ASCII 1 /* build with ASCII support */
+
+#define MAXBACK 20 /* max number of back-up's */
+#define MAXFILES 100 /* max number of open helpfiles */
+
+#define FTCOMPRESSED 0x01 /* 1=compressed, 0=ascii */
+#define FTFORMATTED 0x02 /* 1=formatted, 0=unformatted */
+#define FTMERGED 0x04 /* 1=merged index, 0=normal */
+
+#define REGISTER register
+
+#define HIGHONLY(l) ((ulong)l & 0xffff0000)
+#define HIGH(l) ((ushort)(HIGHONLY(l) >> 16))
+#define LOW(l) ((ushort)((ulong)l & 0xffff))
+
+/*
+** Forward declarations for client application call-back routines
+*/
+
+#if rjsa
+#define HelpDealloc(sel) DosFreeSeg(sel)
+#define HelpLock(sel) ((void *)((ulong)sel << 16))
+#define HelpUnlock(sel)
+#else
+#define HelpDealloc(x) free(x)
+#define HelpLock(x) (x)
+#define HelpUnlock(x)
+#endif
+
+
+
+
+void pascal HelpCloseFile(FILE *);
+mh pascal HelpAlloc(ushort);
+FILE * pascal OpenFileOnPath(char *, int);
+ulong pascal ReadHelpFile(FILE *, ulong, char *, ushort);
+
+/*
+** intlineattr
+** internal representation of lineattributes
+*/
+typedef struct intlineattr { /* ILA */
+ uchar attr; /* attribute index */
+ uchar cb; /* count of bytes */
+ } intlineattr;
+
+/******************************************************************************
+**
+** PB maniputalors
+** Macros for locking and unlocking handle:offsets, as appropriate.
+*/
+#ifdef HOFFSET
+#define PBLOCK(ho) (((char *)HelpLock(HIGH(ho))) + LOW(ho))
+#define PBUNLOCK(ho) HelpUnlock(HIGH(ho))
+#else
+#define PBLOCK(ho) ((void *)ho)
+#define PBUNLOCK(ho)
+#endif
+
+
+
+PCHAR pascal hlp_locate (SHORT ln, PCHAR pTopic);
+
+
+FILE *pathopen (char *name, char *buf, char *mode);
diff --git a/private/utils/mep/help/inc/huffman.h b/private/utils/mep/help/inc/huffman.h
new file mode 100644
index 000000000..f1f79b347
--- /dev/null
+++ b/private/utils/mep/help/inc/huffman.h
@@ -0,0 +1,8 @@
+/***
+ *
+ * encode.h - header file for encode.c
+ *
+ * [] 22-Jun-87 KHD Created
+ * 01-Jul-87 LeeAc Modified.
+ *
+ *****************************************************************/
diff --git a/private/utils/mep/help/inc/rtf.h b/private/utils/mep/help/inc/rtf.h
new file mode 100644
index 000000000..f0efb40e3
--- /dev/null
+++ b/private/utils/mep/help/inc/rtf.h
@@ -0,0 +1,94 @@
+/*
+** rtf.h - definitions for the character codes used by RTF. |
+**
+** Copyright <C> 1987, Microsoft Corporation
+**
+** Purpose:
+**
+** Revision History:
+**
+** [] 17-Dec-1987 LN: Stolen from Excel code
+**
+*/
+#define cRTFMinus '-'
+#define cRTFPlus '+'
+#define cRTFTilda '~'
+#define cRTFDash '-'
+#define cRTFUnder '_'
+#define cRTFSemi ';'
+#define cRTFq '\''
+#define cRTFlb '{'
+#define cRTFrb '}'
+#define cRTFbs '\\'
+#define cRTFv 'v'
+
+/*
+** defines for primary symbol type
+*/
+#define SK_NORMAL 0 /* normal type, check token */
+#define SK_SKIPDEST 1 /* skip entire destination */
+#define SK_SKIPVALUE 2 /* skip the value */
+#define SK_SPECIAL 4 /* special character */
+#define SK_REPLACE 5 /* replace RTF token */
+#define SK_NIL 0xff /* nil type */
+
+/*
+** defines for symbols we actually care about
+*/
+#define TK_OFF 0x80 /* high bit is on/off flag */
+#define TK_NIL 0
+#define TK_ANSI 1
+#define TK_BITMAP 2 /* compressed bitmap filename follows? */
+#define TK_BLUE 3
+#define TK_BOLD 4
+#define TK_BORDERB 5
+#define TK_BORDERL 6
+#define TK_BORDERR 7
+#define TK_BORDERT 8
+#define TK_BOX 9
+#define TK_CENTERED 10
+#define TK_COLORBACK 11
+#define TK_COLORFORE 12
+#define TK_COLORTABLE 13
+#define TK_FIRSTLINE 14
+#define TK_FONTSIZE 15
+#define TK_FORMULA 16
+#define TK_GREEN 17
+#define TK_HEX 18
+#define TK_INVISIBLE 19 /* hidden text is filename: note/topic/bitmap */
+#define TK_ITALIC 20
+#define TK_JUSTIFY 21
+#define TK_LEFT 22
+#define TK_LEFTINDENT 23
+#define TK_LINE 24
+#define TK_MACCHARS 25
+#define TK_NEWLINE 26
+#define TK_NONBREAKINGDASH 27
+#define TK_NONBREAKINGSPACE 28
+#define TK_NONREQUIREDDASH 29
+#define TK_PARADEFAULT 30
+#define TK_PCCHARS 31
+#define TK_PLAIN 32
+#define TK_RED 33
+#define TK_RIGHT 34
+#define TK_RIGHTINDENT 35
+#define TK_RTAB 36
+#define TK_SIDEBYSIDE 37
+#define TK_SPACEAFTER 38
+#define TK_SPACEBEFORE 39
+#define TK_SPACELINE 40
+#define TK_STRIKEOUT 41 /* strikeout is hotspot for Topic */
+#define TK_TABCHAR 42
+#define TK_TABSTOP 43
+#define TK_UNDERLINE 44 /* underline is hotspot for Definition */
+
+/*
+** structure definition for parse table
+*/
+struct tsnPE
+ {
+ uchar *pch; // pointer to symbol string
+ uchar sk; // primary symbol kind
+ ushort tk; // token - one of the above TK_, or FM_
+ };
+typedef struct tsnPE PE;
diff --git a/private/utils/mep/help/inc/vm.h b/private/utils/mep/help/inc/vm.h
new file mode 100644
index 000000000..d22cb6379
--- /dev/null
+++ b/private/utils/mep/help/inc/vm.h
@@ -0,0 +1,46 @@
+/*************************************************************************
+**
+** vm.h - procedure definitions for VM package
+**
+** Copyright <C> 1988, Microsoft Corporation
+**
+** Purpose:
+**
+** Revision History:
+**
+** [] 21-Apr-1988 LN Created
+**
+*************************************************************************/
+typedef char f; /* boolean */
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+typedef void far * va; /* virtual address */
+
+#define VANIL ((va)0xffffffff) /* NIL value */
+#define VANULL ((va)0) /* NULL value */
+
+ulong pascal far VMsize (long);
+
+uchar far * pascal far FMalloc (ulong);
+void pascal far FMfree (uchar far *);
+uchar far * pascal far LMalloc (ushort);
+
+void pascal far fpbToVA (char far *, va, ushort);
+void pascal far pbToVA (char *, va, ushort);
+void pascal far VATofpb (va, char far *, ushort);
+void pascal far VATopb (va, char *, ushort);
+void pascal far VAToVA (va, va, ulong);
+f pascal far VMInit (void);
+ulong pascal far VMreadlong (va);
+void pascal far VMwritelong (va, long);
+
+void pascal far VMFinish(void);
+void pascal far VMFlush (void);
+void pascal far VMShrink(f);
+
+#ifdef DEBUG
+void pascal far _vmChk (long, long);
+#else
+#define _vmChk(x,y)
+#endif
diff --git a/private/utils/mep/help/inc/zlib.h b/private/utils/mep/help/inc/zlib.h
new file mode 100644
index 000000000..437c362ba
--- /dev/null
+++ b/private/utils/mep/help/inc/zlib.h
@@ -0,0 +1,9 @@
+char *pathcat (char *pDst, char *pSrc);
+char *pname (char *pszName);
+LPSTR strbscan (const LPSTR pszStr, const LPSTR pszSet );
+char fPathChr( int c );
+BOOLEAN forsemi (char *p, BOOLEAN (*proc)( char*, void * ), void *args);
+
+
+#define strend(x) ((x)+strlen(x))
+#define PSEPSTR "/"
diff --git a/private/utils/mep/help/mshelp/help.c b/private/utils/mep/help/mshelp/help.c
new file mode 100644
index 000000000..f520d0a0b
--- /dev/null
+++ b/private/utils/mep/help/mshelp/help.c
@@ -0,0 +1,1745 @@
+/*** help.c - help library main
+*
+* Copyright <C> 1988-1990, Microsoft Corporation
+*
+* Definitions:
+*
+* Context Map: Mapping of context number to topic number.
+* Allows multiple contexts to be associated with a
+* single topic. Syncronized with the context
+* string table, each entry contains the topic
+* number associated with the corresponding context
+* string.
+*
+* Context String: String on which help can be "looked up".
+*
+* Context String Table: Table of all valid context strings in a
+* particular help file.
+*
+* Local Context: A type of context which bypasses the context
+* string and context numbers. In cross references,
+* encoded as a cross reference string of NULL,
+* followed by a topic number ored with 0x8000.
+*
+* nc: (Context Number) A long which uniquely
+* identifies a help file and context string, or
+* for local contexts, the helpfile and topic
+* number. Formatted as:
+*
+* +----------------+----------------+
+* | Fdb Mem Handle | context number |
+* +----------------+----------------+
+*
+* Where the upper word is the memory handle of the
+* allocated fdb for the help file. The lower word
+* is the either the "true" context number (see
+* below) if <= 0x7fff, or the actual topic number
+* or'ed with 0x8000.
+*
+* Topic: Actual help textual entry. May be compressed.
+*
+* Topic Index: Table of file positions of all topics contained
+* in a help file. Indexed by the topic number,
+* returns that topics physical position in the
+* file.
+*
+* Topic Number: Index to a particular topic. Topic numbers are
+* zero based, and reflect the physical ordering of
+* the topics in the file.
+*
+* "True" context number: is the zero based index or string number in the
+* <context string table>. I.E. the "n'th" string
+* has context number "n".
+*
+* The progression from string to true context number to topic number to file
+* position is:
+*
+* 1) Context String ==> "True" Context Number
+*
+* The string is searched for in the <context string table>, and
+* it's number becomes the "true" context number.
+*
+* 2) "True" Context Number ==> Topic Number
+*
+* The context number is an index into the <context map>, returing
+* the topic number associated with the context number.
+*
+* 3) Topic Number ==> File Position
+*
+* The topic number is used as an index into the Topic Index, from
+* which the physical file position is retrieved.
+*
+* Notes:
+* QuickPascal requires NO initialized data. In this case, CLEAR is defined,
+* and the HelpInit routine is included. We also play some pointer games to
+* simple variables, because the C compiler can generate CONST segment
+* entries for the SEG of various vars. (This enables it to load the segment
+* register directly, rather than by using SEG varname and another
+* register). Q/P cannot support this action by the compiler.
+*
+* QuickHelp for OS/2 is reentrant. This code should remain reentrant up to
+* but not including allocating and deallocating fdbs.
+*
+* Revision History:
+*
+* 17-Aug-1990 ln Don't blindly request 64k of an ascii file. Query
+* for size first, then read. Allocations based on
+* previous topic size requests may cause the OS to
+* GPFault for an out of range read.
+* 16-Jul-1990 ln Searching for "filename!" where filename is a QH
+* file, will now fail, rather than GP fault. Searching
+* for "!" will now succeed.
+* 08-Jun-1990 ln Remove HelpLock usage in HelpNcCmp
+* 13-Apr-1990 ln Try to get HelpSzContext to return strings in more
+* cases where it can.
+* 12-Mar-1990 ln Rename CloseFile -> HelpCloseFile
+* 08-Oct-1989 ln Changes to improve the previous change to work (allow
+* decompression) more often in low memory bases.
+* Deallocate table in OpenCore to reduce fragmentation
+* in non-moveable memory systems.
+* 19-May-1989 ln Correct bug in decompressing, where we would not
+* decompress if the tables didn;t exist.
+* 12-Apr-1989 ln Ensure that we handle Locks failing correctly. Also
+* remove TossPortion usage. Unlock handles directly.
+* 10-Mar-1989 ln Change MapTopicToContext to look forward. Changed
+* HelpNc to look begining at passed context string.
+* 17-Jan-1989 ln Correct creation of basename in HelpOpen to account
+* for environment syntax.
+* 09-Dec-1988 ln Add HelpNcUniq
+* 25-Oct-1988 ln Added minascii support to HelpNcPrev. Correct
+* minascii bug in HelpSzContext.
+* 14-Sep-1988 ln Improve doc. Remove ambiguity in MapContextToTopic
+* return value. Improve error checking in various
+* places.
+* 01-Sep-1988 ln Check ReadHelpFile return value in LoadPortion
+* 12-Aug-1988 ln Add check for memory discarded in alloc durring
+* HelpDecomp.
+* 08-Aug-1988 ln Ensure HelpClose closes ALL files. (Off by one error
+* in loop).
+* 14-Apr-1988 ln Modified to conform to QC (CW?) restriction that
+* prohibits any segments from being locked when an
+* allocation is performed.
+* [] 15-Dec-1987 ln Created, for design.
+*
+*************************************************************************/
+
+#include <assert.h> /* debugging assertions */
+#include <io.h> /* I/O function declarations */
+#include <stdlib.h> /* standard library */
+
+#include <stdio.h> /* standard I/O definitions */
+
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+#define MASIZE 512 /* size of ma input buffer */
+#define MAOVER 64 /* size of ma search overlap */
+
+#define ISERROR(x) (((x).mh == 0L) && ((x).cn <= HELPERR_MAX))
+#define SETERROR(x,y) { (x).mh = 0L; (x).cn = y; }
+
+/*************************************************************************
+**
+** Forward definitions
+*/
+void pascal near CloseShrink(nc, f);
+f pascal near LoadFdb (mh, fdb far *);
+mh pascal near LoadPortion (int, mh);
+ushort pascal near MapContexttoTopic (nc, fdb far *);
+nc pascal near MapTopictoContext(ushort, fdb far *, int);
+nc pascal near NextPrev(nc,int);
+nc pascal near OpenCore(FILE *, ulong, uchar far *, struct helpheader *, fdb far *);
+f pascal near PutFdb (mh, fdb far *);
+f pascal near SizePos (nc, ushort *,ulong *);
+
+ushort pascal near decomp (uchar far *, uchar far *, uchar far *, uchar far *);
+char far * pascal near hfmemzer(void far *, ushort);
+char far * pascal near hfstrchr(char far *, char);
+char far * pascal near hfstrcpy(char far *, char far *);
+ushort pascal near hfstrlen(char far *);
+f pascal far HelpCmp (uchar far *, uchar far *, ushort, f, f);
+f pascal near HelpCmpSz (uchar far *, uchar far *);
+void pascal near kwPtrBuild(uchar far *, ushort);
+
+#if ASCII
+long pascal near maLocate (fdb far *, uchar far *, ulong,
+ f (pascal far *)(uchar far *, uchar far *, ushort, f, f));
+
+nc pascal near combineNc (ulong, mh);
+ulong pascal near NctoFo (ulong);
+#endif
+
+/*************************************************************************
+**
+** External Global data
+** BEWARE. The effects of global data on reentrancy should be VERY carefully
+** considered.
+**
+*************************************************************************/
+extern mh tbmhFdb[MAXFILES+1];
+extern char szNil[1];
+extern ushort cBack;
+
+#ifdef CLEAR
+/*************************************************************************
+**
+** HelpInit - One-time initialization
+**
+** Purpose:
+** Performs one-time initialization. Right now that's a zero fill of static
+** memory for those environments which don't support pre-inited static
+** memory.
+**
+** Entry:
+** none
+**
+** Exit:
+** none
+**
+*/
+void far pascal LOADDS HelpInit () {
+
+hfmemzer (tbmhFdb, sizeof(tbmhFdb)); /* zero entire fdb handle table */
+hfmemzer (szNil, sizeof(szNil)); /* zero null string */
+hfmemzer (&cBack, sizeof(cBack)); /* zero back trace count */
+
+/* end HelpInit */}
+#endif
+
+/*************************************************************************
+**
+** HelpOpen - Open help file & return help handle.
+**
+** Purpose:
+** Given the file basename, locate the associated help file on the path, and
+** open it, initializing internal data structures as appropriate.
+**
+** Entry:
+** fpszName - base filename to be openned.
+**
+** Exit:
+** nc initial context for openned file.
+**
+** Exceptions:
+** Returns error code on failure to open for any reason.
+**
+*/
+nc far pascal LOADDS HelpOpen (
+char far *fpszName
+) {
+FILE *fhT; /* temp file handle */
+fdb fdbLocal; /* local copy of fdb to use */
+uchar far *fpszBase; /* base filename */
+void far *fpT;
+struct helpheader hdrLocal; /* for use by opencore */
+nc ncRet = {0,0}; /* first context */
+mh *ptbmhFdb; /* pointer into mh table */
+
+/*
+** create basename by removing possible env variable, drive, and scanning
+** for last path seperator
+*/
+fpszBase = fpszName;
+if (fpT = hfstrchr(fpszBase,':'))
+ fpszBase = (uchar far *)fpT+1;
+while (fpT = hfstrchr(fpszBase,'\\'))
+ fpszBase = (uchar far *)fpT+1;
+/*
+** Scan FDB's for an open file of the same base name. If we encounter the name,
+** in either the true filename, or file header, just return that file's initial
+** context. Otherwise fall below to try and open it.
+*/
+for (ptbmhFdb=&tbmhFdb[1]; ptbmhFdb<=&tbmhFdb[MAXFILES]; ptbmhFdb++) {
+ if (LoadFdb (*ptbmhFdb,&fdbLocal)) {
+ if (HelpCmpSz(fpszBase,fdbLocal.fname) ||
+ HelpCmpSz(fpszBase,fdbLocal.hdr.fname))
+ ncRet = fdbLocal.ncInit;
+ if (ncRet.mh && ncRet.cn)
+ return ncRet;
+ }
+ }
+/*
+** Open file. If we can, then call the core open routine to open the file (and
+** any anything appended to it).
+**
+** Warning: the app may callback HelpClose at this point.
+*/
+if (fhT = OpenFileOnPath(fpszName,FALSE)) {
+ ncRet = OpenCore (fhT,0L,fpszBase,&hdrLocal,&fdbLocal);
+ if (ISERROR(ncRet))
+ HelpCloseFile (fhT);
+ return ncRet;
+ }
+
+SETERROR(ncRet, HELPERR_FNF);
+return ncRet;
+// rjsa return HELPERR_FNF;
+
+/* end HelpOpen*/}
+
+/*************************************************************************
+**
+** OpenCore - Recursive core of HelpOpen
+**
+** Purpose:
+** Given the open file handle, initialize internal data structures as
+** appropriate. Attempt to open any file that is appended.
+**
+** Entry:
+** fhT - Open file handle
+** offset - Offset from start of file of help file to open
+** fpszBase - pointer to base filename
+**
+** Exit:
+** initial context, or NULL on failure.
+**
+** Exceptions:
+** Returns NULL on failure to open for any reason.
+**
+*/
+nc pascal near OpenCore (
+FILE * fhHelp,
+ulong offset,
+uchar far *fpszBase, /* base filename */
+struct helpheader *phdrLocal,
+fdb far *pfdbLocal /* pointer to current FDB */
+) {
+//void far *fpT;
+int ihFree; /* handle for free fdb (& index)*/
+mh mhCur; /* current memory handle */
+nc ncFirst = {0,0}; /* first context */
+nc ncInit; /* first context */
+mh *pmhT; /* pointer into mh table */
+
+/*
+** Read in helpfile header
+*/
+if (ReadHelpFile(fhHelp,
+ offset,
+ (char far *)phdrLocal,
+ (ushort)sizeof(struct helpheader))) {
+/*
+** search for available fdb
+*/
+ for (ihFree = MAXFILES, pmhT = &tbmhFdb[MAXFILES];
+ ihFree && *pmhT;
+ ihFree--, pmhT--);
+/*
+** if an offset is present, and this is NOT a compressed file, or there is no
+** available fdb, ignore the operation.
+*/
+ if ( offset
+ && (phdrLocal->wMagic != wMagicHELP)
+ && (phdrLocal->wMagic != wMagicHELPOld)
+ ) {
+ SETERROR(ncInit, HELPERR_BADAPPEND);
+ return ncInit;
+ // rjsa return HELPERR_BADAPPEND;
+ }
+ if (ihFree == 0) {
+ SETERROR(ncInit, HELPERR_LIMIT);
+ return ncInit;
+ // rjsa return HELPERR_LIMIT;
+ }
+/*
+** allocate fdb. Again, if we can't, skip it all and return NULL.
+*/
+ if (mhCur = *pmhT = HelpAlloc((ushort)sizeof(fdb))) {
+/*
+** Fill in helpfile header & appropriate fdb fields
+*/
+ hfmemzer(pfdbLocal,sizeof(fdb)); /* zero entire fdb */
+ pfdbLocal->fhHelp = fhHelp; /* file handle */
+ ncFirst.mh = pfdbLocal->ncInit.mh = mhCur;
+ ncFirst.cn = pfdbLocal->ncInit.cn = 0L;
+ // rjsa ncFirst = pfdbLocal->ncInit = ((long)mhCur) << 16; /* initial context */
+ pfdbLocal->foff = offset; /* appended offset */
+ hfstrcpy(pfdbLocal->fname,fpszBase); /* include base filename*/
+/*
+** if this is a compressed file (signified by the first two bytes of the header
+** we read in above), then note the file type in the fdb. We unlock the fdb, as
+** MapTopicToContext and the recursion might cause memory allocation. We get a
+** context number for the first topic, and recurse and attempt to open any
+** appended file.
+*/
+ if ( (phdrLocal->wMagic == wMagicHELPOld)
+ || (phdrLocal->wMagic == wMagicHELP)
+ ) {
+ if ((phdrLocal->wMagic == wMagicHELP)
+ && (phdrLocal->wVersion > wHelpVers)) {
+ SETERROR(ncInit, HELPERR_BADVERS);
+ return ncInit;
+ // rjsa return HELPERR_BADVERS;
+ }
+ pfdbLocal->hdr = *phdrLocal;
+ pfdbLocal->ftype = FTCOMPRESSED | FTFORMATTED;
+ if (PutFdb (mhCur, pfdbLocal)) {
+ ncFirst = MapTopictoContext(0,pfdbLocal,0);
+
+ // We free the context map (the only thing loaded by the
+ // MapTopictoContext) in order to reduce fragmentation in
+ // non-moveable memory based systems.
+ //
+ HelpDealloc (pfdbLocal->rgmhSections[HS_CONTEXTMAP]);
+ pfdbLocal->rgmhSections[HS_CONTEXTMAP] = 0;
+
+ ncInit = OpenCore(fhHelp,pfdbLocal->hdr.tbPos[HS_NEXT]+offset,szNil,phdrLocal,pfdbLocal);
+ if (LoadFdb (mhCur, pfdbLocal)) {
+ //if (ncInit.cn > HELPERR_MAX) {
+ if ( !(ISERROR(ncInit)) ) {
+ pfdbLocal->ncLink = ncInit;
+ } else {
+ pfdbLocal->ncLink.mh = (mh)0;
+ pfdbLocal->ncLink.cn = 0L;
+ }
+ // rjsa pfdbLocal->ncLink = ncInit > HELPERR_MAX ? ncInit : 0;
+ pfdbLocal->ncInit = ncFirst;
+ }
+ }
+ }
+#if ASCII
+/*
+** In the case of a minascii formatted file (signified by the first two bytes
+** of the header being ">>") we just set up the filetype and "applications
+** specific character". The default "ncFirst" is the context for the first
+** topic.
+*/
+ else if (phdrLocal->wMagic == 0x3e3e) { /* minascii formatted? */
+ pfdbLocal->ftype = FTFORMATTED;
+ pfdbLocal->hdr.appChar = '>'; /* ignore lines with this*/
+ }
+#endif
+ else if ((phdrLocal->wMagic & 0x8080) == 0) { /* ascii unformatted? */
+ pfdbLocal->ftype = 0;
+ pfdbLocal->hdr.appChar = 0xff; /* ignore lines with this*/
+ }
+ else {
+ SETERROR(ncInit, HELPERR_NOTHELP);
+ return ncInit;
+ // rjsa return HELPERR_NOTHELP;
+ }
+
+ if (!PutFdb (mhCur, pfdbLocal)) {
+ ncFirst.mh = (mh)0;
+ ncFirst.cn = 0L;
+ }
+ }
+ else {
+ SETERROR(ncFirst, HELPERR_MEMORY);
+ // rjsa ncFirst = HELPERR_MEMORY; /* error reading file */
+ }
+}
+else {
+ SETERROR(ncFirst, HELPERR_READ);
+ // rjsa ncFirst = HELPERR_READ; /* error reading file */
+}
+
+return ncFirst; /* return valid context */
+
+/* end OpenCore */}
+
+
+/*************************************************************************
+**
+** HelpClose - Close Help file
+**
+** Purpose:
+** Close a help file, deallocate all memory associated with it, and free the
+** handle.
+**
+** Entry:
+** ncClose - Context for file to be closed. If zero, close all.
+**
+** Exit:
+** None
+**
+** Exceptions:
+** All errors are ignored.
+**
+*/
+void far pascal LOADDS HelpClose (
+nc ncClose
+) {
+CloseShrink(ncClose,TRUE); /* close file(s) */
+/* end HelpClose */}
+
+/*************************************************************************
+**
+** HelpShrink - Release all dynamic memory
+**
+** Purpose:
+** A call to this routines causes the help system to release all dynamic
+** memory it may have in use.
+**
+** Entry:
+** None.
+**
+** Exit:
+** None.
+**
+** Exceptions:
+** None.
+**
+*/
+void far pascal LOADDS HelpShrink(void) {
+ nc ncTmp = {0,0};
+CloseShrink(ncTmp,0);
+// rjsa CloseShrink(0,0);
+/* end HelpShrink */}
+
+/*************************************************************************
+**
+** CloseShrink - Deallocate memory and possibly Close Help file
+**
+** Purpose:
+** Deallocate all memory associated with a help file, and possibly close free
+** it.
+**
+** Entry:
+** ncClose - Context for file. If zero, do all.
+** fClose - TRUE if a close operation.
+**
+** Exit:
+** None
+**
+** Exceptions:
+** All errors are ignored.
+**
+*/
+void pascal near CloseShrink (
+nc ncClose,
+f fClose
+) {
+fdb fdbLocal; /* pointer to current FDB */
+int i;
+mh mhClose; /* fdb mem hdl to file to close */
+mh *pmhFdb; /* pointer to FDB's table entry */
+
+
+mhClose = ncClose.mh; /* get index */
+// rjsa mhClose = (mh)HIGH(ncClose); /* get index */
+for (pmhFdb = &tbmhFdb[0]; /* for each possible entry */
+ pmhFdb <= &tbmhFdb[MAXFILES];
+ pmhFdb++
+ ) {
+ if ((mhClose == 0) /* if all selected */
+ || (mhClose == *pmhFdb)) { /* or this one selected */
+
+ if (LoadFdb (*pmhFdb, &fdbLocal)) { /* if open file */
+/*
+ * Recurse to close/shrink any appended files
+ */
+ if ((fdbLocal.ncLink.mh || fdbLocal.ncLink.cn) && mhClose)
+ CloseShrink (fdbLocal.ncLink, fClose);
+
+ for (i=HS_count-2; i>=0; i--) /* for dyn mem handles */
+ HelpDealloc(fdbLocal.rgmhSections[i]); /* dealloc */
+ hfmemzer(fdbLocal.rgmhSections,sizeof(fdbLocal.rgmhSections));
+
+ if (fClose) {
+ HelpCloseFile(fdbLocal.fhHelp); /* close file */
+ HelpDealloc(*pmhFdb); /* deallocate fdb */
+ *pmhFdb = 0;
+ }
+ else
+ PutFdb (*pmhFdb, &fdbLocal); /* update FDB */
+ }
+ }
+ }
+/* end CloseShrink */}
+
+/*** HelpNcCmp - Look up context string, provide comparison routine
+*
+* Given an ascii string, determine the context number of that string. Uses
+* user-supplied comparison routine.
+*
+* Entry:
+* lpszContext - Pointer to asciiz context string.
+* ncInital - Starting Context, used to locate file.
+* lpfnCmp - far pointer to comparison routine to use.
+*
+* Exit:
+* Context number, if found.
+*
+* Exceptions:
+* Returns NULL if context string not found.
+*
+*************************************************************************/
+nc far pascal LOADDS HelpNcCmp (
+char far *fpszContext,
+nc ncInitial,
+f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
+) {
+f fFound = FALSE; // TRUE -> found
+f fOpened = FALSE; // TRUE -> file was openned here
+fdb fdbLocal; // pointer to current FDB
+char far *fpszT; // temp far pointer
+long i;
+long iStart; // nc to start looking at
+mh mhCur; // memory handle locked
+nc ncRet = {0,0}; // The return value
+char far *fpszContexts; // pointer to context strings
+
+
+// if the context string includes a "filename!", then open that as a help
+// file, and point to the context string which may follow.
+//
+if ((fpszT = hfstrchr(fpszContext,'!')) && (fpszT != fpszContext)) {
+ *fpszT = 0;
+ ncInitial = HelpOpen(fpszContext);
+ *fpszT++ = '!';
+ fpszContext = fpszT;
+ fOpened = TRUE;
+}
+
+// if helpfile was not openned, just return the error
+//
+if (ISERROR(ncInitial)) {
+ ncInitial.mh = (mh)0;
+ ncInitial.cn = 0L;
+ return ncInitial;
+}
+
+// For compressed files we scan the context strings in the file (I know,
+// it's stupid code, but this turns out not to be that speed critical in
+// comparision with decompression, so I haven't bothered), to get the
+// context number.
+//
+// If not found, and there IS a linked (appended) file, we recurse to search
+// that file as well.
+//
+// The context number for compressed files is just the zero based string
+// number, plus the number of predefined contexts, with the fdb memory
+// handle in the upper word.
+//
+if (LoadFdb (ncInitial.mh, &fdbLocal)) {
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+
+ // If not a local context look up, get the context strings, and
+ // search
+ //
+ if (*fpszContext) {
+ mhCur = LoadPortion (HS_CONTEXTSTRINGS, ncInitial.mh);
+ if ( (mhCur == (mh)0)
+ || (mhCur == (mh)(-1))
+ || (!(fpszContexts = HelpLock(mhCur)))
+ ) {
+ ncRet.mh = (mh)0;
+ ncRet.cn = 0L;
+ return ncRet;
+ }
+ i=0;
+
+ // iStart allows us to begin searching from the context string
+ // passed, as opposed to from the begining each time. This
+ // allows the application to "carry on" a search from othe last
+ // place we found a match. This is usefull for multiple
+ // duplicate context resolution, as well as inexact matching.
+ //
+ iStart = ncInitial.cn;
+ if (iStart & 0x8000)
+ iStart = 0;
+ else
+ iStart--; /* table index is 0 based */
+
+ do {
+ if (i >= iStart) {
+ fFound = lpfnCmp ( fpszContext
+ , fpszContexts
+ , 0xffff
+ , (f)(fdbLocal.hdr.wFlags & wfCase)
+ , (f)FALSE);
+ }
+ while (*fpszContexts++); /* point to next string */
+ i++;
+ }
+ while ((i < (int)fdbLocal.hdr.cContexts) && !fFound);
+ HelpUnlock (mhCur);
+
+ if (fFound) { /* if a match found */
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = i + fdbLocal.hdr.cPreDef;
+ // rjsa ncRet = (i+fdbLocal.hdr.cPreDef) /* string # */
+ // | HIGHONLY(ncInitial); /* & fdb handle */
+ }
+ else {
+ ncInitial.mh = (mh)0;
+ ncInitial.cn = 0L;
+ ncRet = HelpNcCmp (fpszContext,fdbLocal.ncLink, lpfnCmp);
+ }
+ }
+ else if (!fOpened) {
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = *(UNALIGNED ushort far *)(fpszContext + 1);
+ // rjsa ncRet = *(ushort far *)(fpszContext + 1) /* word following*/
+ // | HIGHONLY(ncInitial); /* & fdb handle */
+ }
+ }
+#if ASCII
+/*
+** For minimally formatted ascii files, we sequentially scan the file itself
+** for context string definitions until we find the string we care about.
+**
+** The context number for minascii files is the the byte position/4 of the
+** beginning of the associated topic, with the fdb memory handle in the upper
+** word.
+*/
+ else if (fdbLocal.ftype & FTFORMATTED) {
+ if (*fpszContext) {
+ ncRet.cn = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
+ if (ncRet.cn == -1L) {
+ ncRet.mh = (mh)0;
+ ncRet.cn = 0L;
+ } else {
+ ncRet = combineNc(ncRet.cn, fdbLocal.ncInit.mh);
+ }
+ // rjsa ncRet = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
+ // ncRet = (ncRet == -1L)
+ // ? 0
+ // : combineNc(ncRet,HIGH(fdbLocal.ncInit));
+ }
+ }
+/*
+** for unformatted ascii files, there must have been NO context string to be
+** searched for. In that case, the context number is always 1, plus the fdb
+** mem handle.
+*/
+ else if (*fpszContext == 0) { /* if null context string */
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = 1L;
+ // rjsa ncRet = HIGHONLY(ncInitial) + 1;
+ }
+#endif
+}
+
+return ncRet;
+
+/* end HelpNcCmp */}
+
+/*** HelpNc - Look up context string
+*
+* Given an ascii string, determine the context number of that string.
+*
+* Entry:
+* lpszContext - Pointer to asciiz context string.
+* ncInital - Starting Context, used to locate file.
+*
+* Exit:
+* Context number, if found.
+*
+* Exceptions:
+* Returns NULL if context string not found.
+*
+*************************************************************************/
+nc far pascal LOADDS HelpNc (
+char far *fpszContext,
+nc ncInitial
+) {
+return HelpNcCmp (fpszContext, ncInitial, HelpCmp);
+/* end HelpNc */}
+
+
+/*************************************************************************
+**
+** HelpNcCb - Return count of bytes in compressed topic
+**
+** Purpose:
+** Returns the size in bytes of the compressed topic. Provided for
+** applications to determine how big a buffer to allocate.
+**
+** Entry:
+** ncCur - Context number to return info on.
+**
+** Exit:
+** Count of bytes in the compressed topic
+**
+** Exceptions:
+** Returns 0 on error.
+**
+*/
+ushort far pascal LOADDS HelpNcCb (
+nc ncCur
+) {
+ulong position;
+ushort size;
+
+return SizePos(ncCur,&size,&position) ? size+(ushort)4 : (ushort)0;
+
+/* end HelpNcCb */}
+
+/******************************************************************************
+**
+** HelpLook - Return compressed topic text
+**
+** Purpose:
+** Places the compressed topic text referenced by a passed context number into
+** a user supplied buffer.
+**
+** Entry:
+** ncCur - Context number for which to return text
+** pbDest - Pointer to buffer in which to place the result.
+**
+** Exit:
+** Count of bytes in >uncompressed< topic. This is encoded based on file type.
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+ushort far pascal LOADDS HelpLook (
+nc ncCur,
+PB pbDest
+) {
+fdb fdbLocal; /* pointer to current FDB */
+char far *fpszDest;
+int i;
+ulong position = 0;
+ushort size = 0;
+
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb down */
+/*
+** for both kinds of formatted files, we determine the position of the topic,
+** and read it in.
+*/
+ if (fdbLocal.ftype) {
+ if (SizePos (ncCur,&size,&position)) {
+ if (fpszDest = (char far *)PBLOCK(pbDest)) {
+
+#ifdef BIGDEBUG
+ {
+ char DbgBuf[128];
+ sprintf(DbgBuf, "HELP: Reading Topic for Context %d at %lX, size %d\n", ncCur.cn, position + fdbLocal.foff, size );
+ OutputDebugString(DbgBuf);
+ }
+#endif
+
+ size = (ushort)ReadHelpFile(fdbLocal.fhHelp
+ ,position + fdbLocal.foff
+ ,fpszDest
+ ,size);
+
+#ifdef BIGDEBUG
+ {
+ char DbgBuf[128];
+ sprintf(DbgBuf, " Read %d bytes to address %lX\n", size, fpszDest );
+ OutputDebugString(DbgBuf);
+ }
+#endif
+/*
+** for compressed files, if the read was sucessfull, we then return the
+** uncompressed size which is the first word of the topic.
+*/
+#if ASCII
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+#endif
+ if (size)
+ size = *(ushort far *)fpszDest+(ushort)1;
+#if ASCII
+ }
+ else {
+/*
+** for minascii files, We also set up for the terminating NULL by scanning for
+** the ">>" which begins the next topic, adjusting the size as well.
+*/
+ size -= 4;
+ for (i=4; i; i--)
+ if (fpszDest[++size] == '>') break;
+ fpszDest[size++] = 0;
+ }
+#endif
+ }
+ }
+ }
+#if ASCII
+ else { /* unformatted ascii */
+/*
+** for unformatted ascii, we just read in (first 64k of) the file.
+*/
+ if (fpszDest = PBLOCK (pbDest)) {
+ if (SizePos (ncCur,&size,&position)) {
+ size = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,fpszDest,size);
+ fpszDest[size++] = 0; /* terminate ascii text */
+ }
+ }
+ }
+#endif
+ PBUNLOCK (pbDest);
+ }
+if (size) size += sizeof(topichdr); /* adjust for prepended topichdr*/
+return size;
+/* end HelpLook */}
+
+/******************************************************************************
+**
+** HelpDecomp - Decompress Topic Text
+**
+** Purpose:
+** Fully decompress topic text. Decompresses based on current file, from one
+** buffer to another.
+**
+** Entry:
+** pbTopic - Pointer to compressed topic text
+** pbDest - Pointer to destination buffer
+**
+** Exit:
+** FALSE on successful completion
+**
+** Exceptions:
+** Returns TRUE on any error.
+**
+*/
+f far pascal LOADDS HelpDecomp (
+PB pbTopic,
+PB pbDest,
+nc ncContext
+) {
+fdb fdbLocal; // pointer to current FDB
+uchar far *fpszDest; // pointer to destination
+uchar far *fpTopic; // pointer to locked topic
+f fRv = TRUE; // return Value
+mh mhFdb; // handle to the fdb
+mh mhHuff;
+mh mhKey;
+
+mhFdb = ncContext.mh;
+if (LoadFdb (mhFdb, &fdbLocal)) { /* lock fdb down */
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+
+ // This funky sequence of code attempts to ensure that both the
+ // huffman and keyword decompression tables are loaded simultaneously
+ // since we cannot decompress without both.
+ //
+ // We do things three times to cover the following cases:
+ //
+ // 1) huffman loaded ok
+ // keyword loaded ok
+ // huffman already loaded
+ //
+ // 2) huffman loaded ok
+ // keyword loaded ok after HelpShrink (huffman discarded)
+ // huffman re-loaded ok (HelpShrink freed enough for both)
+ //
+ // 3) huffman loaded ok after HelpShrink
+ // keyword loaded ok after HelpShrink (huffman discarded)
+ // huffman re-loaded ok (memory fragmentation allowed it)
+ //
+ // The other cases, where either the load fails immediatly after
+ // any HelpShrink call, are the cases we cannot handle.
+ //
+ // Since handles can change due to the reallocation that can ocurr
+ // in the HelpShrink-reload sequence, we simply do the three
+ // loads, and then ensure that all the handles match what's in the
+ // fdb. If they don't, we fail.
+ //
+ mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
+ mhKey = LoadPortion (HS_KEYPHRASE,mhFdb);
+ mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
+
+ if ( LoadFdb (mhFdb, &fdbLocal)
+ && (mhKey == fdbLocal.rgmhSections[HS_KEYPHRASE])
+ && (mhHuff == fdbLocal.rgmhSections[HS_HUFFTREE])) {
+
+ char far *fpHuff;
+ char far *fpKey;
+
+ // At this point we lock EVERYTHING and ensure that we have
+ // valid pointers to it all. (Some swapped memory systems can
+ // fail at this point, so we need to be sensitive).
+ //
+ fpHuff = HelpLock (mhHuff);
+ fpKey = HelpLock (mhKey);
+ fpTopic = PBLOCK (pbTopic);
+ fpszDest = PBLOCK (pbDest);
+
+ if ( fpTopic
+ && fpszDest
+ && (fpHuff || (mhHuff == 0))
+ && (fpKey || (mhKey == 0))
+ ) {
+ decomp (fpHuff, fpKey, fpTopic, fpszDest+sizeof(topichdr));
+ fRv = FALSE;
+ }
+ }
+
+ // Unlock the handles, if they were valid.
+ //
+ if (mhKey != (mh)(-1))
+ HelpUnlock (mhKey);
+ if (mhHuff != (mh)(-1))
+ HelpUnlock (mhHuff);
+ }
+ else {
+ fpszDest = PBLOCK (pbDest);
+#if ASCII
+/*
+** ascii, just copy
+*/
+ fpTopic = PBLOCK(pbTopic);
+ if (fpTopic && fpszDest) {
+ hfstrcpy(fpszDest+sizeof(topichdr),fpTopic);
+#else
+ {
+#endif
+ fRv = FALSE;
+ }
+ }
+ if (!fRv) {
+ ((topichdr far *)fpszDest)->ftype = fdbLocal.ftype;
+ ((topichdr far *)fpszDest)->appChar = (uchar)fdbLocal.hdr.appChar;
+ ((topichdr far *)fpszDest)->linChar = (uchar)fdbLocal.hdr.appChar;
+ ((topichdr far *)fpszDest)->lnCur = 1;
+ ((topichdr far *)fpszDest)->lnOff = sizeof(topichdr);
+ }
+ PBUNLOCK (pbTopic);
+ PBUNLOCK (pbDest);
+ }
+return fRv;
+/* end HelpDecomp */}
+
+/******************************************************************************
+**
+** HelpNcNext - Return next context number
+**
+** Purpose:
+** Returns the context number corresponding to a physical "next" in the help
+** file.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcNext (
+nc ncCur
+) {
+return NextPrev(ncCur,1); /* get next */
+/* end HelpNcNext */}
+
+/******************************************************************************
+**
+** HelpNcPrev - Return phyiscally previous context
+**
+** Purpose:
+** Returns the context number corresponding to the physically previous topic.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcPrev (
+nc ncCur
+) {
+return NextPrev(ncCur,-1); /* get previous */
+/* end HelpNcPrev */}
+
+/******************************************************************************
+**
+** HelpNcUniq - Return nc guaranteed unique for a given topic
+**
+** Purpose:
+** Maps a context number to a local context number. This is provided such
+** that all context numbers which map to the same topic can be transformed
+** into the same nc which maps to that topic. The information on the
+** context string originally used is lost.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcUniq (
+nc ncCur
+) {
+fdb fdbLocal; /* pointer to current FDB */
+
+if (LoadFdb (ncCur.mh, &fdbLocal))
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+ nc ncTmp;
+
+ ncTmp.mh = fdbLocal.ncInit.mh;
+ ncTmp.cn = MapContexttoTopic(ncCur, &fdbLocal);
+ ncTmp.cn |= 0x8000;
+
+ ncCur = ncTmp;
+
+ // rjsa return MapContexttoTopic (ncCur,&fdbLocal)
+ // | (fdbLocal.ncInit & 0xffff0000)
+ // | 0x8000;
+
+ }
+return ncCur;
+/* end HelpNcUniq */}
+
+/******************************************************************************
+**
+** NextPrev - Return phyiscally next or previous context
+**
+** Purpose:
+** Returns the context number corresponding to the physically next or previous
+** topic.
+**
+** Entry:
+** ncCur = Current Context
+** fNext = 1 for next, -1 for previous.
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc pascal near NextPrev (
+ nc ncCur,
+ int fNext
+ ) {
+
+ fdb fdbLocal; /* pointer to current FDB */
+ REGISTER nc ncNext = {0,0};
+
+ if (LoadFdb (ncCur.mh, &fdbLocal)) {
+
+ //
+ // For a compressed file the next/previous physical is computed by taking the
+ // context number, mapping it to its corresponding topic number, incrementing
+ // or decrementing the topic number (remember, topic numbers are in physical
+ // order), and then mapping that back to a context number.
+ //
+ // When nexting, we also support nexting into any appended file.
+ //
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+ unsigned short cn;
+
+ cn = (ushort)(((ncCur.cn & 0x8000)
+ ? ncCur.cn & 0x7ffff
+ : MapContexttoTopic(ncCur, &fdbLocal))
+ + (ushort)fNext);
+
+ ncNext = MapTopictoContext(cn, (fdb far *)&fdbLocal, fNext);
+
+ // rjsa ncNext = MapTopictoContext((ushort)(((ncCur & 0x8000)
+ // ? ncCur & 0x7fff
+ // : MapContexttoTopic (ncCur,&fdbLocal))
+ // + fNext)
+ // ,(fdb far *)&fdbLocal);
+
+ //
+ // if we could not come up with a next, try to find a next using "local"
+ // context numbers. Map the context number to a topic number, and if that is
+ // not out of range, return it as a context.
+ //
+ if (!(ncNext.cn)) {
+
+ // rjsa if ((ncNext = MapContexttoTopic (ncCur,&fdbLocal)) == 0xffff)
+ // ncNext = 0;
+ ncNext.cn = MapContexttoTopic(ncCur, &fdbLocal);
+
+ if (ncNext.cn == 0xffff) {
+
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+
+ } else {
+
+ ncNext.cn += fNext;
+
+ if (ncNext.cn >= fdbLocal.hdr.cTopics) {
+
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+
+ } else {
+
+ // rjsa ncNext |= (fdbLocal.ncInit & 0xffff0000) | 0x8000;
+ ncNext.mh = fdbLocal.ncInit.mh;
+ ncNext.cn = 0x8000;
+ }
+ }
+ }
+
+ if (!(ncNext.cn & 0x7fff) && (fNext>0)) {
+ ncNext = fdbLocal.ncLink;
+ }
+ }
+
+#if ASCII
+
+ //
+ // minascii files:
+ // next'ing: we just sequentially search the file for the first context to
+ // come along after that pointed to by our current context number.
+ //
+ else if (fdbLocal.ftype & FTFORMATTED) {
+
+ if (fNext > 0) {
+
+ ncNext.cn = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)+4, HelpCmp);
+ if (ncNext.cn == -1L) {
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+ } else {
+ ncNext = combineNc(ncNext.cn, ncCur.mh);
+ }
+ // rjsa ncNext = (ncNext == -1L)
+ // ? 0
+ // : combineNc(ncNext,HIGH(ncCur));
+
+ } else {
+
+ nc ncTemp;
+
+ //
+ // prev'ing: start at the begining of the file, looking for the last context
+ // which is less than the current one.
+ //
+
+ ncNext = ncTemp = fdbLocal.ncInit;
+ while (NctoFo(ncTemp.cn) < NctoFo(ncCur.cn)) {
+ ncNext = ncTemp;
+ ncTemp.cn = maLocate(&fdbLocal,szNil,NctoFo(ncTemp.cn)+4, HelpCmp);
+
+ if (ncTemp.cn == -1L) {
+ ncTemp.mh = (mh)0;
+ ncTemp.cn = 0L;
+ } else {
+ ncTemp = combineNc(ncTemp.cn,fdbLocal.ncInit.mh);
+ }
+ // rjsa ncTemp = (ncTemp == -1L)
+ // ? 0
+ // : combineNc(ncTemp,HIGH(fdbLocal.ncInit));
+ }
+ }
+ }
+#endif
+ }
+ return ncNext;
+}
+
+/*************************************************************************
+**
+** HelpSzContext - Return string mapping to context number
+**
+** Purpose:
+** Construct a string, which when looked-up, will return the passed context
+** number.
+**
+** Entry:
+** pBuf = place to put the string
+** ncCur = The context number desired
+**
+** Exit:
+** True on sucess.
+**
+*/
+f pascal far LOADDS HelpSzContext (
+uchar far *pBuf,
+nc ncCur
+) {
+f fRet = FALSE; /* return value */
+ulong i;
+fdb fdbLocal; /* pointer to current FDB */
+mh mhCur; /* handle we're dealing with */
+char far *fpszContexts; /* pointer to context strings */
+
+*pBuf = 0;
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* lock fdb down */
+/*
+** Everybody starts with a filename
+*/
+ if (*fdbLocal.hdr.fname)
+ pBuf = hfstrcpy(pBuf,fdbLocal.hdr.fname);
+ else
+ pBuf = hfstrcpy(pBuf,fdbLocal.fname);
+ *(ushort far *)pBuf = '!'; /* includes null term */
+ pBuf++;
+ fRet = TRUE;
+
+ // if we've been given a local context number, see if we can synthesize
+ // a context number from which we might get a string. If we can't get
+ // one, then return just the filename.
+ //
+ if ((i = ncCur.cn) & 0x8000) { /* context # */
+ ncCur = MapTopictoContext ((ushort)(ncCur.cn & 0x7fff),&fdbLocal,0);
+ if ((i = ncCur.cn) & 0x8000) /* context # */
+ return fRet;
+ }
+/*
+** For compressed files (signified by being able to load context strings) we
+** just walk the context strings looking for string number "ncCur". Once found,
+** the returned string is just the concatenated filename, "!" and context
+** string.
+*/
+ mhCur = LoadPortion(HS_CONTEXTSTRINGS, ncCur.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpszContexts = HelpLock(mhCur))) {
+ if (i && (i <= fdbLocal.hdr.cContexts)) {
+ while (--i)
+ while (*fpszContexts++);/* point to next string */
+ hfstrcpy(pBuf,fpszContexts);/* copy over */
+ }
+ HelpUnlock (mhCur);
+ }
+ else if (fdbLocal.ftype & FTCOMPRESSED)
+ return FALSE;
+#if ASCII
+/*
+** for min ascii files, we search for the topic, and copy over the context
+** string directly from the file.
+*/
+ else if (fdbLocal.ftype & FTFORMATTED) {
+ long fpos;
+
+ if ((fpos = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)-1,HelpCmp)) != -1L) {
+ fpos = ReadHelpFile(fdbLocal.fhHelp,fpos+2,pBuf,80);
+ *(pBuf+fpos) = 0; /* ensure terminated */
+ if (pBuf = hfstrchr(pBuf,'\r'))
+ *pBuf = 0; /* terminate at CR */
+ }
+ }
+#endif
+ }
+return fRet;
+/* end HelpSzContext */}
+
+/******************************************************************************
+**
+** LoadPortion - Load a section of the help file
+**
+** Purpose:
+** If not loaded, allocates memory for and loads a section (as defined in
+** helpfile.h) of the current help file. Once loaded, or if already loaded,
+** locks it, and returns the the memory handle and pointer.
+**
+** This routine must be far, since it is an entry point for HelpMake
+**
+** Entry:
+** hsCur = Help section to be loaded.
+** mhfdb = memory handle for fdb
+**
+** Exit:
+** returns handle for memory
+**
+** Exceptions:
+** returns NULL on portion not existing, 0xffff on inability to allocate memory.
+**
+*/
+mh pascal near LoadPortion (
+int hsCur,
+mh mhfdb
+) {
+fdb fdbLocal;
+char far *fpDest = 0;
+int i;
+mh mhNew = 0; /* pointer to mh destination */
+ushort osize; /* additional prepended size */
+ushort size;
+
+if (LoadFdb (mhfdb, &fdbLocal)) {
+ if (((mhNew = fdbLocal.rgmhSections[hsCur]) == 0)
+ && fdbLocal.hdr.tbPos[hsCur]) {
+
+ for (i=hsCur+1; i<HS_count; i++)
+ if (fdbLocal.hdr.tbPos[i]) {
+ size = (ushort)(fdbLocal.hdr.tbPos[i]-fdbLocal.hdr.tbPos[hsCur]);
+ break;
+ }
+
+ osize = (hsCur == HS_KEYPHRASE) ? 1024*sizeof(PVOID) : 0;
+/*
+** Alloc the memory required. Re-read the FDB, incase intervening calls to
+** HelpShrink causes deallocs of other beasties.
+*/
+ if ( (mhNew = HelpAlloc(size + osize))
+ && LoadFdb (mhfdb, &fdbLocal)) {
+ fdbLocal.rgmhSections[hsCur] = mhNew;
+ if (PutFdb (mhfdb, &fdbLocal)) {
+ fpDest = (char far *)HelpLock(mhNew);
+ if (fpDest && ReadHelpFile(fdbLocal.fhHelp
+ ,(ulong)fdbLocal.hdr.tbPos[hsCur] + fdbLocal.foff
+ ,fpDest + osize
+ ,size)) {
+
+ if (hsCur == HS_KEYPHRASE)
+ kwPtrBuild(fpDest,size);/* build keyword pointers */
+ HelpUnlock (mhNew);
+ }
+ else {
+ fdbLocal.rgmhSections[hsCur] = 0;
+ HelpDealloc (mhNew);
+ PutFdb (mhfdb, &fdbLocal);
+ mhNew = (mh)(-1);
+ }
+ }
+ else
+ mhNew = (mh)0;
+ }
+ else
+ mhNew = (mh)(-1);
+ }
+ }
+
+return mhNew;
+
+/* end LoadPortion */}
+
+/*************************************************************************
+**
+** SizePos - Return count of bytes in compressed topic, and position
+**
+** Purpose:
+** Returns the size in bytes of the compressed topic, and it's location in the
+** help file.
+**
+** Entry:
+** ncCur - Context number to return info on.
+** psize - Pointer to place to put the size
+** ppos - Pointer to place to put the position
+**
+** Exit:
+** Returns TRUE on success.
+**
+** Exceptions:
+** Returns FALSE on all errors.
+**
+** Algorithm:
+**
+** If current help handle valid
+** If filetype is compressed
+** If context map not loaded, load it
+** Lock context map
+** Map context to topic number
+** Unlock context map
+** If topic index not loaded, load it
+** Lock topic index
+** size is difference in file positions
+** Unlock topic index
+** else if filetype is formatted ascii
+** seek to context file position
+** scan for next context definition
+** size is difference in file positions
+** else if filetype is unformatted ascii
+** size is filesize
+*/
+f pascal near SizePos (
+nc ncCur,
+ushort *psize,
+ulong *ppos
+) {
+fdb fdbLocal; /* pointer to current FDB */
+char far *fpT; /* temp pointer */
+REGISTER f fRv = FALSE; /* return value */
+ushort iTopic; /* topic index */
+mh mhCur; /* handle being locked */
+
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb copy */
+ if (fdbLocal.ftype & FTCOMPRESSED) {/* if a standard compressed file*/
+ if ((iTopic = MapContexttoTopic (ncCur,&fdbLocal)) != 0xffff) {
+ mhCur = LoadPortion(HS_INDEX,ncCur.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
+ *ppos = ((long far *)fpT)[iTopic];
+ *psize = (ushort)(((long far *)fpT)[iTopic+1] - *ppos);
+ HelpUnlock (mhCur);
+ fRv = TRUE;
+ }
+ }
+ }
+
+#if ASCII
+ else if (fdbLocal.ftype & FTFORMATTED) {/* if a formatted ascii file*/
+ if ((*psize = (ushort)(maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)+4, HelpCmp)))
+ == 0xffff)
+ *psize = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
+ else
+ *psize -= (ushort)NctoFo(ncCur.cn);
+ *ppos = (ulong) maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)-1, HelpCmp);
+ fRv = TRUE;
+ }
+ else { /* unformatted ascii */
+ *ppos = ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
+ *psize = (*ppos > (ulong)(65535-sizeof(topichdr)-4))
+ ? (ushort)(65535-sizeof(topichdr)-4)
+ : (ushort)*ppos;
+ *ppos = 0L; /* position is always zero. */
+ fRv = TRUE;
+ }
+#endif
+ }
+
+return fRv;
+/* end SizePos */}
+
+/************************************************************************
+**
+** MapContexttoTopic
+**
+** Purpose:
+** Given a context number, return the topic number which it maps to. This
+** is just a direct index of the context number into the context map.
+**
+** Entry:
+** ncCur = context number to be mapped
+** fpfdbCur = pointer to associated fdb
+**
+** Exit:
+** Returns zero based topic number, or 0xffff on error.
+*/
+ushort pascal near MapContexttoTopic (
+nc ncCur, /* context number to map */
+fdb far *fpfdbCur /* pointer to current FDB */
+) {
+REGISTER ushort topic = 0xffff; /* value to return */
+ushort far *fpT; /* pointer to context map */
+mh mhCur; /* handle being locked */
+
+if (ncCur.cn) {
+/*
+** Local contexts: the topic number is already encoded in the low word, if the
+** high bit of that word is set.
+*/
+ if (ncCur.cn & 0x8000)
+ topic = (ushort)(ncCur.cn & 0x7fff);
+/*
+** Normal Contexts: low word of nc is an index into the context map which
+** returns the topic number
+*/
+ else {
+ mhCur = LoadPortion(HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
+ topic = fpT[ncCur.cn-1];
+ HelpUnlock (mhCur);
+ }
+ }
+ }
+return topic;
+/* end MapContexttoTopic */}
+
+/************************************************************************
+**
+** MapTopictoContext
+**
+** Purpose:
+** Given a topic number, return a context which maps to it.
+**
+** This involves searching the context map for the first context entry that
+** maps to the desired topic number.
+**
+** Entry:
+** iTopic = topic number to map back to a context number
+** fpfdbCur = pointer to associated fdb
+**
+** Exit:
+** Returns a valid nc into the file.
+**
+** Exceptions:
+** If the incoming iTopic is invalid, or a read error occurs, then the nc
+** returned refers to the topic number 0.
+**
+*/
+nc pascal near MapTopictoContext(
+ushort iTopic, /* topic number to map */
+fdb far *fpfdbCur, /* pointer to current FDB */
+int Dir
+) {
+ ushort cTopics; /* number of topics to search */
+ ushort far *fpContextMap; /* pointer to the context map */
+ mh mhPortion; /* mem handle for the context map*/
+ nc ncMatch = {0,0}; /* return value */
+
+ mhPortion = LoadPortion (HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
+ if (mhPortion && (mhPortion != (mh)(-1))) {
+ if (fpContextMap = HelpLock(mhPortion)) {
+ if (iTopic >= fpfdbCur->hdr.cTopics) {
+ iTopic = 0;
+ }
+ ncMatch.mh = (mh)0L;
+ ncMatch.cn = 0x8000 | iTopic;
+ // rjsa ncMatch = 0x8000 | iTopic;
+ cTopics = 0;
+ while (cTopics < fpfdbCur->hdr.cContexts) {
+ if ( Dir == 0 ) {
+ if (iTopic == fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics; /* nc's are one based */
+ break;
+ }
+ } else if ( Dir > 0 ) {
+ if (iTopic <= fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics; /* nc's are one based */
+ break;
+ }
+
+ } else if ( Dir < 0 ) {
+
+ if (iTopic == fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics;
+ break;
+ } else if (iTopic < fpContextMap[cTopics-1]) {
+ ncMatch.cn = cTopics-1;
+ break;
+ }
+ }
+ }
+ //if ( iTopic != fpContextMap[cTopics-1] ) {
+ // ncMatch.cn = 0;
+ //}
+ if ( cTopics >= fpfdbCur->hdr.cContexts) {
+ ncMatch.cn = 0;
+ }
+ HelpUnlock (mhPortion);
+ }
+ }
+ ncMatch.mh = (fpfdbCur->ncInit).mh;
+ return ncMatch;
+ // rjsa return ncMatch | HIGHONLY(fpfdbCur->ncInit);
+}
+
+/************************************************************************
+**
+** LoadFdb - make local copy of fdb.
+**
+** Purpose:
+** Used to create a local copy of an FDB, so that we don't have to keep a
+** locked, far copy around.
+**
+** Entry:
+** mhFdb - memory handle for the FDB
+** fpFdbDest - Pointer to destination for FDB copy
+**
+** Exit:
+** returns TRUE if FDB copied.
+*/
+f pascal near LoadFdb (
+mh mhfdb,
+fdb far *fpfdbDest
+) {
+fdb far *fpfdbCur; /* pointer to current FDB */
+
+if (fpfdbCur = HelpLock (mhfdb)) {
+ *fpfdbDest = *fpfdbCur;
+ HelpUnlock (mhfdb);
+ return TRUE;
+ }
+return FALSE;
+/* end LoadFdb */}
+
+/************************************************************************
+**
+** PutFdb - make local copy of fdb permanent.
+**
+** Purpose:
+** Used to copy a local copy of an FDB to the "real" one, so that we don't
+** have to keep a locked, far copy around.
+**
+** Entry:
+** mhFdb - memory handle for the FDB
+** fpfdbSrc - Pointer to source of FDB copy
+**
+** Exit:
+** returns TRUE if FDB copied.
+*/
+f pascal near PutFdb (
+mh mhfdb,
+fdb far *fpfdbSrc
+) {
+fdb far *fpfdbCur; /* pointer to current FDB */
+
+if (fpfdbCur = HelpLock (mhfdb)) {
+ *fpfdbCur = *fpfdbSrc;
+ HelpUnlock (mhfdb);
+ return TRUE;
+ }
+return FALSE;
+/* end PutFdb */}
+
+#if ASCII
+/************************************************************************
+**
+** maLocate - Locate context in minimally formatted ascii file.
+**
+** Purpose:
+** Performs sequential searches on mimimally formatted ascii files to locate
+** lines beginning with ">>" and a context string.
+**
+** Entry:
+** fpfdbCur = Pointer to current fdb
+** fpszSrc = Pointer to context string to be found (or null for next
+** string)
+** offset = offset at which to begin search.
+** lpfnCMp = pointer to comparison routine to use
+**
+** Exit:
+** returns file offset of ">>" of context string.
+**
+** Exceptions:
+** returns -1 on error.
+**
+*/
+long pascal near maLocate (
+fdb far *fpfdbCur,
+uchar far *fpszSrc,
+ulong offset,
+f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
+) {
+uchar buffer[MASIZE+1]; /* input buffer */
+ushort cbBuf = 0; /* count of bytes in buffer */
+ushort cbSrc; /* length of source string */
+uchar far *pBuf; /* pointer into buffer */
+uchar far *pBufT; /* temp pointer into buffer */
+
+cbSrc = hfstrlen(fpszSrc)+1; /* get length of input */
+if (offset == 0xffffffff) /* special case */
+ offset = 0;
+while (cbBuf += (ushort)ReadHelpFile(fpfdbCur->fhHelp
+ , offset+cbBuf
+ , buffer+cbBuf
+ , MASIZE-cbBuf)) {
+
+ buffer[cbBuf] = 0; /* ensure strings terminated */
+ pBuf = &buffer[0];
+ while (pBuf = hfstrchr(pBuf,'>')) { /* look for start of context */
+ if ((*(pBuf+1) == '>') /* if >> found */
+ && ((*(pBuf-1) == '\n') /* at beginning of line */
+ || ((offset == 0) /* or beginning of file */
+ && (pBuf == (char far *)&buffer[0])))) {
+ pBufT = pBuf +2;
+ if (lpfnCmp (fpszSrc, pBufT, cbSrc, FALSE, TRUE))
+ return offset + (ulong)(pBuf - (uchar far *)&buffer[0]);
+ }
+ pBuf += 2;
+ }
+ if (cbBuf == MASIZE) { /* if buffer full */
+ hfstrcpy(buffer,buffer+MASIZE-MAOVER); /* copy down overlap */
+ cbBuf = MAOVER; /* and leave that in */
+ offset += MASIZE-MAOVER; /* file pos of buffer[0] */
+ }
+ else {
+ offset += cbBuf;
+ cbBuf = 0; /* else we're empty */
+ }
+ }
+return -1;
+
+/* end maLocate */}
+#endif
diff --git a/private/utils/mep/help/mshelp/makefile b/private/utils/mep/help/mshelp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/help/mshelp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/help/mshelp/mshelp.def b/private/utils/mep/help/mshelp/mshelp.def
new file mode 100644
index 000000000..8686b0eaa
--- /dev/null
+++ b/private/utils/mep/help/mshelp/mshelp.def
@@ -0,0 +1,29 @@
+LIBRARY MSHELP
+
+DESCRIPTION 'Help engine'
+
+EXPORTS
+ HelpcLines
+ HelpClose
+ HelpCtl
+ HelpDecomp
+ HelpGetCells
+ HelpGetInfo
+ HelpGetLine
+ HelpGetLineAttr
+ HelpHlNext
+ HelpLook
+ HelpNc
+ HelpNcBack
+ HelpNcCb
+ HelpNcCmp
+ HelpNcNext
+ HelpNcPrev
+ HelpNcRecord
+ HelpNcUniq
+ HelpOpen
+ HelpShrink
+ HelpSzContext
+ HelpXRef
+ LoadFdb
+ LoadPortion
diff --git a/private/utils/mep/help/mshelp/mshelp.rc b/private/utils/mep/help/mshelp/mshelp.rc
new file mode 100644
index 000000000..039e42627
--- /dev/null
+++ b/private/utils/mep/help/mshelp/mshelp.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "MS Help Utility DLL"
+#define VER_INTERNALNAME_STR "mshelp"
+#define VER_ORIGINALNAME_STR "MSHELP.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/help/mshelp/mshelp1.def b/private/utils/mep/help/mshelp/mshelp1.def
new file mode 100644
index 000000000..d06263f3a
--- /dev/null
+++ b/private/utils/mep/help/mshelp/mshelp1.def
@@ -0,0 +1,29 @@
+LIBRARY MSHELP1
+
+DESCRIPTION 'Help engine'
+
+EXPORTS
+ _HelpcLines
+ _HelpClose
+ _HelpCtl
+ _HelpDecomp
+ _HelpGetCells
+ _HelpGetInfo
+ _HelpGetLine
+ _HelpGetLineAttr
+ _HelpHlNext
+ _HelpLook
+ _HelpNc
+ _HelpNcBack
+ _HelpNcCb
+ _HelpNcCmp
+ _HelpNcNext
+ _HelpNcPrev
+ _HelpNcRecord
+ _HelpNcUniq
+ _HelpOpen
+ _HelpShrink
+ _HelpSzContext
+ _HelpXRef
+ _LoadFdb
+ _LoadPortion
diff --git a/private/utils/mep/help/mshelp/sources b/private/utils/mep/help/mshelp/sources
new file mode 100644
index 000000000..f99b23b8c
--- /dev/null
+++ b/private/utils/mep/help/mshelp/sources
@@ -0,0 +1,24 @@
+MAJORCOMP=utils
+MINORCOMP=mshelp
+
+TARGETNAME=mshelp
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+SYNCHRONIZE_DRAIN=1
+
+# TARGETLIBS=..\enginlib\obj\*\engine.lib \nt\public\sdk\lib\*\kernel32.lib \nt\public\sdk\lib\*\crt.lib
+LINKLIBS=..\enginlib\obj\*\engine.lib
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib \
+ \nt\private\sdktools\ztools\src\obj\*\ztools.lib \
+ \nt\public\sdk\lib\*\user32.lib
+
+INCLUDES=.;..\inc;
+
+SOURCES= help.c mshelp.rc
+
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+UMRES=obj\*\mshelp.res
+USE_CRTDLL=1