v08i023: The JOVE text editor, Part04/13

sources-request at mirror.UUCP sources-request at mirror.UUCP
Wed Feb 4 15:01:13 AEST 1987


Submitted by: seismo!rochester!jpayne (Jonathan Payne)
Mod.sources: Volume 8, Issue 23
Archive-name: jove/Part04

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "End of archive 4 (of 13)."
# Contents:  io.c iproc-pipes.c iproc-ptys.c iproc.c keymaps.txt rec.c
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'io.c'" '(20767 characters)'
if test -f 'io.c' ; then 
  echo shar: will not over-write existing file "'io.c'"
else
sed 's/^X//' >io.c <<'@//E*O*F io.c//'
X/************************************************************************
X * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
X * provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is *
X * included in all the files.                                           *
X ************************************************************************/
X
X#include "jove.h"
X#include "io.h"
X#include "termcap.h"
X
X#ifdef IPROCS
X#   include <signal.h>
X#endif
X
X#include <sys/stat.h>
X#include <sys/file.h>
X#include <errno.h>
X
X#ifndef W_OK
X#   define W_OK	2
X#   define F_OK	0
X#endif
X
Xlong	io_chars;		/* number of chars in this open_file */
Xint	io_lines;		/* number of lines in this open_file */
Xprivate int	tellall;	/* display file io info? */
X
X#ifdef VMUNIX
Xchar	iobuff[LBSIZE],
X	genbuf[LBSIZE],
X	linebuf[LBSIZE];
X#else
Xchar	*iobuff,
X	*genbuf,
X	*linebuf;
X#endif
X
X#ifdef BACKUPFILES
Xint	BkupOnWrite = 0;
X#endif
X
Xclose_file(fp)
XFile	*fp;
X{
X	if (fp) {
X		f_close(fp);
X		if (tellall != QUIET)
X			add_mess(" %d lines, %D characters.",
X				 io_lines,
X				 io_chars);
X	}
X}
X
X/* Write the region from line1/char1 to line2/char2 to FP.  This
X   never CLOSES the file since we don't know if we want to. */
X
Xint	EndWNewline = 1;
X
Xputreg(fp, line1, char1, line2, char2, makesure)
Xregister File	*fp;
XLine	*line1,
X	*line2;
X{
X	register int	c;
X	register char	*lp;
X
X	if (makesure)
X		(void) fixorder(&line1, &char1, &line2, &char2);
X	while (line1 != line2->l_next) {
X		lp = lcontents(line1) + char1;
X		if (line1 == line2) {
X			fputnchar(lp, (char2 - char1), fp);
X			io_chars += (char2 - char1);
X		} else while (c = *lp++) {
X			putc(c, fp);
X			io_chars++;
X		}
X		if (line1 != line2) {
X			io_lines++;
X			io_chars++;
X			putc('\n', fp);
X		}
X		line1 = line1->l_next;
X		char1 = 0;
X	}
X	flush(fp);
X}
X
Xread_file(file, is_insert)
Xchar	*file;
X{
X	Bufpos	save;
X	File	*fp;
X
X	if (!is_insert) {
X		curbuf->b_ntbf = 0;
X		set_ino(curbuf);
X	}
X	fp = open_file(file, iobuff, F_READ, !COMPLAIN, !QUIET);
X	if (fp == NIL) {
X		if (!is_insert && errno == ENOENT)
X			s_mess("(new file)");
X		else
X			s_mess(IOerr("open", file));
X		return;
X	}
X	DOTsave(&save);
X	dofread(fp);
X	SetDot(&save);
X	if (is_insert && io_chars > 0)
X		modify();
X	getDOT();
X	close_file(fp);
X}
X
Xdofread(fp)
Xregister File	*fp;
X{
X	char	end[LBSIZE];
X	int	xeof = 0;
X	Line	*savel = curline;
X	int	savec = curchar;
X	disk_line	f_getputl() ;
X
X	strcpy(end, linebuf + curchar);
X	xeof = f_gets(fp, linebuf + curchar, LBSIZE - curchar);
X	SavLine(curline, linebuf);
X	if (!xeof) do {
X		curline = listput(curbuf, curline);
X		xeof = f_getputl(curline, fp);
X	} while (!xeof);
X	getDOT();
X	linecopy(linebuf, (curchar = strlen(linebuf)), end);
X	SavLine(curline, linebuf);
X	IFixMarks(savel, savec, curline, curchar);
X}
X
XSaveFile()
X{
X	if (IsModified(curbuf)) {
X		if (curbuf->b_fname == 0)
X			WriteFile();
X		else {
X			filemunge(curbuf->b_fname);
X			chk_mtime(curbuf, curbuf->b_fname, "save");
X			file_write(curbuf->b_fname, 0);
X			unmodify();
X		}
X	} else
X		message("No changes need to be written.");
X}
X
Xchar	*HomeDir;	/* home directory */
Xint	HomeLen = -1;	/* length of home directory string */
X
X#ifndef CHDIR
X
Xchar *
Xpr_name(fname)
Xchar	*fname;
X{
X	if (fname == 0)
X		return 0;
X
X	if (strncmp(fname, HomeDir, HomeLen) == 0) {
X		static char	name_buf[100];
X
X		sprintf(name_buf, "~%s", fname + HomeLen);
X		return name_buf;
X	}
X
X	return fname;
X}
X
X#else
X
X#define NDIRS	5
X
Xprivate char	*DirStack[NDIRS] = {0};
Xprivate int	DirSP = 0;	/* Directory stack pointer */
X#define PWD	(DirStack[DirSP])
X
Xchar *
Xpwd()
X{
X	return PWD;
X}
X
Xchar *
Xpr_name(fname)
Xchar	*fname;
X{
X	int	n;
X
X	if (fname == 0)
X		return 0;
X	n = numcomp(fname, PWD);
X
X	if ((PWD[n] == 0) &&	/* Matched to end of PWD */
X	    (fname[n] == '/'))
X		return fname + n + 1;
X
X	if (strcmp(HomeDir, "/") != 0 && strncmp(fname, HomeDir, HomeLen) == 0) {
X		static char	name_buf[100];
X
X		sprintf(name_buf, "~%s", fname + HomeLen);
X		return name_buf;
X	}
X
X	return fname;	/* return entire path name */
X}
X
XChdir()
X{
X	char	dirbuf[FILESIZE];
X
X	(void) ask_file((char *) 0, PWD, dirbuf);
X	if (chdir(dirbuf) == -1) {
X		s_mess("cd: cannot change into %s.", dirbuf);
X		return;
X	}
X	UpdModLine++;
X	setCWD(dirbuf);
X}
X
X#ifndef JOB_CONTROL
Xchar *
Xgetwd()
X{
X	Buffer	*old = curbuf;
X	char	*ret_val;
X
X	SetBuf(do_select((Window *) 0, "pwd-output"));
X	curbuf->b_type = B_PROCESS;
X	(void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", (char *) 0);
X	ToFirst();
X	ret_val = sprint(linebuf);
X	SetBuf(old);
X	return ret_val;
X}
X#endif
X
XsetCWD(d)
Xchar	*d;
X{
X	if (PWD == 0)
X		PWD = malloc((unsigned) strlen(d) + 1);
X	else {
X		extern char	*ralloc();
X
X		PWD = ralloc(PWD, strlen(d) + 1);
X	}
X	strcpy(PWD, d);
X}
X
XgetCWD()
X{
X	char	*cwd = getenv("CWD");
X#ifdef JOB_CONTROL
X	extern char	*getwd();
X	char	pathname[FILESIZE];
X#endif
X
X	if (cwd == 0)
X#ifdef JOB_CONTROL
X		cwd = getwd(pathname);
X#else
X		cwd = getwd();
X#endif
X
X	setCWD(cwd);
X}	
X
XprDIRS()
X{
X	register int	i;
X
X	s_mess(": %f ");
X	for (i = DirSP; i >= 0; i--)
X		add_mess("%s ", pr_name(DirStack[i]));
X}
X
XprCWD()
X{
X	s_mess(": %f => \"%s\"", PWD);
X}
X
XPushd()
X{
X	char	*newdir,
X		dirbuf[FILESIZE];
X
X	newdir = ask_file((char *) 0, NullStr, dirbuf);
X	UpdModLine++;
X	if (*newdir == 0) {	/* Wants to swap top two entries */
X		char	*old_top;
X
X		if (DirSP == 0)
X			complain("pushd: no other directory.");
X		old_top = PWD;
X		DirStack[DirSP] = DirStack[DirSP - 1];
X		DirStack[DirSP - 1] = old_top;
X		(void) chdir(PWD);
X	} else {
X		if (chdir(dirbuf) == -1) {
X			s_mess("pushd: cannot change into %s.", dirbuf);
X			return;
X		}
X
X		if (DirSP + 1 >= NDIRS)
X			complain("pushd: full stack; max of %d pushes.", NDIRS);
X		DirSP++;
X		setCWD(dirbuf);
X	}
X	prDIRS();
X}
X
XPopd()
X{
X	if (DirSP == 0)
X		complain("popd: directory stack is empty.");
X	UpdModLine++;
X	free(PWD);
X	PWD = 0;
X	DirSP--;
X	(void) chdir(PWD);	/* If this doesn't work, we's in deep shit. */
X	prDIRS();
X}
X
Xprivate char *
Xdbackup(base, offset, c)
Xregister char	*base,
X		*offset,
X		c;
X{
X	while (offset > base && *--offset != c)
X		;
X	return offset;
X}
X
Xdfollow(file, into)
Xchar	*file,
X	*into;
X{
X	char	*dp,
X		*sp;
X
X	if (*file == '/') {		/* Absolute pathname */
X		strcpy(into, "/");
X		file++;
X	} else
X		strcpy(into, PWD);
X	dp = into + strlen(into);
X
X	sp = file;
X	do {
X		if (*file == 0)
X			break;
X		if (sp = index(file, '/'))
X			*sp = 0;
X		if (strcmp(file, ".") == 0)
X			;	/* So it will get to the end of the loop */
X		else if (strcmp(file, "..") == 0) {
X			*(dp = dbackup(into, dp, '/')) = 0;
X			if (dp == into)
X				strcpy(into, "/"), dp = into + 1;
X		} else {
X			if (into[strlen(into) - 1] != '/')
X				(void) strcat(into, "/");
X			(void) strcat(into, file);
X			dp += strlen(file);	/* stay at the end */
X		}
X		file = sp + 1;
X	} while (sp != 0);
X}
X
X#endif CHDIR
X
Xget_hdir(user, buf)
Xregister char	*user,
X		*buf;
X{
X	char	fbuf[LBSIZE],
X		pattern[100];
X	register int	u_len;
X	File	*fp;
X
X	u_len = strlen(user);
X	fp = open_file("/etc/passwd", fbuf, F_READ, COMPLAIN, QUIET);
X	sprintf(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user);
X	while (f_gets(fp, genbuf, LBSIZE) != EOF)
X		if ((strncmp(genbuf, user, u_len) == 0) &&
X		    (LookingAt(pattern, genbuf, 0))) {
X			putmatch(1, buf, FILESIZE);
X			close_file(fp);
X			return;
X		}
X	f_close(fp);
X	complain("[unknown user: %s]", user);
X}
X
XPathParse(name, intobuf)
Xchar	*name,
X	*intobuf;
X{
X	char	localbuf[FILESIZE];
X
X	intobuf[0] = localbuf[0] = '\0';
X	if (*name == '\0')
X		return;
X	if (*name == '~') {
X		if (name[1] == '/' || name[1] == '\0') {
X			strcpy(localbuf, HomeDir);
X			name++;
X		} else {
X			char	*uendp = index(name, '/'),
X				unamebuf[30];
X
X			if (uendp == 0)
X				uendp = name + strlen(name);
X			name = name + 1;
X			null_ncpy(unamebuf, name, uendp - name);
X			get_hdir(unamebuf, localbuf);
X			name = uendp;
X		}
X	} else if (*name == '\\')
X		name++;
X	(void) strcat(localbuf, name);
X#ifdef CHDIR
X	dfollow(localbuf, intobuf);
X#else
X	strcpy(intobuf, localbuf);
X#endif
X}
X
Xfilemunge(newname)
Xchar	*newname;
X{
X	struct stat	stbuf;
X
X	if (newname == 0)
X		return;
X	if (stat(newname, &stbuf))
X		return;
X	if ((stbuf.st_ino != curbuf->b_ino) &&
X	    ((stbuf.st_mode & S_IFMT) != S_IFCHR) &&
X	    (strcmp(newname, curbuf->b_fname) != 0)) {
X		rbell();
X		confirm("\"%s\" already exists; overwrite it? ", newname);
X	}
X}
X
XWrtReg()
X{
X	DoWriteReg(0);
X}
X
XAppReg()
X{
X	DoWriteReg(1);
X}
X
Xint	CreatMode = DFLT_MODE;
X
XDoWriteReg(app)
X{
X	char	fnamebuf[FILESIZE],
X		*fname;
X	Mark	*mp = CurMark();
X	File	*fp;
X
X	/* Won't get here if there isn't a Mark */
X	fname = ask_file((char *) 0, (char *) 0, fnamebuf);
X
X#ifdef BACKUPFILES
X	if (!app) {
X		filemunge(fname);
X
X		if (BkupOnWrite)
X			file_backup(fname);
X	}
X#else
X	if (!app)
X		filemunge(fname);
X#endif
X
X	fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
X	putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES);
X	close_file(fp);
X}
X
Xint	OkayBadChars = 0;
X
XWriteFile()
X{
X	char	*fname,
X		fnamebuf[FILESIZE];
X
X	fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
X	/* Don't allow bad characters when creating new files. */
X	if (!OkayBadChars && strcmp(curbuf->b_fname, fnamebuf) != 0) {
X		static char	*badchars = "!$^&*()~`{}\"'\\|<>? ";
X		register char	*cp = fnamebuf;
X		register int	c;
X
X		while (c = *cp++)
X			if (c < ' ' || c == '\177' || index(badchars, c))
X				complain("'%p': bad character in filename.", c);
X	}
X
X	chk_mtime(curbuf, fname, "write");
X	filemunge(fname);
X	curbuf->b_type = B_FILE;  	/* In case it wasn't before. */
X	setfname(curbuf, fname);
X	file_write(fname, 0);
X	unmodify();
X}
X
XFile *
Xopen_file(fname, buf, how, ifbad, loudness)
Xregister char	*fname;
Xchar	*buf;
Xregister int	how;
X{
X	register File	*fp;
X
X	io_chars = 0;
X	io_lines = 0;
X	tellall = loudness;
X
X	fp = f_open(fname, how, buf, LBSIZE);
X	if (fp == NIL) {
X                message(IOerr((how == F_READ) ? "open" : "create", fname));
X		if (ifbad == COMPLAIN)
X			complain((char *) 0);
X	} else {
X		int	readonly = FALSE;
X
X		if (access(fname, W_OK) == -1 && errno != ENOENT)
X			readonly = TRUE;
X							 
X		if (loudness != QUIET)
X			f_mess("\"%s\"%s", pr_name(fname),
X				   readonly ? " [Read only]" : NullStr);
X	}
X	return fp;
X}
X
X/* Check to see if the file has been modified since it was
X   last written.  If so, make sure they know what they're
X   doing.
X
X   I hate to use another stat(), but to use confirm we gotta
X   do this before we open the file. */
X
Xchk_mtime(thisbuf, fname, how)
XBuffer	*thisbuf;
Xchar	*fname,
X	*how;
X{
X	struct stat	stbuf;
X	Buffer	*b;
X    	char	*mesg = "Shall I go ahead and %s anyway? ";
X
X	if ((thisbuf->b_mtime != 0) &&		/* if we care ... */
X	    (b = file_exists(fname)) &&		/* we already have this file */
X	    (b == thisbuf) &&			/* and it's the current buffer */
X	    (stat(fname, &stbuf) != -1) &&	/* and we can stat it */
X	    (stbuf.st_mtime != b->b_mtime)) {	/* and there's trouble. */
X	    	rbell();
X		redisplay();	/* Ring that bell! */
X	    	TOstart("Warning", TRUE);
X	    	Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname));
X		Typeout("visited or saved.  Probably someone else is editing");
X		Typeout("your file at the same time.");
X	    	if (how) {
X			Typeout("");
X			Typeout("Type \"y\" if I should %s, anyway.", how);
X		    	f_mess(mesg, how);
X		}
X	    	TOstop();
X	    	if (how)
X		    	confirm(mesg, how);
X	}
X}
X
Xfile_write(fname, app)
Xchar	*fname;
X{
X	File	*fp;
X
X#ifdef BACKUPFILES
X	if (!app && BkupOnWrite)
X		file_backup(fname);
X#endif
X
X	fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
X
X	if (EndWNewline) {	/* Make sure file ends with a newLine */
X		Bufpos	save;
X
X		DOTsave(&save);
X		ToLast();
X		if (length(curline))	/* Not a blank Line */
X			LineInsert(1);
X		SetDot(&save);
X	}
X	putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO);
X	set_ino(curbuf);
X	close_file(fp);
X}
X
XReadFile()
X{
X	char	*fname,
X		fnamebuf[FILESIZE];
X
X	fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
X	chk_mtime(curbuf, fname, "read");
X
X	if (IsModified(curbuf)) {
X		char	*y_or_n;
X		int	c;
X
X		for (;;) {
X			rbell();
X			y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name);
X			c = Upper(*y_or_n);
X			if (c == 'Y' || c == 'N')
X				break;
X		}			
X		if (c == 'Y')
X			SaveFile();
X	}
X
X	unmodify();
X	initlist(curbuf);
X	setfname(curbuf, fname);
X	read_file(fname, 0);
X}
X
XInsFile()
X{
X	char	*fname,
X		fnamebuf[FILESIZE];
X
X	fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
X	read_file(fname, 1);
X}
X
X#include "temp.h"
X
Xint	DOLsave = 0;	/* Do Lsave flag.  If lines aren't being save
X			   when you think they should have been, this
X			   flag is probably not being set, or is being
X			   cleared before lsave() was called. */
X
Xprivate int	nleft,	/* number of good characters left in current block */
X		tmpfd = -1;
Xprivate disk_line	DFree = 1;
X			/* pointer to end of tmp file */
Xprivate char	*tfname;
X
Xtmpinit()
X{
X	char	buf[FILESIZE];
X
X	sprintf(buf, "%s/%s", TmpFilePath, d_tempfile);
X	tfname = copystr(buf);
X	tfname = mktemp(tfname);
X	(void) close(creat(tfname, 0600));
X	tmpfd = open(tfname, 2);
X	if (tmpfd == -1)
X		complain("Warning: cannot create tmp file!");
X}
X
Xtmpclose()
X{
X	(void) close(tmpfd);
X	tmpfd = -1;
X	(void) unlink(tfname);
X}
X
X/* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
X   long. */
X
Xint	Jr_Len;		/* Length of Just Read Line. */
Xprivate char	*getblock();
X
Xgetline(addr, buf)
Xdisk_line	addr;
Xregister char	*buf;
X{
X	register char	*bp,
X			*lp;
X
X	lp = buf;
X	bp = getblock(addr >> 1, READ);
X	while (*lp++ = *bp++)
X		;
X	Jr_Len = (lp - buf) - 1;
X}
X
X/* Put `buf' and return the disk address */
X
Xdisk_line
Xputline(buf)
Xchar	*buf;
X{
X	register char	*bp,
X			*lp;
X	register int	nl;
X	disk_line	free_ptr;
X
X	lp = buf;
X	free_ptr = DFree;
X	bp = getblock(free_ptr, WRITE);
X	nl = nleft;
X	free_ptr = blk_round(free_ptr);
X	while (*bp = *lp++) {
X		if (*bp++ == '\n') {
X			*--bp = 0;
X			break;
X		}
X		if (--nl == 0) {
X			free_ptr = forward_block(free_ptr);
X			DFree = free_ptr;
X			bp = getblock(free_ptr, WRITE);
X			lp = buf;	/* start over ... */
X			nl = nleft;
X		}
X	}
X	free_ptr = DFree;
X	DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE);
X	         /* (lp - buf) includes the null */
X	return (free_ptr << 1);
X}
X
X/* The theory is that critical section of code inside this procedure
X   will never cause a problem to occur.  Basically, we need to ensure
X   that two blocks are in memory at the same time, but I think that
X   this can never screw up. */
X
X#define lockblock(addr)
X#define unlockblock(addr)
X
Xdisk_line
Xf_getputl(line, fp)
XLine	*line;
Xregister File	*fp;
X{
X	register char	*bp;
X	register int	c,
X			nl,
X			max = LBSIZE;
X	disk_line	free_ptr;
X	char		*base;
X
X	free_ptr = DFree;
X	base = bp = getblock(free_ptr, WRITE);
X	nl = nleft;
X	free_ptr = blk_round(free_ptr);
X	while (--max > 0) {
X		c = getc(fp);
X		if (c == EOF || c == '\n')
X			break;
X		if (--nl == 0) {
X			char	*newbp;
X			int	nbytes;
X
X			lockblock(free_ptr);
X			DFree = free_ptr = forward_block(free_ptr);
X			nbytes = bp - base;
X			newbp = getblock(free_ptr, WRITE);
X			nl = nleft;
X			byte_copy(base, newbp, nbytes);
X			bp = newbp + nbytes;
X			base = newbp;
X			unlockblock(free_ptr);
X		}
X		*bp++ = c;
X	}
X	*bp++ = '\0';
X	free_ptr = DFree;
X	DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE);
X	line->l_dline = (free_ptr << 1);
X	if (max == 0) {
X		add_mess(" [Line too long]");
X		rbell();
X		return EOF;
X	}
X	if (c == EOF) {
X		if (--bp != base)
X			add_mess(" [Incomplete last line]");
X		return EOF;
X	}
X	io_lines++;
X	return NIL;
X}
X
Xtypedef struct block {
X	short	b_dirty,
X		b_bno;
X	char	b_buf[BUFSIZ];
X	struct block
X		*b_LRUnext,
X		*b_LRUprev,
X		*b_HASHnext;
X} Block;
X
X#define HASHSIZE	7	/* Primes work best (so I'm told) */
X#define B_HASH(bno)	(bno % HASHSIZE)
X
Xprivate Block	b_cache[NBUF],
X		*bht[HASHSIZE] = {0},		/* Block hash table */
X		*f_block = 0,
X		*l_block = 0;
Xprivate int	max_bno = -1,
X		NBlocks;
X
Xprivate int	(*blkio)();
X
Xprivate
Xreal_blkio(b, iofcn)
Xregister Block	*b;
Xregister int	(*iofcn)();
X{
X	(void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * BUFSIZ, 0);
X	if ((*iofcn)(tmpfd, b->b_buf, BUFSIZ) != BUFSIZ)
X		error("Tmp file %s error.", (iofcn == read) ? "read" : "write");
X}
X
Xprivate
Xfake_blkio(b, iofcn)
Xregister Block	*b;
Xregister int	(*iofcn)();
X{
X	tmpinit();
X	blkio = real_blkio;
X	real_blkio(b, iofcn);
X}
X
Xd_cache_init()
X{
X	register Block	*bp,	/* Block pointer */
X			**hp;	/* Hash pointer */
X	register short	bno;
X
X	for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) {
X		NBlocks++;
X		bp->b_dirty = 0;
X		bp->b_bno = bno;
X		if (l_block == 0)
X			l_block = bp;
X		bp->b_LRUprev = 0;
X		bp->b_LRUnext = f_block;
X		if (f_block != 0)
X			f_block->b_LRUprev = bp;
X		f_block = bp;
X
X		bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]);
X		*hp = bp;
X	}
X	blkio = fake_blkio;
X}
X
XSyncTmp()
X{
X#ifdef MSDOS
X	register int	bno = 0;
X	BLock *lookup();
X
X	for (bno = 0; bno <= max_bno; )
X		(*blkio)(lookup(bno++), write);
X#else
X	register Block	*b;
X
X	for (b = f_block; b != 0; b = b->b_LRUnext)
X		if (b->b_dirty) {
X			(*blkio)(b, write);
X			b->b_dirty = 0;
X		}
X#endif
X}
X
Xprivate Block *
Xlookup(bno)
Xregister short	bno;
X{
X	register Block	*bp;
X
X	for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext)
X		if (bp->b_bno == bno)
X			break;
X	return bp;
X}
X
Xprivate
XLRUunlink(b)
Xregister Block	*b;
X{
X	if (b->b_LRUprev == 0)
X		f_block = b->b_LRUnext;
X	else
X		b->b_LRUprev->b_LRUnext = b->b_LRUnext;
X	if (b->b_LRUnext == 0)
X		l_block = b->b_LRUprev;
X	else
X		b->b_LRUnext->b_LRUprev = b->b_LRUprev;
X}
X
Xprivate Block *
Xb_unlink(bp)
Xregister Block	*bp;
X{
X	register Block	*hp,
X			*prev = 0;
X
X	LRUunlink(bp);
X	/* Now that we have the block, we remove it from its position
X	   in the hash table, so we can THEN put it somewhere else with
X	   it's new block assignment. */
X
X	for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext)
X		if (hp == bp)
X			break;
X	if (hp == 0) {
X		printf("\rBlock %d missing!", bp->b_bno);
X		finish(0);
X	}
X	if (prev)
X		prev->b_HASHnext = hp->b_HASHnext;
X	else
X		bht[B_HASH(bp->b_bno)] = hp->b_HASHnext;
X
X	if (bp->b_dirty) {	/* Do, now, the delayed write */
X		(*blkio)(bp, write);
X		bp->b_dirty = 0;
X	}
X
X	return bp;
X}
X
X/* Get a block which contains at least part of the line with the address
X   atl.  Returns a pointer to the block and sets the global variable
X   nleft (number of good characters left in the buffer). */
X
Xprivate char *
Xgetblock(atl, iof)
Xdisk_line	atl;
X{
X	register int	bno,
X			off;
X	register Block	*bp;
X	static Block	*lastb = 0;
X
X	bno = daddr_to_bno(atl);
X	off = daddr_to_off(atl);
X	if (bno >= MAX_BLOCKS)
X		error("Tmp file too large.  Get help!");
X	nleft = BUFSIZ - off;
X	if (lastb != 0 && lastb->b_bno == bno) {
X		lastb->b_dirty |= iof;
X		return lastb->b_buf + off;
X	}
X
X	/* The requested block already lives in memory, so we move
X	   it to the end of the LRU list (making it Most Recently Used)
X	   and then return a pointer to it. */
X	if (bp = lookup(bno)) {
X		if (bp != l_block) {
X			LRUunlink(bp);
X			if (l_block == 0)
X				f_block = l_block = bp;
X			else
X				l_block->b_LRUnext = bp;
X			bp->b_LRUprev = l_block;
X			l_block = bp;
X			bp->b_LRUnext = 0;
X		}
X		if (bp->b_bno > max_bno)
X			max_bno = bp->b_bno;
X		bp->b_dirty |= iof;
X		lastb = bp;
X		return bp->b_buf + off;
X	}
X
X	/* The block we want doesn't reside in memory so we take the
X	   least recently used clean block (if there is one) and use
X	   it.  */
X	bp = f_block;
X	if (bp->b_dirty)	/* The best block is dirty ... */
X		SyncTmp();
X
X	bp = b_unlink(bp);
X	if (l_block == 0)
X		l_block = f_block = bp;
X	else
X		l_block->b_LRUnext = bp;	/* Place it at the end ... */
X	bp->b_LRUprev = l_block;
X	l_block = bp;
X	bp->b_LRUnext = 0;		/* so it's Most Recently Used */
X
X	bp->b_dirty = iof;
X	bp->b_bno = bno;
X	bp->b_HASHnext = bht[B_HASH(bno)];
X	bht[B_HASH(bno)] = bp;
X
X	/* Get the current contents of the block UNLESS this is a new
X	   block that's never been looked at before, i.e., it's past
X	   the end of the tmp file. */
X
X	if (bp->b_bno <= max_bno)
X		(*blkio)(bp, read);
X	else
X		max_bno = bno;
X
X	lastb = bp;
X	return bp->b_buf + off;
X}
X
Xchar *
Xlbptr(line)
XLine	*line;
X{
X	return getblock(line->l_dline >> 1, READ);
X}
X
X/* save the current contents of linebuf, if it has changed */
X
Xlsave()
X{
X	if (curbuf == 0 || !DOLsave)	/* Nothing modified recently */
X		return;
X
X	if (strcmp(lbptr(curline), linebuf) != 0)
X		SavLine(curline, linebuf);	/* Put linebuf on the disk. */
X	DOLsave = 0;
X}
X
X#ifdef BACKUPFILES
Xfile_backup(fname)
Xchar *fname;
X{
X	char	*s;
X	register int	i;
X	int	fd1,
X		fd2;
X	char	tmp1[BUFSIZ],
X		tmp2[BUFSIZ];
X	
X	strcpy(tmp1, fname);
X	
X	if ((s = rindex(tmp1, '/')) == NULL)
X		sprintf(tmp2, "#%s", fname);
X	else {
X		*s++ = '\0';
X		sprintf(tmp2, "%s/#%s", tmp1, s);
X	}
X
X	if ((fd1 = open(fname, 0)) < 0)
X		return;
X
X	if ((fd2 = creat(tmp2, CreatMode)) < 0) {
X		(void) close(fd1);
X		return;
X	}
X
X	while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0)
X		write(fd2, tmp1, i);
X
X#ifdef BSD4_2
X	(void) fsync(fd2);
X#endif
X	(void) close(fd2);
X	(void) close(fd1);
X}
X#endif
@//E*O*F io.c//
if test 20767 -ne "`wc -c <'io.c'`"; then
    echo shar: error transmitting "'io.c'" '(should have been 20767 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'iproc-pipes.c'" '(5738 characters)'
