[comp.sources.unix] v14i059: Jove, an emacs variant, version 4.9, Part03/21

rsalz@bbn.com (Rich Salz) (04/26/88)

Submitted-by: Jonathan Payne <jpayne@cs.rochester.edu>
Posting-number: Volume 14, Issue 59
Archive-name: jove4.9/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 21)."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './Ovmakefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./Ovmakefile'\"
else
echo shar: Extracting \"'./Ovmakefile'\" \(6758 characters\)
sed "s/^X//" >'./Ovmakefile' <<'END_OF_FILE'
X###########################################################################
X# This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE #
X# is 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# TMPDIR is where the tmp files get stored, usually /tmp or /tmp/jove.  If
X# your system does not remove subdirectories of /tmp on reboot (lots do
X# remove them these days) then it makes sense to make TMPDIR be /tmp/jove.
X# But if you want to recover buffers on system crashes, you should create a
X# directory that doesn't get clearned upon reboot, and use that instead.
X# You would probably want to clean out that directory periodically with
X# /etc/cron.  LIBDIR is for online documentation, the PORTSRV process,
X# RECOVER, and the system-wide .joverc file.  BINDIR is where to put the
X# executables JOVE and TEACHJOVE.  MANDIR is where the manual pages go for
X# JOVE, RECOVER and TEACHJOVE.  MANEXT is the extension for the man pages,
X# e.g., jove.1 or jove.l or jove.m.
X
DESTDIR =
TMPDIR = /tmp
LIBDIR = /usr/lib/jove
BINDIR = /bin
MANDIR = /usr/man/man1
MANEXT = 1
SHELL = /bin/csh
X
X# These should all just be right if the above ones are.
JOVE = $(DESTDIR)$(BINDIR)/jove
RECOVER = $(DESTDIR)$(LIBDIR)/recover
TEACHJOVE = $(DESTDIR)$(BINDIR)/teachjove
JOVERC = $(DESTDIR)$(LIBDIR)/.joverc
CMDS.DOC = $(DESTDIR)$(LIBDIR)/cmds.doc
TEACH-JOVE = $(DESTDIR)$(LIBDIR)/teach-jove
PORTSRV = $(DESTDIR)$(LIBDIR)/portsrv
JOVEM = $(DESTDIR)$(MANDIR)/jove.$(MANEXT)
RECOVERM = $(DESTDIR)$(MANDIR)/recover.$(MANEXT)
TEACHJOVEM = $(DESTDIR)$(MANDIR)/teachjove.$(MANEXT)
X
X# Select the right libraries for your system.
X#	2.9BSD:	LIBS =	-ltermlib -ljobs
X#	v7:	LIBS =	-ltermlib
X#	4.1BSD:	LIBS =	-ltermlib -ljobs
X#	4.2BSD:	LIBS =	-ltermlib
X#	4.3BSD:	LIBS =	-ltermlib
X
OVLIBS = -lovtermcap -lovjobs
LIBS = -ltermcap -ljobs
X
X# If you are not VMUNIX (vax running Berkeley Version 4), you must specify
X# the -i flags (split I/D space) and maybe the -x option (for adb to work).
X#	2.9BSD:	LDFLAGS = -x -i
X#	v7:	LDFLAGS = -x -i
X#	4.1BSD:	LDFLAGS =
X#	4.2BSD:	LDFLAGS =
X#	4.3BSD:	LDFLAGS =
X
LDFLAGS =  -x -i
X
CFLAGS = -O -V
X
COFLAGS = -rworking -q
X
BASESEG = funcdefs.o keymaps.o argcount.o ask.o buf.o ctype.o delete.o disp.o fmt.o fp.o \
X	  insert.o io.o jove.o malloc.o marks.o misc.o move.o re.o \
X	  screen.o table.o tune.o util.o version.o
OVLAY1 = abbrev.o rec.o paragraph.o macros.o
OVLAY2 = c.o wind.o vars.o
OVLAY3 = extend.o
OVLAY4 = iproc.o re1.o
OVLAY5 = proc.o scandir.o term.o case.o
X
OBJECTS = $(BASESEG) $(OVLAY1) $(OVLAY2) $(OVLAY3) $(OVLAY4) $(OVLAY5)
X
C-FILES = funcdefs.c abbrev.c argcount.c ask.c buf.c c.c case.c ctype.c delete.c disp.c \
X	extend.c fmt.c fp.c insert.c io.c iproc.c iproc-pipes.c iproc-ptys.c \
X	jove.c macros.c malloc.c marks.c misc.c move.c paragraph.c proc.c \
X	re.c re1.c rec.c scandir.c screen.c table.c term.c util.c vars.c version.c \
X	wind.c
X
H-FILES = ctype.h io.h jove.h re.h rec.h table.h temp.h termcap.h tune.h
X
BACKUPS = $(C-FILES) $(H-FILES) $(DOCS) teachjove.c recover.c setmaps.c portsrv.c \
X	tune.template Makefile Ovmakefile keymaps.txt README tags
X
DOCS =	doc/cmds.doc.nr doc/example.rc doc/jove.1 doc/jove.2 doc/jove.3 \
X	doc/jove.4 doc/jove.nr doc/recover.nr doc/system.rc doc/teach-jove \
X	doc/teachjove.nr doc/README
X
all:	xjove recover teachjove portsrv
X
xjove:	$(OBJECTS)
X	ld $(LDFLAGS) /lib/crt0.o \
X		-Z $(OVLAY1) \
X		-Z $(OVLAY2) \
X		-Z $(OVLAY3) \
X		-Z $(OVLAY4) \
X		-Z $(OVLAY5) \
X		-L $(BASESEG) \
X		-o xjove $(OVLIBS) -lovc
X	checkobj xjove
X	@-size xjove
X	@-date
X
portsrv:	portsrv.c
X	cc -o portsrv -n -O portsrv.c $(LIBS)
X
recover:	recover.c tune.o rec.h temp.h
X	cc -o recover -n -O recover.c tune.o -ljobs
X
teachjove:	teachjove.c
X	cc -o teachjove -n -O -DTEACHJOVE=\"$(TEACH-JOVE)\" teachjove.c
X
setmaps:	setmaps.c funcdefs.c
X	cc -o setmaps setmaps.c
X
keymaps.c:	setmaps keymaps.txt
X	setmaps < keymaps.txt > keymaps.c
X
tune.c: Makefile tune.template
X	@echo "/* Changes should be made in Makefile, not to this file! */" > tune.c
X	@echo "" >> tune.c
X	@sed -e 's;TMPDIR;$(TMPDIR);' \
X	     -e 's;LIBDIR;$(LIBDIR);' \
X	     -e 's;BINDIR;$(BINDIR);' \
X	     -e 's;SHELL;$(SHELL);' tune.template >> tune.c
X
install: $(LIBDIR) $(TEACH-JOVE) $(CMDS.DOC) $(JOVERC) $(PORTSRV) $(RECOVER) \
X	 $(JOVE) $(TEACHJOVE) $(JOVEM) $(RECOVERM) $(TEACHJOVEM)
X
X$(DESTDIR)$(LIBDIR):
X	-mkdir (DESTDIR)$(LIBDIR)
X
X$(TEACH-JOVE): doc/teach-jove
X	install -c -m 644 doc/teach-jove $(TEACH-JOVE)
X
X$(CMDS.DOC): doc/cmds.doc
X	install -c -m 644 doc/cmds.doc $(CMDS.DOC)
X
X$(JOVERC): doc/system.rc
X	install -c -m 644 doc/system.rc $(JOVERC)
X
X$(PORTSRV): portsrv
X	install -c -m 755 portsrv $(PORTSRV)
X
X$(RECOVER): recover
X	install -c -m 755 recover $(RECOVER)
X
X$(JOVE): xjove
X	install -c -m 755 xjove $(JOVE)
X
X$(TEACHJOVE): teachjove
X	install -c -m 755 teachjove $(TEACHJOVE)
X
X$(JOVEM): doc/jove.nr
X	@sed -e 's;TMPDIR;$(TMPDIR);' \
X	     -e 's;LIBDIR;$(LIBDIR);' \
X	     -e 's;SHELL;$(SHELL);' doc/jove.nr > /tmp/jove.nr
X	install -m 644 /tmp/jove.nr $(JOVEM)
X
X$(RECOVERM): doc/recover.nr
X	@sed -e 's;TMPDIR;$(TMPDIR);' \
X	     -e 's;LIBDIR;$(LIBDIR);' \
X	     -e 's;SHELL;$(SHELL);' doc/recover.nr > /tmp/recover.nr
X	install -m 644 /tmp/recover.nr $(RECOVERM)
X
X$(TEACHJOVEM): doc/teachjove.nr
X	@sed -e 's;TMPDIR;$(TMPDIR);' \
X	     -e 's;LIBDIR;$(LIBDIR);' \
X	     -e 's;SHELL;$(SHELL);' doc/teachjove.nr > /tmp/teachjove.nr
X	install -m 644 /tmp/teachjove.nr $(TEACHJOVEM)
X
echo:
X	@echo $(C-FILES) $(H-FILES)
X
lint:
X	lint -x $(C-FILES)
X	echo Done
X
tags:
X	ctags -w $(C-FILES) $(H-FILES)
X
X
jove.shar:
X	shar $(BACKUPS) doc/* > jove.shar
X
backup:
X	tar cf backup $(BACKUPS)
X
tape-backup:
X	tar cbf 20 /dev/rmt0 $(BACKUPS)
X
clean:
X	rm -f a.out core $(OBJECTS) keymaps.c xjove \
X		portsrv recover setmaps teachjove
X
X# abbrev.o: jove.h tune.h
X# ask.o: jove.h tune.h
X# buf.o: jove.h tune.h
X# c.o: jove.h tune.h
X# delete.o: jove.h tune.h
X# disp.o: jove.h tune.h termcap.h
X# extend.o: jove.h tune.h
X# fmt.o: jove.h tune.h termcap.h
X# funcdefs.o: jove.h tune.h
X# insert.o: jove.h tune.h
X# io.o: jove.h tune.h termcap.h temp.h
X# iproc.o: jove.h tune.h
X# jove.o: jove.h tune.h termcap.h
X# macros.o: jove.h tune.h
X# marks.o: jove.h tune.h
X# misc.o: jove.h tune.h
X# move.o: jove.h tune.h
X# portsrv.o: jove.h tune.h
X# proc.o: jove.h tune.h
X# re.o: jove.h tune.h
X# rec.o: jove.h tune.h temp.h rec.h
X# recover.o: jove.h tune.h temp.h rec.h
X# screen.o: jove.h tune.h temp.h termcap.h
X# setmaps.o: jove.h tune.h
X# term.o: jove.h tune.h
X# tune.o: tune.h
X# util.o: jove.h tune.h
X# wind.o: jove.h tune.h termcap.h
END_OF_FILE
if test 6758 -ne `wc -c <'./Ovmakefile'`; then
    echo shar: \"'./Ovmakefile'\" unpacked with wrong size!
fi
# end of './Ovmakefile'
fi
if test -f './abbrev.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./abbrev.c'\"
else
echo shar: Extracting \"'./abbrev.c'\" \(6522 characters\)
sed "s/^X//" >'./abbrev.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is 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
X#ifdef ABBREV
X
X#include "io.h"
X#include "ctype.h"
X
X#ifdef MSDOS
X#include <io.h>
X#endif
X#define HASHSIZE	20
X
struct abbrev {
X	unsigned int	a_hash;
X	char	*a_abbrev,
X		*a_phrase;
X	struct abbrev	*a_next;
X	data_obj	*a_cmdhook;
X};
X
X#ifdef MAC
X#	undef private
X#	define private
X#endif
X
X#ifdef	LINT_ARGS
private	void
X	define(struct abbrev **, char *, char *),
X	def_abbrev(struct abbrev **),
X	rest_abbrevs(char *),
X	save_abbrevs(char *);
X
private	unsigned int hash(char *);
private	struct abbrev * lookup(struct abbrev **, char *);
X#else
private	void
X	define(),
X	def_abbrev(),
X	rest_abbrevs(),
X	save_abbrevs();
X
private	unsigned int hash();
private	struct abbrev * lookup();
X#endif	/* LINT_ARGS */
X
X#ifdef MAC
X#	undef private
X#	define private static
X#endif
X
X#define GLOBAL	NMAJORS
private struct abbrev	*A_tables[NMAJORS + 1][HASHSIZE] = {0};
X
int AutoCaseAbbrev = 1;
X
private unsigned int
hash(a)
register char	*a;
X{
X	register unsigned int	hashval = 0;
X	register int	c;
X
X	while (c = *a++)
X		hashval = (hashval << 2) + c;
X
X	return hashval;
X}
X
private void
def_abbrev(table)
struct abbrev	*table[HASHSIZE];
X{
X	char	abbrev[100],
X		phrase[100];
X
X	strcpy(abbrev, ask((char *) 0, "abbrev: "));
X	strcpy(phrase, ask((char *) 0, "abbrev: %s phrase: ", abbrev));
X	define(table, abbrev, phrase);
X}
X
private struct abbrev *
lookup(table, abbrev)
register struct abbrev	*table[HASHSIZE];
register char	*abbrev;
X{
X	register struct abbrev	*ap;
X	unsigned int	h;
X
X	h = hash(abbrev);
X	for (ap = table[h % HASHSIZE]; ap; ap = ap->a_next)
X		if (ap->a_hash == h && strcmp(ap->a_abbrev, abbrev) == 0)
X			break;
X	return ap;
X}
X
private void
define(table, abbrev, phrase)
register struct abbrev	*table[HASHSIZE];
char	*abbrev,
X	*phrase;
X{
X	register struct abbrev	*ap;
X
X	ap = lookup(table, abbrev);
X	if (ap == 0) {
X		register unsigned int	h = hash(abbrev);
X
X		ap = (struct abbrev *) emalloc(sizeof *ap);
X		ap->a_hash = h;
X		ap->a_abbrev = copystr(abbrev);
X		h %= HASHSIZE;
X		ap->a_next = table[h];
X		ap->a_cmdhook = 0;
X		table[h] = ap;
X	} else
X		free(ap->a_phrase);
X	ap->a_phrase = copystr(phrase);
X}
X
void
AbbrevExpand()
X{
X	Bufpos	point;
X	char	wordbuf[100];
X	register char	*wp = wordbuf,
X			*cp;
X#if !(defined(IBMPC) || defined(MAC))
X	register int	c;
X#else
X	int c;
X#endif	
X	int	UC_count = 0;
X	struct abbrev	*ap;
X
X	DOTsave(&point);
X    WITH_TABLE(curbuf->b_major)
X	b_word(1);
X	while (curchar < point.p_char && ismword(c = linebuf[curchar])) {
X		if (AutoCaseAbbrev) {
X			if (isupper(c)) {
X				UC_count += 1;
X#if (defined(IBMPC) || defined(MAC))
X				lower(&c);
X#else
X				c = tolower(c);
X#endif				
X			}
X		}
X		*wp++ = c;
X		curchar += 1;
X	}
X	*wp = '\0';
X    END_TABLE();
X
X	if ((ap = lookup(A_tables[curbuf->b_major], wordbuf)) == 0 &&
X	    (ap = lookup(A_tables[GLOBAL], wordbuf)) == 0) {
X		SetDot(&point);
X		return;
X	}
X	del_char(BACKWARD, (wp - wordbuf));
X
X	for (cp = ap->a_phrase; c = *cp; ) {
X		if (AutoCaseAbbrev) {
X			insert_c(islower(c) && UC_count &&
X			       (cp == ap->a_phrase || (UC_count > 1 && (cp[-1] == ' '))) ?
X				toupper(c) : c, 1);
X		} else
X			insert_c(c, 1);
X		cp += 1;
X	}
X	if (ap->a_cmdhook != 0)
X		ExecCmd(ap->a_cmdhook);
X}
X
private char	*mode_names[NMAJORS + 1] = {
X	"Fundamental Mode",
X	"Text Mode",
X	"C Mode",
X#ifdef LISP
X	"Lisp Mode",
X#endif
X	"Global"
X};
X
private void
save_abbrevs(file)
char	*file;
X{
X	File	*fp;
X	struct abbrev	*ap,
X			**tp;
X	char	buf[LBSIZE];
X	int	i,
X		count = 0;
X
X	fp = open_file(file, buf, F_WRITE, COMPLAIN, QUIET);
X	for (i = 0; i <= GLOBAL; i++) {
X		fprintf(fp, "------%s abbrevs------\n", mode_names[i]);
X		for (tp = A_tables[i]; tp < &A_tables[i][HASHSIZE]; tp++)
X			for (ap = *tp; ap; ap = ap->a_next) {
X				fprintf(fp, "%s:%s\n",
X					ap->a_abbrev,
X					ap->a_phrase);
X				count += 1;
X			}
X	}
X	f_close(fp);
X	add_mess(" %d written.", count);
X}
X
private void
rest_abbrevs(file)
char	*file;
X{
X	int	eof = 0,
X		mode = -1,	/* Will be ++'d immediately */
X		lnum = 0;
X	char	*phrase_p;
X	File	*fp;
X	char	buf[LBSIZE];
X
X	fp = open_file(file, buf, F_READ, COMPLAIN, QUIET);
X	while (mode <= GLOBAL) {
X		eof = f_gets(fp, genbuf, LBSIZE);
X		if (eof || genbuf[0] == '\0')
X			break;
X		lnum += 1;
X		if (strncmp(genbuf, "------", 6) == 0) {
X			mode += 1;
X			continue;
X		}
X		if (mode == -1)
fmterr:			complain("Abbrev. format error, line %d.", file, lnum);
X		phrase_p = index(genbuf, ':');
X		if (phrase_p == 0)
X			goto fmterr;
X		*phrase_p++ = '\0';	/* Null terminate the abbrev. */
X		define(A_tables[mode], genbuf, phrase_p);
X	}
X	f_close(fp);
X	message(NullStr);
X}
X
void
DefGAbbrev()
X{
X	def_abbrev(A_tables[GLOBAL]);
X}
X
void
DefMAbbrev()
X{
X	def_abbrev(A_tables[curbuf->b_major]);
X}
X
void
SaveAbbrevs()
X{
X	char	filebuf[FILESIZE];
X
X	save_abbrevs(ask_file((char *) 0, (char *) 0, filebuf));
X}
X
void
RestAbbrevs()
X{
X	char	filebuf[FILESIZE];
X
X	rest_abbrevs(ask_file((char *) 0, (char *) 0, filebuf));
X}
X
void
EditAbbrevs()
X{
X	char	*tname = "jove_wam.$$$",
X		*EditName = "Abbreviation Edit";
X	Buffer	*obuf = curbuf,
X		*ebuf;
X
X	if (ebuf = buf_exists(EditName)) {
X		if (ebuf->b_type != B_SCRATCH)
X			confirm("Over-write buffer %b?", ebuf);
X	}
X	SetBuf(ebuf = do_select(curwind, EditName));
X	ebuf->b_type = B_SCRATCH;
X	initlist(ebuf);
X	/* Empty buffer.  Save the definitions to a tmp file
X	   and read them into this buffer so we can edit them. */
X	save_abbrevs(tname);
X	read_file(tname, NO);
X	message("[Edit definitions and then type C-X C-C]");
X	Recur();		/* We edit them ... now */
X	/* RESetBuf in case we deleted the buffer while we were editing. */
X	SetBuf(ebuf = do_select(curwind, EditName));
X	if (IsModified(ebuf)) {
X		SetBuf(ebuf);
X		file_write(tname, 0);
X		rest_abbrevs(tname);
X		unmodify();
X	}
X	(void) unlink(tname);
X	SetBuf(do_select(curwind, obuf->b_name));
X}
X
void
BindMtoW()
X{
X	struct abbrev	*ap;
X	char	*word;
X	data_obj	*hook;
X
X	word = ask((char *) 0, "Word: ");
X
X	if ((ap = lookup(A_tables[curbuf->b_major], word)) == 0 &&
X	    (ap = lookup(A_tables[GLOBAL], word)) == 0)
X	    	complain("%s: unknown abbrev.", word);
X
X	hook = findmac("Macro: ");
X	if (hook == 0)
X		complain("[Undefined macro]");
X	ap->a_cmdhook = hook;
X}
X
X#endif /* ABBREV */
END_OF_FILE
if test 6522 -ne `wc -c <'./abbrev.c'`; then
    echo shar: \"'./abbrev.c'\" unpacked with wrong size!
