
# 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 Wed Jan 13 14:06:36 PST 1988
# Contents:  file.c fileio.c hp110.c hp150.c input.c io.c
 
echo x - file.c
sed 's/^@//' > "file.c" <<'@//E*O*F file.c//'
/*	FILE.C:   for MicroEMACS

	The routines in this file handle the reading, writing
	and lookup of disk files.  All of details about the
	reading and writing of the disk are in "fileio.c".

*/

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

#if	MEGAMAX
overlay "file"
#endif

/*
 * Read a file into the current
 * buffer. This is really easy; all you do it
 * find the name of the file, and call the standard
 * "read a file into the current buffer" code.
 * Bound to "C-X C-R".
 */
fileread(f, n)
{
	register int	s;
	char fname[NFILEN];

        if (restflag)           /* don't allow this command if restricted */
		return(resterr());
	if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
		return(s);
	return(readin(fname, TRUE));
}

/*
 * Insert a file into the current
 * buffer. This is really easy; all you do it
 * find the name of the file, and call the standard
 * "insert a file into the current buffer" code.
 * Bound to "C-X C-I".
 */
insfile(f, n)
{
	register int	s;
	char fname[NFILEN];

        if (restflag)           /* don't allow this command if restricted */
		return(resterr());
        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
	if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
		return(s);
	return(ifile(fname));
}

/*
 * Select a file for editing.
 * Look around to see if you can find the
 * fine in another buffer; if you can find it
 * just switch to the buffer. If you cannot find
 * the file, create a new buffer, read in the
 * text, and switch to the new buffer.
 * Bound to C-X C-F.
 */
filefind(f, n)
{
	char fname[NFILEN];	/* file user wishes to find */
	register int s; 	/* status return */

        if (restflag)           /* don't allow this command if restricted */
		return(resterr());
	if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
		return(s);
	return(getfile(fname, TRUE));
}

viewfile(f, n)	/* visit a file in VIEW mode */
{
	char fname[NFILEN];	/* file user wishes to find */
	register int s; 	/* status return */
	register WINDOW *wp;	/* scan for windows that need updating */

        if (restflag)           /* don't allow this command if restricted */
		return(resterr());
	if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
		return (s);
	s = getfile(fname, FALSE);
	if (s) {	/* if we succeed, put it in view mode */
		curwp->w_bufp->b_mode |= MDVIEW;

		/* scan through and update mode lines of all windows */
		wp = wheadp;
		while (wp != NULL) {
			wp->w_flag |= WFMODE;
			wp = wp->w_wndp;
		}
	}
	return(s);
}

#if	CRYPT
resetkey()	/* reset the encryption key if needed */

{
	register int s; /* return status */

	/* turn off the encryption flag */
	cryptflag = FALSE;

	/* if we are in crypt mode */
	if (curbp->b_mode & MDCRYPT) {
		if (curbp->b_key[0] == 0) {
			s = setkey(FALSE, 0);
			if (s != TRUE)
				return(s);
		}

		/* let others know... */
		cryptflag = TRUE;

		/* and set up the key to be used! */
		/* de-encrypt it */
		crypt((char *)NULL, 0);
		crypt(curbp->b_key, strlen(curbp->b_key));

		/* re-encrypt it...seeding it to start */
		crypt((char *)NULL, 0);
		crypt(curbp->b_key, strlen(curbp->b_key));
	}

	return(TRUE);
}
#endif

getfile(fname, lockfl)

char fname[];		/* file name to find */
int lockfl;		/* check the file for locks? */

{
	register BUFFER *bp;
	register LINE	*lp;
	register int	i;
	register int	s;
	char bname[NBUFN];	/* buffer name to put file */

	for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
		if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
			swbuffer(bp);
			lp = curwp->w_dotp;
			i = curwp->w_ntrows/2;
			while (i-- && lback(lp)!=curbp->b_linep)
				lp = lback(lp);
			curwp->w_linep = lp;
			curwp->w_flag |= WFMODE|WFHARD;
			mlwrite("[Old buffer]");
			return (TRUE);
		}
	}
	makename(bname, fname); 		/* New buffer name.	*/
	while ((bp=bfind(bname, FALSE, 0)) != NULL) {
		s = mlreply("Buffer name: ", bname, NBUFN);
		if (s == ABORT) 		/* ^G to just quit	*/
			return (s);
		if (s == FALSE) {		/* CR to clobber it	*/
			makename(bname, fname);
			break;
		}
	}
	if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
		mlwrite("Cannot create buffer");
		return (FALSE);
	}
	if (--curbp->b_nwnd == 0) {		/* Undisplay.		*/
		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 to it.	*/
	curwp->w_bufp = bp;
	curbp->b_nwnd++;
	return(readin(fname, lockfl));		/* Read it in.		*/
}

/*
 * Read file "fname" into the current
 * buffer, blowing away any text found there. Called
 * by both the read and find commands. Return the final
 * status of the read. Also called by the mainline,
 * to read in a file specified on the command line as
 * an argument. If the filename ends in a ".c", CMODE is
 * set for the current buffer.
 */
readin(fname, lockfl)

char	fname[];	/* name of file to read */
int	lockfl; 	/* check for file locks? */

{
	register LINE	*lp1;
	register LINE	*lp2;
	register int	i;
	register WINDOW *wp;
	register BUFFER *bp;
	register int	s;
	register int	nbytes;
	register int	nline;
	register char	*sptr;		/* pointer into filename string */
	int		lflag;		/* any lines longer than allowed? */
	char		line[NLINE];

#if	FILOCK
	if (lockfl && lockchk(fname) == ABORT)
		return(ABORT);
#endif
#if	CRYPT
	s = resetkey();
	if (s != TRUE)
		return(s);
#endif
	bp = curbp;				/* Cheap.		*/
	if ((s=bclear(bp)) != TRUE)		/* Might be old.	*/
		return (s);
	bp->b_flag &= ~(BFINVS|BFCHG);
#if	ACMODE
	if (strlen(fname) > 1) {		/* check if a 'C' file	*/
		sptr = fname + strlen(fname) - 2;
		if (*sptr == '.' &&
		   (*(sptr + 1) == 'c' || *(sptr + 1) == 'h'))
			bp->b_mode |= MDCMOD;
	}
#endif

	strcpy(bp->b_fname, fname);

	/* turn off ALL keyboard translation in case we get a dos error */
	TTkclose();

	if ((s=ffropen(fname)) == FIOERR)	/* Hard file open.	*/
		goto out;
	if (s == FIOFNF) {			/* File not found.	*/
		mlwrite("[New file]");
		goto out;
	}
	mlwrite("[Reading file]");
	nline = 0;
	lflag = FALSE;
	while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG
	    || s == FIOFUN) {
		if (s == FIOLNG) {
			lflag = TRUE;
			--nline;
		}
		nbytes = strlen(line);
		if ((lp1=lalloc(nbytes)) == NULL) {
			s = FIOERR;		/*, anIeep message on the	*/
			break;			/* display.		*/
		}
		lp2 = lback(curbp->b_linep);
		lp2->l_fp = lp1;
		lp1->l_fp = curbp->b_linep;
		lp1->l_bp = lp2;
		curbp->b_linep->l_bp = lp1;
		for (i=0; i<nbytes; ++i)
			lputc(lp1, i, line[i]);
		++nline;
		if (s == FIOFUN)
			break;
	}
	ffclose();				/* Ignore errors.	*/
	strcpy(line, "[");
	if (lflag)
		strcat(line, "Long lines wrapped, ");
	if (s == FIOFUN)
		strcat(line, "Funny line at EOF, ");
        if (s == FIOEOF || s == FIOFUN) {        /* Don't zap message!	 */
		sprintf(&line[strlen(line)], "Read %d line", nline);
		if (nline > 1)
			strcat(line, "s");
		strcat(line, "]");
	}
	if (s != FIOERR)
		mlwrite(line);

