
# 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 Fri Jan 22 13:39:13 PST 1988
# Contents:  README Makefile Makeshar ansi.c basic.c bind.c buffer.c dg10.c
 
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
NCSA Cray/Sun Distributed EMACS

In this directory:
  1) ctool.sh	source for the Sun part
  2) ue*.sh	source for the Cray part

   These are both shar files (shell archive).  To extract the actual
source files copy the *.sh files to a unix machine.  Make directories
uemacs/Sun and uemacs/Cray.  While in the directory uemacs/Sun, enter
"sh ctool.sh" to extract the source of the Sunview program.  This also
unpacks a file named ".craymacros", which is hidden.  This can be edited
to taste and placed in your home directory.  To compile, type "make". 
The executable "craytool" is invoked as "craytool telnet ncsad".  You
may wish to define an alias:

cray	craytool telnet ncsad -Wp 0 0

Telnet must have been modified (echo character = ^P) in order to be able
to change suffixes on the cray and to have normal operation of the
command line editor/macro facilities (no echoing). 
   You will not need the ue*.sh files if you are using the NCSA Cray, as
the necessary files (uemacs and uehelp) are in public.  They can be extracted
as above.  The files uecomp and uelink are used to compile the program.


Note for Sun3/110C
   Performance is better on the black & white screen.  You can start a
second (b&w) suntools session by entering
  suntools -d /dev/bwtwo0 -toggle_enable -n &
  adjacentscreens -c /dev/fb -l /dev/bwtwo0
from a shell window.  Then move the mouse off the screen to the left.



Notes on porting the Cray half:
   Except for a few shortened file names, all of the changes from standard
MicroEMACS 3.8b are ifdef'd by the macros CRAY and TCPIP.  These and other
configuration switches are set in estruc.h.  Both switches MUST be set.
The non-TCPIP code is for a version that operated in an entirely different
manner.  The most likely ports will be to
	1) Unicos Crays.
	2) CTSS Crays using a different ipc system.
   This implementation uses the Livermore hybrid C compiler (hcc), for which
the libraries are very weak.  To correct one of the weakest areas, Steve
Dorner's double buffered file io routines are substituted (see io.c, fileio.c,
and related files).  Communication is done directly at the level of sockets,
using tcplib (an in-house NCSA product).  On a Unix Cray these ipc calls (in
termio.c) should be replaced by normal internet socket calls.  This change
and possibly removing the file io stuff are probably the only changes
required (apart from any improvements you may wish to make).
   The type of distribution used (keeping the bulk of the editor on the
mainframe instead of distributing at the file io end) is probably more
suitable for the Cray 2 than the XMP.  On a heavily loaded XMP there are
annoying delays when the process is swapped out.  The executable is quite
small (~80kwords with hcc, roughly half that with the Cray C 1.0 compiler)
and the swapping problem should disappear on the Cray 2.  In anticipation
of the Cray 2 I did not distribute the editor at the file io end.  As it is
it is rougly as network efficient as fred, but can't handle huge files
because it will load the whole file into memory (on the Cray) and hence
add to the swapping problems.  On the plus side, actively using the editor
will tend to prevent the process from being swapped out.
   I think it is possible to distribute MicroEMACS at the file end, even
though most of the code is written assuming the whole file is in memory.
The strategy that I would try would be to replace the macros lforw, lback,
etc (in estruc.h) with function calls that check for the line in local
memory and, on failing, request a block from a simple editing file server
on the Cray.  The Cray end in this case would, in addition to handling block
read/write requests, perform global functions such as "replace string".




Porting to different workstations:
   The Sun part is notifier based.  It was to take advantage of the