fi
# end of './abbrev.c'
fi
if test -f './delete.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./delete.c'\"
else
echo shar: Extracting \"'./delete.c'\" \(6544 characters\)
sed "s/^X//" >'./delete.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is 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/* Routines to perform all kinds of deletion.  */
X
X#include "jove.h"
X
X/* Assumes that either line1 or line2 is actual the current line, so it can
X   put its result into linebuf. */
X
void
patchup(line1, char1, line2, char2)
Line	*line1,
X	*line2;
register int	char1,
X		char2;
X{
X	if (line1 != line2)
X		ChkWindows(line1, line2);
X	DotTo(line1, char1);
X	modify();
X	linecopy(linebuf, curchar, lcontents(line2) + char2);
X
X	/* The following is a redisplay optimization. */
X	if (line1 != line2 && (char1 == 0 && char2 == 0))
X		line1->l_dline = line2->l_dline;
X
X	DFixMarks(line1, char1, line2, char2);
X	makedirty(curline);
X}
X
X/* Deletes the region by unlinking the lines in the middle,
X   and patching things up.  The unlinked lines are still in
X   order.  */
X
Line *
reg_delete(line1, char1, line2, char2)
Line	*line1,
X	*line2;
X{
X	register Line	*retline;
X
X	if ((line1 == line2 && char1 == char2) || line2 == 0)
X		complain((char *) 0);
X	(void) fixorder(&line1, &char1, &line2, &char2);
X
X	retline = nbufline();	/* New buffer line */
X
X	(void) ltobuf(line1, genbuf);
X	if (line1 == line2)
X		genbuf[char2] = '\0';
X
X	retline->l_prev = 0;
X	retline->l_dline = putline(&genbuf[char1]);
X	patchup(line1, char1, line2, char2);
X
X	if (line1 == line2)
X		retline->l_next = 0;
X	else {
X		retline->l_next = line1->l_next;
X		(void) ltobuf(line2, genbuf);
X		genbuf[char2] = '\0';
X		line2->l_dline = putline(genbuf);
X		/* Shorten this line */
X	}
X
X	if (line1 != line2) {
X		line1->l_next = line2->l_next;
X		if (line1->l_next)
X			line1->l_next->l_prev = line1;
X		else
X			curbuf->b_last = line1;
X		line2->l_next = 0;
X	}
X
X	return retline;
X}
X
void
lremove(line1, line2)
register Line	*line1,
X		*line2;
X{
X	Line	*next = line1->l_next;
X
X	if (line1 == line2)
X		return;
X	line1->l_next = line2->l_next;
X	if (line1->l_next)
X		line1->l_next->l_prev = line1;
X	else
X		curbuf->b_last = line1;
X	lfreereg(next, line2);	/* Put region at end of free line list. */
X}
X
X/* Delete character forward */
X
void
DelNChar()
X{
X	del_char(FORWARD, arg_value());
X}
X
X/* Delete character backward */
X
void
DelPChar()
X{
X	if (MinorMode(OverWrite)) {
X		int	count = min(arg_value(), curchar);
X
X		b_char(count);
X
X		/* overwrite with spaces */
X		set_arg_value(count);
X		LastKeyStruck = ' ';
X		SelfInsert();
X
X		b_char(count);
X	} else		
X		del_char(BACKWARD, arg_value());
X}
X
X/* Delete some characters.  If deleting forward then call for_char
X   to the final position otherwise call back_char.  Then delete the
X   region between the two with patchup(). */
X
void
del_char(dir, num)
X{
X	Bufpos	before,
X		after;
X	int	killp = (abs(num) > 1);
X
X	DOTsave(&before);
X	if (dir == FORWARD) f_char(num);
X		else b_char(num);
X	if (before.p_line == curline && before.p_char == curchar)
X		complain((char *) 0);
X	if (killp)
X		reg_kill(before.p_line, before.p_char, 1);
X	else {
X		DOTsave(&after);
X		(void) fixorder(&before.p_line, &before.p_char, &after.p_line, &after.p_char);
X		patchup(before.p_line, before.p_char, after.p_line, after.p_char);
X		lremove(before.p_line, after.p_line);
X	}
X}
X
X/* This kills a region between point, and line1/char1 and puts it on
X   the kill-ring.  If the last command was one of the kill commands,
X   the region is appended (prepended if backwards) to the last entry.  */
X
int	killptr = 0;
Line	*killbuf[NUMKILLS];
X
void
reg_kill(line2, char2, dot_moved)
Line	*line2;
X{
X	Line	*nl,
X		*line1 = curline;
X	int	char1 = curchar;
X	int	backwards;
X
X	backwards = !fixorder(&line1, &char1, &line2, &char2);
X	/* This is a kludge!  But it possible for commands that don't
X	   know which direction they are deleting in (e.g., delete
X	   previous word could have been called with a negative argument
X	   in which case, it wouldn't know that it really deleted
X	   forward. */
X
X	if (!dot_moved)
X		backwards = !backwards;
X
X	DotTo(line1, char1);
X
X	nl = reg_delete(line1, char1, line2, char2);
X
X	if (last_cmd != KILLCMD) {
X		killptr = ((killptr + 1) % NUMKILLS);
X		lfreelist(killbuf[killptr]);
X		killbuf[killptr] = nl;
X	} else {
X		Line	*lastln = lastline(nl);
X
X		if (backwards)
X			(void) DoYank(nl, 0, lastln, length(lastln), killbuf[killptr], 0, (Buffer *) 0);
X		else {
X			Line	*olastln = lastline(killbuf[killptr]);
X
X			(void) DoYank(nl, 0, lastln, length(lastln), olastln, length(olastln), (Buffer *) 0);
X		}
X	}
X	this_cmd = KILLCMD;
X}
X
void
DelReg()
X{
X	register Mark	*mp = CurMark();
X
X	reg_kill(mp->m_line, mp->m_char, 0);
X}
X
X/* Save a region.  A pretend kill. */
X
void
CopyRegion()
X{
X	register Line	*nl;
X	register Mark	*mp;
X	register int	status;
X
X	mp = CurMark();
X	if (mp->m_line == curline && mp->m_char == curchar)
X		complain((char *) 0);
X
X	killptr = ((killptr + 1) % NUMKILLS);
X	if (killbuf[killptr])
X		lfreelist(killbuf[killptr]);
X	nl = killbuf[killptr] = nbufline();
X	SavLine(nl, NullStr);
X	nl->l_next = nl->l_prev = 0;
X
X	status = inorder(mp->m_line, mp->m_char, curline, curchar);
X	if (status == -1)
X		return;
X
X	if (status)
X		(void) DoYank(mp->m_line, mp->m_char, curline, curchar,
X				nl, 0, (Buffer *) 0);
X	else
X		(void) DoYank(curline, curchar, mp->m_line, mp->m_char,
X				nl, 0, (Buffer *) 0);
X}
X
void
DelWtSpace()
X{
X	register char	*ep = &linebuf[curchar],
X			*sp = &linebuf[curchar];
X
X	while (*ep == ' ' || *ep == '\t')
X		ep += 1;
X	while (sp > linebuf && *(sp - 1) == ' ' || *(sp - 1) == '\t')
X		sp -= 1;
X	if (sp != ep) {
X		curchar = sp - linebuf;
X		DFixMarks(curline, curchar, curline, curchar + (ep - sp));
X		strcpy(sp, ep);
X		makedirty(curline);
X		modify();
X	}
X}
X
void
DelBlnkLines()
X{
X	register Mark	*dot;
X	int	all;
X
X	if (!blnkp(&linebuf[curchar]))
X		return;
X	dot = MakeMark(curline, curchar, M_FLOATER);
X	all = !blnkp(linebuf);
X	while (blnkp(linebuf) && curline->l_prev)
X		SetLine(curline->l_prev);
X	all |= (firstp(curline));
X	Eol();
X	DelWtSpace();
X	line_move(FORWARD, 1, NO);
X	while (blnkp(linebuf) && !eobp()) {
X		DelWtSpace();
X		del_char(FORWARD, 1);
X	}
X	if (!all && !eobp())
X		open_lines(1);
X	ToMark(dot);
X	DelMark(dot);
X}
X
void
DelNWord()
X{
X	dword(1);
X}
X
void
DelPWord()
X{
X	dword(0);
X}
X
void
dword(forward)
X{
X	Bufpos	savedot;
X
X	DOTsave(&savedot);
X	if(forward)  ForWord();
X		else BackWord();
X	reg_kill(savedot.p_line, savedot.p_char, 1);
X}
END_OF_FILE
if test 6544 -ne `wc -c <'./delete.c'`; then
    echo shar: \"'./delete.c'\" unpacked with wrong size!
