[mod.sources] v06i076: MicroEmacs, Version 3.7

sources-request@mirror.UUCP (07/30/86)

Submitted by: ihnp4!pur-ee!pur-phy!duncan!lawrence
Mod.sources: Volume 6, Issue 76
Archive-name: uEmacs3.7/Part06

[  This is the latest revision of one of two programs named "MicroEmacs";
   when discussing these on the net, or in contacting the authors, make
   sure to mention the version number -- in this case 3.7 -- as that is
   the easiest way to distinguish between them.  Daniel will be posting
   uuencoded executables in net.micro.pc and net.micro.amiga; the file
   'readme' contains information on how to also get these from him
   directly.   --r$ ]

echo extracting - fileio.c
sed 's/^X//' > fileio.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file read and write ASCII files from the disk. All of
X * the knowledge about files are here. A better message writing scheme should
X * be used.
X */
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
XFILE    *ffp;                           /* File pointer, all functions. */
X
X/*
X * Open a file for reading.
X */
Xffropen(fn)
Xchar    *fn;
X{
X        if ((ffp=fopen(fn, "r")) == NULL)
X                return (FIOFNF);
X        return (FIOSUC);
X}
X
X/*
X * Open a file for writing. Return TRUE if all is well, and FALSE on error
X * (cannot create).
X */
Xffwopen(fn)
Xchar    *fn;
X{
X#if     VMS
X        register int    fd;
X
X        if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0
X        || (ffp=fdopen(fd, "w")) == NULL) {
X#else
X        if ((ffp=fopen(fn, "w")) == NULL) {
X#endif
X                mlwrite("Cannot open file for writing");
X                return (FIOERR);
X        }
X        return (FIOSUC);
X}
X
X/*
X * Close a file. Should look at the status in all systems.
X */
Xffclose()
X{
X#if	MSDOS
X	fputc(26, ffp);		/* add a ^Z at the end of the file */
X#endif
X	
X#if     V7 | USG | BSD | (MSDOS & (LATTICE | MSC))
X        if (fclose(ffp) != FALSE) {
X                mlwrite("Error closing file");
X                return(FIOERR);
X        }
X        return(FIOSUC);
X#else
X        fclose(ffp);
X        return (FIOSUC);
X#endif
X}
X
X/*
X * Write a line to the already opened file. The "buf" points to the buffer,
X * and the "nbuf" is its length, less the free newline. Return the status.
X * Check only at the newline.
X */
Xffputline(buf, nbuf)
Xchar    buf[];
X{
X        register int    i;
X
X        for (i = 0; i < nbuf; ++i)
X                fputc(buf[i]&0xFF, ffp);
X
X        fputc('\n', ffp);
X
X        if (ferror(ffp)) {
X                mlwrite("Write I/O error");
X                return (FIOERR);
X        }
X
X        return (FIOSUC);
X}
X
X/*
X * Read a line from a file, and store the bytes in the supplied buffer. The
X * "nbuf" is the length of the buffer. Complain about long lines and lines
X * at the end of the file that don't have a newline present. Check for I/O
X * errors too. Return status.
X */
Xffgetline(buf, nbuf)
Xregister char   buf[];
X{
X        register int    c;
X        register int    i;
X
X        i = 0;
X
X        while ((c = fgetc(ffp)) != EOF && c != '\n') {
X                if (i >= nbuf-2) {
X			buf[nbuf - 2] = c;	/* store last char read */
X			buf[nbuf - 1] = 0;	/* and terminate it */
X                        mlwrite("File has long line");
X                        return (FIOLNG);
X                }
X                buf[i++] = c;
X        }
X
X        if (c == EOF) {
X                if (ferror(ffp)) {
X                        mlwrite("File read error");
X                        return (FIOERR);
X                }
X
X                if (i != 0) {
X                        mlwrite("File has funny line at EOF");
X                        return (FIOERR);
X                }
X                return (FIOEOF);
X        }
X
X        buf[i] = 0;
X        return (FIOSUC);
X}
FRIDAY_NIGHT
echo extracting - hp150.c
sed 's/^X//' > hp150.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file provide support for HP150 screens
X * and routines to access the Keyboard through KEYCODE mode.
X * It compiles into nothing if not an HP150 screen device.
X * added by Daniel Lawrence
X */
X
X#define	termdef	1			/* don't define "term" external */
X
X#include        <stdio.h>
X#include        "estruct.h"
X#include	"edef.h"
X
X#if     HP150
X
X#define NROW    24                      /* Screen size.                 */
X#define NCOL    80                      /* Edit if you want to.         */
X#define	MARGIN	8			/* size of minimim margin and	*/
X#define	SCRSIZ	64			/* scroll size for extended lines */
X#define	NPAUSE	15			/* # times thru update to pause */
X#define BEL     0x07                    /* BEL character.               */
X#define ESC     0x1B                    /* ESC character.               */
X
Xextern  int     openhp();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern	int	hpflush();
Xextern  int     closehp();
Xextern  int     hp15move();
Xextern  int     hp15eeol();
Xextern  int     hp15eeop();
Xextern  int     hp15beep();
Xextern	int	gethpkey();
Xextern	int	hp15rev();
X#if	COLOR
Xextern	int	hp15fcol();
Xextern	int	hp15bcol();
X#endif
X
X/* weird to ascii translation table */
X
Xchar trans[][2] = {
X	0x24,	9,	/* tab */
X	0x25,	13,	/* ret */
X	0x27,	8,	/* backspace */
X	0x30,	48,	/* zero */
X	0x31,	49,	/* one */
X	0x32,	50,	/* two */
X	0x33,	51,	/* three */
X	0x34,	52,	/* four */
X	0x35,	53,	/* five */
X	0x36,	54,	/* six */
X	0x37,	55,	/* seven */
X	0x38,	56,	/* eight */
X	0x39,	57,	/* nine */
X	0x50,	13,	/* enter */
X	0x54,	27,	/* break -> ESC */
X	0x55,	27,	/* esc */
X	0x58,	24,	/* stop -> ^X */
X	0x70,	45,	/* N-minus */
X	0x71,	42,	/* N-asterisk */
X	0x72,	43,	/* N-plus */
X	0x73,	47,	/* N-slash */
X	0x74,	44,	/* N-comma */
X	0x75,	13,	/* N-enter */
X	0x76,	9,	/* N-tab */
X	0x77,	46	/* N-period */
X};
X
X#define NTRANS	sizeof(trans) / 2
X
Xunion REGS r;		/* register set for bios and dos (AGIOS) calls */
Xint capslock = 0;	/* caps lock flag */
X
X/*
X * Standard terminal interface dispatch table. Most of the fields point into
X * "termio" code.
X */
XTERM    term    = {
X        NROW-1,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X	openhp,
X        closehp,
X	gethpkey,
X        ttputc,
X        hpflush,
X        hp15move,
X        hp15eeol,
X        hp15eeop,
X        hp15beep,
X        hp15rev
X#if	COLOR
X	, hp15fcol,
X	hp15bcol
X#endif
X};
X
Xhp15move(row, col)
X{
X        ttputc(ESC);
X        ttputc('&');
X        ttputc('a');
X        hp15parm(col);
X        ttputc('c');
X        hp15parm(row);
X        ttputc('R');
X}
X
Xhpflush()
X
X{
X
X}
X
Xhp15eeol()
X{
X        ttputc(ESC);
X        ttputc('K');
X}
X
Xhp15eeop()
X{
X        ttputc(ESC);
X        ttputc('J');
X}
X
Xhp15rev(status)		/* change the reverse video status */
X
Xint status;	/* TRUE = on, FALSE = off */
X
X{
X	ttputc(ESC);
X	ttputc('&');
X	ttputc('d');
X	ttputc(status ? 'B': '@');
X}
X
Xhp15beep()
X{
X        ttputc(BEL);
X        ttflush();
X}
X
Xhp15parm(n)
Xregister int    n;
X{
X        register int    q;
X
X        q = n/10;
X        if (q != 0)
X                hp15parm(q);
X        ttputc((n%10) + '0');
X}
X
X#if	COLOR
Xhp15fcol()	/* we really can't do colors here, so just ignore it */
X{
X}
X
Xhp15bcol()	/* we really can't do colors here, so just ignore it */
X{
X}
X#endif
X
Xgethpkey()	/* get a key from the HP keyboard while in keycode mode */
X
X{
X	static int keepflag = 0;	/* kept ahead char flag */
X	static int keepchar = 0;	/* kept ehead flag */
X	int c;
X	int devid;			/* device ID */
X	int ctype;			/* type of character gotten */
X	int shiftb;			/* state of shift keys */
X	int i;
X	
X	/* if we are in an extended char sequence, finish it */
X	if (keepflag != 0) {
X		keepflag = 0;
X		return(keepchar);
X	}
X
X	/* grab the next 4 char sequence */
Xnext:	shiftb = ttgetc();
X	devid = ttgetc();
X	c = ttgetc();
X	ttgetc();		/* skip null byte */
X	
X	/* make sure we are from the keyboard */
X	if (devid != 192)
X		goto next;
X
X	/* if normal ascii, return it */
X	if ((shiftb & 0x80) == 0) {
X		if (capslock && c >= 'a' && c <= 'z')
X			c -= 32;
X		return(c);
X	}
X
X	/* check specifically for the caps lock key */
X	if (c == 0x56) {
X		capslock = ~capslock;
X		goto next;
X	}
X
X	/* check to see if it needs translation */
X	for (i=0; i < NTRANS; i++)
X		if (trans[i][0] == c)
X			return((int)trans[i][1]);
X
X	/* other wise, shove it in the keep char and return the leadin code */
X	keepchar = c;
X	keepflag = 1;
X	return(0);
X}
X
Xopenhp()		/* open the HP150 keyboard for input */
X
X{
X	revexist = TRUE;
X
X	/* define key charectoristics with AGIOS call (0, 40) */
X	defkey();
X
X	/* Turn on RAW mode with MSDOS call 44h */
X	rawon();
X
X	/* Turn off Control-C checking  MS-DOS 33h */
X	ckeyoff();
X
X	/* Turn on keycode mode with AGIOS call (0,43) */
X	keycon();
X}
X
Xclosehp()		/* close the HP150 keyboard for input */
X
X{
X	/* define key charectoristics with AGIOS call (0, 40) */
X	undefkey();
X	
X	/* Turn off RAW mode with MSDOS call 44h */
X	rawoff();
X
X	/* Turn on Control-C checking  MS-DOS 33h */
X	ckeyon();
X
X	/* Turn off keycode mode with AGIOS call (0,43) */
X	keycoff();
X}
X
Xrawon()		/* put the HP150 keyboard into RAW mode */
X
X{
X	/* get the IO control info */
X
X	r.x.ax = 0x4400;	/* IO ctrl get device information */
X	r.x.bx = 0x0001;	/* File handle; 1 for console */
X	intdos(&r, &r);		/* go fer it */
X
X	r.h.dh = 0;		/* clear high byte for put */
X	r.h.dl |= 0x20;		/* set raw bit */
X
X	/* and put it back */
X
X	r.x.ax = 0x4401;	/* IO ctrl put device information */
X	r.x.bx = 0x0001;	/* File handle; 1 for console */
X	intdos(&r, &r);		/* go fer it */
X}
X
Xrawoff()	/* put the HP150 keyboard into COOKED mode */
X
X{
X	/* get the IO control info */
X
X	r.x.ax = 0x4400;	/* IO ctrl get device information */
X	r.x.bx = 0x0001;	/* File handle; 1 for console */
X	intdos(&r, &r);		/* go fer it */
X
X	r.h.dh = 0;		/* clear high byte for put */
X	r.h.dl &= 0xdf;		/* set raw bit */
X
X	/* and put it back */
X
X	r.x.ax = 0x4401;	/* IO ctrl put device information */
X	r.x.bx = 0x0001;	/* File handle; 1 for console */
X	intdos(&r, &r);		/* go fer it */
X}
X
X
Xckeyoff()	/* turn control-C trapping off */
X
X{
X	r.h.ah = 0x33;	/* ctrl-break check */
X	r.h.al = 1;	/* set the state of the ctrl-break check */
X	r.h.dl = 0;	/* turn it off */
X	intdos(&r, &r);
X}
X
Xckeyon()	/* turn control-C trapping on */
X
X{
X	r.h.ah = 0x33;	/* ctrl-break check */
X	r.h.al = 1;	/* set the state of the ctrl-break check */
X	r.h.dl = 1;	/* turn it on */
X	intdos(&r, &r);
X}
X
Xagios(buf, len)	/* perform an AGIOS call */
X
Xchar *buf;	/* sequence of bytes in command */
Xint len;	/* length of command in bytes */
X
X{
X	r.x.ax = 0x4403;	/* I/O ctrl write */
X	r.x.bx = 1;		/* console handle */
X	r.x.cx = len;		/* buffer length */
X	r.x.dx = (unsigned)buf;	/* buffer address */
X	return(intdos(&r, &r));	/* do it */
X}
X
Xkeycon()	/* turn keycode mode on */
X
X{
X	static char cmd[] = {43, 0, 1};
X
X	return(agios(&cmd[0], 3));
X}
X
Xkeycoff()	/* turn keycode mode off */
X
X{
X	static char cmd[] = {43, 0, 0};
X
X	return(agios(&cmd[0], 3));
X}
X
Xdefkey()	/* change all special keys to intercept mode */
X
X{
X	static char cmd[] = {40, 0, 2, 0, 0xfe, 0};
X
X	return(agios(&cmd[0], 6));
X}
X
Xundefkey()	/* change all special keys to intercept mode */
X
X{
X	static char cmd[] = {40, 0, 0, 0, 0xfe, 0};
X
X	return(agios(&cmd[0], 6));
X}
X
X#else
X
Xh15hello()
X
X{
X}
X#endif
FRIDAY_NIGHT
echo extracting - ibmpc.c
sed 's/^X//' > ibmpc.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file provide support for the IBM-PC and other
X * compatible terminals. It goes directly to the graphics RAM to do
X * screen output. It compiles into nothing if not an IBM-PC driver
X */
X
X#define	termdef	1			/* don't define "term" external */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X#if     IBMPC
X
X#define NROW    25                      /* Screen size.                 */
X#define NCOL    80                      /* Edit if you want to.         */
X#define	MARGIN	8			/* size of minimim margin and	*/
X#define	SCRSIZ	64			/* scroll size for extended lines */
X#define	NPAUSE	200			/* # times thru update to pause */
X#define BEL     0x07                    /* BEL character.               */
X#define ESC     0x1B                    /* ESC character.               */
X#define	SPACE	32			/* space character		*/
X#define	SCADD	0xb8000000L		/* address of screen RAM	*/
X
Xint *scptr[NROW];			/* pointer to screen lines	*/
Xint sline[NCOL];			/* screen line image		*/
X
Xextern  int     ttopen();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern  int     ttclose();
Xextern  int     ibmmove();
Xextern  int     ibmeeol();
Xextern  int     ibmeeop();
Xextern  int     ibmbeep();
Xextern  int     ibmopen();
Xextern	int	ibmrev();
Xextern	int	ibmclose();
Xextern	int	ibmputc();
X
X#if	COLOR
Xextern	int	ibmfcol();
Xextern	int	ibmbcol();
X
Xint	cfcolor = -1;		/* current forground color */
Xint	cbcolor = -1;		/* current background color */
Xint	ctrans[] =		/* ansi to ibm color translation table */
X	{0, 4, 2, 6, 1, 5, 3, 7};
X#endif
X
X/*
X * Standard terminal interface dispatch table. Most of the fields point into
X * "termio" code.
X */
XTERM    term    = {
X        NROW-1,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        ibmopen,
X        ibmclose,
X        ttgetc,
X	ibmputc,
X        ttflush,
X        ibmmove,
X        ibmeeol,
X        ibmeeop,
X        ibmbeep,
X	ibmrev
X#if	COLOR
X	, ibmfcol,
X	ibmbcol
X#endif
X};
X
Xextern union REGS rg;
X
X#if	COLOR
Xibmfcol(color)		/* set the current output color */
X
Xint color;	/* color to set */
X
X{
X	cfcolor = ctrans[color];
X}
X
Xibmbcol(color)		/* set the current background color */
X
Xint color;	/* color to set */
X
X{
X        cbcolor = ctrans[color];
X}
X#endif
X
Xibmmove(row, col)
X{
X	rg.h.ah = 2;		/* set cursor position function code */
X	rg.h.dl = col;
X	rg.h.dh = row;
X	rg.h.bh = 0;		/* set screen page number */
X	int86(0x10, &rg, &rg);
X}
X
Xibmeeol()	/* erase to the end of the line */
X
X{
X	int attr;	/* attribute byte mask to place in RAM */
X	int *lnptr;	/* pointer to the destination line */
X	int i;
X	int ccol;	/* current column cursor lives */
X	int crow;	/*	   row	*/
X
X	/* find the current cursor position */
X	rg.h.ah = 3;		/* read cursor position function code */
X	rg.h.bh = 0;		/* current video page */
X	int86(0x10, &rg, &rg);
X	ccol = rg.h.dl;		/* record current column */
X	crow = rg.h.dh;		/* and row */
X
X	/* build the attribute byte and setup the screen pointer */
X#if	COLOR
X	attr = (((cbcolor & 15) << 4) | (cfcolor & 15)) << 8;
X#else
X	attr = 0x0700;
X#endif
X	lnptr = &sline[0];
X	for (i=0; i < NCOL; i++)
X		*lnptr++ = SPACE | attr;
X
X	/* wait for vertical retrace to be off */
X	while ((inp(0x3da) & 8))
X		;
X
X	/* and to be back on */
X	while ((inp(0x3da) & 8) == 0)
X		;
X
X	/* and send the string out */
X	movmem(&sline[0], scptr[crow]+ccol, (NCOL-ccol)*2);
X
X}
X
Xibmputc(ch)	/* put a character at the current position in the
X		   current colors */
X
Xint ch;
X
X{
X	rg.h.ah = 14;		/* write char to screen with current attrs */
X	rg.h.al = ch;
X#if	COLOR
X	rg.h.bl = cfcolor;
X#else
X	rg.h.bl = 0x07;
X#endif
X	int86(0x10, &rg, &rg);
X}
X
Xibmeeop()
X{
X	int attr;		/* attribute to fill screen with */
X
X	rg.h.ah = 6;		/* scroll page up function code */
X	rg.h.al = 0;		/* # lines to scroll (clear it) */
X	rg.x.cx = 0;		/* upper left corner of scroll */
X	rg.x.dx = 0x174f;	/* lower right corner of scroll */
X#if	COLOR
X	attr = ((ctrans[gbcolor] & 15) << 4) | (ctrans[gfcolor] & 15);
X#else
X	attr = 0;
X#endif
X	rg.h.bh = attr;
X	int86(0x10, &rg, &rg);
X}
X
Xibmrev(state)		/* change reverse video state */
X
Xint state;	/* TRUE = reverse, FALSE = normal */
X
X{
X	/* This never gets used under the IBM-PC driver */
X}
X
Xibmbeep()
X{
X	bdos(6, BEL, 0);
X}
X
Xibmopen()
X{
X	scinit();
X	revexist = TRUE;
X        ttopen();
X}
X
Xibmclose()
X
X{
X#if	COLOR
X	ibmfcol(7);
X	ibmbcol(0);
X#endif
X	ttclose();
X}
X
Xscinit()	/* initialize the screen head pointers */
X
X{
X	union {
X		long laddr;	/* long form of address */
X		int *paddr;	/* pointer form of address */
X	} addr;
X	int i;
X
X	/* initialize the screen pointer array */
X	for (i = 0; i < NROW; i++) {
X		addr.laddr = SCADD + (long)(NCOL * i * 2);
X		scptr[i] = addr.paddr;
X	}
X}
X
Xscwrite(row, outstr, forg, bacg)	/* write a line out*/
X
Xint row;	/* row of screen to place outstr on */
Xchar *outstr;	/* string to write out (must be NCOL long) */
Xint forg;	/* forground color of string to write */
Xint bacg;	/* background color */
X
X{
X	int attr;	/* attribute byte mask to place in RAM */
X	int *lnptr;	/* pointer to the destination line */
X	int i;
X
X	/* build the attribute byte and setup the screen pointer */
X#if	COLOR
X	attr = (((ctrans[bacg] & 15) << 4) | (ctrans[forg] & 15)) << 8;
X#else
X	attr = (((bacg & 15) << 4) | (forg & 15)) << 8;
X#endif
X	lnptr = &sline[0];
X	for (i=0; i<NCOL; i++)
X		*lnptr++ = (outstr[i] & 255) | attr;
X
X	/* wait for vertical retrace to be off */
X	while ((inp(0x3da) & 8))
X		;
X
X	/* and to be back on */
X	while ((inp(0x3da) & 8) == 0)
X		;
X
X	/* and send the string out */
X	movmem(&sline[0], scptr[row],NCOL*2);
X}
X#else
Xibmhello()
X{
X}
X#endif
FRIDAY_NIGHT
echo extracting - input.c
sed 's/^X//' > input.c << 'FRIDAY_NIGHT'
X/*	INPUT:	Various input routines for MicroEMACS 3.7
X		written by Daniel Lawrence
X		5/9/86						*/
X
X#include	<stdio.h>
X#include	"estruct.h"
X#include	"edef.h"
X
X/*
X * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
X * ABORT. The ABORT status is returned if the user bumps out of the question
X * with a ^G. Used any time a confirmation is required.
X */
X
Xmlyesno(prompt)
X
Xchar *prompt;
X
X{
X	char c;			/* input character */
X	char buf[NPAT];		/* prompt to user */
X
X	for (;;) {
X		/* build and prompt the user */
X		strcpy(buf, prompt);
X		strcat(buf, " [y/n]? ");
X		mlwrite(buf);
X
X		/* get the responce */
X		c = (*term.t_getchar)();
X
X		if (c == BELL)		/* Bail out! */
X			return(ABORT);
X
X		if (c=='y' || c=='Y')
X			return(TRUE);
X
X		if (c=='n' || c=='N')
X			return(FALSE);
X	}
X}
X
X/*
X * Write a prompt into the message line, then read back a response. Keep
X * track of the physical position of the cursor. If we are in a keyboard
X * macro throw the prompt away, and return the remembered response. This
X * lets macros run at full speed. The reply is always terminated by a carriage
X * return. Handle erase, kill, and abort keys.
X */
X
Xmlreply(prompt, buf, nbuf)
X    char *prompt;
X    char *buf;
X{
X	return(mlreplyt(prompt,buf,nbuf,'\n'));
X}
X
X/*	A more generalized prompt/reply function allowing the caller
X	to specify the proper terminator. If the terminator is not
X	a return ('\n') it will echo as "<NL>"
X							*/
Xmlreplyt(prompt, buf, nbuf, eolchar)
X
Xchar *prompt;
Xchar *buf;
Xchar eolchar;
X
X{
X	register int cpos;	/* current character position in string */
X	register int i;
X	register int c;
X	register int quotef;	/* are we quoting the next char? */
X	register int status;	/* status return value */
X
X
X	cpos = 0;
X	quotef = FALSE;
X
X	if (kbdmop != NULL) {
X		while ((c = *kbdmop++) != '\0')
X			buf[cpos++] = c;
X
X		buf[cpos] = 0;
X
X		if (buf[0] == 0)
X			return(FALSE);
X
X		return(TRUE);
X	}
X
X	/* check to see if we are executing a command line */
X	if (clexec) {
X		status = nxtarg(buf);
X		buf[nbuf-1] = 0;	/* make sure we null terminate it */
X		return(status);
X	}
X
X	mlwrite(prompt);
X
X	for (;;) {
X	/* get a character from the user. if it is a <ret>, change it
X	   to a <NL>							*/
X		c = (*term.t_getchar)();
X		if (c == 0x0d)
X			c = '\n';
X
X		if (c == eolchar && quotef == FALSE) {
X			buf[cpos++] = 0;
X
X			if (kbdmip != NULL) {
X				if (kbdmip+cpos > &kbdm[NKBDM-3]) {
X					ctrlg(FALSE, 0);
X					(*term.t_flush)();
X					return(ABORT);
X				}
X
X				for (i=0; i<cpos; ++i)
X					*kbdmip++ = buf[i];
X				}
X
X				(*term.t_move)(term.t_nrow, 0);
X				ttcol = 0;
X				(*term.t_flush)();
X
X				if (buf[0] == 0)
X					return(FALSE);
X
X				return(TRUE);
X
X			} else if (c == 0x07 && quotef == FALSE) {
X				/* Bell, abort */
X				(*term.t_putchar)('^');
X				(*term.t_putchar)('G');
X				ttcol += 2;
X				ctrlg(FALSE, 0);
X				(*term.t_flush)();
X				return(ABORT);
X
X			} else if ((c==0x7F || c==0x08) && quotef==FALSE) {
X				/* rubout/erase */
X				if (cpos != 0) {
X					(*term.t_putchar)('\b');
X					(*term.t_putchar)(' ');
X					(*term.t_putchar)('\b');
X					--ttcol;
X
X					if (buf[--cpos] < 0x20) {
X						(*term.t_putchar)('\b');
X						(*term.t_putchar)(' ');
X						(*term.t_putchar)('\b');
X						--ttcol;
X					}
X
X					if (buf[cpos] == '\n') {
X						(*term.t_putchar)('\b');
X						(*term.t_putchar)('\b');
X						(*term.t_putchar)(' ');
X						(*term.t_putchar)(' ');
X						(*term.t_putchar)('\b');
X						(*term.t_putchar)('\b');
X						--ttcol;
X						--ttcol;
X					}
X
X					(*term.t_flush)();
X				}
X
X			} else if (c == 0x15 && quotef == FALSE) {
X				/* C-U, kill */
X				while (cpos != 0) {
X					(*term.t_putchar)('\b');
X					(*term.t_putchar)(' ');
X					(*term.t_putchar)('\b');
X					--ttcol;
X
X					if (buf[--cpos] < 0x20) {
X						(*term.t_putchar)('\b');
X						(*term.t_putchar)(' ');
X						(*term.t_putchar)('\b');
X						--ttcol;
X					}
X				}
X
X				(*term.t_flush)();
X
X			} else if (c == quotec && quotef == FALSE) {
X				quotef = TRUE;
X			} else {
X				quotef = FALSE;
X				if (cpos < nbuf-1) {
X					buf[cpos++] = c;
X
X					if ((c < ' ') && (c != '\n')) {
X						(*term.t_putchar)('^');
X						++ttcol;
X						c ^= 0x40;
X					}
X
X					if (c != '\n')
X						(*term.t_putchar)(c);
X					else {	/* put out <NL> for <ret> */
X						(*term.t_putchar)('<');
X						(*term.t_putchar)('N');
X						(*term.t_putchar)('L');
X						(*term.t_putchar)('>');
X						ttcol += 3;
X					}
X				++ttcol;
X				(*term.t_flush)();
X			}
X		}
X	}
X}
X
X/* get a command name from the command line. Command completion means
X   that pressing a <SPACE> will attempt to complete an unfinished command
X   name if it is unique.
X*/
X
Xint (*getname())()
X
X{
X	register int cpos;	/* current column on screen output */
X	register int c;
X	register char *sp;	/* pointer to string for output */
X	register NBIND *ffp;	/* first ptr to entry in name binding table */
X	register NBIND *cffp;	/* current ptr to entry in name binding table */
X	register NBIND *lffp;	/* last ptr to entry in name binding table */
X	char buf[NSTRING];	/* buffer to hold tentative command name */
X	int (*fncmatch())();
X
X	/* starting at the begining of the string buffer */
X	cpos = 0;
X
X	/* if we are executing a keyboard macro, fill our buffer from there,
X	   and attempt a straight match */
X	if (kbdmop != NULL) {
X		while ((c = *kbdmop++) != '\0')
X			buf[cpos++] = c;
X
X		buf[cpos] = 0;
X
X		/* return the result of a match */
X		return(fncmatch(&buf[0]));
X	}
X
X	/* if we are executing a command line get the next arg and match it */
X	if (clexec) {
X		if (nxtarg(buf) != TRUE)
X			return(FALSE);
X		return(fncmatch(&buf[0]));
X	}
X
X	/* build a name string from the keyboard */
X	while (TRUE) {
X		c = (*term.t_getchar)();
X
X		/* if we are at the end, just match it */
X		if (c == 0x0d) {
X			buf[cpos] = 0;
X
X			/* save keyboard macro string if needed */
X			if (kbdtext(&buf[0]) == ABORT)
X				return( (int (*)()) NULL);
X
X			/* and match it off */
X			return(fncmatch(&buf[0]));
X
X		} else if (c == 0x07) {	/* Bell, abort */
X			(*term.t_putchar)('^');
X			(*term.t_putchar)('G');
X			ttcol += 2;
X			ctrlg(FALSE, 0);
X			(*term.t_flush)();
X			return( (int (*)()) NULL);
X
X		} else if (c == 0x7F || c == 0x08) {	/* rubout/erase */
X			if (cpos != 0) {
X				(*term.t_putchar)('\b');
X				(*term.t_putchar)(' ');
X				(*term.t_putchar)('\b');
X				--ttcol;
X				--cpos;
X				(*term.t_flush)();
X			}
X
X		} else if (c == 0x15) {	/* C-U, kill */
X			while (cpos != 0) {
X				(*term.t_putchar)('\b');
X				(*term.t_putchar)(' ');
X				(*term.t_putchar)('\b');
X				--cpos;
X				--ttcol;
X			}
X
X			(*term.t_flush)();
X
X		} else if (c == ' ') {
X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
X	/* attempt a completion */
X	buf[cpos] = 0;		/* terminate it for us */
X	ffp = &names[0];	/* scan for matches */
X	while (ffp->n_func != NULL) {
X		if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
X			/* a possible match! More than one? */
X			if ((ffp + 1)->n_func == NULL ||
X			   (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
X				/* no...we match, print it */
X				sp = ffp->n_name + cpos;
X				while (*sp)
X					(*term.t_putchar)(*sp++);
X				(*term.t_flush)();
X				return(ffp->n_func);
X			} else {
X/* << << << << << << << << << << << << << << << << << */
X	/* try for a partial match against the list */
X
X	/* first scan down until we no longer match the current input */
X	lffp = (ffp + 1);
X	while ((lffp+1)->n_func != NULL) {
X		if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
X			break;
X		++lffp;
X	}
X
X	/* and now, attempt to partial complete the string, char at a time */
X	while (TRUE) {
X		/* add the next char in */
X		buf[cpos] = ffp->n_name[cpos];
X
X		/* scan through the candidates */
X		cffp = ffp + 1;
X		while (cffp <= lffp) {
X			if (cffp->n_name[cpos] != buf[cpos])
X				goto onward;
X			++cffp;
X		}
X
X		/* add the character */
X		(*term.t_putchar)(buf[cpos++]);
X	}
X/* << << << << << << << << << << << << << << << << << */
X			}
X		}
X		++ffp;
X	}
X
X	/* no match.....beep and onward */
X	(*term.t_beep)();
Xonward:;
X	(*term.t_flush)();
X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
X		} else {
X			if (cpos < NSTRING-1 && c > ' ') {
X				buf[cpos++] = c;
X				(*term.t_putchar)(c);
X			}
X
X			++ttcol;
X			(*term.t_flush)();
X		}
X	}
X}
X
Xkbdtext(buf)	/* add this text string to the current keyboard macro
X		   definition						*/
X
Xchar *buf;	/* text to add to keyboard macro */
X
X{
X	/* if we are defining a keyboard macro, save it */
X	if (kbdmip != NULL) {
X		if (kbdmip+strlen(buf) > &kbdm[NKBDM-4]) {
X			ctrlg(FALSE, 0);
X			(*term.t_flush)();
X			return(ABORT);
X		}
X
X		/* copy string in and null terminate it */
X		while (*buf)
X			*kbdmip++ = *buf++;
X		*kbdmip++ = 0;
X	}
X	return(TRUE);
X}
X
X/*	GET1KEY:	Get one keystroke. The only prefixs legal here
X			are the SPEC and CTRL prefixes.
X								*/
X
Xget1key()
X
X{
X	int    c;
X#if	AMIGA
X	int	d;
X#endif
X
X	/* get a keystroke */
X        c = (*term.t_getchar)();
X
X#if RAINBOW
X
X        if (c & Function_Key)
X                {
X                int i;
X
X                for (i = 0; i < lk_map_size; i++)
X                        if (c == lk_map[i][0])
X                                return lk_map[i][1];
X                }
X        else if (c == Shift + 015) return CTRL | 'J';
X        else if (c == Shift + 0x7F) return META | 0x7F;
X#endif
X
X#if	MSDOS
X	if (c == 0) {				/* Apply SPEC prefix	*/
X	        c = (*term.t_getchar)();
X	        if (c>=0x00 && c<=0x1F)		/* control key? */
X        	        c = CTRL | (c+'@');
X		return(SPEC | c);
X	}
X#endif
X
X#if	AMIGA
X	/* apply SPEC prefix */
X	if ((unsigned)c == 155) {
X		c = (*term.t_getchar)();
X
X		/* first try to see if it is a cursor key */
X		if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
X			return(SPEC | c);
X
X		/* next, a 2 char sequence */
X		d = (*term.t_getchar)();
X		if (d == '~')
X			return(SPEC | c);
X
X		/* decode a 3 char sequence */
X		c = d + 32;
X		/* if a shifted function key, eat the tilde */
X		if (d >= '0' && d <= '9')
X			d = (*term.t_getchar)();
X		return(SPEC | c);
X	}
X#endif
X
X#if  WANGPC
X	if (c == 0x1F) {			/* Apply SPEC prefix    */
X	        c = (*term.t_getchar)();
X		return(SPEC | c);
X	}
X#endif
X
X        if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
X                c = CTRL | (c+'@');
X        return (c);
X}
X
X/*	GETCMD:	Get a command from the keyboard. Process all applicable
X		prefix keys
X							*/
Xgetcmd()
X
X{
X	int c;		/* fetched keystroke */
X
X	/* get initial character */
X	c = get1key();
X
X	/* process META prefix */
X	if (c == metac) {
X		c = get1key();
X	        if (c>='a' && c<='z')		/* Force to upper */
X        	        c -= 0x20;
X	        if (c>=0x00 && c<=0x1F)		/* control key */
X	        	c = CTRL | (c+'@');
X		return(META | c);
X	}
X
X	/* process CTLX prefix */
X	if (c == ctlxc) {
X		c = get1key();
X	        if (c>='a' && c<='z')		/* Force to upper */
X        	        c -= 0x20;
X	        if (c>=0x00 && c<=0x1F)		/* control key */
X	        	c = CTRL | (c+'@');
X		return(CTLX | c);
X	}
X
X	/* otherwise, just return it */
X	return(c);
X}
FRIDAY_NIGHT
echo extracting - isearch.c
sed 's/^X//' > isearch.c << 'FRIDAY_NIGHT'
X/*
X * The functions in this file implement commands that perform incremental
X * searches in the forward and backward directions.  This "ISearch" command
X * is intended to emulate the same command from the original EMACS 
X * implementation (ITS).  Contains references to routines internal to
X * SEARCH.C.
X *
X * REVISION HISTORY:
X *
X *	D. R. Banks 9-May-86
X *	- added ITS EMACSlike ISearch
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X/*	string search input parameters	*/
X
X#define	PTBEG	1	/* leave the point at the beginning on search */
X#define	PTEND	2	/* leave the point at the end on search */
X
X#define	CMDBUFLEN 256	/* Length of our command buffer */
X
Xextern int forscan();			/* Handy search routine */
Xextern int eq();			/* Compare chars, match case */
X
X/* A couple of "own" variables for re-eat */
X
Xint	(*saved_get_char)();		/* Get character routine */
Xint	eaten_char = -1;		/* Re-eaten char */
X
X/* A couple more "own" variables for the command string */
X
Xchar	cmd_buff[CMDBUFLEN];	/* Save the command args here */
Xint	cmd_offset;			/* Current offset into command buff */
Xint	cmd_reexecute = -1;		/* > 0 if re-executing command */
X
X/* Some character constants within ISearch */
X
X#define	IS_ABORT	0x07	/* Abort the isearch */
X#define IS_BACKSP	0x08	/* Delete previous char */
X#define	IS_TAB		0x09	/* Tab character (allowed search char) */
X#define IS_NEWLINE	0x0D	/* New line from keyboard (Carriage return) */
X#define	IS_QUOTE	0x11	/* Quote next character */
X#define IS_REVERSE	0x12	/* Search backward */
X#define	IS_FORWARD	0x13	/* Search forward */
X#define	IS_VMSQUOTE	0x16	/* VMS quote character */
X#define	IS_VMSFORW	0x18	/* Search forward for VMS */
X#define	IS_QUIT		0x1B	/* Exit the search */
X#define	IS_RUBOUT	0x7F	/* Delete previous character */
X
X/*
X * Subroutine to do incremental reverse search.  It actually uses the
X * same code as the normal incremental search, as both can go both ways.
X */
X 
Xint risearch(f, n)
X{
X    LINE *curline;			/* Current line on entry	      */
X    int  curoff;			/* Current offset on entry	      */
X
X    /* remember the initial . on entry: */
X
X    curline = curwp->w_dotp;		/* Save the current line pointer      */
X    curoff  = curwp->w_doto;		/* Save the current offset	      */
X
X    /* Make sure the search doesn't match where we already are:		      */
X
X    backchar(TRUE, 1);			/* Back up a character		      */
X
X    if (!(isearch(f, -n)))		/* Call ISearch backwards	      */
X    {					/* If error in search:		      */
X	curwp->w_dotp = curline;	/* Reset the line pointer	      */
X	curwp->w_doto = curoff;		/*  and the offset to original value  */
X	curwp->w_flag |= WFMOVE;	/* Say we've moved		      */
X	update(FALSE);			/* And force an update		      */
X	mlwrite ("[search failed]");	/* Say we died			      */
X    } else mlerase ();			/* If happy, just erase the cmd line  */
X}
X
X/* Again, but for the forward direction */
X
Xint fisearch(f, n)
X{
X    LINE *curline;			/* Current line on entry	      */
X    int  curoff;			/* Current offset on entry	      */
X
X    /* remember the initial . on entry: */
X
X    curline = curwp->w_dotp;		/* Save the current line pointer      */
X    curoff  = curwp->w_doto;		/* Save the current offset	      */
X
X    /* do the search */
X
X    if (!(isearch(f, n)))		/* Call ISearch forwards	      */
X    {					/* If error in search:		      */
X	curwp->w_dotp = curline;	/* Reset the line pointer	      */
X	curwp->w_doto = curoff;		/*  and the offset to original value  */
X	curwp->w_flag |= WFMOVE;	/* Say we've moved		      */
X	update(FALSE);			/* And force an update		      */
X	mlwrite ("[search failed]");	/* Say we died			      */
X    } else mlerase ();			/* If happy, just erase the cmd line  */
X}
X
X/*
X * Subroutine to do an incremental search.  In general, this works similarly
X * to the older micro-emacs search function, except that the search happens
X * as each character is typed, with the screen and cursor updated with each
X * new search character.
X *
X * While searching forward, each successive character will leave the cursor
X * at the end of the entire matched string.  Typing a Control-S or Control-X
X * will cause the next occurrence of the string to be searched for (where the
X * next occurrence does NOT overlap the current occurrence).  A Control-R will
X * change to a backwards search, ESC will terminate the search and Control-G
X * will abort the search.  Rubout will back up to the previous match of the
X * string, or if the starting point is reached first, it will delete the
X * last character from the search string.
X *
X * While searching backward, each successive character will leave the cursor
X * at the beginning of the matched string.  Typing a Control-R will search
X * backward for the next occurrence of the string.  Control-S or Control-X
X * will revert the search to the forward direction.  In general, the reverse
X * incremental search is just like the forward incremental search inverted.
X *
X * In all cases, if the search fails, the user will be feeped, and the search
X * will stall until the pattern string is edited back into something that
X * exists (or until the search is aborted).
X */
X 
Xisearch(f, n)
X{
X    int			status;		/* Search status */
X    int			col;		/* prompt column */
X    register int	cpos;		/* character number in search string  */
X    register int	c;		/* current input character */
X    char		pat_save[NPAT];	/* Saved copy of the old pattern str  */
X    LINE		*curline;	/* Current line on entry	      */
X    int			curoff;		/* Current offset on entry	      */
X    int			init_direction;	/* The initial search direction	      */
X
X    /* Initialize starting conditions */
X
X    cmd_reexecute = -1;		/* We're not re-executing (yet?)      */
X    cmd_offset = 0;			/* Start at the beginning of the buff */
X    cmd_buff[0] = '\0';		/* Init the command buffer	      */
X    strncpy (pat_save, pat, NPAT);	/* Save the old pattern string	      */
X    curline = curwp->w_dotp;		/* Save the current line pointer      */
X    curoff  = curwp->w_doto;		/* Save the current offset	      */
X    init_direction = n;			/* Save the initial search direction  */
X
X    /* This is a good place to start a re-execution: */
X
Xstart_over:
X
X    /* ask the user for the text of a pattern */
X    col = promptpattern("ISearch: ");		/* Prompt, remember the col   */
X
X    cpos = 0;					/* Start afresh		      */
X    status = TRUE;				/* Assume everything's cool   */
X
X    /*
X       Get the first character in the pattern.  If we get an initial Control-S
X       or Control-R, re-use the old search string and find the first occurrence
X     */
X
X    c = get_char();				/* Get the first character    */
X    if ((c == IS_FORWARD) ||
X        (c == IS_REVERSE) ||
X        (c == IS_VMSFORW))			/* Reuse old search string?   */
X    {
X    	for (cpos = 0; pat[cpos] != 0; cpos++)	/* Yup, find the length	      */
X    	    col = echochar(pat[cpos],col);	/*  and re-echo the string    */
X	if (c == IS_REVERSE) {			/* forward search?	      */
X	    n = -1;				/* No, search in reverse      */
X	    backchar (TRUE, 1);			/* Be defensive about EOB     */
X	} else
X	    n = 1;				/* Yes, search forward	      */
X	status = scanmore(pat,n,status);	/* Do the search	      */
X	c = get_char ();			/* Get another character      */
X    }
X
X    /* Top of the per character loop */
X        	
X    for (;;)					/* ISearch per character loop */
X    {
X	/* Check for magic characters first: */
X	/* Most cases here change the search */
X
X	switch (c)				/* dispatch on the input char */
X	{
X	  case IS_ABORT:			/* If abort search request    */
X	    return(FALSE);			/* Quit searching again	      */
X
X	  case IS_REVERSE:			/* If backward search	      */
X	  case IS_FORWARD:			/* If forward search	      */
X	  case IS_VMSFORW:			/*  of either flavor	      */
X	    if (c == IS_REVERSE)		/* If reverse search	      */
X		n = -1;				/* Set the reverse direction  */
X	    else				/* Otherwise, 		      */
X		n = 1;				/*  go forward		      */
X	    status = scanmore(pat,n,TRUE);	/* Start the search again     */
X	    c = get_char ();			/* Get the next char	      */
X	    continue;				/* Go continue with the search*/
X
X	  case IS_QUIT:				/* Want to quit searching?    */
X	    return (TRUE);			/* Quit searching now	      */
X
X	  case IS_NEWLINE:			/* Carriage return	      */
X	    c = '\n';				/* Make it a new line	      */
X	    break;				/* Make sure we use it	      */
X
X	  case IS_QUOTE:			/* Quote character	      */
X	  case IS_VMSQUOTE:			/*  of either variety	      */
X	    c = get_char ();			/* Get the next char	      */
X
X	  case IS_TAB:				/* Generically allowed	      */
X	  case '\n':				/*  controlled characters     */
X	    break;				/* Make sure we use it	      */
X
X	  case IS_BACKSP:			/* If a backspace:            */
X	  case IS_RUBOUT:			/*  or if a Rubout:	      */
X	    if (cmd_offset <= 1)		/* Anything to delete?	      */
X		return (TRUE);			/* No, just exit	      */
X	    --cmd_offset;			/* Back up over the Rubout    */
X	    cmd_buff[--cmd_offset] = '\0'; /* Yes, delete last char   */
X	    curwp->w_dotp = curline;		/* Reset the line pointer     */
X	    curwp->w_doto = curoff;		/*  and the offset	      */
X	    n = init_direction;			/* Reset the search direction */
X	    strncpy (pat, pat_save, NPAT);	/* Restore the old search str */
X	    cmd_reexecute = 0;		/* Start the whole mess over  */
X	    goto start_over;			/* Let it take care of itself */
X
X	  /* Presumably a quasi-normal character comes here */
X
X	  default:				/* All other chars    	      */
X	    if (c < ' ')			/* Is it printable?	      */
X	    {					/* Nope.		      */
X		reeat (c);			/* Re-eat the char	      */
X		return (TRUE);			/* And return the last status */
X	    }
X	}  /* Switch */
X
X	/* I guess we got something to search for, so search for it	      */
X
X	pat[cpos++] = c;			/* put the char in the buffer */
X	if (cpos >= NPAT)			/* too many chars in string?  */
X	{					/* Yup.  Complain about it    */
X	    mlwrite("? Search string too long");
X	    return(TRUE);			/* Return an error	      */
X	}
X	pat[cpos] = 0;				/* null terminate the buffer  */
X	col = echochar(c,col);			/* Echo the character	      */
X	if (!status) {				/* If we lost last time	      */
X	    (*term.t_putchar)(BELL);		/* Feep again		      */
X	    (*term.t_flush)();			/* see that the feep feeps    */
X	} else					/* Otherwise, we must have won*/
X	    if (!(status = checknext(c,pat,n,status))) /* See if match	      */
X		status = scanmore(pat,n,TRUE);	/*  or find the next match    */
X	c = get_char ();			/* Get the next char	      */
X    } /* for {;;} */
X}
X
X/*
X * Trivial routine to insure that the next character in the search string is
X * still true to whatever we're pointing to in the buffer.  This routine will
X * not attempt to move the "point" if the match fails, although it will 
X * implicitly move the "point" if we're forward searching, and find a match,
X * since that's the way forward isearch works.
X *
X * If the compare fails, we return FALSE and assume the caller will call
X * scanmore or something.
X */
X
Xint checknext (chr, patrn, dir, sts)/* Check next character in search string */
Xchar	chr;			/* Next char to look for		 */
Xchar	*patrn;			/* The entire search string (incl chr)   */
Xint	dir;			/* Search direction			 */
Xint	sts;			/* Search status			 */
X{
X    register LINE *curline;		/* current line during scan	      */
X    register int curoff;		/* position within current line	      */
X    register int buffchar;		/* character at current position      */
X    int status;				/* how well things go		      */
X
X    if (!sts) return(FALSE);		/* Don't try unless ok so far	      */
X
X    /* setup the local scan pointer to current "." */
X
X    curline = curwp->w_dotp;		/* Get the current line structure     */
X    curoff  = curwp->w_doto;		/* Get the offset within that line    */
X
X    if (dir > 0)			/* If searching forward		      */
X    {
X    	if (curoff == llength(curline)) /* If at end of line		      */
X    	{
X	    curline = lforw(curline);	/* Skip to the next line	      */
X	    if (curline == curbp->b_linep)
X		return (FALSE);		/* Abort if at end of buffer	      */
X	    curoff = 0;			/* Start at the beginning of the line */
X	    buffchar = '\n';		/* And say the next char is NL	      */
X	} else
X	    buffchar = lgetc(curline, curoff++); /* Get the next char	      */
X	if (status = eq(buffchar, chr))	/* Is it what we're looking for?      */
X	{
X	    curwp->w_dotp = curline;	/* Yes, set the buffer's point	      */
X	    curwp->w_doto = curoff;	/*  to the matched character	      */
X	    curwp->w_flag |= WFMOVE;	/* Say that we've moved		      */
X	}
X	return (status);		/* And return the status	      */
X    } else				/* Else, if reverse search:	      */
X	return (match_pat (patrn));	/* See if we're in the right place    */
X}
X
X/*
X * This hack will search for the next occurrence of <pat> in the buffer, either
X * forward or backward.  It is called with the status of the prior search
X * attempt, so that it knows not to bother if it didn't work last time.  If
X * we can't find any more matches, "point" is left where it was before.  If
X * we do find a match, "point" will be at the end of the matched string for
X * forward searches and at the beginning of the matched string for reverse
X * searches.
X */
X 
Xint scanmore(patrn,dir,sts)	/* search forward or back for a pattern	      */
Xchar	*patrn;			/* string to scan for			      */
Xint	dir;			/* direction to search			      */
Xint	sts;			/* previous search status		      */
X{
X    if (sts) 			/* don't try unless successful last time      */
X    {
X    	if (dir < 0)				/* reverse search?	      */
X	    sts = bakscan(patrn);		/* Yes, call our hacky routine*/
X	else
X	    sts = forscan(patrn,PTEND);		/* Nope. Go forward	      */
X    }
X    if (!sts) {
X    	(*term.t_putchar)(BELL);		/* Feep if search fails       */
X	(*term.t_flush)();			/* see that the feep feeps    */
X    }
X    return(sts);				/* else, don't even try	      */
X}
X
X/*
X * The following is a minimal implementation of the reverse of "forscan".
X * We aren't using the routine in SEARCH.C because it likes to type stuff,
X * but the real solution is probably to fix that instead of duplicate the
X * code here like we're doing.  On the other hand, we don't want to touch
X * more modules than we have to for this first round ...
X *
X * This always leaves "." at the beginning of the matched pattern string
X */
X
Xint bakscan (patrn)		/* Scan backwards for a match		      */
Xchar	*patrn;			/* Search string to be matched		      */
X{
X    LINE *initline;			/* initial line pointer before scan   */
X    int initoff;			/* position within initial line	      */
X
X    /* Remember "point" on entry: */
X
X    initline = curwp->w_dotp;		/* Get the current line structure     */
X    initoff  = curwp->w_doto;		/* Get the offset within that line    */
X
X    /*
X     * Loop here, stepping the cursor until we match or until we reach the top
X     * of the buffer
X     */
X
X    while (backchar(TRUE, 1))			/* As long as there're chars  */
X	if (match_pat (patrn))			/* See if we match	      */
X	    return (TRUE);			/* Yep.  Stop'er right here   */
X    curwp->w_dotp = initline;			/* Top of buffer, just reset  */
X    curwp->w_doto = initoff;			/*   to original "point"      */
X    curwp->w_flag |= WFMOVE;			/* In case backchar moved us  */
X    return (FALSE);				/* And return failure	      */
X}
X
X/*
X * The following is a worker subroutine used by the reverse search.  It
X * compares the pattern string with the characters at "." for equality. If
X * any characters mismatch, it will return FALSE.
X *
X * This isn't used for forward searches, because forward searches leave "."
X * at the end of the search string (instead of in front), so all that needs to
X * be done is match the last char input.
X */
X
Xint match_pat (patrn)	/* See if the pattern string matches string at "."   */
Xchar	*patrn;		/* String to match to buffer			     */
X{
X    register int  i;			/* Generic loop index/offset	      */
X    register int buffchar;		/* character at current position      */
X    register LINE *curline;		/* current line during scan	      */
X    register int curoff;		/* position within current line	      */
X
X    /* setup the local scan pointer to current "." */
X
X    curline = curwp->w_dotp;		/* Get the current line structure     */
X    curoff  = curwp->w_doto;		/* Get the offset within that line    */
X
X    /* top of per character compare loop: */
X
X    for (i = 0; i < strlen(patrn); i++)	/* Loop for all characters in patrn   */
X    {
X    	if (curoff == llength(curline)) /* If at end of line		      */
X    	{
X	    curline = lforw(curline);	/* Skip to the next line	      */
X	    curoff = 0;			/* Start at the beginning of the line */
X	    if (curline == curbp->b_linep)
X		return (FALSE);		/* Abort if at end of buffer	      */
X	    buffchar = '\n';		/* And say the next char is NL	      */
X	} else
X	    buffchar = lgetc(curline, curoff++); /* Get the next char	      */
X	if (!eq(buffchar, patrn[i]))	/* Is it what we're looking for?      */
X	    return (FALSE);		/* Nope, just punt it then	      */
X    }
X    return (TRUE);			/* Everything matched? Let's celebrate*/
X}
X
X/* Routine to prompt for I-Search string. */
X
Xint promptpattern(prompt)
Xchar *prompt;
X{
X    char tpat[NPAT+20];
X
X    strcpy(tpat, prompt);		/* copy prompt to output string */
X    strcat(tpat, " [");			/* build new prompt string */
X    expandp(pat, &tpat[strlen(tpat)], NPAT/2);	/* add old pattern */
X    strcat(tpat, "]<ESC>: ");
X
X    /* check to see if we are executing a command line */
X    if (!clexec) {
X	mlwrite(tpat);
X    }
X    return(strlen(tpat));
X}
X
X/* routine to echo i-search characters */
X
Xint echochar(c,col)
Xint	c;	/* character to be echoed */
Xint	col;	/* column to be echoed in */
X{
X    movecursor(term.t_nrow,col);		/* Position the cursor	      */
X    if ((c < ' ') || (c == 0x7F))		/* Control character?	      */
X    {
X	switch (c)				/* Yes, dispatch special cases*/
X	{
X	  case '\n':				/* Newline		      */
X	    (*term.t_putchar)('<');
X	    (*term.t_putchar)('N');
X	    (*term.t_putchar)('L');
X	    (*term.t_putchar)('>');
X	    col += 3;
X	    break;
X
X	  case '\t':				/* Tab			      */
X	    (*term.t_putchar)('<');
X	    (*term.t_putchar)('T');
X	    (*term.t_putchar)('A');
X	    (*term.t_putchar)('B');
X	    (*term.t_putchar)('>');
X	    col += 4;
X	    break;
X
X	  case 0x7F:				/* Rubout:		      */
X	    (*term.t_putchar)('^');		/* Output a funny looking     */
X	    (*term.t_putchar)('?');		/*  indication of Rubout      */
X	    col++;				/* Count the extra char       */
X	    break;
X
X	  default:				/* Vanilla control char       */
X	    (*term.t_putchar)('^');		/* Yes, output prefix	      */
X    	    (*term.t_putchar)(c+0x40);		/* Make it "^X"		      */
X	    col++;				/* Count this char	      */
X	}
X    } else
X	(*term.t_putchar)(c);			/* Otherwise, output raw char */
X    (*term.t_flush)();				/* Flush the output	      */
X    return(++col);				/* return the new column no   */
X}
X
X/*
X * Routine to get the next character from the input stream.  If we're reading
X * from the real terminal, force a screen update before we get the char. 
X * Otherwise, we must be re-executing the command string, so just return the
X * next character.
X */
X
Xint get_char ()
X{
X    int	c;				/* A place to get a character	      */
X
X    /* See if we're re-executing: */
X
X    if (cmd_reexecute >= 0)		/* Is there an offset?		      */
X	if ((c = cmd_buff[cmd_reexecute++]) != 0)
X	    return (c);			/* Yes, return any character	      */
X
X    /* We're not re-executing (or aren't any more).  Try for a real char      */
X
X    cmd_reexecute = -1;		/* Say we're in real mode again	      */
X    update(FALSE);			/* Pretty up the screen		      */
X    if (cmd_offset >= CMDBUFLEN-1)	/* If we're getting too big ...	      */
X    {
X	mlwrite ("? command too long");	/* Complain loudly and bitterly	      */
X	return (IS_QUIT);		/* And force a quit		      */
X    }
X    c = (*term.t_getchar)();		/* Get the next character	      */
X    cmd_buff[cmd_offset++] = c; /* Save the char for next time        */
X    cmd_buff[cmd_offset] = '\0';/* And terminate the buffer	      */
X    return (c);				/* Return the character		      */
X}
X
X/*
X * Hacky routine to re-eat a character.  This will save the character to be
X * re-eaten by redirecting the input call to a routine here.  Hack, etc.
X */
X
X/* Come here on the next term.t_getchar call: */
X
Xint uneat()
X{
X    int c;
X
X    term.t_getchar = saved_get_char;	/* restore the routine address	      */
X    c = eaten_char;			/* Get the re-eaten char	      */
X    eaten_char = -1;			/* Clear the old char		      */
X    return(c);				/* and return the last char	      */
X}
X
Xint reeat(c)
Xint	c;
X{
X    if (eaten_char != -1)		/* If we've already been here	      */
X	return (NULL);			/* Don't do it again		      */
X    eaten_char = c;			/* Else, save the char for later      */
X    saved_get_char = term.t_getchar;	/* Save the char get routine	      */
X    term.t_getchar = uneat;		/* Replace it with ours		      */
X}
X
FRIDAY_NIGHT
echo es.6 completed!
: That's all folks!