
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by tralfaz!ove on Mon Nov 14 21:37:47 EST 1988
# Contents:  Makefile Makefile.simple Makeshar ansi.c basic.c bind.c buffer.c
#	crypt.c
 
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
#
# Makfile for MicroEmacs.  Kind of cheap, the defs for what system this
# is realy running on is in estruct.h.  The primary purpose of this makefile
# is to provide a convenient installation routine for the file into
# system directories.
#
# 	Author:				Date:
# 		Adam Fritz			July 30,1987

DESTDIR = /usr/local
LIBS = /home/NeWS/lib/libcps.a
CFLAGS = -g -I/home/NeWS/include
TARGET = me
ALIAS = uemacs

HEADERS = ebind.h evar.h estruct.h esearch.h epath.h efunc.h edef.h 

SRC = news.c termio.c display.c word.c window.c spawn.c \
      region.c search.c main.c random.c isearch.c lock.c line.c \
      input.c fileio.c exec.c file.c eval.c \
      dolock.c buffer.c crypt.c bind.c basic.c

OBJ = news.o termio.o display.o word.o window.o spawn.o \
      region.o search.o main.o random.o isearch.o lock.o line.o \
      input.o fileio.o exec.o file.o eval.o \
      dolock.o buffer.o crypt.o bind.o basic.o


$(TARGET) : $(OBJ)
	cc $(CFLAGS) -o $(TARGET) $(OBJ) $(LIBS)

install : $(TARGET)
	install -s -m 0755 $(TARGET) $(DESTDIR)
	install -c -m 0644 emacs.hlp $(DESTDIR)

alias : $(DESTDIR)/$(TARGET)
	ln $(DESTDIR)/$(TARGET) $(DESTDIR)/$(ALIAS)

clean :
	rm -f *.o

news.h: news.cps
	cps news.cps

depend:	 ${SRC} ${HDRS}
	mv -f Makefile Makefile.orig
	(sed -e '/^#DEPENDS/,$$d' Makefile.orig ; \
		echo "#DEPENDS" ; \
		cc -M $(CFLAGS) $? ) > Makefile
#DEPENDS
news.o: news.c
news.o: /usr/include/stdio.h
news.o: ./estruct.h
news.o: ./edef.h
news.o: ./news.h
word.o: word.c
word.o: /usr/include/stdio.h
word.o: ./estruct.h
word.o: ./edef.h
vmsvt.o: vmsvt.c
vmsvt.o: /usr/include/stdio.h
vmsvt.o: ./estruct.h
vmsvt.o: ./edef.h
window.o: window.c
window.o: /usr/include/stdio.h
window.o: ./estruct.h
window.o: ./edef.h
vt52.o: vt52.c
vt52.o: /usr/include/stdio.h
vt52.o: ./estruct.h
vt52.o: ./edef.h
tipc.o: tipc.c
tipc.o: /usr/include/stdio.h
tipc.o: ./estruct.h
tipc.o: ./edef.h
tcap.o: tcap.c
tcap.o: /usr/include/stdio.h
tcap.o: ./estruct.h
tcap.o: ./edef.h
termio.o: termio.c
termio.o: /usr/include/stdio.h
termio.o: ./estruct.h
termio.o: ./edef.h
termio.o: /usr/include/sgtty.h
termio.o: /usr/include/sys/ioctl.h
termio.o: /usr/include/sys/ttychars.h
termio.o: /usr/include/sys/ttydev.h
termio.o: /usr/include/signal.h
termio.o: /usr/include/sys/ioctl.h
spawn.o: spawn.c
spawn.o: /usr/include/stdio.h
spawn.o: ./estruct.h
spawn.o: ./edef.h
spawn.o: /usr/include/signal.h
st520.o: st520.c
st520.o: /usr/include/stdio.h
st520.o: ./estruct.h
st520.o: ./edef.h
region.o: region.c
region.o: /usr/include/stdio.h
region.o: ./estruct.h
region.o: ./edef.h
search.o: search.c
search.o: /usr/include/stdio.h
search.o: ./estruct.h
search.o: ./edef.h
main.o: main.c
main.o: /usr/include/stdio.h
main.o: ./estruct.h
main.o: ./efunc.h
main.o: ./edef.h
main.o: ./ebind.h
random.o: random.c
random.o: /usr/include/stdio.h
random.o: ./estruct.h
random.o: ./edef.h
isearch.o: isearch.c
isearch.o: /usr/include/stdio.h
isearch.o: ./estruct.h
isearch.o: ./edef.h
lock.o: lock.c
lock.o: /usr/include/stdio.h
lock.o: ./estruct.h
lock.o: ./edef.h
lock.o: /usr/include/sys/errno.h
line.o: line.c
line.o: /usr/include/stdio.h
line.o: ./estruct.h
line.o: ./edef.h
ibmpc.o: ibmpc.c
ibmpc.o: /usr/include/stdio.h
ibmpc.o: ./estruct.h
ibmpc.o: ./edef.h
input.o: input.c
input.o: /usr/include/stdio.h
input.o: ./estruct.h
input.o: ./edef.h
hp110.o: hp110.c
hp110.o: /usr/include/stdio.h
hp110.o: ./estruct.h
hp110.o: ./edef.h
hp150.o: hp150.c
hp150.o: /usr/include/stdio.h
hp150.o: ./estruct.h
hp150.o: ./edef.h
fileio.o: fileio.c
fileio.o: /usr/include/stdio.h
fileio.o: ./estruct.h
fileio.o: ./edef.h
exec.o: exec.c
exec.o: /usr/include/stdio.h
exec.o: ./estruct.h
exec.o: ./edef.h
file.o: file.c
file.o: /usr/include/stdio.h
file.o: ./estruct.h
file.o: ./edef.h
eval.o: eval.c
eval.o: /usr/include/stdio.h
eval.o: ./estruct.h
eval.o: ./edef.h
eval.o: ./evar.h
display.o: display.c
display.o: /usr/include/stdio.h
display.o: ./estruct.h
display.o: ./edef.h
dolock.o: dolock.c
buffer.o: buffer.c
buffer.o: /usr/include/stdio.h
buffer.o: ./estruct.h
buffer.o: ./edef.h
crypt.o: crypt.c
crypt.o: /usr/include/stdio.h
crypt.o: ./estruct.h
crypt.o: ./edef.h
dg10.o: dg10.c
dg10.o: /usr/include/stdio.h
dg10.o: ./estruct.h
dg10.o: ./edef.h
bind.o: bind.c
bind.o: /usr/include/stdio.h
bind.o: ./estruct.h
bind.o: ./edef.h
bind.o: ./epath.h
basic.o: basic.c
basic.o: /usr/include/stdio.h
basic.o: ./estruct.h
basic.o: ./edef.h
ansi.o: ansi.c
ansi.o: /usr/include/stdio.h
ansi.o: ./estruct.h
ansi.o: ./edef.h
@//E*O*F Makefile//
chmod u=rw,g=r,o=r Makefile
 
echo x - Makefile.simple
sed 's/^@//' > "Makefile.simple" <<'@//E*O*F Makefile.simple//'
CFLAGS=		-O
LIBS=		../lib/libcps.a -lnet

OFILES=		news.o basic.o bind.o buffer.o display.o file.o \
		fileio.o input.o line.o lock.c main.o \
		random.o region.o \
		search.o spawn.o termio.o window.o word.o \
		exec.o eval.o isearch.o crypt.o

HFILES=		estruct.h edef.h efunc.h epath.h ebind.h evar.h

emacs:		$(OFILES)
		$(CC) $(CFLAGS) $(OFILES) $(LIBS) -lc -o emacs

$(OFILES):	$(HFILES)

news.o:		news.h

news.h:		news.cps
		cps news.cps
@//E*O*F Makefile.simple//
chmod u=rw,g=r,o=r Makefile.simple
 
echo x - Makeshar
sed 's/^@//' > "Makeshar" <<'@//E*O*F Makeshar//'
# make the shar files

ONE =	Makefile Makefile.simple Makeshar ansi.c basic.c bind.c	\
	buffer.c crypt.c

TWO =	dg10.c display.c dolock.c eval.c

THREE =	exec.c file.c fileio.c hp110.c hp150.c

FOUR =	ibmpc.c input.c isearch.c line.c lock.c

FIVE =	main.c news.c 

SIX =	random.c search.c

SEVEN =	region.c spawn.c spawn.c,v st520.c

EIGHT =	tcap.c termio.c tipc.c vmsvt.c vt52.c window.c README.NeWS

NINE =	word.c z309.c ebind.h edef.h efunc.h epath.h

TEN =	estruct.h evar.h emacs.hlp news.cps make.ini z100bios.asm

all :	dist/ne1.sh dist/ne2.sh dist/ne3.sh dist/ne4.sh dist/ne5.sh \
	dist/ne6.sh dist/ne7.sh dist/ne8.sh dist/ne9.sh dist/ne10.sh

