/*** htest - help engine test harness * * Copyright 1987, Microsoft Corporation * * Revision History: * * 15-Dec-1988 ln Added dump command * [] 21-Oct-1988 LN New Version * *************************************************************************/ #include #include #include #include #if defined (OS2) #define INCL_SUB #define INCL_DOSMODULEMGR #define INCL_DOSFILEMGR #define INCL_DOSMISC #include #include #else #include #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= 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; i0) { 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