notifier facilities that Sunview was used.  Unfortunately, this makes
porting harder.  Xwindow may also provide such facilities.  If so, that
may be a fairly easy port.  Otherwise I would recommend writing a simple
notifier (catch signals on active descriptors, store them tagged by
type, and invoke the appropriate handler when it's safe to do so).  This
reduces writing the craytool program to the task of determining what
action should be taken for each event type (which is all the Sun version
does).  A simple version for generic unix shouldn't be too difficult.

@//E*O*F README//
chmod u=rw,g=r,o=r README
 
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
CFLAGS=		-g

OFILES=		ansi.o basic.o bind.o buffer.o displa.o file.o \
		fileio.o hp150.o input.o line.o lock.c main.o \
		random.o region.o \
		search.o spawn.o tcap.o termio.o vt52.o window.o word.o \
		exec.o eval.o isearc.o

CFILES=		ansi.c basic.c bind.c buffer.c displa.c  file.c \
		fileio.c hp150.c input.c line.c lock.c main.c \
		random.c region.c \
		search.c spawn.c tcap.c termio.c vt52.c window.c word.c \
		exec.c eval.c isearc.c

HFILES=		estruc.h edef.h efunc.h epath.h ebind.h evar.h esearc.h

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

$(OFILES):	$(HFILES)
@//E*O*F Makefile//
chmod u=rw,g=r,o=r Makefile
 
echo x - Makeshar
sed 's/^@//' > "Makeshar" <<'@//E*O*F Makeshar//'
# make the shar files

ONE =	README Makefile Makeshar ansi.c basic.c bind.c buffer.c dg10.c

TWO =	displa.c dolock.c egapc.c eval.c exec.c

THREE =	file.c fileio.c hp110.c hp150.c input.c io.c

FOUR =	isearc.c line.c lock.c uehelp uecomp uelink

FIVE =	main.c random.c

SIX =	region.c search.c spawn.c st520.c

SEVEN =	tcap.c termio.c tipc.c vmsvt.c vt52.c window.c word.c

EIGHT =	bug.h ctype.h ebind.h edef.h efunc.h epath.h esearc.h \
	estruc.h evar.h io.h ll.h macros.h tcplib.h


all :	dist/ue1.sh dist/ue2.sh dist/ue3.sh dist/ue4.sh dist/ue5.sh \
	dist/ue6.sh dist/ue7.sh dist/ue8.sh

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

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

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

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

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

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

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

dist/ue8.sh : $(EIGHT)
	shar -b -v $(EIGHT) >dist/ue8.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	"estruc.h"
#include	"edef.h"

#if	ANSI

#if	AMIGA
#define NROW	23			/* Screen size. 		*/
#define NCOL	77			/* Edit if you want to. 	*/
#else
#define NROW	34			/* Screen size. 		*/
#define NCOL	80			/* Edit if you want to. 	*/
#endif

#if	CRAY
#define NPAUSE	10
#else
#define NPAUSE	100			/* # times thru update to pause */
#endif

#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 */
#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('[');
	ansiparm(color+30);
	ttputc('m');
	cfcolor = color;
}

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

int color;	/* color to set */

{
	if (color == cbcolor)
		return;
	ttputc(ESC);
	ttputc('[');
	ansiparm(color+40);
	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);
}

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) & ! CRAY
	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



#if	CRAY
/* write a row of text, no flushing, no saving of cursor location */
ansiputs(row, s)
int	row ;
char	*s ;	/* string */
{
int	i, last ;

/* see how many chars at tail of s are whitespace */
	for ( i=NCOL-1; i>=0; i-- )
		if ( s[i]!=' ' && s[i]!='\t' && s[i]!=NULL ) break ;
	last = i ;

/* put cursor to beginning of line */
	ttputc(ESC);
	ttputc('[');
	ansiparm(row+1);
	ttputc(';');
	ansiparm(1);
	ttputc('H');

/* output the text.  Use eeol if it helps */
	if ( NCOL-last < 5 )
		for ( i=0; i<NCOL; i++ ) ttputc(s[i]) ;
	else {
		for ( i=0; i<=last; i++ ) ttputc(s[i]) ;
		ttputc('\033') ;
		ttputc('[') ;
		ttputc('K') ;
	}
}
#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	"estruc.h"
#include	"edef.h"

#if	MEGAMAX & ST520
overlay "basic"
#endif

