[comp.sources.misc] v03i032: mg 2a part 8 of 15

BLARSON@ECLA.USC.EDU (Bob Larson) (05/26/88)

comp.sources.misc: Volume 3, Issue 32
Submitted-By: "Bob Larson" <BLARSON@ECLA.USC.EDU>
Archive-Name: mg2a/Part08

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	sys/default/README
#	sys/default/alloca.c
#	sys/default/chrdef.h
#	sys/default/cinfo.c
#	sys/default/tty.c
#	sys/default/ttydef.h
#	sys/default/ttykbd.c
#	sys/default/varargs.h
#	sys/prime/cinfo.c
#	sys/prime/fileio.c
#	sys/prime/make.cpl
#	sys/prime/mg.64v.options.c
#	sys/prime/mg.options.c
#	sys/prime/readme
#	sys/prime/spawn.c
#	sys/prime/stackptr$.pma
#	sys/prime/sysdef.h
#	sys/prime/ttyio.c
#	sys/prime/varargs.h.ins.cc
# This archive created: Sun May 22 02:24:06 1988
# By:	blarson
if test -d sys
then true
else mkdir sys
fi
if test -d sys/default
then true
else mkdir sys/default
fi
if test -d sys/prime
then true
else mkdir sys/prime
fi
cat << \SHAR_EOF > sys/default/README
			MG Termcap Terminal Driver

The termcap library needs to know where to get the terminal type and
termcap capibilities file from.  UNIX and Os9/68k users should

	setenv TERM term-type

to their terminal type, and

	setenv TERMCAP termcap-file

if they are using a non-standard termcap file.  VMS users should see
[.SYS.VMS]AAAREADME.1ST for information on how to define the logical
names TERM and ETC to point to the termcap definition file.  Users of
other operating systems should do the aproprate thing.  For an example
of a termcap file, UNIX users may look in /etc/termcap, Os9/68k users
may look at /dd/sys/termcap (if present), and VMS users should see the
file [.SYS.VMS.TERMCAP]TERMCAP. 

MG requires that certain terminal capabilities exist in the specified
termcap entry.  The "cm" (cursor motion) capability *must* be
available to use MG.  (Yes, it is possible to fake cm with some other
capibilities, but MG doesn't try.) If your terminal is one that uses
control characters in the paramater portion of the "cm" string, the
"up" and "bc" capabilites may also be needed.  (See your termlib
documentation for when this is so.)

If the following capabilities are available, they are used.  The AL
and DL sequences are not totally standard, but having them improves
the performance of the editor, since it doesn't have to redraw the
screen to delete a line.  They should not be used if they need control
characters as paramaters.

	cd	-- clear display
	ce	-- clear to end of line

	al	-- insert 1 line
	dl	-- delete 1 line

	AL	-- insert multiple lines (note capitalization)
	DL	-- delete multiple lines (note capitalization)

	ti	-- cursor movement initialization string
	te	-- cursor movement end string

The cs capability is not as standard as some of the other
capibilities, but is used by MG when available.  It is used to define
a "scrolling region", which defines a window within the screen where
all the action takes place.  A newline character at the bottom of this
area scrolls the rest of the text in the area up one line, just like
the normal screen; a reverse linefeed (sr) at the top of the window
moves all the text in the area down a line.  MG does not properly
handle "cs" if your terminal needs control characters as paramaters,
and in this case "cs" should not be defined.

If the cs and sr capabilities are available, the termcap driver uses
these to make the insert/delete line functions work more smoothly. If
only the cs capability is present, it is still used for the delete
line function, but not for inserting lines.

Use of the cs capability is often desirable, but is not a win on
bit-mapped screens such as Sun workstation console windows.  This is
because it takes longer to scroll the window than to redraw it.  If
you are using a workstation window, you might consider using a termcap
entry that doesn't have the cs capability.

The definition of the cs capability is: the first parameter in the
sequence defines the first row (origin 0) that is in the scrolling
region, and the second argument defines the last row to include in the
scrolling region.

	cs	-- set scrolling region (arg1 = top, arg2 = bottom)
	sr	-- reverse index

The following capabilities provide for an enhanced (reverse-video or
otherwise rendered) mode line.  The sg entry should not be present on
terminals that do this to characters as they are placed on the screen.
Terminals that put a region of the screen in the standout mode should
have sg defined as numeric: :sg#0: for terminals that do this on
regions but don't take any character positions to do this, (this may
be a non-standard interprition of the meaning of sg) and the number of
character positions taken by any other terminal.

	so	-- enter standout mode
	se	-- leave standout mode
	sg	-- number of character positions used by standout

		Terminal-specific initialization file

If the MG termcap terminal driver is compiled with XKEYS defined, and
the startup file option is enabled as well, MG will look for a
terminal-specific initialization file.  The name of the terminal
initialization file varies between operating systems, but will usually
look like .mg-TERM, where TERM represents your terminal type.  For
example, a terminal initialization file under Unix and VMS for the DEC
VT100 terminal (termcap type vt100) would have the name ".mg-vt100". 

The terminal-specific startup file has the same format as the mg
startup file, and is executed immediately after the startup file
during mg's startup phase.  An example vt100 initialization file
follows, which globally binds the key sequences sent by the VT100
terminal (in keypad mode) to the appropriate functions.