out:
	TTkopen();	/* open the keyboard again */
	for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
		if (wp->w_bufp == curbp) {
			wp->w_linep = lforw(curbp->b_linep);
			wp->w_dotp  = lforw(curbp->b_linep);
			wp->w_doto  = 0;
			wp->w_markp = NULL;
			wp->w_marko = 0;
			wp->w_flag |= WFMODE|WFHARD;
		}
	}
	if (s == FIOERR || s == FIOFNF) 	/* False if error.	*/
		return(FALSE);
#if	CRAY
	report_modes() ;
#endif
	return (TRUE);
}

/*
 * Take a file name, and from it
 * fabricate a buffer name. This routine knows
 * about the syntax of file names on the target system.
 * I suppose that this information could be put in
 * a better place than a line of code.
 */
makename(bname, fname)
char	bname[];
char	fname[];
{
	register char	*cp1;
	register char	*cp2;

	cp1 = &fname[0];
	while (*cp1 != 0)
		++cp1;

#if	AMIGA
	while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
		--cp1;
#endif
#if	VMS
	while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
		--cp1;
#endif
#if	CPM
	while (cp1!=&fname[0] && cp1[-1]!=':')
		--cp1;
#endif
#if	MSDOS
	while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
		--cp1;
#endif
#if	FINDER
	while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
		--cp1;
#endif
#if	V7 | USG | BSD
	while (cp1!=&fname[0] && cp1[-1]!='/')
		--cp1;
#endif
	cp2 = &bname[0];
	while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
		*cp2++ = *cp1++;
	*cp2 = 0;
}

/*
 * Ask for a file name, and write the
 * contents of the current buffer to that file.
 * Update the remembered file name and clear the
 * buffer changed flag. This handling of file names
 * is different from the earlier versions, and
 * is more compatable with Gosling EMACS than
 * with ITS EMACS. Bound to "C-X C-W".
 */
filewrite(f, n)
{
	register WINDOW *wp;
	register int	s;
	char		fname[NFILEN];

        if (restflag)           /* don't allow this command if restricted */
		return(resterr());
	if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
		return (s);
	if ((s=writeout(fname)) == TRUE) {
		strcpy(curbp->b_fname, fname);
		curbp->b_flag &= ~BFCHG;
		wp = wheadp;			/* Update mode lines.	*/
		while (wp != NULL) {
			if (wp->w_bufp == curbp)
				wp->w_flag |= WFMODE;
			wp = wp->w_wndp;
		}
	}
	return (s);
}

/*
 * Save the contents of the current
 * buffer in its associatd file. No nothing
 * if nothing has changed (this may be a bug, not a
 * feature). Error if there is no remembered file
 * name for the buffer. Bound to "C-X C-S". May
 * get called by "C-Z".
 */
filesave(f, n)
{
	register WINDOW *wp;
	register int	s;

        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
	if ((curbp->b_flag&BFCHG) == 0) 	/* Return, no changes.	*/
		return (TRUE);
	if (curbp->b_fname[0] == 0) {		/* Must have a name.	*/
		mlwrite("No file name");
		return (FALSE);
	}
	if ((s=writeout(curbp->b_fname)) == TRUE) {
		curbp->b_flag &= ~BFCHG;
		wp = wheadp;			/* Update mode lines.	*/
		while (wp != NULL) {
			if (wp->w_bufp == curbp)
				wp->w_flag |= WFMODE;
			wp = wp->w_wndp;
		}
	}
	return (s);
}

/*
 * This function performs the details of file
 * writing. Uses the file management routines in the
 * "fileio.c" package. The number of lines written is
 * displayed. Sadly, it looks inside a LINE; provide
 * a macro for this. Most of the grief is error
 * checking of some sort.
 */
writeout(fn)
char	*fn;
{
	register int	s;
	register LINE	*lp;
	register int	nline;

#if	CRYPT
	s = resetkey();
	if (s != TRUE)
		return(s);
#endif
	/* turn off ALL keyboard translation in case we get a dos error */
	TTkclose();

	if ((s=ffwopen(fn)) != FIOSUC) {	/* Open writes message. */
		TTkopen();
		return (FALSE);
	}
	mlwrite("[Writing..]"); 		/* tell us were writing */
	lp = lforw(curbp->b_linep);		/* First line.		*/
	nline = 0;				/* Number of lines.	*/
	while (lp != curbp->b_linep) {
		if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
			break;
		++nline;
		lp = lforw(lp);
	}
	if (s == FIOSUC) {			/* No write error.	*/
		s = ffclose();
		if (s == FIOSUC) {		/* No close error.	*/
			if (nline == 1)
				mlwrite("[Wrote 1 line]");
			else
				mlwrite("[Wrote %d lines]", nline);
		}
	} else					/* Ignore close error	*/
		ffclose();			/* if a write error.	*/
	TTkopen();
	if (s != FIOSUC)			/* Some sort of error.	*/
		return (FALSE);
	return (TRUE);
}

/*
 * The command allows the user
 * to modify the file name associated with
 * the current buffer. It is like the "f" command
 * in UNIX "ed". The operation is simple; just zap
 * the name in the BUFFER structure, and mark the windows
 * as needing an update. You can type a blank line at the
 * prompt if you wish.
 */
filename(f, n)
{
	register WINDOW *wp;
	register int	s;
	char		fname[NFILEN];

        if (restflag)           /* don't allow this command if restricted */
		return(resterr());
	if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
		return (s);
	if (s == FALSE)
		strcpy(curbp->b_fname, "");
	else
		strcpy(curbp->b_fname, fname);
	wp = wheadp;				/* Update mode lines.	*/
	while (wp != NULL) {
		if (wp->w_bufp == curbp)
			wp->w_flag |= WFMODE;
		wp = wp->w_wndp;
	}
	curbp->b_mode &= ~MDVIEW;	/* no longer read only mode */
	return (TRUE);
}

/*
 * Insert file "fname" into the current
 * buffer, Called by insert file command. Return the final
 * status of the read.
 */
ifile(fname)
char	fname[];
{
	register LINE	*lp0;
	register LINE	*lp1;
	register LINE	*lp2;
	register int	i;
	register BUFFER *bp;
	register int	s;
	register int	nbytes;
	register int	nline;
	int		lflag;		/* any lines longer than allowed? */
	char		line[NLINE];

	bp = curbp;				/* Cheap.		*/
	bp->b_flag |= BFCHG;			/* we have changed	*/
	bp->b_flag &= ~BFINVS;			/* and are not temporary*/
	if ((s=ffropen(fname)) == FIOERR)	/* Hard file open.	*/
		goto out;
	if (s == FIOFNF) {			/* File not found.	*/
		mlwrite("[No such file]");
		return(FALSE);
	}
	mlwrite("[Inserting file]");

#if	CRYPT
	s = resetkey();
	if (s != TRUE)
		return(s);
#endif
	/* back up a line and save the mark here */
	curwp->w_dotp = lback(curwp->w_dotp);
	curwp->w_doto = 0;
	curwp->w_markp = curwp->w_dotp;
	curwp->w_marko = 0;

	nline = 0;
	lflag = FALSE;
	while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG
	    || s == FIOFUN) {
		if (s == FIOLNG) {
			lflag = TRUE;
			--nline;
		}
		nbytes = strlen(line);
		if ((lp1=lalloc(nbytes)) == NULL) {
			s = FIOERR;		/*,Ieep message on the	*/
			break;			/* display.		*/
		}
		lp0 = curwp->w_dotp;	/* line previous to insert */
		lp2 = lp0->l_fp;	/* line after insert */

		/* re-link new line between lp0 and lp2 */
		lp2->l_bp = lp1;
		lp0->l_fp = lp1;
		lp1->l_bp = lp0;
		lp1->l_fp = lp2;

		/* and advance and write out the current line */
		curwp->w_dotp = lp1;
		for (i=0; i<nbytes; ++i)
			lputc(lp1, i, line[i]);
		++nline;
		if (s == FIOFUN)
			break;
	}
	ffclose();				/* Ignore errors.	*/
	curwp->w_markp = lforw(curwp->w_markp);
	strcpy(line, "[");
	if (lflag)
		strcat(line, "Long lines wrapped, ");
	if (s == FIOFUN)
		strcat(line, "Funny line at EOF, ");
        if (s == FIOEOF || s == FIOFUN) {        /* Don't zap message!	 */
		sprintf(&line[strlen(line)], "Inserted %d line", nline);
		if (nline > 1)
			strcat(line, "s");
		strcat(line, "]");
	}
	if (s != FIOERR)
		mlwrite(line);