dist/ne1.sh : $(ONE)
	shar -b -v $(ONE) >dist/ne1.sh

dist/ne2.sh : $(TWO)
	shar -b -v $(TWO) >dist/ne2.sh

dist/ne3.sh : $(THREE)
	shar -b -v $(THREE) >dist/ne3.sh

dist/ne4.sh : $(FOUR)
	shar -b -v $(FOUR) >dist/ne4.sh

dist/ne5.sh : $(FIVE)
	shar -b -v $(FIVE) >dist/ne5.sh

dist/ne6.sh : $(SIX)
	shar -b -v $(SIX) >dist/ne6.sh

dist/ne7.sh : $(SEVEN)
	shar -b -v $(SEVEN) >dist/ne7.sh

dist/ne8.sh : $(EIGHT)
	shar -b -v $(EIGHT) >dist/ne8.sh

dist/ne9.sh : $(NINE)
	shar -b 	-v $(NINE) >dist/ne9.sh

dist/ne10.sh : $(TEN)
	shar -b 	-v $(TEN) >dist/ne10.sh



@//E*O*F Makeshar//
chmod u=rw,g=r,o=r Makeshar
 
echo x - ansi.c
sed 's/^@//' > "ansi.c" <<'@//E*O*F ansi.c//'
/*
 * The routines in this file provide support for ANSI style terminals
 * over a serial line. The serial I/O services are provided by routines in
 * "termio.c". It compiles into nothing if not an ANSI device.
 */

#define	termdef	1			/* don't define "term" external */

#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"

#if     ANSI

#if	AMIGA
#define NROW    23                      /* Screen size.                 */
#define NCOL    77                      /* Edit if you want to.         */
#else
#define NROW    25                      /* Screen size.                 */
#define NCOL    80                      /* Edit if you want to.         */
#endif
#define	NPAUSE	100			/* # times thru update to pause */
#define	MARGIN	8			/* size of minimim margin and	*/
#define	SCRSIZ	64			/* scroll size for extended lines */
#define BEL     0x07                    /* BEL character.               */
#define ESC     0x1B                    /* ESC character.               */

extern  int     ttopen();               /* Forward references.          */
extern  int     ttgetc();
extern  int     ttputc();
extern  int     ttflush();
extern  int     ttclose();
extern  int     ansimove();
extern  int     ansieeol();
extern  int     ansieeop();
extern  int     ansibeep();
extern  int     ansiopen();
extern	int	ansirev();
extern	int	ansiclose();
extern	int	ansikopen();
extern	int	ansikclose();
extern	int	ansicres();

#if	COLOR
extern	int	ansifcol();
extern	int	ansibcol();

int	cfcolor = -1;		/* current forground color */
int	cbcolor = -1;		/* current background color */

#if	AMIGA
/* apperently the AMIGA does not follow the ANSI standards as
   regards to colors....maybe because of the default pallette
   settings?
*/

int coltran[8] = {2, 3, 5, 7, 0, 4, 6, 1};	/* color translation table */
#endif
#endif

/*
 * Standard terminal interface dispatch table. Most of the fields point into
 * "termio" code.
 */
TERM    term    = {
	NROW-1,
        NROW-1,
        NCOL,
        NCOL,
	MARGIN,
	SCRSIZ,
	NPAUSE,
        ansiopen,
        ansiclose,
	ansikopen,
	ansikclose,
        ttgetc,
        ttputc,
        ttflush,
        ansimove,
        ansieeol,
        ansieeop,
        ansibeep,
	ansirev,
	ansicres
#if	COLOR
	, ansifcol,
	ansibcol
#endif
};

#if	COLOR
ansifcol(color)		/* set the current output color */

int color;	/* color to set */

{
	if (color == cfcolor)
		return;
	ttputc(ESC);
	ttputc('[');
#if	AMIGA
	ansiparm(coltran[color]+30);
#else
	ansiparm(color+30);
#endif
	ttputc('m');
	cfcolor = color;
}

ansibcol(color)		/* set the current background color */

int color;	/* color to set */

{
	if (color == cbcolor)
		return;
	ttputc(ESC);
	ttputc('[');
#if	AMIGA
	ansiparm(coltran[color]+40);
#else
	ansiparm(color+40);
#endif
	ttputc('m');
        cbcolor = color;
}
#endif

ansimove(row, col)
{
        ttputc(ESC);
        ttputc('[');
        ansiparm(row+1);
        ttputc(';');
        ansiparm(col+1);
        ttputc('H');
}

ansieeol()
{
        ttputc(ESC);
        ttputc('[');
        ttputc('K');
}

ansieeop()
{
#if	COLOR
	ansifcol(gfcolor);
	ansibcol(gbcolor);
#endif
        ttputc(ESC);
        ttputc('[');
        ttputc('J');
}

ansirev(state)		/* change reverse video state */

int state;	/* TRUE = reverse, FALSE = normal */

{
#if	COLOR
	int ftmp, btmp;		/* temporaries for colors */
#endif

	ttputc(ESC);
	ttputc('[');
	ttputc(state ? '7': '0');
	ttputc('m');
#if	COLOR
	if (state == FALSE) {
		ftmp = cfcolor;
		btmp = cbcolor;
		cfcolor = -1;
		cbcolor = -1;
		ansifcol(ftmp);
		ansibcol(btmp);
	}
#endif
}

ansicres()	/* change screen resolution */

{
	return(TRUE);
}

spal(dummy)		/* change pallette settings */

{
	/* none for now */
}

ansibeep()
{
        ttputc(BEL);
        ttflush();
}

ansiparm(n)
register int    n;
{
        register int q,r;

        q = n/10;
        if (q != 0) {
		r = q/10;
		if (r != 0) {
			ttputc((r%10)+'0');
		}
		ttputc((q%10) + '0');
        }
        ttputc((n%10) + '0');
}

ansiopen()
{
#if     V7 | USG | BSD
        register char *cp;
        char *getenv();

        if ((cp = getenv("TERM")) == NULL) {
                puts("Shell variable TERM not defined!");
                exit(1);
        }
        if (strcmp(cp, "vt100") != 0) {
                puts("Terminal type not 'vt100'!");
                exit(1);
        }
#endif
	strcpy(sres, "NORMAL");
	revexist = TRUE;
        ttopen();
}

ansiclose()

{
#if	COLOR
	ansifcol(7);
	ansibcol(0);
#endif
	ttclose();
}

ansikopen()	/* open the keyboard (a noop here) */

{
}

ansikclose()	/* close the keyboard (a noop here) */

{
}

#if	FLABEL
fnclabel(f, n)		/* label a function key */

int f,n;	/* default flag, numeric argument [unused] */

{
	/* on machines with no function keys...don't bother */
	return(TRUE);
}
#endif
#else
ansihello()
{
}
#endif
@//E*O*F ansi.c//
chmod u=rw,g=r,o=r ansi.c
 
echo x - basic.c
sed 's/^@//' > "basic.c" <<'@//E*O*F basic.c//'
/*
 * The routines in this file move the cursor around on the screen. They
 * compute a new value for the cursor, then adjust ".". The display code
 * always updates the cursor location, so only moves between lines, or
 * functions that adjust the top line in the window and invalidate the
 * framing, are hard.
 */
#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"

/*
 * Move the cursor to the
 * beginning of the current line.
 * Trivial.
 */
gotobol(f, n)
{
        curwp->w_doto  = 0;
        return (TRUE);
}

/*
 * Move the cursor backwards by "n" characters. If "n" is less than zero call
 * "forwchar" to actually do the move. Otherwise compute the new cursor
 * location. Error if you try and move out of the buffer. Set the flag if the
 * line pointer for dot changes.
 */
backchar(f, n)
register int    n;
{
        register LINE   *lp;

        if (n < 0)
                return (forwchar(f, -n));
        while (n--) {
                if (curwp->w_doto == 0) {
                        if ((lp=lback(curwp->w_dotp)) == curbp->b_linep)
                                return (FALSE);
                        curwp->w_dotp  = lp;
                        curwp->w_doto  = llength(lp);
                        curwp->w_flag |= WFMOVE;
                } else
                        curwp->w_doto--;
        }
        return (TRUE);
}

/*
 * Move the cursor to the end of the current line. Trivial. No errors.
 */
gotoeol(f, n)
{
        curwp->w_doto  = llength(curwp->w_dotp);
        return (TRUE);
}

/*
 * Move the cursor forwards by "n" characters. If "n" is less than zero call
 * "backchar" to actually do the move. Otherwise compute the new cursor
 * location, and move ".". Error if you try and move off the end of the
 * buffer. Set the flag if the line pointer for dot changes.
 */
forwchar(f, n)
register int    n;
{
        if (n < 0)
                return (backchar(f, -n));
        while (n--) {
                if (curwp->w_doto == llength(curwp->w_dotp)) {
                        if (curwp->w_dotp == curbp->b_linep)
                                return (FALSE);
                        curwp->w_dotp  = lforw(curwp->w_dotp);
                        curwp->w_doto  = 0;
                        curwp->w_flag |= WFMOVE;
                } else
                        curwp->w_doto++;
        }
        return (TRUE);
}

