V9/cmd/emacs/emacs_vt.c

#include <stdio.h>
#ifdef ux3
#include <termio.h>
#else
#include <sgtty.h>
#endif
/* EMACS_MODES: c !fill */
char *getenv();
/* macro definitions */

#define EOL '\n'

char *UP;					/* cursor up line */
char *DOWN;
char *BACK;
char *FORWARD;
char *HOME;
char *CLEAR;
char *CLREST;
char *CLINE;
char *BELL;
char *CURAD;
char *TMAP;
char *SMAP;
char *NOP;
char *LOPEN;
char *LDEL;
char *INSERTC;
char *INSERTM;
char *OSERTC;
char *INSERTP;
char *DELC;
char *SSCROLL;
char *RSCROLL;
char *CR;
char *SCREG;
char *ULINE;
char *UEND;
int EOVER;
char *SCINIT;
char *VEXIT;
char *RELDOWN;
char *RELUP;
char *RELFORW;
char *RELBACK;
int XBASE;
int YBASE;
int SCRWID;
int SCRNLIN;
int SCRWRAP;
int VCOST;
int SRCADD;
int MI;
int IN;
int DELMODE;

/* character definitions */

#define META 0200
#define MTA(mtach) ('mtach'+0200)	/* make meta char */
#define ESC 033
#define NEWLINE 037
#define RUB 0177

/* DISPLAY MODE PARAMETERS */

int WRAPON = 0;				/* perform ! processing at EOL */
int INSON = 0;				/* use INSERTC/DELC */

/* screen display data */

char ttobuf[BUFSIZ];

int drain;
int mline;
int mcol;
int SCRLINES;				/*  number of lines in window */
int ECHOL;				/* line for prompting */
int MODLN;				/* line for buffer and file data */



/* statistics */

long nmput;				/* calls to mputc */
long noutc;				/* actual characters output */
int ninch;				/* number of characters input */
int ntwrite;				/* number of terminal writes */
int nbwrite;				/* number of buffer writes */
int nbseek;				/* number of seeks of buffer */
int nbread;				/* number of buffer reads */
int nmkline;				/* number of makeline calls */

extern int errno;

/* function definitions */

char *getname();
/*VARARGS*/ char *execl();

/* lint definitions */

#ifdef lint
#define IGNORE(x) if(x);
#else
#define IGNORE(x) (x)
#endif

/* emacs display definitions */


/* EMACS_MODES: c !fill */

char ldchar;				/* last clobbered character */
char ldcol;				/* collumn of ldchar */
char osert = 0;				/* flag indicating insert char mode */
int acost;				/* cost of absolute positioning */
int lUP;				/* cost of UP */
int lDOWN;				/* cost of DOWN */
int lBAK;				/* cost of BACK */
int lCR;

int psx;
int psy;
int saveline;
int savecol;
int scrlin;
int scrcol;
int ttywarp;				/* tty warp factor (stty speed) */

/* display data */

#define TTYLEN 256			/* total area for tty data strings */
char ttystrings[TTYLEN];


struct sparm {
	char *t_pname;
	int *t_padd;
};

struct sparm ttydata[] = {
	"up",(int *) &UP,
	"do",(int *) &DOWN,
	"bc",(int *) &BACK,
	"nd",(int *) &FORWARD,
	"ho",(int *) &HOME,
	"cl",(int *) &CLEAR,
	"cd",(int *) &CLREST,
	"ce",(int *) &CLINE,
	"bl",(int *) &BELL,
	"cm",(int *) &CURAD,
	"tm",(int *) &TMAP,
	"tM",(int *) &SMAP,
	"pc",(int *) &NOP,
	"al",(int *) &LOPEN,
	"dl",(int *) &LDEL,
	"ic",(int *) &INSERTC,
	"im",(int *) &INSERTM,
	"ei",(int *) &OSERTC,
	"ip",(int *) &INSERTP,
	"dc",(int *) &DELC,
	"sf",(int *) &SSCROLL,
	"sr",(int *) &RSCROLL,
	"cr",(int *) &CR,
	"cs",(int *) &SCREG,
	"ul",(int *) &ULINE,
	"ue",(int *) &UEND,
	"eo",&EOVER,
	"vs",(int *) &SCINIT,
	"ve",(int *) &VEXIT,
	"bx",&XBASE,
	"by",&YBASE,
	"co",&SCRWID,
	"li",&SCRNLIN,
	"am",&SCRWRAP,
	"vc",(int *) &VCOST,
	"rc",(int *) &SRCADD,
	"mi",(int *) &MI,
	"in",(int *) &IN,
	"dm",&DELMODE,
	"ru",(int *) &RELUP,
	"rd",(int *) &RELDOWN,
	"rl",(int *) &RELFORW,
	"rr",(int *) &RELBACK,
	0,0,
};