if test -f 'iproc-pipes.c' ; then 
  echo shar: will not over-write existing file "'iproc-pipes.c'"
else
sed 's/^X//' >iproc-pipes.c <<'@//E*O*F iproc-pipes.c//'
X/************************************************************************
X * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
X * provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is *
X * included in all the files.                                           *
X ************************************************************************/
X
X#ifdef BSD4_2
X#   include <sys/wait.h>
X#else
X#   include <wait.h>
X#endif
X#include <signal.h>
X#include <sgtty.h>
X
Xtypedef struct process	Process;
X
X#define DEAD	1	/* Dead but haven't informed user yet */
X#define STOPPED	2	/* Job stopped */
X#define RUNNING	3	/* Just running */
X#define NEW	4	/* This process is brand new */
X
X/* If process is dead, flags says how. */
X#define EXITED	1
X#define KILLED	2
X
X#define isdead(p)	(p == 0 || proc_state(p) == DEAD || p->p_toproc == -1)
X
X#define proc_buf(p)	(p->p_buffer->b_name)
X#define proc_cmd(p)	(p->p_name)
X#define proc_state(p)	(p->p_state)
X
Xprivate Process	*procs = 0;
X
Xint	ProcInput,
X	ProcOutput,
X	NumProcs = 0;
X
Xstatic char *
Xpstate(p)
XProcess	*p;
X{
X	switch (proc_state(p)) {
X	case NEW:
X		return "Pre-birth";
X
X	case STOPPED:
X		return "Stopped";
X
X	case RUNNING:
X		return "Running";
X
X	case DEAD:
X		if (p->p_howdied == EXITED) {
X			if (p->p_reason == 0)
X				return "Done";
X			return sprint("[Exit %d]", p->p_reason);
X		}
X		return sprint("[Killed %d]", p->p_reason);
X
X	default:
X		return "Unknown state.";
X	}
X}
X
Xstatic Process *
Xproc_pid(pid)
X{
X	register Process	*p;
X
X	for (p = procs; p != 0; p = p->p_next)
X		if (p->p_portpid == pid)
X			break;
X
X	return p;
X}
X
Xprocs_read()
X{
X	struct header {
X		int	pid;
X		int	nbytes;
X	} header;
X	int	n;
X	long	nbytes;
X	static int	here = 0;
X
X	if (here)	
X		return;
X	sighold(SIGCHLD);	/* Block any other children. */
X	here++;
X	for (;;) {
X		(void) ioctl(ProcInput, FIONREAD, (struct sgttyb *) &nbytes);
X		if (nbytes < sizeof header)
X			break;
X		n = read(ProcInput, (char *) &header, sizeof header);
X		if (n != sizeof header)
X			finish(1);
X		read_proc(header.pid, header.nbytes);
X	}
X	redisplay();
X	here = 0;
X	sigrelse(SIGCHLD);
X}
X
Xread_proc(pid, nbytes)
Xint	pid;
Xregister int	nbytes;
X{
X	register Process	*p;
X	int	n;
X	char	ibuf[512];
X
X	if ((p = proc_pid(pid)) == 0) {
X		printf("\riproc: unknown pid (%d)", pid);
X		return;
X	}
X	if (proc_state(p) == NEW) {
X		int	rpid;
X		/* Pid of real child, not of portsrv. */
X
X		doread(ProcInput, (char *) &rpid, nbytes);
X		nbytes -= sizeof rpid;
X		p->p_pid = rpid;
X		p->p_state = RUNNING;
X	}
X
X	if (nbytes == EOF) {		/* Okay to clean up this process */
X		p->p_eof = 1;
X		NumProcs--;	/* As far as getch() in main is concerned */
X		return;
X	}
X
X	while (nbytes > 0) {
X		n = min((sizeof ibuf) - 1, nbytes);
X		doread(ProcInput, ibuf, n);
X		ibuf[n] = 0;	/* Null terminate for convenience */
X		nbytes -= n;
X		proc_rec(p, ibuf);
X	}
X}
X
XProcKill()
X{
X	proc_kill(curbuf->b_process, SIGKILL);
X}
X
XProcInt()
X{
X	proc_kill(curbuf->b_process, SIGINT);
X}
X
XProcQuit()
X{
X	proc_kill(curbuf->b_process, SIGQUIT);
X}
X
Xstatic
Xproc_close(p)
XProcess	*p;
X{
X	(void) close(p->p_toproc);
X	p->p_toproc = -1;	/* Writes will fail. */
X}
X
Xdo_rtp(mp)
Xregister Mark	*mp;
X{
X	register Process	*p = curbuf->b_process;
X	Line	*line1 = curline,
X		*line2 = mp->m_line;
X	int	char1 = curchar,
X		char2 = mp->m_char;
X	char	*gp;
X
X	if (isdead(p) || p->p_buffer != curbuf)
X		return;
X
X	(void) fixorder(&line1, &char1, &line2, &char2);
X	while (line1 != line2->l_next) {
X		gp = ltobuf(line1, genbuf) + char1;
X		if (line1 == line2)
X			gp[char2] = '\0';
X		else
X			strcat(gp, "\n");
X		(void) write(p->p_toproc, gp, strlen(gp));
X		line1 = line1->l_next;
X		char1 = 0;
X	}
X}
X
X/* VARARGS3 */
X
Xprivate
Xproc_strt(bufname, clobber, va_alist)
Xchar	*bufname;
Xva_dcl
X{
X	Window	*owind = curwind;
X	int	toproc[2],
X		pid;
X	Process	*newp;
X	Buffer	*newbuf;
X    	char	*argv[32],
X    		*cp,
X    		foo[10],
X		cmdbuf[128];
X    	int	i;
X	va_list	ap;
X
X	isprocbuf(bufname);	/* make sure BUFNAME is either nonexistant
X				   or is of type B_PROCESS */
X	dopipe(toproc);
X
X	switch (pid = fork()) {
X	case -1:
X		pclose(toproc);
X		complain("[Fork failed.]");
X
X	case 0:
X	    	argv[0] = "portsrv";
X	    	argv[1] = foo;
X		sprintf(foo, "%d", ProcInput);
X		va_start(ap);
X		make_argv(&argv[2], ap);
X		va_end(ap);
X		(void) dup2(toproc[0], 0);
X		(void) dup2(ProcOutput, 1);
X		(void) dup2(ProcOutput, 2);
X		pclose(toproc);
X		execv(Portsrv, args);
X		printf("Execl failed.\n");
X		_exit(1);
X	}
X
X	sighold(SIGCHLD);
X	newp = (Process *) malloc(sizeof *newp);
X	newp->p_next = procs;
X	newp->p_state = NEW;
X	newp->p_cmd = 0;
X
X	cmdbuf[0] = '\0';
X	va_start(ap);
X	while (cp = va_arg(ap, char *))
X		sprintf(&cmdbuf[strlen(cmdbuf)], "%s ", cp);
X	va_end(ap);
X	newp->p_name = copystr(cmdbuf);
X	procs = newp;
X	newp->p_portpid = pid;
X	newp->p_pid = -1;
X
X	newbuf = do_select((Window *) 0, bufname);
X	newbuf->b_type = B_PROCESS;
X	newp->p_buffer = newbuf;
X	newbuf->b_process = newp;	/* sorta circular, eh? */
X	pop_wind(bufname, clobber, B_PROCESS);
X	ToLast();
X	if (!bolp())
X		LineInsert(1);
X	/* Pop_wind() after everything is set up; important!
X	   Bindings won't work right unless newbuf->b_process is already
X	   set up BEFORE NEWBUF is first SetBuf()'d. */
X	newp->p_mark = MakeMark(curline, curchar, FLOATER);
X
X	newp->p_toproc = toproc[1];
X	newp->p_reason = 0;
X	newp->p_eof = 0;
X	NumProcs++;
X	(void) close(toproc[0]);
X	sigrelse(SIGCHLD);
X	SetWind(owind);
X}
X
Xpinit()
X{
X	int	p[2];
X
X	(void) signal(SIGCHLD, proc_child);
X	(void) pipe(p);
X	ProcInput = p[0];
X	ProcOutput = p[1];
X	(void) signal(INPUT_SIG, procs_read);
X	sighold(INPUT_SIG);	/* Released during terminal read */
X}
X
Xdoread(fd, buf, n)
Xchar	*buf;
X{
X	int	nread;
X
X	if ((nread = read(fd, buf, n)) != n)
X		complain("Cannot read %d (got %d) bytes.", n, nread);
X}
@//E*O*F iproc-pipes.c//
if test 5738 -ne "`wc -c <'iproc-pipes.c'`"; then
    echo shar: error transmitting "'iproc-pipes.c'" '(should have been 5738 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'iproc-ptys.c'" '(7160 characters)'