gotoline(f, n)		/* move to a particular line.
			   argument (n) must be a positive integer for
			   this to actually do anything		*/

{
	register int status;	/* status return */
	char arg[NSTRING];	/* buffer to hold argument */

	/* get an argument if one doesnt exist */
	if (f == FALSE) {
		if ((status = mlreply("Line to GOTO: ", arg, "")) != TRUE) {
			mlwrite("[Aborted]");
			return(status);
		}
		n = atoi(arg);
	}

	if (n < 1)		/* if a bogus argument...then leave */
		return(FALSE);

	/* first, we go to the start of the buffer */
        curwp->w_dotp  = lforw(curbp->b_linep);
        curwp->w_doto  = 0;
	return(forwline(f, n-1));
}

/*
 * Goto the beginning of the buffer. Massive adjustment of dot. This is
 * considered to be hard motion; it really isn't if the original value of dot
 * is the same as the new value of dot. Normally bound to "M-<".
 */
gotobob(f, n)
{
        curwp->w_dotp  = lforw(curbp->b_linep);
        curwp->w_doto  = 0;
        curwp->w_flag |= WFHARD;
        return (TRUE);
}

/*
 * Move to the end of the buffer. Dot is always put at the end of the file
 * (ZJ). The standard screen code does most of the hard parts of update.
 * Bound to "M->".
 */
gotoeob(f, n)
{
        curwp->w_dotp  = curbp->b_linep;
        curwp->w_doto  = 0;
        curwp->w_flag |= WFHARD;
        return (TRUE);
}

/*
 * Move forward by full lines. If the number of lines to move is less than
 * zero, call the backward line function to actually do it. The last command
 * controls how the goal column is set. Bound to "C-N". No errors are
 * possible.
 */
forwline(f, n)
{
        register LINE   *dlp;

        if (n < 0)
                return (backline(f, -n));

	/* if we are on the last line as we start....fail the command */
	if (curwp->w_dotp == curbp->b_linep)
		return(FALSE);

	/* if the last command was not note a line move,
	   reset the goal column */
        if ((lastflag&CFCPCN) == 0)
                curgoal = getccol(FALSE);

	/* flag this command as a line move */
        thisflag |= CFCPCN;

	/* and move the point down */
        dlp = curwp->w_dotp;
        while (n-- && dlp!=curbp->b_linep)
                dlp = lforw(dlp);

	/* reseting the current position */
        curwp->w_dotp  = dlp;
        curwp->w_doto  = getgoal(dlp);
        curwp->w_flag |= WFMOVE;
        return (TRUE);
}

/*
 * This function is like "forwline", but goes backwards. The scheme is exactly
 * the same. Check for arguments that are less than zero and call your
 * alternate. Figure out the new line and call "movedot" to perform the
 * motion. No errors are possible. Bound to "C-P".
 */
backline(f, n)
{
        register LINE   *dlp;

        if (n < 0)
                return (forwline(f, -n));


	/* if we are on the last line as we start....fail the command */
	if (lback(curwp->w_dotp) == curbp->b_linep)
		return(FALSE);

	/* if the last command was not note a line move,
	   reset the goal column */
        if ((lastflag&CFCPCN) == 0)
                curgoal = getccol(FALSE);

	/* flag this command as a line move */
        thisflag |= CFCPCN;

	/* and move the point up */
        dlp = curwp->w_dotp;
        while (n-- && lback(dlp)!=curbp->b_linep)
                dlp = lback(dlp);

	/* reseting the current position */
        curwp->w_dotp  = dlp;
        curwp->w_doto  = getgoal(dlp);
        curwp->w_flag |= WFMOVE;
        return (TRUE);
}

#if	WORDPRO
gotobop(f, n)	/* go back to the beginning of the current paragraph
		   here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
		   combination to delimit the beginning of a paragraph	*/

int f, n;	/* default Flag & Numeric argument */