out:
	/* advance to the next line and mark the window for changes */
	curwp->w_dotp = lforw(curwp->w_dotp);
	curwp->w_flag |= WFHARD | WFMODE;

	/* copy window parameters back to the buffer structure */
	curbp->b_dotp = curwp->w_dotp;
	curbp->b_doto = curwp->w_doto;
	curbp->b_markp = curwp->w_markp;
	curbp->b_marko = curwp->w_marko;

	if (s == FIOERR)			/* False if error.	*/
		return (FALSE);
	return (TRUE);
}
@//E*O*F file.c//
chmod u=rw,g=r,o=r file.c
 
echo x - fileio.c
sed 's/^@//' > "fileio.c" <<'@//E*O*F fileio.c//'
/*
 * The routines in this file read and write ASCII files from the disk. All of
 * the knowledge about files are here. A better message writing scheme should
 * be used.
 *    The Cray version uses double buffered io routines, written by Steve
 * Dorner.
 */
#include	<stdio.h>
#include	"estruc.h"
#include	"edef.h"

#if	CRAY
#include	"io.h"
#undef	ferror
#undef	EOF
#define EOF	'\034'		/* wierd CTSS EOF, also uses ^D */
#define FILE	CFILE
#define fopen	cfopen
#define fclose	cfclose
#define fputc	cfputc
#define fgetc	cfgetc
#define ferror	cferror
#endif

#if	MEGAMAX
overlay "fileio"
#endif

FILE	*ffp;				/* File pointer, all functions. */

/*
 * Open a file for reading.
 */
ffropen(fn)
char	*fn;
{
	if ((ffp=fopen(fn, "r")) == NULL)
		return (FIOFNF);
	return (FIOSUC);
}

/*
 * Open a file for writing. Return TRUE if all is well, and FALSE on error
 * (cannot create).
 */
ffwopen(fn)
char	*fn;
{
#if	VMS
	register int	fd;

	if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0
	|| (ffp=fdopen(fd, "w")) == NULL) {
#else
	if ((ffp=fopen(fn, "w")) == NULL) {
#endif
		mlwrite("Cannot open file for writing");
		return (FIOERR);
	}
	return (FIOSUC);
}

/*
 * Close a file. Should look at the status in all systems.
 */
ffclose()
{
#if	MSDOS & CTRLZ
	fputc(26, ffp); 	/* add a ^Z at the end of the file */
#endif
	
#if	V7 | USG | BSD | (MSDOS & (LATTICE | MSC))
	if (fclose(ffp) != FALSE) {
		mlwrite("Error closing file");
		return(FIOERR);
	}
	return(FIOSUC);
#else
	fclose(ffp);
	return (FIOSUC);
#endif
}

/*
 * Write a line to the already opened file. The "buf" points to the buffer,
 * and the "nbuf" is its length, less the free newline. Return the status.
 * Check only at the newline.
 */
ffputline(buf, nbuf)
char	buf[];
{
	register int	i;
#if	CRYPT
	char c; 	/* character to translate */

	if (cryptflag) {
		for (i = 0; i < nbuf; ++i) {
			c = buf[i] & 0xff;
			crypt(&c, 1);
			fputc(c, ffp);
		}
	} else
		for (i = 0; i < nbuf; ++i)
			fputc(buf[i]&0xFF, ffp);
#else
	for (i = 0; i < nbuf; ++i)
		fputc(buf[i]&0xFF, ffp);
#endif

#if	ST520
	fputc('\r', ffp);
#endif	      
	fputc('\n', ffp);

	if (ferror(ffp)) {
		mlwrite("Write I/O error");
		return (FIOERR);
	}

	return (FIOSUC);
}

/*
 * Read a line from a file, and store the bytes in the supplied buffer. The
 * "nbuf" is the length of the buffer. Complain about long lines and lines
 * at the end of the file that don't have a newline present. Check for I/O
 * errors too. Return status.
 */
ffgetline(buf, nbuf)
register char	buf[];
{
	register int	c;
	register int	i;

	i = 0;

#if	CRAY
	while ((c = fgetc(ffp)) != EOF && c != '\n') {
#else
	while ((c = fgetc(ffp)) != EOF && c != '\n') {
#endif
		if (i >= nbuf-2) {
			buf[nbuf - 2] = c;	/* store last char read */
			buf[nbuf - 1] = 0;	/* and terminate it */
#if	CRAY
			mlwrite("Binary file?  File not read successfully") ;
			return(FIOERR) ;
#else
			mlwrite("File has long line");
#endif
#if	CRYPT
			if (cryptflag)
				crypt(buf, strlen(buf));
#endif
			return (FIOLNG);
		}
		buf[i++] = c;
	}

#if	ST520
	if(buf[i-1] == '\r')
		i--;
#endif
#if	CRAY
	if (c == EOF ) {
#else
	if (c == EOF ) {
#endif
		if (ferror(ffp)) {
			mlwrite("File read error");
			return (FIOERR);
		}

		if (i != 0) {
			buf[i] = 0;
			return(FIOFUN);
		}

		return (FIOEOF);
	}

	buf[i] = 0;
#if	CRYPT
	if (cryptflag)
		crypt(buf, strlen(buf));
#endif
	return (FIOSUC);
}

@//E*O*F fileio.c//
chmod u=rw,g=r,o=r fileio.c
 
echo x - hp110.c
sed 's/^@//' > "hp110.c" <<'@//E*O*F hp110.c//'

/*
 *	HP110:	Hewlett Packard 110 Screen Driver
 */

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

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

#if	HP110

#define NROW	16			/* 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	0x1B			/* ESC character.		*/

extern	int	ttopen();		/* Forward references.		*/
extern	int	ttgetc();
extern	int	ttputc();
extern	int	ttflush();
extern	int	ttclose();
extern	int	h110move();
extern	int	h110eeol();
extern	int	h110eeop();
extern	int	h110beep();
extern	int	h110open();
extern	int	h110rev();
extern	int	h110cres();
extern	int	h110close();
extern	int	h110kopen();
extern	int	h110kclose();

#if	COLOR
extern	int	h110fcol();
extern	int	h110bcol();

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,
	h110open,
	h110close,
	h110kopen,
	h110kclose,
	ttgetc,
	ttputc,
	ttflush,
	h110move,
	h110eeol,
	h110eeop,
	h110beep,
	h110rev,
	h110cres
#if	COLOR
	, h110fcol,
	h110bcol
#endif
};

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

int color;	/* color to set */

{
	if (color == cfcolor)
		return;
	ttputc(ESC);
	ttputc('[');
	h110parm(color+30);
	ttputc('m');
	cfcolor = color;
}

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

int color;	/* color to set */

{
	if (color == cbcolor)
		return;
	ttputc(ESC);
	ttputc('[');
	h110parm(color+40);
	ttputc('m');
	cbcolor = color;
}
#endif

h110move(row, col)
{
	ttputc(ESC);
	ttputc('[');
	h110parm(row+1);
	ttputc(';');
	h110parm(col+1);
	ttputc('H');
}

h110eeol()
{
	ttputc(ESC);
	ttputc('[');
	ttputc('0');
	ttputc('K');
}

h110eeop()
{
#if	COLOR
	h110fcol(gfcolor);
	h110bcol(gbcolor);
#endif
	ttputc(ESC);
	ttputc('[');
	ttputc('0');
	ttputc('J');
}

h110rev(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;
		h110fcol(ftmp);
		h110bcol(btmp);
	}
#endif
}

h110cres()	/* change screen resolution */

{
	return(TRUE);
}

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

h110parm(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');
}

h110open()
{
	strcpy(sres, "15LINE");
	revexist = TRUE;
	ttopen();
}

h110close()