if test -f 'iproc-ptys.c' ; then 
  echo shar: will not over-write existing file "'iproc-ptys.c'"
else
sed 's/^X//' >iproc-ptys.c <<'@//E*O*F iproc-ptys.c//'
X/************************************************************************
X * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
X * provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is *
X * included in all the files.                                           *
X ************************************************************************/
X
X#ifdef BSD4_2
X#   include <sys/wait.h>
X#else
X#   include <wait.h>
X#endif
X#include <signal.h>
X#include <sgtty.h>
X
X#define DEAD	1	/* Dead but haven't informed user yet */
X#define STOPPED	2	/* Job stopped */
X#define RUNNING	3	/* Just running */
X#define NEW	4	/* This process is brand new */
X
X/* If process is dead, flags says how. */
X#define EXITED	1
X#define KILLED	2
X
X#define isdead(p)	(p == 0 || proc_state(p) == DEAD || p->p_fd == -1)
X
X#define proc_buf(p)	(p->p_buffer->b_name)
X#define proc_cmd(p)	(p->p_name)
X#define proc_state(p)	(p->p_state)
X
Xprivate Process	*procs = 0;
X
Xint	global_fd = 1,
X	NumProcs = 0;
X
X#ifdef BRLUNIX
X	extern struct sg_brl sg1;
X#else
X	extern struct sgttyb sg1;
X#endif
X
Xextern struct tchars tc1;
X
X#ifdef TIOCSLTC
X	extern struct ltchars ls1;
X#endif
X
Xstatic char *
Xpstate(p)
XProcess	*p;
X{
X	switch (proc_state(p)) {
X	case STOPPED:
X		return "Stopped";
X
X	case RUNNING:
X		return "Running";
X
X	case DEAD:
X		if (p->p_howdied == EXITED) {
X			if (p->p_reason == 0)
X				return "Done";
X			return sprint("exit(%d)", p->p_reason);
X		}
X		return sprint("Killed(%d)", p->p_reason);
X
X	default:
X		return "Unknown state.";
X	}
X}
X
Xstatic Process *
Xproc_pid(pid)
X{
X	register Process	*p;
X
X	for (p = procs; p != 0; p = p->p_next)
X		if (p->p_pid == pid)
X			break;
X
X	return p;
X}
X
Xread_proc(fd)
Xregister int	fd;
X{
X	register Process	*p;
X	unsigned int	n;
X	char	ibuf[1024];
X
X	for (p = procs; p != 0; p = p->p_next)
X		if (p->p_fd == fd)
X			break;
X
X	if (p == 0) {
X		printf("\riproc: unknown fd %d", fd);
X		return;
X	}
X
X	n = read(fd, ibuf, sizeof(ibuf) - 1);
X	if (n == 0) {
X		proc_close(p);
X		NumProcs--;
X		return;
X	}
X	ibuf[n] = '\0';
X	proc_rec(p, ibuf);
X	redisplay();
X}
X
XProcKill()
X{
X	register Buffer	*b;
X	Process	*buf_to_proc();
X	char	*bname;
X
X	bname = ask_buf(curbuf);
X
X	if ((b = buf_exists(bname)) == 0)
X		complain("[No such buffer]");
X	if (b->b_process == 0)
X		complain("%s not tied to a process.", bname);
X	proc_kill(b->b_process, SIGKILL);
X}
X
XProcCont()
X{
X	Process	*p;
X
X	if ((p = curbuf->b_process) == 0)
X		complain("[No process]");
X	if (p->p_state != DEAD) {
X		proc_kill(p, SIGCONT);
X		p->p_state = RUNNING;
X	}		
X}
X
XProcEof()
X{
X	send_p(tc1.t_eofc);
X}
X
XProcInt()
X{
X	send_p(tc1.t_intrc);
X}
X
XProcQuit()
X{
X	send_p(tc1.t_quitc);
X}
X
XProcStop()
X{
X	send_p(ls1.t_suspc);
X}
X
XProcDStop()
X{
X	send_p(ls1.t_dsuspc);
X}
X
Xsend_p(c)
Xchar	c;
X{
X	Process	*p;
X
X	if ((p = curbuf->b_process) == 0)
X		complain("[No process]");
X	ToLast();
X	(void) write(p->p_fd, &c, 1);
X}
X
Xstatic
Xproc_close(p)
XProcess *p;
X{
X	(void) close(p->p_fd);
X	global_fd &= ~(1 << p->p_fd);
X	p->p_eof++;
X}
X
Xdo_rtp(mp)
Xregister Mark	*mp;
X{
X	register Process	*p = curbuf->b_process;
X	Line	*line1 = curline,
X		*line2 = mp->m_line;
X	int	char1 = curchar,
X		char2 = mp->m_char;
X	char	*gp;
X
X	if (isdead(p) || p->p_buffer != curbuf)
X		return;
X
X	(void) fixorder(&line1, &char1, &line2, &char2);
X	while (line1 != line2->l_next) {
X		gp = ltobuf(line1, genbuf) + char1;
X		if (line1 == line2)
X			gp[char2] = '\0';
X		else
X			strcat(gp, "\n");
X		(void) write(p->p_fd, gp, strlen(gp));
X		line1 = line1->l_next;
X		char1 = 0;
X	}
X}
X
X/* VARARGS3 */
X
Xprivate
Xproc_strt(bufname, clobber, va_alist)
Xchar	*bufname;
Xva_dcl
X{
X	va_list	ap;
X	char	*argv[32],
X		*cp;
X	Window *owind	= curwind;
X	int	pid;
X	Process	*newp;
X	Buffer 	*newbuf;
X	int	i,
X		f,
X		ttyfd;
X	long 	ldisc,
X		lmode;
X	register char	*s,
X			*t;
X	extern int	errno;
X	static char	ttybuf[11],
X			ptybuf[11];
X	char	cmdbuf[128];
X#ifdef BRLUNIX
X	struct sg_brl sg;
X#else
X	struct sgttyb sg;
X#endif
X
X#ifdef TIOCGWINSZ
X	struct winsize win;
X#else
X#  ifdef BTL_BLIT
X#  include <sys/jioctl.h>
X	struct jwinsize jwin;
X#  endif
X#endif
X
X	isprocbuf(bufname);	/* make sure BUFNAME is either nonexistant
X				   or is of type B_PROCESS */
X	for (s = "pqrs"; *s; s++) {
X		for (t = "0123456789abcdef"; *t; t++) {
X			sprintf(ptybuf, "/dev/pty%c%c", *s, *t);
X			if ((ttyfd = open(ptybuf, 2)) >= 0) {
X				strcpy(ttybuf, ptybuf);
X				ttybuf[5] = 't';
X				/* make sure both ends are available */
X				if ((i = open(ttybuf, 2)) < 0)
X					continue;
X				(void) close(i);
X				goto out;
X			}
X		}
X	}
X
Xout:	if (s == 0 && t == 0)
X		complain("[Out of ptys!]");
X
X#ifdef TIOCGETD
X	(void) ioctl(0, TIOCGETD, (struct sgttyb *) &ldisc);
X#endif
X#ifdef TIOCLGET
X	(void) ioctl(0, TIOCLGET, (struct sgttyb *) &lmode);
X#endif
X#ifdef TIOCGWINSZ
X	(void) ioctl(0, TIOCGWINSZ, (struct sgttyb *) &win);
X#else
X#  ifdef BTL_BLIT
X	(void) ioctl(0, JWINSIZE, (struct sgttyb *) &jwin);
X#  endif BTL_BLIT
X#endif
X
X	switch (pid = fork()) {
X	case -1:
X		(void) close(ttyfd);
X		complain("[Fork failed!]");
X
X	case 0:
X		for (i = 0; i < 32; i++)
X			(void) close(i);
X
X#ifdef TIOCNOTTY
X		if ((i = open("/dev/tty", 2)) >= 0) {
X			(void) ioctl(i, TIOCNOTTY, (struct sgttyb *) 0);
X			(void) close(i);
X		}
X#endif
X		i = open(ttybuf, 2);
X		for (f = 0; f <= 2; f++)
X			(void) dup2(i, f);
X
X#ifdef TIOCSETD
X		(void) ioctl(0, TIOCSETD, (struct sgttyb *) &ldisc);
X#endif
X#ifdef TIOCLSET
X		(void) ioctl(0, TIOCLSET, (struct sgttyb *) &lmode);
X#endif
X#ifdef TIOCSETC
X		(void) ioctl(0, TIOCSETC, (struct sgttyb *) &tc1);
X#endif
X#ifdef TIOCSLTC
X		(void) ioctl(0, TIOCSLTC, (struct sgttyb *) &ls1);
X#endif
X
X#ifdef TIOCGWINSZ
X#    ifdef SIGWINCH
X		(void) signal(SIGWINCH, SIG_IGN);
X#    endif
X		win.ws_row = curwind->w_height;
X		(void) ioctl(0, TIOCSWINSZ, (struct sgttyb *) &win);
X#else
X#  ifdef BTL_BLIT
X		jwin.bytesy = curwind->w_height;
X		(void) ioctl(0, JSWINSIZE, (struct sgttyb *) &jwin);
X#  endif
X#endif
X
X		sg = sg1;
X		sg.sg_flags &= ~(ECHO | CRMOD);
X		(void) stty(0, &sg);
X
X		i = getpid();
X		(void) ioctl(0, TIOCSPGRP, (struct sgttyb *) &i);
X		(void) setpgrp(0, i);
X		va_start(ap);
X		make_argv(argv, ap);
X		va_end(ap);
X		execv(argv[0], &argv[1]);
X		(void) write(1, "execve failed!\n", 15);
X		_exit(errno + 1);
X	}
X
X	sighold(SIGCHLD);
X#ifdef SIGWINCH
X	sighold(SIGWINCH);
X#endif
X	newp = (Process *) emalloc(sizeof *newp);
X
X	newp->p_fd = ttyfd;
X	newp->p_pid = pid;
X	newp->p_eof = 0;
X
X	newbuf = do_select((Window *) 0, bufname);
X	newbuf->b_type = B_PROCESS;
X	newp->p_buffer = newbuf;
X	newbuf->b_process = newp;	/* sorta circular, eh? */
X	pop_wind(bufname, clobber, B_PROCESS);
X	/* Pop_wind() after everything is set up; important!
X	   Bindings won't work right unless newbuf->b_process is already
X	   set up BEFORE NEWBUF is first SetBuf()'d. */
X	ToLast();
X	if (!bolp())
X		LineInsert(1);
X
X	cmdbuf[0] = '\0';
X	va_start(ap);
X	while (cp = va_arg(ap, char *))
X		sprintf(&cmdbuf[strlen(cmdbuf)], "%s ", cp++);
X	va_end(ap);
X
X	newp->p_name = copystr(cmdbuf);
X	newp->p_state = RUNNING;
X	newp->p_reason = 0;
X	newp->p_mark = MakeMark(curline, curchar, FLOATER);
X
X	newp->p_next = procs;
X	procs = newp;
X	NumProcs++;
X	global_fd |= 1 << newp->p_fd;
X	sigrelse(SIGCHLD);
X	SetWind(owind);
X}
X	
Xpinit()
X{
X	(void) signal(SIGCHLD, proc_child);
X}
@//E*O*F iproc-ptys.c//
if test 7160 -ne "`wc -c <'iproc-ptys.c'`"; then
    echo shar: error transmitting "'iproc-ptys.c'" '(should have been 7160 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'iproc.c'" '(6421 characters)'