{
	register int suc;	/* success of last backchar */

	if (n < 0)	/* the other way...*/
		return(gotoeop(f, -n));

	while (n-- > 0) {	/* for each one asked for */

		/* first scan back until we are in a word */
		suc = backchar(FALSE, 1);
		while (!inword() && suc)
			suc = backchar(FALSE, 1);
		curwp->w_doto = 0;	/* and go to the B-O-Line */

		/* and scan back until we hit a <NL><NL> or <NL><TAB>
		   or a <NL><SPACE>					*/
		while (lback(curwp->w_dotp) != curbp->b_linep)
			if (llength(curwp->w_dotp) != 0 &&
			    lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
			    lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
				curwp->w_dotp = lback(curwp->w_dotp);
			else
				break;

		/* and then forward until we are in a word */
		suc = forwchar(FALSE, 1);
		while (suc && !inword())
			suc = forwchar(FALSE, 1);
	}
	curwp->w_flag |= WFMOVE;	/* force screen update */
	return(TRUE);
}

gotoeop(f, n)	/* go forword to the end of the current paragraph
		   here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
		   combination to delimit the beginning of a paragraph	*/

int f, n;	/* default Flag & Numeric argument */

{
	register int suc;	/* success of last backchar */

	if (n < 0)	/* the other way...*/
		return(gotobop(f, -n));

	while (n-- > 0) {	/* for each one asked for */

		/* first scan forward until we are in a word */
		suc = forwchar(FALSE, 1);
		while (!inword() && suc)
			suc = forwchar(FALSE, 1);
		curwp->w_doto = 0;	/* and go to the B-O-Line */
		if (suc)	/* of next line if not at EOF */
			curwp->w_dotp = lforw(curwp->w_dotp);

		/* and scan forword until we hit a <NL><NL> or <NL><TAB>
		   or a <NL><SPACE>					*/
		while (curwp->w_dotp != curbp->b_linep) {
			if (llength(curwp->w_dotp) != 0 &&
			    lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
			    lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
				curwp->w_dotp = lforw(curwp->w_dotp);
			else
				break;
		}

		/* and then backward until we are in a word */
		suc = backchar(FALSE, 1);
		while (suc && !inword()) {
			suc = backchar(FALSE, 1);
		}
		curwp->w_doto = llength(curwp->w_dotp);	/* and to the EOL */
	}
	curwp->w_flag |= WFMOVE;	/* force screen update */
	return(TRUE);
}
#endif

/*
 * This routine, given a pointer to a LINE, and the current cursor goal
 * column, return the best choice for the offset. The offset is returned.
 * Used by "C-N" and "C-P".
 */
getgoal(dlp)
register LINE   *dlp;
{
        register int    c;
        register int    col;
        register int    newcol;
        register int    dbo;

        col = 0;
        dbo = 0;
        while (dbo != llength(dlp)) {
                c = lgetc(dlp, dbo);
                newcol = col;
                if (c == '\t')
                        newcol |= 0x07;
                else if (c<0x20 || c==0x7F)
                        ++newcol;
                ++newcol;
                if (newcol > curgoal)
                        break;
                col = newcol;
                ++dbo;
        }
        return (dbo);
}

/*
 * Scroll forward by a specified number of lines, or by a full page if no
 * argument. Bound to "C-V". The "2" in the arithmetic on the window size is
 * the overlap; this value is the default overlap value in ITS EMACS. Because
 * this zaps the top line in the display window, we have to do a hard update.
 */
forwpage(f, n)
register int    n;
{
        register LINE   *lp;

        if (f == FALSE) {
                n = curwp->w_ntrows - 2;        /* Default scroll.      */
                if (n <= 0)                     /* Forget the overlap   */
                        n = 1;                  /* if tiny window.      */
        } else if (n < 0)
                return (backpage(f, -n));
#if     CVMVAS
        else                                    /* Convert from pages   */
                n *= curwp->w_ntrows;           /* to lines.            */
#endif
        lp = curwp->w_linep;
        while (n-- && lp!=curbp->b_linep)
                lp = lforw(lp);
        curwp->w_linep = lp;
        curwp->w_dotp  = lp;
        curwp->w_doto  = 0;
        curwp->w_flag |= WFHARD;
        return (TRUE);
}

/*
 * This command is like "forwpage", but it goes backwards. The "2", like
 * above, is the overlap between the two windows. The value is from the ITS
 * EMACS manual. Bound to "M-V". We do a hard update for exactly the same
 * reason.
 */
backpage(f, n)
register int    n;
{
        register LINE   *lp;

        if (f == FALSE) {
                n = curwp->w_ntrows - 2;        /* Default scroll.      */
                if (n <= 0)                     /* Don't blow up if the */
                        n = 1;                  /* window is tiny.      */
        } else if (n < 0)
                return (forwpage(f, -n));
#if     CVMVAS
        else                                    /* Convert from pages   */
                n *= curwp->w_ntrows;           /* to lines.            */
#endif
        lp = curwp->w_linep;
        while (n-- && lback(lp)!=curbp->b_linep)
                lp = lback(lp);
        curwp->w_linep = lp;
        curwp->w_dotp  = lp;
        curwp->w_doto  = 0;
        curwp->w_flag |= WFHARD;
        return (TRUE);
}

/*
 * Set the mark in the current window to the value of "." in the window. No
 * errors are possible. Bound to "M-.".
 */
setmark(f, n)
{
        curwp->w_markp = curwp->w_dotp;
        curwp->w_marko = curwp->w_doto;
        mlwrite("[Mark set]");
        return (TRUE);
}

/*
 * Swap the values of "." and "mark" in the current window. This is pretty
 * easy, bacause all of the hard work gets done by the standard routine
 * that moves the mark about. The only possible error is "no mark". Bound to
 * "C-X C-X".
 */
swapmark(f, n)
{
        register LINE   *odotp;
        register int    odoto;

        if (curwp->w_markp == NULL) {
                mlwrite("No mark in this window");
                return (FALSE);
        }
        odotp = curwp->w_dotp;
        odoto = curwp->w_doto;
        curwp->w_dotp  = curwp->w_markp;
        curwp->w_doto  = curwp->w_marko;
        curwp->w_markp = odotp;
        curwp->w_marko = odoto;
        curwp->w_flag |= WFMOVE;
        return (TRUE);
}



#if	NeWS
/* SETCURSOR
 *
 * Mouse support function.  Put the cursor to the requested location.
 * The cursor will be put just after the last character of the line if 
 * requested past the line.  The coordinates are expected in the command
 * stream.
 *   In the case of multiple windows, the window indicated by the mouse
 * is located and made the current window.
 */
setcursor()
{
int	row, col, pasteol ;
register LINE	*dlp;
WINDOW *wp0 ;		/* current window on entry */

	row = tgetc() ;		/* tgetc does no CTRL translation */
	col = tgetc() ;

/* find the window we are pointing to */
	wp0 = curwp ;
	while ( row < curwp->w_toprow ||
		row > curwp->w_ntrows + curwp->w_toprow ) {
		nextwind(FALSE,0) ;
		if ( curwp == wp0 ) break ;	/* full circle */
	}

/* move to the right row */
	row -= curwp->w_toprow ;
	dlp = curwp->w_linep ;			/* get pointer to 1st line */
	while ( row-- && (dlp != curbp->b_linep) ) dlp = lforw(dlp) ;
	curwp->w_dotp = dlp ;			/* set dot line pointer */

	/* now move the dot over until near the requested column */
	curgoal = col ;		/* a global for this ?? */
	curwp->w_doto = getgoal(dlp) ;
	curwp->w_flag |= WFMOVE;
	return (TRUE);
}
#endif




@//E*O*F basic.c//
chmod u=rw,g=r,o=r basic.c
 
echo x - bind.c
sed 's/^@//' > "bind.c" <<'@//E*O*F bind.c//'
/*	This file is for functions having to do with key bindings,
	descriptions, help commands and startup file.

	written 11-feb-86 by Daniel Lawrence
								*/

#include	<stdio.h>
#include	"estruct.h"
#include	"edef.h"
#include	"epath.h"

extern int meta(), cex(), unarg(), ctrlg(); /* dummy prefix binding functions */

help(f, n)	/* give me some help!!!!
		   bring up a fake buffer and read the help file
		   into it with view mode			*/
{
	register WINDOW *wp;	/* scaning pointer to windows */
	register BUFFER *bp;	/* buffer pointer to help */
	char *fname;		/* ptr to file returned by flook() */

	/* first check if we are already here */
	bp = bfind("emacs.hlp", FALSE, BFINVS);

	if (bp == NULL) {
		fname = flook(pathname[1], FALSE);
		if (fname == NULL) {
			mlwrite("[Help file is not online]");
			return(FALSE);
		}
	}

	/* split the current window to make room for the help stuff */
	if (splitwind(FALSE, 1) == FALSE)
			return(FALSE);

	if (bp == NULL) {
		/* and read the stuff in */
		if (getfile(fname, FALSE) == FALSE)
			return(FALSE);
	} else
		swbuffer(bp);

	/* make this window in VIEW mode, update all mode lines */
	curwp->w_bufp->b_mode |= MDVIEW;
	curwp->w_bufp->b_flag |= BFINVS;
	wp = wheadp;
	while (wp != NULL) {
		wp->w_flag |= WFMODE;
		wp = wp->w_wndp;
	}
	return(TRUE);
}

deskey(f, n)	/* describe the command for a certain key */

{
	register int c;		/* key to describe */
	register char *ptr;	/* string pointer to scan output strings */
	char outseq[NSTRING];	/* output buffer for command sequence */
	int (*getbind())();

	/* prompt the user to type us a key to describe */
	mlwrite(": describe-key ");

	/* get the command sequence to describe
	   change it to something we can print as well */
	cmdstr(c = getckey(FALSE), &outseq[0]);

	/* and dump it out */
	ostring(outseq);
	ostring(" ");

	/* find the right ->function */
	if ((ptr = getfname(getbind(c))) == NULL)
		ptr = "Not Bound";

	/* output the command sequence */
	ostring(ptr);
}

/* bindtokey:	add a new key to the key binding table		*/

bindtokey(f, n)

int f, n;	/* command arguments [IGNORED] */

{
	register unsigned int c;/* command key to bind */
	register (*kfunc)();	/* ptr to the requested function to bind to */
	register KEYTAB *ktp;	/* pointer into the command table */
	register int found;	/* matched command flag */
	char outseq[80];	/* output buffer for keystroke sequence */
	int (*getname())();

	/* prompt the user to type in a key to bind */
	mlwrite(": bind-to-key ");

	/* get the function name to bind it to */
#if	NeWS
	newsimmediateon() ;
	kfunc = getname();
	newsimmediateoff() ;
#else
	kfunc = getname();
#endif

	if (kfunc == NULL) {
		mlwrite("[No such function]");
		return(FALSE);
	}
	ostring(" ");

	/* get the command sequence to bind */
	c = getckey((kfunc == meta) || (kfunc == cex) ||
	            (kfunc == unarg) || (kfunc == ctrlg));

	/* change it to something we can print as well */
	cmdstr(c, &outseq[0]);

	/* and dump it out */
	ostring(outseq);

	/* if the function is a prefix key */
	if (kfunc == meta || kfunc == cex ||
	    kfunc == unarg || kfunc == ctrlg) {

		/* search for an existing binding for the prefix key */
		ktp = &keytab[0];
		found = FALSE;
		while (ktp->k_fp != NULL) {
			if (ktp->k_fp == kfunc)
				unbindchar(ktp->k_code);
			++ktp;
		}

		/* reset the appropriate global prefix variable */
		if (kfunc == meta)
			metac = c;
		if (kfunc == cex)
			ctlxc = c;
		if (kfunc == unarg)
			reptc = c;
		if (kfunc == ctrlg)
			abortc = c;
	}

	/* search the table to see if it exists */
	ktp = &keytab[0];
	found = FALSE;
	while (ktp->k_fp != NULL) {
		if (ktp->k_code == c) {
			found = TRUE;
			break;
		}
		++ktp;
	}

	if (found) {	/* it exists, just change it then */
		ktp->k_fp = kfunc;
	} else {	/* otherwise we need to add it to the end */
		/* if we run out of binding room, bitch */
		if (ktp >= &keytab[NBINDS]) {
			mlwrite("Binding table FULL!");
			return(FALSE);
		}

		ktp->k_code = c;	/* add keycode */
		ktp->k_fp = kfunc;	/* and the function pointer */
		++ktp;			/* and make sure the next is null */
		ktp->k_code = 0;
		ktp->k_fp = NULL;
	}
	return(TRUE);
}

/* unbindkey:	delete a key from the key binding table	*/

unbindkey(f, n)

int f, n;	/* command arguments [IGNORED] */

{
	register int c;		/* command key to unbind */
	char outseq[80];	/* output buffer for keystroke sequence */

	/* prompt the user to type in a key to unbind */
	mlwrite(": unbind-key ");

	/* get the command sequence to unbind */
	c = getckey(FALSE);		/* get a command sequence */

	/* change it to something we can print as well */
	cmdstr(c, &outseq[0]);

	/* and dump it out */
	ostring(outseq);

	/* if it isn't bound, bitch */
	if (unbindchar(c) == FALSE) {
		mlwrite("[Key not bound]");
		return(FALSE);
	}
	return(TRUE);
}

unbindchar(c)

int c;		/* command key to unbind */

{
	register KEYTAB *ktp;	/* pointer into the command table */
	register KEYTAB *sktp;	/* saved pointer into the command table */
	register int found;	/* matched command flag */

	/* search the table to see if the key exists */
	ktp = &keytab[0];
	found = FALSE;
	while (ktp->k_fp != NULL) {
		if (ktp->k_code == c) {
			found = TRUE;
			break;
		}
		++ktp;
	}

	/* if it isn't bound, bitch */
	if (!found)
		return(FALSE);

	/* save the pointer and scan to the end of the table */
	sktp = ktp;
	while (ktp->k_fp != NULL)
		++ktp;
	--ktp;		/* backup to the last legit entry */

	/* copy the last entry to the current one */
	sktp->k_code = ktp->k_code;
	sktp->k_fp   = ktp->k_fp;

	/* null out the last one */
	ktp->k_code = 0;
	ktp->k_fp = NULL;
	return(TRUE);
}

desbind(f, n)	/* describe bindings
		   bring up a fake buffer and list the key bindings
		   into it with view mode			*/

#if	APROP
{
	buildlist(TRUE, "");
}

apro(f, n)	/* Apropos (List functions that match a substring) */

{
	char mstring[NSTRING];	/* string to match cmd names to */
	int status;		/* status return */

	status = mlreply("Apropos string: ", mstring, NSTRING - 1);
	if (status != TRUE)
		return(status);

	return(buildlist(FALSE, mstring));
}

buildlist(type, mstring)  /* build a binding list (limited or full) */

int type;	/* true = full list,   false = partial list */
char *mstring;	/* match string if a partial list */

#endif
{
#if	ST520 & LATTICE
#define	register		
#endif
	register WINDOW *wp;	/* scanning pointer to windows */
	register KEYTAB *ktp;	/* pointer into the command table */
	register NBIND *nptr;	/* pointer into the name binding table */
	register BUFFER *bp;	/* buffer to put binding list into */
	char *strp;		/* pointer int string to send */
	int cpos;		/* current position to use in outseq */
	char outseq[80];	/* output buffer for keystroke sequence */

	/* split the current window to make room for the binding list */
	if (splitwind(FALSE, 1) == FALSE)
			return(FALSE);

	/* and get a buffer for it */
	bp = bfind("Binding list", TRUE, 0);
	if (bp == NULL || bclear(bp) == FALSE) {
		mlwrite("Can not display binding list");
		return(FALSE);
	}

	/* let us know this is in progress */
	mlwrite("[Building binding list]");

	/* disconect the current buffer */
        if (--curbp->b_nwnd == 0) {             /* Last use.            */
                curbp->b_dotp  = curwp->w_dotp;
                curbp->b_doto  = curwp->w_doto;
                curbp->b_markp = curwp->w_markp;
                curbp->b_marko = curwp->w_marko;
        }

	/* connect the current window to this buffer */
	curbp = bp;	/* make this buffer current in current window */
	bp->b_mode = 0;		/* no modes active in binding list */
	bp->b_nwnd++;		/* mark us as more in use */
	wp = curwp;
	wp->w_bufp = bp;
	wp->w_linep = bp->b_linep;
	wp->w_flag = WFHARD|WFFORCE;
	wp->w_dotp = bp->b_dotp;
	wp->w_doto = bp->b_doto;
	wp->w_markp = NULL;
	wp->w_marko = 0;

	/* build the contents of this window, inserting it line by line */
	nptr = &names[0];
	while (nptr->n_func != NULL) {

		/* add in the command name */
		strcpy(outseq, nptr->n_name);
		cpos = strlen(outseq);
		
#if	APROP
		/* if we are executing an apropos command..... */
		if (type == FALSE &&
		    /* and current string doesn't include the search string */
		    strinc(outseq, mstring) == FALSE)
			goto fail;
#endif
		/* search down any keys bound to this */
		ktp = &keytab[0];
		while (ktp->k_fp != NULL) {
			if (ktp->k_fp == nptr->n_func) {
				/* padd out some spaces */
				while (cpos < 25)
					outseq[cpos++] = ' ';

				/* add in the command sequence */
				cmdstr(ktp->k_code, &outseq[cpos]);
				while (outseq[cpos] != 0)
					++cpos;

				/* and add it as a line into the buffer */
				strp = &outseq[0];
				while (*strp != 0)
					linsert(1, *strp++);
				lnewline();

				cpos = 0;	/* and clear the line */
			}
			++ktp;
		}

		/* if no key was bound, we need to dump it anyway */
		if (cpos > 0) {
			outseq[cpos] = 0;
			strp = &outseq[0];
			while (*strp != 0)
				linsert(1, *strp++);
			lnewline();
		}

fail:		/* and on to the next name */
		++nptr;
	}

	curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
	curbp->b_flag &= ~BFCHG;	/* don't flag this as a change */
	wp->w_dotp = lforw(bp->b_linep);/* back to the beginning */
	wp->w_doto = 0;
	wp = wheadp;			/* and update ALL mode lines */
	while (wp != NULL) {
		wp->w_flag |= WFMODE;
		wp = wp->w_wndp;
	}
	mlwrite("");	/* clear the mode line */
	return(TRUE);
}

#if	APROP
strinc(source, sub)	/* does source include sub? */

char *source;	/* string to search in */
char *sub;	/* substring to look for */

{
	char *sp;	/* ptr into source */
	char *nxtsp;	/* next ptr into source */
	char *tp;	/* ptr into substring */

	/* for each character in the source string */
	sp = source;
	while (*sp) {
		tp = sub;
		nxtsp = sp;

		/* is the substring here? */
		while (*tp) {
			if (*nxtsp++ != *tp)
				break;
			else
				tp++;
		}

		/* yes, return a success */
		if (*tp == 0)
			return(TRUE);

		/* no, onward */
		sp++;
	}
	return(FALSE);
}
#endif

/* get a command key sequence from the keyboard	*/

unsigned int getckey(mflag)

int mflag;	/* going for a meta sequence? */

{
	register unsigned int c;	/* character fetched */
#if	MSC | TURBO
	register unsigned char *tp;	/* pointer into the token */
#else
	register char *tp;		/* pointer into the token */
#endif
	char tok[NSTRING];		/* command incoming */

	/* check to see if we are executing a command line */
	if (clexec) {
		macarg(tok);	/* get the next token */
		return(stock(tok));
	}

	/* or the normal way */
	if (mflag)
		c = get1key();
	else
		c = getcmd();
	return(c);
}

/* execute the startup file */

startup(sfname)

char *sfname;	/* name of startup file (null if default) */

{
	char *fname;	/* resulting file name to execute */

	/* look up the startup file */
	if (*sfname != 0)
		fname = flook(sfname, TRUE);
	else
		fname = flook(pathname[0], TRUE);

	/* if it isn't around, don't sweat it */
	if (fname == NULL)
		return(TRUE);

	/* otherwise, execute the sucker */
	return(dofile(fname));
}

/*	Look up the existance of a file along the normal or PATH
	environment variable. Look first in the HOME directory if
	asked and possible
*/

char *flook(fname, hflag)

char *fname;	/* base file name to search for */
int hflag;	/* Look in the HOME environment variable first? */

{
	register char *home;	/* path to home directory */
	register char *path;	/* environmental PATH variable */
	register char *sp;	/* pointer into path spec */
	register int i;		/* index */
	register int status;	/* return status */
	static char fspec[NSTRING];	/* full path spec to search */
	char *getenv();

#if	ENVFUNC

	if (hflag) {
		home = getenv("HOME");
		if (home != NULL) {
			/* build home dir file spec */
			strcpy(fspec, home);
			strcat(fspec, "/");
			strcat(fspec, fname);

			/* and try it out */
			if (ffropen(fspec) == FIOSUC) {
				ffclose();
				return(fspec);
			}
		}
	}
#endif

	/* always try the current directory first */
	if (ffropen(fname) == FIOSUC) {
		ffclose();
		return(fname);
	}

#if	ENVFUNC
	/* get the PATH variable */
	path = getenv("PATH");
	if (path != NULL)
		while (*path) {

			/* build next possible file spec */
			sp = fspec;
			while (*path && (*path != PATHCHR))
				*sp++ = *path++;
			*sp++ = '/';
			*sp = 0;
			strcat(fspec, fname);

			/* and try it out */
			if (ffropen(fspec) == FIOSUC) {
				ffclose();
				return(fspec);
			}

			if (*path == PATHCHR)
				++path;
		}
#endif

	/* look it up via the old table method */
	for (i=2; i < NPNAMES; i++) {
		strcpy(fspec, pathname[i]);
		strcat(fspec, fname);

		/* and try it out */
		if (ffropen(fspec) == FIOSUC) {
			ffclose();
			return(fspec);
		}
	}

	return(NULL);	/* no such luck */
}

cmdstr(c, seq)	/* change a key command to a string we can print out */

int c;		/* sequence to translate */
char *seq;	/* destination string for sequence */

{
	char *ptr;	/* pointer into current position in sequence */

	ptr = seq;

	/* apply meta sequence if needed */
	if (c & META) {
		*ptr++ = 'M';
		*ptr++ = '-';
	}

	/* apply ^X sequence if needed */
	if (c & CTLX) {
		*ptr++ = '^';
		*ptr++ = 'X';
	}

	/* apply SPEC sequence if needed */
	if (c & SPEC) {
		*ptr++ = 'F';
		*ptr++ = 'N';
	}

	/* apply control sequence if needed */
	if (c & CTRL) {
		*ptr++ = '^';
	}

	c = c & 255;	/* strip the prefixes */

	/* and output the final sequence */

	*ptr++ = c;
	*ptr = 0;	/* terminate the string */
}

/*	This function looks a key binding up in the binding table	*/

int (*getbind(c))()

int c;	/* key to find what is bound to it */

{
	register KEYTAB *ktp;

        ktp = &keytab[0];                       /* Look in key table.   */
        while (ktp->k_fp != NULL) {
                if (ktp->k_code == c)
                        return(ktp->k_fp);
                ++ktp;
        }

	/* no such binding */
	return(NULL);
}

/* getfname:	This function takes a ptr to function and gets the name
		associated with it
*/

char *getfname(func)

int (*func)();	/* ptr to the requested function to bind to */

{
	register NBIND *nptr;	/* pointer into the name binding table */

	/* skim through the table, looking for a match */
	nptr = &names[0];
	while (nptr->n_func != NULL) {
		if (nptr->n_func == func)
			return(nptr->n_name);
		++nptr;
	}
	return(NULL);
}

int (*fncmatch(fname))() /* match fname to a function in the names table
			    and return any match or NULL if none		*/

char *fname;	/* name to attempt to match */

{
	register NBIND *ffp;	/* pointer to entry in name binding table */

	/* scan through the table, returning any match */
	ffp = &names[0];
	while (ffp->n_func != NULL) {
		if (strcmp(fname, ffp->n_name) == 0)
			return(ffp->n_func);
		++ffp;
	}
	return(NULL);
}

/* stock:	String key name TO Command Key		*/

unsigned int stock(keyname)

char *keyname;		/* name of key to translate to Command key form */

{
	register unsigned int c;	/* key sequence to return */

	/* parse it up */
	c = 0;

	/* first, the META prefix */
	if (*keyname == 'M' && *(keyname+1) == '-') {
		c = META;
		keyname += 2;
	}

	/* next the function prefix */
	if (*keyname == 'F' && *(keyname+1) == 'N') {
		c |= SPEC;
		keyname += 2;
	}

	/* control-x as well... (but not with FN) */
	if (*keyname == '^' && *(keyname+1) == 'X'&& !(c & SPEC)) {
		c |= CTLX;
		keyname += 2;
	}

	/* a control char? */
	if (*keyname == '^' && *(keyname+1) != 0) {
		c |= CTRL;
		++keyname;
	}
	if (*keyname < 32) {
		c |= CTRL;
		*keyname += 'A';
	}


	/* make sure we are not lower case (not with function keys)*/
	if (*keyname >= 'a' && *keyname <= 'z' && !(*keyname & SPEC))
		*keyname -= 32;

	/* the final sequence... */
	c |= *keyname;
	return(c);
}

char *transbind(skey)	/* string key name to binding name.... */

char *skey;	/* name of keey to get binding for */

{
	char *bindname;
	unsigned int stock();
	int (*getbind())();

	bindname = getfname(getbind(stock(skey)));
	if (bindname == NULL)
		bindname = "ERROR";

	return(bindname);
}
@//E*O*F bind.c//
chmod u=rw,g=r,o=r bind.c
 
echo x - buffer.c
sed 's/^@//' > "buffer.c" <<'@//E*O*F buffer.c//'
/*
 * Buffer management.
 * Some of the functions are internal,
 * and some are actually attached to user
 * keys. Like everyone else, they set hints
 * for the display system.
 */
#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"

/*
 * Attach a buffer to a window. The
 * values of dot and mark come from the buffer
 * if the use count is 0. Otherwise, they come
 * from some other window.
 */
usebuffer(f, n)
{
        register BUFFER *bp;
        register int    s;
        char            bufn[NBUFN];

        if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE)
                return (s);
        if ((bp=bfind(bufn, TRUE, 0)) == NULL)
                return (FALSE);
	return(swbuffer(bp));
}

nextbuffer(f, n)	/* switch to the next buffer in the buffer list */

int f, n;	/* default flag, numeric argument */
{
	register BUFFER *bp;	/* eligable buffer to switch to*/
	register BUFFER *bbp;	/* eligable buffer to switch to*/

	/* make sure the arg is legit */
	if (f == FALSE)
		n = 1;
	if (n < 1)
		return(FALSE);

	bbp = curbp;
	while (n-- > 0) {
		/* advance to the next buffer */
		bp = bbp->b_bufp;

		/* cycle through the buffers to find an eligable one */
		while (bp == NULL || bp->b_flag & BFINVS) {
			if (bp == NULL)
				bp = bheadp;
			else
				bp = bp->b_bufp;

			/* don't get caught in an infinite loop! */
			if (bp == bbp)
				return(FALSE);

		}		

		bbp = bp;
	}

	return(swbuffer(bp));
}

swbuffer(bp)	/* make buffer BP current */

BUFFER *bp;

{
        register WINDOW *wp;

        if (--curbp->b_nwnd == 0) {             /* Last use.            */
                curbp->b_dotp  = curwp->w_dotp;
                curbp->b_doto  = curwp->w_doto;
                curbp->b_markp = curwp->w_markp;
                curbp->b_marko = curwp->w_marko;
        }
        curbp = bp;                             /* Switch.              */
	if (curbp->b_active != TRUE) {		/* buffer not active yet*/
		/* read it in and activate it */
		readin(curbp->b_fname, TRUE);
		curbp->b_dotp = lforw(curbp->b_linep);
		curbp->b_doto = 0;
		curbp->b_active = TRUE;
	}
        curwp->w_bufp  = bp;
        curwp->w_linep = bp->b_linep;           /* For macros, ignored. */
        curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty.         */
        if (bp->b_nwnd++ == 0) {                /* First use.           */
                curwp->w_dotp  = bp->b_dotp;
                curwp->w_doto  = bp->b_doto;
                curwp->w_markp = bp->b_markp;
                curwp->w_marko = bp->b_marko;
#if     NeWS
	        newsreportmodes() ;
#endif
                return (TRUE);
        }
        wp = wheadp;                            /* Look for old.        */
        while (wp != NULL) {
                if (wp!=curwp && wp->w_bufp==bp) {
                        curwp->w_dotp  = wp->w_dotp;
                        curwp->w_doto  = wp->w_doto;
                        curwp->w_markp = wp->w_markp;
                        curwp->w_marko = wp->w_marko;
                        break;
                }
                wp = wp->w_wndp;
        }
#if     NeWS
        newsreportmodes() ;
#endif
        return (TRUE);
}

/*
 * Dispose of a buffer, by name.
 * Ask for the name. Look it up (don't get too
 * upset if it isn't there at all!). Get quite upset
 * if the buffer is being displayed. Clear the buffer (ask
 * if the buffer has been changed). Then free the header
 * line and the buffer header. Bound to "C-X K".
 */
killbuffer(f, n)

{
	register BUFFER *bp;
        register int    s;
        char bufn[NBUFN];

        if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE)
                return(s);
        if ((bp=bfind(bufn, FALSE, 0)) == NULL) /* Easy if unknown.     */
                return (TRUE);
	if(bp->b_flag & BFINVS)		/* Deal with special buffers	*/
			return (TRUE);		/* by doing nothing.	*/
	return(zotbuf(bp));
}

