[comp.sources.misc] v07i051: CRISP release 1.9 part 30/32

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (06/22/89)

Posting-number: Volume 7, Issue 51
Submitted-by: fox@marlow.UUCP (Paul Fox)
Archive-name: crisp1.9/part31



#!/bin/sh
# this is part 10 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file ./tty.c continued
#
CurArch=10
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file ./tty.c"
sed 's/^X//' << 'SHAR_EOF' >> ./tty.c
X	char	*bg[16];
X	} COLORS;
XCOLORS	colors = {
X	{"\033[0;30m", "\033[0;34m", "\033[0;32m", "\033[0;36m", /* Foreground. */
X	 "\033[0;31m", "\033[0;35m", "\033[0;33m", "\033[0;37m",
X	 "\033[30;1m", "\033[34;1m", "\033[32;1m", "\033[36;1m",
X	 "\033[31;1m", "\033[35;1m", "\033[33;1m", "\033[37;1m"},
X	{"\033[40m", "\033[44m", "\033[42m", "\033[46m", /* Background. */
X	 "\033[41m", "\033[45m", "\033[43m", "\033[47m",
X	 "\033[40;1m", "\033[44;1m", "\033[42;1m", "\033[46;1m",
X	 "\033[41;1m", "\033[45;1m", "\033[43;1m", "\033[47;1m"},
X	};
X
Xint     LI;                     /* standard # lines */
Xint	AM;			/* Has auto-margins.		*/
Xchar
X	*AL,                    /* add line */
X	*BC,			/* Backspace character. */
X	*CD,			/* Clear to end of display.		*/
X	*CE,			/* Clear to end of line. */
X	*CL,			/* Clear screen 			*/
X	*CM,			/* Cursor motion */
X	*CS,                    /* set scroll region                    */
X	*DC,			/* Delete a character.	*/
X	*DL,                    /* del line */
X	*EI,                    /* end insert mode */
X	*HO,			/* Home cursor.		*/
X	*IC,                    /* insert a single space */
X	*IM,                    /* insert mode */
X	*IS,			/* Init sequence. */
X	*MB,			/* Turn on blinking.			*/
X	*MD,			/* Make bold 				*/
X	*ME,			/* Turn off all attributes.		*/
X	*RS,			/* Reset sequence. 			*/
X	*SE,			/* End standout mode.			*/
X	*SO,			/* Start standout mode.			*/
X	*SR,                    /* back index (used with scroll region  */
X	*TE,                    /* term end --- end using cursor motion */
X	*TI,                    /* term init -- start using cursor motion */
X	*UP,			/* Cursor up.		*/
X	*pAL,                   /* parameterized add line */
X	*pDL;                   /* parameterized delete line */
X	
Xchar    *K[NFKEYS];             /* other function key codes             */
Xchar	*KS, *KE;               /* enter keypad mode, exit keypad mode  */
Xint     SG;     /* number of glitches, 0 for invisable, -1 for none     */
Xchar	*termcap_strings = 
X"AL DL al bc cd ce cl cm cs dc dl ei ho ic im is ks ke mb me mr rs se so sr te ti up ";
Xchar	**termcap_ptrs[] = {
X	&pAL, &pDL,
X	&AL, &BC, &CD, &CE, &CL, &CM, &CS, &DC, &DL, &EI, &HO, &IC, 
X	&IM, &IS, &KS, &KE, &MB, &MD, &ME, &RS, &SE, &SO, &SR, &TE, &TI, &UP
X		};
X
X/*
X * Initialize the terminal when the editor
X * gets started up.
X */
Xstatic char tcbuf[TCAPSLEN];
X
Xvoid
Xttinit() 
X{
X	char *ggetenv();
X	char *p, *tgetstr();
X	char *tv_stype;
X	char	*tptr;
X	char	***cptr;
X	char	*cp;
X
X	if ((tv_stype = ggetenv("TERM")) == NULL)
X		panic("Environment variable TERM not defined!");
X
X	if((tgetent(tcbuf, tv_stype)) != 1) {
X		extern char *termcap_dir;
X		fprintf(stderr, 
X			"Terminal type '%s' not found in %s.\n",
X			tv_stype, termcap_dir);
X		exit(1);
X		}
X
X	p = tcapbuf;
X
X	LI = tgetnum("li");
X	AM = tgetflag("am");
X	SG = tgetnum("sg");
X
X	cptr = termcap_ptrs;
X	for (tptr = termcap_strings; *tptr; tptr += 3) {
X		char	*cp;
X		char	tmpbuf[3];
X		tmpbuf[0] = tptr[0];
X		tmpbuf[1] = tptr[1];
X		tmpbuf[2] = 0;
X		if ((cp = tgetstr(tmpbuf, &p)) && *cp)
X			**cptr = cp;
X		cptr++;
X		}
X	/*PC = pc ? *pc : 0;*/
X	if (cp = tgetstr("kh", &p))
X		K[KEY_HOME	- KFIRST] = cp;
X	if (cp = tgetstr("ku", &p))
X		K[KEY_UP	- KFIRST] = cp;
X	if (cp = tgetstr("kd", &p))
X		K[KEY_DOWN	- KFIRST] = cp;
X	if (cp = tgetstr("kl", &p))
X		K[KEY_LEFT	- KFIRST] = cp;
X	if (cp = tgetstr("kr", &p))
X		K[KEY_RIGHT	- KFIRST] = cp;
X	if (cp = tgetstr("EN", &p))
X		K[KEY_END	- KFIRST] = cp;
X	if (cp = tgetstr("PU", &p))
X		K[KEY_PAGEUP	- KFIRST] = cp;
X	if (cp = tgetstr("PD", &p))
X		K[KEY_PAGEDOWN	- KFIRST] = cp;
X
X	if (CM == NULL)
X	    panic("No cursor move (cm) capability in termcap.");
X	if (UP == NULL)
X	    panic("No upline (up) capability in termcap.");
X# if	defined(SIGWINCH)
X	{void ttwinch();
X	signal(SIGWINCH, ttwinch);
X	}
X# endif
X
X	if(!CE) tceeol = ncol;
X	else    tceeol = charcost(CE);
X
X	/* Estimate cost of inserting a line */
X	if (CS && SR)   tcinsl = charcost(CS)*2 + charcost(SR);
X	else if (pAL)   tcinsl = charcost(pAL);
X	else if (AL)    tcinsl = charcost(AL);
X	else            tcinsl = HUGE;   /* make this cost high enough */
X
X	/* Estimate cost of deleting a line */
X	if (CS)         tcdell = charcost(CS)*2 + 1;
X	else if (pDL)   tcdell = charcost(pDL);
X	else if (DL)    tcdell = charcost(DL);
X	else            tcdell = HUGE;   /* make this cost high enough */
X
X	/* Flag to indicate that we can both insert and delete lines */
X	insdel = (AL || pAL) && (DL || pDL);
X
X	if (p >= &tcapbuf[TCAPSLEN])
X		panic("Terminal description too big!\n");
X
X	/* tgoto() doesnt work properly with real termcap -- leave *
X	/* this in for now. */
X# if	1 || defined(MY_TERMCAP)
X	{
X	void close_termcap();
X	close_termcap();
X	}
X# endif
X}
Xttinit1()
X{
X	ttresize();                     /* set nrow & ncol      */
X	flush_col_cache();
X	if (TI) 
X		putpad (TI);     /* init the term */
X	if (IS) 
X		putpad (IS);     /* init the term */
X	if (KS) 
X		putpad(KS);
X}
X/*----------------------------------------
X/* Routine to decypher termcap style strings.
X/* Needed by code in set_term_escapes.
X/*----------------------------------------*/
X
X# define	XDIGIT(x)	(x <= '9' ? x - '0' : \
X				 (x >= 'a' && x <= 'z') ? x - 'a' + 10 : \
X				 (x - 'A' + 10))
Xchar *
Xtcopy_string(dp, bp, delim)
Xregister	char	*dp, *bp;
X{	register int n;
X
X	while (*bp != delim && *bp) {
X		if (*bp == '^') {
X			*dp++ = *++bp & 0x1f;
X			bp++;
X			continue;
X			}
X		if (*bp != '\\') {
X			*dp++ = *bp++;
X			continue;
X			}
X		switch (*++bp) {
X		  case 'E':	*dp++ = 0x1b; break;
X		  case 'r':	*dp++ = '\r'; break;
X		  case 'n':	*dp++ = '\n'; break;
X		  case 't':	*dp++ = '\t'; break;
X		  case 'b':	*dp++ = '\b'; break;
X		  case 'f':	*dp++ = '\f'; break;
X		  case '0': case '1': case '2': case '3':
X			n = 0;
X			while (*bp >= '0' && *bp <= '7')
X				n = 8*n + *bp++ - '0';
X			bp--;
X			*dp++ = (char) n;
X			break;
X		  case 'x':
X			bp++;
X			n = XDIGIT(*bp);
X			bp++;
X			n = n * 16 + XDIGIT(*bp);
X			*dp++ = (char) n;
X			break;
X		  default:	*dp++ = *bp; break;
X		  }
X		bp++; 
X		}
X	*dp++ = NULL;
X	return dp;
X}
X
X/*
X * Clean up the terminal, in anticipation of
X * a return to the command interpreter. This is a no-op
X * on the ANSI display. On the SCALD display, it sets the
X * window back to half screen scrolling. Perhaps it should
X * query the display for the increment, and put it
X * back to what it was.
X */
Xvoid
Xtttidy() 
X{
X	if (RS && *RS) putpad (RS);     /* set the term back to normal mode */
X	if (TE && *TE) putpad (TE);     /* set the term back to normal mode */
X	if (KE) 
X		putpad(KE);
X}
X
X/*
X * Move the cursor to the specified
X * origin 0 row and column position. Try to
X * optimize out extra moves; redisplay may
X * have left the cursor in the right
X * location last time!
X */
Xvoid
Xttmove(row, col) 
Xu_int16	row;
Xu_int16	col;
X{
X	char        *tgoto();
X	extern char *HO;
X	if (ttrow == row && ttcol == col)
X		return;
X
X	if (col == 0 && row == 0 && HO)
X		putpad(HO);
X	else if (ttcol == col && row == ttrow+1)
X		ttputpad('\n');
X	else if (ttcol == col+1 && row == ttrow+1) {
X		ttputpad('\n');
X		ttputpad('\b');
X		}
X	else if (ttcol-1 == col && row == ttrow)
X		ttputpad('\b');
X	else if (ttrow == row && pt.pt_escC[0] && col > ttcol && ttcol > 1) {
X		putpad(tgoto(pt.pt_escC, 0, col - ttcol));
X		}
X	else {
X		char *cp = tgoto(CM, (int) col, (int) row);
X/*		int len = strlen(cp);
X		if (row == ttrow && col + len < ttcol) {
X			int i;
X			for (i = 0; i++ < ttcol - col; i++)
X				ttputpad('\b');
X			}
X		else*/
X			putpad(cp);
X		}
X	ttrow = row;
X	ttcol = col;
X}
X/*
X * Erase to end of line.
X */
Xvoid
Xtteeol() 
X{
X    if(CE) putpad(CE);
X    else {
X	register int i=ncol-ttcol;
X	while(i--) ttputc(' ');
X	ttrow = ttcol = HUGE;
X    }
X}
X
Xttclear()
X{
X	if (CL == NULL) {
X		ttmove((u_int16) 0, (u_int16) 0);
X		tteeop();
X		}
X	else {
X		ttrow = 0;
X		ttcol = 0;
X		putpad(CL);
X		}
X}
X/*
X * Erase to end of page.
X */
Xvoid
Xtteeop() 
X{
X    if(CD) putpad(CD);
X    else {
X	putpad(CE);
X	if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1);
X	else {          /* do it by hand */
X	    register int line;
X	    for (line = ttrow + 1; line <= LI; ++line) {
X		ttmove((u_int16) line, (u_int16) 0);
X		tteeol();
X	    }
X	}
X	ttrow = ttcol = HUGE;
X    }
X}
X
X/*
X * Make a noise.
X */
Xvoid
Xttbeep() 
X{
X	ttputc(BEL);
X	/*----------------------------------------
X	/*   Adjust cursor because ttputc() thinks
X	/*   BEL moves the cursor.
X	/*----------------------------------------*/
X	ttcol--;
X	ttflush();
X}
Xbeep()
X{
X	ttbeep();
X	return 0;
X}
X
X/*
X * Insert nchunk blank line(s) onto the
X * screen, scrolling the last line on the
X * screen off the bottom.  Use the scrolling
X * region if possible for a smoother display.
X * If no scrolling region, use a set
X * of insert and delete line sequences
X */
Xttinsl(row, bot, nchunk) 
X{
X	register int        i;
X
X	if (row == bot) {           /* Case of one line insert is special  */
X		ttmove((u_int16) row, (u_int16) 0);
X		tteeol();
X		return TRUE;
X	}
X	if (CS && SR) {             /* Use scroll region and back index     */
X		ttwindow(row,bot);
X		ttmove((u_int16) row, (u_int16) 0);
X		while (nchunk--) putpad(SR);
X		/*ttnowindow();*/
X		return TRUE;
X		}
X	if (insdel) {
X		ttmove((u_int16) (1+bot-nchunk), (u_int16) 0);
X		if (pDL) 
X			putpad (tgoto(pDL, 0, nchunk));
X		else 
X			for (i=0; i<nchunk; i++)/* For all lines in the chunk */
X				putpad(DL);
X		ttmove((u_int16) row, (u_int16) 0);
X		if (pAL) 
X			putpad (tgoto(pAL, 0, nchunk));
X		else 
X			for (i=0; i<nchunk; i++)/* For all lines in the chunk*/
X				putpad(AL);
X		ttrow = HUGE;
X		ttcol = HUGE;
X		return TRUE;
X		}
X	return FALSE;
X}
X
X/*
X * Delete nchunk line(s) from "row", replacing the
X * bottom line on the screen with a blank line. 
X * Unless we're using the scrolling region, this is 
X * done with a crafty sequences of insert and delete 
X * lines.  The presence of the echo area makes a
X * boundry condition go away.
X */
Xttdell(row, bot, nchunk)
X{	register int        i;
X
X	if (row == bot) {           /* One line special case        */
X		ttmove((u_int16) row, (u_int16) 0);
X		tteeol();
X		return TRUE;
X		}
X	if (CS) {                   /* scrolling region     */
X		ttwindow(row, bot);
X		ttmove((u_int16) bot, (u_int16) 0);
X		while (nchunk--) ttputc(LF);
X		return TRUE;
X		}
X	if(insdel) {
X		ttmove((u_int16) row, (u_int16) 0);
X		if (pDL) 
X			putpad (tgoto(pDL, 0, nchunk));
X		else 
X			for (i=0; i<nchunk; i++)
X				putpad(DL);
X		ttmove((u_int16) (1+bot-nchunk), (u_int16) 0);
X		if (pAL) 
X			putpad (tgoto(pAL, 0, nchunk));
X		else 
X			for (i=0; i<nchunk; i++)
X				putpad(AL);
X		ttrow = HUGE;
X		ttcol = HUGE;
X		return TRUE;
X		}
X	return FALSE;	
X}
X
X/*
X * This routine sets the scrolling window
X * on the display to go from line "top" to line
X * "bot" (origin 0, inclusive). The caller checks
X * for the pathalogical 1 line scroll window that
X * doesn't work right, and avoids it. The "ttrow"
X * and "ttcol" variables are set to a crazy value
X * to ensure that the next call to "ttmove" does
X * not turn into a no-op (the window adjustment
X * moves the cursor).
X * 
X */
Xvoid
Xttwindow(top, bot)
X{
X	if (CS && (tttop!=top || ttbot!=bot)) {
X		putpad(tgoto(CS, bot, top));
X		ttrow = HUGE;                   /* Unknown.             */
X		ttcol = HUGE;
X		tttop = top;                    /* Remember region.     */
X		ttbot = bot;
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 */
Xstatic	int	tthue = -1;
Xstatic	int 	tt_fg = -1;
Xstatic	int	tt_bg = -1;
Xstatic int gso = FALSE;
Xvoid
Xflush_col_cache()
X{
X	tthue = tt_fg = tt_bg = -1;
X}
Xvoid
Xttcolor(color)
X{	int	fg, bg;
X
X	if (tthue == color)
X		return;
X	tthue = color;
X	if (!pt.pt_color) {
X		if (color == FG(col_table.c_normal) ||
X		    color == FG(col_table.c_messages)) {
X			putpad(SE); 
X			}
X		else if (color == FG(col_table.c_select) ||
X		    color == FG(col_table.c_error)) {
X			putpad(SE);
X			putpad(MD);
X			}
X		else {
X			putpad(SO);
X			}
X		return;
X		}
X	fg = (color & FG_COLOR) >> FG_SHIFT;
X	bg = (color & BG_COLOR) >> BG_SHIFT;
X	if (fg != tt_fg) {
X		putpad(colors.fg[fg]);
X		tt_fg = fg;
X		}
X	if (bg != tt_bg) {
X		putpad(colors.bg[bg]);
X		tt_bg = bg;
X		}
X}
Xvoid
Xttresize() 
X{
X	setttysize();
X	if (nrow < 1)
X		nrow = 1;
X	if (ncol < 1)
X		ncol = 1;
X}
Xvoid
Xttwinch()
X{
X# if	defined(SIGWINCH)
X	void	ttwinch1();
X	
X	int oncol = ncol;
X	int	onrow = nrow;
X	ttresize();
X	signal(SIGWINCH, ttwinch);
X	update();
X# endif
X}
Xvoid
Xttwinch1(oncol, onrow, ncol, nrow)
X{	register WINDOW *wp;
X	extern	int	sgarbf;
X	int	diffcol, diffrow;
X	
X	vtinit1();
X	diffcol = ncol - oncol;
X	diffrow = nrow - onrow;
X	for (wp = wheadp; wp; wp = wp->w_wndp) {
X		int 	right_edge;
X		int	last_line;
X		/*----------------------------------------
X		/*   Adjust window width only if its right
X		/*   hand edge touches the right hand edge
X		/*   of the window.
X		/*----------------------------------------*/
X		right_edge = wp->w_x + wp->w_w;
X		last_line = wp->w_y + wp->w_h;
X		if (wp->w_tiled)
X			right_edge++;
X		if (right_edge == oncol)
X			wp->w_w += diffcol;
X		/*----------------------------------------
X		/*   Adjust window height if window's
X		/*   bottom line touches bottom of screen.
X		/*----------------------------------------*/
X		if (last_line == onrow - 3)
X			wp->w_h += diffrow;
X		}
X	sgarbf = TRUE;
X}
X
Xstatic int cci;
X
Xstatic void                 /* fake char output for charcost() */
Xfakec(c) char c; 
X{
X#ifdef  lint
X	c++;
X#endif
X	cci++;
X}
X
X/* calculate the cost of doing string s */
Xcharcost (s) char *s; 
X{
X    cci = 0;
X
X    tputs(s, nrow, fakec);
X    return cci;
X}
Xvoid
Xputpad(str) 
Xchar *str; 
X{
X	if (str == NULL)
X		return;
X/*	if (str == SO) {
X		if (gso)
X			return;
X		gso = TRUE;
X		}
X	else if (str == SE) {
X		if (!gso)
X			return;
X		gso = FALSE;
X		}	*/
X	tputs(str, 1, ttputpad);
X}
Xvoid
Xttspace(n, space, stay)
X{	u_int16	oldrow = ttrow;
X	u_int16	oldcol = ttcol;
X
X	if (n <= 0)
X		return;
X	ttputc(space);
X	if (--n <= 0)
X		return;
X	if (pt.pt_space[0]) {
X		putpad(tgoto(pt.pt_space, 0, n));
X		if (!stay)
X			ttmove(oldrow, oldcol + n + 1);
X		}
X	else {
X		while (n-- > 0)
X			ttputc(space);
X		}
X	if (stay)
X		ttmove(oldrow, oldcol);
X	
X}
Xttrepeat(ch, n)
X{
X	if (n > 12 && pt.pt_repeat[0]) {
X		ttputc(ch);
X		putpad(tgoto(pt.pt_repeat, 0, n-1));
X		ttmove(ttrow, ttcol + n - 1);
X		}
X	while (n-- > 0)
X		ttputc(ch);
X
X
X}
X
SHAR_EOF
echo "File ./tty.c is complete"
chmod 0444 ./tty.c || echo "restore of ./tty.c fails"
mkdir . >/dev/null 2>&1
echo "x - extracting ./ttyio.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > ./ttyio.c &&
X/**************************************************************
X *
X *	CRISP - Custom Reduced Instruction Set Programmers Editor
X *
X *	(C) Paul Fox, 1989
X *	43, Jerome Close	      Tel: +44 6284 4222
X *	    Marlow
X *	     Bucks.
X *		England SL7 1TX
X *
X *
X *    Please See COPYRIGHT notice.
X *
X **************************************************************/
X
X# include        "list.h"
XSCCSID("@(#) ttyio.c 1.15, (C) P. Fox");
X
X# if	defined(SUN)
X# 	include	<sys/time.h>
X# 	include	<termio.h>
X# endif
X# if	defined(XENIX)
X# 	include	<termio.h>
X# endif
X
X
X
X# define	TTY_FD	0
X# define	BIT(x)	(1 << (x))
X
X# if	defined(SELECT)
X# include	<sys/types.h>
X# include	<sys/time.h>
X
X# endif
Xlong	sel_bits = BIT(TTY_FD);
X
X# define	CENTISECONDS	5	/* x .01 seconds */
Xvoid	ttflush();
X
X#define NOBUF   136                     /* Output buffer size.          */
X
Xlong	st_charout;			/* Number of characters output.	*/
X
Xchar    obuf[NOBUF+10];                 /* Output buffer.               */
Xint     nobuf;                          /* buffer count                 */
Xint	timeout_flag = FALSE;	/* TRUE when we are in VMIN/VTIME mode.*/
Xint	reading_char;
Xunsigned char kbdq = 0;
Xextern int ega43_flag;
Xint old_ega_flag = -1;
X
Xu_int16		nrow;                   /* Terminal size, rows.         */
Xu_int16		ncol;                   /* Terminal size, columns.      */
X
X/*
X * This function gets called once, to set up
X * the terminal channel.  This version turns off flow
X * control.  This may be wrong for your system, but no
X * good solution has really been found (daveb).
X */
Xvoid
Xttopen()
X{
X	sys_open();
X	ttinit1();
X}
Xvoid
Xtttimeout(yes)
X{
X	if (yes == timeout_flag)
X		return;
X	timeout_flag = yes;
X	sys_timeout(yes);
X}
X/*
X * This function gets called just
X * before we go back home to the shell. Put all of
X * the terminal parameters back.
X */
Xvoid
Xttclose()
X{
X	ttflush();
X	sys_close();
X	old_ega_flag = -1;
X}
X
X/*
X * Write character to the display.
X * Characters are buffered up, to make things
X * a little bit more efficient.
X */
Xvoid
Xttputpad(c)
X{
X	if (nobuf >= NOBUF)
X		ttflush();
X	obuf[nobuf++] = (char) c;
X}
Xvoid
Xttputs(str)
Xregister char	*str;
X{
X	while (*str)
X		ttputc(*str++);
X}
Xvoid
Xttputc(c)
Xregister int c;
X{
X	extern int scr_attr;
X	register int	color = c & COLOR_MASK;
X	extern int AM;
X
X	if (nobuf >= NOBUF)
X		ttflush();
X
X	ttcolor(color);
X
X	c &= 0xff;
X/*	if (c & 0x80 && c < (0x80 + ' ')) {*/
X	if (c & 0x80) {
X		if (c >= CH_MIN && c <= CH_MAX) {
X			char	*cp = "?";
X			switch (c) {
X			  case CH_HORIZONTAL:	cp = pt.pt_horizontal; break;
X			  case CH_VERTICAL:	cp = pt.pt_vertical; break;
X			  case CH_TOP_LEFT:	cp = pt.pt_top_left; break;
X			  case CH_TOP_RIGHT:	cp = pt.pt_top_right; break;
X			  case CH_BOT_LEFT:	cp = pt.pt_bot_left; break;
X			  case CH_BOT_RIGHT:	cp = pt.pt_bot_right; break;
X			  case CH_TOP_JOIN:	cp = pt.pt_top_join; break;
X			  case CH_BOT_JOIN:	cp = pt.pt_bot_join; break;
X			  case CH_LEFT_JOIN:	cp = pt.pt_left_join; break;
X			  case CH_RIGHT_JOIN:	cp = pt.pt_right_join; break;
X			  case CH_CROSS:	cp = pt.pt_cross; break;
X			  	  }
X			strcpy(obuf + nobuf, cp);
X			nobuf += strlen(cp);
X			}
X		else if (c >= 0x80 + ' ')
X			goto hell;
X		else	{
X			c &= 0x7f;
X			if (c == 0x1b && pt.pt_escape[0])
X				strcpy(obuf+nobuf, pt.pt_escape);
X			else
X				sprintf(obuf+nobuf, pt.pt_character, c ? c : 0x80);
X			nobuf += strlen(obuf+nobuf);
X			}
X		goto end_of_function;
X		}
X	if (c == 0)
X		return;
Xhell:
X	obuf[nobuf++] = (char) c;
X	if (c == '\b') {
X		ttcol--;
X		return;
X		}
Xend_of_function:
X	if (++ttcol >= ncol && AM) {
X		ttcol = 0;
X		ttrow++;
X		}		
X}
X
Xvoid
Xttflush()
X{	extern int background;
X
X	if (nobuf != 0) {
X		st_charout += nobuf;
X		if (background == FALSE)
X			sys_write(1, obuf, nobuf);
X		nobuf = 0;
X	}
X}
XKEY
Xgetkey()
X{
X	int	n;
X	unsigned char ch;
X	extern int num_pty;
X	extern long time_last_key_pressed;
X	KEY	key;
X	static unsigned char	buf[32];	/* Buffer for current key being read in */
X	static unsigned char *bufptr = NULL;
X	unsigned char	*cp = buf;
X	int	pass2 = FALSE;
X	extern int push_cnt;
X# if	defined(SELECT)
X	struct timeval timeout;
X	struct timeval *tp = NULL;
X	
X	timeout.tv_sec = 0;
X	timeout.tv_usec = 0;
X# endif
X
X	if (push_cnt)
X		return get_push();
X		
X	if (bufptr) {
X		ch = *bufptr++;
X		if (*bufptr == NULL)
X			bufptr = NULL;
X		return ch;
X		}
X		
X	while (1) {
X		extern int child_sig;
X		extern void proc_wait();
X		/*----------------------------------------
X		/*   Check to see if clock has gone off
X		/*   and we need to call somebody. We can
X		/*   only safely do this whilst we are NOT
X		/*   reading a character from the keyboard.
X		/*----------------------------------------*/
X		clock_check();
X		if (kbdq) {
X			ch = kbdq;
X			kbdq = 0;
X			goto got_char;
X			}
X		/*----------------------------------------
X		/*   If SIGCLD gone off then we should be
X		/*   safe here to go and process it.
X		/*----------------------------------------*/
X		if (child_sig)
X			proc_wait(-1);
X		
X		reading_char = TRUE;
X# if	defined(SELECT)
X		if (pass2) {
X			timeout.tv_usec = CENTISECONDS * 100 * 1000;
X			tp = &timeout;
X			}
X		if (tp || num_pty) {
X			int	fd, bits;
X			long readbits = sel_bits;
X			long	kbd_ready;
X			long	pty_ready;
X			int nfds = select(32, &readbits, (long *) NULL, (long *) NULL,
X				tp);
X			if (nfds < 0)
X				continue;
X			kbd_ready = BIT(TTY_FD) & readbits;
X			pty_ready = FALSE;
X			/*----------------------------------------
X			/*   Handle all pty's first.
X			/*----------------------------------------*/
X			for (fd = 0, bits = 0; readbits && bits < 32; 
X			     bits++, readbits >>= 1, fd++) {
X				if (fd == TTY_FD)
X				     	continue;
X				if ((BIT(fd) & readbits) == 0)
X					continue;
X				p_poll();
X				pty_ready = TRUE;
X				}
X			if (kbdq)
X				continue;
X			if (!kbd_ready) {
X				if (tp && pty_ready == FALSE)
X					goto return_ch;
X				continue;
X				}
X			}
X# endif
X# if	!defined(SELECT)
X		tttimeout(pass2);
X# endif
X		/*----------------------------------------
X		/*   Check to see if we have anything in
X		/*   playback buffer, before finally going
X		/*   to the keyboard for a character.
X		/*----------------------------------------*/
X		if ((ch = grab_char()) == 0) {
X			if (sys_getchar(TTY_FD, &ch, 1) != 1) {
X				if (pass2)
X					goto return_ch;
X				continue;
X				}
X			}
X
Xgot_char:
X		reading_char = FALSE;
X		*cp++ = ch;
X		*cp = NULL;
X		time_last_key_pressed = time((long *) 0);
X		key = check_key(buf, cp - buf);
X		if (key > 0) {
X			store_char(key);
X			return key;
X			}
X		if (key == 0) {
Xreturn_ch:		
X			if (buf[1])
X				bufptr = &buf[1];
X			store_char (buf[0]);
X			return buf[0];
X			}
X		pass2 = TRUE;
X		}
X}
X
Xtypeahead()					     
X{
X	if (kbdq)
X		return kbdq;
X
X	if (kbdq = grab_char())
X		return kbdq;
X
X	kbdq = sys_checkc();
X	return kbdq;
X}
X
X
Xvoid
Xpanic(s)
Xchar *s;
X{
X	u_close();
X	vttidy();
X	fprintf(stderr, "CRISP PANIC: %s\r\n", s);
X	exit(1);
X}
X
Xdo_ega()
X{	int	arg = argv[1].l_flags == F_NULL ? 0 : argv[1].l_int;
X
X	accumulator = ega43_flag ? 43 : 25;
X	if (argv[1].l_flags == F_NULL)
X		return;
X		
X	if (arg == 43)
X		arg = 1;
X	else if (arg == 25)
X		arg = 0;
X	ega_switch(arg);
X}
Xvoid
Xsetttysize()
X{	extern char *ggetenv();
X	extern int	AM;
X	
X#ifdef  TIOCGWINSZ
X	struct winsize	winsize;
X
X	if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
X		nrow = winsize.ws_row;
X		ncol = winsize.ws_col;
X		}
X	if (nrow == 0 || ncol == 0)
X#endif
X	if ((nrow= (u_int16) tgetnum ("li")) == 0
X	   || (ncol= (u_int16) tgetnum ("co")) == 0) {
X		nrow = 24;
X		ncol = 80;
X		}
X# if	defined(CONS_GET)
X	{extern int console_mode;
X	if (console_mode > 0) {
X		switch (console_mode) {
X		  case M_ENH_C80x43:
X			ega_switch(1);
X			nrow = 43;
X			break;
X		  case M_ENH_C80x25:
X			ega_switch(0);
X			nrow = 25;
X			break;
X		  }
X		}
X	}
X# endif
X	if (ggetenv("LINES")) {
X		nrow = atoi(ggetenv("LINES"));
X		AM = FALSE;
X		}
X	if (ggetenv("COLUMNS")) {
X		ncol = atoi(ggetenv("COLUMNS"));
X		AM = FALSE;
X		}
X}
Xega_switch(flag)
X{	extern int sgarbf;
X	extern void ttwinch1();
X	int	onrow = nrow;
X		
X	if (flag)
X		flag = 1;
X
X	if (old_ega_flag == flag)
X		return;
X	
X	old_ega_flag = ega43_flag = flag;
X	if (flag) {
X# if	defined(SW_ENHC80x43)
X		ioctl(1, SW_ENHC80x43, 1);
X		nrow = 43;
X# endif
X		ttwinch1(ncol, onrow, ncol, nrow);
X		}
X	else {
X# if	defined(SW_ENHC80x25)
X		ioctl(1, SW_ENHC80x25, 1);
X		nrow = 25;
X# endif
X		ttwinch1(ncol, onrow, ncol, nrow);
X		}
X	flush_col_cache();
X}
X
SHAR_EOF
chmod 0444 ./ttyio.c || echo "restore of ./ttyio.c fails"
mkdir . >/dev/null 2>&1
echo "x - extracting ./ttykbd.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > ./ttykbd.c &&
X/**************************************************************
X *
X *	CRISP - Custom Reduced Instruction Set Programmers Editor
X *
X *	(C) Paul Fox, 1989
X *	43, Jerome Close	      Tel: +44 6284 4222
X *	    Marlow
X *	     Bucks.
X *		England SL7 1TX
X *
X *
X *    Please See COPYRIGHT notice.
X *
X **************************************************************/
X# include	"list.h"
X# include	"alt.h"
X
XSCCSID("@(#) ttykbd.c 1.11, (C) P. Fox");
X
X/*
X0x80-0x8b	128-139		F1-F12
X0x8c-0x97	140-151		SHIFT-F1  -  SHIFT-F12
X0x98-0xA3	152-163		CTRL-F1   -  CTRL-F12
X0xA4-0xAF	164-175		ALT-F1    -  ALT-F12
X0xB0-0xC9	176-201		ALT-A	  -  ALT-Z
X0xCA-0xD3	202-211		Key-0, Key-9
X			0xCA/202=INS
X			0xCB/203=END,  0xCC/204=DOWN, 0xCD/205=PgDn,
X			0xCE/206=LEFT, 0xCF/207=5,    0xD0/208=RIGHT,
X			0xD1/209=HOME, 0xD2/210=UP,   0xD3/211=PgUp
X0xD4/212=DEL, 0xD5/213=+, 0xD6/214=-, 0xD7/215=*
X0xD8-0xE5	216-229		CTRL-0 .. CTRL-9, DEL, +, -, *
X			0xDF/223=Ctrl-Home	0xD9/217=Ctrl-End
X			0xE1/225=Ctrl-PgUp	0xDB/219=Ctrl-Pgdn
X			0xDC/220=Ctrl-<-	0xDE/222=Ctrl- ->
X0xE6		230	Back-tab
X*/
X# define	MAX_PUSHBACK	12
X
Xint	reading_char = FALSE;
Xstatic	u_char	key_buf[16];
Xextern	long	time_last_key_pressed;
Xu_char	push_buf[MAX_PUSHBACK];
Xint		push_cnt = 0;
Xchar		user_call[64];	/* Last macro called from keyboard by user*/
X
Xchar	*aitokey();
Xstatic	short	akeytoi();
Xtypedef	char	*KEYBOARD[NKEYS];
Xtypedef	struct	MAP	{
X		char	*m_keys;	/* Key sequence.		   */
X		char	*m_value;	/* String assigned to.		   */
X		int	m_flags;	/* Tells us whether m_value is a   */
X					/* string or a list.		   */
X		} MAP;
X
X# define	K_ALLOC		0x01	/* Key has been alloc'ed and should*/
X					/* be freed when finished with.	   */
X# define	K_LIST		0x02	/* Key is assigned to a list.	   */
Xstruct	kbd_stk {
X	int		k_id;
X	int		k_ref;		/* Reference count for this keyboard. */
X					/* When this becomes zero, we may free*/
X					/* it. Otherwise, it still exists in  */
X					/* the keyboard stack.		      */
X	u_char		k_flags[NKEYS];
X	KEYBOARD	k_keys;
X	Head_p		k_maps;		/* Multicharacter key combinations.	*/
X	};
X
XHead_p	hd_kbd;
XHead_p	hd_kstk;
Xstruct	kbd_stk	*kp;
X#define KFIRST  0x0080                  /* First special.               */
Xextern char	*K[];
Xchar	character;
Xint	kid = 1;
X
Xextern struct k_tbl k_tbl[];
Xvoid
Xkey_init()
X{	extern char	*chk_alloc();
X	int	i;
X	struct kbd_stk *kptr;
X
X	hd_kbd = ll_init();
X	hd_kstk = ll_init();
X
X	kptr = (struct kbd_stk *) chk_alloc(sizeof (struct kbd_stk));
X	kptr->k_id = kid++;
X	kptr->k_ref = 1;
X	kptr->k_maps = ll_init();
X	for (i = 0; i < NKEYS; i++) {
X		kptr->k_keys[i] = NULL;
X		kptr->k_flags[i] = 0;
X		}
X	for (i = 0; k_tbl[i].name; i++) {
X		kptr->k_keys[k_tbl[i].key] = k_tbl[i].name;
X		kptr->k_flags[k_tbl[i].key] = 0;
X		}
X	ll_push(hd_kbd, (char *) kptr);
X	kp = kptr;
X	K[BACK_TAB - KFIRST] = strdup("\033[Z");
X}
Xkbd_type()
X{
X	register	int	i;
X
X	for (i = 0; i < 127; i++) {
X		if (kp->k_keys[i] && kp->k_flags[i] & K_ALLOC)
X			chk_free(kp->k_keys[i]);
X		kp->k_keys[i] = NULL;
X		}
X	
X	return 0;
X}
Xpush_back()
X{
X	push_back1((int) argv[1].l_int);
X
X	return 0;
X}
Xpush_back1(ch)
X{
X	if (push_cnt < MAX_PUSHBACK)
X		push_buf[push_cnt++] = ch;
X}
Xget_push()
X{	int	ch;
X	register int i;
X	if (push_cnt) {
X		ch = push_buf[0];
X		for (i = 0; i < MAX_PUSHBACK - 1; i++)
X			push_buf[i] = push_buf[i+1];
X		push_cnt--;
X		return ch;
X		}
X	return 0;
X}
Xassign_to_key()
X{	int	key;
X	char	*cp;
X	char	*macro_name;
X	int	flags = K_ALLOC;
X	char	buf1[80];
X	char	buf[BUFSIZ];
X
X	if ((cp = get_arg1("Enter key: ", buf, sizeof buf)) == NULL)
X		return;
X	key = akeytoi(cp);
X
X	if (argc < 3 || argv[2].l_flags == F_NULL) {
X		if (ereply("Enter macro name to assign: ", buf1, sizeof buf1)
X			!= TRUE)
X			return;
X		macro_name = strdup(buf1);
X		}
X	else if (argv[2].l_flags == F_LIST) {
X		LIST	*copy_list();
X		macro_name = (char *) copy_list(argv[2].l_list);
X		flags = K_LIST | K_ALLOC;
X		}
X	else
X		macro_name = strdup(get_str(2));
X
X	if (key >= 0) {
X		free_key(key);
X		kp->k_keys[key] = macro_name;
X		kp->k_flags[key] = flags;
X		}
X	else {
X		MAP *mp = (MAP *) chk_alloc (sizeof (MAP));
X		mp->m_keys = strdup(key_buf);
X		mp->m_value = macro_name;
X		mp->m_flags = flags;
X		ll_push(kp->k_maps, (char *) mp);
X		return;
X		}
X}
X
Xfree_key(key)
X{
X	if (kp->k_flags[key] & K_ALLOC)
X		chk_free(kp->k_keys[key]);
X}
Xstatic short
Xakeytoi(cp)
Xregister char *cp;
X{
X	int	width;
X
X	for (width = 0; *cp; width++) {
X		if (*cp == '<') {
X			key_buf[width] = (u_char) new_akeytoi(cp);
X			while (*cp)
X				if (*cp++ == '>')
X					break;
X			}
X		else if (*cp == '#') {
X			key_buf[width] = (u_char) atoi(++cp);
X			while (isdigit(*cp))
X				cp++;
X			}
X		else {
X			key_buf[width] = 0;
X			if (*cp == '%')
X				cp++;
X			if (*cp == '\\')
X				key_buf[width] = (u_char) *++cp;
X			else if (*cp == '^')
X				key_buf[width] = (u_char) *++cp & 0x1f;
X			else
X				key_buf[width] = (u_char) *cp;
X			cp++;
X			}
X		if (width >= sizeof key_buf)
X			break;
X		}
X	if (width == 1)
X		return key_buf[0];
X	key_buf[width] = 0;
X	return -1;
X}
Xkey_to_int()
X{	
X	accumulator = akeytoi(get_str(1));
X	return 0;
X}
Xint_to_key()
X{
X	strl_acc_assign(aitokey((short) argv[1].l_int));
X	return 0;
X}
Xcheck_key(buf, len)
Xchar *buf;
X{
X	register char **cpp;
X	List_p	lp;
X	KEY key;
X	
X	/*--------------------------------------
X	 *   Check for normal function keys first.
X	 *--------------------------------------*/
X	for (cpp = K; cpp < &K[NFKEYS]; cpp++) {
X		if (*cpp == NULL)
X			continue;
X		if (strcmp(*cpp, buf) == 0)
X			return (KEY) (cpp - K + KFIRST);
X		if (strncmp(*cpp, buf, len) == 0)
X			return -1;
X		}
X	/*--------------------------------------
X	 *   Check for multiple characters key
X	 *   sequences.
X	 *--------------------------------------*/
X	for (key = KFIRST + NFKEYS, lp = ll_first(kp->k_maps); lp; 
X		key++, lp = ll_next(lp)) {
X		MAP *mp = (MAP *) ll_elem(lp);
X		if (strcmp(buf, mp->m_keys) == 0)
X			return key;
X		if (strcmp(buf, mp->m_keys, len) == 0)
X			return -1;
X		}
X	return 0;
X}
X# if 0
XKEY
Xgetkey()
X{	register char	**cpp;
X	static unsigned char	buf[12];
X	static unsigned char	*bufptr = NULL;
X	static unsigned char	*cp;
X	static int	l;
X	int	i;
X	unsigned char ch;
X	int	timeout = FALSE;
X	List_p	lp;
X	KEY	key;
X	int	ambiguous;
X
X	if (push_cnt) {
X		ch = push_buf[0];
X		for (i = 0; i < MAX_PUSHBACK - 1; i++)
X			push_buf[i] = push_buf[i+1];
X		push_cnt--;
X		return ch;
X		}
X
X	if (bufptr) {
X		ch = *bufptr++;
X		if (*bufptr == NULL)
X			bufptr = NULL;
X		return ch;
X		}
X	cp = buf;
X	l = 0;
X	while (1) {
X		tttimeout(timeout);
X
X		reading_char = TRUE;
X		if (ch = *cp = (char) ttgetc()) {
X			extern long time();
X			store_char(*cp++);
X			*cp = NULL;
X			l++;
X			time_last_key_pressed = time((long *) 0);
X			}
X		reading_char = FALSE;
X		/*--------------------------------------
X		 *   Check for normal function keys first.
X		 *--------------------------------------*/
X		ambiguous = FALSE;
X		for (cpp = K; cpp < &K[NFKEYS]; cpp++) {
X			if (*cpp == NULL)
X				continue;
X			if (strcmp(*cpp, buf) == 0)
X				return (KEY) (cpp - K + KFIRST);
X			if (strncmp(*cpp, buf, l) == 0) {
X				ambiguous = TRUE;
X				break;
X				}
X			}
X		/*--------------------------------------
X		 *   Check for multiple characters key
X		 *   sequences.
X		 *--------------------------------------*/
X		if (!ambiguous) {
X			for (key = KFIRST + NFKEYS, lp = ll_first(kp->k_maps); lp; 
X				key++, lp = ll_next(lp)) {
X				MAP *mp = (MAP *) ll_elem(lp);
X				if (strcmp(buf, mp->m_keys) == 0)
X					return key;
X				if (strncmp(buf, mp->m_keys, l) == 0) {
X					ambiguous = TRUE;
X					ch = 1;	/* Non-zero.	*/
X					break;
X					}
X				}
X			}
X		if (ch == 0 || !ambiguous) {
X			if (buf[1])
X				bufptr = &buf[1];
X			tttimeout(FALSE);
X			return buf[0];
X			}
X		timeout = TRUE;
X		}
X	
X}
X# endif
Xinq_command()
X{
X	strl_acc_assign(user_call);
X	return 0;
X}
Xexec_key(c)
X{	register char	*cp;
X	int	list_flag;
X	char	*get_key_assignment();
X
X	u_chain();
X	cp = get_key_assignment(c, &list_flag);
X	character = (char) c;
X
X	remember_macro(cp, list_flag);
X		
X	if (list_flag) {
X		LISTV	result;
X		eval((LIST *) cp, &result);
X		return 0;
X		}
X
X	if (cp[0] != '_')
X		strcpy(user_call, cp);
X	trace_log("\nKEY_EXEC:	%s\n", cp);
X	return str_exec(cp);
X}
Xchar *
Xget_key_assignment(c, list_flagp)
Xint *list_flagp;
X{
X	register List_p	lp;
X	register char *cp;
X	*list_flagp = TRUE;
X	
X	if (c >= KFIRST + NFKEYS) {
X		int	i = c - KFIRST - NFKEYS;
X		MAP	*mp;
X		for (lp = ll_first(kp->k_maps); i-- > 0 && lp; )
X			lp = ll_next(lp);
X		mp = (MAP *) ll_elem(lp);
X		cp = mp->m_value;
X		if (mp->m_flags & K_LIST)
X			return cp;
X		}
X	else if (curbp->b_keyboard) {
X		cp = curbp->b_keyboard->k_keys[c];
X		if (curbp->b_keyboard->k_flags[c] & K_LIST)
X			return cp;
X		if (cp && strcmp(cp, "nothing") == 0) {
X			cp = kp->k_keys[c];
X			if (kp->k_flags[c] & K_LIST)
X				return cp;
X			}
X		}
X	else {
X		cp = kp->k_keys[c];
X		if (kp->k_flags[c] & K_LIST)
X			return cp;
X		}
X	*list_flagp = FALSE;
X	return cp ? cp : "self_insert";
X}
Xinq_keyboard()
X{
X	accumulator = kp->k_id;
X	return 0;
X}
Xinq_local_keyboard()
X{
X	accumulator = curbp->b_keyboard ? curbp->b_keyboard->k_id : 0;
X	return 0;
X}
Xkbd_push()
X{	register int	i = argv[1].l_flags == F_NULL ? 0 : (int) argv[1].l_int;
X	register int	j;
X
X	if (i) {
X		List_p	lp;
X		for (lp = ll_first(hd_kbd); lp; lp = ll_next(lp)) {
X			kp = (struct kbd_stk *) ll_elem(lp);
X			if (kp->k_id == i) {
X				kp->k_ref++;
X				break;
X				}
X			}
X		if (lp == NULL) {
X			for (lp = ll_first(hd_kstk); lp; lp = ll_next(lp)) {
X				kp = (struct kbd_stk *) ll_elem(lp);
X				if (kp->k_id == i) {
X					ll_delete(lp);
X					break;
X					}
X				}
X			}
X		if (lp == NULL)
X			errorf("keyboard_push: %d not found.", i);
X		}
X	else {
X		kp = (struct kbd_stk *) chk_alloc(sizeof (struct kbd_stk));
X		kp->k_id = kid++;
X		kp->k_maps = ll_init();
X		for (j = 0; j < NKEYS; j++) {
X			kp->k_keys[j] = i ? (char *) NULL : "nothing";
X			kp->k_flags[j] = 0;
X			}
X		}
X	ll_push(hd_kbd, (char *) kp);
X
X	return 0;
X	
X}
Xkbd_pop()
X{	int	i = argv[1].l_flags == F_NULL ? 0 : (int) argv[1].l_int;
X	register int	j;
X	List_p lp = ll_first(hd_kbd);
X
X	if (lp == NULL)
X		return 0;
X	kp = (struct kbd_stk *) ll_elem(lp);
X	(void) ll_pop(hd_kbd);
X
X	if (i == 0) {
X		if (--kp->k_ref <= 0) {
X			for (j = 0; j < NKEYS; j++)
X				if (kp->k_keys[j] && kp->k_flags[j] & K_ALLOC)
X					chk_free(kp->k_keys[j]);
X			for (lp = ll_first(kp->k_maps); lp; 
X				lp = ll_next(lp)) {
X				MAP	*mp = (MAP *) ll_elem(lp);
X				chk_free(mp->m_keys);
X				chk_free(mp->m_value);
X				}
X			ll_clear(kp->k_maps);
X			ll_free(kp->k_maps);
X			chk_free((char *) kp);
X			}
X		}
X	else {
X		ll_append(hd_kstk, (char *) kp);
X		}
X	lp = ll_first(hd_kbd);
X	kp = lp ? (struct kbd_stk *) ll_elem(lp) : NULL;
X
X	return 0;
X}
Xuse_local_keyboard()
X{
X	struct	kbd_stk	*kp;
X	register List_p	lp;
X
X	accumulator = 0;
X	if (argv[1].l_int == 0) {
X		curbp->b_keyboard = NULL;
X		return 0;
X		}
X	for (lp = ll_first(hd_kstk); lp; lp = ll_next(lp)) {
X		kp = (struct kbd_stk *) ll_elem(lp);
X		if (kp->k_id == argv[1].l_int) {
X			curbp->b_keyboard = kp;
X			return 0;
X			}
X		}
X	accumulator = -1;
X	return 0;
X}
Xinq_assignment()
X{	char	*cp;
X	short	key;
X	int	from_key = argv[2].l_flags == F_NULL || argv[2].l_int == 0;
X
X	if (from_key) {
X		if (argv[1].l_flags == F_INT)
X			key = argv[1].l_int;
X		else
X			key = akeytoi(get_str(1));
X		if (key >= 0) {
X			if (curbp->b_keyboard) {
X				cp = curbp->b_keyboard->k_keys[key];
X				if (cp && strcmp(cp, "nothing") == 0)
X					cp = kp->k_keys[key];
X				}
X			else 
X				cp = kp->k_keys[key];
X			}
X		else
X			cp = "nothing";
X		if (cp == NULL) {
X			character = (char) key;
X			cp = "self_insert";
X			}
X		strl_acc_assign(cp);
X		return 0;
X		}
X	str_acc_assign("", 0);
X	if (curbp->b_keyboard)
X		find_assignment(curbp->b_keyboard->k_keys);
X	find_assignment(kp->k_keys);
X
X	if (saccumulator[0] == NULL)
X		strl_acc_assign("nothing", 7);
X	return 0;
X}
Xfind_assignment(cpp)
Xregister char	**cpp;
X{	char	buf[BUFSIZ];
X	char	*sp;
X	short	key;
X	char	*str1 = get_str(1);
X
X	strcpy(buf, saccumulator);
X	sp = buf + strlen(buf);
X
X	for (key = 0; key < NKEYS; key++, cpp++) {
X		if (*cpp && strcmp(*cpp, str1) == 0) {
X			if (sp != buf) {
X				strcpy(sp, "<-also>");
X				sp += 7;
X				}
X			strcpy(sp, aitokey(key));
X			sp += strlen(sp);
X			}
X		}
X	strl_acc_assign(buf);
X}
X# undef	PLUS
X# undef MINUS
X# define	CTRL	0x0100
X# define	SHIFT	0x0200
X# define	ALT	0x0400
X# define	KEYPAD	0x0800
X
X# define	ALL	(CTRL|SHIFT|ALT|KEYPAD)
X
X# define	UP	210
X# define	DOWN	204
X# define	LEFT	206
X# define	RIGHT	208
X# define	HOME	209
X# define	END	203
X# define	PGUP	211
X# define	PGDN	205
X# define	STAR	42
X# define	MINUS	169
X# define	PLUS	168
X# define	DEL	152
X# define	INS	KEY_0
X/*
X# define	F1	128
X# define	F2	129
X# define	F3	130
X# define	F4	131
X# define	F5	132
X# define	F6	133
X# define	F7	134
X# define	F8	135
X# define	F9	136
X# define	F10	137
X*/
X# define	F11	138
X# define	F12	139
X# define	BACKSPACE	8
X# define	ENTER	'\r'
Xstruct map {
X	int	len;
X	char	*name;
X	short	value;
X	};
Xstruct map	special[] = {
X	{0, "<Ctrl-Home>",		223},
X	{0, "<Ctrl-End>",		217},
X	{0, "<Ctrl-PgUp>",		225},
X	{0, "<Ctrl-PgDn>",		219},
X	{0, "<Ctrl-Left arrow>",	220},
X	{0, "<Ctrl-Right arrow>",	222},
X	{0, "<Ins>",		KEY_0},
X	{0, "<Del>",		212},
X	{0, "<Delete>",		127},
X	{0, "<Keypad-plus>",	213},
X	{0, "<Keypad-minus>",	214},
X	{0, "<Keypad-star>",	215},
X	{0}
X	};
X
Xstruct	map	stoi[] = {
X	{3, "ESC",		0x1b},
X	{1, "{",		'{'},
X	{1, "}",		'}'},
X	{5, "SPACE",		' '},
X	{5, "ENTER",		ENTER},
X	{3, "TAB",		0x09},
X	{5, "ARROW",		0},
X	{4, "CTRL",		CTRL},
X	{5, "SHIFT",		SHIFT},
X	{3, "ALT",		ALT},
X	{6, "KEYPAD",		KEYPAD},
X	{4, "GREY",		KEYPAD},
X	{2, "UP",		UP},
X	{4, "DOWN",		DOWN},
X	{4, "LEFT",		LEFT},
X	{5, "RIGHT",		RIGHT},
X	{4, "HOME",		HOME},
X	{3, "END",		END},
X	{4, "PGUP",		PGUP},
X	{4, "PGDN",		PGDN},
X	{4, "STAR",		STAR},
X	{5, "MINUS",		MINUS},
X	{4, "PLUS",		PLUS},
X	{3, "DEL",		DEL},
X	{3, "INS",		INS},
X	{3, "F12",		F12},
X	{3, "F11",		F11},
X	{3, "F10",		F10},
X	{2, "F9",		F9},
X	{2, "F8",		F8},
X	{2, "F7",		F7},
X	{2, "F6",		F6},
X	{2, "F5",		F5},
X	{2, "F4",		F4},
X	{2, "F3",		F3},
X	{2, "F2",		F2},
X	{2, "F1",		F1},
X	{9, "BACKSPACE",	BACKSPACE},
X	0
X	};
Xchar *
Xaitokey(key)
Xshort key;
X{
X	struct map *mp;
X	static char buf[32];
X	register char *cp;
X	int	alpha_cnt = 0;
X
X	if (key >= ALT_A && key <= ALT_Z) {
X		sprintf(buf, "<Alt-%c>", key - ALT_A + 'A');
X		return buf;
X		}
X	if (key >= SHIFT_F1 && key <= SHIFT_F1+11) {
X		sprintf(buf, "<Shift-F%d>", key - SHIFT_F1 + 1);
X		return buf;
X		}
X	if (key >= CTRL_F1 && key <= CTRL_F1+11) {
X		sprintf(buf, "<Ctrl-F%d>", key - CTRL_F1 + 1);
X		return buf;
X		}
X	if (key >= ALT_F1 && key <= ALT_F1+11) {
X		sprintf(buf, "<Alt-F%d>", key - ALT_F1 + 1);
X		return buf;
X		}
X	if (key >= ALT_0 && key <= ALT_0+9) {
X		sprintf(buf, "<Alt-%d>", key - ALT_0);
X		return buf;
X		}
X	if (key == BACK_TAB)
X		return "<Shift-Tab>";
X
X	for (mp = special; mp->name; mp++)
X		if (mp->value == key)
X			return mp->name;
X
X	for (mp = stoi; mp->name; mp++)
X		if (mp->value == (short) (key & 0xff)) {
X			sprintf(buf, "<%s>", mp->name);
X			for (cp = buf; *cp; cp++)
X				if (*cp >= 'A' && *cp <= 'Z')
X					if (alpha_cnt++)
X						*cp += 0x20;
X			return buf;
X			}
X	if (key < ' ')
X		sprintf(buf, "<Ctrl-%c>", key + 'A' - 1);
X	else
X		sprintf(buf, "#%d", key);
X	return buf;
X}
X			
Xnew_akeytoi(string)
Xchar	*string;
X{	char	str[80];
X	register char	*cp;
X	int	flags = 0;
X	int	ch;
X	register struct map *mp;
X
X	strcpy(str, string+1);
X	for (cp = str; *cp; cp++)
X		if (islower(*cp))
X			*cp = toupper(*cp);
X
X	for (cp = str; *cp && *cp != '>'; ) {
X		if (*cp == ' ' || *cp == '-' || *cp == '\t') {
X			cp++;
X			continue;
X			}
X		for (mp = stoi; mp->name; mp++)
X			if (strncmp(mp->name, cp, mp->len) == 0) {
X				cp += mp->len;
X				flags |= mp->value;
X				break;
X				}
X		if (mp->name == 0) {
X			flags |= *cp;
X			break;
X			}
X		}
X	ch = flags & 0xff;
X	switch (flags & ALL) {
X		case 0:		return ch;
X		case SHIFT:
X			if (ch >= F1 && ch <= F12)
X				return ch + 12;
X			if (ch >= 'A' && ch <= 'Z')
X				return ch - 0x20;
X			if (ch == UP || ch == DOWN || ch == LEFT || ch == RIGHT)
X				return 0;
X			if (ch == '\t')
X				return BACK_TAB;
X			if (isdigit(ch))
X				return 0;
X			return ch;
X		case CTRL:
X			if (ch == ENTER)
X				return '\n';
X			if (ch >= F1 && ch <= F12)
X				return ch + 24;
X			if (ch >= 'A' && ch <= 'Z')
X				return ch & 0x1f;
X			if (ch == UP || ch == DOWN || ch == LEFT || ch == RIGHT)
X				return ch + 14;
X			if (ch == '{' || ch == '}')
X				return 0;
X			if (isdigit(ch))
X				return 0;
X			return ch;
X		case ALT:
X			if (ch >= F1 && ch <= F12)
X				return ch + 32;
X			if (ch >= 'A' && ch <= 'Z')
X				return (ch - 'A') + ALT_A;
X			if (isdigit(ch))
X				return (ch - '0') + ALT_0;
X			return ch;
X		case KEYPAD:
X			switch (ch) {
X			case MINUS: 	return 214;
X			case PLUS:	return 213;
X			default:
X				return 0;
X			}
X		case SHIFT|KEYPAD:
X			return 0;
X		}	
X	ewprintf("Not decoded - %s", string);
X	return 0;
X}
SHAR_EOF
chmod 0444 ./ttykbd.c || echo "restore of ./ttykbd.c fails"
mkdir . >/dev/null 2>&1
echo "x - extracting ./undo.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > ./undo.c &&
X/**************************************************************
X *
X *	CRISP - Custom Reduced Instruction Set Programmers Editor
X *
X *	(C) Paul Fox, 1989
X *	43, Jerome Close	      Tel: +44 6284 4222
X *	    Marlow
X *	     Bucks.
X *		England SL7 1TX
X *
X *
X *    Please See COPYRIGHT notice.
X *
X *   Code to implement the undo and redo facilities.
X **************************************************************/
X# include	"list.h"
XSCCSID("@(#) undo.c 1.14, (C) 1989, P. Fox");
Xstatic void	re_goto();
Xstatic void	u_write();
Xstatic undo_check();
X
Xenum	undo_opcodes {
X	GOTO	= 0,
X	INSERT	= 1,
X	DELETE	= 2,
X	RAISE	= 3,
X	DROP	= 4,
X	SCRAP	= 5,	/* Operation should do an undo on the scrap */
X			/* buffer.				    */
X	};
X
Xextern	long	ftell();
Xextern	char	*mktemp();
Xextern	doing_selfinsert;
Xstatic read_last_undo();
Xstatic	int	undoing_scrap = FALSE;	/* If TRUE stops us printing 	*/
X					/* 'Undone.' twice.		*/
XFILE	*ufp = NULL;
Xenum undo_state {
X	NORMAL,
X	REDO,
X	UNDO
X	} undo_state = NORMAL;
X
Xstruct undo {
X	enum undo_opcodes	u_opcode;
X	int	u_line;
X	int	u_col;
X	ANCHOR	u_anchor;
X	RSIZE	u_length;
X	long	u_last1;		/* Used for backing up over (write_buffer) */
X					/* mark.			    */
X	long	u_last;			/* tell() position of previous undo */
X	int	u_chain;		/* Non-zero if part of a single	    */
X					/* undo.			    */
X	};
Xchar	*u_fname;
Xint	u_atend = FALSE;		/* If TRUE dont fseek to eof.	*/
Xvoid
Xu_init()
X{	char	temp_file[64];
X	char	*get_tmpdir();
X	char	*sys_delim();
X
X	sprintf(temp_file, "%s%sundoXXXXXX", get_tmpdir(), sys_delim());
X	u_fname = mktemp(temp_file);
X	
X	if ((ufp = fopen(u_fname, "w+")) == NULL) {
X		printf("Cannot create undo file:\n");
X		perror(u_fname);
X		gr_exit();
X		}
X	/*-------------------------*/
X	/* Ensure ftell(ufp) != 0) */
X	/*-------------------------*/
X	fwrite("Undo", 4, 1, ufp);
X	unlink(u_fname);
X}
Xchar *
Xget_tmpdir()
X{	extern char *ggetenv();
X	char *cp;
X	
X	if ((cp = ggetenv("BTMP")) != NULL)
X		return cp;
X	if ((cp = ggetenv("TMP")) != NULL)
X		return cp;
X# if defined(VMS)
X	return "[-]";
X# else
X	return "/tmp";
X# endif
X}
Xvoid
Xu_close()
X{
X	if (ufp)
X		unlink(u_fname);
X}
Xvoid
Xu_insert(n)
XRSIZE	n;
X{	register LINE	*clp;
X	register int	cbo;
X	register int	line;
X	struct undo undo_buf;
X
X	if (n == 0 || undo_check())
X		return;
X
X	if (undo_state == NORMAL)
X		curbp->b_nummod++;
X	undo_buf.u_opcode = INSERT;
X	undo_buf.u_length = n;
X
X	u_write(&undo_buf);
X
X	line = *cur_line;
X	cbo = current_offset(*cur_col, FALSE);
X	for ( ; line < curbp->b_numlines && n > 0; line++, cbo = 0) {
X		RSIZE	x,w;
X		clp = vm_lock_line(line);
X		x = llength(clp) - cbo;
X		w = x;
X		if (x >= n)
X			w = n;
X		fwrite(&ltext(clp)[cbo], (int) w, 1, ufp);
X		vm_unlock(line);
X		if (n -= w) {
X			fputc('\n', ufp);
X			n--;
X			}
X		}
X
X
X}
Xvoid
Xu_delete(n)
XRSIZE	n;
X{	struct undo undo_buf1;
X	struct undo undo_buf;
X	undo_info *up;
X	
X	if (n == 0 || undo_check())
X		return;
X	up = undo_state == UNDO ? &curbp->b_redo : &curbp->b_undo;
X	if (doing_selfinsert && up->u_last) {
X		if (read_last_undo(&undo_buf1, up))
X			goto normal;
X		if (undo_buf1.u_opcode == DELETE) {
X			extern char character;
X# ifdef	DEBUG
X			{char buf[128];
X			extern int dflag;
X			if (dflag & DB_UNDO) {
X				sprintf(buf, 
X					"undo(COLLAPSING, %d + %d => %d)\n",
X					undo_buf1.u_length, n, 
X					undo_buf1.u_length + n);
X				trace_log(buf, (char *) NULL);
X				}
X			}
X# endif
X			if ((isalnum(curbp->b_uchar) && isalnum(character)) ||
X			    (isspace(curbp->b_uchar) && isspace(character)) ||
X			    (curbp->b_uchar == 0x1B || character == 0x1B) ||
X			    (ispunct(curbp->b_uchar) && ispunct(character))) {
X				undo_buf1.u_length += n;
X				if (!u_atend)
X					fseek(ufp, up->u_last, 0);
X				fwrite((char *) &undo_buf1, sizeof undo_buf1, 1, ufp);
X				fseek(ufp, 0l, 2);
X				u_atend = TRUE;
X				return;
X				}
X			}
X		}
Xnormal:
X	if (undo_state == NORMAL)
X		curbp->b_nummod++;
X	undo_buf.u_opcode = DELETE;
X	undo_buf.u_length = n;
X	u_write(&undo_buf);
X
X}
Xvoid
Xu_chain()
X{	extern int playing_back;
X	if (!playing_back) {
X		curbp->b_undo.u_chain = 0;
X		curbp->b_redo.u_chain = 0;
X		}
X}
Xvoid
Xu_terminate()
X{
X	undo_info *up = undo_state == NORMAL ? &curbp->b_undo : &curbp->b_redo;
X	
X	up->u_last1 = up->u_last;
X	up->u_last = 0;
X}
Xvoid
Xu_dot()
X{	struct undo undo_buf;
X
X	if (undo_check())
X		return;
X	undo_buf.u_opcode = GOTO;
X	u_write(&undo_buf);
X}
X
Xvoid
Xu_raise()
X{	struct undo undo_buf;
X	if (undo_check())
X		return;
X	undo_buf.u_opcode = RAISE;
X	u_write(&undo_buf);
X}
Xvoid
Xu_drop()
X{	struct undo undo_buf;
X
X	if (undo_check())
X		return;
X
X	undo_buf.u_opcode = DROP;
X
X	undo_buf.u_anchor = *curbp->b_anchor;
X	u_write(&undo_buf);
X}
Xvoid
Xu_scrap()
X{	struct undo undo_buf;
X
X	if (undo_check())
X		return;
X	undo_buf.u_opcode = SCRAP;
X	u_write(&undo_buf);
X		
X}
X/* Undo utility routines. */
Xstatic
Xundo_check()
X{
X	if (/*undo_state == REDO || */curbp->b_system || ufp == NULL)
X		return TRUE;
X	/*----------------------------------------
X	/*   If user isn't undoing an undo
X	/*   then terminate the redo chain so we
X	/*   dont confuse user.
X	/*----------------------------------------*/
X	if (undo_state == NORMAL)
X		curbp->b_redo.u_last = 0;
X	return FALSE;
X}
Xstatic void
Xu_write(undop)
Xstruct undo *undop;
X{	undo_info *up;
X
X	if (undo_state == UNDO)
X		up = &curbp->b_redo;
X	else
X		up = &curbp->b_undo;
X		
X	undop->u_line = *cur_line;
X	undop->u_col = *cur_col;
X	undop->u_last1 = up->u_last1;
X	undop->u_last = up->u_last;
X	undop->u_chain = up->u_chain++;
X	if (!u_atend)
X		fseek(ufp, 0l, 2);
X	up->u_last = ftell(ufp);
X
X	u_debug(undop, undo_state == NORMAL ? "normal" :
X			undo_state == UNDO ? "undo" : "redo");
X	fwrite((char *) undop, sizeof *undop, 1, ufp);
X	u_atend = TRUE;
X}
Xu_debug(undop, str)
Xstruct undo *undop;
Xchar	*str;
X{
X# ifdef	DEBUG
X	char buf[128];
X	extern int dflag;
X	if (dflag & DB_UNDO) {
X		sprintf(buf, 
X	"%s(%s, line=%d, col=%d, len=%ld, last=%08lx, chain=%d)\n", str,
X			undop->u_opcode == GOTO ? "GOTO" :
X			undop->u_opcode == INSERT ? "INSERT" :
X			undop->u_opcode == DELETE ? "DELETE" :
X			undop->u_opcode == RAISE ? "RAISE" :
X			undop->u_opcode == DROP ? "DROP" : 
X			undop->u_opcode == SCRAP ? "SCRAP" : "??",
X			undop->u_line, undop->u_col,
X			undop->u_length, undop->u_last, undop->u_chain);
X		trace_log(buf, (char *) NULL);
X		}
X# endif
X}
Xundo()
X{	int	undo_mod = argv[1].l_flags == F_INT ? argv[1].l_int : 0;
X	int	past_mark = argv[2].l_flags == F_INT ? argv[2].l_int : 0;
X	long	num = -1;
X	static int sub_undo();
X	struct undo undo_buf;
X	enum undo_state	saved_undo_state = undo_state;
X	int	redo = argv[3].l_flags == F_INT;
X	undo_info *up = redo ? &curbp->b_redo : &curbp->b_undo;
Xtrace_log(redo ? "doing redo\n" : "doing undo\n", (char *) NULL);
X	if (up->u_last == 0 && past_mark) {
X		up->u_last = up->u_last1;
X		up->u_last1 = 0;
X		}
X	undo_state = redo ? REDO : UNDO;
X	do {
X		if (sub_undo(&undo_buf, redo, up)) {
X			undo_state = NORMAL;
X			return;
X			}
X		if (num < 0 && undo_buf.u_chain > 2)
X			ewprintf("Undoing command...");
X		if (num < 0)
X			num = undo_buf.u_chain;
X		else if (num && undo_buf.u_chain)
X			percentage(num - undo_buf.u_chain, num, "Undoing", "command");
X		if (undo_mod && 
X		    (undo_buf.u_opcode != INSERT &&
X		     undo_buf.u_opcode != DELETE))
X			undo_buf.u_chain = 1;
X		}
X	while (undo_buf.u_chain);
X	undo_state = saved_undo_state;
X	if (!undoing_scrap)
X		ewprintf(redo ? "Redone." : "Undone.");
X	return;
X}
Xstatic
Xsub_undo(undop, redo, up)
Xstruct undo *undop;
Xundo_info *up;
X{	long pos;
X	char	buf[64];
X	int	n;
X
X	if (up->u_last == 0) {
X		ewprintf("Nothing to %s.", redo ? "redo" : "undo");
X		curbp->b_flag &= ~BFCHG;
X		return -1;
X		}
X	if (read_last_undo(undop, up))
X		return -1;
X	u_debug(undop, "UNDOING");
X	up->u_last = undop->u_last;
X	up->u_last1 = undop->u_last1;
X	switch (undop->u_opcode) {
X	  case INSERT:
SHAR_EOF
echo "End of part 10"
echo "File ./undo.c is continued in part 11"
echo "11" > s2_seq_.tmp
exit 0
-- 
=====================			Reuters Ltd PLC, 
Tel: +44 628 891313 x. 212		 Westthorpe House,
UUCP:     fox%marlow.uucp@idec.stc.co.uk  Little Marlow,
					   Bucks, England SL7 3RQ