if test -f 'iproc.c' ; then 
  echo shar: will not over-write existing file "'iproc.c'"
else
sed 's/^X//' >iproc.c <<'@//E*O*F iproc.c//'
X/************************************************************************
X * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
X * provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is *
X * included in all the files.                                           *
X ************************************************************************/
X
X#include "jove.h"
X#include <varargs.h>
X
X#ifdef IPROCS
X
Xint	proc_child();
X
X#ifdef PIPEPROCS
X#   include "iproc-pipes.c"
X#else
X#   include "iproc-ptys.c"
X#endif
X
Xchar	proc_prompt[80] = "% ";
X
XKillProcs()
X{
X	register Process	*p;
X	register int	killem = -1;		/* -1 means undetermined */
X	register char	*yorn;
X
X	for (p = procs; p != 0; p = p->p_next)
X		if (!isdead(p)) {
X			if (killem == -1) {
X				yorn = ask("y", "Should I kill your i-processes? ");
X				killem = (Upper(*yorn) == 'Y');
X			}
X			if (killem)
X				proc_kill(p, SIGKILL);
X		}
X}
X
Xpbuftiedp(b)
Xregister Buffer	*b;
X{
X	register Process	*p = b->b_process;
X
X	if (!isdead(p))
X		complain("Process %s, attached to %b, is %s.",
X			 proc_cmd(p), b, pstate(p));
X}
X
X/* Process receive: receives the characters in buf, and appends them to
X   the buffer associated with p. */
X
Xstatic
Xproc_rec(p, buf)
Xregister Process	*p;
Xchar	*buf;
X{
X	Buffer	*saveb = curbuf;
X	register Window	*w;
X	register Mark	*savepoint;
X	int	sameplace = 0,
X		do_disp = 0;
X
X	if (curwind->w_bufp == p->p_buffer)
X		w = curwind;
X	else
X		w = windbp(p->p_buffer);	/* Is this window visible? */
X	if (w != 0)
X		do_disp = (in_window(w, p->p_mark->m_line) != -1);
X	SetBuf(p->p_buffer);
X	savepoint = MakeMark(curline, curchar, FLOATER);
X	ToMark(p->p_mark);	/* Where output last stopped. */
X	if (savepoint->m_line == curline && savepoint->m_char == curchar)
X		sameplace++;
X
X	ins_str(buf, YES);
X	if (do_disp) {
X		w->w_line = curline;
X		w->w_char = curchar;
X		redisplay();
X	}
X	MarkSet(p->p_mark, curline, curchar);
X	if (!sameplace)
X		ToMark(savepoint);	/* Back to where we were. */
X	DelMark(savepoint);
X	SetBuf(saveb);
X}
X
Xproc_kill(p, sig)
Xregister Process	*p;
X{
X	if (isdead(p))
X		return;
X	if (killpg(p->p_pid, sig) == -1)
X		s_mess("Cannot kill %s!", proc_buf(p));
X}
X
X/* Deal with a process' death.  proc_rec turns on the FREEUP bit when it
X   it gets the "EOF" from portsrv.  FREEUP'd processes get unlinked from
X   the list, and the proc stucture and proc_buf(p) get free'd up, here. */
X
Xprivate
XDealWDeath()
X{
X	register Process	*p,
X				*next,
X				*prev = 0;
X	
X	for (p = procs; p != 0; p = next) {
X		next = p->p_next;
X		if (!p->p_eof) {
X			prev = p;
X			continue;
X		}
X		proc_close(p);
X		PopPBs();			/* not a process anymore */
X		p->p_buffer->b_process = 0;	/* we're killing ourself */
X		free((char *) p->p_name);
X		free((char *) p);
X		if (prev)
X			prev->p_next = next;
X		else
X			procs = next;
X	}
X}
X
XProcList()
X{
X	register Process	*p;
X	char	*fmt = "%-15s  %-15s  %-8s %s",
X		pidstr[10];
X
X	if (procs == 0) {
X		message("[No subprocesses]");
X		return;
X	}
X	TOstart("Process list", TRUE);
X
X	Typeout(fmt, "Buffer", "Status", "Pid ", "Command");
X	Typeout(fmt, "------", "------", "--- ", "-------");
X	for (p = procs; p != 0; p = p->p_next) {
X		sprintf(pidstr, "%d", p->p_pid);
X		Typeout(fmt, proc_buf(p), pstate(p), pidstr, p->p_name);
X	}
X	DealWDeath();
X	TOstop();
X}
X
XProcNewline()
X{
X	SendData(YES);
X}
X
XProcSendData()
X{
X	SendData(NO);
X}
X
Xprivate
XSendData(newlinep)
X{
X	register Process	*p = curbuf->b_process;
X
X	if (isdead(p))
X		return;
X	if (lastp(curline)) {
X		Eol();
X		if (newlinep)
X			LineInsert(1);
X		do_rtp(p->p_mark);
X		MarkSet(p->p_mark, curline, curchar);
X	} else {
X		Bol();
X		while (LookingAt(proc_prompt, linebuf, curchar))
X			SetDot(dosearch(proc_prompt, 1, 1));
X		strcpy(genbuf, linebuf + curchar);
X		ToLast();
X		ins_str(genbuf, NO);
X	}
X}
X
XShellProc()
X{
X	char	*shbuf = "*shell*";
X	register Buffer	*b;
X
X	b = buf_exists(shbuf);
X	if (b == 0 || isdead(b->b_process))
X		proc_strt(shbuf, NO, Shell, "-i", (char *) 0);
X	pop_wind(shbuf, NO, -1);
X}
X
XIprocess()
X{
X	extern char	ShcomBuf[100],
X			*MakeName();
X	register char	*command;
X
X	command = ask(ShcomBuf, ProcFmt);
X	null_ncpy(ShcomBuf, command, (sizeof ShcomBuf) - 1);
X	proc_strt(MakeName(command), YES, Shell, ShFlags, command, (char *) 0);
X}
X
Xproc_child()
X{
X	union wait	w;
X	register int	pid;
X
X	for (;;) {
X#ifndef VMUNIX
X		pid = wait2(&w.w_status, (WNOHANG | WUNTRACED));
X#else
X		pid = wait3(&w, (WNOHANG | WUNTRACED), (struct rusage *) 0);
X#endif
X		if (pid <= 0)
X			break;
X		kill_off(pid, w);
X	}
X}
X
Xkill_off(pid, w)
Xregister int	pid;
Xunion wait	w;
X{
X	char	str[128];
X	register Process	*child;
X
X	if ((child = proc_pid(pid)) == 0)
X		return;
X
X	if (WIFSTOPPED(w))
X		child->p_state = STOPPED;
X	else {
X		child->p_state = DEAD;
X		if (WIFEXITED(w))
X			child->p_howdied = EXITED;
X		else if (WIFSIGNALED(w)) {
X			child->p_reason = w.w_termsig;
X			child->p_howdied = KILLED;
X		}
X		proc_close(child);
X	}
X	sprintf(str, "[Process %s: %s]\n",
X		proc_cmd(child),
X		pstate(child));
X	proc_rec(child, str);
X}
X
X/* Push/pod process bindings.  I openly acknowledge that this is a
X   kludge, but I can't be bothered making it right. */
X
Xstruct proc_bind {
X	int		pb_key;
X	data_obj	**pb_map;
X	data_obj	*pb_push;
X	data_obj	*pb_cmd;
X	struct proc_bind *pb_next;
X};
X
Xstruct proc_bind *PBinds = 0;
X
XPopPBs()
X{
X	register struct proc_bind *p;
X
X	for (p = PBinds; p != 0; p = p->pb_next)
X		p->pb_map[p->pb_key] = p->pb_push;
X}
X
XPushPBs()
X{
X	register struct proc_bind *p;
X
X	for (p = PBinds; p != 0; p = p->pb_next) {
X		p->pb_push = p->pb_map[p->pb_key];
X		p->pb_map[p->pb_key] = p->pb_cmd;
X	}
X}
X/* VARARGS0 */
X
XProcBind()
X{
X	register data_obj	*d;
X
X	if ((d = findcom(ProcFmt)) == 0)
X		return;
X	s_mess(": %f %s ", d->Name);
X	ProcB2(mainmap, EOF, d);
X}
X
XProcB2(map, lastkey, cmd)
Xdata_obj	**map,
X		*cmd;
X{
X	register struct proc_bind *p;
X	register data_obj	**nextmap;
X	int	c;
X
X	c = addgetc();
X	if (c == EOF) {
X		if (lastkey == EOF)
X			complain("[Empty key sequence]");
X		complain("[Unexpected end-of-line]");
X	} else {
X		if (nextmap = IsPrefix(map[c]))
X			ProcB2(nextmap, c, cmd);
X		else {
X			if (curbuf->b_process)
X				PopPBs();
X
X			for (p = PBinds; p != 0; p = p->pb_next)
X				if (p->pb_key == c && p->pb_map == map)
X					break;
X			if (p == 0) {
X				p = (struct proc_bind *) emalloc(sizeof *p);
X				p->pb_next = PBinds;
X				PBinds = p;
X			}
X			p->pb_map = map;
X			p->pb_key = c;
X			p->pb_cmd = cmd;
X
X			if (curbuf->b_process)
X				PushPBs();
X		}
X	}
X}
X
X#endif IPROCS
@//E*O*F iproc.c//
if test 6421 -ne "`wc -c <'iproc.c'`"; then
    echo shar: error transmitting "'iproc.c'" '(should have been 6421 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'keymaps.txt'" '(10930 characters)'