zotbuf(bp)	/* kill the buffer pointed to by bp */

register BUFFER *bp;

{
        register BUFFER *bp1;
        register BUFFER *bp2;
        register int    s;

        if (bp->b_nwnd != 0) {                  /* Error if on screen.  */
                mlwrite("Buffer is being displayed");
                return (FALSE);
        }
        if ((s=bclear(bp)) != TRUE)             /* Blow text away.      */
                return (s);
        free((char *) bp->b_linep);             /* Release header line. */
        bp1 = NULL;                             /* Find the header.     */
        bp2 = bheadp;
        while (bp2 != bp) {
                bp1 = bp2;
                bp2 = bp2->b_bufp;
        }
        bp2 = bp2->b_bufp;                      /* Next one in chain.   */
        if (bp1 == NULL)                        /* Unlink it.           */
                bheadp = bp2;
        else
                bp1->b_bufp = bp2;
        free((char *) bp);                      /* Release buffer block */
        return (TRUE);
}

namebuffer(f,n)		/*	Rename the current buffer	*/

int f, n;		/* default Flag & Numeric arg */

{
	register BUFFER *bp;	/* pointer to scan through all buffers */
	char bufn[NBUFN];	/* buffer to hold buffer name */

	/* prompt for and get the new buffer name */
ask:	if (mlreply("Change buffer name to: ", bufn, NBUFN) != TRUE)
		return(FALSE);

	/* and check for duplicates */
	bp = bheadp;
	while (bp != NULL) {
		if (bp != curbp) {
			/* if the names the same */
			if (strcmp(bufn, bp->b_bname) == 0)
				goto ask;  /* try again */
		}
		bp = bp->b_bufp;	/* onward */
	}

	strcpy(curbp->b_bname, bufn);	/* copy buffer name to structure */
	curwp->w_flag |= WFMODE;	/* make mode line replot */
	mlerase();
	return(TRUE);
}