char *endput = "____________________";



#define SCRCONT '!'
int TABSTOP = 8;

#define NSCRLIN 48			/* max screen lines */
#define NSCRCOL 128			/* max screen columns */
char cmap[NSCRLIN] [NSCRCOL];
int scrjnk[NSCRLIN];	/* column of last non-white character */



/* character type table */

#define PLAIN 0
#define CONTRL 1
#define TAB 2
#define BACKSP 3

char ctype[128] = {
	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,
	BACKSP,	TAB,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,
	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,
	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,	CONTRL,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,
	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	PLAIN,	CONTRL,
};


/* display heuristics */

#define CFILL 30			/* average chars/line */
#define PATIENCE 2000			/* number of millisecends of */
					/* output to buffer before */
					/* looking for type ahead */


/* display macros */

#define mputc(chr) (((mcol<scrjnk[mline]) && (chr == cmap[mline][mcol]))? mcol++ : mptc(chr))

/* trace stuff */


char *termdir = SDIR/terminals/%s";


/* Terminal I/O modes, sgttyb for before unix 3.0, termio for later */

int SREGION = 24;

#ifdef ux3
struct termio ttyjunk;
#else
struct sgttyb ttyjunk;
#endif

int ttyerase = '#';
int ttykill = '@';
int ttyintr = '';
int ttyeof = '';

#define NBAUD 16			/* number of baud rates */
char charms[NBAUD]  = {			/* ms per char in various rates */
	100,
	100,				/* 50 */
	100,				/* 75 */
	100,				/* 110 */
	70,				/* 134 */
	66,				/* 150 */
	50,				/* 200 */
	33,				/* 300 */
	16,				/* 600 */
	8,				/* 1200 */
	5,				/* 1800 */
	4,				/* 2400 */
	2,				/* 4800 */
	1,				/* 9600 */
	1,				/* EXTA */
	1,				/* EXTB */
};
	
xgo(x,y)

{
	ldchar = 0;
	mline = x;
	mcol = y;
}


/* beep -- obvious */

beep()

{
	PUTS(BELL);			/* print a bell */
}

/* move both the display matrix pointer and the actual display to the
 * specified line and column */

mgo(x,y)

register x,y;

{

	sgo(mline = x,mcol = y);
}


/* move the display cursor to the specified destination.  sgo attempts
 * to optimize the movement, using single character or absolute
 * positioning */

sgo(x,y)

register x,y;

{
	int mx,my;
	int xcost;						/* cost with all relative movement */
	int ycost;						/* cost with carriage return */
									/* acost is cost of absolute positioning */
	
/* calculate relative costs of various movements.  cost functions  */
/* automatically indicate that un-doable motions have infinite cost */
	

	
	
	/* calculate xcost and ycost */

	mx = x-scrlin;
	if (mx<0) {
		mx = -mx;
		xcost = mx*lUP;
	} else xcost = mx*lDOWN;

	ycost = y + xcost + lCR;
	
	my = y-scrcol;
	if (my<0) {
		my = -my;
		xcost +=my*lBAK;
	} else xcost += my;


	if (acost < ycost) {
		if (acost < xcost) {
									/* do absolute positioning */
			if (CURAD) {	/* have absolute addrs */
				if (SRCADD) {
					eprintf(CURAD,x+XBASE,y+YBASE);
				} else { 
					eprintf(CURAD,y+YBASE,x+XBASE);
				}
			} else {	/* have relative addrs */
				if (x>scrlin) printf (RELDOWN,mx);
				if (x<scrlin) printf (RELUP,mx);
				if (y>scrcol) printf (RELFORW,my);
				if (y<scrcol) printf (RELBACK,my);
			}
			scrlin=x;
			scrcol=y;
			return;
		}		/* else relative is cheap, do it */
	} else {
		if (osert && (MI == 0)) {
			unsert();
		}
		if (ycost < xcost) {	/* do carriage return processing */
			PUTS(CR);		/* carriage return */
			scrcol = 0;
						/* fall through to finish with relative motion */
		}
	}

	while (x != scrlin) {
		if (x < scrlin) {
			PUTS(UP);
			scrlin--;
		} else {
			PUTS(DOWN);
			scrlin++;
		}
	}

	/* now correct row */

	while (y != scrcol) {
		if (y < scrcol) {
			PUTS(BACK);
			scrcol--;
		} else {
			if (FORWARD == NULL)  {
				if (osert) {
					unsert();
				}
				x = cmap[scrlin] [scrcol];
				if ((x == 0)|| (scrjnk[scrlin]<=scrcol)) x=cmap[scrlin] [scrcol] = ' ';
				putit(x);	 /* re-write */
			} else {
				PUTS(FORWARD);
			}
			scrcol++;
		}
	};
	return;
}

