[comp.sources.misc] v04i015: Support for MG2A under MS-DOS

jbs@ll-xn.UUCP (Jeff Siegal) (08/06/88)

Posting-number: Volume 4, Issue 15
Submitted-by: "Jeff Siegal" <jbs@ll-xn.UUCP>
Archive-name: dos-mg2a

The enclosed shar file adds MS-DOS to the systems supported by the
current release of MG (2A).  It should be extracted into an empty
directory called "msdos", under "sys" in the mg source directory.

Jeff Siegal
----
#! /bin/sh
# To extract, remove mail header lines and type "sh filename"
if [ ! -s ./README ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./README
sed -e 's/^X//' > ./README << '!FaR!OuT!'
XThis is the source for the MS-DOS version of mg2a.  These files are
Xintended to reside in a directory sys/msdos underneath the main mg2a
Xsource directory. 
X
XThis code will run under both "Turbo C 1.5" and "Microsoft C 5.1"
X
XTo compile using Turbo C 1.5, copy makefile.tc from the sys/msdos
Xdirectory into the main mg2a source directory, then cd into the main
Xdirectory and use the Turbo C "make" program (just type "make"). 
X
XTo compile using Microsoft C 5.1, cd into the main directory and type
X"make sys\msdos\makefile.msc"
X
XA few random notes:
X
Xo   The display routines rely on the ROM BIOS interface.  This has the
X    advantage of being more portable, but at the expense of display
X    speed.  Direct memory-mapped display code or using ANSI sequences with
X    NANSI or FANSI-Console could be much faster.  To keep the program
X    small and maintain portability, enhancements such as these should
X    be supported as compile-time options (e.g. with #ifdef's)
X
X    The only display mode supported is 24 x 80.  To fix this, you will
X    need to change NROW and NCOL ttydef.h to be the largest # of rows
X    and columns supported, then you will have to change either
X    ttresize() in "tty.c" or setttysize() in "ttyio.c" to check the
X    BIOS parameter memory for the current screen size.
X
Xo   Note that the keyboard support also goes through the BIOS.
X    The "backspace" key generates DELETE (so that it does a
X    delete-backwards, while control-h still returns control-h (i.e.
X    HELP).  Arrow keys, HOME, END, PgUp, PgDn, etc.  are supported
X    (look in ttykbd.c) The ALT key works like a META key for alpha
X    keys, but the BIOS doesn't return keycodes for certain ALT
X    key combinations (I wish ALT-SHIFT-< worked!)  8 bit characters
X    (the line drawing set!) are supported, but to enter them, you
X    must use ALT-ddd (where ddd are digits on the numeric keypad).
X
Xo   The dired mode SEEMS to work, but I am not real happy with "dired" in the
X    first place, and the MS-DOS implementation isn't very well tested.
X    Presumably this is one area which will be enhanced in mg 2b.
X
Xo   REGEX compiles OK, but doesn't seem to work right.  I haven't done any
X    extensive testing, and I'm not sure what is breaking down.  If you 
X    want to play with this, you must add the
X    string "-DREGEX" to the CDEFS macro in the makefile (don't try to
X    add it to sysdef.h:  regex.c won't compile right (sigh)).
X
X    Anyway, I've got no use for REGEX at the moment, and compiling it
X    in adds 15K to the base executable size of 90K.  I pass.
X
XGood luck with this.  We hope you find it useful.  Please send any
Ximprovements you make.
X
XCredits:
X
XJohn P. Nelson (decvax!genrad!jpn, jpn@genrad.com) did the Turbo C
Xport and most of the work (based on his earlier work on
XMicroGnuEmacs).  Jeff Siegal (jbs@eddie.mit.edu) brought it up under
XMicrosoft C and fixed a few bugs. 
X
XThis document was written by John P. Nelson and modified by Jeff Siegal.
!FaR!OuT!
fi
if [ ! -s ./alloca.c ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./alloca.c
sed -e 's/^X//' > ./alloca.c << '!FaR!OuT!'
X/* alloca is only required by the GNU regex code */
X#ifdef REGEX
X/*
X	alloca -- (mostly) portable public-domain implementation
X
X	last edit:	86/01/26	D A Gwyn
X
X	This implementation of the PWB library alloca() function,
X	which is used to allocate space off the run-time stack so
X	that it is automatically reclaimed upon procedure exit, 
X	was inspired by discussions with J. Q. Johnson of Cornell.
X
X	It should work under any C implementation that uses an
X	actual procedure stack (as opposed to a linked list of
X	frames).  There are some preprocessor constants that can
X	be defined when compiling for your specific system, for
X	improved efficiency; however, the defaults should be okay.
X
X	The general concept of this implementation is to keep
X	track of all alloca()-allocated blocks, and reclaim any
X	that are found to be deeper in the stack than the current
X	invocation.  This heuristic does not reclaim storage as
X	soon as it becomes invalid, but it will do so eventually.
X
X	As a special case, alloca(0) reclaims storage without
X	allocating any.  It is a good idea to use alloca(0) in
X	your main control loop, etc. to force garbage collection.
X*/
X#ifndef lint
Xstatic char	SCCSid[] = "@(#)alloca.c	1.1";	/* for the "what" utility */
X#endif
X
X#ifdef X3J11
Xtypedef void	*pointer;		/* generic pointer type */
X#else
Xtypedef char	*pointer;		/* generic pointer type */
X#endif
X
X#define	NULL	0			/* null pointer constant */
X
Xextern void	free();
Xextern pointer	malloc();
X
X/*
X	Define STACK_DIRECTION if you know the direction of stack
X	growth for your system; otherwise it will be automatically
X	deduced at run-time.
X
X	STACK_DIRECTION > 0 => grows toward higher addresses
X	STACK_DIRECTION < 0 => grows toward lower addresses
X	STACK_DIRECTION = 0 => direction of growth unknown
X*/
X
X#ifndef STACK_DIRECTION
X#define	STACK_DIRECTION	0		/* direction unknown */
X#endif
X
X#if STACK_DIRECTION != 0
X
X#define	STACK_DIR	STACK_DIRECTION	/* known at compile-time */
X
X#else	/* STACK_DIRECTION == 0; need run-time code */
X
Xstatic int	stack_dir = 0;		/* 1 or -1 once known */
X#define	STACK_DIR	stack_dir
X
Xstatic void
Xfind_stack_direction( /* void */ )
X	{
X	static char	*addr = NULL;	/* address of first
X					   `dummy', once known */
X	auto char	dummy;		/* to get stack address */
X
X	if ( addr == NULL )
X		{			/* initial entry */
X		addr = &dummy;
X
X		find_stack_direction();	/* recurse once */
X		}
X	else				/* second entry */
X		if ( &dummy > addr )
X			stack_dir = 1;	/* stack grew upward */
X		else
X			stack_dir = -1;	/* stack grew downward */
X	}
X
X#endif	/* STACK_DIRECTION == 0 */
X
X/*
X	An "alloca header" is used to:
X	(a) chain together all alloca()ed blocks;
X	(b) keep track of stack depth.
X
X	It is very important that sizeof(header) agree with malloc()
X	alignment chunk size.  The following default should work okay.
X*/
X
X#ifndef	ALIGN_SIZE
X#define	ALIGN_SIZE	sizeof(double)
X#endif
X
Xtypedef union hdr
X	{
X	char	align[ALIGN_SIZE];	/* to force sizeof(header) */
X	struct	{
X		union hdr	*next;	/* for chaining headers */
X		char		*deep;	/* for stack depth measure */
X		}	h;
X	}	header;
X
X/*
X	alloca( size ) returns a pointer to at least `size' bytes of
X	storage which will be automatically reclaimed upon exit from
X	the procedure that called alloca().  Originally, this space
X	was supposed to be taken from the current stack frame of the
X	caller, but that method cannot be made to work for some
X	implementations of C, for example under Gould's UTX/32.
X*/
X
Xpointer
Xalloca( size )				/* returns pointer to storage */
X	unsigned	size;		/* # bytes to allocate */
X	{
X	static header	*last = NULL;	/* -> last alloca header */
X	auto char	probe;		/* probes stack depth: */
X	register char	*depth = &probe;
X
X#if STACK_DIRECTION == 0
X	if ( STACK_DIR == 0 )		/* unknown growth direction */
X		find_stack_direction();
X#endif
X
X	/* Reclaim garbage, defined as all alloca()ed storage that
X	   was allocated from deeper in the stack than currently. */
X
X	{
X	register header	*hp;		/* traverses linked list */
X
X	for ( hp = last; hp != NULL; )
X		if ( STACK_DIR > 0 && hp->h.deep > depth
X		  || STACK_DIR < 0 && hp->h.deep < depth
X		   )	{
X			register header	*np = hp->h.next;
X
X			free( (pointer)hp );	/* collect garbage */
X
X			hp = np;	/* -> next header */
X			}
X		else
X			break;		/* rest are not deeper */
X
X	last = hp;			/* -> last valid storage */
X	}
X
X	if ( size == 0 )
X		return NULL;		/* no allocation required */
X
X	/* Allocate combined header + user data storage. */
X
X	{
X	register pointer	new = malloc( sizeof(header) + size );
X					/* address of header */
X
X	if ( new == NULL )
X		return NULL;		/* abort() is traditional */
X
X	((header *)new)->h.next = last;
X	((header *)new)->h.deep = depth;
X
X	last = (header *)new;
X
X	/* User storage begins just after header. */
X
X	return (pointer)((char *)new + sizeof(header));
X	}
X	}
X#endif
!FaR!OuT!
fi
if [ ! -s ./chrdef.h ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./chrdef.h
sed -e 's/^X//' > ./chrdef.h << '!FaR!OuT!'
X/*
X * sys/msdos/chardef.h: character set specific #defines for mg 2a
X */
X
X#ifndef	CHARMASK
X/*
X * casting should be at least as efficent as anding with 0xff,
X * and won't have the size problems.  Override in sysdef.h if no
X * unsigned char type.
X */
X#define	CHARMASK(c)	((unsigned char) (c))
X#endif
X
X/*
X * These flags, and the macros below them,
X * make up a do-it-yourself set of "ctype" macros that
X * understand the DEC multinational set, and let me ask
X * a slightly different set of questions.
X */
X#define _W	0x01			/* Word.			*/
X#define _U	0x02			/* Upper case letter.		*/
X#define _L	0x04			/* Lower case letter.		*/
X#define _C	0x08			/* Control.			*/
X#define _P	0x10			/* end of sentence punctuation	*/
X#define	_D	0x20			/* is decimal digit		*/
X
X#define ISWORD(c)	((cinfo[CHARMASK(c)]&_W)!=0)
X#define ISCTRL(c)	((cinfo[CHARMASK(c)]&_C)!=0)
X#define ISUPPER(c)	((cinfo[CHARMASK(c)]&_U)!=0)
X#define ISLOWER(c)	((cinfo[CHARMASK(c)]&_L)!=0)
X#define ISEOSP(c)	((cinfo[CHARMASK(c)]&_P)!=0)
X#define	ISDIGIT(c)	((cinfo[CHARMASK(c)]&_D)!=0)
X#define TOUPPER(c)	((c)-0x20)
X#define TOLOWER(c)	((c)+0x20)
X
X/*
X * generally useful thing for chars
X */
X#define CCHR(x)		((x) ^ 0x40)	/* CCHR('?') == DEL */
X
X#ifndef	METACH
X#define	METACH	CCHR('[')
X#endif
X
X#ifdef	XKEYS
X#define	K00	256
X#define	K01	257
X#define	K02	258
X#define	K03	259
X#define	K04	260
X#define	K05	261
X#define	K06	262
X#define	K07	263
X#define	K08	264
X#define	K09	265
X#define	K0A	266
X#define	K0B	267
X#define	K0C	268
X#define	K0D	269
X#define	K0E	270
X#define	K0F	271
X#define	K10	272
X#define	K11	273
X#define	K12	274
X#define	K13	275
X#define	K14	276
X#define	K15	277
X#define	K16	278
X#define	K17	279
X#define	K18	280
X#define	K19	281
X#define	K1A	282
X#define	K1B	283
X#define	K1C	284
X#define	K1D	285
X#define	K1E	286
X#define	K1F	287
X#define	K20	288
X#define	K21	289
X#define	K22	290
X#define	K23	291
X#define	K24	292
X#define	K25	293
X#define	K26	294
X#define	K27	295
X#define	K28	296
X#define	K29	297
X#define	K2A	298
X#define	K2B	299
X#define	K2C	300
X#define	K2D	301
X#define	K2E	302
X#define	K2F	303
X#endif
!FaR!OuT!
fi
if [ ! -s ./cinfo.c ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./cinfo.c
sed -e 's/^X//' > ./cinfo.c << '!FaR!OuT!'
X/*
X *		Character class tables.
X * Do it yourself character classification
X * macros, that understand the multinational character set,
X * and let me ask some questions the standard macros (in
X * ctype.h) don't let you ask.
X */
X#include	"def.h"
X
X/*
X * This table, indexed by a character drawn
X * from the 256 member character set, is used by my
X * own character type macros to answer questions about the
X * type of a character. It handles the full multinational
X * character set, and lets me ask some questions that the
X * standard "ctype" macros cannot ask.
X */
Xchar	cinfo[256] = {
X	_C,		_C,		_C,		_C,	/* 0x0X */
X	_C,		_C,		_C,		_C,
X	_C,		_C,		_C,		_C,
X	_C,		_C,		_C,		_C,
X	_C,		_C,		_C,		_C,	/* 0x1X */
X	_C,		_C,		_C,		_C,
X	_C,		_C,		_C,		_C,
X	_C,		_C,		_C,		_C,
X	0,		_P,		0,		0,	/* 0x2X */
X	_W,		_W,		0,		_W,
X	0,		0,		0,		0,
X	0,		0,		_P,		0,
X	_D|_W,		_D|_W,		_D|_W,		_D|_W,	/* 0x3X */
X	_D|_W,		_D|_W,		_D|_W,		_D|_W,
X	_D|_W,		_D|_W,		0,		0,
X	0,		0,		0,		_P,
X	0,		_U|_W,		_U|_W,		_U|_W,	/* 0x4X */
X	_U|_W,		_U|_W,		_U|_W,		_U|_W,
X	_U|_W,		_U|_W,		_U|_W,		_U|_W,
X	_U|_W,		_U|_W,		_U|_W,		_U|_W,
X	_U|_W,		_U|_W,		_U|_W,		_U|_W,	/* 0x5X */
X	_U|_W,		_U|_W,		_U|_W,		_U|_W,
X	_U|_W,		_U|_W,		_U|_W,		0,
X	0,		0,		0,		0,
X	0,		_L|_W,		_L|_W,		_L|_W,	/* 0x6X */
X	_L|_W,		_L|_W,		_L|_W,		_L|_W,
X	_L|_W,		_L|_W,		_L|_W,		_L|_W,
X	_L|_W,		_L|_W,		_L|_W,		_L|_W,
X	_L|_W,		_L|_W,		_L|_W,		_L|_W,	/* 0x7X */
X	_L|_W,		_L|_W,		_L|_W,		_L|_W,
X	_L|_W,		_L|_W,		_L|_W,		0,
X	0,		0,		0,		0,
X	_W,		_W,		_W,		_W,	/* 0x8X */
X	_W,		_W,		_W,		_W,
X	_W,		_W,		_W,		_W,
X	_W,		_W,		_W,		_W,
X	_W,		_W,		_W,		_W,	/* 0x9X */
X	_W,		_W,		_W,		_W,
X	_W,		_W,		_W,		0,
X	0,		0,		0,		0,
X	_W,		_W,		_W,		_W,	/* 0xAX */
X	_W,		_W,		_W,		_W,
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,	/* 0xBX */
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,	/* 0xCX */
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,	/* 0xDX */
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,	/* 0xEX */
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,	/* 0xFX */
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X	0,		0,		0,		0,
X};
X
X/*
X * Find the name of a keystroke.  Needs to be changed to handle 8-bit printing
X * characters and function keys better.	 Returns a pointer to the terminating
X * '\0'.
X */
X
Xchar *keyname(cp, k)
Xregister char *cp;
Xregister int k;
X{
X    register char *np;
X#ifdef	FKEYS
X    extern char *keystrings[];
X#endif
X
X    if(k < 0) k = CHARMASK(k);			/* sign extended char */
X    switch(k) {
X	case CCHR('@'): np = "NUL"; break;
X	case CCHR('I'): np = "TAB"; break;
X	case CCHR('J'): np = "LFD"; break; /* yuck, but that's what GNU calls it */
X	case CCHR('M'): np = "RET"; break;
X	case CCHR('['): np = "ESC"; break;
X	case ' ':	np = "SPC"; break; /* yuck again */
X	case CCHR('?'): np = "DEL"; break;
X	default:
X#ifdef	FKEYS
X	    if(k >= KFIRST && k <= KLAST &&
X		    (np = keystrings[k - KFIRST]) != NULL)
X		break;
X#endif
X	    if(k > CCHR('?')) {
X		*cp++ = '0';
X		*cp++ = ((k>>6)&7) + '0';
X		*cp++ = ((k>>3)&7) + '0';
X		*cp++ = (k&7) + '0';
X		*cp = '\0';
X		return cp;
X	    }
X	    if(k < ' ') {
X		*cp++ = 'C';
X		*cp++ = '-';
X		k = CCHR(k);
X		if(ISUPPER(k)) k = TOLOWER(k);
X	    }
X	    *cp++ = k;
X	    *cp = '\0';
X	    return cp;
X    }
X    (VOID) strcpy(cp, np);
X    return cp + strlen(cp);
X}
!FaR!OuT!
fi
if [ ! -s ./fileio.c ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./fileio.c
sed -e 's/^X//' > ./fileio.c << '!FaR!OuT!'
X/*
X * Name:	Mg 2a
X * 		MSDOS file I/O (TurboC 1.5)
X */
X#include	"def.h"
X#include	<stdio.h>
X
X#ifdef MSC
X#include	<dos.h>
X#endif /* MSC */
X
X#ifndef F_OK
X#define F_OK	0
X#define X_OK	1
X#define W_OK	2
X#define R_OK	4
X#endif
X
X#ifndef NO_DIR
Xextern char *wdir;
X#endif
X
Xstatic	FILE	*ffp;
X
X/*
X * Open a file for reading.
X */
Xffropen(fn)
Xchar	*fn;
X{
X	if ((ffp=fopen(fn, "rb")) == NULL)
X		return (FIOFNF);
X	return (FIOSUC);
X}
X
X/*
X * Open a file for writing.
X * Return TRUE if all is well, and
X * FALSE on error (cannot create).
X */
Xffwopen(fn)
Xchar	*fn;
X{
X	if ((ffp=fopen(fn, "wb")) == NULL) {
X		ewprintf("Cannot open file for writing");
X		return (FIOERR);
X	}
X	return (FIOSUC);
X}
X
X/*
X * Close a file.
X * Should look at the status.
X */
Xffclose()
X{
X	(VOID) fclose(ffp);
X	return (FIOSUC);
X}
X
X/*
X * Write a line to the already
X * opened file. The "buf" points to the
X * buffer, and the "nbuf" is its length, less
X * the free newline. Return the status.
X * Check only at the newline.
X */
Xffputline(buf, nbuf)
Xregister char	buf[];
X{
X	register int	i;
X
X	for (i=0; i<nbuf; ++i)
X		putc(buf[i]&0xFF, ffp);
X	putc('\r', ffp);	/* MSDOS wants \r\n line seperators */
X	putc('\n', ffp);
X	if (ferror(ffp) != FALSE) {
X		ewprintf("Write I/O error");
X		return (FIOERR);
X	}
X	return (FIOSUC);
X}
X
X/*
X * Write a buffer to the already
X * opened file. bp points to the
X * buffer. Return the status.
X * Check only at the newline and
X * end of buffer.
X */
Xffputbuf(bp)
XBUFFER *bp;
X{
X    register char *cp;
X    register char *cpend;
X    register LINE *lp;
X    register LINE *lpend;
X
X    lpend = bp->b_linep;
X    lp = lforw(lpend);
X    do {
X	cp = &ltext(lp)[0];		/* begining of line	*/
X	cpend = &cp[llength(lp)];	/* end of line		*/
X	while(cp != cpend) {
X	    putc(*cp, ffp);
X	    cp++;	/* putc may evalualte arguments more than once */
X	}
X	lp = lforw(lp);
X	if(lp == lpend) break;		/* no implied newline on last line */
X	putc('\r', ffp);	/* MSDOS wants \r\n line seperators */
X	putc('\n', ffp);
X    } while(!ferror(ffp));
X    if(ferror(ffp)) {
X	ewprintf("Write I/O error");
X	return FIOERR;
X    }
X    return FIOSUC;
X}
X
X/*
X * Read a line from a file, and store the bytes
X * in the supplied buffer. Stop on end of file or end of
X * line. Don't get upset by files that don't have an end of
X * line on the last line; this seem to be common on CP/M-86 and
X * MS-DOS.  Delete any CR followed by a NL:  This is the normal
X * format for MS_DOS files, but also occurs when files are transferred
X * from VMS or MS-DOS to Unix.
X */
Xffgetline(buf, nbuf, nbytes)
Xregister char	buf[];
Xregister int	*nbytes;
X{
X	register int	c;
X	register int	i;
X
X	i = 0;
X	for (;;) {
X		c = getc(ffp);
Xrescan:
X		if (c == '\r') {		/* Delete any non-stray	*/
X			c = getc(ffp);		/* carriage returns.	*/
X			if (c != '\n') {
X				buf[i++] = '\r';
X				if (i >= nbuf) return FIOLONG;
X				goto rescan;
X			}
X		}
X		if (c==EOF || c=='\n')		/* End of line.		*/
X			break;
X		buf[i++] = c;
X		if (i >= nbuf) return FIOLONG;
X	}
X	if (c == EOF  && ferror(ffp) != FALSE) {
X		ewprintf("File read error");
X		return FIOERR;
X	}
X	*nbytes = i;
X	return c==EOF ? FIOEOF : FIOSUC;
X}
X
X#ifndef	NO_BACKUP
X/*
X * Rename the file "fname" into a backup copy.
X * On Unix the backup has the same name as the
X * original file, with a "~" on the end - unfortunately
X * this does not map well to MS-DOS - the old .bak convention
X * is used.
X */
Xfbackupfile(fname)
Xchar	*fname;
X{
X	register char	*nname, *ptr;
X	char *strchr();
X
X	if ((nname=malloc(strlen(fname)+3+1)) == NULL)
X		return (ABORT);
X	(void) strcpy(nname, fname);
X	if ((ptr = strchr(nname, '.')) != 0)
X	    strcpy(ptr, ".bak");
X	else
X	    strcat(ptr, ".bak");
X
X	if (strcmp(fname, nname) == 0) {
X		free(nname);
X		return FALSE;
X	}
X
X	(void) unlink(nname);		/* Ignore errors.	*/
X	(void) rename(fname, nname);
X	free(nname);
X	return (TRUE);
X}
X#endif
X
X/*
X * The string "fn" is a file name.
X * convert all filenames to lower case, and convert all '\\' characters
X * to forward slashes.  This is simply my preference, uppercase and
X * back slashes are also viable.
X */
X/*ARGSUSED*/
Xadjustmsdos(fn)
Xregister char	*fn;
X{
X	register char c;
X
X	while ((c = *fn) != '0') {
X		if (ISUPPER(c))
X			*fn = TOLOWER(c);
X		if (c=='/')
X			*fn = '\\';
X		++fn;
X	}
X}
X
X
X
X#ifndef	NO_STARTUP
X#define STARTUPNAME ".mg"
X/*
X * find the users startup file, and return it's name. Check for
X * if MGSTARTUP is defined, then use that.   Otherwise, look
X * for .mg in the current directory, then in the root directory.
X */
Xchar *
Xstartupfile() 
X{
X	register char	*file;
X	static char	temp[NFILEN];
X	char		*getenv();
X
X	if ((file = getenv("MGSTARTUP")) != NULL )
X		{
X		if (access(file, F_OK) == 0)
X		    return file;
X		return NULL;
X		}
X	if (access (STARTUPNAME, F_OK) == 0)
X		return STARTUPNAME;
X	strcpy(temp, "/");
X	strcat(temp, STARTUPNAME);
X	if (access (temp, F_OK) == 0)
X		return temp;
X	return NULL;
X}
X#endif
X
X/*******************************************************************/
X/* new stuff between release 1a and 2a                             */
X/*******************************************************************/
X
X/* convert all filenames to a canonical format, which in the case of
X * MSDOS is X:/currentdir/filename.  Note that each drive letter has
X * it's OWN current directory, so if the user specifies a drive letter,
X * we use that drive's current directory, not it's root.
X */
X
X/* MSC doesn't have getdrive and getcurdir routines; simulate them. 
X * They are both pretty gross.  Blame Microsoft */
X
X#ifdef MSC
Xunsigned getdisk()
X{
X    unsigned currentdrive;
X
X    _dos_getdrive(&currentdrive);
X    return currentdrive-1;
X}
X
Xvoid getcurdir(unsigned drivenumber, char *buf)
X{
X    unsigned currentdrive = getdisk()+1;
X    unsigned number_of_drives;		/* unused */
X    static char bufr[NFILEN];
X
X    _dos_setdrive(drivenumber, &number_of_drives);
X    getcwd(&bufr[0], NFILEN-1);
X    _dos_setdrive(currentdrive, &number_of_drives);
X    strcpy(buf, &bufr[3]);
X}
X#endif
X
Xchar *adjustname(fn)
Xregister char *fn;
X{
X    register char *cp;
X    static char fnb[NFILEN];
X    struct passwd *pwent;
X
X    cp = fnb;
X    /* handle A:foo\bar */
X    if (fn[0] && fn[1] == ':') {
X	*cp++ = *fn++;
X	*cp++ = *fn++;
X	*cp = '\0';
X	adjustmsdos(fnb);	/* force case to lower */
X	if (*fn != '/' && *fn != '\\') {
X	    *cp++ = '\\';
X	    getcurdir(fnb[0]-'a'+1, cp);
X	    cp = fnb + strlen(fnb);
X	}
X	else
X	    *cp++ = *fn++;
X    }
X    /* handle \foo\bar */
X    else if (*fn == '/' || *fn == '\\') {
X	*cp++ = (char) (getdisk() + 'a');
X	*cp++ = ':';
X	*cp++ = *fn++;
X    }
X    else {
X	strcpy(fnb, wdir);
X	cp = fnb + strlen(fnb);
X    }
X
X    if(cp != fnb && cp[-1] != '/' && cp[-1] != '\\') *cp++ = '\\';
X
X    /* at this point, we should have a drive, and at least a single */
X    /* slash.  Now copy over the rest of the filename, while handling */
X    /* certain pathalogical cases */
X
X    /* convert "//" to "/", "/./" to "/", and "/x/../" to "/" */
X    while(*fn) {
X    	switch(*fn) {
X	    case '.':
X		switch(fn[1]) {
X	            case '\0':
X		    	*--cp = '\0';
X			adjustmsdos(fnb);
X		    	return fnb;
X	    	    case '/':
X		    case '\\':
X	    	    	fn += 2;
X		    	continue;
X		    case '.':
X		    	if(fn[2]=='/' || fn[2]=='\\' || fn[2] == '\0') {
X			    --cp;
X			    while(cp > fnb && *--cp != '/' && *cp != '\\')
X				;
X			    if (cp==fnb) cp += 2;
X			    ++cp;
X			    if(fn[2]=='\0') {
X			        *--cp = '\0';
X				adjustmsdos(fnb);
X			        return fnb;
X			    }
X		            fn += 3;
X		            continue;
X		        }
X		        break;
X		    default:
X		    	break;
X	        }
X		break;
X	    case '/':
X	    case '\\':
X	    	fn++;
X	    	continue;
X	    default:
X	    	break;
X	}
X	while(*fn && (*cp++ = *fn++) != '/' && fn[-1] != '\\')
X	    ;
X    }
X    if (cp != fnb + 3 && cp[-1]=='\\') --cp;
X    *cp = '\0';
X    adjustmsdos(fnb);
X    return fnb;
X}
X
X#ifndef NO_DIRED
X#include "kbd.h"
X#define DIRFILE "_dirlist_.$$$"
X
XBUFFER *dired_(dirname)
Xchar *dirname;
X{
X    register BUFFER *bp;
X    char line[256];
X    BUFFER *findbuffer();
X    char *strncpy();
X    int i;
X
X    if((dirname = adjustname(dirname)) == NULL) {
X	ewprintf("Bad directory name");
X	return NULL;
X    }
X    if((bp = findbuffer(dirname)) == NULL) {
X	ewprintf("Could not create buffer");
X	return NULL;
X    }
X    if(bclear(bp) != TRUE) return FALSE;
X    (VOID) strcpy(line, "dir ");
X    (VOID) strcat(line, dirname);
X    (VOID) strcat(line, " > ");
X    (VOID) strcat(line, DIRFILE);
X    system(line);
X    if (ffropen(DIRFILE) != FIOSUC) {
X 	ewprintf("Can't open temporary dir file");
X 	return NULL;
X    }
X    line[0] = line[1] = ' ';
X    if (ffgetline(&line[2], sizeof(line)-3, &i) != FIOSUC) {
X	ffclose();
X	(void)unlink(DIRFILE);
X	ewprintf("No such directory: `%s'", dirname);
X    	return NULL;
X    }
X    while (ffgetline(&line[2], sizeof(line)-3, &i) == FIOSUC) {
X	line[i+2] = '\0';
X	(VOID) addline(bp, line);
X    }
X    ffclose();
X    (void)unlink(DIRFILE);
X
X    bp->b_dotp = lforw(bp->b_linep);		/* go to first line */
X    (VOID) strncpy(bp->b_fname, dirname, NFILEN);
X    if((bp->b_modes[0] = name_mode("dired")) == NULL) {
X	bp->b_modes[0] = &map_table[0];
X	ewprintf("Could not find mode dired");
X	return NULL;
X    }
X    bp->b_nmodes = 0;
X    return bp;
X}
X
X/* this is really ugly, but then so was the UNIX version! */
X#define BASENAME 2
X#define EXT	11
X#define DIR	15
Xd_makename(lp, fn)
Xregister LINE *lp;
Xregister char *fn;
X{
X    register char *cp;
X    register char *last;
X    int len;
X    extern char *strchr();
X
X    if(llength(lp) != 41) return ABORT;
X    if(lgetc(lp,BASENAME) == ' ') return ABORT;
X    if(lgetc(lp,EXT-1) != ' ') return ABORT;
X    (VOID) strcpy(fn, curbp->b_fname);
X    cp = fn + strlen(fn);
X    if ((cp[-1] != '\\') && (cp[-1] != '/'))	/* append '/' if needed	*/
X	*cp++ = '\\';
X    if ((last = strchr(lp->l_text+BASENAME, ' ')) == 0) return ABORT;
X    len = last - (lp->l_text+BASENAME);
X    bcopy(lp->l_text+BASENAME, cp, len);
X    cp += len;
X    if ((last = strchr(lp->l_text+EXT, ' ')) == 0) return ABORT;
X    len = last - (lp->l_text+EXT);
X    if (len != 0) {
X	*cp++ = '.';
X	bcopy(lp->l_text+EXT, cp, len);
X    }
X    cp[len] = '\0';
X    return (strncmp(lp->l_text+DIR, "<DIR>", 5) == 0);
X}
X
X/* sorry, this is a hack - jpn */
X/* I should probably fix this */
Xcopy(frname, toname)
Xchar *frname, *toname;
X{
X    char buffer[512];
X    int pid;
X    int status;
X    char cmdbuf[80];
X
X    sprintf(cmdbuf, "Copy %s %s", frname, toname);
X    system(cmdbuf);
X    return TRUE;
X}
X
Xunlinkdir(f)
Xchar *f;
X{
X	return (rmdir(f));
X}
X
X#endif /* NO_DIRED */
!FaR!OuT!
fi
if [ ! -s ./makefile.msc ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./makefile.msc
sed -e 's/^X//' > ./makefile.msc << '!FaR!OuT!'
X# Microsoft C 5.1 Makefile for MG 2A.
XSYS	= msdos
XCDEFS	= /DMSC
XDEBUG   = 
XCFLAGS	= /AL /Oilt /Gs $(CDEFS) $(DEBUG)
XCC      = cl
X
X# standard headers
XDEF = def.h sysdef.h ttydef.h chrdef.h
X
X# implicit compilation rule
X.c.obj:
X	$(CC) /c $(CFLAGS) $*.c
X
X# files that can be removed, because they are really just copies
XHCLEAN = sysdef.h ttydef.h chrdef.h varargs.h
XCCLEAN = cinfo.c fileio.c spawn.c tty.c ttyio.c ttykbd.c
X
X# object file list
XOBJ = alloca.obj basic.obj buffer.obj cinfo.obj dir.obj dired.obj display.obj \
X    echo.obj extend.obj file.obj fileio.obj help.obj kbd.obj keymap.obj \
X    line.obj macro.obj main.obj match.obj modes.obj paragrap.obj \
X    random.obj regex.obj region.obj re_searc.obj search.obj spawn.obj \
X    tty.obj ttyio.obj ttykbd.obj version.obj window.obj word.obj
X
X# this doesn't work right: del only takes one argument (sigh).
X#clean:
X#	-del $(HCLEAN)
X#	-del $(CCLEAN)
X#	-del *.obj
X#	-del mg.exe
X
X# files copied from msdos directory
Xsysdef.h: sys\$(SYS)\sysdef.h
X	copy sys\$(SYS)\sysdef.h
X
Xttydef.h: sys\$(SYS)\ttydef.h
X	copy sys\$(SYS)\ttydef.h
X
Xchrdef.h: sys\$(SYS)\chrdef.h
X	copy sys\$(SYS)\chrdef.h
X
Xvarargs.h: sys\$(SYS)\varargs.h
X	copy sys\$(SYS)\varargs.h
X
Xalloca.c: sys\default\alloca.c
X	copy sys\default\alloca.c
X
Xcinfo.c: sys\$(SYS)\cinfo.c
X	copy sys\$(SYS)\cinfo.c
X
Xfileio.c: sys\$(SYS)\fileio.c
X	copy sys\$(SYS)\fileio.c
X
Xspawn.c: sys\$(SYS)\spawn.c
X	copy sys\$(SYS)\spawn.c
X
Xtty.c:   sys\$(SYS)\tty.c
X	copy sys\$(SYS)\tty.c
X
Xttyio.c: sys\$(SYS)\ttyio.c
X	copy sys\$(SYS)\ttyio.c
X
Xttykbd.c: sys\$(SYS)\ttykbd.c
X	copy sys\$(SYS)\ttykbd.c
X
X# header dependencies
X
Xbasic.obj: basic.c $(DEF)
X
Xbuffer.obj: buffer.c $(DEF) kbd.h
X
Xdir.obj: dir.c $(DEF)
X
Xdired.obj: dired.c $(DEF)
X
Xdisplay.obj: display.c $(DEF) kbd.h
X
Xecho.obj: echo.c $(DEF) key.h varargs.h macro.h
X
Xextend.obj: extend.c $(DEF) kbd.h macro.h key.h
X
Xfile.obj: file.c $(DEF)
X
Xhelp.obj: help.c $(DEF) kbd.h key.h macro.h
X
Xkbd.obj: kbd.c $(DEF) kbd.h key.h macro.h
X
Xkeymap.obj: keymap.c $(DEF) kbd.h
X
Xline.obj: line.c $(DEF)
X
Xmacro.obj: macro.c $(DEF) key.h macro.h
X
Xmain.obj: main.c $(DEF) macro.h
X
Xmatch.obj: match.c $(DEF) key.h
X
Xmodes.obj: modes.c $(DEF) kbd.h
X
Xparagrap.obj: paragrap.c $(DEF)
X
Xrandom.obj: random.c $(DEF)
X
Xregex.obj: regex.c $(DEF) regex.h
X
Xregion.obj: region.c $(DEF)
X
Xre_searc.obj: re_searc.c $(DEF) macro.h regex.h
X
Xsearch.obj: search.c $(DEF) macro.h
X
Xversion.obj: version.c $(DEF)
X
Xwindow.obj: window.c $(DEF)
X
Xword.obj: word.c $(DEF)
X
Xalloca.obj: alloca.c
X
Xcinfo.obj: $(DEF) cinfo.c
X
Xfileio.obj: $(DEF) kbd.h fileio.c
X
Xspawn.obj: $(DEF) spawn.c
X
Xtty.obj: $(DEF) tty.c
X
Xttyio.obj: $(DEF) ttyio.c
X
Xttykbd.obj: $(DEF) ttykbd.c
X
X# add /Fm to the CC line to get a load map
Xmg.exe: $(OBJ)
X	$(CC) $(CFLAGS) /FeMG.EXE *.obj
X
!FaR!OuT!
fi
if [ ! -s ./makefile.tc ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./makefile.tc
sed -e 's/^X//' > ./makefile.tc << '!FaR!OuT!'
X# Turbo C Makefile for MG 2A.
XSYS	= msdos
XCDEFS	=
X# suppress some annoying warnings
XWARN	= -w-stu -w-par
XCFLAGS	= -ml $(CDEFS) $(WARN)
XCC      = tcc
X
X# standard headers
XDEF = def.h sysdef.h ttydef.h chrdef.h
X
X# implicit compilation rule
X.c.obj:
X	$(CC) -c $(CFLAGS) $<
X
X# files that can be removed, because they are really just copies
XHCLEAN = sysdef.h ttydef.h chrdef.h varargs.h
XCCLEAN = cinfo.c fileio.c spawn.c tty.c ttyio.c ttykbd.c
X
X# object file list
XOBJ = alloca.obj basic.obj buffer.obj cinfo.obj dir.obj dired.obj display.obj \
X    echo.obj extend.obj file.obj fileio.obj help.obj kbd.obj keymap.obj \
X    line.obj macro.obj main.obj match.obj modes.obj paragrap.obj \
X    random.obj regex.obj region.obj re_searc.obj search.obj spawn.obj \
X    tty.obj ttyio.obj ttykbd.obj version.obj window.obj word.obj
X
X# add -M to the CC line to get a load map
Xmg.exe: $(OBJ)
X	$(CC) -emg $(CFLAGS) *.obj
X
X# this doesn't work right: del only takes one argument (sigh).
Xclean:
X	-del $(HCLEAN)
X	-del $(CCLEAN)
X	-del *.obj
X	-del mg.exe
X
X# files copied from msdos directory
Xsysdef.h: sys/$(SYS)/sysdef.h
X	copy sys/$(SYS)/sysdef.h
X
Xttydef.h: sys/$(SYS)/ttydef.h
X	copy sys/$(SYS)/ttydef.h
X
Xchrdef.h: sys/$(SYS)/chrdef.h
X	copy sys/$(SYS)/chrdef.h
X
Xvarargs.h: sys/$(SYS)/varargs.h
X	copy sys/$(SYS)/varargs.h
X
Xalloca.c: sys/$(SYS)/alloca.c
X	copy sys/$(SYS)/alloca.c
X
Xcinfo.c: sys/$(SYS)/cinfo.c
X	copy sys/$(SYS)/cinfo.c
X
Xfileio.c: sys/$(SYS)/fileio.c
X	copy sys/$(SYS)/fileio.c
X
Xspawn.c: sys/$(SYS)/spawn.c
X	copy sys/$(SYS)/spawn.c
X
Xtty.c:   sys/$(SYS)/tty.c
X	copy sys/$(SYS)/tty.c
X
Xttyio.c: sys/$(SYS)/ttyio.c
X	copy sys/$(SYS)/ttyio.c
X
Xttykbd.c: sys/$(SYS)/ttykbd.c
X	copy sys/$(SYS)/ttykbd.c
X
X# header dependencies
Xbasic.obj: $(DEF)
Xbuffer.obj: $(DEF) kbd.h
Xdir.obj: $(DEF)
Xdired.obj: $(DEF)
Xdisplay.obj: $(DEF) kbd.h
Xecho.obj: $(DEF) key.h varargs.h macro.h
Xextend.obj: $(DEF) kbd.h macro.h key.h
Xfile.obj: $(DEF)
Xhelp.obj: $(DEF) kbd.h key.h macro.h
Xkbd.obj: $(DEF) kbd.h key.h macro.h
Xkeymap.obj: $(DEF) kbd.h
Xline.obj: $(DEF)
Xmacro.obj: $(DEF) key.h macro.h
Xmain.obj: $(DEF) macro.h
Xmatch.obj: $(DEF) key.h
Xmodes.obj: $(DEF) kbd.h
Xparagrap.obj: $(DEF)
Xrandom.obj: $(DEF)
Xregex.obj: $(DEF) regex.h
Xregion.obj: $(DEF)
Xre_searc.obj: $(DEF) macro.h regex.h
Xsearch.obj: $(DEF) macro.h
Xversion.obj: $(DEF)
Xwindow.obj: $(DEF)
Xword.obj: $(DEF)
X
Xalloca.obj: alloca.c
Xcinfo.obj: $(DEF) cinfo.c
Xfileio.obj: $(DEF) kbd.h fileio.c
Xspawn.obj: $(DEF) spawn.c
Xtty.obj: $(DEF) tty.c
Xttyio.obj: $(DEF) ttyio.c
Xttykbd.obj: $(DEF) ttykbd.c
!FaR!OuT!
fi
if [ ! -s ./spawn.c ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./spawn.c
sed -e 's/^X//' > ./spawn.c << '!FaR!OuT!'
X/*
X * Name:	Mg 2a
X *		Spawn CLI for MSDOS (TurboC 1.5)
X *
X */
X#include	"def.h"
X#include	<process.h>
X
Xextern	char	*getenv();
X
X/*
X * On MSDOS, we got no job control like system V, so always
X * run a subshell. Bound to "C-C", and used
X * as a subcommand by "C-Z". (daveb)
X *
X * Returns 0 if the shell executed OK, something else if
X * we couldn't start shell or it exited badly.
X */
Xspawncli(f, n, k)
X{
X	char *comspec;
X	int		errp = FALSE;
X
X	ttcolor(CTEXT);
X	ttnowindow();
X	ttmove(nrow-1, 0);
X	if (epresf != FALSE) {
X		tteeol();
X		epresf = FALSE;
X	}
X	ttclose();
X	sgarbf = TRUE;				/* Force repaint.	*/
X	if ((comspec = getenv("COMSPEC")) == NULL)
X		errp = -1;
X	else
X		errp = spawnl(P_WAIT, comspec, "COMMAND.COM", (char *)NULL);
X
X	ttopen();
X	if(errp == -1)
X		ewprintf("Failed to create process");
X
X	return ( errp );
X}
!FaR!OuT!
fi
if [ ! -s ./sysdef.h ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./sysdef.h
sed -e 's/^X//' > ./sysdef.h << '!FaR!OuT!'
X/*
X * Name:	Mg 2a
X *		MSDOS system header file (TurboC 1.5)
X */
X
X/* can't include these, the ANSI style prototypes conflict with the
X * definitions in defs.h
X */
X/* #include <stdlib.h> */
X/* #include <string.h> */
X/* #include <dir.h> */
X/* #include <stdio.h> */
X#define NULL	0L
X
X#define	KBLOCK	1024			/* Kill grow.			*/
X#define	GOOD	0			/* Good exit status.		*/
X#define	MAXPATH	256			/* Maximum length of path for chdir */
X
X#define LOCAL_VARARGS			/* use sys/default/varargs.h */
X#define DO_METAKEY			/* ALT acts like META */
X#define METABIT 0x200
X#define FKEYS				/* we have dedicated function keys */
X/* #define NO_DIRED */			/* dired works now */
X#define C_ALLOCA			/* used by regex, C version of alloca*/
X
Xtypedef long	RSIZE;			/* Type for file/region sizes	*/
Xtypedef short	KCHAR;			/* Type for internal keystrokes	*/
X/* typedef short	KEY;		/* Type for internal keystrokes	*/
X
X/*
X * Macros used by the buffer name making code.
X * Start at the end of the file name, scan to the left
X * until BDC1 (or BDC2, if defined) is reached. The buffer
X * name starts just to the right of that location, and
X * stops at end of string (or at the next BDC3 character,
X * if defined). BDC2 and BDC3 are mainly for VMS.
X */
X#define	BDC1	'/'
X#define	BDC2	'\\'
X
X#define bcopy(s,d,n)	memcpy(d,s,n)	/* memory-to-memory copy	*/
X#define bcmp(s1,s2,n)	memcmp(s2,s1,n) /* memory comparison		*/
X#define bzero(s,n)	memset(s,0,n)	/* memory zero			*/
X
X#define fncmp	stricmp
X#define getwd(cwd)	getcwd(cwd,NFILEN) /* get current working dir	*/
Xextern char *getcwd();
X
X#define MALLOCROUND(m)	(m+=7,m&=~7)	/* round up to 8 byte boundry	*/
!FaR!OuT!
fi
if [ ! -s ./tty.c ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./tty.c
sed -e 's/^X//' > ./tty.c << '!FaR!OuT!'
X/*
X * Mg 2b  (turboc 1.5/MSC 1.5)
X *   IBM-PC and compatible BIOS based display driver.
X *   - this will tend to be a bit slower than a driver that
X *     writes directly to the memory mapped screen, but with
X *     the large # of display adapters floating around, I'd
X *     rather let the bios do the work.
X * 
X *     I DO recommend FANSI-CONSOLE which significantly speeds
X *     up display bios calls, however.
X */
X#include	"def.h"
X#include	<dos.h>
X
X#define	BEL	0x07			/* BEL character.		*/
X
Xextern	int	ttrow;
Xextern	int	ttcol;
Xextern	int	tttop;
Xextern	int	ttbot;
Xextern	int	tthue;
X
Xstatic int biocol = 0;
X
Xint	tceeol = 2;			/* Costs are set later */
Xint	tcinsl = 5;
Xint	tcdell = 5;
X
Xstatic	int insdel = TRUE;	/* Do we have both insert & delete line? */
Xstatic int rendition =0x07;
X
Xint	ttputc();
X
X/*
X * Initialize the terminal when the editor
X * gets started up.
X */
Xttinit() {
X}
X
X/*
X * Clean up the terminal, in anticipation of
X * a return to the command interpreter.
X */
Xtttidy() {
X}
X
X/*
X * Move the cursor to the specified
X * origin 0 row and column position.
X */
Xttmove(row, col) {
X    ttcol = col;
X    ttrow = row;
X    _move(row, col);
X}
X
X_move(row, col) {
X    union REGS rg;
X
X    biocol = col;
X    rg.h.ah = 2;		/* set cursor position function code */
X    rg.h.dl = col;
X    rg.h.dh = row;
X    rg.h.bh = 0;		/* set screen page number */
X    int86(0x10, &rg, &rg);
X}
X
X/*
X * Erase to end of line.
X */
Xtteeol() {
X    union REGS rg;
X
X    rg.h.ah = 9;	/* write character/rendition */
X    rg.h.bh = 0;
X    rg.x.cx = ncol-biocol;
X    rg.h.al = ' ';
X    rg.h.bl = rendition;
X
X    int86(0x10, &rg, &rg);
X}
X
X/*
X * Erase to end of page.
X */
Xtteeop() {
X    ttdell(ttrow, nrow, nrow - ttrow);
X}
X
X/*
X * Make a noise.
X */
Xttbeep() {
X    union REGS rg;
X
X    rg.h.ah = 14;	/* write tty */
X    rg.h.al = BEL;
X
X    int86(0x10, &rg, &rg);
X}
X
X/*
X * Insert nchunk blank line(s) onto the
X * screen, scrolling the last line on the
X * screen off the bottom.
X */
Xttinsl(row, bot, nchunk) {
X    union REGS rg;
X    
X    if (row == bot) {		/* Case of one line insert is 	*/
X	ttmove(row, 0);		/*	special			*/
X	tteeol();
X	return;
X    }
X
X    rg.h.ah = 7;	/* scroll down */
X    rg.h.bh = 0x07;
X    rg.h.al = nchunk;
X    rg.h.ch = row;
X    rg.h.cl = 0;
X    rg.h.dh = bot;
X    rg.h.dl = ncol - 1;
X
X    int86(0x10, &rg, &rg);
X}
X
X/*
X * Delete nchunk line(s) from "row", replacing the
X * bottom line on the screen with a blank line. 
X */
X
Xttdell(row, bot, nchunk)
X{
X    union REGS rg;
X
X    if (row == bot) {		/* One line special case	*/
X	ttmove(row, 0);
X	tteeol();
X	return;
X    }
X    rg.h.ah = 6;	/* scroll up */
X    rg.h.bh = 0x07;
X    rg.h.al = nchunk;
X    rg.h.ch = row;
X    rg.h.cl = 0;
X    rg.h.dh = bot;
X    rg.h.dl = ncol - 1;
X
X    int86(0x10, &rg, &rg);
X}
X
X/*
X * Switch to full screen scroll. This is
X * used by "spawn.c" just before is suspends the
X * editor, and by "display.c" when it is getting ready
X * to exit.
X */
Xttnowindow()
X{
X}
X
X/*
X * Set the current writing color to the
X * specified color. Watch for color changes that are
X * not going to do anything (the color is already right)
X * and don't send anything to the display.
X * The rainbow version does this in putline.s on a
X * line by line basis, so don't bother sending
X * out the color shift.
X */
Xttcolor(color) register int color; {
X    if (color != tthue) {
X	if (color == CTEXT) {		/* Normal video.	*/
X	    rendition = 0x07;
X	} else if (color == CMODE) {	/* Reverse video.	*/
X	    rendition = 0x70;
X	}
X	tthue = color;			/* Save the color.	*/
X    }
X}
X
X/*
X * This routine is called by the
X * "refresh the screen" command to try and resize
X * the display. The new size, which must be deadstopped
X * to not exceed the NROW and NCOL limits, it stored
X * back into "nrow" and "ncol". Display can always deal
X * with a screen NROW by NCOL. Look in "window.c" to
X * see how the caller deals with a change.
X */
Xttresize() {
X	setttysize();
X}
X
X/* calculate the cost of doing string s */
Xcharcost (s) char *s; {
X    return strlen(s);
X}
X
Xttputc(c)
Xunsigned char c;
X{
X    union REGS rg;
X
X    if (c == '\b') {
X	if (biocol-1 > 0) {
X	    _move(ttrow, biocol-1);
X	}
X	return;
X    }
X    else if (c == '\r') {
X	_move(ttrow, 0);
X	return;
X    }
X    rg.h.ah = 9;	/* write character/rendition */
X    rg.h.bh = 0;
X    rg.x.cx = 1;
X    rg.h.al = c;
X    rg.h.bl = rendition;
X
X    int86(0x10, &rg, &rg);
X
X    if (biocol+1 >= ncol)
X	_move(ttrow + 1, 0);
X    else
X	_move(ttrow, biocol + 1);
X}
X
Xstruct nap
X    {
X    long napvalue;
X    long basetime;
X    };
X
Xttwait()
X    {
X    struct nap timer;
X    napstart(200, &timer);
X    while (napchk(&timer) == 0)
X	if (typeahead())
X	    return 0;
X    return 1;
X    }
X
X/***************************/
X/* MSDOS time functions    */
X/***************************/
X
X/* Apparantly Turbo C has a sleep library routine; MSC doesn't -jbs */
X
X#define gettime(_a) ((((long)(_a.x.cx)) << 16)+_a.x.dx)
X
X#ifdef MSC
Xsleep(amount)
X    {
X    while (amount--)
X	nap(100);
X    }
X#endif
X
X/* nap in units of 100ths of seconds via busy loops. */
Xnap(amount)
X    {
X    struct nap tim;
X    napstart(amount, &tim);
X    while(napchk(&tim) == 0)
X	;
X    }
X
Xnapstart(amount,sav)
Xint amount;
Xregister struct nap *sav;
X    {
X    union REGS inregs, outregs;
X    int hunds, secs;
X
X    inregs.h.ah = 0x2c;			/* get time */
X    int86(0x21, &inregs, &outregs);
X
X    /* glitch in hardware RTC (time warp) makes this necessary */
X    inregs = outregs;
X    inregs.h.dl = 0;		/* seconds counter may be slow to increment */
X    if (inregs.h.dh > 0)
X	--inregs.h.dh;		/* paranoia */
X    if (inregs.h.cl > 0)
X	--inregs.h.cl;		/* more paranoia */
X    /* end of glitch handling */
X
X    sav->basetime = gettime(inregs);	/* in case of wraparound */
X
X    /* convert hundredths of seconds to future time structure */
X    secs = outregs.h.dh;
X    hunds = outregs.h.dl + amount;
X
X    while (hunds >= 100) {
X	hunds -= 100;
X	++secs;
X    }
X    outregs.h.dl = hunds;
X    while (secs >= 60) {
X	secs -= 60;
X	++outregs.h.cl;			/* increment minutes */
X    }
X    outregs.h.dh = secs;
X
X    /* check for minute and hour wraparound */
X    if (outregs.h.cl >= 60)
X	{
X	outregs.h.cl -= 60;
X	++outregs.h.ch;			/* increment hours */
X	}
X    if (outregs.h.ch >= 24)
X	{
X	outregs.h.ch -= 24;
X	}
X    sav->napvalue = gettime(outregs);
X    }
X
Xnapchk(sav)
Xregister struct nap *sav;
X    {
X    union REGS inregs, outregs;
X    long current;
X
X    inregs.h.ah = 0x2c;			/* get time */
X    int86(0x21, &inregs, &outregs);
X
X    current = gettime(outregs);
X
X    if(sav->napvalue > sav->basetime)
X	{
X	if (current >= sav->napvalue || current < sav->basetime)
X	    return 1;
X	}
X    else if (current >= sav->napvalue && current < sav->basetime)
X	return 1;
X    return 0;
X    }
!FaR!OuT!
fi
if [ ! -s ./ttydef.h ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./ttydef.h
sed -e 's/^X//' > ./ttydef.h << '!FaR!OuT!'
X/*
X *	Termcap terminal file, nothing special, just make it big
X *	enough for windowing systems.
X */
X
X#define	GOSLING			/* Compile in fancy display.	*/
X/* #define	MEMMAP		*/	/* Not memory mapped video.	*/
X
X#define	NROW	25    			/* Rows.			*/
X#define	NCOL	80			/* Columns.			*/
X#define	MOVE_STANDOUT			/* don't move in standout mode	*/
X/* #define	STANDOUT_GLITCH		/* possible standout glitch	*/
X#define XKEYS
X
X#define KFIRST	K00
X#define KHOME	K00
X#define KDOWN	K01
X#define	KUP	K02
X#define	KLEFT	K03
X#define	KRIGHT	K04
X#define	KPGUP	K05
X#define	KPGDN	K06
X#define	KEND	K07
X#define	KDELETE	K08
X#define	KINSERT	K09
X#define KCLEFT	K0A
X#define KCRIGHT	K0B
X#define KCPGUP	K0C
X#define KCPGDN	K0D
X#define KCHOME	K0E
X#define KCEND	K0F
X
X#define	KF1	K10
X#define KF2	K11
X#define KF3	K12
X#define KF4	K13
X#define KF5	K14
X#define KF6	K15
X#define KF7	K16
X#define KF8	K17
X#define	KF9	K18
X#define KF10	K19
X#define	KSF1	K1A
X#define	KSF2	K1B
X#define	KSF3	K1C
X#define	KSF4	K1D
X#define	KSF5	K1E
X#define	KSF6	K1F
X#define	KSF7	K20
X#define	KSF8	K21
X#define	KSF9	K22
X#define	KSF10	K23
X#define KCF1	K24
X#define KCF2	K25
X#define KCF3	K26
X#define KCF4	K27
X#define KCF5	K28
X#define KCF6	K29
X#define KCF7	K2A
X#define KCF8	K2B
X#define KCF9	K2C
X#define KCF10	K2D
X#define KLAST	K2D
X
X#define	NFUND_XMAPS	1
X#define	FUND_XMAPS	{KFIRST,KLAST,ibm_keys,(KEYMAP*)NULL}
Xextern	int (*(ibm_keys[]))(); /* should be FN ibmkeys[], but not defined yet */
X/*
X * Extra map segments for dired mode -- just use fundamental mode segments
X */
X#define	NDIRED_XMAPS	NFUND_XMAPS
X#define	DIRED_XMAPS	FUND_XMAPS
X
!FaR!OuT!
fi
if [ ! -s ./ttyio.c ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./ttyio.c
sed -e 's/^X//' > ./ttyio.c << '!FaR!OuT!'
X/*
X * Name:	Mg 2b
X *		MSDOS terminal I/O (TurboC 1.5)
X *
X * The functions in this file
X * negotiate with the operating system for
X * keyboard characters, and write characters to
X * the display
X *
X * This version goes along with tty/ibmbios/tty.c.
X * Terminal size is determined there, rather than here.
X */
X#include	"def.h"
X
X#include	<stdio.h>
X#include	<fcntl.h>
X#include	<signal.h>
X
Xstatic int ttyactivep = FALSE;		/* terminal in editor mode?	*/
X
Xint	nrow;				/* Terminal size, rows.		*/
Xint	ncol;				/* Terminal size, columns.	*/
X
X/*
X * This function gets called once, to set up
X * the terminal channel.  This is essentially a no-op
X * on msdos, since I/O will all be done via bios calls.
X */
Xttopen()
X{
X	if (ttyactivep)
X		return;
X
X	signal(SIGINT, SIG_IGN);
X
X	nrow = 25;			/* initial guess */
X	ncol = 80;
X
X	ttyactivep = TRUE;
X}
X
X/*
X * This function gets called just
X * before we go back home to the shell. Another
X * MSDOS no_op.
X */
Xttclose()
X{
X	if(!ttyactivep)
X		return;
X	ttyactivep = FALSE;
X}
X
X/********************************************************************/
X/* ttputc, ttgetc & typeahead have been deleted from this file, and */
X/* moved into the tty specific code.  There is no operating-system  */
X/* generic way to do these                                          */
X/********************************************************************/
X
X/*
X * Flush output.  This function is a no-op
X */
Xttflush()
X{
X}
X
X/*
X * panic:  print error and die, leaving core file.
X */
Xpanic(s)
Xchar *s;
X{
X	fprintf(stderr, "%s\r\n", s);
X#ifdef SYSCLEANUP
X	SYSCLEANUP;
X#endif
X	exit(1);
X}
X
X
X/*
X** This should check the size of the window, and reset if needed.
X*/
X
Xsetttysize()
X{
X	nrow = 25;
X	ncol = 80;
X}
X
X
Xvoid interrupt donothing()
X    {
X    return;	/* continue program */
X    }
X
X/* Turbo C does not have a "signal" function. */
X/* since all I need to use it for is to ignore ^C, this substitute works ok */
Xsignal(sig, action)
Xint sig;
Xint (*action)();
X    {
X    if (sig != SIGINT || action != SIG_IGN)
X	{
X	printf("Runtime error in signal: only SIGINT, SIG_IGN supported!\n");
X	exit(1);
X	}
X    setvect(0x23, donothing);
X    }
!FaR!OuT!
fi
if [ ! -s ./ttykbd.c ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./ttykbd.c
sed -e 's/^X//' > ./ttykbd.c << '!FaR!OuT!'
X/*
X * Name:	Mg 2a
X *		IBM BIOS keyboard driver (TurboC 1.5)
X *
X */
X
X#include	"def.h"
X#include	<dos.h>
X
X#ifdef MSC
X#include	<bios.h>
X#endif /* MSC */
X
X#define KMETA	METABIT
X
Xchar	*keystrings[] = {
X	"Home",		"Down-Arrow",	"Up-Arrow",	"Left-Arrow",
X	"Right-Arrow",	"Page-Up",	"Page-Down",	"End",
X	"Delete",	"Insert",	"Control-Left", "Control-Right",
X	"Control-PgUp",	"Control-PgDn",	"Control-Home",	"Control-End",
X	"F1",		"F2",		"F3",		"F4",
X	"F5",		"F6",		"F7",		"F8",
X	"F9",		"F10",		"FS1",		"FS2",
X	"FS3",		"FS4",		"FS5",		"FS6",
X	"FS7",		"FS8",		"FS9",		"FS10",
X	"FC1",		"FC2",		"FC3",		"FC4",
X	"FC5",		"FC6",		"FC7",		"FC8",
X	"FC9",		"FC10",
X};
X
X/* convert IBM bios extended scan codes to appropriate function key values */
Xstatic KCHAR extended[] = {
X	-1,		-1,		-1,		0,	  /* 0-3 */
X	-1,		-1,		-1,		-1,	  /* 4-7 */
X	-1,		-1,		-1,		-1,	  /* 8-11 */
X	-1,		-1,		-1,		-1,	  /* 12-15 */
X	KMETA|'Q',	KMETA|'W',	KMETA|'E',	KMETA|'R',/* 16-19 */
X	KMETA|'T',	KMETA|'Y',	KMETA|'U',	KMETA|'I',/* 20-23 */
X	KMETA|'O',	KMETA|'P',	-1,		-1,	  /* 24-27 */
X	-1,		-1,		KMETA|'A',	KMETA|'S',/* 28-31 */
X	KMETA|'D',	KMETA|'F',	KMETA|'G',	KMETA|'H',/* 32-35 */
X	KMETA|'J',	KMETA|'K',	KMETA|'L',	-1,	  /* 36-39 */
X	-1,		-1,		-1,		-1,	  /* 40-43 */
X	KMETA|'Z',	KMETA|'X',	KMETA|'C',	KMETA|'V',/* 44-47 */
X	KMETA|'B',	KMETA|'N',	KMETA|'M',	-1,	  /* 48-51 */
X	-1,		-1,		/* oops - miscounted */	  /* 52-53 */
X	-1,		-1,		-1,		-1,	  /* 54-57 */
X	-1,		KF1,		KF2,		KF3,	  /* 58-61 */
X	KF4,		KF5,		KF6,		KF7,	  /* 62-65 */
X	KF8,		KF9,		KF10,		-1,	  /* 66-69 */
X	-1,		KHOME,		KUP,		KPGUP,	  /* 70-73 */
X	-1,		KLEFT,		-1,		KRIGHT,	  /* 74-77 */
X	-1,		KEND,		KDOWN,		KPGDN,	  /* 78-81 */
X	KINSERT,	KDELETE,	KSF1,		KSF2,	  /* 82-85 */
X	KSF3,		KSF4,		KSF5,		KSF6,	  /* 86-89 */
X	KSF7,		KSF8,		KSF9,		KSF10,	  /* 90-93 */
X	KCF1,		KCF2,		KCF3,		KCF4,	  /* 94-97 */
X	KCF5,		KCF6,		KCF7,		KCF8,	  /* 98-101 */
X	KCF9,		KCF10,		KMETA|KF1,	KMETA|KF2,/* 102-105 */
X	KMETA|KF3,	KMETA|KF4,	KMETA|KF5,	KMETA|KF6,/* 106-109 */
X	KMETA|KF7,	KMETA|KF8,	KMETA|KF9,	KMETA|KF10,/* 110-113 */
X	-1,		KCLEFT,		KCRIGHT,	KCEND,	  /* 114-117 */
X	KCPGDN,		KCHOME,		KMETA|'1',	KMETA|'2',/* 118-121 */
X	KMETA|'3',	KMETA|'4',	KMETA|'5',	KMETA|'6',/* 122-125 */
X	KMETA|'7',	KMETA|'8',	KMETA|'9',	KMETA|'0',/* 126-129 */
X	KMETA|'-',	KMETA|'=',	KCPGUP,			  /* 130-132 */
X};
X
X#define NEXTENDED (sizeof(extended)-sizeof(KCHAR))
X
Xstatic KCHAR savedkey = -1;
X
Xgetkbd() {
X    return (ttgetc());
X}
X
X/*
X * Get keyboard character, and interpret
X * any special keys on the keyboard.
X */
Xttgetc() {
X    KCHAR temp;
X
X    while (savedkey == -1)
X	getakey();
X
X    temp = savedkey;
X    savedkey = -1;
X    return temp;
X}
X
Xgetakey() {
X    union REGS rg;
X
X    rg.h.ah = 0;		/* read keyboard */
X    int86(0x16, &rg, &rg);
X    if (rg.h.al) {
X	if (rg.h.al == '\b' && rg.h.ah == 0x0E)
X	    rg.h.al = 0x7F;	/* transform backspace key into delete */
X				/* control H is still backspace */
X	savedkey = rg.h.al;	/* normal key value */
X    }
X    else {
X	if (rg.h.ah >= NEXTENDED)
X	    savedkey = -1;
X	else
X	    savedkey = extended[rg.h.ah];
X    }
X}
X
Xpollkbd()
X{
X#ifdef MSC
X    return _bios_keybrd(_KEYBRD_READY);
X#else
X    return bioskey(1);
X#endif /* MSC */
X}
X
Xtypeahead() {
X    if (savedkey != -1)
X	return 1;
X    if (pollkbd())
X	getakey();
X    return (savedkey != -1);
X}
X
Xttykeymapinit() {
X    /* mg 2a no longer lets me easily bind things at run time. */
X    /* instead, I make up a keymap, and link it in at compile time */
X}
X
Xextern	int	gotobol();		/* Move to start of line	*/
Xextern	int	backchar();		/* Move backward by characters	*/
Xextern	int	gotoeol();		/* Move to end of line		*/
Xextern	int	forwchar();		/* Move forward by characters	*/
Xextern	int	gotobob();		/* Move to start of buffer	*/
Xextern	int	gotoeob();		/* Move to end of buffer	*/
Xextern	int	gotobop();		/* Move to start of display page*/
Xextern	int	gotoeop();		/* Move to end of display page	*/
Xextern	int	forwline();		/* Move forward by lines	*/
Xextern	int	backline();		/* Move backward by lines	*/
Xextern	int	forwpage();		/* Move forward by pages	*/
Xextern	int	backpage();		/* Move backward by pages	*/
Xextern	int	openline();		/* Open up a blank line		*/
Xextern	int	forwdel();		/* Forward delete		*/
Xextern	int	rescan();		/* for unmapped keys		*/
Xextern	int	backword();		/* Backup by words		*/
Xextern	int	forwword();		/* Advance by words		*/
Xextern	int	killline();		/* Kill forward			*/
X
XPF	ibm_keys[] = {
X	gotobol,	/* Home			(0x100)	*/
X	forwline,	/* Down				*/
X	backline,	/* Up				*/
X	backchar,	/* Left				*/
X	forwchar,	/* Right			*/
X	backpage,	/* Page Up			*/
X	forwpage,	/* Page Dn			*/
X	gotoeol,	/* End				*/
X	forwdel,	/* Delete			*/
X	openline,	/* Insert			*/
X	backword,	/* Control Left			*/
X	forwword,	/* Control Right		*/
X	gotobob,	/* Control PgUp           	*/
X	gotoeob,	/* Control PgDn         	*/
X	gotobop,	/* Control HOME			*/
X	gotoeop,	/* Control END			*/
X
X	/* function keys - initially unassigned */
X	rescan, rescan, rescan, rescan,
X	rescan, rescan, rescan, rescan,
X	rescan, rescan, rescan, rescan,
X	rescan, rescan, rescan, rescan,
X	rescan, rescan, rescan, rescan,
X	rescan, rescan, rescan, rescan,
X	rescan, rescan, rescan, rescan,
X	rescan, rescan,
X};
!FaR!OuT!
fi
if [ ! -s ./varargs.h ]
then
if [ ! -d . ]
then
	mkdir .
	echo mkdir .
fi
echo x - ./varargs.h
sed -e 's/^X//' > ./varargs.h << '!FaR!OuT!'
X/* varargs.h for MicroGnuEmacs 2a.  This one will work on systems that	*/
X/* the non-varargs version of mg 1 did.					*/
X/* based on the one I wrote for os9/68k .  I did not look at the bsd code. */
X
X/* by Robert A. Larson */
X
X/* assumptions made about how arguments are passed:			*/
X/*	arguments are stored in a block of memory with no padding between. */
X/*	The first argument will have the lowest address			*/
X
X/* varargs is a "portable" way to write a routine that takes a variable */
X/* number of arguements.  This implemination agrees with both the 4.2bsd*/
X/* and Sys V documentation of varargs.  Note that just because varargs.h*/
X/* is used does not mean that it is used properly.			*/
X
X#define va_dcl		unsigned va_alist;
X
Xtypedef	char *va_list;
X
X#define	va_start(pvar)		((pvar) = (char *)&va_alist)
X
X#define va_arg(pvar,type)	(((pvar)+=sizeof(type)),*(((type *)(pvar)) - 1))
X
X#define va_end(pvar)		/* va_end is simple */
!FaR!OuT!
fi
exit