/*
	List all of the active buffers.  First update the special
	buffer that holds the list.  Next make sure at least 1
	window is displaying the buffer list, splitting the screen
	if this is what it takes.  Lastly, repaint all of the
	windows that are displaying the list.  Bound to "C-X C-B". 
	A numeric argument forces it to list invisable buffers as
	well.
*/

listbuffers(f, n)
{
        register WINDOW *wp;
        register BUFFER *bp;
        register int    s;

        if ((s=makelist(f)) != TRUE)
                return (s);
        if (blistp->b_nwnd == 0) {              /* Not on screen yet.   */
                if ((wp=wpopup()) == NULL)
                        return (FALSE);
                bp = wp->w_bufp;
                if (--bp->b_nwnd == 0) {
                        bp->b_dotp  = wp->w_dotp;
                        bp->b_doto  = wp->w_doto;
                        bp->b_markp = wp->w_markp;
                        bp->b_marko = wp->w_marko;
                }
                wp->w_bufp  = blistp;
                ++blistp->b_nwnd;
        }
        wp = wheadp;
        while (wp != NULL) {
                if (wp->w_bufp == blistp) {
                        wp->w_linep = lforw(blistp->b_linep);
                        wp->w_dotp  = lforw(blistp->b_linep);
                        wp->w_doto  = 0;
                        wp->w_markp = NULL;
                        wp->w_marko = 0;
                        wp->w_flag |= WFMODE|WFHARD;
                }
                wp = wp->w_wndp;
        }
        return (TRUE);
}