if test -f 'keymaps.txt' ; then 
  echo shar: will not over-write existing file "'keymaps.txt'"
else
sed 's/^X//' >keymaps.txt <<'@//E*O*F keymaps.txt//'
X/************************************************************************
X * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
X * provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is *
X * included in all the files.                                           *
X ************************************************************************/
X
X/* Warning:  You probably shouldn't put ifdefs anywhere *inside* the keymaps
X   definitions.  It'll screw up the stuff in comments (at least), and maybe
X   a few other things.  Yes, it *WILL* screw up the comments ... but it's
X   not clear that you care ... */
X
X#include "jove.h"
X
Xkeymap	mainmap = {
X	"set-mark",			/* ^@ */
X	"beginning-of-line",		/* ^A */
X	"backward-character",		/* ^B */
X	"unbound",			/* ^C */
X	"delete-next-character",	/* ^D */
X	"end-of-line",			/* ^E */
X	"forward-character",		/* ^F */
X	"unbound",			/* ^G */
X	"delete-previous-character",	/* ^H */
X	"handle-tab",			/* ^I */
X	"newline-and-indent",		/* ^J */
X	"kill-to-end-of-line",		/* ^K */
X	"redraw-display",		/* ^L */
X	"newline",			/* ^M */
X	"next-line",			/* ^N */
X	"newline-and-backup",		/* ^O */
X	"previous-line",		/* ^P */
X	"quoted-insert",		/* ^Q */
X	"search-reverse",		/* ^R */
X	"search-forward",		/* ^S */
X	"transpose-characters",		/* ^T */
X	"quadruple-numeric-argument",	/* ^U */
X	"next-page",			/* ^V */
X	"kill-region",			/* ^W */
X	"prefix-2",			/* ^X */
X	"yank",				/* ^Y */
X	"scroll-up",			/* ^Z */
X	"prefix-1",			/* ^[ */
X	"search-forward",		/* ^\ */
X	"unbound",			/* ^] */
X	"quoted-insert",		/* ^^ */
X	"unbound",			/* ^_ */
X	"self-insert",			/*    */
X	"self-insert",			/* !  */
X	"self-insert",			/* "  */
X	"self-insert",			/* #  */
X	"self-insert",			/* $  */
X	"self-insert",			/* %  */
X	"self-insert",			/* &  */
X	"self-insert",			/* '  */
X	"self-insert",			/* (  */
X	"paren-flash",			/* )  */
X	"self-insert",			/* *  */
X	"self-insert",			/* +  */
X	"self-insert",			/* ,  */
X	"self-insert",			/* -  */
X	"self-insert",			/* .  */
X	"self-insert",			/* /  */
X	"self-insert",			/* 0  */
X	"self-insert",			/* 1  */
X	"self-insert",			/* 2  */
X	"self-insert",			/* 3  */
X	"self-insert",			/* 4  */
X	"self-insert",			/* 5  */
X	"self-insert",			/* 6  */
X	"self-insert",			/* 7  */
X	"self-insert",			/* 8  */
X	"self-insert",			/* 9  */
X	"self-insert",			/* :  */
X	"self-insert",			/* ;  */
X	"self-insert",			/* <  */
X	"self-insert",			/* =  */
X	"self-insert",			/* >  */
X	"self-insert",			/* ?  */
X	"self-insert",			/* @  */
X	"self-insert",			/* A  */
X	"self-insert",			/* B  */
X	"self-insert",			/* C  */
X	"self-insert",			/* D  */
X	"self-insert",			/* E  */
X	"self-insert",			/* F  */
X	"self-insert",			/* G  */
X	"self-insert",			/* H  */
X	"self-insert",			/* I  */
X	"self-insert",			/* J  */
X	"self-insert",			/* K  */
X	"self-insert",			/* L  */
X	"self-insert",			/* M  */
X	"self-insert",			/* N  */
X	"self-insert",			/* O  */
X	"self-insert",			/* P  */
X	"self-insert",			/* Q  */
X	"self-insert",			/* R  */
X	"self-insert",			/* S  */
X	"self-insert",			/* T  */
X	"self-insert",			/* U  */
X	"self-insert",			/* V  */
X	"self-insert",			/* W  */
X	"self-insert",			/* X  */
X	"self-insert",			/* Y  */
X	"self-insert",			/* Z  */
X	"self-insert",			/* [  */
X	"self-insert",			/* \  */
X	"paren-flash",			/* ]  */
X	"self-insert",			/* ^  */
X	"self-insert",			/* _  */
X	"self-insert",			/* `  */
X	"self-insert",			/* a  */
X	"self-insert",			/* b  */
X	"self-insert",			/* c  */
X	"self-insert",			/* d  */
X	"self-insert",			/* e  */
X	"self-insert",			/* f  */
X	"self-insert",			/* g  */
X	"self-insert",			/* h  */
X	"self-insert",			/* i  */
X	"self-insert",			/* j  */
X	"self-insert",			/* k  */ 
X	"self-insert",			/* l  */
X	"self-insert",			/* m  */
X	"self-insert",			/* n  */
X	"self-insert",			/* o  */
X	"self-insert",			/* p  */
X	"self-insert",			/* q  */
X	"self-insert",			/* r  */
X	"self-insert",			/* s  */
X	"self-insert",			/* t  */
X	"self-insert",			/* u  */
X	"self-insert",			/* v  */
X	"self-insert",			/* w  */
X	"self-insert",			/* x  */
X	"self-insert",			/* y  */
X	"self-insert",			/* z  */
X	"self-insert",			/* {  */
X	"self-insert",			/* |  */
X	"paren-flash",			/* }  */
X	"self-insert",			/* ~  */
X	"delete-previous-character"	/* ^? */
X};
X
Xstruct data_obj	*pref1map[0200] = {
X	"unbound",			/* ^@ */
X	"unbound",			/* ^A */
X	"backward-s-expression",	/* ^B */
X	"unbound",			/* ^C */
X	"down-list",			/* ^D */
X	"unbound",			/* ^E */
X	"forward-s-expression",		/* ^F */
X	"unbound",			/* ^G */
X	"unbound",			/* ^H */
X	"unbound",			/* ^I */
X	"unbound",			/* ^J */
X	"kill-s-expression",		/* ^K */
X	"clear-and-redraw",		/* ^L */
X	"unbound",			/* ^M */
X	"forward-list",			/* ^N */
X	"unbound",			/* ^O */
X	"backward-list",		/* ^P */
X	"unbound",			/* ^Q */
X	"unbound",			/* ^R */
X	"unbound",			/* ^S */
X	"unbound",			/* ^T */
X	"backward-up-list",		/* ^U */
X	"page-next-window",		/* ^V */
X	"unbound",			/* ^W */
X	"unbound",			/* ^X */
X	"unbound",			/* ^Y */
X	"unbound",			/* ^Z */
X	"unbound",			/* ^[ */
X	"unbound",			/* ^\ */
X	"unbound",			/* ^] */
X	"unbound",			/* ^^ */
X	"unbound",			/* ^_ */
X	"unbound",			/*    */
X	"unbound",			/* !  */
X	"unbound",			/* "  */
X	"unbound",			/* #  */
X	"unbound",			/* $  */
X	"unbound",			/* %  */
X	"unbound",			/* &  */
X	"unbound",			/* '  */
X	"unbound",			/* (  */
X	"unbound",			/* )  */
X	"unbound",			/* *  */
X	"unbound",			/* +  */
X	"beginning-of-window",		/* ,  */
X	"digit",			/* -  */
X	"end-of-window",		/* .  */
X	"unbound",			/* /  */
X	"digit",			/* 0  */
X	"digit",			/* 1  */
X	"digit",			/* 2  */
X	"digit",			/* 3  */
X	"digit",			/* 4  */
X	"digit",			/* 5  */
X	"digit",			/* 6  */
X	"digit",			/* 7  */
X	"digit",			/* 8  */
X	"digit",			/* 9  */
X	"unbound",			/* :  */
X	"unbound",			/* ;  */
X	"beginning-of-file",		/* <  */
X	"unbound",			/* =  */
X	"end-of-file",			/* >  */
X	"describe-command",		/* ?  */
X	"unbound",			/* @  */
X	"backward-sentence",		/* A  */
X	"backward-word",		/* B  */
X	"case-word-capitalize",		/* C  */
X	"kill-next-word",		/* D  */
X	"forward-sentence",		/* E  */
X	"forward-word",			/* F  */
X	"goto-line",			/* G  */
X	"unbound",			/* H  */
X	"make-macro-interactive",	/* I  */
X	"fill-paragraph",		/* J  */
X	"kill-to-end-of-sentence",	/* K  */ 
X	"case-word-lower",		/* L  */
X	"first-non-blank",		/* M  */
X	"unbound",			/* N  */
X	"unbound",			/* O  */
X	"unbound",			/* P  */
X	"query-replace-string",		/* Q  */
X	"replace-string",		/* R  */
X	"unbound",			/* S  */
X	"unbound",			/* T  */
X	"case-word-upper",		/* U  */
X	"previous-page",		/* V  */
X	"copy-region",			/* W  */
X	"execute-named-command",	/* X  */
X	"yank-pop",			/* Y  */
X	"scroll-down",			/* Z  */
X	"backward-paragraph",		/* [  */
X	"delete-white-space",		/* \  */
X	"forward-paragraph",		/* ]  */
X	"unbound",			/* ^  */
X	"unbound",			/* _  */
X	"unbound",			/* `  */
X	"backward-sentence",		/* a  */
X	"backward-word",		/* b  */
X	"case-word-capitalize",		/* c  */
X	"kill-next-word",		/* d  */
X	"forward-sentence",		/* e  */
X	"forward-word",			/* f  */
X	"goto-line",			/* g  */
X	"unbound",			/* h  */
X	"make-macro-interactive",	/* i  */
X	"fill-paragraph",		/* j  */
X	"kill-to-end-of-sentence",	/* k  */ 
X	"case-word-lower",		/* l  */
X	"first-non-blank",		/* m  */
X	"unbound",			/* n  */
X	"unbound",			/* o  */
X	"unbound",			/* p  */
X	"query-replace-string",		/* q  */
X	"replace-string",		/* r  */
X	"unbound",			/* s  */
X	"unbound",			/* t  */
X	"case-word-upper",		/* u  */
X	"previous-page",		/* v  */
X	"copy-region",			/* w  */
X	"execute-named-command",	/* x  */
X	"yank-pop",			/* y  */
X	"scroll-down",			/* z  */
X	"unbound",			/* {  */
X	"unbound",			/* |  */
X	"unbound",			/* }  */
X	"make-buffer-unmodified",	/* ~  */
X	"kill-previous-word"		/* ^? */
X};
X
Xkeymap	pref2map = {
X	"unbound",			/* ^@ */
X	"unbound",			/* ^A */
X	"list-buffers",			/* ^B */
X	"exit-jove",			/* ^C */
X	"unbound",			/* ^D */
X	"compile-it",			/* ^E */
X	"find-file",			/* ^F */
X	"unbound",			/* ^G */
X	"unbound",			/* ^H */
X	"insert-file",			/* ^I */
X	"unbound",			/* ^J */
X	"unbound",			/* ^K */
X	"unbound",			/* ^L */
X	"write-modified-files",		/* ^M */
X	"next-error",			/* ^N */
X	"delete-blank-lines",		/* ^O */
X	"previous-error",		/* ^P */
X	"unbound",			/* ^Q */
X	"visit-file",			/* ^R */
X	"save-file",			/* ^S */
X	"transpose-lines",		/* ^T */
X	"unbound",			/* ^U */
X	"visit-file",			/* ^V */
X	"write-file",			/* ^W */
X	"exchange-point-and-mark",	/* ^X */
X	"unbound",			/* ^Y */
X	"unbound",			/* ^Z */
X	"unbound",			/* ^[ */
X	"save-file",			/* ^\ */
X	"unbound",			/* ^] */
X	"unbound",			/* ^^ */
X	"unbound",			/* ^_ */
X	"unbound",			/*    */
X	"shell-command",		/* !  */
X	"unbound",			/* "  */
X	"unbound",			/* #  */
X	"unbound",			/* $  */
X	"unbound",			/* %  */
X	"unbound",			/* &  */
X	"unbound",			/* '  */
X	"start-remember",		/* (  */
X	"stop-remembering",		/* )  */
X	"unbound",			/* *  */
X	"unbound",			/* +  */
X	"unbound",			/* ,  */
X	"unbound",			/* -  */
X	"unbound",			/* .  */
X	"unbound",			/* /  */
X	"unbound",			/* 0  */
X	"delete-other-windows",		/* 1  */
X	"split-current-window",		/* 2  */
X	"unbound",			/* 3  */
X	"window-find",			/* 4  */
X	"unbound",			/* 5  */
X	"unbound",			/* 6  */
X	"unbound",			/* 7  */
X	"unbound",			/* 8  */
X	"unbound",			/* 9  */
X	"unbound",			/* :  */
X	"unbound",			/* ;  */
X	"unbound",			/* <  */
X	"unbound",			/* =  */
X	"unbound",			/* >  */
X	"describe-key",			/* ?  */
X	"unbound",			/* @  */
X	"unbound",			/* A  */
X	"select-buffer",		/* B  */
X	"unbound",			/* C  */
X	"delete-current-window",	/* D  */
X	"execute-keyboard-macro",	/* E  */
X	"unbound",			/* F  */
X	"unbound",			/* G  */
X	"unbound",			/* H  */
X	"unbound",			/* I  */
X	"unbound",			/* J  */
X	"delete-buffer",		/* K  */
X	"unbound",			/* L  */
X	"unbound",			/* M  */
X	"next-window",			/* N  */
X	"previous-window",		/* O  */
X	"previous-window",		/* P  */
X	"unbound",			/* Q  */
X	"unbound",			/* R  */
X	"save-file",		/* S  */
X	"find-tag",			/* T  */
X	"unbound",			/* U  */
X	"unbound",			/* V  */
X	"unbound",			/* W  */
X	"unbound",			/* X  */
X	"unbound",			/* Y  */
X	"unbound",			/* Z  */
X	"unbound",			/* [  */
X	"unbound",			/* \  */
X	"unbound",			/* ]  */
X	"grow-window",			/* ^  */
X	"unbound",			/* _  */
X	"unbound",			/* `  */
X	"unbound",			/* a  */
X	"select-buffer",		/* b  */
X	"unbound",			/* c  */
X	"delete-current-window",	/* d  */
X	"execute-keyboard-macro",	/* e  */
X	"unbound",			/* f  */
X	"unbound",			/* g  */
X	"unbound",			/* h  */
X	"unbound",			/* i  */
X	"unbound",			/* j  */
X	"delete-buffer",		/* k  */
X	"unbound",			/* l  */
X	"unbound",			/* m  */
X	"next-window",			/* n  */
X	"previous-window",		/* o  */
X	"previous-window",		/* p  */
X	"unbound",			/* q  */
X	"unbound",			/* r  */
X	"save-file",		/* s  */
X	"find-tag",			/* t  */
X	"unbound",			/* u  */
X	"unbound",			/* v  */
X	"unbound",			/* w  */
X	"unbound",			/* x  */
X	"unbound",			/* y  */
X	"unbound",			/* z  */
X	"unbound",			/* {  */
X	"unbound",			/* |  */
X	"unbound",			/* }  */
X	"unbound",			/* ~  */
X	"kill-to-beginning-of-sentence"	/* ^? */
X};
X
Xkeymap	miscmap = {0};
@//E*O*F keymaps.txt//
if test 10930 -ne "`wc -c <'keymaps.txt'`"; then
    echo shar: error transmitting "'keymaps.txt'" '(should have been 10930 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'rec.c'" '(2901 characters)'