/*
 * 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 forwwards 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	CRAY
/* 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	"estruc.h"
#include	"edef.h"
#include	"epath.h"

#if	MEGAMAX & ST520
overlay "bind"
#endif

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

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

{
	register int c; 	/* command character to describe */
	register char *ptr;	/* string pointer to scan output strings */
	register KEYTAB *ktp;	/* pointer into the command table */
	register int found;	/* matched command flag */
	register NBIND *nptr;	/* pointer into the name binding table */
	char outseq[80];	/* output buffer for command sequence */

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

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

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

	/* and dump it out */
	ptr = &outseq[0];
	while (*ptr)
		TTputc(*ptr++);
	TTputc(' ');		/* space it out */

	/* find the right ->function */
	ktp = &keytab[0];
	found = FALSE;
	while (ktp->k_fp != NULL) {
		if (ktp->k_code == c) {
			found = TRUE;
			break;
		}
		++ktp;
	}

	if (!found)
		strcpy(outseq,"Not Bound");
	else {
		/* match it against the name binding table */
		nptr = &names[0];
		strcpy(outseq,"[Bad binding]");
		while (nptr->n_func != NULL) {
			if (nptr->n_func == ktp->k_fp) {
				strcpy(outseq, nptr->n_name);
				break;
			}
			++nptr;
		}
	}

	/* output the command sequence */
	ptr = &outseq[0];
	while (*ptr)
		TTputc(*ptr++);
}

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;

#if	CRAY		/* Tell which Sun fkey it is */
	if ( c & SPEC ) {
		c &= ~SPEC ;	/* strip off SPEC prefix */
		if ( c == 0 ) strcpy( seq, "<mouse>" ) ;
		else if (c >= '1' && c <= '9') sprintf(seq, "<f%d>", c-'1'+1) ;
		else if (c >= 33 && c <= 41) sprintf(seq, "<F%d>", c-' ') ;
		else if (c >= 17 && c <= 25) sprintf(seq, "^<f%d>", c-16) ;
		else if (c >= 'a' && c <= 'o') sprintf(seq, "<r%d>", c-'a'+1) ;
		else if (c >= 'A' && c <= 'O') sprintf(seq, "<R%d>", c-'A'+1) ;
		else if (c >= 1 && c <= 15) sprintf(seq, "^<r%d>", c) ;
		else strcpy(seq, "<unknown>") ;
		return ;
	}
#endif

	/* 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++ = '^';
	}

#if	CRAY		/* cray meta prefix is 256 */
	c = c & 127 ;
#else
	c = c & 255;	/* strip the prefixes */
#endif

	/* and output the final sequence */

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

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);
}

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);
}

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

bindtokey(f, n)

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

{
	register int c; 	/* command key to bind */
	register (*kfunc)();	/* ptr to the requexted function to bind to */
	register char *ptr;	/* ptr to dump out input key string */
	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	CRAY
	sends("\\(I)") ;	/* immediate mode on */
	kfunc = getname();
	sends("\\(i)") ;	/* immediate mode off */
#else
	kfunc = getname();
#endif

	if (kfunc == NULL) {
		mlwrite("[No such function]");
		return(FALSE);
	}
	TTputc(' ');		/* space it out */
	TTflush();

	/* 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 */
	ptr = &outseq[0];
	while (*ptr)
		TTputc(*ptr++);

	/* 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 */
	register char *ptr;	/* ptr to dump out input key string */
	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 */
	ptr = &outseq[0];
	while (*ptr)
		TTputc(*ptr++);

        /* 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
{
	register WINDOW *wp;	/* scnaning 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

getckey(mflag)	/* get a command key sequence from the keyboard */

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

{
	register int c; 	/* character fetched */
	register char *tp;	/* pointer into the token */
	char tok[NSTRING];	/* command incoming */

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

		/* parse it up */
		tp = &tok[0];
		c = 0;

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

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

		/* control-x as well... */
		if (*tp == '^' && *(tp+1) == 'X') {
			c |= CTLX;
			tp += 2;
		}

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

		/* make sure we are not lower case */
		if (c >= 'a' && c <= 'z')
			c -= 32;

		/* the final sequence... */
		c |= *tp;

		return(c);
	}

	/* 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	((MSDOS | AMIGA) & (LATTICE | AZTEC | MSC)) | V7 | USG | BSD

	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 */
			status = ffropen(fspec);
			if (status == FIOSUC) {
				ffclose();
				return(fspec);
			}
		}
	}

	/* 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 */
			status = ffropen(fspec);
			if (status == 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 */
		status = ffropen(fspec);
		if (status == FIOSUC) {
			ffclose();
			return(fspec);
		}
	}

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

