diff options
Diffstat (limited to 'private/utils/mep/help')
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 |