if test -f 'rec.c' ; then 
  echo shar: will not over-write existing file "'rec.c'"
else
sed 's/^X//' >rec.c <<'@//E*O*F rec.c//'
X/************************************************************************
X * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
X * provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is *
X * included in all the files.                                           *
X ************************************************************************/
X
X#include "jove.h"
X#include "io.h"
X#include "rec.h"
X#include <sys/file.h>
X
Xprivate int	rec_fd = 0;
Xprivate char	*recfname;
Xprivate File	*rec_out;
X
X#ifndef L_SET
X#	define L_SET 0
X#endif
X
Xprivate struct rec_head	Header;
X
Xrecinit()
X{
X	char	buf[128];
X
X	sprintf(buf, "%s/%s", TmpFilePath, p_tempfile);
X	recfname = copystr(buf);
X	recfname = mktemp(recfname);
X	rec_fd = creat(recfname, 0644);
X	if (rec_fd == -1) {
X		complain("Cannot create \"%s\"; recovery disabled.", recfname);
X		return;
X	}
X	/* Initialize the record IO. */
X	rec_out = fd_open(recfname, F_WRITE|F_LOCKED, rec_fd, iobuff, LBSIZE);
X
X	/* Initialize the record header. */
X	Header.Uid = getuid();
X	Header.Pid = getpid();
X	Header.UpdTime = 0L;
X	Header.Nbuffers = 0;
X	(void) write(rec_fd, (char *) &Header, sizeof Header);
X}
X
Xrecclose()
X{
X	if (rec_fd == -1)
X		return;
X	(void) close(rec_fd);
X	(void) unlink(recfname);
X}
X
Xstatic
Xputaddr(addr, p)
Xdisk_line	addr;
Xregister File	*p;
X{
X	register char	*cp = (char *) &addr;
X	register int	nchars = sizeof (disk_line);
X
X	while (--nchars >= 0)
X		putc(*cp++ & 0377, p);
X}
X
Xstatic
Xputn(cp, nbytes)
Xregister char	*cp;
Xregister int	nbytes;
X{
X	while (--nbytes >= 0)
X		putc(*cp++ & 0377, rec_out);
X}
X
X/* Write out the line pointers for buffer B. */
X
Xstatic
Xdmppntrs(b)
Xregister Buffer	*b;
X{
X	register Line	*lp;
X
X	for (lp = b->b_first; lp != 0; lp = lp->l_next)
X		putaddr(lp->l_dline, rec_out);
X}
X
X/* dump the buffer info and then the actual line pointers. */
X
Xstatic
Xdmp_buf(b)
Xregister Buffer	*b;
X{
X	static struct rec_entry	record;
X	register Line	*lp;
X	register int	nlines = 0;
X
X	for (lp = b->b_first; lp != 0; lp = lp->l_next, nlines++)
X		;
X	strcpy(record.r_fname, b->b_fname ? b->b_fname : NullStr);
X	strcpy(record.r_bname, b->b_name);
X	record.r_nlines = nlines;
X	putn((char *) &record, sizeof record);
X	dmppntrs(b);
X}
X
X/* Goes through all the buffers and syncs them to the disk. */
X
Xint	SyncFreq = 50;
X
XSyncRec()
X{
X	register Buffer	*b;
X
X	if (rec_fd == 0)
X		recinit();	/* Init recover file. */
X	if (rec_fd == -1)
X		return;
X	lseek(rec_fd, 0L, L_SET);
X	(void) time(&Header.UpdTime);
X	Header.Nbuffers = 0;
X	for (b = world; b != 0; b = b->b_next)
X		if (b->b_type == B_SCRATCH || !IsModified(b))
X			continue;
X		else
X			Header.Nbuffers++;
X	putn((char *) &Header, sizeof Header);
X	if (Header.Nbuffers != 0) {
X		SyncTmp();
X		for (b = world; b != 0; b = b->b_next)
X			if (b->b_type == B_SCRATCH || !IsModified(b))
X				continue;
X			else
X				dmp_buf(b);
X	}
X	flush(rec_out);
X}
@//E*O*F rec.c//
if test 2901 -ne "`wc -c <'rec.c'`"; then
    echo shar: error transmitting "'rec.c'" '(should have been 2901 characters)'
fi
fi # end of overwriting check
echo shar: "End of archive 4 (of 13)."
cp /dev/null ark4isdone
DONE=true
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13; do
    if test -f ark${I}isdone; then
        echo "You have run archive ${I}."
    else
        echo "You still need to run archive ${I}."
        DONE=false
    fi
done
case $DONE in
    true)
        echo "You have run all 13 archives."
        echo 'Now read the README and Makefile.'
        ;;
esac
##  End of shell archive.
exit 0



More information about the Mod.sources mailing list