/*
 * This routine rebuilds the
 * text in the special secret buffer
 * that holds the buffer list. It is called
 * by the list buffers command. Return TRUE
 * if everything works. Return FALSE if there
 * is an error (if there is no memory). Iflag
 * indecates weather to list hidden buffers.
 */
makelist(iflag)

int iflag;	/* list hidden buffer flag */

{
        register char   *cp1;
        register char   *cp2;
        register int    c;
        register BUFFER *bp;
        register LINE   *lp;
        register int    s;
	register int	i;
        long nbytes;		/* # of bytes in current buffer */
        char b[7+1];
        char line[128];

        blistp->b_flag &= ~BFCHG;               /* Don't complain!      */
        if ((s=bclear(blistp)) != TRUE)         /* Blow old text away   */
                return (s);
        strcpy(blistp->b_fname, "");
        if (addline("AC MODES        Size Buffer        File") == FALSE
        ||  addline("-- -----        ---- ------        ----") == FALSE)
                return (FALSE);
        bp = bheadp;                            /* For all buffers      */

	/* build line to report global mode settings */
	cp1 = &line[0];
	*cp1++ = ' ';
	*cp1++ = ' ';
	*cp1++ = ' ';

	/* output the mode codes */
	for (i = 0; i < NUMMODES; i++)
		if (gmode & (1 << i))
			*cp1++ = modecode[i];
		else
			*cp1++ = '.';
	strcpy(cp1, "         Global Modes");
	if (addline(line) == FALSE)
		return(FALSE);

	/* output the list of buffers */
        while (bp != NULL) {
		/* skip invisable buffers if iflag is false */
                if (((bp->b_flag&BFINVS) != 0) && (iflag != TRUE)) {
                        bp = bp->b_bufp;
                        continue;
                }
                cp1 = &line[0];                 /* Start at left edge   */

		/* output status of ACTIVE flag (has the file been read in? */
                if (bp->b_active == TRUE)    /* "@" if activated       */
                        *cp1++ = '@';
                else
                        *cp1++ = ' ';

		/* output status of changed flag */
                if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed       */
                        *cp1++ = '*';
                else
                        *cp1++ = ' ';
                *cp1++ = ' ';                   /* Gap.                 */

		/* output the mode codes */
		for (i = 0; i < NUMMODES; i++) {
			if (bp->b_mode & (1 << i))
				*cp1++ = modecode[i];
			else
				*cp1++ = '.';
		}
                *cp1++ = ' ';                   /* Gap.                 */
                nbytes = 0L;                    /* Count bytes in buf.  */
                lp = lforw(bp->b_linep);
                while (lp != bp->b_linep) {
                        nbytes += (long)llength(lp)+1L;
                        lp = lforw(lp);
                }
                ltoa(b, 7, nbytes);             /* 6 digit buffer size. */
                cp2 = &b[0];
                while ((c = *cp2++) != 0)
                        *cp1++ = c;
                *cp1++ = ' ';                   /* Gap.                 */
                cp2 = &bp->b_bname[0];          /* Buffer name          */
                while ((c = *cp2++) != 0)
                        *cp1++ = c;
                cp2 = &bp->b_fname[0];          /* File name            */
                if (*cp2 != 0) {
                        while (cp1 < &line[2+1+5+1+6+1+NBUFN])
                                *cp1++ = ' ';
                        while ((c = *cp2++) != 0) {
                                if (cp1 < &line[128-1])
                                        *cp1++ = c;
                        }
                }
                *cp1 = 0;                       /* Add to the buffer.   */
                if (addline(line) == FALSE)
                        return (FALSE);
                bp = bp->b_bufp;
        }
        return (TRUE);                          /* All done             */
}

ltoa(buf, width, num)

char   buf[];
int    width;
long   num;

{
        buf[width] = 0;                         /* End of string.       */
        while (num >= 10) {                     /* Conditional digits.  */
                buf[--width] = (int)(num%10L) + '0';
                num /= 10L;
        }
        buf[--width] = (int)num + '0';          /* Always 1 digit.      */
        while (width != 0)                      /* Pad with blanks.     */
                buf[--width] = ' ';
}

/*
 * The argument "text" points to
 * a string. Append this line to the
 * buffer list buffer. Handcraft the EOL
 * on the end. Return TRUE if it worked and
 * FALSE if you ran out of room.
 */
addline(text)
char    *text;
{
        register LINE   *lp;
        register int    i;
        register int    ntext;

        ntext = strlen(text);
        if ((lp=lalloc(ntext)) == NULL)
                return (FALSE);
        for (i=0; i<ntext; ++i)
                lputc(lp, i, text[i]);
        blistp->b_linep->l_bp->l_fp = lp;       /* Hook onto the end    */
        lp->l_bp = blistp->b_linep->l_bp;
        blistp->b_linep->l_bp = lp;
        lp->l_fp = blistp->b_linep;
        if (blistp->b_dotp == blistp->b_linep)  /* If "." is at the end */
                blistp->b_dotp = lp;            /* move it to new line  */
        return (TRUE);
}

/*
 * Look through the list of
 * buffers. Return TRUE if there
 * are any changed buffers. Buffers
 * that hold magic internal stuff are
 * not considered; who cares if the
 * list of buffer names is hacked.
 * Return FALSE if no buffers
 * have been changed.
 */
anycb()
{
        register BUFFER *bp;

        bp = bheadp;
        while (bp != NULL) {
                if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
                        return (TRUE);
                bp = bp->b_bufp;
        }
        return (FALSE);
}

/*
 * Find a buffer, by name. Return a pointer
 * to the BUFFER structure associated with it.
 * If the buffer is not found
 * and the "cflag" is TRUE, create it. The "bflag" is
 * the settings for the flags in in buffer.
 */
BUFFER  *
bfind(bname, cflag, bflag)
register char   *bname;
{
        register BUFFER *bp;
	register BUFFER *sb;	/* buffer to insert after */
        register LINE   *lp;
	char *malloc();

        bp = bheadp;
        while (bp != NULL) {
                if (strcmp(bname, bp->b_bname) == 0)
                        return (bp);
                bp = bp->b_bufp;
        }
        if (cflag != FALSE) {
                if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
                        return (NULL);
                if ((lp=lalloc(0)) == NULL) {
                        free((char *) bp);
                        return (NULL);
                }
		/* find the place in the list to insert this buffer */
		if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
			/* insert at the beginning */
	                bp->b_bufp = bheadp;
        	        bheadp = bp;
        	} else {
			sb = bheadp;
			while (sb->b_bufp != NULL) {
				if (strcmp(sb->b_bufp->b_bname, bname) > 0)
					break;
				sb = sb->b_bufp;
			}

			/* and insert it */
       			bp->b_bufp = sb->b_bufp;
        		sb->b_bufp = bp;
       		}

		/* and set up the other buffer fields */
		bp->b_active = TRUE;
                bp->b_dotp  = lp;
                bp->b_doto  = 0;
                bp->b_markp = NULL;
                bp->b_marko = 0;
                bp->b_flag  = bflag;
		bp->b_mode  = gmode;
                bp->b_nwnd  = 0;
                bp->b_linep = lp;
                strcpy(bp->b_fname, "");
                strcpy(bp->b_bname, bname);
#if	CRYPT
		bp->b_key[0] = 0;
#endif
                lp->l_fp = lp;
                lp->l_bp = lp;
        }
        return (bp);
}