{
#if	COLOR
	h110fcol(7);
	h110bcol(0);
#endif
	ttclose();
}

h110kopen()

{
}

h110kclose()

{
}

#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
h110hello()
{
}
#endif
@//E*O*F hp110.c//
chmod u=rw,g=r,o=r hp110.c
 
echo x - hp150.c
sed 's/^@//' > "hp150.c" <<'@//E*O*F hp150.c//'

/*
 * The routines in this file provide support for HP150 screens
 * and routines to access the Keyboard through KEYCODE mode.
 * It compiles into nothing if not an HP150 screen device.
 * added by Daniel Lawrence
 */

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

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

#if	HP150

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

extern	int	openhp();		/* Forward references.		*/
extern	int	ttgetc();
extern	int	ttputc();
extern	int	ttflush();
extern	int	hpflush();
extern	int	closehp();
extern	int	hp15kopen();
extern	int	hp15kclose();
extern	int	hp15move();
extern	int	hp15eeol();
extern	int	hp15eeop();
extern	int	hp15beep();
extern	int	gethpkey();
extern	int	hp15rev();
extern	int	hp15cres();
#if	COLOR
extern	int	hp15fcol();
extern	int	hp15bcol();
#endif

/* weird to ascii translation table */

char trans[][2] = {
	0x24,	9,	/* tab */
	0x25,	13,	/* ret */
	0x27,	8,	/* backspace */
	0x30,	48,	/* zero */
	0x31,	49,	/* one */
	0x32,	50,	/* two */
	0x33,	51,	/* three */
	0x34,	52,	/* four */
	0x35,	53,	/* five */
	0x36,	54,	/* six */
	0x37,	55,	/* seven */
	0x38,	56,	/* eight */
	0x39,	57,	/* nine */
	0x50,	13,	/* enter */
	0x54,	27,	/* break -> ESC */
	0x55,	27,	/* esc */
	0x58,	24,	/* stop -> ^X */
	0x70,	45,	/* N-minus */
	0x71,	42,	/* N-asterisk */
	0x72,	43,	/* N-plus */
	0x73,	47,	/* N-slash */
	0x74,	44,	/* N-comma */
	0x75,	13,	/* N-enter */
	0x76,	9,	/* N-tab */
	0x77,	46	/* N-period */
};

#define NTRANS	sizeof(trans) / 2

union REGS r;		/* register set for bios and dos (AGIOS) calls */
int capslock = 0;	/* caps lock flag */

/*
 * Standard terminal interface dispatch table. Most of the fields point into
 * "termio" code.
 */
TERM	term	= {
	NROW-1,
	NROW-1,
	NCOL,
	NCOL,
	MARGIN,
	SCRSIZ,
	NPAUSE,
	openhp,
	closehp,
	hp15kopen,
	hp15kclose,
	gethpkey,
	ttputc,
	hpflush,
	hp15move,
	hp15eeol,
	hp15eeop,
	hp15beep,
	hp15rev,
	hp15cres
#if	COLOR
	, hp15fcol,
	hp15bcol
#endif
};

hp15move(row, col)
{
	ttputc(ESC);
	ttputc('&');
	ttputc('a');
	hp15parm(col);
	ttputc('c');
	hp15parm(row);
	ttputc('R');
}

hpflush()

{

}

hp15eeol()
{
	ttputc(ESC);
	ttputc('K');
}

hp15eeop()
{
	ttputc(ESC);
	ttputc('J');
}

hp15rev(status) 	/* change the reverse video status */

int status;	/* TRUE = on, FALSE = off */

{
	ttputc(ESC);
	ttputc('&');
	ttputc('d');
	ttputc((status != FALSE) ? 'B': '@');
}

hp15cres()	/* change screen resolution */

{
	return(TRUE);
}

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