fi
# end of './delete.c'
fi
if test -f './fp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./fp.c'\"
else
echo shar: Extracting \"'./fp.c'\" \(7807 characters\)
sed "s/^X//" >'./fp.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is 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 "ctype.h"
X#include "termcap.h"
X
X#ifdef MAC
X#	include "mac.h"
X#else
X#	include <sys/stat.h>
X#	ifndef MSDOS
X#		include <sys/file.h>
X#	else /* MSDOS */
X#		include <fcntl.h>
X#		include <io.h>
X#	endif /* MSDOS */
X#endif /* MAC */
X
X#include <errno.h>
X
X#ifdef MAC
X#	undef private
X#	define private
X#endif
X
X#ifdef	LINT_ARGS
private File * f_alloc(char *, int, int, char *, int);
X#ifdef RAINBOW
private int rbwrite(int, char *, int);
X#endif
X#else
private File * f_alloc();
X#ifdef RAINBOW
private int rbwrite();
X#endif
X#endif	/* LINT_ARGS */
X
X#ifdef MAC
X#	undef private
X#	define private static
X#endif
X
X#ifndef L_SET
X#	define L_SET 0
X#endif
X
X#define MAXFILES	20	/* good enough for my purposes */
X
private File	_openfiles[MAXFILES] = {0};
X
private File *
f_alloc(name, flags, fd, buffer, buf_size)
char	*name,
X	*buffer;
X{
X	register File	*fp;
X	register int	i;
X
X	for (fp = _openfiles, i = 0; i < MAXFILES; i++, fp++)
X		if (fp->f_flags == 0)
X			break;
X	if (i == MAXFILES)
X		complain("[Too many open files!]");
X	fp->f_bufsize = buf_size;
X	fp->f_cnt = 0;
X	fp->f_fd = fd;
X	fp->f_flags = flags;
X	if (buffer == 0) {
X		buffer = emalloc(buf_size);
X		fp->f_flags |= F_MYBUF;
X	}
X	fp->f_base = fp->f_ptr = buffer;
X	fp->f_name = copystr(name);
X
X	return fp;
X}
X
void
gc_openfiles()
X{
X	register File	*fp;
X
X	for (fp = _openfiles; fp < &_openfiles[MAXFILES]; fp++)
X		if (fp->f_flags != 0 && (fp->f_flags & F_LOCKED) == 0)
X			f_close(fp);
X}
X
File *
fd_open(name, flags, fd, buffer, bsize)
char	*name,
X	*buffer;
X{
X	return f_alloc(name, flags, fd, buffer, bsize);
X}
X
File *
f_open(name, flags, buffer, buf_size)
char	*name,
X	*buffer;
X{
X	register int	fd;
X	int	mode = F_MODE(flags);
X
X	if (mode == F_READ)
X		fd = open(name, 0);
X	if (mode == F_APPEND) {
X		fd = open(name, 1);
X		if (fd == -1)
X			mode = F_WRITE;
X		else
X			(void) lseek(fd, 0L, 2);
X	}
X	if (mode == F_WRITE)
X		fd = creat(name, CreatMode);
X	if (fd == -1)
X		return NIL;
X#ifdef MSDOS
X	else
X		setmode(fd, 0x8000);
X#endif /* MSDOS */
X	return f_alloc(name, flags, fd, buffer, buf_size);
X}
X
void
f_close(fp)
File	*fp;
X{
X	flush(fp);
X#ifdef BSD4_2 
X	if (fp->f_flags & (F_WRITE|F_APPEND))
X		(void) fsync(fp->f_fd);
X#endif 
X	(void) close(fp->f_fd);
X	if (fp->f_flags & F_MYBUF)
X		free(fp->f_base);
X	free(fp->f_name);
X	fp->f_flags = 0;	/* indicates that we're available */
X}
X
int
filbuf(fp)
File	*fp;
X{
X	if (fp->f_flags & (F_EOF|F_ERR))
X		return EOF;
X	fp->f_ptr = fp->f_base;
X#ifndef MSDOS
X	do
X#endif /* MSDOS */
X		fp->f_cnt = read(fp->f_fd, fp->f_base, fp->f_bufsize);
X#ifndef MSDOS
X	while (fp->f_cnt == -1 && errno == EINTR);
X#endif /* MSDOS */
X	if (fp->f_cnt == -1) {
X		printf("[Read error %d]", errno);
X		fp->f_flags |= F_ERR;
X	}
X	if (fp->f_cnt == 0) {
X		fp->f_flags |= F_EOF;
X		return EOF;
X	}
X	io_chars += fp->f_cnt;
X	return getc(fp);
X}
X
void
putstr(s)
register char	*s;
X{
X#ifndef IBMPC
X	register int	c;
X
X	while (c = *s++)
X		putchar(c);
X#else /* IBMPC */
X	write_emif(s);
X#endif /* IBMPC */
X}
X
void
fputnchar(s, n, fp)
register char	*s;
register int	n;
register File	*fp;
X{
X	while (--n >= 0)
X		putc(*s++, fp);
X}
X
void
flusho()
X{
X#ifndef IBMPC
X	_flush(EOF, stdout);
X#endif /* IBMPC */
X}
X
void
flush(fp)
File	*fp;
X{
X	_flush(EOF, fp);
X}
X
void
f_seek(fp, offset)
register File	*fp;
off_t	offset;
X{
X	if (fp->f_flags & F_WRITE)
X		flush(fp);
X	fp->f_cnt = 0;		/* next read will filbuf(), next write
X				   will flush() with no bad effects */
X	lseek(fp->f_fd, (long) offset, L_SET);
X}
X
int		/* is void - but for lints sake */
X_flush(c, fp)
register File	*fp;
X{
X	register int	n;
X
X	if (fp->f_flags & (F_READ | F_STRING | F_ERR))
X		return EOF;
X	if (((n = (fp->f_ptr - fp->f_base)) > 0) &&
X#ifndef RAINBOW
X	    (write(fp->f_fd, fp->f_base, n) != n) &&
X#else
X	    (rbwrite(fp->f_fd, fp->f_base, n) != n) &&
X#endif
X	    (fp != stdout)) {
X	    	fp->f_flags |= F_ERR;
X		error("[I/O error(%d); file = %s, fd = %d]",
X			errno, fp->f_name, fp->f_fd);
X	}
X
X	fp->f_cnt = fp->f_bufsize;
X	fp->f_ptr = fp->f_base;
X	if (c != EOF)
X		return putc(c, fp);
X}
X
int
f_gets(fp, buf, max)
register File	*fp;
char	*buf;
X{
X	register char	*cp = buf;
X	register int	c;
X	char	*endp = buf + max - 1;
X
X	if (fp->f_flags & F_EOF)
X		return EOF;
X	while (((c = getc(fp)) != EOF) && (c != '\n')) {
X		if (c == '\0')  /* possibly different from NULL */
X			break;		/* sorry we don't read nulls */
X#ifdef MSDOS
X		if (c == '\r') {
X			if ((c = getc(fp)) == '\n')
X			   break;
X			else
X			   *cp++ = '\r';
X		}
X#endif /* MSDOS */
X		if (cp >= endp) {
X			add_mess(" [Line too long]");
X			rbell();
X			return EOF;
X		}
X		*cp++ = c;
X	}
X	*cp = '\0';
X	if (c == EOF) {
X		if (cp != buf)
X			add_mess(" [Incomplete last line]");
X		fp->f_flags |= F_EOF;
X		return EOF;
X	}
X	io_lines += 1;
X	return 0;	/* this means okay */
X}
X
X/* skip to beginning of next line, i.e., next read returns first
X   character of new line */
X
void
f_toNL(fp)
register File	*fp;
X{
X	register int	c;
X
X	if (fp->f_flags & F_EOF)
X		return;
X	while (((c = getc(fp)) != EOF) && (c != '\n'))
X		;
X	if (c == EOF)
X		fp->f_flags |= F_EOF;
X}
X
void
f_readn(fp, addr, n)
register File	*fp;
register char	*addr;
register int	n;
X{
X	while (--n >= 0)
X		*addr++ = getc(fp);
X}
X
int
f_getint(fp)
File	*fp;
X{
X	int	n = 0,
X		c;
X
X	while (isdigit(c = getc(fp)))
X		n = (n * 10) + c;
X	return n;
X}
X
X/* Deals with output to the terminal, setting up the amount of characters
X   to be buffered depending on the output baud rate.  Why it's in a 
X   separate file I don't know ... */
X
private char	one_buf;
X
int	BufSize = 1;
X
private File	_stdout = {1, 1, 1, F_WRITE, &one_buf, &one_buf};
File	*stdout = &_stdout;
X
X/* put a string with padding */
X
X#ifndef IBMPC
void
tputc(c)
X{
X	putchar(c);
X}
X
X#undef putchar		/* for files which forget to include io.h,
X					   here's a real putchar procedure. */
void
putchar(c)
X{
X	putc(c, stdout);
X}
X
X#endif /* IBMPC */
X#ifndef MAC
void
putpad(str, lines)
char	*str;
X{
X#ifndef IBMPC
X	if (str)
X		tputs(str, lines, tputc);
X#else /* IBMPC */
X	write_emif(str);
X#endif /* IBMPC */
X}
X#endif
X
X/* Determine the number of characters to buffer at each baud rate.  The
X   lower the number, the quicker the response when new input arrives.  Of
X   course the lower the number, the more prone the program is to stop in
X   output.  Decide what matters most to you. This sets BufSize to the right
X   number or chars, and initiaizes `stdout'.  */
X
void
settout(ttbuf)
char	*ttbuf;
X{
X#ifndef MAC
X#ifndef MSDOS
X	static int speeds[] = {
X		1,	/* 0	*/
X		1,	/* 50	*/
X		1,	/* 75	*/
X		1,	/* 110	*/
X		1,	/* 134	*/
X		1,	/* 150	*/
X		1,	/* 200	*/
X		2,	/* 300	*/
X		4,	/* 600	*/
X		8,	/* 1200 */
X		16,	/* 1800	*/
X		32,	/* 2400	*/
X		128,	/* 4800	*/
X		256,	/* 9600	*/
X		512,	/* EXTA	*/
X		1024	/* EXT	*/
X	};
X	flusho();		/* flush the one character buffer */
X	BufSize = min(MAXTTYBUF, speeds[ospeed] * max(LI / 24, 1));
X	stdout = fd_open("/dev/tty", F_WRITE|F_LOCKED, 1, ttbuf, BufSize);
X#else /* MSDOS */
X#ifndef IBMPC
X	flusho();		/* flush the one character buffer */
X	BufSize = BUFSIZ; 
X	stdout = fd_open("con", F_WRITE|F_LOCKED, 1, ttbuf, BufSize);
X#endif	/* IBMPC */
X#endif /* MSDOS */
X#endif /* MAC */
X}
X
X#ifdef RAINBOW
X
X/*
X * use the Rainbow's video output function
X */
X
X#include <dos.h>
X
private int
rbwrite(fd, buf, cnt)
char *buf;
X{
X	union REGS vr;
X
X	if (fd != 1) {
X		write(fd, buf, cnt);
X	} else {
X		while (cnt-- > 0) {
X			vr.x.ax = *buf++;
X			vr.x.di = 0;
X			int86(0x18, &vr, &vr);
X		}
X	}
X}
X#endif /* RAINBOW */
END_OF_FILE
if test 7807 -ne `wc -c <'./fp.c'`; then
    echo shar: \"'./fp.c'\" unpacked with wrong size!