@//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	"estruc.h"
#include	"edef.h"

#if	MEGAMAX & ST520
overlay "buffer"
#endif

/*
 * 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 */

{
	register BUFFER *bp;

	bp = curbp->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;
	}
	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	CRAY
	report_modes() ;
#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	CRAY
	report_modes() ;
#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".
 */
listbuffers(f, n)
{
	register WINDOW *wp;
	register BUFFER *bp;
	register int	s;

	if ((s=makelist()) != 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).
 */
makelist()
{
	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) {
		if ((bp->b_flag&BFINVS) != 0) { /* Skip magic ones.	*/
			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 - dg10.c
sed 's/^@//' > "dg10.c" <<'@//E*O*F dg10.c//'

/*
 * The routines in this file provide support for the Data General Model 10
 * Microcomputer.
 */

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

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

#if	DG10

#define NROW	24			/* Screen size. 		*/
#define NCOL	80			/* Edit if you want to. 	*/
#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	30			/* DG10 ESC character.		*/

extern	int	ttopen();		/* Forward references.		*/
extern	int	ttgetc();
extern	int	ttputc();
extern	int	ttflush();
extern	int	ttclose();
extern	int	dg10kopen();
extern	int	dg10kclose();
extern	int	dg10move();
extern	int	dg10eeol();
extern	int	dg10eeop();
extern	int	dg10beep();
extern	int	dg10open();
extern	int	dg10rev();
extern	int	dg10close();
extern	int	dg10cres();

#if	COLOR
extern	int	dg10fcol();
extern	int	dg10bcol();

int	cfcolor = -1;		/* current forground color */
int	cbcolor = -1;		/* current background color */
int	ctrans[] = {		/* emacs -> DG10 color translation table */
	0, 4, 2, 6, 1, 5, 3, 7};
#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,
	dg10open,
	dg10close,
	dg10kopen,
	dg10kclose,
	ttgetc,
	ttputc,
	ttflush,
	dg10move,
	dg10eeol,
	dg10eeop,
	dg10beep,
	dg10rev,
	dg10cres
#if	COLOR
	, dg10fcol,
	dg10bcol
#endif
};

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

int color;	/* color to set */

{
	if (color == cfcolor)
		return;
	ttputc(ESC);
	ttputc(0101);
	ttputc(ctrans[color]);
	cfcolor = color;
}

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

int color;	/* color to set */

{
	if (color == cbcolor)
		return;
	ttputc(ESC);
	ttputc(0102);
	ttputc(ctrans[color]);
	cbcolor = color;
}
#endif

dg10move(row, col)
{
	ttputc(16);
	ttputc(col);
	ttputc(row);
}

dg10eeol()
{
	ttputc(11);
}

dg10eeop()
{
#if	COLOR
	dg10fcol(gfcolor);
	dg10bcol(gbcolor);
#endif
	ttputc(ESC);
	ttputc(0106);
	ttputc(0106);
}

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

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

{
#if	COLOR
	if (state == TRUE) {
		dg10fcol(0);
		dg10bcol(7);
	}
#else
	ttputc(ESC);
	ttputc(state ? 0104: 0105);
#endif
}

dg10cres()	/* change screen resolution */

{
	return(TRUE);
}

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

dg10open()
{
	strcpy(sres, "NORMAL");
	revexist = TRUE;
	ttopen();
}

dg10close()

{
#if	COLOR
	dg10fcol(7);
	dg10bcol(0);
#endif
	ttclose();
}

dg10kopen()

{
}

dg10kclose()

{
}

#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
dg10hello()
{
}
#endif
@//E*O*F dg10.c//
chmod u=rw,g=r,o=r dg10.c
 
exit 0