/*
 * This routine blows away all of the text
 * in a buffer. If the buffer is marked as changed
 * then we ask if it is ok to blow it away; this is
 * to save the user the grief of losing text. The
 * window chain is nearly always wrong if this gets
 * called; the caller must arrange for the updates
 * that are required. Return TRUE if everything
 * looks good.
 */
bclear(bp)
register BUFFER *bp;
{
        register LINE   *lp;
        register int    s;

        if ((bp->b_flag&BFINVS) == 0            /* Not scratch buffer.  */
        && (bp->b_flag&BFCHG) != 0              /* Something changed    */
        && (s=mlyesno("Discard changes")) != TRUE)
                return (s);
        bp->b_flag  &= ~BFCHG;                  /* Not changed          */
        while ((lp=lforw(bp->b_linep)) != bp->b_linep)
                lfree(lp);
        bp->b_dotp  = bp->b_linep;              /* Fix "."              */
        bp->b_doto  = 0;
        bp->b_markp = NULL;                     /* Invalidate "mark"    */
        bp->b_marko = 0;
        return (TRUE);
}

unmark(f, n)	/* unmark the current buffers change flag */

int f, n;	/* unused command arguments */

{
	curbp->b_flag &= ~BFCHG;
	curwp->w_flag |= WFMODE;
	return(TRUE);
}
@//E*O*F buffer.c//
chmod u=rw,g=r,o=r buffer.c
 
echo x - crypt.c
sed 's/^@//' > "crypt.c" <<'@//E*O*F crypt.c//'
/*	Crypt:	Encryption routines for MicroEMACS
		written by Dana Hoggatt and Daniel Lawrence
*/

#include	<stdio.h>
#include	"estruct.h"
#include	"edef.h"

#if	CRYPT
setkey(f, n)	/* reset encryption key of current buffer */

int f;		/* default flag */
int n;		/* numeric argument */

{
	register int status;	/* return status */
	int odisinp;		/* original vlaue of disinp */
	char key[NPAT];		/* new encryption string */

	/* turn command input echo off */
	odisinp = disinp;
	disinp = FALSE;

	/* get the string to use as an encrytion string */
	status = mlreply("Encryption String: ", key, NPAT - 1);
	disinp = odisinp;
        if (status != TRUE)
                return(status);

	/* and encrypt it */
	crypt((char *)NULL, 0);
	crypt(key, strlen(key));

	/* and save it off */
	strcpy(curbp->b_key, key);
	mlwrite(" ");		/* clear it off the bottom line */
	return(TRUE);
}

/**********
 *
 *	crypt - in place encryption/decryption of a buffer
 *
 *	(C) Copyright 1986, Dana L. Hoggatt
 *	1216, Beck Lane, Lafayette, IN
 *
 *	When consulting directly with the author of this routine, 
 *	please refer to this routine as the "DLH-POLY-86-B CIPHER".  
 *
 *	This routine was written for Dan Lawrence, for use in V3.8 of
 *	MicroEMACS, a public domain text/program editor.  
 *
 *	I kept the following goals in mind when preparing this function:
 *
 *	    1.	All printable characters were to be encrypted back
 *		into the printable range, control characters and
 *		high-bit characters were to remain unaffected.  this
 *		way, encrypted would still be just as cheap to 
 *		transmit down a 7-bit data path as they were before.
 *
 *	    2.	The encryption had to be portable.  The encrypted 
 *		file from one computer should be able to be decrypted 
 *		on another computer.
 *
 *	    3.	The encryption had to be inexpensive, both in terms
 *		of speed and space.
 *
 *	    4.	The system needed to be secure against all but the
 *		most determined of attackers.
 *
 *	For encryption of a block of data, one calls crypt passing 
 *	a pointer to the data block and its length. The data block is 
 *	encrypted in place, that is, the encrypted output overwrites 
 *	the input.  Decryption is totally isomorphic, and is performed 
 *	in the same manner by the same routine.  
 *
 *	Before using this routine for encrypting data, you are expected 
 *	to specify an encryption key.  This key is an arbitrary string,
 *	to be supplied by the user.  To set the key takes two calls to 
 *	crypt().  First, you call 
 *
 *		crypt(NULL, vector)
 *
 *	This resets all internal control information.  Typically (and 
 *	specifically in the case on MICRO-emacs) you would use a "vector" 
 *	of 0.  Other values can be used to customize your editor to be 
 *	"incompatable" with the normally distributed version.  For 
 *	this purpose, the best results will be obtained by avoiding
 *	multiples of 95.
 *
 *	Then, you "encrypt" your password by calling 
 *
 *		crypt(pass, strlen(pass))
 *
 *	where "pass" is your password string.  Crypt() will destroy 
 *	the original copy of the password (it becomes encrypted), 
 *	which is good.  You do not want someone on a multiuser system 
 *	to peruse your memory space and bump into your password.  
 *	Still, it is a better idea to erase the password buffer to 
 *	defeat memory perusal by a more technical snooper.  
 *
 *	For the interest of cryptologists, at the heart of this 
 *	function is a Beaufort Cipher.  The cipher alphabet is the 
 *	range of printable characters (' ' to '~'), all "control" 
 *	and "high-bit" characters are left unaltered.
 *
 *	The key is a variant autokey, derived from a wieghted sum 
 *	of all the previous clear text and cipher text.  A counter 
 *	is used as salt to obiterate any simple cyclic behavior 
 *	from the clear text, and key feedback is used to assure 
 *	that the entire message is based on the original key, 
 *	preventing attacks on the last part of the message as if 
 *	it were a pure autokey system.
 *
 *	Overall security of encrypted data depends upon three 
 *	factors:  the fundamental cryptographic system must be 
 *	difficult to compromise; exhaustive searching of the key 
 *	space must be computationally expensive; keys and plaintext 
 *	must remain out of sight.  This system satisfies this set
 *	of conditions to within the degree desired for MicroEMACS.
 *
 *	Though direct methods of attack (against systems such as 
 *	this) do exist, they are not well known and will consume 
 *	considerable amounts of computing time.  An exhaustive
 *	search requires over a billion investigations, on average.
 *
 *	The choice, entry, storage, manipulation, alteration, 
 *	protection and security of the keys themselves are the 
 *	responsiblity of the user.  
 *
 **********/

crypt(bptr, len)
register char *bptr;	/* buffer of characters to be encrypted */
register unsigned len;	/* number of characters in the buffer */
{
	register int cc;	/* current character being considered */

	static long key = 0;	/* 29 bit encipherment key */
	static int salt = 0;	/* salt to spice up key with */

	if (!bptr) {		/* is there anything here to encrypt? */
		key = len;	/* set the new key */
		salt = len;	/* set the new salt */
		return;
	}
	while (len--) {		/* for every character in the buffer */

		cc = *bptr;	/* get a character out of the buffer */

		/* only encipher printable characters */
		if ((cc >= ' ') && (cc <= '~')) {

/**  If the upper bit (bit 29) is set, feed it back into the key.  This 
	assures us that the starting key affects the entire message.  **/

			key &= 0x1FFFFFFFL;	/* strip off overflow */
			if (key & 0x10000000L) {
				key ^= 0x0040A001L;	/* feedback */
			}

/**  Down-bias the character, perform a Beaufort encipherment, and 
	up-bias the character again.  We want key to be positive 
	so that the left shift here will be more portable and the 
	mod95() faster   **/

			cc = mod95((int)(key % 95) - (cc - ' ')) + ' ';

/**  the salt will spice up the key a little bit, helping to obscure 
	any patterns in the clear text, particularly when all the 
	characters (or long sequences of them) are the same.  We do 
	not want the salt to go negative, or it will affect the key 
	too radically.  It is always a good idea to chop off cyclics 
	to prime values.  **/

			if (++salt >= 20857) {	/* prime modulus */
				salt = 0;
			}

/**  our autokey (a special case of the running key) is being 
	generated by a wieghted checksum of clear text, cipher 
	text, and salt.   **/

			key = key + key + cc + *bptr + salt;
		}
		*bptr++ = cc;	/* put character back into buffer */
	}
	return;
}

static int mod95(val)

register int val;

{
	/*  The mathematical MOD does not match the computer MOD  */

	/*  Yes, what I do here may look strange, but it gets the
		job done, and portably at that.  */

	while (val >= 9500)
		val -= 9500;
	while (val >= 950)
		val -= 950;
	while (val >= 95)
		val -= 95;
	while (val < 0)
		val += 95;
	return (val);
}
#else
nocrypt()
{
}
#endif
@//E*O*F crypt.c//
chmod u=rw,g=r,o=r crypt.c
 
exit 0
