[net.sources] VMS like HELP for the PC. Executable in comp.sys.ibm.pc.

broehl@watale.UUCP (Michael A. Shiels) (12/11/86)

This is a help program which was written to simulate the VMS help facility
using a directory structure which is traversed.  This version also has
alot of customization features and pauses every 24 lines because it uses
the NANSI.SYS raw mode.

I hope I put in all the support routines.  It's hard to tell when all I do
is link with my whole library.  But it is too big too post!!


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by watale!broehl on Wed Dec 10 21:44:11 EST 1986
# Contents:  cd.c cptodlow.c cptolow.x cpy.x denv.x findfile.c fptext.c
#	fptext.x getargs.c getargs.h getargs.x help.c help.man help.rc
#	helpdir.c helpdir.h intro.txt make.ini makefile masdos.h maserr.h
#	mynewlin.x mynewline.def next.c next.x reargv.c reargv.x setraw2.c
#	ssort.c ssort.x unargv.c unargv.x
 
echo x - cd.c
sed 's/^@//' > "cd.c" <<'@//E*O*F cd.c//'
#define LINT_ARGS
#include	<stdio.h>
#include	<dos.h>

cd( name )
register char	*name;
{
	union REGS regs;
	int	todrive,todrive2;

	if( name[1] == ':')
	{
		todrive = toupper(*name) - 'A';
		bdos( 0x0E, todrive, 0);
		regs.h.ah = 0x19;
		regs.h.al = 0x00;
		intdos( &regs, &regs );
		todrive2 = regs.h.al;
		if( todrive != todrive2 )
			return( -1 );
		name += 2;
	}

	if( *name  &&  chdir( name ) < 0 )
		return( -1 );
	return( 0 );
}

chdrv( name )
register char	*name;
{
	union REGS regs;
	int	todrive,todrive2;

	todrive = toupper(*name) - 'A';
	bdos( 0x0E, todrive, 0);
	regs.h.ah = 0x19;
	regs.h.al = 0x00;
	intdos( &regs, &regs );
	todrive2 = regs.h.al;
	if( todrive != todrive2 )
		return( -1 );
	return( 0 );
}

@//E*O*F cd.c//
chmod u=rw,g=r,o=r cd.c
 