fi
# end of './fp.c'
fi
if test -f './iproc-pipes.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./iproc-pipes.c'\"
else
echo shar: Extracting \"'./iproc-pipes.c'\" \(5928 characters\)
sed "s/^X//" >'./iproc-pipes.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is 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_toproc == -1)
X#define makedead(p)	(proc_state(p) = DEAD)
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
private Process	*procs = 0;
X
int	ProcInput,
X	ProcOutput,
X	NumProcs = 0;
X
char *
pstate(p)
Process	*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
static Process *
proc_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
procs_read()
X{
X	struct header {
X		int	pid;
X		int	nbytes;
X	} header;
X	int	n;
X	long	nbytes;
X	static int	here = NO;
X
X	if (here)	
X		return;
X	sighold(SIGCHLD);	/* block any other children */
X	here = YES;
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	here = NO;
X	sigrelse(SIGCHLD);
X}
X
read_proc(pid, nbytes)
int	pid;
register 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		proc_close(p);
X		makedead(p);
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
ProcKill()
X{
X	proc_kill(curbuf->b_process, SIGKILL);
X}
X
ProcInt()
X{
X	proc_kill(curbuf->b_process, SIGINT);
X}
X
ProcQuit()
X{
X	proc_kill(curbuf->b_process, SIGQUIT);
X}
X
private
proc_close(p)
Process	*p;
X{
X	sighold(SIGCHLD);
X
X	if (p->p_toproc >= 0) {
X		(void) close(p->p_toproc);
X		p->p_toproc = -1;	/* writes will fail */
X		NumProcs -= 1;
X	}
X
X	sigrelse(SIGCHLD);
X}
X
do_rtp(mp)
register 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
private
proc_strt(bufname, clobber, va_alist)
char	*bufname;
va_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	sighold(SIGCHLD);
X#ifdef SIGWINCH
X	sighold(SIGWINCH);
X#endif
X	switch (pid = fork()) {
X	case -1:
X		pclose(toproc);
X		complain("[Fork failed.]");
X
X	case 0:
X		sigrelse(SIGCHLD);
X#ifdef SIGWINCH
X		sigrelse(SIGWINCH);
X#endif
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, argv);
X		printf("execl failed\n");
X		_exit(1);
X	}
X
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, M_FLOATER);
X
X	newp->p_toproc = toproc[1];
X	newp->p_reason = 0;
X	NumProcs += 1;
X	(void) close(toproc[0]);
X	SetWind(owind);
X	sigrelse(SIGCHLD);
X#ifdef SIGWINCH
X	sigrelse(SIGWINCH);
X#endif
X}
X
pinit()
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
doread(fd, buf, n)
char	*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}
END_OF_FILE
if test 5928 -ne `wc -c <'./iproc-pipes.c'`; then
    echo shar: \"'./iproc-pipes.c'\" unpacked with wrong size!