----------------------------------CUT HERE-----------------------------------
;
; Small key definition file for VT100 terminals using the termcap
; driver. This only works if XKEYS is defined during compilation.
;
(global-set-key "\eOA" 'previous-line)	; up arrow
(global-set-key "\eOB" 'next-line)	; down arrow
(global-set-key "\eOC" 'forward-char)	; right arrow
(global-set-key "\eOD" 'backward-char)	; left arrow
SHAR_EOF
cat << \SHAR_EOF > sys/default/alloca.c
/*
	alloca -- (mostly) portable public-domain implementation

	last edit:	86/01/26	D A Gwyn

	This implementation of the PWB library alloca() function,
	which is used to allocate space off the run-time stack so
	that it is automatically reclaimed upon procedure exit, 
	was inspired by discussions with J. Q. Johnson of Cornell.

	It should work under any C implementation that uses an
	actual procedure stack (as opposed to a linked list of
	frames).  There are some preprocessor constants that can
	be defined when compiling for your specific system, for
	improved efficiency; however, the defaults should be okay.

	The general concept of this implementation is to keep
	track of all alloca()-allocated blocks, and reclaim any
	that are found to be deeper in the stack than the current
	invocation.  This heuristic does not reclaim storage as
	soon as it becomes invalid, but it will do so eventually.

	As a special case, alloca(0) reclaims storage without
	allocating any.  It is a good idea to use alloca(0) in
	your main control loop, etc. to force garbage collection.
*/
#ifndef lint
static char	SCCSid[] = "@(#)alloca.c	1.1";	/* for the "what" utility */
#endif

#ifdef X3J11
typedef void	*pointer;		/* generic pointer type */
#else
typedef char	*pointer;		/* generic pointer type */
#endif

#define	NULL	0			/* null pointer constant */

extern void	free();
extern pointer	malloc();

/*
	Define STACK_DIRECTION if you know the direction of stack
	growth for your system; otherwise it will be automatically
	deduced at run-time.

	STACK_DIRECTION > 0 => grows toward higher addresses
	STACK_DIRECTION < 0 => grows toward lower addresses
	STACK_DIRECTION = 0 => direction of growth unknown
*/

#ifndef STACK_DIRECTION
#define	STACK_DIRECTION	0		/* direction unknown */
#endif

#if STACK_DIRECTION != 0

#define	STACK_DIR	STACK_DIRECTION	/* known at compile-time */

#else	/* STACK_DIRECTION == 0; need run-time code */

static int	stack_dir = 0;		/* 1 or -1 once known */
#define	STACK_DIR	stack_dir

static void
find_stack_direction( /* void */ )
	{
	static char	*addr = NULL;	/* address of first
					   `dummy', once known */
	auto char	dummy;		/* to get stack address */

	if ( addr == NULL )
		{			/* initial entry */
		addr = &dummy;

		find_stack_direction();	/* recurse once */
		}
	else				/* second entry */
		if ( &dummy > addr )
			stack_dir = 1;	/* stack grew upward */
		else
			stack_dir = -1;	/* stack grew downward */
	}

#endif	/* STACK_DIRECTION == 0 */

/*
	An "alloca header" is used to:
	(a) chain together all alloca()ed blocks;
	(b) keep track of stack depth.

	It is very important that sizeof(header) agree with malloc()
	alignment chunk size.  The following default should work okay.
*/

#ifndef	ALIGN_SIZE
#define	ALIGN_SIZE	sizeof(double)
#endif

typedef union hdr
	{
	char	align[ALIGN_SIZE];	/* to force sizeof(header) */
	struct	{
		union hdr	*next;	/* for chaining headers */
		char		*deep;	/* for stack depth measure */
		}	h;
	}	header;

/*
	alloca( size ) returns a pointer to at least `size' bytes of
	storage which will be automatically reclaimed upon exit from
	the procedure that called alloca().  Originally, this space
	was supposed to be taken from the current stack frame of the
	caller, but that method cannot be made to work for some
	implementations of C, for example under Gould's UTX/32.
*/

pointer
alloca( size )				/* returns pointer to storage */
	unsigned	size;		/* # bytes to allocate */
	{
	static header	*last = NULL;	/* -> last alloca header */
	auto char	probe;		/* probes stack depth: */
	register char	*depth = &probe;

#if STACK_DIRECTION == 0
	if ( STACK_DIR == 0 )		/* unknown growth direction */
		find_stack_direction();
#endif

	/* Reclaim garbage, defined as all alloca()ed storage that
	   was allocated from deeper in the stack than currently. */

	{
	register header	*hp;		/* traverses linked list */

	for ( hp = last; hp != NULL; )
		if ( STACK_DIR > 0 && hp->h.deep > depth
		  || STACK_DIR < 0 && hp->h.deep < depth
		   )	{
			register header	*np = hp->h.next;

			free( (pointer)hp );	/* collect garbage */

			hp = np;	/* -> next header */
			}
		else
			break;		/* rest are not deeper */

	last = hp;			/* -> last valid storage */
	}

	if ( size == 0 )
		return NULL;		/* no allocation required */

	/* Allocate combined header + user data storage. */

	{
	register pointer	new = malloc( sizeof(header) + size );
					/* address of header */

	if ( new == NULL )
		return NULL;		/* abort() is traditional */

	((header *)new)->h.next = last;
	((header *)new)->h.deep = depth;

	last = (header *)new;

	/* User storage begins just after header. */

	return (pointer)((char *)new + sizeof(header));
	}
	}
SHAR_EOF
cat << \SHAR_EOF > sys/default/chrdef.h
/*
 * sys/default/chardef.h: character set specific #defines for mg 2a
 * Warning: System specific ones exist
 */

#ifndef	CHARMASK
/*
 * casting should be at least as efficent as anding with 0xff,
 * and won't have the size problems.  Override in sysdef.h if no
 * unsigned char type.
 */
#define	CHARMASK(c)	((unsigned char) (c))
#endif

/*
 * These flags, and the macros below them,
 * make up a do-it-yourself set of "ctype" macros that
 * understand the DEC multinational set, and let me ask
 * a slightly different set of questions.
 */
#define _W	0x01			/* Word.			*/
#define _U	0x02			/* Upper case letter.		*/
#define _L	0x04			/* Lower case letter.		*/
#define _C	0x08			/* Control.			*/
#define _P	0x10			/* end of sentence punctuation	*/
#define	_D	0x20			/* is decimal digit		*/

#define ISWORD(c)	((cinfo[CHARMASK(c)]&_W)!=0)
#define ISCTRL(c)	((cinfo[CHARMASK(c)]&_C)!=0)
#define ISUPPER(c)	((cinfo[CHARMASK(c)]&_U)!=0)
#define ISLOWER(c)	((cinfo[CHARMASK(c)]&_L)!=0)
#define ISEOSP(c)	((cinfo[CHARMASK(c)]&_P)!=0)
#define	ISDIGIT(c)	((cinfo[CHARMASK(c)]&_D)!=0)
#define TOUPPER(c)	((c)-0x20)
#define TOLOWER(c)	((c)+0x20)

/*
 * generally useful thing for chars
 */
#define CCHR(x)		((x) ^ 0x40)	/* CCHR('?') == DEL */

#ifndef	METACH
#define	METACH	CCHR('[')
#endif

#ifdef	XKEYS
#define	K00	256
#define	K01	257
#define	K02	258
#define	K03	259
#define	K04	260
#define	K05	261
#define	K06	262
#define	K07	263
#define	K08	264
#define	K09	265
#define	K0A	266
#define	K0B	267
#define	K0C	268
#define	K0D	269
#define	K0E	270
#define	K0F	271
#define	K10	272
#define	K11	273
#define	K12	274
#define	K13	275
#define	K14	276
#define	K15	277
#define	K16	278
#define	K17	279
#define	K18	280
#define	K19	281
#define	K1A	282
#define	K1B	283
#define	K1C	284
#define	K1D	285
#define	K1E	286
#define	K1F	287
#endif
SHAR_EOF
cat << \SHAR_EOF > sys/default/cinfo.c
/*
 *		Character class tables.
 * Do it yourself character classification
 * macros, that understand the multinational character set,
 * and let me ask some questions the standard macros (in
 * ctype.h) don't let you ask.
 */
#include	"def.h"

/*
 * This table, indexed by a character drawn
 * from the 256 member character set, is used by my
 * own character type macros to answer questions about the
 * type of a character. It handles the full multinational
 * character set, and lets me ask some questions that the
 * standard "ctype" macros cannot ask.
 */
char	cinfo[256] = {
	_C,		_C,		_C,		_C,	/* 0x0X */
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,	/* 0x1X */
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	0,		_P,		0,		0,	/* 0x2X */
	_W,		_W,		0,		_W,
	0,		0,		0,		0,
	0,		0,		_P,		0,
	_D|_W,		_D|_W,		_D|_W,		_D|_W,	/* 0x3X */
	_D|_W,		_D|_W,		_D|_W,		_D|_W,
	_D|_W,		_D|_W,		0,		0,
	0,		0,		0,		_P,
	0,		_U|_W,		_U|_W,		_U|_W,	/* 0x4X */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,	/* 0x5X */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		0,
	0,		0,		0,		0,
	0,		_L|_W,		_L|_W,		_L|_W,	/* 0x6X */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,	/* 0x7X */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		0,
	0,		0,		0,		_C,
	0,		0,		0,		0,	/* 0x8X */
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,	/* 0x9X */
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,	/* 0xAX */
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,	/* 0xBX */
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,	/* 0xCX */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	0,		_U|_W,		_U|_W,		_U|_W,	/* 0xDX */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		0,		_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,	/* 0xEX */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	0,		_L|_W,		_L|_W,		_L|_W,	/* 0xFX */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		0,		0
};

/*
 * Find the name of a keystroke.  Needs to be changed to handle 8-bit printing
 * characters and function keys better.	 Returns a pointer to the terminating
 * '\0'.
 */

char *keyname(cp, k)
register char *cp;
register int k;
{
    register char *np;
#ifdef	FKEYS
    extern char *keystrings[];
#endif

    if(k < 0) k = CHARMASK(k);			/* sign extended char */
    switch(k) {
	case CCHR('@'): np = "NUL"; break;
	case CCHR('I'): np = "TAB"; break;
	case CCHR('J'): np = "LFD"; break; /* yuck, but that's what GNU calls it */
	case CCHR('M'): np = "RET"; break;
	case CCHR('['): np = "ESC"; break;
	case ' ':	np = "SPC"; break; /* yuck again */
	case CCHR('?'): np = "DEL"; break;
	default:
#ifdef	FKEYS
	    if(k >= KFIRST && k <= KLAST &&
		    (np = keystrings[k - KFIRST]) != NULL)
		break;
#endif
	    if(k > CCHR('?')) {
		*cp++ = '0';
		*cp++ = ((k>>6)&7) + '0';
		*cp++ = ((k>>3)&7) + '0';
		*cp++ = (k&7) + '0';
		*cp = '\0';
		return cp;
	    }
	    if(k < ' ') {
		*cp++ = 'C';
		*cp++ = '-';
		k = CCHR(k);
		if(ISUPPER(k)) k = TOLOWER(k);
	    }
	    *cp++ = k;
	    *cp = '\0';
	    return cp;
    }
    (VOID) strcpy(cp, np);
    return cp + strlen(cp);
}
SHAR_EOF
cat << \SHAR_EOF > sys/default/tty.c
/*
 * Termcap/terminfo display driver
 *
 * Termcap is a terminal information database and routines to describe
 * terminals on most UNIX systems.  Many other systems have adopted
 * this as a reasonable way to allow for widly varying and ever changing
 * varieties of terminal types.	 This should be used where practical.
 */
/* Known problems:
 *	If you have a terminal with no clear to end of screen and
 *	memory of lines below the ones visible on the screen, display
 *	will be wrong in some cases.  I doubt that any such terminal
 *	was ever made, but I thought everyone with delete line would
 *	have clear to end of screen too...
 *
 *	Code for terminals without clear to end of screen and/or clear
 *	to end of line has not been extensivly tested.
 *
 *	Cost calculations are very rough.  Costs of insert/delete line
 *	may be far from the truth.  This is accentuated by display.c
 *	not knowing about multi-line insert/delete.
 *
 *	Using scrolling region vs insert/delete line should probably
 *	be based on cost rather than the assuption that scrolling
 *	region operations look better.
 */
#include	"def.h"

#define BEL	0x07			/* BEL character.		*/

extern	int	ttrow;
extern	int	ttcol;
extern	int	tttop;
extern	int	ttbot;
extern	int	tthue;

int	tceeol;			/* Costs are set later */
int	tcinsl;
int	tcdell;

static	int	insdel;		/* Do we have both insert & delete line? */

#ifdef NO_RESIZE
static	setttysize();
#endif

char	*tgetstr();
char	*tgoto();
int	ttputc();

#define TCAPSLEN 1024

char tcapbuf[TCAPSLEN];

/* PC, UP, and BC are used by termlib, so must be extern and have these
 * names unless you have a non-standard termlib.
 */

int	LI;			/* standard # lines */
char	PC,
	*CM,
	*CE,
	*UP,
	*BC,
	*IM,			/* insert mode */
	*IC,			/* insert a single space */
	*EI,			/* end insert mode */
	*DC,
	*AL,			/* add line */
	*DL,			/* del line */
	*pAL,			/* parameterized add line */
	*pDL,			/* parameterized delete line */
	*TI,			/* term init -- start using cursor motion */
	*TE,			/* term end --- end using cursor motion */
	*SO,
	*SE,
	*CD,
	*CS,			/* set scroll region			*/
	*SF,			/* forw index (used with scroll region)	*/
	*SR;			/* back index (used with scroll region)	*/
#ifdef	XKEYS
char	*KS, *KE;		/* enter keypad mode, exit keypad mode	*/
#endif
int	SG;	/* number of glitches, 0 for invisible, -1 for none	*/
	/* (yes virginia, there are terminals with invisible glitches)	*/

/*
 * Initialize the terminal when the editor
 * gets started up.
 */
static char tcbuf[1024];

ttinit() {
	char *tv_stype;
	char *t, *p, *tgetstr();
#ifndef gettermtype		/* (avoid declaration if #define) */
	char *gettermtype();	/* system dependent function to determin terminal type */
#endif

	if((tv_stype = gettermtype()) == NULL)
		panic("Could not determine terminal type");
	if((tgetent(tcbuf, tv_stype)) != 1) {
		(VOID) strcpy(tcbuf, "Unknown terminal type ");
		(VOID) strcat(tcbuf, tv_stype);
		panic(tcbuf);
	}

	p = tcapbuf;
	t = tgetstr("pc", &p);
	if(t) PC = *t;

	LI = tgetnum("li");
	CD = tgetstr("cd", &p);
	CM = tgetstr("cm", &p);
	CE = tgetstr("ce", &p);
	UP = tgetstr("up", &p);
	BC = tgetstr("bc", &p);
	IM = tgetstr("im", &p);
	IC = tgetstr("ic", &p);
	EI = tgetstr("ei", &p);
	DC = tgetstr("dc", &p);
	AL = tgetstr("al", &p);
	DL = tgetstr("dl", &p);
	pAL= tgetstr("AL", &p);	/* parameterized insert and del. line */
	pDL= tgetstr("DL", &p);
	TI = tgetstr("ti", &p);
	TE = tgetstr("te", &p);
	SO = tgetstr("so", &p);
	SE = tgetstr("se", &p);
	CS = tgetstr("cs", &p); /* set scrolling region */
	SF = tgetstr("sf", &p);
	if(!SF || !*SF) {	/* this is what GNU Emacs does */
	    SF = tgetstr("do", &p);
	    if(!SF || !*SF) {
		SF = tgetstr("nl", &p);
		if(!SF || !*SF) SF = "\n";
	    }
	}
	SR = tgetstr("sr", &p);
	SG = tgetnum("sg");	/* standout glitch	*/
#ifdef	XKEYS
	KS = tgetstr("ks", &p);	/* keypad start, keypad end	*/
	KE = tgetstr("ke", &p);
#endif

	if(CM == NULL || UP == NULL)
	    panic("This terminal is to stupid to run MicroGnuEmacs\n");
	ttresize();			/* set nrow & ncol	*/

	/* watch out for empty capabilities (sure to be wrong)	*/
	if (CE && !*CE) CE = NULL;
	if (CS && !*CS) CS = NULL;
	if (SR && !*SR) SR = NULL;
	if (AL && !*AL) AL = NULL;
	if (DL && !*DL) DL = NULL;
	if (pAL && !*pAL) pAL = NULL;
	if (pDL && !*pDL) pDL = NULL;
	if (CD && !*CD) CD = NULL;

	if(!CE) tceeol = ncol;
	else	tceeol = charcost(CE);

	/* Estimate cost of inserting a line */
	if (CS && SR)	tcinsl = charcost(CS)*2 + charcost(SR);
	else if (pAL)	tcinsl = charcost(pAL);
	else if (AL)	tcinsl = charcost(AL);
	else		tcinsl = NROW * NCOL;	/* make this cost high enough */

	/* Estimate cost of deleting a line */
	if (CS)		tcdell = charcost(CS)*2 + charcost(SF);
	else if (pDL)	tcdell = charcost(pDL);
	else if (DL)	tcdell = charcost(DL);
	else		tcdell = NROW * NCOL;	/* make this cost high enough */

	/* Flag to indicate that we can both insert and delete lines */
	insdel = (AL || pAL) && (DL || pDL);

	if (p >= &tcapbuf[TCAPSLEN])
		panic("Terminal description too big!\n");
	if (TI && *TI) putpad(TI, 1);	/* init the term */
}

/*
 * Clean up the terminal, in anticipation of
 * a return to the command interpreter. This is a no-op
 * on the ANSI display. On the SCALD display, it sets the
 * window back to half screen scrolling. Perhaps it should
 * query the display for the increment, and put it
 * back to what it was.
 */
tttidy() {
	if (TE && *TE) putpad(TE, 1);	/* set the term back to normal mode */
#ifdef	XKEYS
	ttykeymaptidy();
#endif
}

/*
 * Move the cursor to the specified
 * origin 0 row and column position. Try to
 * optimize out extra moves; redisplay may
 * have left the cursor in the right
 * location last time!
 */
ttmove(row, col) {
    char	*tgoto();

    if (ttrow!=row || ttcol!=col) {
	putpad(tgoto(CM, col, row), 1);
	ttrow = row;
	ttcol = col;
    }
}

/*
 * Erase to end of line.
 */
tteeol() {
    if(CE) putpad(CE, 1);
    else {
	register int i=ncol-ttcol;
	while(i--) ttputc(' ');
	ttrow = ttcol = HUGE;
    }
}

/*
 * Erase to end of page.
 */
tteeop() {
    if(CD) putpad(CD, nrow - ttrow);
    else {
	putpad(CE, 1);
	if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1);
	else {		/* do it by hand */
	    register int line;
	    for (line = ttrow + 1; line <= LI; ++line) {
		ttmove(line, 0);
		tteeol();
	    }
	}
	ttrow = ttcol = HUGE;
    }
}

/*
 * Make a noise.
 */
ttbeep() {
	ttputc(BEL);
	ttflush();
}

/*
 * Insert nchunk blank line(s) onto the
 * screen, scrolling the last line on the
 * screen off the bottom.  Use the scrolling
 * region if possible for a smoother display.
 * If no scrolling region, use a set
 * of insert and delete line sequences
 */
ttinsl(row, bot, nchunk) {
    register int	i, nl;

    if (row == bot) {		/* Case of one line insert is	*/
	ttmove(row, 0);		/*	special			*/
	tteeol();
	return;
    }
    if (CS && SR) {		/* Use scroll region and back index	*/
	nl = bot - row;
	ttwindow(row,bot);
	ttmove(row, 0);
	while (nchunk--) putpad(SR, nl);
	ttnowindow();
	return;
    } else if (insdel) {
	ttmove(1+bot-nchunk, 0);
	nl = nrow - ttrow;
	if (pDL) putpad(tgoto(pDL, 0, nchunk), nl);
	else for (i=0; i<nchunk; i++)	/* For all lines in the chunk	*/
		putpad(DL, nl);
	ttmove(row, 0);
	nl = nrow - ttrow;	/* ttmove() changes ttrow */
	if (pAL) putpad(tgoto(pAL, 0, nchunk), nl);
	else for (i=0; i<nchunk; i++)	/* For all lines in the chunk	*/
		putpad(AL, nl);
	ttrow = HUGE;
	ttcol = HUGE;
    } else panic("ttinsl: Can't insert/delete line");
}

/*
 * Delete nchunk line(s) from "row", replacing the
 * bottom line on the screen with a blank line.
 * Unless we're using the scrolling region, this is
 * done with a crafty sequences of insert and delete
 * lines.  The presence of the echo area makes a
 * boundry condition go away.
 */
ttdell(row, bot, nchunk)
{
    register int	i, nl;

    if (row == bot) {		/* One line special case	*/
	ttmove(row, 0);
	tteeol();
	return;
    }
    if (CS) {			/* scrolling region	*/
	nl = bot - row;
	ttwindow(row, bot);
	ttmove(bot, 0);
	while (nchunk--) putpad(SF, nl);
	ttnowindow();
    }
    else if(insdel) {
	ttmove(row, 0);			/* Else use insert/delete line	*/
	nl = nrow - ttrow;
	if (pDL) putpad(tgoto(pDL, 0, nchunk), nl);
	else for (i=0; i<nchunk; i++)	/* For all lines in the chunk	*/
		putpad(DL, nl);
	ttmove(1+bot-nchunk,0);
	nl = nrow - ttrow;	/* ttmove() changes ttrow */
	if (pAL) putpad(tgoto(pAL, 0, nchunk), nl);
	else for (i=0; i<nchunk; i++)	/* For all lines in the chunk	*/
		putpad(AL, nl);
	ttrow = HUGE;
	ttcol = HUGE;
    } else panic("ttdell: Can't insert/delete line");
}

/*
 * This routine sets the scrolling window
 * on the display to go from line "top" to line
 * "bot" (origin 0, inclusive). The caller checks
 * for the pathalogical 1 line scroll window that
 * doesn't work right, and avoids it. The "ttrow"
 * and "ttcol" variables are set to a crazy value
 * to ensure that the next call to "ttmove" does
 * not turn into a no-op (the window adjustment
 * moves the cursor).
 *
 */
ttwindow(top, bot)
{
	if (CS && (tttop!=top || ttbot!=bot)) {
		putpad(tgoto(CS, bot, top), nrow - ttrow);
		ttrow = HUGE;			/* Unknown.		*/
		ttcol = HUGE;
		tttop = top;			/* Remember region.	*/
		ttbot = bot;
	}
}

/*
 * Switch to full screen scroll. This is
 * used by "spawn.c" just before is suspends the
 * editor, and by "display.c" when it is getting ready
 * to exit.  This function gets to full screen scroll
 * by telling the terminal to set a scrolling regin
 * that is LI or nrow rows high, whichever is larger.
 * This behavior seems to work right on systems
 * where you can set your terminal size.
 */
ttnowindow()
{
    if (CS) {
	putpad(tgoto(CS, (nrow > LI ? nrow : LI) - 1, 0), nrow - ttrow);
	ttrow = HUGE;			/* Unknown.		*/
	ttcol = HUGE;
	tttop = HUGE;			/* No scroll region.	*/
	ttbot = HUGE;
    }
}

/*
 * Set the current writing color to the
 * specified color. Watch for color changes that are
 * not going to do anything (the color is already right)
 * and don't send anything to the display.
 * The rainbow version does this in putline.s on a
 * line by line basis, so don't bother sending
 * out the color shift.
 */
ttcolor(color) register int color; {
    if (color != tthue) {
	if (color == CTEXT) {		/* Normal video.	*/
	    putpad(SE, 1);
	} else if (color == CMODE) {	/* Reverse video.	*/
	    putpad(SO, 1);
	}
	tthue = color;			/* Save the color.	*/
    }
}

/*
 * This routine is called by the
 * "refresh the screen" command to try and resize
 * the display. The new size, which must be deadstopped
 * to not exceed the NROW and NCOL limits, it stored
 * back into "nrow" and "ncol". Display can always deal
 * with a screen NROW by NCOL. Look in "window.c" to
 * see how the caller deals with a change.
 */
ttresize() {
	setttysize();			/* found in "ttyio.c",	*/
					/* ask OS for tty size	*/
	if (nrow < 1)			/* Check limits.	*/
		nrow = 1;
	else if (nrow > NROW)
		nrow = NROW;
	if (ncol < 1)
		ncol = 1;
	else if (ncol > NCOL)
		ncol = NCOL;
}

#ifdef NO_RESIZE
static setttysize() {
	nrow = tgetnum("li");
	ncol = tgetnum("co");
}
#endif

static int cci;

/*ARGSUSED*/
static int		/* fake char output for charcost() */
fakec(c)
char c;
{
	cci++;
}

/* calculate the cost of doing string s */
charcost (s) char *s; {
    cci = 0;

    tputs(s, nrow, fakec);
    return cci;
}
SHAR_EOF
cat << \SHAR_EOF > sys/default/ttydef.h
/*
 *	Termcap terminal file, nothing special, just make it big
 *	enough for windowing systems.
 */

#define GOSLING			/* Compile in fancy display.	*/
/* #define	MEMMAP		*/	/* Not memory mapped video.	*/

#define NROW	66			/* (maximum) Rows.		*/
#define NCOL	132			/* (maximum) Columns.		*/
/* #define	MOVE_STANDOUT		/* don't move in standout mode	*/
#define STANDOUT_GLITCH			/* possible standout glitch	*/
#define TERMCAP				/* for possible use in ttyio.c	*/

#define getkbd()	(ttgetc())

#ifndef XKEYS
#define ttykeymapinit() {}
#endif

extern	int tputs();
#define	putpad(str, num)	tputs(str, num, ttputc)

#define	KFIRST	K00
#define	KLAST	K00
SHAR_EOF
cat << \SHAR_EOF > sys/default/ttykbd.c
/*
 * Name:	MG 2a
 *		Termcap keyboard driver using key files
 * Created:	22-Nov-1987 Mic Kaczmarczik (mic@emx.cc.utexas.edu)
 */

#include	"def.h"
#ifdef	XKEYS

/*
 * Get keyboard character.  Very simple if you use keymaps and keys files.
 * Bob was right -- the old XKEYS code is not the right solution.
 * FKEYS code is not usefull other than to help debug FKEYS code in
 * extend.c.
 */

#ifdef FKEYS
char	*keystrings[] = { NULL } ;
#endif

/*
 * Turn on function keys using KS, then load a keys file, if available.
 * The keys file is located in the same manner as the startup file is,
 * depending on what startupfile() does on your system.
 */
extern	int	ttputc();

ttykeymapinit()
{
	extern	char *KS;
#ifndef	NO_STARTUP
	char *cp, *startupfile();

	if (cp = gettermtype()) {
		if (((cp = startupfile(cp)) != NULL)
			&& (load(cp) != TRUE))
			ewprintf("Error reading key initialization file");
	}
#endif
	if (KS && *KS)			/* turn on keypad	*/
		putpad(KS, 1);
}

/*
 * Clean up the keyboard -- called by tttidy()
 */
ttykeymaptidy()
{
	extern	char *KE;

	if (KE && *KE)
		putpad(KE, 1);	/* turn off keypad		*/
}

#endif
SHAR_EOF
cat << \SHAR_EOF > sys/default/varargs.h
/* varargs.h for MicroGnuEmacs 2a.  This one will work on systems that	*/
/* the non-varargs version of mg 1 did.					*/
/* based on the one I wrote for os9/68k .  I did not look at the bsd code. */

/* by Robert A. Larson */

/* assumptions made about how arguments are passed:			*/
/*	arguments are stored in a block of memory with no padding between. */
/*	The first argument will have the lowest address			*/

/* varargs is a "portable" way to write a routine that takes a variable */
/* number of arguements.  This implemination agrees with both the 4.2bsd*/
/* and Sys V documentation of varargs.  Note that just because varargs.h*/
/* is used does not mean that it is used properly.			*/

#define va_dcl		unsigned va_alist;

typedef	char *va_list;

#define	va_start(pvar)		((pvar) = (char *)&va_alist)

#define va_arg(pvar,type)	(((pvar)+=sizeof(type)),*(((type *)(pvar)) - 1))

#define va_end(pvar)		/* va_end is simple */
SHAR_EOF
cat << \SHAR_EOF > sys/prime/cinfo.c
/*
 *		Character class tables.
 * Do it yourself character classification
 * macros, that understand the multinational character set,
 * and let me ask some questions the standard macros (in
 * ctype.h) don't let you ask.
 *
 * primos specific version
 */
#include	"def.h"

/*
 * This table, indexed by a character drawn
 * from the 256 member character set, is used by my
 * own character type macros to answer questions about the
 * type of a character. It handles the full multinational
 * character set, and lets me ask some questions that the
 * standard "ctype" macros cannot ask.
 */
char	cinfo[256] = {
	_C,		_C,		_C,		_C,	/* 0x0X */
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,	/* 0x1X */
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	0,		_P,		0,		0,	/* 0x2X */
	_W,		_W,		0,		_W,
	0,		0,		0,		0,
	0,		0,		_P,		0,
	_D|_W,		_D|_W,		_D|_W,		_D|_W,	/* 0x3X */
	_D|_W,		_D|_W,		_D|_W,		_D|_W,
	_D|_W,		_D|_W,		0,		0,
	0,		0,		0,		_P,
	0,		_U|_W,		_U|_W,		_U|_W,	/* 0x4X */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,	/* 0x5X */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		0,
	0,		0,		0,		0,
	0,		_L|_W,		_L|_W,		_L|_W,	/* 0x6X */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,	/* 0x7X */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		0,
	0,		0,		0,		_C,
	_C,		_C,		_C,		_C,	/* 0x8X */
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,	/* 0x9X */
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	0,		_P,		0,		0,	/* 0xAX */
	_W,		_W,		0,		_W,
	0,		0,		0,		0,
	0,		0,		_P,		0,
	_D|_W,		_D|_W,		_D|_W,		_D|_W,	/* 0xbX */
	_D|_W,		_D|_W,		_D|_W,		_D|_W,
	_D|_W,		_D|_W,		0,		0,
	0,		0,		0,		_P,
	0,		_U|_W,		_U|_W,		_U|_W,	/* 0xCX */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,	/* 0xDX */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		0,
	0,		0,		0,		0,
	0,		_L|_W,		_L|_W,		_L|_W,	/* 0xEX */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,	/* 0xFX */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		0,
	0,		0,		0,		_C,
};

/*
 * Find the name of a keystroke.  Needs to be changed to handle 8-bit printing
 * characters and function keys better.	 Returns a pointer to the terminating
 * '\0'.
 */

char *keyname(cp, k)
register char *cp;
register int k;
{
    register char *np;
#ifdef	FKEYS
    extern char *keystrings[];
#endif

    if(k < 0) k = CHARMASK(k);			/* sign extended char */
    switch(k) {
	case CCHR('@'): np = "NUL"; break;
	case CCHR('I'): np = "TAB"; break;
	case CCHR('J'): np = "LFD"; break; /* yuck, but that's what GNU calls it */
	case CCHR('M'): np = "RET"; break;
	case CCHR('['): np = "ESC"; break;
	case ' ':	np = "SPC"; break; /* yuck again */
	case CCHR('?'): np = "DEL"; break;
	default:
#ifdef	FKEYS
	    if(k >= KFIRST && k <= KLAST &&
		    (np = keystrings[k - KFIRST]) != NULL)
		break;
#endif
	    if(k < CCHR('@')) {
		*cp++ = '0';
		*cp++ = ((k>>6)&7) + '0';
		*cp++ = ((k>>3)&7) + '0';
		*cp++ = (k&7) + '0';
		*cp = '\0';
		return cp;
	    }
	    if(k < ' ') {
		*cp++ = 'C';
		*cp++ = '-';
		k = CCHR(k);
		if(ISUPPER(k)) k = TOLOWER(k);
	    }
	    *cp++ = k;
	    *cp = '\0';
	    return cp;
    }
    (VOID) strcpy(cp, np);
    return cp + strlen(cp);
}
SHAR_EOF
cat << \SHAR_EOF > sys/prime/fileio.c
/*
 * Prime fileio.c for MicroGnuEmacs by Robert A. Larson
 *	system dependent file io routines
 *
 * Prime keeps the parity bit of every character set, as does mg 2a for primos.
 */
#include <errd.ins.cc>
#include <keys.ins.cc>
#include "def.h"

static FILE    *ffp;
char *index(), *rindex();
fortran void cnam$$(), at$(), at$abs(), at$any(), at$hom(), clo$fu();
fortran void gpath$(), dir$se(), cv$fdv();
fortran long srsfx$();

/*
 * Open a file for reading.
 */
ffropen(fn)
char   *fn;
{
	if ((ffp=fopen(fn, "r")) == NULL)
		return (FIOFNF);
	return (FIOSUC);
}

/*
 * Open a file for writing.
 * Return TRUE if all is well, and
 * FALSE on error (cannot create).
 */
ffwopen(fn)
char	*fn;
{
	short unit, type, sfu, code;
	struct {short len; char data[128];} fnb;
	register char *cp = &fnb.data[0];
	struct {short len; char data[32];} basename;

	/* most of this is to get a SAM rather than DAM file ... */
	(void) strcpy(fnb.data, fn);
	fnb.len = strlen(fnb.data);
	(void) srsfx$((short)(k$writ+k$getu+k$nsam), fnb, unit, type,
	    (short)0, (short)0, basename, sfu, code);
#ifdef OPEN_BUG
	if(code==0) {
	    clo$fu(unit, code);
	    fnb.data[fnb.len] = '\0';
	    if((ffp=fopen(fnb.data, "w"))!=NULL) return FIOSUC;
	}
	ewprintf("Cannot open file for writing");
	return FIOERR;
#else
	if (code != 0 || (ffp=fdopen(open("", -2, unit), "w")) == NULL) {
		ewprintf("Cannot open file for writing");
		if(code==0) clo$fu(unit, code);
		return (FIOERR);
	}
	return (FIOSUC);
#endif
}

/*
 * Close a file.
 * Should look at the status.
 */
ffclose()
{
	fclose(ffp);
	return (FIOSUC);
}

/*
 * Write a buffer to the already
 * opened file. bp points to the
 * buffer. Return the status.
 * Check only at the newline and
 * end of buffer.
 */
ffputbuf(bp)
BUFFER *bp;
{
    register char *cp;
    register char *cpend;
    register LINE *lp;
    register LINE *lpend;

    lpend = bp->b_linep;
    lp = lforw(lpend);
    do {
	cp = &ltext(lp)[0];		/* begining of line	*/
	cpend = &cp[llength(lp)];	/* end of line		*/
	while(cp != cpend) {
	    putc(*cp, ffp);
	    cp++;	/* putc may evalualte arguments more than once */
	}
	lp = lforw(lp);
	if(lp == lpend) break;		/* no implied newline on last line */
	putc('\n', ffp);
    } while(!ferror(ffp));
    if(ferror(ffp)) {
	ewprintf("Write I/O error");
	return FIOERR;
    }
    return FIOSUC;
}

/*
 * Read a line from a file, and store the bytes
 * in the supplied buffer. Stop on end of file or end of
 * line.  When FIOEOF is returned, there is a valid line
 * of data without the normally implied \n.
 */
ffgetline(buf, nbuf, nbytes)
register char	*buf;
register int	nbuf;
register int	*nbytes;
{
	register int	c;
	register int	i;

	i = 0;
	while((c = getc(ffp))!=EOF && c!='\n') {
		buf[i++] = c;
		if (i >= nbuf) return FIOLONG;
	}
	if (c == EOF  && ferror(ffp) != FALSE) {
		ewprintf("File read error");
		return FIOERR;
	}
	*nbytes = i;
	return c==EOF ? FIOEOF : FIOSUC;
}

#ifndef NO_BACKUP
/*
 * Rename the file "fname" into a backup copy.
 */
fbackupfile(fname)
char   *fname;
{
    struct {short len; char data[128];} back;
    struct {short len; char data[32];} ent;
    register char *cp;
    short code = 0, i;

    strcpy(back.data, fname);
    strcat(back.data, ".BAK");
    (void) delete(back.data);
    if((cp = rindex(back.data, '>'))!=NULL) {
	if(back.data[0]==('<') && index(back.data, '>')==cp) {
	    strncpy(ent.data, back.data+1, ent.len = (cp - back.data) - 1);
	    at$abs((short)k$setc, ent, (short)0, code);
	} else {
	    back.len = (cp - back.data);
	    if(index(back.data, '>') == cp)
		 at$any((short)k$setc, back, code);
	    else at$((short)k$setc, back, code);
	}
	if(code) return FALSE;
	cp++;
	/* cnam$$ needs word aligned strings */
	strncpy(ent.data, cp, back.len = strlen(cp));
	cp = ent.data;
    } else back.len = strlen(cp = back.data);
    cnam$$((char [])cp, (short)(back.len - 4), (char [])cp, back.len, code);
    at$hom(i);
    return code == 0;
}
#endif

/*
 * The string "fn" is a file name.  Prepend the directory name if
 * it's relative to the current directory.
 */
#ifndef NO_DIR
extern char *wdir;
#endif

char *adjustname(fn)
register char  *fn;
{
    static char fnb[NFILEN];
    register char *cp = fnb;
    register char *cp2;

#ifndef NO_DIR
    if((fn[0] == '*' && fn[1] == '>') || index(fn, '>')==NULL) {
	cp2 = wdir;
	while(*cp2) {
	    *cp = *cp2;
	    cp++;
	    cp2++;
	}
	*cp++ = '>';
	if(fn[1]=='>') fn+=2;
    }
#endif
    while(*fn) {
	*cp = ISUPPER(*fn) ? TOLOWER(*fn) : *fn;
	cp++;
	fn++;
    }
    *cp = '\0';
    return fnb;
}

#ifndef NO_STARTUP
char *startupfile(suffix)
char *suffix;
{
	short code, len;
	static char startname[128];
	register char *cp;

	gpath$((short)k$inia, (short)-3, (char [])startname,
	      (short)(128 - 5), len, code);
	if (code==0) {
	    strcpy(startname + len, ">.MG");
	    if(suffix) {
		startname[len+4] = '.';
		strcpy(startname + len + 5, suffix);
	    }
	    if(access(startname, 4)==0)
		return startname;
	}
	strcpy(startname, "MG*>.MG");
	if(suffix) {
	    startname[7] = '.';
	    strcpy(startname+8, suffix);
	}
	if(access(startname, 4)==0)
	    return startname;
	return (char *)NULL;
}
#endif

/* compare file names */
fncmp(fn1, fn2)
register char *fn1, *fn2;
{
    /* ignore disk name if on one but not the other */
    if(*fn1 != *fn2) {
	if(*fn1 == '<') {
	    fn1 = index(fn1, '>');
	    if(fn1 == NULL) return -1;
	    fn1++;
	} else if(*fn2 == '<') {
	    fn2 = index(fn2, '>');
	    if(fn2 == NULL) return -1;
	    fn2++;
	} else return -1;
    } else fn1++, fn2++;
    /* compare ignoring case */
    while(*fn1) {
	if((*fn1 != *fn2) && (!ISUPPER(*fn1) || (TOLOWER(*fn1) == *fn2))
			  && (!ISUPPER(*fn2) || (TOLOWER(*fn2) == *fn1)))
	    return -1;
	fn1++;
	fn2++;
    }
    return *fn2;
}

#ifndef NO_DIRED
#include "kbd.h"

BUFFER *dired_(dirname)
char *dirname;
{
    register BUFFER *bp;
    LINE *lp, *blp;
    BUFFER *findbuffer();
    short dirunit, j, code, type, init, counts[4], i, nent;
    struct {short len; char dat[128];} dir;
    struct ent {short len; char dat[32];} base;
    static struct ent wild[1] = {{2, {'@','@'}}};
    static struct {
	short vers;
	struct ent *wp;
	short count;
	struct {unsigned dirs:1, seg_dirs:1, files:1, acats:1, rbf:1, spare:11;} desired;
	long mb, ma, bb, ba, cb, ca, ab, aa;
    } sel = {
	1,
	&wild[0],
	1,
	{1, 1, 1, 0, 0, 0},
	0, 0, 0, 0, 0, 0, 0, 0,
    }, *s = &sel;
#define MAXSE 16
    struct {
	struct {unsigned type:8, length:8;} ecw;
	struct ent name;
	struct {unsigned spare:5, odel:1, owrite:1, oread:1, delp:1,
	    spare2:4, nodel:1, nowrite:1, noread:1;} prot;
	struct {unsigned lrat:1, dumped:1, dos:1, spec:1, rwl: 2,
	    spare:2, type:8;} info;
	long dtm;
	short nondefault, logical_type, trunc;
	long dtb, dtc, dta;
    } ret[MAXSE], *r = &ret[0];
    static char *types[] = {"SAM", "DAM", "SEGSAM", "SEGDAM", "UFD",
	"ACAT", "CAM"};
    static char *rwlock[] = {"sys", "excl", "updt", "none"};

    if((dirname = adjustname(dirname)) == NULL) {
	ewprintf("Bad directory name");
	return NULL;
    }
    (void) strncpy(dir.dat, dirname, dir.len = strlen(dirname));
    if(dir.dat[dir.len-1]=='>') dir.len--;
    else strcat(dirname, ">");
    if((bp = findbuffer(dirname)) == NULL) {
	ewprintf("Could not create directory buffer");
	return NULL;
    }
    if(bclear(bp) != TRUE) return NULL;
    (void) srsfx$((short)(k$read+k$getu), dir, dirunit, type,
	(short)0, (short)0, base, j, code);
    if(code!=0) {
	ewprintf("Could not open directory '%s'", dirname);
	return NULL;
    }
    if(type<2 || type > 4) {
	clo$fu(dirunit, code);
	ewprintf("Not a directory '%s'", dirname);
	return NULL;
    }
    for(init = 0x8000; ; init = 0) {
	dir$se(dirunit, type, init, s, r, (short)MAXSE,
	    (short)((sizeof ret[0])/2), nent, (short [])counts, (short)4, code);
	if(code!=0 && (code!=e$eof || nent==0)) break;
	for(i=0; i < nent; i++) {
	    cv$fdv(ret[i].dtm, j, base);
	    for(j=0; j<ret[i].name.len; j++)
		if(ISUPPER(ret[i].name.dat[j]))
		    ret[i].name.dat[j] = TOLOWER(ret[i].name.dat[j]);
#define D_FILEPOS 36
	    if((lp = lalloc(D_FILEPOS + 1 + ret[i].name.len)) != NULL) {
		sprintf(lp->l_text, "  %-6s  %-4s  %.18s  %.*s",
		    types[ret[i].info.type], rwlock[ret[i].info.rwl],
		    base.dat, ret[i].name.len, ret[i].name.dat);
		llength(lp)--;
		for(blp=bp->b_linep->l_fp; blp!=bp->b_linep; blp=blp->l_fp) {
		    j = strncmp(ret[i].name.dat, &blp->l_text[D_FILEPOS],
			ret[i].name.len);
		    if(j < 0 || (j==0 && ret[i].name.len <=
			llength(blp)-D_FILEPOS)) break;
		}
		lp->l_fp = blp;
		lp->l_bp = blp->l_bp;
		blp->l_bp = lp;
		lp->l_bp->l_fp = lp;
	    } else {
		clo$fu(dirunit, code);
		return NULL;
	    }
	}
    }
    if(code!=e$eof) ewprintf("Directory read error %d", code);
    clo$fu(dirunit, code);
    bp->b_dotp = lforw(bp->b_linep);
    bp->b_doto = 0;
    bp->b_markp = NULL;
    strncpy(bp->b_fname, dirname, NFILEN);
    if((bp->b_modes[0] = name_mode("dired")) == NULL) {
	bp->b_modes[0] = &map_table[0];
	ewprintf("Could not find mode dired");
	return NULL;
    }
    bp->b_nmodes = 0;
    return bp;
}

d_makename(lp, fn)
register LINE *lp;
register char *fn;
{
    register char *cp;

    if(llength(lp) <= D_FILEPOS) return ABORT;
    (VOID) strcpy(fn, curbp->b_fname);
    cp = fn + strlen(fn);
    bcopy(&lp->l_text[D_FILEPOS], cp, llength(lp) - D_FILEPOS);
    cp[llength(lp) - D_FILEPOS] = '\0';
    return strncmp(&lp->l_text[2], "UFD", 3)==0 ||
	strncmp(&lp->l_text[2], "SEG", 3)==0;
}

rename(old, new)
char *old, *new;
{
    struct {short len; char dat[128];} f;
    struct {short len; char dat[32];} oldent;
    char *cp;
    short code;

    old = adjustname(old);
    cp = rindex(old, '>');
    strncpy(f.dat, old, f.len = cp - old);
    at$((short)k$setc, f, code);
    if(code!=0) return -1;
    cp++;
    strncpy(oldent.dat, cp, oldent.len = strlen(cp));
    strncpy(f.dat, new, f.len = strlen(new));
    cnam$$((char [])oldent.dat, oldent.len, (char [])f.dat, f.len, code);
    if(code!=0) {
	at$hom(code);
	return -1;
    }
    at$hom(code);
    return 0;
}
#endif

#ifndef NO_DIR
char *getwd(cwd)
char *cwd;
{
    char homedir[128];	     /* cwd may not be word alligned */
    short len, code;
    register char *cp1, *cp2;

    gpath$((short)k$homa, (short)-2, (char [])homedir, (short)128, len, code);
    if(code!=0) return NULL;
    cp1 = cwd;
    cp2 = homedir;
    while(len--) {
	*cp1 = ISUPPER(*cp2) ? TOLOWER(*cp2) : *cp2;
	cp1++;
	cp2++;
    }
    *cp1 = '\0';
    return cwd;
}
#endif
SHAR_EOF
cat << \SHAR_EOF > sys/prime/make.cpl
/* make for micrognuemacs on primos
/* by Robert A. Larson
&args como:-como; ph:-ph; v64v: -64v;
&if ^ [null %como%] &then como make.como
&if ^ [null %ph%] &then &do
  chap idle
&end
&do f &list *>sys>prime>sysdef.h *>sys>default>ttydef.h *>sys>default>chrdef.h
  &if ^ [exists [entryname %f%]] &then copy %f% -rpt
  &else &if [attrib [entryname %f%] -dtm] < [attrib %f% -dtm] ~
    &then copy %f% -nq -rpt
&end
&set_var w := [attrib def.h -dtm]
&if %w% < [attrib sysdef.h -dtm] &then &set_var w := [attrib sysdef.h -dtm]
&if %w% < [attrib ttydef.h -dtm] &then &set_var w := [attrib ttydef.h -dtm]
&if %w% < [attrib chrdef.h -dtm] &then &set_var w := [attrib chrdef.h -dtm]
&if [null %v64v%] &then &do
  &if %w% < [attrib *>sys>prime>mg.options.c -dtm] ~
    &then &set_var w := [attrib *>sys>prime>mg.options.c -dtm]
  &set_var binext := .bin
&end
&else &do
  &if %w% < [attrib *>sys>prime>mg.64v.options.c -dtm] ~
    &then &set_var w := [attrib *>sys>prime>mg.64v.options.c -dtm]
  &set_var binext := .64v.bin
  &set_var m := ^ [exists stackptr$.64v.bin]
  &if ^ %m% &then &do
    &set_var bw := [attrib stackptr$.64v.bin -dtm]
    &set_var m := [attrib *>sys>prime>stackptr$.pma -dtm] > %bw% | %w% > %bw%
  &end
  &if %m% &then pma *>sys>prime>stackptr$.pma -list no -bin stackptr$.64v.bin
&end
&s dir := *
&do f &list basic.c buffer.c dir.c dired.c display.c echo.c extend.c file.c ~
    help.c kbd.c keymap.c line.c macro.c main.c match.c modes.c paragraph.c ~
    random.c region.c search.c version.c window.c word.c
  &call compile
&end
&s dir := *>sys>prime
&do f &list cinfo.c fileio.c spawn.c ttyio.c
  &call compile
&end
&s dir := *>sys>default
&do f &list tty.c
  &call compile
&end
&s dir := *>termlib
&do f &list fgetlr.c tgetent.c tgetflag.c tgetnum.c tgetstr.c tgoto.c tputs.c
  &call compile
&end
date
time
&set_var u := 0
&data bind
  version mg 2a
  no_wildcard
  no_iteration
  li ccmain
  &do f &items [wild @%binext% -single u]
    lo %f%
  &end
  li c_lib
  li
  dynt -all
  rdc
  &if [null %v64v%] &then &do
    map mg.map
    file mg.run
  &end
  &else &do
    map mg.64v.map
    file mg.64v.run
  &end
&end
date
time
&if ^ [null %como%] &then como -end
&return

&routine compile
      &set_var b := [before %f% '.']%binext%
      &set_var f := %dir%>%f%
      &set_var m := ^ [exists %b%]
      &if ^ %m% &then &do             /* avoid attrib on non-existant file
        &set_var bw := [attrib %b% -dtm]
        &set_var m := [attrib %f% -dtm] > %bw% | %w% > %bw%
      &end
      &if %m% &then &do
        type %f%
        date
        &if [null %v64v%] &then &do
          ci %f% -optionsfile *>sys>prime>mg.options.c -bin %b%
        &end
        &else &do
          cc %f% -optionsfile *>sys>prime>mg.64v.options.c -bin %b%
        &end
      &end
&return


SHAR_EOF
cat << \SHAR_EOF > sys/prime/mg.64v.options.c
/* options for Primos Mg by Robert A. Larson

/* 64v mode version
-64v
-newfortran
/* define to indicate primos
-define __50SERIES
/* get routine names in stack dump
-store_owner_field
/* tell it to run fast
-standardintrinsics
-optimize
/* find varargs.h in *>sys>prime
-include *>sys>prime

/* real options
-define NO_DIRED                /* no 64v mode support in dired code
-define PREFIXREGION
-define NOTAB
SHAR_EOF
cat << \SHAR_EOF > sys/prime/mg.options.c
/* options for Prime MicroGnuEmacs by Robert A. Larson

-32ix
/* get routine names in stack dump
-store_owner_field
/* tell it to run fast
-standardintrinsics
-optimize 1
/* -pbstring was broken, and either got fixed or the other changes...
-pbstring
/* find varargs.h in *>sys>prime
-include *>sys>prime

/* real options
-define PREFIXREGION
-define NOTAB

SHAR_EOF
cat << \SHAR_EOF > sys/prime/readme

MicroGnuEmacs 2a for primos

This version has only been tested under primos 21.0 (.0, .1, .2s) in
32ix mode.  The dired code does not run in 64v mode.  (pl1 type ptr
options(short) is a pain to simulate in 64v mode C.)  The pre-rev 21
code should work, but ^p, ^j, and a true meta key will be unusable.

One major problem has been descovered: mg will always fail if it is
already in memory.  (access violations, illegal segno, etc.) This is a
bug that has been reported to prime.  I recomend aliasing mg to remepf
mg;mg .  (Further oddity: sometime remepf gets access violations!) To
get your line back to a normal mode after this has happended, set your
terminal's parity to mark and type "set_async -pro tty -echo -xoff"
followed by a linefeed.

Some pre-21 verisons of the C library had a bug in open(), there is
code that can be included with a #define in fileio.c to avoid this
problem.  The -pbstring option is broken in some Prime C compiler
versions, if you notice strange problems try recompiling with
-lbstring.

The rev 21 version will not run over primenet since the terminal line
cannot be conditioned properly.

Support for Prime's extended character set rather than a meta key
should not be hard to add.  (chrdef.h, cinfo.c, and ttyio.c are what
would need changes.)

Installation:
  copy *>sys>prime>make.cpl
  ph make -ph -como             [add -64v if 64v mode is needed.]
When phantom is finished:
  copy mg.run cmdnc0>==         [32ix mode]
or
  copy mg.64v.run cmdnc0>=.run  [64v mode]

Global variable .termcap (or .termcap$) should be set to the pathname
of the termcap file if the default of mg*>termcap is inappropraite,
and .terminal_type$ (or .term) should be set to your terminal type.
(Global variables are manipulated with the primos commands
define_gvar, set_var, and list_var.) The C library must be in your
search rules.  Your .mg initalization file should be located in your
inital attach point, if you don't have one the one in mg* will be used
if available.  (Terminal specific files may also be used.) Prime
emacs's termcap file does not work well with mg.

On pre-rev 21 systems, due to primos limitations, neither ^P or ^J are
usable input, and true meta keys are not supported.  If ^P is
accidentaly typed and you have break enabled, mg may be resumed with
the start command (and the screen should be refreshed with the
recenter command ^L).

Primos programs other than mg and the C compiler do not understand tab
characters, so use of notab mode is recomended.

The options to make.cpl are:

    -ph         chap -idle
    -como       create como file make.como
    -64v        create 64v rather than 32ix mode version

Compilation options are in the files mg.options.c and
mg.64v.options.c.

Warnings to potential modifiers:

        The source to mg contains tab characters.  These should be
converted to spaces before printing or editing with an editor that
does not cope with tabs.

	Make.cpl does not have all dependencies, if one of the new .h
files is changed, delete all applicable .bin files.
SHAR_EOF
cat << \SHAR_EOF > sys/prime/spawn.c
/*
 * prime spawn.c for micrognuemacs
 */
#include       "def.h"

spawncli(f, n)
{
       fortran void comlv$();
       ttcolor(CTEXT);
       ttnowindow();
       ttmove(nrow-1, 0);
       if (epresf != FALSE) {
	       tteeol();
	       epresf = FALSE;
       }
       ttclose();
       comlv$();
       sgarbf = TRUE;		/* Force repaint.	*/
       ttopen();
#ifndef NO_DIR
       (void) dirinit();	/* current directory may have changed */
#endif
       return (TRUE);
}
SHAR_EOF
cat << \SHAR_EOF > sys/prime/stackptr$.pma
*        stackptr$.pma  -- used by 64v varargs.h.ins.cc
* 02/22/87 Robert Larson  Name chagned to avoid potention conflict

         SEG
         SYML
         RLIT
         ENT       STACKPTR$

START    EAXB      SB%+4,*
         PRTN

         LINK
STACKPTR$ ECB      START
         END
SHAR_EOF
cat << \SHAR_EOF > sys/prime/sysdef.h
/*
 * Prime specific definitions for MicroGnuEmacs 2a
 */
#include <stdio.h>

#define	       PCC		       /* "[]" gets an error.		      */
#define	       KBLOCK  1024	       /* Kill grow.			      */
#define	       GOOD    0	       /* Good exit status.		      */
#define	       NO_RESIZE	       /* screen size is constant	      */
#define	       MAXPATH 256

/* typedefs for gnu version */
typedef int    RSIZE;	       /* Type for file/region sizes   */
typedef short  KCHAR;	       /* Type for internal keystrokes */

/*
 * Macros used by the buffer name making code.
 * Start at the end of the file name, scan to the left
 * until BDC1 (or BDC2, if defined) is reached. The buffer
 * name starts just to the right of that location, and
 * stops at end of string (or at the next BDC3 character,
 * if defined). BDC2 and BDC3 are mainly for VMS.
 */
#define	       BDC1    '>'

#define bcopy(from,to,len)	  if(1) {\
    register char *from_=from, *to_=to; register int len_=len;\
    while(len_--) *to_++ = *from_++;} else

#define MALLOCROUND(m) (m+=7, m&=~7)   /* round to 8 byte boundary */

char *gettermtype();	/* #define fails because of static storage */

#define unlink(f)    delete(f)
#define unlinkdir(f) delete(f)

#ifdef DO_METAKEY
#define METABIT 0400
#endif
SHAR_EOF
cat << \SHAR_EOF > sys/prime/ttyio.c
/*
 *     sys>prime>ttyio.c by Robert A. Larson
 *
 * The functions in this file
 * negotiate with the operating system for
 * keyboard characters, and write characters to
 * the display in a barely buffered fashion.
 */
#include       "def.h"

#define	       NOBUF   512	       /* Output buffer size.	       */

char   obuf[NOBUF];		       /* Output buffer.	       */
short  nobuf;			       /* characters in obuf	       */
int    nrow;			       /* Terminal size, rows.	       */
int    ncol;			       /* Terminal size, columns.      */
short  ospeed;			       /* Terminal speed, for termlib.l */

#ifndef PRE21
/* use undocumented calls to set terminal modes */
#define NSETTINGS 6
fortran void as$lin(), as$get(), as$set();
static short myline = 0;
static short reset[NSETTINGS][2];
#else
/* do the best we can without undocumented calls */
fortran short duplx$();
fortran void break$();
short duplx;
#endif

/*
 * This function gets called once, to set up
 * the terminal channel.
 */

ttopen()
{
#ifndef PRE21
    short code, vers, len, bad;
    static short settings[NSETTINGS][2] = {
	{1, 0},			       /* no echo */
	{2, 0},			       /* don't echo line feed for cr */
	{3, 0},			       /* disable ^S/^Q processing */
	{11, 0},		       /* parity: none */
	{12, 3},		       /* character length: 8 */
	{15, 1},		       /* tran protocol */
    };
    short plist[38][2];
    short *p;
    register int i;

    if(myline==0) {
	as$lin(myline, code);
	if(code!=0) panic("Can't get terminal line");
	/* do io to get terminal type before setting modes */
	(void) gettermtype();
    }
    p = &plist[0][0];
    as$get(myline, vers, p, len, code);
    if(code!=0) panic("Can't determine current settings");
    ospeed = plist[9-1][1];
    for(i=0; i < NSETTINGS; i++) {
	reset[i][0] = settings[i][0];
	reset[i][1] = plist[settings[i][0]-1][1];
    }
    p = &settings[0][0];
    as$set(myline, (short)0, p, (short)NSETTINGS, code, bad);
    if(code!=0) panic("Can't set terminal modes");
#else
    (void) gettermtype();
    duplx = duplx$((short)-1);
    (void) duplx$((unsigned short)0140000);
    ospeed = 4; /* assume 9600 for debugging */
#endif
    nobuf = 0;
}

/*
 * This function gets called just
 * before we go back home to the shell. Put all of
 * the terminal parameters back.
 */
ttclose()
{
#ifndef PRE21
    short code, bad;
    short *p;
#endif

    ttflush();
#ifndef PRE21
    p = &reset[0][0];
    as$set(myline, (short)0, p, (short)NSETTINGS, code, bad);
    if(code!=0) {
	printf("Can't reset terminal modes: code: %d bad: %d\n",
	    code, bad);
	exit(1);
    }
#else
    (void) duplx$(duplx);
#endif
}

/*
 * Write character to the display.
 * Characters are buffered up, to make things
 * a little bit more efficient.
 */
ttputc(c)
{
       if (nobuf >= NOBUF)
	       ttflush();
       obuf[nobuf++] = c;
}

/*
 * Flush output.
 */
ttflush()
{
       fortran void tnoua();

       if (nobuf != 0) {
	       tnoua((char [])obuf, nobuf);
	       nobuf = 0;
       }
}

/*
 * Read character from terminal.
 * Parity bit is stripped, to be normal
 */
ttgetc()
{
    fortran void t1in();
    short c;

    t1in(c);
#ifdef DO_METAKEY
    if(c&0200) c |= METABIT;
#endif
    c |= 0200;
#ifdef PRE21
    if(c=='\n') return '\r';	   /* fix repping done by primos */
#ifdef DO_METAKEY
    if(c==('\n'|METABIT)) return '\r'|METABIT;
#endif
#endif
    return c;
}

int typeahead()
{
    fortran short tty$in();

    return tty$in() < 0;
}

panic(s) char *s; {
  fortran void tnoua(), tnou();

  ttclose();
  tnoua((char [])"Panic: ", (short)7);
  tnou((char [])s, (short)strlen(s));
  exit(1);
}

#ifndef NO_DPROMPT
ttwait() {
  register short i = 20;
  fortran short tty$in();
  fortran void sleep$();

  while(i--) {
    if(tty$in()<0) return FALSE;
    sleep$((long)100);
  }
  return tty$in() >= 0;
}
#endif

char *gettermtype()
{
    register char *cp;
    char *gvget();
    static char termtype[64] = "";

    if(termtype[0]!='\0') return termtype;
    cp = gvget(".TERMINAL_TYPE$");     /* get terminal type */
    if(cp==NULL) cp = gvget(".TERM");
    if(cp != NULL) {
	strncpy(termtype, cp, 64);
	return termtype;
    }
    fputs("Terminal type? ", stdout);
    fgets(termtype, 64, stdin);
    putchar('\n');
    termtype[strlen(termtype)-1] = '\0';	/* chop off \n */
    return termtype;
}
SHAR_EOF
cat << \SHAR_EOF > sys/prime/varargs.h.ins.cc
/* varargs.h.ins.cc  -- varargs for both 32ix and 64v mode C unser primos */
/* 02/22/87 Robert Larson  Cleanup  (Variable name changes to avoid conflicts) */

#ifdef __CI
/* varargs.h for 32ix mode on a Prime 9955 */
/* Modified from the Primix varargs.h by James M Synge. */
typedef char *va_list;

#define va_alist       _va_arg1
#define va_dcl	       char va_alist;
#define va_start(list) list = ((va_list)(&_va_arg1))
#define va_end(list)

#define va_arg(list,mode)	((mode *)((list) += sizeof(mode)))[-1]

#else

typedef int **va_list;
extern short *stackptr$();

#define va_alist \
	/* first argument at SB%+45 */ \
	_v0,_v1,_v2,_v3,_v4,_v5,_v6,_v7,_v8,_v9,_v10, \
	_v11,_v12,_v13,_v14,_v15,_v16,_v17,_v18,_v19,_v20, \
	_v21,_v22,_v23,_v24,_v25,_v26,_v27,_v28,_v29,_v30, \
	_v31,_v32,_v33,_v34,_v35,_v36,_v37,_v38,_v39,_v40, \
	_v41,_v42,_v43,_v44,_v45,_v46,_v47,_v48,_v49,_v50, \
	_v51,_v52,_v53,_v54,_v55,_v56,_v57,_v58,_v59,_v60, \
	_v61,_v62,_v63,_v64,_v65,_v66,_v67,_v68,_v69

#define va_dcl int *_v0;
#define va_start(list) list = ((va_list)(stackptr$() + 042))
#define va_end(list)
#define va_arg(list, mode) ( (sizeof(mode) == sizeof(char *)) ? \
			     ((**(mode **)((list)++)))	: \
			     ((mode) (**((list)++))) )
#endif
SHAR_EOF
#	End of shell archive
exit 0
-------