/* unsert -- LEAVE insert character mode */

unsert()
{
	eprintf(OSERTC); /* can't stay inserting */
	osert = 0;
}

/* a simple guide to all of the various putc routines in this program: 
 * xputc puts a character out, translating control and meta characters
 * to prefix sequences, and calling sputc to put out the individual
 * characters.  sputc checks for end of line, and if so wraps to the
 * next line.  sputc calls mputc to output characters.  mputc updates
 * the next character in the display to be whaat is put out.  Display
 * takes place only if the character on the screen is not that called for
 * already. */


mptc(c)
register c;
{
	nmput++;			/* count for stats */
	if ((c == ' ') && (mcol >= scrjnk[mline])) {

		cmap[mline] [mcol++] = c;
		return;
	}
	if ((mcol != scrcol) || (mline != scrlin)) sgo(mline,mcol);
	if (DELC && INSON && (c == cmap [mline] [mcol+1]) && (mcol+3 <scrjnk[mline]) && (ldchar == 0)) {
		register i;
		SREGION=scrjnk[mline]-mcol; /* number of char's gobbled */
		if (DELMODE && (osert == 0)) {
			eprintf(INSERTM);
			osert++;
		}
		eprintf(DELC); 	/*clobber next char */
		for (i = mcol; i <=scrjnk[mline];i++) {
			cmap[mline] [i] = cmap[mline] [i+1];
		}
		scrjnk[mline]--;
	} else {
		if ((INSERTC || INSERTM) && INSON && (c == ldchar) && (mcol == ldcol+1) && (mcol<scrjnk[mline])) {
			register i;
			if (INSERTM && (osert == 0)) {
				eprintf(INSERTM); 	 /* open space */
				osert = 1;
			}
			if (scrjnk[mline] >SCRWID) scrjnk[mline]--;
			for (i = scrjnk[mline]++; i >= mcol;i--) {
				cmap[mline] [i+1] = cmap[mline] [i];
			}
			if (INSERTC) eprintf(INSERTC);
			cmap[mline] [mcol] = 0;
		} else {
			if (osert) {
				unsert();
			}
		}
		putit(c);
		if (osert && INSERTP) eprintf(INSERTP);
		if (ldchar == 0) ldcol = mcol;		/* remember where it was */
		ldchar = cmap[mline][mcol]; /* save last clobber */
		if ((scrcol++ >= SCRWID) && SCRWRAP) {
			scrlin++;
			scrcol=0;
		}
	}
	cmap[mline] [mcol] = c;
	while (scrjnk[mline] <mcol) cmap[mline] [scrjnk[mline]++] = ' ';
	if (++mcol> scrjnk[mline]) scrjnk[mline] = mcol;
}

/* getname prompts for a string, using ps, and inputs a string */

/* rubout and @ can be used to edit the string as enterred, and  causes
 * a quit, returning no input string
 * ^Y causes the current buffer name to be brought out
 */
#define FNLEN 128
char fnbuf[FNLEN];


char *
getname(ps)

register char *ps;