fi
# end of './iproc-pipes.c'
fi
if test -f './iproc-ptys.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./iproc-ptys.c'\"
else
echo shar: Extracting \"'./iproc-ptys.c'\" \(7915 characters\)
sed "s/^X//" >'./iproc-ptys.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is 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#include <errno.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	/* brand new, never been ... received no input */
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#define makedead(p)	(proc_state(p) = DEAD)
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
private Process	*procs = 0;
X
long	global_fd = 1;
int	NumProcs = 0;
X
X#ifdef BRLUNIX
X	extern struct sg_brl sg1;
X#else
X	extern struct sgttyb sg1;
X#endif
X
extern struct tchars tc1;
X
X#ifdef TIOCSLTC
X	extern struct ltchars ls1;
X#endif
X
char *
pstate(p)
Process	*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	case NEW:
X		return "New";
X
X	default:
X		return "Unknown state";
X	}
X}
X
static Process *
proc_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
read_proc(fd)
register 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 == -1 && errno == EIO) {
X		if (proc_state(p) == NEW)
X			return;
X		proc_close(p);
X		makedead(p);
X		return;
X	} else {
X		if (proc_state(p) != RUNNING) {
X			proc_state(p) = RUNNING;
X			UpdModLine = YES;
X		}
X	}
X	if (n <= 0) {
X		if (n == 0)
X			strcpy(ibuf, "[Process EOF]");
X		else
X			sprintf(ibuf, "\n[pty read error: %d]\n", errno);
X	} else
X		ibuf[n] = '\0';
X	proc_rec(p, ibuf);
X}
X
ProcKill()
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
ProcCont()
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
ProcEof()
X{
X	send_p(tc1.t_eofc);
X}
X
ProcInt()
X{
X	send_p(tc1.t_intrc);
X}
X
ProcQuit()
X{
X	send_p(tc1.t_quitc);
X}
X
ProcStop()
X{
X	send_p(ls1.t_suspc);
X}
X
ProcDStop()
X{
X	send_p(ls1.t_dsuspc);
X}
X
send_p(c)
char	c;
X{
X	Process	*p;
X	char	buf[2];
X
X	if ((p = curbuf->b_process) == 0)
X		complain("[No process]");
X	ToLast();
X	buf[0] = c;
X	buf[1] = '\0';
X	proc_rec(p, buf);
X	(void) write(p->p_fd, &c, 1);
X}
X
private
proc_close(p)
Process *p;
X{
X	sighold(SIGCHLD);	/* be mutually exclusive */
X
X	if (p->p_fd >= 0) {
X		(void) close(p->p_fd);
X		global_fd &= ~(1L << p->p_fd);
X		NumProcs -= 1;
X		p->p_fd = -1;
X	}
X
X	sigrelse(SIGCHLD);
X}
X
do_rtp(mp)
register 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	int	nbytes;
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		if (nbytes = strlen(gp))
X			(void) write(p->p_fd, gp, nbytes);
X		line1 = line1->l_next;
X		char1 = 0;
X	}
X}
X
X/* VARARGS2 */
X
private
proc_strt(bufname, clobber, va_alist)
char	*bufname;
va_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		ptyfd,
X		ttyfd,
X	 	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 ((ptyfd = 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
out:	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	sighold(SIGCHLD);
X#ifdef SIGWINCH
X	sighold(SIGWINCH);
X#endif
X	switch (pid = fork()) {
X	case -1:
X		(void) close(ptyfd);
X		message("[Fork failed!]");
X		goto fail;
X
X	case 0:
X		sigrelse(SIGCHLD);
X#ifdef SIGWINCH
X		sigrelse(SIGWINCH);
X#endif
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		if ((ttyfd = open(ttybuf, 2)) < 0)
X			exit(-1);
X		(void) dup2(ttyfd, 1);
X		(void) dup2(ttyfd, 2);
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	newp = (Process *) emalloc(sizeof *newp);
X
X	newp->p_fd = ptyfd;
X	newp->p_pid = pid;
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 = NEW;
X	newp->p_reason = 0;
X	newp->p_mark = MakeMark(curline, curchar, M_FLOATER);
X
X	newp->p_next = procs;
X	procs = newp;
X	NumProcs += 1;
X	global_fd |= 1L << newp->p_fd;
X	SetWind(owind);
X
fail:	sigrelse(SIGCHLD);
X#ifdef SIGWINCH
X	sigrelse(SIGWINCH);
X#endif
X}
X	
pinit()
X{
X	(void) signal(SIGCHLD, proc_child);
X}
X
END_OF_FILE
if test 7915 -ne `wc -c <'./iproc-ptys.c'`; then
    echo shar: \"'./iproc-ptys.c'\" unpacked with wrong size!
fi
# end of './iproc-ptys.c'
fi
if test -f './macros.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./macros.c'\"
else
echo shar: Extracting \"'./macros.c'\" \(7870 characters\)
sed "s/^X//" >'./macros.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is 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 "ctype.h"
X#include "io.h"
X
X#ifdef MAC
X#	undef private
X#	define private
X#endif
X
X#ifdef	LINT_ARGS
private void
X	add_mac(struct macro *),
X	del_mac(struct macro *),
X	pop_macro_stack(void),
X	push_macro_stack(struct macro *, int);
X	
private int
X	PrefChar(int);
X
private struct macro * mac_exists(char *);
X#else
private void
X	add_mac(),
X	del_mac(),
X	pop_macro_stack(),
X	push_macro_stack();
X	
private int
X	PrefChar();
X
private struct macro * mac_exists();
X#endif	/* LINT_ARGS */
X
X#ifdef MAC
X#	undef private
X#	define private static
X#endif
X
struct macro	*macros = 0;		/* macros */
int	InMacDefine = NO;
X
private void
add_mac(new)
struct macro	*new;
X{
X	register struct macro	*mp,
X				*prev = 0;
X
X	for (mp = macros; mp != 0; prev = mp, mp = mp->m_nextm)
X		if (mp == new)
X			return;
X
X	if (prev)
X		prev->m_nextm = new;
X	else
X		macros = new;
X	new->m_nextm = 0;
X	new->Type = MACRO;
X}
X
private void
del_mac(mac)
struct macro	*mac;
X{
X	register struct macro	*m;
X
X	for (m = macros; m != 0; m = m->m_nextm)
X		if (m->m_nextm == mac) {
X			m->m_nextm = mac->m_nextm;
X			break;
X		}
X	free(mac->Name);
X	free(mac->m_body);
X	free((char *) mac);
X}
X
struct macro	KeyMacro;	/* Macro used for defining */
X
X/* To execute a macro, we have a "stack" of running macros.  Whenever
X   we execute a macro, we push it on the stack, run it, then pop it
X   from the stack.  */
struct m_thread {
X	struct m_thread	*mt_prev;
X	struct macro	*mt_mp;
X	int	mt_offset,
X		mt_count;
X};
X
private struct m_thread	*mac_stack = 0;
X
void
unwind_macro_stack()
X{
X	while (mac_stack != 0)
X		pop_macro_stack();
X}
X
private void
pop_macro_stack()
X{
X	register struct m_thread	*m;
X
X	if ((m = mac_stack) == 0)
X		return;
X	mac_stack = m->mt_prev;
X	free_mthread(m);
X}
X
struct m_thread *
alloc_mthread()
X{
X	return (struct m_thread *) emalloc(sizeof (struct m_thread));
X}
X
void
free_mthread(t)
struct m_thread	*t;
X{
X	free((char *) t);
X}
X
private void
push_macro_stack(m, count)
struct macro	*m;
X{
X	struct m_thread	*t;
X
X	t = alloc_mthread();
X	t->mt_prev = mac_stack;
X	mac_stack = t;
X	t->mt_offset = 0;
X	t->mt_mp = m;
X	t->mt_count = count;
X}
X
void
do_macro(mac)
struct macro	*mac;
X{
X	push_macro_stack(mac, arg_value());
X}
X
private struct macro *
mac_exists(name)
char	*name;
X{
X	register struct macro	*mp;
X
X	for (mp = macros; mp; mp = mp->m_nextm)
X		if (strcmp(mp->Name, name) == 0)
X			return mp;
X	return 0;
X}
X
void
mac_init()
X{
X	add_mac(&KeyMacro);
X	KeyMacro.Name = "keyboard-macro";
X	KeyMacro.m_len = 0;
X	KeyMacro.m_buflen = 16;
X	KeyMacro.m_body = emalloc(KeyMacro.m_buflen);
X}
X
void
mac_putc(c)
int	c;
X{
X	if (KeyMacro.m_len >= KeyMacro.m_buflen) {
X		KeyMacro.m_buflen += 16;
X		KeyMacro.m_body = realloc(KeyMacro.m_body, (unsigned) KeyMacro.m_buflen);
X		if (KeyMacro.m_body == 0) {
X			KeyMacro.m_buflen = KeyMacro.m_len = 0;
X			complain("[Can't allocate storage for keyboard macro]");
X		}
X	}
X	KeyMacro.m_body[KeyMacro.m_len++] = c;
X}
X
int
in_macro()
X{
X	return (mac_stack != 0);
X}
X
int
mac_getc()
X{
X	struct m_thread	*mthread;
X	struct macro	*m;
X
X	if ((mthread = mac_stack) == 0)
X		return -1;
X	m = mthread->mt_mp;
X	if (mthread->mt_offset == m->m_len) {
X		mthread->mt_offset = 0;
X		if (--mthread->mt_count == 0)
X			pop_macro_stack();
X		return mac_getc();
X	}
X	return m->m_body[mthread->mt_offset++];
X}
X
void
NameMac()
X{
X	char	*name;
X	struct macro	*m;
X
X	if (KeyMacro.m_len == 0)
X		complain("[No keyboard macro to name!]");
X	if (in_macro() || InMacDefine)
X		complain("[Can't name while defining/executing]");
X	if ((m = mac_exists(name = ask((char *) 0, ProcFmt))) == 0)
X		m = (struct macro *) emalloc(sizeof *m);
X	else {
X		if (strcmp(name, KeyMacro.Name) == 0)
X			complain("[Can't name it that!]");
X		free(m->Name);
X		free(m->m_body);
X	}
X	name = copystr(name);
X	m->Type = KeyMacro.Type;
X	m->m_len = KeyMacro.m_len;
X	m->m_buflen = KeyMacro.m_buflen;
X	m->m_body = emalloc(m->m_buflen);
X	byte_copy(KeyMacro.m_body, m->m_body, m->m_len);
X	m->m_flags = SAVE;
X	m->Name = name;
X	add_mac(m);
X}
X
void
RunMacro()
X{
X	struct macro	*m;
X
X	if (m = (struct macro *) findmac(ProcFmt))
X		do_macro(m);
X}
X
void
pr_putc(c, fp)
File	*fp;
X{
X	if (c == '\\' || c == '^')
X		putc('\\', fp);
X	 else if (isctrl(c)) {
X		putc('^', fp);
X		c = (c == RUBOUT) ? '?' : (c + '@');
X	}
X	putc(c, fp);
X}
X
void
WriteMacs()
X{
X	struct macro	*m;
X	char	*file,
X		filebuf[FILESIZE];
X	File	*fp;
X	int	i;
X
X	file = ask_file((char *) 0, (char *) 0, filebuf);
X	fp = open_file(file, iobuff, F_WRITE, COMPLAIN, QUIET);
X
X	/* Don't write the keyboard macro which is always the first */
X	for (m = macros->m_nextm; m != 0; m = m->m_nextm) {
X		fprintf(fp, "define-macro %s ", m->Name);
X		for (i = 0; i < m->m_len; i++)
X			pr_putc(m->m_body[i], fp);
X		putc('\n', fp);
X		m->m_flags &= ~SAVE;
X	}
X	close_file(fp);
X}
X
void
DefKBDMac()
X{
X	char	*macro_name,
X		*macro_body,
X		nextc,
X		c,
X		macro_buffer[LBSIZE];
X	int	i;
X	struct macro	*m;
X
X	macro_name = do_ask(" \r\n", (int (*)()) 0, (char *) 0, ProcFmt);
X	if (macro_name == 0)
X		complain("[No default]");
X	macro_name = copystr(macro_name);
X	if (m = mac_exists(macro_name))
X		del_mac(m);
X	macro_body = ask((char *) 0, ": %f %s enter body: ", macro_name);
X	i = 0;
X	while ((c = *macro_body++) != '\0') {
X		if (c == '\\') {
X			if ((nextc = *macro_body++) == LF)
X				complain("[Premature end of line]");
X			c = nextc;
X		} else if (c == '^') {
X			if ((nextc = *macro_body++) == '?')
X				c = RUBOUT;
X			else if (isalpha(nextc) || index("@[\\]^_", nextc))
X				c = CTL(nextc);
X			else
X				complain("Bad control-character: '%c'", nextc);
X		}
X		macro_buffer[i++] = c;
X	}
X	m = (struct macro *) emalloc(sizeof (*m));
X	m->Name = macro_name;
X	m->m_len = m->m_buflen = i;
X	m->m_body = emalloc(i);
X	m->m_flags = InJoverc ? 0 : SAVE;
X	byte_copy(macro_buffer, m->m_body, i);
X	add_mac(m);
X}
X
void
Remember()
X{
X	/* We're already executing the macro; ignore any attempts
X	   to define the keyboard macro while we are executing. */
X	if (in_macro())
X		return;
X	if (InMacDefine)
X		message("[Already defining ... continue with definition]");
X	else {
X		UpdModLine = YES;
X		InMacDefine = YES;
X		KeyMacro.m_len = 0;
X		message("Defining...");
X	}
X}
X
X/* Is `c' a prefix character */
X
private int
PrefChar(c)
X{
X	return (int) IsPrefix(mainmap[c]);
X}
X
void
Forget()
X{
X	char	*cp;
X	struct macro	*m = &KeyMacro;
X
X	UpdModLine = YES;
X	if (InMacDefine) {
X		message("Keyboard macro defined.");
X		InMacDefine = NO;
X
X		/* try and strip off the key sequence that invoked us */
X		cp = &m->m_body[m->m_len - 2];
X		if (PrefChar(*cp))
X			m->m_len -= 2;
X		else if (commands[cp[1]].c_proc == Forget)
X			m->m_len -= 1;
X	} else
X		complain("[end-kbd-macro: not currently defining macro!]");
X}
X
void
ExecMacro()
X{
X	do_macro(&KeyMacro);
X}
X
void
MacInter()
X{
X	extern int	Interactive;
X
X	if (!Asking)
X		return;
X	Interactive = 1;
X}
X
int
ModMacs()
X{
X	register struct macro	*m;
X
X	for (m = macros->m_nextm; m != 0; m = m->m_nextm)
X		if (m->m_flags & SAVE)
X			return YES;
X	return NO;
X}
X
data_obj *
findmac(prompt)
char	*prompt;
X{
X	char	*strings[100];
X	register char	**strs = strings;
X	register int	com;
X	register struct macro	*m = macros;
X
X	for (; m != 0; m = m->m_nextm)
X		*strs++ = m->Name;
X	*strs = 0;
X
X	if ((com = complete(strings, prompt, NOTHING)) < 0)
X		return 0;
X	m = macros;
X	while (--com >= 0)
X		m = m->m_nextm;
X	return (data_obj *) m;
X}
X
void
DelMacro()
X{
X	struct macro	*m;
X
X	if ((m = (struct macro *) findmac(ProcFmt)) == 0)
X		return;
X	if (m == &KeyMacro)
X		complain("[It's illegal to delete the keyboard-macro!]");
X	del_mac(m);
X}
END_OF_FILE
if test 7870 -ne `wc -c <'./macros.c'`; then
    echo shar: \"'./macros.c'\" unpacked with wrong size!
fi
# end of './macros.c'
fi
echo shar: End of archive 3 \(of 21\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 21 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.