[comp.sources.misc] MicroEmacs 3.9

allbery@ncoast.UUCP (11/15/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.1')
# If you do not see the message
#	`mes.1 completed!'
# then the file was incomplete.
echo extracting - ansi.c
sed 's/^X//' > ansi.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file provide support for ANSI style terminals
X * over a serial line. The serial I/O services are provided by routines in
X * "termio.c". It compiles into nothing if not an ANSI device.
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     ANSI
X
X#if	AMIGA
X#define NROW    23                      /* Screen size.                 */
X#define NCOL    77                      /* Edit if you want to.         */
X#else
X#define NROW    25                      /* Screen size.                 */
X#define NCOL    80                      /* Edit if you want to.         */
X#endif
X#define	NPAUSE	100			/* # times thru update to pause */
X#define	MARGIN	8			/* size of minimim margin and	*/
X#define	SCRSIZ	64			/* scroll size for extended lines */
X#define BEL     0x07                    /* BEL character.               */
X#define ESC     0x1B                    /* ESC character.               */
X
Xextern  int     ttopen();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern  int     ttclose();
Xextern  int     ansimove();
Xextern  int     ansieeol();
Xextern  int     ansieeop();
Xextern  int     ansibeep();
Xextern  int     ansiopen();
Xextern	int	ansirev();
Xextern	int	ansiclose();
Xextern	int	ansikopen();
Xextern	int	ansikclose();
Xextern	int	ansicres();
X
X#if	COLOR
Xextern	int	ansifcol();
Xextern	int	ansibcol();
X
Xint	cfcolor = -1;		/* current forground color */
Xint	cbcolor = -1;		/* current background color */
X
X#if	AMIGA
X/* apperently the AMIGA does not follow the ANSI standards as
X   regards to colors....maybe because of the default pallette
X   settings?
X*/
X
Xint coltran[8] = {2, 3, 5, 7, 0, 4, 6, 1};	/* color translation table */
X#endif
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        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        ansiopen,
X        ansiclose,
X	ansikopen,
X	ansikclose,
X        ttgetc,
X        ttputc,
X        ttflush,
X        ansimove,
X        ansieeol,
X        ansieeop,
X        ansibeep,
X	ansirev,
X	ansicres
X#if	COLOR
X	, ansifcol,
X	ansibcol
X#endif
X};
X
X#if	COLOR
Xansifcol(color)		/* set the current output color */
X
Xint color;	/* color to set */
X
X{
X	if (color == cfcolor)
X		return;
X	ttputc(ESC);
X	ttputc('[');
X#if	AMIGA
X	ansiparm(coltran[color]+30);
X#else
X	ansiparm(color+30);
X#endif
X	ttputc('m');
X	cfcolor = color;
X}
X
Xansibcol(color)		/* set the current background color */
X
Xint color;	/* color to set */
X
X{
X	if (color == cbcolor)
X		return;
X	ttputc(ESC);
X	ttputc('[');
X#if	AMIGA
X	ansiparm(coltran[color]+40);
X#else
X	ansiparm(color+40);
X#endif
X	ttputc('m');
X        cbcolor = color;
X}
X#endif
X
Xansimove(row, col)
X{
X        ttputc(ESC);
X        ttputc('[');
X        ansiparm(row+1);
X        ttputc(';');
X        ansiparm(col+1);
X        ttputc('H');
X}
X
Xansieeol()
X{
X        ttputc(ESC);
X        ttputc('[');
X        ttputc('K');
X}
X
Xansieeop()
X{
X#if	COLOR
X	ansifcol(gfcolor);
X	ansibcol(gbcolor);
X#endif
X        ttputc(ESC);
X        ttputc('[');
X        ttputc('J');
X}
X
Xansirev(state)		/* change reverse video state */
X
Xint state;	/* TRUE = reverse, FALSE = normal */
X
X{
X#if	COLOR
X	int ftmp, btmp;		/* temporaries for colors */
X#endif
X
X	ttputc(ESC);
X	ttputc('[');
X	ttputc(state ? '7': '0');
X	ttputc('m');
X#if	COLOR
X	if (state == FALSE) {
X		ftmp = cfcolor;
X		btmp = cbcolor;
X		cfcolor = -1;
X		cbcolor = -1;
X		ansifcol(ftmp);
X		ansibcol(btmp);
X	}
X#endif
X}
X
Xansicres()	/* change screen resolution */
X
X{
X	return(TRUE);
X}
X
Xspal(dummy)		/* change pallette settings */
X
X{
X	/* none for now */
X}
X
Xansibeep()
X{
X        ttputc(BEL);
X        ttflush();
X}
X
Xansiparm(n)
Xregister int    n;
X{
X        register int q,r;
X
X        q = n/10;
X        if (q != 0) {
X		r = q/10;
X		if (r != 0) {
X			ttputc((r%10)+'0');
X		}
X		ttputc((q%10) + '0');
X        }
X        ttputc((n%10) + '0');
X}
X
Xansiopen()
X{
X#if     V7 | USG | BSD
X        register char *cp;
X        char *getenv();
X
X        if ((cp = getenv("TERM")) == NULL) {
X                puts("Shell variable TERM not defined!");
X                exit(1);
X        }
X        if (strcmp(cp, "vt100") != 0) {
X                puts("Terminal type not 'vt100'!");
X                exit(1);
X        }
X#endif
X	strcpy(sres, "NORMAL");
X	revexist = TRUE;
X        ttopen();
X}
X
Xansiclose()
X
X{
X#if	COLOR
X	ansifcol(7);
X	ansibcol(0);
X#endif
X	ttclose();
X}
X
Xansikopen()	/* open the keyboard (a noop here) */
X
X{
X}
X
Xansikclose()	/* close the keyboard (a noop here) */
X
X{
X}
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument [unused] */
X
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X#else
Xansihello()
X{
X}
X#endif
FRIDAY_NIGHT
echo extracting - basic.c
sed 's/^X//' > basic.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file move the cursor around on the screen. They
X * compute a new value for the cursor, then adjust ".". The display code
X * always updates the cursor location, so only moves between lines, or
X * functions that adjust the top line in the window and invalidate the
X * framing, are hard.
X */
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X/*
X * Move the cursor to the
X * beginning of the current line.
X * Trivial.
X */
Xgotobol(f, n)
X{
X        curwp->w_doto  = 0;
X        return (TRUE);
X}
X
X/*
X * Move the cursor backwards by "n" characters. If "n" is less than zero call
X * "forwchar" to actually do the move. Otherwise compute the new cursor
X * location. Error if you try and move out of the buffer. Set the flag if the
X * line pointer for dot changes.
X */
Xbackchar(f, n)
Xregister int    n;
X{
X        register LINE   *lp;
X
X        if (n < 0)
X                return (forwchar(f, -n));
X        while (n--) {
X                if (curwp->w_doto == 0) {
X                        if ((lp=lback(curwp->w_dotp)) == curbp->b_linep)
X                                return (FALSE);
X                        curwp->w_dotp  = lp;
X                        curwp->w_doto  = llength(lp);
X                        curwp->w_flag |= WFMOVE;
X                } else
X                        curwp->w_doto--;
X        }
X        return (TRUE);
X}
X
X/*
X * Move the cursor to the end of the current line. Trivial. No errors.
X */
Xgotoeol(f, n)
X{
X        curwp->w_doto  = llength(curwp->w_dotp);
X        return (TRUE);
X}
X
X/*
X * Move the cursor forwards by "n" characters. If "n" is less than zero call
X * "backchar" to actually do the move. Otherwise compute the new cursor
X * location, and move ".". Error if you try and move off the end of the
X * buffer. Set the flag if the line pointer for dot changes.
X */
Xforwchar(f, n)
Xregister int    n;
X{
X        if (n < 0)
X                return (backchar(f, -n));
X        while (n--) {
X                if (curwp->w_doto == llength(curwp->w_dotp)) {
X                        if (curwp->w_dotp == curbp->b_linep)
X                                return (FALSE);
X                        curwp->w_dotp  = lforw(curwp->w_dotp);
X                        curwp->w_doto  = 0;
X                        curwp->w_flag |= WFMOVE;
X                } else
X                        curwp->w_doto++;
X        }
X        return (TRUE);
X}
X
Xgotoline(f, n)		/* move to a particular line.
X			   argument (n) must be a positive integer for
X			   this to actually do anything		*/
X
X{
X	register int status;	/* status return */
X	char arg[NSTRING];	/* buffer to hold argument */
X
X	/* get an argument if one doesnt exist */
X	if (f == FALSE) {
X		if ((status = mlreply("Line to GOTO: ", arg, NSTRING)) != TRUE) {
X			mlwrite("[Aborted]");
X			return(status);
X		}
X		n = atoi(arg);
X	}
X
X	if (n < 1)		/* if a bogus argument...then leave */
X		return(FALSE);
X
X	/* first, we go to the start of the buffer */
X        curwp->w_dotp  = lforw(curbp->b_linep);
X        curwp->w_doto  = 0;
X	return(forwline(f, n-1));
X}
X
X/*
X * Goto the beginning of the buffer. Massive adjustment of dot. This is
X * considered to be hard motion; it really isn't if the original value of dot
X * is the same as the new value of dot. Normally bound to "M-<".
X */
Xgotobob(f, n)
X{
X        curwp->w_dotp  = lforw(curbp->b_linep);
X        curwp->w_doto  = 0;
X        curwp->w_flag |= WFHARD;
X        return (TRUE);
X}
X
X/*
X * Move to the end of the buffer. Dot is always put at the end of the file
X * (ZJ). The standard screen code does most of the hard parts of update.
X * Bound to "M->".
X */
Xgotoeob(f, n)
X{
X        curwp->w_dotp  = curbp->b_linep;
X        curwp->w_doto  = 0;
X        curwp->w_flag |= WFHARD;
X        return (TRUE);
X}
X
X/*
X * Move forward by full lines. If the number of lines to move is less than
X * zero, call the backward line function to actually do it. The last command
X * controls how the goal column is set. Bound to "C-N". No errors are
X * possible.
X */
Xforwline(f, n)
X{
X        register LINE   *dlp;
X
X        if (n < 0)
X                return (backline(f, -n));
X
X	/* if we are on the last line as we start....fail the command */
X	if (curwp->w_dotp == curbp->b_linep)
X		return(FALSE);
X
X	/* if the last command was not note a line move,
X	   reset the goal column */
X        if ((lastflag&CFCPCN) == 0)
X                curgoal = getccol(FALSE);
X
X	/* flag this command as a line move */
X        thisflag |= CFCPCN;
X
X	/* and move the point down */
X        dlp = curwp->w_dotp;
X        while (n-- && dlp!=curbp->b_linep)
X                dlp = lforw(dlp);
X
X	/* reseting the current position */
X        curwp->w_dotp  = dlp;
X        curwp->w_doto  = getgoal(dlp);
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
X}
X
X/*
X * This function is like "forwline", but goes backwards. The scheme is exactly
X * the same. Check for arguments that are less than zero and call your
X * alternate. Figure out the new line and call "movedot" to perform the
X * motion. No errors are possible. Bound to "C-P".
X */
Xbackline(f, n)
X{
X        register LINE   *dlp;
X
X        if (n < 0)
X                return (forwline(f, -n));
X
X
X	/* if we are on the last line as we start....fail the command */
X	if (lback(curwp->w_dotp) == curbp->b_linep)
X		return(FALSE);
X
X	/* if the last command was not note a line move,
X	   reset the goal column */
X        if ((lastflag&CFCPCN) == 0)
X                curgoal = getccol(FALSE);
X
X	/* flag this command as a line move */
X        thisflag |= CFCPCN;
X
X	/* and move the point up */
X        dlp = curwp->w_dotp;
X        while (n-- && lback(dlp)!=curbp->b_linep)
X                dlp = lback(dlp);
X
X	/* reseting the current position */
X        curwp->w_dotp  = dlp;
X        curwp->w_doto  = getgoal(dlp);
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
X}
X
X#if	WORDPRO
Xgotobop(f, n)	/* go back to the beginning of the current paragraph
X		   here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
X		   combination to delimit the beginning of a paragraph	*/
X
Xint f, n;	/* default Flag & Numeric argument */
X
X{
X	register int suc;	/* success of last backchar */
X
X	if (n < 0)	/* the other way...*/
X		return(gotoeop(f, -n));
X
X	while (n-- > 0) {	/* for each one asked for */
X
X		/* first scan back until we are in a word */
X		suc = backchar(FALSE, 1);
X		while (!inword() && suc)
X			suc = backchar(FALSE, 1);
X		curwp->w_doto = 0;	/* and go to the B-O-Line */
X
X		/* and scan back until we hit a <NL><NL> or <NL><TAB>
X		   or a <NL><SPACE>					*/
X		while (lback(curwp->w_dotp) != curbp->b_linep)
X			if (llength(curwp->w_dotp) != 0 &&
X			    lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
X			    lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
X				curwp->w_dotp = lback(curwp->w_dotp);
X			else
X				break;
X
X		/* and then forward until we are in a word */
X		suc = forwchar(FALSE, 1);
X		while (suc && !inword())
X			suc = forwchar(FALSE, 1);
X	}
X	curwp->w_flag |= WFMOVE;	/* force screen update */
X	return(TRUE);
X}
X
Xgotoeop(f, n)	/* go forword to the end of the current paragraph
X		   here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
X		   combination to delimit the beginning of a paragraph	*/
X
Xint f, n;	/* default Flag & Numeric argument */
X
X{
X	register int suc;	/* success of last backchar */
X
X	if (n < 0)	/* the other way...*/
X		return(gotobop(f, -n));
X
X	while (n-- > 0) {	/* for each one asked for */
X
X		/* first scan forward until we are in a word */
X		suc = forwchar(FALSE, 1);
X		while (!inword() && suc)
X			suc = forwchar(FALSE, 1);
X		curwp->w_doto = 0;	/* and go to the B-O-Line */
X		if (suc)	/* of next line if not at EOF */
X			curwp->w_dotp = lforw(curwp->w_dotp);
X
X		/* and scan forword until we hit a <NL><NL> or <NL><TAB>
X		   or a <NL><SPACE>					*/
X		while (curwp->w_dotp != curbp->b_linep) {
X			if (llength(curwp->w_dotp) != 0 &&
X			    lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
X			    lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
X				curwp->w_dotp = lforw(curwp->w_dotp);
X			else
X				break;
X		}
X
X		/* and then backward until we are in a word */
X		suc = backchar(FALSE, 1);
X		while (suc && !inword()) {
X			suc = backchar(FALSE, 1);
X		}
X		curwp->w_doto = llength(curwp->w_dotp);	/* and to the EOL */
X	}
X	curwp->w_flag |= WFMOVE;	/* force screen update */
X	return(TRUE);
X}
X#endif
X
X/*
X * This routine, given a pointer to a LINE, and the current cursor goal
X * column, return the best choice for the offset. The offset is returned.
X * Used by "C-N" and "C-P".
X */
Xgetgoal(dlp)
Xregister LINE   *dlp;
X{
X        register int    c;
X        register int    col;
X        register int    newcol;
X        register int    dbo;
X
X        col = 0;
X        dbo = 0;
X        while (dbo != llength(dlp)) {
X                c = lgetc(dlp, dbo);
X                newcol = col;
X                if (c == '\t')
X                        newcol |= 0x07;
X                else if (c<0x20 || c==0x7F)
X                        ++newcol;
X                ++newcol;
X                if (newcol > curgoal)
X                        break;
X                col = newcol;
X                ++dbo;
X        }
X        return (dbo);
X}
X
X/*
X * Scroll forward by a specified number of lines, or by a full page if no
X * argument. Bound to "C-V". The "2" in the arithmetic on the window size is
X * the overlap; this value is the default overlap value in ITS EMACS. Because
X * this zaps the top line in the display window, we have to do a hard update.
X */
Xforwpage(f, n)
Xregister int    n;
X{
X        register LINE   *lp;
X
X        if (f == FALSE) {
X                n = curwp->w_ntrows - 2;        /* Default scroll.      */
X                if (n <= 0)                     /* Forget the overlap   */
X                        n = 1;                  /* if tiny window.      */
X        } else if (n < 0)
X                return (backpage(f, -n));
X#if     CVMVAS
X        else                                    /* Convert from pages   */
X                n *= curwp->w_ntrows;           /* to lines.            */
X#endif
X        lp = curwp->w_linep;
X        while (n-- && lp!=curbp->b_linep)
X                lp = lforw(lp);
X        curwp->w_linep = lp;
X        curwp->w_dotp  = lp;
X        curwp->w_doto  = 0;
X        curwp->w_flag |= WFHARD;
X        return (TRUE);
X}
X
X/*
X * This command is like "forwpage", but it goes backwards. The "2", like
X * above, is the overlap between the two windows. The value is from the ITS
X * EMACS manual. Bound to "M-V". We do a hard update for exactly the same
X * reason.
X */
Xbackpage(f, n)
Xregister int    n;
X{
X        register LINE   *lp;
X
X        if (f == FALSE) {
X                n = curwp->w_ntrows - 2;        /* Default scroll.      */
X                if (n <= 0)                     /* Don't blow up if the */
X                        n = 1;                  /* window is tiny.      */
X        } else if (n < 0)
X                return (forwpage(f, -n));
X#if     CVMVAS
X        else                                    /* Convert from pages   */
X                n *= curwp->w_ntrows;           /* to lines.            */
X#endif
X        lp = curwp->w_linep;
X        while (n-- && lback(lp)!=curbp->b_linep)
X                lp = lback(lp);
X        curwp->w_linep = lp;
X        curwp->w_dotp  = lp;
X        curwp->w_doto  = 0;
X        curwp->w_flag |= WFHARD;
X        return (TRUE);
X}
X
X/*
X * Set the mark in the current window to the value of "." in the window. No
X * errors are possible. Bound to "M-.".
X */
Xsetmark(f, n)
X{
X        curwp->w_markp = curwp->w_dotp;
X        curwp->w_marko = curwp->w_doto;
X        mlwrite("[Mark set]");
X        return (TRUE);
X}
X
X/*
X * Swap the values of "." and "mark" in the current window. This is pretty
X * easy, bacause all of the hard work gets done by the standard routine
X * that moves the mark about. The only possible error is "no mark". Bound to
X * "C-X C-X".
X */
Xswapmark(f, n)
X{
X        register LINE   *odotp;
X        register int    odoto;
X
X        if (curwp->w_markp == NULL) {
X                mlwrite("No mark in this window");
X                return (FALSE);
X        }
X        odotp = curwp->w_dotp;
X        odoto = curwp->w_doto;
X        curwp->w_dotp  = curwp->w_markp;
X        curwp->w_doto  = curwp->w_marko;
X        curwp->w_markp = odotp;
X        curwp->w_marko = odoto;
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
X}
FRIDAY_NIGHT
echo extracting - bind.c
sed 's/^X//' > bind.c << 'FRIDAY_NIGHT'
X/*	This file is for functions having to do with key bindings,
X	descriptions, help commands and startup file.
X
X	written 11-feb-86 by Daniel Lawrence
X								*/
X
X#include	<stdio.h>
X#include	"estruct.h"
X#include	"edef.h"
X#include	"epath.h"
X
Xextern int meta(), cex(), unarg(), ctrlg(); /* dummy prefix binding functions */
X
Xhelp(f, n)	/* give me some help!!!!
X		   bring up a fake buffer and read the help file
X		   into it with view mode			*/
X{
X	register WINDOW *wp;	/* scaning pointer to windows */
X	register BUFFER *bp;	/* buffer pointer to help */
X	char *fname;		/* ptr to file returned by flook() */
X
X	/* first check if we are already here */
X	bp = bfind("emacs.hlp", FALSE, BFINVS);
X
X	if (bp == NULL) {
X		fname = flook(pathname[1], FALSE);
X		if (fname == NULL) {
X			mlwrite("[Help file is not online]");
X			return(FALSE);
X		}
X	}
X
X	/* split the current window to make room for the help stuff */
X	if (splitwind(FALSE, 1) == FALSE)
X			return(FALSE);
X
X	if (bp == NULL) {
X		/* and read the stuff in */
X		if (getfile(fname, FALSE) == FALSE)
X			return(FALSE);
X	} else
X		swbuffer(bp);
X
X	/* make this window in VIEW mode, update all mode lines */
X	curwp->w_bufp->b_mode |= MDVIEW;
X	curwp->w_bufp->b_flag |= BFINVS;
X	wp = wheadp;
X	while (wp != NULL) {
X		wp->w_flag |= WFMODE;
X		wp = wp->w_wndp;
X	}
X	return(TRUE);
X}
X
Xdeskey(f, n)	/* describe the command for a certain key */
X
X{
X	register int c;		/* key to describe */
X	register char *ptr;	/* string pointer to scan output strings */
X	char outseq[NSTRING];	/* output buffer for command sequence */
X	int (*getbind())();
X
X	/* prompt the user to type us a key to describe */
X	mlwrite(": describe-key ");
X
X	/* get the command sequence to describe
X	   change it to something we can print as well */
X	cmdstr(c = getckey(FALSE), &outseq[0]);
X
X	/* and dump it out */
X	ostring(outseq);
X	ostring(" ");
X
X	/* find the right ->function */
X	if ((ptr = getfname(getbind(c))) == NULL)
X		ptr = "Not Bound";
X
X	/* output the command sequence */
X	ostring(ptr);
X}
X
X/* bindtokey:	add a new key to the key binding table		*/
X
Xbindtokey(f, n)
X
Xint f, n;	/* command arguments [IGNORED] */
X
X{
X	register unsigned int c;/* command key to bind */
X	register int (*kfunc)();/* ptr to the requested function to bind to */
X	register KEYTAB *ktp;	/* pointer into the command table */
X	register int found;	/* matched command flag */
X	char outseq[80];	/* output buffer for keystroke sequence */
X	int (*getname())();
X
X	/* prompt the user to type in a key to bind */
X	mlwrite(": bind-to-key ");
X
X	/* get the function name to bind it to */
X	kfunc = getname();
X	if (kfunc == NULL) {
X		mlwrite("[No such function]");
X		return(FALSE);
X	}
X	ostring(" ");
X
X	/* get the command sequence to bind */
X	c = getckey((kfunc == meta) || (kfunc == cex) ||
X	            (kfunc == unarg) || (kfunc == ctrlg));
X
X	/* change it to something we can print as well */
X	cmdstr(c, &outseq[0]);
X
X	/* and dump it out */
X	ostring(outseq);
X
X	/* if the function is a prefix key */
X	if (kfunc == meta || kfunc == cex ||
X	    kfunc == unarg || kfunc == ctrlg) {
X
X		/* search for an existing binding for the prefix key */
X		ktp = &keytab[0];
X		found = FALSE;
X		while (ktp->k_fp != NULL) {
X			if (ktp->k_fp == kfunc)
X				unbindchar(ktp->k_code);
X			++ktp;
X		}
X
X		/* reset the appropriate global prefix variable */
X		if (kfunc == meta)
X			metac = c;
X		if (kfunc == cex)
X			ctlxc = c;
X		if (kfunc == unarg)
X			reptc = c;
X		if (kfunc == ctrlg)
X			abortc = c;
X	}
X
X	/* search the table to see if it exists */
X	ktp = &keytab[0];
X	found = FALSE;
X	while (ktp->k_fp != NULL) {
X		if (ktp->k_code == c) {
X			found = TRUE;
X			break;
X		}
X		++ktp;
X	}
X
X	if (found) {	/* it exists, just change it then */
X		ktp->k_fp = kfunc;
X	} else {	/* otherwise we need to add it to the end */
X		/* if we run out of binding room, bitch */
X		if (ktp >= &keytab[NBINDS]) {
X			mlwrite("Binding table FULL!");
X			return(FALSE);
X		}
X
X		ktp->k_code = c;	/* add keycode */
X		ktp->k_fp = kfunc;	/* and the function pointer */
X		++ktp;			/* and make sure the next is null */
X		ktp->k_code = 0;
X		ktp->k_fp = NULL;
X	}
X	return(TRUE);
X}
X
X/* unbindkey:	delete a key from the key binding table	*/
X
Xunbindkey(f, n)
X
Xint f, n;	/* command arguments [IGNORED] */
X
X{
X	register int c;		/* command key to unbind */
X	char outseq[80];	/* output buffer for keystroke sequence */
X
X	/* prompt the user to type in a key to unbind */
X	mlwrite(": unbind-key ");
X
X	/* get the command sequence to unbind */
X	c = getckey(FALSE);		/* get a command sequence */
X
X	/* change it to something we can print as well */
X	cmdstr(c, &outseq[0]);
X
X	/* and dump it out */
X	ostring(outseq);
X
X	/* if it isn't bound, bitch */
X	if (unbindchar(c) == FALSE) {
X		mlwrite("[Key not bound]");
X		return(FALSE);
X	}
X	return(TRUE);
X}
X
Xunbindchar(c)
X
Xint c;		/* command key to unbind */
X
X{
X	register KEYTAB *ktp;	/* pointer into the command table */
X	register KEYTAB *sktp;	/* saved pointer into the command table */
X	register int found;	/* matched command flag */
X
X	/* search the table to see if the key exists */
X	ktp = &keytab[0];
X	found = FALSE;
X	while (ktp->k_fp != NULL) {
X		if (ktp->k_code == c) {
X			found = TRUE;
X			break;
X		}
X		++ktp;
X	}
X
X	/* if it isn't bound, bitch */
X	if (!found)
X		return(FALSE);
X
X	/* save the pointer and scan to the end of the table */
X	sktp = ktp;
X	while (ktp->k_fp != NULL)
X		++ktp;
X	--ktp;		/* backup to the last legit entry */
X
X	/* copy the last entry to the current one */
X	sktp->k_code = ktp->k_code;
X	sktp->k_fp   = ktp->k_fp;
X
X	/* null out the last one */
X	ktp->k_code = 0;
X	ktp->k_fp = NULL;
X	return(TRUE);
X}
X
Xdesbind(f, n)	/* describe bindings
X		   bring up a fake buffer and list the key bindings
X		   into it with view mode			*/
X
X#if	APROP
X{
X	buildlist(TRUE, "");
X}
X
Xapro(f, n)	/* Apropos (List functions that match a substring) */
X
X{
X	char mstring[NSTRING];	/* string to match cmd names to */
X	int status;		/* status return */
X
X	status = mlreply("Apropos string: ", mstring, NSTRING - 1);
X	if (status != TRUE)
X		return(status);
X
X	return(buildlist(FALSE, mstring));
X}
X
Xbuildlist(type, mstring)  /* build a binding list (limited or full) */
X
Xint type;	/* true = full list,   false = partial list */
Xchar *mstring;	/* match string if a partial list */
X
X#endif
X{
X#if	ST520 & LATTICE
X#define	register		
X#endif
X	register WINDOW *wp;	/* scanning pointer to windows */
X	register KEYTAB *ktp;	/* pointer into the command table */
X	register NBIND *nptr;	/* pointer into the name binding table */
X	register BUFFER *bp;	/* buffer to put binding list into */
X	char *strp;		/* pointer int string to send */
X	int cpos;		/* current position to use in outseq */
X	char outseq[80];	/* output buffer for keystroke sequence */
X
X	/* split the current window to make room for the binding list */
X	if (splitwind(FALSE, 1) == FALSE)
X			return(FALSE);
X
X	/* and get a buffer for it */
X	bp = bfind("Binding list", TRUE, 0);
X	if (bp == NULL || bclear(bp) == FALSE) {
X		mlwrite("Can not display binding list");
X		return(FALSE);
X	}
X
X	/* let us know this is in progress */
X	mlwrite("[Building binding list]");
X
X	/* disconect the current buffer */
X        if (--curbp->b_nwnd == 0) {             /* Last use.            */
X                curbp->b_dotp  = curwp->w_dotp;
X                curbp->b_doto  = curwp->w_doto;
X                curbp->b_markp = curwp->w_markp;
X                curbp->b_marko = curwp->w_marko;
X        }
X
X	/* connect the current window to this buffer */
X	curbp = bp;	/* make this buffer current in current window */
X	bp->b_mode = 0;		/* no modes active in binding list */
X	bp->b_nwnd++;		/* mark us as more in use */
X	wp = curwp;
X	wp->w_bufp = bp;
X	wp->w_linep = bp->b_linep;
X	wp->w_flag = WFHARD|WFFORCE;
X	wp->w_dotp = bp->b_dotp;
X	wp->w_doto = bp->b_doto;
X	wp->w_markp = NULL;
X	wp->w_marko = 0;
X
X	/* build the contents of this window, inserting it line by line */
X	nptr = &names[0];
X	while (nptr->n_func != NULL) {
X
X		/* add in the command name */
X		strcpy(outseq, nptr->n_name);
X		cpos = strlen(outseq);
X		
X#if	APROP
X		/* if we are executing an apropos command..... */
X		if (type == FALSE &&
X		    /* and current string doesn't include the search string */
X		    strinc(outseq, mstring) == FALSE)
X			goto fail;
X#endif
X		/* search down any keys bound to this */
X		ktp = &keytab[0];
X		while (ktp->k_fp != NULL) {
X			if (ktp->k_fp == nptr->n_func) {
X				/* padd out some spaces */
X				while (cpos < 25)
X					outseq[cpos++] = ' ';
X
X				/* add in the command sequence */
X				cmdstr(ktp->k_code, &outseq[cpos]);
X				strcat(outseq, "\n");
X
X				/* and add it as a line into the buffer */
X				if (linstr(outseq) != TRUE)
X					return(FALSE);
X
X				cpos = 0;	/* and clear the line */
X			}
X			++ktp;
X		}
X
X		/* if no key was bound, we need to dump it anyway */
X		if (cpos > 0) {
X			outseq[cpos++] = '\n';
X			outseq[cpos] = 0;
X			if (linstr(outseq) != TRUE)
X				return(FALSE);
X		}
X
Xfail:		/* and on to the next name */
X		++nptr;
X	}
X
X	curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
X	curbp->b_flag &= ~BFCHG;	/* don't flag this as a change */
X	wp->w_dotp = lforw(bp->b_linep);/* back to the beginning */
X	wp->w_doto = 0;
X	wp = wheadp;			/* and update ALL mode lines */
X	while (wp != NULL) {
X		wp->w_flag |= WFMODE;
X		wp = wp->w_wndp;
X	}
X	mlwrite("");	/* clear the mode line */
X	return(TRUE);
X}
X
X#if	APROP
Xstrinc(source, sub)	/* does source include sub? */
X
Xchar *source;	/* string to search in */
Xchar *sub;	/* substring to look for */
X
X{
X	char *sp;	/* ptr into source */
X	char *nxtsp;	/* next ptr into source */
X	char *tp;	/* ptr into substring */
X
X	/* for each character in the source string */
X	sp = source;
X	while (*sp) {
X		tp = sub;
X		nxtsp = sp;
X
X		/* is the substring here? */
X		while (*tp) {
X			if (*nxtsp++ != *tp)
X				break;
X			else
X				tp++;
X		}
X
X		/* yes, return a success */
X		if (*tp == 0)
X			return(TRUE);
X
X		/* no, onward */
X		sp++;
X	}
X	return(FALSE);
X}
X#endif
X
X/* get a command key sequence from the keyboard	*/
X
Xunsigned int getckey(mflag)
X
Xint mflag;	/* going for a meta sequence? */
X
X{
X	register unsigned int c;	/* character fetched */
X	char tok[NSTRING];		/* command incoming */
X
X	/* check to see if we are executing a command line */
X	if (clexec) {
X		macarg(tok);	/* get the next token */
X		return(stock(tok));
X	}
X
X	/* or the normal way */
X	if (mflag)
X		c = get1key();
X	else
X		c = getcmd();
X	return(c);
X}
X
X/* execute the startup file */
X
Xstartup(sfname)
X
Xchar *sfname;	/* name of startup file (null if default) */
X
X{
X	char *fname;	/* resulting file name to execute */
X
X	/* look up the startup file */
X	if (*sfname != 0)
X		fname = flook(sfname, TRUE);
X	else
X		fname = flook(pathname[0], TRUE);
X
X	/* if it isn't around, don't sweat it */
X	if (fname == NULL)
X		return(TRUE);
X
X	/* otherwise, execute the sucker */
X	return(dofile(fname));
X}
X
X/*	Look up the existance of a file along the normal or PATH
X	environment variable. Look first in the HOME directory if
X	asked and possible
X*/
X
Xchar *flook(fname, hflag)
X
Xchar *fname;	/* base file name to search for */
Xint hflag;	/* Look in the HOME environment variable first? */
X
X{
X	register char *home;	/* path to home directory */
X	register char *path;	/* environmental PATH variable */
X	register char *sp;	/* pointer into path spec */
X	register int i;		/* index */
X	static char fspec[NSTRING];	/* full path spec to search */
X	char *getenv();
X
X#if	ENVFUNC
X
X	if (hflag) {
X		home = getenv("HOME");
X		if (home != NULL) {
X			/* build home dir file spec */
X			strcpy(fspec, home);
X			strcat(fspec, "/");
X			strcat(fspec, fname);
X
X			/* and try it out */
X			if (ffropen(fspec) == FIOSUC) {
X				ffclose();
X				return(fspec);
X			}
X		}
X	}
X#endif
X
X	/* always try the current directory first */
X	if (ffropen(fname) == FIOSUC) {
X		ffclose();
X		return(fname);
X	}
X
X#if	ENVFUNC
X	/* get the PATH variable */
X	path = getenv("PATH");
X	if (path != NULL)
X		while (*path) {
X
X			/* build next possible file spec */
X			sp = fspec;
X#if	ST520 & MWC
X			while (*path && (*path != PATHCHR) && (*path != ','))
X#else
X			while (*path && (*path != PATHCHR))
X#endif
X				*sp++ = *path++;
X
X			/* add a terminating dir separator if we need it */
X			if (sp != fspec)
X#if	ST520
X				*sp++ = '\\';
X#else
X				*sp++ = '/';
X#endif
X			*sp = 0;
X			strcat(fspec, fname);
X
X			/* and try it out */
X			if (ffropen(fspec) == FIOSUC) {
X				ffclose();
X				return(fspec);
X			}
X
X#if	ST520 & MWC
X			if ((*path == PATHCHR) || (*path == ','))
X#else
X			if (*path == PATHCHR)
X#endif
X				++path;
X		}
X#endif
X
X	/* look it up via the old table method */
X	for (i=2; i < NPNAMES; i++) {
X		strcpy(fspec, pathname[i]);
X		strcat(fspec, fname);
X
X		/* and try it out */
X		if (ffropen(fspec) == FIOSUC) {
X			ffclose();
X			return(fspec);
X		}
X	}
X
X	return(NULL);	/* no such luck */
X}
X
Xcmdstr(c, seq)	/* change a key command to a string we can print out */
X
Xint c;		/* sequence to translate */
Xchar *seq;	/* destination string for sequence */
X
X{
X	char *ptr;	/* pointer into current position in sequence */
X
X	ptr = seq;
X
X	/* apply meta sequence if needed */
X	if (c & META) {
X		*ptr++ = 'M';
X		*ptr++ = '-';
X	}
X
X	/* apply ^X sequence if needed */
X	if (c & CTLX) {
X		*ptr++ = '^';
X		*ptr++ = 'X';
X	}
X
X	/* apply SPEC sequence if needed */
X	if (c & SPEC) {
X		*ptr++ = 'F';
X		*ptr++ = 'N';
X	}
X
X	/* apply control sequence if needed */
X	if (c & CTRL) {
X		*ptr++ = '^';
X	}
X
X	c = c & 255;	/* strip the prefixes */
X
X	/* and output the final sequence */
X
X	*ptr++ = c;
X	*ptr = 0;	/* terminate the string */
X}
X
X/*	This function looks a key binding up in the binding table	*/
X
Xint (*getbind(c))()
X
Xint c;	/* key to find what is bound to it */
X
X{
X	register KEYTAB *ktp;
X
X        ktp = &keytab[0];                       /* Look in key table.   */
X        while (ktp->k_fp != NULL) {
X                if (ktp->k_code == c)
X                        return(ktp->k_fp);
X                ++ktp;
X        }
X
X	/* no such binding */
X	return(NULL);
X}
X
X/* getfname:	This function takes a ptr to function and gets the name
X		associated with it
X*/
X
Xchar *getfname(func)
X
Xint (*func)();	/* ptr to the requested function to bind to */
X
X{
X	register NBIND *nptr;	/* pointer into the name binding table */
X
X	/* skim through the table, looking for a match */
X	nptr = &names[0];
X	while (nptr->n_func != NULL) {
X		if (nptr->n_func == func)
X			return(nptr->n_name);
X		++nptr;
X	}
X	return(NULL);
X}
X
Xint (*fncmatch(fname))() /* match fname to a function in the names table
X			    and return any match or NULL if none		*/
X
Xchar *fname;	/* name to attempt to match */
X
X{
X	register NBIND *ffp;	/* pointer to entry in name binding table */
X
X	/* scan through the table, returning any match */
X	ffp = &names[0];
X	while (ffp->n_func != NULL) {
X		if (strcmp(fname, ffp->n_name) == 0)
X			return(ffp->n_func);
X		++ffp;
X	}
X	return(NULL);
X}
X
X/* stock:	String key name TO Command Key		*/
X
Xunsigned int stock(keyname)
X
Xchar *keyname;		/* name of key to translate to Command key form */
X
X{
X	register unsigned int c;	/* key sequence to return */
X
X	/* parse it up */
X	c = 0;
X
X	/* first, the META prefix */
X	if (*keyname == 'M' && *(keyname+1) == '-') {
X		c = META;
X		keyname += 2;
X	}
X
X	/* next the function prefix */
X	if (*keyname == 'F' && *(keyname+1) == 'N') {
X		c |= SPEC;
X		keyname += 2;
X	}
X
X	/* control-x as well... (but not with FN) */
X	if (*keyname == '^' && *(keyname+1) == 'X'&& !(c & SPEC)) {
X		c |= CTLX;
X		keyname += 2;
X	}
X
X	/* a control char? */
X	if (*keyname == '^' && *(keyname+1) != 0) {
X		c |= CTRL;
X		++keyname;
X	}
X	if (*keyname < 32) {
X		c |= CTRL;
X		*keyname += 'A';
X	}
X
X
X	/* make sure we are not lower case (not with function keys)*/
X	if (*keyname >= 'a' && *keyname <= 'z' && !(c & SPEC))
X		*keyname -= 32;
X
X	/* the final sequence... */
X	c |= *keyname;
X	return(c);
X}
X
Xchar *transbind(skey)	/* string key name to binding name.... */
X
Xchar *skey;	/* name of keey to get binding for */
X
X{
X	char *bindname;
X	unsigned int stock();
X	int (*getbind())();
X
X	bindname = getfname(getbind(stock(skey)));
X	if (bindname == NULL)
X		bindname = "ERROR";
X
X	return(bindname);
X}
FRIDAY_NIGHT
echo mes.1 completed!
# That's all folks!

allbery@ncoast.UUCP (11/15/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.2')
# If you do not see the message
#	`mes.2 completed!'
# then the file was incomplete.
echo extracting - buffer.c
sed 's/^X//' > buffer.c << 'FRIDAY_NIGHT'
X/*
X * Buffer management.
X * Some of the functions are internal,
X * and some are actually attached to user
X * keys. Like everyone else, they set hints
X * for the display system.
X */
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X/*
X * Attach a buffer to a window. The
X * values of dot and mark come from the buffer
X * if the use count is 0. Otherwise, they come
X * from some other window.
X */
Xusebuffer(f, n)
X{
X        register BUFFER *bp;
X        register int    s;
X        char            bufn[NBUFN];
X
X        if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE)
X                return (s);
X        if ((bp=bfind(bufn, TRUE, 0)) == NULL)
X                return (FALSE);
X	return(swbuffer(bp));
X}
X
Xnextbuffer(f, n)	/* switch to the next buffer in the buffer list */
X
Xint f, n;	/* default flag, numeric argument */
X{
X	register BUFFER *bp;	/* eligable buffer to switch to*/
X	register BUFFER *bbp;	/* eligable buffer to switch to*/
X
X	/* make sure the arg is legit */
X	if (f == FALSE)
X		n = 1;
X	if (n < 1)
X		return(FALSE);
X
X	bbp = curbp;
X	while (n-- > 0) {
X		/* advance to the next buffer */
X		bp = bbp->b_bufp;
X
X		/* cycle through the buffers to find an eligable one */
X		while (bp == NULL || bp->b_flag & BFINVS) {
X			if (bp == NULL)
X				bp = bheadp;
X			else
X				bp = bp->b_bufp;
X
X			/* don't get caught in an infinite loop! */
X			if (bp == bbp)
X				return(FALSE);
X
X		}		
X
X		bbp = bp;
X	}
X
X	return(swbuffer(bp));
X}
X
Xswbuffer(bp)	/* make buffer BP current */
X
XBUFFER *bp;
X
X{
X        register WINDOW *wp;
X
X        if (--curbp->b_nwnd == 0) {             /* Last use.            */
X                curbp->b_dotp  = curwp->w_dotp;
X                curbp->b_doto  = curwp->w_doto;
X                curbp->b_markp = curwp->w_markp;
X                curbp->b_marko = curwp->w_marko;
X        }
X        curbp = bp;                             /* Switch.              */
X	if (curbp->b_active != TRUE) {		/* buffer not active yet*/
X		/* read it in and activate it */
X		readin(curbp->b_fname, TRUE);
X		curbp->b_dotp = lforw(curbp->b_linep);
X		curbp->b_doto = 0;
X		curbp->b_active = TRUE;
X	}
X        curwp->w_bufp  = bp;
X        curwp->w_linep = bp->b_linep;           /* For macros, ignored. */
X        curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty.         */
X        if (bp->b_nwnd++ == 0) {                /* First use.           */
X                curwp->w_dotp  = bp->b_dotp;
X                curwp->w_doto  = bp->b_doto;
X                curwp->w_markp = bp->b_markp;
X                curwp->w_marko = bp->b_marko;
X                return (TRUE);
X        }
X        wp = wheadp;                            /* Look for old.        */
X        while (wp != NULL) {
X                if (wp!=curwp && wp->w_bufp==bp) {
X                        curwp->w_dotp  = wp->w_dotp;
X                        curwp->w_doto  = wp->w_doto;
X                        curwp->w_markp = wp->w_markp;
X                        curwp->w_marko = wp->w_marko;
X                        break;
X                }
X                wp = wp->w_wndp;
X        }
X        return (TRUE);
X}
X
X/*
X * Dispose of a buffer, by name.
X * Ask for the name. Look it up (don't get too
X * upset if it isn't there at all!). Get quite upset
X * if the buffer is being displayed. Clear the buffer (ask
X * if the buffer has been changed). Then free the header
X * line and the buffer header. Bound to "C-X K".
X */
Xkillbuffer(f, n)
X
X{
X	register BUFFER *bp;
X        register int    s;
X        char bufn[NBUFN];
X
X        if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE)
X                return(s);
X        if ((bp=bfind(bufn, FALSE, 0)) == NULL) /* Easy if unknown.     */
X                return (TRUE);
X	if(bp->b_flag & BFINVS)		/* Deal with special buffers	*/
X			return (TRUE);		/* by doing nothing.	*/
X	return(zotbuf(bp));
X}
X
Xzotbuf(bp)	/* kill the buffer pointed to by bp */
X
Xregister BUFFER *bp;
X
X{
X        register BUFFER *bp1;
X        register BUFFER *bp2;
X        register int    s;
X
X        if (bp->b_nwnd != 0) {                  /* Error if on screen.  */
X                mlwrite("Buffer is being displayed");
X                return (FALSE);
X        }
X        if ((s=bclear(bp)) != TRUE)             /* Blow text away.      */
X                return (s);
X        free((char *) bp->b_linep);             /* Release header line. */
X        bp1 = NULL;                             /* Find the header.     */
X        bp2 = bheadp;
X        while (bp2 != bp) {
X                bp1 = bp2;
X                bp2 = bp2->b_bufp;
X        }
X        bp2 = bp2->b_bufp;                      /* Next one in chain.   */
X        if (bp1 == NULL)                        /* Unlink it.           */
X                bheadp = bp2;
X        else
X                bp1->b_bufp = bp2;
X        free((char *) bp);                      /* Release buffer block */
X        return (TRUE);
X}
X
Xnamebuffer(f,n)		/*	Rename the current buffer	*/
X
Xint f, n;		/* default Flag & Numeric arg */
X
X{
X	register BUFFER *bp;	/* pointer to scan through all buffers */
X	char bufn[NBUFN];	/* buffer to hold buffer name */
X
X	/* prompt for and get the new buffer name */
Xask:	if (mlreply("Change buffer name to: ", bufn, NBUFN) != TRUE)
X		return(FALSE);
X
X	/* and check for duplicates */
X	bp = bheadp;
X	while (bp != NULL) {
X		if (bp != curbp) {
X			/* if the names the same */
X			if (strcmp(bufn, bp->b_bname) == 0)
X				goto ask;  /* try again */
X		}
X		bp = bp->b_bufp;	/* onward */
X	}
X
X	strcpy(curbp->b_bname, bufn);	/* copy buffer name to structure */
X	curwp->w_flag |= WFMODE;	/* make mode line replot */
X	mlerase();
X	return(TRUE);
X}
X
X/*
X	List all of the active buffers.  First update the special
X	buffer that holds the list.  Next make sure at least 1
X	window is displaying the buffer list, splitting the screen
X	if this is what it takes.  Lastly, repaint all of the
X	windows that are displaying the list.  Bound to "C-X C-B". 
X	A numeric argument forces it to list invisable buffers as
X	well.
X*/
X
Xlistbuffers(f, n)
X{
X        register WINDOW *wp;
X        register BUFFER *bp;
X        register int    s;
X
X        if ((s=makelist(f)) != TRUE)
X                return (s);
X        if (blistp->b_nwnd == 0) {              /* Not on screen yet.   */
X                if ((wp=wpopup()) == NULL)
X                        return (FALSE);
X                bp = wp->w_bufp;
X                if (--bp->b_nwnd == 0) {
X                        bp->b_dotp  = wp->w_dotp;
X                        bp->b_doto  = wp->w_doto;
X                        bp->b_markp = wp->w_markp;
X                        bp->b_marko = wp->w_marko;
X                }
X                wp->w_bufp  = blistp;
X                ++blistp->b_nwnd;
X        }
X        wp = wheadp;
X        while (wp != NULL) {
X                if (wp->w_bufp == blistp) {
X                        wp->w_linep = lforw(blistp->b_linep);
X                        wp->w_dotp  = lforw(blistp->b_linep);
X                        wp->w_doto  = 0;
X                        wp->w_markp = NULL;
X                        wp->w_marko = 0;
X                        wp->w_flag |= WFMODE|WFHARD;
X                }
X                wp = wp->w_wndp;
X        }
X        return (TRUE);
X}
X
X/*
X * This routine rebuilds the
X * text in the special secret buffer
X * that holds the buffer list. It is called
X * by the list buffers command. Return TRUE
X * if everything works. Return FALSE if there
X * is an error (if there is no memory). Iflag
X * indecates weather to list hidden buffers.
X */
Xmakelist(iflag)
X
Xint iflag;	/* list hidden buffer flag */
X
X{
X        register char   *cp1;
X        register char   *cp2;
X        register int    c;
X        register BUFFER *bp;
X        register LINE   *lp;
X        register int    s;
X	register int	i;
X        long nbytes;		/* # of bytes in current buffer */
X        char b[7+1];
X        char line[128];
X
X        blistp->b_flag &= ~BFCHG;               /* Don't complain!      */
X        if ((s=bclear(blistp)) != TRUE)         /* Blow old text away   */
X                return (s);
X        strcpy(blistp->b_fname, "");
X        if (addline("ACT MODES        Size Buffer        File") == FALSE
X        ||  addline("--- -----        ---- ------        ----") == FALSE)
X                return (FALSE);
X        bp = bheadp;                            /* For all buffers      */
X
X	/* build line to report global mode settings */
X	cp1 = &line[0];
X	*cp1++ = ' ';
X	*cp1++ = ' ';
X	*cp1++ = ' ';
X	*cp1++ = ' ';
X
X	/* output the mode codes */
X	for (i = 0; i < NUMMODES; i++)
X		if (gmode & (1 << i))
X			*cp1++ = modecode[i];
X		else
X			*cp1++ = '.';
X	strcpy(cp1, "         Global Modes");
X	if (addline(line) == FALSE)
X		return(FALSE);
X
X	/* output the list of buffers */
X        while (bp != NULL) {
X		/* skip invisable buffers if iflag is false */
X                if (((bp->b_flag&BFINVS) != 0) && (iflag != TRUE)) {
X                        bp = bp->b_bufp;
X                        continue;
X                }
X                cp1 = &line[0];                 /* Start at left edge   */
X
X		/* output status of ACTIVE flag (has the file been read in? */
X                if (bp->b_active == TRUE)    /* "@" if activated       */
X                        *cp1++ = '@';
X                else
X                        *cp1++ = ' ';
X
X		/* output status of changed flag */
X                if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed       */
X                        *cp1++ = '*';
X                else
X                        *cp1++ = ' ';
X
X		/* report if the file is truncated */
X                if ((bp->b_flag&BFTRUNC) != 0)
X                        *cp1++ = '#';
X                else
X                        *cp1++ = ' ';
X
X                *cp1++ = ' ';	/* space */
X
X		/* output the mode codes */
X		for (i = 0; i < NUMMODES; i++) {
X			if (bp->b_mode & (1 << i))
X				*cp1++ = modecode[i];
X			else
X				*cp1++ = '.';
X		}
X                *cp1++ = ' ';                   /* Gap.                 */
X                nbytes = 0L;                    /* Count bytes in buf.  */
X                lp = lforw(bp->b_linep);
X                while (lp != bp->b_linep) {
X                        nbytes += (long)llength(lp)+1L;
X                        lp = lforw(lp);
X                }
X                ltoa(b, 7, nbytes);             /* 6 digit buffer size. */
X                cp2 = &b[0];
X                while ((c = *cp2++) != 0)
X                        *cp1++ = c;
X                *cp1++ = ' ';                   /* Gap.                 */
X                cp2 = &bp->b_bname[0];          /* Buffer name          */
X                while ((c = *cp2++) != 0)
X                        *cp1++ = c;
X                cp2 = &bp->b_fname[0];          /* File name            */
X                if (*cp2 != 0) {
X                        while (cp1 < &line[3+1+5+1+6+4+NBUFN])
X                                *cp1++ = ' ';
X                        while ((c = *cp2++) != 0) {
X                                if (cp1 < &line[128-1])
X                                        *cp1++ = c;
X                        }
X                }
X                *cp1 = 0;                       /* Add to the buffer.   */
X                if (addline(line) == FALSE)
X                        return (FALSE);
X                bp = bp->b_bufp;
X        }
X        return (TRUE);                          /* All done             */
X}
X
Xltoa(buf, width, num)
X
Xchar   buf[];
Xint    width;
Xlong   num;
X
X{
X        buf[width] = 0;                         /* End of string.       */
X        while (num >= 10) {                     /* Conditional digits.  */
X                buf[--width] = (int)(num%10L) + '0';
X                num /= 10L;
X        }
X        buf[--width] = (int)num + '0';          /* Always 1 digit.      */
X        while (width != 0)                      /* Pad with blanks.     */
X                buf[--width] = ' ';
X}
X
X/*
X * The argument "text" points to
X * a string. Append this line to the
X * buffer list buffer. Handcraft the EOL
X * on the end. Return TRUE if it worked and
X * FALSE if you ran out of room.
X */
Xaddline(text)
Xchar    *text;
X{
X        register LINE   *lp;
X        register int    i;
X        register int    ntext;
X
X        ntext = strlen(text);
X        if ((lp=lalloc(ntext)) == NULL)
X                return (FALSE);
X        for (i=0; i<ntext; ++i)
X                lputc(lp, i, text[i]);
X        blistp->b_linep->l_bp->l_fp = lp;       /* Hook onto the end    */
X        lp->l_bp = blistp->b_linep->l_bp;
X        blistp->b_linep->l_bp = lp;
X        lp->l_fp = blistp->b_linep;
X        if (blistp->b_dotp == blistp->b_linep)  /* If "." is at the end */
X                blistp->b_dotp = lp;            /* move it to new line  */
X        return (TRUE);
X}
X
X/*
X * Look through the list of
X * buffers. Return TRUE if there
X * are any changed buffers. Buffers
X * that hold magic internal stuff are
X * not considered; who cares if the
X * list of buffer names is hacked.
X * Return FALSE if no buffers
X * have been changed.
X */
Xanycb()
X{
X        register BUFFER *bp;
X
X        bp = bheadp;
X        while (bp != NULL) {
X                if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
X                        return (TRUE);
X                bp = bp->b_bufp;
X        }
X        return (FALSE);
X}
X
X/*
X * Find a buffer, by name. Return a pointer
X * to the BUFFER structure associated with it.
X * If the buffer is not found
X * and the "cflag" is TRUE, create it. The "bflag" is
X * the settings for the flags in in buffer.
X */
XBUFFER  *
Xbfind(bname, cflag, bflag)
Xregister char   *bname;
X{
X        register BUFFER *bp;
X	register BUFFER *sb;	/* buffer to insert after */
X        register LINE   *lp;
X	char *malloc();
X
X        bp = bheadp;
X        while (bp != NULL) {
X                if (strcmp(bname, bp->b_bname) == 0)
X                        return (bp);
X                bp = bp->b_bufp;
X        }
X        if (cflag != FALSE) {
X                if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
X                        return (NULL);
X                if ((lp=lalloc(0)) == NULL) {
X                        free((char *) bp);
X                        return (NULL);
X                }
X		/* find the place in the list to insert this buffer */
X		if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
X			/* insert at the beginning */
X	                bp->b_bufp = bheadp;
X        	        bheadp = bp;
X        	} else {
X			sb = bheadp;
X			while (sb->b_bufp != NULL) {
X				if (strcmp(sb->b_bufp->b_bname, bname) > 0)
X					break;
X				sb = sb->b_bufp;
X			}
X
X			/* and insert it */
X       			bp->b_bufp = sb->b_bufp;
X        		sb->b_bufp = bp;
X       		}
X
X		/* and set up the other buffer fields */
X		bp->b_active = TRUE;
X                bp->b_dotp  = lp;
X                bp->b_doto  = 0;
X                bp->b_markp = NULL;
X                bp->b_marko = 0;
X                bp->b_flag  = bflag;
X		bp->b_mode  = gmode;
X                bp->b_nwnd  = 0;
X                bp->b_linep = lp;
X                strcpy(bp->b_fname, "");
X                strcpy(bp->b_bname, bname);
X#if	CRYPT
X		bp->b_key[0] = 0;
X#endif
X                lp->l_fp = lp;
X                lp->l_bp = lp;
X        }
X        return (bp);
X}
X
X/*
X * This routine blows away all of the text
X * in a buffer. If the buffer is marked as changed
X * then we ask if it is ok to blow it away; this is
X * to save the user the grief of losing text. The
X * window chain is nearly always wrong if this gets
X * called; the caller must arrange for the updates
X * that are required. Return TRUE if everything
X * looks good.
X */
Xbclear(bp)
Xregister BUFFER *bp;
X{
X        register LINE   *lp;
X        register int    s;
X
X        if ((bp->b_flag&BFINVS) == 0            /* Not scratch buffer.  */
X        && (bp->b_flag&BFCHG) != 0              /* Something changed    */
X        && (s=mlyesno("Discard changes")) != TRUE)
X                return (s);
X        bp->b_flag  &= ~BFCHG;                  /* Not changed          */
X        while ((lp=lforw(bp->b_linep)) != bp->b_linep)
X                lfree(lp);
X        bp->b_dotp  = bp->b_linep;              /* Fix "."              */
X        bp->b_doto  = 0;
X        bp->b_markp = NULL;                     /* Invalidate "mark"    */
X        bp->b_marko = 0;
X        return (TRUE);
X}
X
Xunmark(f, n)	/* unmark the current buffers change flag */
X
Xint f, n;	/* unused command arguments */
X
X{
X	curbp->b_flag &= ~BFCHG;
X	curwp->w_flag |= WFMODE;
X	return(TRUE);
X}
FRIDAY_NIGHT
echo extracting - crypt.c
sed 's/^X//' > crypt.c << 'FRIDAY_NIGHT'
X/*	Crypt:	Encryption routines for MicroEMACS
X		written by Dana Hoggatt and Daniel Lawrence
X*/
X
X#include	<stdio.h>
X#include	"estruct.h"
X#include	"edef.h"
X
X#if	CRYPT
Xsetkey(f, n)	/* reset encryption key of current buffer */
X
Xint f;		/* default flag */
Xint n;		/* numeric argument */
X
X{
X	register int status;	/* return status */
X	int odisinp;		/* original vlaue of disinp */
X	char key[NPAT];		/* new encryption string */
X
X	/* turn command input echo off */
X	odisinp = disinp;
X	disinp = FALSE;
X
X	/* get the string to use as an encrytion string */
X	status = mlreply("Encryption String: ", key, NPAT - 1);
X	disinp = odisinp;
X        if (status != TRUE)
X                return(status);
X
X	/* and encrypt it */
X	crypt((char *)NULL, 0);
X	crypt(key, strlen(key));
X
X	/* and save it off */
X	strcpy(curbp->b_key, key);
X	mlwrite(" ");		/* clear it off the bottom line */
X	return(TRUE);
X}
X
X/**********
X *
X *	crypt - in place encryption/decryption of a buffer
X *
X *	(C) Copyright 1986, Dana L. Hoggatt
X *	1216, Beck Lane, Lafayette, IN
X *
X *	When consulting directly with the author of this routine, 
X *	please refer to this routine as the "DLH-POLY-86-B CIPHER".  
X *
X *	This routine was written for Dan Lawrence, for use in V3.8 of
X *	MicroEMACS, a public domain text/program editor.  
X *
X *	I kept the following goals in mind when preparing this function:
X *
X *	    1.	All printable characters were to be encrypted back
X *		into the printable range, control characters and
X *		high-bit characters were to remain unaffected.  this
X *		way, encrypted would still be just as cheap to 
X *		transmit down a 7-bit data path as they were before.
X *
X *	    2.	The encryption had to be portable.  The encrypted 
X *		file from one computer should be able to be decrypted 
X *		on another computer.
X *
X *	    3.	The encryption had to be inexpensive, both in terms
X *		of speed and space.
X *
X *	    4.	The system needed to be secure against all but the
X *		most determined of attackers.
X *
X *	For encryption of a block of data, one calls crypt passing 
X *	a pointer to the data block and its length. The data block is 
X *	encrypted in place, that is, the encrypted output overwrites 
X *	the input.  Decryption is totally isomorphic, and is performed 
X *	in the same manner by the same routine.  
X *
X *	Before using this routine for encrypting data, you are expected 
X *	to specify an encryption key.  This key is an arbitrary string,
X *	to be supplied by the user.  To set the key takes two calls to 
X *	crypt().  First, you call 
X *
X *		crypt(NULL, vector)
X *
X *	This resets all internal control information.  Typically (and 
X *	specifically in the case on MICRO-emacs) you would use a "vector" 
X *	of 0.  Other values can be used to customize your editor to be 
X *	"incompatable" with the normally distributed version.  For 
X *	this purpose, the best results will be obtained by avoiding
X *	multiples of 95.
X *
X *	Then, you "encrypt" your password by calling 
X *
X *		crypt(pass, strlen(pass))
X *
X *	where "pass" is your password string.  Crypt() will destroy 
X *	the original copy of the password (it becomes encrypted), 
X *	which is good.  You do not want someone on a multiuser system 
X *	to peruse your memory space and bump into your password.  
X *	Still, it is a better idea to erase the password buffer to 
X *	defeat memory perusal by a more technical snooper.  
X *
X *	For the interest of cryptologists, at the heart of this 
X *	function is a Beaufort Cipher.  The cipher alphabet is the 
X *	range of printable characters (' ' to '~'), all "control" 
X *	and "high-bit" characters are left unaltered.
X *
X *	The key is a variant autokey, derived from a wieghted sum 
X *	of all the previous clear text and cipher text.  A counter 
X *	is used as salt to obiterate any simple cyclic behavior 
X *	from the clear text, and key feedback is used to assure 
X *	that the entire message is based on the original key, 
X *	preventing attacks on the last part of the message as if 
X *	it were a pure autokey system.
X *
X *	Overall security of encrypted data depends upon three 
X *	factors:  the fundamental cryptographic system must be 
X *	difficult to compromise; exhaustive searching of the key 
X *	space must be computationally expensive; keys and plaintext 
X *	must remain out of sight.  This system satisfies this set
X *	of conditions to within the degree desired for MicroEMACS.
X *
X *	Though direct methods of attack (against systems such as 
X *	this) do exist, they are not well known and will consume 
X *	considerable amounts of computing time.  An exhaustive
X *	search requires over a billion investigations, on average.
X *
X *	The choice, entry, storage, manipulation, alteration, 
X *	protection and security of the keys themselves are the 
X *	responsiblity of the user.  
X *
X **********/
X
Xcrypt(bptr, len)
Xregister char *bptr;	/* buffer of characters to be encrypted */
Xregister unsigned len;	/* number of characters in the buffer */
X{
X	register int cc;	/* current character being considered */
X
X	static long key = 0;	/* 29 bit encipherment key */
X	static int salt = 0;	/* salt to spice up key with */
X
X	if (!bptr) {		/* is there anything here to encrypt? */
X		key = len;	/* set the new key */
X		salt = len;	/* set the new salt */
X		return;
X	}
X	while (len--) {		/* for every character in the buffer */
X
X		cc = *bptr;	/* get a character out of the buffer */
X
X		/* only encipher printable characters */
X		if ((cc >= ' ') && (cc <= '~')) {
X
X/**  If the upper bit (bit 29) is set, feed it back into the key.  This 
X	assures us that the starting key affects the entire message.  **/
X
X			key &= 0x1FFFFFFFL;	/* strip off overflow */
X			if (key & 0x10000000L) {
X				key ^= 0x0040A001L;	/* feedback */
X			}
X
X/**  Down-bias the character, perform a Beaufort encipherment, and 
X	up-bias the character again.  We want key to be positive 
X	so that the left shift here will be more portable and the 
X	mod95() faster   **/
X
X			cc = mod95((int)(key % 95) - (cc - ' ')) + ' ';
X
X/**  the salt will spice up the key a little bit, helping to obscure 
X	any patterns in the clear text, particularly when all the 
X	characters (or long sequences of them) are the same.  We do 
X	not want the salt to go negative, or it will affect the key 
X	too radically.  It is always a good idea to chop off cyclics 
X	to prime values.  **/
X
X			if (++salt >= 20857) {	/* prime modulus */
X				salt = 0;
X			}
X
X/**  our autokey (a special case of the running key) is being 
X	generated by a wieghted checksum of clear text, cipher 
X	text, and salt.   **/
X
X			key = key + key + cc + *bptr + salt;
X		}
X		*bptr++ = cc;	/* put character back into buffer */
X	}
X	return;
X}
X
Xstatic int mod95(val)
X
Xregister int val;
X
X{
X	/*  The mathematical MOD does not match the computer MOD  */
X
X	/*  Yes, what I do here may look strange, but it gets the
X		job done, and portably at that.  */
X
X	while (val >= 9500)
X		val -= 9500;
X	while (val >= 950)
X		val -= 950;
X	while (val >= 95)
X		val -= 95;
X	while (val < 0)
X		val += 95;
X	return (val);
X}
X#else
Xnocrypt()
X{
X}
X#endif
FRIDAY_NIGHT
echo extracting - dg10.c
sed 's/^X//' > dg10.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file provide support for the Data General Model 10
X * Microcomputer.
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     DG10
X
X#define NROW    24                      /* Screen size.                 */
X#define NCOL    80                      /* Edit if you want to.         */
X#define	NPAUSE	100			/* # times thru update to pause */
X#define	MARGIN	8			/* size of minimim margin and	*/
X#define	SCRSIZ	64			/* scroll size for extended lines */
X#define BEL     0x07                    /* BEL character.               */
X#define ESC     30                      /* DG10 ESC character.          */
X
Xextern  int     ttopen();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern  int     ttclose();
Xextern	int	dg10kopen();
Xextern	int	dg10kclose();
Xextern  int     dg10move();
Xextern  int     dg10eeol();
Xextern  int     dg10eeop();
Xextern  int     dg10beep();
Xextern  int     dg10open();
Xextern	int	dg10rev();
Xextern	int	dg10close();
Xextern	int	dg10cres();
X
X#if	COLOR
Xextern	int	dg10fcol();
Xextern	int	dg10bcol();
X
Xint	cfcolor = -1;		/* current forground color */
Xint	cbcolor = -1;		/* current background color */
Xint	ctrans[] = {		/* emacs -> DG10 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        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        dg10open,
X        dg10close,
X	dg10kopen,
X	dg10kclose,
X        ttgetc,
X        ttputc,
X        ttflush,
X        dg10move,
X        dg10eeol,
X        dg10eeop,
X        dg10beep,
X	dg10rev,
X	dg10cres
X#if	COLOR
X	, dg10fcol,
X	dg10bcol
X#endif
X};
X
X#if	COLOR
Xdg10fcol(color)		/* set the current output color */
X
Xint color;	/* color to set */
X
X{
X	if (color == cfcolor)
X		return;
X	ttputc(ESC);
X	ttputc(0101);
X	ttputc(ctrans[color]);
X	cfcolor = color;
X}
X
Xdg10bcol(color)		/* set the current background color */
X
Xint color;	/* color to set */
X
X{
X	if (color == cbcolor)
X		return;
X	ttputc(ESC);
X	ttputc(0102);
X	ttputc(ctrans[color]);
X        cbcolor = color;
X}
X#endif
X
Xdg10move(row, col)
X{
X	ttputc(16);
X        ttputc(col);
X	ttputc(row);
X}
X
Xdg10eeol()
X{
X        ttputc(11);
X}
X
Xdg10eeop()
X{
X#if	COLOR
X	dg10fcol(gfcolor);
X	dg10bcol(gbcolor);
X#endif
X        ttputc(ESC);
X        ttputc(0106);
X        ttputc(0106);
X}
X
Xdg10rev(state)		/* change reverse video state */
X
Xint state;	/* TRUE = reverse, FALSE = normal */
X
X{
X#if	COLOR
X	if (state == TRUE) {
X		dg10fcol(0);
X		dg10bcol(7);
X	}
X#else
X	ttputc(ESC);
X	ttputc(state ? 0104: 0105);
X#endif
X}
X
Xdg10cres()	/* change screen resolution */
X
X{
X	return(TRUE);
X}
X
Xspal()		/* change palette string */
X
X{
X	/*	Does nothing here	*/
X}
X
Xdg10beep()
X{
X        ttputc(BEL);
X        ttflush();
X}
X
Xdg10open()
X{
X	strcpy(sres, "NORMAL");
X	revexist = TRUE;
X        ttopen();
X}
X
Xdg10close()
X
X{
X#if	COLOR
X	dg10fcol(7);
X	dg10bcol(0);
X#endif
X	ttclose();
X}
X
Xdg10kopen()
X
X{
X}
X
Xdg10kclose()
X
X{
X}
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument [unused] */
X
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X#else
Xdg10hello()
X{
X}
X#endif
FRIDAY_NIGHT
echo mes.2 completed!
# That's all folks!

allbery@ncoast.UUCP (11/15/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.3')
# If you do not see the message
#	`mes.3 completed!'
# then the file was incomplete.
echo extracting - display.c
sed 's/^X//' > display.c << 'FRIDAY_NIGHT'
X/*
X * The functions in this file handle redisplay. There are two halves, the
X * ones that update the virtual display screen, and the ones that make the
X * physical display screen the same as the virtual display screen. These
X * functions use hints that are left in the windows by the commands.
X *
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
Xtypedef struct  VIDEO {
X        int	v_flag;                 /* Flags */
X#if	COLOR
X	int	v_fcolor;		/* current forground color */
X	int	v_bcolor;		/* current background color */
X	int	v_rfcolor;		/* requested forground color */
X	int	v_rbcolor;		/* requested background color */
X#endif
X        char    v_text[1];              /* Screen data. */
X}       VIDEO;
X
X#define VFCHG   0x0001                  /* Changed flag			*/
X#define	VFEXT	0x0002			/* extended (beyond column 80)	*/
X#define	VFREV	0x0004			/* reverse video status		*/
X#define	VFREQ	0x0008			/* reverse video request	*/
X#define	VFCOL	0x0010			/* color change requested	*/
X
XVIDEO   **vscreen;                      /* Virtual screen. */
X#if	MEMMAP == 0
XVIDEO   **pscreen;                      /* Physical screen. */
X#endif
X
X/*
X * Initialize the data structures used by the display code. The edge vectors
X * used to access the screens are set up. The operating system's terminal I/O
X * channel is set up. All the other things get initialized at compile time.
X * The original window has "WFCHG" set, so that it will get completely
X * redrawn on the first call to "update".
X */
Xvtinit()
X{
X    register int i;
X    register VIDEO *vp;
X    char *malloc();
X
X    TTopen();		/* open the screen */
X    TTkopen();		/* open the keyboard */
X    TTrev(FALSE);
X    vscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *));
X
X    if (vscreen == NULL)
X        exit(1);
X
X#if	MEMMAP == 0
X    pscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *));
X
X    if (pscreen == NULL)
X        exit(1);
X#endif
X
X    for (i = 0; i < term.t_mrow; ++i)
X        {
X        vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_mcol);
X
X        if (vp == NULL)
X            exit(1);
X
X	vp->v_flag = 0;
X#if	COLOR
X	vp->v_rfcolor = 7;
X	vp->v_rbcolor = 0;
X#endif
X        vscreen[i] = vp;
X#if	MEMMAP == 0
X        vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_mcol);
X
X        if (vp == NULL)
X            exit(1);
X
X	vp->v_flag = 0;
X        pscreen[i] = vp;
X#endif
X        }
X}
X
X#if	CLEAN
X/* free up all the dynamically allocated video structures */
X
Xvtfree()
X{
X	int i;
X	for (i = 0; i < term.t_mrow; ++i) {
X		free(vscreen[i]);
X#if	MEMMAP == 0
X		free(pscreen[i]);
X#endif
X	}
X	free(vscreen);
X#if	MEMMAP == 0
X	free(pscreen);
X#endif
X}
X#endif
X
X/*
X * Clean up the virtual terminal system, in anticipation for a return to the
X * operating system. Move down to the last line and clear it out (the next
X * system prompt will be written in the line). Shut down the channel to the
X * terminal.
X */
Xvttidy()
X{
X    mlerase();
X    movecursor(term.t_nrow, 0);
X    TTflush();
X    TTclose();
X    TTkclose();
X}
X
X/*
X * Set the virtual cursor to the specified row and column on the virtual
X * screen. There is no checking for nonsense values; this might be a good
X * idea during the early stages.
X */
Xvtmove(row, col)
X{
X    vtrow = row;
X    vtcol = col;
X}
X
X/* Write a character to the virtual screen. The virtual row and
X   column are updated. If we are not yet on left edge, don't print
X   it yet. If the line is too long put a "$" in the last column.
X   This routine only puts printing characters into the virtual
X   terminal buffers. Only column overflow is checked.
X*/
X
Xvtputc(c)
X
Xint c;
X
X{
X	register VIDEO *vp;	/* ptr to line being updated */
X
X	vp = vscreen[vtrow];
X
X	if (c == '\t') {
X		do {
X			vtputc(' ');
X		} while (((vtcol + taboff)&0x07) != 0);
X	} else if (vtcol >= term.t_ncol) {
X		++vtcol;
X		vp->v_text[term.t_ncol - 1] = '$';
X	} else if (c < 0x20 || c == 0x7F) {
X		vtputc('^');
X		vtputc(c ^ 0x40);
X	} else {
X		if (vtcol >= 0)
X			vp->v_text[vtcol] = c;
X		++vtcol;
X	}
X}
X
X/*
X * Erase from the end of the software cursor to the end of the line on which
X * the software cursor is located.
X */
Xvteeol()
X{
X    register VIDEO      *vp;
X
X    vp = vscreen[vtrow];
X    while (vtcol < term.t_ncol)
X        vp->v_text[vtcol++] = ' ';
X}
X
X/* upscreen:	user routine to force a screen update
X		always finishes complete update		*/
X
Xupscreen(f, n)
X
X{
X	update(TRUE);
X	return(TRUE);
X}
X
X/*
X * Make sure that the display is right. This is a three part process. First,
X * scan through all of the windows looking for dirty ones. Check the framing,
X * and refresh the screen. Second, make sure that "currow" and "curcol" are
X * correct for the current window. Third, make the virtual and physical
X * screens the same.
X */
Xupdate(force)
X
Xint force;	/* force update past type ahead? */
X
X{
X	register WINDOW *wp;
X
X#if	TYPEAH
X	if (force == FALSE && typahead())
X		return(TRUE);
X#endif
X#if	VISMAC == 0
X	if (force == FALSE && kbdmode == PLAY)
X		return(TRUE);
X#endif
X
X	/* update any windows that need refreshing */
X	wp = wheadp;
X	while (wp != NULL) {
X		if (wp->w_flag) {
X			/* if the window has changed, service it */
X			reframe(wp);	/* check the framing */
X			if ((wp->w_flag & ~WFMODE) == WFEDIT)
X				updone(wp);	/* update EDITed line */
X			else if (wp->w_flag & ~WFMOVE)
X				updall(wp);	/* update all lines */
X			if (wp->w_flag & WFMODE)
X				modeline(wp);	/* update modeline */
X			wp->w_flag = 0;
X			wp->w_force = 0;
X		}
X		/* on to the next window */
X		wp = wp->w_wndp;
X	}
X
X	/* recalc the current hardware cursor location */
X	updpos();
X
X#if	MEMMAP
X	/* update the cursor and flush the buffers */
X	movecursor(currow, curcol - lbound);
X#endif
X
X	/* check for lines to de-extend */
X	upddex();
X
X	/* if screen is garbage, re-plot it */
X	if (sgarbf != FALSE)
X		updgar();
X
X	/* update the virtual screen to the physical screen */
X	updupd(force);
X
X	/* update the cursor and flush the buffers */
X	movecursor(currow, curcol - lbound);
X	TTflush();
X	return(TRUE);
X}
X
X/*	reframe:	check to see if the cursor is on in the window
X			and re-frame it if needed or wanted		*/
X
Xreframe(wp)
X
XWINDOW *wp;
X
X{
X	register LINE *lp;
X	register int i;
X
X	/* if not a requested reframe, check for a needed one */
X	if ((wp->w_flag & WFFORCE) == 0) {
X		lp = wp->w_linep;
X		for (i = 0; i < wp->w_ntrows; i++) {
X
X			/* if the line is in the window, no reframe */
X			if (lp == wp->w_dotp)
X				return(TRUE);
X
X			/* if we are at the end of the file, reframe */
X			if (lp == wp->w_bufp->b_linep)
X				break;
X
X			/* on to the next line */
X			lp = lforw(lp);
X		}
X	}
X
X	/* reaching here, we need a window refresh */
X	i = wp->w_force;
X
X	/* how far back to reframe? */
X	if (i > 0) {		/* only one screen worth of lines max */
X		if (--i >= wp->w_ntrows)
X			i = wp->w_ntrows - 1;
X	} else if (i < 0) {	/* negative update???? */
X		i += wp->w_ntrows;
X		if (i < 0)
X			i = 0;
X	} else
X		i = wp->w_ntrows / 2;
X
X	/* backup to new line at top of window */
X	lp = wp->w_dotp;
X	while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
X		--i;
X		lp = lback(lp);
X	}
X
X	/* and reset the current line at top of window */
X	wp->w_linep = lp;
X	wp->w_flag |= WFHARD;
X	wp->w_flag &= ~WFFORCE;
X	return(TRUE);
X}
X
X/*	updone:	update the current line	to the virtual screen		*/
X
Xupdone(wp)
X
XWINDOW *wp;	/* window to update current line in */
X
X{
X	register LINE *lp;	/* line to update */
X	register int sline;	/* physical screen line to update */
X	register int i;
X
X	/* search down the line we want */
X	lp = wp->w_linep;
X	sline = wp->w_toprow;
X	while (lp != wp->w_dotp) {
X		++sline;
X		lp = lforw(lp);
X	}
X
X	/* and update the virtual line */
X	vscreen[sline]->v_flag |= VFCHG;
X	vscreen[sline]->v_flag &= ~VFREQ;
X	vtmove(sline, 0);
X	for (i=0; i < llength(lp); ++i)
X		vtputc(lgetc(lp, i));
X#if	COLOR
X	vscreen[sline]->v_rfcolor = wp->w_fcolor;
X	vscreen[sline]->v_rbcolor = wp->w_bcolor;
X#endif
X	vteeol();
X}
X
X/*	updall:	update all the lines in a window on the virtual screen */
X
Xupdall(wp)
X
XWINDOW *wp;	/* window to update lines in */
X
X{
X	register LINE *lp;	/* line to update */
X	register int sline;	/* physical screen line to update */
X	register int i;
X
X	/* search down the lines, updating them */
X	lp = wp->w_linep;
X	sline = wp->w_toprow;
X	while (sline < wp->w_toprow + wp->w_ntrows) {
X
X		/* and update the virtual line */
X		vscreen[sline]->v_flag |= VFCHG;
X		vscreen[sline]->v_flag &= ~VFREQ;
X		vtmove(sline, 0);
X		if (lp != wp->w_bufp->b_linep) {
X			/* if we are not at the end */
X			for (i=0; i < llength(lp); ++i)
X				vtputc(lgetc(lp, i));
X			lp = lforw(lp);
X		}
X
X		/* on to the next one */
X#if	COLOR
X		vscreen[sline]->v_rfcolor = wp->w_fcolor;
X		vscreen[sline]->v_rbcolor = wp->w_bcolor;
X#endif
X		vteeol();
X		++sline;
X	}
X
X}
X
X/*	updpos:	update the position of the hardware cursor and handle extended
X		lines. This is the only update for simple moves.	*/
X
Xupdpos()
X
X{
X	register LINE *lp;
X	register int c;
X	register int i;
X
X	/* find the current row */
X	lp = curwp->w_linep;
X	currow = curwp->w_toprow;
X	while (lp != curwp->w_dotp) {
X		++currow;
X		lp = lforw(lp);
X	}
X
X	/* find the current column */
X	curcol = 0;
X	i = 0;
X	while (i < curwp->w_doto) {
X		c = lgetc(lp, i++);
X		if (c == '\t')
X			curcol |= 0x07;
X		else
X			if (c < 0x20 || c == 0x7f)
X				++curcol;
X
X		++curcol;
X	}
X
X	/* if extended, flag so and update the virtual line image */
X	if (curcol >=  term.t_ncol - 1) {
X		vscreen[currow]->v_flag |= (VFEXT | VFCHG);
X		updext();
X	} else
X		lbound = 0;
X}
X
X/*	upddex:	de-extend any line that derserves it		*/
X
Xupddex()
X
X{
X	register WINDOW *wp;
X	register LINE *lp;
X	register int i,j;
X
X	wp = wheadp;
X
X	while (wp != NULL) {
X		lp = wp->w_linep;
X		i = wp->w_toprow;
X
X		while (i < wp->w_toprow + wp->w_ntrows) {
X			if (vscreen[i]->v_flag & VFEXT) {
X				if ((wp != curwp) || (lp != wp->w_dotp) ||
X				   (curcol < term.t_ncol - 1)) {
X					vtmove(i, 0);
X					for (j = 0; j < llength(lp); ++j)
X						vtputc(lgetc(lp, j));
X					vteeol();
X
X					/* this line no longer is extended */
X					vscreen[i]->v_flag &= ~VFEXT;
X					vscreen[i]->v_flag |= VFCHG;
X				}
X			}
X			lp = lforw(lp);
X			++i;
X		}
X		/* and onward to the next window */
X		wp = wp->w_wndp;
X	}
X}
X
X/*	updgar:	if the screen is garbage, clear the physical screen and
X		the virtual screen and force a full update		*/
X
Xupdgar()
X
X{
X	register char *txt;
X	register int i,j;
X
X	for (i = 0; i < term.t_nrow; ++i) {
X		vscreen[i]->v_flag |= VFCHG;
X#if	REVSTA
X		vscreen[i]->v_flag &= ~VFREV;
X#endif
X#if	COLOR
X		vscreen[i]->v_fcolor = gfcolor;
X		vscreen[i]->v_bcolor = gbcolor;
X#endif
X#if	MEMMAP == 0
X		txt = pscreen[i]->v_text;
X		for (j = 0; j < term.t_ncol; ++j)
X			txt[j] = ' ';
X#endif
X	}
X
X	movecursor(0, 0);		 /* Erase the screen. */
X	(*term.t_eeop)();
X	sgarbf = FALSE;			 /* Erase-page clears */
X	mpresf = FALSE;			 /* the message area. */
X#if	COLOR
X	mlerase();			/* needs to be cleared if colored */
X#endif
X}
X
X/*	updupd:	update the physical screen from the virtual screen	*/
X
Xupdupd(force)
X
Xint force;	/* forced update flag */
X
X{
X	register VIDEO *vp1;
X	register int i;
X
X	for (i = 0; i < term.t_nrow; ++i) {
X		vp1 = vscreen[i];
X
X		/* for each line that needs to be updated*/
X		if ((vp1->v_flag & VFCHG) != 0) {
X#if	TYPEAH
X			if (force == FALSE && typahead())
X				return(TRUE);
X#endif
X#if	MEMMAP
X			updateline(i, vp1);
X#else
X			updateline(i, vp1, pscreen[i]);
X#endif
X		}
X	}
X	return(TRUE);
X}
X
X/*	updext: update the extended line which the cursor is currently
X		on at a column greater than the terminal width. The line
X		will be scrolled right or left to let the user see where
X		the cursor is
X								*/
X
Xupdext()
X
X{
X	register int rcursor;	/* real cursor location */
X	register LINE *lp;	/* pointer to current line */
X	register int j;		/* index into line */
X
X	/* calculate what column the real cursor will end up in */
X	rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
X	taboff = lbound = curcol - rcursor + 1;
X
X	/* scan through the line outputing characters to the virtual screen */
X	/* once we reach the left edge					*/
X	vtmove(currow, -lbound);	/* start scanning offscreen */
X	lp = curwp->w_dotp;		/* line to output */
X	for (j=0; j<llength(lp); ++j)	/* until the end-of-line */
X		vtputc(lgetc(lp, j));
X
X	/* truncate the virtual line, restore tab offset */
X	vteeol();
X	taboff = 0;
X
X	/* and put a '$' in column 1 */
X	vscreen[currow]->v_text[0] = '$';
X}
X
X/*
X * Update a single line. This does not know how to use insert or delete
X * character sequences; we are using VT52 functionality. Update the physical
X * row and column variables. It does try an exploit erase to end of line. The
X * RAINBOW version of this routine uses fast video.
X */
X#if	MEMMAP
X/*	UPDATELINE specific code for the IBM-PC and other compatables */
X
Xupdateline(row, vp1)
X
Xint row;		/* row of screen to update */
Xstruct VIDEO *vp1;	/* virtual screen image */
X
X{
X#if	COLOR
X	scwrite(row, vp1->v_text, vp1->v_rfcolor, vp1->v_rbcolor);
X	vp1->v_fcolor = vp1->v_rfcolor;
X	vp1->v_bcolor = vp1->v_rbcolor;
X#else
X	if (vp1->v_flag & VFREQ)
X		scwrite(row, vp1->v_text, 0, 7);
X	else
X		scwrite(row, vp1->v_text, 7, 0);
X#endif
X	vp1->v_flag &= ~(VFCHG | VFCOL);	/* flag this line as changed */
X
X}
X
X#else
X
Xupdateline(row, vp1, vp2)
X
Xint row;		/* row of screen to update */
Xstruct VIDEO *vp1;	/* virtual screen image */
Xstruct VIDEO *vp2;	/* physical screen image */
X
X{
X#if RAINBOW
X/*	UPDATELINE specific code for the DEC rainbow 100 micro	*/
X
X    register char *cp1;
X    register char *cp2;
X    register int nch;
X
X    /* since we don't know how to make the rainbow do this, turn it off */
X    flags &= (~VFREV & ~VFREQ);
X
X    cp1 = &vp1->v_text[0];                    /* Use fast video. */
X    cp2 = &vp2->v_text[0];
X    putline(row+1, 1, cp1);
X    nch = term.t_ncol;
X
X    do
X        {
X        *cp2 = *cp1;
X        ++cp2;
X        ++cp1;
X        }
X    while (--nch);
X    *flags &= ~VFCHG;
X#else
X/*	UPDATELINE code for all other versions		*/
X
X	register char *cp1;
X	register char *cp2;
X	register char *cp3;
X	register char *cp4;
X	register char *cp5;
X	register int nbflag;	/* non-blanks to the right flag? */
X	int rev;		/* reverse video flag */
X	int req;		/* reverse video request flag */
X
X
X	/* set up pointers to virtual and physical lines */
X	cp1 = &vp1->v_text[0];
X	cp2 = &vp2->v_text[0];
X
X#if	COLOR
X	TTforg(vp1->v_rfcolor);
X	TTbacg(vp1->v_rbcolor);
X#endif
X
X#if	REVSTA | COLOR
X	/* if we need to change the reverse video status of the
X	   current line, we need to re-write the entire line     */
X	rev = (vp1->v_flag & VFREV) == VFREV;
X	req = (vp1->v_flag & VFREQ) == VFREQ;
X	if ((rev != req)
X#if	COLOR
X	    || (vp1->v_fcolor != vp1->v_rfcolor) || (vp1->v_bcolor != vp1->v_rbcolor)
X#endif
X#if	HP150
X	/* the HP150 has some reverse video problems */
X	    || req || rev
X#endif
X			) {
X		movecursor(row, 0);	/* Go to start of line. */
X		/* set rev video if needed */
X		if (rev != req)
X			(*term.t_rev)(req);
X
X		/* scan through the line and dump it to the screen and
X		   the virtual screen array				*/
X		cp3 = &vp1->v_text[term.t_ncol];
X		while (cp1 < cp3) {
X			TTputc(*cp1);
X			++ttcol;
X			*cp2++ = *cp1++;
X		}
X		/* turn rev video off */
X		if (rev != req)
X			(*term.t_rev)(FALSE);
X
X		/* update the needed flags */
X		vp1->v_flag &= ~VFCHG;
X		if (req)
X			vp1->v_flag |= VFREV;
X		else
X			vp1->v_flag &= ~VFREV;
X#if	COLOR
X		vp1->v_fcolor = vp1->v_rfcolor;
X		vp1->v_bcolor = vp1->v_rbcolor;
X#endif
X		return(TRUE);
X	}
X#endif
X
X	/* advance past any common chars at the left */
X	while (cp1 != &vp1->v_text[term.t_ncol] && cp1[0] == cp2[0]) {
X		++cp1;
X		++cp2;
X	}
X
X/* This can still happen, even though we only call this routine on changed
X * lines. A hard update is always done when a line splits, a massive
X * change is done, or a buffer is displayed twice. This optimizes out most
X * of the excess updating. A lot of computes are used, but these tend to
X * be hard operations that do a lot of update, so I don't really care.
X */
X	/* if both lines are the same, no update needs to be done */
X	if (cp1 == &vp1->v_text[term.t_ncol]) {
X 		vp1->v_flag &= ~VFCHG;		/* flag this line is changed */
X		return(TRUE);
X	}
X
X	/* find out if there is a match on the right */
X	nbflag = FALSE;
X	cp3 = &vp1->v_text[term.t_ncol];
X	cp4 = &vp2->v_text[term.t_ncol];
X
X	while (cp3[-1] == cp4[-1]) {
X		--cp3;
X		--cp4;
X		if (cp3[0] != ' ')		/* Note if any nonblank */
X			nbflag = TRUE;		/* in right match. */
X	}
X
X	cp5 = cp3;
X
X	/* Erase to EOL ? */
X	if (nbflag == FALSE && eolexist == TRUE && (req != TRUE)) {
X		while (cp5!=cp1 && cp5[-1]==' ')
X			--cp5;
X
X		if (cp3-cp5 <= 3)		/* Use only if erase is */
X			cp5 = cp3;		/* fewer characters. */
X	}
X
X	movecursor(row, cp1 - &vp1->v_text[0]);	/* Go to start of line. */
X#if	REVSTA
X	TTrev(rev);
X#endif
X
X	while (cp1 != cp5) {		/* Ordinary. */
X		TTputc(*cp1);
X		++ttcol;
X		*cp2++ = *cp1++;
X	}
X
X	if (cp5 != cp3) {		/* Erase. */
X		TTeeol();
X		while (cp1 != cp3)
X			*cp2++ = *cp1++;
X	}
X#if	REVSTA
X	TTrev(FALSE);
X#endif
X	vp1->v_flag &= ~VFCHG;		/* flag this line as updated */
X	return(TRUE);
X#endif
X}
X#endif
X
X/*
X * Redisplay the mode line for the window pointed to by the "wp". This is the
X * only routine that has any idea of how the modeline is formatted. You can
X * change the modeline format by hacking at this routine. Called by "update"
X * any time there is a dirty window.
X */
Xmodeline(wp)
X    WINDOW *wp;
X{
X    register char *cp;
X    register int c;
X    register int n;		/* cursor position count */
X    register BUFFER *bp;
X    register int i;		/* loop index */
X    register int lchar;		/* character to draw line in buffer with */
X    register int firstm;	/* is this the first mode? */
X    char tline[NLINE];		/* buffer for part of mode line */
X
X    n = wp->w_toprow+wp->w_ntrows;      	/* Location. */
X    vscreen[n]->v_flag |= VFCHG | VFREQ | VFCOL;/* Redraw next time. */
X#if	COLOR
X    vscreen[n]->v_rfcolor = 0;			/* black on */
X    vscreen[n]->v_rbcolor = 7;			/* white.....*/
X#endif
X    vtmove(n, 0);                       	/* Seek to right line. */
X    if (wp == curwp)				/* mark the current buffer */
X	lchar = '=';
X    else
X#if	REVSTA
X	if (revexist)
X		lchar = ' ';
X	else
X#endif
X		lchar = '-';
X
X    bp = wp->w_bufp;
X    if ((bp->b_flag&BFTRUNC) != 0)
X	vtputc('#');
X    else
X	vtputc(lchar);
X
X    if ((bp->b_flag&BFCHG) != 0)                /* "*" if changed. */
X        vtputc('*');
X    else
X        vtputc(lchar);
X
X    n  = 2;
X    strcpy(tline, " ");				/* Buffer name. */
X    strcat(tline, PROGNAME);
X    strcat(tline, " ");
X    strcat(tline, VERSION);
X    strcat(tline, " (");
X
X    /* display the modes */
X
X	firstm = TRUE;
X	for (i = 0; i < NUMMODES; i++)	/* add in the mode flags */
X		if (wp->w_bufp->b_mode & (1 << i)) {
X			if (firstm != TRUE)
X				strcat(tline, " ");
X			firstm = FALSE;
X			strcat(tline, modename[i]);
X		}
X	strcat(tline,") ");
X
X    cp = &tline[0];
X    while ((c = *cp++) != 0)
X        {
X        vtputc(c);
X        ++n;
X        }
X
X#if 0
X    vtputc(lchar);
X    vtputc((wp->w_flag&WFCOLR) != 0  ? 'C' : lchar);
X    vtputc((wp->w_flag&WFMODE) != 0  ? 'M' : lchar);
X    vtputc((wp->w_flag&WFHARD) != 0  ? 'H' : lchar);
X    vtputc((wp->w_flag&WFEDIT) != 0  ? 'E' : lchar);
X    vtputc((wp->w_flag&WFMOVE) != 0  ? 'V' : lchar);
X    vtputc((wp->w_flag&WFFORCE) != 0 ? 'F' : lchar);
X    vtputc(lchar);
X    n += 8;
X#endif
X
X    vtputc(lchar);
X    vtputc(lchar);
X    vtputc(' ');
X    n += 3;
X    cp = &bp->b_bname[0];
X
X    while ((c = *cp++) != 0)
X        {
X        vtputc(c);
X        ++n;
X        }
X
X    vtputc(' ');
X    vtputc(lchar);
X    vtputc(lchar);
X    n += 3;
X
X    if (bp->b_fname[0] != 0)            /* File name. */
X        {
X	vtputc(' ');
X	++n;
X        cp = "File: ";
X
X        while ((c = *cp++) != 0)
X            {
X            vtputc(c);
X            ++n;
X            }
X
X        cp = &bp->b_fname[0];
X
X        while ((c = *cp++) != 0)
X            {
X            vtputc(c);
X            ++n;
X            }
X
X        vtputc(' ');
X        ++n;
X        }
X
X    while (n < term.t_ncol)             /* Pad to full width. */
X        {
X        vtputc(lchar);
X        ++n;
X        }
X}
X
Xupmode()	/* update all the mode lines */
X
X{
X	register WINDOW *wp;
X
X	wp = wheadp;
X	while (wp != NULL) {
X		wp->w_flag |= WFMODE;
X		wp = wp->w_wndp;
X	}
X}
X
X/*
X * Send a command to the terminal to move the hardware cursor to row "row"
X * and column "col". The row and column arguments are origin 0. Optimize out
X * random calls. Update "ttrow" and "ttcol".
X */
Xmovecursor(row, col)
X    {
X    if (row!=ttrow || col!=ttcol)
X        {
X        ttrow = row;
X        ttcol = col;
X        TTmove(row, col);
X        }
X    }
X
X/*
X * Erase the message line. This is a special routine because the message line
X * is not considered to be part of the virtual screen. It always works
X * immediately; the terminal buffer is flushed via a call to the flusher.
X */
Xmlerase()
X    {
X    int i;
X    
X    movecursor(term.t_nrow, 0);
X    if (discmd == FALSE)
X    	return;
X
X#if	COLOR
X     TTforg(7);
X     TTbacg(0);
X#endif
X    if (eolexist == TRUE)
X	    TTeeol();
X    else {
X        for (i = 0; i < term.t_ncol - 1; i++)
X            TTputc(' ');
X        movecursor(term.t_nrow, 1);	/* force the move! */
X        movecursor(term.t_nrow, 0);
X    }
X    TTflush();
X    mpresf = FALSE;
X    }
X
X/*
X * Write a message into the message line. Keep track of the physical cursor
X * position. A small class of printf like format items is handled. Assumes the
X * stack grows down; this assumption is made by the "++" in the argument scan
X * loop. Set the "message line" flag TRUE.
X */
X
Xmlwrite(fmt, arg)
X
Xchar *fmt;	/* format string for output */
Xchar *arg;	/* pointer to first argument to print */
X
X{
X	register int c;		/* current char in format string */
X	register char *ap;	/* ptr to current data field */
X
X	/* if we are not currently echoing on the command line, abort this */
X	if (discmd == FALSE) {
X		movecursor(term.t_nrow, 0);
X		return;
X	}
X
X#if	COLOR
X	/* set up the proper colors for the command line */
X	TTforg(7);
X	TTbacg(0);
X#endif
X
X	/* if we can not erase to end-of-line, do it manually */
X	if (eolexist == FALSE) {
X		mlerase();
X		TTflush();
X	}
X
X	movecursor(term.t_nrow, 0);
X	ap = (char *) &arg;
X	while ((c = *fmt++) != 0) {
X		if (c != '%') {
X			TTputc(c);
X			++ttcol;
X		} else {
X			c = *fmt++;
X			switch (c) {
X				case 'd':
X					mlputi(*(int *)ap, 10);
X					ap += sizeof(int);
X					break;
X
X				case 'o':
X					mlputi(*(int *)ap,  8);
X					ap += sizeof(int);
X					break;
X
X				case 'x':
X					mlputi(*(int *)ap, 16);
X					ap += sizeof(int);
X					break;
X
X				case 'D':
X					mlputli(*(long *)ap, 10);
X					ap += sizeof(long);
X					break;
X
X				case 's':
X					mlputs(*(char **)ap);
X					ap += sizeof(char *);
X					break;
X
X				case 'f':
X					mlputf(*(int *)ap);
X					ap += sizeof(int);
X					break;
X
X				default:
X					TTputc(c);
X					++ttcol;
X			}
X		}
X	}
X
X	/* if we can, erase to the end of screen */
X	if (eolexist == TRUE)
X		TTeeol();
X	TTflush();
X	mpresf = TRUE;
X}
X
X/*	Force a string out to the message line regardless of the
X	current $discmd setting. This is needed when $debug is TRUE
X	and for the write-message and clear-message-line commands
X*/
X
Xmlforce(s)
X
Xchar *s;	/* string to force out */
X
X{
X	register int oldcmd;	/* original command display flag */
X
X	oldcmd = discmd;	/* save the discmd value */
X	discmd = TRUE;		/* and turn display on */
X	mlwrite(s);		/* write the string out */
X	discmd = oldcmd;	/* and restore the original setting */
X}
X
X/*
X * Write out a string. Update the physical cursor position. This assumes that
X * the characters in the string all have width "1"; if this is not the case
X * things will get screwed up a little.
X */
Xmlputs(s)
X    char *s;
X    {
X    register int c;
X
X    while ((c = *s++) != 0)
X        {
X        TTputc(c);
X        ++ttcol;
X        }
X    }
X
X/*
X * Write out an integer, in the specified radix. Update the physical cursor
X * position.
X */
Xmlputi(i, r)
X    {
X    register int q;
X    static char hexdigits[] = "0123456789ABCDEF";
X
X    if (i < 0)
X        {
X        i = -i;
X        TTputc('-');
X        }
X
X    q = i/r;
X
X    if (q != 0)
X        mlputi(q, r);
X
X    TTputc(hexdigits[i%r]);
X    ++ttcol;
X    }
X
X/*
X * do the same except as a long integer.
X */
Xmlputli(l, r)
X    long l;
X    {
X    register long q;
X
X    if (l < 0)
X        {
X        l = -l;
X        TTputc('-');
X        }
X
X    q = l/r;
X
X    if (q != 0)
X        mlputli(q, r);
X
X    TTputc((int)(l%r)+'0');
X    ++ttcol;
X    }
X
X/*
X *	write out a scaled integer with two decimal places
X */
X
Xmlputf(s)
X
Xint s;	/* scaled integer to output */
X
X{
X	int i;	/* integer portion of number */
X	int f;	/* fractional portion of number */
X
X	/* break it up */
X	i = s / 100;
X	f = s % 100;
X
X	/* send out the integer portion */
X	mlputi(i, 10);
X	TTputc('.');
X	TTputc((f / 10) + '0');
X	TTputc((f % 10) + '0');
X	ttcol += 3;
X}	
X
X#if RAINBOW
X
Xputline(row, col, buf)
X    int row, col;
X    char buf[];
X    {
X    int n;
X
X    n = strlen(buf);
X    if (col + n - 1 > term.t_ncol)
X        n = term.t_ncol - col + 1;
X    Put_Data(row, col, n, buf);
X    }
X#endif
X
FRIDAY_NIGHT
echo mes.3 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/15/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.4')
# If you do not see the message
#	`mes.4 completed!'
# then the file was incomplete.
echo extracting - dolock.c
sed 's/^X//' > dolock.c << 'FRIDAY_NIGHT'
X#if	0
X/*	dolock:	MDBS specific Unix 4.2BSD file locking mechinism
X		this is not to be distributed generally		*/
X
X#include	<mdbs.h>
X#include	<mdbsio.h>
X#include	<sys/types.h>
X#include	<sys/stat.h>
X
X/* included by port.h: mdbs.h, mdbsio.h, sys/types.h, sys/stat.h */
X
X
X#ifndef bsdunix
Xchar *dolock(){return(NULL);}
Xchar *undolock(){return(NULL);}
X#else
X
X#include <pwd.h>
X#include <errno.h>
X
Xextern int errno;
X
X#define LOCKDIR ".xlk"
X
X#define LOCKMSG "LOCK ERROR -- "
X#define LOCKMSZ sizeof(LOCKMSG)
X#define LOCKERR(s) { strcat(lmsg,s); oldumask = umask(oldumask); return(lmsg); }
X
X/**********************
X *
X * dolock -- lock the file fname
X *
X * if successful, returns NULL 
X * if file locked, returns username of person locking the file
X * if other error, returns "LOCK ERROR: explanation"
X *
X * Jon Reid, 2/19/86
X *
X *********************/
X
XBOOL parent = FALSE;
XBOOL tellall = FALSE;
X
Xchar *gtname(filespec)		/* get name component of unix-style filespec */
Xchar *filespec;
X{
X	char *rname, *rindex();
X
X	rname = rindex(filespec,'/');
X
X	if (rname != NULL)
X		return(rname);
X	else
X		return(filespec);
X}
X
Xchar *getpath(filespec)
Xchar *filespec;
X{
X	char rbuff[LFILEN];
X	char *rname, *rindex();
X
X	strcpy(rbuff,filespec);
X	rname = rindex(rbuff,'/');
X
X	if (rname == NULL)
X		return(NULL);
X	else
X	{
X		*(++rname) = '\0';
X		return(rbuff);
X	}
X
X}
X
Xchar *dolock(fname)
X	char *fname;
X{
X	static char lockname[LFILEN] = LOCKDIR;
X	static char username[12];
X	static char lmsg[40] = LOCKMSG;
X	char *pathfmt;
X	struct stat statblk;
X	struct passwd *pblk;
X	long pid, getpid();
X	FILE *lf, *fopen();
X	int oldumask;
X
X	oldumask = umask(0);	/* maximum access allowed to lock files */
X
X
X	  if (*fname != '/')
X	   pathfmt = "./%s%s";
X	  else
X	   pathfmt = "%s/%s";
X	  sprintf(lockname,pathfmt,getpath(fname), LOCKDIR);
X
X	  if (tellall) printf("checking for existence of %s\n",lockname);
X
X	  if (stat(lockname,&statblk))
X	  {
X		 if (tellall) printf("making directory %s\n",lockname);
X		 mkdir(lockname,0777); 
X	  }
X
X	  sprintf(lockname,"%s/%s",lockname,gtname(fname));
X
X	  if (tellall) printf("checking for existence of %s\n",lockname);
X
X	  if (stat(lockname,&statblk))
X	  {
Xmakelock:  	if (tellall) printf("creating %s\n",lockname);
X
X		if ((lf = fopen(lockname,FOP_TW)) == NULL)
X		  LOCKERR("could not create lock file")
X	        else
X	  	{
X			if (parent)
X			 pid = getppid();	/* parent pid */
X			else
X			 pid = getpid();	/* current pid */
X
X			 if (tellall)
X			  printf("pid is %ld\n",pid); 
X
X			 fprintf(lf,"%ld",pid); /* write pid to lock file */
X
X			fclose(lf);
X			oldumask = umask(oldumask);
X			return(NULL);
X		}
X	  }
X	  else
X	  {
X		if (tellall) printf("reading lock file %s\n",lockname);
X		if ((lf = fopen(lockname,FOP_TR)) == NULL)
X		  LOCKERR("could not read lock file")
X	        else
X	  	{
X			fscanf(lf,"%ld",&pid); /* contains current pid */
X			fclose(lf);
X			if (tellall)
X			 printf("pid in %s is %ld\n",lockname, pid);
X			if (tellall)
X			 printf("signaling process %ld\n", pid);
X			if (kill(pid,0))
X				switch (errno)
X				{
X				  case ESRCH:	/* process not found */
X						goto makelock;
X						break;
X				  case EPERM:	/* process exists, not yours */
X			 			if (tellall) 
X						 puts("process exists");
X						break;
X				  default:
X					LOCKERR("kill was bad")
X					break;
X				}
X			else
X			 if (tellall) puts("kill was good; process exists");
X		}
X		if ((pblk = getpwuid(statblk.st_uid)) == NULL)
X		  sprintf(username,"uid %d",atoi(statblk.st_uid));
X		else
X		  strcpy(username,pblk->pw_name);
X
X		oldumask = umask(oldumask);
X		return(username);
X	  }
X}
X
X/**********************
X *
X * undolock -- unlock the file fname
X *
X * if successful, returns NULL 
X * if other error, returns "LOCK ERROR: explanation"
X *
X * Jon Reid, 2/19/86
X *
X *********************/
X
Xchar *undolock(fname)
X	char *fname;
X{
X	static char lockname[LFILEN] = LOCKDIR;
X	static char lmsg[40] = LOCKMSG;
X	char *pathfmt;
X
X	  if (*fname != '/')
X	   pathfmt = "./%s%s";
X	  else
X	   pathfmt = "%s/%s";
X	  sprintf(lockname,pathfmt,getpath(fname), LOCKDIR);
X
X	  sprintf(lockname,"%s/%s",lockname,gtname(fname));
X
X	  if (tellall) printf("attempting to unlink %s\n",lockname);
X
X	  if (unlink(lockname))
X	  { 
X		strcat(lmsg,"could not remove lock file"); 
X		return(lmsg); 
X	  }
X	  else
X	  	  return(NULL);
X}
X
X#endif
X
X/******************
X * end dolock module
X *******************/
X
X#else
Xdolhello()
X{
X}
X#endif
X
FRIDAY_NIGHT
echo extracting - eval.c
sed 's/^X//' > eval.c << 'FRIDAY_NIGHT'
X/*	EVAL.C:	Expresion evaluation functions for
X		MicroEMACS
X
X	written 1986 by Daniel Lawrence				*/
X
X#include	<stdio.h>
X#include	"estruct.h"
X#include	"edef.h"
X#include	"evar.h"
X
Xvarinit()		/* initialize the user variable list */
X
X{
X	register int i;
X
X	for (i=0; i < MAXVARS; i++)
X		uv[i].u_name[0] = 0;
X}
X
Xchar *gtfun(fname)	/* evaluate a function */
X
Xchar *fname;		/* name of function to evaluate */
X
X{
X	register int fnum;		/* index to function to eval */
X	register int status;		/* return status */
X	register char *tsp;		/* temporary string pointer */
X	char arg1[NSTRING];		/* value of first argument */
X	char arg2[NSTRING];		/* value of second argument */
X	char arg3[NSTRING];		/* value of third argument */
X	static char result[2 * NSTRING];	/* string result */
X	char *flook();			/* look file up on path */
X	char *xlat();			/* translate a char string */
X#if	ENVFUNC
X	char *getenv();			/* get environment string */
X#endif
X
X	/* look the function up in the function table */
X	fname[3] = 0;	/* only first 3 chars significant */
X	mklower(fname);	/* and let it be upper or lower case */
X	for (fnum = 0; fnum < NFUNCS; fnum++)
X		if (strcmp(fname, funcs[fnum].f_name) == 0)
X			break;
X
X	/* return errorm on a bad reference */
X	if (fnum == NFUNCS)
X		return(errorm);
X
X	/* if needed, retrieve the first argument */
X	if (funcs[fnum].f_type >= MONAMIC) {
X		if ((status = macarg(arg1)) != TRUE)
X			return(errorm);
X
X		/* if needed, retrieve the second argument */
X		if (funcs[fnum].f_type >= DYNAMIC) {
X			if ((status = macarg(arg2)) != TRUE)
X				return(errorm);
X	
X			/* if needed, retrieve the third argument */
X			if (funcs[fnum].f_type >= TRINAMIC)
X				if ((status = macarg(arg3)) != TRUE)
X					return(errorm);
X		}
X	}
X		
X
X	/* and now evaluate it! */
X	switch (fnum) {
X		case UFADD:	return(itoa(atoi(arg1) + atoi(arg2)));
X		case UFSUB:	return(itoa(atoi(arg1) - atoi(arg2)));
X		case UFTIMES:	return(itoa(atoi(arg1) * atoi(arg2)));
X		case UFDIV:	return(itoa(atoi(arg1) / atoi(arg2)));
X		case UFMOD:	return(itoa(atoi(arg1) % atoi(arg2)));
X		case UFNEG:	return(itoa(-atoi(arg1)));
X		case UFCAT:	strcpy(result, arg1);
X				return(strcat(result, arg2));
X		case UFLEFT:	return(strncpy(result, arg1, atoi(arg2)));
X		case UFRIGHT:	return(strcpy(result,
X					&arg1[(strlen(arg1) - atoi(arg2))]));
X		case UFMID:	return(strncpy(result, &arg1[atoi(arg2)-1],
X					atoi(arg3)));
X		case UFNOT:	return(ltos(stol(arg1) == FALSE));
X		case UFEQUAL:	return(ltos(atoi(arg1) == atoi(arg2)));
X		case UFLESS:	return(ltos(atoi(arg1) < atoi(arg2)));
X		case UFGREATER:	return(ltos(atoi(arg1) > atoi(arg2)));
X		case UFSEQUAL:	return(ltos(strcmp(arg1, arg2) == 0));
X		case UFSLESS:	return(ltos(strcmp(arg1, arg2) < 0));
X		case UFSGREAT:	return(ltos(strcmp(arg1, arg2) > 0));
X		case UFIND:	return(strcpy(result, getval(arg1)));
X		case UFAND:	return(ltos(stol(arg1) && stol(arg2)));
X		case UFOR:	return(ltos(stol(arg1) || stol(arg2)));
X		case UFLENGTH:	return(itoa(strlen(arg1)));
X		case UFUPPER:	return(mkupper(arg1));
X		case UFLOWER:	return(mklower(arg1));
X		case UFTRUTH:	return(ltos(atoi(arg1) == 42));
X		case UFASCII:	return(itoa((int)arg1[0]));
X		case UFCHR:	result[0] = atoi(arg1);
X				result[1] = 0;
X				return(result);
X		case UFGTKEY:	result[0] = tgetc();
X				result[1] = 0;
X				return(result);
X		case UFRND:	return(itoa((ernd() % abs(atoi(arg1))) + 1));
X		case UFABS:	return(itoa(abs(atoi(arg1))));
X		case UFSINDEX:	return(itoa(sindex(arg1, arg2)));
X		case UFENV:
X#if	ENVFUNC
X				tsp = getenv(arg1);
X				return(tsp == NULL ? "" : tsp);
X#else
X				return("");
X#endif
X		case UFBIND:	return(transbind(arg1));
X		case UFEXIST:	return(ltos(fexist(arg1)));
X		case UFFIND:
X				tsp = flook(arg1, TRUE);
X				return(tsp == NULL ? "" : tsp);
X 		case UFBAND:	return(itoa(atoi(arg1) & atoi(arg2)));
X 		case UFBOR:	return(itoa(atoi(arg1) | atoi(arg2)));
X 		case UFBXOR:	return(itoa(atoi(arg1) ^ atoi(arg2)));
X		case UFBNOT:	return(itoa(~atoi(arg1)));
X		case UFXLATE:	return(xlat(arg1, arg2, arg3));
X	}
X
X	exit(-11);	/* never should get here */
X}
X
Xchar *gtusr(vname)	/* look up a user var's value */
X
Xchar *vname;		/* name of user variable to fetch */
X
X{
X
X	register int vnum;	/* ordinal number of user var */
X
X	/* scan the list looking for the user var name */
X	for (vnum = 0; vnum < MAXVARS; vnum++) {
X		if (uv[vnum].u_name[0] == 0)
X			return(errorm);
X		if (strcmp(vname, uv[vnum].u_name) == 0)
X			return(uv[vnum].u_value);
X	}
X
X	/* return errorm if we run off the end */
X	return(errorm);
X}
X
Xchar *gtenv(vname)
X
Xchar *vname;		/* name of environment variable to retrieve */
X
X{
X	register int vnum;	/* ordinal number of var refrenced */
X	char *getkill();
X
X	/* scan the list, looking for the referenced name */
X	for (vnum = 0; vnum < NEVARS; vnum++)
X		if (strcmp(vname, envars[vnum]) == 0)
X			break;
X
X	/* return errorm on a bad reference */
X	if (vnum == NEVARS)
X		return(errorm);
X
X	/* otherwise, fetch the appropriate value */
X	switch (vnum) {
X		case EVFILLCOL:	return(itoa(fillcol));
X		case EVPAGELEN:	return(itoa(term.t_nrow + 1));
X		case EVCURCOL:	return(itoa(getccol(FALSE)));
X		case EVCURLINE: return(itoa(getcline()));
X		case EVRAM:	return(itoa((int)(envram / 1024l)));
X		case EVFLICKER:	return(ltos(flickcode));
X		case EVCURWIDTH:return(itoa(term.t_ncol));
X		case EVCBUFNAME:return(curbp->b_bname);
X		case EVCFNAME:	return(curbp->b_fname);
X		case EVSRES:	return(sres);
X		case EVDEBUG:	return(ltos(macbug));
X		case EVSTATUS:	return(ltos(cmdstatus));
X		case EVPALETTE:	return(palstr);
X		case EVASAVE:	return(itoa(gasave));
X		case EVACOUNT:	return(itoa(gacount));
X		case EVLASTKEY: return(itoa(lastkey));
X		case EVCURCHAR:
X			return(curwp->w_dotp->l_used ==
X					curwp->w_doto ? itoa('\n') :
X				itoa(lgetc(curwp->w_dotp, curwp->w_doto)));
X		case EVDISCMD:	return(ltos(discmd));
X		case EVVERSION:	return(VERSION);
X		case EVPROGNAME:return(PROGNAME);
X		case EVSEED:	return(itoa(seed));
X		case EVDISINP:	return(ltos(disinp));
X		case EVWLINE:	return(itoa(curwp->w_ntrows));
X		case EVCWLINE:	return(itoa(getwpos()));
X		case EVTARGET:	saveflag = lastflag;
X				return(itoa(curgoal));
X		case EVSEARCH:	return(pat);
X		case EVREPLACE:	return(rpat);
X		case EVMATCH:	return((patmatch == NULL)? "": patmatch);
X		case EVKILL:	return(getkill());
X		case EVCMODE:	return(itoa(curbp->b_mode));
X		case EVGMODE:	return(itoa(gmode));
X		case EVTPAUSE:	return(itoa(term.t_pause));
X		case EVPENDING:
X#if	TYPEAH
X				return(ltos(typahead()));
X#else
X				return(falsem);
X#endif
X		case EVLWIDTH:	return(itoa(llength(curwp->w_dotp)));
X		case EVLINE:	return(getctext());
X		case EVGFLAGS:	return(itoa(gflags));
X		case EVRVAL:	return(itoa(rval));
X	}
X	exit(-12);	/* again, we should never get here */
X}
X
Xchar *getkill()		/* return some of the contents of the kill buffer */
X
X{
X	register int size;	/* max number of chars to return */
X	char value[NSTRING];	/* temp buffer for value */
X
X	if (kbufh == NULL)
X		/* no kill buffer....just a null string */
X		value[0] = 0;
X	else {
X		/* copy in the contents... */
X		if (kused < NSTRING)
X			size = kused;
X		else
X			size = NSTRING - 1;
X		strncpy(value, kbufh->d_chunk, size);
X	}
X
X	/* and return the constructed value */
X	return(value);
X}
X
Xint setvar(f, n)		/* set a variable */
X
Xint f;		/* default flag */
Xint n;		/* numeric arg (can overide prompted value) */
X
X{
X	register int status;	/* status return */
X#if	DEBUGM
X	register char *sp;	/* temp string pointer */
X	register char *ep;	/* ptr to end of outline */
X#endif
X	VDESC vd;		/* variable num/type */
X	char var[NVSIZE+1];	/* name of variable to fetch */
X	char value[NSTRING];	/* value to set variable to */
X
X	/* first get the variable to set.. */
X	if (clexec == FALSE) {
X		status = mlreply("Variable to set: ", &var[0], NVSIZE);
X		if (status != TRUE)
X			return(status);
X	} else {	/* macro line argument */
X		/* grab token and skip it */
X		execstr = token(execstr, var, NVSIZE + 1);
X	}
X
X	/* check the legality and find the var */
X	findvar(var, &vd, NVSIZE + 1);
X	
X	/* if its not legal....bitch */
X	if (vd.v_type == -1) {
X		mlwrite("%%No such variable as '%s'", var);
X		return(FALSE);
X	}
X
X	/* get the value for that variable */
X	if (f == TRUE)
X		strcpy(value, itoa(n));
X	else {
X		status = mlreply("Value: ", &value[0], NSTRING);
X		if (status != TRUE)
X			return(status);
X	}
X
X	/* and set the appropriate value */
X	status = svar(&vd, value);
X
X#if	DEBUGM
X	/* if $debug == TRUE, every assignment will echo a statment to
X	   that effect here. */
X	
X	if (macbug) {
X		strcpy(outline, "(((");
X
X		/* assignment status */
X		strcat(outline, ltos(status));
X		strcat(outline, ":");
X
X		/* variable name */
X		strcat(outline, var);
X		strcat(outline, ":");
X
X		/* and lastly the value we tried to assign */
X		strcat(outline, value);
X		strcat(outline, ")))");
X
X		/* expand '%' to "%%" so mlwrite wont bitch */
X		sp = outline;
X		while (*sp)
X			if (*sp++ == '%') {
X				/* advance to the end */
X				ep = --sp;
X				while (*ep++)
X					;
X				/* null terminate the string one out */
X				*(ep + 1) = 0;
X				/* copy backwards */
X				while(ep-- > sp)
X					*(ep + 1) = *ep;
X
X				/* and advance sp past the new % */
X				sp += 2;					
X			}
X
X		/* write out the debug line */
X		mlforce(outline);
X		update(TRUE);
X
X		/* and get the keystroke to hold the output */
X		if (get1key() == abortc) {
X			mlforce("[Macro aborted]");
X			status = FALSE;
X		}
X	}
X#endif
X
X	/* and return it */
X	return(status);
X}
X
Xfindvar(var, vd, size)	/* find a variables type and name */
X
Xchar *var;	/* name of var to get */
XVDESC *vd;	/* structure to hold type and ptr */
Xint size;	/* size of var array */
X
X{
X	register int vnum;	/* subscript in varable arrays */
X	register int vtype;	/* type to return */
X
Xfvar:	vtype = -1;
X	switch (var[0]) {
X
X		case '$': /* check for legal enviromnent var */
X			for (vnum = 0; vnum < NEVARS; vnum++)
X				if (strcmp(&var[1], envars[vnum]) == 0) {
X					vtype = TKENV;
X					break;
X				}
X			break;
X
X		case '%': /* check for existing legal user variable */
X			for (vnum = 0; vnum < MAXVARS; vnum++)
X				if (strcmp(&var[1], uv[vnum].u_name) == 0) {
X					vtype = TKVAR;
X					break;
X				}
X			if (vnum < MAXVARS)
X				break;
X
X			/* create a new one??? */
X			for (vnum = 0; vnum < MAXVARS; vnum++)
X				if (uv[vnum].u_name[0] == 0) {
X					vtype = TKVAR;
X					strcpy(uv[vnum].u_name, &var[1]);
X					break;
X				}
X			break;
X
X		case '&':	/* indirect operator? */
X			var[4] = 0;
X			if (strcmp(&var[1], "ind") == 0) {
X				/* grab token, and eval it */
X				execstr = token(execstr, var, size);
X				strcpy(var, getval(var));
X				goto fvar;
X			}
X	}
X
X	/* return the results */
X	vd->v_num = vnum;
X	vd->v_type = vtype;
X	return;
X}
X
Xint svar(var, value)		/* set a variable */
X
XVDESC *var;	/* variable to set */
Xchar *value;	/* value to set to */
X
X{
X	register int vnum;	/* ordinal number of var refrenced */
X	register int vtype;	/* type of variable to set */
X	register int status;	/* status return */
X	register int c;		/* translated character */
X	register char * sp;	/* scratch string pointer */
X
X	/* simplify the vd structure (we are gonna look at it a lot) */
X	vnum = var->v_num;
X	vtype = var->v_type;
X
X	/* and set the appropriate value */
X	status = TRUE;
X	switch (vtype) {
X	case TKVAR: /* set a user variable */
X		if (uv[vnum].u_value != NULL)
X			free(uv[vnum].u_value);
X		sp = malloc(strlen(value) + 1);
X		if (sp == NULL)
X			return(FALSE);
X		strcpy(sp, value);
X		uv[vnum].u_value = sp;
X		break;
X
X	case TKENV: /* set an environment variable */
X		status = TRUE;	/* by default */
X		switch (vnum) {
X		case EVFILLCOL:	fillcol = atoi(value);
X				break;
X		case EVPAGELEN:	status = newsize(TRUE, atoi(value));
X				break;
X		case EVCURCOL:	status = setccol(atoi(value));
X				break;
X		case EVCURLINE:	status = gotoline(TRUE, atoi(value));
X				break;
X		case EVRAM:	break;
X		case EVFLICKER:	flickcode = stol(value);
X				break;
X		case EVCURWIDTH:status = newwidth(TRUE, atoi(value));
X				break;
X		case EVCBUFNAME:strcpy(curbp->b_bname, value);
X				curwp->w_flag |= WFMODE;
X				break;
X		case EVCFNAME:	strcpy(curbp->b_fname, value);
X				curwp->w_flag |= WFMODE;
X				break;
X		case EVSRES:	status = TTrez(value);
X				break;
X		case EVDEBUG:	macbug = stol(value);
X				break;
X		case EVSTATUS:	cmdstatus = stol(value);
X				break;
X		case EVPALETTE:	strncpy(palstr, value, 48);
X				spal(palstr);
X				break;
X		case EVASAVE:	gasave = atoi(value);
X				break;
X		case EVACOUNT:	gacount = atoi(value);
X				break;
X		case EVLASTKEY:	lastkey = atoi(value);
X				break;
X		case EVCURCHAR:	ldelete(1L, FALSE);	/* delete 1 char */
X				c = atoi(value);
X				if (c == '\n')
X					lnewline(FALSE, 1);
X				else
X					linsert(1, c);
X				backchar(FALSE, 1);
X				break;
X		case EVDISCMD:	discmd = stol(value);
X				break;
X		case EVVERSION:	break;
X		case EVPROGNAME:break;
X		case EVSEED:	seed = atoi(value);
X				break;
X		case EVDISINP:	disinp = stol(value);
X				break;
X		case EVWLINE:	status = resize(TRUE, atoi(value));
X				break;
X		case EVCWLINE:	status = forwline(TRUE,
X						atoi(value) - getwpos());
X				break;
X		case EVTARGET:	curgoal = atoi(value);
X				thisflag = saveflag;
X				break;
X		case EVSEARCH:	strcpy(pat, value);
X				rvstrcpy(tap, pat);
X#if	MAGIC
X				mcclear();
X#endif
X				break;
X		case EVREPLACE:	strcpy(rpat, value);
X				break;
X		case EVMATCH:	break;
X		case EVKILL:	break;
X		case EVCMODE:	curbp->b_mode = atoi(value);
X				curwp->w_flag |= WFMODE;
X				break;
X		case EVGMODE:	gmode = atoi(value);
X				break;
X		case EVTPAUSE:	term.t_pause = atoi(value);
X				break;
X		case EVPENDING:	break;
X		case EVLWIDTH:	break;
X		case EVLINE:	putctext(value);
X		case EVGFLAGS:	gflags = atoi(value);
X				break;
X		case EVRVAL:	break;
X		}
X		break;
X	}
X	return(status);
X}
X
X/*	atoi:	ascii string to integer......This is too
X		inconsistant to use the system's	*/
X
Xatoi(st)
X
Xchar *st;
X
X{
X	int result;	/* resulting number */
X	int sign;	/* sign of resulting number */
X	char c;		/* current char being examined */
X
X	result = 0;
X	sign = 1;
X
X	/* skip preceding whitespace */
X	while (*st == ' ' || *st == '\t')
X		++st;
X
X	/* check for sign */
X	if (*st == '-') {
X		sign = -1;
X		++st;
X	}
X	if (*st == '+')
X		++st;
X
X	/* scan digits, build value */
X	while ((c = *st++))
X		if (c >= '0' && c <= '9')
X			result = result * 10 + c - '0';
X		else
X			return(0);
X
X	return(result * sign);
X}
X
X/*	itoa:	integer to ascii string.......... This is too
X		inconsistant to use the system's	*/
X
Xchar *itoa(i)
X
Xint i;	/* integer to translate to a string */
X
X{
X	register int digit;		/* current digit being used */
X	register char *sp;		/* pointer into result */
X	register int sign;		/* sign of resulting number */
X	static char result[INTWIDTH+1];	/* resulting string */
X
X	/* record the sign...*/
X	sign = 1;
X	if (i < 0) {
X		sign = -1;
X		i = -i;
X	}
X
X	/* and build the string (backwards!) */
X	sp = result + INTWIDTH;
X	*sp = 0;
X	do {
X		digit = i % 10;
X		*(--sp) = '0' + digit;	/* and install the new digit */
X		i = i / 10;
X	} while (i);
X
X	/* and fix the sign */
X	if (sign == -1) {
X		*(--sp) = '-';	/* and install the minus sign */
X	}
X
X	return(sp);
X}
X
Xint gettyp(token)	/* find the type of a passed token */
X
Xchar *token;	/* token to analyze */
X
X{
X	register char c;	/* first char in token */
X
X	/* grab the first char (this is all we need) */
X	c = *token;
X
X	/* no blanks!!! */
X	if (c == 0)
X		return(TKNUL);
X
X	/* a numeric literal? */
X	if (c >= '0' && c <= '9')
X		return(TKLIT);
X
X	switch (c) {
X		case '"':	return(TKSTR);
X
X		case '!':	return(TKDIR);
X		case '@':	return(TKARG);
X		case '#':	return(TKBUF);
X		case '$':	return(TKENV);
X		case '%':	return(TKVAR);
X		case '&':	return(TKFUN);
X		case '*':	return(TKLBL);
X
X		default:	return(TKCMD);
X	}
X}
X
Xchar *getval(token)	/* find the value of a token */
X
Xchar *token;		/* token to evaluate */
X
X{
X	register int status;	/* error return */
X	register BUFFER *bp;	/* temp buffer pointer */
X	register int blen;	/* length of buffer argument */
X	register int distmp;	/* temporary discmd flag */
X	static char buf[NSTRING];/* string buffer for some returns */
X
X	switch (gettyp(token)) {
X		case TKNUL:	return("");
X
X		case TKARG:	/* interactive argument */
X				strcpy(token, getval(&token[1]));
X				distmp = discmd;	/* echo it always! */
X				discmd = TRUE;
X				status = getstring(token,
X					   buf, NSTRING, ctoec('\n'));
X				discmd = distmp;
X				if (status == ABORT)
X					return(errorm);
X				return(buf);
X
X		case TKBUF:	/* buffer contents fetch */
X
X				/* grab the right buffer */
X				strcpy(token, getval(&token[1]));
X				bp = bfind(token, FALSE, 0);
X				if (bp == NULL)
X					return(errorm);
X		
X				/* if the buffer is displayed, get the window
X				   vars instead of the buffer vars */
X				if (bp->b_nwnd > 0) {
X					curbp->b_dotp = curwp->w_dotp;
X					curbp->b_doto = curwp->w_doto;
X				}
X
X				/* make sure we are not at the end */
X				if (bp->b_linep == bp->b_dotp)
X					return(errorm);
X		
X				/* grab the line as an argument */
X				blen = bp->b_dotp->l_used - bp->b_doto;
X				if (blen > NSTRING)
X					blen = NSTRING;
X				strncpy(buf, bp->b_dotp->l_text + bp->b_doto,
X					blen);
X				buf[blen] = 0;
X		
X				/* and step the buffer's line ptr ahead a line */
X				bp->b_dotp = bp->b_dotp->l_fp;
X				bp->b_doto = 0;
X
X				/* if displayed buffer, reset window ptr vars*/
X				if (bp->b_nwnd > 0) {
X					curwp->w_dotp = curbp->b_dotp;
X					curwp->w_doto = 0;
X					curwp->w_flag |= WFMOVE;
X				}
X
X				/* and return the spoils */
X				return(buf);		
X
X		case TKVAR:	return(gtusr(token+1));
X		case TKENV:	return(gtenv(token+1));
X		case TKFUN:	return(gtfun(token+1));
X		case TKDIR:	return(errorm);
X		case TKLBL:	return(errorm);
X		case TKLIT:	return(token);
X		case TKSTR:	return(token+1);
X		case TKCMD:	return(token);
X	}
X}
X
Xint stol(val)	/* convert a string to a numeric logical */
X
Xchar *val;	/* value to check for stol */
X
X{
X	/* check for logical values */
X	if (val[0] == 'F')
X		return(FALSE);
X	if (val[0] == 'T')
X		return(TRUE);
X
X	/* check for numeric truth (!= 0) */
X	return((atoi(val) != 0));
X}
X
Xchar *ltos(val)		/* numeric logical to string logical */
X
Xint val;	/* value to translate */
X
X{
X	if (val)
X		return(truem);
X	else
X		return(falsem);
X}
X
Xchar *mkupper(str)	/* make a string upper case */
X
Xchar *str;		/* string to upper case */
X
X{
X	char *sp;
X
X	sp = str;
X	while (*sp) {
X		if ('a' <= *sp && *sp <= 'z')
X			*sp += 'A' - 'a';
X		++sp;
X	}
X	return(str);
X}
X
Xchar *mklower(str)	/* make a string lower case */
X
Xchar *str;		/* string to lower case */
X
X{
X	char *sp;
X
X	sp = str;
X	while (*sp) {
X		if ('A' <= *sp && *sp <= 'Z')
X			*sp += 'a' - 'A';
X		++sp;
X	}
X	return(str);
X}
X
Xint abs(x)	/* take the absolute value of an integer */
X
Xint x;
X
X{
X	return(x < 0 ? -x : x);
X}
X
Xint ernd()	/* returns a random integer */
X
X{
X	seed = abs(seed * 1721 + 10007);
X	return(seed);
X}
X
Xint sindex(source, pattern)	/* find pattern within source */
X
Xchar *source;	/* source string to search */
Xchar *pattern;	/* string to look for */
X
X{
X	char *sp;	/* ptr to current position to scan */
X	char *csp;	/* ptr to source string during comparison */
X	char *cp;	/* ptr to place to check for equality */
X
X	/* scanning through the source string */
X	sp = source;
X	while (*sp) {
X		/* scan through the pattern */
X		cp = pattern;
X		csp = sp;
X		while (*cp) {
X			if (!eq(*cp, *csp))
X				break;
X			++cp;
X			++csp;
X		}
X
X		/* was it a match? */
X		if (*cp == 0)
X			return((int)(sp - source) + 1);
X		++sp;
X	}
X
X	/* no match at all.. */
X	return(0);
X}
X
X/*	Filter a string through a translation table	*/
X
Xchar *xlat(source, lookup, trans)
X
Xchar *source;	/* string to filter */
Xchar *lookup;	/* characters to translate */
Xchar *trans;	/* resulting translated characters */
X
X{
X	register char *sp;	/* pointer into source table */
X	register char *lp;	/* pointer into lookup table */
X	register char *rp;	/* pointer into result */
X	static char result[NSTRING];	/* temporary result */
X
X	/* scan source string */
X	sp = source;
X	rp = result;
X	while (*sp) {
X		/* scan lookup table for a match */
X		lp = lookup;
X		while (*lp) {
X			if (*sp == *lp) {
X				*rp++ = trans[lp - lookup];
X				goto xnext;
X			}
X			++lp;
X		}
X
X		/* no match, copy in the source char untranslated */
X		*rp++ = *sp;
X
Xxnext:		++sp;
X	}
X
X	/* terminate and return the result */
X	*rp = 0;
X	return(result);
X}
FRIDAY_NIGHT
echo mes.4 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/15/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.5')
# If you do not see the message
#	`mes.5 completed!'
# then the file was incomplete.
echo extracting - exec.c
sed 's/^X//' > exec.c << 'FRIDAY_NIGHT'
X/*	This file is for functions dealing with execution of
X	commands, command lines, buffers, files and startup files
X
X	written 1986 by Daniel Lawrence				*/
X
X#include	<stdio.h>
X#include	"estruct.h"
X#include	"edef.h"
X
X/* namedcmd:	execute a named command even if it is not bound */
X
Xnamedcmd(f, n)
X
Xint f, n;	/* command arguments [passed through to command executed] */
X
X{
X	register int (*kfunc)(); /* ptr to the requexted function to bind to */
X	int (*getname())();
X
X	/* prompt the user to type a named command */
X	mlwrite(": ");
X
X	/* and now get the function name to execute */
X	kfunc = getname();
X	if (kfunc == NULL) {
X		mlwrite("[No such function]");
X		return(FALSE);
X	}
X
X	/* and then execute the command */
X	return((*kfunc)(f, n));
X}
X
X/*	execcmd:	Execute a command line command to be typed in
X			by the user					*/
X
Xexeccmd(f, n)
X
Xint f, n;	/* default Flag and Numeric argument */
X
X{
X	register int status;		/* status return */
X	char cmdstr[NSTRING];		/* string holding command to execute */
X
X	/* get the line wanted */
X	if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
X		return(status);
X
X	execlevel = 0;
X	return(docmd(cmdstr));
X}
X
X/*	docmd:	take a passed string as a command line and translate
X		it to be executed as a command. This function will be
X		used by execute-command-line and by all source and
X		startup files. Lastflag/thisflag is also updated.
X
X	format of the command line is:
X
X		{# arg} <command-name> {<argument string(s)>}
X
X*/
X
Xdocmd(cline)
X
Xchar *cline;	/* command line to execute */
X
X{
X	register int f;		/* default argument flag */
X	register int n;		/* numeric repeat value */
X	int (*fnc)();		/* function to execute */
X	int status;		/* return status of function */
X	int oldcle;		/* old contents of clexec flag */
X	char *oldestr;		/* original exec string */
X	char tkn[NSTRING];	/* next token off of command line */
X	int (*fncmatch())();
X		
X	/* if we are scanning and not executing..go back here */
X	if (execlevel)
X		return(TRUE);
X
X	oldestr = execstr;	/* save last ptr to string to execute */
X	execstr = cline;	/* and set this one as current */
X
X	/* first set up the default command values */
X	f = FALSE;
X	n = 1;
X	lastflag = thisflag;
X	thisflag = 0;
X
X	if ((status = macarg(tkn)) != TRUE) {	/* and grab the first token */
X		execstr = oldestr;
X		return(status);
X	}
X
X	/* process leadin argument */
X	if (gettyp(tkn) != TKCMD) {
X		f = TRUE;
X		strcpy(tkn, getval(tkn));
X		n = atoi(tkn);
X
X		/* and now get the command to execute */
X		if ((status = macarg(tkn)) != TRUE) {
X			execstr = oldestr;
X			return(status);	
X		}	
X	}
X
X	/* and match the token to see if it exists */
X	if ((fnc = fncmatch(tkn)) == NULL) {
X		mlwrite("[No such Function]");
X		execstr = oldestr;
X		return(FALSE);
X	}
X	
X	/* save the arguments and go execute the command */
X	oldcle = clexec;		/* save old clexec flag */
X	clexec = TRUE;			/* in cline execution */
X	status = (*fnc)(f, n);		/* call the function */
X	cmdstatus = status;		/* save the status */
X	clexec = oldcle;		/* restore clexec flag */
X	execstr = oldestr;
X	return(status);
X}
X
X/* token:	chop a token off a string
X		return a pointer past the token
X*/
X
Xchar *token(src, tok, size)
X
Xchar *src, *tok;	/* source string, destination token string */
Xint size;		/* maximum size of token */
X
X{
X	register int quotef;	/* is the current string quoted? */
X	register char c;	/* temporary character */
X
X	/* first scan past any whitespace in the source string */
X	while (*src == ' ' || *src == '\t')
X		++src;
X
X	/* scan through the source string */
X	quotef = FALSE;
X	while (*src) {
X		/* process special characters */
X		if (*src == '~') {
X			++src;
X			if (*src == 0)
X				break;
X			switch (*src++) {
X				case 'r':	c = 13; break;
X				case 'n':	c = 10; break;
X				case 't':	c = 9;  break;
X				case 'b':	c = 8;  break;
X				case 'f':	c = 12; break;
X				default:	c = *(src-1);
X			}
X			if (--size > 0) {
X				*tok++ = c;
X			}
X		} else {
X			/* check for the end of the token */
X			if (quotef) {
X				if (*src == '"')
X					break;
X			} else {
X				if (*src == ' ' || *src == '\t')
X					break;
X			}
X
X			/* set quote mode if quote found */
X			if (*src == '"')
X				quotef = TRUE;
X
X			/* record the character */
X			c = *src++;
X			if (--size > 0)
X				*tok++ = c;
X		}
X	}
X
X	/* terminate the token and exit */
X	if (*src)
X		++src;
X	*tok = 0;
X	return(src);
X}
X
Xmacarg(tok)	/* get a macro line argument */
X
Xchar *tok;	/* buffer to place argument */
X
X{
X	int savcle;	/* buffer to store original clexec */
X	int status;
X
X	savcle = clexec;	/* save execution mode */
X	clexec = TRUE;		/* get the argument */
X	status = nextarg("", tok, NSTRING, ctoec('\n'));
X	clexec = savcle;	/* restore execution mode */
X	return(status);
X}
X
X/*	nextarg:	get the next argument	*/
X
Xnextarg(prompt, buffer, size, terminator)
X
Xchar *prompt;		/* prompt to use if we must be interactive */
Xchar *buffer;		/* buffer to put token into */
Xint size;		/* size of the buffer */
Xint terminator;		/* terminating char to be used on interactive fetch */
X
X{
X	/* if we are interactive, go get it! */
X	if (clexec == FALSE)
X		return(getstring(prompt, buffer, size, terminator));
X
X	/* grab token and advance past */
X	execstr = token(execstr, buffer, size);
X
X	/* evaluate it */
X	strcpy(buffer, getval(buffer));
X	return(TRUE);
X}
X
X/*	storemac:	Set up a macro buffer and flag to store all
X			executed command lines there			*/
X
Xstoremac(f, n)
X
Xint f;		/* default flag */
Xint n;		/* macro number to use */
X
X{
X	register struct BUFFER *bp;	/* pointer to macro buffer */
X	char bname[NBUFN];		/* name of buffer to use */
X
X	/* must have a numeric argument to this function */
X	if (f == FALSE) {
X		mlwrite("No macro specified");
X		return(FALSE);
X	}
X
X	/* range check the macro number */
X	if (n < 1 || n > 40) {
X		mlwrite("Macro number out of range");
X		return(FALSE);
X	}
X
X	/* construct the macro buffer name */
X	strcpy(bname, "[Macro xx]");
X	bname[7] = '0' + (n / 10);
X	bname[8] = '0' + (n % 10);
X
X	/* set up the new macro buffer */
X	if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
X		mlwrite("Can not create macro");
X		return(FALSE);
X	}
X
X	/* and make sure it is empty */
X	bclear(bp);
X
X	/* and set the macro store pointers to it */
X	mstore = TRUE;
X	bstore = bp;
X	return(TRUE);
X}
X
X#if	PROC
X/*	storeproc:	Set up a procedure buffer and flag to store all
X			executed command lines there			*/
X
Xstoreproc(f, n)
X
Xint f;		/* default flag */
Xint n;		/* macro number to use */
X
X{
X	register struct BUFFER *bp;	/* pointer to macro buffer */
X	register int status;		/* return status */
X	char bname[NBUFN];		/* name of buffer to use */
X
X	/* a numeric argument means its a numbered macro */
X	if (f == TRUE)
X		return(storemac(f, n));
X
X	/* get the name of the procedure */
X        if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE)
X                return(status);
X
X	/* construct the macro buffer name */
X	bname[0] = '[';
X	strcat(bname, "]");
X
X	/* set up the new macro buffer */
X	if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
X		mlwrite("Can not create macro");
X		return(FALSE);
X	}
X
X	/* and make sure it is empty */
X	bclear(bp);
X
X	/* and set the macro store pointers to it */
X	mstore = TRUE;
X	bstore = bp;
X	return(TRUE);
X}
X
X/*	execproc:	Execute a procedure				*/
X
Xexecproc(f, n)
X
Xint f, n;	/* default flag and numeric arg */
X
X{
X        register BUFFER *bp;		/* ptr to buffer to execute */
X        register int status;		/* status return */
X        char bufn[NBUFN+2];		/* name of buffer to execute */
X
X	/* find out what buffer the user wants to execute */
X        if ((status = mlreply("Execute procedure: ", &bufn[1], NBUFN)) != TRUE)
X                return(status);
X
X	/* construct the buffer name */
X	bufn[0] = '[';
X	strcat(bufn, "]");
X
X	/* find the pointer to that buffer */
X        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
X		mlwrite("No such procedure");
X                return(FALSE);
X        }
X
X	/* and now execute it as asked */
X	while (n-- > 0)
X		if ((status = dobuf(bp)) != TRUE)
X			return(status);
X	return(TRUE);
X}
X#endif
X
X/*	execbuf:	Execute the contents of a buffer of commands	*/
X
Xexecbuf(f, n)
X
Xint f, n;	/* default flag and numeric arg */
X
X{
X        register BUFFER *bp;		/* ptr to buffer to execute */
X        register int status;		/* status return */
X        char bufn[NSTRING];		/* name of buffer to execute */
X
X	/* find out what buffer the user wants to execute */
X        if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
X                return(status);
X
X	/* find the pointer to that buffer */
X        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
X		mlwrite("No such buffer");
X                return(FALSE);
X        }
X
X	/* and now execute it as asked */
X	while (n-- > 0)
X		if ((status = dobuf(bp)) != TRUE)
X			return(status);
X	return(TRUE);
X}
X
X/*	dobuf:	execute the contents of the buffer pointed to
X		by the passed BP
X
X	Directives start with a "!" and include:
X
X	!endm		End a macro
X	!if (cond)	conditional execution
X	!else
X	!endif
X	!return		Return (terminating current macro)
X	!goto <label>	Jump to a label in the current macro
X	!force		Force macro to continue...even if command fails
X	!while (cond)	Execute a loop if the condition is true
X	!endwhile
X	
X	Line Labels begin with a "*" as the first nonblank char, like:
X
X	*LBL01
X*/
X
Xdobuf(bp)
X
XBUFFER *bp;	/* buffer to execute */
X
X{
X        register int status;	/* status return */
X	register LINE *lp;	/* pointer to line to execute */
X	register LINE *hlp;	/* pointer to line header */
X	register LINE *glp;	/* line to goto */
X	LINE *mp;		/* Macro line storage temp */
X	int dirnum;		/* directive index */
X	int linlen;		/* length of line to execute */
X	int i;			/* index */
X	int c;			/* temp character */
X	int force;		/* force TRUE result? */
X	WINDOW *wp;		/* ptr to windows to scan */
X	WHBLOCK *whlist;	/* ptr to !WHILE list */
X	WHBLOCK *scanner;	/* ptr during scan */
X	WHBLOCK *whtemp;	/* temporary ptr to a WHBLOCK */
X	char *einit;		/* initial value of eline */
X	char *eline;		/* text of line to execute */
X	char tkn[NSTRING];	/* buffer to evaluate an expresion in */
X
X#if	DEBUGM
X	char *sp;			/* temp for building debug string */
X	register char *ep;	/* ptr to end of outline */
X#endif
X
X	/* clear IF level flags/while ptr */
X	execlevel = 0;
X	whlist = NULL;
X	scanner = NULL;
X
X	/* scan the buffer to execute, building WHILE header blocks */
X	hlp = bp->b_linep;
X	lp = hlp->l_fp;
X	while (lp != hlp) {
X		/* scan the current line */
X		eline = lp->l_text;
X		i = lp->l_used;
X
X		/* trim leading whitespace */
X		while (i-- > 0 && (*eline == ' ' || *eline == '\t'))
X			++eline;
X
X		/* if theres nothing here, don't bother */
X		if (i <= 0)
X			goto nxtscan;
X
X		/* if is a while directive, make a block... */
X		if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') {
X			whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
X			if (whtemp == NULL) {
Xnoram:				mlwrite("%%Out of memory during while scan");
Xfailexit:			freewhile(scanner);
X				freewhile(whlist);
X				return(FALSE);
X			}
X			whtemp->w_begin = lp;
X			whtemp->w_type = BTWHILE;
X			whtemp->w_next = scanner;
X			scanner = whtemp;
X		}
X
X		/* if is a BREAK directive, make a block... */
X		if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') {
X			if (scanner == NULL) {
X				mlwrite("%%!BREAK outside of any !WHILE loop");
X				goto failexit;
X			}
X			whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
X			if (whtemp == NULL)
X				goto noram;
X			whtemp->w_begin = lp;
X			whtemp->w_type = BTBREAK;
X			whtemp->w_next = scanner;
X			scanner = whtemp;
X		}
X
X		/* if it is an endwhile directive, record the spot... */
X		if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) {
X			if (scanner == NULL) {
X				mlwrite("%%!ENDWHILE with no preceding !WHILE in '%s'",
X					bp->b_bname);
X				goto failexit;
X			}
X			/* move top records from the scanner list to the
X			   whlist until we have moved all BREAK records
X			   and one WHILE record */
X			do {
X				scanner->w_end = lp;
X				whtemp = whlist;
X				whlist = scanner;
X				scanner = scanner->w_next;
X				whlist->w_next = whtemp;
X			} while (whlist->w_type == BTBREAK);
X		}
X
Xnxtscan:	/* on to the next line */
X		lp = lp->l_fp;
X	}
X
X	/* while and endwhile should match! */
X	if (scanner != NULL) {
X		mlwrite("%%!WHILE with no matching !ENDWHILE in '%s'",
X			bp->b_bname);
X		goto failexit;
X	}
X
X	/* let the first command inherit the flags from the last one..*/
X	thisflag = lastflag;
X
X	/* starting at the beginning of the buffer */
X	hlp = bp->b_linep;
X	lp = hlp->l_fp;
X	while (lp != hlp) {
X		/* allocate eline and copy macro line to it */
X		linlen = lp->l_used;
X		if ((einit = eline = malloc(linlen+1)) == NULL) {
X			mlwrite("%%Out of Memory during macro execution");
X			freewhile(whlist);
X			return(FALSE);
X		}
X		strncpy(eline, lp->l_text, linlen);
X		eline[linlen] = 0;	/* make sure it ends */
X
X		/* trim leading whitespace */
X		while (*eline == ' ' || *eline == '\t')
X			++eline;
X
X		/* dump comments and blank lines */
X		if (*eline == ';' || *eline == 0)
X			goto onward;
X
X#if	DEBUGM
X		/* if $debug == TRUE, every line to execute
X		   gets echoed and a key needs to be pressed to continue
X		   ^G will abort the command */
X	
X		if (macbug) {
X			strcpy(outline, "<<<");
X	
X			/* debug macro name */
X			strcat(outline, bp->b_bname);
X			strcat(outline, ":");
X	
X			/* debug if levels */
X			strcat(outline, itoa(execlevel));
X			strcat(outline, ":");
X
X			/* and lastly the line */
X			strcat(outline, eline);
X			strcat(outline, ">>>");
X	
X			/* change all '%' to ':' so mlwrite won't expect arguments */
X			sp = outline;
X			while (*sp)
X			if (*sp++ == '%') {
X				/* advance to the end */
X				ep = --sp;
X				while (*ep++)
X					;
X				/* null terminate the string one out */
X				*(ep + 1) = 0;
X				/* copy backwards */
X				while(ep-- > sp)
X					*(ep + 1) = *ep;
X
X				/* and advance sp past the new % */
X				sp += 2;					
X			}
X	
X			/* write out the debug line */
X			mlforce(outline);
X			update(TRUE);
X	
X			/* and get the keystroke */
X			if ((c = get1key()) == abortc) {
X				mlforce("[Macro aborted]");
X				freewhile(whlist);
X				return(FALSE);
X			}
X
X			if (c == metac)
X				macbug = FALSE;
X		}
X#endif
X
X		/* Parse directives here.... */
X		dirnum = -1;
X		if (*eline == '!') {
X			/* Find out which directive this is */
X			++eline;
X			for (dirnum = 0; dirnum < NUMDIRS; dirnum++)
X				if (strncmp(eline, dname[dirnum],
X				            strlen(dname[dirnum])) == 0)
X					break;
X
X			/* and bitch if it's illegal */
X			if (dirnum == NUMDIRS) {
X				mlwrite("%%Unknown Directive");
X				freewhile(whlist);
X				return(FALSE);
X			}
X
X			/* service only the !ENDM macro here */
X			if (dirnum == DENDM) {
X				mstore = FALSE;
X				bstore = NULL;
X				goto onward;
X			}
X
X			/* restore the original eline....*/
X			--eline;
X		}
X
X		/* if macro store is on, just salt this away */
X		if (mstore) {
X			/* allocate the space for the line */
X			linlen = strlen(eline);
X			if ((mp=lalloc(linlen)) == NULL) {
X				mlwrite("Out of memory while storing macro");
X				return (FALSE);
X			}
X	
X			/* copy the text into the new line */
X			for (i=0; i<linlen; ++i)
X				lputc(mp, i, eline[i]);
X	
X			/* attach the line to the end of the buffer */
X	       		bstore->b_linep->l_bp->l_fp = mp;
X			mp->l_bp = bstore->b_linep->l_bp;
X			bstore->b_linep->l_bp = mp;
X			mp->l_fp = bstore->b_linep;
X			goto onward;
X		}
X	
X
X		force = FALSE;
X
X		/* dump comments */
X		if (*eline == '*')
X			goto onward;
X
X		/* now, execute directives */
X		if (dirnum != -1) {
X			/* skip past the directive */
X			while (*eline && *eline != ' ' && *eline != '\t')
X				++eline;
X			execstr = eline;
X
X			switch (dirnum) {
X			case DIF:	/* IF directive */
X				/* grab the value of the logical exp */
X				if (execlevel == 0) {
X					if (macarg(tkn) != TRUE)
X						goto eexec;
X					if (stol(tkn) == FALSE)
X						++execlevel;
X				} else
X					++execlevel;
X				goto onward;
X
X			case DWHILE:	/* WHILE directive */
X				/* grab the value of the logical exp */
X				if (execlevel == 0) {
X					if (macarg(tkn) != TRUE)
X						goto eexec;
X					if (stol(tkn) == TRUE)
X						goto onward;
X				}
X				/* drop down and act just like !BREAK */
X
X			case DBREAK:	/* BREAK directive */
X				if (dirnum == DBREAK && execlevel)
X					goto onward;
X
X				/* jump down to the endwhile */
X				/* find the right while loop */
X				whtemp = whlist;
X				while (whtemp) {
X					if (whtemp->w_begin == lp)
X						break;
X					whtemp = whtemp->w_next;
X				}
X			
X				if (whtemp == NULL) {
X					mlwrite("%%Internal While loop error");
X					freewhile(whlist);
X					return(FALSE);
X				}
X			
X				/* reset the line pointer back.. */
X				lp = whtemp->w_end;
X				goto onward;
X
X			case DELSE:	/* ELSE directive */
X				if (execlevel == 1)
X					--execlevel;
X				else if (execlevel == 0 )
X					++execlevel;
X				goto onward;
X
X			case DENDIF:	/* ENDIF directive */
X				if (execlevel)
X					--execlevel;
X				goto onward;
X
X			case DGOTO:	/* GOTO directive */
X				/* .....only if we are currently executing */
X				if (execlevel == 0) {
X
X					/* grab label to jump to */
X					eline = token(eline, golabel, NPAT);
X					linlen = strlen(golabel);
X					glp = hlp->l_fp;
X					while (glp != hlp) {
X						if (*glp->l_text == '*' &&
X						    (strncmp(&glp->l_text[1], golabel,
X						            linlen) == 0)) {
X							lp = glp;
X							goto onward;
X						}
X						glp = glp->l_fp;
X					}
X					mlwrite("%%No such label");
X					freewhile(whlist);
X					return(FALSE);
X				}
X				goto onward;
X	
X			case DRETURN:	/* RETURN directive */
X				if (execlevel == 0)
X					goto eexec;
X				goto onward;
X
X			case DENDWHILE:	/* ENDWHILE directive */
X				if (execlevel) {
X					--execlevel;
X					goto onward;
X				} else {
X					/* find the right while loop */
X					whtemp = whlist;
X					while (whtemp) {
X						if (whtemp->w_type == BTWHILE &&
X						    whtemp->w_end == lp)
X							break;
X						whtemp = whtemp->w_next;
X					}
X		
X					if (whtemp == NULL) {
X						mlwrite("%%Internal While loop error");
X						freewhile(whlist);
X						return(FALSE);
X					}
X		
X					/* reset the line pointer back.. */
X					lp = whtemp->w_begin->l_bp;
X					goto onward;
X				}
X
X			case DFORCE:	/* FORCE directive */
X				force = TRUE;
X
X			}
X		}
X
X		/* execute the statement */
X		status = docmd(eline);
X		if (force)		/* force the status */
X			status = TRUE;
X
X		/* check for a command error */
X		if (status != TRUE) {
X			/* look if buffer is showing */
X			wp = wheadp;
X			while (wp != NULL) {
X				if (wp->w_bufp == bp) {
X					/* and point it */
X					wp->w_dotp = lp;
X					wp->w_doto = 0;
X					wp->w_flag |= WFHARD;
X				}
X				wp = wp->w_wndp;
X			}
X			/* in any case set the buffer . */
X			bp->b_dotp = lp;
X			bp->b_doto = 0;
X			free(einit);
X			execlevel = 0;
X			freewhile(whlist);
X			return(status);
X		}
X
Xonward:		/* on to the next line */
X		free(einit);
X		lp = lp->l_fp;
X	}
X
Xeexec:	/* exit the current function */
X	execlevel = 0;
X	freewhile(whlist);
X        return(TRUE);
X}
X
Xfreewhile(wp)	/* free a list of while block pointers */
X
XWHBLOCK *wp;	/* head of structure to free */
X
X{
X	if (wp == NULL)
X		return;
X	if (wp->w_next)
X		freewhile(wp->w_next);
X	free(wp);
X}
X
Xexecfile(f, n)	/* execute a series of commands in a file */
X
Xint f, n;	/* default flag and numeric arg to pass on to file */
X
X{
X	register int status;	/* return status of name query */
X	char fname[NSTRING];	/* name of file to execute */
X	char *fspec;		/* full file spec */
X
X	if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
X		return(status);
X
X#if	1
X	/* look up the path for the file */
X	fspec = flook(fname, TRUE);
X
X	/* if it isn't around */
X	if (fspec == NULL)
X		return(FALSE);
X
X#endif
X	/* otherwise, execute it */
X	while (n-- > 0)
X		if ((status=dofile(fspec)) != TRUE)
X			return(status);
X
X	return(TRUE);
X}
X
X/*	dofile:	yank a file into a buffer and execute it
X		if there are no errors, delete the buffer on exit */
X
Xdofile(fname)
X
Xchar *fname;	/* file name to execute */
X
X{
X	register BUFFER *bp;	/* buffer to place file to exeute */
X	register BUFFER *cb;	/* temp to hold current buf while we read */
X	register int status;	/* results of various calls */
X	char bname[NBUFN];	/* name of buffer */
X
X	makename(bname, fname);		/* derive the name of the buffer */
X	unqname(bname);			/* make sure we don't stomp things */
X	if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
X		return(FALSE);
X
X	bp->b_mode = MDVIEW;	/* mark the buffer as read only */
X	cb = curbp;		/* save the old buffer */
X	curbp = bp;		/* make this one current */
X	/* and try to read in the file to execute */
X	if ((status = readin(fname, FALSE)) != TRUE) {
X		curbp = cb;	/* restore the current buffer */
X		return(status);
X	}
X
X	/* go execute it! */
X	curbp = cb;		/* restore the current buffer */
X	if ((status = dobuf(bp)) != TRUE)
X		return(status);
X
X	/* if not displayed, remove the now unneeded buffer and exit */
X	if (bp->b_nwnd == 0)
X		zotbuf(bp);
X	return(TRUE);
X}
X
X/*	cbuf:	Execute the contents of a numbered buffer	*/
X
Xcbuf(f, n, bufnum)
X
Xint f, n;	/* default flag and numeric arg */
Xint bufnum;	/* number of buffer to execute */
X
X{
X        register BUFFER *bp;		/* ptr to buffer to execute */
X        register int status;		/* status return */
X	static char bufname[] = "[Macro xx]";
X
X	/* make the buffer name */
X	bufname[7] = '0' + (bufnum / 10);
X	bufname[8] = '0' + (bufnum % 10);
X
X	/* find the pointer to that buffer */
X        if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
X        	mlwrite("Macro not defined");
X                return(FALSE);
X        }
X
X	/* and now execute it as asked */
X	while (n-- > 0)
X		if ((status = dobuf(bp)) != TRUE)
X			return(status);
X	return(TRUE);
X}
X
Xcbuf1(f, n)
X
X{
X	cbuf(f, n, 1);
X}
X
Xcbuf2(f, n)
X
X{
X	cbuf(f, n, 2);
X}
X
Xcbuf3(f, n)
X
X{
X	cbuf(f, n, 3);
X}
X
Xcbuf4(f, n)
X
X{
X	cbuf(f, n, 4);
X}
X
Xcbuf5(f, n)
X
X{
X	cbuf(f, n, 5);
X}
X
Xcbuf6(f, n)
X
X{
X	cbuf(f, n, 6);
X}
X
Xcbuf7(f, n)
X
X{
X	cbuf(f, n, 7);
X}
X
Xcbuf8(f, n)
X
X{
X	cbuf(f, n, 8);
X}
X
Xcbuf9(f, n)
X
X{
X	cbuf(f, n, 9);
X}
X
Xcbuf10(f, n)
X
X{
X	cbuf(f, n, 10);
X}
X
Xcbuf11(f, n)
X
X{
X	cbuf(f, n, 11);
X}
X
Xcbuf12(f, n)
X
X{
X	cbuf(f, n, 12);
X}
X
Xcbuf13(f, n)
X
X{
X	cbuf(f, n, 13);
X}
X
Xcbuf14(f, n)
X
X{
X	cbuf(f, n, 14);
X}
X
Xcbuf15(f, n)
X
X{
X	cbuf(f, n, 15);
X}
X
Xcbuf16(f, n)
X
X{
X	cbuf(f, n, 16);
X}
X
Xcbuf17(f, n)
X
X{
X	cbuf(f, n, 17);
X}
X
Xcbuf18(f, n)
X
X{
X	cbuf(f, n, 18);
X}
X
Xcbuf19(f, n)
X
X{
X	cbuf(f, n, 19);
X}
X
Xcbuf20(f, n)
X
X{
X	cbuf(f, n, 20);
X}
X
Xcbuf21(f, n)
X
X{
X	cbuf(f, n, 21);
X}
X
Xcbuf22(f, n)
X
X{
X	cbuf(f, n, 22);
X}
X
Xcbuf23(f, n)
X
X{
X	cbuf(f, n, 23);
X}
X
Xcbuf24(f, n)
X
X{
X	cbuf(f, n, 24);
X}
X
Xcbuf25(f, n)
X
X{
X	cbuf(f, n, 25);
X}
X
Xcbuf26(f, n)
X
X{
X	cbuf(f, n, 26);
X}
X
Xcbuf27(f, n)
X
X{
X	cbuf(f, n, 27);
X}
X
Xcbuf28(f, n)
X
X{
X	cbuf(f, n, 28);
X}
X
Xcbuf29(f, n)
X
X{
X	cbuf(f, n, 29);
X}
X
Xcbuf30(f, n)
X
X{
X	cbuf(f, n, 30);
X}
X
Xcbuf31(f, n)
X
X{
X	cbuf(f, n, 31);
X}
X
Xcbuf32(f, n)
X
X{
X	cbuf(f, n, 32);
X}
X
Xcbuf33(f, n)
X
X{
X	cbuf(f, n, 33);
X}
X
Xcbuf34(f, n)
X
X{
X	cbuf(f, n, 34);
X}
X
Xcbuf35(f, n)
X
X{
X	cbuf(f, n, 35);
X}
X
Xcbuf36(f, n)
X
X{
X	cbuf(f, n, 36);
X}
X
Xcbuf37(f, n)
X
X{
X	cbuf(f, n, 37);
X}
X
Xcbuf38(f, n)
X
X{
X	cbuf(f, n, 38);
X}
X
Xcbuf39(f, n)
X
X{
X	cbuf(f, n, 39);
X}
X
Xcbuf40(f, n)
X
X{
X	cbuf(f, n, 40);
X}
X
X
FRIDAY_NIGHT
echo extracting - file.c
sed 's/^X//' > file.c << 'FRIDAY_NIGHT'
X/*	FILE.C:   for MicroEMACS
X
X	The routines in this file handle the reading, writing
X	and lookup of disk files.  All of details about the
X	reading and writing of the disk are in "fileio.c".
X
X*/
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X/*
X * Read a file into the current
X * buffer. This is really easy; all you do it
X * find the name of the file, and call the standard
X * "read a file into the current buffer" code.
X * Bound to "C-X C-R".
X */
Xfileread(f, n)
X{
X        register int    s;
X        char fname[NFILEN];
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
X                return(s);
X        return(readin(fname, TRUE));
X}
X
X/*
X * Insert a file into the current
X * buffer. This is really easy; all you do it
X * find the name of the file, and call the standard
X * "insert a file into the current buffer" code.
X * Bound to "C-X C-I".
X */
Xinsfile(f, n)
X{
X        register int    s;
X        char fname[NFILEN];
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
X                return(s);
X        return(ifile(fname));
X}
X
X/*
X * Select a file for editing.
X * Look around to see if you can find the
X * fine in another buffer; if you can find it
X * just switch to the buffer. If you cannot find
X * the file, create a new buffer, read in the
X * text, and switch to the new buffer.
X * Bound to C-X C-F.
X */
Xfilefind(f, n)
X{
X        char fname[NFILEN];	/* file user wishes to find */
X        register int s;		/* status return */
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
X                return(s);
X	return(getfile(fname, TRUE));
X}
X
Xviewfile(f, n)	/* visit a file in VIEW mode */
X{
X        char fname[NFILEN];	/* file user wishes to find */
X        register int s;		/* status return */
X	register WINDOW *wp;	/* scan for windows that need updating */
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
X                return (s);
X	s = getfile(fname, FALSE);
X	if (s) {	/* if we succeed, put it in view mode */
X		curwp->w_bufp->b_mode |= MDVIEW;
X
X		/* scan through and update mode lines of all windows */
X		wp = wheadp;
X		while (wp != NULL) {
X			wp->w_flag |= WFMODE;
X			wp = wp->w_wndp;
X		}
X	}
X	return(s);
X}
X
X#if	CRYPT
Xresetkey()	/* reset the encryption key if needed */
X
X{
X	register int s;	/* return status */
X
X	/* turn off the encryption flag */
X	cryptflag = FALSE;
X
X	/* if we are in crypt mode */
X	if (curbp->b_mode & MDCRYPT) {
X		if (curbp->b_key[0] == 0) {
X			s = setkey(FALSE, 0);
X			if (s != TRUE)
X				return(s);
X		}
X
X		/* let others know... */
X		cryptflag = TRUE;
X
X		/* and set up the key to be used! */
X		/* de-encrypt it */
X		crypt((char *)NULL, 0);
X		crypt(curbp->b_key, strlen(curbp->b_key));
X
X		/* re-encrypt it...seeding it to start */
X		crypt((char *)NULL, 0);
X		crypt(curbp->b_key, strlen(curbp->b_key));
X	}
X
X	return(TRUE);
X}
X#endif
X
Xgetfile(fname, lockfl)
X
Xchar fname[];		/* file name to find */
Xint lockfl;		/* check the file for locks? */
X
X{
X        register BUFFER *bp;
X        register LINE   *lp;
X        register int    i;
X        register int    s;
X        char bname[NBUFN];	/* buffer name to put file */
X
X#if	MSDOS
X	mklower(fname);		/* msdos isn't case sensitive */
X#endif
X        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
X                if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
X			swbuffer(bp);
X                        lp = curwp->w_dotp;
X                        i = curwp->w_ntrows/2;
X                        while (i-- && lback(lp)!=curbp->b_linep)
X                                lp = lback(lp);
X                        curwp->w_linep = lp;
X                        curwp->w_flag |= WFMODE|WFHARD;
X                        mlwrite("[Old buffer]");
X                        return (TRUE);
X                }
X        }
X        makename(bname, fname);                 /* New buffer name.     */
X        while ((bp=bfind(bname, FALSE, 0)) != NULL) {
X		/* old buffer name conflict code */
X                s = mlreply("Buffer name: ", bname, NBUFN);
X                if (s == ABORT)                 /* ^G to just quit      */
X                        return (s);
X                if (s == FALSE) {               /* CR to clobber it     */
X                        makename(bname, fname);
X                        break;
X                }
X        }
X        if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
X                mlwrite("Cannot create buffer");
X                return (FALSE);
X        }
X        if (--curbp->b_nwnd == 0) {             /* Undisplay.           */
X                curbp->b_dotp = curwp->w_dotp;
X                curbp->b_doto = curwp->w_doto;
X                curbp->b_markp = curwp->w_markp;
X                curbp->b_marko = curwp->w_marko;
X        }
X        curbp = bp;                             /* Switch to it.        */
X        curwp->w_bufp = bp;
X        curbp->b_nwnd++;
X        return(readin(fname, lockfl));          /* Read it in.          */
X}
X
X/*
X	Read file "fname" into the current buffer, blowing away any text
X	found there.  Called by both the read and find commands.  Return
X	the final status of the read.  Also called by the mainline, to
X	read in a file specified on the command line as an argument. 
X	The command bound to M-FNR is called after the buffer is set up
X	and before it is read. 
X*/
X
Xreadin(fname, lockfl)
X
Xchar    fname[];	/* name of file to read */
Xint	lockfl;		/* check for file locks? */
X
X{
X        register LINE   *lp1;
X        register LINE   *lp2;
X        register int    i;
X        register WINDOW *wp;
X        register BUFFER *bp;
X        register int    s;
X        register int    nbytes;
X        register int    nline;
X	int		lflag;		/* any lines longer than allowed? */
X	char mesg[NSTRING];
X
X#if	FILOCK
X	if (lockfl && lockchk(fname) == ABORT)
X		return(ABORT);
X#endif
X#if	CRYPT
X	s = resetkey();
X	if (s != TRUE)
X		return(s);
X#endif
X        bp = curbp;                             /* Cheap.               */
X        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
X                return (s);
X        bp->b_flag &= ~(BFINVS|BFCHG);
X        strcpy(bp->b_fname, fname);
X
X	/* let a user macro get hold of things...if he wants */
X	execute(META|SPEC|'R', FALSE, 1);
X
X	/* turn off ALL keyboard translation in case we get a dos error */
X	TTkclose();
X
X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
X                goto out;
X
X        if (s == FIOFNF) {                      /* File not found.      */
X                mlwrite("[New file]");
X                goto out;
X        }
X
X	/* read the file in */
X        mlwrite("[Reading file]");
X        nline = 0;
X	lflag = FALSE;
X        while ((s=ffgetline()) == FIOSUC) {
X                nbytes = strlen(fline);
X                if ((lp1=lalloc(nbytes)) == NULL) {
X                        s = FIOMEM;             /* Keep message on the  */
X                        break;                  /* display.             */
X                }
X                lp2 = lback(curbp->b_linep);
X                lp2->l_fp = lp1;
X                lp1->l_fp = curbp->b_linep;
X                lp1->l_bp = lp2;
X                curbp->b_linep->l_bp = lp1;
X                for (i=0; i<nbytes; ++i)
X                        lputc(lp1, i, fline[i]);
X                ++nline;
X        }
X        ffclose();                              /* Ignore errors.       */
X	strcpy(mesg, "[");
X	if (s==FIOERR) {
X		strcat(mesg, "I/O ERROR, ");
X		curbp->b_flag |= BFTRUNC;
X	}
X	if (s == FIOMEM) {
X		strcat(mesg, "OUT OF MEMORY, ");
X		curbp->b_flag |= BFTRUNC;
X	}
X	sprintf(&mesg[strlen(mesg)], "Read %d line", nline);
X        if (nline > 1)
X		strcat(mesg, "s");
X	strcat(mesg, "]");
X	mlwrite(mesg);
X
Xout:
X	TTkopen();	/* open the keyboard again */
X        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
X                if (wp->w_bufp == curbp) {
X                        wp->w_linep = lforw(curbp->b_linep);
X                        wp->w_dotp  = lforw(curbp->b_linep);
X                        wp->w_doto  = 0;
X                        wp->w_markp = NULL;
X                        wp->w_marko = 0;
X                        wp->w_flag |= WFMODE|WFHARD;
X                }
X        }
X        if (s == FIOERR || s == FIOFNF)		/* False if error.      */
X                return(FALSE);
X        return (TRUE);
X}
X
X/*
X * Take a file name, and from it
X * fabricate a buffer name. This routine knows
X * about the syntax of file names on the target system.
X * I suppose that this information could be put in
X * a better place than a line of code.
X */
Xmakename(bname, fname)
Xchar    bname[];
Xchar    fname[];
X{
X        register char *cp1;
X        register char *cp2;
X
X        cp1 = &fname[0];
X        while (*cp1 != 0)
X                ++cp1;
X
X#if     AMIGA
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
X                --cp1;
X#endif
X#if     VMS
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
X                --cp1;
X#endif
X#if     CPM
X        while (cp1!=&fname[0] && cp1[-1]!=':')
X                --cp1;
X#endif
X#if     MSDOS
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
X                --cp1;
X#endif
X#if     ST520
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
X                --cp1;
X#endif
X#if     FINDER
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
X                --cp1;
X#endif
X#if     V7 | USG | BSD
X        while (cp1!=&fname[0] && cp1[-1]!='/')
X                --cp1;
X#endif
X        cp2 = &bname[0];
X        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
X                *cp2++ = *cp1++;
X        *cp2 = 0;
X}
X
Xunqname(name)	/* make sure a buffer name is unique */
X
Xchar *name;	/* name to check on */
X
X{
X	register char *sp;
X
X	/* check to see if it is in the buffer list */
X	while (bfind(name, 0, FALSE) != NULL) {
X
X		/* go to the end of the name */
X		sp = name;
X		while (*sp)
X			++sp;
X		if (sp == name || (*(sp-1) <'0' || *(sp-1) > '8')) {
X			*sp++ = '0';
X			*sp = 0;
X		} else
X			*(--sp) += 1;
X	}
X}
X
X/*
X * Ask for a file name, and write the
X * contents of the current buffer to that file.
X * Update the remembered file name and clear the
X * buffer changed flag. This handling of file names
X * is different from the earlier versions, and
X * is more compatable with Gosling EMACS than
X * with ITS EMACS. Bound to "C-X C-W".
X */
Xfilewrite(f, n)
X{
X        register WINDOW *wp;
X        register int    s;
X        char            fname[NFILEN];
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
X                return (s);
X        if ((s=writeout(fname)) == TRUE) {
X                strcpy(curbp->b_fname, fname);
X                curbp->b_flag &= ~BFCHG;
X                wp = wheadp;                    /* Update mode lines.   */
X                while (wp != NULL) {
X                        if (wp->w_bufp == curbp)
X                                wp->w_flag |= WFMODE;
X                        wp = wp->w_wndp;
X                }
X        }
X        return (s);
X}
X
X/*
X * Save the contents of the current
X * buffer in its associatd file. No nothing
X * if nothing has changed (this may be a bug, not a
X * feature). Error if there is no remembered file
X * name for the buffer. Bound to "C-X C-S". May
X * get called by "C-Z".
X */
Xfilesave(f, n)
X{
X        register WINDOW *wp;
X        register int    s;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes.  */
X                return (TRUE);
X        if (curbp->b_fname[0] == 0) {           /* Must have a name.    */
X                mlwrite("No file name");
X                return (FALSE);
X        }
X
X	/* complain about truncated files */
X	if ((curbp->b_flag&BFTRUNC) != 0) {
X		if (mlyesno("Truncated file..write it out") == FALSE) {
X			mlwrite("[Aborted]");
X			return(FALSE);
X		}
X	}
X
X        if ((s=writeout(curbp->b_fname)) == TRUE) {
X                curbp->b_flag &= ~BFCHG;
X                wp = wheadp;                    /* Update mode lines.   */
X                while (wp != NULL) {
X                        if (wp->w_bufp == curbp)
X                                wp->w_flag |= WFMODE;
X                        wp = wp->w_wndp;
X                }
X        }
X        return (s);
X}
X
X/*
X * This function performs the details of file
X * writing. Uses the file management routines in the
X * "fileio.c" package. The number of lines written is
X * displayed. Sadly, it looks inside a LINE; provide
X * a macro for this. Most of the grief is error
X * checking of some sort.
X */
Xwriteout(fn)
Xchar    *fn;
X{
X        register int    s;
X        register LINE   *lp;
X        register int    nline;
X
X#if	CRYPT
X	s = resetkey();
X	if (s != TRUE)
X		return(s);
X#endif
X	/* turn off ALL keyboard translation in case we get a dos error */
X	TTkclose();
X
X        if ((s=ffwopen(fn)) != FIOSUC) {        /* Open writes message. */
X		TTkopen();
X                return (FALSE);
X        }
X	mlwrite("[Writing...]");		/* tell us were writing */
X        lp = lforw(curbp->b_linep);             /* First line.          */
X        nline = 0;                              /* Number of lines.     */
X        while (lp != curbp->b_linep) {
X                if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
X                        break;
X                ++nline;
X                lp = lforw(lp);
X        }
X        if (s == FIOSUC) {                      /* No write error.      */
X                s = ffclose();
X                if (s == FIOSUC) {              /* No close error.      */
X                        if (nline == 1)
X                                mlwrite("[Wrote 1 line]");
X                        else
X                                mlwrite("[Wrote %d lines]", nline);
X                }
X        } else                                  /* Ignore close error   */
X                ffclose();                      /* if a write error.    */
X	TTkopen();
X        if (s != FIOSUC)                        /* Some sort of error.  */
X                return (FALSE);
X        return (TRUE);
X}
X
X/*
X * The command allows the user
X * to modify the file name associated with
X * the current buffer. It is like the "f" command
X * in UNIX "ed". The operation is simple; just zap
X * the name in the BUFFER structure, and mark the windows
X * as needing an update. You can type a blank line at the
X * prompt if you wish.
X */
Xfilename(f, n)
X{
X        register WINDOW *wp;
X        register int    s;
X        char            fname[NFILEN];
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
X                return (s);
X        if (s == FALSE)
X                strcpy(curbp->b_fname, "");
X        else
X                strcpy(curbp->b_fname, fname);
X        wp = wheadp;                            /* Update mode lines.   */
X        while (wp != NULL) {
X                if (wp->w_bufp == curbp)
X                        wp->w_flag |= WFMODE;
X                wp = wp->w_wndp;
X        }
X	curbp->b_mode &= ~MDVIEW;	/* no longer read only mode */
X        return (TRUE);
X}
X
X/*
X * Insert file "fname" into the current
X * buffer, Called by insert file command. Return the final
X * status of the read.
X */
Xifile(fname)
Xchar    fname[];
X{
X        register LINE   *lp0;
X        register LINE   *lp1;
X        register LINE   *lp2;
X        register int    i;
X        register BUFFER *bp;
X        register int    s;
X        register int    nbytes;
X        register int    nline;
X	int		lflag;		/* any lines longer than allowed? */
X	char mesg[NSTRING];
X
X        bp = curbp;                             /* Cheap.               */
X        bp->b_flag |= BFCHG;			/* we have changed	*/
X	bp->b_flag &= ~BFINVS;			/* and are not temporary*/
X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
X                goto out;
X        if (s == FIOFNF) {                      /* File not found.      */
X                mlwrite("[No such file]");
X		return(FALSE);
X        }
X        mlwrite("[Inserting file]");
X
X#if	CRYPT
X	s = resetkey();
X	if (s != TRUE)
X		return(s);
X#endif
X	/* back up a line and save the mark here */
X	curwp->w_dotp = lback(curwp->w_dotp);
X	curwp->w_doto = 0;
X	curwp->w_markp = curwp->w_dotp;
X	curwp->w_marko = 0;
X
X        nline = 0;
X	lflag = FALSE;
X        while ((s=ffgetline()) == FIOSUC) {
X                nbytes = strlen(fline);
X                if ((lp1=lalloc(nbytes)) == NULL) {
X                        s = FIOMEM;             /* Keep message on the  */
X                        break;                  /* display.             */
X                }
X		lp0 = curwp->w_dotp;	/* line previous to insert */
X		lp2 = lp0->l_fp;	/* line after insert */
X
X		/* re-link new line between lp0 and lp2 */
X		lp2->l_bp = lp1;
X		lp0->l_fp = lp1;
X		lp1->l_bp = lp0;
X		lp1->l_fp = lp2;
X
X		/* and advance and write out the current line */
X		curwp->w_dotp = lp1;
X                for (i=0; i<nbytes; ++i)
X                        lputc(lp1, i, fline[i]);
X                ++nline;
X        }
X        ffclose();                              /* Ignore errors.       */
X	curwp->w_markp = lforw(curwp->w_markp);
X	strcpy(mesg, "[");
X	if (s==FIOERR) {
X		strcat(mesg, "I/O ERROR, ");
X		curbp->b_flag |= BFTRUNC;
X	}
X	if (s == FIOMEM) {
X		strcat(mesg, "OUT OF MEMORY, ");
X		curbp->b_flag |= BFTRUNC;
X	}
X	sprintf(&mesg[strlen(mesg)], "Inserted %d line", nline);
X        if (nline > 1)
X		strcat(mesg, "s");
X	strcat(mesg, "]");
X	mlwrite(mesg);
X
Xout:
X	/* advance to the next line and mark the window for changes */
X	curwp->w_dotp = lforw(curwp->w_dotp);
X	curwp->w_flag |= WFHARD | WFMODE;
X
X	/* copy window parameters back to the buffer structure */
X	curbp->b_dotp = curwp->w_dotp;
X	curbp->b_doto = curwp->w_doto;
X	curbp->b_markp = curwp->w_markp;
X	curbp->b_marko = curwp->w_marko;
X
X        if (s == FIOERR)                        /* False if error.      */
X                return (FALSE);
X        return (TRUE);
X}
FRIDAY_NIGHT
echo mes.5 completed!
# That's all folks{#

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/15/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.6')
# If you do not see the message
#	`mes.6 completed!'
# then the file was incomplete.
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.
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
XFILE	*ffp;		/* File pointer, all functions. */
Xint eofflag;		/* end-of-file flag */
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	eofflag = FALSE;
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	/* free this since we do not need it anymore */
X	if (fline) {
X		free(fline);
X		fline = NULL;
X	}
X
X#if	MSDOS & CTRLZ
X	fputc(26, ffp);		/* add a ^Z at the end of the file */
X#endif
X	
X#if     V7 | USG | BSD | (MSDOS & (LATTICE | MSC | TURBO)) | (ST520 & MWC)
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#if	CRYPT
X	char c;		/* character to translate */
X
X	if (cryptflag) {
X	        for (i = 0; i < nbuf; ++i) {
X			c = buf[i] & 0xff;
X			crypt(&c, 1);
X			fputc(c, ffp);
X		}
X	} else
X	        for (i = 0; i < nbuf; ++i)
X        	        fputc(buf[i]&0xFF, ffp);
X#else
X        for (i = 0; i < nbuf; ++i)
X                fputc(buf[i]&0xFF, ffp);
X#endif
X
X#if	ST520 & ADDCR
X        fputc('\r', ffp);
X#endif        
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()
X
X{
X        register int c;		/* current character read */
X        register int i;		/* current index into fline */
X	register char *tmpline;	/* temp storage for expanding line */
X
X	/* if we are at the end...return it */
X	if (eofflag)
X		return(FIOEOF);
X
X	/* dump fline if it ended up too big */
X	if (flen > NSTRING) {
X		free(fline);
X		fline = NULL;
X	}
X
X	/* if we don't have an fline, allocate one */
X	if (fline == NULL)
X		if ((fline = malloc(flen = NSTRING)) == NULL)
X			return(FIOMEM);
X
X	/* read the line in */
X        i = 0;
X        while ((c = fgetc(ffp)) != EOF && c != '\n') {
X                fline[i++] = c;
X		/* if it's longer, get more room */
X                if (i >= flen) {
X                	if ((tmpline = malloc(flen+NSTRING)) == NULL)
X                		return(FIOMEM);
X                	strncpy(tmpline, fline, flen);
X                	flen += NSTRING;
X                	free(fline);
X                	fline = tmpline;
X                }
X        }
X
X#if	ST520
X	if(fline[i-1] == '\r')
X		i--;
X#endif
X
X	/* test for any errors that may have occured */
X        if (c == EOF) {
X                if (ferror(ffp)) {
X                        mlwrite("File read error");
X                        return(FIOERR);
X                }
X
X                if (i != 0)
X			eofflag = TRUE;
X		else
X			return(FIOEOF);
X        }
X
X	/* terminate and decrypt the string */
X        fline[i] = 0;
X#if	CRYPT
X	if (cryptflag)
X		crypt(fline, strlen(fline));
X#endif
X        return(FIOSUC);
X}
X
Xint fexist(fname)	/* does <fname> exist on disk? */
X
Xchar *fname;		/* file to check for existance */
X
X{
X	FILE *fp;
X
X	/* try to open the file for reading */
X	fp = fopen(fname, "r");
X
X	/* if it fails, just return false! */
X	if (fp == NULL)
X		return(FALSE);
X
X	/* otherwise, close it and report true */
X	fclose(fp);
X	return(TRUE);
X}
X
X#if	AZTEC & MSDOS
X#undef	fgetc
X/*	a1getc:		Get an ascii char from the file input stream
X			but DO NOT strip the high bit
X*/
X
Xint a1getc(fp)
X
XFILE *fp;
X
X{
X	int c;		/* translated character */
X
X	c = getc(fp);	/* get the character */
X
X	/* if its a <LF> char, throw it out  */
X	while (c == 10)
X		c = getc(fp);
X
X	/* if its a <RETURN> char, change it to a LF */
X	if (c == '\r')
X		c = '\n';
X
X	/* if its a ^Z, its an EOF */
X	if (c == 26)
X		c = EOF;
X
X	return(c);
X}
X#endif
FRIDAY_NIGHT
echo extracting - hp110.c
sed 's/^X//' > hp110.c << 'FRIDAY_NIGHT'
X/*
X *	HP110:	Hewlett Packard 110 Screen 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     HP110
X
X#define NROW    16                      /* Screen size.                 */
X#define NCOL    80                      /* Edit if you want to.         */
X#define	NPAUSE	100			/* # times thru update to pause */
X#define	MARGIN	8			/* size of minimim margin and	*/
X#define	SCRSIZ	64			/* scroll size for extended lines */
X#define BEL     0x07                    /* BEL character.               */
X#define ESC     0x1B                    /* ESC character.               */
X
Xextern  int     ttopen();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern  int     ttclose();
Xextern  int     h110move();
Xextern  int     h110eeol();
Xextern  int     h110eeop();
Xextern  int     h110beep();
Xextern  int     h110open();
Xextern	int	h110rev();
Xextern	int	h110cres();
Xextern	int	h110close();
Xextern	int	h110kopen();
Xextern	int	h110kclose();
X
X#if	COLOR
Xextern	int	h110fcol();
Xextern	int	h110bcol();
X
Xint	cfcolor = -1;		/* current forground color */
Xint	cbcolor = -1;		/* current background color */
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        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        h110open,
X        h110close,
X	h110kopen,
X	h110kclose,
X        ttgetc,
X        ttputc,
X        ttflush,
X        h110move,
X        h110eeol,
X        h110eeop,
X        h110beep,
X	h110rev,
X	h110cres
X#if	COLOR
X	, h110fcol,
X	h110bcol
X#endif
X};
X
X#if	COLOR
Xh110fcol(color)		/* set the current output color */
X
Xint color;	/* color to set */
X
X{
X	if (color == cfcolor)
X		return;
X	ttputc(ESC);
X	ttputc('[');
X	h110parm(color+30);
X	ttputc('m');
X	cfcolor = color;
X}
X
Xh110bcol(color)		/* set the current background color */
X
Xint color;	/* color to set */
X
X{
X	if (color == cbcolor)
X		return;
X	ttputc(ESC);
X	ttputc('[');
X	h110parm(color+40);
X	ttputc('m');
X        cbcolor = color;
X}
X#endif
X
Xh110move(row, col)
X{
X        ttputc(ESC);
X        ttputc('[');
X        h110parm(row+1);
X        ttputc(';');
X        h110parm(col+1);
X        ttputc('H');
X}
X
Xh110eeol()
X{
X        ttputc(ESC);
X        ttputc('[');
X	ttputc('0');
X        ttputc('K');
X}
X
Xh110eeop()
X{
X#if	COLOR
X	h110fcol(gfcolor);
X	h110bcol(gbcolor);
X#endif
X        ttputc(ESC);
X        ttputc('[');
X	ttputc('0');
X        ttputc('J');
X}
X
Xh110rev(state)		/* change reverse video state */
X
Xint state;	/* TRUE = reverse, FALSE = normal */
X
X{
X#if	COLOR
X	int ftmp, btmp;		/* temporaries for colors */
X#endif
X
X	ttputc(ESC);
X	ttputc('[');
X	ttputc(state ? '7': '0');
X	ttputc('m');
X#if	COLOR
X	if (state == FALSE) {
X		ftmp = cfcolor;
X		btmp = cbcolor;
X		cfcolor = -1;
X		cbcolor = -1;
X		h110fcol(ftmp);
X		h110bcol(btmp);
X	}
X#endif
X}
X
Xh110cres()	/* change screen resolution */
X
X{
X	return(TRUE);
X}
X
Xspal()		/* change pallette register */
X
X{
X	/*   not here */
X}
X
Xh110beep()
X{
X        ttputc(BEL);
X        ttflush();
X}
X
Xh110parm(n)
Xregister int    n;
X{
X        register int q,r;
X
X        q = n/10;
X        if (q != 0) {
X		r = q/10;
X		if (r != 0) {
X			ttputc((r%10)+'0');
X		}
X		ttputc((q%10) + '0');
X        }
X        ttputc((n%10) + '0');
X}
X
Xh110open()
X{
X	strcpy(sres, "15LINE");
X	revexist = TRUE;
X        ttopen();
X}
X
Xh110close()
X
X{
X#if	COLOR
X	h110fcol(7);
X	h110bcol(0);
X#endif
X	ttclose();
X}
X
Xh110kopen()
X
X{
X}
X
Xh110kclose()
X
X{
X}
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument [unused] */
X
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X#else
Xh110hello()
X{
X}
X#endif
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	hp15kopen();
Xextern	int	hp15kclose();
Xextern  int     hp15move();
Xextern  int     hp15eeol();
Xextern  int     hp15eeop();
Xextern  int     hp15beep();
Xextern	int	gethpkey();
Xextern	int	hp15rev();
Xextern	int	hp15cres();
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        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X	openhp,
X        closehp,
X	hp15kopen,
X	hp15kclose,
X	gethpkey,
X        ttputc,
X        hpflush,
X        hp15move,
X        hp15eeol,
X        hp15eeop,
X        hp15beep,
X        hp15rev,
X        hp15cres
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 != FALSE) ? 'B': '@');
X}
X
Xhp15cres()	/* change screen resolution */
X
X{
X	return(TRUE);
X}
X
Xspal()		/* change pallette register */
X
X{
X	/*   not here */
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 screen for input */
X
X{
X	strcpy(sres, "NORMAL");
X	revexist = TRUE;
X}
X
Xclosehp()		/* close the HP150 screen for input */
X
X{
X}
X
Xhp15kopen()		/* open the HP150 keyboard for input */
X
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	/* display the application softkey labels */
X	dsplbls();
X}
X
Xhp15kclose()		/* 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
X#ifdef	unsigned
X#undef	unsigned
X#endif
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
Xdsplbls()	/* display the application softkey labels on the screen */
X
X{
X	static char cmd[] = {11, 0};
X
X	return(agios(&cmd[0], 2));
X}
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument */
X
X{
X	register int status;	/* return status */
X	register int i;		/* loop index */
X	char lbl[17];	/* returned label contents */
X	/* AGIOS command buffer */
X	static char cmd[] = {8, 0, 1, 0, 7, 7, 7, 7, 10, 0, 10, 0};
X	/*                   code  key#  ptr to      top    bottom
X	                                 label string  attribute */
X	union {		/* union to cast ptr into AGIOS arg string */
X		char *ptr;	/* pointer to arg string */
X		char cstr[4];
X	} ptru;
X
X	/* must have a numeric argument */
X	if (f == FALSE) {
X		mlwrite("%Need function key number");
X		return(FALSE);
X	}
X
X	/* and it must be a legal key number */
X	if (n < 1 || n > 8) {
X		mlwrite("%Function key number out of range");
X		return(FALSE);
X	}
X
X	/* get the string to send */
X	status = mlreply("Label contents: ", &lbl[0], 17);
X	if (status != TRUE)
X		return(status);
X
X	/* pad the label out */
X	for (i=0; i < 17; i++) {
X		if (lbl[i] == 0)
X			break;
X	}
X	for (; i < 16; i++)
X		lbl[i] = ' ';
X	lbl[16] = 0;
X
X	/* set up the parameters */
X	cmd[2] = n;			/* function key number */
X	ptru.ptr = &lbl[0];		/* set up pointer to label string */
Xforce:	cmd[4] = ptru.cstr[0];
X	cmd[5] = ptru.cstr[1];
X	cmd[6] = ptru.cstr[2];
X	cmd[7] = ptru.cstr[3];
X
X	/* and send it out */
X	agios(&cmd[0], 12);
X	return(TRUE);
X}
X#endif
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 * Supported monitor cards include CGA, MONO and EGA.
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#define NROW	43			/* Max 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
X#define	SCADC	0xb8000000L		/* CGA address of screen RAM	*/
X#define	SCADM	0xb0000000L		/* MONO address of screen RAM	*/
X#define SCADE	0xb8000000L		/* EGA address of screen RAM	*/
X
X#define MONOCRSR 0x0B0D			/* monochrome cursor	    */
X#define CGACRSR 0x0607			/* CGA cursor		    */
X#define EGACRSR 0x0709			/* EGA cursor		    */
X
X#define	CDCGA	0			/* color graphics card		*/
X#define	CDMONO	1			/* monochrome text card		*/
X#define	CDEGA	2			/* EGA color adapter		*/
X#define	CDSENSE	9			/* detect the card type		*/
X
X#define NDRIVE	3			/* number of screen drivers	*/
X
Xint dtype = -1;				/* current display type		*/
Xchar drvname[][8] = {			/* screen resolution names	*/
X	"CGA", "MONO", "EGA"
X};
Xlong scadd;				/* address of screen ram	*/
Xint *scptr[NROW];			/* pointer to screen lines	*/
Xunsigned int sline[NCOL];		/* screen line image		*/
Xint egaexist = FALSE;			/* is an EGA card available?	*/
Xextern union REGS rg;			/* cpu register for use of DOS calls */
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	ibmcres();
Xextern	int	ibmclose();
Xextern	int	ibmputc();
Xextern	int	ibmkopen();
Xextern	int	ibmkclose();
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        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        ibmopen,
X        ibmclose,
X	ibmkopen,
X	ibmkclose,
X        ttgetc,
X	ibmputc,
X        ttflush,
X        ibmmove,
X        ibmeeol,
X        ibmeeop,
X        ibmbeep,
X	ibmrev,
X	ibmcres
X#if	COLOR
X	, ibmfcol,
X	ibmbcol
X#endif
X};
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	unsigned int attr;	/* attribute byte mask to place in RAM */
X	unsigned 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	if (dtype != CDMONO)
X		attr = (((cbcolor & 15) << 4) | (cfcolor & 15)) << 8;
X	else
X		attr = 0x0700;
X#else
X	attr = 0x0700;
X#endif
X	lnptr = &sline[0];
X	for (i=0; i < term.t_ncol; i++)
X		*lnptr++ = SPACE | attr;
X
X	if (flickcode && (dtype == CDCGA)) {
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
X	/* and send the string out */
X	movmem(&sline[0], scptr[crow]+ccol, (term.t_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	if (dtype != CDMONO)
X		rg.h.bl = cfcolor;
X	else
X		rg.h.bl = 0x07;
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 = (term.t_nrow << 8) | (term.t_ncol - 1);
X				/* lower right corner of scroll */
X#if	COLOR
X	if (dtype != CDMONO)
X		attr = ((ctrans[gbcolor] & 15) << 4) | (ctrans[gfcolor] & 15);
X	else
X		attr = 0;
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
Xibmcres(res)	/* change screen resolution */
X
Xchar *res;	/* resolution to change to */
X
X{
X	int i;		/* index */
X
X	for (i = 0; i < NDRIVE; i++)
X		if (strcmp(res, drvname[i]) == 0) {
X			scinit(i);
X			return(TRUE);
X		}
X	return(FALSE);
X}
X
Xspal()	/* reset the pallette registers */
X
X{
X	/* nothin here now..... */
X}
X
Xibmbeep()
X{
X#if	MWC86
X	putcnb(BEL);
X#else
X	bdos(6, BEL, 0);
X#endif
X}
X
Xibmopen()
X{
X	scinit(CDSENSE);
X	revexist = TRUE;
X        ttopen();
X}
X
Xibmclose()
X
X{
X#if	COLOR
X	ibmfcol(7);
X	ibmbcol(0);
X#endif
X	/* if we had the EGA open... close it */
X	if (dtype == CDEGA)
X		egaclose();
X
X	ttclose();
X}
X
Xibmkopen()	/* open the keyboard */
X
X{
X}
X
Xibmkclose()	/* close the keyboard */
X
X{
X}
X
Xscinit(type)	/* initialize the screen head pointers */
X
Xint type;	/* type of adapter to init for */
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	/* if asked...find out what display is connected */
X	if (type == CDSENSE)
X		type = getboard();
X
X	/* if we have nothing to do....don't do it */
X	if (dtype == type)
X		return(TRUE);
X
X	/* if we try to switch to EGA and there is none, don't */
X	if (type == CDEGA && egaexist != TRUE)
X		return(FALSE);
X
X	/* if we had the EGA open... close it */
X	if (dtype == CDEGA)
X		egaclose();
X
X	/* and set up the various parameters as needed */
X	switch (type) {
X		case CDMONO:	/* Monochrome adapter */
X				scadd = SCADM;
X				newsize(TRUE, 25);
X				break;
X
X		case CDCGA:	/* Color graphics adapter */
X				scadd = SCADC;
X				newsize(TRUE, 25);
X				break;
X
X		case CDEGA:	/* Enhanced graphics adapter */
X				scadd = SCADE;
X				egaopen();
X				newsize(TRUE, 43);
X				break;
X	}
X
X	/* reset the $sres environment variable */
X	strcpy(sres, drvname[type]);
X	dtype = type;
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	return(TRUE);
X}
X
X/* getboard:	Determine which type of display board is attached.
X		Current known types include:
X
X		CDMONO	Monochrome graphics adapter
X		CDCGA	Color Graphics Adapter
X		CDEGA	Extended graphics Adapter
X*/
X
X/* getboard:	Detect the current display adapter
X		if MONO		set to MONO
X		   CGA		set to CGA	EGAexist = FALSE
X		   EGA		set to CGA	EGAexist = TRUE
X*/
X
Xint getboard()
X
X{
X	int type;	/* board type to return */
X
X	type = CDCGA;
X	int86(0x11, &rg, &rg);
X	if ((((rg.x.ax >> 4) & 3) == 3))
X		type = CDMONO;
X
X	/* test if EGA present */
X	rg.x.ax = 0x1200;
X	rg.x.bx = 0xff10;
X	int86(0x10,&rg, &rg);		/* If EGA, bh=0-1 and bl=0-3 */
X	egaexist = !(rg.x.bx & 0xfefc);	/* Yes, it's EGA */
X	return(type);
X}
X
Xegaopen()	/* init the computer to work with the EGA */
X
X{
X	/* put the beast into EGA 43 row mode */
X	rg.x.ax = 3;
X	int86(16, &rg, &rg);
X
X	rg.h.ah = 17;		/* set char. generator function code */
X	rg.h.al = 18;		/*  to 8 by 8 double dot ROM         */
X	rg.h.bl = 0;		/* block 0                           */
X	int86(16, &rg, &rg);
X
X	rg.h.ah = 18;		/* alternate select function code    */
X	rg.h.al = 0;		/* clear AL for no good reason       */
X	rg.h.bl = 32;		/* alt. print screen routine         */
X	int86(16, &rg, &rg);
X
X	rg.h.ah = 1;		/* set cursor size function code */
X	rg.x.cx = 0x0607;	/* turn cursor on code */
X	int86(0x10, &rg, &rg);
X
X	outp(0x3d4, 10);	/* video bios bug patch */
X	outp(0x3d5, 6);
X}
X
Xegaclose()
X
X{
X	/* put the beast into 80 column mode */
X	rg.x.ax = 3;
X	int86(16, &rg, &rg);
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 term.t_ncol long) */
Xint forg;	/* forground color of string to write */
Xint bacg;	/* background color */
X
X{
X	unsigned int attr;	/* attribute byte mask to place in RAM */
X	unsigned 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	if (dtype != CDMONO)
X		attr = (((ctrans[bacg] & 15) << 4) | (ctrans[forg] & 15)) << 8;
X	else
X		attr = (((bacg & 15) << 4) | (forg & 15)) << 8;
X#else
X	attr = (((bacg & 15) << 4) | (forg & 15)) << 8;
X#endif
X	lnptr = &sline[0];
X	for (i=0; i<term.t_ncol; i++)
X		*lnptr++ = (outstr[i] & 255) | attr;
X
X	if (flickcode && (dtype == CDCGA)) {
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
X	/* and send the string out */
X	movmem(&sline[0], scptr[row],term.t_ncol*2);
X}
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument [unused] */
X
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X#else
Xibmhello()
X{
X}
X#endif
X
FRIDAY_NIGHT
echo mes.6 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/15/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.7')
# If you do not see the message
#	`mes.7 completed!'
# then the file was incomplete.
echo extracting - input.c
sed 's/^X//' > input.c << 'FRIDAY_NIGHT'
X/*	INPUT:	Various input routines for MicroEMACS
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 = tgetc();
X
X		if (c == ectoc(abortc))		/* 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(nextarg(prompt, buf, nbuf, ctoec('\n')));
X}
X
Xmlreplyt(prompt, buf, nbuf, eolchar)
X
Xchar *prompt;
Xchar *buf;
Xint eolchar;
X
X{
X	return(nextarg(prompt, buf, nbuf, eolchar));
X}
X
X/*	ectoc:	expanded character to character
X		colapse the CTRL and SPEC flags back into an ascii code   */
X
Xectoc(c)
X
Xint c;
X
X{
X	if (c & CTRL)
X		c = c & ~(CTRL | 0x40);
X	if (c & SPEC)
X		c= c & 255;
X	return(c);
X}
X
X/*	ctoec:	character to extended character
X		pull out the CTRL and SPEC prefixes (if possible)	*/
X
Xctoec(c)
X
Xint c;
X
X{
X        if (c>=0x00 && c<=0x1F)
X                c = CTRL | (c+'@');
X        return (c);
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#if	ST520 & LATTICE
X#define register		
X#endif
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 beginning of the string buffer */
X	cpos = 0;
X
X	/* if we are executing a command line get the next arg and match it */
X	if (clexec) {
X		if (macarg(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 = tgetc();
X
X		/* if we are at the end, just match it */
X		if (c == 0x0d) {
X			buf[cpos] = 0;
X
X			/* and match it off */
X			return(fncmatch(&buf[0]));
X
X		} else if (c == ectoc(abortc)) {	/* Bell, abort */
X			ctrlg(FALSE, 0);
X			TTflush();
X			return( (int (*)()) NULL);
X
X		} else if (c == 0x7F || c == 0x08) {	/* rubout/erase */
X			if (cpos != 0) {
X				TTputc('\b');
X				TTputc(' ');
X				TTputc('\b');
X				--ttcol;
X				--cpos;
X				TTflush();
X			}
X
X		} else if (c == 0x15) {	/* C-U, kill */
X			while (cpos != 0) {
X				TTputc('\b');
X				TTputc(' ');
X				TTputc('\b');
X				--cpos;
X				--ttcol;
X			}
X
X			TTflush();
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					TTputc(*sp++);
X				TTflush();
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		TTputc(buf[cpos++]);
X	}
X/* << << << << << << << << << << << << << << << << << */
X			}
X		}
X		++ffp;
X	}
X
X	/* no match.....beep and onward */
X	TTbeep();
Xonward:;
X	TTflush();
X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
X		} else {
X			if (cpos < NSTRING-1 && c > ' ') {
X				buf[cpos++] = c;
X				TTputc(c);
X			}
X
X			++ttcol;
X			TTflush();
X		}
X	}
X}
X
X/*	tgetc:	Get a key from the terminal driver, resolve any keyboard
X		macro action					*/
X
Xint tgetc()
X
X{
X	int c;	/* fetched character */
X
X	/* if we are playing a keyboard macro back, */
X	if (kbdmode == PLAY) {
X
X		/* if there is some left... */
X		if (kbdptr < kbdend)
X			return((int)*kbdptr++);
X
X		/* at the end of last repitition? */
X		if (--kbdrep < 1) {
X			kbdmode = STOP;
X#if	VISMAC == 0
X			/* force a screen update after all is done */
X			update(FALSE);
X#endif
X		} else {
X
X			/* reset the macro to the begining for the next rep */
X			kbdptr = &kbdm[0];
X			return((int)*kbdptr++);
X		}
X	}
X
X	/* fetch a character from the terminal driver */
X	c = TTgetc();
X
X	/* record it for $lastkey */
X	lastkey = c;
X
X	/* save it if we need to */
X	if (kbdmode == RECORD) {
X		*kbdptr++ = c;
X		kbdend = kbdptr;
X
X		/* don't overrun the buffer */
X		if (kbdptr == &kbdm[NKBDM - 1]) {
X			kbdmode = STOP;
X			TTbeep();
X		}
X	}
X
X	/* and finally give the char back */
X	return(c);
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 = tgetc();
X
X#if	MSDOS | ST520
X	if (c == 0) {				/* Apply SPEC prefix	*/
X	        c = tgetc();
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 = tgetc();
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 = tgetc();
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 = tgetc();
X		return(SPEC | c);
X	}
X#endif
X
X#if  WANGPC
X	if (c == 0x1F) {			/* Apply SPEC prefix    */
X	        c = tgetc();
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	VT100
X	/* if ESC must be recognized.... change this to a 1 */
X	if (c == metac || c == (CTRL | '['))
X#else
X	if (c == metac) {
X#endif
X		c = get1key();
X	        if (islower(c))		/* Force to upper */
X        	        c ^= DIFCASE;
X	        if (c>=0x00 && c<=0x1F)		/* control key */
X	        	c = CTRL | (c+'@');
X#if	VT100
X		if (c == '[' || c == 'O') {
X			c = get1key();
X			return(SPEC | c);
X		}
X#endif
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}
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							*/
Xgetstring(prompt, buf, nbuf, eolchar)
X
Xchar *prompt;
Xchar *buf;
Xint eolchar;
X
X{
X	register int cpos;	/* current character position in string */
X	register int c;
X	register int quotef;	/* are we quoting the next char? */
X
X	cpos = 0;
X	quotef = FALSE;
X
X	/* prompt the user for the input string */
X	mlwrite(prompt);
X
X	for (;;) {
X		/* get a character from the user */
X		c = get1key();
X
X		/* If it is a <ret>, change it to a <NL> */
X		if (c == (CTRL | 0x4d))
X			c = CTRL | 0x40 | '\n';
X
X		/* if they hit the line terminate, wrap it up */
X		if (c == eolchar && quotef == FALSE) {
X			buf[cpos++] = 0;
X
X			/* clear the message line */
X			mlwrite("");
X			TTflush();
X
X			/* if we default the buffer, return FALSE */
X			if (buf[0] == 0)
X				return(FALSE);
X
X			return(TRUE);
X		}
X
X		/* change from command form back to character form */
X		c = ectoc(c);
X
X		if (c == ectoc(abortc) && quotef == FALSE) {
X			/* Abort the input? */
X			ctrlg(FALSE, 0);
X			TTflush();
X			return(ABORT);
X		} else if ((c==0x7F || c==0x08) && quotef==FALSE) {
X			/* rubout/erase */
X			if (cpos != 0) {
X				outstring("\b \b");
X				--ttcol;
X
X				if (buf[--cpos] < 0x20) {
X					outstring("\b \b");
X					--ttcol;
X				}
X
X				if (buf[cpos] == '\n') {
X					outstring("\b\b  \b\b");
X					ttcol -= 2;
X				}
X				TTflush();
X			}
X
X		} else if (c == 0x15 && quotef == FALSE) {
X			/* C-U, kill */
X			while (cpos != 0) {
X				outstring("\b \b");
X				--ttcol;
X
X				if (buf[--cpos] < 0x20) {
X					outstring("\b \b");
X					--ttcol;
X				}
X			}
X			TTflush();
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					outstring("^");
X					++ttcol;
X					c ^= 0x40;
X				}
X
X				if (c != '\n') {
X					if (disinp)
X						TTputc(c);
X				} else {	/* put out <NL> for <ret> */
X					outstring("<NL>");
X					ttcol += 3;
X				}
X				++ttcol;
X				TTflush();
X			}
X		}
X	}
X}
X
Xoutstring(s)	/* output a string of input characters */
X
Xchar *s;	/* string to output */
X
X{
X	if (disinp)
X		while (*s)
X			TTputc(*s++);
X}
X
Xostring(s)	/* output a string of output characters */
X
Xchar *s;	/* string to output */
X
X{
X	if (discmd)
X		while (*s)
X			TTputc(*s++);
X}
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 *	John M. Gamble 5-Oct-86
X *	- Made iterative search use search.c's scanner() routine.
X *	  This allowed the elimination of bakscan().
X *	- Put isearch constants into estruct.h
X *	- Eliminated the passing of 'status' to scanmore() and
X *	  checknext(), since there were no circumstances where
X *	  it ever equalled FALSE.
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X#if	ISRCH
X
Xextern int scanner();			/* 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
Xint	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
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, META 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    register int	expc;		/* function expanded input char	      */
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 = ectoc(expc = 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);		/* Do the search	      */
X	c = ectoc(expc = 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 special characters first: */
X	/* Most cases here change the search */
X
X	if (expc == metac)			/* Want to quit searching?    */
X	    return (TRUE);			/* Quit searching now	      */
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);		/* Start the search again     */
X	    c = ectoc(expc = get_char());	/* Get the next char	      */
X	    continue;				/* Go continue with the search*/
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 = ectoc(expc = 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	    TTputc(BELL);		/* Feep again		      */
X	    TTflush();			/* see that the feep feeps    */
X	} else					/* Otherwise, we must have won*/
X	    if (!(status = checknext(c, pat, n))) /* See if match	      */
X		status = scanmore(pat, n);	/*  or find the next match    */
X	c = ectoc(expc = 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)	/* 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			 */
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
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)	/* search forward or back for a pattern	      */
Xchar	*patrn;			/* string to scan for			      */
Xint	dir;			/* direction to search			      */
X{
X	int	sts;			/* search status		      */
X
X    	if (dir < 0)				/* reverse search?	      */
X    	{
X		rvstrcpy(tap, patrn);		/* Put reversed string in tap */
X		sts = scanner(tap, REVERSE, PTBEG);
X	}
X	else
X		sts = scanner(patrn, FORWARD, PTEND);	/* Nope. Go forward   */
X
X	if (!sts)
X	{
X		TTputc(BELL);	/* Feep if search fails       */
X		TTflush();		/* see that the feep feeps    */
X	}
X
X	return(sts);				/* else, don't even try	      */
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, "]<META>: ");
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	    TTputc('<');
X	    TTputc('N');
X	    TTputc('L');
X	    TTputc('>');
X	    col += 3;
X	    break;
X
X	  case '\t':				/* Tab			      */
X	    TTputc('<');
X	    TTputc('T');
X	    TTputc('A');
X	    TTputc('B');
X	    TTputc('>');
X	    col += 4;
X	    break;
X
X	  case 0x7F:				/* Rubout:		      */
X	    TTputc('^');		/* Output a funny looking     */
X	    TTputc('?');		/*  indication of Rubout      */
X	    col++;				/* Count the extra char       */
X	    break;
X
X	  default:				/* Vanilla control char       */
X	    TTputc('^');		/* Yes, output prefix	      */
X    	    TTputc(c+0x40);		/* Make it "^X"		      */
X	    col++;				/* Count this char	      */
X	}
X    } else
X	TTputc(c);			/* Otherwise, output raw char */
X    TTflush();				/* 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 (metac);			/* And force a quit		      */
X    }
X    c = get1key();		/* 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#else
Xisearch()
X{
X}
X#endif
FRIDAY_NIGHT
echo mes.7 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/15/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.8')
# If you do not see the message
#	`mes.8 completed!'
# then the file was incomplete.
echo extracting - line.c
sed 's/^X//' > line.c << 'FRIDAY_NIGHT'
X/*
X * The functions in this file are a general set of line management utilities.
X * They are the only routines that touch the text. They also touch the buffer
X * and window structures, to make sure that the necessary updating gets done.
X * There are routines in this file that handle the kill buffer too. It isn't
X * here for any good reason.
X *
X * Note that this code only updates the dot and mark values in the window list.
X * Since all the code acts on the current window, the buffer that we are
X * editing must be being displayed, which means that "b_nwnd" is non zero,
X * which means that the dot and mark values in the buffer headers are nonsense.
X */
X
X#include	<stdio.h>
X#include	"estruct.h"
X#include	"edef.h"
X
XKILL *ykbuf;	/* ptr to current kill buffer chunk being yanked */
Xint ykboff;	/* offset into that chunk */
X
X/*
X * This routine allocates a block of memory large enough to hold a LINE
X * containing "used" characters. The block is always rounded up a bit. Return
X * a pointer to the new block, or NULL if there isn't any memory left. Print a
X * message in the message line if no space.
X */
XLINE *lalloc(used)
X
Xregister int	used;
X
X{
X	register LINE	*lp;
X	register int	size;
X	char *malloc();
X
X	size = (used+NBLOCK-1) & ~(NBLOCK-1);
X	if (size == 0)				/* Assume that an empty */
X		size = NBLOCK;			/* line is for type-in. */
X	if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
X		mlwrite("[OUT OF MEMORY]");
X		return (NULL);
X	}
X	lp->l_size = size;
X	lp->l_used = used;
X	return (lp);
X}
X
X/*
X * Delete line "lp". Fix all of the links that might point at it (they are
X * moved to offset 0 of the next line. Unlink the line from whatever buffer it
X * might be in. Release the memory. The buffers are updated too; the magic
X * conditions described in the above comments don't hold here.
X */
Xlfree(lp)
Xregister LINE	*lp;
X{
X	register BUFFER *bp;
X	register WINDOW *wp;
X
X	wp = wheadp;
X	while (wp != NULL) {
X		if (wp->w_linep == lp)
X			wp->w_linep = lp->l_fp;
X		if (wp->w_dotp	== lp) {
X			wp->w_dotp  = lp->l_fp;
X			wp->w_doto  = 0;
X		}
X		if (wp->w_markp == lp) {
X			wp->w_markp = lp->l_fp;
X			wp->w_marko = 0;
X		}
X		wp = wp->w_wndp;
X	}
X	bp = bheadp;
X	while (bp != NULL) {
X		if (bp->b_nwnd == 0) {
X			if (bp->b_dotp	== lp) {
X				bp->b_dotp = lp->l_fp;
X				bp->b_doto = 0;
X			}
X			if (bp->b_markp == lp) {
X				bp->b_markp = lp->l_fp;
X				bp->b_marko = 0;
X			}
X		}
X		bp = bp->b_bufp;
X	}
X	lp->l_bp->l_fp = lp->l_fp;
X	lp->l_fp->l_bp = lp->l_bp;
X	free((char *) lp);
X}
X
X/*
X * This routine gets called when a character is changed in place in the current
X * buffer. It updates all of the required flags in the buffer and window
X * system. The flag used is passed as an argument; if the buffer is being
X * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
X * mode line needs to be updated (the "*" has to be set).
X */
Xlchange(flag)
Xregister int	flag;
X{
X	register WINDOW *wp;
X
X	if (curbp->b_nwnd != 1) 		/* Ensure hard. 	*/
X		flag = WFHARD;
X	if ((curbp->b_flag&BFCHG) == 0) {	/* First change, so	*/
X		flag |= WFMODE; 		/* update mode lines.	*/
X		curbp->b_flag |= BFCHG;
X	}
X	wp = wheadp;
X	while (wp != NULL) {
X		if (wp->w_bufp == curbp)
X			wp->w_flag |= flag;
X		wp = wp->w_wndp;
X	}
X}
X
Xinsspace(f, n)	/* insert spaces forward into text */
X
Xint f, n;	/* default flag and numeric argument */
X
X{
X	linsert(n, ' ');
X	backchar(f, n);
X}
X
X/*
X * linstr -- Insert a string at the current point
X */
X
Xlinstr(instr)
Xchar	*instr;
X{
X	register int status = TRUE;
X	char tmpc;
X
X	if (instr != NULL)
X		while ((tmpc = *instr) && status == TRUE) {
X			status = (tmpc == '\n'? lnewline(): linsert(1, tmpc));
X
X			/* Insertion error? */
X			if (status != TRUE) {
X				mlwrite("%%Out of memory while inserting");
X				break;
X			}
X			instr++;
X		}
X	return(status);
X}
X
X/*
X * Insert "n" copies of the character "c" at the current location of dot. In
X * the easy case all that happens is the text is stored in the line. In the
X * hard case, the line has to be reallocated. When the window list is updated,
X * take special care; I screwed it up once. You always update dot in the
X * current window. You update mark, and a dot in another window, if it is
X * greater than the place where you did the insert. Return TRUE if all is
X * well, and FALSE on errors.
X */
X
Xlinsert(n, c)
X{
X	register char	*cp1;
X	register char	*cp2;
X	register LINE	*lp1;
X	register LINE	*lp2;
X	register LINE	*lp3;
X	register int	doto;
X	register int	i;
X	register WINDOW *wp;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	lchange(WFEDIT);
X	lp1 = curwp->w_dotp;			/* Current line 	*/
X	if (lp1 == curbp->b_linep) {		/* At the end: special	*/
X		if (curwp->w_doto != 0) {
X			mlwrite("bug: linsert");
X			return (FALSE);
X		}
X		if ((lp2=lalloc(n)) == NULL)	/* Allocate new line	*/
X			return (FALSE);
X		lp3 = lp1->l_bp;		/* Previous line	*/
X		lp3->l_fp = lp2;		/* Link in		*/
X		lp2->l_fp = lp1;
X		lp1->l_bp = lp2;
X		lp2->l_bp = lp3;
X		for (i=0; i<n; ++i)
X			lp2->l_text[i] = c;
X		curwp->w_dotp = lp2;
X		curwp->w_doto = n;
X		return (TRUE);
X	}
X	doto = curwp->w_doto;			/* Save for later.	*/
X	if (lp1->l_used+n > lp1->l_size) {	/* Hard: reallocate	*/
X		if ((lp2=lalloc(lp1->l_used+n)) == NULL)
X			return (FALSE);
X		cp1 = &lp1->l_text[0];
X		cp2 = &lp2->l_text[0];
X		while (cp1 != &lp1->l_text[doto])
X			*cp2++ = *cp1++;
X		cp2 += n;
X		while (cp1 != &lp1->l_text[lp1->l_used])
X			*cp2++ = *cp1++;
X		lp1->l_bp->l_fp = lp2;
X		lp2->l_fp = lp1->l_fp;
X		lp1->l_fp->l_bp = lp2;
X		lp2->l_bp = lp1->l_bp;
X		free((char *) lp1);
X	} else {				/* Easy: in place	*/
X		lp2 = lp1;			/* Pretend new line	*/
X		lp2->l_used += n;
X		cp2 = &lp1->l_text[lp1->l_used];
X		cp1 = cp2-n;
X		while (cp1 != &lp1->l_text[doto])
X			*--cp2 = *--cp1;
X	}
X	for (i=0; i<n; ++i)			/* Add the characters	*/
X		lp2->l_text[doto+i] = c;
X	wp = wheadp;				/* Update windows	*/
X	while (wp != NULL) {
X		if (wp->w_linep == lp1)
X			wp->w_linep = lp2;
X		if (wp->w_dotp == lp1) {
X			wp->w_dotp = lp2;
X			if (wp==curwp || wp->w_doto>doto)
X				wp->w_doto += n;
X		}
X		if (wp->w_markp == lp1) {
X			wp->w_markp = lp2;
X			if (wp->w_marko > doto)
X				wp->w_marko += n;
X		}
X		wp = wp->w_wndp;
X	}
X	return (TRUE);
X}
X
X/*
X * Overwrite a character into the current line at the current position
X *
X */
X
Xlowrite(c)
X
Xchar c;		/* character to overwrite on current position */
X
X{
X	if (curwp->w_doto < curwp->w_dotp->l_used &&
X		(lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
X		 (curwp->w_doto) % 8 == 7))
X			ldelete(1L, FALSE);
X	return(linsert(1, c));
X}
X
X/*
X * lover -- Overwrite a string at the current point
X */
X
Xlover(ostr)
X
Xchar	*ostr;
X
X{
X	register int status = TRUE;
X	char tmpc;
X
X	if (ostr != NULL)
X		while ((tmpc = *ostr) && status == TRUE) {
X			status = (tmpc == '\n'? lnewline(): lowrite(tmpc));
X
X			/* Insertion error? */
X			if (status != TRUE) {
X				mlwrite("%%Out of memory while overwriting");
X				break;
X			}
X			ostr++;
X		}
X	return(status);
X}
X
X/*
X * Insert a newline into the buffer at the current location of dot in the
X * current window. The funny ass-backwards way it does things is not a botch;
X * it just makes the last line in the file not a special case. Return TRUE if
X * everything works out and FALSE on error (memory allocation failure). The
X * update of dot and mark is a bit easier then in the above case, because the
X * split forces more updating.
X */
Xlnewline()
X{
X	register char	*cp1;
X	register char	*cp2;
X	register LINE	*lp1;
X	register LINE	*lp2;
X	register int	doto;
X	register WINDOW *wp;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	lchange(WFHARD);
X	lp1  = curwp->w_dotp;			/* Get the address and	*/
X	doto = curwp->w_doto;			/* offset of "."	*/
X	if ((lp2=lalloc(doto)) == NULL) 	/* New first half line	*/
X		return (FALSE);
X	cp1 = &lp1->l_text[0];			/* Shuffle text around	*/
X	cp2 = &lp2->l_text[0];
X	while (cp1 != &lp1->l_text[doto])
X		*cp2++ = *cp1++;
X	cp2 = &lp1->l_text[0];
X	while (cp1 != &lp1->l_text[lp1->l_used])
X		*cp2++ = *cp1++;
X	lp1->l_used -= doto;
X	lp2->l_bp = lp1->l_bp;
X	lp1->l_bp = lp2;
X	lp2->l_bp->l_fp = lp2;
X	lp2->l_fp = lp1;
X	wp = wheadp;				/* Windows		*/
X	while (wp != NULL) {
X		if (wp->w_linep == lp1)
X			wp->w_linep = lp2;
X		if (wp->w_dotp == lp1) {
X			if (wp->w_doto < doto)
X				wp->w_dotp = lp2;
X			else
X				wp->w_doto -= doto;
X		}
X		if (wp->w_markp == lp1) {
X			if (wp->w_marko < doto)
X				wp->w_markp = lp2;
X			else
X				wp->w_marko -= doto;
X		}
X		wp = wp->w_wndp;
X	}
X	return (TRUE);
X}
X
X/*
X * This function deletes "n" bytes, starting at dot. It understands how do deal
X * with end of lines, etc. It returns TRUE if all of the characters were
X * deleted, and FALSE if they were not (because dot ran into the end of the
X * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
X */
Xldelete(n, kflag)
X
Xlong n; 	/* # of chars to delete */
Xint kflag;	/* put killed text in kill buffer flag */
X
X{
X	register char	*cp1;
X	register char	*cp2;
X	register LINE	*dotp;
X	register int	doto;
X	register int	chunk;
X	register WINDOW *wp;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	while (n != 0) {
X		dotp = curwp->w_dotp;
X		doto = curwp->w_doto;
X		if (dotp == curbp->b_linep)	/* Hit end of buffer.	*/
X			return (FALSE);
X		chunk = dotp->l_used-doto;	/* Size of chunk.	*/
X		if (chunk > n)
X			chunk = n;
X		if (chunk == 0) {		/* End of line, merge.	*/
X			lchange(WFHARD);
X			if (ldelnewline() == FALSE
X			|| (kflag!=FALSE && kinsert('\n')==FALSE))
X				return (FALSE);
X			--n;
X			continue;
X		}
X		lchange(WFEDIT);
X		cp1 = &dotp->l_text[doto];	/* Scrunch text.	*/
X		cp2 = cp1 + chunk;
X		if (kflag != FALSE) {		/* Kill?		*/
X			while (cp1 != cp2) {
X				if (kinsert(*cp1) == FALSE)
X					return (FALSE);
X				++cp1;
X			}
X			cp1 = &dotp->l_text[doto];
X		}
X		while (cp2 != &dotp->l_text[dotp->l_used])
X			*cp1++ = *cp2++;
X		dotp->l_used -= chunk;
X		wp = wheadp;			/* Fix windows		*/
X		while (wp != NULL) {
X			if (wp->w_dotp==dotp && wp->w_doto>=doto) {
X				wp->w_doto -= chunk;
X				if (wp->w_doto < doto)
X					wp->w_doto = doto;
X			}
X			if (wp->w_markp==dotp && wp->w_marko>=doto) {
X				wp->w_marko -= chunk;
X				if (wp->w_marko < doto)
X					wp->w_marko = doto;
X			}
X			wp = wp->w_wndp;
X		}
X		n -= chunk;
X	}
X	return (TRUE);
X}
X
X/* getctext:	grab and return a string with the text of
X		the current line
X*/
X
Xchar *getctext()
X
X{
X	register LINE *lp;	/* line to copy */
X	register int size;	/* length of line to return */
X	register char *sp;	/* string pointer into line */
X	register char *dp;	/* string pointer into returned line */
X	char rline[NSTRING];	/* line to return */
X
X	/* find the contents of the current line and its length */
X	lp = curwp->w_dotp;
X	sp = lp->l_text;
X	size = lp->l_used;
X	if (size >= NSTRING)
X		size = NSTRING - 1;
X
X	/* copy it across */
X	dp = rline;
X	while (size--)
X		*dp++ = *sp++;
X	*dp = 0;
X	return(rline);
X}
X
X/* putctext:	replace the current line with the passed in text	*/
X
Xputctext(iline)
X
Xchar *iline;	/* contents of new line */
X
X{
X	register int status;
X
X	/* delete the current line */
X	curwp->w_doto = 0;	/* starting at the beginning of the line */
X	if ((status = killtext(TRUE, 1)) != TRUE)
X		return(status);
X
X	/* insert the new line */
X	if ((status = linstr(iline)) != TRUE)
X		return(status);
X	status = lnewline();
X	backline(TRUE, 1);
X	return(status);
X}
X
X/*
X * Delete a newline. Join the current line with the next line. If the next line
X * is the magic header line always return TRUE; merging the last line with the
X * header line can be thought of as always being a successful operation, even
X * if nothing is done, and this makes the kill buffer work "right". Easy cases
X * can be done by shuffling data around. Hard cases require that lines be moved
X * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
X * "ldelete" only.
X */
Xldelnewline()
X{
X	register char	*cp1;
X	register char	*cp2;
X	register LINE	*lp1;
X	register LINE	*lp2;
X	register LINE	*lp3;
X	register WINDOW *wp;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	lp1 = curwp->w_dotp;
X	lp2 = lp1->l_fp;
X	if (lp2 == curbp->b_linep) {		/* At the buffer end.	*/
X		if (lp1->l_used == 0)		/* Blank line.		*/
X			lfree(lp1);
X		return (TRUE);
X	}
X	if (lp2->l_used <= lp1->l_size-lp1->l_used) {
X		cp1 = &lp1->l_text[lp1->l_used];
X		cp2 = &lp2->l_text[0];
X		while (cp2 != &lp2->l_text[lp2->l_used])
X			*cp1++ = *cp2++;
X		wp = wheadp;
X		while (wp != NULL) {
X			if (wp->w_linep == lp2)
X				wp->w_linep = lp1;
X			if (wp->w_dotp == lp2) {
X				wp->w_dotp  = lp1;
X				wp->w_doto += lp1->l_used;
X			}
X			if (wp->w_markp == lp2) {
X				wp->w_markp  = lp1;
X				wp->w_marko += lp1->l_used;
X			}
X			wp = wp->w_wndp;
X		}
X		lp1->l_used += lp2->l_used;
X		lp1->l_fp = lp2->l_fp;
X		lp2->l_fp->l_bp = lp1;
X		free((char *) lp2);
X		return (TRUE);
X	}
X	if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
X		return (FALSE);
X	cp1 = &lp1->l_text[0];
X	cp2 = &lp3->l_text[0];
X	while (cp1 != &lp1->l_text[lp1->l_used])
X		*cp2++ = *cp1++;
X	cp1 = &lp2->l_text[0];
X	while (cp1 != &lp2->l_text[lp2->l_used])
X		*cp2++ = *cp1++;
X	lp1->l_bp->l_fp = lp3;
X	lp3->l_fp = lp2->l_fp;
X	lp2->l_fp->l_bp = lp3;
X	lp3->l_bp = lp1->l_bp;
X	wp = wheadp;
X	while (wp != NULL) {
X		if (wp->w_linep==lp1 || wp->w_linep==lp2)
X			wp->w_linep = lp3;
X		if (wp->w_dotp == lp1)
X			wp->w_dotp  = lp3;
X		else if (wp->w_dotp == lp2) {
X			wp->w_dotp  = lp3;
X			wp->w_doto += lp1->l_used;
X		}
X		if (wp->w_markp == lp1)
X			wp->w_markp  = lp3;
X		else if (wp->w_markp == lp2) {
X			wp->w_markp  = lp3;
X			wp->w_marko += lp1->l_used;
X		}
X		wp = wp->w_wndp;
X	}
X	free((char *) lp1);
X	free((char *) lp2);
X	return (TRUE);
X}
X
X/*
X * Delete all of the text saved in the kill buffer. Called by commands when a
X * new kill context is being created. The kill buffer array is released, just
X * in case the buffer has grown to immense size. No errors.
X */
Xkdelete()
X{
X	KILL *kp;	/* ptr to scan kill buffer chunk list */
X
X	if (kbufh != NULL) {
X
X		/* first, delete all the chunks */
X		kbufp = kbufh;
X		while (kbufp != NULL) {
X			kp = kbufp->d_next;
X			free(kbufp);
X			kbufp = kp;
X		}
X
X		/* and reset all the kill buffer pointers */
X		kbufh = kbufp = NULL;
X		kused = KBLOCK; 	        
X	}
X}
X
X/*
X * Insert a character to the kill buffer, allocating new chunks as needed.
X * Return TRUE if all is well, and FALSE on errors.
X */
X
Xkinsert(c)
X
Xint c;		/* character to insert in the kill buffer */
X
X{
X	KILL *nchunk;	/* ptr to newly malloced chunk */
X
X	/* check to see if we need a new chunk */
X	if (kused >= KBLOCK) {
X		if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL)
X			return(FALSE);
X		if (kbufh == NULL)	/* set head ptr if first time */
X			kbufh = nchunk;
X		if (kbufp != NULL)	/* point the current to this new one */
X			kbufp->d_next = nchunk;
X		kbufp = nchunk;
X		kbufp->d_next = NULL;
X		kused = 0;
X	}
X
X	/* and now insert the character */
X	kbufp->d_chunk[kused++] = c;
X	return(TRUE);
X}
X
X/*
X * Yank text back from the kill buffer. This is really easy. All of the work
X * is done by the standard insert routines. All you do is run the loop, and
X * check for errors. Bound to "C-Y".
X */
Xyank(f, n)
X{
X	register int	c;
X	register int	i;
X	register char	*sp;	/* pointer into string to insert */
X	KILL *kp;		/* pointer into kill buffer */
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	if (n < 0)
X		return (FALSE);
X	/* make sure there is something to yank */
X	if (kbufh == NULL)
X		return(TRUE);		/* not an error, just nothing */
X
X	/* for each time.... */
X	while (n--) {
X		kp = kbufh;
X		while (kp != NULL) {
X			if (kp->d_next == NULL)
X				i = kused;
X			else
X				i = KBLOCK;
X			sp = kp->d_chunk;
X			while (i--) {
X				if ((c = *sp++) == '\n') {
X					if (lnewline() == FALSE)
X						return (FALSE);
X				} else {
X					if (linsert(1, c) == FALSE)
X						return (FALSE);
X				}
X			}
X			kp = kp->d_next;
X		}
X	}
X	return (TRUE);
X}
FRIDAY_NIGHT
echo extracting - lock.c
sed 's/^X//' > lock.c << 'FRIDAY_NIGHT'
X/*	LOCK:	File locking command routines for MicroEMACS
X		written by Daniel Lawrence
X								*/
X
X#include <stdio.h>
X#include "estruct.h"
X#include "edef.h"
X
X#if	FILOCK
X#if	BSD
X#include <sys/errno.h>
X
Xextern int sys_nerr;		/* number of system error messages defined */
Xextern char *sys_errlist[];	/* list of message texts */
Xextern int errno;		/* current error */
X
Xchar *lname[NLOCKS];	/* names of all locked files */
Xint numlocks;		/* # of current locks active */
X
X/* lockchk:	check a file for locking and add it to the list */
X
Xlockchk(fname)
X
Xchar *fname;	/* file to check for a lock */
X
X{
X	register int i;		/* loop indexes */
X	register int status;	/* return status */
X	char *undolock();
X
X	/* check to see if that file is already locked here */
X	if (numlocks > 0)
X		for (i=0; i < numlocks; ++i)
X			if (strcmp(fname, lname[i]) == 0)
X				return(TRUE);
X
X	/* if we have a full locking table, bitch and leave */
X	if (numlocks == NLOCKS) {
X		mlwrite("LOCK ERROR: Lock table full");
X		return(ABORT);
X	}
X
X	/* next, try to lock it */
X	status = lock(fname);
X	if (status == ABORT)	/* file is locked, no override */
X		return(ABORT);
X	if (status == FALSE)	/* locked, overriden, dont add to table */
X		return(TRUE);
X
X	/* we have now locked it, add it to our table */
X	lname[++numlocks - 1] = (char *)malloc(strlen(fname) + 1);
X	if (lname[numlocks - 1] == NULL) {	/* malloc failure */
X		undolock(fname);		/* free the lock */
X		mlwrite("Cannot lock, out of memory");
X		--numlocks;
X		return(ABORT);
X	}
X
X	/* everthing is cool, add it to the table */
X	strcpy(lname[numlocks-1], fname);
X	return(TRUE);
X}
X
X/*	lockrel:	release all the file locks so others may edit */
X
Xlockrel()
X
X{
X	register int i;		/* loop index */
X	register int status;	/* status of locks */
X	register int s;		/* status of one unlock */
X
X	status = TRUE;
X	if (numlocks > 0)
X		for (i=0; i < numlocks; ++i) {
X			if ((s = unlock(lname[i])) != TRUE)
X				status = s;
X			free(lname[i]);
X		}
X	numlocks = 0;
X	return(status);
X}
X
X/* lock:	Check and lock a file from access by others
X		returns	TRUE = files was not locked and now is
X			FALSE = file was locked and overridden
X			ABORT = file was locked, abort command
X*/
X
Xlock(fname)
X
Xchar *fname;	/* file name to lock */
X
X{
X	register char *locker;	/* lock error message */
X	register int status;	/* return status */
X	char msg[NSTRING];	/* message string */
X	char *dolock();
X
X	/* attempt to lock the file */
X	locker = dolock(fname);
X	if (locker == NULL)	/* we win */
X		return(TRUE);
X
X	/* file failed...abort */
X	if (strncmp(locker, "LOCK", 4) == 0) {
X		lckerror(locker);
X		return(ABORT);
X	}
X
X	/* someone else has it....override? */
X	strcpy(msg, "File in use by ");
X	strcat(msg, locker);
X	strcat(msg, ", overide?");
X	status = mlyesno(msg);		/* ask them */
X	if (status == TRUE)
X		return(FALSE);
X	else
X		return(ABORT);
X}
X
X/*	unlock:	Unlock a file
X		this only warns the user if it fails
X							*/
X
Xunlock(fname)
X
Xchar *fname;	/* file to unlock */
X
X{
X	register char *locker;	/* undolock return string */
X	char *undolock();
X
X	/* unclock and return */
X	locker = undolock(fname);
X	if (locker == NULL)
X		return(TRUE);
X
X	/* report the error and come back */
X	lckerror(locker);
X	return(FALSE);
X}
X
Xlckerror(errstr)	/* report a lock error */
X
Xchar *errstr;		/* lock error string to print out */
X
X{
X	char obuf[NSTRING];	/* output buffer for error message */
X
X	strcpy(obuf, errstr);
X	strcat(obuf, " - ");
X	if (errno < sys_nerr)
X		strcat(obuf, sys_errlist[errno]);
X	else
X		strcat(obuf, "[can not get system error message]");
X	mlwrite(obuf);
X}
X#endif
X#else
Xlckhello()	/* dummy function */
X{
X}
X#endif
FRIDAY_NIGHT
echo extracting - main.c
sed 's/^X//' > main.c << 'FRIDAY_NIGHT'
X/*
X *	MicroEMACS 3.9
X * 			written by Dave G. Conroy.
X *			substatially modified by Daniel M. Lawrence
X *
X *	(C)opyright 1987 by Daniel M. Lawrence
X *	MicroEMACS 3.9 can be copied and distributed freely for any
X *	non-commercial purposes. MicroEMACS 3.9 can only be incorporated
X *	into commercial software with the permission of the current author.
X *
X * This file contains the main driving routine, and some keyboard processing
X * code, for the MicroEMACS screen editor.
X *
X * REVISION HISTORY:
X *
X * 1.0  Steve Wilhite, 30-Nov-85
X *      - Removed the old LK201 and VT100 logic. Added code to support the
X *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
X *        1 Console In ROM INT. See "rainbow.h" for the function key defs
X *      Steve Wilhite, 1-Dec-85
X *      - massive cleanup on code in display.c and search.c
X *
X * 2.0  George Jones, 12-Dec-85
X *      - Ported to Amiga.
X *
X * 3.0  Daniel Lawrence, 29-Dec-85
X *      - rebound keys/added new fast buffered I/O for AMIGA
X *	- added META- repeat commands
X *	- added reposition default to center screen (yeah!)
X *	- changed exit with modified buffers message
X *	- made filesave tell us what it is doing
X *	- changed search string entry to terminate with <ESC>
X *	  so we can use <NL> in search/replace strings
X *	- updated version number in mode line to 3.0
X *	12-Jan-86
X *	- Added code to reconize the search/replace functions
X *	- Added code to perform search/replace & query functions
X *	14-Jan-86
X *	- moved search logic to separate function in search.c
X *	- added replace and query replace functions
X *	- separated out control key expansions to be used by others in search.c
X *	15-Jan-86
X *	- changed "visiting" to finding
X *	- changed yes/no responses to not need return
X *	- cleaned up various messages
X *	16-jan-86
X *	- fixed spurious spawn message in MSDOS
X *	- added ^X-S synonym to save command
X *	- moved escape to shell to ^X-C
X *	21-jan-86
X *	- added code to suspend shell under BSD
X *	22-jan-86
X *	- added function key support (SPEC) under MSDOS
X *	- Abort now prints [Aborted] on message line
X *	23-jan-86
X *	- Added modes and commands to set/unset them
X *	24-jan-86
X *	- Added Goto Line command
X *	- added Rename Buffer command
X *	28-jan-86
X *	- added goto beginning and end of paragraph commands (META-P/META-N)
X *	- re-wrote kdelete to use realloc. Gained MUCH speed here when
X *	  doing large wipes on both UNIX and MSDOS. Changed kill buffer
X *	  allocation block size from 256 bytes to 1 k
X *	29-jan-86
X *	- moved extern function declarations to efunc.h
X *	- made name[] name binding table
X *	30-jan-86
X *	- fixed Previous/Next paragraph command not to wrap around EOF
X *	- added Fill Paragraph command (META-Q)
X *	4-feb-86
X *	- added code to properly display long lines, scrolling them right
X *	  to left
X *	5-feb-85
X *	- rewrote code to right/left scroll...much better
X *	- added shifted arrow keys on IBMPC
X *	6-feb-85
X *	- add option to allow forward-word to jump to beginning of
X *	  next word instead of end of current one. This is different from
X *	  other emacs' but can be configured off in estruct.h
X *	- added VIEW mode to allow a buffer to be read only
X *	   (-v switch on command line will activate this)
X *	- changed quick exit to write out ALL changed buffers!!!
X *	  MAKE SURE YOU KNOW THIS WHEN META-Zing
X *	10-feb-86
X *	- added handling of lines longer than allowed on file read in
X *	  (they wrap on additional lines)
X *	- made having space clear the message line and NOT insert itself
X *	  a configuration option in ed.h
X *	11-feb-86
X *	- added Describe-command and Help commands.
X *	13-feb-86
X *	- added View file command (^X ^V) and finished HELP command
X *	14-feb-86
X *	- added option to let main loop skip update if type ahead commands
X *	   are queued up
X *	16-feb-86
X *	- added Insert File command
X *	17-feb-86
X *	- added scroll next window up/down commands
X *	18-feb-86
X *	- added CMODE indentation
X *	- re-arranged header files to standardize extern and global
X *	  definitions
X *	- changed version number to 3.2
X *	- added numeric arguments to search, reverse search and
X *	  search and replace
X *	24-feb-86
X *	- added Bind To Key function (^C for now) to allow the user
X *	  to change his command keys
X *	- added Unbind key function (M-^C for now)
X *	- added execute named command to execute unbound commands (M-X)
X *	- added describe bindings command (not bound)
X *	- changed version number to 3.3
X *	25-feb-86
X *	- scrapped CERROR mode (too many compilers)
X *	- added EXACT mode for case sensitive searchers
X *	26-feb-86
X *	- added command completion on execute named command and
X *	  all routined grabbing a command name
X *	- adding execute-command-line command and its support functions
X *	  (in preparation for sourcing files)
X *	- added Execute Buffer command
X *	27-feb-86
X *	- added execute(source) file command and added code to automatically
X *	  execute emacs.rc (or .emacsrc on UNIX) before initial read in
X *	- changed version number to 3.4
X *	4-mar-86
X *	- changed word delete to be consistant with word move (it gets
X *	  rid of the inter word space now) This is configurable with the
X *	  NFWORD symbol in estruct.h
X *	- added B_ACTIVE entry to the buffer table. Let emacs read multiple
X *	  file names from the command line and only read them in as needed
X *	5-mar-85
X *	- rewrote command line parser to get rid of my patchy code
X *	- changed version number to 3.5
X *	1-apr-86
X *	- added support for Aztec C 3.20e under MSDOS
X *	- fixed bug in mlwrite on ADM3's and their ilk under V7
X *	- added insertion of pounds in column one under CMODE
X *	- changed version number to 3.6
X *	3-apr-86
X *	- added next-buffer command (^X-X)
X *	5-apr-86
X *	- added kill paragraph command (M-^W)
X *	- changed fill-paragraph to leave 2 spaces after a period at the
X *	  end of a word.
X *	- added OVERWRITE mode
X *	7-apr-86
X *	- fixed overwrite mode to handle tabs
X *	8-apr-86
X *	- added add/delete global mode (<ESC>M & <ESC> ^M) commands
X *	9-apr-86
X *	- added insert space command
X *	- moved bindings around		^C	insert space
X *					M-K	bind-to-key
X *					INSERT	insert space
X *					DELETE	forwdel
X *	- added hunt forward and hunt reverse commands
X *	10-apr-86
X *	- fixed bug in DOBUF with non-terminated command string
X *	15-apr-86
X *	- fixed tab expansion bug in DISPLAY which hung the AMIGA
X *	  (sent in by Dawn Banks)
X *	- fixed curcol problen if forwline/backline during keyboard
X *	  macro execution (sent in by Ernst Christen)
X *	- added AMIGA function/cursor key support
X *	- fixed nonterminating <NL> replacement bug
X *	- fixed word wrapping problems
X *	16-apr-86
X *	- updated documentation and froze development for 3.6 net release
X *	23-apr-86	version 3.6a
X *	- added foreground and background colors. Setable with the
X *	  add mode commands for the moment
X *	24-apr-86
X *	- added command to pipe CLI output to a buffer
X *	25-apr-86
X *	- added Dana Hoggatt's code to replace Lattice's sick system()
X *	  function. Now we no longer care what the switchar is.
X *	- cleaned up the positioning on several of the spawing commands
X *	26-apr-86
X *	- added an output flush in vttidy(). Unix really appreciates this.
X *	- added filter-buffer (^X#) command to send a buffer through
X *	  a DOS filter
X *	- made automatic CMODE on .c and .h file compilation dependant
X *	  in estruct.h
X *	1-may-86
X *	- optimized some code in update(). It certainly need a lot more.
X *	- added Aztec profiling capabilities. These are conditional on
X *	  the APROF symbol in estruct.h
X *	2-may-86
X *	- added (u)ndo command in query-replace. undoes last repalce.
X *	6-may-86
X *	- re-organized and wrote the update() function in display.c
X *	  Now my color hacks are in the right places and the code can be
X *	  understood.
X *	[Released version 3.6f for BETA test sites]
X *	8-may-86
X *	- fixed bug in new display routine to wrap cursor on extended
X *	  lines at the right time
X *	- modified the buffer-position command to give reasonable info
X *	9-may-86
X *	- improved the word wrap algorithm as not to discard non-space
X *	  delimiters. The backscan now looks for white space rather than
X *	  !inword().
X *	[Released version 3.6g to Krannert]
X *	10-may-86
X *	- Added IBMPC.C an IBM-PC specific display driver. This makes paging
X *	  4-6 times faster. Also made some conditional changes to DISPLAY.C
X *	  to eliminate the pscreen[] if using the PC driver.
X *	[changed version number to 3.6i]
X *	12-may-86
X *	- added delete-window (^X 0) command to dispose of a single window
X *	- fixed problem with multiple prefixes from a command line which
X *	  was reported by John Gamble
X *	14-may-86
X *	- Added Aztec support for the IBMPC display driver. Had to
X *	  readjust some includes and defines for this.
X *	- fixed bug in delete-window.
X *	- fixed some bizarre behavior with the cursor after coming back
X *	  from spawn calls.
X *	[changed version number to 3.7 freezing development for net release]
X *	15-may-86
X *	- (that didn't last long...) Added execute-macro-(1 thru 20) commands
X *	  to execute macro buffers (named "[Macro nn]")
X *	- changed BFTEMP to BFINVS and cleaned up treatment of invisible
X *	  buffers.
X *	16-may-86
X *	- added store-macro (unbound) to store any executed command lines to
X *	  macro buffer.
X *	- added clear-message-line (unbound) command to do just that
X *	- added resize-window command to change a window's size to the
X *	  specified argument
X *	- improved help's logic not to re-read the file if it was already
X *	  in a buffer
X *	- added MAGIC mode to all structures and command tables, but the
X *	  regular expression code that John Gamble is writing is not ready.
X *	18-may-86
X *	- added interactive prompt requests in command line execution (i.e.
X *	  while executing a macro, a parameter starting with an at sign (@)
X *	  causes emacs to prompt with the rest of the parameter and return
X *	  the resulting input as the value of the parameter).
X *	- added arguments to split-current-window to force the cursor into
X *	  the upper or lower window.
X *	20-may-86
X *	- added support for the Microsoft C compiler as per the changes
X *	  sent in by Oliver Sharp
X *	- made some upgrades and fixes for VMS sent in by Guy Streeter
X *	21-may-86
X *	- fixed an Aztec bug in ttgetc by clearing the upper byte
X *	- fixed buf in CMODE with #preprocesser input (bug fix submitted by
X *	  Willis of unknown path)
X *	- added support of alternative startup file ( @<filename> ) in
X *	  the command line
X *	- added ^Q quoting in interactive input (mlreplyt()).
X *	- added re-binding of meta-prefix and ctlx-prefix
X *	22-may-86
X *	- reorganized getkey routines to make more sense and let prefix
X *	  binding work properly.
X *	23-may-86
X *	- checked new code on BSD4.2 and made a few fixes
X *	- added optional fence matching while in CMODE
X *	- added goto and search command line arguments by Mike Spitzer
X *	26-may-86
X *	- added parameter fetching from buffers
X *	27-may-86
X *	- fixed some HP150 bugs......
X *	31-may-86
X *	- Added Wang PC keyboard support from modifications by
X *	  Sid Shapiro @ Wang Institute
X *	- Fixed some reverse video bugs with code submitted by Peter Chubb
X *	- Fixed bug in nextbuffer reported by Dave Forslund
X *	- added system V support (USG) from Linwood Varney
X *	2-jun-86
X *	- changed defines to just define one Unix define (for example,
X *	  just define BSD for Unix BSD 4.2)
X *	- Added Incremental search functions written by D. R. Banks
X *	  in file ISEARCH.C
X *	- added insert-string (unbound) command to help the macro
X *	  language out.
X *	- added unmark-buffer (M-~) command to turn off the current buffers
X *	  change flag
X *	- fixed nxtarg to truncate strings longer than asked for max length
X *	4-jun-86
X *	- added special characters in command line tokens. Tilde (~) is
X *	  the special lead-in character for "nrtb".
X *	- Fixed bad ifdef in Aztec code so it could look at HOME dir
X *	  for startup, help, and emacs.rc files
X *	6-jun-86
X *	- make delete word commands clear the kill buffer if not after another
X *	  kill command
X *	11-jun-86
X *	- made ~@ in string arguments pass as char(192) to nxtarg() so one can
X *	  quote @ at the beginning of string arguments
X *	- changed buffer size vars in listbuffers() to long (for big files)
X *	- re-wrote buffer-position command to be much faster
X *	12-jun-86
X *	- added count-words (M-^C) command to count the words/chars and
X *	  lines in a region
X *	- changed regions so they could be larger than 65535 (short ->
X *	  long in the REGION structure)
X *	- changed ldelete() and all callers to use a long size. The kill
X *	  buffer will still have a problem >65535 that can not be solved
X *	  until I restructure it.
X *	- grouped paragraph commands and word count together under symbol
X *	  WORDPRO to allow them to be conditionally made (or not)
X *	13-jun-86
X *	- re-wrote kill buffer routines again. Now they support an unlimited
X *	  size kill buffer, and are (in theory) faster.
X *	- changed delete-next-word (M-D) to not eat the newline after a word,
X *	  instead it checks and eats a newline at the cursor.
X *	17-jun-86
X *	- added numeric argument to next/previous-window to access the nth
X *	  window from the top/bottom
X *	- added support for the Data General 10 MSDOS machine
X *	- added save-window (unbound) and restore-window (unbound) commands
X *	  for the use of the menu script. Save-window remembers which window
X *	  is current, and restore-window returns the cursor to that window.
X *	20-jun-86
X *	- fixed a bug with the fence matching locking up near the beginning
X *	  of a buffer
X *	- added argument to update to selectively force a complete update
X *	- added update-screen (unbound) command so macros can force a
X *	  screen update
X *	21-jun-86
X *	- rearranged token() and nxtarg() calls so that command names and
X *	  repeat counts could also be prompted and fetched from buffers
X *	  [this broke later with the exec re-write....]
X *	- added write-message (unbound) command to write out a message
X *	  on the message line (for macros)
X *	- changed ifdef's so that color modes are recognized as legal in
X *	  b/w version, and simply do nothing (allowing us to use the same
X *	  script files)
X *	[Released version 3.7 on July 1 to the net and elswhere]
X *	2-jul-86
X *	- Changed search string terminator to always be the meta character
X *	  even if it is rebound.
X *	3-jul-86
X *	- removed extra calls to set color in startup code. This caused the
X *	  original current window to always be the global colors.
X *	7-jul-86
X *	- Fixed bugs in mlreplyt() to work properly with all terminators
X *	  including control and spec characters
X *	22-jul-86
X *	- fixed replaces() so that it will return FALSE properly on the
X *	  input of the replacement string.
X *	- added a definition for FAILED as a return type.....
X *	- changed version number to 3.7b
X *	23-jul-86
X *	- fixed o -> 0 problem in TERMIO.C
X *	- made ^U universal-argument re-bindable
X *	- wrote atoi() for systems (like Aztec) where it acts strangely
X *	- changed version number to 3.7c
X *	25-jul-86
X *	- make ^G abort-command rebindable
X *	29-jul-86
X *	- added HP110 Portable Computer support
X *	- changed version number to 3.7d
X *	30-jul-86
X *	- Fixed a couple of errors in the new VMS code as pointer
X *	  out by Ken Shacklford
X *	- split terminal open/close routines into screen and keyboard
X *	  open/close routines
X *	- closed the keyboard during all disk I/O so that OS errors
X *	  can be respoded to correctly (especially on the HP150)
X *	- changed version number to 3.7e
X *	31-jul-86
X *	- added label-function-key (unbound) command under symbol FLABEL
X *	  (primarily for the HP150)
X *	4-aug-86
X *	- added fixes for Microsoft C as suggested by ihnp4!ihuxm!gmd1
X *		<<remember to fix [list] deletion bug as reported
X *		  by craig@hp-pcd>>
X *	8-aug-86
X *	- fixed beginning misspelling error everywhere
X *	- fixed some more MSC errors
X *	- changed version number to 3.7g
X *	20-aug-86
X *	- fixed CMODE .h scanning bug
X *	- changed version number to 3.7h
X *	30-aug-86
X *	- fixed killing renamed [list] buffer (it can't) as submitted
X *	  by James Aldridge
X *	- Added code to allow multiple lines to display during
X *	  vertical retrace
X *	  [total disaster....yanked it back out]
X *	9-sep-86
X *	- added M-A (apropos) command to list commands containing a substring.
X *	- fixed an inefficiency in the display update code submitted
X *	  by William W. Carlson (wwc@pur-ee)
X *	10-sep-86
X *	- added Dana Hoggatt's code for encryption and spliced it into the
X *	  proper commands. CRYPT mode now triggers encryption.
X *	- added -k flag to allow encryption key (no spaces) in command line
X *	14-sep-86
X *	- added missing lastflag/thisflag processing to docmd()
X *	- changed version to 3.7i and froze for partial release via mail
X *	  and BBS
X *	05-oct-86
X *	- changed some strcpys in MAIN.C to strncpys as suggested by John
X *	  Gamble
X *	- replaces SEARCH.C and ISEARCH.C with versions modified by
X *	  John Gamble
X *	10-oct-86
X *	- removed references to lflick....it just won't work that way.
X *	- removed defines LAT2 and LAT3...the code no longer is Lattice
X *	  version dependant.
X *	14-oct-86
X *	- changed spawn so that it will not not pause if executed from
X *	  a command line
X *	15-oct-86
X *	- added argument concatination (+) to the macro parsing
X *	- added [] as fence pairs
X *	16-oct-86
X *	- rewrote all macro line parsing routines and rearranged the
X *	  mlreply code. Saved 6K!!! Have blazed the path for expanding
X *	  the command language.
X *	17-oct-86
X *	- added new keyboard macro routines (plus a new level to the
X *	  input character function)
X *	22-oct-86
X *	- improved EGA cursor problems
X *	- added -r (restricted) switch to command line for BBS use
X *	06-nov-86
X *	- fixed terminator declarations from char to int in getarg() and
X *	  nxtarg() in EXEC.C as pointed out by John Gamble
X *	07-nov-86
X *	- made wordrap() user callable as wrap-word (M-FNW) and changed
X *	  the getckey() routine so that illegal keystrokes (too many
X *	  prefixes set) could be used for internal bindings. When word
X *	  wrap conditions are met, the keystroke M-FNW is executed. Added
X *	  word wrap check/call to newline().
X *	11-nov-86
X *	- added and checked support for Mark Williams C 86
X *	12-nov-86
X *	- added goto-matching-fence (M-^F) command to jump to a matching
X *	  fence "({[]})" or beep if there is none. This can reframe the
X *	  screen.
X *	- added code and structure elements to support change-screen-size
X *	  command (M-^S) to change the number of lines being used by
X *	  MicroEMACS.
X *	15-nov-86
X *	- finished debugging change-screen-size
X *	17-nov-86
X *	- Incorporated in James Turner's modifications for the Atari ST
X *		23-sep-86
X *		- added support for the Atari ST line of computers (jmt)
X *		  - added a '\r' to the end of each line on output and strip
X *		    it on input for the SHOW function from the desktop
X *		  - added 3 new mode functions (HIREZ, MEDREZ, and LOREZ);
X *		    chgrez routine in TERM structure; and MULTREZ define in
X *		    ESTRUCT.H to handle multiple screen resolutions
X *	[note....ST still not running under Lattice yet...]
X *	25-nov-86
X *	- Made the filter-buffer (^X-#) command not work on VIEW mode
X *	  buffers
X *	- Made the quick-exit (M-Z) command throw out a newline after
X *	  each message so they could be seen.
X *	26-nov-86
X *	- fixed a couple of bugs in change-screen-size (M-^S) command
X *	- changed file read behavior on long lines and last lines
X *	  with no newline (it no longer throws the partial line out)
X *	- [as suggested by Dave Tweten] Made adding a ^Z to the end
X *	  of an output file under MSDOS configurable under the
X *	  CTRL-Z symbol in ESTRUCT.H
X *	- [Dave Tweten] Spawn will look up the "TMP" environment variable
X *	  for use during various pipeing commands.
X *	- [Dave Tweten] changed pipe command under MSDOS to use '>>'
X *	  instead of '>'
X *	04-dec-86
X *	- moved processing of '@' and '#' so that they can be outside
X *	  the quotes in an argument, and added hooks to process '%' for
X *	  environment and user variables.
X *	- modified IBMPC.C to sense the graphics adapter (CGA and MONO)
X *	  at runtime to cut down on the number of versions.
X *	05-dec-86
X *	- changed macro directive character to "!" instead of "$" (see
X *	  below) and fixed the standard .rc file to comply.
X *	- added code to interpret environment variables ($vars). Added
X *	  hooks for built in functions (&func). So, to recap:
X *
X *		@<string>	prompt and return a string from the user
X *		#<buffer name>	get the next line from a buffer and advance
X *		%<var>		get user variable <var>
X *		$<evar>		get environment variable <evar>
X *		&<func>		evaluate function <func>
X *
X *	- allowed repeat counts to be any of the above
X *	- added code to allow insert-string (unbound) to use its
X *	  repeat count properly
X *	- added set (^X-A) command to set variables. Only works on
X *	  environmental vars yet.
X *	9-dec-86
X *	- added some code for user defined variables...more to come
X *	- added options for malloc() memory pool tracking
X *	- preliminary user variables (%) working
X *	- changed terminal calls to macro's (to prepare for the new
X *	  terminal drivers)
X *	15-dec-86
X *	- changed previous-line (^P) and next-line (^N) to return a
X *	  FALSE at the end or beginning of the file so repeated
X *	  macros involving them terminate properly!
X *	- added code for $CURCOL and $CURLINE
X *	20-dec-86
X *	- set (^X-A) now works with all vars
X *	- added some new functions
X *	  	&ADD &SUB &TIMES &DIV &MOD &NEG &CAT
X *	- once again rearranged functions to control macro execution. Did
X *	  away with getarg()
X *	23-dec-86
X *	- added string functions
X *	  	&LEFt &RIGht &MID
X *	31-dec-86
X *	- added many logical functions
X *	  	&NOT &EQUal &LESs &GREater
X *	- added string functions
X *	  	&SEQual &SLEss &SGReater
X *	- added variable indirection with &INDirect
X *	- made fixes to allow recursive macro executions
X *	  (improved speed during macro execution as well)
X *	3-jan-87
X *	- added $FLICKER to control flicker supression
X *	- made spawn commands restricted
X *	- cleaned up lots of unintentional int<->char problems
X *	4-jan-87
X *	- Fixed broken pipe-command (^X-@) command under MSDOS
X *	- added !IF  !ELSE  !ENDIF  directives and changed the
X *	  name of !END to !ENDM....real slick stuff
X *	5-jan-87
X *	- quick-exit (M-Z) aborts on any filewrite errors
X *	8-jan-87
X *	- debugged a lot of the new directive and evaluation code.
X *	  BEWARE of stack space overflows! (increasing stack to
X *	  16K under MSDOS)
X *	- removed non-standard DEC Rainbow keyboard support...let someone
X *	  PLEASE implement this in the standard manner using key bindings
X *	  and send the results to me.
X *	- added change-screen-width () command and $CURWIDTH variable
X *	11-jan-87
X *	- fixed an incredibly deeply buried bug in vtputc and combined
X *	  it with vtpute (saving about 200 bytes!)
X *	16-jan-87
X *	- added code to handle controlling multiple screen resolutions...
X *	  allowed the IBM-PC driver to force Mono or CGA modes.
X *	- added current buffer name and filename variables
X *	  $cbufname and $cfname
X *	18-jan-87
X *	- added $sres variable to control screen resolution
X *	- added $debug variable to control macro debugging code (no longer
X *	  is this activated by GLOBAL spell mode)
X *	- fixed bug in -g command line option
X *	- Released Version 3.8 to BBSNET
X *	21-jan-87
X *	- added $status variable to record return status of last command
X *	2-feb-87
X *	- added ATARI 1040 support...runs in all three modes right now
X *	- added $palette var with palette value in it
X *	- undefined "register" in BIND.C and INPUT.C for ST520 & LATTICE
X *	  to get around a nasty Lattice bug
X *	4-feb-87
X *	- added, debugged code for switching all 1040ST color modes, added
X *	  code for HIGH monochrome mode as well, DENSE still pending
X *	5-feb-87
X *	- with John Gamble, found and corrected the infamous bad matching
X *	  fence problems.
X *	- added error return check in various add/delete mode commands
X *	10-feb-87
X *	- re-arrange code in docmd() so that labels are stored in
X *	  macro buffers
X *	- fixed !RETURN to only return if (execlevel == 0) [If we are
X *	  currently executing]
X *	14-feb-87
X *	- added to outp() calls in the EGA driver to fix a bug in the BIOS
X *	- adding code for 1040ST 40 line DENSE mode (not complete)
X *	25-feb-87
X *	- added auto-save "ASAVE" mode....variables $asave and $acount
X *	  control the frequency of saving and count until next save
X *	- added &and and &or as functions for logical anding and oring
X *	- added string length &LEN, upper and lower case string funtions
X *	  &LOWER and &UPPER
X *	27-feb-87
X *	- added $lastkey   last keystroke struck and
X *	        $curchar    character under cursor
X *	28-feb-87
X *	- added code for trim-line (^X^T) command and table entries
X *	  for the entab-line (^X^E) and detab-line (^X^D) commands.
X *	  These are conditional on AEDIT (Advanced editing) in estruct.h
X *	18-mar-87
X *	- finished above three commands
X *	- added $version environment variable to return the current
X *	  MicroEMACS version number
X *	- added $discmd emvironment variable. This is a logical flag that
X *	  indicates if emacs should be echoing commands on the command line.
X *	  real useful in order to stop flashing macros and .rc files
X *	- added $progname environment variable. this always returns the
X *	  string "MicroEMACS". OEM's should change this so that macros can
X *	  tell if they are running on an unmodified emacs or not.
X *	- fixed a minor bug in the CGA/MONO detection routine in IBMPC.C
X *	20-mar-87
X *	- integrated EGAPC.C into IBMPC.C and eliminated the file. Now an
X *	  EGA user can switch from EGA to CGA modes at will
X *	- A LOT of little fixes and corrections sent in by John Ruply
X *	25-mar-87
X *	- Fixed buffer variables so they will work when referencing the
X *	  current buffer
X *	26-mar-87
X *	- Fixed atoi() to be more reasonable. trailing whitespace ignored,
X *	  only one leading sign, no non-digits allowed after the sign.
X *	- fixed buffer variables to go from the point to the end of
X *	  line.
X *	28-mar-87
X *	- fixed bugs with 8 bit chars as submited by Jari Salminen
X *	- replace AZTEC/MSDOS agetc() with a1getc() which won't strip
X *	  the high order bit
X *	30-mar-87
X *	- changed list-buffers (^X^B) so that with any argument, it will
X *	  also list the normally invisable buffers
X *	- added store-procedure and execute-procedure/run (M-^E)
X *	  commands to store and execute named procedures.
X *	31-mar-87
X *	- Fixed infinite loop in ^X-X command (when [LIST] is the
X *	  only buffer left) as pointed out by John Maline
X *	- made filenames in getfile() always lower case as pointed
X *	  out by John Maline
X *	2-apr-87
X *	- Fixed buffer variables so they would work on non-current displayed
X *	  buffers. They should now work with ALL buffers....
X *	3-apr-87
X *	- Yanked AZTEC profiling code....not very useful
X *	- Modified IBMPC driver so it will not start in EGA mode
X *	- allow the next-buffer (^X-X) command to have a preceding
X *	  non-negative argument.
X *	14-apr-87
X *	- added John Gamble's modified search.c. The code has cut apx
X *	  200-300 bytes off the executable.
X *	- added the &RND function to generate a random integer between
X *	  1 and its arguments value. Also $SEED is availible as the
X *	  random number seed.
X *	- changed the -k command line switch so if there is no argument,
X *	  it will prompt for one when the file is read
X *	15-apr-87
X *	- added 20 bytes of buffer in getval()'s local argument alloc so
X *	  when it returns a value, it has enough stack space to do at least
X *	  one strcpy() before stomping on the returned value. ALWAYS call
X *	  getval() ONLY from within a strcpy() call.
X *	- made $curcol return a 1 based value instead of a zero based one.
X *	  [changed this back later for 3.8o   it was simply wrong.....]
X *	16-apr-87
X *	- re-wrote strncpy() for AZTEC & MSDOS so it null terminates the
X *	  string.
X *	- changed pipe() to pipecmd() to avoid conflicts with various
X *	  UNIX systems
X *	24-apr-87
X *	- changed open parameters on AMIGA window open to 0/0/640/200
X *	[Froze and released v3.8i via BBS net]
X *	14-may-87
X *	- added nop (M-FNC) that gets called on every command loop
X *	- added $wline, returns and sets # lines in current window
X *	- added $cwline, returns and set current line within window
X *	- added $target, returns/sets target for line moves
X *	- added $search, returns/sets default search string
X *	- added $replace, returns/sets default replace string
X *	- added $match, returns last matched string in magic search
X *	29-may-87
X *	- rewrote word deletes to not kill trailing non-whitespace after
X *	  the last word. Also a zero argument will cause it to just delete
X *	  the word and nothing else.
X *	- more fixes for the search pattern environment variables
X *	30-may-87
X *	- forced all windows to redraw on a width change
X *	2-jun-87
X *	- forced clear-message-line to overide $discmd
X *	- added mlforce() routine and call it in clear-message-line,
X *	  write-message and when $debug is TRUE
X *	- recoded the startup sequence in main()....Much Better...
X *	4-jun-87
X *	- forced interactive arguments ( @"question" ) to ALWAYS be echoed
X *	  regardless of the setting of $discmd.
X *	7-jun-87
X *	- started adding support for Turbo C under MSDOS
X *	11-jun-87
X *	- words now include ONLY upper/lower case alphas and digits
X *	- fixed some more bugs with the startup..(ORed in the global modes)
X *	- took more limits off the self-insert list....
X *	16-jun-87
X *	- macro debugging now displays the name of the current macro.
X *	- fixed a problem in expandp() in search.c that kept high-byte
X *	  characters from working in search strings
X *	18-jun-87
X *	- added &sindex <str1> <str2> function which searches for string 2
X *	  within string 1
X *	[released verion 3.8o internally]
X *	19-jun-87
X *	- added $cmode and $gmode to return and set the mode of the
X *	  current buffer and the global mode
X *	- separated findvar() out from setvar() so it could be used in
X *	  the !LOOP directive (which got canned....read on)
X *	- %No such variable message now types the name of the offending
X *	  variable
X *	22-jun-87
X *	- fixed startup bug when editing the startup file
X *	- added the !LOOP <var> <label> directive
X *	26-jun-87
X *	- dumped !LOOP......added !WHILE. This needed and caused a vaste
X *	  reorginization in exec.c which mainly involved moving all the
X *	  directive handling from docmd() to dobuf(), in the process
X *	  getting rid of a lot of junk and making the result smaller
X *	  than it started.....(yea!)
X *	- added $tpause to control the fence flashing time in CMODE.
X *	  The value is machine dependant, but you can multiply the
X *	  original in macros to stay machine independant. (as
X *	  suggested by Baron O.A. Grey)
X *	- added hook to execute M-FNR (null) during a file read, after
X *	  the name is set and right before the file is read. Took out
X *	  any auto-CMODE code, as this is now handled with a macro.
X *	  (also suggested by Baron O.A. Grey)
X *	- Added Baron O.A. Grey's SYSTEM V typeahead() code...I hope
X *	  this works....if you check this out, drop me a line.
X *	- Added new variable $pending, returns a logical telling if
X *	  a typed ahead character is pending.
X *	29-jun-87
X *	- Made adjustmode() use curbp-> instead of curwp->w_bufp-> which
X *	  fixed some bugs in the startup routines.
X *	- added $lwidth to return the length of the current line
X *	2-jul-87
X *	- Added &env <str> which returns the value of the environment
X *	  variable <str> where possible
X *	- Fixed a NASTY bug in execbuf()..the buffer for the name
X *	  of the buffer to execute was NBUFN long, and got overflowed
X *	  with a long interactive argument.
X *	3-jul-87
X *	- Moved the loop to match a key against its binding out of execute()
X *	  to getbind() so it could be used later elsewhere.
X *	- Added &bind <keyname> which returns the function bound to the
X *	  named key
X *	- changed execute-file to look in the executable path first...
X *	6-jul-87
X *	- changed $curchar to return a newline at the end of a line and
X *	  it no longer advances the cursor
X *	- a lot of minor changes sent by various people....
X *	7-jul-87
X *	- some amiga specific fixes as suggested by Kenn Barry
X *	- added $line [read/write] that contains the current line in the
X *	  current buffer
X *	- changed $curcol so setting it beyond the end of the line will
X *	  move the cursor to the end of the line and then fail.
X *	10-jul-87
X *	- added a number of fixes and optimizations along with the rest
X *	  of the TURBO-C support as submited by John Maline
X *	13-jun-87
X *	- caused dobuf() to copy lastflag to thisflag so the first
X *	  command executed will inherit the lastflag from the command
X *	  before the execute-buffer command. (needed this for smooth
X *	  scrolling to work)
X *	- made flook() look first in the $HOME directory, then in the
X *	  current directory, then down the $PATH, and then in the
X *	  list in epath.h
X *	14-jul-87
X *	- added some fixes for VMS along with support for the SMG
X *	  screen package as submited by Curtis Smith
X *	15-jul-87
X *	- fixed M-^H (delete-previous-word) so it can delete the first
X *	  word in a file....I think there may be more of this kind of thing
X *	  to fix.
X *	16-jul-87
X *	- added code to allow arbitrary sized lines to be read from files..
X *	  speed up file reading in the process.
X *	- made out of memory conditions safer.. especial on file reads
X *	- fixed a bug in bind having to do with uppercasing function
X *	  key names (submitted by Jari Salminen)
X *	- made ST520 exit in the same resolution that EMACS was started in
X *	  (for the 1040ST)
X *	[FROZE development and released version 3.9 to USENET]
X *	{It never made it.....got killed by comp.unix.sources}
X *	15-sep-87
X *	- added support for Mark Williams C on the Atari ST
X *	- made the MALLOC debugging package only conditional on RAMSIZE
X *	- added code for flagging truncated buffers
X *	23-sep-87
X *	- fixed &RIGHT to return the <arg2> rightmost characters
X *	- fixed a buffer in getval() to be static....things are stabler
X *	  now.
X *	- moved all the stack size declarations to after include "estruct.h"
X *	  they work a lot better now....... (rather than not at all)
X *	- made Atari ST spawns all work with MWshell
X *	- fixed spawning on the 1040ST under MWC
X *	27-sep-87
X *	- added &exist function to check to see if a named file exist
X *	- added &find function to find a file along the PATH
X *	- added -A switch to run "error.cmd" from command line
X *	- added $gflags to control startup behavior....
X *	03-oct-87
X *	- changed ":c\" to "c:" in epath.h for the AMIGA as suggested
X *	  by Tom Edds
X *	- added binary and, or, and xor functions as submited by John Maline
X *	  (&band   &bor    and  &bxor)
X *	- added binary not (&bnot) function
X *	- added fixes for gotoline() and nextarg() as submited by David
X *	  Dermott
X *	- fixed return value of $curwidth as submitted by David Dermott
X *	- fixed several calls to ldelete() to have a long first argument
X *	  (pointed out by David Dermott)
X *	- Fixed a bug in stock() which prevented uppercase FN bindings as
X *	  pointed out by many people
X *	- changed dofile() to make sure all executed files don't conflict
X *	  with existing buffer names. Took out cludged code in main.c to
X *	  handle this problem... this solution is better (suggested by
X *	  Don Nash)
X *	05-oct-87
X *	- added in John Gamble's code to allow for a replacement regular
X *	  expresion character in MAGIC mode
X *	[note: under MSDOS  we are still TOO BIG!!!!]
X *	- added overwrite-string as a new user callable function, and
X *	  lowrite(c) as an internal function for overwriting characters
X *	- added &xlate function to translate strings according to a
X *	  translation table
X *	10-oct-87
X *	- added code to allow emacs to clean its own buffers on exit.
X *	  useful if emacs is used as a subprogram. Conditional on
X *	  the CLEAN definition in estruct.h
X *	14-oct-87
X *	- swallowed very hard and switched to LARGE code/LARGE data model
X *	- packaged and released version 3.9c internally
X *	  (MSDOS executables compiled with TURBO C Large model) 
X *	16-oct-87
X *	- temporary fix for FUNCTION keys now includes the Meta-O sequence
X *	  if VT100 is definined (submited by Jeff Lomicka)
X *	- an VT100 also triggers input.c to force ESC to always
X *	  be interpeted as META as well as the currently bound key
X *	- fixed a bug in the VMSVT driver as pointed out by Dave Dermott
X *	- added a size parameter to token() to eliminate problems with
X *	  long variable names. (as sugested by Ray Wallace)
X *	18-oct-87
X *	- fixed a bug in the free ram code that did not clear the buffer
X *	  flag causing emacs to ask for more confirnmations on the way out.
X *	19-oct-87
X *	- added ^X-$ execute-program call to directly execute a program
X *	  without going through a shell... not all environments have this
X *	  code completed yet (uses shell-command where not)
X *	[Froze for 3.9d release internally]
X *	28-oct-87
X *	- added code for Atari ST DENSE mode and new bell as submited
X *	  by J. C. Benoist
X *	- made extra CR for ST files conditional on ADDCR. This is only
X *	  needed to make the desktop happy...and is painful for porting
X *	  files (with 2 CR's) elsewhere (Also from J. C. Benoist)
X *	- added optional more intellegent (and larger) close brace
X *	  insertion code (also from J. C. Benoist)
X *	4-nov-87
X *	- fixed AZTEC spawning... all MSDOS spawns should work now
X *	- a META key while debugging will turn $debug to false
X *	  and continue execution.
X *	[Froze for version 3.9e USENET release]
X */
X
X#include        <stdio.h>
X
X/* make global definitions not external */
X#define	maindef
X
X#include        "estruct.h"	/* global structures and defines */
X#include	"efunc.h"	/* function declarations and name table	*/
X#include	"edef.h"	/* global definitions */
X#include	"ebind.h"	/* default key bindings */
X
X/* for MSDOS, increase the default stack space */
X
X#if	MSDOS & LATTICE
Xunsigned _stack = 32766;
X#endif
X
X#if	ATARI & MWC
Xlong _stksize = 32766L;		/* reset stack size (must be even) */
X#endif
X
X#if	MSDOS & AZTEC
Xint _STKSIZ = 32766/16;		/* stack size in paragraphs */
Xint _STKRED = 1024;		/* stack checking limit */
Xint _HEAPSIZ = 4096/16;		/* (in paragraphs) */
Xint _STKLOW = 0;		/* default is stack above heap (small only) */
X#endif
X
X#if	MSDOS & TURBO
Xextern unsigned _stklen = 32766;
X#endif
X
X#if     VMS
X#include        <ssdef.h>
X#define GOOD    (SS$_NORMAL)
X#endif
X
X#ifndef GOOD
X#define GOOD    0
X#endif
X
X#if	CALLED
Xemacs(argc, argv)
X#else
Xmain(argc, argv)
X#endif
Xint argc;	/* # of arguments */
Xchar *argv[];	/* argument strings */
X
X{
X        register int    c;		/* command character */
X        register int    f;		/* default flag */
X        register int    n;		/* numeric repeat count */
X        register int    mflag;		/* negative flag on repeat */
X	register BUFFER *bp;		/* temp buffer pointer */
X	register int	firstfile;	/* first file flag */
X	register int	carg;		/* current arg to scan */
X	register int	startflag;	/* startup executed flag */
X	BUFFER *firstbp = NULL;		/* ptr to first buffer in cmd line */
X	int basec;			/* c stripped of meta character */
X	int viewflag;			/* are we starting in view mode? */
X        int gotoflag;                   /* do we need to goto a line at start? */
X        int gline;                      /* if so, what line? */
X        int searchflag;                 /* Do we need to search at start? */
X	int saveflag;			/* temp store for lastflag */
X	int errflag;			/* C error processing? */
X        char bname[NBUFN];		/* buffer name of file to read */
X#if	CRYPT
X	int cryptflag;			/* encrypting on the way in? */
X	char ekey[NPAT];		/* startup encryption key */
X#endif
X	char *strncpy();
X	extern *pathname[];		/* startup file path/name array */
X
X	/* initialize the editor */
X        vtinit();		/* Display */
X        edinit("main");		/* Buffers, windows */
X	varinit();		/* user variables */
X
X	viewflag = FALSE;	/* view mode defaults off in command line */
X	gotoflag = FALSE;	/* set to off to begin with */
X	searchflag = FALSE;	/* set to off to begin with */
X	firstfile = TRUE;	/* no file to edit yet */
X	startflag = FALSE;	/* startup file not executed yet */
X	errflag = FALSE;	/* not doing C error parsing */
X#if	CRYPT
X	cryptflag = FALSE;	/* no encryption by default */
X#endif
X#if	CALLED
X	eexitflag = FALSE;	/* not time to exit yet */
X#endif
X
X	/* Parse the command line */
X	for (carg = 1; carg < argc; ++carg) {
X
X		/* Process Switches */
X		if (argv[carg][0] == '-') {
X			switch (argv[carg][1]) {
X				/* Process Startup macroes */
X				case 'a':	/* process error file */
X				case 'A':
X					errflag = TRUE;
X					break;
X				case 'e':	/* -e for Edit file */
X				case 'E':
X					viewflag = FALSE;
X					break;
X				case 'g':	/* -g for initial goto */
X				case 'G':
X					gotoflag = TRUE;
X					gline = atoi(&argv[carg][2]);
X					break;
X#if	CRYPT
X				case 'k':	/* -k<key> for code key */
X				case 'K':
X					cryptflag = TRUE;
X					strcpy(ekey, &argv[carg][2]);
X					break;
X#endif
X				case 'r':	/* -r restrictive use */
X				case 'R':
X					restflag = TRUE;
X					break;
X				case 's':	/* -s for initial search string */
X				case 'S':
X					searchflag = TRUE;
X					strncpy(pat,&argv[carg][2],NPAT);
X					break;
X				case 'v':	/* -v for View File */
X				case 'V':
X					viewflag = TRUE;
X					break;
X				default:	/* unknown switch */
X					/* ignore this for now */
X					break;
X			}
X
X		} else if (argv[carg][0]== '@') {
X
X			/* Process Startup macroes */
X			if (startup(&argv[carg][1]) == TRUE)
X				/* don't execute emacs.rc */
X				startflag = TRUE;
X
X		} else {
X
X			/* Process an input file */
X
X			/* set up a buffer for this file */
X	                makename(bname, argv[carg]);
X			unqname(bname);
X
X			/* set this to inactive */
X			bp = bfind(bname, TRUE, 0);
X			strcpy(bp->b_fname, argv[carg]);
X			bp->b_active = FALSE;
X			if (firstfile) {
X				firstbp = bp;
X				firstfile = FALSE;
X			}
X
X			/* set the modes appropriatly */
X			if (viewflag)
X				bp->b_mode |= MDVIEW;
X#if	CRYPT
X			if (cryptflag) {
X				bp->b_mode |= MDCRYPT;
X				crypt((char *)NULL, 0);
X				crypt(ekey, strlen(ekey));
X				strncpy(bp->b_key, ekey, NPAT);
X			}
X#endif
X		}
X	}
X
X	/* if we are C error parsing... run it! */
X	if (errflag) {
X		if (startup("error.cmd") == TRUE)
X			startflag = TRUE;
X	}
X
X	/* if invoked with no other startup files,
X	   run the system startup file here */
X	if (startflag == FALSE) {
X		startup("");
X		startflag = TRUE;
X	}
X
X	/* if there are any files to read, read the first one! */
X	bp = bfind("main", FALSE, 0);
X	if (firstfile == FALSE && (gflags & GFREAD)) {
X		swbuffer(firstbp);
X		curbp->b_mode |= gmode;
X		zotbuf(bp);
X	} else
X		bp->b_mode |= gmode;
X
X        /* Deal with startup gotos and searches */
X        if (gotoflag && searchflag) {
X        	update(FALSE);
X		mlwrite("[Can not search and goto at the same time!]");
X	}
X        else if (gotoflag) {
X                if (gotoline(TRUE,gline) == FALSE) {
X                	update(FALSE);
X			mlwrite("[Bogus goto argument]");
X		}
X        } else if (searchflag) {
X                if (forwhunt(FALSE, 0) == FALSE)
X                	update(FALSE);
X        }
X
X	/* setup to process commands */
X        lastflag = 0;                           /* Fake last flags.     */
X
Xloop:
X
X#if	CALLED
X	/* if we were called as a subroutine and want to leave, do so */
X	if (eexitflag)
X		return(eexitval);
X#endif 
X
X	/* execute the "command" macro...normally null */
X	saveflag = lastflag;	/* preserve lastflag through this */
X	execute(META|SPEC|'C', FALSE, 1);
X	lastflag = saveflag;
X
X	/* Fix up the screen    */
X        update(FALSE);
X
X	/* get the next command from the keyboard */
X	c = getcmd();
X
X	/* if there is something on the command line, clear it */
X        if (mpresf != FALSE) {
X                mlerase();
X                update(FALSE);
X#if	CLRMSG
X                if (c == ' ')                   /* ITS EMACS does this  */
X                        goto loop;
X#endif
X        }
X        f = FALSE;
X        n = 1;
X
X	/* do META-# processing if needed */
X
X	basec = c & ~META;		/* strip meta char off if there */
X	if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
X		f = TRUE;		/* there is a # arg */
X		n = 0;			/* start with a zero default */
X		mflag = 1;		/* current minus flag */
X		c = basec;		/* strip the META */
X		while ((c >= '0' && c <= '9') || (c == '-')) {
X			if (c == '-') {
X				/* already hit a minus or digit? */
X				if ((mflag == -1) || (n != 0))
X					break;
X				mflag = -1;
X			} else {
X				n = n * 10 + (c - '0');
X			}
X			if ((n == 0) && (mflag == -1))	/* lonely - */
X				mlwrite("Arg:");
X			else
X				mlwrite("Arg: %d",n * mflag);
X
X			c = getcmd();	/* get the next key */
X		}
X		n = n * mflag;	/* figure in the sign */
X	}
X
X	/* do ^U repeat argument processing */
X
X        if (c == reptc) {                  /* ^U, start argument   */
X                f = TRUE;
X                n = 4;                          /* with argument of 4 */
X                mflag = 0;                      /* that can be discarded. */
X                mlwrite("Arg: 4");
X                while ((c=getcmd()) >='0' && c<='9' || c==reptc || c=='-'){
X                        if (c == reptc)
X				if ((n > 0) == ((n*4) > 0))
X	                                n = n*4;
X	                        else
X	                        	n = 1;
X                        /*
X                         * If dash, and start of argument string, set arg.
X                         * to -1.  Otherwise, insert it.
X                         */
X                        else if (c == '-') {
X                                if (mflag)
X                                        break;
X                                n = 0;
X                                mflag = -1;
X                        }
X                        /*
X                         * If first digit entered, replace previous argument
X                         * with digit and set sign.  Otherwise, append to arg.
X                         */
X                        else {
X                                if (!mflag) {
X                                        n = 0;
X                                        mflag = 1;
X                                }
X                                n = 10*n + c - '0';
X                        }
X                        mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
X                }
X                /*
X                 * Make arguments preceded by a minus sign negative and change
X                 * the special argument "^U -" to an effective "^U -1".
X                 */
X                if (mflag == -1) {
X                        if (n == 0)
X                                n++;
X                        n = -n;
X                }
X        }
X
X	/* and execute the command */
X        execute(c, f, n);
X        goto loop;
X}
X
X/*
X * Initialize all of the buffers and windows. The buffer name is passed down
X * as an argument, because the main routine may have been told to read in a
X * file by default, and we want the buffer name to be right.
X */
Xedinit(bname)
Xchar    bname[];
X{
X        register BUFFER *bp;
X        register WINDOW *wp;
X	char *malloc();
X
X        bp = bfind(bname, TRUE, 0);             /* First buffer         */
X        blistp = bfind("[List]", TRUE, BFINVS); /* Buffer list buffer   */
X        wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
X        if (bp==NULL || wp==NULL || blistp==NULL)
X                exit(1);
X        curbp  = bp;                            /* Make this current    */
X        wheadp = wp;
X        curwp  = wp;
X        wp->w_wndp  = NULL;                     /* Initialize window    */
X        wp->w_bufp  = bp;
X        bp->b_nwnd  = 1;                        /* Displayed.           */
X        wp->w_linep = bp->b_linep;
X        wp->w_dotp  = bp->b_linep;
X        wp->w_doto  = 0;
X        wp->w_markp = NULL;
X        wp->w_marko = 0;
X        wp->w_toprow = 0;
X#if	COLOR
X	/* initalize colors to global defaults */
X	wp->w_fcolor = gfcolor;
X	wp->w_bcolor = gbcolor;
X#endif
X        wp->w_ntrows = term.t_nrow-1;           /* "-1" for mode line.  */
X        wp->w_force = 0;
X        wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
X}
X
X/*
X * This is the general command execution routine. It handles the fake binding
X * of all the keys to "self-insert". It also clears out the "thisflag" word,
X * and arranges to move it to the "lastflag", so that the next command can
X * look at it. Return the status of command.
X */
Xexecute(c, f, n)
X{
X        register int status;
X	int (*execfunc)();		/* ptr to function to execute */
X	int (*getbind())();
X
X	/* if the keystroke is a bound function...do it */
X	execfunc = getbind(c);
X        if (execfunc != NULL) {
X		thisflag = 0;
X		status	 = (*execfunc)(f, n);
X		lastflag = thisflag;
X		return (status);
X        }
X
X        /*
X         * If a space was typed, fill column is defined, the argument is non-
X         * negative, wrap mode is enabled, and we are now past fill column,
X	 * and we are not read-only, perform word wrap.
X         */
X        if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
X	    n >= 0 && getccol(FALSE) > fillcol &&
X	    (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
X		execute(META|SPEC|'W', FALSE, 1);
X
X        if ((c>=0x20 && c<=0xFF)) {	/* Self inserting.      */
X                if (n <= 0) {                   /* Fenceposts.          */
X                        lastflag = 0;
X                        return (n<0 ? FALSE : TRUE);
X                }
X                thisflag = 0;                   /* For the future.      */
X
X		/* if we are in overwrite mode, not at eol,
X		   and next char is not a tab or we are at a tab stop,
X		   delete a char forword			*/
X		if (curwp->w_bufp->b_mode & MDOVER &&
X		    curwp->w_doto < curwp->w_dotp->l_used &&
X			(lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
X			 (curwp->w_doto) % 8 == 7))
X				ldelete(1L, FALSE);
X
X		/* do the appropriate insertion */
X		if (c == '}' && (curbp->b_mode & MDCMOD) != 0)
X	        	status = insbrace(n, c);
X	        else if (c == '#' && (curbp->b_mode & MDCMOD) != 0)
X	        	status = inspound();
X	        else
X	                status = linsert(n, c);
X
X#if	CFENCE
X		/* check for CMODE fence matching */
X		if ((c == '}' || c == ')' || c == ']') &&
X				(curbp->b_mode & MDCMOD) != 0)
X			fmatch(c);
X#endif
X
X		/* check auto-save mode */
X		if (curbp->b_mode & MDASAVE)
X			if (--gacount == 0) {
X				/* and save the file if needed */
X				upscreen(FALSE, 0);
X				filesave(FALSE, 0);
X				gacount = gasave;
X			}
X
X                lastflag = thisflag;
X                return (status);
X        }
X	TTbeep();
X	mlwrite("[Key not bound]");		/* complain		*/
X        lastflag = 0;                           /* Fake last flags.     */
X        return (FALSE);
X}
X
X/*
X * Fancy quit command, as implemented by Norm. If the any buffer has
X * changed do a write on that buffer and exit emacs, otherwise simply exit.
X */
Xquickexit(f, n)
X{
X	register BUFFER *bp;	/* scanning pointer to buffers */
X        register BUFFER *oldcb; /* original current buffer */
X	register int status;
X
X        oldcb = curbp;                          /* save in case we fail */
X
X	bp = bheadp;
X	while (bp != NULL) {
X	        if ((bp->b_flag&BFCHG) != 0	/* Changed.             */
X        	&& (bp->b_flag&BFINVS) == 0) {	/* Real.                */
X			curbp = bp;		/* make that buffer cur	*/
X			mlwrite("[Saving %s]",bp->b_fname);
X			mlwrite("\n");
X                	if ((status = filesave(f, n)) != TRUE) {
X                		curbp = oldcb;	/* restore curbp */
X                		return(status);
X                	}
X		}
X	bp = bp->b_bufp;			/* on to the next buffer */
X	}
X        quit(f, n);                             /* conditionally quit   */
X	return(TRUE);
X}
X
X/*
X * Quit command. If an argument, always quit. Otherwise confirm if a buffer
X * has been changed and not written out. Normally bound to "C-X C-C".
X */
Xquit(f, n)
X{
X        register int    s;
X
X        if (f != FALSE                          /* Argument forces it.  */
X        || anycb() == FALSE                     /* All buffers clean.   */
X						/* User says it's OK.   */
X        || (s=mlyesno("Modified buffers exist. Leave anyway")) == TRUE) {
X#if	FILOCK
X		if (lockrel() != TRUE) {
X			TTputc('\n');
X			TTputc('\r');
X			TTclose();
X			TTkclose();
X			exit(1);
X		}
X#endif
X                vttidy();
X		if (f)
X			exit(n);
X		else
X	                exit(GOOD);
X        }
X	mlwrite("");
X        return(s);
X}
X
X/*
X * Begin a keyboard macro.
X * Error if not at the top level in keyboard processing. Set up variables and
X * return.
X */
Xctlxlp(f, n)
X{
X        if (kbdmode != STOP) {
X                mlwrite("%%Macro already active");
X                return(FALSE);
X        }
X        mlwrite("[Start macro]");
X	kbdptr = &kbdm[0];
X	kbdend = kbdptr;
X        kbdmode = RECORD;
X        return (TRUE);
X}
X
X/*
X * End keyboard macro. Check for the same limit conditions as the above
X * routine. Set up the variables and return to the caller.
X */
Xctlxrp(f, n)
X{
X        if (kbdmode == STOP) {
X                mlwrite("%%Macro not active");
X                return(FALSE);
X        }
X	if (kbdmode == RECORD) {
X	        mlwrite("[End macro]");
X	        kbdmode = STOP;
X	}
X        return(TRUE);
X}
X
X/*
X * Execute a macro.
X * The command argument is the number of times to loop. Quit as soon as a
X * command gets an error. Return TRUE if all ok, else FALSE.
X */
Xctlxe(f, n)
X{
X        if (kbdmode != STOP) {
X                mlwrite("%%Macro already active");
X                return(FALSE);
X        }
X        if (n <= 0)
X                return (TRUE);
X	kbdrep = n;		/* remember how many times to execute */
X	kbdmode = PLAY;		/* start us in play mode */
X	kbdptr = &kbdm[0];	/*    at the beginning */
X	return(TRUE);
X}
X
X/*
X * Abort.
X * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
X * Sometimes called as a routine, to do general aborting of stuff.
X */
Xctrlg(f, n)
X{
X        TTbeep();
X	kbdmode = STOP;
X	mlwrite("[Aborted]");
X        return(ABORT);
X}
X
X/* tell the user that this command is illegal while we are in
X   VIEW (read-only) mode				*/
X
Xrdonly()
X
X{
X	TTbeep();
X	mlwrite("[Key illegal in VIEW mode]");
X	return(FALSE);
X}
X
Xresterr()
X
X{
X	TTbeep();
X	mlwrite("[That command is RESTRICTED]");
X	return(FALSE);
X}
X
Xnullproc()	/* user function that does NOTHING */
X
X{
X}
X
Xmeta()	/* dummy function for binding to meta prefix */
X{
X}
X
Xcex()	/* dummy function for binding to control-x prefix */
X{
X}
X
Xunarg()	/* dummy function for binding to universal-argument */
X{
X}
X
X/*****		Compiler specific Library functions	****/
X
X#if	MWC86 & MSDOS
Xmovmem(source, dest, size)
X
Xchar *source;	/* mem location to move memory from */
Xchar *dest;	/* memory location to move text to */
Xint size;	/* number of bytes to move */
X
X{
X	register int i;
X
X	for (i=0; i < size; i++)
X		*dest++ = *source++;
X}
X#endif
X
X#if	MSDOS | AMIGA | ST520
X/*	strncpy:	copy a string...with length restrictions
X			ALWAYS null terminate
X*/
X
Xchar *strncpy(dst, src, maxlen)
X
Xchar *dst;	/* destination of copied string */
Xchar *src;	/* source */
Xint maxlen;	/* maximum length */
X
X{
X	char *dptr;	/* ptr into dst */
X
X	dptr = dst;
X	while (*src && (maxlen-- > 0))
X		*dptr++ = *src++;
X	*dptr = 0;
X	return(dst);
X}
X#endif
X
X#if	RAMSIZE
X/*	These routines will allow me to track memory usage by placing
X	a layer on top of the standard system malloc() and free() calls.
X	with this code defined, the environment variable, $RAM, will
X	report on the number of bytes allocated via malloc.
X
X	with SHOWRAM defined, the number is also posted on the
X	end of the bottom mode line and is updated whenever it is changed.
X*/
X
X#undef	malloc
X#undef	free
X
Xchar *allocate(nbytes)	/* allocate nbytes and track */
X
Xunsigned nbytes;	/* # of bytes to allocate */
X
X{
X	char *mp;	/* ptr returned from malloc */
X	char *malloc();
X
X	mp = malloc(nbytes);
X	if (mp) {
X		envram += nbytes;
X#if	RAMSHOW
X		dspram();
X#endif
X	}
X
X	return(mp);
X}
X
Xrelease(mp)	/* release malloced memory and track */
X
Xchar *mp;	/* chunk of RAM to release */
X
X{
X	unsigned *lp;	/* ptr to the long containing the block size */
X
X	if (mp) {
X		/* update amount of ram currently malloced */
X		lp = ((unsigned *)mp) - 1;
X		envram -= (long)*lp - 2;
X		free(mp);
X#if	RAMSHOW
X		dspram();
X#endif
X	}
X}
X
X#if	RAMSHOW
Xdspram()	/* display the amount of RAM currently malloced */
X
X{
X	char mbuf[20];
X	char *sp;
X
X	TTmove(term.t_nrow - 1, 70);
X#if	COLOR
X	TTforg(7);
X	TTbacg(0);
X#endif
X	sprintf(mbuf, "[%lu]", envram);
X	sp = &mbuf[0];
X	while (*sp)
X		TTputc(*sp++);
X	TTmove(term.t_nrow, 0);
X	movecursor(term.t_nrow, 0);
X}
X#endif
X#endif
X
X/*	On some primitave operation systems, and when emacs is used as
X	a subprogram to a larger project, emacs needs to de-alloc its
X	own used memory
X*/
X
X#if	CLEAN
Xcexit(status)
X
Xint status;	/* return status of emacs */
X
X{
X	register BUFFER *bp;	/* buffer list pointer */
X	register WINDOW *wp;	/* window list pointer */
X	register WINDOW *tp;	/* temporary window pointer */
X
X	/* first clean up the windows */
X	wp = wheadp;
X	while (wp) {
X		tp = wp->w_wndp;
X		free(wp);
X		wp = tp;
X	}
X	wheadp = NULL;
X
X	/* then the buffers */
X	bp = bheadp;
X	while (bp) {
X		bp->b_nwnd = 0;
X		bp->b_flag = 0;	/* don't say anything about a changed buffer! */
X		zotbuf(bp);
X		bp = bheadp;
X	}
X
X	/* and the kill buffer */
X	kdelete();
X
X	/* and the video buffers */
X	vtfree();
X
X	/* and now.. we leave [pick the return if we are a subprogram] */
X#if	CALLED
X	eexitflag = TRUE;	/* flag a program exit */
X	eexitval = status;
X	return(status);
X#else
X#undef	exit
X	exit(status);
X#endif
X}
X#endif
FRIDAY_NIGHT
echo mes.8 completed!
# That's all folks!

allbery@ncoast.UUCP (11/17/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.9')
# If you do not see the message
#	`mes.9 completed!'
# then the file was incomplete.
echo extracting - random.c
sed 's/^X//' > random.c << 'FRIDAY_NIGHT'
X/*
X * This file contains the command processing functions for a number of random
X * commands. There is no functional grouping here, for sure.
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
Xint     tabsize;                        /* Tab size (0: use real tabs)  */
X
X/*
X * Set fill column to n.
X */
Xsetfillcol(f, n)
X{
X        fillcol = n;
X	mlwrite("[Fill column is %d]",n);
X        return(TRUE);
X}
X
X/*
X * Display the current position of the cursor, in origin 1 X-Y coordinates,
X * the character that is under the cursor (in hex), and the fraction of the
X * text that is before the cursor. The displayed column is not the current
X * column, but the column that would be used on an infinite width display.
X * Normally this is bound to "C-X =".
X */
Xshowcpos(f, n)
X{
X        register LINE   *lp;		/* current line */
X        register long   numchars;	/* # of chars in file */
X        register int	numlines;	/* # of lines in file */
X        register long   predchars;	/* # chars preceding point */
X        register int	predlines;	/* # lines preceding point */
X        register int    curchar;	/* character under cursor */
X        int ratio;
X        int col;
X	int savepos;			/* temp save for current offset */
X	int ecol;			/* column pos/end of current line */
X
X	/* starting at the beginning of the buffer */
X        lp = lforw(curbp->b_linep);
X
X	/* start counting chars and lines */
X        numchars = 0;
X        numlines = 0;
X        while (lp != curbp->b_linep) {
X		/* if we are on the current line, record it */
X		if (lp == curwp->w_dotp) {
X			predlines = numlines;
X			predchars = numchars + curwp->w_doto;
X			if ((curwp->w_doto) == llength(lp))
X				curchar = '\n';
X			else
X				curchar = lgetc(lp, curwp->w_doto);
X		}
X		/* on to the next line */
X		++numlines;
X		numchars += llength(lp) + 1;
X		lp = lforw(lp);
X        }
X
X	/* if at end of file, record it */
X	if (curwp->w_dotp == curbp->b_linep) {
X		predlines = numlines;
X		predchars = numchars;
X	}
X
X	/* Get real column and end-of-line column. */
X	col = getccol(FALSE);
X	savepos = curwp->w_doto;
X	curwp->w_doto = llength(curwp->w_dotp);
X	ecol = getccol(FALSE);
X	curwp->w_doto = savepos;
X
X        ratio = 0;              /* Ratio before dot. */
X        if (numchars != 0)
X                ratio = (100L*predchars) / numchars;
X
X	/* summarize and report the info */
X	mlwrite("Line %d/%d Col %d/%d Char %D/%D (%d%%) char = 0x%x",
X		predlines+1, numlines+1, col, ecol,
X		predchars, numchars, ratio, curchar);
X        return (TRUE);
X}
X
Xgetcline()	/* get the current line number */
X
X{
X        register LINE   *lp;		/* current line */
X        register int	numlines;	/* # of lines before point */
X
X	/* starting at the beginning of the buffer */
X        lp = lforw(curbp->b_linep);
X
X	/* start counting lines */
X        numlines = 0;
X        while (lp != curbp->b_linep) {
X		/* if we are on the current line, record it */
X		if (lp == curwp->w_dotp)
X			break;
X		++numlines;
X		lp = lforw(lp);
X        }
X
X	/* and return the resulting count */
X	return(numlines + 1);
X}
X
X/*
X * Return current column.  Stop at first non-blank given TRUE argument.
X */
Xgetccol(bflg)
Xint bflg;
X{
X        register int c, i, col;
X        col = 0;
X        for (i=0; i<curwp->w_doto; ++i) {
X                c = lgetc(curwp->w_dotp, i);
X                if (c!=' ' && c!='\t' && bflg)
X                        break;
X                if (c == '\t')
X                        col |= 0x07;
X                else if (c<0x20 || c==0x7F)
X                        ++col;
X                ++col;
X        }
X        return(col);
X}
X
X/*
X * Set current column.
X */
Xsetccol(pos)
X
Xint pos;	/* position to set cursor */
X
X{
X        register int c;		/* character being scanned */
X	register int i;		/* index into current line */
X	register int col;	/* current cursor column   */
X	register int llen;	/* length of line in bytes */
X
X	col = 0;
X	llen = llength(curwp->w_dotp);
X
X	/* scan the line until we are at or past the target column */
X	for (i = 0; i < llen; ++i) {
X		/* upon reaching the target, drop out */
X		if (col >= pos)
X			break;
X
X		/* advance one character */
X                c = lgetc(curwp->w_dotp, i);
X                if (c == '\t')
X                        col |= 0x07;
X                else if (c<0x20 || c==0x7F)
X                        ++col;
X                ++col;
X        }
X
X	/* set us at the new position */
X	curwp->w_doto = i;
X
X	/* and tell weather we made it */
X	return(col >= pos);
X}
X
X/*
X * Twiddle the two characters on either side of dot. If dot is at the end of
X * the line twiddle the two characters before it. Return with an error if dot
X * is at the beginning of line; it seems to be a bit pointless to make this
X * work. This fixes up a very common typo with a single stroke. Normally bound
X * to "C-T". This always works within a line, so "WFEDIT" is good enough.
X */
Xtwiddle(f, n)
X{
X        register LINE   *dotp;
X        register int    doto;
X        register int    cl;
X        register int    cr;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        dotp = curwp->w_dotp;
X        doto = curwp->w_doto;
X        if (doto==llength(dotp) && --doto<0)
X                return (FALSE);
X        cr = lgetc(dotp, doto);
X        if (--doto < 0)
X                return (FALSE);
X        cl = lgetc(dotp, doto);
X        lputc(dotp, doto+0, cr);
X        lputc(dotp, doto+1, cl);
X        lchange(WFEDIT);
X        return (TRUE);
X}
X
X/*
X * Quote the next character, and insert it into the buffer. All the characters
X * are taken literally, with the exception of the newline, which always has
X * its line splitting meaning. The character is always read, even if it is
X * inserted 0 times, for regularity. Bound to "C-Q"
X */
Xquote(f, n)
X{
X        register int    s;
X        register int    c;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        c = tgetc();
X        if (n < 0)
X                return (FALSE);
X        if (n == 0)
X                return (TRUE);
X        if (c == '\n') {
X                do {
X                        s = lnewline();
X                } while (s==TRUE && --n);
X                return (s);
X        }
X        return (linsert(n, c));
X}
X
X/*
X * Set tab size if given non-default argument (n <> 1).  Otherwise, insert a
X * tab into file.  If given argument, n, of zero, change to true tabs.
X * If n > 1, simulate tab stop every n-characters using spaces. This has to be
X * done in this slightly funny way because the tab (in ASCII) has been turned
X * into "C-I" (in 10 bit code) already. Bound to "C-I".
X */
Xtab(f, n)
X{
X        if (n < 0)
X                return (FALSE);
X        if (n == 0 || n > 1) {
X                tabsize = n;
X                return(TRUE);
X        }
X        if (! tabsize)
X                return(linsert(1, '\t'));
X        return(linsert(tabsize - (getccol(FALSE) % tabsize), ' '));
X}
X
X#if	AEDIT
Xdetab(f, n)		/* change tabs to spaces */
X
Xint f,n;	/* default flag and numeric repeat count */
X
X{
X	register int inc;	/* increment to next line [sgn(n)] */
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X
X	if (f == FALSE)
X		n = 1;
X
X	/* loop thru detabbing n lines */
X	inc = ((n > 0) ? 1 : -1);
X	while (n) {
X		curwp->w_doto = 0;	/* start at the beginning */
X
X		/* detab the entire current line */
X		while (curwp->w_doto < llength(curwp->w_dotp)) {
X			/* if we have a tab */
X			if (lgetc(curwp->w_dotp, curwp->w_doto) == '\t') {
X				ldelete(1L, FALSE);
X				insspace(TRUE, 8 - (curwp->w_doto & 7));
X			}
X			forwchar(FALSE, 1);
X		}
X
X		/* advance/or back to the next line */
X		forwline(TRUE, inc);
X		n -= inc;
X	}
X	curwp->w_doto = 0;	/* to the begining of the line */
X	thisflag &= ~CFCPCN;	/* flag that this resets the goal column */
X	lchange(WFEDIT);	/* yes, we have made at least an edit */
X	return(TRUE);
X}
X
Xentab(f, n)		/* change spaces to tabs where posible */
X
Xint f,n;	/* default flag and numeric repeat count */
X
X{
X	register int inc;	/* increment to next line [sgn(n)] */
X	register int fspace;	/* pointer to first space if in a run */
X	register int ccol;	/* current cursor column */
X	register char cchar;	/* current character */
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X
X	if (f == FALSE)
X		n = 1;
X
X	/* loop thru entabbing n lines */
X	inc = ((n > 0) ? 1 : -1);
X	while (n) {
X		curwp->w_doto = 0;	/* start at the beginning */
X
X		/* entab the entire current line */
X		fspace = -1;
X		ccol = 0;
X		while (curwp->w_doto < llength(curwp->w_dotp)) {
X			/* see if it is time to compress */
X			if ((fspace >= 0) && (nextab(fspace) <= ccol))
X				if (ccol - fspace < 2)
X					fspace = -1;
X				else {
X		/* there is a bug here dealing with mixed space/tabed
X		   lines.......it will get fixed		*/
X					backchar(TRUE, ccol - fspace);
X					ldelete((long)(ccol - fspace), FALSE);
X					linsert(1, '\t');	
X					fspace = -1;
X				}
X
X			/* get the current character */
X			cchar = lgetc(curwp->w_dotp, curwp->w_doto);
X
X			switch (cchar) {
X				case '\t': /* a tab...count em up */
X					ccol = nextab(ccol);
X					break;
X
X				case ' ':  /* a space...compress? */
X					if (fspace == -1)
X						fspace = ccol;
X					ccol++;
X					break;
X
X				default:   /* any other char...just count */
X					ccol++;
X					fspace = -1;
X					break;
X			}
X			forwchar(FALSE, 1);
X		}
X
X		/* advance/or back to the next line */
X		forwline(TRUE, inc);
X		n -= inc;
X	}
X	curwp->w_doto = 0;	/* to the begining of the line */
X	thisflag &= ~CFCPCN;	/* flag that this resets the goal column */
X	lchange(WFEDIT);	/* yes, we have made at least an edit */
X	return(TRUE);
X}
X
Xtrim(f, n)	/* trim trailing whitespace from the point to eol */
X
Xint f,n;	/* default flag and numeric repeat count */
X
X{
X	register LINE *lp;	/* current line pointer */
X	register int offset;	/* original line offset position */
X	register int length;	/* current length */
X	register int inc;	/* increment to next line [sgn(n)] */
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X
X	if (f == FALSE)
X		n = 1;
X
X	/* loop thru trimming n lines */
X	inc = ((n > 0) ? 1 : -1);
X	while (n) {
X		lp = curwp->w_dotp;		/* find current line text */
X		offset = curwp->w_doto;		/* save original offset */
X		length = lp->l_used;		/* find current length */
X
X		/* trim the current line */
X		while (length > offset) {
X			if (lgetc(lp, length-1) != ' ' &&
X			    lgetc(lp, length-1) != '\t')
X			    	break;
X			length--;
X		}
X		lp->l_used = length;
X
X		/* advance/or back to the next line */
X		forwline(TRUE, inc);
X		n -= inc;
X	}
X	lchange(WFEDIT);
X	thisflag &= ~CFCPCN;	/* flag that this resets the goal column */
X	return(TRUE);
X}
X#endif
X
X/*
X * Open up some blank space. The basic plan is to insert a bunch of newlines,
X * and then back up over them. Everything is done by the subcommand
X * procerssors. They even handle the looping. Normally this is bound to "C-O".
X */
Xopenline(f, n)
X{
X        register int    i;
X        register int    s;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if (n < 0)
X                return (FALSE);
X        if (n == 0)
X                return (TRUE);
X        i = n;                                  /* Insert newlines.     */
X        do {
X                s = lnewline();
X        } while (s==TRUE && --i);
X        if (s == TRUE)                          /* Then back up overtop */
X                s = backchar(f, n);             /* of them all.         */
X        return (s);
X}
X
X/*
X * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
X * indentation as specified.
X */
Xnewline(f, n)
X{
X	register int    s;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	if (n < 0)
X		return (FALSE);
X
X	/* if we are in C mode and this is a default <NL> */
X	if (n == 1 && (curbp->b_mode & MDCMOD) &&
X	    curwp->w_dotp != curbp->b_linep)
X		return(cinsert());
X
X        /*
X         * If a newline was typed, fill column is defined, the argument is non-
X         * negative, wrap mode is enabled, and we are now past fill column,
X	 * and we are not read-only, perform word wrap.
X         */
X        if ((curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
X	    getccol(FALSE) > fillcol &&
X	    (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
X		execute(META|SPEC|'W', FALSE, 1);
X
X	/* insert some lines */
X	while (n--) {
X		if ((s=lnewline()) != TRUE)
X			return (s);
X	}
X	return (TRUE);
X}
X
Xcinsert()	/* insert a newline and indentation for C */
X
X{
X	register char *cptr;	/* string pointer into text to copy */
X	register int tptr;	/* index to scan into line */
X	register int bracef;	/* was there a brace at the end of line? */
X	register int i;
X	char ichar[NSTRING];	/* buffer to hold indent of last line */
X
X	/* grab a pointer to text to copy indentation from */
X	cptr = &curwp->w_dotp->l_text[0];
X
X	/* check for a brace */
X	tptr = curwp->w_doto - 1;
X	bracef = (cptr[tptr] == '{');
X
X	/* save the indent of the previous line */
X	i = 0;
X	while ((i < tptr) && (cptr[i] == ' ' || cptr[i] == '\t')
X		&& (i < NSTRING - 1)) {
X		ichar[i] = cptr[i];
X		++i;
X	}
X	ichar[i] = 0;		/* terminate it */
X
X	/* put in the newline */
X	if (lnewline() == FALSE)
X		return(FALSE);
X
X	/* and the saved indentation */
X	linstr(ichar);
X
X	/* and one more tab for a brace */
X	if (bracef)
X		tab(FALSE, 1);
X
X	return(TRUE);
X}
X
X#if	NBRACE
Xinsbrace(n, c)	/* insert a brace into the text here...we are in CMODE */
X
Xint n;	/* repeat count */
Xint c;	/* brace to insert (always } for now) */
X
X{
X	register int ch;	/* last character before input */
X	register int oc;	/* caractere oppose a c */
X	register int i, count;
X	register int target;	/* column brace should go after */
X	register LINE *oldlp;
X	register int  oldoff;
X
X	/* if we aren't at the beginning of the line... */
X	if (curwp->w_doto != 0)
X
X	/* scan to see if all space before this is white space */
X		for (i = curwp->w_doto - 1; i >= 0; --i) {
X			ch = lgetc(curwp->w_dotp, i);
X			if (ch != ' ' && ch != '\t')
X				return(linsert(n, c));
X		}
X
X	/* chercher le caractere oppose correspondant */
X	switch (c) {
X		case '}': oc = '{'; break;
X		case ']': oc = '['; break;
X		case ')': oc = '('; break;
X		default: return(FALSE);
X	}
X	
X	oldlp = curwp->w_dotp;
X	oldoff = curwp->w_doto;
X	
X	count = 1; backchar(FALSE, 1);
X	
X	while (count > 0) {
X		if (curwp->w_doto == llength(curwp->w_dotp))
X			ch = '\n';
X		else
X			ch = lgetc(curwp->w_dotp, curwp->w_doto);
X
X		if (ch == c)  ++count;
X		if (ch == oc) --count;
X		
X		backchar(FALSE, 1);
X		if (boundry(curwp->w_dotp, curwp->w_doto, REVERSE))
X			break;
X	}
X	
X	if (count != 0) {	/* no match */
X		curwp->w_dotp = oldlp;
X		curwp->w_doto = oldoff;
X		return(linsert(n, c));
X	}
X	
X	curwp->w_doto = 0;		/* debut de ligne */
X	/* aller au debut de la ligne apres la tabulation */
X	while ((ch = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || ch == '\t')
X		forwchar(FALSE, 1);
X
X	/* delete back first */
X	target = getccol(FALSE);	/* c'est l'indent que l'on doit avoir */
X	curwp->w_dotp = oldlp;
X	curwp->w_doto = oldoff;
X	
X	while (target != getccol(FALSE)) {
X		if (target < getccol(FALSE))	/* on doit detruire des caracteres */
X			while (getccol(FALSE) > target)
X				backdel(FALSE, 1);
X		else {				/* on doit en inserer */
X			while (target - getccol(FALSE) >= 8)
X				linsert(1,'\t');
X			linsert(target - getccol(FALSE), ' ');
X		}
X	}
X
X	/* and insert the required brace(s) */
X	return(linsert(n, c));
X}
X#else
Xinsbrace(n, c)	/* insert a brace into the text here...we are in CMODE */
X
Xint n;	/* repeat count */
Xint c;	/* brace to insert (always { for now) */
X
X{
X	register int ch;	/* last character before input */
X	register int i;
X	register int target;	/* column brace should go after */
X
X	/* if we are at the beginning of the line, no go */
X	if (curwp->w_doto == 0)
X		return(linsert(n,c));
X
X	/* scan to see if all space before this is white space */
X	for (i = curwp->w_doto - 1; i >= 0; --i) {
X		ch = lgetc(curwp->w_dotp, i);
X		if (ch != ' ' && ch != '\t')
X			return(linsert(n, c));
X	}
X
X	/* delete back first */
X	target = getccol(FALSE);	/* calc where we will delete to */
X	target -= 1;
X	target -= target % (tabsize == 0 ? 8 : tabsize);
X	while (getccol(FALSE) > target)
X		backdel(FALSE, 1);
X
X	/* and insert the required brace(s) */
X	return(linsert(n, c));
X}
X#endif
X
Xinspound()	/* insert a # into the text here...we are in CMODE */
X
X{
X	register int ch;	/* last character before input */
X	register int i;
X
X	/* if we are at the beginning of the line, no go */
X	if (curwp->w_doto == 0)
X		return(linsert(1,'#'));
X
X	/* scan to see if all space before this is white space */
X	for (i = curwp->w_doto - 1; i >= 0; --i) {
X		ch = lgetc(curwp->w_dotp, i);
X		if (ch != ' ' && ch != '\t')
X			return(linsert(1, '#'));
X	}
X
X	/* delete back first */
X	while (getccol(FALSE) >= 1)
X		backdel(FALSE, 1);
X
X	/* and insert the required pound */
X	return(linsert(1, '#'));
X}
X
X/*
X * Delete blank lines around dot. What this command does depends if dot is
X * sitting on a blank line. If dot is sitting on a blank line, this command
X * deletes all the blank lines above and below the current line. If it is
X * sitting on a non blank line then it deletes all of the blank lines after
X * the line. Normally this command is bound to "C-X C-O". Any argument is
X * ignored.
X */
Xdeblank(f, n)
X{
X        register LINE   *lp1;
X        register LINE   *lp2;
X        long nld;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        lp1 = curwp->w_dotp;
X        while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
X                lp1 = lp2;
X        lp2 = lp1;
X        nld = 0;
X        while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
X                ++nld;
X        if (nld == 0)
X                return (TRUE);
X        curwp->w_dotp = lforw(lp1);
X        curwp->w_doto = 0;
X        return (ldelete(nld, FALSE));
X}
X
X/*
X * Insert a newline, then enough tabs and spaces to duplicate the indentation
X * of the previous line. Assumes tabs are every eight characters. Quite simple.
X * Figure out the indentation of the current line. Insert a newline by calling
X * the standard routine. Insert the indentation by inserting the right number
X * of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
X * subcomands failed. Normally bound to "C-J".
X */
Xindent(f, n)
X{
X        register int    nicol;
X        register int    c;
X        register int    i;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if (n < 0)
X                return (FALSE);
X        while (n--) {
X                nicol = 0;
X                for (i=0; i<llength(curwp->w_dotp); ++i) {
X                        c = lgetc(curwp->w_dotp, i);
X                        if (c!=' ' && c!='\t')
X                                break;
X                        if (c == '\t')
X                                nicol |= 0x07;
X                        ++nicol;
X                }
X                if (lnewline() == FALSE
X                || ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE)
X                || ((i=nicol%8)!=0 && linsert(i,  ' ')==FALSE))
X                        return (FALSE);
X        }
X        return (TRUE);
X}
X
X/*
X * Delete forward. This is real easy, because the basic delete routine does
X * all of the work. Watches for negative arguments, and does the right thing.
X * If any argument is present, it kills rather than deletes, to prevent loss
X * of text if typed with a big argument. Normally bound to "C-D".
X */
Xforwdel(f, n)
X{
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if (n < 0)
X                return (backdel(f, -n));
X        if (f != FALSE) {                       /* Really a kill.       */
X                if ((lastflag&CFKILL) == 0)
X                        kdelete();
X                thisflag |= CFKILL;
X        }
X        return (ldelete((long)n, f));
X}
X
X/*
X * Delete backwards. This is quite easy too, because it's all done with other
X * functions. Just move the cursor back, and delete forwards. Like delete
X * forward, this actually does a kill if presented with an argument. Bound to
X * both "RUBOUT" and "C-H".
X */
Xbackdel(f, n)
X{
X        register int    s;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if (n < 0)
X                return (forwdel(f, -n));
X        if (f != FALSE) {                       /* Really a kill.       */
X                if ((lastflag&CFKILL) == 0)
X                        kdelete();
X                thisflag |= CFKILL;
X        }
X        if ((s=backchar(f, n)) == TRUE)
X                s = ldelete((long)n, f);
X        return (s);
X}
X
X/*
X * Kill text. If called without an argument, it kills from dot to the end of
X * the line, unless it is at the end of the line, when it kills the newline.
X * If called with an argument of 0, it kills from the start of the line to dot.
X * If called with a positive argument, it kills from dot forward over that
X * number of newlines. If called with a negative argument it kills backwards
X * that number of newlines. Normally bound to "C-K".
X */
Xkilltext(f, n)
X{
X        register LINE   *nextp;
X        long chunk;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if ((lastflag&CFKILL) == 0)             /* Clear kill buffer if */
X                kdelete();                      /* last wasn't a kill.  */
X        thisflag |= CFKILL;
X        if (f == FALSE) {
X                chunk = llength(curwp->w_dotp)-curwp->w_doto;
X                if (chunk == 0)
X                        chunk = 1;
X        } else if (n == 0) {
X                chunk = curwp->w_doto;
X                curwp->w_doto = 0;
X        } else if (n > 0) {
X                chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
X                nextp = lforw(curwp->w_dotp);
X                while (--n) {
X                        if (nextp == curbp->b_linep)
X                                return (FALSE);
X                        chunk += llength(nextp)+1;
X                        nextp = lforw(nextp);
X                }
X        } else {
X                mlwrite("neg kill");
X                return (FALSE);
X        }
X        return(ldelete(chunk, TRUE));
X}
X
Xsetmode(f, n)	/* prompt and set an editor mode */
X
Xint f, n;	/* default and argument */
X
X{
X	adjustmode(TRUE, FALSE);
X}
X
Xdelmode(f, n)	/* prompt and delete an editor mode */
X
Xint f, n;	/* default and argument */
X
X{
X	adjustmode(FALSE, FALSE);
X}
X
Xsetgmode(f, n)	/* prompt and set a global editor mode */
X
Xint f, n;	/* default and argument */
X
X{
X	adjustmode(TRUE, TRUE);
X}
X
Xdelgmode(f, n)	/* prompt and delete a global editor mode */
X
Xint f, n;	/* default and argument */
X
X{
X	adjustmode(FALSE, TRUE);
X}
X
Xadjustmode(kind, global)	/* change the editor mode status */
X
Xint kind;	/* true = set,		false = delete */
Xint global;	/* true = global flag,	false = current buffer flag */
X{
X	register char *scan;		/* scanning pointer to convert prompt */
X	register int i;			/* loop index */
X	register int status;		/* error return on input */
X#if	COLOR
X	register int uflag;		/* was modename uppercase?	*/
X#endif
X	char prompt[50];	/* string to prompt user with */
X	char cbuf[NPAT];		/* buffer to recieve mode name into */
X
X	/* build the proper prompt string */
X	if (global)
X		strcpy(prompt,"Global mode to ");
X	else
X		strcpy(prompt,"Mode to ");
X
X	if (kind == TRUE)
X		strcat(prompt, "add: ");
X	else
X		strcat(prompt, "delete: ");
X
X	/* prompt the user and get an answer */
X
X	status = mlreply(prompt, cbuf, NPAT - 1);
X	if (status != TRUE)
X		return(status);
X
X	/* make it uppercase */
X
X	scan = cbuf;
X#if	COLOR
X	uflag = (*scan >= 'A' && *scan <= 'Z');
X#endif
X	while (*scan != 0) {
X		if (*scan >= 'a' && *scan <= 'z')
X			*scan = *scan - 32;
X		scan++;
X	}
X
X	/* test it first against the colors we know */
X	for (i=0; i<NCOLORS; i++) {
X		if (strcmp(cbuf, cname[i]) == 0) {
X			/* finding the match, we set the color */
X#if	COLOR
X			if (uflag)
X				if (global)
X					gfcolor = i;
X				else
X					curwp->w_fcolor = i;
X			else
X				if (global)
X					gbcolor = i;
X				else
X					curwp->w_bcolor = i;
X
X			curwp->w_flag |= WFCOLR;
X#endif
X			mlerase();
X			return(TRUE);
X		}
X	}
X
X	/* test it against the modes we know */
X
X	for (i=0; i < NUMMODES; i++) {
X		if (strcmp(cbuf, modename[i]) == 0) {
X			/* finding a match, we process it */
X			if (kind == TRUE)
X				if (global)
X					gmode |= (1 << i);
X				else
X					curbp->b_mode |= (1 << i);
X			else
X				if (global)
X					gmode &= ~(1 << i);
X				else
X					curbp->b_mode &= ~(1 << i);
X			/* display new mode line */
X			if (global == 0)
X				upmode();
X			mlerase();	/* erase the junk */
X			return(TRUE);
X		}
X	}
X
X	mlwrite("No such mode!");
X	return(FALSE);
X}
X
X/*	This function simply clears the message line,
X		mainly for macro usage			*/
X
Xclrmes(f, n)
X
Xint f, n;	/* arguments ignored */
X
X{
X	mlforce("");
X	return(TRUE);
X}
X
X/*	This function writes a string on the message line
X		mainly for macro usage			*/
X
Xwritemsg(f, n)
X
Xint f, n;	/* arguments ignored */
X
X{
X	register char *sp;	/* pointer into buf to expand %s */
X	register char *np;	/* ptr into nbuf */
X	register int status;
X	char buf[NPAT];		/* buffer to recieve message into */
X	char nbuf[NPAT*2];	/* buffer to expand string into */
X
X	if ((status = mlreply("Message to write: ", buf, NPAT - 1)) != TRUE)
X		return(status);
X
X	/* expand all '%' to "%%" so mlwrite won't expect arguments */
X	sp = buf;
X	np = nbuf;
X	while (*sp) {
X		*np++ = *sp;
X		if (*sp++ == '%')
X			*np++ = '%';
X	}
X	*np = '\0';
X
X	/* write the message out */
X	mlforce(nbuf);
X	return(TRUE);
X}
X
X#if	CFENCE
X/*	the cursor is moved to a matching fence	*/
X
Xgetfence(f, n)
X
Xint f, n;	/* not used */
X
X{
X	register LINE *oldlp;	/* original line pointer */
X	register int oldoff;	/* and offset */
X	register int sdir;	/* direction of search (1/-1) */
X	register int count;	/* current fence level count */
X	register char ch;	/* fence type to match against */
X	register char ofence;	/* open fence */
X	register char c;	/* current character in scan */
X
X	/* save the original cursor position */
X	oldlp = curwp->w_dotp;
X	oldoff = curwp->w_doto;
X
X	/* get the current character */
X	if (oldoff == llength(oldlp))
X		ch = '\n';
X	else
X		ch = lgetc(oldlp, oldoff);
X
X	/* setup proper matching fence */
X	switch (ch) {
X		case '(': ofence = ')'; sdir = FORWARD; break;
X		case '{': ofence = '}'; sdir = FORWARD; break;
X		case '[': ofence = ']'; sdir = FORWARD; break;
X		case ')': ofence = '('; sdir = REVERSE; break;
X		case '}': ofence = '{'; sdir = REVERSE; break;
X		case ']': ofence = '['; sdir = REVERSE; break;
X		default: TTbeep(); return(FALSE);
X	}
X
X	/* set up for scan */
X	count = 1;
X	if (sdir == REVERSE)
X		backchar(FALSE, 1);
X	else
X		forwchar(FALSE, 1);
X
X	/* scan until we find it, or reach the end of file */
X	while (count > 0) {
X		if (curwp->w_doto == llength(curwp->w_dotp))
X			c = '\n';
X		else
X			c = lgetc(curwp->w_dotp, curwp->w_doto);
X		if (c == ch)
X			++count;
X		if (c == ofence)
X			--count;
X		if (sdir == FORWARD)
X			forwchar(FALSE, 1);
X		else
X			backchar(FALSE, 1);
X		if (boundry(curwp->w_dotp, curwp->w_doto, sdir))
X			break;
X	}
X
X	/* if count is zero, we have a match, move the sucker */
X	if (count == 0) {
X		if (sdir == FORWARD)
X			backchar(FALSE, 1);
X		else
X			forwchar(FALSE, 1);
X		curwp->w_flag |= WFMOVE;
X		return(TRUE);
X	}
X
X	/* restore the current position */
X	curwp->w_dotp = oldlp;
X	curwp->w_doto = oldoff;
X	TTbeep();
X	return(FALSE);
X}
X#endif
X
X/*	Close fences are matched against their partners, and if
X	on screen the cursor briefly lights there		*/
X
Xfmatch(ch)
X
Xchar ch;	/* fence type to match against */
X
X{
X	register LINE *oldlp;	/* original line pointer */
X	register int oldoff;	/* and offset */
X	register LINE *toplp;	/* top line in current window */
X	register int count;	/* current fence level count */
X	register char opench;	/* open fence */
X	register char c;	/* current character in scan */
X	register int i;
X
X	/* first get the display update out there */
X	update(FALSE);
X
X	/* save the original cursor position */
X	oldlp = curwp->w_dotp;
X	oldoff = curwp->w_doto;
X
X	/* setup proper open fence for passed close fence */
X	if (ch == ')')
X		opench = '(';
X	else if (ch == '}')
X		opench = '{';
X	else
X		opench = '[';
X
X	/* find the top line and set up for scan */
X	toplp = curwp->w_linep->l_bp;
X	count = 1;
X	backchar(FALSE, 2);
X
X	/* scan back until we find it, or reach past the top of the window */
X	while (count > 0 && curwp->w_dotp != toplp) {
X		if (curwp->w_doto == llength(curwp->w_dotp))
X			c = '\n';
X		else
X			c = lgetc(curwp->w_dotp, curwp->w_doto);
X		if (c == ch)
X			++count;
X		if (c == opench)
X			--count;
X		backchar(FALSE, 1);
X		if (curwp->w_dotp == curwp->w_bufp->b_linep->l_fp &&
X		    curwp->w_doto == 0)
X			break;
X	}
X
X	/* if count is zero, we have a match, display the sucker */
X	/* there is a real machine dependant timing problem here we have
X	   yet to solve......... */
X	if (count == 0) {
X		forwchar(FALSE, 1);
X		for (i = 0; i < term.t_pause; i++)
X			update(FALSE);
X	}
X
X	/* restore the current position */
X	curwp->w_dotp = oldlp;
X	curwp->w_doto = oldoff;
X	return(TRUE);
X}
X
Xistring(f, n)	/* ask for and insert a string into the current
X		   buffer at the current point */
X
Xint f, n;	/* ignored arguments */
X
X{
X	register int status;	/* status return code */
X	char tstring[NPAT+1];	/* string to add */
X
X	/* ask for string to insert */
X	status = mlreplyt("String to insert<META>: ", tstring, NPAT, metac);
X	if (status != TRUE)
X		return(status);
X
X	if (f == FALSE)
X		n = 1;
X
X	if (n < 0)
X		n = - n;
X
X	/* insert it */
X	while (n-- && (status = linstr(tstring)))
X		;
X	return(status);
X}
X
Xovstring(f, n)	/* ask for and overwite a string into the current
X		   buffer at the current point */
X
Xint f, n;	/* ignored arguments */
X
X{
X	register int status;	/* status return code */
X	char tstring[NPAT+1];	/* string to add */
X
X	/* ask for string to insert */
X	status = mlreplyt("String to overwrite<META>: ", tstring, NPAT, metac);
X	if (status != TRUE)
X		return(status);
X
X	if (f == FALSE)
X		n = 1;
X
X	if (n < 0)
X		n = - n;
X
X	/* insert it */
X	while (n-- && (status = lover(tstring)))
X		;
X	return(status);
X}
X
FRIDAY_NIGHT
echo mes.9 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/17/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.10')
# If you do not see the message
#	`mes.10 completed!'
# then the file was incomplete.
echo extracting - region.c
sed 's/^X//' > region.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file
X * deal with the region, that magic space
X * between "." and mark. Some functions are
X * commands. Some functions are just for
X * internal use.
X */
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X#if	MEGAMAX & ST520
Xoverlay	"region"
X#endif
X
X/*
X * Kill the region. Ask "getregion"
X * to figure out the bounds of the region.
X * Move "." to the start, and kill the characters.
X * Bound to "C-W".
X */
Xkillregion(f, n)
X{
X        register int    s;
X        REGION          region;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if ((s=getregion(&region)) != TRUE)
X                return (s);
X        if ((lastflag&CFKILL) == 0)             /* This is a kill type  */
X                kdelete();                      /* command, so do magic */
X        thisflag |= CFKILL;                     /* kill buffer stuff.   */
X        curwp->w_dotp = region.r_linep;
X        curwp->w_doto = region.r_offset;
X        return (ldelete(region.r_size, TRUE));
X}
X
X/*
X * Copy all of the characters in the
X * region to the kill buffer. Don't move dot
X * at all. This is a bit like a kill region followed
X * by a yank. Bound to "M-W".
X */
Xcopyregion(f, n)
X{
X        register LINE   *linep;
X        register int    loffs;
X        register int    s;
X        REGION          region;
X
X        if ((s=getregion(&region)) != TRUE)
X                return (s);
X        if ((lastflag&CFKILL) == 0)             /* Kill type command.   */
X                kdelete();
X        thisflag |= CFKILL;
X        linep = region.r_linep;                 /* Current line.        */
X        loffs = region.r_offset;                /* Current offset.      */
X        while (region.r_size--) {
X                if (loffs == llength(linep)) {  /* End of line.         */
X                        if ((s=kinsert('\n')) != TRUE)
X                                return (s);
X                        linep = lforw(linep);
X                        loffs = 0;
X                } else {                        /* Middle of line.      */
X                        if ((s=kinsert(lgetc(linep, loffs))) != TRUE)
X                                return (s);
X                        ++loffs;
X                }
X        }
X	mlwrite("[region copied]");
X        return (TRUE);
X}
X
X/*
X * Lower case region. Zap all of the upper
X * case characters in the region to lower case. Use
X * the region code to set the limits. Scan the buffer,
X * doing the changes. Call "lchange" to ensure that
X * redisplay is done in all buffers. Bound to
X * "C-X C-L".
X */
Xlowerregion(f, n)
X{
X        register LINE   *linep;
X        register int    loffs;
X        register int    c;
X        register int    s;
X        REGION          region;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if ((s=getregion(&region)) != TRUE)
X                return (s);
X        lchange(WFHARD);
X        linep = region.r_linep;
X        loffs = region.r_offset;
X        while (region.r_size--) {
X                if (loffs == llength(linep)) {
X                        linep = lforw(linep);
X                        loffs = 0;
X                } else {
X                        c = lgetc(linep, loffs);
X                        if (c>='A' && c<='Z')
X                                lputc(linep, loffs, c+'a'-'A');
X                        ++loffs;
X                }
X        }
X        return (TRUE);
X}
X
X/*
X * Upper case region. Zap all of the lower
X * case characters in the region to upper case. Use
X * the region code to set the limits. Scan the buffer,
X * doing the changes. Call "lchange" to ensure that
X * redisplay is done in all buffers. Bound to
X * "C-X C-L".
X */
Xupperregion(f, n)
X{
X        register LINE   *linep;
X        register int    loffs;
X        register int    c;
X        register int    s;
X        REGION          region;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if ((s=getregion(&region)) != TRUE)
X                return (s);
X        lchange(WFHARD);
X        linep = region.r_linep;
X        loffs = region.r_offset;
X        while (region.r_size--) {
X                if (loffs == llength(linep)) {
X                        linep = lforw(linep);
X                        loffs = 0;
X                } else {
X                        c = lgetc(linep, loffs);
X                        if (c>='a' && c<='z')
X                                lputc(linep, loffs, c-'a'+'A');
X                        ++loffs;
X                }
X        }
X        return (TRUE);
X}
X
X/*
X * This routine figures out the
X * bounds of the region in the current window, and
X * fills in the fields of the "REGION" structure pointed
X * to by "rp". Because the dot and mark are usually very
X * close together, we scan outward from dot looking for
X * mark. This should save time. Return a standard code.
X * Callers of this routine should be prepared to get
X * an "ABORT" status; we might make this have the
X * conform thing later.
X */
Xgetregion(rp)
Xregister REGION *rp;
X{
X        register LINE   *flp;
X        register LINE   *blp;
X        long fsize;
X        long bsize;
X
X        if (curwp->w_markp == NULL) {
X                mlwrite("No mark set in this window");
X                return (FALSE);
X        }
X        if (curwp->w_dotp == curwp->w_markp) {
X                rp->r_linep = curwp->w_dotp;
X                if (curwp->w_doto < curwp->w_marko) {
X                        rp->r_offset = curwp->w_doto;
X                        rp->r_size = (long)(curwp->w_marko-curwp->w_doto);
X                } else {
X                        rp->r_offset = curwp->w_marko;
X                        rp->r_size = (long)(curwp->w_doto-curwp->w_marko);
X                }
X                return (TRUE);
X        }
X        blp = curwp->w_dotp;
X        bsize = (long)curwp->w_doto;
X        flp = curwp->w_dotp;
X        fsize = (long)(llength(flp)-curwp->w_doto+1);
X        while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
X                if (flp != curbp->b_linep) {
X                        flp = lforw(flp);
X                        if (flp == curwp->w_markp) {
X                                rp->r_linep = curwp->w_dotp;
X                                rp->r_offset = curwp->w_doto;
X                                rp->r_size = fsize+curwp->w_marko;
X                                return (TRUE);
X                        }
X                        fsize += llength(flp)+1;
X                }
X                if (lback(blp) != curbp->b_linep) {
X                        blp = lback(blp);
X                        bsize += llength(blp)+1;
X                        if (blp == curwp->w_markp) {
X                                rp->r_linep = blp;
X                                rp->r_offset = curwp->w_marko;
X                                rp->r_size = bsize - curwp->w_marko;
X                                return (TRUE);
X                        }
X                }
X        }
X        mlwrite("Bug: lost mark");
X        return (FALSE);
X}
X
FRIDAY_NIGHT
echo extracting - search.c
sed 's/^X//' > search.c << 'FRIDAY_NIGHT'
X/*
X * The functions in this file implement commands that search in the forward
X * and backward directions.  There are no special characters in the search
X * strings.  Probably should have a regular expression search, or something
X * like that.
X *
X * Aug. 1986 John M. Gamble:
X *	Made forward and reverse search use the same scan routine.
X *
X *	Added a limited number of regular expressions - 'any',
X *	'character class', 'closure', 'beginning of line', and
X *	'end of line'.
X *
X *	Replacement metacharacters will have to wait for a re-write of
X *	the replaces function, and a new variation of ldelete().
X *
X *	For those curious as to my references, i made use of
X *	Kernighan & Plauger's "Software Tools."
X *	I deliberately did not look at any published grep or editor
X *	source (aside from this one) for inspiration.  I did make use of
X *	Allen Hollub's bitmap routines as published in Doctor Dobb's Journal,
X *	June, 1985 and modified them for the limited needs of character class
X *	matching.  Any inefficiences, bugs, stupid coding examples, etc.,
X *	are therefore my own responsibility.
X *
X * April 1987: John M. Gamble
X *	Deleted the "if (n == 0) n = 1;" statements in front of the
X *	search/hunt routines.  Since we now use a do loop, these
X *	checks are unnecessary.  Consolidated common code into the
X *	function delins().  Renamed global mclen matchlen,
X *	and added the globals matchline, matchoff, patmatch, and
X *	mlenold.
X *	This gave us the ability to unreplace regular expression searches,
X *	and to put the matched string into an evironment variable.
X *	SOON TO COME: Meta-replacement characters!
X *
X *	25-apr-87	DML
X *	- cleaned up an unneccessary if/else in forwsearch() and
X *	  backsearch()
X *	- savematch() failed to malloc room for the terminating byte
X *	  of the match string (stomp...stomp...). It does now. Also
X *	  it now returns gracefully if malloc fails
X *
X *	July 1987: John M. Gamble
X *	Set the variables matchlen and matchoff in the 'unreplace'
X *	section of replaces().  The function savematch() would
X *	get confused if you replaced, unreplaced, then replaced
X *	again (serves you right for being so wishy-washy...)
X *
X *	August 1987: John M. Gamble
X *	Put in new function rmcstr() to create the replacement
X *	meta-character array.  Modified delins() so that it knows
X *	whether or not to make use of the array.  And, put in the
X *	appropriate new structures and variables.
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X#if	LATTICE
X#define	void	int
X#endif
X
Xstatic int    readpattern();
Xstatic int    replaces();
Xstatic int    nextch();
X#if	MAGIC
Xstatic int    cclmake();
Xstatic int    mcstr();
Xstatic int    rmcstr();
Xstatic int    mceq();
Xstatic void   setbit();
Xstatic int    amatch();
Xstatic int    biteq();
Xstatic BITMAP clearbits();
X#endif
X
X/*
X * forwsearch -- Search forward.  Get a search string from the user, and
X *	search for the string.  If found, reset the "." to be just after
X *	the match string, and (perhaps) repaint the display.
X */
Xforwsearch(f, n)
Xint f, n;	/* default flag / numeric argument */
X{
X	register int status = TRUE;
X
X	/* If n is negative, search backwards.
X	 * Otherwise proceed by asking for the search string.
X	 */
X	if (n < 0)
X		return(backsearch(f, -n));
X
X	/* Ask the user for the text of a pattern.  If the
X	 * response is TRUE (responses other than FALSE are
X	 * possible), search for the pattern for as long as
X	 * n is positive (n == 0 will go through once, which
X	 * is just fine).
X	 */
X	if ((status = readpattern("Search", &pat[0], TRUE)) == TRUE) {
X		do {
X#if	MAGIC
X			if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
X				status = mcscanner(&mcpat[0], FORWARD, PTEND);
X			else
X#endif
X				status = scanner(&pat[0], FORWARD, PTEND);
X		} while ((--n > 0) && status);
X
X		/* Save away the match, or complain
X		 * if not there.
X		 */
X		if (status == TRUE)
X			savematch();
X		else
X			mlwrite("Not found");
X	}
X	return(status);
X}
X
X/*
X * forwhunt -- Search forward for a previously acquired search string.
X *	If found, reset the "." to be just after the match string,
X *	and (perhaps) repaint the display.
X */
X
Xforwhunt(f, n)
Xint f, n;	/* default flag / numeric argument */
X{
X	register int status = TRUE;
X
X	if (n < 0)		/* search backwards */
X		return(backhunt(f, -n));
X
X	/* Make sure a pattern exists, or that we didn't switch
X	 * into MAGIC mode until after we entered the pattern.
X	 */
X	if (pat[0] == '\0')
X	{
X		mlwrite("No pattern set");
X		return FALSE;
X	}
X#if	MAGIC
X	if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
X		 mcpat[0].mc_type == MCNIL)
X	{
X		if (!mcstr())
X			return FALSE;
X	}
X#endif
X
X	/* Search for the pattern for as long as
X	 * n is positive (n == 0 will go through once, which
X	 * is just fine).
X	 */
X	do
X	{
X#if	MAGIC
X		if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
X			status = mcscanner(&mcpat[0], FORWARD, PTEND);
X		else
X#endif
X			status = scanner(&pat[0], FORWARD, PTEND);
X	} while ((--n > 0) && status);
X
X	/* Save away the match, or complain
X	 * if not there.
X	 */
X	if (status == TRUE)
X		savematch();
X	else
X		mlwrite("Not found");
X
X	return(status);
X}
X
X/*
X * backsearch -- Reverse search.  Get a search string from the user, and
X *	search, starting at "." and proceeding toward the front of the buffer.
X *	If found "." is left pointing at the first character of the pattern
X *	(the last character that was matched).
X */
Xbacksearch(f, n)
Xint f, n;	/* default flag / numeric argument */
X{
X	register int status = TRUE;
X
X	/* If n is negative, search forwards.
X	 * Otherwise proceed by asking for the search string.
X	 */
X	if (n < 0)
X		return(forwsearch(f, -n));
X
X	/* Ask the user for the text of a pattern.  If the
X	 * response is TRUE (responses other than FALSE are
X	 * possible), search for the pattern for as long as
X	 * n is positive (n == 0 will go through once, which
X	 * is just fine).
X	 */
X	if ((status = readpattern("Reverse search", &pat[0], TRUE)) == TRUE) {
X		do {
X#if	MAGIC
X			if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
X				status = mcscanner(&tapcm[0], REVERSE, PTBEG);
X			else
X#endif
X				status = scanner(&tap[0], REVERSE, PTBEG);
X		} while ((--n > 0) && status);
X
X		/* Save away the match, or complain
X		 * if not there.
X		 */
X		if (status == TRUE)
X			savematch();
X		else
X			mlwrite("Not found");
X	}
X	return(status);
X}
X
X/*
X * backhunt -- Reverse search for a previously acquired search string,
X *	starting at "." and proceeding toward the front of the buffer.
X *	If found "." is left pointing at the first character of the pattern
X *	(the last character that was matched).
X */
Xbackhunt(f, n)
Xint f, n;	/* default flag / numeric argument */
X{
X	register int	status = TRUE;
X
X	if (n < 0)
X		return(forwhunt(f, -n));
X
X	/* Make sure a pattern exists, or that we didn't switch
X	 * into MAGIC mode until after we entered the pattern.
X	 */
X	if (tap[0] == '\0')
X	{
X		mlwrite("No pattern set");
X		return FALSE;
X	}
X#if	MAGIC
X	if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
X		 tapcm[0].mc_type == MCNIL)
X	{
X		if (!mcstr())
X			return FALSE;
X	}
X#endif
X
X	/* Go search for it for as long as
X	 * n is positive (n == 0 will go through once, which
X	 * is just fine).
X	 */
X	do
X	{
X#if	MAGIC
X		if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
X			status = mcscanner(&tapcm[0], REVERSE, PTBEG);
X		else
X#endif
X			status = scanner(&tap[0], REVERSE, PTBEG);
X	} while ((--n > 0) && status);
X
X	/* Save away the match, or complain
X	 * if not there.
X	 */
X	if (status == TRUE)
X		savematch();
X	else
X		mlwrite("Not found");
X
X	return(status);
X}
X
X#if	MAGIC
X/*
X * mcscanner -- Search for a meta-pattern in either direction.  If found,
X *	reset the "." to be at the start or just after the match string,
X *	and (perhaps) repaint the display.
X */
Xint	mcscanner(mcpatrn, direct, beg_or_end)
XMC	*mcpatrn;	/* pointer into pattern */
Xint	direct;		/* which way to go.*/
Xint	beg_or_end;	/* put point at beginning or end of pattern.*/
X{
X	LINE *curline;			/* current line during scan */
X	int curoff;			/* position within current line */
X
X	/* If we are going in reverse, then the 'end' is actually
X	 * the beginning of the pattern.  Toggle it.
X	 */
X	beg_or_end ^= direct;
X
X	/*
X	 * Save the old matchlen length, in case it is
X	 * very different (closure) from the old length.
X	 * This is important for query-replace undo
X	 * command.
X	 */
X	mlenold = matchlen;
X
X	/* Setup local scan pointers to global ".".
X	 */
X	curline = curwp->w_dotp;
X	curoff  = curwp->w_doto;
X
X	/* Scan each character until we hit the head link record.
X	 */
X	while (!boundry(curline, curoff, direct))
X	{
X		/* Save the current position in case we need to
X		 * restore it on a match, and initialize matchlen to
X		 * zero in case we are doing a search for replacement.
X		 */
X		matchline = curline;
X		matchoff = curoff;
X		matchlen = 0;
X
X		if (amatch(mcpatrn, direct, &curline, &curoff))
X		{
X			/* A SUCCESSFULL MATCH!!!
X			 * reset the global "." pointers.
X			 */
X			if (beg_or_end == PTEND)	/* at end of string */
X			{
X				curwp->w_dotp = curline;
X				curwp->w_doto = curoff;
X			}
X			else		/* at beginning of string */
X			{
X				curwp->w_dotp = matchline;
X				curwp->w_doto = matchoff;
X			}
X
X			curwp->w_flag |= WFMOVE; /* flag that we have moved */
X			return TRUE;
X		}
X
X		/* Advance the cursor.
X		 */
X		nextch(&curline, &curoff, direct);
X	}
X
X	return FALSE;	/* We could not find a match.*/
X}
X
X/*
X * amatch -- Search for a meta-pattern in either direction.  Based on the
X *	recursive routine amatch() (for "anchored match") in
X *	Kernighan & Plauger's "Software Tools".
X */
Xstatic int	amatch(mcptr, direct, pcwline, pcwoff)
Xregister MC	*mcptr;	/* string to scan for */
Xint		direct;		/* which way to go.*/
XLINE		**pcwline;	/* current line during scan */
Xint		*pcwoff;	/* position within current line */
X{
X	register int c;			/* character at current position */
X	LINE *curline;			/* current line during scan */
X	int curoff;			/* position within current line */
X	int nchars;
X
X	/* Set up local scan pointers to ".", and get
X	 * the current character.  Then loop around
X	 * the pattern pointer until success or failure.
X	 */
X	curline = *pcwline;
X	curoff = *pcwoff;
X
X	/* The beginning-of-line and end-of-line metacharacters
X	 * do not compare against characters, they compare
X	 * against positions.
X	 * BOL is guaranteed to be at the start of the pattern
X	 * for forward searches, and at the end of the pattern
X	 * for reverse searches.  The reverse is true for EOL.
X	 * So, for a start, we check for them on entry.
X	 */
X	if (mcptr->mc_type == BOL)
X	{
X		if (curoff != 0)
X			return FALSE;
X		mcptr++;
X	}
X
X	if (mcptr->mc_type == EOL)
X	{
X		if (curoff != llength(curline))
X			return FALSE;
X		mcptr++;
X	}
X
X	while (mcptr->mc_type != MCNIL)
X	{
X		c = nextch(&curline, &curoff, direct);
X
X		if (mcptr->mc_type & CLOSURE)
X		{
X			/* Try to match as many characters as possible
X			 * against the current meta-character.  A
X			 * newline never matches a closure.
X			 */
X			nchars = 0;
X			while (c != '\n' && mceq(c, mcptr))
X			{
X				c = nextch(&curline, &curoff, direct);
X				nchars++;
X			}
X
X			/* We are now at the character that made us
X			 * fail.  Try to match the rest of the pattern.
X			 * Shrink the closure by one for each failure.
X			 * Since closure matches *zero* or more occurences
X			 * of a pattern, a match may start even if the
X			 * previous loop matched no characters.
X			 */
X			mcptr++;
X
X			for (;;)
X			{
X				c = nextch(&curline, &curoff, direct ^ REVERSE);
X
X				if (amatch(mcptr, direct, &curline, &curoff))
X				{
X					matchlen += nchars;
X					goto success;
X				}
X
X				if (nchars-- == 0)
X					return FALSE;
X			}
X		}
X		else			/* Not closure.*/
X		{
X			/* The only way we'd get a BOL metacharacter
X			 * at this point is at the end of the reversed pattern.
X			 * The only way we'd get an EOL metacharacter
X			 * here is at the end of a regular pattern.
X			 * So if we match one or the other, and are at
X			 * the appropriate position, we are guaranteed success
X			 * (since the next pattern character has to be MCNIL).
X			 * Before we report success, however, we back up by
X			 * one character, so as to leave the cursor in the
X			 * correct position.  For example, a search for ")$"
X			 * will leave the cursor at the end of the line, while
X			 * a search for ")<NL>" will leave the cursor at the
X			 * beginning of the next line.  This follows the
X			 * notion that the meta-character '$' (and likewise
X			 * '^') match positions, not characters.
X			 */
X			if (mcptr->mc_type == BOL)
X				if (curoff == llength(curline))
X				{
X					c = nextch(&curline, &curoff,
X						   direct ^ REVERSE);
X					goto success;
X				}
X				else
X					return FALSE;
X
X			if (mcptr->mc_type == EOL)
X				if (curoff == 0)
X				{
X					c = nextch(&curline, &curoff,
X						   direct ^ REVERSE);
X					goto success;
X				}
X				else
X					return FALSE;
X
X			/* Neither BOL nor EOL, so go through
X			 * the meta-character equal function.
X			 */
X			if (!mceq(c, mcptr))
X				return FALSE;
X		}
X
X		/* Increment the length counter and
X		 * advance the pattern pointer.
X		 */
X		matchlen++;
X		mcptr++;
X	}			/* End of mcptr loop.*/
X
X	/* A SUCCESSFULL MATCH!!!
X	 * Reset the "." pointers.
X	 */
Xsuccess:
X	*pcwline = curline;
X	*pcwoff  = curoff;
X
X	return TRUE;
X}
X#endif
X
X/*
X * scanner -- Search for a pattern in either direction.  If found,
X *	reset the "." to be at the start or just after the match string,
X *	and (perhaps) repaint the display.
X */
Xint	scanner(patrn, direct, beg_or_end)
Xunsigned char *patrn;	/* string to scan for */
Xint	direct;		/* which way to go.*/
Xint	beg_or_end;	/* put point at beginning or end of pattern.*/
X{
X	register int	c;		/* character at current position */
X	register unsigned char *patptr;	/* pointer into pattern */
X	LINE	*curline;		/* current line during scan */
X	int	curoff;			/* position within current line */
X	LINE	*scanline;		/* current line during scanning */
X	int	scanoff;		/* position in scanned line */
X
X	/* If we are going in reverse, then the 'end' is actually
X	 * the beginning of the pattern.  Toggle it.
X	 */
X	beg_or_end ^= direct;
X
X	/* Set up local pointers to global ".".
X	 */
X	curline = curwp->w_dotp;
X	curoff = curwp->w_doto;
X
X	/* Scan each character until we hit the head link record.
X	 */
X	while (!boundry(curline, curoff, direct))
X	{
X		/* Save the current position in case we match
X		 * the search string at this point.
X		 */
X		matchline = curline;
X		matchoff = curoff;
X
X		/* Get the character resolving newlines, and
X		 * test it against first char in pattern.
X		 */
X		c = nextch(&curline, &curoff, direct);
X
X		if (eq(c, patrn[0]))	/* if we find it..*/
X		{
X			/* Setup scanning pointers.
X			 */
X			scanline = curline;
X			scanoff = curoff;
X			patptr = &patrn[0];
X
X			/* Scan through the pattern for a match.
X			 */
X			while (*++patptr != '\0')
X			{
X				c = nextch(&scanline, &scanoff, direct);
X
X				if (!eq(c, *patptr))
X					goto fail;
X			}
X
X			/* A SUCCESSFULL MATCH!!!
X			 * reset the global "." pointers
X			 */
X			if (beg_or_end == PTEND)	/* at end of string */
X			{
X				curwp->w_dotp = scanline;
X				curwp->w_doto = scanoff;
X			}
X			else		/* at beginning of string */
X			{
X				curwp->w_dotp = matchline;
X				curwp->w_doto = matchoff;
X			}
X
X			curwp->w_flag |= WFMOVE; /* Flag that we have moved.*/
X			return TRUE;
X
X		}
Xfail:;			/* continue to search */
X	}
X
X	return FALSE;	/* We could not find a match */
X}
X
X/*
X * eq -- Compare two characters.  The "bc" comes from the buffer, "pc"
X *	from the pattern.  If we are not in EXACT mode, fold out the case.
X */
Xint	eq(bc, pc)
Xregister int	bc;
Xregister int	pc;
X{
X	if ((curwp->w_bufp->b_mode & MDEXACT) == 0)
X	{
X		if (islower(bc))
X			bc ^= DIFCASE;
X
X		if (islower(pc))
X			pc ^= DIFCASE;
X	}
X
X	return (bc == pc);
X}
X
X/*
X * readpattern -- Read a pattern.  Stash it in apat.  If it is the
X *	search string, create the reverse pattern and the magic
X *	pattern, assuming we are in MAGIC mode (and defined that way).
X *	Apat is not updated if the user types in an empty line.  If
X *	the user typed an empty line, and there is no old pattern, it is
X *	an error.  Display the old pattern, in the style of Jeff Lomicka.
X *	There is some do-it-yourself control expansion.  Change to using
X *	<META> to delimit the end-of-pattern to allow <NL>s in the search
X *	string. 
X */
Xstatic int	readpattern(prompt, apat, srch)
Xchar	*prompt;
Xchar	apat[];
Xint	srch;
X{
X	int status;
X	char tpat[NPAT+20];
X
X	strcpy(tpat, prompt);	/* copy prompt to output string */
X	strcat(tpat, " [");	/* build new prompt string */
X	expandp(&apat[0], &tpat[strlen(tpat)], NPAT/2);	/* add old pattern */
X	strcat(tpat, "]<META>: ");
X
X	/* Read a pattern.  Either we get one,
X	 * or we just get the META charater, and use the previous pattern.
X	 * Then, if it's the search string, make a reversed pattern.
X	 * *Then*, make the meta-pattern, if we are defined that way.
X	 */
X	if ((status = mlreplyt(tpat, tpat, NPAT, metac)) == TRUE)
X	{
X		strcpy(apat, tpat);
X		if (srch)	/* If we are doing the search string.*/
X		{
X			/* Reverse string copy, and remember
X			 * the length for substitution purposes.
X			 */
X			rvstrcpy(tap, apat);
X			mlenold = matchlen = strlen(apat);
X		}
X#if	MAGIC
X		/* Only make the meta-pattern if in magic mode,
X		 * since the pattern in question might have an
X		 * invalid meta combination.
X		 */
X		if ((curwp->w_bufp->b_mode & MDMAGIC) == 0)
X		{
X			mcclear();
X			rmcclear();
X		}
X		else
X			status = srch? mcstr(): rmcstr();
X#endif
X	}
X	else if (status == FALSE && apat[0] != 0)	/* Old one */
X		status = TRUE;
X
X	return(status);
X}
X
X/*
X * savematch -- We found the pattern?  Let's save it away.
X */
Xsavematch()
X{
X	register char	*ptr;		/* pointer to last match string */
X	register int	j;
X	LINE		*curline;	/* line of last match */
X	int		curoff;		/* offset "      "    */
X
X	/* Free any existing match string, then
X	 * attempt to allocate a new one.
X	 */
X	if (patmatch != NULL)
X		free(patmatch);
X
X	ptr = patmatch = malloc(matchlen + 1);
X
X	if (ptr != NULL)
X	{
X		curoff = matchoff;
X		curline = matchline;
X
X		for (j = 0; j < matchlen; j++)
X			*ptr++ = nextch(&curline, &curoff, FORWARD);
X
X		*ptr = '\0';
X	}
X}
X
X/*
X * rvstrcpy -- Reverse string copy.
X */
Xrvstrcpy(rvstr, str)
Xregister char	*rvstr, *str;
X{
X	register int i;
X
X	str += (i = strlen(str));
X
X	while (i-- > 0)
X		*rvstr++ = *--str;
X
X	*rvstr = '\0';
X}
X
X/*
X * sreplace -- Search and replace.
X */
Xsreplace(f, n)
Xint f;		/* default flag */
Xint n;		/* # of repetitions wanted */
X{
X	return(replaces(FALSE, f, n));
X}
X
X/*
X * qreplace -- search and replace with query.
X */
Xqreplace(f, n)
Xint f;		/* default flag */
Xint n;		/* # of repetitions wanted */
X{
X	return(replaces(TRUE, f, n));
X}
X
X/*
X * replaces -- Search for a string and replace it with another
X *	string.  Query might be enabled (according to kind).
X */
Xstatic int	replaces(kind, f, n)
Xint	kind;	/* Query enabled flag */
Xint	f;	/* default flag */
Xint	n;	/* # of repetitions wanted */
X{
X	register int status;	/* success flag on pattern inputs */
X	register int rlength;	/* length of replacement string */
X	register int numsub;	/* number of substitutions */
X	register int nummatch;	/* number of found matches */
X	int nlflag;		/* last char of search string a <NL>? */
X	int nlrepl;		/* was a replace done on the last line? */
X	char c;			/* input char for query */
X	char tpat[NPAT];	/* temporary to hold search pattern */
X	LINE *origline;		/* original "." position */
X	int origoff;		/* and offset (for . query option) */
X	LINE *lastline;		/* position of last replace and */
X	int lastoff;		/* offset (for 'u' query option) */
X
X	if (curbp->b_mode & MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X
X	/* Check for negative repetitions.
X	 */
X	if (f && n < 0)
X		return(FALSE);
X
X	/* Ask the user for the text of a pattern.
X	 */
X	if ((status = readpattern(
X	    (kind == FALSE ? "Replace" : "Query replace"), &pat[0], TRUE))
X								!= TRUE)
X		return(status);
X
X	/* Ask for the replacement string.
X	 */
X	if ((status = readpattern("with", &rpat[0], FALSE)) == ABORT)
X		return(status);
X
X	/* Find the length of the replacement string.
X	 */
X	rlength = strlen(&rpat[0]);
X
X	/* Set up flags so we can make sure not to do a recursive
X	 * replace on the last line.
X	 */
X	nlflag = (pat[matchlen - 1] == '\n');
X	nlrepl = FALSE;
X
X	if (kind)
X	{
X		/* Build query replace question string.
X		 */
X		strcpy(tpat, "Replace '");
X		expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3);
X		strcat(tpat, "' with '");
X		expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3);
X		strcat(tpat, "'? ");
X
X		/* Initialize last replaced pointers.
X		 */
X		lastline = NULL;
X		lastoff = 0;
X	}
X
X	/* Save original . position, init the number of matches and
X	 * substitutions, and scan through the file.
X	 */
X	origline = curwp->w_dotp;
X	origoff = curwp->w_doto;
X	numsub = 0;
X	nummatch = 0;
X
X	while ( (f == FALSE || n > nummatch) &&
X		(nlflag == FALSE || nlrepl == FALSE) )
X	{
X		/* Search for the pattern.
X		 * If we search with a regular expression,
X		 * matchlen is reset to the true length of
X		 * the matched string.
X		 */
X#if	MAGIC
X		if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
X		{
X			if (!mcscanner(&mcpat[0], FORWARD, PTBEG))
X				break;
X		}
X		else
X#endif
X			if (!scanner(&pat[0], FORWARD, PTBEG))
X				break;		/* all done */
X
X		++nummatch;	/* Increment # of matches */
X
X		/* Check if we are on the last line.
X		 */
X		nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
X
X		/* Check for query.
X		 */
X		if (kind)
X		{
X			/* Get the query.
X			 */
Xpprompt:		mlwrite(&tpat[0], &pat[0], &rpat[0]);
Xqprompt:
X			update(TRUE);  /* show the proposed place to change */
X			c = tgetc();			/* and input */
X			mlwrite("");			/* and clear it */
X
X			/* And respond appropriately.
X			 */
X			switch (c)
X			{
X				case 'y':	/* yes, substitute */
X				case ' ':
X					savematch();
X					break;
X
X				case 'n':	/* no, onword */
X					forwchar(FALSE, 1);
X					continue;
X
X				case '!':	/* yes/stop asking */
X					kind = FALSE;
X					break;
X
X				case 'u':	/* undo last and re-prompt */
X
X					/* Restore old position.
X					 */
X					if (lastline == NULL)
X					{
X						/* There is nothing to undo.
X						 */
X						TTbeep();
X						goto pprompt;
X					}
X					curwp->w_dotp = lastline;
X					curwp->w_doto = lastoff;
X					lastline = NULL;
X					lastoff = 0;
X
X					/* Delete the new string.
X					 */
X					backchar(FALSE, rlength);
X					status = delins(rlength, patmatch, FALSE);
X					if (status != TRUE)
X						return (status);
X
X					/* Record one less substitution,
X					 * backup, save our place, and
X					 * reprompt.
X					 */
X					--numsub;
X					backchar(FALSE, mlenold);
X					matchline = curwp->w_dotp;
X					matchoff  = curwp->w_doto;
X					goto pprompt;
X
X				case '.':	/* abort! and return */
X					/* restore old position */
X					curwp->w_dotp = origline;
X					curwp->w_doto = origoff;
X					curwp->w_flag |= WFMOVE;
X
X				case BELL:	/* abort! and stay */
X					mlwrite("Aborted!");
X					return(FALSE);
X
X				default:	/* bitch and beep */
X					TTbeep();
X
X				case '?':	/* help me */
X					mlwrite(
X"(Y)es, (N)o, (!)Do rest, (U)ndo last, (^G)Abort, (.)Abort back, (?)Help: ");
X					goto qprompt;
X
X			}	/* end of switch */
X		}	/* end of "if kind" */
X
X		/*
X		 * Delete the sucker, and insert its
X		 * replacement.
X		 */
X		status = delins(matchlen, &rpat[0], TRUE);
X		if (status != TRUE)
X			return (status);
X
X		/* Save our position, since we may
X		 * undo this.
X		 */
X		if (kind)
X		{
X			lastline = curwp->w_dotp;
X			lastoff = curwp->w_doto;
X		}
X
X		numsub++;	/* increment # of substitutions */
X	}
X
X	/* And report the results.
X	 */
X	mlwrite("%d substitutions", numsub);
X	return(TRUE);
X}
X
X/*
X * delins -- Delete a specified length from the current point
X *	then either insert the string directly, or make use of
X *	replacement meta-array.
X */
Xdelins(dlength, instr, use_meta)
Xint	dlength;
Xchar	*instr;
Xint	use_meta;
X{
X	int	status;
X#if	MAGIC
X	RMC	*rmcptr;
X#endif
X
X	/* Zap what we gotta,
X	 * and insert its replacement.
X	 */
X	if ((status = ldelete((long) dlength, FALSE)) != TRUE)
X		mlwrite("%%ERROR while deleting");
X	else
X#if	MAGIC
X		if ((rmagical && use_meta) &&
X		     (curwp->w_bufp->b_mode & MDMAGIC) != 0) {
X			rmcptr = &rmcpat[0];
X			while (rmcptr->mc_type != MCNIL && status == TRUE) {
X				if (rmcptr->mc_type == LITCHAR)
X					status = linstr(rmcptr->rstr);
X				else
X					status = linstr(patmatch);
X				rmcptr++;
X			}
X		} else
X#endif
X			status = linstr(instr);
X
X	return(status);
X}
X
X/*
X * expandp -- Expand control key sequences for output.
X */
Xexpandp(srcstr, deststr, maxlength)
Xchar	*srcstr;	/* string to expand */
Xchar	*deststr;	/* destination of expanded string */
Xint	maxlength;	/* maximum chars in destination */
X{
X	unsigned char c;	/* current char to translate */
X
X	/* Scan through the string.
X	 */
X	while ((c = *srcstr++) != 0)
X	{
X		if (c == '\n')		/* it's a newline */
X		{
X			*deststr++ = '<';
X			*deststr++ = 'N';
X			*deststr++ = 'L';
X			*deststr++ = '>';
X			maxlength -= 4;
X		}
X		else if (c < 0x20 || c == 0x7f)	/* control character */
X		{
X			*deststr++ = '^';
X			*deststr++ = c ^ 0x40;
X			maxlength -= 2;
X		}
X		else if (c == '%')
X		{
X			*deststr++ = '%';
X			*deststr++ = '%';
X			maxlength -= 2;
X		}
X		else			/* any other character */
X		{
X			*deststr++ = c;
X			maxlength--;
X		}
X
X		/* check for maxlength */
X		if (maxlength < 4)
X		{
X			*deststr++ = '$';
X			*deststr = '\0';
X			return(FALSE);
X		}
X	}
X	*deststr = '\0';
X	return(TRUE);
X}
X
X/*
X * boundry -- Return information depending on whether we may search no
X *	further.  Beginning of file and end of file are the obvious
X *	cases, but we may want to add further optional boundry restrictions
X *	in future, a' la VMS EDT.  At the moment, just return TRUE or
X *	FALSE depending on if a boundry is hit (ouch).
X */
Xint	boundry(curline, curoff, dir)
XLINE	*curline;
Xint	curoff, dir;
X{
X	register int	border;
X
X	if (dir == FORWARD)
X	{
X		border = (curoff == llength(curline)) &&
X			 (lforw(curline) == curbp->b_linep);
X	}
X	else
X	{
X		border = (curoff == 0) &&
X			 (lback(curline) == curbp->b_linep);
X	}
X	return (border);
X}
X
X/*
X * nextch -- retrieve the next/previous character in the buffer,
X *	and advance/retreat the point.
X *	The order in which this is done is significant, and depends
X *	upon the direction of the search.  Forward searches look at
X *	the current character and move, reverse searches move and
X *	look at the character.
X */
Xstatic int nextch(pcurline, pcuroff, dir)
XLINE	**pcurline;
Xint	*pcuroff;
Xint	dir;
X{
X	register LINE	*curline;
X	register int	curoff;
X	register int	c;
X
X	curline = *pcurline;
X	curoff = *pcuroff;
X
X	if (dir == FORWARD)
X	{
X		if (curoff == llength(curline))		/* if at EOL */
X		{
X			curline = lforw(curline);	/* skip to next line */
X			curoff = 0;
X			c = '\n';			/* and return a <NL> */
X		}
X		else
X			c = lgetc(curline, curoff++);	/* get the char */
X	}
X	else			/* Reverse.*/
X	{
X		if (curoff == 0)
X		{
X			curline = lback(curline);
X			curoff = llength(curline);
X			c = '\n';
X		}
X		else
X			c = lgetc(curline, --curoff);
X
X	}
X	*pcurline = curline;
X	*pcuroff = curoff;
X
X	return (c);
X}
X
X#if	MAGIC
X/*
X * mcstr -- Set up the 'magic' array.  The closure symbol is taken as
X *	a literal character when (1) it is the first character in the
X *	pattern, and (2) when preceded by a symbol that does not allow
X *	closure, such as a newline, beginning of line symbol, or another
X *	closure symbol.
X *
X *	Coding comment (jmg):  yes, i know i have gotos that are, strictly
X *	speaking, unnecessary.  But right now we are so cramped for
X *	code space that i will grab what i can in order to remain
X *	within the 64K limit.  C compilers actually do very little
X *	in the way of optimizing - they expect you to do that.
X */
Xstatic int mcstr()
X{
X	MC	*mcptr, *rtpcm;
X	char	*patptr;
X 	int	mj;
X 	int	pchr;
X 	int	status = TRUE;
X 	int	does_closure = FALSE;
X
X	/* If we had metacharacters in the MC array previously,
X	 * free up any bitmaps that may have been allocated.
X	 */
X	if (magical)
X		mcclear();
X
X	magical = FALSE;
X	mj = 0;
X	mcptr = &mcpat[0];
X	patptr = &pat[0];
X
X	while ((pchr = *patptr) && status)
X	{
X		switch (pchr)
X		{
X			case MC_CCL:
X				status = cclmake(&patptr, mcptr);
X				magical = TRUE;
X				does_closure = TRUE;
X				break;
X			case MC_BOL:
X				if (mj != 0)
X					goto litcase;
X
X				mcptr->mc_type = BOL;
X				magical = TRUE;
X				does_closure = FALSE;
X				break;
X			case MC_EOL:
X				if (*(patptr + 1) != '\0')
X					goto litcase;
X
X				mcptr->mc_type = EOL;
X				magical = TRUE;
X				does_closure = FALSE;
X				break;
X			case MC_ANY:
X				mcptr->mc_type = ANY;
X				magical = TRUE;
X				does_closure = TRUE;
X				break;
X			case MC_CLOSURE:
X				/* Does the closure symbol mean closure here?
X				 * If so, back up to the previous element
X				 * and indicate it is enclosed.
X				 */
X				if (!does_closure)
X					goto litcase;
X				mj--;
X				mcptr--;
X				mcptr->mc_type |= CLOSURE;
X				magical = TRUE;
X				does_closure = FALSE;
X				break;
X
X			/* Note: no break between MC_ESC case and the default.
X			 */
X			case MC_ESC:
X				if (*(patptr + 1) != '\0')
X				{
X					pchr = *++patptr;
X					magical = TRUE;
X				}
X			default:
Xlitcase:			mcptr->mc_type = LITCHAR;
X				mcptr->u.lchar = pchr;
X				does_closure = (pchr != '\n');
X				break;
X		}		/* End of switch.*/
X		mcptr++;
X		patptr++;
X		mj++;
X	}		/* End of while.*/
X
X	/* Close off the meta-string.
X	 */
X	mcptr->mc_type = MCNIL;
X
X	/* Set up the reverse array, if the status is good.  Please note the
X	 * structure assignment - your compiler may not like that.
X	 * If the status is not good, nil out the meta-pattern.
X	 * The only way the status would be bad is from the cclmake()
X	 * routine, and the bitmap for that member is guarenteed to be
X	 * freed.  So we stomp a MCNIL value there, and call mcclear()
X	 * to free any other bitmaps.
X	 */
X	if (status)
X	{
X		rtpcm = &tapcm[0];
X		while (--mj >= 0)
X		{
X#if	LATTICE
X			movmem(--mcptr, rtpcm++, sizeof (MC));
X#endif
X
X#if	MWC86 | AZTEC | MSC | TURBO | VMS | USG | BSD | V7
X			*rtpcm++ = *--mcptr;
X#endif
X		}
X		rtpcm->mc_type = MCNIL;
X	}
X	else
X	{
X		(--mcptr)->mc_type = MCNIL;
X		mcclear();
X	}
X
X	return(status);
X}
X
X/*
X * rmcstr -- Set up the replacement 'magic' array.  Note that if there
X *	are no meta-characters encountered in the replacement string,
X *	the array is never actually created - we will just use the
X *	character array rpat[] as the replacement string.
X */
Xstatic int rmcstr()
X{
X	RMC	*rmcptr;
X	char	*patptr;
X	int	status = TRUE;
X	int	mj;
X
X	patptr = &rpat[0];
X	rmcptr = &rmcpat[0];
X	mj = 0;
X	rmagical = FALSE;
X
X	while (*patptr && status == TRUE)
X	{
X		switch (*patptr)
X		{
X			case MC_DITTO:
X
X				/* If there were non-magical characters
X				 * in the string before reaching this
X				 * character, plunk it in the replacement
X				 * array before processing the current
X				 * meta-character.
X				 */
X				if (mj != 0)
X				{
X					rmcptr->mc_type = LITCHAR;
X					if ((rmcptr->rstr = malloc(mj + 1)) == NULL)
X					{
X						mlwrite("%%Out of memory");
X						status = FALSE;
X						break;
X					}
X					strncpy(rmcptr->rstr, patptr - mj, mj);
X					rmcptr++;
X					mj = 0;
X				}
X				rmcptr->mc_type = DITTO;
X				rmcptr++;
X				rmagical = TRUE;
X				break;
X
X			case MC_ESC:
X				rmcptr->mc_type = LITCHAR;
X
X				/* We malloc mj plus two here, instead
X				 * of one, because we have to count the
X				 * current character.
X				 */
X				if ((rmcptr->rstr = malloc(mj + 2)) == NULL)
X				{
X					mlwrite("%%Out of memory");
X					status = FALSE;
X					break;
X				}
X
X				strncpy(rmcptr->rstr, patptr - mj, mj + 1);
X
X				/* If MC_ESC is not the last character
X				 * in the string, find out what it is
X				 * escaping, and overwrite the last
X				 * character with it.
X				 */
X				if (*(patptr + 1) != '\0')
X					*((rmcptr->rstr) + mj) = *++patptr;
X
X				rmcptr++;
X				mj = 0;
X				rmagical = TRUE;
X				break;
X
X			default:
X				mj++;
X		}
X		patptr++;
X	}
X
X	if (rmagical && mj > 0)
X	{
X		rmcptr->mc_type = LITCHAR;
X		if ((rmcptr->rstr = malloc(mj + 1)) == NULL)
X		{
X			mlwrite("%%Out of memory.");
X			status = FALSE;
X		}
X		strncpy(rmcptr->rstr, patptr - mj, mj);
X		rmcptr++;
X	}
X
X	rmcptr->mc_type = MCNIL;
X}
X
X/*
X * mcclear -- Free up any CCL bitmaps, and MCNIL the MC search arrays.
X */
Xmcclear()
X{
X	register MC	*mcptr;
X
X	mcptr = &mcpat[0];
X
X	while (mcptr->mc_type != MCNIL)
X	{
X		if ((mcptr->mc_type & MASKCL) == CCL ||
X		    (mcptr->mc_type & MASKCL) == NCCL)
X			free(mcptr->u.cclmap);
X		mcptr++;
X	}
X	mcpat[0].mc_type = tapcm[0].mc_type = MCNIL;
X}
X
X/*
X * rmcclear -- Free up any strings, and MCNIL the RMC array.
X */
Xrmcclear()
X{
X	register RMC	*rmcptr;
X
X	rmcptr = &rmcpat[0];
X
X	while (rmcptr->mc_type != MCNIL)
X	{
X		if (rmcptr->mc_type == LITCHAR)
X			free(rmcptr->rstr);
X		rmcptr++;
X	}
X
X	rmcpat[0].mc_type = MCNIL;
X}
X
X/*
X * mceq -- meta-character equality with a character.  In Kernighan & Plauger's
X *	Software Tools, this is the function omatch(), but i felt there
X *	were too many functions with the 'match' name already.
X */
Xstatic int	mceq(bc, mt)
Xint	bc;
XMC	*mt;
X{
X	register int result;
X
X	switch (mt->mc_type & MASKCL)
X	{
X		case LITCHAR:
X			result = eq(bc, mt->u.lchar);
X			break;
X
X		case ANY:
X			result = (bc != '\n');
X			break;
X
X		case CCL:
X			if (!(result = biteq(bc, mt->u.cclmap)))
X			{
X				if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
X				    (isletter(bc)))
X				{
X					result = biteq(CHCASE(bc), mt->u.cclmap);
X				}
X			}
X			break;
X
X		case NCCL:
X			result = !biteq(bc, mt->u.cclmap);
X
X			if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
X			    (isletter(bc)))
X			{
X				result &= !biteq(CHCASE(bc), mt->u.cclmap);
X			}
X			break;
X
X		default:
X			mlwrite("mceq: what is %d?", mt->mc_type);
X			result = FALSE;
X			break;
X
X	}	/* End of switch.*/
X
X	return (result);
X}
X
X/*
X * cclmake -- create the bitmap for the character class.
X *	ppatptr is left pointing to the end-of-character-class character,
X *	so that a loop may automatically increment with safety.
X */
Xstatic int	cclmake(ppatptr, mcptr)
Xchar	**ppatptr;
XMC	*mcptr;
X{
X	BITMAP		clearbits();
X	BITMAP		bmap;
X	register char	*patptr;
X	register int	pchr, ochr;
X
X	if ((bmap = clearbits()) == NULL)
X	{
X		mlwrite("%%Out of memory");
X		return FALSE;
X	}
X
X	mcptr->u.cclmap = bmap;
X	patptr = *ppatptr;
X
X	/*
X	 * Test the initial character(s) in ccl for
X	 * special cases - negate ccl, or an end ccl
X	 * character as a first character.  Anything
X	 * else gets set in the bitmap.
X	 */
X	if (*++patptr == MC_NCCL)
X	{
X		patptr++;
X		mcptr->mc_type = NCCL;
X	}
X	else
X		mcptr->mc_type = CCL;
X
X	if ((ochr = *patptr) == MC_ECCL)
X	{
X		mlwrite("%%No characters in character class");
X		return (FALSE);
X	}
X	else
X	{
X		if (ochr == MC_ESC)
X			ochr = *++patptr;
X
X		setbit(ochr, bmap);
X		patptr++;
X	}
X
X	while (ochr != '\0' && (pchr = *patptr) != MC_ECCL)
X	{
X		switch (pchr)
X		{
X			/* Range character loses its meaning
X			 * if it is the last character in
X			 * the class.
X			 */
X			case MC_RCCL:
X				if (*(patptr + 1) == MC_ECCL)
X					setbit(pchr, bmap);
X				else
X				{
X					pchr = *++patptr;
X					while (++ochr <= pchr)
X						setbit(ochr, bmap);
X				}
X				break;
X
X			/* Note: no break between case MC_ESC and the default.
X			 */
X			case MC_ESC:
X				pchr = *++patptr;
X			default:
X				setbit(pchr, bmap);
X				break;
X		}
X		patptr++;
X		ochr = pchr;
X	}
X
X	*ppatptr = patptr;
X
X	if (ochr == '\0')
X	{
X		mlwrite("%%Character class not ended");
X		free(bmap);
X		return FALSE;
X	}
X	return TRUE;
X}
X
X/*
X * biteq -- is the character in the bitmap?
X */
Xstatic int	biteq(bc, cclmap)
Xint	bc;
XBITMAP	cclmap;
X{
X	if (bc >= HICHAR)
X		return FALSE;
X
X	return( (*(cclmap + (bc >> 3)) & BIT(bc & 7))? TRUE: FALSE );
X}
X
X/*
X * clearbits -- Allocate and zero out a CCL bitmap.
X */
Xstatic	BITMAP clearbits()
X{
X	char		*malloc();
X
X	BITMAP		cclstart, cclmap;
X	register int	j;
X
X	if ((cclmap = cclstart = (BITMAP) malloc(HIBYTE)) != NULL)
X		for (j = 0; j < HIBYTE; j++)
X			*cclmap++ = 0;
X
X	return (cclstart);
X}
X
X/*
X * setbit -- Set a bit (ON only) in the bitmap.
X */
Xstatic void setbit(bc, cclmap)
Xint	bc;
XBITMAP	cclmap;
X{
X	if (bc < HICHAR)
X		*(cclmap + (bc >> 3)) |= BIT(bc & 7);
X}
X#endif
FRIDAY_NIGHT
echo mes.10 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/17/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.11')
# If you do not see the message
#	`mes.11 completed!'
# then the file was incomplete.
echo extracting - spawn.c
sed 's/^X//' > spawn.c << 'FRIDAY_NIGHT'
X/*	Spawn:	various DOS access commands
X		for MicroEMACS
X*/
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X#if     AMIGA
X#define  NEW   1006L
X#endif
X
X#if     VMS
X#define EFN     0                               /* Event flag.          */
X
X#include        <ssdef.h>                       /* Random headers.      */
X#include        <stsdef.h>
X#include        <descrip.h>
X#include        <iodef.h>
X
Xextern  int     oldmode[3];                     /* In "termio.c"        */
Xextern  int     newmode[3];                     /* In "termio.c"        */
Xextern  short   iochan;                         /* In "termio.c"        */
X#endif
X
X#if     V7 | USG | BSD
X#include        <signal.h>
Xextern int vttidy();
X#endif
X
X#if	MSDOS & (MSC | TURBO)
X#include	<process.h>
X#endif
X
X/*
X * Create a subjob with a copy of the command intrepreter in it. When the
X * command interpreter exits, mark the screen as garbage so that you do a full
X * repaint. Bound to "^X C". The message at the start in VMS puts out a newline.
X * Under some (unknown) condition, you don't get one free when DCL starts up.
X */
Xspawncli(f, n)
X{
X#if     AMIGA
X        long newcli;
X
X#endif
X
X#if     V7 | USG | BSD
X        register char *cp;
X        char    *getenv();
X#endif
X
X	/* don't allow this command if restricted */
X	if (restflag)
X		return(resterr());
X
X#if	AMIGA
X        mlwrite("[Starting new CLI]");
X        sgarbf = TRUE;
X        Execute("NEWCLI \"CON:0/0/640/200/MicroEMACS Subprocess\"", 0L, 0L);
X        return(TRUE);
X#endif
X
X#if     VMS
X        movecursor(term.t_nrow, 0);             /* In last line.        */
X        mlputs("[Starting DCL]\r\n");
X        TTflush(); 	                     /* Ignore "ttcol".      */
X        sgarbf = TRUE;
X        return (sys(NULL));                     /* NULL => DCL.         */
X#endif
X#if     CPM
X        mlwrite("Not in CP/M-86");
X#endif
X#if     MSDOS & (AZTEC | MSC | TURBO)
X        movecursor(term.t_nrow, 0);             /* Seek to last line.   */
X        TTflush();
X	TTkclose();
X	shellprog("");
X	TTkopen();
X        sgarbf = TRUE;
X        return(TRUE);
X#endif
X#if     ST520 & MWC
X	mlerase();	/* clear the message line */
X        TTflush();
X	TTkclose();
X	system("msh.prg");
X	TTkopen();
X        sgarbf = TRUE;
X        return(TRUE);
X#endif
X#if     MSDOS & LATTICE
X        movecursor(term.t_nrow, 0);             /* Seek to last line.   */
X        TTflush();
X	TTkclose();
X        sys("\\command.com", "");               /* Run CLI.             */
X	TTkopen();
X        sgarbf = TRUE;
X        return(TRUE);
X#endif
X#if     V7 | USG | BSD
X        movecursor(term.t_nrow, 0);             /* Seek to last line.   */
X        TTflush();
X        TTclose();                              /* stty to old settings */
X        if ((cp = getenv("SHELL")) != NULL && *cp != '\0')
X                system(cp);
X        else
X#if	BSD
X                system("exec /bin/csh");
X#else
X                system("exec /bin/sh");
X#endif
X        sgarbf = TRUE;
X	sleep(2);
X        TTopen();
X        return(TRUE);
X#endif
X}
X
X#if	BSD
X
Xbktoshell()		/* suspend MicroEMACS and wait to wake up */
X{
X	int pid;
X
X	vttidy();
X	pid = getpid();
X	kill(pid,SIGTSTP);
X}
X
Xrtfrmshell()
X{
X	TTopen();
X	curwp->w_flag = WFHARD;
X	sgarbf = TRUE;
X}
X#endif
X
X/*
X * Run a one-liner in a subjob. When the command returns, wait for a single
X * character to be typed, then mark the screen as garbage so a full repaint is
X * done. Bound to "C-X !".
X */
Xspawn(f, n)
X{
X        register int    s;
X        char            line[NLINE];
X
X#if     AMIGA
X        long newcli;
X#endif
X
X	/* don't allow this command if restricted */
X	if (restflag)
X		return(resterr());
X
X#if	AMIGA
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return (s);
X        newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
X        Execute(line, 0L, newcli);
X        Close(newcli);
X        tgetc();     /* Pause.               */
X        sgarbf = TRUE;
X        return(TRUE);
X#endif
X
X#if     VMS
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return (s);
X        TTputc('\n');                /* Already have '\r'    */
X        TTflush();
X        s = sys(line);                          /* Run the command.     */
X        mlputs("\r\n\n[End]");                  /* Pause.               */
X        TTflush();
X        tgetc();
X        sgarbf = TRUE;
X        return (s);
X#endif
X#if     CPM
X        mlwrite("Not in CP/M-86");
X        return (FALSE);
X#endif
X#if     MSDOS
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return(s);
X	movecursor(term.t_nrow - 1, 0);
X	TTkclose();
X        shellprog(line);
X	TTkopen();
X	/* if we are interactive, pause here */
X	if (clexec == FALSE) {
X	        mlputs("\r\n\n[End]");
X        	tgetc();
X        }
X        sgarbf = TRUE;
X        return (TRUE);
X#endif
X#if     ST520 & MWC
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return(s);
X	mlerase();
X	TTkclose();
X        system(line);
X	TTkopen();
X	/* if we are interactive, pause here */
X	if (clexec == FALSE) {
X	        mlputs("\r\n\n[End]");
X        	tgetc();
X        }
X        sgarbf = TRUE;
X        return (TRUE);
X#endif
X#if     V7 | USG | BSD
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return (s);
X        TTputc('\n');                /* Already have '\r'    */
X        TTflush();
X        TTclose();                              /* stty to old modes    */
X        system(line);
X        TTopen();
X        mlputs("[End]");                        /* Pause.               */
X        TTflush();
X        while ((s = tgetc()) != '\r' && s != ' ')
X                ;
X        sgarbf = TRUE;
X        return (TRUE);
X#endif
X}
X
X/*
X * Run an external program with arguments. When it returns, wait for a single
X * character to be typed, then mark the screen as garbage so a full repaint is
X * done. Bound to "C-X $".
X */
X
Xexecprg(f, n)
X
X{
X        register int    s;
X        char            line[NLINE];
X
X#if     AMIGA
X        long newcli;
X#endif
X
X	/* don't allow this command if restricted */
X	if (restflag)
X		return(resterr());
X
X#if	AMIGA
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return (s);
X        newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
X        Execute(line, 0L, newcli);
X        Close(newcli);
X        tgetc();     /* Pause.               */
X        sgarbf = TRUE;
X        return(TRUE);
X#endif
X
X#if     VMS
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return (s);
X        TTputc('\n');                /* Already have '\r'    */
X        TTflush();
X        s = sys(line);                          /* Run the command.     */
X        mlputs("\r\n\n[End]");                  /* Pause.               */
X        TTflush();
X        tgetc();
X        sgarbf = TRUE;
X        return (s);
X#endif
X#if     CPM
X        mlwrite("Not in CP/M-86");
X        return (FALSE);
X#endif
X#if     MSDOS
X        if ((s=mlreply("$", line, NLINE)) != TRUE)
X                return(s);
X	movecursor(term.t_nrow - 1, 0);
X	TTkclose();
X        execprog(line);
X	TTkopen();
X	/* if we are interactive, pause here */
X	if (clexec == FALSE) {
X	        mlputs("\r\n\n[End]");
X        	tgetc();
X        }
X        sgarbf = TRUE;
X        return (TRUE);
X#endif
X#if     ST520 & MWC
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return(s);
X	mlerase();
X	TTkclose();
X        system(line);
X	TTkopen();
X	/* if we are interactive, pause here */
X	if (clexec == FALSE) {
X	        mlputs("\r\n\n[End]");
X        	tgetc();
X        }
X        sgarbf = TRUE;
X        return (TRUE);
X#endif
X#if     V7 | USG | BSD
X        if ((s=mlreply("!", line, NLINE)) != TRUE)
X                return (s);
X        TTputc('\n');                /* Already have '\r'    */
X        TTflush();
X        TTclose();                              /* stty to old modes    */
X        system(line);
X        TTopen();
X        mlputs("[End]");                        /* Pause.               */
X        TTflush();
X        while ((s = tgetc()) != '\r' && s != ' ')
X                ;
X        sgarbf = TRUE;
X        return (TRUE);
X#endif
X}
X
X/*
X * Pipe a one line command into a window
X * Bound to ^X @
X */
Xpipecmd(f, n)
X{
X        register int    s;	/* return status from CLI */
X	register WINDOW *wp;	/* pointer to new window */
X	register BUFFER *bp;	/* pointer to buffer to zot */
X        char	line[NLINE];	/* command line send to shell */
X	static char bname[] = "command";
X
X#if	AMIGA
X	static char filnam[] = "ram:command";
X        long newcli;
X#else
X	static char filnam[NSTRING] = "command";
X#endif
X
X#if     MSDOS | (ST520 & MWC)
X	char *tmp;
X	char *getenv();
X	FILE *fp;
X	FILE *fopen();
X#endif
X
X	/* don't allow this command if restricted */
X	if (restflag)
X		return(resterr());
X
X#if	MSDOS
X	if ((tmp = getenv("TMP")) == NULL)
X		strcpy(filnam, "command");
X	else {
X		strcpy(filnam, tmp);
X                strcat(filnam,"\\command");
X        }
X#endif
X
X#if     VMS
X	mlwrite("Not availible under VMS");
X	return(FALSE);
X#endif
X#if     CPM
X        mlwrite("Not availible under CP/M-86");
X        return(FALSE);
X#endif
X
X	/* get the command to pipe in */
X        if ((s=mlreply("@", line, NLINE)) != TRUE)
X                return(s);
X
X	/* get rid of the command output buffer if it exists */
X        if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
X		/* try to make sure we are off screen */
X		wp = wheadp;
X		while (wp != NULL) {
X			if (wp->w_bufp == bp) {
X				onlywind(FALSE, 1);
X				break;
X			}
X			wp = wp->w_wndp;
X		}
X		if (zotbuf(bp) != TRUE)
X
X			return(FALSE);
X	}
X
X#if     AMIGA
X        newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
X	strcat(line, " >");
X	strcat(line, filnam);
X        Execute(line, 0L, newcli);
X	s = TRUE;
X        Close(newcli);
X        sgarbf = TRUE;
X#endif
X#if     MSDOS | (ST520 & MWC)
X	strcat(line," >>");
X	strcat(line,filnam);
X	movecursor(term.t_nrow - 1, 0);
X	TTkclose();
X#if	MSDOS
X        shellprog(line);
X#else
X	system(line);
X#endif
X	TTkopen();
X        sgarbf = TRUE;
X	if ((fp = fopen(filnam, "r")) == NULL) {
X		s = FALSE;
X	} else {
X		fclose(fp);
X		s = TRUE;
X	}
X#endif
X#if     V7 | USG | BSD
X        TTputc('\n');                /* Already have '\r'    */
X        TTflush();
X        TTclose();                              /* stty to old modes    */
X	strcat(line,">");
X	strcat(line,filnam);
X        system(line);
X        TTopen();
X        TTflush();
X        sgarbf = TRUE;
X        s = TRUE;
X#endif
X
X	if (s != TRUE)
X		return(s);
X
X	/* split the current window to make room for the command output */
X	if (splitwind(FALSE, 1) == FALSE)
X			return(FALSE);
X
X	/* and read the stuff in */
X	if (getfile(filnam, FALSE) == FALSE)
X		return(FALSE);
X
X	/* make this window in VIEW mode, update all mode lines */
X	curwp->w_bufp->b_mode |= MDVIEW;
X	wp = wheadp;
X	while (wp != NULL) {
X		wp->w_flag |= WFMODE;
X		wp = wp->w_wndp;
X	}
X
X	/* and get rid of the temporary file */
X	unlink(filnam);
X	return(TRUE);
X}
X
X/*
X * filter a buffer through an external DOS program
X * Bound to ^X #
X */
Xfilter(f, n)
X
X{
X        register int    s;	/* return status from CLI */
X	register BUFFER *bp;	/* pointer to buffer to zot */
X        char line[NLINE];	/* command line send to shell */
X	char tmpnam[NFILEN];	/* place to store real file name */
X	static char bname1[] = "fltinp";
X
X#if	AMIGA
X	static char filnam1[] = "ram:fltinp";
X	static char filnam2[] = "ram:fltout";
X        long newcli;
X#else
X	static char filnam1[] = "fltinp";
X	static char filnam2[] = "fltout";
X#endif
X
X	/* don't allow this command if restricted */
X	if (restflag)
X		return(resterr());
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X
X#if     VMS
X	mlwrite("Not availible under VMS");
X	return(FALSE);
X#endif
X#if     CPM
X        mlwrite("Not availible under CP/M-86");
X        return(FALSE);
X#endif
X
X	/* get the filter name and its args */
X        if ((s=mlreply("#", line, NLINE)) != TRUE)
X                return(s);
X
X	/* setup the proper file names */
X	bp = curbp;
X	strcpy(tmpnam, bp->b_fname);	/* save the original name */
X	strcpy(bp->b_fname, bname1);	/* set it to our new one */
X
X	/* write it out, checking for errors */
X	if (writeout(filnam1) != TRUE) {
X		mlwrite("[Cannot write filter file]");
X		strcpy(bp->b_fname, tmpnam);
X		return(FALSE);
X	}
X
X#if     AMIGA
X        newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
X	strcat(line, " <ram:fltinp >ram:fltout");
X        Execute(line,0L,newcli);
X	s = TRUE;
X        Close(newcli);
X        sgarbf = TRUE;
X#endif
X#if     MSDOS | (ST520 & MWC)
X	strcat(line," <fltinp >fltout");
X	movecursor(term.t_nrow - 1, 0);
X	TTkclose();
X#if	MSDOS
X        shellprog(line);
X#else
X	system(line);
X#endif
X	TTkopen();
X        sgarbf = TRUE;
X	s = TRUE;
X#endif
X#if     V7 | USG | BSD
X        TTputc('\n');                /* Already have '\r'    */
X        TTflush();
X        TTclose();                              /* stty to old modes    */
X	strcat(line," <fltinp >fltout");
X        system(line);
X        TTopen();
X        TTflush();
X        sgarbf = TRUE;
X        s = TRUE;
X#endif
X
X	/* on failure, escape gracefully */
X	if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
X		mlwrite("[Execution failed]");
X		strcpy(bp->b_fname, tmpnam);
X		unlink(filnam1);
X		unlink(filnam2);
X		return(s);
X	}
X
X	/* reset file name */
X	strcpy(bp->b_fname, tmpnam);	/* restore name */
X	bp->b_flag |= BFCHG;		/* flag it as changed */
X
X	/* and get rid of the temporary file */
X	unlink(filnam1);
X	unlink(filnam2);
X	return(TRUE);
X}
X
X#if     VMS
X/*
X * Run a command. The "cmd" is a pointer to a command string, or NULL if you
X * want to run a copy of DCL in the subjob (this is how the standard routine
X * LIB$SPAWN works. You have to do wierd stuff with the terminal on the way in
X * and the way out, because DCL does not want the channel to be in raw mode.
X */
Xsys(cmd)
Xregister char   *cmd;
X{
X        struct  dsc$descriptor  cdsc;
X        struct  dsc$descriptor  *cdscp;
X        long    status;
X        long    substatus;
X        long    iosb[2];
X
X        status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
X                          oldmode, sizeof(oldmode), 0, 0, 0, 0);
X        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
X                return (FALSE);
X        cdscp = NULL;                           /* Assume DCL.          */
X        if (cmd != NULL) {                      /* Build descriptor.    */
X                cdsc.dsc$a_pointer = cmd;
X                cdsc.dsc$w_length  = strlen(cmd);
X                cdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
X                cdsc.dsc$b_class   = DSC$K_CLASS_S;
X                cdscp = &cdsc;
X        }
X        status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
X        if (status != SS$_NORMAL)
X                substatus = status;
X        status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
X                          newmode, sizeof(newmode), 0, 0, 0, 0);
X        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
X                return (FALSE);
X        if ((substatus&STS$M_SUCCESS) == 0)     /* Command failed.      */
X                return (FALSE);
X        return (TRUE);
X}
X#endif
X
X#if	~AZTEC & ~MSC & ~TURBO & MSDOS
X
X/*
X * This routine, once again by Bob McNamara, is a C translation of the "system"
X * routine in the MWC-86 run time library. It differs from the "system" routine
X * in that it does not unconditionally append the string ".exe" to the end of
X * the command name. We needed to do this because we want to be able to spawn
X * off "command.com". We really do not understand what it does, but if you don't
X * do it exactly "malloc" starts doing very very strange things.
X */
Xsys(cmd, tail)
Xchar    *cmd;
Xchar    *tail;
X{
X#if MWC
X        register unsigned n;
X        extern   char     *__end;
X
X        n = __end + 15;
X        n >>= 4;
X        n = ((n + dsreg() + 16) & 0xFFF0) + 16;
X        return(execall(cmd, tail, n));
X#endif
X
X#if LATTICE
X        return(forklp(cmd, tail, (char *)NULL));
X#endif
X}
X#endif
X
X#if	MSDOS & LATTICE
X/*	System: a modified version of lattice's system() function
X		that detects the proper switchar and uses it
X		written by Dana Hogget				*/
X
Xsystem(cmd)
X
Xchar *cmd;	/*  Incoming command line to execute  */
X
X{
X	char *getenv();
X	static char *swchar = "/C";	/*  Execution switch  */
X	union REGS inregs;	/*  parameters for dos call  */
X	union REGS outregs;	/*  Return results from dos call  */
X	char *shell;		/*  Name of system command processor  */
X	char *p;		/*  Temporary pointer  */
X	int ferr;		/*  Error condition if any  */
X
X	/*  get name of system shell  */
X	if ((shell = getenv("COMSPEC")) == NULL) {
X		return (-1);		/*  No shell located  */
X	}
X
X	p = cmd;
X	while (isspace(*p)) {		/*  find out if null command */
X		p++;
X	}
X
X	/**  If the command line is not empty, bring up the shell  **/
X	/**  and execute the command.  Otherwise, bring up the     **/
X	/**  shell in interactive mode.   **/
X
X	if (p && *p) {
X		/**  detect current switch character and us it  **/
X		inregs.h.ah = 0x37;	/*  get setting data  */
X		inregs.h.al = 0x00;	/*  get switch character  */
X		intdos(&inregs, &outregs);
X		*swchar = outregs.h.dl;
X		ferr = forkl(shell, "command", swchar, cmd, (char *)NULL);
X	} else {
X		ferr = forkl(shell, "command", (char *)NULL);
X	}
X
X	return (ferr ? ferr : wait());
X}
X#endif
X
X#if	MSDOS & LATTICE
Xextern int _oserr;
X#endif
X
X#if	MSDOS & AZTEC
Xextern int errno;
X#endif
X
X#if	MSDOS & (TURBO | LATTICE | AZTEC)
X/*	SHELLPROG: Execute a command in a subshell		*/
X
Xshellprog(cmd)
X
Xchar *cmd;	/*  Incoming command line to execute  */
X
X{
X	char *shell;		/* Name of system command processor */
X	char *p;		/* Temporary pointer */
X	char swchar;		/* switch character to use */
X	union REGS regs;	/* parameters for dos call */
X	char comline[NSTRING];	/* constructed command line */
X	char *getenv();
X
X	/*  detect current switch character and set us up to use it */
X	regs.h.ah = 0x37;	/*  get setting data  */
X	regs.h.al = 0x00;	/*  get switch character  */
X	intdos(&regs, &regs);
X	swchar = (char)regs.h.dl;
X
X	/*  get name of system shell  */
X	if ((shell = getenv("COMSPEC")) == NULL) {
X		return(FALSE);		/*  No shell located  */
X	}
X
X	/* trim leading whitespace off the command */
X	while (*cmd == ' ' || *cmd == '\t')	/*  find out if null command */
X		cmd++;
X
X	/**  If the command line is not empty, bring up the shell  **/
X	/**  and execute the command.  Otherwise, bring up the     **/
X	/**  shell in interactive mode.   **/
X
X	if (*cmd) {
X		strcpy(comline, shell);
X		strcat(comline, " ");
X		comline[strlen(comline) + 1] = 0;
X		comline[strlen(comline)] = swchar;
X		strcat(comline, "c ");
X		strcat(comline, cmd);
X		return(execprog(comline));
X	} else
X		return(execprog(shell));
X}
X
X/*	EXECPROG:	A function to execute a named program
X			with arguments
X*/
X
Xexecprog(cmd)
X
Xchar *cmd;	/*  Incoming command line to execute  */
X
X{
X	char *sp;		/* temporary string pointer */
X	char f1[38];		/* FCB1 area (not initialized */
X	char f2[38];		/* FCB2 area (not initialized */
X	char prog[NSTRING];	/* program filespec */
X	char tail[NSTRING];	/* command tail with length byte */
X	union REGS regs;	/* parameters for dos call  */
X	struct SREGS segreg;	/* segment registers for dis call */
X	struct pblock {		/* EXEC parameter block */
X		short envptr;	/* 2 byte pointer to environment string */
X		char *cline;	/* 4 byte pointer to command line */
X		char *fcb1;	/* 4 byte pointer to FCB at PSP+5Ch */
X		char *fcb2;	/* 4 byte pointer to FCB at PSP+6Ch */
X	} pblock;
X	char *flook();
X
X	/* parse the command name from the command line */
X	sp = prog;
X	while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
X		*sp++ = *cmd++;
X	*sp = 0;
X
X	/* and parse out the command tail */
X	while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
X		++cmd;
X	*tail = (char)(strlen(cmd)); /* record the byte length */
X	strcpy(&tail[1], cmd);
X	strcat(&tail[1], "\r");
X
X	/* look up the program on the path trying various extentions */
X	if ((sp = flook(prog, TRUE)) == NULL)
X		if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
X			strcpy(&prog[strlen(prog)-4], ".com");
X			if ((sp = flook(prog, TRUE)) == NULL)
X				return(FALSE);
X		}
X	strcpy(prog, sp);
X
X	/* get a pointer to this PSPs environment segment number */
X	segread(&segreg);
X
X	/* set up the EXEC parameter block */
X	pblock.envptr = 0;	/* make the child inherit the parents env */
X	pblock.fcb1 = f1;		/* point to a blank FCB */
X	pblock.fcb2 = f2;		/* point to a blank FCB */
X        pblock.cline = tail;		/* parameter line pointer */
X
X	/* and make the call */
X	regs.h.ah = 0x4b;	/* EXEC Load or Execute a Program */
X	regs.h.al = 0x00;	/* load end execute function subcode */
X#if	AZTEC
X	regs.x.ds = ((unsigned long)(prog) >> 16);	/* program name ptr */
X#else
X	segreg.ds = ((unsigned long)(prog) >> 16);	/* program name ptr */
X#endif
X	regs.x.dx = (unsigned int)(prog);
X#if	AZTEC
X	regs.x.es = regs.x.ds;
X	/*regs.x.es = ((unsigned long)(&pblock) >> 16);	* set up param block ptr */
X#else
X	segreg.es = ((unsigned long)(&pblock) >> 16);	/* set up param block ptr */
X#endif
X	regs.x.bx = (unsigned int)(&pblock);
X#if	LATTICE
X#define	CFLAG	1
X	if ((intdosx(&regs, &regs, &segreg) & CFLAG) == 0) {
X		regs.h.ah = 0x4d;	/* get child process return code */
X		intdos(&regs, &regs);	/* go do it */
X		rval = regs.x.ax;	/* save child's return code */
X	} else
X		rval = -_oserr;		/* failed child call */
X#endif
X#if	AZTEC
X#define	CFLAG	1
X	if ((sysint(0x21, &regs, &regs) & CFLAG) == 0) {
X		regs.h.ah = 0x4d;	/* get child process return code */
X		sysint(0x21, &regs, &regs);	/* go do it */
X		rval = regs.x.ax;	/* save child's return code */
X	} else
X		rval = -errno;		/* failed child call */
X#endif
X#if	TURBO
X	intdosx(&regs, &regs, &segreg);
X	if (regs.x.cflag == 0) {
X		regs.h.ah = 0x4d;	/* get child process return code */
X		intdos(&regs, &regs);	/* go do it */
X		rval = regs.x.ax;	/* save child's return code */
X	} else
X		rval = -_doserrno;	/* failed child call */
X#endif
X	return((rval < 0) ? FALSE : TRUE);
X}
X#endif
FRIDAY_NIGHT
echo extracting - st520.c
sed 's/^X//' > st520.c << 'FRIDAY_NIGHT'
X/*
X
XThe routines in this file provide support for the Atari 520 or 1040ST
Xusing VT52 emulation.  The I/O services are provided here as well.  It
Xcompiles into nothing if not a 520ST style device. The only compiler
Xsupported directly is Mark Williams C
X
XAdditional code and ideas from:
X
X		James Turner
X		Jeff Lomicka
X		J. C. Benoist
X
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	ATARI & ST520
X
X/*
X	These routines provide support for the ATARI 1040ST and 520ST
Xusing the virtual VT52 Emulator
X
X*/
X
X#include	<osbind.h>
X#include	<aline.h>
X#include	<linea.h>
X
X#define NROW	50	/* 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	300	/* # times thru update to pause */
X#define BIAS	0x20	/* Origin 0 coordinate bias.	*/
X#define ESC	0x1B	/* ESC character.		*/
X#define SCRFONT 2	/* index of 8x16 monochrome system default font */
X#define DENSIZE	50	/* # of lines in a dense screen	*/
X
X/****	ST Internals definitions		*****/
X
X/*	BIOS calls */
X
X#define	BCONSTAT	1	/* return input device status */
X#define	CONIN		2	/* read character from device */
X#define	BCONOUT		3	/* write character to device */
X
X/*	XBIOS calls */
X
X#define	INITMOUS	0	/* initialize the mouse */
X#define	GETREZ		4	/* get current resolution */
X#define	SETSCREEN	5	/* set screen resolution */
X#define	SETPALETTE	6	/* set the color pallette */
X#define	SETCOLOR	7	/* set or read a color */
X#define	CURSCONF	21	/* set cursor configuration */
X#define	IKBDWS		25	/* intelligent keyboard send command */
X#define	KBDVBASE	34	/* get keyboard table base */
X
X/*	GEMDOS calls */
X
X#define	EXEC		0x4b	/* Exec off a process */
X
X#define	CON		2	/* CON: Keyboard and screen device */
X
X/*	Palette color definitions	*/
X
X#define	LOWPAL	"000700070770007707077777"
X#define	MEDPAL	"000700007777"
X#define	HIGHPAL	"111000"
X
X/*	ST Global definitions		*/
X
X/* keyboard vector table */
Xstruct KVT {
X	long midivec;		/* midi input */
X	long vkbderr;		/* keyboard error */
X	long vmiderr;		/* MIDI error */
X	long statvec;		/* IKBD status */
X	int (*mousevec)();	/* mouse vector */
X	long clockvec;		/* clock vector */
X	long joyvec;		/* joystict vector */
X} *ktable;
X
Xint (*sysmint)();			/* system mouse interupt handler */
X
X/* mouse parameter table */
Xstruct Param {
X	char topmode;
X	char buttons;
X	char xparam;
X	char yparam;
X	int xmax,ymax;
X	int xinitial,yinitial;
X} mparam;
X
Xint initrez;			/* initial screen resolution */
Xint currez;			/* current screen resolution */
Xchar resname[][8] = {		/* screen resolution names */
X	"LOW", "MEDIUM", "HIGH", "DENSE"
X};
Xshort spalette[16];		/* original color palette settings */
Xshort palette[16];		/* current palette settings */
X
XLINEA *aline;	/* Pointer to line a parameter block returned by init */
X
XNLINEA *naline;	/* Pointer to line a parameters at negative offsets  */
X
XFONT  **fonts;	/* Array of pointers to the three system font headers */
X		/* returned by init (in register A1)                  */
X
XWORD  (**foncs)();    /* Array of pointers to the 15 line a functions      */
X                     /* returned by init (in register A2)                 */
X                     /* only valid in ROM'ed TOS                          */
X
XFONT *system_font;	/* pointer to default system font */
XFONT *small_font;	/* pointer to small font */
X
Xextern  int     ttopen();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern  int     ttclose();
Xextern  int     stmove();
Xextern  int     steeol();
Xextern  int     steeop();
Xextern  int     stbeep();
Xextern  int     stopen();
Xextern	int	stclose();
Xextern	int	stgetc();
Xextern	int	stputc();
Xextern	int	strev();
Xextern	int	strez();
Xextern	int	stkopen();
Xextern	int	stkclose();
X
X#if	COLOR
Xextern	int	stfcol();
Xextern	int	stbcol();
X#endif
X
X/*
X * Dispatch table. All the
X * hard fields just point into the
X * terminal I/O code.
X */
XTERM    term    = {
X	NROW-1,
X        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        &stopen,
X        &stclose,
X	&stkopen,
X	&stkclose,
X        &stgetc,
X	&stputc,
X        &ttflush,
X        &stmove,
X        &steeol,
X        &steeop,
X        &stbeep,
X        &strev,
X	&strez
X#if	COLOR
X	, &stfcol,
X	&stbcol
X#endif
X};
X
Xvoid init_aline()
X{
X       linea0();
X       aline = (LINEA *)(la_init.li_a0);
X       fonts = (FONT **)(la_init.li_a1);
X       foncs = la_init.li_a2;
X       naline = ((NLINEA *)aline) - 1;
X}
X
Xinit()
X{
X       init_aline();
X       system_font = fonts[SCRFONT];        /* save it */
X	small_font = fonts[1];
X}
X
X
Xswitch_font(fp)
X
XFONT *fp;
X
X{
X       /* See aline.h for description of fields */
X	/* these definitions are temporary...too many cooks!!! */
X#undef	V_CEL_HT
X#undef	V_CEL_WR
X#undef	V_CEL_MY
X#undef	V_CEL_MX
X#undef	V_FNT_ST
X#undef	V_FNT_ND
X#undef	V_FNT_AD
X#undef	V_FNT_WR
X#undef	V_OFF_AD
X#undef	VWRAP
X#undef	V_Y_MAX
X#undef	V_X_MAX
X
X       naline->V_CEL_HT = fp->form_height;
X       naline->V_CEL_WR = aline->VWRAP * fp->form_height;
X       naline->V_CEL_MY = (naline->V_Y_MAX / fp->form_height) - 1;
X       naline->V_CEL_MX = (naline->V_X_MAX / fp->max_cell_width) - 1;
X       naline->V_FNT_WR = fp->form_width;
X       naline->V_FNT_ST = fp->first_ade;
X       naline->V_FNT_ND = fp->last_ade;
X       naline->V_OFF_AD = fp->off_table;
X       naline->V_FNT_AD =  fp->dat_table;
X}
X
Xstmove(row, col)
X{
X        stputc(ESC);
X        stputc('Y');
X        stputc(row+BIAS);
X        stputc(col+BIAS);
X}
X
Xsteeol()
X{
X        stputc(ESC);
X        stputc('K');
X}
X
Xsteeop()
X{
X#if	COLOR
X	stfcol(gfcolor);
X	stbcol(gbcolor);
X#endif
X        stputc(ESC);
X        stputc('J');
X}
X
Xstrev(status)	/* set the reverse video state */
X
Xint status;	/* TRUE = reverse video, FALSE = normal video */
X
X{
X	if (currez > 1) {
X		stputc(ESC);
X		stputc(status ? 'p' : 'q');
X	}
X}
X
X#if	COLOR
Xmapcol(clr)	/* medium rez color translation */
X
Xint clr;	/* emacs color number to translate */
X
X{
X	static int mctable[] = {0, 1, 2, 3, 2, 1, 2, 3};
X
X	if (currez != 1)
X		return(clr);
X	else
X		return(mctable[clr]);
X}
X
Xstfcol(color)	/* set the forground color */
X
Xint color;	/* color to set forground to */
X
X{
X	if (currez < 2) {
X		stputc(ESC);
X		stputc('b');
X		stputc(mapcol(color));
X	}
X}
X
Xstbcol(color)	/* set the background color */
X
Xint color;	/* color to set background to */
X
X
X{
X	if (currez < 2) {
X		stputc(ESC);
X		stputc('c');
X		stputc(mapcol(color));
X	}
X}
X#endif
X
Xstatic char beep[] = {
X	0x00, 0x00,
X	0x01, 0x01,
X	0x02, 0x01,
X	0x03, 0x01,
X	0x04, 0x02,
X	0x05, 0x01,
X	0x07, 0x38,
X	0x08, 0x10,
X	0x09, 0x10,
X	0x0A, 0x10,
X	0x0B, 0x00,
X	0x0C, 0x30,
X	0x0D, 0x03,
X	0xFF, 0x00
X};
X
Xstbeep()
X{
X	Dosound(beep);
X}
X
Xdomouse()	/* mouse interupt handler */
X
X{
X	return((*sysmint)());
X}
X
Xstkopen()	/* open the keyboard (and mouse) */
X
X{
X	/* grab the keyboard vector table */
X	ktable = (struct KVT *)xbios(KBDVBASE);
X	sysmint = ktable->mousevec;	/* save mouse vector */
X
X	/* initialize the mouse */
X	mparam.topmode = 0;
X	mparam.buttons = 4;
X	mparam.xparam = 8;
X	mparam.yparam = 10;
X	mparam.xmax = 79;
X	mparam.ymax = 23;
X	mparam.xinitial = 0;
X	mparam.yinitial = 0;
X	xbios(INITMOUS, 4, &mparam, &domouse);
X}
X
Xstopen()	/* open the screen */
X
X{
X	int i;
X
X        ttopen();
X	eolexist = TRUE;
X	init();
X
X	/* switch to a steady cursor */
X	xbios(CURSCONF, 3);
X
X	/* save the current color palette */
X	for (i=0; i<16; i++)
X		spalette[i] = xbios(SETCOLOR, i, -1);
X
X	/* and find the current resolution */
X	initrez = currez = xbios(GETREZ);
X	strcpy(sres, resname[currez]);
X
X	/* set up the screen size and palette */
X	switch (currez) {
X		case 0:	term.t_mrow = 25 - 1;
X			term.t_nrow = 25 - 1;
X			term.t_ncol = 40;
X			strcpy(palstr, LOWPAL);
X			break;
X
X		case 1: term.t_mrow = 25 - 1;
X			term.t_nrow = 25 - 1;
X			strcpy(palstr, MEDPAL);
X			break;
X
X		case 2: term.t_mrow = DENSIZE - 1;
X			term.t_nrow = 25 - 1;
X			strcpy(palstr, HIGHPAL);
X	}
X
X	/* and set up the default palette */
X	spal(palstr);
X
X	stputc(ESC);	/* automatic overflow off */
X	stputc('w');
X	stputc(ESC);	/* turn cursor on */
X	stputc('e');
X}
X
Xstkclose()	/* close the keyboard (and mouse) */
X
X{
X	static char resetcmd[] = {0x80, 0x01};	/* keyboard reset command */
X
X	/* restore the mouse interupt routines */
X	xbios(INITMOUS, 2, &mparam, (long)sysmint);
X
X	/* and reset the keyboard controller */
X	xbios(IKBDWS, 1, &resetcmd[0]);
X}
X
Xstclose()
X
X{
X	stputc(ESC);	/* auto overflow on */
X	stputc('v');
X
X	/* switch to a flashing cursor */
X	xbios(CURSCONF, 2);
X
X	/* restore the original screen resolution */
X	if (currez == 3)
X		switch_font(system_font);
X	strez(resname[initrez]);
X
X	/* restore the original palette settings */
X	xbios(SETPALETTE, spalette);
X
X	ttclose();
X}
X
X/* 	spal(pstr):	reset the current palette according to a
X			"palette string" of the form
X
X	000111222333444555666777
X
X	which contains the octal values for the palette registers
X*/
X
Xspal(pstr)
X
Xchar *pstr;	/* palette string */
X
X{
X	int pal;	/* current palette position */
X	int clr;	/* current color value */
X	int i;
X
X	for (pal = 0; pal < 16; pal++) {
X		if (*pstr== 0)
X			break;
X
X		/* parse off a color */
X		clr = 0;
X		for (i = 0; i < 3; i++)
X			if (*pstr)
X				clr = clr * 16 + (*pstr++ - '0');
X		palette[pal] = clr;
X	};
X
X	/* and now set it */
X	xbios(SETPALETTE, palette);
X}
X
Xstgetc()	/* get a char from the keyboard */
X
X{
X	register long rval;	/* return value from BIOS call */
X	static int funkey = 0;	/* held fuction key scan code */
X	static long sh;		/* shift/alt key on held function? */
X	long bios();
X
X	/* if there is a pending function key, return it */
X	if (funkey) {
X		if (sh) {	/* alt or cntrl */
X			if (funkey >= 0x3B && funkey <= 0x44) {
X				rval = funkey + '^' - ';';
X				if (sh & 0x08)	/* alt */
X					rval += 10;
X				funkey = 0;
X				return(rval & 255);
X			}
X		}
X		rval = funkey;
X		funkey = 0;
X	} else {
X		/* waiting... flash the cursor */
X		xbios(CURSCONF, 2);
X
X		/* get the character */
X		rval = bios(CONIN, CON);
X		sh = Getshift(-1) & 0x0cL; /* see if alt or cntrl depressed */
X		if ((rval & 255L) == 0L) {
X			funkey = (rval >> 16L) & 255;
X			rval = 0;
X		}
X
X	}
X
X	/* and switch to a steady cursor */
X	xbios(CURSCONF, 3);
X
X	return(rval & 255);
X}
X
Xstputc(c)	/* output char c to the screen */
X
Xchar c;		/* character to print out */
X
X{
X	bios(BCONOUT, CON, c);
X}
X
Xstrez(newrez)	/* change screen resolution */
X
Xchar *newrez;	/* requested resolution */
X
X{
X	int nrez;	/* requested new resolution */
X
X	/* first, decode the resolution name */
X	for (nrez = 0; nrez < 4; nrez++)
X		if (strcmp(newrez, resname[nrez]) == 0)
X			break;
X	if (nrez == 4) {
X		mlwrite("%%No such resolution");
X		return(FALSE);
X	}
X
X	/* next, make sure this resolution is legal for this monitor */
X	if ((currez < 2 && nrez > 1) || (currez > 1 && nrez < 2)) {
X		mlwrite("%%Resolution illegal for this monitor");
X		return(FALSE);
X	}
X
X	/* eliminate non-changes */
X	if (currez == nrez)
X		return(TRUE);
X
X	/* finally, make the change */
X	switch (nrez) {
X		case 0:	/* low resolution - 16 colors */
X			newwidth(TRUE, 40);
X			strcpy(palstr, LOWPAL);
X			xbios(SETSCREEN, -1L, -1L, 0);
X			break;
X
X		case 1:	/* medium resolution - 4 colors */
X			newwidth(TRUE, 80);
X			strcpy(palstr, MEDPAL);
X			xbios(SETSCREEN, -1L, -1L, 1);
X			break;
X
X		case 2:	/* High resolution - 2 colors - 25 lines */
X			newsize(TRUE, 25);
X			strcpy(palstr, HIGHPAL);
X			switch_font(system_font);
X			break;
X
X		case 3:	/* Dense resolution - 2 colors - 40 lines */
X			newsize(TRUE, DENSIZE);
X			strcpy(palstr, HIGHPAL);
X			switch_font(small_font);
X			break;
X	}
X
X	/* and set up the default palette */
X	spal(palstr);
X	currez = nrez;
X	strcpy(sres, resname[currez]);
X
X	stputc(ESC);	/* automatic overflow off */
X	stputc('w');
X	stputc(ESC);	/* turn cursor on */
X	stputc('e');
X
X	return(TRUE);
X}
X
X#if	LATTICE
Xsystem(cmd)	/* call the system to execute a new program */
X
Xchar *cmd;	/* command to execute */
X
X{
X	char *pptr;			/* pointer into program name */
X	char pname[NSTRING];		/* name of program to execute */
X	char tail[NSTRING];		/* command tail */
X
X	/* scan off program name.... */
X	pptr = pname;
X	while (*cmd && (*cmd != ' ' && *cmd != '\t'))
X		*pptr++ = *cmd++;
X	*pptr = 0;
X
X	/* create program name length/string */
X	tail[0] = strlen(cmd);
X	strcpy(&tail[1], cmd);
X
X	/* go do it! */
X	return(gemdos(		(int)EXEC,
X				(int)0,
X				(char *)pname,
X				(char *)tail,
X				(char *)NULL));
X}
X#endif
X
X#if	TYPEAH
Xtypahead()
X
X{
X	int rval;	/* return value from BIOS call */
X
X	/* get the status of the console */
X	rval = bios(BCONSTAT, CON);
X
X	/* end return the results */
X	if (rval == 0)
X		return(FALSE);
X	else
X		return(TRUE);
X}
X#endif
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument [unused] */
X
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X#else
Xsthello()
X{
X}
X#endif
FRIDAY_NIGHT
echo mes.11 completed!
# That's all folsca

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/17/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.12')
# If you do not see the message
#	`mes.12 completed!'
# then the file was incomplete.
echo extracting - tcap.c
sed 's/^X//' > tcap.c << 'FRIDAY_NIGHT'
X/*	tcap:	Unix V5, V7 and BS4.2 Termcap video driver
X		for MicroEMACS
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 TERMCAP
X
X#define	MARGIN	8
X#define	SCRSIZ	64
X#define	NPAUSE	10			/* # times thru update to pause */
X#define BEL     0x07
X#define ESC     0x1B
X
Xextern int      ttopen();
Xextern int      ttgetc();
Xextern int      ttputc();
Xextern int	tgetnum();
Xextern int      ttflush();
Xextern int      ttclose();
Xextern int	tcapkopen();
Xextern int	tcapkclose();
Xextern int      tcapmove();
Xextern int      tcapeeol();
Xextern int      tcapeeop();
Xextern int      tcapbeep();
Xextern int	tcaprev();
Xextern int	tcapcres();
Xextern int      tcapopen();
Xextern int      tput();
Xextern char     *tgoto();
X#if	COLOR
Xextern	int	tcapfcol();
Xextern	int	tcapbcol();
X#endif
X
X#define TCAPSLEN 315
Xchar tcapbuf[TCAPSLEN];
Xchar *UP, PC, *CM, *CE, *CL, *SO, *SE;
X
XTERM term = {
X	NULL,	/* these four values are set dynamically at open time */
X	NULL,
X	NULL,
X	NULL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        tcapopen,
X        ttclose,
X        tcapkopen,
X        tcapkclose,
X        ttgetc,
X        ttputc,
X        ttflush,
X        tcapmove,
X        tcapeeol,
X        tcapeeop,
X        tcapbeep,
X        tcaprev,
X        tcapcres
X#if	COLOR
X	, tcapfcol,
X	tcapbcol
X#endif
X};
X
Xtcapopen()
X
X{
X        char *getenv();
X        char *t, *p, *tgetstr();
X        char tcbuf[1024];
X        char *tv_stype;
X        char err_str[72];
X
X        if ((tv_stype = getenv("TERM")) == NULL)
X        {
X                puts("Environment variable TERM not defined!");
X                exit(1);
X        }
X
X        if ((tgetent(tcbuf, tv_stype)) != 1)
X        {
X                sprintf(err_str, "Unknown terminal type %s!", tv_stype);
X                puts(err_str);
X                exit(1);
X        }
X
X 
X       if ((term.t_nrow=(short)tgetnum("li")-1) == -1){
X               puts("termcap entry incomplete (lines)");
X               exit(1);
X       }
X	term.t_mrow =  term.t_nrow;
X
X       if ((term.t_ncol=(short)tgetnum("co")) == -1){
X               puts("Termcap entry incomplete (columns)");
X               exit(1);
X       }
X	term.t_mcol = term.t_ncol;
X
X        p = tcapbuf;
X        t = tgetstr("pc", &p);
X        if(t)
X                PC = *t;
X
X        CL = tgetstr("cl", &p);
X        CM = tgetstr("cm", &p);
X        CE = tgetstr("ce", &p);
X        UP = tgetstr("up", &p);
X	SE = tgetstr("se", &p);
X	SO = tgetstr("so", &p);
X	if (SO != NULL)
X		revexist = TRUE;
X
X        if(CL == NULL || CM == NULL || UP == NULL)
X        {
X                puts("Incomplete termcap entry\n");
X                exit(1);
X        }
X
X	if (CE == NULL)		/* will we be able to use clear to EOL? */
X		eolexist = FALSE;
X		
X        if (p >= &tcapbuf[TCAPSLEN])
X        {
X                puts("Terminal description too big!\n");
X                exit(1);
X        }
X        ttopen();
X}
X
Xtcapkopen()
X
X{
X	strcpy(sres, "NORMAL");
X}
X
Xtcapkclose()
X
X{
X}
X
Xtcapmove(row, col)
Xregister int row, col;
X{
X        putpad(tgoto(CM, col, row));
X}
X
Xtcapeeol()
X{
X        putpad(CE);
X}
X
Xtcapeeop()
X{
X        putpad(CL);
X}
X
Xtcaprev(state)		/* change reverse video status */
X
Xint state;		/* FALSE = normal video, TRUE = reverse video */
X
X{
X	static int revstate = FALSE;
X	if (state) {
X		if (SO != NULL)
X			putpad(SO);
X	} else
X		if (SE != NULL)
X			putpad(SE);
X}
X
Xtcapcres()	/* change screen resolution */
X
X{
X	return(TRUE);
X}
X
Xspal(dummy)	/* change palette string */
X
X{
X	/*	Does nothing here	*/
X}
X
X#if	COLOR
Xtcapfcol()	/* no colors here, ignore this */
X{
X}
X
Xtcapbcol()	/* no colors here, ignore this */
X{
X}
X#endif
X
Xtcapbeep()
X{
X	ttputc(BEL);
X}
X
Xputpad(str)
Xchar    *str;
X{
X	tputs(str, 1, ttputc);
X}
X
Xputnpad(str, n)
Xchar    *str;
X{
X	tputs(str, n, ttputc);
X}
X
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument [unused] */
X
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X#else
X
Xhello()
X{
X}
X
X#endif
FRIDAY_NIGHT
echo extracting - termio.c
sed 's/^X//' > termio.c << 'FRIDAY_NIGHT'
X/*
X * The functions in this file negotiate with the operating system for
X * characters, and write characters in a barely buffered fashion on the display.
X * All operating systems.
X */
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X#if   MSDOS & TURBO
X#include <conio.h>
X#endif
X
X#if     AMIGA
X#define NEW 1006L
X#define AMG_MAXBUF      1024L
Xstatic long terminal;
Xstatic char     scrn_tmp[AMG_MAXBUF+1];
Xstatic long     scrn_tmp_p = 0;
X#endif
X
X#if     VMS
X#include        <stsdef.h>
X#include        <ssdef.h>
X#include        <descrip.h>
X#include        <iodef.h>
X#include        <ttdef.h>
X#include	<tt2def.h>
X
X#define NIBUF   128                     /* Input buffer size            */
X#define NOBUF   1024                    /* MM says bug buffers win!     */
X#define EFN     0                       /* Event flag                   */
X
Xchar    obuf[NOBUF];                    /* Output buffer                */
Xint     nobuf;                  /* # of bytes in above    */
Xchar    ibuf[NIBUF];                    /* Input buffer          */
Xint     nibuf;                  /* # of bytes in above  */
Xint     ibufi;                  /* Read index                   */
Xint     oldmode[3];                     /* Old TTY mode bits            */
Xint     newmode[3];                     /* New TTY mode bits            */
Xshort   iochan;                  /* TTY I/O channel             */
X#endif
X
X#if     CPM
X#include        <bdos.h>
X#endif
X
X#if     MSDOS & (LATTICE | MSC | TURBO | AZTEC | MWC86)
Xunion REGS rg;		/* cpu register for use of DOS calls */
Xint nxtchar = -1;	/* character held from type ahead    */
X#endif
X
X#if RAINBOW
X#include "rainbow.h"
X#endif
X
X#if	USG			/* System V */
X#include	<signal.h>
X#include	<termio.h>
X#include	<fcntl.h>
Xint kbdflgs;			/* saved keyboard fd flags	*/
Xint kbdpoll;			/* in O_NDELAY mode			*/
Xint kbdqp;			/* there is a char in kbdq	*/
Xchar kbdq;			/* char we've already read	*/
Xstruct	termio	otermio;	/* original terminal characteristics */
Xstruct	termio	ntermio;	/* charactoristics to use inside */
X#endif
X
X#if V7 | BSD
X#undef	CTRL
X#include        <sgtty.h>        /* for stty/gtty functions */
X#include	<signal.h>
Xstruct  sgttyb  ostate;          /* saved tty state */
Xstruct  sgttyb  nstate;          /* values for editor mode */
Xstruct tchars	otchars;	/* Saved terminal special character set */
Xstruct tchars	ntchars = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
X				/* A lot of nothing */
X#if BSD
X#include <sys/ioctl.h>		/* to get at the typeahead */
Xextern	int rtfrmshell();	/* return from suspended shell */
X#define	TBUFSIZ	128
Xchar tobuf[TBUFSIZ];		/* terminal output buffer */
X#endif
X#endif
X
X/*
X * This function is called once to set up the terminal device streams.
X * On VMS, it translates TT until it finds the terminal, then assigns
X * a channel to it and sets it raw. On CPM it is a no-op.
X */
Xttopen()
X{
X#if     AMIGA
X	char oline[NSTRING];
X#if	AZTEC
X	extern	Enable_Abort;	/* Turn off ctrl-C interrupt */
X
X	Enable_Abort = 0;	/* for the Manx compiler */
X#endif
X	strcpy(oline, "RAW:0/0/640/200/");
X	strcat(oline, PROGNAME);
X	strcat(oline, " ");
X	strcat(oline, VERSION);
X	strcat(oline, "/Amiga");
X        terminal = Open(oline, NEW);
X#endif
X#if     VMS
X        struct  dsc$descriptor  idsc;
X        struct  dsc$descriptor  odsc;
X        char    oname[40];
X        int     iosb[2];
X        int     status;
X
X        odsc.dsc$a_pointer = "TT";
X        odsc.dsc$w_length  = strlen(odsc.dsc$a_pointer);
X        odsc.dsc$b_dtype        = DSC$K_DTYPE_T;
X        odsc.dsc$b_class        = DSC$K_CLASS_S;
X        idsc.dsc$b_dtype        = DSC$K_DTYPE_T;
X        idsc.dsc$b_class        = DSC$K_CLASS_S;
X        do {
X                idsc.dsc$a_pointer = odsc.dsc$a_pointer;
X                idsc.dsc$w_length  = odsc.dsc$w_length;
X                odsc.dsc$a_pointer = &oname[0];
X                odsc.dsc$w_length  = sizeof(oname);
X                status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
X                if (status!=SS$_NORMAL && status!=SS$_NOTRAN)
X                        exit(status);
X                if (oname[0] == 0x1B) {
X                        odsc.dsc$a_pointer += 4;
X                        odsc.dsc$w_length  -= 4;
X                }
X        } while (status == SS$_NORMAL);
X        status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
X        if (status != SS$_NORMAL)
X                exit(status);
X        status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
X                          oldmode, sizeof(oldmode), 0, 0, 0, 0);
X        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
X                exit(status);
X        newmode[0] = oldmode[0];
X        newmode[1] = oldmode[1] | TT$M_NOECHO;
X        newmode[1] &= ~(TT$M_TTSYNC|TT$M_HOSTSYNC);
X        newmode[2] = oldmode[2] | TT2$M_PASTHRU;
X        status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
X                          newmode, sizeof(newmode), 0, 0, 0, 0);
X        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
X                exit(status);
X        term.t_nrow = (newmode[1]>>24) - 1;
X        term.t_ncol = newmode[0]>>16;
X
X#endif
X#if     CPM
X#endif
X
X#if     MSDOS & (HP150 == 0) & LATTICE
X	/* kill the ctrl-break interupt */
X	rg.h.ah = 0x33;		/* control-break check dos call */
X	rg.h.al = 1;		/* set the current state */
X	rg.h.dl = 0;		/* set it OFF */
X	intdos(&rg, &rg);	/* go for it! */
X#endif
X
X#if	USG
X	ioctl(0, TCGETA, &otermio);	/* save old settings */
X	ntermio.c_iflag = 0;		/* setup new settings */
X	ntermio.c_oflag = 0;
X	ntermio.c_cflag = otermio.c_cflag;
X	ntermio.c_lflag = 0;
X	ntermio.c_line = otermio.c_line;
X	ntermio.c_cc[VMIN] = 1;
X	ntermio.c_cc[VTIME] = 0;
X	ioctl(0, TCSETA, &ntermio);	/* and activate them */
X	kbdflgs = fcntl( 0, F_GETFL, 0 );
X	kbdpoll = FALSE;
X#endif
X
X#if     V7 | BSD
X        gtty(0, &ostate);                       /* save old state */
X        gtty(0, &nstate);                       /* get base of new state */
X        nstate.sg_flags |= RAW;
X        nstate.sg_flags &= ~(ECHO|CRMOD);       /* no echo for now... */
X        stty(0, &nstate);                       /* set mode */
X	ioctl(0, TIOCGETC, &otchars);		/* Save old characters */
X	ioctl(0, TIOCSETC, &ntchars);		/* Place new character into K */
X#if	BSD
X	/* provide a smaller terminal output buffer so that
X	   the type ahead detection works better (more often) */
X	setbuffer(stdout, &tobuf[0], TBUFSIZ);
X	signal(SIGTSTP,SIG_DFL);	/* set signals so that we can */
X	signal(SIGCONT,rtfrmshell);	/* suspend & restart emacs */
X#endif
X#endif
X	/* on all screens we are not sure of the initial position
X	   of the cursor					*/
X	ttrow = 999;
X	ttcol = 999;
X}
X
X/*
X * This function gets called just before we go back home to the command
X * interpreter. On VMS it puts the terminal back in a reasonable state.
X * Another no-operation on CPM.
X */
Xttclose()
X{
X#if     AMIGA
X#if	LATTICE
X        amg_flush();
X        Close(terminal);
X#endif
X#if	AZTEC
X        amg_flush();
X	Enable_Abort = 1;	/* Fix for Manx */
X        Close(terminal);
X#endif
X#endif
X
X#if     VMS
X        int     status;
X        int     iosb[1];
X
X        ttflush();
X        status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
X                 oldmode, sizeof(oldmode), 0, 0, 0, 0);
X        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
X                exit(status);
X        status = SYS$DASSGN(iochan);
X        if (status != SS$_NORMAL)
X                exit(status);
X#endif
X#if     CPM
X#endif
X#if     MSDOS & (HP150 == 0) & LATTICE
X	/* restore the ctrl-break interupt */
X	rg.h.ah = 0x33;		/* control-break check dos call */
X	rg.h.al = 1;		/* set the current state */
X	rg.h.dl = 1;		/* set it ON */
X	intdos(&rg, &rg);	/* go for it! */
X#endif
X
X#if	USG
X	ioctl(0, TCSETA, &otermio);	/* restore terminal settings */
X	fcntl(0, F_SETFL, kbdflgs);
X#endif
X
X#if     V7 | BSD
X        stty(0, &ostate);
X	ioctl(0, TIOCSETC, &otchars);	/* Place old character into K */
X#endif
X}
X
X/*
X * Write a character to the display. On VMS, terminal output is buffered, and
X * we just put the characters in the big array, after checking for overflow.
X * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
X * MS-DOS (use the very very raw console output routine).
X */
Xttputc(c)
X#if     AMIGA
X        char c;
X#endif
X{
X#if     AMIGA
X        scrn_tmp[scrn_tmp_p++] = c;
X        if(scrn_tmp_p>=AMG_MAXBUF)
X                amg_flush();
X#endif
X#if     VMS
X        if (nobuf >= NOBUF)
X                ttflush();
X        obuf[nobuf++] = c;
X#endif
X
X#if     CPM
X        bios(BCONOUT, c, 0);
X#endif
X
X#if     MSDOS & MWC86
X        putcnb(c);
X#endif
X
X#if	MSDOS & (LATTICE | AZTEC) & ~IBMPC
X	bdos(6, c, 0);
X#endif
X
X#if RAINBOW
X        Put_Char(c);                    /* fast video */
X#endif
X
X
X#if     V7 | USG | BSD
X        fputc(c, stdout);
X#endif
X}
X
X#if	AMIGA
Xamg_flush()
X{
X        if(scrn_tmp_p)
X                Write(terminal,scrn_tmp,scrn_tmp_p);
X        scrn_tmp_p = 0;
X}
X#endif
X
X/*
X * Flush terminal buffer. Does real work where the terminal output is buffered
X * up. A no-operation on systems where byte at a time terminal I/O is done.
X */
Xttflush()
X{
X#if     AMIGA
X        amg_flush();
X#endif
X#if     VMS
X        int     status;
X        int     iosb[2];
X
X        status = SS$_NORMAL;
X        if (nobuf != 0) {
X                status = SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
X                         iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
X                if (status == SS$_NORMAL)
X                        status = iosb[0] & 0xFFFF;
X                nobuf = 0;
X        }
X        return (status);
X#endif
X
X#if     CPM
X#endif
X
X#if     MSDOS
X#endif
X
X#if     V7 | USG | BSD
X        fflush(stdout);
X#endif
X}
X
X/*
X * Read a character from the terminal, performing no editing and doing no echo
X * at all. More complex in VMS that almost anyplace else, which figures. Very
X * simple on CPM, because the system can do exactly what you want.
X */
Xttgetc()
X{
X#if     AMIGA
X        char ch;
X        amg_flush();
X        Read(terminal, &ch, 1L);
X        return(255 & (int)ch);
X#endif
X#if     VMS
X        int     status;
X        int     iosb[2];
X        int     term[2];
X
X        while (ibufi >= nibuf) {
X                ibufi = 0;
X                term[0] = 0;
X                term[1] = 0;
X                status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
X                         iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
X                if (status != SS$_NORMAL)
X                        exit(status);
X                status = iosb[0] & 0xFFFF;
X                if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
X                        exit(status);
X                nibuf = (iosb[0]>>16) + (iosb[1]>>16);
X                if (nibuf == 0) {
X                        status = SYS$QIOW(EFN, iochan, IO$_READLBLK,
X                                 iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
X                        if (status != SS$_NORMAL
X                        || (status = (iosb[0]&0xFFFF)) != SS$_NORMAL)
X                                exit(status);
X                        nibuf = (iosb[0]>>16) + (iosb[1]>>16);
X                }
X        }
X        return (ibuf[ibufi++] & 0xFF);    /* Allow multinational  */
X#endif
X
X#if     CPM
X        return (biosb(BCONIN, 0, 0));
X#endif
X
X#if RAINBOW
X        int Ch;
X
X        while ((Ch = Read_Keyboard()) < 0);
X
X        if ((Ch & Function_Key) == 0)
X                if (!((Ch & 0xFF) == 015 || (Ch & 0xFF) == 0177))
X                        Ch &= 0xFF;
X
X        return Ch;
X#endif
X
X#if     MSDOS & MWC86
X        return (getcnb());
X#endif
X
X#if	MSDOS & (LATTICE | MSC | TURBO | AZTEC)
X	int c;		/* character read */
X
X	/* if a char already is ready, return it */
X	if (nxtchar >= 0) {
X		c = nxtchar;
X		nxtchar = -1;
X		return(c);
X	}
X
X	/* call the dos to get a char */
X	rg.h.ah = 7;		/* dos Direct Console Input call */
X	intdos(&rg, &rg);
X	c = rg.h.al;		/* grab the char */
X	return(c & 255);
X#endif
X
X#if     V7 | BSD
X        return(127 & fgetc(stdin));
X#endif
X
X#if	USG
X	if( kbdqp )
X		kbdqp = FALSE;
X	else
X	{
X		if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
X			return FALSE;
X		kbdpoll = FALSE;
X		while (read(0, &kbdq, 1) != 1)
X			;
X	}
X	return ( kbdq & 127 );
X#endif
X}
X
X#if	TYPEAH & (~ST520)
X/* typahead:	Check to see if any characters are already in the
X		keyboard buffer
X*/
X
Xtypahead()
X
X{
X#if	MSDOS & (MSC | TURBO)
X	if (kbhit() != 0)
X		return(TRUE);
X	else
X		return(FALSE);
X#endif
X
X#if	MSDOS & (LATTICE | AZTEC | MWC86)
X	int c;		/* character read */
X	int flags;	/* cpu flags from dos call */
X
X	if (nxtchar >= 0)
X		return(TRUE);
X
X	rg.h.ah = 6;	/* Direct Console I/O call */
X	rg.h.dl = 255;	/*         does console input */
X#if	LATTICE | AZTEC
X	flags = intdos(&rg, &rg);
X#else
X	intcall(&rg, &rg, 0x21);
X	flags = rg.x.flags;
X#endif
X	c = rg.h.al;	/* grab the character */
X
X	/* no character pending */
X	if ((flags & 64) != 0)
X		return(FALSE);
X
X	/* save the character and return true */
X	nxtchar = c;
X	return(TRUE);
X#endif
X
X#if	BSD
X	int x;	/* holds # of pending chars */
X
X	return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x);
X#endif
X
X#if	USG
X	if( !kbdqp )
X	{
X		if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
X			return(FALSE);
X		kbdqp = (1 == read( 0, &kbdq, 1 ));
X	}
X	return ( kbdqp );
X#endif
X	return(FALSE);
X}
X#endif
X
FRIDAY_NIGHT
echo extracting - tipc.c
sed 's/^X//' > tipc.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file provide support for the TI-PC and other
X * compatible terminals. It goes directly to the graphics RAM to do
X * screen output. It compiles into nothing if not a TI-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     TIPC
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   0xDE000L                /* address of screen RAM        */
X
X#define CHAR_ENABLE     0x08            /* TI attribute to show char    */
X#define TI_REVERSE      0x10            /* TI attribute to reverse char */
X#define BLACK   0+CHAR_ENABLE           /* TI attribute for Black       */
X#define BLUE    1+CHAR_ENABLE           /* TI attribute for Blue        */
X#define RED     2+CHAR_ENABLE           /* TI attribute for Red         */
X#define MAGENTA 3+CHAR_ENABLE           /* TI attribute for Magenta     */
X#define GREEN   4+CHAR_ENABLE           /* TI attribute for Green       */
X#define CYAN    5+CHAR_ENABLE           /* TI attribute for Cyan        */
X#define YELLOW  6+CHAR_ENABLE           /* TI attribute for Yellow      */
X#define WHITE   7+CHAR_ENABLE           /* TI attribute for White       */
X
X
Xextern  int     ttopen();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern  int     ttclose();
Xextern  int     timove();
Xextern  int     tieeol();
Xextern  int     tieeop();
Xextern  int     tibeep();
Xextern  int     tiopen();
Xextern  int     tirev();
Xextern	int	ticres();
Xextern  int     ticlose();
Xextern  int     tiputc();
X
X#if     COLOR
Xextern  int     tifcol();
Xextern  int     tibcol();
X
Xint     cfcolor = -1;           /* current forground color */
Xint     cbcolor = -1;           /* current background color */
Xint     ctrans[] =              /* ansi to ti color translation table */
X        {BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE};
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        NROW-1,
X        NCOL,
X        NCOL,
X        MARGIN,
X        SCRSIZ,
X        NPAUSE,
X        tiopen,
X        ticlose,
X        ttgetc,
X        tiputc,
X        ttflush,
X        timove,
X        tieeol,
X        tieeop,
X        tibeep,
X        tirev,
X        ticres
X#if     COLOR
X        , tifcol,
X        tibcol
X#endif
X};
X
Xextern union REGS rg;
X
X#if     COLOR
Xsetatt( attr )
Xint attr;
X{
X        rg.h.ah = 0x16;         /* set the forground character attribute */
X        rg.h.bl = attr;
X        int86( 0x49, &rg, &rg );
X}
X
Xtifcol(color)           /* set the current output color */
X
Xint color;      /* color to set */
X
X{
X        cfcolor = ctrans[color];
X        setatt ( cfcolor );
X}
X
Xtibcol(color)           /* set the current background color */
X
Xint color;      /* color to set */
X
X{
X        cbcolor = ctrans[color];
X}
X#endif
X
Xtimove(row, col)
X{
X        rg.h.ah = 2;            /* set cursor position function code */
X        rg.h.dh = col;
X        rg.h.dl = row;
X        int86(0x49, &rg, &rg);
X}
X
Xtieeol()        /* erase to the end of the line */
X
X{
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        int86(0x49, &rg, &rg);
X        ccol = rg.h.dh;         /* record current column */
X        crow = rg.h.dl;         /* and row */
X
X        rg.h.ah = 0x09;         /* Write character at cursor position */
X        rg.h.al = ' ';          /* Space */
X        rg.h.bl = cfcolor;
X        rg.x.cx = NCOL-ccol;    /* Number of characters to write */
X        int86(0x49, &rg, &rg);
X
X}
X
Xtiputc(ch)      /* put a character at the current position in the
X                   current colors */
X
Xint ch;
X
X{
X        rg.h.ah = 0x0E;         /* write char to screen with current attrs */
X        rg.h.al = ch;
X        int86(0x49, &rg, &rg);
X}
X
Xtieeop()                        /* Actually a clear screen */
X{
X
X        rg.h.ah = 0x13;         /* Clear Text Screen and Home Cursor */
X        int86(0x49, &rg, &rg);
X}
X
Xtirev(state)            /* change reverse video state */
X
Xint state;      /* TRUE = reverse, FALSE = normal */
X
X{
X        setatt( state ? cbcolor : cfcolor  );
X}
X
Xticres()	/* change screen resolution */
X
X{
X	return(TRUE);
X}
X
Xspal()		/* change palette string */
X
X{
X	/*	Does nothing here	*/
X}
X
Xtibeep()
X{
X        bdos(6, BEL, 0);
X}
X
Xtiopen()
X{
X	strcpy(sres, "NORMAL");
X        revexist = TRUE;
X        ttopen();
X}
X
Xticlose()
X
X{
X#if     COLOR
X        tifcol(7);
X        tibcol(0);
X#endif
X        ttclose();
X}
X#else
Xtihello()
X{
X}
X#endif
X
FRIDAY_NIGHT
echo extracting - vmsvt.c
sed 's/^X//' > vmsvt.c << 'FRIDAY_NIGHT'
X/*
X *  Advanced VMS terminal driver
X *
X *  Knows about any terminal defined in SMGTERMS.TXT and TERMTABLE.TXT
X *  located in SYS$SYSTEM.
X *
X *  Author:  Curtis Smith
X *  Last Updated: 07/14/87
X */
X
X#include	<stdio.h>		/* Standard I/O package		*/
X#include	"estruct.h"		/* Emacs' structures		*/
X#include	"edef.h"		/* Emacs' definitions		*/
X
X#if	VMSVT
X
X#include	 <descrip.h>		/* Descriptor definitions	*/
X
X/*  These would normally come from iodef.h and ttdef.h  */
X#define IO$_SENSEMODE	0x27		/* Sense mode of terminal	*/
X#define TT$_UNKNOWN	0x00		/* Unknown terminal		*/
X
X/** Forward references **/
Xint vmsopen(), ttclose(), vmskopen(), vmskclose(), ttgetc(), ttputc();
Xint ttflush(), vmsmove(), vmseeol(), vmseeop(), vmsbeep(), vmsrev();
Xint vmscres();
Xextern int eolexist, revexist;
Xextern char sres[];
X
X#if COLOR
Xint vmsfcol(), vmsbcol();
X#endif
X
X/** SMG stuff **/
Xstatic char * begin_reverse, * end_reverse, * erase_to_end_line;
Xstatic char * erase_whole_display;
Xstatic int termtype;
X
X#define SMG$K_BEGIN_REVERSE		0x1bf
X#define SMG$K_END_REVERSE		0x1d6
X#define SMG$K_SET_CURSOR_ABS		0x23a
X#define SMG$K_ERASE_WHOLE_DISPLAY	0x1da
X#define SMG$K_ERASE_TO_END_LINE		0x1d9
X
X
X/* Dispatch table. All hard fields just point into the terminal I/O code. */
XTERM	term	= {
X	24 - 1,				/* Max number of rows allowable */
X	/* Filled in */ - 1,		/* Current number of rows used	*/
X	132,				/* Max number of columns	*/
X	/* Filled in */ 0,		/* Current number of columns	*/
X	64,				/* Min margin for extended lines*/
X	8,				/* Size of scroll region	*/
X	100,				/* # times thru update to pause */
X	vmsopen,			/* Open terminal at the start	*/
X	ttclose,			/* Close terminal at end	*/
X	vmskopen,			/* Open keyboard		*/
X	vmskclose,			/* Close keyboard		*/
X	ttgetc,				/* Get character from keyboard	*/
X	ttputc,				/* Put character to display	*/
X	ttflush,			/* Flush output buffers		*/
X	vmsmove,			/* Move cursor, origin 0	*/
X	vmseeol,			/* Erase to end of line		*/
X	vmseeop,			/* Erase to end of page		*/
X	vmsbeep,			/* Beep				*/
X	vmsrev,				/* Set reverse video state	*/
X	vmscres				/* Change screen resolution	*/
X#if	COLOR
X	, vmsfcol,			/* Set forground color		*/
X	vmsbcol				/* Set background color		*/
X#endif
X};
X
X/***
X *  ttputs  -  Send a string to ttputc
X *
X *  Nothing returned
X ***/
Xttputs(string)
Xchar * string;				/* String to write		*/
X{
X	if (string)
X		while (*string != '\0')
X			ttputc(*string++);
X}
X
X
X/***
X *  vmsmove  -  Move the cursor (0 origin)
X *
X *  Nothing returned
X ***/
Xvmsmove(row, col)
Xint row;				/* Row position			*/
Xint col;				/* Column position		*/
X{
X	char buffer[32];
X	int ret_length;
X	static int request_code = SMG$K_SET_CURSOR_ABS;
X	static int max_buffer_length = sizeof(buffer);
X	static int arg_list[3] = { 2 };
X	register char * cp;
X	
X	register int i;
X
X	/* Set the arguments into the arg_list array
X	 * SMG assumes the row/column positions are 1 based (boo!)
X	 */
X	arg_list[1] = row + 1;
X	arg_list[2] = col + 1;
X
X	if ((smg$get_term_data(		/* Get terminal data		*/
X		&termtype,		/* Terminal table address	*/
X		&request_code,		/* Request code			*/
X		&max_buffer_length,	/* Maximum buffer length	*/
X		&ret_length,		/* Return length		*/
X		buffer,			/* Capability data buffer	*/
X		arg_list)		/* Argument list array		*/
X
X	/* We'll know soon enough if this doesn't work		*/
X			& 1) == 0) {
X				ttputs("OOPS");
X				return;
X			}
X
X	/* Send out resulting sequence				*/
X	i = ret_length;
X	cp = buffer;
X	while (i-- > 0)
X		ttputc(*cp++);
X}
X
X
X/***
X *  vmsrev  -  Set the reverse video status
X *
X *  Nothing returned
X ***/
Xvmsrev(status)
Xint status;				/* TRUE if setting reverse	*/
X{
X	if (status)
X		ttputs(begin_reverse);
X	else 
X		ttputs(end_reverse);
X}
X
X/***
X *  vmscres  -  Change screen resolution (which it doesn't)
X *
X *  Nothing returned
X ***/
Xvmscres()
X{
X	/* But it could.  For vt100/vt200s, one could switch from
X	80 and 132 columns modes */
X}
X
X
X#if	COLOR
X/***
X *  vmsfcol  -  Set the forground color (not implimented)
X *
X *  Nothing returned
X ***/
Xvmsfcol()
X{
X}
X
X/***
X *  vmsbcol  -  Set the background color (not implimented)
X *
X *  Nothing returned
X ***/
Xvmsbcol()
X{
X}
X#endif
X
X/***
X *  vmseeol  -  Erase to end of line
X *
X *  Nothing returned
X ***/
Xvmseeol()
X{
X	ttputs(erase_to_end_line);
X}
X
X
X/***
X *  vmseeop  -  Erase to end of page (clear screen)
X *
X *  Nothing returned
X ***/
Xvmseeop()
X{
X	ttputs(erase_whole_display);
X}
X
X
X/***
X *  vmsbeep  -  Ring the bell
X *
X *  Nothing returned
X ***/
Xvmsbeep()
X{
X	ttputc('\007');
X}
X
X
X/***
X *  vmsgetstr  -  Get an SMG string capability by name
X *
X *  Returns:	Escape sequence
X *		NULL	No escape sequence available
X ***/ 
Xchar * vmsgetstr(request_code)
Xint request_code;			/* Request code			*/
X{
X	register char * result;
X	static char seq_storage[1024];
X	static char * buffer = seq_storage;
X	static int arg_list[2] = { 1, 1 };
X	int max_buffer_length, ret_length;
X
X	/*  Precompute buffer length */
X	
X	max_buffer_length = (seq_storage + sizeof(seq_storage)) - buffer;
X
X	/* Get terminal commands sequence from master table */
X
X	if ((smg$get_term_data(	/* Get terminal data		*/
X		&termtype,	/* Terminal table address	*/
X		&request_code,	/* Request code			*/
X		&max_buffer_length,/* Maximum buffer length	*/
X		&ret_length,	/* Return length		*/
X		buffer,		/* Capability data buffer	*/
X		arg_list)	/* Argument list array		*/
X
X	/* If this doesn't work, try again with no arguments */
X	
X		& 1) == 0 && 
X
X		(smg$get_term_data(	/* Get terminal data		*/
X			&termtype,	/* Terminal table address	*/
X			&request_code,	/* Request code			*/
X			&max_buffer_length,/* Maximum buffer length	*/
X			&ret_length,	/* Return length		*/
X			buffer)		/* Capability data buffer	*/
X
X	/* Return NULL pointer if capability is not available */
X	
X			& 1) == 0)
X				return NULL;
X
X	/* Check for empty result */
X	if (ret_length == 0)
X		return NULL;
X	
X	/* Save current position so we can return it to caller */
X
X	result = buffer;
X
X	/* NIL terminate the sequence for return */
X	
X	buffer[ret_length] = 0;
X
X	/* Advance buffer */
X
X	buffer += ret_length + 1;
X
X	/* Return capability to user */
X	return result;
X}
X
X
X/** I/O information block definitions **/
Xstruct iosb {			/* I/O status block			*/
X	short	i_cond;		/* Condition value			*/
X	short	i_xfer;		/* Transfer count			*/
X	long	i_info;		/* Device information			*/
X};
Xstruct termchar {		/* Terminal characteristics		*/
X	char	t_class;	/* Terminal class			*/
X	char	t_type;		/* Terminal type			*/
X	short	t_width;	/* Terminal width in characters		*/
X	long	t_mandl;	/* Terminal's mode and length		*/
X	long	t_extend;	/* Extended terminal characteristics	*/
X};
Xstatic struct termchar tc;	/* Terminal characteristics		*/
X
X/***
X *  vmsgtty - Get terminal type from system control block
X *
X *  Nothing returned
X ***/
Xvmsgtty()
X{
X	short fd;
X	int status;
X	struct iosb iostatus;
X	$DESCRIPTOR(devnam, "SYS$INPUT");
X
X	/* Assign input to a channel */
X	status = sys$assign(&devnam, &fd, 0, 0);
X	if ((status & 1) == 0)
X		exit (status);
X
X	/* Get terminal characteristics */
X	status = sys$qiow(		/* Queue and wait		*/
X		0,			/* Wait on event flag zero	*/
X		fd,			/* Channel to input terminal	*/
X		IO$_SENSEMODE,		/* Get current characteristic	*/
X		&iostatus,		/* Status after operation	*/
X		0, 0,			/* No AST service		*/
X		&tc,			/* Terminal characteristics buf */
X		sizeof(tc),		/* Size of the buffer		*/
X		0, 0, 0, 0);		/* P3-P6 unused			*/
X
X	/* De-assign the input device */
X	if ((sys$dassgn(fd) & 1) == 0)
X		exit(status);
X
X	/* Jump out if bad status */
X	if ((status & 1) == 0)
X		exit(status);
X	if ((iostatus.i_cond & 1) == 0)
X		exit(iostatus.i_cond);
X}
X
X
X/***
X *  vmsopen  -  Get terminal type and open terminal
X *
X *  Nothing returned
X ***/
Xvmsopen()
X{
X	/* Get terminal type */
X	vmsgtty();
X	if (tc.t_type == TT$_UNKNOWN) {
X		printf("Terminal type is unknown!\n");
X		printf("Try set your terminal type with SET TERMINAL/INQUIRE\n");
X		printf("Or get help on SET TERMINAL/DEVICE_TYPE\n");
X		exit(3);
X	}
X
X	/* Access the system terminal definition table for the		*/
X	/* information of the terminal type returned by IO$_SENSEMODE	*/
X	if ((smg$init_term_table_by_type(&tc.t_type, &termtype) & 1) == 0)
X		return -1;
X		
X	/* Set sizes */
X	term.t_nrow = ((unsigned int) tc.t_mandl >> 24) - 1;
X	term.t_ncol = tc.t_width;
X
X	/* Get some capabilities */
X	begin_reverse = vmsgetstr(SMG$K_BEGIN_REVERSE);
X	end_reverse = vmsgetstr(SMG$K_END_REVERSE);
X	revexist = begin_reverse != NULL && end_reverse != NULL;
X	erase_to_end_line = vmsgetstr(SMG$K_ERASE_TO_END_LINE);
X	eolexist = erase_to_end_line != NULL;
X	erase_whole_display = vmsgetstr(SMG$K_ERASE_WHOLE_DISPLAY);
X
X	/* Set resolution */
X	strcpy(sres, "NORMAL");
X
X	/* Open terminal I/O drivers */
X	ttopen();
X}
X
X
X/***
X *  vmskopen  -  Open keyboard (not used)
X *
X *  Nothing returned
X ***/
Xvmskopen()
X{
X}
X
X
X/***
X *  vmskclose  -  Close keyboard (not used)
X *
X *  Nothing returned
X ***/
Xvmskclose()
X{
X}
X
X
X/***
X *  fnclabel  -  Label function keys (not used)
X *
X *  Nothing returned
X ***/
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
Xint f,n;	/* default flag, numeric argument [unused] */
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X
X
X/***
X *  spal  -  Set palette type  (Are you kidding?)
X *
X *  Nothing returned
X ***/
Xspal()
X{
X}
X
X#else
X
X/***
X *  hellovms  -  Avoid error because of empty module
X *
X *  Nothing returned
X ***/
Xhellovms()
X{
X}
X
X#endif
FRIDAY_NIGHT
echo mes.12 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/17/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.13')
# If you do not see the message
#	`mes.13 completed!'
# then the file was incomplete.
echo extracting - vt52.c
sed 's/^X//' > vt52.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file
X * provide support for VT52 style terminals
X * over a serial line. The serial I/O services are
X * provided by routines in "termio.c". It compiles
X * into nothing if not a VT52 style device. The
X * bell on the VT52 is terrible, so the "beep"
X * routine is conditionalized on defining BEL.
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     VT52
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	100			/* # times thru update to pause */
X#define BIAS    0x20                    /* Origin 0 coordinate bias.    */
X#define ESC     0x1B                    /* ESC character.               */
X#define BEL     0x07                    /* ascii bell character         */
X
Xextern  int     ttopen();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern  int     ttclose();
Xextern  int     vt52move();
Xextern  int     vt52eeol();
Xextern  int     vt52eeop();
Xextern  int     vt52beep();
Xextern  int     vt52open();
Xextern	int	vt52rev();
Xextern	int	vt52cres();
Xextern	int	vt52kopen();
Xextern	int	vt52kclose();
X
X#if	COLOR
Xextern	int	vt52fcol();
Xextern	int	vt52bcol();
X#endif
X
X/*
X * Dispatch table. All the
X * hard fields just point into the
X * terminal I/O code.
X */
XTERM    term    = {
X	NROW-1,
X        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        &vt52open,
X        &ttclose,
X	&vt52kopen,
X	&vt52kclose,
X        &ttgetc,
X        &ttputc,
X        &ttflush,
X        &vt52move,
X        &vt52eeol,
X        &vt52eeop,
X        &vt52beep,
X        &vt52rev,
X        &vt52cres
X#if	COLOR
X	, &vt52fcol,
X	&vt52bcol
X#endif
X};
X
Xvt52move(row, col)
X{
X        ttputc(ESC);
X        ttputc('Y');
X        ttputc(row+BIAS);
X        ttputc(col+BIAS);
X}
X
Xvt52eeol()
X{
X        ttputc(ESC);
X        ttputc('K');
X}
X
Xvt52eeop()
X{
X        ttputc(ESC);
X        ttputc('J');
X}
X
Xvt52rev(status)	/* set the reverse video state */
X
Xint status;	/* TRUE = reverse video, FALSE = normal video */
X
X{
X	/* can't do this here, so we won't */
X}
X
Xvt52cres()	/* change screen resolution - (not here though) */
X
X{
X	return(TRUE);
X}
X
Xspal()		/* change palette string */
X
X{
X	/*	Does nothing here	*/
X}
X
X#if	COLOR
Xvt52fcol()	/* set the forground color [NOT IMPLIMENTED] */
X{
X}
X
Xvt52bcol()	/* set the background color [NOT IMPLIMENTED] */
X{
X}
X#endif
X
Xvt52beep()
X{
X#ifdef  BEL
X        ttputc(BEL);
X        ttflush();
X#endif
X}
X
Xvt52open()
X{
X#if     V7 | BSD
X        register char *cp;
X        char *getenv();
X
X        if ((cp = getenv("TERM")) == NULL) {
X                puts("Shell variable TERM not defined!");
X                exit(1);
X        }
X        if (strcmp(cp, "vt52") != 0 && strcmp(cp, "z19") != 0) {
X                puts("Terminal type not 'vt52'or 'z19' !");
X                exit(1);
X        }
X#endif
X        ttopen();
X}
X
Xvt52kopen()
X
X{
X}
X
Xvt52kclose()
X
X{
X}
X
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument [unused] */
X
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X#else
X
Xvt52hello()
X
X{
X}
X
X#endif
FRIDAY_NIGHT
echo extracting - window.c
sed 's/^X//' > window.c << 'FRIDAY_NIGHT'
X/*
X * Window management. Some of the functions are internal, and some are
X * attached to keys that the user actually types.
X */
X
X#include        <stdio.h>
X#include        "estruct.h"
X#include	"edef.h"
X
X#if	MEGAMAX & ST520
Xoverlay	"window"
X#endif
X
X/*
X * Reposition dot in the current window to line "n". If the argument is
X * positive, it is that line. If it is negative it is that line from the
X * bottom. If it is 0 the window is centered (this is what the standard
X * redisplay code does). With no argument it defaults to 0. Bound to M-!.
X */
Xreposition(f, n)
X    {
X    if (f == FALSE)	/* default to 0 to center screen */
X	n = 0;
X    curwp->w_force = n;
X    curwp->w_flag |= WFFORCE;
X    return (TRUE);
X    }
X
X/*
X * Refresh the screen. With no argument, it just does the refresh. With an
X * argument it recenters "." in the current window. Bound to "C-L".
X */
Xrefresh(f, n)
X    {
X    if (f == FALSE)
X        sgarbf = TRUE;
X    else
X        {
X        curwp->w_force = 0;             /* Center dot. */
X        curwp->w_flag |= WFFORCE;
X        }
X
X    return (TRUE);
X    }
X
X/*
X * The command make the next window (next => down the screen) the current
X * window. There are no real errors, although the command does nothing if
X * there is only 1 window on the screen. Bound to "C-X C-N".
X *
X * with an argument this command finds the <n>th window from the top
X *
X */
Xnextwind(f, n)
X
Xint f, n;	/* default flag and numeric argument */
X
X{
X	register WINDOW *wp;
X	register int nwindows;		/* total number of windows */
X
X	if (f) {
X
X		/* first count the # of windows */
X		wp = wheadp;
X		nwindows = 1;
X		while (wp->w_wndp != NULL) {
X			nwindows++;
X			wp = wp->w_wndp;
X		}
X
X		/* if the argument is negative, it is the nth window
X		   from the bottom of the screen			*/
X		if (n < 0)
X			n = nwindows + n + 1;
X
X		/* if an argument, give them that window from the top */
X		if (n > 0 && n <= nwindows) {
X			wp = wheadp;
X			while (--n)
X				wp = wp->w_wndp;
X		} else {
X			mlwrite("Window number out of range");
X			return(FALSE);
X		}
X	} else
X		if ((wp = curwp->w_wndp) == NULL)
X			wp = wheadp;
X	curwp = wp;
X	curbp = wp->w_bufp;
X	upmode();
X	return (TRUE);
X}
X
X/*
X * This command makes the previous window (previous => up the screen) the
X * current window. There arn't any errors, although the command does not do a
X * lot if there is 1 window.
X */
Xprevwind(f, n)
X{
X	register WINDOW *wp1;
X	register WINDOW *wp2;
X
X	/* if we have an argument, we mean the nth window from the bottom */
X	if (f)
X		return(nextwind(f, -n));
X
X	wp1 = wheadp;
X	wp2 = curwp;
X
X	if (wp1 == wp2)
X		wp2 = NULL;
X
X	while (wp1->w_wndp != wp2)
X		wp1 = wp1->w_wndp;
X
X	curwp = wp1;
X	curbp = wp1->w_bufp;
X	upmode();
X	return (TRUE);
X}
X
X/*
X * This command moves the current window down by "arg" lines. Recompute the
X * top line in the window. The move up and move down code is almost completely
X * the same; most of the work has to do with reframing the window, and picking
X * a new dot. We share the code by having "move down" just be an interface to
X * "move up". Magic. Bound to "C-X C-N".
X */
Xmvdnwind(f, n)
X
Xint n;
X
X{
X	return (mvupwind(f, -n));
X}
X
X/*
X * Move the current window up by "arg" lines. Recompute the new top line of
X * the window. Look to see if "." is still on the screen. If it is, you win.
X * If it isn't, then move "." to center it in the new framing of the window
X * (this command does not really move "."; it moves the frame). Bound to
X * "C-X C-P".
X */
Xmvupwind(f, n)
X    int n;
X
X    {
X    register LINE *lp;
X    register int i;
X
X    lp = curwp->w_linep;
X
X    if (n < 0)
X        {
X        while (n++ && lp!=curbp->b_linep)
X            lp = lforw(lp);
X        }
X    else
X        {
X        while (n-- && lback(lp)!=curbp->b_linep)
X            lp = lback(lp);
X        }
X
X    curwp->w_linep = lp;
X    curwp->w_flag |= WFHARD;            /* Mode line is OK. */
X
X    for (i = 0; i < curwp->w_ntrows; ++i)
X        {
X        if (lp == curwp->w_dotp)
X            return (TRUE);
X        if (lp == curbp->b_linep)
X            break;
X        lp = lforw(lp);
X        }
X
X    lp = curwp->w_linep;
X    i  = curwp->w_ntrows/2;
X
X    while (i-- && lp != curbp->b_linep)
X        lp = lforw(lp);
X
X    curwp->w_dotp  = lp;
X    curwp->w_doto  = 0;
X    return (TRUE);
X    }
X
X/*
X * This command makes the current window the only window on the screen. Bound
X * to "C-X 1". Try to set the framing so that "." does not have to move on the
X * display. Some care has to be taken to keep the values of dot and mark in
X * the buffer structures right if the distruction of a window makes a buffer
X * become undisplayed.
X */
Xonlywind(f, n)
X{
X        register WINDOW *wp;
X        register LINE   *lp;
X        register int    i;
X
X        while (wheadp != curwp) {
X                wp = wheadp;
X                wheadp = wp->w_wndp;
X                if (--wp->w_bufp->b_nwnd == 0) {
X                        wp->w_bufp->b_dotp  = wp->w_dotp;
X                        wp->w_bufp->b_doto  = wp->w_doto;
X                        wp->w_bufp->b_markp = wp->w_markp;
X                        wp->w_bufp->b_marko = wp->w_marko;
X                }
X                free((char *) wp);
X        }
X        while (curwp->w_wndp != NULL) {
X                wp = curwp->w_wndp;
X                curwp->w_wndp = wp->w_wndp;
X                if (--wp->w_bufp->b_nwnd == 0) {
X                        wp->w_bufp->b_dotp  = wp->w_dotp;
X                        wp->w_bufp->b_doto  = wp->w_doto;
X                        wp->w_bufp->b_markp = wp->w_markp;
X                        wp->w_bufp->b_marko = wp->w_marko;
X                }
X                free((char *) wp);
X        }
X        lp = curwp->w_linep;
X        i  = curwp->w_toprow;
X        while (i!=0 && lback(lp)!=curbp->b_linep) {
X                --i;
X                lp = lback(lp);
X        }
X        curwp->w_toprow = 0;
X        curwp->w_ntrows = term.t_nrow-1;
X        curwp->w_linep  = lp;
X        curwp->w_flag  |= WFMODE|WFHARD;
X        return (TRUE);
X}
X
X/*
X * Delete the current window, placing its space in the window above,
X * or, if it is the top window, the window below. Bound to C-X 0.
X */
X
Xdelwind(f,n)
X
Xint f, n;	/* arguments are ignored for this command */
X
X{
X	register WINDOW *wp;	/* window to recieve deleted space */
X	register WINDOW *lwp;	/* ptr window before curwp */
X	register int target;	/* target line to search for */
X
X	/* if there is only one window, don't delete it */
X	if (wheadp->w_wndp == NULL) {
X		mlwrite("Can not delete this window");
X		return(FALSE);
X	}
X
X	/* find window before curwp in linked list */
X	wp = wheadp;
X	lwp = NULL;
X	while (wp != NULL) {
X		if (wp == curwp)
X			break;
X		lwp = wp;
X		wp = wp->w_wndp;
X	}
X
X	/* find recieving window and give up our space */
X	wp = wheadp;
X	if (curwp->w_toprow == 0) {
X		/* find the next window down */
X		target = curwp->w_ntrows + 1;
X		while (wp != NULL) {
X			if (wp->w_toprow == target)
X				break;
X			wp = wp->w_wndp;
X		}
X		if (wp == NULL)
X			return(FALSE);
X		wp->w_toprow = 0;
X		wp->w_ntrows += target;
X	} else {
X		/* find the next window up */
X		target = curwp->w_toprow - 1;
X		while (wp != NULL) {
X			if ((wp->w_toprow + wp->w_ntrows) == target)
X				break;
X			wp = wp->w_wndp;
X		}
X		if (wp == NULL)
X			return(FALSE);
X		wp->w_ntrows += 1 + curwp->w_ntrows;
X	}
X
X	/* get rid of the current window */
X	if (--curwp->w_bufp->b_nwnd == 0) {
X		curwp->w_bufp->b_dotp = curwp->w_dotp;
X		curwp->w_bufp->b_doto = curwp->w_doto;
X		curwp->w_bufp->b_markp = curwp->w_markp;
X		curwp->w_bufp->b_marko = curwp->w_marko;
X	}
X	if (lwp == NULL)
X		wheadp = curwp->w_wndp;
X	else
X		lwp->w_wndp = curwp->w_wndp;
X	free((char *)curwp);
X	curwp = wp;
X	wp->w_flag |= WFHARD;
X	curbp = wp->w_bufp;
X	upmode();
X	return(TRUE);
X}
X
X/*
X
XSplit the current window.  A window smaller than 3 lines cannot be
Xsplit.  An argument of 1 forces the cursor into the upper window, an
Xargument of two forces the cursor to the lower window.  The only other
Xerror that is possible is a "malloc" failure allocating the structure
Xfor the new window.  Bound to "C-X 2". 
X
X */
Xsplitwind(f, n)
X
Xint f, n;	/* default flag and numeric argument */
X
X{
X        register WINDOW *wp;
X        register LINE   *lp;
X        register int    ntru;
X        register int    ntrl;
X        register int    ntrd;
X        register WINDOW *wp1;
X        register WINDOW *wp2;
X	char *malloc();
X
X        if (curwp->w_ntrows < 3) {
X                mlwrite("Cannot split a %d line window", curwp->w_ntrows);
X                return (FALSE);
X        }
X        if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
X                mlwrite("[OUT OF MEMORY]");
X                return (FALSE);
X        }
X        ++curbp->b_nwnd;                        /* Displayed twice.     */
X        wp->w_bufp  = curbp;
X        wp->w_dotp  = curwp->w_dotp;
X        wp->w_doto  = curwp->w_doto;
X        wp->w_markp = curwp->w_markp;
X        wp->w_marko = curwp->w_marko;
X        wp->w_flag  = 0;
X        wp->w_force = 0;
X#if	COLOR
X	/* set the colors of the new window */
X	wp->w_fcolor = gfcolor;
X	wp->w_bcolor = gbcolor;
X#endif
X        ntru = (curwp->w_ntrows-1) / 2;         /* Upper size           */
X        ntrl = (curwp->w_ntrows-1) - ntru;      /* Lower size           */
X        lp = curwp->w_linep;
X        ntrd = 0;
X        while (lp != curwp->w_dotp) {
X                ++ntrd;
X                lp = lforw(lp);
X        }
X        lp = curwp->w_linep;
X        if (((f == FALSE) && (ntrd <= ntru)) || ((f == TRUE) && (n == 1))) {
X                /* Old is upper window. */
X                if (ntrd == ntru)               /* Hit mode line.       */
X                        lp = lforw(lp);
X                curwp->w_ntrows = ntru;
X                wp->w_wndp = curwp->w_wndp;
X                curwp->w_wndp = wp;
X                wp->w_toprow = curwp->w_toprow+ntru+1;
X                wp->w_ntrows = ntrl;
X        } else {                                /* Old is lower window  */
X                wp1 = NULL;
X                wp2 = wheadp;
X                while (wp2 != curwp) {
X                        wp1 = wp2;
X                        wp2 = wp2->w_wndp;
X                }
X                if (wp1 == NULL)
X                        wheadp = wp;
X                else
X                        wp1->w_wndp = wp;
X                wp->w_wndp   = curwp;
X                wp->w_toprow = curwp->w_toprow;
X                wp->w_ntrows = ntru;
X                ++ntru;                         /* Mode line.           */
X                curwp->w_toprow += ntru;
X                curwp->w_ntrows  = ntrl;
X                while (ntru--)
X                        lp = lforw(lp);
X        }
X        curwp->w_linep = lp;                    /* Adjust the top lines */
X        wp->w_linep = lp;                       /* if necessary.        */
X        curwp->w_flag |= WFMODE|WFHARD;
X        wp->w_flag |= WFMODE|WFHARD;
X        return (TRUE);
X}
X
X/*
X * Enlarge the current window. Find the window that loses space. Make sure it
X * is big enough. If so, hack the window descriptions, and ask redisplay to do
X * all the hard work. You don't just set "force reframe" because dot would
X * move. Bound to "C-X Z".
X */
Xenlargewind(f, n)
X{
X        register WINDOW *adjwp;
X        register LINE   *lp;
X        register int    i;
X
X        if (n < 0)
X                return (shrinkwind(f, -n));
X        if (wheadp->w_wndp == NULL) {
X                mlwrite("Only one window");
X                return (FALSE);
X        }
X        if ((adjwp=curwp->w_wndp) == NULL) {
X                adjwp = wheadp;
X                while (adjwp->w_wndp != curwp)
X                        adjwp = adjwp->w_wndp;
X        }
X        if (adjwp->w_ntrows <= n) {
X                mlwrite("Impossible change");
X                return (FALSE);
X        }
X        if (curwp->w_wndp == adjwp) {           /* Shrink below.        */
X                lp = adjwp->w_linep;
X                for (i=0; i<n && lp!=adjwp->w_bufp->b_linep; ++i)
X                        lp = lforw(lp);
X                adjwp->w_linep  = lp;
X                adjwp->w_toprow += n;
X        } else {                                /* Shrink above.        */
X                lp = curwp->w_linep;
X                for (i=0; i<n && lback(lp)!=curbp->b_linep; ++i)
X                        lp = lback(lp);
X                curwp->w_linep  = lp;
X                curwp->w_toprow -= n;
X        }
X        curwp->w_ntrows += n;
X        adjwp->w_ntrows -= n;
X        curwp->w_flag |= WFMODE|WFHARD;
X        adjwp->w_flag |= WFMODE|WFHARD;
X        return (TRUE);
X}
X
X/*
X * Shrink the current window. Find the window that gains space. Hack at the
X * window descriptions. Ask the redisplay to do all the hard work. Bound to
X * "C-X C-Z".
X */
Xshrinkwind(f, n)
X{
X        register WINDOW *adjwp;
X        register LINE   *lp;
X        register int    i;
X
X        if (n < 0)
X                return (enlargewind(f, -n));
X        if (wheadp->w_wndp == NULL) {
X                mlwrite("Only one window");
X                return (FALSE);
X        }
X        if ((adjwp=curwp->w_wndp) == NULL) {
X                adjwp = wheadp;
X                while (adjwp->w_wndp != curwp)
X                        adjwp = adjwp->w_wndp;
X        }
X        if (curwp->w_ntrows <= n) {
X                mlwrite("Impossible change");
X                return (FALSE);
X        }
X        if (curwp->w_wndp == adjwp) {           /* Grow below.          */
X                lp = adjwp->w_linep;
X                for (i=0; i<n && lback(lp)!=adjwp->w_bufp->b_linep; ++i)
X                        lp = lback(lp);
X                adjwp->w_linep  = lp;
X                adjwp->w_toprow -= n;
X        } else {                                /* Grow above.          */
X                lp = curwp->w_linep;
X                for (i=0; i<n && lp!=curbp->b_linep; ++i)
X                        lp = lforw(lp);
X                curwp->w_linep  = lp;
X                curwp->w_toprow += n;
X        }
X        curwp->w_ntrows -= n;
X        adjwp->w_ntrows += n;
X        curwp->w_flag |= WFMODE|WFHARD;
X        adjwp->w_flag |= WFMODE|WFHARD;
X        return (TRUE);
X}
X
X/*	Resize the current window to the requested size	*/
X
Xresize(f, n)
X
Xint f, n;	/* default flag and numeric argument */
X
X{
X	int clines;	/* current # of lines in window */
X	
X	/* must have a non-default argument, else ignore call */
X	if (f == FALSE)
X		return(TRUE);
X
X	/* find out what to do */
X	clines = curwp->w_ntrows;
X
X	/* already the right size? */
X	if (clines == n)
X		return(TRUE);
X
X	return(enlargewind(TRUE, n - clines));
X}
X
X/*
X * Pick a window for a pop-up. Split the screen if there is only one window.
X * Pick the uppermost window that isn't the current window. An LRU algorithm
X * might be better. Return a pointer, or NULL on error.
X */
XWINDOW  *
Xwpopup()
X{
X        register WINDOW *wp;
X
X        if (wheadp->w_wndp == NULL              /* Only 1 window        */
X        && splitwind(FALSE, 0) == FALSE)        /* and it won't split   */
X                return (NULL);
X        wp = wheadp;                            /* Find window to use   */
X        while (wp!=NULL && wp==curwp)
X                wp = wp->w_wndp;
X        return (wp);
X}
X
Xscrnextup(f, n)		/* scroll the next window up (back) a page */
X
X{
X	nextwind(FALSE, 1);
X	backpage(f, n);
X	prevwind(FALSE, 1);
X}
X
Xscrnextdw(f, n)		/* scroll the next window down (forward) a page */
X
X{
X	nextwind(FALSE, 1);
X	forwpage(f, n);
X	prevwind(FALSE, 1);
X}
X
Xsavewnd(f, n)		/* save ptr to current window */
X
X{
X	swindow = curwp;
X	return(TRUE);
X}
X
Xrestwnd(f, n)		/* restore the saved screen */
X
X{
X	register WINDOW *wp;
X
X	/* find the window */
X	wp = wheadp;
X	while (wp != NULL) {
X		if (wp == swindow) {
X			curwp = wp;
X			curbp = wp->w_bufp;
X			upmode();
X			return (TRUE);
X		}
X		wp = wp->w_wndp;
X	}
X
X	mlwrite("[No such window exists]");
X	return(FALSE);
X}
X
Xnewsize(f, n)	/* resize the screen, re-writing the screen */
X
Xint f;	/* default flag */
Xint n;	/* numeric argument */
X
X{
X	WINDOW *wp;	/* current window being examined */
X	WINDOW *nextwp;	/* next window to scan */
X	WINDOW *lastwp;	/* last window scanned */
X	int lastline;	/* screen line of last line of current window */
X
X	/* if the command defaults, assume the largest */
X	if (f == FALSE)
X		n = term.t_mrow + 1;
X
X	/* make sure it's in range */
X	if (n < 3 || n > term.t_mrow + 1) {
X		mlwrite("%%Screen size out of range");
X		return(FALSE);
X	}
X
X	if (term.t_nrow == n - 1)
X		return(TRUE);
X	else if (term.t_nrow < n - 1) {
X
X		/* go to the last window */
X		wp = wheadp;
X		while (wp->w_wndp != NULL)
X			wp = wp->w_wndp;
X
X		/* and enlarge it as needed */
X		wp->w_ntrows = n - wp->w_toprow - 2;
X		wp->w_flag |= WFHARD|WFMODE;
X
X	} else {
X
X		/* rebuild the window structure */
X		nextwp = wheadp;
X		wp = NULL;
X		lastwp = NULL;
X		while (nextwp != NULL) {
X			wp = nextwp;
X			nextwp = wp->w_wndp;
X	
X			/* get rid of it if it is too low */
X			if (wp->w_toprow > n - 2) {
X
X				/* save the point/mark if needed */
X				if (--wp->w_bufp->b_nwnd == 0) {
X					wp->w_bufp->b_dotp = wp->w_dotp;
X					wp->w_bufp->b_doto = wp->w_doto;
X					wp->w_bufp->b_markp = wp->w_markp;
X					wp->w_bufp->b_marko = wp->w_marko;
X				}
X	
X				/* update curwp and lastwp if needed */
X				if (wp == curwp)
X					curwp = wheadp;
X					curbp = curwp->w_bufp;
X				if (lastwp != NULL)
X					lastwp->w_wndp = NULL;
X
X				/* free the structure */
X				free((char *)wp);
X				wp = NULL;
X
X			} else {
X				/* need to change this window size? */
X				lastline = wp->w_toprow + wp->w_ntrows - 1;
X				if (lastline >= n - 2) {
X					wp->w_ntrows = n - wp->w_toprow - 2;
X					wp->w_flag |= WFHARD|WFMODE;
X				}
X			}
X	
X			lastwp = wp;
X		}
X	}
X
X	/* screen is garbage */
X	term.t_nrow = n - 1;
X	sgarbf = TRUE;
X	return(TRUE);
X}
X
Xnewwidth(f, n)	/* resize the screen, re-writing the screen */
X
Xint f;	/* default flag */
Xint n;	/* numeric argument */
X
X{
X	register WINDOW *wp;
X
X	/* if the command defaults, assume the largest */
X	if (f == FALSE)
X		n = term.t_mcol;
X
X	/* make sure it's in range */
X	if (n < 10 || n > term.t_mcol) {
X		mlwrite("%%Screen width out of range");
X		return(FALSE);
X	}
X
X	/* otherwise, just re-width it (no big deal) */
X	term.t_ncol = n;
X	term.t_margin = n / 10;
X	term.t_scrsiz = n - (term.t_margin * 2);
X
X	/* florce all windows to redraw */
X	wp = wheadp;
X	while (wp) {
X		wp->w_flag |= WFHARD | WFMOVE | WFMODE;
X		wp = wp->w_wndp;
X	}
X	sgarbf = TRUE;
X
X	return(TRUE);
X}
X
Xint getwpos()	/* get screen offset of current line in current window */
X
X{
X	register int sline;	/* screen line from top of window */
X	register LINE *lp;	/* scannile line pointer */
X
X	/* search down the line we want */
X	lp = curwp->w_linep;
X	sline = 1;
X	while (lp != curwp->w_dotp) {
X		++sline;
X		lp = lforw(lp);
X	}
X
X	/* and return the value */
X	return(sline);
X}
FRIDAY_NIGHT
echo extracting - word.c
sed 's/^X//' > word.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file implement commands that work word or a
X * paragraph at a time.  There are all sorts of word mode commands.  If I
X * do any sentence mode commands, they are likely to be put in this file. 
X */
X
X#include	<stdio.h>
X#include	"estruct.h"
X#include	"edef.h"
X
X/* Word wrap on n-spaces. Back-over whatever precedes the point on the current
X * line and stop on the first word-break or the beginning of the line. If we
X * reach the beginning of the line, jump back to the end of the word and start
X * a new line.	Otherwise, break the line at the word-break, eat it, and jump
X * back to the end of the word.
X * Returns TRUE on success, FALSE on errors.
X */
Xwrapword(f, n)
X
Xint f;		/* default flag */
Xint n;		/* numeric argument */
X 
X{
X	register int cnt;	/* size of word wrapped to next line */
X	register int c;		/* charector temporary */
X
X	/* backup from the <NL> 1 char */
X	if (!backchar(0, 1))
X		return(FALSE);
X
X	/* back up until we aren't in a word,
X	   make sure there is a break in the line */
X	cnt = 0;
X	while (((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ')
X				&& (c != '\t')) {
X		cnt++;
X		if (!backchar(0, 1))
X			return(FALSE);
X		/* if we make it to the beginning, start a new line */
X		if (curwp->w_doto == 0) {
X			gotoeol(FALSE, 0);
X			return(lnewline());
X		}
X	}
X
X	/* delete the forward white space */
X	if (!forwdel(0, 1))
X		return(FALSE);
X
X	/* put in a end of line */
X	if (!lnewline())
X		return(FALSE);
X
X	/* and past the first word */
X	while (cnt-- > 0) {
X		if (forwchar(FALSE, 1) == FALSE)
X			return(FALSE);
X	}
X	return(TRUE);
X}
X
X/*
X * Move the cursor backward by "n" words. All of the details of motion are
X * performed by the "backchar" and "forwchar" routines. Error if you try to
X * move beyond the buffers.
X */
Xbackword(f, n)
X{
X	if (n < 0)
X		return (forwword(f, -n));
X	if (backchar(FALSE, 1) == FALSE)
X		return (FALSE);
X	while (n--) {
X		while (inword() == FALSE) {
X			if (backchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X		while (inword() != FALSE) {
X			if (backchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X	}
X	return (forwchar(FALSE, 1));
X}
X
X/*
X * Move the cursor forward by the specified number of words. All of the motion
X * is done by "forwchar". Error if you try and move beyond the buffer's end.
X */
Xforwword(f, n)
X{
X	if (n < 0)
X		return (backword(f, -n));
X	while (n--) {
X		while (inword() == TRUE) {
X			if (forwchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X
X		while (inword() == FALSE) {
X			if (forwchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X	}
X	return(TRUE);
X}
X
X/*
X * Move the cursor forward by the specified number of words. As you move,
X * convert any characters to upper case. Error if you try and move beyond the
X * end of the buffer. Bound to "M-U".
X */
Xupperword(f, n)
X{
X	register int	c;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	if (n < 0)
X		return (FALSE);
X	while (n--) {
X		while (inword() == FALSE) {
X			if (forwchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X		while (inword() != FALSE) {
X			c = lgetc(curwp->w_dotp, curwp->w_doto);
X			if (c>='a' && c<='z') {
X				c -= 'a'-'A';
X				lputc(curwp->w_dotp, curwp->w_doto, c);
X				lchange(WFHARD);
X			}
X			if (forwchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X	}
X	return (TRUE);
X}
X
X/*
X * Move the cursor forward by the specified number of words. As you move
X * convert characters to lower case. Error if you try and move over the end of
X * the buffer. Bound to "M-L".
X */
Xlowerword(f, n)
X{
X	register int	c;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	if (n < 0)
X		return (FALSE);
X	while (n--) {
X		while (inword() == FALSE) {
X			if (forwchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X		while (inword() != FALSE) {
X			c = lgetc(curwp->w_dotp, curwp->w_doto);
X			if (c>='A' && c<='Z') {
X				c += 'a'-'A';
X				lputc(curwp->w_dotp, curwp->w_doto, c);
X				lchange(WFHARD);
X			}
X			if (forwchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X	}
X	return (TRUE);
X}
X
X/*
X * Move the cursor forward by the specified number of words. As you move
X * convert the first character of the word to upper case, and subsequent
X * characters to lower case. Error if you try and move past the end of the
X * buffer. Bound to "M-C".
X */
Xcapword(f, n)
X{
X	register int	c;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	if (n < 0)
X		return (FALSE);
X	while (n--) {
X		while (inword() == FALSE) {
X			if (forwchar(FALSE, 1) == FALSE)
X				return (FALSE);
X		}
X		if (inword() != FALSE) {
X			c = lgetc(curwp->w_dotp, curwp->w_doto);
X			if (c>='a' && c<='z') {
X				c -= 'a'-'A';
X				lputc(curwp->w_dotp, curwp->w_doto, c);
X				lchange(WFHARD);
X			}
X			if (forwchar(FALSE, 1) == FALSE)
X				return (FALSE);
X			while (inword() != FALSE) {
X				c = lgetc(curwp->w_dotp, curwp->w_doto);
X				if (c>='A' && c<='Z') {
X					c += 'a'-'A';
X					lputc(curwp->w_dotp, curwp->w_doto, c);
X					lchange(WFHARD);
X				}
X				if (forwchar(FALSE, 1) == FALSE)
X					return (FALSE);
X			}
X		}
X	}
X	return (TRUE);
X}
X
X/*
X * Kill forward by "n" words. Remember the location of dot. Move forward by
X * the right number of words. Put dot back where it was and issue the kill
X * command for the right number of characters. With a zero argument, just
X * kill one word and no whitespace. Bound to "M-D".
X */
Xdelfword(f, n)
X{
X	register LINE	*dotp;	/* original cursor line */
X	register int	doto;	/*	and row */
X	register int c;		/* temp char */
X	long size;		/* # of chars to delete */
X
X	/* don't allow this command if we are in read only mode */
X	if (curbp->b_mode&MDVIEW)
X		return(rdonly());
X
X	/* ignore the command if there is a negative argument */
X	if (n < 0)
X		return (FALSE);
X
X	/* Clear the kill buffer if last command wasn't a kill */
X	if ((lastflag&CFKILL) == 0)
X		kdelete();
X	thisflag |= CFKILL;	/* this command is a kill */
X
X	/* save the current cursor position */
X	dotp = curwp->w_dotp;
X	doto = curwp->w_doto;
X
X	/* figure out how many characters to give the axe */
X	size = 0;
X
X	/* get us into a word.... */
X	while (inword() == FALSE) {
X		if (forwchar(FALSE, 1) == FALSE)
X			return(FALSE);
X		++size;
X	}
X
X	if (n == 0) {
X		/* skip one word, no whitespace! */
X		while (inword() == TRUE) {
X			if (forwchar(FALSE, 1) == FALSE)
X				return(FALSE);
X			++size;
X		}
X	} else {
X		/* skip n words.... */
X		while (n--) {
X	
X			/* if we are at EOL; skip to the beginning of the next */
X			while (curwp->w_doto == llength(curwp->w_dotp)) {
X				if (forwchar(FALSE, 1) == FALSE)
X					return(FALSE);
X				++size;
X			}
X	
X			/* move forward till we are at the end of the word */
X			while (inword() == TRUE) {
X				if (forwchar(FALSE, 1) == FALSE)
X					return(FALSE);
X				++size;
X			}
X	
X			/* if there are more words, skip the interword stuff */
X			if (n != 0)
X				while (inword() == FALSE) {
X					if (forwchar(FALSE, 1) == FALSE)
X						return(FALSE);
X					++size;
X				}
X		}
X	
X		/* skip whitespace and newlines */
X		while ((curwp->w_doto == llength(curwp->w_dotp)) ||
X			((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ') ||
X			(c == '\t')) {
X				if (forwchar(FALSE, 1) == FALSE)
X					break;
X				++size;
X		}
X	}
X
X	/* restore the original position and delete the words */
X	curwp->w_dotp = dotp;
X	curwp->w_doto = doto;
X	return (ldelete(size, TRUE));
X}
X
X/*
X * Kill backwards by "n" words. Move backwards by the desired number of words,
X * counting the characters. When dot is finally moved to its resting place,
X * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
X */
Xdelbword(f, n)
X{
X	long size;
X
X	/* don't allow this command if we are in read only mode */
X	if (curbp->b_mode&MDVIEW)
X		return(rdonly());
X
X	/* ignore the command if there is a nonpositive argument */
X	if (n <= 0)
X		return (FALSE);
X
X	/* Clear the kill buffer if last command wasn't a kill */
X	if ((lastflag&CFKILL) == 0)
X		kdelete();
X	thisflag |= CFKILL;	/* this command is a kill */
X
X	if (backchar(FALSE, 1) == FALSE)
X		return (FALSE);
X	size = 0;
X	while (n--) {
X		while (inword() == FALSE) {
X			if (backchar(FALSE, 1) == FALSE)
X				return (FALSE);
X			++size;
X		}
X		while (inword() != FALSE) {
X			++size;
X			if (backchar(FALSE, 1) == FALSE)
X				goto bckdel;
X		}
X	}
X	if (forwchar(FALSE, 1) == FALSE)
X		return (FALSE);
Xbckdel:	return (ldelete(size, TRUE));
X}
X
X/*
X * Return TRUE if the character at dot is a character that is considered to be
X * part of a word. The word character list is hard coded. Should be setable.
X */
Xinword()
X{
X	register int	c;
X
X	if (curwp->w_doto == llength(curwp->w_dotp))
X		return (FALSE);
X	c = lgetc(curwp->w_dotp, curwp->w_doto);
X	if (c>='a' && c<='z')
X		return (TRUE);
X	if (c>='A' && c<='Z')
X		return (TRUE);
X	if (c>='0' && c<='9')
X		return (TRUE);
X	return (FALSE);
X}
X
X#if	WORDPRO
Xfillpara(f, n)	/* Fill the current paragraph according to the current
X		   fill column						*/
X
Xint f, n;	/* deFault flag and Numeric argument */
X
X{
X	register int c;			/* current char durring scan	*/
X	register int wordlen;		/* length of current word	*/
X	register int clength;		/* position on line during fill	*/
X	register int i;			/* index during word copy	*/
X	register int newlength;		/* tentative new line length	*/
X	register int eopflag;		/* Are we at the End-Of-Paragraph? */
X	register int firstflag;		/* first word? (needs no space)	*/
X	register LINE *eopline;		/* pointer to line just past EOP */
X	register int dotflag;		/* was the last char a period?	*/
X	char wbuf[NSTRING];		/* buffer for current word	*/
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X	if (fillcol == 0) {	/* no fill column set */
X		mlwrite("No fill column set");
X		return(FALSE);
X	}
X
X	/* record the pointer to the line just past the EOP */
X	gotoeop(FALSE, 1);
X	eopline = lforw(curwp->w_dotp);
X
X	/* and back top the beginning of the paragraph */
X	gotobop(FALSE, 1);
X
X	/* initialize various info */
X	clength = curwp->w_doto;
X	if (clength && curwp->w_dotp->l_text[0] == TAB)
X		clength = 8;
X	wordlen = 0;
X	dotflag = FALSE;
X
X	/* scan through lines, filling words */
X	firstflag = TRUE;
X	eopflag = FALSE;
X	while (!eopflag) {
X		/* get the next character in the paragraph */
X		if (curwp->w_doto == llength(curwp->w_dotp)) {
X			c = ' ';
X			if (lforw(curwp->w_dotp) == eopline)
X				eopflag = TRUE;
X		} else
X			c = lgetc(curwp->w_dotp, curwp->w_doto);
X
X		/* and then delete it */
X		ldelete(1L, FALSE);
X
X		/* if not a separator, just add it in */
X		if (c != ' ' && c != '\t') {
X			dotflag = (c == '.');		/* was it a dot */
X			if (wordlen < NSTRING - 1)
X				wbuf[wordlen++] = c;
X		} else if (wordlen) {
X			/* at a word break with a word waiting */
X			/* calculate tentitive new length with word added */
X			newlength = clength + 1 + wordlen;
X			if (newlength <= fillcol) {
X				/* add word to current line */
X				if (!firstflag) {
X					linsert(1, ' '); /* the space */
X					++clength;
X				}
X				firstflag = FALSE;
X			} else {
X				/* start a new line */
X				lnewline();
X				clength = 0;
X			}
X
X			/* and add the word in in either case */
X			for (i=0; i<wordlen; i++) {
X				linsert(1, wbuf[i]);
X				++clength;
X			}
X			if (dotflag) {
X				linsert(1, ' ');
X				++clength;
X			}
X			wordlen = 0;
X		}
X	}
X	/* and add a last newline for the end of our new paragraph */
X	lnewline();
X	return(TRUE);
X}
X
Xkillpara(f, n)	/* delete n paragraphs starting with the current one */
X
Xint f;	/* default flag */
Xint n;	/* # of paras to delete */
X
X{
X	register int status;	/* returned status of functions */
X
X	while (n--) {		/* for each paragraph to delete */
X
X		/* mark out the end and beginning of the para to delete */
X		gotoeop(FALSE, 1);
X
X		/* set the mark here */
X		curwp->w_markp = curwp->w_dotp;
X		curwp->w_marko = curwp->w_doto;
X
X		/* go to the beginning of the paragraph */
X		gotobop(FALSE, 1);
X		curwp->w_doto = 0;	/* force us to the beginning of line */
X	
X		/* and delete it */
X		if ((status = killregion(FALSE, 1)) != TRUE)
X			return(status);
X
X		/* and clean up the 2 extra lines */
X		ldelete(2L, TRUE);
X	}
X	return(TRUE);
X}
X
X
X/*	wordcount:	count the # of words in the marked region,
X			along with average word sizes, # of chars, etc,
X			and report on them.			*/
X
Xwordcount(f, n)
X
Xint f, n;	/* ignored numeric arguments */
X
X{
X	register LINE *lp;	/* current line to scan */
X	register int offset;	/* current char to scan */
X	long size;		/* size of region left to count */
X	register int ch;	/* current character to scan */
X	register int wordflag;	/* are we in a word now? */
X	register int lastword;	/* were we just in a word? */
X	long nwords;		/* total # of words */
X	long nchars;		/* total number of chars */
X	int nlines;		/* total number of lines in region */
X	int avgch;		/* average number of chars/word */
X	int status;		/* status return code */
X	REGION region;		/* region to look at */
X
X	/* make sure we have a region to count */
X	if ((status = getregion(&region)) != TRUE)
X		return(status);
X	lp = region.r_linep;
X	offset = region.r_offset;
X	size = region.r_size;
X
X	/* count up things */
X	lastword = FALSE;
X	nchars = 0L;
X	nwords = 0L;
X	nlines = 0;
X	while (size--) {
X
X		/* get the current character */
X		if (offset == llength(lp)) {	/* end of line */
X			ch = '\n';
X			lp = lforw(lp);
X			offset = 0;
X			++nlines;
X		} else {
X			ch = lgetc(lp, offset);
X			++offset;
X		}
X
X		/* and tabulate it */
X		wordflag = ((ch >= 'a' && ch <= 'z') ||
X			    (ch >= 'A' && ch <= 'Z') ||
X			    (ch >= '0' && ch <= '9'));
X		if (wordflag == TRUE && lastword == FALSE)
X			++nwords;
X		lastword = wordflag;
X		++nchars;
X	}
X
X	/* and report on the info */
X	if (nwords > 0L)
X		avgch = (int)((100L * nchars) / nwords);
X	else
X		avgch = 0;
X
X	mlwrite("Words %D Chars %D Lines %d Avg chars/word %f",
X		nwords, nchars, nlines + 1, avgch);
X	return(TRUE);
X}
X#endif
FRIDAY_NIGHT
echo mes.13 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/17/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.14')
# If you do not see the message
#	`mes.14 completed!'
# then the file was incomplete.
echo extracting - z309.c
sed 's/^X//' > z309.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file provide support for the Zenith Z-100 PC
X * family.  It goes directly to the graphics RAM to do screen output. 
X * It compiles into nothing if not a Zenith 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     Z309
X
X/* set NROW to 25 for 25-line interlaced mode */
X#define NROW    50                      /* 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
X#define	SCADC	0xb8000000L		/* CGA address of screen RAM	*/
X#define	SCADM	0xb0000000L		/* MONO address of screen RAM	*/
X
X#define	CDMONO	0			/* monochrome text card		*/
X#define	CDCGA50	1			/* 50-line color graphics card	*/
X#define CDCGI25 2			/* 25-line interlaced CGA text	*/
X#define CDCGA25 3			/* 25-line color graphics card	*/
X#define	CDSENSE	9			/* detect the card type		*/
X
Xint dtype = CDCGA50;			/* current display type		*/
Xlong scadd;				/* address of screen ram	*/
Xint *scptr[NROW];			/* pointer to screen lines	*/
Xint sline[NCOL];			/* screen line image		*/
Xextern union REGS rg;			/* cpu register for use of DOS calls */
X
Xextern  int     ttopen();               /* Forward references.          */
Xextern  int     ttgetc();
Xextern  int     ttputc();
Xextern  int     ttflush();
Xextern  int     ttclose();
Xextern  int     z309move();
Xextern  int     z309eeol();
Xextern  int     z309eeop();
Xextern  int     z309beep();
Xextern  int     z309open();
Xextern	int	z309rev();
Xextern	int	z309cres();
Xextern	int	z309close();
Xextern	int	z309putc();
Xextern	int	z309kopen();
Xextern	int	z309kclose();
X
X#if	COLOR
Xextern	int	z309fcol();
Xextern	int	z309bcol();
X
Xint	cfcolor = -1;		/* current forground color */
Xint	cbcolor = -1;		/* current background color */
Xint	ctrans[] =		/* ansi to z309 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        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        z309open,
X        z309close,
X	z309kopen,
X	z309kclose,
X        ttgetc,
X	z309putc,
X        ttflush,
X        z309move,
X        z309eeol,
X        z309eeop,
X        z309beep,
X	z309rev,
X	z309cres
X#if	COLOR
X	, z309fcol,
X	z309bcol
X#endif
X};
X
Xextern union REGS rg;
X
X#if	COLOR
Xz309fcol(color)		/* set the current output color */
X
Xint color;	/* color to set */
X
X{
X	cfcolor = ctrans[color];
X}
X
Xz309bcol(color)		/* set the current background color */
X
Xint color;	/* color to set */
X
X{
X        cbcolor = ctrans[color];
X}
X#endif
Xz309move(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
Xz309eeol()	/* 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	if (dtype != CDMONO)
X		attr = (((cbcolor & 15) << 4) | (cfcolor & 15)) << 8;
X	else
X		attr = 0x0700;
X#else
X	attr = 0x0700;
X#endif
X	lnptr = &sline[0];
X	for (i=0; i < term.t_ncol; i++)
X		*lnptr++ = SPACE | attr;
X
X#if 0	/* Heath/Zenith builds flicker-less CGAs */
X	if (flickcode) {
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#endif
X
X	/* and send the string out */
X	movmem(&sline[0], scptr[crow]+ccol, (term.t_ncol-ccol)*2);
X
X}
X
Xz309putc(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	if (dtype != CDMONO)
X		rg.h.bl = cfcolor;
X	else
X		rg.h.bl = 0x07;
X#else
X	rg.h.bl = 0x07;
X#endif
X	int86(0x10, &rg, &rg);
X}
X
Xz309eeop()
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/*HERE*/	rg.x.dx = 0x184f;	/* lower right corner of scroll */
X#if	COLOR
X	if (dtype != CDMONO)
X		attr = ((ctrans[gbcolor] & 15) << 4) | (ctrans[gfcolor] & 15);
X	else
X		attr = 0;
X#else
X	attr = 0;
X#endif
X	rg.h.bh = attr;
X	int86(0x10, &rg, &rg);
X}
X
Xz309rev(state)		/* change reverse video state */
X
Xint state;	/* TRUE = reverse, FALSE = normal */
X
X{
X	/* This never gets used under the z309-PC driver */
X}
X
Xz309cres(res)	/* change screen resolution */
X
Xchar *res;	/* resolution to change to */
X
X{
X	if (strcmp(res, "CGA50") == 0) {
X		scinit(CDCGA50);
X		return(TRUE);
X	} else if (strcmp(res, "MONO") == 0) {
X		scinit(CDMONO);
X		return(TRUE);
X	} else
X		return(FALSE);
X}
X
Xz309beep()
X{
X#if	MWC86
X	putcnb(BEL);
X#else
X	bdos(6, BEL, 0);
X#endif
X}
X
Xz309open()
X{
X	scinit(CDSENSE);
X	revexist = TRUE;
X        ttopen();
X}
X
Xz309close()
X
X{
X	rg.h.ah = 101;
X	rg.h.al = 1;	/* 25-line interlace mode */
X	int86(0x10, &rg, &rg); 
X#if	COLOR
X	z309fcol(7);
X	z309bcol(0);
X#endif
X	ttclose();
X}
X
Xz309kopen()	/* open the keyboard */
X
X{
X}
X
Xz309kclose()	/* close the keyboard */
X
X{
X}
X
Xscinit(type)	/* initialize the screen head pointers */
X
Xint type;	/* type of adapter to init for */
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	/* if asked...find out what display is connected */
X	int86(0x11, &rg, &rg);
X	dtype = CDCGA50;
X	scadd = SCADC;
X	strcpy(sres, "CGA50");
X	if ((((rg.x.ax >> 4) & 11) == 3) || type == CDMONO) {
X		strcpy(sres, "MONO");
X		dtype = CDMONO;
X		scadd = SCADM;
X	}
X	else {
X		rg.h.ah = 101;
X/* set al = 1 for 25-line interlace mode */		
X		rg.h.al = 2;	/* 50-line interlace mode */
X		int86(0x10, &rg, &rg); 
X	}
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 term.t_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	if (dtype != CDMONO)
X		attr = (((ctrans[bacg] & 15) << 4) | (ctrans[forg] & 15)) << 8;
X	else
X		attr = (((bacg & 15) << 4) | (forg & 15)) << 8;
X#else
X	attr = (((bacg & 15) << 4) | (forg & 15)) << 8;
X#endif
X	lnptr = &sline[0];
X	for (i=0; i<term.t_ncol; i++)
X		*lnptr++ = (outstr[i] & 255) | attr;
X
X#if 0	/* Heath/Zenith builds flicker-less CGAs */
X	if (flickcode) {
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#endif	
X
X	/* and send the string out */
X	movmem(&sline[0], scptr[row],term.t_ncol*2);
X}
X
X#if	FLABEL
Xfnclabel(f, n)		/* label a function key */
X
Xint f,n;	/* default flag, numeric argument [unused] */
X
X{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
X}
X#endif
X#else
Xz309hello()
X{
X}
X#endif
FRIDAY_NIGHT
echo extracting - makefile.mwc
sed 's/^X//' > makefile.mwc << 'FRIDAY_NIGHT'
X#
X# Makefile for MicroEMACS 3.9 on the Atari ST using Mark Williams C
X#
XSRC=.
XCC=cc
XCFLAGS=-I. -A
X
XOBJS=	basic.o bind.o buffer.o crypt.o display.o eval.o exec.o file.o\
X	fileio.o input.o isearch.o line.o main.o random.o region.o search.o\
X	spawn.o st520.o termio.o word.o window.o
X
Xemacs.prg:	$(OBJS)
X		$(CC) -o emacs.prg $(OBJS)
X
Xbasic.o: $(SRC)\basic.c ebind.h epath.h efunc.h edef.h estruct.h
Xbind.o: $(SRC)\bind.c ebind.h epath.h efunc.h edef.h estruct.h
Xbuffer.o: $(SRC)\buffer.c ebind.h epath.h efunc.h edef.h estruct.h
Xcrypt.o: $(SRC)\crypt.c ebind.h epath.h efunc.h edef.h estruct.h
Xdisplay.o: $(SRC)\display.c ebind.h epath.h efunc.h edef.h estruct.h
Xeval.o: $(SRC)\eval.c ebind.h epath.h efunc.h edef.h estruct.h evar.h
Xexec.o: $(SRC)\exec.c ebind.h epath.h efunc.h edef.h estruct.h
Xfile.o: $(SRC)\file.c ebind.h epath.h efunc.h edef.h estruct.h
Xfileio.o: $(SRC)\fileio.c ebind.h epath.h efunc.h edef.h estruct.h
Xinput.o: $(SRC)\input.c ebind.h epath.h efunc.h edef.h estruct.h
Xisearch.o: $(SRC)\isearch.c ebind.h epath.h efunc.h edef.h estruct.h
Xline.o: $(SRC)\line.c ebind.h epath.h efunc.h edef.h estruct.h
Xmain.o: $(SRC)\main.c ebind.h efunc.h edef.h estruct.h
Xrandom.o: $(SRC)\random.c ebind.h epath.h efunc.h edef.h estruct.h
Xregion.o: $(SRC)\region.c ebind.h epath.h efunc.h edef.h estruct.h
Xsearch.o: $(SRC)\search.c ebind.h epath.h efunc.h edef.h estruct.h
Xspawn.o: $(SRC)\spawn.c ebind.h epath.h efunc.h edef.h estruct.h
Xst520.o: $(SRC)\st520.c ebind.h epath.h efunc.h edef.h estruct.h
Xtermio.o: $(SRC)\termio.c ebind.h epath.h efunc.h edef.h estruct.h
Xword.o: $(SRC)\word.c ebind.h epath.h efunc.h edef.h estruct.h
Xwindow.o: $(SRC)\window.c ebind.h epath.h efunc.h edef.h estruct.h
FRIDAY_NIGHT
echo extracting - makefile.unx
sed 's/^X//' > makefile.unx << 'FRIDAY_NIGHT'
XCFLAGS=		-O
X
XOFILES=		ansi.o basic.o bind.o buffer.o crypt.o dg10.o \
X		display.o eval.o exec.o file.o fileio.o \
X		hp110.o hp150.o ibmpc.o input.o isearch.o line.o \
X		lock.o main.o random.o region.o search.o spawn.o \
X		st520.o tcap.o termio.o tipc.o vmsvt.o vt52.o \
X		window.o word.o z309.o
X
XCFILES=		ansi.c basic.c bind.c buffer.c crypt.c dg10.c \
X		display.c eval.c exec.c file.c fileio.c \
X		hp110.c hp150.c ibmpc.c input.c isearch.c line.c \
X		lock.c main.c random.c region.c search.c spawn.c \
X		st520.c tcap.c termio.c tipc.c vmsvt.c vt52.c \
X		window.c word.c z309.c
X
XHFILES=		estruct.h edef.h efunc.h epath.h ebind.h evar.h
X
Xemacs:		$(OFILES)
X		$(CC) $(CFLAGS) $(OFILES) -ltermcap -lc -o emacs
X
X$(OFILES):	$(HFILES)
FRIDAY_NIGHT
echo extracting - aline.h
sed 's/^X//' > aline.h << 'FRIDAY_NIGHT'
X
X               /***********************************************\
X               *                                               *
X               *                    aline.h                    *
X               *       Common include file for C interface     *
X               *       to low level Line A calls               *
X               *                                               *
X               *       J.R. Bammi                              *
X               *         decvax!cwruecmp!bammi                 *
X               *         bammi%cwru.edu.CSNET                  *
X               *         bammi@cwru.edu.ARPA                   *
X               *         CIS: 71515,155                        *
X               *                                               *
X               \***********************************************/
X
X#define	WORD	int
X#define	VOID	void
X
X/*****************************************************************************\
X*                                                                            *
X*                                 Defines                                     *
X*                                                                            *
X\*****************************************************************************/
X
X/*
X *  Object colors (default pallette)
X *
X */
X#define WHITE    0
X#define BLACK    1
X#define RED      2
X#define GREEN    3
X#define BLUE     4
X#define CYAN     5
X#define YELLOW   6
X#define MAGENTA  7
X#define LWHITE   8
X#define LBLACK   9
X#define LRED     10
X#define LGREEN   11
X#define LBLUE    12
X#define LCYAN    13
X#define LYELLOW  14
X#define LMAGENTA 15
X
X
X/* 
X * Vdi writing modes
X *
X */
X#define MD_REPLACE 1
X#define MD_TRANS   2
X#define MD_XOR     3
X#define MD_ERASE   4
X
X
X/*
X * Raster Op Codes
X *
X */
X#define ALL_WHITE  0
X#define S_AND_D    1
X#define	S_AND_NOTD 2
X#define S_ONLY     3
X#define NOTS_AND_D 4
X#define	D_ONLY     5
X#define S_XOR_D    6
X#define S_OR_D     7
X#define	NOT_SORD   8
X#define	NOT_SXORD  9
X#define D_INVERT  10
X#define	NOT_D     11
X#define	S_OR_NOTD 12
X#define NOTS_OR_D 13
X#define	NOT_SANDD 14
X#define ALL_BLACK 15
X
X/*
X * Sprite formats
X *
X */
X#define SP_VDI     0
X#define SP_XOR     1
X
X/*
X * Line A Opcodes
X *
X */
X#define INIT		0
X#define PUTPIXEL	1
X#define GETPIXEL	2
X#define LINE		3
X#define HLINE		4
X#define RECTANGLE	5
X#define FPOLYGON	6
X#define BITBLT		7
X#define TEXTBLT		8
X#define SHOWMOUSE	9
X#define HIDEMOUSE	10
X#define TRANMOUSE	11
X#define USPRITE		12
X#define DSPRITE		13
X#define CPYRASTER	14
X#define FSEEDFILL	15      /* ROM TOS only */
X
X
X/*****************************************************************************\
X*                                                                            *
X*                                 Types                                       *
X*                                                                            *
X\*****************************************************************************/
X
X       /*
X        * Global Variables at negative offsets from the Line A parameter
X        * block address returned by init. (I have no way of telling if this
X        * list is complete).
X        *
X        */
X/* Name   Offset  Type Description                                          */
X/* --------------------------------------------------------------------------*/
X/* V_Y_MAX    -4   W   Max Y pixel value of the screen                      */
X/* V_STATUS   -6   W   Text Status byte                                     */
X/*                       Bit   Field           Zero            One          */
X/*                       0     cursor flash    disabled        enabled      */
X/*                       1     flash state     off             on           */
X/*                       2     cursor visible  no              yes          */
X/*                       3     end of line     no-wrap         wrap         */
X/*                       4     inverse video   on              off          */
X/*                       5     cursor saved    false           true         */
X/* V_OFF_AD  -10   L   Font offset table address                            */
X/* V_X_MAX   -12   W   Max X pixel value                                    */
X/* V_FNT_WR  -14   W   Width of Font Form in bytes (see type FONT below)    */
X/* V_FNT_ST  -16   W   First font ASCII code (first_ade)                    */
X/* V_FNT_ND  -18   W   Last  font ASCII code (last_ade )                    */
X/* V_FNT_AD  -22   L   Font Form address                                    */
X/*                     Mono Spaced, 8 pixels wide and byte aligned, any ht. */
X/* V_CUR_TIM -23   B   Cursor countdown timer                               */
X/* V_CUR_CNT -24   B   Cursor flash interval( in frames)                    */
X/* V_CUR_CY  -26   W   Y cursor position                                    */
X/* V_CUR_CX  -28   W   X cursor position                                    */
X/* V_CUR_OFF -30   W   Offset from screen base to first cell (bytes)        */
X/* V_CUR_AD  -34   L   Current cursor address                               */
X/* V_COL_FG  -36   W   Foreground color index                               */
X/* V_COL_BG  -38   W   Background color index                               */
X/* V_CEL_WR  -40   W   Offset to next vertical cell (bytes)                 */
X/* V_CEL_MY  -42   W   Max cells high - 1                                   */
X/* V_CEL_MX  -44   W   Max cells across - 1                                 */
X/* V_CEL_HT  -46   W   Cell height in pixels (font form's height)           */
X/* --------------------------------------------------------------------------*/
X
X/*
X * Atari finally named these variables
X * so here they are
X *
X */
Xtypedef struct {
X       WORD    V_CEL_HT;    /* *((WORD  *)((char  *)aline - (char  *)46L)) */
X       WORD    V_CEL_MX;    /* *((WORD  *)((char  *)aline - (char  *)44L)) */
X       WORD    V_CEL_MY;    /* *((WORD  *)((char  *)aline - (char  *)42L)) */
X       WORD    V_CEL_WR;    /* *((WORD  *)((char  *)aline - (char  *)40L)) */
X       WORD    V_COL_BG;    /* *((WORD  *)((char  *)aline - (char  *)38L)) */
X       WORD    V_COL_FG;    /* *((WORD  *)((char  *)aline - (char  *)36L)) */
X       char    *V_CUR_AD;   /* *((char **)((char **)aline - (char **)34L)) */
X       WORD    V_CUR_OFF;   /* *((WORD  *)((char  *)aline - (char  *)30L)) */
X       WORD    V_CUR_CX;    /* *((WORD  *)((char  *)aline - (char  *)28L)) */
X       WORD    V_CUR_CY;    /* *((WORD  *)((char  *)aline - (char  *)26L)) */
X       WORD    V_CUR_CNT;   /* *((char  *)((char  *)aline - (char  *)24L)) */
X/*     char    V_CUR_TIM;    *((char  *)((char  *)aline - (char  *)23L))   */
X       char    **V_FNT_AD;  /* *((char **)((char **)aline - (char **)22L)) */
X       WORD    V_FNT_ND;    /* *((WORD  *)((char  *)aline - (char  *)18L)) */
X       WORD    V_FNT_ST;    /* *((WORD  *)((char  *)aline - (char  *)16L)) */
X       WORD    V_FNT_WR;    /* *((WORD  *)((char  *)aline - (char  *)14L)) */
X       WORD    V_X_MAX;     /* *((WORD  *)((char  *)aline - (char  *)12L)) */
X       char    **V_OFF_AD;  /* *((char **)((char **)aline - (char **)10L)) */
X       WORD    V_STATUS;    /* *((WORD  *)((char  *)aline - (char  *) 6L)) */
X       WORD    V_Y_MAX;     /* *((WORD  *)((char  *)aline - (char  *) 4L)) */
X       WORD    xxdummy;     /* *((WORD  *)((char  *)aline - (char  *) 2L)) */
X} NLINEA;
X
X       /* A pointer to the type LINEA is returned by the Line A init call
X        * ($A000), in registers A0 and D0.
X         * This pointer is saved in the global variable 'aline'.
X        *
X        */
Xtypedef struct {
X
X/* Type    Name       Offset   Function                    Comments                 */
X/* ------------------------------------------------------------------------- */
X   WORD   VPLANES;    /*  0  # of Planes        Also see CurrRez             */
X   WORD   VWRAP;      /*  2  Bytes / scan line    "    "    "                */
X                      /*     VWRAP can be changed to implement special effect*/
X                      /*     Doubling VWRAP will skip every other scan line  */
X                      /*                                                     */
X                      /*                                                     */
X   WORD   *CONTRL;    /*  4  Ptr to CONTRL Array  Contrl gets set to this    */
X   WORD   *INTIN;     /*  8  Ptr to INTIN  Array  Intin  gets set to this    */
X   WORD   *PTSIN;     /* 12  Ptr to PTSIN  Array  Ptsin  gets set to this    */
X   WORD   *INTOUT;    /* 16  Ptr to INTOUT Array  Intout gets set to this    */
X   WORD   *PTSOUT;    /* 20  Ptr to PTSOUT Array  Ptsout gets set to this    */
X                      /*     CONTRL is the control array                     */
X                      /*     INTIN is the array of input parameters          */
X                      /*     PTSIN is the array of input coordinates         */
X                      /*          Even entrys are X coordinate               */
X                      /*          Odd  entrys are corresponding Y coodinates */
X                      /*     INTOUT is the array of output parameters        */
X                      /*     PTSOUT is the array of output coordinates       */
X                      /*        organizes like PTSIN.                        */
X                      /*                                                     */
X   WORD   COLBIT0;    /* 24  Plane 0 Color Value  All Three Rez's            */
X   WORD   COLBIT1;    /* 26  Plane 1 Color Value  Med and Low Rez only       */
X   WORD   COLBIT2;    /* 28  Plane 2 Color Value  Low Rez only               */
X   WORD   COLBIT3;    /* 30  Plane 3 Color Value  Low Rez Only               */
X                      /*     Foreground color COLBIT0 + 2*COLBIT1 + 4*COLBIT2*/
X                      /*                      + 8*COLBIT3                    */
X                      /*                                                     */
X                      /*                                                     */
X   WORD   LSTLIN;     /* 32  Always set to -1, Done for you in init_aline()  */
X                      /*     Does anyone know what it is supposed to be?     */
X                      /*                                                     */
X   WORD   LNMASK;     /* 34  Linemask used when drawing lines, same as Vdi's */
X                      /*     line style                                      */
X                      /*                                                     */
X   WORD   WMODE;      /* 36  Writing mode                                    */
X                      /*     0=Replace Mode-Replace all bits in Dest with src*/
X                      /*     1=Trans. Mode-Only additional bits in src set(OR*/
X                      /*     2=Xor Mode- Src XOR Dest                        */
X                      /*     3=Inverse Trans.- (NOT src) Or Dest             */
X                      /*     Values upto 16 are permitted                    */
X                      /*                                                     */
X   WORD   X1;         /* 38  X1 coordinate used in various calls             */
X                      /*                                                     */
X   WORD   Y1;         /* 40  Y1 coordinate used in various calls             */
X                      /*                                                     */
X   WORD   X2;         /* 42  X2 coordinate used in various calls             */
X                      /*                                                     */
X   WORD   Y2;         /* 44  Y2 coordinate used in various calls             */
X                      /*                                                     */
X                      /*                                                     */
X   WORD   *PATPTR;    /* 46  Pointer to current fill pattern                 */
X                      /*     Must be integral power of 2 (words) in length   */
X   WORD   PATMSK;     /* 50  I don't know why they call it a mask. It is in  */
X                      /*     reality the length in words of the current patt.*/
X   WORD   MFILL;      /* 52  Multi Plane fill flag 1 == Current fill Pattern */
X                      /*     is for Muti Plane.                              */
X                      /*                                                     */
X                      /*                                                     */
X   WORD   CLIP;       /* 54  Clipping Flag 1 == TRUE                         */
X   WORD   XMINCL;     /* 56  Min X of clipping window                        */
X   WORD   YMINCL;     /* 58  Min Y of clipping window                        */
X   WORD   XMAXCL;     /* 60  Max X of clipping window                        */
X   WORD   YMAXCL;     /* 62  Max Y of clipping window                        */
X                      /*                                                     */
X                      /*                                                     */
X   WORD   XDDA;       /* 64  Accumulator for Scaling, Must be set to 0x08000 */
X                      /*     before each call to Text Blt. Done for you in   */
X                      /*     in aline_text()                                 */
X   WORD   DDAINC;     /* 66  Scaling factor - Fractional amount to scale char*/
X                      /*     When scaling up = 256 *(Size-Textsize)/Textsize */
X                      /*     When scaling down = 256*(Size)/Textsize         */
X                      /*     scaling down does not work                      */
X   WORD   SCALDIR;    /* 68  Scaling direction 0 == down                     */
X   WORD   MONO;       /* 70  Mono flag 0== current font is a propotional font*/
X                      /*     Its Ok for Thickening to increase the width of  */
X                      /*     the current character.                          */
X                      /*     1 == current font is mono spaced, so thickening */
X                      /*     may not increase the width of the current char  */
X                      /*                                                     */
X   WORD   SOURCEX;    /* 72  X coordinate of character in the font form      */
X                      /*     SOURCEX is caluclated from info in the font     */
X                      /*     header for the current font (see FONT type)     */
X                      /*     SOURCEX = off_table[char-first_ade]             */
X                      /*     SOURCEX is calculated for you in aline_text()   */
X                      /*     The pointer to a table of font header for the   */
X                      /*     internal fonts is returned in A2 on init (A000) */
X   WORD   SOURCEY;    /* 74  Y coodinate of character in the font form       */
X                      /*     Typically set to 0 (top line of font form)      */
X   WORD   DESTX;      /* 76  X coordinate of character on screen             */
X   WORD   DESTY;      /* 78  Y coordinate of character on screen             */
X   WORD   DELX;       /* 80  Width of Character                              */
X                      /*     Difference between two SOURCEX's                */
X   WORD   DELY;       /* 82  Height of Character                             */
X                      /*     form_height field of FONT_HEAD of current font  */
X   WORD   *FBASE;     /* 84  Pointer to start of font form                   */
X   WORD   FWIDTH;     /* 88  Width of the current font's form                */
X                      /*                                                     */
X   WORD   STYLE;      /* 90  Vector of style flags                           */
X                      /*     Bit 0 = Thicken Flag                            */
X                      /*     Bit 1 = Lighten Flag                            */
X                      /*     Bit 2 = Skewing Flag                            */
X                      /*     Bit 3 = Underline Flag (ignored)                */
X                      /*     Bit 4 = Outline Flag                            */
X                      /*                                                     */
X   WORD   LITEMASK;   /* 92  Mask used for lightening text                   */
X                      /*     The Mask is picked up from the font header      */
X   WORD   SKEWMASK;   /* 94  Mask used for skewing text                      */
X                      /*     The Mask is picked up from the font header      */
X   WORD   WEIGHT;     /* 96  The number of bits by which to thicken text     */
X                      /*     The number is picked up from the font header    */
X   WORD   ROFF;       /* 98  Offset above baseline when skewing              */
X                      /*     Again picked up from the font header            */
X                      /*                                                     */
X   WORD   LOFF;       /* 100 Offset below character baseline when skewing    */
X                      /*     Again picked up from the font header            */
X                      /*                                                     */
X   WORD   SCALE;      /* 102 Scaling Flag 1 == true                          */
X                      /*                                                     */
X   WORD   CHUP;       /* 104 Character rotation vector.                      */
X                      /*     0 = normal (0 degrees)                          */
X                      /*     1800 = 180 degrees                              */
X                      /*     2700 = 270 degrees                              */
X                      /*                                                     */
X   WORD   TEXTFG;     /* 106 Text foreground color                           */
X                      /*                                                     */
X   char   *SCRTCHP;   /* 108 Address of buffer required for creating special */
X                      /*     text effects. The size of this buffer should be */
X                      /*     1K according the Internals. The Atari document  */
X                      /*     of course does not talk about such things :-)   */
X                      /*                                                     */
X   WORD   SCRPT2;     /* 112 The offset of the scaling buffer buffer in above*/
X                      /*     buffer. Internals suggests an offset of 0x0040  */
X                      /*     As usual the Atari document does'nt say a thing */
X                      /*                                                     */
X   WORD   TEXTBG;     /* 114 Text background color (Ram Vdi only)            */
X                      /*     used for the BitBlt writing modes (4-19) only   */
X                      /*                                                     */
X   WORD   COPYTRAN;   /* 116 Copy raster form type flag (Ram vdi only)       */
X                      /*     0 => Opaque type                                */
X                      /*          n-plane source  ->  n-plane dest           */
X                      /*              BitBlt writing modes (4-19)            */
X                      /*    ~0 => Transparent type                           */
X                      /*          1-plane source  ->  n-plane dest           */
X                      /*              Vdi writing modes (1-3)                */
X                      /*                                                     */
X   WORD(*SEEDABORT)();/* 118 Pointer to function returning int, which is     */
X                      /*     called by the fill logic to allow the fill to   */
X                      /*     be aborted. If the routine returns FALSE (0)    */
X                      /*     the fill is not aborted. If it returns TRUE (~0)*/
X                      /*     the fill is aborted                             */
X/* ------------------------------------------------------------------------- */
X
X} LINEA;             /*       P H E W !!!!!                                  */
X
X
X
X /* A pointer to array of type FONT is returned by the Line A init call
X  * ($A000), in regsister A1.
X  * This pointer is saved in the global array variable 'fonts[]'.
X  *
X  */
X
Xtypedef struct _font {
X
X/* Type    Name       Offset   Function                    Comments          */
X/* ------------------------------------------------------------------------- */
X   WORD   font_id;    /*  0 Font face identifier  1 == system font           */
X                      /*                                                     */
X   WORD   size;       /*  2 Font size in points                              */
X                      /*                                                     */
X   char   name[32];   /*  4 Face name                                        */
X                      /*                                                     */
X   WORD   first_ade;  /* 36 Lowest ADE value in the face (lowest ASCII value */
X                      /*    of displayable character).                       */
X                      /*                                                     */
X   WORD   last_ade;   /* 38 Highest ADE value in the face (highest ASCII valu*/
X                      /*    of displayable character).                       */
X                      /*                                                     */
X   WORD   top;        /* 40 Distance of top line relative to baseline        */
X                      /*                                                     */
X   WORD   ascent;     /* 42 Distance of ascent line relative to baseline     */
X                      /*                                                     */
X   WORD   half;       /* 44 Distance of half line relative to baseline       */
X                      /*                                                     */
X   WORD   descent;    /* 46 Distance of decent line relative to baseline     */
X                      /*                                                     */
X   WORD   bottom;     /* 48 Distance of bottom line relative to baseline     */
X                      /*    All distances are measured in absolute values    */
X                      /*    rather than as offsets. They are always +ve      */
X                      /*                                                     */
X WORD max_char_width; /* 50 Width of the widest character in font            */
X                      /*                                                     */
X WORD max_cell_width; /* 52 Width of the widest cell character cell in face  */
X                      /*                                                     */
X   WORD left_offset;  /* 54 Left Offset see Vdi appendix G                   */
X                      /*                                                     */
X   WORD right_offset; /* 56 Right offset   "      "     "                    */
X                      /*                                                     */
X   WORD   thicken;    /* 58 Number of pixels by which to thicken characters  */
X                      /*                                                     */
X   WORD   ul_size;    /* 60 Width in  pixels of the underline                */
X                      /*                                                     */
X   WORD   lighten;    /* 62 The mask used to lighten characters              */
X                      /*                                                     */
X   WORD   skew;       /* 64 The mask used to determine when to perform       */
X                      /*    additional rotation on the character to perform  */
X                      /*    skewing                                          */
X                      /*                                                     */
X   WORD   flags;      /* 66 Flags                                            */
X                      /*      bit 0 set if default system font               */
X                      /*      bit 1 set if horiz offset table should be used */
X                      /*      bit 2 byte-swap flag (thanks to Intel idiots)  */
X                      /*      bit 3 set if mono spaced font                  */
X                      /*                                                     */
X   char   *h_table;   /* 68 Pointer to horizontal offset table               */
X                      /*                                                     */
X   WORD   *off_table; /* 72 Pointer to character offset table                */
X                      /*                                                     */
X   char   *dat_table; /* 76 Pointer to font data                             */
X                      /*                                                     */
X   WORD   form_width; /* 80 Form width (#of bytes /scanline in font data)    */
X                      /*                                                     */
X   WORD   form_height;/* 82 Form height (#of scanlines in font data)         */
X                      /*                                                     */
X struct _font *next_font;  /* 84 Pointer to next font in face                */
X                      /*                                                     */
X/* ------------------------------------------------------------------------- */
X} FONT;
X
X       
X       /*
X        * OP_TAB type required for Bit Blt parameter block.
X        * each entry defines the logic operation to apply for
X        * the 4 Fore/Back ground bit combinations
X        */
Xtypedef struct {
X
X/* Type    Name       Offset   Function             Comments                 */
X/* ------------------------------------------------------------------------- */
X   char   fg0bg0;     /* 0     Logic op to employ when both FG and BG are 0  */
X   char   fg0bg1;     /* 1     Logic op to employ when FG = 0 and BG = 1     */
X   char   fg1bg0;     /* 2     Logic op to employ when FG = 1 and BG = 0     */
X   char   fg1bg1;     /* 3     Logic op to employ when both FG and BG are 1  */
X/* ------------------------------------------------------------------------- */
X} OP_TAB;
X
X
X/*
X * Source and destination description blocks
X */
Xtypedef struct  {
X       WORD    bl_xmin;                /* Minimum x                    */
X       WORD    bl_ymin;                /* Minimum y                    */
X       char    *bl_form;               /* Word aligned memory form     */
X       WORD    bl_nxwd;                /* Offset to next word in line  */
X       WORD    bl_nxln;                /* Offset to next line in plane */
X       WORD    bl_nxpl;                /* Offset to next plane         */
X}SDDB;
X
X       /* Offsets to next word in plane */
X#define HI_NXWD        2
X#define MED_NXWD       4
X#define LOW_NXWD       8
X
X       /* Scan line widths of the screen */
X#define HI_NXLN        80
X#define MED_NXLN       160
X#define LOW_NXLN       160
X
X       /*
X        * Offsets between planes - always the same due to
X        * the way the STs video memory is laid out
X         */
X#define NXPL           2
X
X       /* 
X        * Bit Blt Parameter Block Type (for function $A007)
X        *
X        */
X
Xtypedef struct {
X
X/* Type           Name           Offset   Function          Comments         */
X/* ------------------------------------------------------------------------- */
X   WORD           bb_b_wd;     /*       width of block in pixels             */
X   WORD           bb_b_ht;     /*       height of block in pixels            */
X   WORD           bb_plane_ct; /*       number of planes to blit             */
X   WORD           bb_fg_col;   /*       foreground color                     */
X   WORD           bb_bg_col;   /*       back   ground color                  */
X   OP_TAB  bb_op_tab;          /*       logic for fg x bg combination        */
X   SDDB           bb_s;        /*       source info block                    */
X   SDDB           bb_d;        /*       destination info block               */
X   WORD           *bb_p_addr;  /*       pattern buffer address               */
X   WORD           bb_p_nxln;   /*       offset to next line in pattern       */
X   WORD           bb_p_nxpl;   /*       offset to next plane in pattern      */
X   WORD           bb_p_mask;   /*       pattern index mask                   */
X   char           bb_fill[24]; /*       work space                           */
X/* ------------------------------------------------------------------------- */
X} BBPB;
X
X
X/*
X * Memory Form Definition Block
X *
X */
Xtypedef struct
X{
X       char            *fd_addr;    /* Addrerss of upper left corner of firs*/
X                                    /* plane of raster area. If NULL then   */
X                                    /* MFDB is for a physical device        */
X       WORD            fd_w;        /* Form Width in Pixels                 */
X       WORD            fd_h;        /* Form Height in Pixels                */
X       WORD            fd_wdwidth;  /* Form Width in words (fd_w/sizeof(int)*/
X       WORD            fd_stand;    /* Form format 0= device spec 1=standard*/
X       WORD            fd_nplanes;  /* Number of memory planes              */
X       WORD            fd_r1;       /* Reserved                             */
X       WORD            fd_r2;       /* Reserved                             */
X       WORD            fd_r3;       /* Reserved                             */
X} MFDB;
X
X
X
X
X/*
X * Sprite definition block
X *
X */
Xtypedef struct
X{
X       WORD    sp_xhot;                /* Offset to X hot spot           */
X       WORD    sp_yhot;                /* Offset to Y hot spot           */
X       WORD    sp_format;              /* Format SP_VDI or SP_XOR        */
X       WORD    sp_bg;                  /* Background color               */
X       WORD    sp_fg;                  /* Foregroud color                */
X       WORD    sp_data[32];            /* Sprite data -                  */
X                                       /* Alternating words of back/fore */
X                                       /* ground data                    */
X                                       /* Note that:                     */
X                                       /*   sprite save block is         */
X                                       /*  10+VPLANES*64 bytes long      */
X
X} SFORM;
FRIDAY_NIGHT
echo mes.14 completed!
# That's all folks!

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/17/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.15')
# If you do not see the message
#	`mes.15 completed!'
# then the file was incomplete.
echo extracting - ebind.h
sed 's/^X//' > ebind.h << 'FRIDAY_NIGHT'
X/*	EBIND:		Initial default key to function bindings for
X			MicroEMACS 3.7
X*/
X
X/*
X * Command table.
X * This table  is *roughly* in ASCII order, left to right across the
X * characters of the command. This explains the funny location of the
X * control-X commands.
X */
XKEYTAB  keytab[NBINDS] = {
X	{CTRL|'A',		gotobol},
X	{CTRL|'B',		backchar},
X	{CTRL|'C',		insspace},
X	{CTRL|'D',		forwdel},
X	{CTRL|'E',		gotoeol},
X	{CTRL|'F',		forwchar},
X	{CTRL|'G',		ctrlg},
X	{CTRL|'H',		backdel},
X	{CTRL|'I',		tab},
X	{CTRL|'J',		indent},
X	{CTRL|'K',		killtext},
X	{CTRL|'L',		refresh},
X	{CTRL|'M',		newline},
X	{CTRL|'N',		forwline},
X	{CTRL|'O',		openline},
X	{CTRL|'P',		backline},
X	{CTRL|'Q',		quote},
X	{CTRL|'R',		backsearch},
X	{CTRL|'S',		forwsearch},
X	{CTRL|'T',		twiddle},
X	{CTRL|'U',		unarg},
X	{CTRL|'V',		forwpage},
X	{CTRL|'W',		killregion},
X	{CTRL|'X',		cex},
X	{CTRL|'Y',		yank},
X	{CTRL|'Z',		backpage},
X	{CTRL|']',		meta},
X	{CTLX|CTRL|'B',		listbuffers},
X	{CTLX|CTRL|'C',		quit},          /* Hard quit.           */
X#if	AEDIT
X	{CTLX|CTRL|'D',		detab},
X	{CTLX|CTRL|'E',		entab},
X#endif
X	{CTLX|CTRL|'F',		filefind},
X	{CTLX|CTRL|'I',		insfile},
X	{CTLX|CTRL|'L',		lowerregion},
X	{CTLX|CTRL|'M',		delmode},
X	{CTLX|CTRL|'N',		mvdnwind},
X	{CTLX|CTRL|'O',		deblank},
X	{CTLX|CTRL|'P',		mvupwind},
X	{CTLX|CTRL|'R',		fileread},
X	{CTLX|CTRL|'S',		filesave},
X#if	AEDIT
X	{CTLX|CTRL|'T',		trim},
X#endif
X	{CTLX|CTRL|'U',		upperregion},
X	{CTLX|CTRL|'V',		viewfile},
X	{CTLX|CTRL|'W',		filewrite},
X	{CTLX|CTRL|'X',		swapmark},
X	{CTLX|CTRL|'Z',		shrinkwind},
X	{CTLX|'?',		deskey},
X	{CTLX|'!',		spawn},
X	{CTLX|'@',		pipecmd},
X	{CTLX|'#',		filter},
X	{CTLX|'$',		execprg},
X	{CTLX|'=',		showcpos},
X	{CTLX|'(',		ctlxlp},
X	{CTLX|')',		ctlxrp},
X	{CTLX|'^',		enlargewind},
X	{CTLX|'0',		delwind},
X	{CTLX|'1',		onlywind},
X	{CTLX|'2',		splitwind},
X	{CTLX|'A',		setvar},
X	{CTLX|'B',		usebuffer},
X	{CTLX|'C',		spawncli},
X#if	BSD
X	{CTLX|'D',		bktoshell},
X#endif
X	{CTLX|'E',		ctlxe},
X	{CTLX|'F',		setfillcol},
X	{CTLX|'K',		killbuffer},
X	{CTLX|'M',		setmode},
X	{CTLX|'N',		filename},
X	{CTLX|'O',		nextwind},
X	{CTLX|'P',		prevwind},
X#if	ISRCH
X	{CTLX|'R',		risearch},
X	{CTLX|'S',		fisearch},
X#endif
X	{CTLX|'W',		resize},
X	{CTLX|'X',		nextbuffer},
X	{CTLX|'Z',		enlargewind},
X#if	WORDPRO
X	{META|CTRL|'C',		wordcount},
X#endif
X#if	PROC
X	{META|CTRL|'E',		execproc},
X#endif
X#if	CFENCE
X	{META|CTRL|'F',		getfence},
X#endif
X	{META|CTRL|'H',		delbword},
X	{META|CTRL|'K',		unbindkey},
X	{META|CTRL|'L',		reposition},
X	{META|CTRL|'M',		delgmode},
X	{META|CTRL|'N',		namebuffer},
X	{META|CTRL|'R',		qreplace},
X	{META|CTRL|'S',		newsize},
X	{META|CTRL|'T',		newwidth},
X	{META|CTRL|'V',		scrnextdw},
X#if	WORDPRO
X	{META|CTRL|'W',		killpara},
X#endif
X	{META|CTRL|'Z',		scrnextup},
X	{META|' ',		setmark},
X	{META|'?',		help},
X	{META|'!',		reposition},
X	{META|'.',		setmark},
X	{META|'>',		gotoeob},
X	{META|'<',		gotobob},
X	{META|'~',		unmark},
X#if	APROP
X	{META|'A',		apro},
X#endif
X	{META|'B',		backword},
X	{META|'C',		capword},
X	{META|'D',		delfword},
X#if	CRYPT
X	{META|'E',		setkey},
X#endif
X	{META|'F',		forwword},
X	{META|'G',		gotoline},
X	{META|'K',		bindtokey},
X	{META|'L',		lowerword},
X	{META|'M',		setgmode},
X#if	WORDPRO
X	{META|'N',		gotoeop},
X	{META|'P',		gotobop},
X	{META|'Q',		fillpara},
X#endif
X	{META|'R',		sreplace},
X#if	BSD
X	{META|'S',		bktoshell},
X#endif
X	{META|'U',		upperword},
X	{META|'V',		backpage},
X	{META|'W',		copyregion},
X	{META|'X',		namedcmd},
X	{META|'Z',		quickexit},
X	{META|0x7F,              delbword},
X
X#if	MSDOS & (HP150 == 0) & (WANGPC == 0) & (HP110 == 0)
X	{SPEC|CTRL|'_',		forwhunt},
X	{SPEC|CTRL|'S',		backhunt},
X	{SPEC|71,		gotobob},
X	{SPEC|72,		backline},
X	{SPEC|73,		backpage},
X	{SPEC|75,		backchar},
X	{SPEC|77,		forwchar},
X	{SPEC|79,		gotoeob},
X	{SPEC|80,		forwline},
X	{SPEC|81,		forwpage},
X	{SPEC|82,		insspace},
X	{SPEC|83,		forwdel},
X	{SPEC|115,		backword},
X	{SPEC|116,		forwword},
X#if	WORDPRO
X	{SPEC|132,		gotobop},
X	{SPEC|118,		gotoeop},
X#endif
X	{SPEC|84,		cbuf1},
X	{SPEC|85,		cbuf2},
X	{SPEC|86,		cbuf3},
X	{SPEC|87,		cbuf4},
X	{SPEC|88,		cbuf5},
X	{SPEC|89,		cbuf6},
X	{SPEC|90,		cbuf7},
X	{SPEC|91,		cbuf8},
X	{SPEC|92,		cbuf9},
X	{SPEC|93,		cbuf10},
X#endif
X
X#if	HP150
X	{SPEC|32,		backline},
X	{SPEC|33,		forwline},
X	{SPEC|35,		backchar},
X	{SPEC|34,		forwchar},
X	{SPEC|44,		gotobob},
X	{SPEC|46,		forwpage},
X	{SPEC|47,		backpage},
X	{SPEC|82,		nextwind},
X	{SPEC|68,		openline},
X	{SPEC|69,		killtext},
X	{SPEC|65,		forwdel},
X	{SPEC|64,		ctlxe},
X	{SPEC|67,		refresh},
X	{SPEC|66,		reposition},
X	{SPEC|83,		help},
X	{SPEC|81,		deskey},
X#endif
X
X#if	HP110
X	{SPEC|0x4b,		backchar},
X	{SPEC|0x4d,		forwchar},
X	{SPEC|0x48,		backline},
X	{SPEC|0x50,		forwline},
X	{SPEC|0x43,		help},
X	{SPEC|0x73,		backword},
X	{SPEC|0x74,		forwword},
X	{SPEC|0x49,		backpage},
X	{SPEC|0x51,		forwpage},
X	{SPEC|84,		cbuf1},
X	{SPEC|85,		cbuf2},
X	{SPEC|86,		cbuf3},
X	{SPEC|87,		cbuf4},
X	{SPEC|88,		cbuf5},
X	{SPEC|89,		cbuf6},
X	{SPEC|90,		cbuf7},
X	{SPEC|91,		cbuf8},
X#endif
X
X#if	AMIGA
X	{SPEC|'?',		help},
X	{SPEC|'A',		backline},
X	{SPEC|'B',		forwline},
X	{SPEC|'C',		forwchar},
X	{SPEC|'D',		backchar},
X	{SPEC|'T',		backpage},
X	{SPEC|'S',		forwpage},
X	{SPEC|'a',		backword},
X	{SPEC|'`',		forwword},
X	{SPEC|'P',		cbuf1},
X	{SPEC|'Q',		cbuf2},
X	{SPEC|'R',		cbuf3},
X	{SPEC|'S',		cbuf4},
X	{SPEC|'T',		cbuf5},
X	{SPEC|'U',		cbuf6},
X	{SPEC|'V',		cbuf7},
X	{SPEC|'W',		cbuf8},
X	{SPEC|'X',		cbuf9},
X	{SPEC|'Y',		cbuf10},
X	{127,			forwdel},
X#endif
X
X#if	ST520
X	{SPEC|'b',		help},
X	{SPEC|'H',		backline},
X	{SPEC|'P',		forwline},
X	{SPEC|'M',		forwchar},
X	{SPEC|'K',		backchar},
X	{SPEC|'t',		setmark},
X	{SPEC|'a',		yank},
X	{SPEC|'R',		insspace},
X	{SPEC|'G',		gotobob},
X	{127,			forwdel},
X	{SPEC|84,		cbuf1},
X	{SPEC|85,		cbuf2},
X	{SPEC|86,		cbuf3},
X	{SPEC|87,		cbuf4},
X	{SPEC|88,		cbuf5},
X	{SPEC|89,		cbuf6},
X	{SPEC|90,		cbuf7},
X	{SPEC|91,		cbuf8},
X	{SPEC|92,		cbuf9},
X	{SPEC|93,		cbuf10},
X#endif
X
X#if  WANGPC
X	SPEC|0xE0,              quit,           /* Cancel */
X	SPEC|0xE1,              help,           /* Help */
X	SPEC|0xF1,              help,           /* ^Help */
X	SPEC|0xE3,              ctrlg,          /* Print */
X	SPEC|0xF3,              ctrlg,          /* ^Print */
X	SPEC|0xC0,              backline,       /* North */
X	SPEC|0xD0,              gotobob,        /* ^North */
X	SPEC|0xC1,              forwchar,       /* East */
X	SPEC|0xD1,              gotoeol,        /* ^East */
X	SPEC|0xC2,              forwline,       /* South */
X	SPEC|0xD2,              gotobop,        /* ^South */
X	SPEC|0xC3,              backchar,       /* West */
X	SPEC|0xD3,              gotobol,        /* ^West */
X	SPEC|0xC4,              ctrlg,          /* Home */
X	SPEC|0xD4,              gotobob,        /* ^Home */
X	SPEC|0xC5,              filesave,       /* Execute */
X	SPEC|0xD5,              ctrlg,          /* ^Execute */
X	SPEC|0xC6,              insfile,        /* Insert */
X	SPEC|0xD6,              ctrlg,          /* ^Insert */
X	SPEC|0xC7,              forwdel,        /* Delete */
X	SPEC|0xD7,              killregion,     /* ^Delete */
X	SPEC|0xC8,              backpage,       /* Previous */
X	SPEC|0xD8,              prevwind,       /* ^Previous */
X	SPEC|0xC9,              forwpage,       /* Next */
X	SPEC|0xD9,              nextwind,       /* ^Next */
X	SPEC|0xCB,              ctrlg,          /* Erase */
X	SPEC|0xDB,              ctrlg,          /* ^Erase */
X	SPEC|0xDC,              ctrlg,          /* ^Tab */
X	SPEC|0xCD,              ctrlg,          /* BackTab */
X	SPEC|0xDD,              ctrlg,          /* ^BackTab */
X	SPEC|0x80,              ctrlg,          /* Indent */
X	SPEC|0x90,              ctrlg,          /* ^Indent */
X	SPEC|0x81,              ctrlg,          /* Page */
X	SPEC|0x91,              ctrlg,          /* ^Page */
X	SPEC|0x82,              ctrlg,          /* Center */
X	SPEC|0x92,              ctrlg,          /* ^Center */
X	SPEC|0x83,              ctrlg,          /* DecTab */
X	SPEC|0x93,              ctrlg,          /* ^DecTab */
X	SPEC|0x84,              ctrlg,          /* Format */
X	SPEC|0x94,              ctrlg,          /* ^Format */
X	SPEC|0x85,              ctrlg,          /* Merge */
X	SPEC|0x95,              ctrlg,          /* ^Merge */
X	SPEC|0x86,              setmark,        /* Note */
X	SPEC|0x96,              ctrlg,          /* ^Note */
X	SPEC|0x87,              ctrlg,          /* Stop */
X	SPEC|0x97,              ctrlg,          /* ^Stop */
X	SPEC|0x88,              forwsearch,     /* Srch */
X	SPEC|0x98,              backsearch,     /* ^Srch */
X	SPEC|0x89,              sreplace,       /* Replac */
X	SPEC|0x99,              qreplace,       /* ^Replac */
X	SPEC|0x8A,              ctrlg,          /* Copy */
X	SPEC|0x9A,              ctrlg,          /* ^Copy */
X	SPEC|0x8B,              ctrlg,          /* Move */
X	SPEC|0x9B,              ctrlg,          /* ^Move */
X	SPEC|0x8C,              namedcmd,       /* Command */
X	SPEC|0x9C,              spawn,          /* ^Command */
X	SPEC|0x8D,              ctrlg,          /* ^ */
X	SPEC|0x9D,              ctrlg,          /* ^^ */
X	SPEC|0x8E,              ctrlg,          /* Blank */
X	SPEC|0x9E,              ctrlg,          /* ^Blank */
X	SPEC|0x8F,              gotoline,       /* GoTo */
X	SPEC|0x9F,              usebuffer,      /* ^GoTo */
X#endif
X 
X	{0x7F,			backdel},
X
X	/* special internal bindings */
X	SPEC|META|'W',		wrapword,	/* called on word wrap */
X	SPEC|META|'C',		nullproc,	/*  every command input */
X	SPEC|META|'R',		nullproc,	/*  on file read */
X	{0,			NULL}
X};
X
X#if RAINBOW
X
X#include "rainbow.h"
X
X/*
X * Mapping table from the LK201 function keys to the internal EMACS character.
X */
X
Xshort lk_map[][2] = {
X	Up_Key,                         CTRL+'P',
X	Down_Key,                       CTRL+'N',
X	Left_Key,                       CTRL+'B',
X	Right_Key,                      CTRL+'F',
X	Shift+Left_Key,                 META+'B',
X	Shift+Right_Key,                META+'F',
X	Control+Left_Key,               CTRL+'A',
X	Control+Right_Key,              CTRL+'E',
X	Prev_Scr_Key,                   META+'V',
X	Next_Scr_Key,                   CTRL+'V',
X	Shift+Up_Key,                   META+'<',
X	Shift+Down_Key,                 META+'>',
X	Cancel_Key,                     CTRL+'G',
X	Find_Key,                       CTRL+'S',
X	Shift+Find_Key,                 CTRL+'R',
X	Insert_Key,                     CTRL+'Y',
X	Options_Key,                    CTRL+'D',
X	Shift+Options_Key,              META+'D',
X	Remove_Key,                     CTRL+'W',
X	Shift+Remove_Key,               META+'W',
X	Select_Key,                     CTRL+'@',
X	Shift+Select_Key,               CTLX+CTRL+'X',
X	Interrupt_Key,                  CTRL+'U',
X	Keypad_PF2,                     META+'L',
X	Keypad_PF3,                     META+'C',
X	Keypad_PF4,                     META+'U',
X	Shift+Keypad_PF2,               CTLX+CTRL+'L',
X	Shift+Keypad_PF4,               CTLX+CTRL+'U',
X	Keypad_1,                       CTLX+'1',
X	Keypad_2,                       CTLX+'2',
X	Do_Key,                         CTLX+'E',
X	Keypad_4,                       CTLX+CTRL+'B',
X	Keypad_5,                       CTLX+'B',
X	Keypad_6,                       CTLX+'K',
X	Resume_Key,                     META+'!',
X	Control+Next_Scr_Key,           CTLX+'N',
X	Control+Prev_Scr_Key,           CTLX+'P',
X	Control+Up_Key,                 CTLX+CTRL+'P',
X	Control+Down_Key,               CTLX+CTRL+'N',
X	Help_Key,                       CTLX+'=',
X	Shift+Do_Key,                   CTLX+'(',
X	Control+Do_Key,                 CTLX+')',
X	Keypad_0,                       CTLX+'Z',
X	Shift+Keypad_0,                 CTLX+CTRL+'Z',
X	Main_Scr_Key,                   CTRL+'C',
X	Keypad_Enter,                   CTLX+'!',
X	Exit_Key,                       CTLX+CTRL+'C',
X	Shift+Exit_Key,                 CTRL+'Z'
X};
X
X#define lk_map_size     (sizeof(lk_map)/2)
X#endif
X
FRIDAY_NIGHT
echo extracting - edef.h
sed 's/^X//' > edef.h << 'FRIDAY_NIGHT'
X/*	EDEF:		Global variable definitions for
X			MicroEMACS 3.9
X
X			written by Dave G. Conroy
X			modified by Steve Wilhite, George Jones
X			greatly modified by Daniel Lawrence
X*/
X
X/* some global fuction declarations */
X
Xchar *flook();
Xchar *getctext();
Xchar *getfname();
Xchar *getval();
Xchar *gtenv();
Xchar *gtfun();
Xchar *gtusr();
Xchar *itoa();
Xchar *ltos();
Xchar *malloc();
Xchar *mklower();
Xchar *mkupper();
Xchar *strcat();
Xchar *strcpy();
Xchar *strncpy();
Xchar *token();
Xchar *transbind();
Xunsigned int getckey();
Xunsigned int stock();
X
X#ifdef	maindef
X
X/* for MAIN.C */
X
X/* initialized global definitions */
X
Xint     fillcol = 72;                   /* Current fill column          */
Xshort   kbdm[NKBDM];			/* Macro                        */
Xchar	*execstr = NULL;		/* pointer to string to execute	*/
Xchar	golabel[NPAT] = "";		/* current line to go to	*/
Xint	execlevel = 0;			/* execution IF level		*/
Xint	eolexist = TRUE;		/* does clear to EOL exist	*/
Xint	revexist = FALSE;		/* does reverse video exist?	*/
Xint	flickcode = FALSE;		/* do flicker supression?	*/
Xchar	*modename[] = {			/* name of modes		*/
X	"WRAP", "CMODE", "SPELL", "EXACT", "VIEW", "OVER",
X	"MAGIC", "CRYPT", "ASAVE"};
Xchar	modecode[] = "WCSEVOMYA";	/* letters to represent modes	*/
Xint	gmode = 0;			/* global editor mode		*/
Xint	gflags = GFREAD;		/* global control flag		*/
Xint	gfcolor = 7;			/* global forgrnd color (white)	*/
Xint	gbcolor	= 0;			/* global backgrnd color (black)*/
Xint	gasave = 256;			/* global ASAVE size		*/
Xint	gacount = 256;			/* count until next ASAVE	*/
Xint     sgarbf  = TRUE;                 /* TRUE if screen is garbage	*/
Xint     mpresf  = FALSE;                /* TRUE if message in last line */
Xint	clexec	= FALSE;		/* command line execution flag	*/
Xint	mstore	= FALSE;		/* storing text to macro flag	*/
Xint	discmd	= TRUE;			/* display command flag		*/
Xint	disinp	= TRUE;			/* display input characters	*/
Xstruct	BUFFER *bstore = NULL;		/* buffer to store macro text to*/
Xint     vtrow   = 0;                    /* Row location of SW cursor */
Xint     vtcol   = 0;                    /* Column location of SW cursor */
Xint     ttrow   = HUGE;                 /* Row location of HW cursor */
Xint     ttcol   = HUGE;                 /* Column location of HW cursor */
Xint	lbound	= 0;			/* leftmost column of current line
X					   being displayed */
Xint	taboff	= 0;			/* tab offset for display	*/
Xint	metac = CTRL | '[';		/* current meta character */
Xint	ctlxc = CTRL | 'X';		/* current control X prefix char */
Xint	reptc = CTRL | 'U';		/* current universal repeat char */
Xint	abortc = CTRL | 'G';		/* current abort command char	*/
X
Xint	quotec = 0x11;			/* quote char during mlreply() */
Xchar	*cname[] = {			/* names of colors		*/
X	"BLACK", "RED", "GREEN", "YELLOW", "BLUE",
X	"MAGENTA", "CYAN", "WHITE"};
XKILL *kbufp  = NULL;		/* current kill buffer chunk pointer	*/
XKILL *kbufh  = NULL;		/* kill buffer header pointer		*/
Xint kused = KBLOCK;		/* # of bytes used in kill buffer	*/
XWINDOW *swindow = NULL;		/* saved window pointer			*/
Xint cryptflag = FALSE;		/* currently encrypting?		*/
Xshort	*kbdptr;		/* current position in keyboard buf */
Xshort	*kbdend = &kbdm[0];	/* ptr to end of the keyboard */
Xint	kbdmode = STOP;		/* current keyboard macro mode	*/
Xint	kbdrep = 0;		/* number of repetitions	*/
Xint	restflag = FALSE;	/* restricted use?		*/
Xint	lastkey = 0;		/* last keystoke		*/
Xint	seed = 0;		/* random number seed		*/
Xlong	envram = 0l;	/* # of bytes current in use by malloc */
Xint	macbug = FALSE;		/* macro debuging flag		*/
Xchar	errorm[] = "ERROR";	/* error literal		*/
Xchar	truem[] = "TRUE";	/* true literal			*/
Xchar	falsem[] = "FALSE";	/* false litereal		*/
Xint	cmdstatus = TRUE;	/* last command status		*/
Xchar	palstr[49] = "";	/* palette string		*/
Xint	saveflag = 0;		/* Flags, saved with the $target var */
Xchar	*fline = NULL;		/* dynamic return line */
Xint	flen = 0;		/* current length of fline */
Xint	rval = 0;		/* return value of a subprocess */
X#if	CALLED
Xint	eexitflag = FALSE;	/* EMACS exit flag */
Xint	eexitval = 0;		/* and the exit return value */
X#endif
X
X/* uninitialized global definitions */
X
Xint     currow;                 /* Cursor row                   */
Xint     curcol;                 /* Cursor column                */
Xint     thisflag;               /* Flags, this command          */
Xint     lastflag;               /* Flags, last command          */
Xint     curgoal;                /* Goal for C-P, C-N            */
XWINDOW  *curwp;                 /* Current window               */
XBUFFER  *curbp;                 /* Current buffer               */
XWINDOW  *wheadp;                /* Head of list of windows      */
XBUFFER  *bheadp;                /* Head of list of buffers      */
XBUFFER  *blistp;                /* Buffer for C-X C-B           */
X
XBUFFER  *bfind();               /* Lookup a buffer by name      */
XWINDOW  *wpopup();              /* Pop up window creation       */
XLINE    *lalloc();              /* Allocate a line              */
Xchar	sres[NBUFN];		/* current screen resolution	*/
X
Xchar    pat[NPAT];                      /* Search pattern		*/
Xchar	tap[NPAT];			/* Reversed pattern array.	*/
Xchar	rpat[NPAT];			/* replacement pattern		*/
X
X/* The variable matchlen holds the length of the matched
X * string - used by the replace functions.
X * The variable patmatch holds the string that satisfies
X * the search command.
X * The variables matchline and matchoff hold the line and
X * offset position of the *start* of match.
X */
Xunsigned int	matchlen = 0;
Xunsigned int	mlenold  = 0;
Xchar		*patmatch = NULL;
XLINE		*matchline = NULL;
Xint		matchoff = 0;
X
X#if	MAGIC
X/*
X * The variables magical and rmagical determine if there
X * were actual metacharacters in the search and replace strings -
X * if not, then we don't have to use the slower MAGIC mode
X * search functions.
X */
Xshort int	magical = FALSE;
Xshort int	rmagical = FALSE;
XMC		mcpat[NPAT];		/* the magic pattern		*/
XMC		tapcm[NPAT];		/* the reversed magic pattern	*/
XRMC		rmcpat[NPAT];		/* the replacement magic array	*/
X
X#endif
X
X/* directive name table:
X	This holds the names of all the directives....	*/
X
Xchar *dname[] = {
X	"if", "else", "endif",
X	"goto", "return", "endm",
X	"while", "endwhile", "break",
X	"force"
X};
X
X#if	DEBUGM
X/*	vars needed for macro debugging output	*/
Xchar outline[NSTRING];		/* global string to hold debug line text */
X#endif
X
X#else
X
X/* for all the other .C files */
X
X/* initialized global external declarations */
X
Xextern  int     fillcol;                /* Fill column                  */
Xextern  short   kbdm[];                 /* Holds kayboard macro data    */
Xextern  char    pat[];                  /* Search pattern               */
Xextern	char	rpat[];			/* Replacement pattern		*/
Xextern	char	*execstr;		/* pointer to string to execute	*/
Xextern	char	golabel[];		/* current line to go to	*/
Xextern	int	execlevel;		/* execution IF level		*/
Xextern	int	eolexist;		/* does clear to EOL exist?	*/
Xextern	int	revexist;		/* does reverse video exist?	*/
Xextern	int	flickcode;		/* do flicker supression?	*/
Xextern	char *modename[];		/* text names of modes		*/
Xextern	char	modecode[];		/* letters to represent modes	*/
Xextern	KEYTAB keytab[];		/* key bind to functions table	*/
Xextern	NBIND names[];			/* name to function table	*/
Xextern	int	gmode;			/* global editor mode		*/
Xextern	int	gflags;			/* global control flag		*/
Xextern	int	gfcolor;		/* global forgrnd color (white)	*/
Xextern	int	gbcolor;		/* global backgrnd color (black)*/
Xextern	int	gasave;			/* global ASAVE size		*/
Xextern	int	gacount;		/* count until next ASAVE	*/
Xextern  int     sgarbf;                 /* State of screen unknown      */
Xextern  int     mpresf;                 /* Stuff in message line        */
Xextern	int	clexec;			/* command line execution flag	*/
Xextern	int	mstore;			/* storing text to macro flag	*/
Xextern	int	discmd;			/* display command flag		*/
Xextern	int	disinp;			/* display input characters	*/
Xextern	struct	BUFFER *bstore;		/* buffer to store macro text to*/
Xextern	int     vtrow;                  /* Row location of SW cursor */
Xextern	int     vtcol;                  /* Column location of SW cursor */
Xextern	int     ttrow;                  /* Row location of HW cursor */
Xextern	int     ttcol;                  /* Column location of HW cursor */
Xextern	int	lbound;			/* leftmost column of current line
X					   being displayed */
Xextern	int	taboff;			/* tab offset for display	*/
Xextern	int	metac;			/* current meta character */
Xextern	int	ctlxc;			/* current control X prefix char */
Xextern	int	reptc;			/* current universal repeat char */
Xextern	int	abortc;			/* current abort command char	*/
X
Xextern	int	quotec;			/* quote char during mlreply() */
Xextern	char	*cname[];		/* names of colors		*/
Xextern KILL *kbufp;			/* current kill buffer chunk pointer */
Xextern KILL *kbufh;			/* kill buffer header pointer	*/
Xextern int kused;			/* # of bytes used in KB        */
Xextern WINDOW *swindow;			/* saved window pointer		*/
Xextern int cryptflag;			/* currently encrypting?	*/
Xextern	short	*kbdptr;		/* current position in keyboard buf */
Xextern	short	*kbdend;		/* ptr to end of the keyboard */
Xextern	int kbdmode;			/* current keyboard macro mode	*/
Xextern	int kbdrep;			/* number of repetitions	*/
Xextern	int restflag;			/* restricted use?		*/
Xextern	int lastkey;			/* last keystoke		*/
Xextern	int seed;			/* random number seed		*/
Xextern	long envram;		/* # of bytes current in use by malloc */
Xextern	int	macbug;			/* macro debuging flag		*/
Xextern	char	errorm[];		/* error literal		*/
Xextern	char	truem[];		/* true literal			*/
Xextern	char	falsem[];		/* false litereal		*/
Xextern	int	cmdstatus;		/* last command status		*/
Xextern	char	palstr[];		/* palette string		*/
Xextern	int	saveflag;		/* Flags, saved with the $target var */
Xextern	char	*fline;			/* dynamic return line */
Xextern	int	flen;			/* current length of fline */
Xextern	int	rval;			/* return value of a subprocess */
X#if	CALLED
Xextern	int	eexitflag;		/* EMACS exit flag */
Xextern	int	eexitval;		/* and the exit return value */
X#endif
X
X/* uninitialized global external declarations */
X
Xextern  int     currow;                 /* Cursor row                   */
Xextern  int     curcol;                 /* Cursor column                */
Xextern  int     thisflag;               /* Flags, this command          */
Xextern  int     lastflag;               /* Flags, last command          */
Xextern  int     curgoal;                /* Goal for C-P, C-N            */
Xextern  WINDOW  *curwp;                 /* Current window               */
Xextern  BUFFER  *curbp;                 /* Current buffer               */
Xextern  WINDOW  *wheadp;                /* Head of list of windows      */
Xextern  BUFFER  *bheadp;                /* Head of list of buffers      */
Xextern  BUFFER  *blistp;                /* Buffer for C-X C-B           */
X
Xextern  BUFFER  *bfind();               /* Lookup a buffer by name      */
Xextern  WINDOW  *wpopup();              /* Pop up window creation       */
Xextern  LINE    *lalloc();              /* Allocate a line              */
Xextern	char	sres[NBUFN];		/* current screen resolution	*/
Xextern	char    pat[];                  /* Search pattern		*/
Xextern	char	tap[];			/* Reversed pattern array.	*/
Xextern	char	rpat[];			/* replacement pattern		*/
X
Xextern unsigned int matchlen;
Xextern unsigned int mlenold;
Xextern char *patmatch;
Xextern LINE *matchline;
Xextern int matchoff;
X
X#if	MAGIC
Xextern short int magical;
Xextern short int rmagical;
Xextern MC mcpat[NPAT];		/* the magic pattern		*/
Xextern MC tapcm[NPAT];		/* the reversed magic pattern	*/
Xextern RMC rmcpat[NPAT];	/* the replacement magic array	*/
X#endif
X
Xextern char *dname[];		/* directive name table		*/
X
X#if	DEBUGM
X/*	vars needed for macro debugging output	*/
Xextern char outline[];		/* global string to hold debug line text */
X#endif
X
X#endif
X
X/* terminal table defined only in TERM.C */
X
X#ifndef	termdef
Xextern  TERM    term;                   /* Terminal information.        */
X#endif
X
X
FRIDAY_NIGHT
echo extracting - efunc.h
sed 's/^X//' > efunc.h << 'FRIDAY_NIGHT'
X/*	EFUNC.H:	MicroEMACS function declarations and names
X
X		This file list all the C code functions used by MicroEMACS
X	and the names to use to bind keys to them. To add functions,
X	declare it here in both the extern function list and the name
X	binding table.
X
X*/
X
X/*	External function declarations		*/
X
Xextern  int     ctrlg();                /* Abort out of things          */
Xextern  int     quit();                 /* Quit                         */
Xextern  int     ctlxlp();               /* Begin macro                  */
Xextern  int     ctlxrp();               /* End macro                    */
Xextern  int     ctlxe();                /* Execute macro                */
Xextern  int     fileread();             /* Get a file, read only        */
Xextern  int     filefind();		/* Get a file, read write       */
Xextern  int     filewrite();            /* Write a file                 */
Xextern  int     filesave();             /* Save current file            */
Xextern  int     filename();             /* Adjust file name             */
Xextern  int     getccol();              /* Get current column           */
Xextern  int     gotobol();              /* Move to start of line        */
Xextern  int     forwchar();             /* Move forward by characters   */
Xextern  int     gotoeol();              /* Move to end of line          */
Xextern  int     backchar();             /* Move backward by characters  */
Xextern  int     forwline();             /* Move forward by lines        */
Xextern  int     backline();             /* Move backward by lines       */
Xextern  int     forwpage();             /* Move forward by pages        */
Xextern  int     backpage();             /* Move backward by pages       */
Xextern  int     gotobob();              /* Move to start of buffer      */
Xextern  int     gotoeob();              /* Move to end of buffer        */
Xextern  int     setfillcol();           /* Set fill column.             */
Xextern  int     setmark();              /* Set mark                     */
Xextern  int     swapmark();             /* Swap "." and mark            */
Xextern  int     forwsearch();           /* Search forward               */
Xextern  int     backsearch();           /* Search backwards             */
Xextern	int	sreplace();		/* search and replace		*/
Xextern	int	qreplace();		/* search and replace w/query	*/
Xextern  int     showcpos();             /* Show the cursor position     */
Xextern  int     nextwind();             /* Move to the next window      */
Xextern  int     prevwind();             /* Move to the previous window  */
Xextern  int     onlywind();             /* Make current window only one */
Xextern  int     splitwind();            /* Split current window         */
Xextern  int     mvdnwind();             /* Move window down             */
Xextern  int     mvupwind();             /* Move window up               */
Xextern  int     enlargewind();          /* Enlarge display window.      */
Xextern  int     shrinkwind();           /* Shrink window.               */
Xextern  int     listbuffers();          /* Display list of buffers      */
Xextern  int     usebuffer();            /* Switch a window to a buffer  */
Xextern  int     killbuffer();           /* Make a buffer go away.       */
Xextern  int     reposition();           /* Reposition window            */
Xextern  int     refresh();              /* Refresh the screen           */
Xextern  int     twiddle();              /* Twiddle characters           */
Xextern  int     tab();                  /* Insert tab                   */
Xextern  int     newline();              /* Insert CR-LF                 */
Xextern  int     indent();               /* Insert CR-LF, then indent    */
Xextern  int     openline();             /* Open up a blank line         */
Xextern  int     deblank();              /* Delete blank lines           */
Xextern  int     quote();                /* Insert literal               */
Xextern  int     backword();             /* Backup by words              */
Xextern  int     forwword();             /* Advance by words             */
Xextern  int     forwdel();              /* Forward delete               */
Xextern  int     backdel();              /* Backward delete              */
Xextern  int     killtext();             /* Kill forward                 */
Xextern  int     yank();                 /* Yank back from killbuffer.   */
Xextern  int     upperword();            /* Upper case word.             */
Xextern  int     lowerword();            /* Lower case word.             */
Xextern  int     upperregion();          /* Upper case region.           */
Xextern  int     lowerregion();          /* Lower case region.           */
Xextern  int     capword();              /* Initial capitalize word.     */
Xextern  int     delfword();             /* Delete forward word.         */
Xextern  int     delbword();             /* Delete backward word.        */
Xextern  int     killregion();           /* Kill region.                 */
Xextern  int     copyregion();           /* Copy region to kill buffer.  */
Xextern  int     spawncli();             /* Run CLI in a subjob.         */
Xextern  int     spawn();                /* Run a command in a subjob.   */
X#if	BSD
Xextern	int	bktoshell();		/* suspend emacs to parent shell*/
Xextern	int	rtfrmshell();		/* return from a suspended state*/
X#endif
Xextern  int     quickexit();            /* low keystroke style exit.    */
Xextern	int	setmode();		/* set an editor mode		*/
Xextern	int	delmode();		/* delete a mode		*/
Xextern	int	gotoline();		/* go to a numbered line	*/
Xextern	int	namebuffer();		/* rename the current buffer	*/
X#if	WORDPRO
Xextern	int	gotobop();		/* go to beginning/paragraph	*/
Xextern	int	gotoeop();		/* go to end/paragraph		*/
Xextern	int	fillpara();		/* fill current paragraph	*/
X#endif
Xextern	int	help();			/* get the help file here	*/
Xextern	int	deskey();		/* describe a key's binding	*/
Xextern	int	viewfile();		/* find a file in view mode	*/
Xextern	int	insfile();		/* insert a file		*/
Xextern	int	scrnextup();		/* scroll next window back	*/
Xextern	int	scrnextdw();		/* scroll next window down	*/
Xextern	int	bindtokey();		/* bind a function to a key	*/
Xextern	int	unbindkey();		/* unbind a key's function	*/
Xextern	int	namedcmd();		/* execute named command	*/
Xextern	int	desbind();		/* describe bindings		*/
Xextern	int	execcmd();		/* execute a command line	*/
Xextern	int	execbuf();		/* exec commands from a buffer	*/
Xextern	int	execfile();		/* exec commands from a file	*/
Xextern	int	nextbuffer();		/* switch to the next buffer	*/
X#if	WORDPRO
Xextern	int	killpara();		/* kill the current paragraph	*/
X#endif
Xextern	int	setgmode();		/* set a global mode		*/
Xextern	int	delgmode();		/* delete a global mode		*/
Xextern	int	insspace();		/* insert a space forword	*/
Xextern	int	forwhunt();		/* hunt forward for next match	*/
Xextern	int	backhunt();		/* hunt backwards for next match*/
Xextern	int	pipecmd();		/* pipe command into buffer	*/
Xextern	int	filter();		/* filter buffer through dos	*/
Xextern	int	delwind();		/* delete the current window	*/
Xextern	int	cbuf1();		/* execute numbered comd buffer */
Xextern	int	cbuf2();
Xextern	int	cbuf3();
Xextern	int	cbuf4();
Xextern	int	cbuf5();
Xextern	int	cbuf6();
Xextern	int	cbuf7();
Xextern	int	cbuf8();
Xextern	int	cbuf9();
Xextern	int	cbuf10();
Xextern	int	cbuf11();
Xextern	int	cbuf12();
Xextern	int	cbuf13();
Xextern	int	cbuf14();
Xextern	int	cbuf15();
Xextern	int	cbuf16();
Xextern	int	cbuf17();
Xextern	int	cbuf18();
Xextern	int	cbuf19();
Xextern	int	cbuf20();
Xextern	int	cbuf21();
Xextern	int	cbuf22();
Xextern	int	cbuf23();
Xextern	int	cbuf24();
Xextern	int	cbuf25();
Xextern	int	cbuf26();
Xextern	int	cbuf27();
Xextern	int	cbuf28();
Xextern	int	cbuf29();
Xextern	int	cbuf30();
Xextern	int	cbuf31();
Xextern	int	cbuf32();
Xextern	int	cbuf33();
Xextern	int	cbuf34();
Xextern	int	cbuf35();
Xextern	int	cbuf36();
Xextern	int	cbuf37();
Xextern	int	cbuf38();
Xextern	int	cbuf39();
Xextern	int	cbuf40();
Xextern	int	storemac();		/* store text for macro		*/
Xextern	int	resize();		/* resize current window	*/
Xextern	int	clrmes();		/* clear the message line	*/
Xextern	int	meta();			/* meta prefix dummy function	*/
Xextern	int	cex();			/* ^X prefix dummy function	*/
Xextern	int	unarg();		/* ^U repeat arg dummy function	*/
Xextern	int	istring();		/* insert string in text	*/
Xextern	int	unmark();		/* unmark current buffer	*/
X#if	ISRCH
Xextern	int	fisearch();		/* forward incremental search	*/
Xextern	int	risearch();		/* reverse incremental search	*/
X#endif
X#if	WORDPRO
Xextern	int	wordcount();		/* count words in region	*/
X#endif
Xextern	int	savewnd();		/* save current window		*/
Xextern	int	restwnd();		/* restore current window	*/
Xextern	int	upscreen();		/* force screen update		*/
Xextern	int	writemsg();		/* write text on message line	*/
X#if	FLABEL
Xextern	int	fnclabel();		/* set function key label	*/
X#endif
X#if	APROP
Xextern	int	apro();			/* apropos fuction		*/
X#endif
X#if	CRYPT
Xextern	int	setkey();		/* set encryption key		*/
X#endif
Xextern	int	wrapword();		/* wordwrap function		*/
X#if	CFENCE
Xextern	int	getfence();		/* move cursor to a matching fence */
X#endif
Xextern	int	newsize();		/* change the current screen size */
Xextern	int	setvar();		/* set a variables value */
Xextern	int	newwidth();		/* change the current screen width */
X#if	AEDIT
Xextern	int	trim();			/* trim whitespace from end of line */
Xextern	int	detab();		/* detab rest of line */
Xextern	int	entab();		/* entab rest of line */
X#endif
X#if	PROC
Xextern	int	storeproc();		/* store names procedure */
Xextern	int	execproc();		/* execute procedure */
X#endif
Xextern	int	nullproc();		/* does nothing... */
Xextern	int	ovstring();		/* overwrite a string */
Xextern	int	execprg();		/* execute a program */
X
X/*	Name to function binding table
X
X		This table gives the names of all the bindable functions
X	end their C function address. These are used for the bind-to-key
X	function.
X*/
X
XNBIND	names[] = {
X	{"abort-command",		ctrlg},
X	{"add-mode",			setmode},
X	{"add-global-mode",		setgmode},
X#if	APROP
X	{"apropos",			apro},
X#endif
X	{"backward-character",		backchar},
X	{"begin-macro",			ctlxlp},
X	{"beginning-of-file",		gotobob},
X	{"beginning-of-line",		gotobol},
X	{"bind-to-key",			bindtokey},
X	{"buffer-position",		showcpos},
X	{"case-region-lower",		lowerregion},
X	{"case-region-upper",		upperregion},
X	{"case-word-capitalize",	capword},
X	{"case-word-lower",		lowerword},
X	{"case-word-upper",		upperword},
X	{"change-file-name",		filename},
X	{"change-screen-size",		newsize},
X	{"change-screen-width",		newwidth},
X	{"clear-and-redraw",		refresh},
X	{"clear-message-line",		clrmes},
X	{"copy-region",			copyregion},
X#if	WORDPRO
X	{"count-words",			wordcount},
X#endif
X	{"ctlx-prefix",			cex},
X	{"delete-blank-lines",		deblank},
X	{"delete-buffer",		killbuffer},
X	{"delete-mode",			delmode},
X	{"delete-global-mode",		delgmode},
X	{"delete-next-character",	forwdel},
X	{"delete-next-word",		delfword},
X	{"delete-other-windows",	onlywind},
X	{"delete-previous-character",	backdel},
X	{"delete-previous-word",	delbword},
X	{"delete-window",		delwind},
X	{"describe-bindings",		desbind},
X	{"describe-key",		deskey},
X#if	AEDIT
X	{"detab-line",			detab},
X#endif
X	{"end-macro",			ctlxrp},
X	{"end-of-file",			gotoeob},
X	{"end-of-line",			gotoeol},
X#if	AEDIT
X	{"entab-line",			entab},
X#endif
X	{"exchange-point-and-mark",	swapmark},
X	{"execute-buffer",		execbuf},
X	{"execute-command-line",	execcmd},
X	{"execute-file",		execfile},
X	{"execute-macro",		ctlxe},
X	{"execute-macro-1",		cbuf1},
X	{"execute-macro-2",		cbuf2},
X	{"execute-macro-3",		cbuf3},
X	{"execute-macro-4",		cbuf4},
X	{"execute-macro-5",		cbuf5},
X	{"execute-macro-6",		cbuf6},
X	{"execute-macro-7",		cbuf7},
X	{"execute-macro-8",		cbuf8},
X	{"execute-macro-9",		cbuf9},
X	{"execute-macro-10",		cbuf10},
X	{"execute-macro-11",		cbuf11},
X	{"execute-macro-12",		cbuf12},
X	{"execute-macro-13",		cbuf13},
X	{"execute-macro-14",		cbuf14},
X	{"execute-macro-15",		cbuf15},
X	{"execute-macro-16",		cbuf16},
X	{"execute-macro-17",		cbuf17},
X	{"execute-macro-18",		cbuf18},
X	{"execute-macro-19",		cbuf19},
X	{"execute-macro-20",		cbuf20},
X	{"execute-macro-21",		cbuf21},
X	{"execute-macro-22",		cbuf22},
X	{"execute-macro-23",		cbuf23},
X	{"execute-macro-24",		cbuf24},
X	{"execute-macro-25",		cbuf25},
X	{"execute-macro-26",		cbuf26},
X	{"execute-macro-27",		cbuf27},
X	{"execute-macro-28",		cbuf28},
X	{"execute-macro-29",		cbuf29},
X	{"execute-macro-30",		cbuf30},
X	{"execute-macro-31",		cbuf31},
X	{"execute-macro-32",		cbuf32},
X	{"execute-macro-33",		cbuf33},
X	{"execute-macro-34",		cbuf34},
X	{"execute-macro-35",		cbuf35},
X	{"execute-macro-36",		cbuf36},
X	{"execute-macro-37",		cbuf37},
X	{"execute-macro-38",		cbuf38},
X	{"execute-macro-39",		cbuf39},
X	{"execute-macro-40",		cbuf40},
X	{"execute-named-command",	namedcmd},
X#if	PROC
X	{"execute-procedure",		execproc},
X#endif
X	{"execute-program",		execprg},
X	{"exit-emacs",			quit},
X#if	WORDPRO
X	{"fill-paragraph",		fillpara},
X#endif
X	{"filter-buffer",		filter},
X	{"find-file",			filefind},
X	{"forward-character",		forwchar},
X	{"goto-line",			gotoline},
X#if	CFENCE
X	{"goto-matching-fence",		getfence},
X#endif
X	{"grow-window",			enlargewind},
X	{"handle-tab",			tab},
X	{"hunt-forward",		forwhunt},
X	{"hunt-backward",		backhunt},
X	{"help",			help},
X	{"i-shell",			spawncli},
X#if	ISRCH
X	{"incremental-search",		fisearch},
X#endif
X	{"insert-file",			insfile},
X	{"insert-space",		insspace},
X	{"insert-string",		istring},
X#if	WORDPRO
X	{"kill-paragraph",		killpara},
X#endif
X	{"kill-region",			killregion},
X	{"kill-to-end-of-line",		killtext},
X#if	FLABEL
X	{"label-function-key",		fnclabel},
X#endif
X	{"list-buffers",		listbuffers},
X	{"meta-prefix",			meta},
X	{"move-window-down",		mvdnwind},
X	{"move-window-up",		mvupwind},
X	{"name-buffer",			namebuffer},
X	{"newline",			newline},
X	{"newline-and-indent",		indent},
X	{"next-buffer",			nextbuffer},
X	{"next-line",			forwline},
X	{"next-page",			forwpage},
X#if	WORDPRO
X	{"next-paragraph",		gotoeop},
X#endif
X	{"next-window",			nextwind},
X	{"next-word",			forwword},
X	{"nop",				nullproc},
X	{"open-line",			openline},
X	{"overwrite-string",		ovstring},
X	{"pipe-command",		pipecmd},
X	{"previous-line",		backline},
X	{"previous-page",		backpage},
X#if	WORDPRO
X	{"previous-paragraph",		gotobop},
X#endif
X	{"previous-window",		prevwind},
X	{"previous-word",		backword},
X	{"query-replace-string",	qreplace},
X	{"quick-exit",			quickexit},
X	{"quote-character",		quote},
X	{"read-file",			fileread},
X	{"redraw-display",		reposition},
X	{"resize-window",		resize},
X	{"restore-window",		restwnd},
X	{"replace-string",		sreplace},
X#if	ISRCH
X	{"reverse-incremental-search",	risearch},
X#endif
X#if	PROC
X	{"run",				execproc},
X#endif
X	{"save-file",			filesave},
X	{"save-window",			savewnd},
X	{"scroll-next-up",		scrnextup},
X	{"scroll-next-down",		scrnextdw},
X	{"search-forward",		forwsearch},
X	{"search-reverse",		backsearch},
X	{"select-buffer",		usebuffer},
X	{"set",				setvar},
X#if	CRYPT
X	{"set-encryption-key",		setkey},
X#endif
X	{"set-fill-column",		setfillcol},
X	{"set-mark",			setmark},
X	{"shell-command",		spawn},
X	{"shrink-window",		shrinkwind},
X	{"split-current-window",	splitwind},
X	{"store-macro",			storemac},
X#if	PROC
X	{"store-procedure",		storeproc},
X#endif
X#if	BSD
X	{"suspend-emacs",		bktoshell},
X#endif
X	{"transpose-characters",	twiddle},
X#if	AEDIT
X	{"trim-line",			trim},
X#endif
X	{"unbind-key",			unbindkey},
X	{"universal-argument",		unarg},
X	{"unmark-buffer",		unmark},
X	{"update-screen",		upscreen},
X	{"view-file",			viewfile},
X	{"wrap-word",			wrapword},
X	{"write-file",			filewrite},
X	{"write-message",		writemsg},
X	{"yank",			yank},
X
X	{"",			NULL}
X};
FRIDAY_NIGHT
echo mes.15 completed!
# That's all folksmb

nwd@j.cc.purdue.edu (Daniel Lawrence) (11/17/87)

# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh mes.16')
# If you do not see the message
#	`mes.16 completed!'
# then the file was incomplete.
echo extracting - epath.h
sed 's/^X//' > epath.h << 'FRIDAY_NIGHT'
X/*	EPATH:	This file contains certain info needed to locate the
X		MicroEMACS files on a system dependant basis.
X
X									*/
X
X/*	possible names and paths of help files under different OSs	*/
X
Xchar *pathname[] =
X
X#if	AMIGA
X{
X	".emacsrc",
X	"emacs.hlp",
X	"",
X	"sys:c/",
X	"sys:t/",
X	"sys:s/",
X	"c:/",
X	":t/",
X	":s/"
X};
X#endif
X
X#if	ST520
X{
X	"emacs.rc",
X	"emacs.hlp",
X	"\\",
X	"\\bin\\",
X	"\\util\\",
X	""
X};
X#endif
X
X#if	FINDER
X{
X	"emacs.rc",
X	"emacs.hlp",
X	"/bin",
X	"/sys/public",
X	""
X};
X#endif
X
X#if	MSDOS
X{
X	"emacs.rc",
X	"emacs.hlp",
X	"\\sys\\public\\",
X	"\\usr\\bin\\",
X	"\\bin\\",
X	"\\",
X	""
X};
X#endif
X
X#if	V7 | BSD | USG
X{
X	".emacsrc",
X	"emacs.hlp",
X	"/usr/local/",
X	"/usr/lib/",
X	""
X};
X#endif
X
X#if	VMS
X{
X	"emacs.rc",
X	"emacs.hlp",
X	"",
X	"sys$sysdevice:[vmstools]"
X};
X#endif
X
X#define	NPNAMES	(sizeof(pathname)/sizeof(char *))
FRIDAY_NIGHT
echo extracting - estruct.h
sed 's/^X//' > estruct.h << 'FRIDAY_NIGHT'
X/*      ESTRUCT:        Structure and preprocesser defined for
X                        MicroEMACS 3.9
X
X                        written by Dave G. Conroy
X                        modified by Steve Wilhite, George Jones
X                        substantially modified by Daniel Lawrence
X*/
X
X#ifdef	LATTICE
X#undef	LATTICE		/* don't use their definitions...use ours	*/
X#endif
X#ifdef	MSDOS
X#undef	MSDOS
X#endif
X#ifdef	CPM
X#undef	CPM
X#endif
X#ifdef	AMIGA
X#undef	AMIGA
X#endif
X#ifdef	EGA
X#undef	EGA
X#endif
X#ifdef	CTRLZ
X#undef	CTRLZ
X#endif
X
X/*	Program Identification.....
X
X	PROGNAME should always be MicroEMACS for a distibrution
X	unmodified version. People using MicroEMACS as a shell
X	for other products should change this to reflect their
X	product. Macros can query this via the $progname variable
X*/
X
X#define	PROGNAME	"MicroEMACS"
X#define	VERSION		"3.9e"
X
X/*	Machine/OS definitions			*/
X
X#define AMIGA   0                       /* AmigaDOS			*/
X#define ST520   0                       /* ST520, TOS                   */
X#define MSDOS   1                       /* MS-DOS                       */
X#define V7      0                       /* V7 UNIX or Coherent or BSD4.2*/
X#define	BSD	0			/* UNIX BSD 4.2	and ULTRIX	*/
X#define	USG	0			/* UNIX system V		*/
X#define VMS     0                       /* VAX/VMS                      */
X#define CPM     0                       /* CP/M-86                      */
X#define	FINDER	0			/* Macintosh OS			*/
X
X/*	Compiler definitions			*/
X#define	UNIX	0	/* a random UNIX compiler */
X#define MWC	0	/* Marc Williams C */
X#define	LATTICE	0	/* Lattice 2.14 thruough 3.0 compilers */
X#define	AZTEC	1	/* Aztec C 3.20e */
X#define	MSC	0	/* MicroSoft C compile version 3 & 4 */
X#define	TURBO	0	/* Turbo C/MSDOS */
X
X/*	Debugging options	*/
X#define	RAMSIZE	0	/* dynamic RAM memory usage tracking */
X#define	RAMSHOW	0	/* auto dynamic RAM reporting */
X
X/*   Special keyboard definitions            */
X
X#define WANGPC	0		/* WangPC - mostly escape sequences     */
X#define VT100   0               /* Handle VT100 style keypad.   */
X
X/*	Terminal Output definitions		*/
X
X#define ANSI    0			/* ANSI escape sequences	*/
X#define	HP150	0			/* HP150 screen driver		*/
X#define	HP110	0			/* HP110 screen driver		*/
X#define	VMSVT	0			/* various VMS terminal entries	*/
X#define VT52    0                       /* VT52 terminal (Zenith).      */
X#define RAINBOW 0                       /* Use Rainbow fast video.      */
X#define TERMCAP 0                       /* Use TERMCAP                  */
X#define	IBMPC	1			/* IBM-PC CGA/MONO/EGA driver	*/
X#define	DG10	0			/* Data General system/10	*/
X#define	TIPC	0			/* TI Profesional PC driver	*/
X#define	Z309	0			/* Zenith 100 PC family	driver	*/
X#define	MAC	0			/* Macintosh			*/
X#define	ATARI	0			/* Atari 520/1040ST screen	*/
X
X/*	Configuration options	*/
X
X#define CVMVAS  1	/* arguments to page forward/back in pages	*/
X#define	CLRMSG	0	/* space clears the message line with no insert	*/
X#define	CFENCE	1	/* fench matching in CMODE			*/
X#define	TYPEAH	1	/* type ahead causes update to be skipped	*/
X#define DEBUGM	1	/* $debug triggers macro debugging		*/
X#define	VISMAC	0	/* update display during keyboard macros	*/
X#define	CTRLZ	0	/* add a ^Z at end of files under MSDOS only	*/
X#define ADDCR	0	/* ajout d'un CR en fin de chaque ligne (ST520) */
X#define	NBRACE	1	/* new style brace matching command		*/
X
X#define	REVSTA	1	/* Status line appears in reverse video		*/
X#define	COLOR	1	/* color commands and windows			*/
X
X#define	FILOCK	0	/* file locking under unix BSD 4.2		*/
X#define	ISRCH	1	/* Incremental searches like ITS EMACS		*/
X#define	WORDPRO	1	/* Advanced word processing features		*/
X#define	FLABEL	0	/* function key label code [HP150]		*/
X#define	APROP	1	/* Add code for Apropos command			*/
X#define	CRYPT	1	/* file encryption enabled?			*/
X#define MAGIC	1	/* include regular expression matching?		*/
X#define	AEDIT	1	/* advanced editing options: en/detabbing	*/
X#define	PROC	1	/* named procedures				*/
X#define	CLEAN	0	/* de-alloc memory on exit			*/
X#define	CALLED	0	/* is emacs a called subroutine? or stand alone */
X
X#define ASCII	1	/* always using ASCII char sequences for now	*/
X#define EBCDIC	0	/* later IBM mainfraim versions will use EBCDIC	*/
X
X/*	System dependant library redefinitions, structures and includes	*/
X
X#if	TURBO
X#include      <dos.h>
X#include      <mem.h>
X#undef peek
X#undef poke
X#define       peek(a,b,c,d)   movedata(a,b,FP_SEG(c),FP_OFF(c),d)
X#define       poke(a,b,c,d)   movedata(FP_SEG(c),FP_OFF(c),a,b,d)
X#endif
X
X#if	VMS
X#define	atoi	xatoi
X#define	abs	xabs
X#define	getname	xgetname
X#endif
X
X#if	LATTICE
X#define	unsigned
X#endif
X
X#if	AZTEC
X#undef	fputc
X#undef	fgetc
X#if	MSDOS
X#define	fgetc	a1getc
X#define	int86	sysint
X#define	intdos(a, b)	sysint(33, a, b)
X#define	inp	inportb
X#define	outp	outportb
X#else
X#define	fgetc	agetc
X#endif
X#define	fputc	aputc
X
Xstruct XREG {
X	unsigned ax,bx,cx,dx,si,di,ds,es;
X};
X
Xstruct HREG {
X	char al,ah,bl,bh,cl,ch,dl,dh,d1,d2,e1,e2;
X};
X
Xunion REGS {
X	struct XREG x;
X	struct HREG h;
X};
X
Xstruct SREGS {
X	unsigned cs, ss, ds, es;
X};
X#endif
X
X#if	MSDOS & MWC
X#include	<dos.h>
X#define	int86(a, b, c)	intcall(b, c, a)
X#define	inp	in
X
Xstruct XREG {
X	int ax,bx,cx,dx,si,di,ds,es,flags;
X};
X
Xstruct HREG {
X	char al,ah,bl,bh,cl,ch,dl,dh;
X	int ds,es,flags;
X};
X
Xunion REGS {
X	struct XREG x;
X	struct HREG h;
X};
X#endif
X
X#if	MSDOS & MSC
X#include	<dos.h>
X#include	<memory.h>
X#define	peek(a,b,c,d)	movedata(a,b,FP_SEG(c),FP_OFF(c),d)
X#define	poke(a,b,c,d)	movedata(FP_SEG(c),FP_OFF(c),a,b,d)
X#define	movmem(a, b, c)		memcpy(b, a, c)
X#endif
X
X#if	MSDOS & LATTICE
X#undef	CPM
X#undef	LATTICE
X#include	<dos.h>
X#undef	CPM
X#endif
X
X#if	VMS
X#define	unlink(a)	delete(a)
X#endif
X
X/*	define some ability flags */
X
X#if	IBMPC | Z309
X#define	MEMMAP	1
X#else
X#define	MEMMAP	0
X#endif
X
X#if	MSDOS | V7 | USG | BSD | (ST520 & MWC)
X#define	ENVFUNC	1
X#else
X#define	ENVFUNC	0
X#endif
X
X/*	Emacs global flag bit definitions (for gflags)	*/
X
X#define	GFREAD	1
X
X/*	internal constants	*/
X
X#define	NBINDS	256			/* max # of bound keys		*/
X#define NFILEN  80                      /* # of bytes, file name        */
X#define NBUFN   16                      /* # of bytes, buffer name      */
X#define NLINE   256                     /* # of bytes, input line       */
X#define	NSTRING	128			/* # of bytes, string buffers	*/
X#define NKBDM   256                     /* # of strokes, keyboard macro */
X#define NPAT    128                     /* # of bytes, pattern          */
X#define HUGE    1000                    /* Huge number                  */
X#define	NLOCKS	100			/* max # of file locks active	*/
X#define	NCOLORS	8			/* number of supported colors	*/
X#define	KBLOCK	250			/* sizeof kill buffer chunks	*/
X#define	NBLOCK	16			/* line block chunk size	*/
X#define	NVSIZE	10			/* max #chars in a var name	*/
X
X#define CTRL    0x0100                  /* Control flag, or'ed in       */
X#define META    0x0200                  /* Meta flag, or'ed in          */
X#define CTLX    0x0400                  /* ^X flag, or'ed in            */
X#define	SPEC	0x0800			/* special key (function keys)	*/
X
X#ifdef	FALSE
X#undef	FALSE
X#endif
X#ifdef	TRUE
X#undef	TRUE
X#endif
X
X#define FALSE   0                       /* False, no, bad, etc.         */
X#define TRUE    1                       /* True, yes, good, etc.        */
X#define ABORT   2                       /* Death, ^G, abort, etc.       */
X#define	FAILED	3			/* not-quite fatal false return	*/
X
X#define	STOP	0			/* keyboard macro not in use	*/
X#define	PLAY	1			/*		  playing	*/
X#define	RECORD	2			/*		  recording	*/
X
X/*	Directive definitions	*/
X
X#define	DIF		0
X#define DELSE		1
X#define DENDIF		2
X#define DGOTO		3
X#define DRETURN		4
X#define DENDM		5
X#define DWHILE		6
X#define	DENDWHILE	7
X#define	DBREAK		8
X#define DFORCE		9
X
X#define NUMDIRS		10
X
X/*
X * PTBEG, PTEND, FORWARD, and REVERSE are all toggle-able values for
X * the scan routines.
X */
X#define	PTBEG	0	/* Leave the point at the beginning on search	*/
X#define	PTEND	1	/* Leave the point at the end on search		*/
X#define	FORWARD	0			/* forward direction		*/
X#define REVERSE	1			/* backwards direction		*/
X
X#define FIOSUC  0                       /* File I/O, success.           */
X#define FIOFNF  1                       /* File I/O, file not found.    */
X#define FIOEOF  2                       /* File I/O, end of file.       */
X#define FIOERR  3                       /* File I/O, error.             */
X#define	FIOMEM	4			/* File I/O, out of memory	*/
X#define	FIOFUN	5			/* File I/O, eod of file/bad line*/
X
X#define CFCPCN  0x0001                  /* Last command was C-P, C-N    */
X#define CFKILL  0x0002                  /* Last command was a kill      */
X
X#define	BELL	0x07			/* a bell character		*/
X#define	TAB	0x09			/* a tab character		*/
X
X#if	V7 | USG | BSD
X#define	PATHCHR	':'
X#else
X#define	PATHCHR	';'
X#endif
X
X#define	INTWIDTH	sizeof(int) * 3
X
X/*	Macro argument token types					*/
X
X#define	TKNUL	0			/* end-of-string		*/
X#define	TKARG	1			/* interactive argument		*/
X#define	TKBUF	2			/* buffer argument		*/
X#define	TKVAR	3			/* user variables		*/
X#define	TKENV	4			/* environment variables	*/
X#define	TKFUN	5			/* function....			*/
X#define	TKDIR	6			/* directive			*/
X#define	TKLBL	7			/* line label			*/
X#define	TKLIT	8			/* numeric literal		*/
X#define	TKSTR	9			/* quoted string literal	*/
X#define	TKCMD	10			/* command name			*/
X
X/*	Internal defined functions					*/
X
X#define	nextab(a)	(a & ~7) + 8
X#ifdef	abs
X#undef	abs
X#endif
X
X/* DIFCASE represents the integer difference between upper
X   and lower case letters.  It is an xor-able value, which is
X   fortunate, since the relative positions of upper to lower
X   case letters is the opposite of ascii in ebcdic.
X*/
X
X#ifdef	islower
X#undef	islower
X#endif
X
X#if	ASCII
X
X#define	DIFCASE		0x20
X#define isletter(c)	(('a' <= c && 'z' >= c) || ('A' <= c && 'Z' >= c))
X#define islower(c)	(('a' <= c && 'z' >= c))
X#endif
X
X#if	EBCDIC
X
X#define	DIFCASE		0x40
X#define isletter(c)	(('a' <= c && 'i' >= c) || ('j' <= c && 'r' >= c) || ('s' <= c && 'z' >= c) || ('A' <= c && 'I' >= c) || ('J' <= c && 'R' >= c) || ('S' <= c && 'Z' >= c))
X#define islower(c)	(('a' <= c && 'i' >= c) || ('j' <= c && 'r' >= c) || ('s' <= c && 'z' >= c))
X#endif
X
X/*	Dynamic RAM tracking and reporting redefinitions	*/
X
X#if	RAMSIZE
X#define	malloc	allocate
X#define	free	release
X#endif
X
X/*	De-allocate memory always on exit (if the operating system or
X	main program can not
X*/
X
X#if	CLEAN
X#define	exit(a)	cexit(a)
X#endif
X
X/*
X * There is a window structure allocated for every active display window. The
X * windows are kept in a big list, in top to bottom screen order, with the
X * listhead at "wheadp". Each window contains its own values of dot and mark.
X * The flag field contains some bits that are set by commands to guide
X * redisplay. Although this is a bit of a compromise in terms of decoupling,
X * the full blown redisplay is just too expensive to run for every input
X * character.
X */
Xtypedef struct  WINDOW {
X        struct  WINDOW *w_wndp;         /* Next window                  */
X        struct  BUFFER *w_bufp;         /* Buffer displayed in window   */
X        struct  LINE *w_linep;          /* Top line in the window       */
X        struct  LINE *w_dotp;           /* Line containing "."          */
X        short   w_doto;                 /* Byte offset for "."          */
X        struct  LINE *w_markp;          /* Line containing "mark"       */
X        short   w_marko;                /* Byte offset for "mark"       */
X        char    w_toprow;               /* Origin 0 top row of window   */
X        char    w_ntrows;               /* # of rows of text in window  */
X        char    w_force;                /* If NZ, forcing row.          */
X        char    w_flag;                 /* Flags.                       */
X#if	COLOR
X	char	w_fcolor;		/* current forground color	*/
X	char	w_bcolor;		/* current background color	*/
X#endif
X}       WINDOW;
X
X#define WFFORCE 0x01                    /* Window needs forced reframe  */
X#define WFMOVE  0x02                    /* Movement from line to line   */
X#define WFEDIT  0x04                    /* Editing within a line        */
X#define WFHARD  0x08                    /* Better to a full display     */
X#define WFMODE  0x10                    /* Update mode line.            */
X#define	WFCOLR	0x20			/* Needs a color change		*/
X
X/*
X * Text is kept in buffers. A buffer header, described below, exists for every
X * buffer in the system. The buffers are kept in a big list, so that commands
X * that search for a buffer by name can find the buffer header. There is a
X * safe store for the dot and mark in the header, but this is only valid if
X * the buffer is not being displayed (that is, if "b_nwnd" is 0). The text for
X * the buffer is kept in a circularly linked list of lines, with a pointer to
X * the header line in "b_linep".
X * 	Buffers may be "Inactive" which means the files associated with them
X * have not been read in yet. These get read in at "use buffer" time.
X */
Xtypedef struct  BUFFER {
X        struct  BUFFER *b_bufp;         /* Link to next BUFFER          */
X        struct  LINE *b_dotp;           /* Link to "." LINE structure   */
X        short   b_doto;                 /* Offset of "." in above LINE  */
X        struct  LINE *b_markp;          /* The same as the above two,   */
X        short   b_marko;                /* but for the "mark"           */
X        struct  LINE *b_linep;          /* Link to the header LINE      */
X	char	b_active;		/* window activated flag	*/
X        char    b_nwnd;                 /* Count of windows on buffer   */
X        char    b_flag;                 /* Flags                        */
X	int	b_mode;			/* editor mode of this buffer	*/
X        char    b_fname[NFILEN];        /* File name                    */
X        char    b_bname[NBUFN];         /* Buffer name                  */
X#if	CRYPT
X	char	b_key[NPAT];		/* current encrypted key	*/
X#endif
X}       BUFFER;
X
X#define BFINVS  0x01                    /* Internal invisable buffer    */
X#define BFCHG   0x02                    /* Changed since last write     */
X#define	BFTRUNC	0x04			/* buffer was truncated when read */
X
X/*	mode flags	*/
X#define	NUMMODES	9		/* # of defined modes		*/
X
X#define	MDWRAP	0x0001			/* word wrap			*/
X#define	MDCMOD	0x0002			/* C indentation and fence match*/
X#define	MDSPELL	0x0004			/* spell error parcing		*/
X#define	MDEXACT	0x0008			/* Exact matching for searches	*/
X#define	MDVIEW	0x0010			/* read-only buffer		*/
X#define MDOVER	0x0020			/* overwrite mode		*/
X#define MDMAGIC	0x0040			/* regular expresions in search */
X#define	MDCRYPT	0x0080			/* encrytion mode active	*/
X#define	MDASAVE	0x0100			/* auto-save mode		*/
X
X/*
X * The starting position of a region, and the size of the region in
X * characters, is kept in a region structure.  Used by the region commands.
X */
Xtypedef struct  {
X        struct  LINE *r_linep;          /* Origin LINE address.         */
X        short   r_offset;               /* Origin LINE offset.          */
X        long	r_size;                 /* Length in characters.        */
X}       REGION;
X
X/*
X * All text is kept in circularly linked lists of "LINE" structures. These
X * begin at the header line (which is the blank line beyond the end of the
X * buffer). This line is pointed to by the "BUFFER". Each line contains a the
X * number of bytes in the line (the "used" size), the size of the text array,
X * and the text. The end of line is not stored as a byte; it's implied. Future
X * additions will include update hints, and a list of marks into the line.
X */
Xtypedef struct  LINE {
X        struct  LINE *l_fp;             /* Link to the next line        */
X        struct  LINE *l_bp;             /* Link to the previous line    */
X        short   l_size;                 /* Allocated size               */
X        short   l_used;                 /* Used size                    */
X        char    l_text[1];              /* A bunch of characters.       */
X}       LINE;
X
X#define lforw(lp)       ((lp)->l_fp)
X#define lback(lp)       ((lp)->l_bp)
X#define lgetc(lp, n)    ((lp)->l_text[(n)]&0xFF)
X#define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
X#define llength(lp)     ((lp)->l_used)
X
X/*
X * The editor communicates with the display using a high level interface. A
X * "TERM" structure holds useful variables, and indirect pointers to routines
X * that do useful operations. The low level get and put routines are here too.
X * This lets a terminal, in addition to having non standard commands, have
X * funny get and put character code too. The calls might get changed to
X * "termp->t_field" style in the future, to make it possible to run more than
X * one terminal type.
X */
Xtypedef struct  {
X	short	t_mrow;			/* max number of rows allowable */
X        short   t_nrow;                 /* current number of rows used  */
X        short   t_mcol;                 /* max Number of columns.       */
X        short   t_ncol;                 /* current Number of columns.   */
X	short	t_margin;		/* min margin for extended lines*/
X	short	t_scrsiz;		/* size of scroll region "	*/
X	int	t_pause;		/* # times thru update to pause */
X        int     (*t_open)();            /* Open terminal at the start.  */
X        int     (*t_close)();           /* Close terminal at end.       */
X	int	(*t_kopen)();		/* Open keyboard		*/
X	int	(*t_kclose)();		/* close keyboard		*/
X        int     (*t_getchar)();         /* Get character from keyboard. */
X        int     (*t_putchar)();         /* Put character to display.    */
X        int     (*t_flush)();           /* Flush output buffers.        */
X        int     (*t_move)();            /* Move the cursor, origin 0.   */
X        int     (*t_eeol)();            /* Erase to end of line.        */
X        int     (*t_eeop)();            /* Erase to end of page.        */
X        int     (*t_beep)();            /* Beep.                        */
X	int	(*t_rev)();		/* set reverse video state	*/
X	int	(*t_rez)();		/* change screen resolution	*/
X#if	COLOR
X	int	(*t_setfor)();		/* set forground color		*/
X	int	(*t_setback)();		/* set background color		*/
X#endif
X}       TERM;
X
X/*	TEMPORARY macros for terminal I/O  (to be placed in a machine
X					    dependant place later)	*/
X
X#define	TTopen		(*term.t_open)
X#define	TTclose		(*term.t_close)
X#define	TTkopen		(*term.t_kopen)
X#define	TTkclose	(*term.t_kclose)
X#define	TTgetc		(*term.t_getchar)
X#define	TTputc		(*term.t_putchar)
X#define	TTflush		(*term.t_flush)
X#define	TTmove		(*term.t_move)
X#define	TTeeol		(*term.t_eeol)
X#define	TTeeop		(*term.t_eeop)
X#define	TTbeep		(*term.t_beep)
X#define	TTrev		(*term.t_rev)
X#define	TTrez		(*term.t_rez)
X#if	COLOR
X#define	TTforg		(*term.t_setfor)
X#define	TTbacg		(*term.t_setback)
X#endif
X
X/*	structure for the table of initial key bindings		*/
X
Xtypedef struct  {
X        short   k_code;                 /* Key code                     */
X        int     (*k_fp)();              /* Routine to handle it         */
X}       KEYTAB;
X
X/*	structure for the name binding table		*/
X
Xtypedef struct {
X	char *n_name;		/* name of function key */
X	int (*n_func)();	/* function name is bound to */
X}	NBIND;
X
X/*	The editor holds deleted text chunks in the KILL buffer. The
X	kill buffer is logically a stream of ascii characters, however
X	due to its unpredicatable size, it gets implemented as a linked
X	list of chunks. (The d_ prefix is for "deleted" text, as k_
X	was taken up by the keycode structure)
X*/
X
Xtypedef	struct KILL {
X	struct KILL *d_next;	/* link to next chunk, NULL if last */
X	char d_chunk[KBLOCK];	/* deleted text */
X} KILL;
X
X/*	When emacs' command interpetor needs to get a variable's name,
X	rather than it's value, it is passed back as a VDESC variable
X	description structure. The v_num field is a index into the
X	appropriate variable table.
X*/
X
Xtypedef struct VDESC {
X	int v_type;	/* type of variable */
X	int v_num;	/* ordinal pointer to variable in list */
X} VDESC;
X
X/*	The !WHILE directive in the execution language needs to
X	stack references to pending whiles. These are stored linked
X	to each currently open procedure via a linked list of
X	the following structure
X*/
X
Xtypedef struct WHBLOCK {
X	LINE *w_begin;		/* ptr to !while statement */
X	LINE *w_end;		/* ptr to the !endwhile statement*/
X	int w_type;		/* block type */
X	struct WHBLOCK *w_next;	/* next while */
X} WHBLOCK;
X
X#define	BTWHILE		1
X#define	BTBREAK		2
X
X/*
X * Incremental search defines.
X */
X#if	ISRCH
X
X#define	CMDBUFLEN	256	/* Length of our command buffer */
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/* IS_QUIT is no longer used, the variable metac is used instead */
X
X#endif
X
X#if	MAGIC
X/*
X * Defines for the metacharacters in the regular expression
X * search routines.
X */
X#define	MCNIL		0	/* Like the '\0' for strings.*/
X#define	LITCHAR		1	/* Literal character, or string.*/
X#define	ANY		2
X#define	CCL		3
X#define	NCCL		4
X#define	BOL		5
X#define	EOL		6
X#define	DITTO		7
X#define	CLOSURE		256	/* An or-able value.*/
X#define	MASKCL		CLOSURE - 1
X
X#define	MC_ANY		'.'	/* 'Any' character (except newline).*/
X#define	MC_CCL		'['	/* Character class.*/
X#define	MC_NCCL		'^'	/* Negate character class.*/
X#define	MC_RCCL		'-'	/* Range in character class.*/
X#define	MC_ECCL		']'	/* End of character class.*/
X#define	MC_BOL		'^'	/* Beginning of line.*/
X#define	MC_EOL		'$'	/* End of line.*/
X#define	MC_CLOSURE	'*'	/* Closure - does not extend past newline.*/
X#define	MC_DITTO	'&'	/* Use matched string in replacement.*/
X#define	MC_ESC		'\\'	/* Escape - suppress meta-meaning.*/
X
X#define	BIT(n)		(1 << (n))	/* An integer with one bit set.*/
X#define	CHCASE(c)	((c) ^ DIFCASE)	/* Toggle the case of a letter.*/
X
X/* HICHAR - 1 is the largest character we will deal with.
X * HIBYTE represents the number of bytes in the bitmap.
X */
X#define	HICHAR		256
X#define	HIBYTE		HICHAR >> 3
X
X/* Typedefs that define the bitmap type for searching (BITMAP),
X * the meta-character structure for MAGIC mode searching (MC),
X * and the meta-character structure for MAGIC mode replacment (RMC).
X */
Xtypedef char	*BITMAP;
X
Xtypedef	struct {
X	short int	mc_type;
X	union {
X		int	lchar;
X		BITMAP	cclmap;
X	} u;
X} MC;
X
Xtypedef	struct {
X	short int	mc_type;
X	char	*rstr;
X} RMC;
X#endif
X
FRIDAY_NIGHT
echo extracting - evar.h
sed 's/^X//' > evar.h << 'FRIDAY_NIGHT'
X/*	EVAR.H:	Environment and user variable definitions
X		for MicroEMACS
X
X		written 1986 by Daniel Lawrence
X*/
X
X/*	structure to hold user variables and their definitions	*/
X
Xtypedef struct UVAR {
X	char u_name[NVSIZE + 1];		/* name of user variable */
X	char *u_value;				/* value (string) */
X} UVAR;
X
X/*	current user variables (This structure will probably change)	*/
X
X#define	MAXVARS		255
X
XUVAR uv[MAXVARS + 1];	/* user variables */
X
X/*	list of recognized environment variables	*/
X
Xchar *envars[] = {
X	"fillcol",		/* current fill column */
X	"pagelen",		/* number of lines used by editor */
X	"curcol",		/* current column pos of cursor */
X	"curline",		/* current line in file */
X	"ram",			/* ram in use by malloc */
X	"flicker",		/* flicker supression */
X	"curwidth",		/* current screen width */
X	"cbufname",		/* current buffer name */
X	"cfname",		/* current file name */
X	"sres",			/* current screen resolution */
X	"debug",		/* macro debugging */
X	"status",		/* returns the status of the last command */
X	"palette",		/* current palette string */
X	"asave",		/* # of chars between auto-saves */
X	"acount",		/* # of chars until next auto-save */
X	"lastkey",		/* last keyboard char struck */
X	"curchar",		/* current character under the cursor */
X	"discmd",		/* display commands on command line */
X	"version",		/* current version number */
X	"progname",		/* returns current prog name - "MicroEMACS" */
X	"seed",			/* current random number seed */
X	"disinp",		/* display command line input characters */
X	"wline",		/* # of lines in current window */
X	"cwline",		/* current screen line in window */
X	"target",		/* target for line moves */
X	"search",		/* search pattern */
X	"replace",		/* replacement pattern */
X	"match",		/* last matched magic pattern */
X	"kill",			/* kill buffer (read only) */
X	"cmode",		/* mode of current buffer */
X	"gmode",		/* global modes */
X	"tpause",		/* length to pause for paren matching */
X	"pending",		/* type ahead pending flag */
X	"lwidth",		/* width of current line */
X	"line",			/* text of current line */
X	"gflags",		/* global internal emacs flags */
X	"rval",			/* child process return value */
X};
X
X#define	NEVARS	sizeof(envars) / sizeof(char *)
X
X/* 	and its preprocesor definitions		*/
X
X#define	EVFILLCOL	0
X#define	EVPAGELEN	1
X#define	EVCURCOL	2
X#define	EVCURLINE	3
X#define	EVRAM		4
X#define	EVFLICKER	5
X#define	EVCURWIDTH	6
X#define	EVCBUFNAME	7
X#define	EVCFNAME	8
X#define	EVSRES		9
X#define	EVDEBUG		10
X#define	EVSTATUS	11
X#define	EVPALETTE	12
X#define	EVASAVE		13
X#define	EVACOUNT	14
X#define	EVLASTKEY	15
X#define	EVCURCHAR	16
X#define	EVDISCMD	17
X#define	EVVERSION	18
X#define	EVPROGNAME	19
X#define	EVSEED		20
X#define	EVDISINP	21
X#define	EVWLINE		22
X#define EVCWLINE	23
X#define	EVTARGET	24
X#define	EVSEARCH	25
X#define	EVREPLACE	26
X#define	EVMATCH		27
X#define	EVKILL		28
X#define	EVCMODE		29
X#define	EVGMODE		30
X#define	EVTPAUSE	31
X#define	EVPENDING	32
X#define	EVLWIDTH	33
X#define	EVLINE		34
X#define	EVGFLAGS	35
X#define	EVRVAL		36
X
X/*	list of recognized user functions	*/
X
Xtypedef struct UFUNC {
X	char *f_name;	/* name of function */
X	int f_type;	/* 1 = monamic, 2 = dynamic */
X} UFUNC;
X
X#define	NILNAMIC	0
X#define	MONAMIC		1
X#define	DYNAMIC		2
X#define	TRINAMIC	3
X
XUFUNC funcs[] = {
X	"add", DYNAMIC,		/* add two numbers together */
X	"sub", DYNAMIC,		/* subtraction */
X	"tim", DYNAMIC,		/* multiplication */
X	"div", DYNAMIC,		/* division */
X	"mod", DYNAMIC,		/* mod */
X	"neg", MONAMIC,		/* negate */
X	"cat", DYNAMIC,		/* concatinate string */
X	"lef", DYNAMIC,		/* left string(string, len) */
X	"rig", DYNAMIC,		/* right string(string, pos) */
X	"mid", TRINAMIC,	/* mid string(string, pos, len) */
X	"not", MONAMIC,		/* logical not */
X	"equ", DYNAMIC,		/* logical equality check */
X	"les", DYNAMIC,		/* logical less than */
X	"gre", DYNAMIC,		/* logical greater than */
X	"seq", DYNAMIC,		/* string logical equality check */
X	"sle", DYNAMIC,		/* string logical less than */
X	"sgr", DYNAMIC,		/* string logical greater than */
X	"ind", MONAMIC,		/* evaluate indirect value */
X	"and", DYNAMIC,		/* logical and */
X	"or",  DYNAMIC,		/* logical or */
X	"len", MONAMIC,		/* string length */
X	"upp", MONAMIC,		/* uppercase string */
X	"low", MONAMIC,		/* lower case string */
X	"tru", MONAMIC,		/* Truth of the universe logical test */
X	"asc", MONAMIC,		/* char to integer conversion */
X	"chr", MONAMIC,		/* integer to char conversion */
X	"gtk", NILNAMIC,	/* get 1 charater */
X	"rnd", MONAMIC,		/* get a random number */
X	"abs", MONAMIC,		/* absolute value of a number */
X	"sin", DYNAMIC,		/* find the index of one string in another */
X	"env", MONAMIC,		/* retrieve a system environment var */
X	"bin", MONAMIC,		/* loopup what function name is bound to a key */
X	"exi", MONAMIC,		/* check if a file exists */
X	"fin", MONAMIC,		/* look for a file on the path... */
X 	"ban", DYNAMIC,		/* bitwise and   9-10-87  jwm */
X 	"bor", DYNAMIC,		/* bitwise or    9-10-87  jwm */
X 	"bxo", DYNAMIC,		/* bitwise xor	 9-10-87  jwm */
X	"bno", MONAMIC,		/* bitwise not */
X	"xla", TRINAMIC,	/* XLATE character string translation */
X};
X
X#define	NFUNCS	sizeof(funcs) / sizeof(UFUNC)
X
X/* 	and its preprocesor definitions		*/
X
X#define	UFADD		0
X#define	UFSUB		1
X#define	UFTIMES		2
X#define	UFDIV		3
X#define	UFMOD		4
X#define	UFNEG		5
X#define	UFCAT		6
X#define	UFLEFT		7
X#define	UFRIGHT		8
X#define	UFMID		9
X#define	UFNOT		10
X#define	UFEQUAL		11
X#define	UFLESS		12
X#define	UFGREATER	13
X#define	UFSEQUAL	14
X#define	UFSLESS		15
X#define	UFSGREAT	16
X#define	UFIND		17
X#define	UFAND		18
X#define	UFOR		19
X#define	UFLENGTH	20
X#define	UFUPPER		21
X#define	UFLOWER		22
X#define	UFTRUTH		23
X#define	UFASCII		24
X#define	UFCHR		25
X#define	UFGTKEY		26
X#define	UFRND		27
X#define	UFABS		28
X#define	UFSINDEX	29
X#define	UFENV		30
X#define	UFBIND		31
X#define	UFEXIST		32
X#define	UFFIND		33
X#define UFBAND		34
X#define UFBOR		35
X#define UFBXOR		36
X#define	UFBNOT		37
X#define	UFXLATE		38
FRIDAY_NIGHT
echo mes.16 completed!
# That's all folks!