{
	register i;
	register char c;
	char *xp;

	fnbuf[i=0] = 0;	
	for (;;) {
		prompt1("%s%s",ps,fnbuf); /* display prompt */
		mgo(mline,mcol);
		c = mgetchar();
	
		if ((c == '') || (c == ttyintr)) {
			beep();
			unprompt();
			return(NULL);
		}
		if ((c == '
') || (c == '\n')) {
			unprompt();
			return(fnbuf);
		}
		if (c == ttyerase) {
			if (i) {
				i--;
				fnbuf[i] = 0;
			} else beep();
			continue;
		}
		if (c  == ttykill) {
			fnbuf[i=0]=0;
			continue;
		}
		if (c == '') {
			c = 0177 & getchar();
		}
		fnbuf[i++] = c;
		if (i >= FNLEN) {
			beep();
			--i;
		}
		fnbuf[i] = 0;
		continue;
	}
}

/* putout outputs a string (like eprintf) at the current position */

/* position is advanced one line.  If the position overflows the screen,
 * -MORE- is printed, and input  is read.  Any character except ^G
 * continues the display, ^G quits by returning -1 */

/*VARARGS1*/

putout(string,arg1,arg2,arg3,arg4,arg5,arg6)
char *string;
{
	if (mline>=SCRLINES) {
		prompt1("--  MORE --");
		if ((mgetchar()) == ttykill) return(-1);
		unprompt();
		mline=0;		/* TOP */
	}
	prompt(mline,string,arg1,arg2,arg3,arg4,arg5,arg6);
	clrl();
	mgo(++mline,0);
	return(0);
}

/* put out a string on ECHOL */
/*VARARGS1*/

prompt1(string,arg1,arg2,arg3,arg4,arg5)
char *string;
{
	prompt(ECHOL,string,arg1,arg2,arg3,arg4,arg5);
}

/* put out a string at a specified line */

/*VARARGS2*/

prompt(ecl,string,arg1,arg2,arg3,arg4,arg5,arg6)

char *string;
register int ecl;

{
	char pbuf[256];

	if (mline<=SCRLINES) {
		saveline = mline;
		savecol = mcol;
	}
	mline = ecl;
	mcol = 0;
	seprintf(pbuf,string,arg1,arg2,arg3,arg4,arg5,arg6);
	sputs(pbuf);
	psx = mline;
	psy = mcol;
	clrl();
}

/* clear out prompt */

unprompt()

{

	if (mline<=SCRLINES) {		/* if position to save */
		saveline = mline;
		savecol = mcol;
	}
	mgo(ECHOL,0);
	clrl();
	mgo(saveline,savecol);
}


/* return to the position saved before the last prompt */

goback()

{
	mgo(saveline,savecol);
}

/* put one character on the screen checking for end of screen line */

sputc(c)

register c;
{

	register i;

	if (mcol == SCRWID) {
		if (WRAPON) {
			if (mline>=NSCRLIN-1) {
				mline--; /* don't run overboard */
			} else {
				mputc(SCRCONT);
				mline++;
			}
			ldchar = 0;		/* reset ldchar */
			mcol = 0;
		} else {
			mputc(c);
			mline++;
			mcol=0;
			ldchar=0;
			return;
		}
	}
	mputc(c);
}

/* put one character in the display, checking for control and meta chars. */

xputc(c)
register c;
{
	register i;

	c &= 0377;
	if (c & META) {
		sputc('M');
		sputc('-');
		c-= META;
	}
	switch(ctype[c]) {
		char oc;
		case PLAIN:
			if ((!ULINE)||(!EOVER)) {
				sputc(c);
				return;
			}
			if (scrjnk[mline] <= mcol) {
				sputc(c);
				return;
			}
			oc = cmap[mline][mcol] & 0177 ;
			if ((oc == '_') && ((c & 0177) != ' ') 
			&& ((c & 0177) != '_')) {
				sputc(0200 | c);
				return;
			}
			sputc(c);
			return;
		case BACKSP:
			if ((ULINE)&&(EOVER)) {
				if (mcol != 0) xgo(mline,mcol-1);
				return;
			}
			/* NO BREAK HERE */
		case CONTRL:
			sputc('^');
			sputc(c^0100);
			return;

		case TAB:
			i = TABSTOP-(mcol%TABSTOP);
			while (i--) sputc(' ');
			return;

		}
}



/* clear the rest of the line, checking to see if the line previously
 * displayed corresponds to the one displayed here now */

clrl()

{
	register x;
	register y;
	register z;
	int xline;
	int xcol;

	ldchar = 0;			/* wipe out last char */
	x = mline;
	z = mcol;
	y = scrjnk[mline] - mcol;
	if (y > 0) {
		sgo(mline,mcol);			/* go for real */
		if (CLINE) {
			SREGION=y;	/* Number of characters cleared */
			eprintf(CLINE);
		} else {
			xline = mline;
			xcol = mcol;
			while (y--) mputc (' ');
			mgo(xline,xcol);
		}
		scrjnk[x] = z;
	}
}

/* put a string on the screen, translating control and meta */

sputs(xp)
register char *xp;
{
	register c;
	while (c= *xp++) {
		if (c == NEWLINE) {
			if (mline < NSCRLIN) mline++; /* don't overflow */
			mcol = 0;
			xputc('	');
		} else xputc(c);
	}
}

clear()

{
	register int i;
	
	eprintf(CLEAR);
	for (i = 0; i < NSCRLIN; i++) scrjnk[i] = 0;
	scrlin = scrcol = mline = mcol = 0;
}


/* Refresh the screen.  Clears and then restores what we think is there */

rfrsh()
{
	register xline;
	register xcol;
	
	eprintf(CLEAR);
	scrlin=scrcol=0;
	
	for (xline = 0; xline < SCRNLIN; xline++) {
		for (xcol = 0; xcol < scrjnk[xline]; xcol++) {
			if (cmap[xline][xcol]) {
				sgo(xline,xcol);
				putit(cmap[xline][xcol]);
				if ((scrcol++ >= SCRWID) && SCRWRAP) {
					scrlin++;
					scrcol=0;
				}
			}
		}
	}
	ldchar = 0;
}

sdelay(ms)

register int ms;			/* milliseconds of delay */
{
	register i;
	for (i = 0; i < ms;) {
		PUTS(NOP);		/* idle */
		i+=ttywarp;		/* milliseconds/character */
	}
}

ttype()		/* set terminal type */

{
register char *mp;

	mp = getname("Terminal Type? ");
	if (mp == NULL) return;
	sttype(mp);
}

int ttyptr = 0;

/* terminal description file parser: */

/* terminal description file contains lines with 

	parameter=data
	
 * where data is either a number of a string */


ttyparse(mp)
char *mp;

{
	register FILE *file;
	char xbuf[128];
	char optbuf[128];
	register char *cp;
	register int c;
	struct sparm *parmp;
	
	int parm;
	
	
/* find the terminal file and open it */
	
 	seprintf(xbuf,termdir,mp);	/* terminal file */
	
	file = fopen(xbuf,"r");
	
	if (file == NULL) file = fopen(mp,"r");
	
	if (file == NULL) {
		eprintf ("Can't use terminal type %s\n", mp);
		return(0);
	}
	
	/* first find what option we are setting */

nextparm: cp = optbuf;
	while ((c = getc(file)) != '=') {
		if (c == '\n') goto nextparm; /* comment line */
		if (c == EOF) {
			fclose(file);
			return(1); /* abort during option scan */
		}
		*cp++=c;
	}
	*cp = 0;
	
/* look up parameter in parameter table */
	
	for (parmp = ttydata; parmp->t_pname; parmp++) {
		if ((optbuf[0]==parmp->t_pname[0])&& (optbuf[1]==parmp->t_pname[1])) {
			
			c = getc(file);
			if ((c >= '0') && (c <= '9')) {
				parm = 0;
				while ((c >= '0') && (c <= '9')) {
					parm = 10*parm + (c-'0');
					c = getc(file);
				}
				*(parmp->t_padd) = parm;
				if (c != EOF) goto nextparm;
				fclose(file);
				return(1);
			}
			*(parmp->t_padd) = ((int) &ttystrings[ttyptr]);
			
			while ((c != EOF) && (c != EOL)) {
				if (c == '\\') {
					c = getc(file);
					if (c == 'n') c = '\n';
				}
				
				ttystrings[ttyptr++] = c;
				c = getc(file);
			}
			ttystrings[ttyptr++] = 0;
			if (c != EOF) goto nextparm;
		}
	}
	goto nextparm;
}

PUTS(string)

char *string;

{
	if (!drain) while(*string) putchar(0177 & *string++);
}
sttype(mp)
register char *mp;

{
	register struct sparm *parmp;
	
/* First, initialize the tty data */
	


	ttyptr = 0;
	for (parmp = ttydata; parmp->t_pname; parmp++) {
		*(parmp->t_padd) = 0;
	}
	SCRLINES=20;
	SCRWID=80;			/* so we won't bomb */
	
	if (ttyparse(mp)) {
 
		SCRWID--;

		if (SCRNLIN>NSCRLIN) {
			SCRNLIN=NSCRLIN;
		}
		if (SCRWID>NSCRCOL-1) {
			SCRWID=NSCRCOL-1;
		}
		if (VCOST == 0) VCOST = 1;
		SCRLINES = SCRNLIN-4;
		ECHOL = SCRNLIN-1;
		MODLN = SCRNLIN-3;

		if (CURAD) {
			acost = dcost(CURAD);
		} else {
			acost = dcost(RELUP)+dcost(RELFORW);
		}
		lUP = dcost(UP);
		lDOWN = dcost(DOWN);
		lBAK = dcost(BACK);
		lCR = dcost(CR);
		if (OSERTC && (INSERTM == 0)) {
			INSERTM=INSERTC;		/* old style insert modes */
			INSERTC=0;
		}
		if (SCREG) LOPEN = SCREG; /* make sure we use SCREG */
		if ((NOP == NULL) || (*NOP == 0)) NOP = "\200"; /* null pads get lost */

		if (SCINIT) {
			eprintf(SCINIT); /* initialize screen */
		}
		clear();
	}
}

/* dcost -- calculate display cost of a string */

dcost(sp)
register char *sp;
{
	register int dc;
	
	if (sp == NULL) return(1000); /* infinite cost for missing capability */
	
	dc = 0;
	while (*sp) {
		if (*sp++ != '%') dc++;
	}
	return(dc);
}

/* yes or no question */
/*VARARGS1*/
int
gyn(string,arg1,arg2,arg3)

char *string;
char *arg1;
char *arg2;
char *arg3;
{
	register char c;
	
	while (1) {
		prompt(ECHOL,string,arg1,arg2,arg3);
		sgo(mline,mcol);
		c = mgetchar();
		switch(c) {
			
		case 'y':
		case 'Y':
		case ' ':
			return(1);
		case '':	/* This is necessary to insure exit */
		case 'n':
		case 'N':
		case '':
			return(0);
		case '':
			return(-1);
		default:
			prompt(ECHOL-1,"y for yes, n for no, ^G to quit");
		}
	}
};

/* mtop -- move to top of display for message output */

mtop()
{
	mgo(0,0);			/* for messages */
}
	
uncook()
{

/* UNIX 3 code thanks to J. Langer and M. Plotnick */

#ifdef ux3
	struct termio nttyjunk;

	ioctl(1, TCGETA, &ttyjunk);
	nttyjunk=ttyjunk;

#ifdef u370

	nttyjunk.c_iflag |= (BRKINT|ISTRIP|IGNPAR);
	nttyjunk.c_iflag &= 
		~(IGNBRK|IGNPAR|PARMRK|IXON|INLCR|IGNCR|ICRNL|INPCK);
	/* accept break, no crnl mapping, no ^S^Q */ 
	nttyjunk.c_oflag = 0;		/* no delays, no crlf mapping */
	nttyjunk.c_cflag |= CS8 ;
	nttyjunk.c_lflag &= ~(ISIG|ECHO|ICANON); /* no echo, signals,
					    or erase/kill processing */
#else
	nttyjunk.c_iflag |= (BRKINT|ISTRIP);
	nttyjunk.c_iflag &= ~(IGNBRK|PARMRK|INLCR|ICRNL|IGNCR|IXON|IXOFF);
	/* accept break, no crnl mapping, no ^S^Q */ 
	nttyjunk.c_oflag = 0;		/* no delays, no crlf mapping */
	nttyjunk.c_lflag &= ~(ISIG|ECHO|ICANON); /* no echo, signals,
					    or erase/kill processing */
#endif
	nttyjunk.c_cc[VMIN] =  1;	/* return after every character read */
	nttyjunk.c_cc[VTIME] = 1;
	ttywarp = charms[ttyjunk.c_cflag&CBAUD]; /* milliseconds for character */

	ioctl(1, TCSETAW, &nttyjunk);
	ioctl(1, TCXONC,1);		/* Force tty back on */
	
#else

	struct sgttyb nttyjunk;
	
	gtty (1,&ttyjunk);
	nttyjunk=ttyjunk;
	nttyjunk.sg_flags &= (~ECHO);	/* it was so SIMPLE in the old days */
	nttyjunk.sg_flags |= (RAW);
	ttywarp = charms[ttyjunk.sg_ospeed]; /* milliseconds for char */
	stty(1,&nttyjunk);
#endif

#ifndef RT
	ttyerase =	ttyjunk.c_cc[VERASE];
	ttykill =	ttyjunk.c_cc[VKILL];
	ttyeof =	ttyjunk.c_cc[VEOF];
	ttyintr =	ttyjunk.c_cc[VINTR];
#else
	ttyerase =	ttyjunk.sg_erase;
	ttykill =	ttyjunk.sg_kill;
	ttyeof =	'\004';
	ttyintr =	'';
#endif
	if (VEXIT) eprintf(SCINIT); /* RE-init terminal */
}

/* out of raw mode */

cook()
{
	if (VEXIT) eprintf(VEXIT);
	fflush(stdout);			/* force output */
#ifdef ux3
	ioctl(1,TCSETAW, &ttyjunk);
	ioctl(1, TCXONC,1);		/* Force tty back on */
#else
	stty(1,&ttyjunk);
#endif
}


/*VARARGS2*/

char *
nscan(stptr,ret)

register char *stptr;
register int *ret;
{
	register c;

	*ret = 0;
	while (((c = *stptr)>='0') && (c <= '9')) {
		stptr++;
		*ret = *ret*10+(c-'0');
	}
	return(stptr);
}


char *
strcpy(cp,cp1)

register char *cp;
register char *cp1;
{
	while (*cp++ = *cp1++);
	return(cp-1);
}

seprintf(string,fmt, x1)
register char *string;
register char *fmt;
unsigned x1;
{
	int c;
	int width;
	register unsigned int *adx;
	extern char *strcpy();
	
	adx = &x1;
loop:
	while((c = *fmt++) != '%') {
		*string++ = c;
		if(c == '\0') {
			return;
		}
	}
	width = 0;
	c = *fmt++;
	if ((c >= '0') && (c <= '9')) {
		fmt = nscan(fmt-1,&width);
		c = *fmt++;
	}
	
	switch(c) {
	case 'd':
	case 'D':
	case 'o':
	case 'O':
		{
			register int b;
			long n;
			long n1;
			register int i;
			char dstack[20];

			b = (((c=='o') || (c == 'O'))? 8: 10); /* number base */
			if ((c == 'o') || (c == 'd')) {
				n = (long) (*adx);
				if (n > 32768L) n = n-65536L; /* sign correction */
			} else {
				n = *((long *) adx);
				adx += ((sizeof(n)-sizeof(i))/sizeof(i));
			}
			i = 0;
			if (n < 0) {
				n = -n;
				*string++ = '-';
			}
			
			do {
				n1 = n/b;
				dstack[i++] = (short) (n-(n1*b));
				n = n1;
			} while (n != 0);	/* figure number */
			if ((b == 8) && ((i !=1 ) || (dstack[0] != 0))) dstack[i++]=0;
			while (i<width) dstack[i++] = 0;
			while (i > 0) *string++ =(dstack[--i] + '0');	/* print number */
			}
		break;
	case 'P':
		width *= SREGION;
					/* Fall through */
	case 'p':
		while (width > 0) {
			*string++ = *NOP;
			width -= ttywarp;
		}
		adx--;
		break;
	case 's':
		string = strcpy(string,(char *)*adx);
		break;
	case 'm':
	case 'M':
		{
			char *cp;
			if (c=='m') {
				cp = &TMAP[width * (*adx)];
			} else {
				cp = &SMAP[width * (*adx)];
			}
			for (c = 0; c < width; c++) {
				if (*cp) *string++ = *cp++;
			}
		}
		break;
	case 'c':
		c = *adx;
		if (c) {
			*string++ = c;
		} else {
			*string++ = '^';
			*string++ = '@'; /* punt */
		}
		break;
	case '%':
		*string++ ='%';
		adx--;
		break;
	default:
		break;
	}
	adx++;
	goto loop;
}

mgetchar()
{
	fflush(stdout);			/* force output */
	return(0177 & getchar());
}

/*VARARGS1*/

eprintf(string,a1,a2,a3,a4,a5,a6,a7)

register char *string;

{
	char pbuf[1024];
	seprintf(pbuf,string,a1,a2,a3,a4,a5,a6,a7);
	PUTS(pbuf);
}



xprintf(sp,ap1,ap2,ap3,ap4,ap5,ap6)
register char *sp;
{
	char sbuf[0400];		/* buffer */
	register c;
	int x;
	

	sprintf(sbuf,sp,ap1,ap2,ap3,ap4,ap5,ap6);
	sp = sbuf;
	while (c = *sp++) {
		if (c == '\n') {
			clrl();
			if (++mline >= ECHOL) {
				mline=0;
			}
			mcol=0;
		} else {
			xputc(c);
		}
	}
}

die(arg)
int arg;
{
	mgo(SCRNLIN-1,0);
	clrl();
	cook();
	if (arg) abort(arg);
	else exit(0);
}
ttystart()
{
	int i;
	char *tp;
	
	setbuf(stdout,ttobuf);

	uncook();
	for (i = 0; i < 16; i++) {
		signal(i,die);
	}
	tp = getenv("TERM");
	if (tp == NULL) ttype();
	else sttype(tp);
}

insrtc(c)
int c;
{
	if (INSERTC == NULL) return(0);
	INSON = 1;
	ldchar = c;
	ldcol = mcol-1;
	mputc(c);
	INSON = 0;
	return(1);
}
delc()
{
	register i;

	if (DELC == NULL) return(0);
	SREGION=scrjnk[mline]-mcol; /* number of char's gobbled */
	if (DELMODE && (osert == 0)) {
		eprintf(INSERTM);
		osert++;
	}
	eprintf(DELC); 	/*clobber next char */
	for (i = mcol; i <=scrjnk[mline];i++) {
		cmap[mline] [i] = cmap[mline] [i+1];
	}
	scrjnk[mline]--;
	return(1);
}
	
/* adjust vertical position of line -- open (or close) lines on */
/* the screen  argument is the number of lines to add (or drop). */

vadjust(xline,tline,x)

register x;
int xline;
int tline;
{
	register i;
	register j;
	int oldx;

	if (LOPEN == NULL) return(0);
	
	oldx = xline;
	
	if (x<0) {
		x = -x;
		i = 1;
	} else i = 0;
	SREGION=tline-oldx;		/* effected region */
	if (i) {			/* if deleting lines */
		sgo(xline,0);
		
		if (SCREG) {		/*if vt100 stype scrolling */
			eprintf(SCREG,oldx+XBASE,tline+XBASE); /*define region*/
			scrlin = scrcol = 0;
			sgo(tline,0);
			for (i = 0; i < x; i ++) {
				eprintf(SSCROLL);
			}
			eprintf(SCREG,XBASE,SCRNLIN);
			scrlin = scrcol = 0;
		} else {
			for (i = 0; i < x; i++) {
				eprintf(LDEL);
			}
			sgo(tline-x+1,0);
			for (i = 0; i < x; i++) {
				eprintf(LOPEN);
			}
		}
		sgo(oldx,0);
		vshift (oldx,tline,x);
	} else {
		if (SCREG) {		/* if vt100 style scrolling */

			eprintf(SCREG,oldx+XBASE,tline+XBASE); /*define region */
			scrlin = scrcol = 0; /* vt100 dies */
			sgo(xline,0);
			for (i = 0; i < x; i ++) {
				eprintf(RSCROLL);
			}
			eprintf(SCREG,XBASE,SCRNLIN);
			scrlin = scrcol = 0;
		} else {
			sgo(tline+1-x,0);
			for (i = 0; i < x;i++) eprintf(LDEL);
			sgo(oldx,0);
			for (i = 0; i < x; i++) eprintf(LOPEN);
		}
		mgo(oldx,0);
		
		vshift(oldx,tline,-x);
	}
	return(1);
}


/* sscroll -- try to fix display by scrolling */

sscroll(x)

register int x;

{
	register int i;

	
	if (SSCROLL == NULL) return(0);


	sgo(SCRNLIN-1,0);			/* to bottom */
	SREGION=SCRNLIN;			/* number of lines effected */
	for (i = 0; i < x; i++) {
		eprintf(SSCROLL); /* scroll screen */
	}
	vshift (0,SCRNLIN-1,x);
}

/* vshift -- shift the display image from top to bottom (inclusive) by x */


vshift(top,bottom,x)

int top;
int bottom;
int x;

{
	register i;
	register j;
	char *cp1;
	char *cp2;
	int *jnkptr;
	int start;
	int stop;
	register int off;
	
	if (x > 0) {
		off = 1;
		start = top;
		stop = bottom+1;
	} else {
		off = -1;
		start = bottom;
		stop = top-1;
	}
	for (i = start,jnkptr = scrjnk+i; i != stop-x; i+=off,jnkptr+=off) {
		*jnkptr = *(jnkptr+x);
		cp1 = cmap[i];
		cp2 = cmap[i+x];
		for (j = 0; j < *jnkptr; j++) {
			*cp1++ = *cp2++;
		}
	}
	while (i != stop) {
		if (off > 0) {
			*jnkptr++ = 0;
			i++;
		} else {
			*jnkptr-- = 0;
			i--;
		}
	}
}


/* print an underscored character.  */

pu(c)
register char c;
{
	register oc;
	c &= 0177;
	if ((c == 0)||(c == 040)) {
					/* bare underscore */
			putchar('_');
			return;		/* just put out the underscore */
	}
	if (UEND == 0) {
		eprintf(ULINE,c);
	} else {
		eprintf(ULINE); /* enter "underscore mode" */
		putchar(c);
		eprintf(UEND);
	}
}

putit(c)
char c;
{
	if (drain) return;
	if (c & 0200) {
		pu(c);
		return;
	} 
	putchar(0177 & c);
}