hp15parm(n)
register int	n;
{
	register int	q;

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

#if	COLOR
hp15fcol()      /* we really can't do colors here, so just ignore it */
{
}

hp15bcol()      /* we really can't do colors here, so just ignore it */
{
}
#endif

gethpkey()	/* get a key from the HP keyboard while in keycode mode */

{
	static int keepflag = 0;	/* kept ahead char flag */
	static int keepchar = 0;	/* kept ehead flag */
	int c;
	int devid;			/* device ID */
	int ctype;			/* type of character gotten */
	int shiftb;			/* state of shift keys */
	int i;
	
	/* if we are in an extended char sequence, finish it */
	if (keepflag != 0) {
		keepflag = 0;
		return(keepchar);
	}

	/* grab the next 4 char sequence */
next:	shiftb = ttgetc();
	devid = ttgetc();
	c = ttgetc();
	ttgetc();		/* skip null byte */
	
	/* make sure we are from the keyboard */
	if (devid != 192)
		goto next;

	/* if normal ascii, return it */
	if ((shiftb & 0x80) == 0) {
		if (capslock && c >= 'a' && c <= 'z')
			c -= 32;
		return(c);
	}

	/* check specifically for the caps lock key */
	if (c == 0x56) {
		capslock = ~capslock;
		goto next;
	}

	/* check to see if it needs translation */
	for (i=0; i < NTRANS; i++)
		if (trans[i][0] == c)
			return((int)trans[i][1]);

	/* other wise, shove it in the keep char and return the leadin code */
	keepchar = c;
	keepflag = 1;
	return(0);
}

openhp()		/* open the HP150 screen for input */

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

closehp()		/* close the HP150 screen for input */

{
}

hp15kopen()		/* open the HP150 keyboard for input */

{
	/* define key charectoristics with AGIOS call (0, 40) */
	defkey();

	/* Turn on RAW mode with MSDOS call 44h */
	rawon();

	/* Turn off Control-C checking	MS-DOS 33h */
	ckeyoff();

	/* Turn on keycode mode with AGIOS call (0,43) */
	keycon();

	/* display the application softkey labels */
	dsplbls();
}

hp15kclose()		/* close the HP150 keyboard for input */

{
	/* define key charectoristics with AGIOS call (0, 40) */
	undefkey();
	
	/* Turn off RAW mode with MSDOS call 44h */
	rawoff();

	/* Turn on Control-C checking  MS-DOS 33h */
	ckeyon();

	/* Turn off keycode mode with AGIOS call (0,43) */
	keycoff();
}

rawon() 	/* put the HP150 keyboard into RAW mode */

{
	/* get the IO control info */

	r.x.ax = 0x4400;	/* IO ctrl get device information */
	r.x.bx = 0x0001;	/* File handle; 1 for console */
	intdos(&r, &r); 	/* go fer it */

	r.h.dh = 0;		/* clear high byte for put */
	r.h.dl |= 0x20; 	/* set raw bit */

	/* and put it back */

	r.x.ax = 0x4401;	/* IO ctrl put device information */
	r.x.bx = 0x0001;	/* File handle; 1 for console */
	intdos(&r, &r); 	/* go fer it */
}

rawoff()	/* put the HP150 keyboard into COOKED mode */

{
	/* get the IO control info */

	r.x.ax = 0x4400;	/* IO ctrl get device information */
	r.x.bx = 0x0001;	/* File handle; 1 for console */
	intdos(&r, &r); 	/* go fer it */

	r.h.dh = 0;		/* clear high byte for put */
	r.h.dl &= 0xdf; 	/* set raw bit */

	/* and put it back */

	r.x.ax = 0x4401;	/* IO ctrl put device information */
	r.x.bx = 0x0001;	/* File handle; 1 for console */
	intdos(&r, &r); 	/* go fer it */
}


ckeyoff()	/* turn control-C trapping off */

{
	r.h.ah = 0x33;	/* ctrl-break check */
	r.h.al = 1;	/* set the state of the ctrl-break check */
	r.h.dl = 0;	/* turn it off */
	intdos(&r, &r);
}

ckeyon()	/* turn control-C trapping on */

{
	r.h.ah = 0x33;	/* ctrl-break check */
	r.h.al = 1;	/* set the state of the ctrl-break check */
	r.h.dl = 1;	/* turn it on */
	intdos(&r, &r);
}

agios(buf, len) /* perform an AGIOS call */

char *buf;	/* sequence of bytes in command */
int len;	/* length of command in bytes */

{
	r.x.ax = 0x4403;	/* I/O ctrl write */
	r.x.bx = 1;		/* console handle */
	r.x.cx = len;		/* buffer length */
	r.x.dx = (unsigned)buf; /* buffer address */
	return(intdos(&r, &r)); /* do it */
}

keycon()	/* turn keycode mode on */

{
	static char cmd[] = {43, 0, 1};

	return(agios(&cmd[0], 3));
}

keycoff()	/* turn keycode mode off */

{
	static char cmd[] = {43, 0, 0};

	return(agios(&cmd[0], 3));
}

defkey()	/* change all special keys to intercept mode */

{
	static char cmd[] = {40, 0, 2, 0, 0xfe, 0};

	return(agios(&cmd[0], 6));
}

undefkey()	/* change all special keys to intercept mode */

{
	static char cmd[] = {40, 0, 0, 0, 0xfe, 0};

	return(agios(&cmd[0], 6));
}

dsplbls()	/* display the application softkey labels on the screen */

{
	static char cmd[] = {11, 0};

	return(agios(&cmd[0], 2));
}

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

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

{
	register int status;	/* return status */
	register int i; 	/* loop index */
	char lbl[17];	/* returned label contents */
	/* AGIOS command buffer */
	static char cmd[] = {8, 0, 1, 0, 7, 7, 7, 7, 10, 0, 10, 0};
	/*		     code  key#  ptr to      top    bottom
					 label string  attribute */
	union { 	/* union to cast ptr into AGIOS arg string */
		char *ptr;	/* pointer to arg string */
		char cstr[4];
	} ptru;

	/* must have a numeric argument */
	if (f == FALSE) {
		mlwrite("%Need function key number");
		return(FALSE);
	}

	/* and it must be a legal key number */
	if (n < 1 || n > 8) {
		mlwrite("%Function key number out of range");
		return(FALSE);
	}

	/* get the string to send */
	status = mlreply("Label contents: ", &lbl[0], 17);
	if (status != TRUE)
		return(status);

	/* pad the label out */
	for (i=0; i < 17; i++) {
		if (lbl[i] == 0)
			break;
	}
	for (; i < 16; i++)
		lbl[i] = ' ';
	lbl[16] = 0;

	/* set up the parameters */
	cmd[2] = n;			/* function key number */
	ptru.ptr = &lbl[0];		/* set up pointer to label string */
force:	cmd[4] = ptru.cstr[0];
	cmd[5] = ptru.cstr[1];
	cmd[6] = ptru.cstr[2];
	cmd[7] = ptru.cstr[3];

	/* and send it out */
	agios(&cmd[0], 12);
	return(TRUE);
}
#endif
#else

h15hello()

{
}
#endif
@//E*O*F hp150.c//
chmod u=rw,g=r,o=r hp150.c
 
echo x - input.c
sed 's/^@//' > "input.c" <<'@//E*O*F input.c//'
/*	INPUT:	Various input routines for MicroEMACS 3.7
		written by Daniel Lawrence
		5/9/86						*/

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

#if	MEGAMAX
overlay "input"
#endif

/*
 * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
 * ABORT. The ABORT status is returned if the user bumps out of the question
 * with a ^G. Used any time a confirmation is required.
 */

mlyesno(prompt)

char *prompt;

{
	char c; 		/* input character */
	char buf[NPAT]; 	/* prompt to user */

	for (;;) {
		/* build and prompt the user */
		strcpy(buf, prompt);
		strcat(buf, " [y/n]? ");
#if	CRAY
		sends("\\(I)") ;	/* immediate mode on */
		mlwrite(buf);
		c = tgetc();		/* get the responce */
		sends("\\(i)") ;	/* immediate mode off */
#else
		mlwrite(buf);
		c = tgetc();		/* get the responce */
#endif

		if (c == ectoc(abortc)) 	/* Bail out! */
			return(ABORT);

		if (c=='y' || c=='Y')
			return(TRUE);

		if (c=='n' || c=='N')
			return(FALSE);
	}
}

/*
 * Write a prompt into the message line, then read back a response. Keep
 * track of the physical position of the cursor. If we are in a keyboard
 * macro throw the prompt away, and return the remembered response. This
 * lets macros run at full speed. The reply is always terminated by a carriage
 * return. Handle erase, kill, and abort keys.
 */

mlreply(prompt, buf, nbuf)
    char *prompt;
    char *buf;
{
	return(nextarg(prompt, buf, nbuf, ctoec('\n')));
}

mlreplyt(prompt, buf, nbuf, eolchar)

char *prompt;
char *buf;
int eolchar;

{
	return(nextarg(prompt, buf, nbuf, eolchar));
}

/*	ectoc:	expanded character to character
		colapse the CTRL and SPEC flags back into an ascii code   */

ectoc(c)

int c;

{
	if (c & CTRL)
		c = c & ~(CTRL | 0x40);
	if (c & SPEC)
		c= c & 255;
	return(c);
}

/*	ctoec:	character to extended character
		pull out the CTRL and SPEC prefixes (if possible)	*/

ctoec(c)

int c;

{
	if (c>=0x00 && c<=0x1F)
		c = CTRL | (c+'@');
	return (c);
}
 
/* get a command name from the command line. Command completion means
   that pressing a <SPACE> will attempt to complete an unfinished command
   name if it is unique.
*/

int (*getname())()

{
	register int cpos;	/* current column on screen output */
	register int c;
	register char *sp;	/* pointer to string for output */
	register NBIND *ffp;	/* first ptr to entry in name binding table */
	register NBIND *cffp;	/* current ptr to entry in name binding table */
	register NBIND *lffp;	/* last ptr to entry in name binding table */
	char buf[NSTRING];	/* buffer to hold tentative command name */
	int (*fncmatch())();

	/* starting at the beginning of the string buffer */
	cpos = 0;

	/* if we are executing a command line get the next arg and match it */
	if (clexec) {
		if (macarg(buf) != TRUE)
			return(FALSE);
		return(fncmatch(&buf[0]));
	}

	/* build a name string from the keyboard */
	while (TRUE) {
		c = tgetc();

		/* if we are at the end, just match it */
		if (c == 0x0d) {
			buf[cpos] = 0;

			/* and match it off */
			return(fncmatch(&buf[0]));

		} else if (c == ectoc(abortc)) {	/* Bell, abort */
			ctrlg(FALSE, 0);
			TTflush();
			return( (int (*)()) NULL);

		} else if (c == 0x7F || c == 0x08) {	/* rubout/erase */
			if (cpos != 0) {
				TTputc('\b');
				TTputc(' ');
				TTputc('\b');
				--ttcol;
				--cpos;
				TTflush();
			}

		} else if (c == 0x15) { /* C-U, kill */
			while (cpos != 0) {
				TTputc('\b');
				TTputc(' ');
				TTputc('\b');
				--cpos;
				--ttcol;
			}

			TTflush();

		} else if (c == ' ') {
/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
	/* attempt a completion */
	buf[cpos] = 0;		/* terminate it for us */
	ffp = &names[0];	/* scan for matches */
	while (ffp->n_func != NULL) {
		if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
			/* a possible match! More than one? */
			if ((ffp + 1)->n_func == NULL ||
			   (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
				/* no...we match, print it */
				sp = ffp->n_name + cpos;
				while (*sp)
					TTputc(*sp++);
				TTflush();
				return(ffp->n_func);
			} else {
/* << << << << << << << << << << << << << << << << << */
	/* try for a partial match against the list */

	/* first scan down until we no longer match the current input */
	lffp = (ffp + 1);
	while ((lffp+1)->n_func != NULL) {
		if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
			break;
		++lffp;
	}

	/* and now, attempt to partial complete the string, char at a time */
	while (TRUE) {
		/* add the next char in */
		buf[cpos] = ffp->n_name[cpos];

		/* scan through the candidates */
		cffp = ffp + 1;
		while (cffp <= lffp) {
			if (cffp->n_name[cpos] != buf[cpos])
				goto onward;
			++cffp;
		}

		/* add the character */
		TTputc(buf[cpos++]);
	}
/* << << << << << << << << << << << << << << << << << */
			}
		}
		++ffp;
	}

	/* no match.....beep and onward */
	TTbeep();
onward:;
	TTflush();
/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
		} else {
			if (cpos < NSTRING-1 && c > ' ') {
				buf[cpos++] = c;
				TTputc(c);
			}

			++ttcol;
			TTflush();
		}
	}
}

/*	tgetc:	Get a key from the terminal driver, resolve any keyboard
		macro action					*/

int tgetc()

{
	int c;	/* fetched character */

	/* if we are playing a keyboard macro back, */
	if (kbdmode == PLAY) {

		/* if there is some left... */
		if (kbdptr < kbdend)
			return((int)*kbdptr++);

		/* at the end of last repitition? */
		if (--kbdrep < 1) {
			kbdmode = STOP;
#if	VISMAC == 0
			/* force a screen update after all is done */
			update(FALSE);
#endif
		} else {

			/* reset the macro to the begining for the next rep */
			kbdptr = &kbdm[0];
			return((int)*kbdptr++);
		}
	}

	/* fetch a character from the terminal driver */
	c = TTgetc();

	/* save it if we need to */
	if (kbdmode == RECORD) {
		*kbdptr++ = c;
		kbdend = kbdptr;

                /* don't overrun the buffer */
		if (kbdptr == &kbdm[NKBDM - 1]) {
			kbdmode = STOP;
			TTbeep();
		}
	}
	/* and finally give the char back */
	return(c);
}

/*	GET1KEY:	Get one keystroke. The only prefixs legal here
			are the SPEC and CTRL prefixes.
								*/

get1key()

{
	int    c;
#if	AMIGA
	int	d;
#endif

	/* get a keystroke */
	c = tgetc();

#if	MSDOS
	if (c == 0) {				/* Apply SPEC prefix	*/
		c = tgetc();
		if (c>=0x00 && c<=0x1F) 	/* control key? */
			c = CTRL | (c+'@');
		return(SPEC | c);
	}
#endif

#if	AMIGA
	/* apply SPEC prefix */
	if ((unsigned)c == 155) {
		c = tgetc();

		/* first try to see if it is a cursor key */
		if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
			return(SPEC | c);

		/* next, a 2 char sequence */
		d = tgetc();
		if (d == '~')
			return(SPEC | c);

		/* decode a 3 char sequence */
		c = d + 32;
		/* if a shifted function key, eat the tilde */
		if (d >= '0' && d <= '9')
			d = tgetc();
		return(SPEC | c);
	}
#endif

#if  WANGPC
	if (c == 0x1F) {			/* Apply SPEC prefix	*/
		c = tgetc();
		return(SPEC | c);
	}
#endif

	if (c>=0x00 && c<=0x1F) 		/* C0 control -> C-	*/
		c = CTRL | (c+'@');
	return (c);
}

/*	GETCMD: Get a command from the keyboard. Process all applicable
		prefix keys
							*/
getcmd()

{
	int c;		/* fetched keystroke */

	/* get initial character */
	c = get1key();

	/* process META prefix */
	if (c == metac) {
		c = get1key();
		if (islower(c)) 	/* Force to upper */
			c ^= DIFCASE;
		if (c>=0x00 && c<=0x1F) 	/* control key */
			c = CTRL | (c+'@');
		return(META | c);
	}

	/* process CTLX prefix */
	if (c == ctlxc) {
		c = get1key();
		if (c>='a' && c<='z')		/* Force to upper */
			c -= 0x20;
		if (c>=0x00 && c<=0x1F) 	/* control key */
			c = CTRL | (c+'@');
		return(CTLX | c);
	}

	/* otherwise, just return it */
	return(c);
}

/*	A more generalized prompt/reply function allowing the caller
	to specify the proper terminator. If the terminator is not
	a return ('\n') it will echo as "<NL>"
							*/
getstring(prompt, buf, nbuf, eolchar)

char *prompt;
char *buf;
int eolchar;

{
	register int cpos;	/* current character position in string */
	register int c;
	register int quotef;	/* are we quoting the next char? */

	cpos = 0;
	quotef = FALSE;

	/* prompt the user for the input string */
	mlwrite(prompt);

	for (;;) {
		/* get a character from the user */
		c = get1key();

		/* If it is a <ret>, change it to a <NL> */
		if (c == (CTRL | 0x4d))
			c = CTRL | 0x40 | '\n';

		/* if they hit the line terminate, wrap it up */
		if (c == eolchar && quotef == FALSE) {
			buf[cpos++] = 0;

			/* clear the message line */
			mlwrite("");
			TTflush();

			/* if we default the buffer, return FALSE */
			if (buf[0] == 0)
				return(FALSE);

			return(TRUE);
		}

		/* change from command form back to character form */
		c = ectoc(c);

#if	CRAY	/* make sure cursor is where we think it is before output */
		TTmove(ttrow,ttcol) ;
#endif

		if (c == ectoc(abortc) && quotef == FALSE) {
			/* Abort the input? */
			ctrlg(FALSE, 0);
			TTflush();
			return(ABORT);
		} else if ((c==0x7F || c==0x08) && quotef==FALSE) {
			/* rubout/erase */
			if (cpos != 0) {
				outstring("\b \b");
				--ttcol;

				if (buf[--cpos] < 0x20) {
					outstring("\b \b");
					--ttcol;
				}

				if (buf[cpos] == '\n') {
					outstring("\b\b  \b\b");
					ttcol -= 2;
				}
				TTflush();
			}

		} else if (c == 0x15 && quotef == FALSE) {
			/* C-U, kill */
			while (cpos != 0) {
				outstring("\b \b");
				--ttcol;

				if (buf[--cpos] < 0x20) {
					outstring("\b \b");
					--ttcol;
				}
			}
			TTflush();

		} else if (c == quotec && quotef == FALSE) {
			quotef = TRUE;
		} else {
			quotef = FALSE;
			if (cpos < nbuf-1) {
				buf[cpos++] = c;

				if ((c < ' ') && (c != '\n')) {
					outstring("^");
					++ttcol;
					c ^= 0x40;
				}

				if (c != '\n')
					TTputc(c);
				else {	/* put out <NL> for <ret> */
					outstring("<NL>");
					ttcol += 3;
				}
				++ttcol;
				TTflush();
			}
		}
	}
}

outstring(s)	/* output a string of characters */

char *s;	/* string to output */

{
	while (*s)
		TTputc(*s++);
}
@//E*O*F input.c//
chmod u=rw,g=r,o=r input.c
 
echo x - io.c
sed 's/^@//' > "io.c" <<'@//E*O*F io.c//'
#include <stdio.h>
#include "bug.h"
char *malloc();
#define New(y)	((y *)malloc(sizeof(y)))
#include "io.h"
long FirstSize=BLKSIZ;
static char *CodeName();

unsigned long beta[13];

int millidiff()
{
    static int last=0;
    int diff;
    int this;

    this = milliclk();
    diff = this-last;
    last = this;
    return(diff);
}
int milliclk()
{
    long curtime;

    asm(" a1 b02\n");		/* fool code generator */
    asm(" s1 rt\n");
    asm(" curtime,a1 s1\n");
    return((long)((float)curtime*8.5e-6));
}
int GetS1()
{
    long theval;

    asm(" theval,a1 s1\n");
    return((int)theval);
}
/***********************************************************************
* make a string lowercase
***********************************************************************/
MakeLower(theString)
char *theString;
{
    for (;*theString;theString++)
	if (*theString >= 'A' && *theString<='Z') *theString += 'a'-'A';
}
/***********************************************************************
************************************************************************
* Double-buffered file io stuff
************************************************************************
***********************************************************************/
#define MAXIOC 16
static int IOCUsed[MAXIOC];
/***********************************************************************
* open a ctss file.
***********************************************************************/
CFILE *cfopen(theName,theMode)
char *theName;
char *theMode;
{
    return(cfuopen(NULL,theName,theMode));
}
/***********************************************************************
* open a ctss file under an arbitrary user number
***********************************************************************/
CFILE *cfuopen(theUser,theName,theMode)
char *theName;
char *theMode;
int theUser;
{
    CFILE *theFile;
    int theResult;
    int madeIt;

    switch (*theMode)
    {
	case 'a':
	    theResult = Append(theName,theUser,beta,&madeIt);
	    break;
	case 'w':
	    theResult = MakeFile(theName,theUser,beta);
	    break;
	case 'r':
	    theResult = RawOpen(theName,theMode,theUser,beta);
	    break;
    }

    if (theResult>0)
	return(NULL);		/* failure */

    theFile = New(CFILE);

    theFile->cfIOC = beta[4];
    theFile->cfSize = beta[5];
    theFile->cfSpot = (*theMode=='a' && !madeIt) ? theFile->cfSize : 0;
    theFile->cfPerm = beta[7];
    theFile->cfCurBuf = 0;
    theFile->cfBuffer[0].cfcState = CEMPTY;
    theFile->cfBuffer[1].cfcState = CEMPTY;
    theFile->cfMode = *theMode=='a' ? 'w' : *theMode;
    theFile->cfBinary = theMode[1]=='b';
    theFile->cfUser = theUser;
    theFile->cfErr = 0;
    strcpy(theFile->cfName,theName);
    if (*theMode=='r')
	FillCache(theFile);
    else
    {
	theFile->cfBuffer[0].cfcEnd = theFile->cfBuffer[0].cfcBuf;
	theFile->cfBuffer[1].cfcEnd = theFile->cfBuffer[1].cfcBuf;
    }

    return(theFile);
}
/***********************************************************************
* issue an open call
***********************************************************************/
int RawOpen(theName,theMode,theUser,beta)
unsigned long *beta;
char *theName;
char *theMode;
int theUser;
{
    beta[1] = theUser ? 0x301 : 0x300;

    strcpy(&beta[3],"        ");
    strncpy(&beta[3],theName,strlen(theName));

    beta[4] = AlloIOC();

    beta[7] = 0;

    beta[12] = theUser;

    syscall(&beta[1]);

    if (beta[2])
	FreeIOC(beta[4]);
    else if (*theMode=='r' && !(beta[7] & 2) ||
	     *theMode=='w' && !(beta[7] & 1))
    {
	/* no permission--close the file */
	FreeIOC(beta[4]);
	beta[1] = 0x400;
	beta[5] = 0;
	beta[6] = 0;
	syscall(&beta[1]);
	return(1);
    }

    return(beta[2]);
}
/***********************************************************************
* Allocate an ioc
***********************************************************************/
int AlloIOC()
{
    int theIOC;

    for (theIOC=0;theIOC<MAXIOC;theIOC++)
	if (!IOCUsed[theIOC])
	{
	    IOCUsed[theIOC] = 1;
	    return(theIOC);
	}

    return(-1);	/* failure */
}
/***********************************************************************
* Free an ioc
***********************************************************************/
int FreeIOC(theIOC)
int theIOC;
{
    if (theIOC>=0 && theIOC<MAXIOC)
	IOCUsed[theIOC] = 0;
}
/***********************************************************************
* fill a file's read-ahead buffer
***********************************************************************/
FillCache(theFile)
CFILE *theFile;
{
    CCache *theCache;

    /* is there anything more to read? */
    if (theFile->cfSize > theFile->cfSpot && 
	theFile->cfBuffer[0].cfcState!=CERROR &&
	theFile->cfBuffer[1].cfcState!=CERROR)
    {
	theCache = theFile->cfBuffer[theFile->cfCurBuf].cfcState==CEMPTY ?
			&theFile->cfBuffer[theFile->cfCurBuf] :
			&theFile->cfBuffer[1-theFile->cfCurBuf];
	if (theCache->cfcState==CEMPTY)
	{
	    theCache->cfcState = CPEND;
	    FillOneCache(theFile,theCache);
	}
    }
}
/***********************************************************************
* fill a particular cache from a file
***********************************************************************/
FillOneCache(theFile,theCache)
CFILE *theFile;
CCache *theCache;
{
    theCache->cfcDIO.cdSys = 0x5000;
    theCache->cfcDIO.cdIOC = theFile->cfIOC;
    theCache->cfcDIO.cdBuffer = (unsigned long *) theCache->cfcBuf;
    theCache->cfcDIO.cdOffset = theFile->cfSpot;
    theCache->cfcDIO.cdWords = CIOBSIZ/8 > theFile->cfSize-theFile->cfSpot ?
	theFile->cfSize-theFile->cfSpot : CIOBSIZ/8;
    theCache->cfcDIO.cdInterrupt = NULL;

    syscall(&theCache->cfcDIO);

    theFile->cfSpot += theCache->cfcDIO.cdWords;
    theCache->cfcState = CPEND;
}
/***********************************************************************
* wait for IO to complete on a file
***********************************************************************/
BufferWait(theFile)
CFILE *theFile;
{
    CCache *theCache;

    beta[1] = 0x4001;
    beta[3] = theFile->cfIOC;

    syscall(&beta[1]);

    /* IO has now completed on one of the caches */
    theCache = theFile->cfBuffer[theFile->cfCurBuf].cfcState == CPEND ?
		    &theFile->cfBuffer[theFile->cfCurBuf] :
		    &theFile->cfBuffer[1-theFile->cfCurBuf];

    if (theCache->cfcDIO.cdStat)
	theCache->cfcState=CERROR;
    else if (theFile->cfMode=='r')
    {
	theCache->cfcState=CFULL;
	theCache->cfcBegin = theCache->cfcBuf;
	theCache->cfcEnd = theCache->cfcBuf + theCache->cfcDIO.cdWords*8;
	FillCache(theFile);
    }
    else
    {
	theCache->cfcState=CEMPTY;
	theCache->cfcEnd = theCache->cfcBuf;
    }

    return(theCache->cfcState);
}
/***********************************************************************
* read a single character, decompressing blanks
***********************************************************************/
int cfdgetc(theFile)
CFILE *theFile;
{
    int c;
    static int spaces=0;

    if (spaces)
    {
	spaces--;
	return(' ');
    }

    c = cfgetc(theFile);
    if (c=='\033')
    {
	c = cfgetc(theFile);
	if (c>'0')
	{
	    spaces = c-'1';
	    return(' ');
	}
	else
	    return(c);
    }
    else
	return(c);
}
/***********************************************************************
* read a single character
***********************************************************************/
int cfgetc(theFile)
CFILE *theFile;
{
    char theChar;

    if (cfread(theFile,&theChar,1)!=1)
	return(-1);
    else
	return(theChar);
}
/***********************************************************************
* read a block of characters
***********************************************************************/
long cfread(theFile,theBuffer,theCount)
CFILE *theFile;
char *theBuffer;
long theCount;
{
    CCache *theCache;
    long charCount;
    long bytes;

    bytes = 0;
    if (theFile->cfErr) return(-1);
    do
    {
	theCache = &theFile->cfBuffer[theFile->cfCurBuf];

	if (theCache->cfcState==CPEND && BufferWait(theFile)!=CFULL)
	{
	    theFile->cfErr = CERROR;
	    return(-1);		/* read error */
	}

	if (theCache->cfcState!=CFULL)
	    return(bytes);		/* no more data */

	charCount = theCache->cfcEnd - theCache->cfcBegin;

	if (theCount >= charCount)
	{
	    memcpy(theBuffer,theCache->cfcBegin,charCount);
	    theBuffer += charCount;
	    theCount -= charCount;
	    theCache->cfcState=CEMPTY;
	    theFile->cfCurBuf = 1-theFile->cfCurBuf;
	    bytes += charCount;
	}
	else
	{
	    memcpy(theBuffer,theCache->cfcBegin,theCount);
	    theCache->cfcBegin += theCount;
	    bytes += theCount;
	    theCount = 0;
	}
    }
    while(theCount);

    return(bytes);
}
/***********************************************************************
* write a single character
***********************************************************************/
int cfputc(theChar,theFile)
char theChar;
CFILE *theFile;
{
    char buf[8];

    buf[0] = theChar;
    if (cfwrite(theFile,buf,1)!=1)
	return(-1);
    else
	return(theChar);
}
/***********************************************************************
* write some characters
***********************************************************************/
long cfwrite(theFile,theBuffer,theCount)
CFILE *theFile;
char *theBuffer;
long theCount;
{
    long bytes;
    int charCount;
    CCache *theCache;

    bytes = 0;
    if (theFile->cfErr) return(-1);
    do
    {
	theCache = &theFile->cfBuffer[theFile->cfCurBuf];

	if (theCache->cfcState==CPEND && BufferWait(theFile)!=CEMPTY)
	{
	    theFile->cfErr = CERROR;
	    return(bytes);			/* write error */
	}

	charCount = CIOBSIZ - (theCache->cfcEnd - theCache->cfcBuf);

	if (theCount >= charCount)
	{
	    memcpy(theCache->cfcEnd,theBuffer,charCount);
	    theBuffer += charCount;
	    theCount -= charCount;
	    theCache->cfcEnd += charCount;
	    theCache->cfcState=CFULL;
	    WriteOneCache(theFile,theCache);
	    theFile->cfCurBuf = 1-theFile->cfCurBuf;
	    bytes += charCount;
	}
	else
	{
	    memcpy(theCache->cfcEnd,theBuffer,theCount);
	    theCache->cfcEnd += theCount;
	    bytes += theCount;
	    theCount = 0;
	}
    }
    while(theCount);

    return(bytes);
}
/***********************************************************************
* write the contents of a cache to disk
***********************************************************************/
WriteOneCache(theFile,theCache)
CFILE *theFile;
CCache *theCache;
{
    int charCount;

    theCache->cfcDIO.cdSys = 0x6000;
    theCache->cfcDIO.cdIOC = theFile->cfIOC;
    theCache->cfcDIO.cdBuffer = (unsigned long *) theCache->cfcBuf;
    theCache->cfcDIO.cdOffset = theFile->cfSpot;
    charCount = theCache->cfcEnd - theCache->cfcBuf;
    for (;charCount%8;charCount++)
	*theCache->cfcEnd++ = '\0';

    theCache->cfcDIO.cdWords = charCount/8;
    theCache->cfcDIO.cdInterrupt = NULL;

    if (Bug(TIMING))
	printf("%d Writing %d chars.\n",millidiff(),theCache->cfcDIO.cdWords*8);
    theFile->cfSpot += theCache->cfcDIO.cdWords;
    theCache->cfcState = CPEND;

    while (theFile->cfSize < theFile->cfSpot)
    {
	theFile->cfSize += BLKSIZ;
	SetFileSize(theFile->cfName,theFile->cfSize);
    }

    syscall(&theCache->cfcDIO);

}
/***********************************************************************
* close a file
***********************************************************************/
cfclose(theFile)
CFILE *theFile;
{
    CCache *theCache;

    if (theFile->cfMode=='w')
    {
	if (!theFile->cfBinary) cfputc(0x1c,theFile);
	/* be sure we flush buffers */
	theCache = &theFile->cfBuffer[theFile->cfCurBuf];
	if (theCache->cfcState==CEMPTY && theCache->cfcEnd!=theCache->cfcBuf)
	    WriteOneCache(theFile,theCache);
	
	/* now wait */
	if (theFile->cfBuffer[0].cfcState == CPEND) BufferWait(theFile);
	if (theFile->cfBuffer[1].cfcState == CPEND) BufferWait(theFile);

	/* fix the file size */
	SetFileSize(theFile->cfName,theFile->cfSpot);
    }

    /* do the close */
    beta[1] = 0x400;
    beta[4] = theFile->cfIOC;
    beta[5] = theFile->cfPerm;
    beta[6] = 0;
    syscall(&beta[1]);

    FreeIOC(theFile->cfIOC);
    free(theFile);
}
/***********************************************************************
* append to a file
***********************************************************************/
Append(theName,theUser,beta,madeIt)
char *theName;
int theUser;
long *beta;
int *madeIt;
{
    int theResult;

    *madeIt = 0;
    if ((theResult=RawOpen(theName,"w",theUser,beta))!=1)
	return(theResult);
    else
    {
	*madeIt = 1;
	/* file does not exist.  make it. */
	return(MakeFile(theName,theUser,beta));
    }
}
/***********************************************************************
* create a file
***********************************************************************/
MakeFile(theName,theUser,beta)
char *theName;
int theUser;
long *beta;
{
    beta[1] = theUser==NULL ? 0x101 : 0x106;

    strcpy(&beta[3],"        ");
    strncpy(&beta[3],theName,strlen(theName));

    beta[4] = AlloIOC();

    beta[5] = FirstSize;

    beta[6] = 0;

    beta[7] = 3;

    beta[8] = 1;

    beta[9] = theUser;

    syscall(&beta[1]);

    if (beta[2])
	FreeIOC(beta[4]);

    return(beta[2]);
}
/***********************************************************************
* Set file size
***********************************************************************/
SetFileSize(theName,theSize)
char *theName;
long theSize;
{
    beta[1] = 0x702;
    PADCPY(&beta[3],theName);
    beta[4] = theSize;
    syscall(&beta[1]);
    if (beta[2])
	printf("File size %s %d failed %d.\n",theName,theSize,beta[2]);
}
/***********************************************************************
* interpret buffer codes
***********************************************************************/
static char *CodeName(theCode)
int theCode;
{
    switch (theCode)
    {
	case CEMPTY: return("EMPTY");
	case CFULL: return("FULL");
	case CPEND: return("PEND");
	case CERROR: return("ERROR");
	default: return("?");
    }
}
/***********************************************************************
* set initial file size
***********************************************************************/
setcfsize(theSize)
long theSize;
{
    if (theSize>=BLKSIZ)
	FirstSize = theSize;
}
/***********************************************************************
* give a file to another user
***********************************************************************/
char *GiveFile(theName,theUser)
char *theName;
int theUser;
{
    static char newName[9];
    int theLength;
    char *theSpot;

    strcpy(newName,theName);
    theLength = strlen(newName);
    theSpot=NULL;
    do
    {
	beta[1] = 0x500;
	strcpy(&beta[3],"        ");
	strncpy(&beta[3],newName,theLength);
	beta[4] = theUser;

	syscall(&beta[1]);
	if (!beta[2]) break;

	if (theSpot==NULL)
	{
	    if (theLength<6)
	    {
		theSpot = &newName[strlen(newName)];
		theLength += 2;
	    }
	    else
	    {
		theSpot = &newName[6];
		theLength = 8;
	    }
	    strcpy(theSpot,"$`");
	}
	theSpot[1]++;
    }
    while ((beta[2]==1 || beta[2]==2) && theSpot[1]<='z');

    return( beta[2] ? NULL : newName);
}
/***********************************************************************
* remove a file
***********************************************************************/
RemoveFile(theUser,theName)
int theUser;
char *theName;
{
    beta[1] = theUser==0 ? 0x200 : 0x201;
    PADCPY(&beta[3],theName);
    beta[4] = theUser;

    syscall(&beta[1]);

    return(beta[2]);
}
/***********************************************************************
* rename a file
***********************************************************************/
int RenameFile(theUser,theOld,theNew)
int theUser;
char *theOld;
char *theNew;
{
    beta[1] = theUser==0 ? 0x600 : 0x601;
    PADCPY(&beta[3],theOld);
    PADCPY(&beta[4],theNew);
    beta[5] = theUser;

    syscall(&beta[1]);

    return(beta[2]);
}
SetPriority(thePrior)
float thePrior;
{
    beta[1] = 0x2400;
    beta[3] = *((int *)&thePrior);
    beta[5] = 0;

    syscall(&beta[1]);
}
MoreTime(theTime)
long theTime;
{
    beta[1] = 0x2400;
    beta[3] = 0;
    beta[5] = theTime;

    syscall(&beta[1]);
}

@//E*O*F io.c//
chmod u=rw,g=r,o=r io.c
 
exit 0