echo x - cptodlow.c
sed 's/^@//' > "cptodlow.c" <<'@//E*O*F cptodlow.c//'
char	*cptodlower( dest, src )
register char	*dest, *src;
{
	/*	Copy src to dest, mapping all upper case letters to lower
	 *	case. src and dest may be the same.
	 */

	for(; *src ; src++ )
	{
		if( *src == '.' )
			break;
		*dest++ = ('A' <= *src && *src <= 'Z')
					? *src + ('a'-'A') : *src ;
	}
	*dest = '\0' ;
	return dest  ;
@//E*O*F cptodlow.c//
chmod u=rw,g=r,o=r cptodlow.c
 
echo x - cptolow.x
sed 's/^@//' > "cptolow.x" <<'@//E*O*F cptolow.x//'
extern	char	*cptolower( char *, char * );
@//E*O*F cptolow.x//
chmod u=rw,g=r,o=r cptolow.x
 
echo x - cpy.x
sed 's/^@//' > "cpy.x" <<'@//E*O*F cpy.x//'
extern	char	*cpy( char *, char * );
@//E*O*F cpy.x//
chmod u=rw,g=r,o=r cpy.x
 
echo x - denv.x
sed 's/^@//' > "denv.x" <<'@//E*O*F denv.x//'
extern	int		Dfind_orig( void );
extern	int		Dfind_size( void );
extern	int		putdenv( char * );
extern	char	*getdenv( char * );
@//E*O*F denv.x//
chmod u=rw,g=r,o=r denv.x
 
echo x - findfile.c
sed 's/^@//' > "findfile.c" <<'@//E*O*F findfile.c//'
#define LINT_ARGS
#include	<stdio.h>
#include	<stdlib.h>
#include	<ctype.h>
#include	<string.h>
#include	<dos.h>
#include	"masdos.h"

static struct FILEINFO *Dta_save;

find_first( filespec, attributes, dta )
char			*filespec;
unsigned int    attributes;
char 			*dta;
{
        union REGS regs;
        int         ercode;

        D_IN("find_first");
        regs.x.ax = B_GETDTA;
        intdos( &regs, &regs );
        Dta_save = (struct FILEINFO *) regs.x.bx;
        regs.x.ax = B_SETDTA;
        regs.x.dx = dta;
        intdos( &regs, &regs );
        regs.x.ax = B_FINDFIRST;
        regs.x.dx = (int) filespec;
        regs.x.cx = attributes;
        ercode = intdos( &regs, &regs );
        regs.x.ax = B_SETDTA;
        regs.x.dx = (unsigned int) Dta_save;
        intdos( &regs, &regs );
        if( ercode == 0 )
        {
                D_PRT("find_first","no error");
        }
        D_OUT("find_first");
        return( ercode );
}

int find_next( dta )
char	*dta;
{
        union REGS regs;
        int         ercode;

        D_IN("find_next");
        regs.x.ax = B_GETDTA;
        intdos( &regs, &regs );
        Dta_save = (struct FILEINFO *) regs.x.bx;
        regs.x.ax = B_SETDTA;
        regs.x.dx = dta;
        intdos( &regs, &regs );
        regs.x.ax = B_FINDNEXT;
        ercode = intdos( &regs, &regs );
        regs.x.ax = B_SETDTA;
        regs.x.dx = (unsigned int) Dta_save;
        intdos( &regs, &regs );
        if( ercode == 0 )
        {
                D_PRT("find_next","no error");
        }
        D_OUT("find_next");
        return( ercode );
}

ffind_first( filespec, attributes )
char			*filespec;
unsigned int    attributes;
{
        union REGS regs;
        int         ercode;

        D_IN("find_first");
        regs.x.ax = B_FINDFIRST;
        regs.x.dx = (int) filespec;
        regs.x.cx = attributes;
        ercode = intdos( &regs, &regs );
        if( ercode == 0 )
        {
                D_PRT("find_first","no error");
        }
        D_OUT("find_first");
        return( ercode );
}

int ffind_next()
{
        union REGS regs;
        int         ercode;

        D_IN("find_next");
        regs.x.ax = B_FINDNEXT;
        ercode = intdos( &regs, &regs );
        if( ercode == 0 )
        {
                D_PRT("find_next","no error");
        }
        D_OUT("find_next");
        return( ercode );
}

void frstdta()
{
        union REGS regs;

        regs.x.ax = B_SETDTA;
        regs.x.dx = (unsigned int) Dta_save;
        intdos( &regs, &regs );
}

void fchgdta( dta )
char 			*dta;
{
        union REGS regs;

        regs.x.ax = B_GETDTA;
        intdos( &regs, &regs );
        Dta_save = (struct FILEINFO *) regs.x.bx;
        regs.x.ax = B_SETDTA;
        regs.x.dx = dta;
        intdos( &regs, &regs );
}
@//E*O*F findfile.c//
chmod u=rw,g=r,o=r findfile.c
 
echo x - fptext.c
sed 's/^@//' > "fptext.c" <<'@//E*O*F fptext.c//'
/*
*
*!AU: Michael A. Shiels
*!CD: 1-Jun-86
*!FR: Dr. Dobbs July 1985
* 
*/

#define LINT_ARGS
#include <stdio.h>
#include	<signal.h>

#include "masdos.h"

#include	"waitfork.x"

#define PTEXT_IBM

static	int		ptextctrlchit = 0;
static	int		(*oldsignal)();

static	ptextctrlc()
{
	ptextctrlchit = 1;
	signal( SIGINT, ptextctrlc );
}

/*	ptext( dirc, dirv, Arg_Num_Cols, 79 / Arg_Num_Cols,
		(dirc/Arg_Num_Cols) + (dirc % Arg_Num_Cols != 0) ); */

fptexth( linec, linev, numcols, colwidth, numrows, where )
int	     linec, numcols, colwidth;
char	    **linev;
int	     numrows;
FILE	*where;
{
	register int    j,i;
	register char   **lineend, **line, **nextline;
	register int	linenum = 0;

	ptextctrlchit = 0;
	oldsignal = signal( SIGINT, ptextctrlc );

	for( j = numrows ; --j >= 0 && !ptextctrlchit ; )
	{
#ifdef PTEXT_IBM
		putc( ' ', where );
#endif
		lineend = &linev[numcols - 1];
	 
		for( i = numcols ; --i >= 0 && *linev ; linev++ )
		{
			pr_line( *linev, colwidth,
				linev < lineend, where );
		}
		mynewline( where );
	}
	fflush( where );
	signal( SIGINT, oldsignal );
	D_OUT("ptexth");
}

fptextv( linec, linev, numcols, colwidth, numrows, where )
int	     linec, numcols, colwidth;
char	    **linev;
int	     numrows;
FILE	*where;
{
	register int    j;
	register char   **lineend, **line, **nextline;
	register int	linenum = 0;

	lineend = &linev[linec - 1];
	 
	for( j = numrows ; --j >= 0 ; )
	{
#ifdef PTEXT_IBM
		putc( ' ', where );
#endif
		for( line = linev++ ; line <= lineend ; line = nextline )
	    {
			nextline = line + numrows;
			pr_line( *line, colwidth,
				nextline <= lineend );
		}
		mynewline( where );
	}
	D_OUT("ptextv");
}

static pr_line( str, width, padded, where )
register char  *str;
int	    width, padded;
FILE	*where;
{
	int	     col = 0;
	 
	while( col < width && *str )
	{
		if( *str == '\n' )
			break;
		
		else if( *str == '\r' )
		{
			while( col > 0 )
			{
				--col;
				putc( '\b', where );
			}

			str++;
		}
		else if( *str == '\t' )
		{
			str++;
			col++;
			putc( ' ', where );
			 
			while( ( col % 8 ) && col < width )
			{
				putc( ' ', where );
				col++;
			}
		}
		else
		{
			if( *str == Q_ESC )
			{
				putc( *str++, where );
				if( !*str )
					break;
	
				putc( *str++, where );
				if( !*str )
					break;
	
				putc( *str++, where );
				if( !*str )
					break;
			}
			else if( *str == '\b' )
				--col;
			else if( *str >= ' ' )
				++col;
     
		putc( *str++, where );
		}
	}
	if( padded )
		while( col++ < width )
			putc( ' ', where );
}
@//E*O*F fptext.c//
chmod u=rw,g=r,o=r fptext.c
 
echo x - fptext.x
sed 's/^@//' > "fptext.x" <<'@//E*O*F fptext.x//'
extern int fptexth( int, char **, int, int, int, FILE * );
extern int fptextv( int, char **, int, int, int, FILE * );
@//E*O*F fptext.x//
chmod u=rw,g=r,o=r fptext.x
 
echo x - getargs.c
sed 's/^@//' > "getargs.c" <<'@//E*O*F getargs.c//'
/*
*
* Getargs.c
*
*!AU: Michael A. Shiels
*!CD: 21-May-86
*!FR: Dr. Dobb's May 1985
*
*/

#define GETARGS_C
#define LINT_ARGS
#include	<stdio.h>
#include	<stdlib.h>
#include	"masdos.h"
#include	"maserr.h"
#include	"getargs.h"

extern	void	usage( void );
extern	int		stoi( char ** );

typedef int	(*PFI)();

char	ARG_Switch = '/';
int		ARG_ICase = 0;
static	char	getsoptb[100];

static  char    *setarg( argp, linep )
ARG		*argp ;
char	*linep ;
{
	++linep ;
 
	switch( argp->type )
	{
	case    ARG_INTEGER :
			*argp->variable = stoi( &linep ) ;
			break ;
 
	case    ARG_FBOOLEAN :
			*argp->variable = 1;
			break ;
 
	case    ARG_TBOOLEAN :
			*argp->variable = 0;
			break ;
 
	case    ARG_SBOOLEAN :
			*argp->variable = ( *argp->variable ? 0 : 1 );
			break ;
 
	case    ARG_CHARACTER :
			*argp->variable = *linep++ ;
			break ;
 
	case    ARG_STRING :
			*(char **)argp->variable = linep ;
			linep = "" ;
			break;
	
	case	ARG_PROCESS :
			(* (PFI)(argp->variable) )( linep );
			linep = "";
			break;		

	default :
			fprintf( stderr, "GetArgs: Internal Error: Bad Argument Type\n" );
			break ;
	}
	return( linep ) ;
}
 
static  ARG     *findarg( c, tabp, tabsize )
int	     c, tabsize ;
ARG	     *tabp ;
{
	for( ; --tabsize >= 0 ; tabp++ )
	{
		if( ARG_ICase && toupper(tabp->arg) == toupper(c) )
			return( tabp );
		if( tabp->arg == c )
			return( tabp );
		}
		return( NULL );
}
 
static  pr_usage( tabp, tabsize )
ARG		*tabp;
int		tabsize;
{
	for( ; --tabsize >= 0 ; tabp++ )
	{
		switch( tabp->type )
		{
		case    ARG_INTEGER :
				fprintf(stderr, "%c%c<num> %-40s (value is ",
					ARG_Switch, tabp->arg, tabp->errmsg) ;
				fprintf(stderr, "%-5d)\n", *(tabp->variable) ) ;
				break ;
 
		case    ARG_TBOOLEAN :
				fprintf(stderr, "%c%c T    %-40s (value is ",
					ARG_Switch, tabp->arg, tabp->errmsg) ;
				fprintf(stderr, "%-5s)\n", *(tabp->variable)
					? "True" : "False") ;
				break ;
 
		case    ARG_SBOOLEAN :
				fprintf(stderr, "%c%c S    %-40s (value is ",
					ARG_Switch, tabp->arg, tabp->errmsg) ;
				fprintf(stderr, "%-5s)\n", *(tabp->variable)
					? "True" : "False") ;
				break ;
 
		case    ARG_FBOOLEAN :
				fprintf(stderr, "%c%c F    %-40s (value is ",
					ARG_Switch, tabp->arg, tabp->errmsg) ;
				fprintf(stderr, "%-5s)\n", *(tabp->variable)
					? "True" : "False") ;
				break ;
 
		case    ARG_CHARACTER :
				fprintf(stderr, "%c%c<c>   %-40s (value is ",
					ARG_Switch, tabp->arg, tabp->errmsg) ;
				fprintf(stderr, "%-5c)\n", *(tabp->variable) ) ;
				break ;
 
		case    ARG_STRING :
				fprintf(stderr, "%c%c<str> %-40s (value is ",
					ARG_Switch, tabp->arg, tabp->errmsg) ;
				fprintf(stderr, "<%s>)\n",
					*(char **)tabp->variable) ;
				break ;

		case 	ARG_PROCESS :
				fprintf(stderr, "%c%c<str> %-40s\n",
						ARG_Switch, tabp->arg, tabp->errmsg);
				break;
		}
	}
}
 
#define ARG_ERRMSG "Illegal argument <%c>. Legal arguments are:\n\n"
 
int	     getargs( argc, argv, tabp, tabsize )
int	     argc, tabsize ;
char	    **argv ;
ARG	     *tabp ;
{
	register int    nargc ;
	register char   **nargv, *p ;
	register ARG    *argp ;
	char buf[2], *bufp = buf;

	if( (bufp = getenv("SWITCHAR")) )
		ARG_Switch = *bufp;

	nargc = 1 ;
	for( nargv = ++argv ; --argc > 0 ; argv++ )
	{
		if( **argv != ARG_Switch || !strcmp( *argv, "-" ) )
		{
			*nargv++ = *argv ;
			nargc++ ;
		}
		else
		{
			p = ( *argv ) + 1 ;
 
			while( *p )
			{
				if( *p == ARG_Switch )
					p++;
				else if( argp = findarg( *p, tabp, tabsize ) )
				{
					p = setarg( argp, p ) ;
				}
				else
				{
					usage();
					fprintf( stderr, ARG_ERRMSG, *p );
					pr_usage( tabp, tabsize );
					exit( E_USAGE );
				}
			}
		}
	}
	return nargc ;
}

void	getopts( tabp, tabsize, opts )
int	    tabsize ;
ARG	    *tabp ;
char	*opts;
{
	register char   *p ;
	register ARG    *argp ;
	char *buf, *bufp;

	if( (buf = getmenv(opts)) )
	{
		while( bufp = next( &buf, ',', -1 ) )
		{
			p = ( bufp );
			while( *p )
			{
				if( argp = findarg( *p, tabp, tabsize ) )
				{
					p = setarg( argp, p ) ;
				}
				else
				{
					usage();
					fprintf( stderr, ARG_ERRMSG, *p );
					pr_usage( tabp, tabsize );
					exit( E_USAGE );
				}
			}
		}
	}
}

void	getsopts( tabp, tabsize, file )
int	    tabsize ;
ARG	    *tabp ;
char	*file;
{
	register	char	*p ;
	register	ARG		*argp ;
	char	*buf = getsoptb,	*bufp = getsoptb;
	FILE	*fp = NULL;

	strcat( getsoptb, getmenv("GETSOPTS") );
	strcat( getsoptb, file );

	if( (fp = fopen(getsoptb, "r")) )
	{
		if( !getl( getsoptb, 255, fp) )
		{
			fclose( fp );
			return;
		}
		else
		{
			while( bufp = next( &buf, ',', -1 ) )
			{
				p = ( bufp );
				while( *p )
				{
					if( argp = findarg( *p, tabp, tabsize ) )
						p = setarg( argp, p );
					else
					{
							usage();
							fprintf( stderr, ARG_ERRMSG, *p );
							pr_usage( tabp, tabsize );
							exit( E_USAGE );
					}
				}
			}
		}
	}
}
@//E*O*F getargs.c//
chmod u=rw,g=r,o=r getargs.c
 
echo x - getargs.h
sed 's/^@//' > "getargs.h" <<'@//E*O*F getargs.h//'
#ifndef GETARGS_INCLUDED
#define GETARGS_INCLUDED
/*
*
* Getargs.h
*
*!AU: Michael A. Shiels
*!CD: 22-May-86
*!FR: Dr. Dobb's May 1985
*
*/

#define ARG_INTEGER		0
#define ARG_TBOOLEAN	1
#define ARG_SBOOLEAN	2
#define ARG_FBOOLEAN	3
#define ARG_CHARACTER	4
#define ARG_STRING		5
#define ARG_PROCESS		6
 
typedef struct
{
		int				arg;			/* Command Line Switch      */
		int				type;			/* Variable Type            */
		int				*variable;		/* Pointer to Variable      */
		char			*errmsg;		/* Pointer to Error Message */
}
ARG ;

#ifndef GETARGS_C
extern int	ARG_ICase;
extern int	ARG_Switch;
#endif

#endif	/* GETARGS_INCLUDED */
@//E*O*F getargs.h//
chmod u=rw,g=r,o=r getargs.h
 
echo x - getargs.x
sed 's/^@//' > "getargs.x" <<'@//E*O*F getargs.x//'
extern	int		getargs( int, char **, ARG *, int );
extern	void	getopts( ARG *, int, char * );
extern	void	getsopts( ARG *, int, char * );
@//E*O*F getargs.x//
chmod u=rw,g=r,o=r getargs.x
 
echo x - help.c
sed 's/^@//' > "help.c" <<'@//E*O*F help.c//'
/* Help: (C) Copyright 1986 Michael A. Shiels
   
   This program is Copyright by Michael Shiels and may be given away and
   used in other programs as long as the Copyright notices are not removed
   or altered.  No profit can be made from the distribution of this product
   except by the author.
*/

#include	<stdio.h>
#include	<stdlib.h>
#include	<io.h>
#include	<conio.h>
#include	<direct.h>
#include	<process.h>
#include	<signal.h>
#include	<string.h>

#include	"getargs.h"
#include	"masdos.h"
#include	"maserr.h"

#include	"helpdir.h"

#include	"denv.x"
#include	"unargv.x"
#include	"getargs.x"
#include	"reargv.x"
#include	"mynewlin.x"
#include	"fptext.x"

extern	int		Lusage( char * );

static	int     Arg_Copy		= 1;
static	int		Arg_Max_Wild	= 100;
static	int		Arg_Max_Help	= 100;
static	char	*Arg_Help_Dir	= "";
static	int		Arg_Num_Cols	= 5;
static	int		Arg_Vert_Prt	= 0;


ARG Argtab[] =
{
	{ 'c', ARG_INTEGER,		&Arg_Num_Cols,		"Number of columns for Topics" },
	{ 'd', ARG_STRING,		(int *)&Arg_Help_Dir,	"Help Directory" },
	{ 'h', ARG_INTEGER,		&Arg_Max_Help,		"Maximum number of help Topics" },
	{ 'v', ARG_SBOOLEAN,	&Arg_Vert_Prt,		"Print Topics Vertically" },
	{ 'w', ARG_INTEGER,		&Arg_Max_Wild,		"Maximum number of wildcard searchs" },
	{ '(', ARG_SBOOLEAN,	&Arg_Copy,			"Print Copyright Notice" },
	{ '!', ARG_PROCESS,		Lusage,				"Long Usage" }
};

#define ARG_TABSIZE ( sizeof(Argtab) / sizeof(ARG) )

void usage()
{
	E( "Usage: Help [Topic [Subtopic]...]\n" );
	E( "\n" );
	E( "Version 1.00 Copyright (c) 1986, Michael A. Shiels\n");
	E( "\n" );
}

Lusage( dum )
char *dum;
{
	E( "Usage: Help [Topic [Subtopic]...]\n" );
	E( "\n");
	E( "Set the environment variable SWITCHAR to the character\n");
	E( "you wish to use for the Switch Character.\n");
	E( "\n" );
	E( "Set the environment variable HELPOPTS to the standard options\n");
	E( "you wish to have Help use every time.  These can be overidden\n");
	E( "with the command line switches. (eg. HELPOPTS=( will cause it to\n");
	E( "suppress the copyright notice)\n");
	E( "\n" );
	E( "Set the environment variable GETSOPTS to the directory where\n");
	E( "you wish to store the .RC file for Help to use.  These can be overidden\n");
	E( "with the command line switches. (eg. HELP.RC contains ( will\n");
	E( "cause it to supress the copyright notice)\n");
	E( "\n" );
	E2( "Case of the command line switches %s important\n", ARG_ICase ? "is not" : "is" );
	E( "\n" );
	E( "Version 1.00 Copyright (c) 1986, Michael A. Shiels. All rights reserved.\n" );
	E( "\n" );
	exit( E_USAGE );
}

#define HELPDIR "/usr/help"

char	olddir[101];

static	char	helplev[101], *helplevp = helplev;
static	FILE	*stderrR;
static	int		oldraw;
static	int		helpctrlchit = 0;
static	int		helpwild = 0;

extern	helpreset();
extern	char *helpprompt();
extern	void	helplevel();
extern	void	helptopics();
extern	void	helpdisplay1( char * );
extern	void	helpdisplay2( char * );
extern	void	helpr( char * );

mynewline( where )
FILE	*where;
{
	static	int	linenum = 0;
	int	oldraw;

	fputs( "\n", where );
	if( !(++linenum % 24) )
	{
		fflush( where );
		oldraw = getraw( fileno( where ) );
		setraw( fileno( where ), 0 );
		fputs( P_REVERSE, stderr );
		fputs( P_BLINKING, stderr );
		fputs("<Hit any character for next page>",stderr);
		fputs( P_ALL_OFF, stderr );
		getch();
		setraw( fileno( where ), oldraw );

		fputs("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",where);
		fputs("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", where );
		fputs("                                 ",where);
		fputs("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",where);
		fputs("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", where );
		fflush( where );
	}
	return( 0 );
}

helpctrlc()
{
	helpctrlchit = 1;
	signal( SIGINT, helpctrlc );
}

helpreset()
{
	cd( olddir );
	setraw( fileno( stderrR ), 0 );
	fclose( stderrR );
	exit( 0 );
}

char *helpprompt()
{
	static	char		tmpstr[103], *tmpstrp = tmpstr;

	tmpstr[0] = 100;
redo:
	mynewline( stderrR );
	if( helplevp == NULL || *helplevp == NULL )
		fprintf( stderrR, "Topic? " );
	else
		fprintf( stderrR, "%s %s", helplevp, "Subtopic? " );
	fflush( stderrR );
	oldraw = getraw( fileno( stderrR ) );
	setraw( fileno( stderrR ), 0 );
	tmpstrp = cgets( tmpstr );
	setraw( fileno( stderrR ), 1 );
	mynewline( stderrR );
	if( tmpstr[2] == 26 )
		helpreset();
	if( tmpstr[2] == '?' && tmpstr[3] == '\0' )
	{
		helplevel( NULL );
		if( access( "intro.txt", 0 ) >= 0 )
			helpdisplay1( "intro.txt" );
		helptopics();
		goto redo;
	}
	else if( tmpstr[2] == '#' && tmpstr[3] == '\0' )
	{
		helplevel( NULL );
		if( access( "intro.txt", 0 ) >= 0 )
			helpdisplay1( "intro.txt" );
		goto redo;
	}
	else if( tmpstr[2] == '$' && tmpstr[3] == '\0' )
	{
		helplevel( NULL );
		helptopics();
		goto redo;
	}
	else if( tmpstr[2] == '!' && tmpstr[3] == '\0' )
	{
		spawnl( P_WAIT, getenv("COMSPEC"), getenv("COMSPEC"), NULL );
		goto redo;
	}
	else if( tmpstr[2] == '!' )
	{
		system( tmpstrp + 1 );
		goto redo;
	}
	else if( tmpstr[1] > 0 )
		return( tmpstrp );
	else
		return( NULL );
}

void	helplevel( level )
char	*level;
{
	if( (level != NULL && *level != NULL) || (helplevp != NULL && *helplevp != NULL) )
	{
		mynewline( stderrR );
	}
	if( helplevp != NULL && *helplevp != NULL )
		fprintf( stderrR, "%s%s%s", P_REVERSE, helplevp, P_ALL_OFF );
	if( level != NULL && *level != NULL )
		fprintf( stderrR, " %s%s%s", P_REVERSE, level, P_ALL_OFF );
	if( (level != NULL && *level != NULL) || (helplevp != NULL && *helplevp != NULL) )
	{
		mynewline( stderrR );
		mynewline( stderrR );
	}
	fflush( stderrR );
}

static  void  printdir(dirc, dirv, maxwidth)
int	dirc   ;
char	**dirv ;
{
	if( !Arg_Num_Cols )
		Arg_Num_Cols = 79 / (maxwidth+1) ;

	mynewline( stderrR );
    if( Arg_Vert_Prt )
		fptextv( dirc, dirv, Arg_Num_Cols, 79 / Arg_Num_Cols,
			(dirc/Arg_Num_Cols) + (dirc % Arg_Num_Cols != 0), stderrR );
	else
		fptexth( dirc, dirv, Arg_Num_Cols, 79 / Arg_Num_Cols,
			(dirc/Arg_Num_Cols) + (dirc % Arg_Num_Cols != 0), stderrR );
	mynewline( stderrR );
}

void	helptopics()
{
	char	tmpstr[101], *tmpstrp = tmpstr;
	int		i;
	HDIRECTORY	*hdp1 = 0;
	char	*nexthelp;
	
	if( (hdp1 = mk_hdir( Arg_Max_Help )) )
	{
		hdp1->sort  = 1;
		hdp1->dirs	= 1;
		hdp1->files	= 1;
		hdir( "*.hl*" , hdp1 );
		if( (hdp1->ndirs + hdp1->nfiles) )
		{
			mynewline( stderrR );
			if( helplevp == NULL || *helplevp == NULL )
				fprintf( stderrR, "Topics Available." );
			else
				fprintf( stderrR, "Subtopics Available." );
			mynewline( stderrR );
			fflush( stderrR );
			printdir( hdp1->nfiles + hdp1->ndirs, hdp1->dirv, hdp1->width);
		}
		del_hdir( hdp1 );
	}
	else
	{
		E( "Help:helptopics: unable to create hdir structure for topic searching\n" );
	}
}

void	helpdisplay1( filename )
char	*filename;
{
	register FILE	*fp;
	char		buf[1024];
	int		(*oldsignal)();

	if( getenv("HELPDISPLAY1") )
	{
		putenv("CMDLINE");
		spawnlp( P_WAIT, getenv("HELPDISPLAY1"), getenv("HELPDISPLAY1"), filename, NULL );
	}
	else
	{
		helpctrlchit = 0;
		oldsignal = signal( SIGINT, helpctrlc );
		if( (fp = fopen( filename, "r")) )
		{
			while( fgets(buf, 1024, fp) != NULL && !helpctrlchit )
			{
				buf[strlen(buf)-1] = '\0';
				fputs( buf, stderrR );
				mynewline( stderrR );
			}
			fflush( stderrR );
			fclose( fp );
			signal( SIGINT, oldsignal );
			helpctrlchit = 0;
		}
	}
}

void	helpdisplay2( filename )
char	*filename;
{
	register FILE	*fp;
	char		buf[1024];
	int		(*oldsignal)();

	if( getenv("HELPDISPLAY2") )
	{
		putenv("CMDLINE");
		spawnlp( P_WAIT, getenv("HELPDISPLAY2"), getenv("HELPDISPLAY2"), filename, NULL );
	}
	else
	{
		helpctrlchit = 0;
		oldsignal = signal( SIGINT, helpctrlc );
		if( (fp = fopen( filename, "r")) )
		{
			while( fgets(buf, 1024, fp) != NULL && !helpctrlchit )
			{
				buf[strlen(buf)-1] = '\0';
				fputs( buf, stderrR );
				mynewline( stderrR );
			}
			fflush( stderrR );
			fclose( fp );
			signal( SIGINT, oldsignal );
			helpctrlchit = 0;
		}
	}
}

dohelp( retstr )
char	*retstr;
{
	char	tmpstr[101], *tmpstrp = tmpstr;
	char	tmpstr2[101], *tmpstr2p = tmpstr2;
	int		i;
	HDIRECTORY	*hdp = 0;
	char	*nexthelp;
	char	*tmpp;
	int		(*oldsignal)();
	
	nexthelp = next( &retstr, ' ', 0 );
	strcpy( tmpstr, nexthelp );
	strcat( tmpstr, ".hlp" );
	strcpy( tmpstr2, nexthelp );
	strcat( tmpstr2, ".hld" );
	if( chdir( tmpstr2 ) >= 0 )
	{
		strcat( helplevp, " " );
		strcat( helplevp, nexthelp );
		helpr( retstr );
		chdir( ".." );
		tmpp = strrchr( helplevp, ' ' );
		*tmpp = '\0';
	}
	else if( access( tmpstr, 0 ) >= 0 )
	{
		helplevel( nexthelp );
		if( retstr != NULL && *retstr != NULL )
		{
			fprintf( stderrR, "Help: reached end of help tree - ignoring '%s'", retstr );
			mynewline( stderrR );
		}
		helpdisplay2( tmpstr );
	}
	else
	{
		if( (hdp = mk_hdir( Arg_Max_Wild ) ) )
		{
			strcpy( tmpstr, nexthelp );
			strcat( tmpstr, "*.hl*" );
			hdp->files = 1;
			hdp->dirs  = 1;
			hdp->sort  = 1;
			hdir( tmpstr, hdp );
			if( ( hdp->ndirs + hdp->nfiles ) == 1 )
			{
				strcpy( tmpstr, hdp->dirv[0] );
				strcat( tmpstr, retstr );
				dohelp( tmpstrp );
			}
			else if( ( hdp->ndirs + hdp->nfiles ) == 0 )
			{
				fprintf( stderrR, "Help: unable to find help for '%s'", nexthelp );
				mynewline( stderrR );
			}
			else
			{
				i = 0;
				helpwild = 1;
				helpctrlchit = 0;
				oldsignal = signal( SIGINT, helpctrlc );
				while( i <= ( hdp->ndirs + hdp->nfiles - 1 ) && !helpctrlchit )
				{
					strcpy( tmpstr, hdp->dirv[i++] );
					strcat( tmpstr, retstr );
					dohelp( tmpstrp );
					tmpstrp = tmpstr;
				}
				signal( SIGINT, oldsignal );
				helpctrlchit = 0;
				helpwild = 0;
			}
			del_hdir( hdp );
		}
		else
		{
			E( "Help:dohelp: Unable to create hdir structure for multiple help requests\n" );
		}
	}
}

void	helpr( topic )
char	*topic;
{
	char	*retstr = 1;
	
	if( topic == NULL || *topic == NULL )
	{
		helplevel( NULL );
		if( access( "intro.txt", 0 ) >= 0 )
			helpdisplay1( "intro.txt" );
		helptopics();
	}
	else
	{
		dohelp( topic );
	}
	while( retstr != NULL && !helpwild )
	{
		retstr = helpprompt();
		if( retstr != NULL && *retstr != NULL )
		{
			dohelp( retstr );
		}
	}
}

main(argc, argv)
int argc;
char *argv[];
{
	char	helpstr[128], *helpstrp = helpstr;
	
	reargv( &argc, &argv );
	getsopts( Argtab, ARG_TABSIZE, "HELP.RC" );
	Arg_Copy = 1;
	getopts( Argtab, ARG_TABSIZE, "HELPOPTS" );
	argc = getargs( argc, argv, Argtab, ARG_TABSIZE );

	if( Arg_Copy )
		E( "Help Version 1.00 Copyright (c) 1986, Michael A. Shiels. All rights reserved.\n" );

	signal( SIGINT, helpreset );

	stderrR = fopen( "con", "w" );
	if (stderrR == NULL)
	{
		E( "Help: can't open 'con' for rawmode\n");
		exit( 100 );
	}
	setraw( fileno( stderrR ), 1 );

	getcwd( olddir, 101 );

	if( Arg_Help_Dir == NULL || *Arg_Help_Dir == NULL )
		Arg_Help_Dir = getdenv("HELPDIR");
		if( Arg_Help_Dir == NULL || *Arg_Help_Dir == NULL )
			Arg_Help_Dir = HELPDIR;

	if( cd( Arg_Help_Dir ) < 0)
	{
		E2( "Help: Help root directory not found for %s.\n", Arg_Help_Dir );
		exit(100);
	}

	*argv++;
	unargv( argc-1, argv, helpstrp, 128 );

	if (argc >= 1)
	    helpr( helpstr );
	else
		helpr( NULL );

	helpreset();
}
@//E*O*F help.c//
chmod u=rw,g=r,o=r help.c
 
echo x - help.man
sed 's/^@//' > "help.man" <<'@//E*O*F help.man//'
HELP              Michael Shiels' DOSIX Programmer's Manual                HELP



NAME
     help - user-friendly documentation reader


SYNOPSIS
     help [ -c<#>d<str>h<#>vw<#> ] [ topic-path ]


DESCRIPTION
     Help is a documentation reader based closely on the VMS(tm)
     help facility.  Documentation texts are arranged in a tree,
     and the users reads them with the built in interface or with
     another file viewer. Help allows documentation to be treated
     as an n-tree, the structure of the help tree is the structure
     of the directory tree in which the help files reside.

     The help program is invoked from the shell like

          help [ options ] topic sub-topic sub-sub-topic ...

     Topic may be any top-level help file name.  A topic-path is
     a path of topics and their subtopics, down into the tree.
     Topic and subtopic names may be abbreviated, but no wild-
     cards are recognized.

     The options are:

     c<#>   The number will be used as the number of columns for the
            Topic/Subtopic listings.

     d<str> Next argument is the help root directory.  Default is
            what ever $HELPDIR is set to or /usr/help.

     h<#>   The number will be used as the maximum number of help
            topics/subtopics which will ever occur at any level.
            This is usually set up in the HELP.RC file.

     v      This triggers vertical instead of horizontal printing
            of the help topics/subtopics.

     w<#>   The number will be used as the maximum number of help
            topics/subtopics which will be requested during an
            ambiguous helprequest.
            This is usually set up in the HELP.RC file.

     
     The help interactive mode asks the user what help he would
     like next.  The prompt looks like this:

     Topic?

     or like this:

      vi commands deletion Subtopic?

     Where "vi commands deletion" is the help tree path. This
     path is printed for each prompt, and as a header for each
     help text.

     The following commands are meaningful in to the "topic?"
     prompt:

     ?  Print current introduction and subtopic-list again.

     #  Print current introduction again.

     $  Print current subtopic-list again.

     !<CR>
        To shell to the current setting of $COMSPEC.

     !command
        To run the 'command' under $COMSPEC.

     Return <CR>
        Exit this level of help.  If at top level, goes back to
        calling program.

     <subtopic-name>
        Read the documentation for this subtopic, or all subto-
        pics for which this is a legal abbreviation.  Wildcards
        are not permitted, but a short abbreviation matches
        everything longer.

     ^Z Exit the help program.


HELP FILES

     Help files are the text and directories of the help documen-
     tation tree.  There are four kinds of help files: topic directory,
     introduction file, and subtopic file.

     The usual way of calling help is to just type

     % help

     in the shell.  This brings up help in interactive mode at the
     top level of topics.  The user can always abort with ctrl/Z.


GENERAL ENVIRONMENT VARIABLES
     SWITCHAR - is used to detect which character you wish to use for
                the command line option trigger.  Usually it is '/' but
                if you are a UNIXer you can set it to '-'.

     GETSOPTS - is used to locate the HELP.RC file which can be used
                to change some of the defaults for the command line
                switches.  Usually it is used to increase the number
                of help topics/subtopics which can be available at
                any one level.

     COMSPEC - this is used to locate the COMMAND shell.


ENVIRONMENT VARIABLES
     HELPOPTS - is used to override the HELP.RC file and set up personal
                command line preferences.

     HELPDIR - is the root of the help system.

     HELPDISPLAY1 - can be set to a program (such as more) which will be
                    used to display the introductory text file if there
                    is one.

     HELPDISPLAY2 - can be set to a program (such as more) which will be
                    used to display the help files.


EXAMPLE
     HELPDIR = J:/HELP
     Thie disk structure would look like this

     J:\HELP\INTRO.TXT              Introduction which will be display when
                                    the topics at this level are displayed
     J:\HELP\AUTOEXEC.HLP           Help Text
     J:\HELP\GNUPLOT.HLD            Subtopic Directory
     J:\HELP\GNUPLOT.HLD\PLOT.HLP   Subtopic Help Text
     J:\HELP\GNUPLOT.HLD\EXPR.HLD   SubSubtopic Directory
     ...


AUTHOR
     Michael A. Shiels ( mshiels@electrical.watstar.waterloo.EDU )
     604 Bridle Wood
     Burlington, Ontario
     CANADA, L7L 4C7


FILES
	 $GETSOPTS/HELP.RC
	 $HELPDIR/...
	 NANSI.SYS


NOTES
     This program will use the 'RAW' mode of the NANSI.SYS driver if it
     is loaded, but it can still be run with ANSI.SYS.

     All user prompting is read using 'cgets' so CED will work at the
     help prompts.


SEE ALSO
     more, pc-more, smore, list, nansi, ced.


DIAGNOSTICS
     Error messages are printed whenever a request is made to get
     documentation that does not exists, or is not accessible.


BUGS
     The file naming conventions are very strict.
@//E*O*F help.man//
chmod u=rw,g=r,o=r help.man
 
echo x - help.rc
sed 's/^@//' > "help.rc" <<'@//E*O*F help.rc//'
h500,dj:\help
@//E*O*F help.rc//
chmod u=rw,g=r,o=r help.rc
 
echo x - helpdir.c
sed 's/^@//' > "helpdir.c" <<'@//E*O*F helpdir.c//'
/* Help: (C) Copyright 1986 Michael A. Shiels
   
   This program is Copyright by Michael Shiels and may be given away and
   used in other programs as long as the Copyright notices are not removed
   or altered.  No profit can be made from the distribution of this product
   except by the author.
*/

#define LINT_ARGS
#include <stdio.h>
#include <ctype.h>
#include <dos.h>

#include	"masdos.h"

#include "helpdir.h"

#include	"cpy.x"
#include	"next.x"
#include	"cptolow.x"
#include	"ssort.x"

#define iswhite(c)	((c) == ' ' || (c) == '\t')

int	haswild(s)
register char	*s;
{
	for( ; *s ; s++)
		if( *s == '*' || *s == '?' )
			return 1;
	return 0;
}

/*----------------------------------------------------------------------*/

static int  dirtoa( target, infop )
register char	    *target   ;
register struct	FILEINFO  *infop    ;
{
	char *startstr = target;

	target = cptodlower( target, infop->fi_name );

	return( target - startstr );
}

/*----------------------------------------------------------------------*/

static int	add_entry( infop, dp )
struct	FILEINFO		*infop	;
register HDIRECTORY	*dp	;
{
	char		buf[128] ;
	register int	len   ;

	if( IS_HIDDEN(infop->fi_attrib) || *infop->fi_name == '.' )
		return 1;

	if( dp->maxdirs <= 0  )		/* No more room in dirv. return	*/
		return 0;		/* error status			*/

	if( IS_SUBDIR(infop->fi_attrib) )	
	{
		if( dp->dirs )
			dp->ndirs++  ;
		else
			return 1;
	}
	else
	{
		if( dp->files )
			dp->nfiles++  ;
		else
			return 1;
	}

	len = dirtoa( buf, infop );

	if( len > dp->width )
		dp->width = len ;
		
	if( *dp->lastdir = malloc(len + 1) )
	{
		strcpy( *dp->lastdir++, buf )    ;
		--dp->maxdirs;
		return 1;
	}

	return 0;
}

static  int  cmp( pp1, pp2 )
char	**pp1, **pp2;
{
	register char	*p1 = *pp1;
	register char	*p2 = *pp2;
	int		num1, num2;

	while( (num1 = (isdigit(*p1) && isdigit(*p2))) || (*p1 == *p2 && *p1) )
	{
		if( !num1 )
		{
			p1++;
			p2++;
		}
		else
		{
			num1 = num2 = 0;

			do {
				num1 = (num1 * 10) + ( *p1++ - '0');
			} while( isdigit(*p1) );

			do {
				num2 = (num2 * 10) + ( *p2++ - '0');
			} while( isdigit(*p2) );

			if( num1 != num2 )
				return( num1 - num2 );
		}
	}

	return( *p1 - *p2 );
}

/*----------------------------------------------------------------------*/

HDIRECTORY  *mk_hdir( size )
register unsigned size;
{
	register HDIRECTORY  *dp;
	register unsigned   amt_mem;

	amt_mem = sizeof(HDIRECTORY) + (size * sizeof(char *));

	if( !( dp = (HDIRECTORY *) malloc(amt_mem) ))
		return 0;

	memset( dp, 0, amt_mem );	/* Initialize *dp to zeros */

	dp->maxdirs = size ;
	dp->lastdir = dp->dirv;
	return dp;
}

/*----------------------------------------------------------------------*/

del_hdir( dp )
register HDIRECTORY	*dp;
{
	register char	**v;

	for( v = dp->dirv; v < dp->lastdir ; free( *v++ ) )
		;

	free( dp );
}

/*----------------------------------------------------------------------*/

hdir( spec, dp )
char	   *spec;
HDIRECTORY  *dp;
{
	struct	FILEINFO     info;
	char	      **firstdir;

	fchgdta( &info );

	firstdir = dp->lastdir;

	if( !ffind_first( spec, A_ALL)  )
	{
		if( !add_entry(&info, dp ) )	
			goto aborted;

		if( haswild(spec) )
		{
			while( !ffind_next() )
				if( !add_entry(&info, dp ) )
					goto aborted;
		}
	}

	if( dp->sort )
		ssort( (char *)firstdir, dp->lastdir - firstdir,
					sizeof(char*), cmp);
	goto abort;

aborted:
	E( "Help:hdir: unable to add entries - increase the appropriate	parameter\n" );
abort:
	frstdta();			/* Restore the original dta	*/

}
@//E*O*F helpdir.c//
chmod u=rw,g=r,o=r helpdir.c
 
echo x - helpdir.h
sed 's/^@//' > "helpdir.h" <<'@//E*O*F helpdir.h//'
/* Help: (C) Copyright 1986 Michael A. Shiels
   
   This program is Copyright by Michael Shiels and may be given away and
   used in other programs as long as the Copyright notices are not removed
   or altered.  No profit can be made from the distribution of this product
   except by the author.
*/

typedef	struct 
{
	char	 **lastdir ;	/* Most recent addition to dirv		*/
	int	 maxdirs   ;	/* # of free slots in dirv		*/
	int	 nfiles    ;	/* # of used slots that are files	*/
	int	 ndirs	   ;	/* # of used slots that are directories	*/
	unsigned width	  : 7 ; /* Width of widest element in dirv	*/

	unsigned files    : 1 ;	/* Include files in list		*/
	unsigned dirs     : 1 ; /* Include directories in list		*/
	unsigned sort	  : 1 ; /* Sort added entries			*/

	char	 *dirv[1];	/* The first of the dirv entries	*/
}
HDIRECTORY;
@//E*O*F helpdir.h//
chmod u=rw,g=r,o=r helpdir.h
 
echo x - intro.txt
sed 's/^@//' > "intro.txt" <<'@//E*O*F intro.txt//'
Welcome to the Help system.

The following commands can be used at the Topic/Subtopic prompt:

       ? - to redisplay the most recent introduction and topic listing
       # - to redisplay the most recent introdcution only
       $ - to redisplay the most recent topic listing only
       ! - to shell to DOS
       !cmd - to execute the 'cmd'

                                           Any questions or problems mail
                                           MSHIELS@ELECTRICAL

@//E*O*F intro.txt//
chmod u=rw,g=r,o=r intro.txt
 
echo x - make.ini
sed 's/^@//' > "make.ini" <<'@//E*O*F make.ini//'
# This is a sample `make.ini' file for NDMAKE v3.1.  You will probably want
# to customize it for your system.

# Prints a help message.

# The order to search for rules and files is specified by .SUFFIXES
@.SUFFIXES :
@.SUFFIXES : .exe .com .obj .c .asm

# A few macros.
LIB = N:\1
INCLUDE = N:\1

MODEL		= S
CFLAGS		= /A$(MODEL)
CDEFINES	=
CLIBS		=

AFLAGS	= /mx
ALIBS	=

SETARGV	=	$(LIB)\$(MODEL)SETARGV
BINMODE	=	$(LIB)\$(MODEL)BINMODE

LFLAGS = /NOIGNORE

# A few universally useful targets.  This first target is here in case
# you are using NDMAKE without a makefile and you type "make" with no
# arguments.

clean:
	+-erase *.bak
	+-erase *.map

@.BEFORE:
	@+echo NDMake: For help with make, use the command `make -h'
@.AFTER:
	@+echo NDMake: All done.

ASM		=	masm
CC		=	msc
CL		=	cl
LINK	=	link
EXE2BIN	=	exe2bin

CCMP	=	$(CC) $(CFLAGS) $(CDEFINES) /Fo$@ $?
CLINK	=	$(LINK) $<, $@, nul, $(LFLAGS) $(CLIBS)

# DEFAULT RULES
# To produce a `.obj' file from a `.asm' file.
@.asm.obj:
	$(ASM) $(AFLAGS) $*.asm;

# To produce a `.obj' file from a `.c' file.
@.c.obj:
	$(CCMP);


@.obj.exe:
	$(CLINK);

# To produce a `.exe' file from a `.asm' file.
@.asm.exe:
	$(ASM) $(AFLAGS) $*.asm;
	$(LINK) $*.obj, $@, nul, $(ALIBS);

@.asm.com:
	$(ASM) $(AFLAGS) $*.asm;
	$(LINK) $*.obj, $@, nul, $(ALIBS);
	$(EXE2BIN) $*.exe $*.com

@.exe.com:
	$(EXE2BIN) $*.exe $*.com

# To produce a `.exe' file from a `.c' file.
@.c.exe:
	cl $(CFLAGS) $(CDEFINES) $*.c -link $(LFLAGS) $(CLIBS)
@//E*O*F make.ini//
chmod u=rw,g=r,o=r make.ini
 
echo x - makefile
sed 's/^@//' > "makefile" <<'@//E*O*F makefile//'
#/* Help: (C) Copyright 1986 Michael A. Shiels
#   
#   This program is Copyright by Michael Shiels and may be given away and
#   used in other programs as long as the Copyright notices are not removed
#   or altered.  No profit can be made from the distribution of this product
#   except by the author.
#*/
# HELP Makefile
#

help.exe :	help.obj helpdir.obj
	$(CLINK) mshiels;

# Dependants

help.obj :	help.c

helpdir.obj :	helpdir.c

help.c :	helpdir.h

helpdir.c :	helpdir.h



@//E*O*F makefile//
chmod u=rw,g=r,o=r makefile
 
echo x - masdos.h
sed 's/^@//' > "masdos.h" <<'@//E*O*F masdos.h//'
#ifndef MASDOS_INCLUDED
#define MASDOS_INCLUDED

/*
*
* D_ debuging
* A_ attributes for files
* P_ print characteristics
* Q_ characters
* B_ BDOS interupt parameters
*
*/

#define max(a,b)	(((a) > (b)) ? (a) : (b))
#define min(a,b)	(((a) < (b)) ? (a) : (b))
#define abs(a)		(((a) < 0) ? -(a) : (a))

#define EOS(s)		while(*s) s++

#define ISQUOTE(c)	((c)=='\"' || (c)=='\'')
#define ISSQUOTE(c)	((c)=='\'')
#define ISDQUOTE(c)	((c)=='\"')

#define ISWILD(c)	((c)=='*' || (c)=='?' )

#define ISVSBRACE(c)	((c)=='{' || (c)=='(' )
#define ISVEBRACE(c)	((c)=='}' || (c)==')' )

#define SKIPWHITE(p)	while( isspace(*p) ) p++

#define ROUND(n,u)	( !((n) % (u)) ? (n) : (((n) / (u)) + 1) * (u))

#define E(x)		fprintf( stderr, x )
#define E2(x,y)		fprintf( stderr, x, y )

#if (!defined(M_I86CM) && !defined(M_I86LM))
#define	NullS		(char *)0
#else
#define	NullS		(char *)0L
#endif


#ifdef DEBUGGING
#ifdef THIS_IS_MAIN
int	Lev = -1;
#else
extern int Lev;
#endif
#define TRACE(p)		fprintf( stderr, "%*s{ entering %s\n" , ++Lev * 2, "", p )
#define END_TRACE(p)	fprintf( stderr, "%*s} exiting  %s\n" , Lev-- * 2, "", p )
#define P_TRACE(p,q)	fprintf( stderr, "%*s| %s=%s\n", Lev * 2, "", p, q )
#define DIAG(f,a)		fprintf( stderr, "%*s| ", Lev * 2, "" );\
						fprintf( stderr, f, a )
#else
#define TRACE(p)
#define END_TRACE(p)
#define	P_TRACE(p)
#define DIAG(f,a)
#endif

#ifdef DEBUGGING

#define D_IN(p) fprintf(stderr,"(%s) In\n",p)
#define D_OUT(p) fprintf(stderr,"(%s) Out\n",p)
#define D_PRT(p,q) fprintf(stderr,"(%s) %s\n",p,q)

#define D_S(p,q,r) fprintf(stderr,"(%s) %s %s\n",p,q,r)
#define D_I(p,q,r) fprintf(stderr,"(%s) %s %d\n",p,q,r)

#else

#define D_IN(p)
#define D_OUT(p)
#define D_PRT(p,q)

#define D_S(p,q,r)
#define D_I(p,q,r)

#endif

#define NNULL 1

struct FILEINFO
{
        unsigned char    fi_resv[21];                /* Reserved by DOS */
        unsigned char    fi_attrib;                  /* File Attributes */
        unsigned int     fi_time;                    /* Create/Update time */
        unsigned int     fi_date;                    /* Create/Update date */
        unsigned long    fi_fsize;                   /* File Size (bytes) */
        char             fi_name[13];                /* File Name & Extension */
};

#define A_READONLY      0x01
#define A_HIDDEN        0x02
#define A_SYSTEM        0x04
#define A_LABEL         0x08
#define A_SUBDIR        0x10
#define A_DIRTY         0x20

#define A_ALL           0xff
#define A_ALL_FILES     (A_HIDDEN&A_SYSTEM)
#define A_NORM_FILES    0x00

#define IS_READONLY(p)  ((p) & A_READONLY)
#define IS_HIDDEN(p)    ((p) & A_HIDDEN)
#define IS_SYSTEM(p)    ((p) & A_SYSTEM)
#define IS_LABEL(p)     ((p) & A_LABEL)
#define IS_SUBDIR(p)    ((p) & A_SUBDIR)
#define IS_DIRTY(p)     ((p) & A_DIRTY)

#define C_HOUR(p)       (((p) >> 11) & 0x1f)
#define C_MIN(p)        (((p) >> 5) & 0x3f)
#define C_SEC(p)        (((p) << 1) & 0x3e)
#define C_YEAR(p)       ((((p) >> 9) & 0x7f) + 1980)
#define C_MONTH(p)      (((p) >> 5) & 0x0f)
#define C_DAY(p)        (((p)) & 0x1f)

#define Q_ESC           0x1b

#define P_ALL_OFF       "\033[0m"
#define P_BOLDFACE      "\033[1m"
#define P_UNDERLINE     "\033[4m"
#define P_BLINKING      "\033[5m"
#define P_REVERSE       "\033[7m"

#define B_PRGTRM        0x0000
#define B_KBDINP        0x0100
#define B_DSPOUT        0x0200
#define B_AUXINP        0x0300
#define B_AUXOUT        0x0400
#define B_PRNOUT        0x0500
#define B_CONIO         0x0600
#define B_CONDIN        0x0700
#define B_CONINN        0x0800
#define B_PRTSTR        0x0900
#define B_KBDBIN        0x0a00

#define B_SEL_DISK      0x0e00

#define B_SETDTA        0x1a00

#define B_GETDTA        0x2f00

#define B_IOCTL			0x4400

#define B_FINDFIRST     0x4e00
#define B_FINDNEXT      0x4f00

#define IO_CTRL  0x4000
#define IO_ISDEV 0x0080
#define IO_EOF   0x0040
#define IO_RAW   0x0020
#define IO_ISCLK 0x0008
#define IO_ISNUL 0x0004
#define IO_ISCOT 0x0002
#define IO_ISCIN 0x0001

#define	CARRY	 0x01

#endif /* MASDOS_INCLUDED */

@//E*O*F masdos.h//
chmod u=rw,g=r,o=r masdos.h
 
echo x - maserr.h
sed 's/^@//' > "maserr.h" <<'@//E*O*F maserr.h//'
#ifndef MASERR_I_
#define MASERR_I_

/*
*
* E_ error codes
*
*/

#define	E_OK			0
#define	E_USAGE		  200
#define E_FNDENV	  201
#define E_ENVFULL	  202
#define	E_CTLC		  254
#define	E_STACK		  255

#endif	/* MASERR_I_ */

@//E*O*F maserr.h//
chmod u=rw,g=r,o=r maserr.h
 
echo x - mynewlin.x
sed 's/^@//' > "mynewlin.x" <<'@//E*O*F mynewlin.x//'
extern	int	mynewline( FILE * );
@//E*O*F mynewlin.x//
chmod u=rw,g=r,o=r mynewlin.x
 
echo x - mynewline.def
sed 's/^@//' > "mynewline.def" <<'@//E*O*F mynewline.def//'
#include	<stdio.h>

mynewline( where )
FILE	*where;
{
	fputs( "\n", where );
	return( 0 );
}
@//E*O*F mynewline.def//
chmod u=rw,g=r,o=r mynewline.def
 
echo x - next.c
sed 's/^@//' > "next.c" <<'@//E*O*F next.c//'
/*
 * NEXT.C:
 *
 * Skip to the next delimiter seperated object
 *
 */

#define iswhite(c) ( (c) == ' ' || (c) == '\t' || (c) == '\n' )


char	*next( linep, delim, esc )
char	**linep;
{
	/* Linep is the address of a character pointer that points to
	 * a string containing a series of delim seperated objects.
	 * Next will return a pointer to the first non-white object in
	 * *linep, replace the first delimiter it finds with a null, and
	 * advance *linep to point past the null (provided that it's not
	 * at end of string). 0 is returned when an empty string is passed
	 * to next(). White space may be used as a delimiter but
	 * in this case whitespace won't be skipped. A delimiter preceeded
	 * by "esc" is ignored. Quoted strings are copied verbatum.
	 */ 

	register char	*start, *end ;
	int		inquote = 0;

	if( !**linep )
		return 0;

	start = *linep;

	if( !iswhite(delim) )
		for( ; iswhite(*start) ; start++ )
			;

	for( end = start; *end && (*end != delim || inquote) ; end++ )
	{
		if( *end == esc  &&  *(end+1) )
			end++;

		 else if( *end == '"' || *end == '\'' )
			inquote = ~inquote;
	}

	if( *end )
		*end++ = '\0';

	*linep = end;
	return start;
}
@//E*O*F next.c//
chmod u=rw,g=r,o=r next.c
 
echo x - next.x
sed 's/^@//' > "next.x" <<'@//E*O*F next.x//'
extern	char	*next( char **, int, int );
@//E*O*F next.x//
chmod u=rw,g=r,o=r next.x
 
echo x - reargv.c
sed 's/^@//' > "reargv.c" <<'@//E*O*F reargv.c//'
#define REARGV_C
#define LINT_ARGS
#include <stdio.h>
#include <ctype.h>

/*	Re-assemble the argv/argc string using the CMDLINE environment.
 *	Note that the environment string itself is destroyed by this
 *	process.
 */

#define	MAXARGC		((unsigned)128)
#define isquote(c)	( (c)=='\"' || (c)=='\'')

extern	char	*getmenv( char* 	  );

static  int	Envlen;

/*----------------------------------------------------------------------*/

static char	*nextarg( pp )
char		**pp;
{
	register char	*p;
	char		*start;
	register int	term;

	if( !*(p = *pp)  )		/* No more args to get , return 0 */
		return (char *) 0;

	while( isspace(*p) )		/* Skip white space		  */
		p++;

	term = isquote(*p) ? *p++ : ' ' ;

	for( start = p; *p ; p++)
	{
		if( *p == term &&  *(p-1) != '\\' )
		{
			*p++ = '\0';
			break;
		}
	}

	*pp = p;

	return start;
}

/*----------------------------------------------------------------------*/

int	reargv( argcp, argvp )
char	***argvp;
int	*argcp;
{
	char		**argv ;
	register int	argc = 0 ;
	register int	maxc = MAXARGC ;
	static	 char	*vects[MAXARGC];
	char		*p   ;

	if( !(p = getmenv("CMDLINE")) ||  !*p )
		return 0;

	Envlen = strlen(p);

	argv = vects;

	for( maxc=MAXARGC; --maxc >= 0 && (*argv++ = nextarg(&p)); argc++)
		;

	if( maxc < 0 )
		fprintf(stderr, "Library:reargv: Command line truncated\n");

	*argcp = argc;
	*argvp = vects;
	return 1;
}

/*----------------------------------------------------------------------*/

envlen()	/* Returns the original length of the CMDLINE environment */
{
	return Envlen;
}

/*----------------------------------------------------------------------*/

#ifdef DEBUGMAIN

main( argc, argv )
char	**argv;
{
	printf("Original command line is: |");
	while( --argc >= 0 )
		printf("%s|", *argv++ );

	if( !reargv( &argc, &argv ) )
		printf("\nCMDLINE not present\n");
	else
	{
		printf("New argc = %d\n", argc );
		printf("\nModified command line is: |");

		while( --argc >= 0 )
			printf("%s|", *argv++ );

		printf("\n");
	}
}

#endif
@//E*O*F reargv.c//
chmod u=rw,g=r,o=r reargv.c
 
echo x - reargv.x
sed 's/^@//' > "reargv.x" <<'@//E*O*F reargv.x//'
extern	int	reargv( int *, char *** );
extern	int	reargvwv( int *, char *** );
@//E*O*F reargv.x//
chmod u=rw,g=r,o=r reargv.x
 
echo x - setraw2.c
sed 's/^@//' > "setraw2.c" <<'@//E*O*F setraw2.c//'
/*------ setraw.lc ----------------------------------------------
Lattice C routines which get and set the current raw/cooked state
of a file, given its Lattice file descriptor.
Useful when trying to obtain high console output speeds.
----------------------------------------------------------------*/

#include	<dos.h>

#define CARRY 0x1
#define ERROR (-1)
#define TRUE 1
#define FALSE 0

extern _oserr;

/*---- getraw --------------------------------------------------
Returns TRUE if file fd is a device in raw mode; FALSE otherwise.
Returns ERROR, puts errorcode in _oserr, if DOS error.
----------------------------------------------------------------*/
getraw(fd)
int fd;
{
	union REGS inregs;
	union REGS outregs;
	int	flags;

	inregs.x.bx = fd;
	inregs.x.ax = 0x4400;		/* get file attributes */
	flags = intdos( &inregs, &outregs );
	return (outregs.x.dx & 0x20) ? TRUE : FALSE;
}

/*---- setraw --------------------------------------------------
Sets Raw state of file fd to raw_on (if file is not a device, does nothing).
Returns zero if successful.
Returns ERROR & errorcode in _oserr if DOS error.
----------------------------------------------------------------*/
setraw(fd, raw_on)
int fd, raw_on;
{
	union REGS inregs;
	union REGS outregs;
	int	flags;

	inregs.x.ax = 0x4400;		/* get file attributes */
	inregs.x.bx = fd;
	flags = intdos(&inregs, &outregs);
	if ((outregs.x.ax & 0x80) == 0)	/* return zero if not device */
		return 0;

	outregs.x.ax = 0x4401;		/* set file attributes */
	outregs.x.bx = fd;
	outregs.x.dx &= 0xcf;		/* clear old raw bit & hi byte */
	if (raw_on) outregs.x.dx |= 0x20;	/* maybe set new raw bit */
	flags = intdos(&outregs, &inregs);
	return 0;
}
/*-- end of setraw.lc --*/
@//E*O*F setraw2.c//
chmod u=rw,g=r,o=r setraw2.c
 
echo x - ssort.c
sed 's/^@//' > "ssort.c" <<'@//E*O*F ssort.c//'
/*	SSORT.C		Works just like qsort() except that a shell
 *			sort, rather than a quick sort, is used. This
 *	is more efficient than quicksort for small numbers of elements
 *	and it's not recursive so will use much less stack space.
 *	This routine started out as the one in K&R.
 *
 *	12/13/85:  Modified to select a gap from the series
 *		   1, 4, 13, 40, 121 ... as per Knuth.
 *
 *	Copyright (C) 1985, Allen I. Holub.  All rights reserved
 */

void	ssort( base, nel, width, cmp )
char	*base;
int	nel, width;
int	(*cmp)();
{
	register int	i, j;
	int		gap, k, tmp ;
	char		*p1, *p2;

	for( gap=1; gap <= nel; gap = 3*gap + 1 )
		;

	for( gap /= 3;  gap > 0  ; gap /= 3 )
		for( i = gap; i < nel; i++ )
			for( j = i-gap; j >= 0 ; j -= gap )
			{
				p1 = base + ( j      * width);
				p2 = base + ((j+gap) * width);

				if( (*cmp)( p1, p2 ) <= 0 )
					break;

				for( k = width; --k >= 0 ;)
				{
					tmp   = *p1;
					*p1++ = *p2;
					*p2++ = tmp;
				}
			}
}
@//E*O*F ssort.c//
chmod u=rw,g=r,o=r ssort.c
 
echo x - ssort.x
sed 's/^@//' > "ssort.x" <<'@//E*O*F ssort.x//'
extern	void	ssort( char *, int, int, int (*)() );
@//E*O*F ssort.x//
chmod u=rw,g=r,o=r ssort.x
 
echo x - unargv.c
sed 's/^@//' > "unargv.c" <<'@//E*O*F unargv.c//'
#define UNARGV_C
#define LINT_ARGS
#include <stdio.h>

/*	UNARGV.C	Concatantate all argv entries into a single
 *			string.
 */

int	unargv( argc, argv, dest, maxcount )
char	      **argv, *dest;
register int  maxcount;
{
	/*	Turn argv into a single string, with a single ' ' seperating
	 *	each entry. maxcount is the maximum size of dest. Return
	 *	the number of characters put into dest.
	 */

	register char	*src;
	char		*sdest = dest;

	while( --argc >= 0  && maxcount > 0 )
	{
		for( src = *argv++; *src && --maxcount > 0; )
			*dest++ = *src++ ;

		if( --maxcount > 0  &&  argc > 0 )
			*dest++ = ' ';
	}

	*dest = 0;
	return( dest - sdest );
}
@//E*O*F unargv.c//
chmod u=rw,g=r,o=r unargv.c
 
echo x - unargv.x
sed 's/^@//' > "unargv.x" <<'@//E*O*F unargv.x//'
extern int	unargv( int, char **, char *, int );
@//E*O*F unargv.x//
chmod u=rw,g=r,o=r unargv.x
 
exit 0
-- 
  Michael A. Shiels

UUCP: ...path...!watmath!watale!broehl
EDU:  broehl@watale.waterloo.EDU