BSD 4_4_Lite2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Thu, 9 Jan 1992 15:47:04 +0000 (07:47 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Thu, 9 Jan 1992 15:47:04 +0000 (07:47 -0800)
Work on file usr/src/contrib/jove-4.14.6/Readme.dos
Work on file usr/src/contrib/jove-4.14.6/Makefile.dos
Work on file usr/src/contrib/jove-4.14.6/Readme.mac
Work on file usr/src/contrib/jove-4.14.6/README
Work on file usr/src/contrib/jove-4.14.6/argcount.h
Work on file usr/src/contrib/jove-4.14.6/ask.c
Work on file usr/src/contrib/jove-4.14.6/buf.c
Work on file usr/src/contrib/jove-4.14.6/argcount.c
Work on file usr/src/contrib/jove-4.14.6/buf.h
Work on file usr/src/contrib/jove-4.14.6/abbrev.c
Work on file usr/src/contrib/jove-4.14.6/chars.h
Work on file usr/src/contrib/jove-4.14.6/c.c
Work on file usr/src/contrib/jove-4.14.6/case.c
Work on file usr/src/contrib/jove-4.14.6/funcdefs.c
Work on file usr/src/contrib/jove-4.14.6/ctype.h
Work on file usr/src/contrib/jove-4.14.6/disp.c
Work on file usr/src/contrib/jove-4.14.6/ctype.c
Work on file usr/src/contrib/jove-4.14.6/delete.c
Work on file usr/src/contrib/jove-4.14.6/disp.h
Work on file usr/src/contrib/jove-4.14.6/extend.c
Work on file usr/src/contrib/jove-4.14.6/sysdep.h
Work on file usr/src/contrib/jove-4.14.6/fp.h
Work on file usr/src/contrib/jove-4.14.6/fp.c
Work on file usr/src/contrib/jove-4.14.6/pcscr.c
Work on file usr/src/contrib/jove-4.14.6/fmt.c
Work on file usr/src/contrib/jove-4.14.6/misc.c
Work on file usr/src/contrib/jove-4.14.6/getch.c
Work on file usr/src/contrib/jove-4.14.6/kbd.c
Work on file usr/src/contrib/jove-4.14.6/io.h
Work on file usr/src/contrib/jove-4.14.6/insert.c
Work on file usr/src/contrib/jove-4.14.6/io.c
Work on file usr/src/contrib/jove-4.14.6/iproc.c
Work on file usr/src/contrib/jove-4.14.6/iproc-pipes.c
Work on file usr/src/contrib/jove-4.14.6/jove.c
Work on file usr/src/contrib/jove-4.14.6/jove.h
Work on file usr/src/contrib/jove-4.14.6/util.c
Work on file usr/src/contrib/jove-4.14.6/keymaps.h
Work on file usr/src/contrib/jove-4.14.6/iproc.h
Work on file usr/src/contrib/jove-4.14.6/keymaps.c
Work on file usr/src/contrib/jove-4.14.6/list.c
Work on file usr/src/contrib/jove-4.14.6/loadavg.c
Work on file usr/src/contrib/jove-4.14.6/list.h
Work on file usr/src/contrib/jove-4.14.6/keys.txt
Work on file usr/src/contrib/jove-4.14.6/mac.c
Work on file usr/src/contrib/jove-4.14.6/mac.h
Work on file usr/src/contrib/jove-4.14.6/makedep
Work on file usr/src/contrib/jove-4.14.6/marks.c
Work on file usr/src/contrib/jove-4.14.6/menumaps.txt
Work on file usr/src/contrib/jove-4.14.6/macros.c
Work on file usr/src/contrib/jove-4.14.6/mjovers.Hqx
Work on file usr/src/contrib/jove-4.14.6/proc.c
Work on file usr/src/contrib/jove-4.14.6/paragraph.c
Work on file usr/src/contrib/jove-4.14.6/note
Work on file usr/src/contrib/jove-4.14.6/move.c
Work on file usr/src/contrib/jove-4.14.6/tags
Work on file usr/src/contrib/jove-4.14.6/re.c
Work on file usr/src/contrib/jove-4.14.6/portsrv.c
Work on file usr/src/contrib/jove-4.14.6/rec.c
Work on file usr/src/contrib/jove-4.14.6/re.h
Work on file usr/src/contrib/jove-4.14.6/re1.c
Work on file usr/src/contrib/jove-4.14.6/recover.c
Work on file usr/src/contrib/jove-4.14.6/rec.h
Work on file usr/src/contrib/jove-4.14.6/scandir.c
Work on file usr/src/contrib/jove-4.14.6/scandir.h
Work on file usr/src/contrib/jove-4.14.6/screen.c
Work on file usr/src/contrib/jove-4.14.6/screen.h
Work on file usr/src/contrib/jove-4.14.6/setmaps.c
Work on file usr/src/contrib/jove-4.14.6/dataobj.h
Work on file usr/src/contrib/jove-4.14.6/teachjove.c
Work on file usr/src/contrib/jove-4.14.6/style.h
Work on file usr/src/contrib/jove-4.14.6/ttystate.h
Work on file usr/src/contrib/jove-4.14.6/termcap.h
Work on file usr/src/contrib/jove-4.14.6/tune.template
Work on file usr/src/contrib/jove-4.14.6/tune.dos
Work on file usr/src/contrib/jove-4.14.6/term.c
Work on file usr/src/contrib/jove-4.14.6/tune.h
Work on file usr/src/contrib/jove-4.14.6/temp.h
Work on file usr/src/contrib/jove-4.14.6/vars.c
Work on file usr/src/contrib/jove-4.14.6/wind.c
Work on file usr/src/contrib/jove-4.14.6/wait.h
Work on file usr/src/contrib/jove-4.14.6/vars.h
Work on file usr/src/contrib/jove-4.14.6/version.c
Work on file usr/src/contrib/jove-4.14.6/util.h
Work on file usr/src/contrib/jove-4.14.6/Makefile.sun
Work on file usr/src/contrib/jove-4.14.6/iproc-ptys.c
Work on file usr/src/contrib/jove-4.14.6/README.bsdi
Work on file usr/src/contrib/jove-4.14.6/wind.h
Work on file usr/src/contrib/jove-4.14.6/doc/README
Work on file usr/src/contrib/jove-4.14.6/doc/jove.5
Work on file usr/src/contrib/jove-4.14.6/doc/cmds.doc.nr
Work on file usr/src/contrib/jove-4.14.6/doc/example.rc
Work on file usr/src/contrib/jove-4.14.6/doc/jove.1
Work on file usr/src/contrib/jove-4.14.6/doc/jove.2
Work on file usr/src/contrib/jove-4.14.6/doc/jove.nr
Work on file usr/src/contrib/jove-4.14.6/doc/jove.4
Work on file usr/src/contrib/jove-4.14.6/doc/jove.3
Work on file usr/src/contrib/jove-4.14.6/doc/jove.qref
Work on file usr/src/contrib/jove-4.14.6/doc/system.rc
Work on file usr/src/contrib/jove-4.14.6/doc/teachjove.nr
Work on file usr/src/contrib/jove-4.14.6/doc/teach-jove
Work on file usr/src/contrib/jove-4.14.6/doc/ff
Work on file usr/src/contrib/jove-4.14.6/doc/cmds.doc

Synthesized-from: CSRG/cd3/4.4BSD-Lite2

102 files changed:
usr/src/contrib/jove-4.14.6/Makefile.dos [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/Makefile.sun [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/README [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/README.bsdi [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/Readme.dos [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/Readme.mac [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/abbrev.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/argcount.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/argcount.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/ask.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/buf.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/buf.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/c.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/case.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/chars.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/ctype.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/ctype.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/dataobj.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/delete.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/disp.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/disp.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/README [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/cmds.doc [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/cmds.doc.nr [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/example.rc [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/ff [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/jove.1 [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/jove.2 [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/jove.3 [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/jove.4 [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/jove.5 [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/jove.nr [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/jove.qref [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/system.rc [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/teach-jove [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/doc/teachjove.nr [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/extend.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/fmt.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/fp.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/fp.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/funcdefs.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/getch.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/insert.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/io.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/io.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/iproc-pipes.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/iproc-ptys.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/iproc.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/iproc.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/jove.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/jove.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/kbd.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/keymaps.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/keymaps.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/keys.txt [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/list.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/list.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/loadavg.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/mac.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/mac.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/macros.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/makedep [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/marks.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/menumaps.txt [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/misc.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/mjovers.Hqx [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/move.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/note [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/paragraph.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/pcscr.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/portsrv.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/proc.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/re.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/re.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/re1.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/rec.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/rec.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/recover.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/scandir.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/scandir.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/screen.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/screen.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/setmaps.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/style.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/sysdep.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/tags [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/teachjove.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/temp.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/term.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/termcap.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/ttystate.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/tune.dos [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/tune.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/tune.template [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/util.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/util.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/vars.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/vars.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/version.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/wait.h [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/wind.c [new file with mode: 0644]
usr/src/contrib/jove-4.14.6/wind.h [new file with mode: 0644]

diff --git a/usr/src/contrib/jove-4.14.6/Makefile.dos b/usr/src/contrib/jove-4.14.6/Makefile.dos
new file mode 100644 (file)
index 0000000..7d1d4b3
--- /dev/null
@@ -0,0 +1,60 @@
+###########################################################################
+# This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE #
+# is provided to you without charge, and with no warranty.  You may give  #
+# away copies of JOVE, including sources, provided that this notice is    #
+# included in all the files.                                              #
+###########################################################################
+
+MEM = L                        # M for medium or L for large
+DEB = -Gs -Ot          # use -Zi and MEM = M for debugging
+#
+# define LINT_ARGS to use function prototypes
+#
+CFLAGS = -A$(MEM) -J -Zp $(DEB) -DIBMPC
+LIB = M:\LIB
+#
+# linker flags: for debugging use /NOE/NOI/F/B/PAC/CO/STACK:0x2000
+#
+LDFLAGS = /NOE/NOI/MAP/F/B/E/PAC/STACK:0x2000
+#
+# set VPATH as below if you have sources in SRC
+#
+SRC = .
+# VPATH = .;.. # should read .;$(SRC) - but doesn't work
+
+OBJECTS = keys.obj funcdefs.obj abbrev.obj ask.obj buf.obj c.obj \
+       case.obj ctype.obj delete.obj extend.obj argcount.obj \
+       insert.obj io.obj jove.obj macros.obj marks.obj misc.obj move.obj \
+       paragrap.obj proc.obj re.obj re1.obj scandir.obj \
+       list.obj keymaps.obj tune.obj util.obj vars.obj wind.obj \
+       fmt.obj disp.obj term.obj version.obj fp.obj screen.obj getch.obj \
+       pcscr.obj       
+
+HEADERS = ctype.h io.h jove.h re.h list.h temp.h termcap.h tune.h externs.h
+
+jove.exe:      $(OBJECTS) $(HEADERS)
+       link $(OBJECTS) $(LIB)\setargv,xjove $(LDFLAGS);
+
+$(OBJECTS): $(HEADERS)
+
+setmaps.exe:   setmaps.obj funcdefs.c
+       cl setmaps.obj
+
+setmaps.obj:   funcdefs.c keys.txt
+       cl $(CFLAGS) $(SRC)\setmaps.c
+
+keys.c:        setmaps.exe keys.txt
+       setmaps < keys.txt > keys.c
+
+keys.obj:      keys.c jove.h
+       $(CC) $(CFLAGS) -I$(SRC) -c keys.c
+
+# to avoid accidental loss under unix
+tune.c:        tune.dos
+       copy tune.dos tune.c
+
+tune.obj: tune.c
+       $(CC) $(CFLAGS) -I$(SRC) -c tune.c
+
+clean:
+       -rm *.obj setmaps.exe keys.c *.bak *.map
diff --git a/usr/src/contrib/jove-4.14.6/Makefile.sun b/usr/src/contrib/jove-4.14.6/Makefile.sun
new file mode 100644 (file)
index 0000000..ad01c19
--- /dev/null
@@ -0,0 +1,491 @@
+###########################################################################
+# This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE #
+# is provided to you without charge, and with no warranty.  You may give  #
+# away copies of JOVE, including sources, provided that this notice is    #
+# included in all the files.                                              #
+###########################################################################
+
+# TMPDIR is where the tmp files get stored, usually /tmp or /tmp/jove.  If
+# your system does not remove subdirectories of /tmp on reboot (lots do
+# remove them these days) then it makes sense to make TMPDIR be /tmp/jove.
+# But if you want to recover buffers on system crashes, you should create a
+# directory that doesn't get cleaned upon reboot, and use that instead.
+# You would probably want to clean out that directory periodically with
+# /etc/cron.
+# RECDIR is the directory in which RECOVER looks for JOVE's tempfiles.
+#
+# JOVEHOME is the directory in which pieces of JOVE are kept.  It is only used
+#      in the default definitions of SHAREDIR, LIBDIR, BINDIR, and MANDIR.
+# SHAREDIR is for online documentation, and the system-wide .joverc file.
+# LIBDIR is for the PORTSRV and KBD processes and RECOVER.
+# BINDIR is where to put the executables JOVE and TEACHJOVE.
+# MANDIR is where the manual pages go for JOVE, RECOVER and TEACHJOVE.
+# MANEXT is the extension for the man pages, e.g., jove.1 or jove.l or jove.m.
+# DFLTSHELL is the default shell invoked by JOVE and TEACHJOVE.
+#
+# If they don't exist, this makefile will try to create the directories
+# LIBDIR and SHAREDIR.  All others must already exist.
+
+TMPDIR = /var/tmp
+RECDIR = /var/preserve
+
+JOVEHOME = /usr/local
+SHAREDIR = $(JOVEHOME)/lib/jove
+LIBDIR = $(JOVEHOME)/lib/jove
+BINDIR = $(JOVEHOME)/bin
+MANDIR = /usr/man/man$(MANEXT)
+MANEXT = l
+DFLTSHELL = /bin/csh
+
+PROG = jove
+VERSION = 4.14
+
+# These should all just be right if the above ones are.
+JOVE = $(BINDIR)/jove
+TEACHJOVE = $(BINDIR)/teachjove
+RECOVER = $(LIBDIR)/recover
+PORTSRV = $(LIBDIR)/portsrv
+KBD = $(LIBDIR)/kbd
+JOVERC = $(SHAREDIR)/jove.rc
+CMDS.DOC = $(SHAREDIR)/cmds.doc
+TEACH-JOVE = $(SHAREDIR)/teach-jove
+JOVEM = $(MANDIR)/jove.$(MANEXT)
+TEACHJOVEM = $(MANDIR)/teachjove.$(MANEXT)
+
+# Select the right libraries for your system.
+#      2.10BSD:LIBS = -ltermcap
+#      v7:     LIBS = -ltermcap
+#      4.1BSD: LIBS = -ltermcap -ljobs
+#      4.2BSD: LIBS = -ltermcap
+#      4.3BSD: LIBS = -ltermcap
+#      SysV Rel. 2: LIBS = -lcurses
+#      SCO Xenix: LIBS = -ltermcap -lx
+#      SCO: LIBS = -lcurses
+#      AIX on the R6000s: LIBS = -lcurses
+#      MIPS: LIBS = -ltermcap
+
+LIBS = -ltermcap
+
+#      2.10BSD:LDFLAGS =
+#      v7:     LDFLAGS =
+#      4.1BSD: LDFLAGS =
+#      4.2BSD: LDFLAGS =
+#      4.3BSD: LDFLAGS =
+#      SysV Rel. 2: LDFLAGS = -Ml
+#      SCO Xenix: LDFLAGS = -Ml -F 3000
+#      SCO Unix: LDFLAGS = 
+#
+# SEPFLAG should be:
+#      not on a PDP-11:                SEPFLAG =
+#      PDP-11 with separate I&D:       SEPFLAG = -i
+#      PDP-11 without separate I&D:    SEPFLAG = -n
+#
+
+LDFLAGS =
+
+SEPFLAG =
+
+# define a symbol for your OS if it hasn't got one. sysdep.h tries to
+# use cpp predefined symbols to decide on the appropriate behaviour
+# in most cases. Exceptions are
+#      Apple A/UX on macIIs            SYSDEFS=-DA_UX
+#      SunOS4.0                        SYSDEFS=-DSUNOS4
+#      MIPS RiscOS4.x                  -systype bsd43
+#      SCO Unix                        SYSDEFS=-DSCO -DSYSV
+#      IBM RS6000s                     SYSDEFS=-DAIX -D_BSD -D_BSD_INCLUDES -D_NO_PROTO
+#      A system V system that doesn't
+#      define one of SVR2,SVR3,SYSV    SYSDEFS=-DSYSV
+#
+# You can just say 'make SYSDEFS=-Dwhatever' on these systems.
+# 
+SYSDEFS = -DSUNOS4 -DGCC
+
+# for SCO Xenix, set
+#      MEMFLAGS = -Mle
+#      CFLAGS = -LARGE -O -F 3000 -K -Mle  (say -Mle2 for an 80286)
+CC=gcc
+CFLAGS = -O $(SYSDEFS)
+
+# For cross compiling Jove, set CC to the cross compiler, and LOCALC
+# to the local C compiler. LOCALCC will be used for compiling setmaps,
+# which is run as part of the compilation to generate the keymaps.
+# Set LOCALCFLAGS and LOCALLDFLAGS appropriately too. For Xenix, note
+# that LOCALCFLAGS must be set to $(MEMFLAGS)
+
+LOCALCC = $(CC)
+LOCALCFLAGS = $(CFLAGS)        # $(MEMFLAGS)
+LOCALLDFLAGS = $(LDFLAGS)
+
+BASESEG = funcdefs.o keys.o argcount.o ask.o buf.o ctype.o delete.o \
+         disp.o insert.o io.o jove.o loadavg.o marks.o misc.o re.o \
+         screen.o tune.o util.o vars.o version.o list.o keymaps.o
+OVLAY1 = abbrev.o rec.o paragraph.o fmt.o
+OVLAY2 = c.o wind.o fp.o move.o
+OVLAY3 = extend.o macros.o
+OVLAY4 = iproc.o re1.o
+OVLAY5 = proc.o scandir.o term.o case.o
+
+OBJECTS = $(BASESEG) $(OVLAY1) $(OVLAY2) $(OVLAY3) $(OVLAY4) $(OVLAY5)
+
+C_SRC = funcdefs.c abbrev.c argcount.c ask.c buf.c c.c case.c ctype.c \
+       delete.c disp.c extend.c fp.c fmt.c insert.c io.c iproc.c \
+       jove.c list.c loadavg.c macros.c marks.c misc.c move.c paragraph.c \
+       proc.c re.c re1.c rec.c scandir.c screen.c term.c util.c \
+       vars.c version.c wind.c getch.c mac.c keymaps.c pcscr.c
+
+SOURCES = $(C_SRC) portsrv.c recover.c setmaps.c teachjove.c kbd.c
+
+HEADERS = argcount.h buf.h chars.h ctype.h dataobj.h disp.h \
+       externs.h fp.h io.h iproc.h jove.h keymaps.h list.h mac.h \
+       re.h rec.h scandir.h screen.h sysdep.h temp.h termcap.h \
+       ttystate.h tune.h util.h vars.h wait.h wind.h
+
+
+DOCS1 =        doc/example.rc doc/jove.1 doc/jove.2 doc/jove.3 \
+       doc/jove.4 doc/jove.5 doc/jove.nr doc/system.rc \
+       doc/teach-jove doc/teachjove.nr doc/README doc/jove.qref
+DOCS2 = doc/cmds.doc.nr
+DOCS3 = doc/joveman doc/cmds.doc doc/manpage
+DOCS = $(DOCS1) $(DOCS2)
+
+MISC = Makefile Makefile.dos tune.dos tune.template README Readme.dos \
+       Readme.mac iproc-pipes.c iproc-ptys.c
+
+SUPPORT = teachjove.c recover.c setmaps.c portsrv.c kbd.c keys.txt \
+       macvert.c menumaps.txt mjovers.Hqx
+
+BACKUPS = $(HEADERS) $(C_SRC) $(DOCS) $(SUPPORT) $(MISC)
+
+all:   sdate xjove recover teachjove portsrv kbd macvert edate
+
+sdate:
+       @echo "**** make started at `date` ****"
+
+edate:
+       @echo "**** make completed at `date` ****"
+
+xjove: $(OBJECTS)
+       $(CC) $(LDFLAGS) -o xjove $(OBJECTS) $(LIBS)
+       @-size xjove
+
+gjove: $(OBJECTS)
+       ld -X /lib/gcrt0.o -o gjove $(OBJECTS) -lc $(LIBS)
+       @-size gjove
+
+ovjove:        $(OBJECTS)
+       ld $(SEPFLAG) $(LDFLAGS) -X /lib/crt0.o \
+               -Z $(OVLAY1) \
+               -Z $(OVLAY2) \
+               -Z $(OVLAY3) \
+               -Z $(OVLAY4) \
+               -Z $(OVLAY5) \
+               -Y $(BASESEG) \
+               -o xjove $(LIBS) -lc
+       @-size xjove
+
+portsrv:       portsrv.o
+       $(CC) $(LDFLAGS) -o portsrv $(SEPFLAG) portsrv.o $(LIBS)
+
+kbd:   kbd.o
+       $(CC) $(LDFLAGS) -o kbd $(SEPFLAG) kbd.o $(LIBS)
+
+recover:       rectune.h recover.o tune.o rec.h temp.h
+       $(CC) $(LDFLAGS) -o recover $(SEPFLAG) recover.o tune.o $(LIBS)
+
+teachjove:     teachjove.o
+       $(CC) $(LDFLAGS) -o teachjove $(SEPFLAG) teachjove.o $(LIBS)
+
+setmaps:       setmaps.o funcdefs.c
+       $(LOCALCC) $(LOCALLDFLAGS) -o setmaps setmaps.o
+
+teachjove.o:   teachjove.c /usr/include/sys/types.h /usr/include/sys/file.h
+       $(CC) -c $(CFLAGS) -DTEACHJOVE=\"$(TEACH-JOVE)\" teachjove.c
+
+# don't optimize setmaps.c because it produces bad code in some places
+# for some reason
+setmaps.o:     funcdefs.c keys.txt
+       $(LOCALCC) $(LOCALCFLAGS) -c setmaps.c
+
+# ignore error messages from setmaps
+# it doesn't understand ifdefs
+
+keys.c:        setmaps keys.txt
+       -./setmaps < keys.txt > keys.c
+
+keys.o:        keys.c jove.h
+
+tune.c: Makefile tune.template
+       -rm -f tune.c
+       @echo "/* Changes should be made in Makefile, not to this file! */" > tune.c
+       @echo "" >> tune.c
+       @sed -e 's;TMPDIR;$(TMPDIR);' \
+            -e 's;LIBDIR;$(LIBDIR);' \
+            -e 's;SHAREDIR;$(SHAREDIR);' \
+            -e 's;BINDIR;$(BINDIR);' \
+            -e 's;SHELL;$(DFLTSHELL);' tune.template >> tune.c
+
+rectune.h: Makefile
+       -rm -f nrectune.h
+       @echo "/* Changes should be made in Makefile, not to this file! */" > nrectune.h
+       @echo "" >> nrectune.h
+       @echo \#define TMP_DIR \"$(TMPDIR)\" >> nrectune.h
+       @echo \#define REC_DIR \"$(RECDIR)\" >> nrectune.h
+       -cmp -s nrectune.h rectune.h || (rm -f rectune.h; cp nrectune.h rectune.h)
+
+iproc.o: iproc-ptys.c iproc-pipes.c iproc.c
+       $(CC) -c $(CFLAGS) iproc.c
+
+macvert:       macvert.c
+       $(CC) $(CFLAGS) -o macvert macvert.c
+
+# install doesn't work for Xenix (no install program)
+
+install: $(LIBDIR) $(SHAREDIR) \
+        $(TEACH-JOVE) $(CMDS.DOC) $(JOVERC) \
+        $(PORTSRV) $(KBD) $(RECOVER) $(JOVE) $(TEACHJOVE) $(JOVEM) \
+        $(RECOVERM) $(TEACHJOVEM)
+       @echo See the README about changes to /etc/rc or /etc/rc.local
+       @echo so that the system recovers jove files on reboot after a crash
+
+$(LIBDIR)::
+       -mkdir $(LIBDIR)
+
+$(SHAREDIR)::
+       -mkdir $(SHAREDIR)
+
+$(TEACH-JOVE): doc/teach-jove
+       install -c -m 644 doc/teach-jove $(TEACH-JOVE)
+
+doc/cmds.doc:  doc/cmds.doc.nr doc/jove.4 doc/jove.5
+       nroff doc/cmds.doc.nr doc/jove.4 doc/jove.5 > doc/cmds.doc
+
+$(CMDS.DOC): doc/cmds.doc
+       install -c -m 644 doc/cmds.doc $(CMDS.DOC)
+
+$(JOVERC): doc/system.rc
+       install -c -m 644 doc/system.rc $(JOVERC)
+
+$(PORTSRV): portsrv
+       install -c -s -m 755 portsrv $(PORTSRV)
+
+$(KBD): kbd
+       install -c -s -m 755 kbd $(KBD)
+
+$(RECOVER): recover
+       install -c -s -m 755 recover $(RECOVER)
+
+$(JOVE): xjove
+       install -c -m 755 xjove $(JOVE)
+
+$(TEACHJOVE): teachjove
+       install -c -s -m 755 teachjove $(TEACHJOVE)
+
+$(JOVEM): doc/jove.nr
+       @sed -e 's;TMPDIR;$(TMPDIR);' \
+            -e 's;LIBDIR;$(LIBDIR);' \
+            -e 's;SHAREDIR;$(SHAREDIR);' \
+            -e 's;SHELL;$(DFLTSHELL);' doc/jove.nr > /tmp/jove.nr
+       install -m 644 /tmp/jove.nr $(JOVEM)
+
+$(TEACHJOVEM): doc/teachjove.nr
+       @sed -e 's;TMPDIR;$(TMPDIR);' \
+            -e 's;LIBDIR;$(LIBDIR);' \
+            -e 's;SHAREDIR;$(SHAREDIR);' \
+            -e 's;SHELL;$(DFLTSHELL);' doc/teachjove.nr > /tmp/teachjove.nr
+       install -m 644 /tmp/teachjove.nr $(TEACHJOVEM)
+
+echo:
+       @echo $(C-FILES) $(HEADERS)
+
+lint:
+       lint -n $(C_SRC) tune.c keys.c
+       @echo Done
+
+tags:
+       ctags -w $(C_SRC) $(HEADERS) iproc-ptys.c
+
+ciall:
+       ci $(BACKUPS)
+
+coall:
+       co $(BACKUPS)
+
+jove.shar:
+       shar $(BACKUPS) > jove.shar
+
+tar:
+       @tar cvf - `find . -type f -print | \
+               egrep -v '(,v|\.o|xjove|kbd|portsrv|setmaps|~)$$' | \
+               sort`
+
+backup: $(BACKUPS)
+       tar cf backup $(BACKUPS)
+
+tape-backup:
+       tar cf /dev/rst8 $(BACKUPS)
+
+srcdownload:
+       kermit -s $(SUPPORT) $(MISC) $(HEADERS) $(C_SRC)
+
+docdownload:
+       kermit -s $(DOCS1) $(DOCS3)
+       kermit -s doc/cmds.doc.nr -a cmdsdoc.nr
+
+touch:
+       touch $(OBJECTS)
+
+clean:
+       rm -f a.out core *.o keys.c tune.c xjove portsrv kbd recover setmaps \
+       teachjove macvert nrectune.h rectune.h \#* *~ make.log
+
+clobber: clean
+       rm -f *.orig *.rej
+
+# This version only works under 4.3BSD
+depend:
+       @echo '"make depend" only works under 4.3BSD'
+       sed -e '/^# DO NOT DELETE THIS LINE/q' Makefile >Makefile.new
+       for i in ${SOURCES} ; do \
+               cc -M ${CFLAGS} $$i | \
+               awk ' /[/]usr[/]include/ { next } \
+                       { if ($$1 != prev) \
+                   { if (rec != "") print rec; rec = $$0; prev = $$1; } \
+                   else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
+                   else rec = rec " " $$2 } } \
+                   END { print rec } ' >>Makefile.new; \
+       done
+       echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile.new
+       echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile.new
+       echo '# see "make depend" above' >>Makefile.new
+       @echo 'New makefile is in "Makefile.new".  Move it to "Makefile".'
+
+# DO NOT DELETE THIS LINE -- "make depend" uses it
+funcdefs.o: funcdefs.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+funcdefs.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+funcdefs.o: ./externs.h ./ctype.h
+abbrev.o: abbrev.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+abbrev.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+abbrev.o: ./externs.h ./fp.h ./ctype.h
+argcount.o: argcount.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+argcount.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+argcount.o: ./externs.h ./ctype.h
+ask.o: ask.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+ask.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+ask.o: ./termcap.h ./ctype.h ./chars.h ./disp.h ./fp.h ./scandir.h
+buf.o: buf.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+buf.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+buf.o: ./ctype.h ./disp.h ./fp.h ./iproc.h
+c.o: c.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+c.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h ./re.h
+c.o: ./ctype.h ./disp.h
+case.o: case.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+case.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+case.o: ./disp.h ./ctype.h
+ctype.o: ctype.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+ctype.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+ctype.o: ./externs.h ./ctype.h
+delete.o: delete.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+delete.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+delete.o: ./externs.h ./disp.h
+disp.o: disp.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+disp.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+disp.o: ./ctype.h ./termcap.h ./chars.h ./fp.h ./disp.h ./iproc.h
+extend.o: extend.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+extend.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+extend.o: ./externs.h ./fp.h ./termcap.h ./ctype.h ./chars.h ./disp.h ./re.h
+fp.o: fp.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+fp.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h ./fp.h
+fp.o: ./ctype.h ./termcap.h ./disp.h
+fmt.o: fmt.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+fmt.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h ./fp.h
+fmt.o: ./termcap.h ./ctype.h ./disp.h
+insert.o: insert.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+insert.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+insert.o: ./externs.h ./ctype.h ./list.h ./chars.h ./disp.h ./re.h
+io.o: io.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+io.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+io.o: ./list.h ./fp.h ./termcap.h ./ctype.h ./disp.h ./scandir.h ./temp.h
+iproc.o: iproc.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+iproc.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+iproc.o: ./externs.h ./re.h ./ctype.h ./disp.h ./fp.h ./iproc.h ./iproc-ptys.c
+iproc.o: ./wait.h ./ttystate.h
+jove.o: jove.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+jove.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+jove.o: ./fp.h ./termcap.h ./ctype.h ./chars.h ./disp.h ./re.h ./rec.h
+jove.o: ./iproc.h ./ttystate.h
+list.o: list.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+list.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+list.o: ./list.h
+loadavg.o: loadavg.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+loadavg.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+loadavg.o: ./externs.h
+macros.o: macros.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+macros.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+macros.o: ./externs.h ./ctype.h ./fp.h ./chars.h ./disp.h
+marks.o: marks.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+marks.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+marks.o: ./externs.h
+misc.o: misc.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+misc.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+misc.o: ./ctype.h ./disp.h
+move.o: move.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+move.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+move.o: ./re.h ./ctype.h ./disp.h
+paragraph.o: paragraph.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+paragraph.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+paragraph.o: ./externs.h ./disp.h
+proc.o: proc.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+proc.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+proc.o: ./ctype.h ./fp.h ./re.h ./termcap.h ./disp.h ./rec.h ./wait.h
+re.o: re.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+re.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h ./re.h
+re.o: ./ctype.h
+re1.o: re1.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+re1.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h ./fp.h
+re1.o: ./re.h ./ctype.h ./chars.h ./disp.h
+rec.o: rec.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+rec.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h ./fp.h
+rec.o: ./rec.h
+scandir.o: scandir.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+scandir.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+scandir.o: ./externs.h ./scandir.h
+screen.o: screen.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+screen.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+screen.o: ./externs.h ./fp.h ./ctype.h ./termcap.h ./disp.h
+term.o: term.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+term.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+term.o: ./fp.h ./disp.h ./ctype.h ./termcap.h
+util.o: util.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+util.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+util.o: ./ctype.h ./termcap.h ./disp.h ./fp.h
+vars.o: vars.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+vars.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+version.o: version.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+version.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+version.o: ./externs.h
+wind.o: wind.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+wind.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+wind.o: ./termcap.h ./chars.h ./disp.h
+getch.o: getch.c ./tune.h ./sysdep.h
+mac.o: mac.c ./tune.h ./sysdep.h
+keymaps.o: keymaps.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+keymaps.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+keymaps.o: ./externs.h ./list.h ./fp.h ./termcap.h ./chars.h ./disp.h ./re.h
+pcscr.o: pcscr.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+pcscr.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+pcscr.o: ./externs.h
+portsrv.o: portsrv.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+portsrv.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+portsrv.o: ./externs.h
+recover.o: recover.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h
+recover.o: ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h
+recover.o: ./externs.h ./temp.h ./rec.h ./ctype.h ./scandir.c ./scandir.h
+setmaps.o: setmaps.c ./funcdefs.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h
+setmaps.o: ./io.h ./dataobj.h ./keymaps.h ./argcount.h ./util.h ./vars.h
+setmaps.o: ./screen.h ./externs.h ./ctype.h
+teachjove.o: teachjove.c
+kbd.o: kbd.c ./jove.h ./tune.h ./sysdep.h ./buf.h ./wind.h ./io.h ./dataobj.h
+kbd.o: ./keymaps.h ./argcount.h ./util.h ./vars.h ./screen.h ./externs.h
+# DEPENDENCIES MUST END AT END OF FILE
+# IF YOU PUT STUFF HERE IT WILL GO AWAY
+# see "make depend" above
diff --git a/usr/src/contrib/jove-4.14.6/README b/usr/src/contrib/jove-4.14.6/README
new file mode 100644 (file)
index 0000000..d949636
--- /dev/null
@@ -0,0 +1,181 @@
+###########################################################################
+# This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE #
+# is provided to you without charge, and with no warranty.  You may give  #
+# away copies of JOVE, including sources, provided that this notice is    #
+# included in all the files.                                              #
+###########################################################################
+
+To make JOVE edit Makefile to set the right directories for the binaries,
+on line documentation, the man pages, and the TMP files and select the
+appropriate load command (see SEPFLAG in Makefile).  (IMPORTANT! read the
+Makefile carefully.)  "tune.c" will be created from "tune.template" by
+MAKE automatically, and it will use the directories you specified in the
+Makefile.  (NOTE:  You should never edit tune.c directly because your
+changes will be undone by the next make.  If you want to make a change to
+a part of tune.c that isn't a directory name, you should edit
+tune.template.)  Next you must edit "tune.h" selecting the compile time
+options you care about.  See below for a description of all the compile
+time options.  You can type "make" to compile XJOVE, PORTSRV (this is
+compiled but not used on 4.2+ systems), RECOVER TEACHJOVE, and
+MACVERT.  NOTE:  make won't work if it fires up /bin/csh for the shell
+commands.  Test them out to see if they work.  If they do, type "make
+install" to install everything where it belongs.
+
+Here are some things to consider for deciding where to put the tmp files.
+TMPDIR is where the tmp files get stored, usually /tmp or /tmp/jove.  If
+your system does not remove subdirectories of /tmp on reboot (lots do
+remove them these days) then it makes sense to make TMPDIR be /tmp/jove.
+But if you want to recover buffers on system crashes, you should put the 
+lines
+                               (echo preserving Jove files)    >/dev/console
+(cd /tmp; /usr/local/lib/jovelib/recover -syscrash) >/dev/console
+
+in the /etc/rc file BEFORE /tmp is cleared, so that you can recover
+files after reboots. There shoudl be a crontab entry to clear out
+old files in /usr/preserve.
+
+For the pdp11 version there is the Ovmakefile.  This has only been tested
+on 2.9bsd.  It works pretty well, actually, and it is possible to turn on
+all the compile time options with this version.
+
+Bug reports:  If you find bugs in JOVE I would appreciate hearing about
+them.  (My net address is at end of this message.)  So, send me the bug
+reports.  If the bug isn't already fixed, I will ask you to send me the
+fix.  If you haven't found the bug, I may be able to, so don't wait until
+you have found it.  If you make improvements to JOVE and want them
+incorporated into the official version, send me a message explaining what
+the change is, and I will decide whether I want to include it.  If it is
+possible for your change to be #ifdef'd in, that would be best, since I
+want to avoid making JOVE huge.  For instance, if it's a new package type
+thing (say, like word abbrev. mode, or something) then it would be best
+if that were a compile-time option.  I will send out periodic updates to
+comp.sources.unix.  I will report all significant bug fixes there, and to
+net.emacs as well.
+
+Here's a list of the compile time options and what they mean:
+
+ABBREV    - Enables word-abbrev-mode which again is nice for paper writers.
+
+BACKUPFILES - This enables backing up files on write.  I guess lots of
+             people like this feature.  It enables the feature but you
+             can still control whether files are backed up with the
+             make-backup-files variable.
+
+BIFF      - This enables turning on and off BIFF so your screen doesn't
+             get messed up with messages from BIFF.
+
+BSD4_2     - Obviously, if you're a Berkeley 4.2 system.
+
+BSD4_3    - If you're running a Berkeley 4.3 or 2.10 system.
+            This will automatically define BSD4_2, also.
+
+CHDIR     - This enables the directory commands; PUSHD, POPD, DIRS and
+             CD.  These simulate the csh commands exactly, I think.  As
+             a side-effect, absolute path names are enabled, which means
+             JOVE parses file names for "." and ".." and all that to get
+             at what you REALLY mean.  It's nicer when this is enabled,
+             but not essential.
+
+CMT_FMT           - This enables code to format and indent C comments.
+
+ID_CHAR           - Enables support for Insert/Delete character on terminals
+            that have those capabilities.  Couple of problems with this code:
+            it's large, takes up lots of I space which is a problem for the
+            smaller computers (pdp11).  Also, it isn't particularly smart
+            and sometimes does really stupid things.  It sometimes uses
+            insert/delete character when simply redrawing would have been
+            faster.  And if you look at code you'll understand why I don't
+            like it all that much.
+
+IPROCS    - Nice feature which lets you run interactive UNIX commands in
+            windows.  In particular, there is a shell command built
+            in which starts up an interactive shell in a window.  This works
+            only on systems with JOB_CONTROL since it relies on the fancy
+            signal mechanism.
+
+JOB_CONTROL - Versions of UNIX that have the job control facility.
+             Berkeley 2.9-10 systems, and the 4.1-3 systems I know have
+             job stopping, so if you're one of those, define
+             this.  The reason MENLO_JCL is defined when JOB_CONTROL
+             is that the 2.9 signal.h file only defines all of the job
+             stopping signals only when MENLO_JCL is defined.
+
+LISP      - Enables Lisp Mode.  This includes code to indent "properly"
+            for Lisp code and new routines to move over s-expressions.
+            You probably won't want (or need) this on PDP-11's.
+
+MY_MALLOC  - Use the older version of malloc that is more memory efficient
+            than the newer 4BSD version.  The 4BSD version places more
+            importance on the speed of the allocation than the amount of
+            memory it uses.  Make your choice ... JOVE hardly ever calls
+            malloc, anyway, relatively speaking, since it allocates
+            lines in big chunks.  NOTE: This doesn't seem to work on suns
+            and the iAPX286.
+
+PIPEPROCS  - If NOT defined, JOVE will use Berkeley pseudo-ttys when
+            doing interactive processes.  This is infinitely better,
+            since you get job control and all that stuff on i-procs.
+            If defined, the portsrv program will have to be made, and
+            all communication between jove and i-procs will be done using
+            pipes.
+
+RESHAPING  - This is for BRL or Berkeley 4.3 and 2.10 systems.  When the
+            window size of the terminal jove is running in is changed
+            a SIGWINCH is sent to all processes in the tty group.  This
+            define enables code in jove to catch that signal and reshape
+            its windows.
+
+SPELL     - Enables the spell-buffer and parse-spelling-errors commands.
+            They are nice especially if you have lots of paper writers.
+
+WIRED_TERMS - Include compiled-in hard-wired code for certain terminals,
+            like the Concept 100.  If you don't have these terminals,
+            you probably don't need this (but no point in taking it
+            out unless you're low on space).
+
+The macros have been rewritten from scratch.  The most noteable change is
+that they are no longer stored in binary files.  The write-macros-to-file
+command writes a file which is suitable for use with the source command.
+So you can have actual macro definitions in your .joverc if you want.  If
+you have lots of macros defined in the old format, you can use the
+macvert program to convert them to the new style.  You say
+       macvert old-style-macros-file > new-style-macro-file
+
+"doc/system.rc" and "doc/example.rc" are jove initialization files.
+"system.rc" is the "system" rc file here at UoR, and it gets ready every
+time JOVE starts up FOR EVERYONE.  ("make install" should copy the
+system-wide .joverc to the right place automatically.)  After that JOVE
+reads an initialization file in the user's home directory.  "example.rc"
+is my personal .joverc.
+
+The files "jove.[12345]" in DOC are the official JOVE manual.  I got
+permission from Richard Stallman to use his manual for the original EMACS,
+modifying it where necessary for JOVE.  Lots of work was done by Brian
+Harvey on this manual.
+
+There are man pages for jove and teachjove.  Teachjove is for people who
+have never used EMACS style editors.  It is an interactive tutorial, THE
+tutorial written by Stallman for the original EMACS, only slightly
+modified for JOVE in the appropriate places.  The man pages are
+completely up to date, thanks to me.
+
+Thanks to Jay (hack) Fenlason for writing the original pty code.
+
+Thanks to Dave Curry at Purdue for putting in tons of time and effort
+into getting JOVE ready.  It just wouldn't be working without his help.
+
+Thanks to Jeff Mc Carrell at Berkeley for finding bugs and adding
+features, in particular, the comment formatter.
+
+Thanks to Karl Gegenfurtner for making the PC version.
+
+Thanks to Ken Mitchum for the Macintosh verison.
+
+Thanks to Hugh Redelmeier for his input, his experience, countless bug
+fixes, and ... that's it, I guess.
+
+(Thanks to Brian Harvey for teaching me about linked lists ...)
+
+Good luck, have fun.
+
+       Jonathan Payne (jpayne@sun.com until further notice :-)
diff --git a/usr/src/contrib/jove-4.14.6/README.bsdi b/usr/src/contrib/jove-4.14.6/README.bsdi
new file mode 100644 (file)
index 0000000..d0073b2
--- /dev/null
@@ -0,0 +1,11 @@
+This was ported to BSD/386 by Peter Collinson Jan 1992
+
+It is a vanilla 4.14.6 version of Jove, but has my mods for X pointing
+added - see xterm-mouse in cmds.doc - this is untested on BSD/386 -
+works on my sun. The same code compiles and runs on my Sun - SunOS 4.1.1.
+
+I have also had to make some changes to bring the code into the 1990's:
+all calls to select() now use fd_sets for example.
+
+It doesn't compile clean - there are some warnings - life is like that.
+
diff --git a/usr/src/contrib/jove-4.14.6/Readme.dos b/usr/src/contrib/jove-4.14.6/Readme.dos
new file mode 100644 (file)
index 0000000..666ce89
--- /dev/null
@@ -0,0 +1,225 @@
+###########################################################################
+# This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE #
+# is provided to you without charge, and with no warranty.  You may give  #
+# away copies of JOVE, including sources, provided that this notice is    #
+# included in all the files.                                              #
+###########################################################################
+
+HOW TO GET STARTED WITH JOVE:
+=============================
+
+You can immediately start using Jove if you have an IBMPC
+compatible PC, XT or AT. You can fine tune some things by setting
+certain environment variables, but it's not really necessary
+If your computer is not IBM BIOS compatible, you have to set some 
+environment variables before starting Jove.
+What follows is a description of those variables.
+
+ENVIRONMENT VARIABLES USED BY JOVE:
+===================================
+
+TMP (or TMPDIR)
+Jove uses the value of TMP to determine the directory where it should
+put its temporary file. The default is the current directory, and this
+is probably not what you want. In general editing is faster, if TMP
+points to a ramdisk, like "set tmp=d:". You have to know however that
+the temporary file can grow quite big when editing many big files at
+once. So please make sure that you have enough space available on your
+ramdisk. If Jove runs out of space on the device which holds the
+temporary file, you have to leave the editor immediately. You can save
+your work without any trouble, but you have to start over. Please note
+also that the current version of Jove has a big cache for the
+temporary file in memory, which makes it quite fast even if you don't
+have a ramdisk.
+
+DESCRIBE
+This variable tells Jove, where it can find the file that holds the
+online documentation. You should set DESCRIBE to the complete
+path-specification of the file "cmds.doc", which is included as part
+of the documentation. The default for DESCRIBE is "c:/unix/cmds.doc".
+
+JOVERC
+This is the complete path for Jove's startup file. All commands in the
+file, that JOVERC points to, are executed every time when you run
+Jove. If there is a file called "jove.rc" in the current directory,
+then it is also "sourced", ie. the commands in that file are executed.
+That way you can customize Jove to your own taste.
+
+The next two variables are not used by the IBMPC version, and have to
+do with specifying the type of terminal in use on a generic msdos
+computer.
+
+TERM
+This variable should specify the name of the terminal you are using.
+For example, if you have a DEC vt-100 terminal attached to your msdos
+computer, you should give the command "set TERM=vt100" prior to
+starting Jove.
+
+TERMCAP
+This environment variable holds the name of a database with
+descriptions of different terminal types. If you are familiar with the
+Unix operating system, you probably know about TERMCAP. For each
+terminal type, specified by TERM, the TERMCAP database holds an entry,
+which describes how to set the cursor, how to scroll, and many other
+things, for that particular terminal. A small example TERMCAP file
+comes with Jove. If your terminal is not included there, you should ask a
+local Unix guru for help. If you don't have one, you can ask me.
+
+METAKEY
+Some kinds of terminals have a special shift key that Jove can recognize, 
+the so called MetaKey. When the environment variable METAKEY is set, Jove
+assumes that you have such a terminal, and treats the codes that your
+terminal sends in a slightly different way. Pressing down the MetaKey
+and another key at the same time is a then a shorthand for pressing
+first the "esc" key, and then the other key.
+
+
+DIFFERENT VERSIONS OF JOVE:
+===========================
+
+The text above already indicated that Jove comes in different versions
+for different types of computers. Not only that, there also exist
+versions that differ in the way they use the memory of the computer. 
+
+The "large" versions of Jove use all the memory available if it is
+necessary. The temporary file can grow infinitely large in those
+versions. The number of lines that can be edited with the large
+version is about 20000 to 25000 on a PC with 640 kB of memory. Note
+that there is no limit on the size of the file itself.
+The "medium" versions of Jove are more conservative in their use of
+memory. They always take up about 130 kB of memory, which leaves a big
+rest for executing large programs, like the C-Compiler from within
+Jove. The size of the temporary file is also limited to 512 kB in the
+medium versions. The leads to a limit of approximately 4500 to 5000
+lines that can be edited at one time. 
+The standard executable files that are distributed in binary form, are
+usually the large ones. If you need a medium version, you either have
+to recompile Jove from the sources (see below), or you can get get
+it from someone else who has compiled it, for example from me.
+
+There currently exist versions of Jove for three different types of
+msdos computers. PCJOVE is for IBMPC compatible computers. Compatible
+means here that the ROM Bios of your computer has to support the same
+Video output calls as the PC's. So even if your "clone" has trouble
+with many other programs, there's a high chance that Jove will work.
+MSJOVE should generally run on any computer that runs the msdos
+operating system. It strictly uses only well documented system calls
+to do its task. RBJOVE is a special version of MSJOVE for DEC Rainbow
+computers, which uses the Rainbows Bios for screen output and keyboard
+input. This makes it much faster than MSJOVE on the Rainbow.
+
+
+DIFFERENCES BETWEEN JOVE UNDER MSDOS AND UNIX JOVE:
+===================================================
+
+The msdos version of Jove currently supports all of the features that
+are possible to implement under msdos in a reasonable way.
+Version 4.8b in particular supports:
+       filename completion
+       comment filling 
+       creation of backup files
+       word abbreviation mode
+       Lisp mode
+       change directory within Jove
+       executing commands from within Jove
+       filtering regions through msdos commands
+You have to look into the manual for more explanations of these
+features. The things that are missing under msdos are:
+       spell-buffer (obsolete under msdos)
+       interactive shells in a window (not possible)
+There are however some features added, which are specific to the PC
+version.
+
+Variables:
+ Background-color specifies the background color of the screen. The default
+    value is 0, which stands for black.
+ Foreground-color specifies the foreground color of the screen. The default
+    is 1, which stands for white. The attribute used for writing to the
+    screen is formed by (bg&7)<<4 & (fg&7).
+ Mode-line-color specifies the color of the modeline. Its default
+    value is 0, and in that case it is drawn in reverse video. If it has
+    any other value, this value is used as the attribute in Bios calls. 
+ (note that on a monochrome monitor the best thing is to leave the
+ default colors - anything else can lead to blank screens very easily)
+
+Commands:
+ Scroll-previous-page continuously scrolls down screen-full lines.
+ Scroll-next-page continuously scrolls up screen-full lines.
+ Select-buffer-n, where n is in the range 0 to 9, selects buffer n as the
+    working buffer. These commands are bound to the <alt>[0-9] keys by
+    default. For example, pressing the alt key and 3 at the same time
+    switches immediately to buffer 3.
+
+General:
+ PCJOVE supports the whole 8 bit character set of the IBMPC. You can
+ use all the line drawing characters in your files. It also knows
+ about some special foreign characters (Umlaute), which are treated
+ correctly as part of words and in case conversions.
+
+
+VIDEO MODES ON THE IBMPC:
+=========================
+
+This concerns PCJOVE only. When Jove is started, it automatically
+checks which video mode is currently used, and adjusts itself
+correspondingly. This means that Jove will work correctly even in
+40x25 mode. If you have an Ega card, and want to use the special mode
+with 43 lines, set the environment variable TERM to the value EGA, or
+set the variable EGA to any value. This will tell Jove to set the
+screen in 80x43 mode. The regular 80x25 mode is restored upon exit.
+On a color monitor, you can change the screen colors by using the
+commands mentioned above.
+There is a problem in using Jove together with Hershey
+MicroComputing's FansiConsole screen driver. FansiConsole doesn't
+properly set some of the values in the Bios control area. This usually
+leads to a crash when Jove starts. You can restore the information
+Jove needs by giving the command "mode co80" before starting Jove.
+Note that Kermit version 2.30 has the same problem, and that it can
+only be fixed by fixing FansiConsole.
+
+
+COMPILING JOVE UNDER MSDOS:
+===========================
+
+Jove can currently only be compiled with the Version 5.0 of the
+Microsoft C Compiler. Jove uses some library function calls that were
+not included with version 4.0 or earlier of Microsoft C. The makefile
+that is included with the sources will not work with Microsofts lousy
+make. I recommend that you use ndmake, a public domain (or is it
+shareware) make utility, which is much better than Microsofts.
+Jove can be compiled with the medium, or the large memory model. To
+get the IBMPC version, the option "-DIBMPC" should be given at the
+command line for the Compiler. Similarly, the define for the Rainbow
+version is RAINBOW. The variable MSDOS is always defined by the
+compiler. If you want to disable some features you can do so by making
+changes to tune.h.
+If you want to give away the version of Jove you are compiling to
+other people, don't use the loop optimizations or intrinsic
+functions!!! The compiler currently has some bugs in the optimizer,
+which causes it to produce wrong code sometimes, and in unpredictable
+places. Look at the function DoJustify(), in paragraph.c, for an
+example. Note that the #pragma is commented out. because compilers on
+other machines don't like it. If you find that the version you just
+compiled behaves strange in some way, and you compiled with
+optimizations on, check whether it works ok with optimizations
+disabled before you tell all the world about a new bug in Jove.
+If you want to compile MSJOVE or RBJOVE, you need the library MTERMLIB
+or LTERMLIB, for medium or large memory model, respectively. These
+libraries contain the functions for dealing with the termcap database.
+
+If you want to compile Jove with Turbo-C, the port has already been
+done by Brian Campbell (brianc@cognos.uucp). A separate file with the
+diffs is currently available from him, and will probably be included
+as ifdefs in future versions.
+
+If you find a bug in Jove, have some questions, or some suggestions,
+you are always welcome. Just send mail to me. My address is:
+
+          Karl Gegenfurtner
+
+arpa:     karl@hipl.psych.nyu.edu
+uucp      {ihnp4|seismo|allegra}!cmcl2!xp!hipl!karl
+usps:     New York University
+          Dept. of Psychology
+          6 Washington Place 8th floor
+          New York, NY 10003
diff --git a/usr/src/contrib/jove-4.14.6/Readme.mac b/usr/src/contrib/jove-4.14.6/Readme.mac
new file mode 100644 (file)
index 0000000..9c7c097
--- /dev/null
@@ -0,0 +1,410 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+Changes between 4.9 and 4.10:
+
+  New features:
+    1) Reshapeable windows with zoom boxes.
+    2) Filename/directory name completion with macify OFF.
+    3) Double click mouse to set the mark.
+    4) Control-space and control-@ correctly send NUL on MacII/SE.
+    5) Control-` fixed to send backquote char.
+    6) Display update code fixed.
+    
+  Sources:
+    1) Compiles under LSC 3.0. (Probably under 2.13 as well, but
+       not tested with that version).
+    2) Include files redone, with fewer total lines of code.
+    3) No need to modify include files, unless NBUF changed.
+    4) "keymaps.txt" is now "keys.txt".
+    
+  Planned:
+    1) Recover command as separate application.
+    2) Support for MPW compiler vers 2.02.
+    
+   
+Introduction
+
+This file contains a brief description of MacJove, along with
+information necessary to make MacJove from the source files.
+It is assumed that the reader is familiar with Jove from other
+systems, and is somewhat familiar with the Macintosh as well. In
+the future there may be a separate user's manual for MacJove: 
+for the time being, the reader should refer to the Jove manual
+for Unix users.
+
+Description
+
+MacJove is a direct port of Jove to the Macintosh, with the
+overall structure, commands and key bindings left intact. In
+addition, elements of the Macintosh user interface - menus,
+window controls, and the mouse, have been integrated in a manner
+consistent with the overall functioning of Jove.
+
+While the integration of these tools into the Jove environment
+is consistent and, to most users, familiar, Jove departs in
+several places from "Macintosh User Interface Guidelines". Most
+notably, the mouse is used to position the point only, not to
+drag or select text, and the Jove buffer structure is not
+integrated with the clipboard. Also, key bindings conform to
+Jove/Emacs tradition, and not to Macintosh guidelines: i.e.
+control (command)-N is next-line, not "NewFile". The reason for
+these departures is that the majority of MacJove users are likely
+to be those already familiar with Jove or other Emacs editors
+on other systems, and for these users, consistency between machines
+and operating systems is more important than fully exploiting
+the features of a single system. There are numerous other text
+editors which fully follow the Macintosh User Interface Guidelines.
+
+MacJove retains most features of other Joves, but certain commands
+cannot be implemented because of the Macintosh operating system.
+Thus, there is no way to run a sub-process or a shell in a window,
+because there are no shells to run on the Macintosh, and a program
+(currently) can only transfer control to another program, not run
+a child process. For similar reasons, commands dealing with mail,
+with running make, and checking errors, are omitted.
+
+
+
+                      Running MacJove
+
+System Requirements
+
+MacJove should run without difficulty on any Macintosh Plus, SE, or
+Macintosh II, providing that the hierarchical file system (HFS) is used, and
+assuming a reasonably current system file is used. An upgraded 512K Mac
+(with 128K rom) should also work if there is enough memory.  MacJove was
+developed on a Macintosh Plus and Macintosh II running system 4.2 and Finder
+6.0., and has not been fully tested on earlier systems - however, it is
+likely that it will run on system 3.2 and later versions. MacJove has been
+used to a limited extent with Switcher and under Multifinder. In both cases,
+it is important to reserve enough memory for MacJove, as discussed below.
+
+MacJove, as compiled from the sources, uses memory as follows:
+
+   Program Code     approx 116K
+   Static Data      approx  20K
+   Tempfile Cache           64K (heap)
+                           ____
+                           200K total before stack/heap considerations
+
+To this must be added stack and heap space. A bare minimum for this is
+probably 100K or so, but the usage will vary as buffers are created.  With
+Jove, the file itself takes up space only in the tempfile and its cache, but
+the buffer structure requires 3 pointers (12 bytes) for each line in the
+file. For a reasonable editing session with files totalling, say 10000 to
+20000 lines, this additional space can add up. For this reason, it is
+unrealistic to expect to run Jove on a 512K system, unless a very small
+system file is used, few, small files are edited each session, and the
+tempfile cache is reduced (see cache size under Making Jove). You can
+experiment with various memory allocations under Switcher and Multifinder to
+see what works with your editing habits (backup your files first!), but a
+realistic minimum is 400K - 500K and more is great.
+
+When first using MacJove, and if memory space is questionable, SAVE YOUR
+FILES FREQUENTLY. If it is necessary to edit many files, it is often better
+to exit MacJove and restart once in a while, especially if there is a
+question of limited memory.
+
+Operation
+
+
+Running MacJove is similar to other Macintosh applications, and should be
+intuitive. You start up MacJove by either opening, or double-clicking,
+the MacJove icon. If you have previously saved files created with MacJove,
+double-clicking on them will also start up the program, and the files will
+be put into buffers. Several files can be selected simultaneously by this
+method. There is no current way to select command-line options with
+MacJove, but this may change in the future.
+
+The .joverc file, if used, must be present in the same directory as MacJove,
+the "home" directory. The help file, "cmds.doc", must also be in this
+directory. The tempfile, ".joveXXX", will be placed in whatever directory is
+current when the tempfile is first opened - this may or may not be the home
+directory, and may change in the future. The recover file, ".jrecXXX" is
+placed in the home directory. While this file is created and updated as on
+Unix versions of Jove, there is currently no "recover" program for MacJove.
+Hopefully, this will be available soon.
+
+MacJove can edit any text file on the Macintosh, whether created with
+MacJove or another editor. It cannot be used to edit graphics material, and
+graphics material cannot be inserted during operation of MacJove. Files
+created with MacJove are of type 'TEXT' and of signature 'JV01'. This
+signature is being registered with Apple, and may change if necessary. Note
+that once MacJove files have been re-edited with another editor, they likely
+will have new signatures, and double-clicking on them will start the other
+editor, not MacJove.
+
+The standard Macintosh keyboard is inadequate for MacJove (and most anything
+else), so that it is necessary to change a couple of keys. The "`" key
+becomes the ESCAPE key, since it is in the right place for one: to send a
+real "'", hold the command key down while typing it. The command key is used
+for a control key - unfortunately, the location of it is horrible for such a
+purpose. On Macintosh SE and Macintosh II models, a real escape key exists,
+and also a real control key. Note, however, that because of a small bug in
+the keyboard encoding in MacJove, you cannot directly send a NUL (control-@)
+with the control key. Typing command-@ or command-2 will still do this,
+however.
+
+During operation, you can use the keyboard as you would when running Jove on
+any other system. However, many commands also have menu equivalents:  as
+long as MacJove is waiting for a command, you can use either the keyboard or
+the menus. Once you begin selecting a command with either the menus or the
+keyboard, the other is locked out: thus, once you type control-X, MacJove
+expects more characters, and will not let you choose menu items.  Also, if
+you are prompted for input on the command line, the menus are locked out.
+Regardless of how a command is begun, however, only the prompt line (message
+line) is used for input: MacJove does not use dialog boxes, except under the
+"About Jove" menu selection.
+
+Commands listed in the menus are given exactly as their string name in
+the command list, for example "write-file". In addition, variables are
+listed under the "Set" menu. Variables are grouped by type. Non-boolean
+variables are changed on the message line after being selected. Boolean
+variables are marked with a check mark if on, and selecting them toggles
+the value of the variable.
+
+The "Buffer" menu is a special menu, whose action is different than the
+others. The first entries on this menu are the major and minor modes of
+operation, with those of the current buffer marked with check marks.
+Clicking on a major mode will change the major mode of the current buffer to
+that mode, while clicking on a minor mode will toggle that mode's status
+(on/off) for the current buffer. Beneath this is a list of buffers, one for
+each menu item, with the current buffer marked. Clicking on a buffer selects
+that as the current buffer, and the active window will change accordingly.
+
+Window controls (scroll bars) work as expected, and are simply bound to
+the appropriate MacJove command. Occassionally the position of the
+scroll bar may appear inaccurate, particularly with a small buffer.
+
+Files and directories may be selected in two ways. The default method
+is to use the message line to input filenames, and to change directories
+using "cd". If the variable "macify" is set, however, filenames and
+directories can also be set using the standard file dialogs familiar to
+most Mac users. Filename paths are normally given via Unix conventions,
+and not Macintosh conventions: i.e. directories are separated with "/"
+and not ":". On the Buffer menu, however, filenames are listed with ":"
+as the separation character, since "/" cannot be displayed in menu items.
+It is not possible to back up directories beyond the volume level, so
+there is not true "root". To change volumes (disks), macify must be on,
+and the "Drive" selection used.
+
+"Macify" only works for those commands which REQUIRE a file operation, such
+as "visit-file", "insert-file", "write-file".  Operations which first look
+in buffers for files, such as "window-find" and "find-file" never use the
+standard file dialogs.
+
+For a list of all commands and bindings, click on "About Jove" in the
+Apple menu. In the future this may also support the help file.
+
+                      Making MacJove
+
+System Requirements
+
+To make MacJove from the sources, you need a hard disk based Macintosh, at
+least 1 mb of ram, and the LightspeedC compiler, version 2.13 or later.
+Earlier versions may work but have not been used recently. Allow for the
+MacJove files to take up to 1.5 mb of your hard disk. You will need a copy
+of the "BinHex" utility, also.
+
+Since LightspeedC does not work with a Makefile, none is supplied. In
+general, the compiler itself will figure out dependencies for you, within a
+"project". Since there are three separate projects to MacJove, you will
+still have to keep track of some changes, particularly for the setmaps
+project. Also, since LightspeedC only knows of .c and .h dependencies,
+you will have to keep track of setmaps.txt and menumaps.txt yourself.
+
+Preliminary Steps
+
+0) CREATE A FOLDER (DIRECTORY) FOR JOVE. If I have to tell you how to do
+that, don't go any further! Copy the source files - a few aren't needed
+by MacJove, but copy them anyway, so you'll have them in one place. You
+do not need anything in the "doc" subdirectory to create MacJove (but
+you will eventually need cmds.doc, the help file, if you want the
+"describe-command" command to work).
+
+1) CREATE THE RESOURCE FILE: There is only one eight-bit file supplied,
+"mjove.rsrc". This is a small file which contains the program icon and a
+dialog template. This file must have the same name as the MacJove project,
+plus extension ".rsrc". The MacJove project (below), has name "mjove", so
+this file is "mjove.rsrc".  IF YOU RENAME THE PROJECT YOU MUST RENAME THIS
+FILE, ALSO. Using "BinHex", unload the file "mjovers.Hqx" --> "mjove.rsrc".
+
+2) CREATE THE "MJOVELIB" PROJECT: MacJove does not use many of the library
+functions. Despite what the LightspeedC manual states, projects are loaded
+as a whole: since we need only a few functions, we will build a "library" of
+them in the form of a project. Run LightspeedC and create a new project,
+and name it "mjovelib". Add the following files, from the Library Sources,
+to the project. They all go in the same segment:
+
+     onexit.c
+     qsort.c
+     stddata_ctype.c
+     unixexit.c
+     unixid.c
+     unixmem.c
+     unixtime.c
+
+3) EXAMINE THE FILE UNIXTIME.C and make the following correction, if
+necessary. The LightspeedC library function "unixtime.c" returns a string
+containing the time for what is supposed to be Greenwich Mean Time, instead
+of local time. Using the LightspeedC editor, and with the project open,
+examine the file, comment out the definition of "GMTzonedif", and add:
+
+     #define GMTzonedif 0
+
+4) MAKE THE "MJOVELIB" PROJECT. Keeping the edited "unixtime.c" open,
+run "make" on the project - everything will be compiled, with the altered
+version of "unixtime.c". You do not have to permanently save the change
+to unixtime.c, but if you do not, the next time you run "make" on the
+project, it will tell you that it needs recompiling - simply ignore it.
+After the mjovelib project is made, close it. You do not have to convert it
+to a library - it is okay to leave it as a project.
+
+6) CREATE THE "MSETMAPS" PROJECT. Create a new project, name it "msetmaps",
+and add the following files to it:
+
+     setmaps.c
+     stdio
+     strings           (segment 1)
+     unix
+     unix main.c
+     --------
+     MacTraps          (segment 2)
+
+
+You should not change anything else at this point - unless you want to
+reduce memory requirements (see "Running MacJove", above). If it is
+necessary to reduce the memory requirements, then reduce the number of cache
+buffers, NBUF, which is defined near the end of the file (each buffer takes
+up 1K of space while MacJove is running).
+
+#ifdef MAC
+# undef F_COMPLETION
+# define F_COMPLETION 1
+# define rindex strrchr
+# define bzero(s,n) setmem(s,n,0)
+# define swritef sprintf
+# define LINT_ARGS 1
+# define NBUF 64 <---- here
+# define BUFSIZ 1024
+# undef LISP
+# define LISP 1
+# define ANSICODES 0
+# undef ABBREV
+# define ABBREV 1
+# undef CMT_FMT
+# define CMT_FMT 1
+#endif
+
+7) MAKE THE "MSETMAPS" PROJECT. Then choose "Build Application",and name it
+"setmaps". 
+
+8) RUN "SETMAPS" ON THE KEYMAPS.TXT FILE. You can either run "setmaps" from
+LightspeedC, before closing the project, or as the standalone application.
+When prompted for the "Unix command line", enter:
+
+     < keys.txt > keys.c
+
+You will get a few messages from setmaps that it can't find certain
+commands. You can ignore these.
+
+9) RUN "SETMAPS" ON THE MENUMAPS.TXT FILE. Just as before, run "setmaps"
+and enter the following command line:
+
+     < menumaps.txt > menumaps.c
+
+You should not get any messages from setmaps. If the "msetmaps" project is
+still open, close it.
+
+10) CREATE THE "MJOVE" PROJECT. Create a new project, name it "MJOVE" and
+set the Creator (signature) to 'JV01'. Add the following files in the
+following segments:
+
+     abbrev.c
+     argcount.c
+     ask.c
+     buf.c
+     c.c
+     case.c        (segment 1)
+     ctype.c
+     delete.c
+     disp.c
+     extend.c
+     keys.c
+     --------
+     fmt.c
+     fp.c
+     funcdefs.c    (segment 2)
+     insert.c
+     io.c
+     jove.c
+     keymaps.c
+     list.c
+     --------
+     mac.c
+     macros.c
+     marks.c
+     menumaps.c    (segment 3)
+     misc.c
+     move.c
+     paragraph.c
+     --------
+     re.c
+     re1.c
+     rec.c
+     screen.c
+     term.c       (segment 4)
+     util.c
+     vars.c
+     version.c
+     wind.c
+     --------
+     MacTraps
+     mjovelib
+     setjmp.Lib    (segment 5)
+     storage
+     strings
+
+11) MAKE THE MJOVE PROJECT. If you experience any errors, it will most
+likely be from #include files not being in the default path - see the
+LightspeedC manual on setting up your directories. When you are done,
+run the program from the compiler to verify that it is okay, then save it as
+"MacJove" using the "Build Application" command.
+
+12) (Optional) CREATE THE HELP FILE, "CMDS.DOC". If you do not have a copy
+of "cmds.doc", it must be created using nroff. Assuming you have the Jove
+sources on a Unix machine, run "Make doc/cmds.doc" to create this file in
+the "doc" subdirectory, then move the file to the Mac. If you obtained the
+sources from a non-Unix source, this file may already be supplied. Place the
+file in the same directory that MacJove will be in.
+
+                      COMMENTS AND QUESTIONS, BUGS
+
+Although Jove appears to work well on the Mac, I know there are some
+problems. Since Jove cannot effectively use the TextEdit routines, it
+does not comply with some aspects of the Macintosh User Interface
+Guidelines. As has recently been brought to my attention, Jove accesses
+files by pathname only, so that if you have two disks in your machine
+with the same volume (disk) name, it will become confused. This has not
+been fixed. Support for variant keyboards is not good at present.
+
+I try to reply to all inquiries about MacJove, but my schedule is busy,
+and it may be several days before you hear from me on the net. Please
+reply via email to me, or through usenet if possible: the chances that
+I will respond quickly to a written question or suggestion are very
+small, and I am difficult to reach by phone. Please do NOT send disks
+unless I ask you to.
+
+    Ken Mitchum
+    Decision Systems Laboratory
+    University of Pittsburgh
+    1360 Scaife Hall
+    Pittsburgh, Pa. 15261
+
+    (km@cadre.dsl.pittsburgh.edu)
+
diff --git a/usr/src/contrib/jove-4.14.6/abbrev.c b/usr/src/contrib/jove-4.14.6/abbrev.c
new file mode 100644 (file)
index 0000000..8145057
--- /dev/null
@@ -0,0 +1,292 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+
+#ifdef ABBREV
+
+#include "fp.h"
+#include "ctype.h"
+
+#ifdef MSDOS
+# include <io.h>
+#endif
+#define HASHSIZE       20
+
+struct abbrev {
+       unsigned int    a_hash;
+       char    *a_abbrev,
+               *a_phrase;
+       struct abbrev   *a_next;
+       data_obj        *a_cmdhook;
+};
+
+private        void
+       define proto((struct abbrev **, char *, char *));
+
+#define GLOBAL NMAJORS
+private struct abbrev  *A_tables[NMAJORS + 1][HASHSIZE];       /* Must be zeroed! */
+
+bool AutoCaseAbbrev = ON;
+
+private unsigned int
+hash(a)
+register char  *a;
+{
+       register unsigned int   hashval = 0;
+       register int    c;
+
+       while ((c = *a++) != '\0')
+               hashval = (hashval << 2) + c;
+
+       return hashval;
+}
+
+private void
+def_abbrev(table)
+struct abbrev  *table[HASHSIZE];
+{
+       char    abbrev[100],
+               phrase[100];
+
+       null_ncpy(abbrev, ask((char *)NULL, "abbrev: "), sizeof(abbrev)-1);
+       null_ncpy(phrase, ask((char *)NULL, "abbrev: %s phrase: ", abbrev),
+               sizeof(phrase)-1);
+       define(table, abbrev, phrase);
+}
+
+private struct abbrev *
+lookup_abbrev(table, abbrev)
+register struct abbrev *table[HASHSIZE];
+register char  *abbrev;
+{
+       register struct abbrev  *ap;
+       unsigned int    h;
+
+       h = hash(abbrev);
+       for (ap = table[h % HASHSIZE]; ap; ap = ap->a_next)
+               if (ap->a_hash == h && strcmp(ap->a_abbrev, abbrev) == 0)
+                       break;
+       return ap;
+}
+
+private void
+define(table, abbrev, phrase)
+register struct abbrev *table[HASHSIZE];
+char   *abbrev,
+       *phrase;
+{
+       register struct abbrev  *ap;
+
+       ap = lookup_abbrev(table, abbrev);
+       if (ap == NULL) {
+               register unsigned int   h = hash(abbrev);
+
+               ap = (struct abbrev *) emalloc(sizeof *ap);
+               ap->a_hash = h;
+               ap->a_abbrev = copystr(abbrev);
+               h %= HASHSIZE;
+               ap->a_next = table[h];
+               ap->a_cmdhook = NULL;
+               table[h] = ap;
+       } else
+               free((UnivPtr) ap->a_phrase);
+       ap->a_phrase = copystr(phrase);
+}
+
+void
+AbbrevExpand()
+{
+       Bufpos  point;
+       char    wordbuf[100];
+       register char   *wp = wordbuf,
+                       *cp;
+       register int    c;
+
+       int     UC_count = 0;
+       struct abbrev   *ap;
+
+       DOTsave(&point);
+       WITH_TABLE(curbuf->b_major)
+           b_word(1);
+           while (curchar < point.p_char && ismword(c = linebuf[curchar])) {
+                   if (AutoCaseAbbrev) {
+                           if (jisupper(c)) {
+                                   UC_count += 1;
+                                   c = jtolower(c);
+                           }
+                   }
+                   *wp++ = c;
+                   curchar += 1;
+           }
+           *wp = '\0';
+       END_TABLE();
+
+       if ((ap = lookup_abbrev(A_tables[curbuf->b_major], wordbuf)) == NULL &&
+           (ap = lookup_abbrev(A_tables[GLOBAL], wordbuf)) == NULL) {
+               SetDot(&point);
+               return;
+       }
+       del_char(BACKWARD, (wp - wordbuf), NO);
+
+       for (cp = ap->a_phrase; (c = *cp) != '\0'; ) {
+               if (AutoCaseAbbrev) {
+                       insert_c(jislower(c) && UC_count &&
+                              (cp == ap->a_phrase || (UC_count > 1 && (cp[-1] == ' '))) ?
+                               CharUpcase(c) : c, 1);
+               } else
+                       insert_c(c, 1);
+               cp += 1;
+       }
+       if (ap->a_cmdhook != NULL)
+               ExecCmd(ap->a_cmdhook);
+}
+
+private char   *mode_names[NMAJORS + 1] = {
+       "Fundamental Mode",
+       "Text Mode",
+       "C Mode",
+#ifdef LISP
+       "Lisp Mode",
+#endif
+       "Global"
+};
+
+private void
+save_abbrevs(file)
+char   *file;
+{
+       File    *fp;
+       struct abbrev   *ap,
+                       **tp;
+       char    buf[LBSIZE];
+       int     i,
+               count = 0;
+
+       fp = open_file(file, buf, F_WRITE, YES, YES);
+       for (i = 0; i <= GLOBAL; i++) {
+               fwritef(fp, "------%s abbrevs------\n", mode_names[i]);
+               for (tp = A_tables[i]; tp < &A_tables[i][HASHSIZE]; tp++)
+                       for (ap = *tp; ap; ap = ap->a_next) {
+                               fwritef(fp, "%s:%s\n",
+                                       ap->a_abbrev,
+                                       ap->a_phrase);
+                               count += 1;
+                       }
+       }
+       f_close(fp);
+       add_mess(" %d written.", count);
+}
+
+private void
+rest_abbrevs(file)
+char   *file;
+{
+       int     mode = -1,      /* Will be ++'d immediately */
+               lnum = 0;
+       char    *phrase_p;
+       File    *fp;
+       char    buf[LBSIZE];
+
+       fp = open_file(file, buf, F_READ, YES, YES);
+       while (mode <= GLOBAL) {
+               if (f_gets(fp, genbuf, (size_t) LBSIZE) || genbuf[0] == '\0')
+                       break;
+               lnum += 1;
+               if (strncmp(genbuf, "------", (size_t)6) == 0) {
+                       mode += 1;
+                       continue;
+               }
+               if (mode == -1 || (phrase_p = strchr(genbuf, ':')) == NULL)
+                       complain("Abbrev. format error, line %d.", file, lnum);
+               *phrase_p++ = '\0';     /* Null terminate the abbrev. */
+               define(A_tables[mode], genbuf, phrase_p);
+       }
+       f_close(fp);
+       message(NullStr);
+}
+
+void
+DefGAbbrev()
+{
+       def_abbrev(A_tables[GLOBAL]);
+}
+
+void
+DefMAbbrev()
+{
+       def_abbrev(A_tables[curbuf->b_major]);
+}
+
+void
+SaveAbbrevs()
+{
+       char    filebuf[FILESIZE];
+
+       save_abbrevs(ask_file((char *)NULL, (char *)NULL, filebuf));
+}
+
+void
+RestAbbrevs()
+{
+       char    filebuf[FILESIZE];
+
+       rest_abbrevs(ask_file((char *)NULL, (char *)NULL, filebuf));
+}
+
+void
+EditAbbrevs()
+{
+       char    *tname = "jove_wam.$$$",
+               *EditName = "Abbreviation Edit";
+       Buffer  *obuf = curbuf,
+               *ebuf;
+
+       if ((ebuf = buf_exists(EditName)) != NULL) {
+               if (ebuf->b_type != B_SCRATCH)
+                       confirm("Over-write buffer %b? ", ebuf);
+       }
+       SetBuf(ebuf = do_select(curwind, EditName));
+       ebuf->b_type = B_SCRATCH;
+       initlist(ebuf);
+       /* Empty buffer.  Save the definitions to a tmp file
+          and read them into this buffer so we can edit them. */
+       save_abbrevs(tname);
+       read_file(tname, NO);
+       message("[Edit definitions and then type C-X C-C]");
+       Recur();                /* We edit them ... now */
+       /* RESetBuf in case we deleted the buffer while we were editing. */
+       SetBuf(ebuf = do_select(curwind, EditName));
+       if (IsModified(ebuf)) {
+               SetBuf(ebuf);
+               file_write(tname, NO);
+               rest_abbrevs(tname);
+       }
+       (void) unlink(tname);
+       SetBuf(do_select(curwind, obuf->b_name));
+}
+
+void
+BindMtoW()
+{
+       struct abbrev   *ap;
+       char    *word;
+       data_obj        *hook;
+
+       word = ask((char *)NULL, "Word: ");
+
+       if ((ap = lookup_abbrev(A_tables[curbuf->b_major], word)) == NULL &&
+           (ap = lookup_abbrev(A_tables[GLOBAL], word)) == NULL)
+               complain("%s: unknown abbrev.", word);
+
+       hook = findmac("Macro: ");
+       if (hook == NULL)
+               complain("[Undefined macro]");
+       ap->a_cmdhook = hook;
+}
+
+#endif /* ABBREV */
diff --git a/usr/src/contrib/jove-4.14.6/argcount.c b/usr/src/contrib/jove-4.14.6/argcount.c
new file mode 100644 (file)
index 0000000..545559c
--- /dev/null
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+
+private        void
+       gather_numeric_argument proto((int)),
+       quad_numeric_arg proto((void));
+
+int    arg_supplied_p, /* NO, YES, or YES_NODIGIT */
+       arg_count;
+
+/* called by C-U to gather a numeric argument, either C-U's or digits,
+   but not both */
+
+void
+TimesFour()
+{
+       quad_numeric_arg();
+}
+
+/* This initializes the numeric argument to 1 and starts multiplying
+   by 4 (the magic number Stallman came up with).  It is an error to
+   invoke quad_numeric_arg() interactively (via TimesFour()), because
+   it uses the LastKeyStruck variable to know what character signals
+   to multiply again (in the loop). */
+private void
+quad_numeric_arg()
+{
+       int     oldc = LastKeyStruck,
+               newc,
+               narg_count,
+               slow;
+
+       slow = NO;
+       arg_supplied_p = YES;
+       arg_count = 1;
+       this_cmd = ARG_CMD;
+       do {
+               if ((narg_count = arg_count * 4) != 0)
+                       arg_count = narg_count;
+               newc = waitchar(&slow);
+               if (jisdigit(newc) || newc == '-') {
+                    arg_supplied_p = NO;
+                    gather_numeric_argument(newc);
+                    return;
+               }
+       } while (newc == oldc);
+       Ungetc(newc);
+}
+
+private void
+gather_numeric_argument(c)
+       int     c;
+{
+       int     sign = 0;
+       static bool     digited;
+       int     slow = NO;
+
+       if (!jisdigit(c) && c != '-')
+               complain((char *)NULL);
+       if (arg_supplied_p == NO) {     /* if we just got here */
+               arg_count = 0;  /* start over */
+               digited = NO;
+       } else if (arg_supplied_p == YES_NODIGIT) {
+               sign = (arg_count < 0) ? -1 : 1;
+               arg_count = 0;
+       }
+
+       if (!sign)
+               sign = (arg_count < 0) ? -1 : 1;
+       if (sign == -1)
+               arg_count = -arg_count;
+       if (c == '-') {
+               sign = -sign;
+               c = waitchar(&slow);
+       }
+       for (;;) {
+               if (jisdigit(c)) {
+                       arg_count = (arg_count * 10) + (c - '0');
+                       digited = YES;
+               } else {
+                       if (digited)
+                               arg_supplied_p = YES;
+                       else {
+                               arg_count = 1;
+                               if (arg_supplied_p == NO)
+                                       arg_supplied_p = YES_NODIGIT;
+                       }
+                       arg_count *= sign;
+                       this_cmd = ARG_CMD;
+                       Ungetc(c);
+                       return;
+               }
+               c = waitchar(&slow);
+       }
+}
+
+void
+Digit()
+{
+       gather_numeric_argument(LastKeyStruck);
+}
+
+void
+Digit0()
+{
+       gather_numeric_argument('0');
+}
+
+void
+Digit1()
+{
+       gather_numeric_argument('1');
+}
+
+void
+Digit2()
+{
+       gather_numeric_argument('2');
+}
+
+void
+Digit3()
+{
+       gather_numeric_argument('3');
+}
+
+void
+Digit4()
+{
+       gather_numeric_argument('4');
+}
+
+void
+Digit5()
+{
+       gather_numeric_argument('5');
+}
+
+void
+Digit6()
+{
+       gather_numeric_argument('6');
+}
+
+void
+Digit7()
+{
+       gather_numeric_argument('7');
+}
+
+void
+Digit8()
+{
+       gather_numeric_argument('8');
+}
+
+void
+Digit9()
+{
+       gather_numeric_argument('9');
+}
diff --git a/usr/src/contrib/jove-4.14.6/argcount.h b/usr/src/contrib/jove-4.14.6/argcount.h
new file mode 100644 (file)
index 0000000..29b3333
--- /dev/null
@@ -0,0 +1,21 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* macros for getting at and setting the current argument count */
+
+extern int     arg_supplied_p, /* NO, YES, or YES_NODIGIT */
+               arg_count;
+
+#define YES_NODIGIT    2
+
+#define arg_type()             arg_supplied_p
+#define arg_value()            arg_count
+#define set_is_an_arg(there_is)        { arg_supplied_p = (there_is); }
+#define set_arg_value(n)       { arg_supplied_p = YES; arg_count = (n); }
+#define negate_arg_value()     { arg_count = -arg_count; }
+#define clr_arg_value()                { arg_supplied_p = NO; arg_count = 1; }
+#define is_an_arg()            (arg_supplied_p != NO)
diff --git a/usr/src/contrib/jove-4.14.6/ask.c b/usr/src/contrib/jove-4.14.6/ask.c
new file mode 100644 (file)
index 0000000..a106139
--- /dev/null
@@ -0,0 +1,566 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "termcap.h"
+#include "ctype.h"
+#include "chars.h"
+#include "disp.h"
+#include "fp.h"
+#include "scandir.h"
+
+#include <signal.h>
+
+#ifdef MAC
+# include "mac.h"
+#else  /* !MAC */
+# ifdef        STDARGS
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+# ifdef        F_COMPLETION
+#  include <sys/stat.h>
+# endif
+#endif /* !MAC */
+
+int    AbortChar = CTL('G');
+bool   DoEVexpand = NO;        /* should we expand evironment variables? */
+
+bool   Asking = NO;
+int    AskingWidth;
+
+char   Minibuf[LBSIZE];
+private Line   *CurAskPtr = NULL;      /* points at some line in mini-buffer */
+private Buffer *AskBuffer = NULL;      /* Askbuffer points to actual structure */
+
+/* The way the mini-buffer works is this:  The first line of the mini-buffer
+   is where the user does his stuff.  The rest of the buffer contains
+   strings that the user often wants to use, for instance, file names, or
+   common search strings, etc.  If he types C-N or C-P while in ask(), we
+   bump the point up or down a line and extract the contents (we make sure
+   is somewhere in the mini-buffer). */
+
+private Buffer *
+get_minibuf()
+{
+       if (AskBuffer) {                /* make sure ut still exists */
+               register Buffer *b;
+
+               for (b = world; b != NULL; b = b->b_next)
+                       if (b == AskBuffer)
+                               return b;
+       }
+       AskBuffer = do_select((Window *)NULL, "*minibuf*");
+       AskBuffer->b_type = B_SCRATCH;
+       return AskBuffer;
+}
+
+/* Add a string to the mini-buffer. */
+
+void
+minib_add(str, movedown)
+char   *str;
+bool   movedown;
+{
+       register Buffer *saveb = curbuf;
+
+       SetBuf(get_minibuf());
+       LineInsert(1);
+       ins_str(str, NO);
+       if (movedown)
+               CurAskPtr = curline;
+       SetBuf(saveb);
+}
+
+/* look for any substrings of the form $foo in linebuf, and expand
+   them according to their value in the environment (if possible) -
+   this munges all over curchar and linebuf without giving it a second
+   thought (I must be getting lazy in my old age) */
+private void
+EVexpand()
+{
+       register int    c;
+       register char   *lp = linebuf,
+                       *ep;
+       char    varname[128],
+               *vp,
+               *lp_start;
+       Mark    *m = MakeMark(curline, curchar, M_FLOATER);
+
+       while ((c = *lp++) != '\0') {
+               if (c != '$')
+                       continue;
+               lp_start = lp - 1;      /* the $ */
+               vp = varname;
+               while ((c = *lp++) != '\0') {
+                       if (!jisword(c))
+                               break;
+                       *vp++ = c;
+               }
+               *vp = '\0';
+               /* if we find an env. variable with the right
+                  name, we insert it in linebuf, and then delete
+                  the variable name that we're replacing - and
+                  then we continue in case there are others ... */
+               if ((ep = getenv(varname)) != NULL) {
+                       curchar = lp_start - linebuf;
+                       ins_str(ep, NO);
+                       del_char(FORWARD, (int)strlen(varname) + 1, NO);
+                       lp = linebuf + curchar;
+               }
+       }
+       ToMark(m);
+       DelMark(m);
+}
+
+bool   InRealAsk = NO;
+
+private char *
+real_ask(delim, d_proc, def, prompt)
+char   *delim,
+       *def,
+       *prompt;
+bool   (*d_proc) proto((int));
+{
+       jmp_buf savejmp;
+       int     c,
+               prompt_len;
+       Buffer  *saveb = curbuf;
+       volatile int    aborted = NO;
+       int     no_typed = NO;
+       data_obj        *push_cmd = LastCmd;
+       int     o_a_v = arg_value(),
+               o_i_an_a = is_an_arg();
+#ifdef MAC
+               menus_off();
+#endif
+
+       if (InRealAsk)
+               complain((char *) NULL);
+       push_env(savejmp);
+       InRealAsk = YES;
+       SetBuf(get_minibuf());
+       if (!inlist(AskBuffer->b_first, CurAskPtr))
+               CurAskPtr = curline;
+       prompt_len = strlen(prompt);
+       ToFirst();      /* Beginning of buffer. */
+       linebuf[0] = '\0';
+       modify();
+       makedirty(curline);
+
+       if (setjmp(mainjmp)) {
+               if (InJoverc) {         /* this is a kludge */
+                       aborted = YES;
+                       goto cleanup;
+               }
+       }
+
+       for (;;) {
+               clr_arg_value();
+               last_cmd = this_cmd;
+               init_strokes();
+cont:
+               s_mess("%s%s", prompt, linebuf);
+               Asking = YES;
+               AskingWidth = curchar + prompt_len;
+               c = getch();
+
+               if ((c == EOF) || (c != '\0' && strchr(delim, c) != NULL)) {
+                       if (DoEVexpand)
+                               EVexpand();
+                       if (d_proc == (bool(*) proto((int)))NULL || !(*d_proc)(c))
+                               break;
+               } else if (c == AbortChar) {
+                       message("[Aborted]");
+                       aborted = YES;
+                       break;
+               } else switch (c) {
+               case CTL('N'):
+               case CTL('P'):
+               case CTL('U'):          /* Allow ^U as a synonym for ^P */
+                       if (CurAskPtr != NULL) {
+                               int     n = (c == CTL('P') ? -arg_value() : arg_value());
+                               CurAskPtr = next_line(CurAskPtr, n);
+                               if (CurAskPtr == curbuf->b_first && CurAskPtr->l_next != NULL)
+                                       CurAskPtr = CurAskPtr->l_next;
+                               (void) ltobuf(CurAskPtr, linebuf);
+                               modify();
+                               makedirty(curline);
+                               Eol();
+                               this_cmd = 0;
+                       }
+                       break;
+
+               case CTL('R'):
+                       if (def)
+                               ins_str(def, NO);
+                       else
+                               rbell();
+                       break;
+
+               default:
+                       dispatch(c);
+                       break;
+               }
+               if (curbuf != AskBuffer)
+                       SetBuf(AskBuffer);
+               if (curline != curbuf->b_first) {
+                       CurAskPtr = curline;
+                       curline = curbuf->b_first;      /* with whatever is in linebuf */
+               }
+               if (this_cmd == ARG_CMD)
+                       goto cont;
+       }
+cleanup:
+       pop_env(savejmp);
+
+       LastCmd = push_cmd;
+       set_arg_value(o_a_v);
+       set_is_an_arg(o_i_an_a);
+       no_typed = (linebuf[0] == '\0');
+       strcpy(Minibuf, linebuf);
+       SetBuf(saveb);
+       InRealAsk = Asking = Interactive = NO;
+       if (!aborted) {
+               if (!charp()) {
+                       Placur(ILI, 0);
+                       flushscreen();
+               }
+               if (no_typed)
+                       return NULL;
+       } else
+               complain(mesgbuf);
+       return Minibuf;
+}
+
+#ifdef STDARGS
+       char *
+ask(char *def, char *fmt,...)
+#else
+       /*VARARGS2*/ char *
+ask(def, fmt, va_alist)
+       char    *def,
+               *fmt;
+       va_dcl
+#endif
+{
+       char    prompt[128];
+       char    *ans;
+       va_list ap;
+
+       va_init(ap, fmt);
+       format(prompt, sizeof prompt, fmt, ap);
+       va_end(ap);
+       ans = real_ask("\r\n", (bool (*) proto((int))) NULL, def, prompt);
+       if (ans == NULL) {              /* Typed nothing. */
+               if (def == NULL)
+                       complain("[No default]");
+               return def;
+       }
+       return ans;
+}
+
+#ifdef STDARGS
+char *
+do_ask(char *delim, bool (*d_proc) proto((int)), char *def, const char *fmt,...)
+#else
+/*VARARGS4*/ char *
+do_ask(delim, d_proc, def, fmt, va_alist)
+       char    *delim,
+               *def;
+       const char      *fmt;
+       bool    (*d_proc) proto((int));
+       va_dcl
+#endif
+{
+       char    prompt[128];
+       va_list ap;
+
+       va_init(ap, fmt);
+       format(prompt, sizeof prompt, fmt, ap);
+       va_end(ap);
+       return real_ask(delim, d_proc, def, prompt);
+}
+
+#ifdef STDARGS
+       int
+yes_or_no_p(char *fmt, ...)
+#else
+       /*VARARGS1*/ int
+yes_or_no_p(fmt, va_alist)
+       char    *fmt;
+       va_dcl
+#endif
+{
+       char    prompt[128];
+       int     c;
+       va_list ap;
+
+       va_init(ap, fmt);
+       format(prompt, sizeof prompt, fmt, ap);
+       va_end(ap);
+       for (;;) {
+               message(prompt);
+               Asking = YES;   /* so redisplay works */
+               AskingWidth = strlen(prompt);
+               c = getch();
+               Asking = NO;
+               if (c == AbortChar)
+                       complain("[Aborted]");
+               switch (CharUpcase(c)) {
+               case 'Y':
+                       return YES;
+
+               case 'N':
+                       return NO;
+
+               default:
+                       add_mess("[Type Y or N]");
+                       SitFor(10);
+               }
+       }
+       /* NOTREACHED */
+}
+
+#ifdef F_COMPLETION
+
+private char   *fc_filebase;
+bool   DispBadFs = YES;        /* display bad file names? */
+# ifndef       MSDOS
+char   BadExtensions[128] = ".o";
+# else /* MSDOS */
+char   BadExtensions[128] = ".obj .exe .com .bak .arc .lib .zoo";
+# endif        /* MSDOS */
+
+private int
+bad_extension(name)
+char   *name;
+{
+       char    *ip,
+               *bads;
+       size_t  namelen = strlen(name),
+               ext_len;
+
+#ifdef UNIX
+       if (strcmp(name, ".")==0 || strcmp(name, "..")==0)
+               return YES;
+#endif
+       for (ip=bads=BadExtensions; *ip!='\0'; bads = ip+1) {
+               if ((ip = strchr(bads, ' ')) == NULL)
+                       ip = bads + strlen(bads);
+               ext_len = ip - bads;
+               if (ext_len != 0 && ext_len < namelen &&
+                   (strncmp(&name[namelen - ext_len], bads, ext_len) == 0))
+                       return YES;
+       }
+       return NO;
+}
+
+private int
+f_match(file)
+char   *file;
+{
+       int     len = strlen(fc_filebase);
+
+       if (!DispBadFs && bad_extension(file))
+               return NO;
+
+       return ((len == 0) ||
+#ifdef MSDOS
+               (casencmp(file, fc_filebase, strlen(fc_filebase)) == 0)
+#else
+               (strncmp(file, fc_filebase, strlen(fc_filebase)) == 0)
+#endif
+               );
+}
+
+private int
+isdir(name)
+char   *name;
+{
+       struct stat     stbuf;
+       char    filebuf[FILESIZE];
+
+       PathParse(name, filebuf);
+       return ((stat(filebuf, &stbuf) != -1) &&
+               (stbuf.st_mode & S_IFDIR) == S_IFDIR);
+}
+
+private void
+fill_in(dir_vec, n)
+register char  **dir_vec;
+int    n;
+{
+       int     minmatch = 0,
+               numfound = 0,
+               lastmatch = -1,
+               i,
+               the_same = TRUE, /* After filling in, are we the same
+                                   as when we were called? */
+               is_ntdir;       /* Is Newly Typed Directory name */
+
+       for (i = 0; i < n; i++) {
+               /* if it's no, then we have already filtered them out
+                  in f_match() so there's no point in doing it again */
+               if (DispBadFs && bad_extension(dir_vec[i]))
+                       continue;
+               if (numfound)
+                       minmatch = min(minmatch,
+                                      numcomp(dir_vec[lastmatch], dir_vec[i]));
+               else
+                       minmatch = strlen(dir_vec[i]);
+               lastmatch = i;
+               numfound += 1;
+       }
+       /* Ugh.  Beware--this is hard to get right in a reasonable
+          manner.  Please excuse this code--it's past my bedtime. */
+       if (numfound == 0) {
+               rbell();
+               return;
+       }
+       Eol();
+       if (minmatch > (int)strlen(fc_filebase)) {
+               the_same = FALSE;
+               null_ncpy(fc_filebase, dir_vec[lastmatch], (size_t) minmatch);
+               Eol();
+               makedirty(curline);
+       }
+       is_ntdir = ((numfound == 1) &&
+                   (curchar > 0) &&
+                   (linebuf[curchar - 1] != '/') &&
+                   (isdir(linebuf)));
+       if (the_same && !is_ntdir) {
+               add_mess((n == 1) ? " [Unique]" : " [Ambiguous]");
+               SitFor(7);
+       }
+       if (is_ntdir)
+               insert_c('/', 1);
+}
+
+/* called from do_ask() when one of "\r\n ?" is typed.  Does the right
+   thing, depending on which. */
+
+private bool
+f_complete(c)
+int    c;
+{
+       char    dir[FILESIZE],
+               **dir_vec;
+       int     nentries,
+               i;
+
+       if (c == CR || c == LF)
+               return FALSE;   /* tells ask to return now */
+       fc_filebase = strrchr(linebuf, '/');
+#ifdef MSDOS
+       if (fc_filebase == NULL) {
+               fc_filebase = strrchr(linebuf, '\\');
+               if (fc_filebase == NULL)
+                       fc_filebase = strrchr(linebuf, ':');
+       }
+#endif /* MSDOS */
+       if (fc_filebase != NULL) {
+               char    tmp[FILESIZE];
+
+               fc_filebase += 1;
+               null_ncpy(tmp, linebuf, (size_t) (fc_filebase - linebuf));
+               if (tmp[0] == '\0')
+                       strcpy(tmp, "/");
+               PathParse(tmp, dir);
+       } else {
+               fc_filebase = linebuf;
+               strcpy(dir, ".");
+       }
+       if ((nentries = jscandir(dir, &dir_vec, f_match, alphacomp)) == -1) {
+               add_mess(" [Unknown directory: %s]", dir);
+               SitFor(7);
+               return TRUE;
+       }
+       if (nentries == 0) {
+               add_mess(" [No match]");
+               SitFor(7);
+       } else if (c == ' ' || c == '\t')
+               fill_in(dir_vec, nentries);
+       else {
+               /* we're a '?' */
+               int     maxlen = 0,
+                       ncols,
+                       col,
+                       lines,
+                       linespercol;
+
+               TOstart("Completion", FALSE);   /* false means newline only on request */
+               Typeout("(! means file will not be chosen unless typed explicitly)");
+               Typeout((char *)NULL);
+               Typeout("Possible completions (in %s):", dir);
+               Typeout((char *)NULL);
+
+               for (i = 0; i < nentries; i++)
+                       maxlen = max((int)strlen(dir_vec[i]), maxlen);
+               maxlen += 4;    /* pad each column with at least 4 spaces */
+               ncols = (CO - 2) / maxlen;
+               linespercol = 1 + (nentries / ncols);
+
+               for (lines = 0; lines < linespercol; lines++) {
+                       for (col = 0; col < ncols; col++) {
+                               bool    isbad;
+                               int     which;
+
+                               which = (col * linespercol) + lines;
+                               if (which >= nentries)
+                                       break;
+                               if (DispBadFs)
+                                       isbad = bad_extension(dir_vec[which]);
+                               else
+                                       isbad = NO;
+                               Typeout("%s%-*s", isbad ? "!" : NullStr,
+                                       maxlen - isbad, dir_vec[which]);
+                       }
+                       Typeout((char *) NULL);
+               }
+               TOstop();
+       }
+       freedir(&dir_vec, nentries);
+       return TRUE;
+}
+
+#endif /* F_COMPLETION */
+
+char *
+ask_file(prmt, def, buf)
+const char     *prmt;
+char   *def,
+       *buf;
+{
+       char    *ans,
+               prompt[128],
+               *pretty_name = pr_name(def, YES);
+
+       if (prmt) {
+               strcpy(prompt, prmt);
+       } else {
+               if (def != NULL && *def != '\0') {
+                       swritef(prompt, sizeof(prompt), ": %f (default %s) ",
+                               pretty_name);
+                       if ((int)strlen(prompt) * 2 >= CO)
+                               swritef(prompt, sizeof(prompt), ProcFmt);
+               } else {
+                       swritef(prompt, sizeof(prompt), ProcFmt);
+               }
+       }
+#ifdef F_COMPLETION
+       ans = real_ask("\r\n \t?", f_complete, pretty_name, prompt);
+       if (ans == NULL && (ans = pretty_name) == NULL)
+               complain("[No default file name]");
+#else
+       ans = ask(pretty_name, prompt);
+#endif
+       PathParse(ans, buf);
+
+       return buf;
+}
diff --git a/usr/src/contrib/jove-4.14.6/buf.c b/usr/src/contrib/jove-4.14.6/buf.c
new file mode 100644 (file)
index 0000000..7507c6c
--- /dev/null
@@ -0,0 +1,720 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* Contains commands that deal with creating, selecting, killing and
+   listing buffers, and buffer modes, and find-file, etc. */
+
+#include "jove.h"
+#include "ctype.h"
+#include "disp.h"
+#ifdef IPROCS
+# include "fp.h"
+# include "iproc.h"
+#endif
+
+#ifdef MAC
+# include "mac.h"
+#else
+# include <sys/stat.h>
+#endif
+
+private void
+       setbname proto((Buffer *, char *));
+
+private char   *Mainbuf = "Main",
+       *NoName = "Sans un nom!";
+
+Buffer *world = NULL,          /* First in the list */
+       *curbuf = NULL,         /* pointer into world for current buffer */
+       *lastbuf = NULL;        /* Last buffer we were in so we have a default
+                                  buffer during a select buffer. */
+
+/* Toggle BIT in the current buffer's minor mode flags.  If argument is
+   supplied, a positive one always turns on the mode and zero argument
+   always turns it off. */
+
+void
+TogMinor(bit)
+int    bit;
+{
+       if (is_an_arg()) {
+               if (arg_value() == 0)
+                       curbuf->b_minor &= ~bit;
+               else
+                       curbuf->b_minor |= bit;
+       } else
+               curbuf->b_minor ^= bit;
+       UpdModLine = YES;
+}
+
+/* Creates a new buffer, links it at the end of the buffer chain, and
+   returns it. */
+
+private Buffer *free_bufs = NULL;
+
+private Buffer *
+buf_alloc()
+{
+       register Buffer *b,
+                       *lastbp;
+
+       lastbp = NULL;
+       for (b = world; b != NULL; b = b->b_next)
+               lastbp = b;
+
+       if (free_bufs != NULL) {
+               b = free_bufs;
+               free_bufs = b->b_next;
+       } else {
+               b = (Buffer *) emalloc(sizeof (Buffer));
+       }
+       if (lastbp)
+               lastbp->b_next = b;
+       else
+               world = b;
+       b->b_first = NULL;
+       b->b_next = NULL;
+#ifdef MAC
+       b->Type = BUFFER;       /* kludge, but simplifies menu handlers */
+       b->Name = NULL;
+#endif
+       return b;
+}
+
+/* Makes a buffer and initializes it.  Obsolete.  Used to take two
+   arguments, a buffer name and a file name. */
+
+private Buffer *
+mak_buf()
+{
+       register Buffer *newb;
+       register int    i;
+
+       newb = buf_alloc();
+       newb->b_fname = NULL;
+       newb->b_name = NoName;
+       set_ino(newb);
+       newb->b_marks = NULL;
+       newb->b_themark = 0;            /* Index into markring */
+       /* No marks yet */
+       for (i = 0; i < NMARKS; i++)
+               newb->b_markring[i] = NULL;
+       newb->b_modified = NO;
+       newb->b_type = B_FILE;  /* File until proven SCRATCH */
+       newb->b_ntbf = NO;
+       newb->b_minor = 0;
+       newb->b_major = TEXT;
+       newb->b_first = NULL;
+       newb->b_map = NULL;
+#ifdef IPROCS
+       newb->b_process = NULL;
+#endif
+       initlist(newb);
+#ifdef MAC
+       Bufchange = YES;
+#endif
+       return newb;
+}
+
+void
+ReNamBuf()
+{
+       register char   *new = NULL,
+                       *prompt = ProcFmt,
+                       *second = "%s already exists; new name? ";
+
+       for (;;) {
+               new = ask((char *)NULL, prompt, new);
+               if (!buf_exists(new))
+                       break;
+               prompt = second;
+       }
+       setbname(curbuf, new);
+}
+
+void
+FindFile()
+{
+       register char   *name;
+       char    fnamebuf[FILESIZE];
+
+       name = ask_file((char *)NULL, curbuf->b_fname, fnamebuf);
+       SetABuf(curbuf);
+       SetBuf(do_find(curwind, name, NO));
+}
+
+private void
+mkbuflist(bnamp, ebnamp)
+register char  **bnamp;
+char           **ebnamp;
+{
+       register Buffer *b;
+
+       for (b = world; b != NULL; b = b->b_next) {
+               if (b->b_name != NULL) {
+                       *bnamp++ = b->b_name;
+                       if (bnamp >= ebnamp)
+                               complain("too many buffers to list");
+               }
+       }
+       *bnamp = NULL;
+}
+
+char *
+ask_buf(def)
+Buffer *def;
+{
+       char    *bnames[100];
+       register char   *bname;
+       register int    offset;
+       char    prompt[100];
+
+       if (def != NULL && def->b_name != NULL) {
+               swritef(prompt, sizeof(prompt), ": %f (default %s) ",
+                       def->b_name);
+       } else {
+               swritef(prompt, sizeof(prompt), ProcFmt);
+       }
+       mkbuflist(bnames, &bnames[sizeof(bnames) / sizeof(*bnames)]);
+       offset = complete(bnames, prompt, RET_STATE);
+       if (offset == EOF)
+               complain((char *)NULL);
+       if (offset == ORIGINAL || offset == AMBIGUOUS) {
+               bname = Minibuf;
+       } else if (offset == NULLSTRING) {
+               if (def == NULL)
+                       complain((char *)NULL);
+               bname = def->b_name;
+       } else {
+               if (offset < 0)
+                       complain((char *)NULL);
+               bname = bnames[offset];
+       }
+
+       return bname;
+}
+
+void
+BufSelect()
+{
+       register char   *bname;
+
+       bname = ask_buf(lastbuf);
+       SetABuf(curbuf);
+       SetBuf(do_select(curwind, bname));
+}
+
+#ifdef MSDOS
+
+private void
+BufNSelect(n)
+int    n;
+{
+       register Buffer *b;
+
+       for (b = world; b != NULL; b = b->b_next) {
+               if (b->b_name != NULL) {
+                       if (n == 0) {
+                               SetABuf(curbuf);
+                               SetBuf(do_select(curwind, b->b_name));
+                               return;
+                       }
+                       n -= 1;
+               }
+       }
+       complain("[No such buffer]");
+}
+
+void Buf0Select() { BufNSelect(0); }
+void Buf1Select() { BufNSelect(1); }
+void Buf2Select() { BufNSelect(2); }
+void Buf3Select() { BufNSelect(3); }
+void Buf4Select() { BufNSelect(4); }
+void Buf5Select() { BufNSelect(5); }
+void Buf6Select() { BufNSelect(6); }
+void Buf7Select() { BufNSelect(7); }
+void Buf8Select() { BufNSelect(8); }
+void Buf9Select() { BufNSelect(9); }
+
+#endif /* MSDOS */
+
+private void
+defb_wind(b)
+register Buffer *b;
+{
+       register Window *w = fwind;
+       char    *alt;
+
+       if (lastbuf == b || lastbuf == NULL) {
+               lastbuf = NULL;
+               alt = (b->b_next != NULL) ? b->b_next->b_name : Mainbuf;
+       } else
+               alt = lastbuf->b_name;
+
+       do {
+               if (w->w_bufp == b) {
+                       if (one_windp() || alt != Mainbuf)
+                               (void) do_select(w, alt);
+                       else {
+                               Window  *save = w->w_next;
+
+                               del_wind(w);
+                               w = save->w_prev;
+                       }
+               }
+               w = w->w_next;
+       } while (w != fwind || w->w_bufp == b);
+}
+
+private Buffer *
+getNMbuf()
+{
+       register Buffer *delbuf;
+       register char   *bname;
+
+       bname = ask_buf(curbuf);
+       if ((delbuf = buf_exists(bname)) == NULL)
+               complain("[No such buffer]");
+       if (delbuf->b_modified)
+               confirm("%s modified, are you sure? ", bname);
+       return delbuf;
+}
+
+void
+BufErase()
+{
+       register Buffer *delbuf;
+
+       if ((delbuf = getNMbuf()) != NULL) {
+               initlist(delbuf);
+               delbuf->b_modified = NO;
+       }
+}
+
+/* Free a buffer structure.
+ * The actual struct is preserved to reduce the damage
+ * from dangling references to it.  They seem to be pervasive.
+ * We try to reset enough that a dangling reference will be useless.
+ */
+
+private void
+kill_buf(delbuf)
+register Buffer        *delbuf;
+{
+       register Buffer *b,
+                       *lastb = NULL;
+
+#ifdef IPROCS
+       pbuftiedp(delbuf);      /* check for lingering processes */
+#endif
+       /* clean up windows associated with this buffer */
+       if (delbuf == curbuf)
+               curbuf = NULL;
+       if (delbuf == lastbuf)
+               lastbuf = curbuf;       /* even if NULL */
+       defb_wind(delbuf);
+       if (curbuf == NULL)
+               SetBuf(curwind->w_bufp);
+
+       /* unlink the buffer */
+       for (b = world; b != NULL; lastb = b, b = b->b_next)
+               if (b == delbuf)
+                       break;
+       if (lastb)
+               lastb->b_next = delbuf->b_next;
+       else
+               world = delbuf->b_next;
+
+#ifndef        MAC
+       if (perr_buf == delbuf) {
+               ErrFree();
+               perr_buf = NULL;
+       }
+#endif
+
+       lfreelist(delbuf->b_first);
+       delbuf->b_first = delbuf->b_dot = delbuf->b_last = NULL;
+       if (delbuf->b_name) {
+               free((UnivPtr) delbuf->b_name);
+               delbuf->b_name = NULL;
+       }
+       if (delbuf->b_fname) {
+               free((UnivPtr) delbuf->b_fname);
+               delbuf->b_fname = NULL;
+       }
+       flush_marks(delbuf);
+       delbuf->b_marks = NULL;
+
+       delbuf->b_next = free_bufs;
+       free_bufs = delbuf;
+#ifdef MAC
+       Bufchange = YES;
+       delbuf->Name = NULL;
+#endif
+}
+
+/* offer to kill some buffers */
+
+void
+KillSome()
+{
+       register Buffer *b,
+                       *next;
+       Buffer  *oldb;
+       register char   *y_or_n;
+
+       for (b = world; b != NULL; b = next) {
+               next = b->b_next;
+               if (yes_or_no_p("Kill %s? ", b->b_name) == NO)
+                       continue;
+               if (IsModified(b)) {
+                       y_or_n = ask("No", "%s modified; should I save it? ", b->b_name);
+                       if (CharUpcase(*y_or_n) == 'Y') {
+                               oldb = curbuf;
+                               SetBuf(b);
+                               SaveFile();
+                               SetBuf(oldb);
+                       }
+               }
+               kill_buf(b);
+       }
+}
+
+void
+BufKill()
+{
+       Buffer  *b;
+
+       if ((b = getNMbuf()) == NULL)
+               return;
+       kill_buf(b);
+}
+
+private char *
+line_cnt(b, buf, size)
+register Buffer        *b;
+char   *buf;
+size_t size;
+{
+       register int    nlines = 0;
+       register Line   *lp;
+
+       for (lp = b->b_first; lp != NULL; lp = lp->l_next, nlines++)
+               ;
+       swritef(buf, size, "%d", nlines);
+       return buf;
+}
+
+private const char     *const TypeNames[] = {
+       NULL,
+       "Scratch",
+       "File",
+       "Process",
+};
+
+void
+BufList()
+{
+       register char   *fmt = "%-2s %-5s %-11s %-1s %-*s  %-s";
+       register Buffer *b;
+       int     bcount = 1,             /* To give each buffer a number */
+               buf_width = 11;
+       char    nbuf[10];
+
+       for (b = world; b != NULL; b = b->b_next)
+               buf_width = max(buf_width, (int)strlen(b->b_name));
+
+       TOstart("Buffer list", TRUE);   /* true means auto-newline */
+
+       Typeout("(* means buffer needs saving)");
+       Typeout("(+ means file hasn't been read yet)");
+       Typeout(NullStr);
+       Typeout(fmt, "NO", "Lines", "Type", NullStr, buf_width, "Name", "File");
+       Typeout(fmt, "--", "-----", "----", NullStr, buf_width, "----", "----");
+       for (b = world; b != NULL; b = b->b_next) {
+               Typeout(fmt, itoa(bcount++),
+                               line_cnt(b, nbuf, sizeof(nbuf)),
+                               TypeNames[b->b_type],
+                               IsModified(b) ? "*" :
+                                        b->b_ntbf ? "+" : NullStr,
+                               buf_width,
+                               /* For the * (variable length field) */
+                               b->b_name,
+                               filename(b));
+
+               if (TOabort)
+                       break;
+       }
+       TOstop();
+}
+
+private void
+bufname(b)
+register Buffer        *b;
+{
+       char    tmp[100],
+               *cp;
+       int     try = 1;
+
+       if (b->b_fname == NULL)
+               complain("[No file name]");
+       cp = basename(b->b_fname);
+       strcpy(tmp, cp);
+       while (buf_exists(tmp)) {
+               swritef(tmp, sizeof(tmp), "%s.%d", cp, try);
+               try += 1;
+       }
+       setbname(b, tmp);
+}
+
+void
+initlist(b)
+register Buffer        *b;
+{
+       lfreelist(b->b_first);
+       b->b_first = b->b_dot = b->b_last = NULL;
+       (void) listput(b, b->b_first);
+
+       SavLine(b->b_dot, NullStr);
+       b->b_char = 0;
+       AllMarkSet(b, b->b_dot, 0);
+       if (b == curbuf)
+               getDOT();
+}
+
+/* Returns pointer to buffer with name NAME, or if NAME is a string of digits
+   returns the buffer whose number equals those digits.  Otherwise, returns
+   NULL. */
+
+Buffer *
+buf_exists(name)
+register char  *name;
+{
+       register Buffer *bp;
+       int     n;
+
+       if (name == NULL)
+               return NULL;
+
+       for (bp = world; bp != NULL; bp = bp->b_next)
+               if (strcmp(bp->b_name, name) == 0)
+                       return bp;
+
+       /* Doesn't match any names.  Try for a buffer number... */
+
+       if (chr_to_int(name, 10, YES, &n) != INT_BAD) {
+               for (bp = world; n > 1; bp = bp->b_next) {
+                       if (bp == NULL)
+                               break;
+                       n -= 1;
+               }
+               return bp;
+       }
+
+       return NULL;
+}
+
+/* Returns buffer pointer with a file name NAME, if one exists.  Stat's the
+   file and compares inodes, in case NAME is a link, as well as the actual
+   characters that make up the file name. */
+
+Buffer *
+file_exists(name)
+register char  *name;
+{
+       struct stat     stbuf;
+       register struct stat    *s = &stbuf;
+       register Buffer *b = NULL;
+       char    fnamebuf[FILESIZE];
+
+#ifdef MSDOS
+       strlwr(name);
+#endif /* MSDOS */
+       if (name) {
+               PathParse(name, fnamebuf);
+               if (stat(fnamebuf, s) == -1)
+                       s->st_ino = 0;
+               for (b = world; b != NULL; b = b->b_next) {
+                       if (
+#ifndef        MSDOS
+                           (b->b_ino != 0 && b->b_ino == s->st_ino &&
+                            b->b_dev != 0 && b->b_dev == s->st_dev) ||
+#endif /* MSDOS */
+                           (b->b_fname != NULL &&
+                            strcmp(b->b_fname, fnamebuf) == 0))
+                               break;
+               }
+       }
+       return b;
+}
+
+private void
+setbname(b, name)
+register Buffer        *b;
+register char  *name;
+{
+       UpdModLine = YES;       /* Kludge ... but speeds things up considerably */
+       if (name != NULL) {
+               if (b->b_name == NoName)
+                       b->b_name = NULL;
+               b->b_name = freealloc((UnivPtr) b->b_name, strlen(name) + 1);
+               strcpy(b->b_name, name);
+       } else {
+               b->b_name = NULL;
+       }
+#ifdef MAC
+       Bufchange = YES;
+#endif
+}
+
+void
+setfname(b, name)
+register Buffer        *b;
+register char  *name;
+{
+       char    wholename[FILESIZE],
+               oldname[FILESIZE],
+               *oldptr = oldname;
+       Buffer  *save = curbuf;
+
+       SetBuf(b);
+       UpdModLine = YES;       /* Kludge ... but speeds things up considerably */
+       if (b->b_fname == NULL)
+               oldptr = NULL;
+       else
+               strcpy(oldname, b->b_fname);
+       if (name) {
+#ifdef MSDOS
+               strlwr(name);
+#endif /* MSDOS */
+               PathParse(name, wholename);
+               curbuf->b_fname = freealloc((UnivPtr) curbuf->b_fname, strlen(wholename) + 1);
+               strcpy(curbuf->b_fname, wholename);
+       } else
+               b->b_fname = NULL;
+       DoAutoExec(curbuf->b_fname, oldptr);
+       curbuf->b_mtime = curbuf->b_dev = curbuf->b_ino = 0;    /* until they're known. */
+       SetBuf(save);
+#ifdef MAC
+       Bufchange = YES;
+#endif
+}
+
+void
+set_ino(b)
+register Buffer        *b;
+{
+       struct stat     stbuf;
+
+       if (b->b_fname == NULL || stat(pr_name(b->b_fname, NO), &stbuf) == -1) {
+               b->b_dev = 0;
+               b->b_ino = 0;
+               b->b_mtime = 0;
+       } else {
+               b->b_dev = stbuf.st_dev;
+               b->b_ino = stbuf.st_ino;
+               b->b_mtime = stbuf.st_mtime;
+       }
+}
+
+/* Find the file `fname' into buf and put in in window `w' */
+
+Buffer *
+do_find(w, fname, force)
+register Window        *w;
+register char  *fname;
+bool   force;
+{
+       register Buffer *b;
+
+       b = file_exists(fname);
+       if (b == NULL) {
+               b = mak_buf();
+               setfname(b, fname);
+               bufname(b);
+               set_ino(b);
+               b->b_ntbf = YES;
+       }
+       if (force) {
+               Buffer  *oldb = curbuf;
+
+               SetBuf(b);      /* this'll read the file */
+               SetBuf(oldb);
+       }
+       if (w)
+               tiewind(w, b);
+       return b;
+}
+
+/* set alternate buffer */
+
+void
+SetABuf(b)
+Buffer *b;
+{
+       if (b != NULL)
+               lastbuf = b;
+}
+
+
+/* check to see if BP is a valid buffer pointer */
+private bool
+valid_bp(bp)
+register Buffer        *bp;
+{
+       register Buffer *b;
+
+       for (b = world; b != NULL; b = b->b_next)
+               if (b == bp)
+                       return YES;
+       return NO;
+}
+
+void
+SetBuf(newbuf)
+register Buffer        *newbuf;
+{
+       if (newbuf == curbuf || newbuf == NULL)
+               return;
+
+       if (!valid_bp(newbuf))
+               complain("Internal error: (0x%x) is not a valid buffer pointer!", newbuf);
+       lsave();
+       curbuf = newbuf;
+       curline = newbuf->b_dot;
+       curchar = newbuf->b_char;
+       getDOT();
+       /* do the read now ... */
+       if (curbuf->b_ntbf)
+               read_file(curbuf->b_fname, NO);
+#ifdef MAC
+       Modechange = YES;
+#endif
+}
+
+Buffer *
+do_select(w, name)
+register Window        *w;
+register char  *name;
+{
+       register Buffer *new;
+
+       if ((new = buf_exists(name)) == NULL) {
+               new = mak_buf();
+               setfname(new, (char *)NULL);
+               setbname(new, name);
+       }
+       if (w)
+               tiewind(w, new);
+       return new;
+}
+
+void
+buf_init()
+{
+       SetBuf(do_select(curwind, Mainbuf));
+}
diff --git a/usr/src/contrib/jove-4.14.6/buf.h b/usr/src/contrib/jove-4.14.6/buf.h
new file mode 100644 (file)
index 0000000..8f5e4fd
--- /dev/null
@@ -0,0 +1,193 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* maximum length of a line (including '\0').  Currently cannot
+   be larger than a logical disk block. */
+#define        LBSIZE          JBUFSIZ
+
+/* buffer types */
+#define B_SCRATCH      1       /* for internal things, e.g. minibuffer ... */
+#define B_FILE         2       /* normal file (we auto-save these.) */
+#define B_PROCESS      3       /* unix process output in this buffer */
+
+/* major modes */
+#define FUNDAMENTAL    0       /* Fundamental mode */
+#define TEXT           1       /* Text mode */
+#define CMODE          2       /* C mode */
+#ifdef LISP
+# define LISPMODE      3       /* Lisp mode */
+# define NMAJORS       4
+#else
+# define NMAJORS       3
+#endif
+
+#define MajorMode(x)   (curbuf->b_major == (x))
+#define SetMajor(x)    { curbuf->b_major = (x); UpdModLine = YES; }
+
+/* minor modes */
+#define Indent         (1 << 0)        /* indent same as previous line after return */
+#define ShowMatch      (1 << 1)        /* paren flash mode */
+#define Fill           (1 << 2)        /* text fill mode */
+#define OverWrite      (1 << 3)        /* over write mode */
+#define Abbrev         (1 << 4)        /* abbrev mode */
+#define ReadOnly       (1 << 5)        /* buffer is read only */
+
+#define BufMinorMode(b, x)     (((b)->b_minor & (x)) != 0)
+#define MinorMode(x)           BufMinorMode(curbuf, (x))
+
+/* global line scratch buffers */
+#ifdef pdp11
+extern char    *genbuf,        /* scratch pad points at s_genbuf (see main()) */
+               *linebuf,       /* points at s_linebuf */
+               *iobuff;        /* for file reading ... points at s_iobuff */
+#else
+extern char    genbuf[LBSIZE],
+               linebuf[LBSIZE],
+               iobuff[LBSIZE];
+#endif
+
+struct line {
+       Line    *l_prev,                /* pointer to prev */
+               *l_next;                /* pointer to next */
+       daddr   l_dline;                /* pointer to disk location */
+};
+
+struct mark {
+       Line    *m_line;
+       int     m_char;
+       Mark    *m_next;        /* list of marks */
+#define M_FIXED                00
+#define M_FLOATER      01
+#define M_BIG_DELETE   02
+       char    m_flags;        /* FLOATERing mark? */
+};
+
+struct buffer {
+#ifdef MAC
+       int Type;               /* kludge... to look like a data_obj */
+       char *Name;             /* Name will not be used */
+#endif
+       Buffer  *b_next;                /* next buffer in chain */
+       char    *b_name,                /* buffer name */
+               *b_fname;               /* file name associated with buffer */
+       dev_t   b_dev;                  /* device of file name. */
+       ino_t   b_ino;                  /* inode of file name */
+       time_t  b_mtime;                /* last modify time ...
+                                          to detect two people writing
+                                          to the same file */
+       Line    *b_first,               /* pointer to first line in list */
+               *b_dot,                 /* current line */
+               *b_last;                /* last line in list */
+       int     b_char;                 /* current character in line */
+
+#define NMARKS 8                       /* number of marks in the ring */
+
+       Mark    *b_markring[NMARKS],    /* new marks are pushed here */
+#define b_curmark(b)   ((b)->b_markring[(b)->b_themark])
+#define curmark                b_curmark(curbuf)
+               *b_marks;               /* all the marks for this buffer */
+       char    b_themark,              /* current mark (in b_markring) */
+               b_type,                 /* file, scratch, process, iprocess */
+               b_ntbf,                 /* (bool) needs to be found when we
+                                          first select? */
+               b_modified;             /* (bool) is the buffer modified? */
+       int     b_major,                /* major mode */
+               b_minor;                /* and minor mode */
+       struct keymap   *b_map;         /* local bindings (if any) */
+#ifdef IPROCS
+       Process *b_process;             /* process we're attached to */
+#endif
+};
+
+extern Buffer  *world,         /* first buffer */
+               *curbuf,        /* pointer into world for current buffer */
+               *lastbuf,       /* Last buffer we were in so we have a default
+                                  buffer during a select buffer. */
+               *perr_buf;      /* Buffer with error messages */
+
+#define curline        (curbuf->b_dot)
+#define curchar (curbuf->b_char)
+
+/* kill buffer */
+#define NUMKILLS       10      /* number of kills saved in the kill ring */
+extern Line    *killbuf[NUMKILLS];
+
+struct position {
+       Line    *p_line;
+       int     p_char;
+};
+
+extern int     killptr;        /* index into killbuf */
+
+extern Buffer
+       *buf_exists proto((char *name)),
+       *do_find proto((struct window *w, char *fname, bool force)),
+       *do_select proto((struct window *w,char *name)),
+       *file_exists proto((char *name));
+
+extern char
+       *ask_buf proto((struct buffer *def));
+
+extern UnivPtr
+       freealloc proto((UnivPtr obj, size_t size));
+
+#ifdef REALSTDC
+struct macro;  /* forward declaration preventing prototype scoping */
+#endif /* REALSTDC */
+
+extern void
+       TogMinor proto((int bit)),
+       initlist proto((struct buffer *b)),
+       setfname proto((struct buffer *b,char *name)),
+       set_ino proto((struct buffer *b)),
+       SetABuf proto((struct buffer *b)),
+       SetBuf proto((struct buffer *newbuf)),
+       AllMarkSet proto((struct buffer *b,struct line *line,int col)),
+       DFixMarks proto((struct line *line1,int char1,struct line *line2,int char2)),
+       DelMark proto((struct mark *m)),
+       IFixMarks proto((struct line *line1, int char1, struct line *line2, int char2)),
+       MarkSet proto((struct mark *m, struct line *line, int column)),
+       ToMark proto((struct mark *m)),
+       flush_marks proto((Buffer *)),
+       b_char proto((int n)),
+       b_word proto((int num)),
+       del_char proto((int dir,int num,int OK_kill)),
+       do_macro proto((struct macro *mac)),
+       do_set_mark proto((struct line *l, int c)),
+       f_char proto((int n)),
+       f_word proto((int num)),
+       ins_str proto((char *str,int ok_nl)),
+       insert_c proto((int c,int n)),
+       lfreelist proto((struct line *first)),
+       lfreereg proto((struct line *line1,struct line *line2)),
+       line_move proto((int dir, int n, bool line_cmd)),
+       mac_putc proto((int c)),
+       n_indent proto((int goal)),
+       open_lines proto((int n)),
+       reg_kill proto((struct line *line2, int char2, bool dot_moved)),
+       set_mark proto((void)),
+       unwind_macro_stack proto((void)),
+       buf_init proto((void));
+
+extern int
+       ModMacs proto((void)),
+       in_macro proto((void)),
+       mac_getc proto((void)),
+       how_far proto((struct line *line,int col));
+
+extern  struct line
+       *lastline proto((struct line *lp)),
+       *listput proto((struct buffer *buf,struct line *after)),
+       *nbufline proto((void)),
+       *next_line proto((struct line *line,int num)),
+       *prev_line proto((struct line *line,int num)),
+       *reg_delete proto((struct line *line1,int char1,struct line *line2,int char2));
+
+extern Mark
+       *CurMark proto((void)),
+       *MakeMark proto((struct line *line,int column,int type));
+
diff --git a/usr/src/contrib/jove-4.14.6/c.c b/usr/src/contrib/jove-4.14.6/c.c
new file mode 100644 (file)
index 0000000..202e08b
--- /dev/null
@@ -0,0 +1,751 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* Contains commands for C mode.  Paren matching routines are in here. */
+
+#include "jove.h"
+#include "re.h"
+#include "ctype.h"
+#include "disp.h"
+
+private void
+#ifdef CMT_FMT
+       FillComment proto((char *format)),
+#endif
+       FindMatch proto((int));
+
+private int
+backslashed(lp, cpos)
+register char  *lp;
+register int   cpos;
+{
+       register int    cnt = 0;
+
+       while (cpos > 0 && lp[--cpos] == '\\')
+               cnt += 1;
+       return (cnt % 2);
+}
+
+private char   *p_types = "(){}[]";
+private int    mp_kind;
+#define MP_OKAY                0
+#define MP_MISMATCH    1
+#define MP_UNBALANCED  2
+#define MP_INCOMMENT   3
+
+void
+mp_error()
+{
+       switch (mp_kind) {
+       case MP_MISMATCH:
+               message("[Mismatched parentheses]");
+               break;
+
+       case MP_UNBALANCED:
+               message("[Unbalanced parenthesis]");
+               break;
+
+       case MP_INCOMMENT:
+               message("[Inside a comment]");
+               break;
+
+       case MP_OKAY:
+       default:
+               return;
+       }
+       rbell();
+}
+
+/* Search from the current position for the paren that matches p_type.
+   Search in the direction dir.  If can_mismatch is YES then it is okay
+   to have mismatched parens.  If stop_early is YES then when an open
+   paren is found at the beginning of a line, it is assumed that there
+   is no point in backing up further.  This is so when you hit tab or
+   LineFeed outside, in-between procedure/function definitions, it won't
+   sit there searching all the way to the beginning of the file for a
+   match that doesn't exist.  {forward,backward}-s-expression are the
+   only ones that insist on getting the "true" story. */
+
+Bufpos *
+m_paren(p_type, dir, can_mismatch, can_stop)
+int    p_type;
+register int   dir;
+int    can_mismatch;
+int    can_stop;
+{
+       static Bufpos   ret;
+       Bufpos  savedot,
+               *sp;
+       struct RE_block re_blk;
+       int     count = 0;
+       register char   *lp,
+                       c;
+       char    p_match,
+               re_str[128],
+               *cp,
+               quote_c = 0;
+       register int    c_char;
+       int     in_comment = -1,
+               stopped = NO;
+
+       swritef(re_str, sizeof(re_str), "[(){}[\\]%s]",
+               (MajorMode(CMODE)) ? "/\"'" : "\"");
+       REcompile(re_str, YES, &re_blk);
+       if ((cp = strchr(p_types, p_type)) == NULL)
+               complain("[Cannot match %c's]", p_type);
+       p_match = cp[dir];
+       DOTsave(&savedot);
+
+       /* To make things a little faster I avoid copying lines into
+          linebuf by setting curline and curchar by hand.  Warning:
+          this is slightly to very risky.  When I did this there were
+          lots of problems with procedures that expect the contents of
+          curline to be in linebuf. */
+       do {
+               sp = docompiled(dir, &re_blk);
+               if (sp == NULL)
+                       break;
+               lp = lbptr(sp->p_line);
+
+               curline = sp->p_line;
+               curchar = sp->p_char;   /* here's where I cheat */
+
+               c_char = curchar;
+               if (dir == FORWARD)
+                       c_char -= 1;
+               if (backslashed(lp, c_char))
+                       continue;
+               c = lp[c_char];
+               /* check if this is a comment (if we're not inside quotes) */
+               if (quote_c == 0 && c == '/') {
+                       int     new_ic = in_comment;
+
+                       /* close comment */
+                       if ((c_char != 0) && lp[c_char - 1] == '*') {
+                               new_ic = (dir == FORWARD) ? NO : YES;
+                               if (new_ic == NO && in_comment == -1) {
+                                       count = 0;
+                                       quote_c = 0;
+                               }
+                       } else if (lp[c_char + 1] == '*') {
+                               new_ic = (dir == FORWARD) ? YES : NO;
+                               if (new_ic == NO && in_comment == -1) {
+                                       count = 0;
+                                       quote_c = 0;
+                               }
+                       }
+                       in_comment = new_ic;
+               }
+               if (in_comment == YES)
+                       continue;
+               if (c == '"' || c == '\'') {
+                       if (quote_c == c)
+                               quote_c = 0;
+                       else if (quote_c == 0)
+                               quote_c = c;
+               }
+               if (quote_c != 0)
+                       continue;
+               if (jisopenp(c)) {
+                       count += dir;
+                       if (c_char == 0 && can_stop == YES && count >= 0) {
+                               stopped = YES;
+                               break;
+                       }
+               } else if (jisclosep(c))
+                       count -= dir;
+       } while (count >= 0);
+
+       ret.p_line = curline;
+       ret.p_char = curchar;
+
+       curline = savedot.p_line;
+       curchar = savedot.p_char;       /* here's where I undo it */
+
+       if (count >= 0)
+               mp_kind = MP_UNBALANCED;
+       else if (c != p_match)
+               mp_kind = MP_MISMATCH;
+       else
+               mp_kind = MP_OKAY;
+
+       /* If we stopped (which means we were allowed to stop) and there
+          was an error, we clear the error so no error message is printed.
+          An error should be printed ONLY when we are sure about the fact,
+          namely we didn't stop prematurely HOPING that it was the right
+          answer. */
+       if (stopped && mp_kind != MP_OKAY) {
+               mp_kind = MP_OKAY;
+               return NULL;
+       }
+       if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch == YES))
+               return &ret;
+       return NULL;
+}
+
+private void
+do_expr(dir, skip_words)
+register int   dir;
+int    skip_words;
+{
+       register char   c,
+                       syntax = (dir == FORWARD) ? C_BRA : C_KET;
+
+       if (dir == BACKWARD)
+               b_char(1);
+       c = linebuf[curchar];
+       for (;;) {
+               if (!skip_words && ismword(c)) {
+                   WITH_TABLE(curbuf->b_major)
+                       if (dir == FORWARD)
+                           f_word(1);
+                       else
+                           b_word(1);
+                   END_TABLE();
+                   break;
+               } else if (has_syntax(c, syntax)) {
+                       FindMatch(dir);
+                       break;
+               }
+               f_char(dir);
+               if (eobp() || bobp())
+                       return;
+               c = linebuf[curchar];
+       }
+}
+
+void
+FSexpr()
+{
+       register int    num = arg_value();
+
+       if (num < 0) {
+               set_arg_value(-num);
+               BSexpr();
+       }
+       while (--num >= 0)
+               do_expr(FORWARD, NO);
+}
+
+void
+FList()
+{
+       register int    num = arg_value();
+
+       if (num < 0) {
+               set_arg_value(-num);
+               BList();
+       }
+       while (--num >= 0)
+               do_expr(FORWARD, YES);
+}
+
+void
+BSexpr()
+{
+       register int    num = arg_value();
+
+       if (num < 0) {
+               negate_arg_value();
+               FSexpr();
+       }
+       while (--num >= 0)
+               do_expr(BACKWARD, NO);
+}
+
+void
+BList()
+{
+       register int    num = arg_value();
+
+       if (num < 0) {
+               negate_arg_value();
+               FList();
+       }
+       while (--num >= 0)
+               do_expr(BACKWARD, YES);
+}
+
+void
+BUpList()
+{
+       Bufpos  *mp;
+       char    c = (MajorMode(CMODE) ? '}' : ')');
+
+       mp = m_paren(c, BACKWARD, NO, YES);
+       if (mp == NULL)
+               mp_error();
+       else
+               SetDot(mp);
+}
+
+void
+FDownList()
+{
+       Bufpos  *sp;
+       char    *sstr = MajorMode(CMODE) ? "[{([\\])}]" : "[()]";
+
+       sp = dosearch(sstr, FORWARD, YES);
+       if (sp == NULL || has_syntax(lcontents(sp->p_line)[sp->p_char - 1], C_KET))
+               complain("[No contained expression]");
+       SetDot(sp);
+}
+
+/* Move to the matching brace or paren depending on the current position
+   in the buffer. */
+
+private void
+FindMatch(dir)
+int    dir;
+{
+       register Bufpos *bp;
+       register char   c = linebuf[curchar];
+
+       if ((strchr(p_types, c) == NULL) ||
+           (backslashed(linebuf, curchar)))
+               complain((char *)NULL);
+       if (dir == FORWARD)
+               f_char(1);
+       bp = m_paren(c, dir, YES, NO);
+       if (dir == FORWARD)
+               b_char(1);
+       if (bp != NULL)
+               SetDot(bp);
+       mp_error();     /* if there is an error the user wants to
+                          know about it */
+}
+
+#define ALIGN_ARGS     (-1)
+
+/* If CArgIndent == ALIGN_ARGS then the indentation routine will
+   indent a continued line by lining it up with the first argument.
+   Otherwise, it will indent CArgIndent characters past the indent
+   of the first line of the procedure call. */
+
+int    CArgIndent = ALIGN_ARGS;
+
+/* indent for C code */
+Bufpos *
+c_indent(brace)
+int    brace;
+{
+       Bufpos  *bp;
+       int     new_indent = 0,
+               current_indent,
+               increment;
+
+       if (brace == NO)
+               increment = CIndIncrmt;
+       else
+               increment = 0;
+       /* Find matching paren, which may be a mismatch now.  If it
+          is not a matching curly brace then it is a paren (most likely).
+          In that case we try to line up the arguments to a procedure
+          or inside an of statement. */
+       if ((bp = m_paren('}', BACKWARD, YES, YES)) != NULL) {
+               Bufpos  save;
+               int     matching_indent;
+
+               DOTsave(&save);
+               SetDot(bp);             /* go to matching paren */
+               ToIndent();
+               matching_indent = calc_pos(linebuf, curchar);
+               SetDot(bp);
+               switch (linebuf[curchar]) {
+               case '{':
+                       new_indent = matching_indent;
+                       if (!bolp()) {
+                               b_char(1);
+                               /* If we're not within the indent then we
+                                  can assume that there is either a C keyword
+                                  line DO on the line before the brace, or
+                                  there is a parenthesized expression.  If
+                                  that's the case we want to go backward
+                                  over that to the beginning of the expression
+                                  so that we can get the correct indent for
+                                  this matching brace.  This handles wrapped
+                                  if statements, etc. */
+                               if (!within_indent()) {
+                                       Bufpos  savematch;
+
+                                       savematch = *bp;
+
+                                       do_expr(BACKWARD, NO);
+                                       ToIndent();
+                                       new_indent = calc_pos(linebuf, curchar);
+
+                                       /* do_expr() calls b_paren, which
+                                          returns a pointer to a structure,
+                                          and that pointer is in BP so we
+                                          have to save away the matching
+                                          paren and restore it in the
+                                          following line ... sigh */
+                                       *bp = savematch;
+                               }
+                       }
+                       if (brace == NO)
+                               new_indent += (increment - (new_indent % increment));
+                       break;
+
+               case '(':
+                       if (CArgIndent == ALIGN_ARGS) {
+                               f_char(1);
+                               new_indent = calc_pos(linebuf, curchar);
+                       } else
+                               new_indent = matching_indent + CArgIndent;
+                       break;
+               }
+               SetDot(&save);
+       }
+
+       /* new_indent is the "correct" place to indent.  Now we check to
+          see if what we consider as the correct place to indent is to
+          the LEFT of where we already are.  If it is, and we are NOT
+          handling a brace, then we assume that the person wants to tab
+          in further than what we think is right (for some reason) and
+          so we allow that. */
+
+       ToIndent();
+       current_indent = calc_pos(linebuf, curchar);
+       if (brace == NO && new_indent <= current_indent)
+               new_indent = current_indent + (increment - (current_indent % increment));
+       Bol();
+       DelWtSpace();                   /* nice uniform Tabs*Space* */
+       n_indent(new_indent);
+
+       return bp;
+}
+
+private void
+re_indent(incr)
+int    incr;
+{
+       Line    *l1, *l2, *lp;
+       int     c1, c2;
+       Mark    *m = CurMark();
+       Bufpos  savedot;
+
+       DOTsave(&savedot);
+       l1 = curline;
+       c1 = curchar;
+       l2 = m->m_line;
+       c2 = m->m_char;
+       (void) fixorder(&l1, &c1, &l2, &c2);
+       for (lp = l1; lp != l2->l_next; lp = lp->l_next) {
+               int     indent;
+
+               SetLine(lp);
+               ToIndent();
+               indent = calc_pos(linebuf, curchar);
+               if (indent != 0 || linebuf[0] != '\0')
+                       n_indent(indent + incr);
+       }
+       SetDot(&savedot);
+}
+
+void
+LRShift()
+{
+       int     amnt;
+
+       if (is_an_arg())
+               amnt = arg_value();
+       else
+               amnt = CIndIncrmt;
+       re_indent(-amnt);
+}
+
+void
+RRShift()
+{
+       int     amnt;
+
+       if (is_an_arg())
+               amnt = arg_value();
+       else
+               amnt = CIndIncrmt;
+       re_indent(amnt);
+}
+
+#ifdef CMT_FMT
+
+char   CmtFmt[80] = "/*%n%! * %c%!%n */";
+
+void
+Comment()
+{
+       FillComment(CmtFmt);
+}
+
+/* Strip leading and trailing white space.  Skip over any imbedded '\r's. */
+
+private void
+strip_c(from, to)
+char   *from,
+       *to;
+{
+       register char   *fr_p = from,
+                       *to_p = to,
+                       c;
+
+       while ((c = *fr_p) != '\0') {
+               if (c == ' ' || c == '\t' || c == '\r')
+                       fr_p += 1;
+               else
+                       break;
+       }
+       while ((c = *fr_p) != '\0') {
+               if (c != '\r')
+                       *to_p++ = c;
+               fr_p += 1;
+       }
+       while (--to_p >= to)
+               if (*to_p != ' ' && *to_p != '\t')
+                       break;
+       *++to_p = '\0';
+}
+
+private char   open_c[20],     /* the open comment format string */
+               open_pat[20],   /* the search pattern for open comment */
+               l_header[20],   /* the prefix for each comment line */
+               l_trailer[20],  /* the suffix ... */
+               close_c[20],
+               close_pat[20];
+
+private char   *const comment_body[] = {
+       open_c,
+       l_header,
+       l_trailer,
+       close_c
+};
+
+private int    nlflags;
+
+/* Fill in the data structures above from the format string.  Don't return
+   if there's trouble. */
+
+private void
+parse_cmt_fmt(str)
+char   *str;
+{
+       register char   *fmtp = str;
+       register char   *const *c_body = comment_body,
+                       *body_p = *c_body;
+       int     c,
+               newlines = 1;
+
+       /* pick apart the comment string */
+       while ((c = *fmtp++) != '\0') {
+               if (c != '%') {
+                       *body_p++ = c;
+                       continue;
+               }
+               switch(c = *fmtp++) {
+               case 'n':
+                       if (newlines == 2 || newlines == 3)
+                               complain("%n not allowed in line header or trailer: %s",
+                                 fmtp - 2);
+                       nlflags += newlines;
+                       *body_p++ = '\r';
+                       break;
+               case 't':
+                       *body_p++ = '\t';
+                       break;
+               case '%':
+                       *body_p++ = '%';
+                       break;
+               case '!':
+               case 'c':
+                       newlines += 1;
+                       *body_p++ = '\0';
+                       body_p = *++c_body;
+                       break;
+               default:
+                       complain("[Unknown comment escape: %%%c]", c);
+                       break;
+               }
+       }
+       *body_p = '\0';
+       /* make search patterns */
+       strip_c(open_c, open_pat);
+       strip_c(close_c, close_pat);
+}
+
+#define NL_IN_OPEN_C  ((nlflags % 4) == 1)
+#define NL_IN_CLOSE_C (nlflags >= 4)
+
+private void
+FillComment(format)
+char   *format;
+{
+       int     saveRMargin,
+               indent_pos;
+       bool    close_at_dot = NO;
+       size_t  header_len,
+               trailer_len;
+       register char   *cp;
+       static const char       inside_err[] = "[Must be between %s and %s to re-format]";
+       Bufpos  open_c_pt,
+               close_c_pt,
+               tmp_bp,
+               *match_o,
+               *match_c;
+       Mark    *entry_mark,
+               *open_c_mark,
+               *savedot;
+
+       parse_cmt_fmt(format);
+       /* figure out if we're "inside" a comment */
+       if ((match_o = dosearch(open_pat, BACKWARD, NO)) == NULL)
+               complain("No opening %s to match to.", open_pat);
+       open_c_pt = *match_o;
+       if ((match_c = dosearch(close_pat, BACKWARD, NO)) != NULL &&
+           inorder(open_c_pt.p_line, open_c_pt.p_char,
+                   match_c->p_line, match_c->p_char))
+               complain(inside_err, open_pat, close_pat);
+       if ((match_o = dosearch(open_pat, FORWARD, NO)) != NULL) {
+               tmp_bp = *match_o;
+               match_o = &tmp_bp;
+       }
+       if ((match_c = dosearch(close_pat, FORWARD, NO)) != NULL)
+               close_c_pt = *match_c;
+
+       /* Here's where we figure out whether to format from dot or from
+          the close comment.  Note that we've already searched backwards to
+          find the open comment symbol for the comment we are formatting.
+          The open symbol mentioned below refers to the possible existence
+          of the next comment.  There are 5 cases:
+               1) no open or close symbol              ==> dot
+               2) open, but no close symbol            ==> dot
+               3) close, but no open                   ==> close
+               4) open, close are inorder              ==> dot
+               5) open, close are not inorder          ==> close */
+
+
+       if (match_o == (Bufpos *)NULL) {
+               if (match_c == (Bufpos *)NULL)
+                       close_at_dot = YES;
+       } else if (match_c == (Bufpos *)NULL)
+               close_at_dot = YES;
+       else if (inorder(match_o->p_line, match_o->p_char,
+                match_c->p_line, match_c->p_char))
+               close_at_dot = YES;
+       if (close_at_dot) {
+               close_c_pt.p_line = curline;
+               close_c_pt.p_char = curchar;
+       } else {
+               SetDot(match_c);
+       }
+       SetDot(&open_c_pt);
+       open_c_mark = MakeMark(curline, curchar, M_FLOATER);
+       indent_pos = calc_pos(linebuf, curchar);
+       /* search for a close comment; delete it if it exits */
+       SetDot(&close_c_pt);
+       if (!close_at_dot)
+               del_char(BACKWARD, (int)strlen(close_pat), NO);
+       entry_mark = MakeMark(curline, curchar, M_FLOATER);
+       ToMark(open_c_mark);
+       /* always separate the comment body from anything preceeding it */
+       LineInsert(1);
+       DelWtSpace();
+       Bol();
+       for (cp = open_c; *cp; cp++) {
+               if (*cp == '\r') {
+                       if (!eolp())
+                               LineInsert(1);
+                       else
+                               line_move(FORWARD, 1, NO);
+               } else if (*cp == ' ' || *cp == '\t') {
+                       if (linebuf[curchar] != *cp)
+                               insert_c(*cp, 1);
+               } else {
+                       /* Since we matched the open comment string on this
+                          line, we don't need to worry about crossing line
+                          boundaries. */
+                       curchar += 1;
+               }
+       }
+       savedot = MakeMark(curline, curchar, M_FLOATER);
+
+       /* We need to strip the line header pattern of leading white space
+          since we need to match the line after all of its leading
+          whitespace is gone. */
+       for (cp = l_header; *cp && (jisspace(*cp)); cp++)
+               ;
+       header_len = strlen(cp);
+       trailer_len = strlen(l_trailer);
+
+       /* Strip each comment line of the open and close comment strings
+          before reformatting it. */
+
+       do {
+               Bol();
+               DelWtSpace();
+               if (header_len && strncmp(linebuf, cp, header_len)==0)
+                       del_char(FORWARD, (int)header_len, NO);
+               if (trailer_len) {
+                       Eol();
+                       if (((size_t)curchar > trailer_len) &&
+                           (strncmp(&linebuf[curchar - trailer_len],
+                                     l_trailer, trailer_len)==0))
+                               del_char(BACKWARD, (int)trailer_len, NO);
+               }
+               if (curline->l_next != NULL)
+                       line_move(FORWARD, 1, NO);
+               else
+                       break;
+       } while (curline != entry_mark->m_line->l_next);
+
+       do_set_mark(savedot->m_line, savedot->m_char);
+       ToMark(entry_mark);
+       saveRMargin = RMargin;
+       RMargin = saveRMargin - strlen(l_header) -
+                 strlen(l_trailer) - indent_pos + 2;
+       do_rfill(NO);
+       RMargin = saveRMargin;
+       /* get back to the start of the comment */
+       PopMark();
+       do {
+               if (curline != open_c_mark->m_line->l_next) {
+                       Bol();
+                       n_indent(indent_pos);
+                       ins_str(l_header, NO);
+               }
+               Eol();
+               if (NL_IN_CLOSE_C || (curline != entry_mark->m_line))
+                       ins_str(l_trailer, NO);
+               if (curline->l_next != NULL)
+                       line_move(FORWARD, 1, NO);
+               else
+                       break;
+       } while (curline != entry_mark->m_line->l_next);
+       /* handle the close comment symbol */
+       if (curline == entry_mark->m_line->l_next) {
+               line_move(BACKWARD, 1, NO);
+               Eol();
+       }
+       DelWtSpace();
+       /* if the addition of the close symbol would cause the line to be
+          too long, put the close symbol on the next line. */
+       if (!(NL_IN_CLOSE_C) &&
+         (int)strlen(close_c) + calc_pos(linebuf, curchar) > RMargin) {
+               LineInsert(1);
+               n_indent(indent_pos);
+       }
+       for (cp = close_c; *cp; cp++) {
+               if (*cp == '\r') {
+                       LineInsert(1);
+                       n_indent(indent_pos);
+               } else
+                       insert_c(*cp, 1);
+       }
+       ToMark(open_c_mark);
+       Eol();
+       del_char(FORWARD, 1, NO);
+}
+
+#endif /* CMT_FMT */
diff --git a/usr/src/contrib/jove-4.14.6/case.c b/usr/src/contrib/jove-4.14.6/case.c
new file mode 100644 (file)
index 0000000..676e23d
--- /dev/null
@@ -0,0 +1,224 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "disp.h"
+#include "ctype.h"
+
+private        bool
+       lower proto((char *)),
+       upper proto((char *));
+
+private void
+       CaseReg proto((bool up)),
+       case_reg proto((struct line *line1,int char1,struct line *line2,int char2,bool up));
+
+void
+CapChar()
+{
+       register int    num,
+                       restore = NO;
+       Bufpos  b;
+
+       DOTsave(&b);
+
+       num = arg_value();
+       if (num < 0) {
+               restore = YES;
+               num = -num;
+               b_char(num);    /* Cap previous EXP chars */
+       }
+       while (num--) {
+               if (upper(&linebuf[curchar])) {
+                       modify();
+                       makedirty(curline);
+               }
+               if (eolp()) {
+                       if (curline->l_next == NULL)
+                               break;
+                       SetLine(curline->l_next);
+               } else
+                       curchar += 1;
+       }
+       if (restore)
+               SetDot(&b);
+}
+
+void
+CapWord()
+{
+       register int    num,
+                       restore = NO;
+       Bufpos  b;
+
+       DOTsave(&b);
+       num = arg_value();
+       if (num < 0) {
+               restore = YES;
+               num = -num;
+               b_word(num);            /* Cap previous EXP words */
+       }
+       while (num--) {
+               to_word(1);     /* Go to the beginning of the next word. */
+               if (eobp())
+                       break;
+               if (upper(&linebuf[curchar])) {
+                       modify();
+                       makedirty(curline);
+               }
+               curchar += 1;
+               while (!eolp() && jisword(linebuf[curchar])) {
+                       if (lower(&linebuf[curchar])) {
+                               modify();
+                               makedirty(curline);
+                       }
+                       curchar += 1;
+               }
+       }
+       if (restore)
+               SetDot(&b);
+}
+
+private void
+case_word(up)
+bool   up;
+{
+       Bufpos  before;
+
+       DOTsave(&before);
+       ForWord();      /* this'll go backward if negative argument */
+       case_reg(before.p_line, before.p_char, curline, curchar, up);
+}
+
+/* Convert *p to upper case.  Return TRUE iff it was changed. */
+
+private bool
+upper(p)
+register char  *p;
+{
+       if (jislower(*p & CHARMASK)) {
+               *p = CharUpcase(*p & CHARMASK);
+               return YES;
+       }
+       return NO;
+}
+
+/* Convert *p to lower case.  Return TRUE iff it was changed. */
+
+private bool
+lower(p)
+char   *p;
+{
+       int c = *p & CHARMASK;
+
+       if (jisupper(c)) {
+#ifdef ASCII7
+               *p = jtolower(c);
+#else  /* !ASCII7 */
+#ifdef IBMPC
+               if (c <= 127)
+                   c += ' ';
+               else {
+                       switch (c) {
+                       case 142: c = 132; break;               /* Ae */
+                       case 153: c = 148; break;               /* Oe */
+                       case 154: c = 129; break;               /* Ue */
+                       }
+               }
+#endif /* IBMPC */
+#ifdef MAC
+               if (c <= 127)
+                   c += ' ';
+               else {
+                       int n;
+
+                       for(n = 128; ; n++) {
+                               if (n > 255)
+                                       return NO;
+                               if ((CharUpcase(n) == c) && jislower(n)) {
+                                       c = n;
+                                       break;
+                               }
+                       }
+               }
+#endif /* MAC */
+               *p = c;
+#endif /* !ASCII7 */
+               return YES;
+       }
+       return NO;
+}
+
+#ifndef        ASCII7
+char
+jtolower(c)
+char   c;
+{
+    if (jislower(c))
+       (void) lower(&c);
+    return c;
+}
+#endif /*!ASCII7*/
+
+private void
+case_reg(line1, char1, line2, char2, up)
+Line   *line1,
+       *line2;
+int    char1,
+       char2;
+bool   up;
+{
+       (void) fixorder(&line1, &char1, &line2, &char2);
+       DotTo(line1, char1);
+
+       for (;;) {
+               if (curline == line2 && curchar == char2)
+                       break;
+               if (!eolp())
+                       if ((up) ? upper(&linebuf[curchar]) : lower(&linebuf[curchar])) {
+                               makedirty(curline);
+                               modify();
+                       }
+               f_char(1);
+       }
+}
+
+void
+CasRegLower()
+{
+       CaseReg(FALSE);
+}
+
+void
+CasRegUpper()
+{
+       CaseReg(TRUE);
+}
+
+private void
+CaseReg(up)
+bool   up;
+{
+       register Mark   *mp = CurMark();
+       Bufpos  savedot;
+
+       DOTsave(&savedot);
+       case_reg(curline, curchar, mp->m_line, mp->m_char, up);
+       SetDot(&savedot);
+}
+
+void
+UppWord()
+{
+       case_word(TRUE);
+}
+
+void
+LowWord()
+{
+       case_word(FALSE);
+}
diff --git a/usr/src/contrib/jove-4.14.6/chars.h b/usr/src/contrib/jove-4.14.6/chars.h
new file mode 100644 (file)
index 0000000..d6b745a
--- /dev/null
@@ -0,0 +1,14 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define CTL(c)         ((c) & 037)
+#define META(c)                ((c) | 0200)
+#define RUBOUT         '\177'
+#define LF             CTL('J')
+#define CR             CTL('M')
+#define BS             CTL('H')
+#define ESC            '\033'
diff --git a/usr/src/contrib/jove-4.14.6/ctype.c b/usr/src/contrib/jove-4.14.6/ctype.c
new file mode 100644 (file)
index 0000000..5d77726
--- /dev/null
@@ -0,0 +1,250 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+
+const unsigned char    *SyntaxTable = CharTable[FUNDAMENTAL];  /* Current table to use. */
+
+#define        cU      C_UPPER /* Upper case */
+#define        cL      C_LOWER /* Lower case */
+#define        cN      C_DIGIT /* Numeric */
+#define        cP      C_PUNCT /* Punctuation */
+#define        cC      C_CTRL  /* Control */
+#define        cW      C_WORD  /* Word */
+#define        cOp     C_BRA   /* Open Parenthesis */
+#define        cCl     C_KET   /* Close Parenthesis */
+
+const unsigned char CharTable[NMAJORS][NCHARS] = {
+       /* FUNDAMENTAL mode */
+    {
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cP,     cP,     cP,     cP,     cP,     cP,     cP,     cP,
+       cOp|cP, cCl|cP, cP,     cP,     cP,     cP,     cP,     cP,
+       cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,
+       cW|cN,  cW|cN,  cP,     cP,     cP,     cP,     cP,     cP,
+       cP,     cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cOp|cP, cP,     cCl|cP, cP,     cP,
+       cP,     cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cOp|cP, cP,     cCl|cP, cP,     cC,
+#ifdef IBMPC
+       0, cW|cL, 0, 0, cW|cL, 0, 0, 0, 0, 0, 0, 0, 0, 0, cW|cU, 0,
+       0, 0, 0, 0, cW|cL, 0, 0, 0, 0, cW|cU, cW|cU, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif /* IBMPC */
+#ifdef MAC     /* See Inside Macintosh Vol One p. 247 */
+       cW|cU, cW|cU, cW|cU, cW|cU, cW|cU, cW|cU, cW|cU, cW|cL,
+       cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL,
+       cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL,
+       cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL,
+       cP, cP, cP, cP, cP, cP, cP, cP,
+       cP, cP, cP, cP, cP, cP, cW|cU, cW|cU,
+       cP, cP, cP, cP, cP, cW|cU, cW|cL, cW|cU,
+       cW|cU, cW|cL, cP, cP, cP, cW|cU, cW|cL, cW|cL,
+       cP, cP, cP, cP, cP, cP, cW|cU, cP,
+       cP, cP, cP, cW|cU, cW|cU, cW|cU, cW|cU, cW|cU,
+       cP, cP, cP, cP, cP, cP, cP, cP,
+       cW|cU, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif /* MAC */
+    },
+
+       /* TEXT mode */
+    {
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cP,     cP,     cP,     cP,     cP,     cP,     cP,     cP|cW,
+       cOp|cP, cCl|cP, cP,     cP,     cP,     cP,     cP,     cP,
+       cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,
+       cW|cN,  cW|cN,  cP,     cP,     cP,     cP,     cP,     cP,
+       cP,     cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cOp|cP, cP,     cCl|cP, cP,     cP,
+       cP,     cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cOp|cP, cP,     cCl|cP, cP,     cC,
+#ifdef IBMPC
+       0, cW|cL, 0, 0, cW|cL, 0, 0, 0, 0, 0, 0, 0, 0, 0, cW|cU, 0,
+       0, 0, 0, 0, cW|cL, 0, 0, 0, 0, cW|cU, cW|cU, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif /* IBMPC */
+#ifdef MAC     /* See Inside Macintosh Vol One p. 247 */
+       cW|cU, cW|cU, cW|cU, cW|cU, cW|cU, cW|cU, cW|cU, cW|cL,
+       cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL,
+       cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL,
+       cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL, cW|cL,
+       cP, cP, cP, cP, cP, cP, cP, cP,
+       cP, cP, cP, cP, cP, cP, cW|cU, cW|cU,
+       cP, cP, cP, cP, cP, cW|cU, cW|cL, cW|cU,
+       cW|cU, cW|cL, cP, cP, cP, cW|cU, cW|cL, cW|cL,
+       cP, cP, cP, cP, cP, cP, cW|cU, cP,
+       cP, cP, cP, cW|cU, cW|cU, cW|cU, cW|cU, cW|cU,
+       cP, cP, cP, cP, cP, cP, cP, cP,
+       cW|cU, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif /* MAC */
+    },
+
+       /* CMODE */
+    {
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cP,     cP,     cP,     cP,     cP|cW,  cP,     cP,     cP,
+       cOp|cP, cCl|cP, cP,     cP,     cP,     cP,     cP,     cP,
+       cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,
+       cW|cN,  cW|cN,  cP,     cP,     cP,     cP,     cP,     cP,
+       cP,     cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cOp|cP, cP,     cCl|cP, cP,     cP|cW,
+       cP,     cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cOp|cP, cP,     cCl|cP, cP,     cC,
+#ifndef        ASCII7
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+#endif /* !ASCII7 */
+    },
+
+       /* LISP mode */
+#ifdef LISP
+    {
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cC,     cC,     cC,     cC,     cC,     cC,     cC,     cC,
+       cP,     cW|cP,  cP,     cP,     cW|cP,  cW|cP,  cW|cP,  cP,
+       cOp|cP, cCl|cP, cW|cP,  cW|cP,  cP,     cW|cP,  cP,     cW,
+       cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,  cW|cN,
+       cW|cN,  cW|cN,  cW|cP,  cP,     cW|cP,  cW|cP,  cW|cP,  cW|cP,
+       cW|cP,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,  cW|cU,
+       cW|cU,  cW|cU,  cW|cU,  cOp|cP, cP,     cCl|cP, cW|cP,  cW|cP,
+       cP,     cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,  cW|cL,
+       cW|cL,  cW|cL,  cW|cL,  cOp|cW|cP,      cW|cP,  cCl|cW|cP,      cW|cP,  cW|cC,
+#ifndef        ASCII7
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+#endif /* !ASCII7 */
+    },
+#endif /* LISP */
+};
+
+#undef cU
+#undef cL
+#undef cN
+#undef cP
+#undef cC
+#undef cW
+#undef cOp
+#undef cCl
+
+int
+ismword(c)
+int    c;
+{
+       return ((CharTable[curbuf->b_major])[c]&(C_WORD));
+}
+
+/* Map lower case characters to upper case and the rest to themselves. */
+
+const char     RaiseTable[NCHARS] = {
+       '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+       '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+       '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+       '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+       '\040', '!',    '"',    '#',    '$',    '%',    '&',    '\'',
+       '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
+       '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
+       '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
+       '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+       'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+       'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+       'X',    'Y',    'Z',    '[',    '\\',   ']',    '^',    '_',
+       '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+       'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+       'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+       'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177',
+#ifdef IBMPC
+       /* Only lower case codes are Umlauted u, a, and o (indented) */
+       0x80,    0x9A,  0x82,   0x83,    0x8E,  0x85,   0x86,   0x87,
+       0x88,   0x89,   0x8A,   0x8B,   0x8C,   0x8D,   0x8E,   0x8F,
+       0x90,   0x91,   0x92,   0x93,    0x99,  0x95,   0x96,   0x97,
+       0x98,   0x99,   0x9A,   0x9B,   0x9C,   0x9D,   0x9E,   0x9F,
+       0xA0,   0xA1,   0xA2,   0xA3,   0xA4,   0xA5,   0xA6,   0xA7,
+       0xA8,   0xA9,   0xAA,   0xAB,   0xAC,   0xAD,   0xAE,   0xAF,
+       0xB0,   0xB1,   0xB2,   0xB3,   0xB4,   0xB5,   0xB6,   0xB7,
+       0xB8,   0xB9,   0xBA,   0xBB,   0xBC,   0xBD,   0xBE,   0xBF,
+       0xC0,   0xC1,   0xC2,   0xC3,   0xC4,   0xC5,   0xC6,   0xC7,
+       0xC8,   0xC9,   0xCA,   0xCB,   0xCC,   0xCD,   0xCE,   0xCF,
+       0xD0,   0xD1,   0xD2,   0xD3,   0xD4,   0xD5,   0xD6,   0xD7,
+       0xD8,   0xD9,   0xDA,   0xDB,   0xDC,   0xDD,   0xDE,   0xDF,
+       0xE0,   0xE1,   0xE2,   0xE3,   0xE4,   0xE5,   0xE6,   0xE7,
+       0xE8,   0xE9,   0xEA,   0xEB,   0xEC,   0xED,   0xEE,   0xEF,
+       0xF0,   0xF1,   0xF2,   0xF3,   0xF4,   0xF5,   0xF6,   0xF7,
+       0xF8,   0xF9,   0xFA,   0xFB,   0xFC,   0xFD,   0xFE,   0xFF,
+#endif /*!IBMPC*/
+#ifdef MAC
+       0x80,   0x81,   0x82,   0x83,   0x84,   0x85,   0x86,   0x87,
+        0xCB,  0x89,    0x80,   0xCC,   0x81,   0x82,   0x83,  0x8F,
+       0x90,   0x91,   0x92,   0x93,   0x94,   0x95,    0x84,  0x97,
+       0x98,   0x99,    0x85,   0xCD,  0x9C,   0x9D,   0x9E,    0x86,
+       0xA0,   0xA1,   0xA2,   0xA3,   0xA4,   0xA5,   0xA6,   0xA7,
+       0xA8,   0xA9,   0xAA,   0xAB,   0xAC,   0xAD,   0xAE,   0xAF,
+       0xB0,   0xB1,   0xB2,   0xB3,   0xB4,   0xB5,   0xC6,   0xB7,
+       0xB8,    0xB8,  0xBA,   0xBB,   0xBC,   0xBD,   0xAE,   0xAF,
+       0xC0,   0xC1,   0xC2,   0xC3,   0xC4,   0xC5,   0xC6,   0xC7,
+       0xC8,   0xC9,   0xCA,   0xCB,   0xCC,   0xCD,   0xCE,    0xCE,
+       0xD0,   0xD1,   0xD2,   0xD3,   0xD4,   0xD5,   0xD6,   0xD7,
+       0xD8,   0xD9,   0xDA,   0xDB,   0xDC,   0xDD,   0xDE,   0xDF,
+       0xE0,   0xE1,   0xE2,   0xE3,   0xE4,   0xE5,   0xE6,   0xE7,
+       0xE8,   0xE9,   0xEA,   0xEB,   0xEC,   0xED,   0xEE,   0xEF,
+       0xF0,   0xF1,   0xF2,   0xF3,   0xF4,   0xF5,   0xF6,   0xF7,
+       0xF8,   0xF9,   0xFA,   0xFB,   0xFC,   0xFD,   0xFE,   0xFF,
+#endif /*MAC*/
+};
diff --git a/usr/src/contrib/jove-4.14.6/ctype.h b/usr/src/contrib/jove-4.14.6/ctype.h
new file mode 100644 (file)
index 0000000..17e12c3
--- /dev/null
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define        C_UPPER 01      /* UPPER case */
+#define        C_LOWER 02      /* LOWER case */
+#define        C_DIGIT 04      /* DIGIT */
+#define        C_PUNCT 010     /* PUNCTuation */
+#define        C_CTRL  020     /* ConTRoL */
+#define        C_WORD  040     /* WORD */
+#define        C_BRA   0100    /* open BRAket */
+#define        C_KET   0200    /* close braKET */
+
+extern const unsigned char     *SyntaxTable;   /* CharTable[?] */
+#define        jiswhite(c)     (jisspace(c))
+#define        jisword(c)      (SyntaxTable[c]&C_WORD)
+#define        jisalpha(c)     (SyntaxTable[c]&(C_UPPER|C_LOWER))
+#define        jisupper(c)     (SyntaxTable[c]&C_UPPER)
+#define        jislower(c)     (SyntaxTable[c]&C_LOWER)
+#define        jisdigit(c)     (SyntaxTable[c]&C_DIGIT)
+#define        jisspace(c)     ((c) == ' ' || (c) == '\t')
+/* #define     jispunct(c)     (SyntaxTable[c]&C_PUNCT) */
+
+#define        has_syntax(c,s) (SyntaxTable[(c)&CHARMASK]&(s))
+
+
+/* #define     toascii(c)      ((c)&CHARMASK) */
+#define        jiscntrl(c)     ((CharTable[0][c&CHARMASK])&C_CTRL)
+#define        jisopenp(c)     ((CharTable[0][c&CHARMASK])&C_BRA)
+#define        jisclosep(c)    ((CharTable[0][c&CHARMASK])&C_KET)
+
+#ifdef ASCII7
+# define       jtolower(c)     ((c)|040)
+#else  /* !ASCII7 */
+  extern char jtolower proto((int /*char*/));
+#endif /* !ASCII7 */
+
+#define        WITH_TABLE(x) \
+{ \
+       const unsigned char     *push = SyntaxTable; \
+       SyntaxTable = CharTable[(x)];
+
+#define        END_TABLE() \
+       SyntaxTable = push; \
+}
+
+extern const unsigned char     CharTable[NMAJORS][NCHARS];
+extern const char      RaiseTable[NCHARS];
+#define        CharUpcase(c)   (RaiseTable[c])
diff --git a/usr/src/contrib/jove-4.14.6/dataobj.h b/usr/src/contrib/jove-4.14.6/dataobj.h
new file mode 100644 (file)
index 0000000..912979d
--- /dev/null
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define FUNCTION       1
+#define VARIABLE       2
+#define MACRO          3
+#define KEYMAP         4
+#ifdef MAC
+# define BUFFER                6       /* menus can point to buffers, too */
+# define STRING                7       /* a menu string or divider */
+#endif
+
+#define TYPEMASK       07
+#define obj_type(o)    ((o)->Type & TYPEMASK)
+#define MAJOR_MODE     010
+#define MINOR_MODE     020
+#define MODIFIER       040
+#define MODFUNC                (FUNCTION|MODIFIER)
+#define DefMajor(x)    (FUNCTION|MAJOR_MODE|((x) << 8))
+#define DefMinor(x)    (FUNCTION|MINOR_MODE|((x) << 8))
+
+struct macro {
+       int     Type;           /* in this case a macro */
+       char    *Name;          /* name is always second ... */
+       int     m_len,          /* length of macro so we can use ^@ */
+               m_buflen,       /* memory allocated for it */
+               m_flags;
+       char    *m_body;        /* actual body of the macro */
+       struct macro
+               *m_nextm;
+};
+
+struct cmd {
+       int     Type;
+       char    *Name;
+       void (*c_proc) proto((void));
+#ifdef MAC
+       char c_map;                     /* prefix map for About Jove... */
+       char c_key;                     /* key binding for About Jove... */
+#endif
+};
+
+typedef struct data_obj {
+       int     Type;
+       char    *Name;
+} data_obj;    /* points to cmd, macro, keymap or variable */
+
+extern data_obj        *LastCmd;       /* last command invoked */
+
+extern
+#ifndef IBMPC
+const
+#endif
+struct cmd     commands[];
+extern struct macro    *macros;
+
+extern struct macro
+       *macstack[];
+
+extern const struct cmd
+       *FindCmd proto((void (*proc) proto((void))));
+
+extern data_obj
+       *findcom proto((const char *prompt)),
+       *findmac proto((const char *prompt)),
+       *findvar proto((const char *prompt));
diff --git a/usr/src/contrib/jove-4.14.6/delete.c b/usr/src/contrib/jove-4.14.6/delete.c
new file mode 100644 (file)
index 0000000..0910664
--- /dev/null
@@ -0,0 +1,321 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* Routines to perform all kinds of deletion.  */
+
+#include "jove.h"
+#include "disp.h"
+
+/* Assumes that either line1 or line2 is actual the current line, so it can
+   put its result into linebuf. */
+
+private void
+patchup(line1, char1, line2, char2)
+Line   *line1,
+       *line2;
+register int   char1,
+               char2;
+{
+       if (line1 != line2)
+               ChkWindows(line1, line2);
+       DotTo(line1, char1);
+       modify();
+       linecopy(linebuf, curchar, lcontents(line2) + char2);
+
+       /* The following is a redisplay optimization. */
+       if (line1 != line2 && (char1 == 0 && char2 == 0))
+               line1->l_dline = line2->l_dline;
+
+       DFixMarks(line1, char1, line2, char2);
+       makedirty(curline);
+}
+
+/* Deletes the region by unlinking the lines in the middle,
+   and patching things up.  The unlinked lines are still in
+   order.  */
+
+Line *
+reg_delete(line1, char1, line2, char2)
+Line   *line1,
+       *line2;
+int    char1,
+       char2;
+{
+       register Line   *retline;
+
+       if ((line1 == line2 && char1 == char2) || line2 == NULL)
+               complain((char *)NULL);
+       (void) fixorder(&line1, &char1, &line2, &char2);
+
+       retline = nbufline();   /* New buffer line */
+
+       (void) ltobuf(line1, genbuf);
+       if (line1 == line2)
+               genbuf[char2] = '\0';
+
+       retline->l_prev = NULL;
+       retline->l_dline = putline(&genbuf[char1]);
+       patchup(line1, char1, line2, char2);
+
+       if (line1 == line2)
+               retline->l_next = NULL;
+       else {
+               retline->l_next = line1->l_next;
+               (void) ltobuf(line2, genbuf);
+               genbuf[char2] = '\0';
+               line2->l_dline = putline(genbuf);
+               /* Shorten this line */
+       }
+
+       if (line1 != line2) {
+               line1->l_next = line2->l_next;
+               if (line1->l_next)
+                       line1->l_next->l_prev = line1;
+               else
+                       curbuf->b_last = line1;
+               line2->l_next = NULL;
+       }
+
+       return retline;
+}
+
+private void
+lremove(line1, line2)
+register Line  *line1,
+               *line2;
+{
+       Line    *next = line1->l_next;
+
+       if (line1 == line2)
+               return;
+       line1->l_next = line2->l_next;
+       if (line1->l_next)
+               line1->l_next->l_prev = line1;
+       else
+               curbuf->b_last = line1;
+       lfreereg(next, line2);  /* Put region at end of free line list. */
+}
+
+/* delete character forward */
+
+void
+DelNChar()
+{
+       del_char(FORWARD, arg_value(), YES);
+}
+
+/* Delete character backward */
+
+void
+DelPChar()
+{
+       if (MinorMode(OverWrite)) {
+               int     count = min(arg_value(), curchar);
+
+               b_char(count);
+
+               /* overwrite with spaces */
+               set_arg_value(count);
+               LastKeyStruck = ' ';
+               SelfInsert();
+
+               b_char(count);
+       } else
+               del_char(BACKWARD, arg_value(), YES);
+}
+
+/* Delete some characters.  If deleting forward then call for_char
+   to the final position otherwise call back_char.  Then delete the
+   region between the two with patchup(). */
+
+void
+del_char(dir, num, OK_kill)
+int    dir,
+       num,
+       OK_kill;
+{
+       Bufpos  before,
+               after;
+       bool    killp = (OK_kill && (abs(num) > 1));
+
+       DOTsave(&before);
+       if (dir == FORWARD)
+               f_char(num);
+       else
+               b_char(num);
+       if (before.p_line == curline && before.p_char == curchar)
+               complain((char *)NULL);
+       if (killp)
+               reg_kill(before.p_line, before.p_char, YES);
+       else {
+               DOTsave(&after);
+               (void) fixorder(&before.p_line, &before.p_char, &after.p_line, &after.p_char);
+               patchup(before.p_line, before.p_char, after.p_line, after.p_char);
+               lremove(before.p_line, after.p_line);
+       }
+}
+
+/* This kills a region between point, and line1/char1 and puts it on
+   the kill-ring.  If the last command was one of the kill commands,
+   the region is appended (prepended if backwards) to the last entry.  */
+
+int    killptr = 0;
+Line   *killbuf[NUMKILLS];
+
+void
+reg_kill(line2, char2, dot_moved)
+Line   *line2;
+int    char2;
+bool   dot_moved;
+{
+       Line    *nl,
+               *line1 = curline;
+       int     char1 = curchar;
+       bool    backwards;
+
+       backwards = !fixorder(&line1, &char1, &line2, &char2);
+       /* This is a kludge!  But it possible for commands that don't
+          know which direction they are deleting in (e.g., delete
+          previous word could have been called with a negative argument
+          in which case, it wouldn't know that it really deleted
+          forward. */
+
+       if (!dot_moved)
+               backwards = !backwards;
+
+       DotTo(line1, char1);
+
+       nl = reg_delete(line1, char1, line2, char2);
+
+       if (last_cmd != KILLCMD) {
+               killptr = ((killptr + 1) % NUMKILLS);
+               lfreelist(killbuf[killptr]);
+               killbuf[killptr] = nl;
+       } else {
+               Line    *lastln = lastline(nl);
+
+               if (backwards) {
+                       (void) DoYank(nl, 0, lastln, length(lastln), killbuf[killptr], 0, (Buffer *)NULL);
+               } else {
+                       Line    *olastln = lastline(killbuf[killptr]);
+
+                       (void) DoYank(nl, 0, lastln, length(lastln), olastln, length(olastln), (Buffer *)NULL);
+               }
+       }
+       this_cmd = KILLCMD;
+}
+
+void
+DelReg()
+{
+       register Mark   *mp = CurMark();
+
+       reg_kill(mp->m_line, mp->m_char, NO);
+}
+
+/* Save a region.  A pretend kill. */
+
+void
+CopyRegion()
+{
+       register Line   *nl;
+       register Mark   *mp;
+       register int    status;
+
+       mp = CurMark();
+       if (mp->m_line == curline && mp->m_char == curchar)
+               complain((char *)NULL);
+
+       killptr = ((killptr + 1) % NUMKILLS);
+       if (killbuf[killptr])
+               lfreelist(killbuf[killptr]);
+       nl = killbuf[killptr] = nbufline();
+       SavLine(nl, NullStr);
+       nl->l_next = nl->l_prev = NULL;
+
+       status = inorder(mp->m_line, mp->m_char, curline, curchar);
+       if (status == -1)
+               return;
+
+       if (status)
+               (void) DoYank(mp->m_line, mp->m_char, curline, curchar,
+                               nl, 0, (Buffer *)NULL);
+       else
+               (void) DoYank(curline, curchar, mp->m_line, mp->m_char,
+                               nl, 0, (Buffer *)NULL);
+}
+
+void
+DelWtSpace()
+{
+       register char   *ep = &linebuf[curchar],
+                       *sp = &linebuf[curchar];
+
+       while (*ep == ' ' || *ep == '\t')
+               ep += 1;
+       while (sp > linebuf && (sp[-1] == ' ' || sp[-1] == '\t'))
+               sp -= 1;
+       if (sp != ep) {
+               curchar = sp - linebuf;
+               DFixMarks(curline, curchar, curline, curchar + (ep - sp));
+               strcpy(sp, ep);
+               makedirty(curline);
+               modify();
+       }
+}
+
+void
+DelBlnkLines()
+{
+       register Mark   *dot;
+       bool    all;
+
+       if (!blnkp(&linebuf[curchar]))
+               return;
+       dot = MakeMark(curline, curchar, M_FLOATER);
+       all = !blnkp(linebuf);
+       while (blnkp(linebuf) && curline->l_prev)
+               SetLine(curline->l_prev);
+       all |= firstp(curline);
+       Eol();
+       DelWtSpace();
+       line_move(FORWARD, 1, NO);
+       while (blnkp(linebuf) && !eobp()) {
+               DelWtSpace();
+               del_char(FORWARD, 1, NO);
+       }
+       if (!all && !eobp())
+               open_lines(1);
+       ToMark(dot);
+       DelMark(dot);
+}
+
+private void
+dword(forward)
+bool   forward;
+{
+       Bufpos  savedot;
+
+       DOTsave(&savedot);
+       if (forward)
+               ForWord();
+       else
+               BackWord();
+       reg_kill(savedot.p_line, savedot.p_char, YES);
+}
+
+void
+DelNWord()
+{
+       dword(YES);
+}
+
+void
+DelPWord()
+{
+       dword(NO);
+}
diff --git a/usr/src/contrib/jove-4.14.6/disp.c b/usr/src/contrib/jove-4.14.6/disp.c
new file mode 100644 (file)
index 0000000..6f52074
--- /dev/null
@@ -0,0 +1,1496 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+#include "termcap.h"
+#include "chars.h"
+#include "fp.h"
+#include "disp.h"
+#ifdef IPROCS
+# include "iproc.h"
+#endif
+
+#ifdef MAC
+# include "mac.h"
+#else
+# ifdef        STDARGS
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+# include <sys/stat.h>
+#endif
+
+#ifdef MSDOS
+#define SIGHUP 99
+#endif
+
+#include <signal.h>
+
+private void
+#ifdef ID_CHAR
+       DeTab proto((int, char *, char *, size_t, int)),
+       DelChar proto((int, int, int)),
+       InsChar proto((int, int, int, char *)),
+#endif
+       DoIDline proto((int)),
+       do_cl_eol proto((int)),
+       ModeLine proto((Window *)),
+       GotoDot proto((void)),
+       UpdLine proto((int)),
+       UpdWindow proto((Window *, int));
+
+#ifdef MSDOS
+extern void    dobell proto((int x));
+#else
+private void   dobell proto((int x));
+#endif
+
+#ifdef ID_CHAR
+private bool
+       IDchar proto ((char *, int, int)),
+       OkayDelete proto ((int, int, int)),
+       OkayInsert proto ((int, int));
+private int
+       NumSimilar proto ((char *, char *, int)),
+       IDcomp proto ((char *, char *, int));
+#endif
+private int
+       AddLines proto((int, int)),
+       DelLines proto((int, int));
+
+
+
+int    DisabledRedisplay = NO;
+
+/* Kludge windows gets called by the routines that delete lines from the
+   buffer.  If the w->w_line or w->w_top are deleted and this procedure
+   is not called, the redisplay routine will barf. */
+
+void
+ChkWindows(line1, line2)
+Line   *line1,
+       *line2;
+{
+       register Window *w = fwind;
+       register Line   *lp,
+                       *lend = line2->l_next;
+
+       do {
+               if (w->w_bufp == curbuf) {
+                       for (lp = line1->l_next; lp != lend; lp = lp->l_next) {
+                               if (lp == w->w_top)
+                                       w->w_flags |= W_TOPGONE;
+                               if (lp == w->w_line)
+                                       w->w_flags |= W_CURGONE;
+                       }
+               }
+               w = w->w_next;
+       } while (w != fwind);
+}
+
+/* Deleted and killed Lines are about to be recycled: check for dangling refs */
+
+void
+ChkWinLines()
+{
+       register Window *w = fwind;
+
+       do {
+               if (w->w_top == NULL || w->w_top->l_dline == NULL_DADDR)
+                       w->w_flags |= W_TOPGONE;
+               if (w->w_line == NULL || w->w_line->l_dline == NULL_DADDR)
+                       w->w_flags |= W_CURGONE;
+               w = w->w_next;
+       } while (w != fwind);
+}
+
+private bool   RingBell;       /* So if we have a lot of errors ...
+                                 ring the bell only ONCE */
+
+void
+redisplay()
+{
+       register Window *w = fwind;
+       int     lineno,
+               done_ID = NO,
+               i;
+       register struct scrimage        *des_p,
+                                       *phys_p;
+
+       if (DisabledRedisplay == YES)
+               return;
+       curwind->w_line = curwind->w_bufp->b_dot;
+       curwind->w_char = curwind->w_bufp->b_char;
+#ifdef MAC
+       InputPending = NO;
+#else
+       if ((InputPending = charp()) != NO)     /* calls CheckEvent, which could */
+               return; /* result in a call to rediplay(). We don't want that. */
+#endif
+#ifdef BSD_SIGS
+       if (UpdFreq)
+               SigHold(SIGALRM);
+#endif
+       if (RingBell) {
+               dobell(1);
+               RingBell = NO;
+       }
+       AbortCnt = BufSize;             /* initialize this now */
+       if (UpdMesg)
+               DrawMesg(YES);
+
+       for (lineno = 0, w = fwind; lineno < ILI; w = w->w_next) {
+               UpdWindow(w, lineno);
+               lineno += w->w_height;
+       }
+
+       UpdModLine = NO;/* Now that we've called update window, we can
+                          assume that the modeline will be updated.  But
+                          if while redrawing the modeline the user types
+                          a character, ModeLine() is free to set this on
+                          again so that the modeline will be fully drawn
+                          at the next redisplay. */
+
+       des_p = DesiredScreen;
+       phys_p = PhysScreen;
+       for (i = 0; i < ILI; i++, des_p++, phys_p++) {
+               if (!done_ID && (des_p->s_id != phys_p->s_id)) {
+                       DoIDline(i);
+                       done_ID = YES;
+               }
+               if ((des_p->s_flags & (DIRTY | L_MOD)) ||
+                   (des_p->s_id != phys_p->s_id) ||
+                   (des_p->s_vln != phys_p->s_vln) ||
+                   (des_p->s_offset != phys_p->s_offset))
+                       UpdLine(i);
+               if (InputPending)
+                       goto ret;
+       }
+
+       if (Asking) {
+               Placur(LI - 1, min(CO - 2, calc_pos(mesgbuf, AskingWidth)));
+                       /* Nice kludge */
+               flushscreen();
+       } else {
+               GotoDot();
+       }
+ret:
+    ;  /* yuck */
+
+#ifdef BSD_SIGS
+       if (UpdFreq)
+               SigRelse(SIGALRM);
+#endif
+#ifdef MAC
+       if (Windchange)
+               docontrols();
+#endif /* MAC */
+}
+
+#ifndef        IBMPC
+private void
+dobell(n)
+int    n;
+{
+       while (--n >= 0) {
+#ifndef        MAC
+               if (VisBell && VB)
+                       putstr(VB);
+               else
+                       putpad(BL, 1);
+#else
+               SysBeep(5);
+#endif
+       }
+       flushscreen();
+}
+#endif /* IBMPC */
+
+/* find_pos() returns the position on the line, that C_CHAR represents
+   in LINE */
+
+private int
+find_pos(line, c_char)
+Line   *line;
+int    c_char;
+{
+       return calc_pos(lcontents(line), c_char);
+}
+
+int
+calc_pos(lp, c_char)
+register char  *lp;
+register int   c_char;
+{
+       register int    pos = 0;
+       register int    c;
+
+
+       while ((--c_char >= 0) && ((c = *lp++) & CHARMASK) != 0) {
+               if (c == '\t')
+                       pos += (tabstop - (pos % tabstop));
+               else if (jiscntrl(c))
+                       pos += 2;
+               else
+                       pos += 1;
+       }
+       return pos;
+}
+
+bool   UpdModLine = NO,
+       UpdMesg = NO;
+
+private void
+DoIDline(start)
+int    start;
+{
+       register struct scrimage        *des_p = &DesiredScreen[start];
+       struct scrimage *phys_p = &PhysScreen[start];
+       register int    i,
+                       j;
+
+       /* Some changes have been made.  Try for insert or delete lines.
+          If either case has happened, Addlines and/or DelLines will do
+          necessary scrolling, also CONVERTING PhysScreen to account for the
+          physical changes.  The comparison continues from where the
+          insertion/deletion takes place; this doesn't happen very often,
+          usually it happens with more than one window with the same
+          buffer. */
+
+       if (!CanScroll)
+               return;         /* We should never have been called! */
+
+       for (i = start; i < ILI; i++, des_p++, phys_p++)
+               if (des_p->s_id != phys_p->s_id)
+                       break;
+
+       for (; i < ILI; i++) {
+               for (j = i + 1; j < ILI; j++) {
+                       des_p = &DesiredScreen[j];
+                       phys_p = &PhysScreen[j];
+                       if (des_p->s_id != 0 && des_p->s_id == phys_p->s_id)
+                               break;
+                       if (des_p->s_id == PhysScreen[i].s_id) {
+                               if (des_p->s_id == 0)
+                                       continue;
+                               if (AddLines(i, j - i)) {
+                                       DoIDline(j);
+                                       return;
+                               }
+                               break;
+                       }
+                       if ((des_p = &DesiredScreen[i])->s_id == phys_p->s_id) {
+                               if (des_p->s_id == 0)
+                                       continue;
+                               if (DelLines(i, j - i)) {
+                                       DoIDline(i);
+                                       return;
+                               }
+                               break;
+                       }
+               }
+       }
+}
+
+/* Make DesiredScreen reflect what the screen should look like when we are done
+   with the redisplay.  This deals with horizontal scrolling.  Also makes
+   sure the current line of the Window is in the window. */
+
+bool   ScrollAll = NO;
+
+private void
+UpdWindow(w, start)
+register Window        *w;
+int    start;
+{
+       Line    *lp;
+       int     i,
+               upper,          /* top of window */
+               lower,          /* bottom of window */
+               strt_col,       /* starting print column of current line */
+               ntries = 0;     /* # of tries at updating window */
+       register struct scrimage        *des_p,
+                                       *phys_p;
+       Buffer  *bp = w->w_bufp;
+
+retry:
+       if (w->w_flags & W_CURGONE) {
+               w->w_line = bp->b_dot;
+               w->w_char = bp->b_char;
+       }
+       if (w->w_flags & W_TOPGONE)
+               CentWind(w);    /* reset topline of screen */
+       w->w_flags &= ~(W_CURGONE | W_TOPGONE);
+
+       /* make sure that the current line is in the window */
+       upper = start;
+       lower = upper + w->w_height - 1;        /* don't include modeline */
+       for (i = upper, lp = w->w_top; i < lower && lp != NULL; lp = lp->l_next, i++)
+               if (lp == w->w_line)
+                       break;
+       if (i == lower || lp == NULL) {
+               ntries += 1;
+               if (ntries == 1) {
+                       CalcWind(w);
+                       goto retry;
+               } else if (ntries == 2) {
+                       w->w_top = w->w_line = w->w_bufp->b_first;
+                       writef("\rERROR in redisplay: I got hopelessly lost!");
+                       dobell(2);
+                       goto retry;
+               } else if (ntries == 3) {
+                       writef("\n\rOops, still lost, quitting ...\r\n");
+                       finish(SIGHUP);
+               }
+       }
+
+       /* first do some calculations for the current line */
+       {
+               int     diff = (w->w_flags & W_NUMLINES) ? 8 : 0,
+                       end_col;
+
+               strt_col = ScrollAll? w->w_LRscroll : PhysScreen[i].s_offset;
+               end_col = strt_col + (CO - 2) - diff;
+               /* Right now we are displaying from strt_col to
+                  end_col of the buffer line.  These are PRINT
+                  columns, not actual characters. */
+               w->w_dotcol = find_pos(w->w_line, w->w_char);
+               /* if the new dotcol is out of range, reselect
+                  a horizontal window */
+               if ((PhysScreen[i].s_offset == -1) ||
+                   (w->w_dotcol < strt_col) ||
+                   (w->w_dotcol >= end_col)) {
+                       if (w->w_dotcol < ((CO - 2) - diff))
+                               strt_col = 0;
+                       else
+                               strt_col = w->w_dotcol - (CO / 2);
+                       if (ScrollAll) {
+                               if (w->w_LRscroll != strt_col)
+                                       UpdModLine = YES;
+                               w->w_LRscroll = strt_col;
+                       }
+               }
+               w->w_dotline = i;
+               w->w_dotcol += diff;
+       }
+
+       des_p = &DesiredScreen[upper];
+       phys_p = &PhysScreen[upper];
+       for (i = upper, lp = w->w_top; lp != NULL && i < lower; i++, des_p++, phys_p++, lp = lp->l_next) {
+               des_p->s_window = w;
+               des_p->s_lp = lp;
+               /* ??? what is -(daddr)1?  Would NULL_DADDR work as well? -- DHR */
+               des_p->s_id = (lp == curline && DOLsave)?
+                       -(daddr)1 : lp->l_dline & ~DIRTY;
+               des_p->s_flags = isdirty(lp) ? L_MOD : 0;
+               if (w->w_flags & W_NUMLINES)
+                       des_p->s_vln = w->w_topnum + (i - upper);
+               else
+                       des_p->s_vln = 0;
+
+               if (lp == w->w_line)
+                       des_p->s_offset = strt_col;
+               else
+                       des_p->s_offset = w->w_LRscroll;
+       }
+
+       /* Is structure assignment faster than copy each field separately? */
+       if (i < lower) {
+               static const struct scrimage    dirty_plate = { 0, DIRTY, 0, 0, 0, 0 },
+                                       clean_plate = { 0, 0, 0, 0, 0, 0 };
+
+               for (; i < lower; i++, des_p++, phys_p++)
+                       if (phys_p->s_id != 0)
+                               *des_p = dirty_plate;
+                       else
+                               *des_p = clean_plate;
+       }
+
+       des_p->s_window = w;
+       des_p->s_flags = 0;
+       /* ??? The following assignment is very questionable:
+        * - it stores a pointer in an integer variable
+        * - it counts on these values being distinct from
+        *   disk addresses, 0 (NULL_DADDR), and -1.
+        * -- DHR
+        */
+       des_p->s_id = (daddr) w->w_bufp;
+       if (des_p->s_id != phys_p->s_id || UpdModLine)
+               des_p->s_flags = MODELINE | DIRTY;
+#ifdef MAC
+       if (UpdModLine)
+               Modechange = YES;
+       if (w == curwind && w->w_control)
+               SetScrollBar(w->w_control);
+#endif
+}
+
+/* Write whatever is in mesgbuf (maybe we are Asking, or just printed
+   a message).  Turns off the UpdateMesg line flag. */
+
+void
+DrawMesg(abortable)
+bool   abortable;
+{
+#ifndef        MAC             /* same reason as in redisplay() */
+       if (charp())
+               return;
+#endif
+       i_set(ILI, 0);
+       if (swrite(mesgbuf, NO, abortable)) {
+               cl_eol();
+               UpdMesg = NO;
+       }
+       flushscreen();
+}
+
+/* Goto the current position in the current window.  Presumably redisplay()
+   has already been called, and curwind->{w_dotline,w_dotcol} have been set
+   correctly. */
+
+private void
+GotoDot()
+{
+       if (!InputPending) {
+               Placur(curwind->w_dotline,
+                       curwind->w_dotcol - PhysScreen[curwind->w_dotline].s_offset);
+               flushscreen();
+       }
+}
+
+private int
+UntilEqual(start)
+register int   start;
+{
+       register struct scrimage        *des_p = &DesiredScreen[start],
+                                       *phys_p = &PhysScreen[start];
+
+       while ((start < ILI) && (des_p->s_id != phys_p->s_id)) {
+               des_p += 1;
+               phys_p += 1;
+               start += 1;
+       }
+
+       return start;
+}
+
+/* Calls the routine to do the physical changes, and changes PhysScreen to
+   reflect those changes. */
+
+private int
+AddLines(at, num)
+register int   at,
+               num;
+{
+       register int    i;
+       int     bottom = UntilEqual(at + num);
+
+       if (num == 0 || num >= ((bottom - 1) - at))
+               return NO;                              /* we did nothing */
+       v_ins_line(num, at, bottom - 1);
+
+       /* Now change PhysScreen to account for the physical change. */
+
+       for (i = bottom - 1; i - num >= at; i--)
+               PhysScreen[i] = PhysScreen[i - num];
+       for (i = 0; i < num; i++)
+               PhysScreen[at + i].s_id = 0;
+       return YES;                                     /* we did something */
+}
+
+private int
+DelLines(at, num)
+register int   at,
+               num;
+{
+       register int    i;
+       int     bottom = UntilEqual(at + num);
+
+       if (num == 0 || num >= ((bottom - 1) - at))
+               return NO;
+       v_del_line(num, at, bottom - 1);
+
+       for (i = at; num + i < bottom; i++)
+               PhysScreen[i] = PhysScreen[num + i];
+       for (i = bottom - num; i < bottom; i++)
+               PhysScreen[i].s_id = 0;
+       return YES;
+}
+
+/* Update line linenum in window w.  Only set PhysScreen to DesiredScreen
+   if the swrite or cl_eol works, that is nothing is interupted by
+   characters typed. */
+
+private void
+UpdLine(linenum)
+register int   linenum;
+{
+       register struct scrimage        *des_p = &DesiredScreen[linenum];
+       register Window *w = des_p->s_window;
+
+       i_set(linenum, 0);
+       if (des_p->s_flags & MODELINE) {
+               ModeLine(w);
+       } else if (des_p->s_id) {
+               des_p->s_lp->l_dline &= ~DIRTY;
+               des_p->s_flags &= ~(DIRTY | L_MOD);
+#ifdef ID_CHAR
+               if (UseIC) {
+                       char    outbuf[MAXCOLS],
+                               *lptr;
+                       int     fromcol = (w->w_flags & W_NUMLINES) ? 8 : 0;
+
+                       if (w->w_flags & W_NUMLINES)
+                               swritef(outbuf, sizeof(outbuf), "%6d  ",
+                                       des_p->s_vln);
+                       lptr = lcontents(des_p->s_lp);
+                       DeTab(des_p->s_offset, lptr, outbuf + fromcol,
+                               (sizeof outbuf) - 1 - fromcol,
+                               des_p->s_window->w_flags & W_VISSPACE);
+                       if (IDchar(outbuf, linenum, 0))
+                               PhysScreen[linenum] = *des_p;
+                       else if (i_set(linenum, 0), swrite(outbuf, NO, YES))
+                               do_cl_eol(linenum);
+                       else
+                               PhysScreen[linenum].s_id = -1;
+               } else {
+#endif /* ID_CHAR */
+                       if (w->w_flags & W_NUMLINES)
+                               (void) swrite(sprint("%6d  ", des_p->s_vln), NO, YES);
+                       if (BufSwrite(linenum))
+                               do_cl_eol(linenum);
+                       else
+                               PhysScreen[linenum].s_id = -1;
+#ifdef ID_CHAR
+               }
+#endif
+       } else if (PhysScreen[linenum].s_id) {  /* not the same ... make sure */
+               do_cl_eol(linenum);
+       }
+}
+
+private void
+do_cl_eol(linenum)
+register int   linenum;
+{
+       cl_eol();
+       PhysScreen[linenum] = DesiredScreen[linenum];
+}
+
+#ifdef ID_CHAR
+
+/* From here to the end of the file is code that tries to utilize the
+   insert/delete character feature on some terminals.  It is very confusing
+   and not so well written code, AND there is a lot of it.  You may want
+   to use the space for something else. */
+
+bool   IN_INSmode = FALSE;
+
+bool   UseIC = FALSE;
+
+int    IMlen;
+
+private int
+       DClen,
+       IClen,
+       MDClen,
+       MIClen,
+       CElen;
+
+void
+disp_opt_init()
+{
+       DClen = DC ? strlen(DC) : 0;
+       MDClen = M_DC ? strlen(M_DC) : 9999;
+       IClen = IC ? strlen(IC) : 0;
+       MIClen = M_IC ? strlen(M_IC) : 9999;
+       IMlen = IM ? strlen(IM) : 0;
+       CElen = CE ? strlen(CE) : 0;
+
+       UseIC = (IC || IM || M_IC);
+}
+
+void
+INSmode(on)
+bool   on;
+{
+       if (on && !IN_INSmode) {
+               putpad(IM, 1);
+               IN_INSmode = YES;
+       } else if (!on && IN_INSmode) {
+               putpad(EI, 1);
+               IN_INSmode = NO;
+       }
+}
+
+private void
+DeTab(s_offset, buf, outbuf, limit, visspace)
+int    s_offset;
+register char  *buf;
+char   *outbuf;
+size_t limit;
+int    visspace;
+{
+       register char   *phys_p = outbuf,
+                       c;
+       register int    pos = 0;
+       char            *limitp = &outbuf[limit];
+
+#define OkayOut(ch)    { \
+       if ((pos++ >= s_offset) && (phys_p < limitp)) \
+               *phys_p++ = (ch); \
+}
+
+       while ((c = *buf++) != '\0') {
+               if (c == '\t') {
+                       int     nchars = (tabstop - (pos % tabstop));
+
+                       if (visspace) {
+                               OkayOut('>');
+                               nchars -= 1;
+                       }
+                       while (--nchars >= 0)
+                               OkayOut(' ');
+
+               } else if (jiscntrl(c)) {
+                       OkayOut('^');
+                       OkayOut(c == 0177 ? '?' : c + '@');
+               } else {
+                       if (visspace && c == ' ')
+                               c = '_';
+                       OkayOut(c);
+               }
+               if (pos - s_offset >= CO) {
+                       phys_p = &outbuf[CO - 1];
+                       *phys_p++ = '!';
+                       break;
+               }
+       }
+       *phys_p = '\0';
+
+#undef OkayOut
+}
+
+/* ID character routines full of special cases and other fun stuff like that.
+   It actually works though ...
+
+       Returns Non-Zero if you are finished (no differences left). */
+
+private bool
+IDchar(new, lineno, col)
+register char  *new;
+int    lineno,
+       col;
+{
+       register int    i;
+       int     j,
+               oldlen,
+               NumSaved;
+       register struct screenline      *sline = &Screen[lineno];
+
+       oldlen = sline->s_length - sline->s_line;
+
+       for (i = col; i < oldlen && new[i] != '\0'; i++)
+               if (sline->s_line[i] != new[i])
+                       break;
+       if (new[i] == '\0' || i == oldlen)
+               return new[i] == '\0' && i == oldlen;
+
+       for (j = i + 1; j < oldlen && new[j]; j++) {
+               if (new[j] == sline->s_line[i]) {
+                       NumSaved = IDcomp(new + j, sline->s_line + i,
+                                       (int)strlen(new)) + NumSimilar(new + i,
+                                               sline->s_line + i, j - i);
+                       if (OkayInsert(NumSaved, j - i)) {
+                               InsChar(lineno, i, j - i, new);
+                               return IDchar(new, lineno, j);
+                       }
+               }
+       }
+
+       for (j = i + 1; j < oldlen && new[i]; j++) {
+               if (new[i] == sline->s_line[j]) {
+                       NumSaved = IDcomp(new + i, sline->s_line + j,
+                                       oldlen - j);
+                       if (OkayDelete(NumSaved, j - i, new[oldlen] == '\0')) {
+                               DelChar(lineno, i, j - i);
+                               return IDchar(new, lineno, i);
+                       }
+               }
+       }
+       return NO;
+}
+
+private int
+NumSimilar(s, t, n)
+register char  *s,
+               *t;
+int    n;
+{
+       register int    num = 0;
+
+       while (n--)
+               if (*s++ == *t++)
+                       num += 1;
+       return num;
+}
+
+private int
+IDcomp(s, t, len)
+register char  *s,
+               *t;
+int    len;
+{
+       register int    i;
+       int     num = 0,
+               nonspace = 0;
+       char    c;
+
+       for (i = 0; i < len; i++) {
+               if ((c = *s++) != *t++)
+                       break;
+               if (c != ' ')
+                       nonspace++;
+               if (nonspace)
+                       num += 1;
+       }
+
+       return num;
+}
+
+private bool
+OkayDelete(Saved, num, samelength)
+int    Saved,
+       num,
+       samelength;
+{
+       /* If the old and the new are the same length, then we don't
+        * have to clear to end of line.  We take that into consideration.
+        */
+       return ((Saved + (!samelength ? CElen : 0))
+               > min(MDClen, DClen * num));
+}
+
+private bool
+OkayInsert(Saved, num)
+int    Saved,
+       num;
+{
+       register int    n = 0;
+
+       if (IC)         /* Per character prefixes */
+               n = min(num * IClen, MIClen);
+
+       if (IM && !IN_INSmode) {
+               /* Good terminal.  Fewer characters in this case */
+               n += IMlen;
+       }
+
+       n += num;       /* The characters themselves */
+
+       return Saved > n;
+}
+
+private void
+DelChar(lineno, col, num)
+int    lineno,
+       col,
+       num;
+{
+       register char   *from,
+                       *to;
+       register int    i;
+       struct screenline *sp = (&Screen[lineno]);
+
+       Placur(lineno, col);
+       if (M_DC && num > 1) {
+               putargpad(M_DC, num, num);
+       } else {
+               for (i = num; --i >= 0; )
+                       putpad(DC, 1);
+       }
+
+       to = sp->s_line + col;
+       from = to + num;
+
+       byte_copy(from, to, (size_t) (sp->s_length - from + 1));
+       clrline(sp->s_length - num, sp->s_length);
+       sp->s_length -= num;
+}
+
+private void
+InsChar(lineno, col, num, new)
+int    lineno,
+       col,
+       num;
+char   *new;
+{
+       register char   *sp1,
+                       *sp2,   /* To push over the array. */
+                       *sp3;   /* Last character to push over. */
+       int     i;
+
+       i_set(lineno, 0);
+       sp2 = Curline->s_length + num;
+
+       if (sp2 >= cursend) {
+               i_set(lineno, CO - num - 1);
+               cl_eol();
+               sp2 = cursend - 1;
+       }
+       Curline->s_length = sp2;
+       sp1 = sp2 - num;
+       sp3 = Curline->s_line + col;
+
+       while (sp1 >= sp3)
+               *sp2-- = *sp1--;
+
+       new += col;
+       byte_copy(new, sp3, (size_t) num);
+       /* The internal screen is correct, and now we have to do
+          the physical stuff. */
+
+       Placur(lineno, col);
+       if (IM) {
+               if (!IN_INSmode)
+                       INSmode(ON);
+       } else if (M_IC && num > 1) {
+               putargpad(M_IC, num, num);
+       } else if (IC) {
+               for (i = 0; i < num; i++)
+                       putpad(IC, 1);
+       }
+       for (i = 0; i < num; i++) {
+               jputchar(new[i]);
+               if (IN_INSmode)
+                       putpad(IP, 1);
+       }
+       CapCol += num;
+}
+
+#endif /* ID_CHAR */
+
+#ifdef UNIX            /* obviously ... no mail today if not Unix*/
+
+/* chkmail() returns nonzero if there is new mail since the
+   last time we checked. */
+
+char   Mailbox[FILESIZE];      /* initialized in main */
+int    MailInt = 60;           /* check no more often than 60 seconds */
+#ifdef BIFF
+bool   BiffChk = NO;           /* whether to turn off biff while in JOVE */
+#endif
+
+int
+chkmail(force)
+int    force;
+{
+       time_t  now;
+       static int      state = NO;     /* assume unknown */
+       static time_t   last_chk = 0,
+                       mbox_time = 0;
+       struct stat     stbuf;
+
+       if (MailInt == 0)
+               return NO;
+       time(&now);
+       if ((force == NO) && (now < last_chk + MailInt))
+               return state;
+       last_chk = now;
+       if (stat(Mailbox, &stbuf) < 0) {
+               state = NO;             /* no mail */
+               return NO;
+       }
+       if (((stbuf.st_atime > stbuf.st_mtime) &&
+            (stbuf.st_atime > mbox_time)) ||
+           (stbuf.st_size == 0)) {
+               mbox_time = stbuf.st_atime;
+               state = NO;
+       } else if (stbuf.st_mtime > mbox_time) {
+               if (mbox_time > 0)
+                       dobell(2);              /* announce the change */
+               mbox_time = stbuf.st_mtime;
+               state = YES;
+       }
+       return state;
+}
+
+#endif /* UNIX */
+
+/* Print the mode line. */
+
+private char   *mode_p,
+               *mend_p;
+bool   BriteMode = ON;         /* modeline should standout */
+
+private void
+mode_app(str)
+register const char    *str;
+{
+       do ; while ((mode_p < mend_p) && (*mode_p++ = *str++)!='\0');
+       mode_p -= 1;    /* back over the null */
+}
+
+char   ModeFmt[120] = "%3c %w %[%sJOVE (%M)   Buffer: %b  \"%f\" %]%s%m*- %((%t)%s%)%e";
+
+private void
+ModeLine(w)
+register Window        *w;
+{
+       int     n,
+               glue = 0;
+       bool    ign_some = NO;
+       char    line[MAXCOLS],
+               *fmt = ModeFmt,
+               fillc,
+               c;
+       register Buffer *thisbuf = w->w_bufp;
+       register Buffer *bp;
+
+       mode_p = line;
+       mend_p = &line[(sizeof line) - 1];
+
+#ifdef IBMPC
+       /* very subtle - don't mess up attributes too much */
+       fillc = '-';
+#else  /* !IBMPC */
+#  ifdef       MAC
+       fillc = '_';    /* looks better on a Mac */
+#  else        /* !MAC */
+       if (SO == NULL)
+               BriteMode = OFF;
+       fillc = BriteMode ? ' ' : '-';
+#  endif       /* !MAC */
+#endif /* !IBMPC */
+
+       while ((c = *fmt++)!='\0' && mode_p<mend_p) {
+               if (c != '%') {
+                       if (c == '\\')
+                               if ((c = *fmt++) == '\0')
+                                       break;
+                       if (!ign_some)
+                               *mode_p++ = c;
+                       continue;
+               }
+               if ((c = *fmt++) == '\0')       /* char after the '%' */
+                       break;
+               if (ign_some && c != ')')
+                       continue;
+               n = 1;
+               if (c >= '0' && c <= '9') {
+                       n = 0;
+                       while (c >= '0' && c <= '9') {
+                               n = n * 10 + (c - '0');
+                               c = *fmt++;
+                       }
+                       if (c == '\0')
+                               break;
+               }
+               switch (c) {
+               case '(':
+                       if (w->w_next != fwind) /* Not bottom window. */
+                               ign_some = YES;
+                       break;
+
+               case ')':
+                       ign_some = NO;
+                       break;
+
+               case '[':
+               case ']':
+                       for (n=RecDepth; n>0 && mode_p<mend_p; n--)
+                               *mode_p++ = c;
+                       break;
+
+#ifdef UNIX
+               case 'C':       /* check mail here */
+                       if (chkmail(NO) == YES)
+                               mode_app("[New mail]");
+                       break;
+
+#endif /* UNIX */
+
+               case 'M':
+                   {
+                       static const char       *const mmodes[] = {
+                               "Fundamental ",
+                               "Text ",
+                               "C ",
+#ifdef LISP
+                               "Lisp ",
+#endif
+                               NULL
+                       };
+
+                       mode_app(mmodes[thisbuf->b_major]);
+
+                       if (BufMinorMode(thisbuf, Fill))
+                               mode_app("Fill ");
+                       if (BufMinorMode(thisbuf, Abbrev))
+                               mode_app("Abbrev ");
+                       if (BufMinorMode(thisbuf, OverWrite))
+                               mode_app("OvrWt ");
+                       if (BufMinorMode(thisbuf, Indent))
+                               mode_app("Indent ");
+                       if (BufMinorMode(thisbuf, ReadOnly))
+                               mode_app("RO ");
+                       if (InMacDefine)
+                               mode_app("Def ");
+                       mode_p -= 1;    /* Back over the extra space. */
+                       break;
+                   }
+
+               case 'c':
+                       while (--n>=0 && mode_p<mend_p)
+                               *mode_p++ = fillc;
+                       break;
+
+               case 'd':       /* print working directory */
+                       mode_app(pr_name(pwd(), YES));
+                       break;
+
+               case 'e':       /* stretchable glue */
+                       *mode_p++ = '\0';       /* glue marker */
+                       glue++;
+                       break;
+
+               case 'b':
+                       mode_app(thisbuf->b_name);
+                       break;
+
+               case 'f':
+               case 'F':
+                       if (thisbuf->b_fname == NULL)
+                               mode_app("[No file]");
+                       else {
+                               if (c == 'f')
+                                       mode_app(pr_name(thisbuf->b_fname, YES));
+                               else
+                                       mode_app(basename(thisbuf->b_fname));
+                       }
+                       break;
+
+#ifdef LOAD_AV
+               case 'l':
+                   {
+                       int     la = get_la();
+                       char    minibuf[10];
+
+                       swritef(minibuf, sizeof(minibuf), "%d.%02d",
+                              la/100, la%100);
+                       mode_app(minibuf);
+                       break;
+                   }
+#endif
+
+               case 'm':
+                   {
+                       char    yea = (*fmt == '\0') ? '*' : *fmt++;
+                       char    nay = (*fmt == '\0') ? ' ' : *fmt++;
+
+                       *mode_p++ = IsModified(w->w_bufp) ? yea : nay;
+                       break;
+                   }
+
+               case 'n':
+                   {
+                       char    tmp[16];
+
+                       for (bp = world, n = 1; bp != NULL; bp = bp->b_next, n++)
+                               if (bp == thisbuf)
+                                       break;
+
+                       swritef(tmp, sizeof(tmp), "%d", n);
+                       mode_app(tmp);
+                       break;
+                   }
+
+#ifdef IPROCS
+               case 'p':
+                       if (thisbuf->b_type == B_PROCESS) {
+                               char    tmp[40];
+                               Process *p = thisbuf->b_process;
+
+                               swritef(tmp, sizeof(tmp), "(%s%s)",
+                                       ((p == NULL || p->p_dbx_mode == NO)
+                                        ? "" : "DBX "),
+                                       ((p == NULL) ? "No process" :
+                                        pstate(p)));
+                               mode_app(tmp);
+                       }
+                       break;
+#endif
+
+               case 's':
+                       if (mode_p[-1] != ' ')
+                               *mode_p++ = ' ';
+                       break;
+
+               case 't':
+                   {
+                       char    timestr[12];
+
+                       mode_app(get_time((time_t *)NULL, timestr, 11, 16));
+                       break;
+                   }
+
+               case 'w':
+                       if (w->w_LRscroll > 0)
+                               mode_app(">");
+                       break;
+
+               default:
+                       mode_app("?");
+                       break;
+               }
+       }
+
+       /* Glue (Knuth's term) is a field that expands to fill
+        * any leftover space.  Multiple glue fields compete
+        * on an equal basis.  This is a generalization of a
+        * mechanism to allow centring and right-justification.
+        * The original meaning of %e (fill the rest of the
+        * line) has also been generalized.  %e can now
+        * meaningfully be used 0 or more times.
+        */
+
+       if  (glue) {
+               /* 2 space pad plus padding for magic cookies */
+               register char   *to = &line[CO - 2 - (2 * SG)],
+                               *from = mode_p;
+
+               if (to < from)
+                       to = from;
+               mode_p = to;
+               while (from != line) {
+                       if ((*--to = *--from) == '\0') {
+                               register int    portion = (to-from) / glue;
+
+                               glue--;
+                               *to = fillc;
+                               while (--portion >= 0)
+                                       *--to = fillc;
+                       }
+               }
+       }
+
+       *mode_p = '\0';
+
+       /* Highlight mode line. */
+       if (BriteMode) {
+#ifdef ID_CHAR
+               if (IN_INSmode)
+                       INSmode(OFF);
+#endif
+               SO_on();
+       }
+       if (swrite(line, BriteMode, YES))
+               do_cl_eol(i_line);
+       else
+               UpdModLine = YES;
+       if (BriteMode)
+               SO_off();
+}
+
+private void
+v_clear(line1, line2)
+register int   line1;
+int    line2;
+{
+       register struct scrimage        *phys_p, *des_p;
+
+       phys_p = &PhysScreen[line1];
+       des_p = &DesiredScreen[line1];
+
+       while (line1 <= line2) {
+               i_set(line1, 0);
+               cl_eol();
+               phys_p->s_id = des_p->s_id = 0;
+               phys_p += 1;
+               des_p += 1;
+               line1 += 1;
+       }
+}
+
+/* This tries to place the current line of the current window in the
+   center of the window, OR to place it at the arg'th line of the window.
+   This also causes the horizontal position of the line to be centered,
+   if the line needs scrolling, or moved all the way back to the left,
+   if that's possible. */
+void
+RedrawDisplay()
+{
+       int     line;
+       Line    *newtop = prev_line((curwind->w_line = curline), is_an_arg() ?
+                               arg_value() : HALF(curwind));
+
+       if ((line = in_window(curwind, curwind->w_line)) != -1)
+               PhysScreen[line].s_offset = -1;
+       if (newtop == curwind->w_top)
+               v_clear(FLine(curwind), FLine(curwind) + SIZE(curwind));
+       else
+               SetTop(curwind, newtop);
+}
+
+void
+ClAndRedraw()
+{
+       cl_scr(YES);
+}
+
+void
+NextPage()
+{
+       Line    *newline;
+
+       if (Asking)
+               return;
+       if (arg_value() < 0) {
+               negate_arg_value();
+               PrevPage();
+               return;
+       }
+       if (arg_type() == YES)
+               UpScroll();
+       else {
+               if (in_window(curwind, curwind->w_bufp->b_last) != -1) {
+                       rbell();
+                       return;
+               }
+               newline = next_line(curwind->w_top, max(1, SIZE(curwind) - 1));
+               SetTop(curwind, curwind->w_line = newline);
+               if (curwind->w_bufp == curbuf)
+                       SetLine(newline);
+       }
+}
+
+#ifdef MSDOS
+
+void
+PageScrollUp()
+{
+       int i, n;
+
+    n = max(1, SIZE(curwind) - 1);
+       for (i=0; i<n; i++) {
+           UpScroll();
+           redisplay();
+       }
+}
+
+void
+PageScrollDown()
+{
+       int i, n;
+
+       n = max(1, SIZE(curwind) - 1);
+       for (i=0; i<n; i++) {
+           DownScroll();
+           redisplay();
+       }
+}
+#endif /* MSDOS */
+
+void
+PrevPage()
+{
+       Line    *newline;
+
+       if (Asking)
+               return;
+       if (arg_value() < 0) {
+               negate_arg_value();
+               NextPage();
+               return;
+       }
+       if (arg_type() == YES)
+               DownScroll();
+       else {
+               newline = prev_line(curwind->w_top, max(1, SIZE(curwind) - 1));
+               SetTop(curwind, curwind->w_line = newline);
+               if (curwind->w_bufp == curbuf)
+                       SetLine(newline);
+       }
+}
+
+void
+UpScroll()
+{
+       SetTop(curwind, next_line(curwind->w_top, arg_value()));
+       if ((curwind->w_bufp == curbuf) &&
+           (in_window(curwind, curline) == -1))
+               SetLine(curwind->w_top);
+}
+
+void
+DownScroll()
+{
+       SetTop(curwind, prev_line(curwind->w_top, arg_value()));
+       if ((curwind->w_bufp == curbuf) &&
+           (in_window(curwind, curline) == -1))
+               SetLine(curwind->w_top);
+}
+
+bool   VisBell = NO;
+
+void
+rbell()
+{
+       RingBell = YES;
+}
+
+/* Message prints the null terminated string onto the bottom line of the
+   terminal. */
+
+void
+message(str)
+char   *str;
+{
+       if (InJoverc)
+               return;
+       UpdMesg = YES;
+       errormsg = NO;
+       if (str != mesgbuf)
+               null_ncpy(mesgbuf, str, (sizeof mesgbuf) - 1);
+}
+
+/* End of Window */
+
+void
+Eow()
+{
+       if (Asking)
+               return;
+       SetLine(next_line(curwind->w_top, SIZE(curwind) - 1 -
+                       min(SIZE(curwind) - 1, arg_value() - 1)));
+       if (!is_an_arg())
+               Eol();
+}
+
+/* Beginning of Window */
+
+void
+Bow()
+{
+       if (Asking)
+               return;
+       SetLine(next_line(curwind->w_top, min(SIZE(curwind) - 1, arg_value() - 1)));
+}
+
+private int    LineNo,
+               last_col;
+private bool
+               DoAutoNL;
+private Window *old_wind;      /* save the window we were in BEFORE
+                                  before we were called, if UseBuffers
+                                  is nonzero */
+
+bool   UseBuffers = FALSE,
+       TOabort = FALSE;
+
+/* This initializes the typeout.  If send-typeout-to-buffers is set
+   the buffer NAME is created (emptied if it already exists) and output
+   goes to the buffer.  Otherwise output is drawn on the screen and
+   erased by TOstop() */
+
+void
+TOstart(name, auto_newline)
+char   *name;
+bool   auto_newline;
+{
+       if (UseBuffers) {
+               old_wind = curwind;
+               pop_wind(name, YES, B_SCRATCH);
+       } else
+               DisabledRedisplay = YES;
+       TOabort = FALSE;
+       LineNo = last_col = 0;
+       DoAutoNL = auto_newline;
+}
+
+#ifdef STDARGS
+       void
+Typeout(char *fmt, ...)
+#else
+       /*VARARGS1*/ void
+Typeout(fmt, va_alist)
+       char    *fmt;
+       va_dcl
+#endif
+{
+       if (TOabort)
+               return;
+
+       if (!UseBuffers && (LineNo == ILI - 1)) {
+               register int    c;
+
+               LineNo = 0;
+               last_col = 0;
+               f_mess("--more--");
+               if ((c = jgetchar()) != ' ') {
+                       TOabort = TRUE;
+                       if (c != AbortChar && c != RUBOUT)
+                               Ungetc(c);
+                       f_mess(NullStr);
+                       return;
+               }
+               f_mess(NullStr);
+       }
+
+       if (fmt) {
+               char    string[132];
+               va_list ap;
+
+               va_init(ap, fmt);
+               format(string, sizeof string, fmt, ap);
+               va_end(ap);
+               if (UseBuffers) {
+                       ins_str(string, NO);
+               } else {
+                       i_set(LineNo, last_col);
+                       (void) swrite(string, NO, YES);
+                       last_col = i_col;
+               }
+       }
+       if (!UseBuffers) {
+               PhysScreen[LineNo].s_id = -1;
+               if (fmt == NULL || DoAutoNL) {
+                       cl_eol();
+                       flushscreen();
+                       LineNo += 1;
+                       last_col = 0;
+               }
+       } else if (fmt == NULL || DoAutoNL)
+               ins_str("\n", NO);
+}
+
+void
+TOstop()
+{
+       int     c;
+
+       if (UseBuffers) {
+               ToFirst();
+               SetWind(old_wind);
+       } else {
+               if (TOabort) {
+                       DisabledRedisplay = NO;
+               } else {
+                       if (last_col != 0)
+                               Typeout((char *)NULL);
+                       Typeout("----------");
+                       cl_eol();
+                       flushscreen();
+                       c = jgetchar();
+                       if (c != ' ')
+                               Ungetc(c);
+                       DisabledRedisplay = NO;
+               }
+       }
+}
diff --git a/usr/src/contrib/jove-4.14.6/disp.h b/usr/src/contrib/jove-4.14.6/disp.h
new file mode 100644 (file)
index 0000000..daa335a
--- /dev/null
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define DIRTY          ((daddr) 01)    /* needs update for some reason */
+#define MODELINE       02              /* this is a modeline */
+#define L_MOD          04              /* line has been modified internally */
+
+#define makedirty(line)        { (line)->l_dline |= DIRTY; }
+#define isdirty(line)  ((line)->l_dline & DIRTY)
+
+struct scrimage {
+       int     s_offset,       /* offset to start printing at */
+               s_flags,        /* various flags */
+               s_id,           /* which buffer line */
+               s_vln;          /* Visible Line Number */
+       Line    *s_lp;          /* so we can turn off red bit */
+       Window  *s_window;      /* window that contains this line */
+};
+
+extern struct scrimage
+       *DesiredScreen,         /* what we want */
+       *PhysScreen;            /* what we got */
+
+extern bool
+       UpdModLine,     /* whether we want to update the mode line */
+       UpdMesg;        /* update the message line */
+
+extern int
+       chkmail proto((int force)),
+       calc_pos proto((char *lp,int c_char));
+
+extern void
+       disp_opt_init proto((void)),
+       ChkWindows proto((struct line *line1,struct line *line2)),
+       ChkWinLines proto((void)),
+       DrawMesg proto((bool abortable)),
+       TOstart proto((char *name, bool auto_newline)),
+       TOstop proto((void)),
+       Typeout proto((char *, ...)),
+       rbell proto((void)),
+       redisplay proto((void));
+
+extern int
+       DisabledRedisplay;
+
+#ifdef ID_CHAR
+extern bool
+       IN_INSmode;
+
+extern int
+       IMlen;
+
+extern void
+       INSmode proto((bool));
+#endif /* ID_CHAR */
diff --git a/usr/src/contrib/jove-4.14.6/doc/README b/usr/src/contrib/jove-4.14.6/doc/README
new file mode 100644 (file)
index 0000000..0af2336
--- /dev/null
@@ -0,0 +1,6 @@
+To create the jove manual (as opposed to the man pages)
+just do "nroff -ms jove.[12345]" (or ditroff or troff).
+That should do the trick.  The man pages will be installed
+automatically by "make install" in the previous directory.
+And the online/run-time documentation will be installed
+automatically, too.
diff --git a/usr/src/contrib/jove-4.14.6/doc/cmds.doc b/usr/src/contrib/jove-4.14.6/doc/cmds.doc
new file mode 100644 (file)
index 0000000..fc8faa9
--- /dev/null
@@ -0,0 +1,1821 @@
+Alphabetical List of Commands and Variables
+
+:entry "abort-char" "Variable"
+This variable defines JOVE'S abort characer.  When the abort character
+is typed, the current JOVE command is aborted.  The default value is
+C-G.
+
+:entry "add-lisp-special" "Command"
+This command is to tell JOVE what identifiers require special
+indentation in lisp mode.  Lisp functions like defun and let are two
+of the default functions that get treated specially.  This is just a
+kludge to define some of your own.  It prompts for the function name.
+
+:entry "allow-^S-and-^Q" "Variable"
+This variable, when set, tells JOVE that your terminal does not need
+to use the characters C-S and C-Q for flow control, and that it is
+okay to bind things to them.  This variable should be set depending
+upon what kind of terminal you have.
+
+:entry "allow-bad-filenames" "Variable"
+If set, this variable permits filenames to contain "bad" characters
+such as those from the set *&%!"`[]{}.  These files are harder to deal
+with, because the characters mean something to the shell.  The default
+value is "off".
+
+:entry "append-region" "Command"
+This appends the region to a specified file.  If the file does not
+already exist it is created.
+
+:entry "apropos" "Command"
+This types out all the commands, variables and macros with the
+specific keyword in their names.  For each command and macro that
+contains the string, the key sequence that can be used to execute the
+command or macro is printed; with variables, the current value is
+printed.  So, to find all the commands that are related to windows,
+you type
+
+     ESC X apropos window<Return>
+
+
+:entry "auto-case-abbrev" "Variable"
+When this variable is on (the default), word abbreviations are
+adjusted for case automatically.  For example, if "jove" were the
+abbreviation for "jonathan's own version of emacs", then typing "jove"
+would give you "jonathan's own version of emacs", typing "Jove" would
+give you "Jonathan's own version of emacs", and typing "JOVE" would
+give you "Jonathan's Own Version of Emacs".  When this variable is
+"off", upper and lower case are distinguished when looking for the
+abbreviation, i.e., in the example above, "JOVE" and "Jove" would not
+be expanded unless they were defined separately.
+
+:entry "auto-execute-command" "Command"
+This tells JOVE to execute a command automatically when a file whose
+name matches a specified pattern is visited.  The first argument is
+the command you want executed and the second is a regular expression
+pattern that specifies the files that apply.  For example, if you want
+to be in show-match-mode when you edit C source files (that is, files
+that end with ".c" or ".h") you can type
+
+     ESC X auto-execute-command show-match-mode .*.[ch]$
+
+
+:entry "auto-execute-macro" "Command"
+This is like "auto-execute-command" except you use it to execute
+macros automatically instead of built-in commands.
+
+:entry "auto-fill-mode" "Command"
+This turns on Auto Fill mode (or off if it's currently on) in the
+selected buffer.  When JOVE is in Auto Fill mode it automatically
+breaks lines for you when you reach the right margin so you don't have
+to remember to hit Return.  JOVE uses 78 as the right margin but you
+can change that by setting the variable "right-margin" to another
+value.  See the "set" command to learn how to do this.
+
+:entry "auto-indent-mode" "Command"
+This turns on Auto Indent mode (or off if it's currently on) in the
+selected buffer.  When JOVE is in Auto Indent mode, Return indents the
+new line to the same position as the line you were just on.  This is
+useful for lining up C code (or any other language (but what else is
+there besides C?)).  This is out of date because of the new command
+called "newline-and-indent" but it remains because of several
+"requests" on the part of, uh, enthusiastic and excitable users, that
+it be left as it is.
+
+:entry "background-color" "Variable"
+This specifies the background color of the screen (PC version only).
+The default value is 0, which stands for black.
+
+:entry "backward-character" "Command"
+This moves point backward over a single character.  If point is at the
+beginning of the line it moves to the end of the previous line.
+
+:entry "backward-list" "Command"
+This moves backward over a list as opposed to an s-expression.  The
+difference between this and "backward-s-expression" is that this first
+searchs for a ")" and then moves to the matching "(".  This is useful
+when you're trying to find unmatched parens in a program.
+
+:entry "backward-paragraph" "Command"
+This moves point backward to the beginning of the current or previous
+paragraph.  Paragraphs are bounded by lines that begin with a Period
+or Tab, or by blank lines; a change in indentation may also signal a
+break between paragraphs, except that JOVE allows the first line of a
+paragraph to be indented differently from the other lines.
+
+:entry "backward-s-expression" "Command"
+This moves point backward over a s-expression.  It is just like
+"forward-s-expression" with a negative argument.
+
+:entry "backward-sentence" "Command"
+This moves point backward to the beginning of the current or previous
+sentence.  JOVE considers the end of a sentence to be the characters
+".", "!" or "?" followed by a Return or by one or more spaces.
+
+:entry "backward-up-list" "Command"
+This is similar to "backward-s-expression" except it backs up and OUT
+of the enclosing s-expression.  In other words, it moves backward to
+the "(" that would match a ")" if you were to type it right then.
+
+:entry "backward-word" "Command"
+This moves point backward to the beginning of the current or previous
+word.
+
+:entry "bad-filename-extensions" "Variable"
+This contains a list of words separated by spaces which are to be
+considered bad filename extensions, and so will not be counted in
+filename completion.  The default is ".o" so if you have jove.c and
+jove.o in the same directory, the filename completion will not
+complain of an ambiguity because it will ignore jove.o.
+
+:entry "begin-kbd-macro" "Command"
+This starts defining the keyboard macro by remembering all your key
+strokes until you execute "end-kbd-macro," by typing "C-X )".  Because
+of a bug in JOVE you shouldn't terminate the macro by typing "ESC X
+end-kbd-macro"; "end-kbd-macro" must be bound to "C-X )" in order to
+make things work correctly.  To execute the remembered key strokes you
+type "C-X E" which runs the "execute-kbd-macro" command.  Sometimes
+you may want a macro to accept different input each time it runs.  To
+see how to do this, see the "make-macro-interactive" command.
+
+:entry "beginning-of-file" "Command"
+This moves point backward to the beginning of the buffer.  This
+sometimes prints the "Point Pushed" message.  If the top of the buffer
+isn't on the screen JOVE will set the mark so you can go back to where
+you were if you want.
+
+:entry "beginning-of-line" "Command"
+This moves point to the beginning of the current line.
+
+:entry "beginning-of-window" "Command"
+This moves point to the beginning of the current window.  The sequence
+"ESC ," is the same as "ESC <" (beginning of file) except without the
+shift key on the "<", and can thus can easily be remembered.
+
+:entry "bind-keymap-to-key" "Command"
+This is the way to build nested keymaps.  For example, when JOVE
+starts up, internally it does a
+
+     bind-keymap-to-key ESC-map ^[
+
+To make the arrow keys on vt100's work, you would do the following.
+
+     make-keymap vt100-map
+     bind-keymap-to-key vt100-map ^[[
+     bind-to-key next-line ^[[A
+     bind-to-key previous-line ^[[B
+     bind-to-key forward-character ^[[C
+     bind-to-key backward-character ^[[D
+
+I may have gotten the escape sequences wrong, but you get the general
+idea.  Theoretically you can use these keymaps to bind arbitrarily
+long key sequences, like those generated by the SUN keyboards, but
+that is a bit of a pain because you will have to generate a bunch of
+keymaps by hand, almost one per key, because of the way the key
+sequences are organized.  Eventually there will be a more general way
+to have these keymaps built for you.
+
+:entry "bind-macro-to-key" "Command"
+This is like "bind-to-key" except you use it to attach keys to named
+macros.
+
+:entry "bind-macro-to-word-abbrev" "Command"
+This command allows you to bind a macro to a previously defined word
+abbreviation.  Whenever you type the abbreviation, it will first be
+expanded as an abbreviation, and then the macro will be executed.
+Note that if the macro moves around, you should set the mark first
+(C-@) and then exchange the point and mark last (C-X C-X).
+
+:entry "bind-to-key" "Command"
+This attaches a key to an internal JOVE command so that future hits on
+that key invoke that command.  For example, to make "C-W" erase the
+previous word, you type "ESC X bind-to-key kill-previous-word C-W".
+
+:entry "buffer-position" "Command"
+This displays the current file name, current line number, total number
+of lines, percentage of the way through the file, and the position of
+the cursor in the current line.
+
+:entry "c-argument-indentation" "Variable"
+This variable describes how to indent lines which are part of nested
+expressions in C.  The default is -1, which means to indent a
+continued line by lining it up with the first argument of the current
+expression.  Otherwise, the line will be indented by c-argument-
+indentation characters past the indent of the first line of the
+expression.  For example, the default value produces:
+                Typeout(fmt, itoa(bcount++), line_cnt(b, nbuf),
+                        TypeNames[b->b_type],
+                        IsModified(b) ? "*" : b->b_ntbf ? "+" : NullStr,
+                        buf_width, b->b_name, filename(b));
+
+:entry "c-indentation-increment" "Variable"
+This defines a set of tabstops independent of the value of internal-
+tabstops and physical-tabstops.  This value will be used in C mode,
+and JOVE will insert the correct number of spaces and Tabs to get the
+right behavior.  For programmers that like to indent with 4 spaces,
+set this value to 4.  Don't set internal-tabstops to 4 because that
+will not work anymore.  Setting internal-tabstops to 4 tells JOVE to
+display Tabs as every 4 spaces.  This will cause your programs to look
+terrible with anyone else who displays the file with normal tabstops
+at every 8 characters.  Not to mention printing your program won't
+look right.  But all that aside, if you set c-indentation-increment to
+8 (the default), and then set internal-tabstops to 4 as well, JOVE
+will insert TWO Tabs to get the indentation to 8, which is clearly not
+what you want.
+
+:entry "c-mode" "Command"
+This turns on C mode in the currently selected buffer.  This is one of
+currently four possible major modes:  Fundamental, Text, C, Lisp.
+When in C or Lisp mode, Tab, "}", and ")" behave a little differently
+from usual: They are indented to the "right" place for C (or Lisp)
+programs.  In JOVE, the "right" place is simply the way the author
+likes it (but I've got good taste).
+
+:entry "case-character-capitalize" "Command"
+This capitalizes the character after point, i.e., the character under
+the cursor.  If a negative argument is supplied that many characters
+"before" point are upper cased.
+
+:entry "case-ignore-search" "Variable"
+This variable, when set, tells JOVE to treat upper and lower case as
+the same when searching.  Thus "jove" and "JOVE" would match, and
+"JoVe" would match either.  The default value of this variable is
+"off".
+
+:entry "case-region-lower" "Command"
+This changes all the upper case letters in the region to their lower
+case equivalent.
+
+:entry "case-region-upper" "Command"
+This changes all the lower case letters in the region to their upper
+case equivalent.
+
+:entry "case-word-capitalize" "Command"
+This capitalizes the current word by making the current letter upper
+case and making the rest of the word lower case.  Point is moved to
+the end of the word.  If point is not positioned on a word it is first
+moved forward to the beginning of the next word.  If a negative
+argument is supplied that many words "before" point are capitalized.
+This is useful for correcting the word just typed without having to
+move point to the beginning of the word yourself.
+
+:entry "case-word-lower" "Command"
+This lower-cases the current word and leaves point at the end of it.
+If point is in the middle of a word the rest of the word is converted.
+If point is not in a word it is first moved forward to the beginning
+of the next word.  If a negative argument is supplied that many words
+"before" point are converted to lower case.  This is useful for
+correcting the word just typed without having to move point to the
+beginning of the word yourself.
+
+:entry "case-word-upper" "Command"
+This upper-cases the current word and leaves point at the end of it.
+If point is in the middle of a word the rest of the word is converted.
+If point is not in a word it is first moved forward to the beginning
+of the next word.  If a negative argument is supplied that many words
+"before" point are converted to upper case.  This is useful for
+correcting the word just typed without having to move point to the
+beginning of the word yourself.
+
+:entry "cd" "Command"
+This changes the current directory.
+
+:entry "character-to-octal-insert" "Command"
+This inserts a Back-slash followed by the ascii value of the next
+character typed.  For example, "C-G" inserts the string "\007".
+
+:entry "clear-and-redraw" "Command"
+This clears the entire screen and redraws all the windows.  Use this
+when JOVE gets confused about what's on the screen, or when the screen
+gets filled with garbage characters or output from another program.
+
+:entry "comment-format" "Variable"
+This variable tells JOVE how to format your comments when you run the
+command "fill-comment."  Its format is this:
+
+     <open pattern>%!<line header>%c<line trailer>%!<close pattern>
+
+The %!, %c, and %! must appear in the format; everything else is
+optional.  A newline (represented by %n) may appear in the open or
+close patterns.  %% is the representation for %.  The default comment
+format is for C comments.  See "fill-comment" for more.
+
+:entry "compile-it" "Command"
+This compiles your program by running the UNIX command "make" into a
+buffer, and automatically parsing the error messages that are created
+(if any).  See the "parse-errors" command.  To compile a C program
+without "make", use "C-U C-X C-E" and JOVE will prompt for a command
+to run instead of make.  (And then the command you type will become
+the default command.)  You can use this to parse the output from the C
+compiler or the "grep" or "lint" programs.  See also "error-format-
+string" to make it possible to parse errors of a different format.
+
+:entry "continue-process" "Command"
+This sends SIGCONT to the current interactive process, "if" the
+process is currently stopped.
+
+:entry "copy-region" "Command"
+This takes all the text in the region and copies it onto the kill ring
+buffer.  This is just like running "kill-region" followed by the
+"yank" command.  See the "kill-region" and "yank" commands.
+
+:entry "current-error" "Command"
+This moves to the current error in the list of parsed errors.  See the
+"next-error" and "previous-error" commands for more detailed
+information.
+
+:entry "date" "Command"
+This prints the date on the message line.
+
+:entry "dbx-format-string" "Variable"
+This is the default regular-expression search string used by JOVE to
+parse output from dbx running in a shell process.  The default format
+string works when you type "where" or while you're stepping through a
+program, or when you reach a breakpoint.  You shouldn't have to change
+this unless you are using gdb or some other symbolic debugger.
+
+:entry "define-global-word-abbrev" "Command"
+This defines a global abbreviation.
+
+:entry "define-macro" "Command"
+This provides a different mechanism for defining keyboard macros.
+Instead of gathering keystrokes and storing them into the "keyboard-
+macro" (which is how "start-kbd-macro" works), "define-macro" prompts
+for a macro name (terminated with Space, or Newline) and then for the
+actual macro body.  If you wish to specify control characters in the
+macro, you may simply insert them (using the "quoted-insert" command)
+or by inserting the character '^' followed by the appropriate letter
+for that character (e.g., ^A would be the two characters '^' followed
+by 'A').  You may use Back-slash to prevent the '^' from being
+interpreted as part of a control character when you really wish to
+insert one (e.g., a macro body "\^foo" would insert the string "^foo"
+into the buffer, whereas the body "^foo" would be the same as typing
+^F and then inserting the string "oo").  See "write-macros-to-file" to
+see how to save macros.
+
+:entry "define-mode-word-abbrev" "Command"
+This defines a mode-specific abbreviation.
+
+:entry "delete-blank-lines" "Command"
+This deletes all the blank lines around point.  This is useful when
+you previously opened many lines with "C-O" and now wish to delete the
+unused ones.
+
+:entry "delete-buffer" "Command"
+This deletes a buffer and frees up all the memory associated with it.
+Be careful(!) - once a buffer has been deleted it is gone forever.
+JOVE will ask you to confirm if you try to delete a buffer that needs
+saving.  This command is useful for when JOVE runs out of space to
+store new buffers.
+
+:entry "delete-current-window" "Command"
+This deletes the current window and moves point into one of the
+remaining ones.  It is an error to try to delete the only remaining
+window.
+
+:entry "delete-macro" "Command"
+This deletes a macro from the list of named macros.  It is an error to
+delete the keyboard-macro.  Once the macro is deleted it is gone
+forever.  If you are about to save macros to a file and decide you
+don't want to save a particular one, delete it.
+
+:entry "delete-next-character" "Command"
+This deletes the character that's just after point (that is, the
+character under the cursor).  If point is at the end of a line, the
+line separator is deleted and the next line is joined with the current
+one.
+
+:entry "delete-other-windows" "Command"
+This deletes all the other windows except the current one.  This can
+be thought of as going back into One Window mode.
+
+:entry "delete-previous-character" "Command"
+This deletes the character that's just before point (that is, the
+character before the cursor).  If point is at the beginning of the
+line, the line separator is deleted and that line is joined with the
+previous one.
+
+:entry "delete-white-space" "Command"
+This deletes all the Tabs and Spaces around point.
+
+:entry "describe-bindings" "Command"
+This types out a list containing each bound key and the command that
+gets invoked every time that key is typed.  To make a wall chart of
+JOVE commands, set "send-typeout-to-buffer" to "on" and JOVE will
+store the key bindings in a buffer which you can save to a file and
+then print.
+
+:entry "describe-command" "Command"
+This prints some info on a specified command.
+
+:entry "describe-key" "Command"
+This waits for you to type a key and then tells the name of the
+command that gets invoked every time that key is hit.  Once you have
+the name of the command you can use the "describe-command" command to
+find out exactly what it does.
+
+:entry "describe-variable" "Command"
+This prints some info on a specified variable.
+
+:entry "digit" "Command"
+This reads a numeric argument.  When you type "ESC" followed by a
+number, "digit" keeps reading numbers until you type some other
+command.  Then that command is executes with the numeric argument you
+specified.
+
+:entry "digit-1" "Command"
+This pretends you typed "ESC 1".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-2" "Command"
+This pretends you typed "ESC 2".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-3" "Command"
+This pretends you typed "ESC 3".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-4" "Command"
+This pretends you typed "ESC 4".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-5" "Command"
+This pretends you typed "ESC 5".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-6" "Command"
+This pretends you typed "ESC 6".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-7" "Command"
+This pretends you typed "ESC 7".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-8" "Command"
+This pretends you typed "ESC 8".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-9" "Command"
+This pretends you typed "ESC 9".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "digit-0" "Command"
+This pretends you typed "ESC 0".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+
+:entry "dirs" "Command"
+This prints out the directory stack.  See the "cd", "pushd", "popd"
+commands for more info.
+
+:entry "disable-biff" "Variable"
+When this is set, JOVE disables biff when you're editing and enables
+it again when you get out of JOVE, or when you pause to the parent
+shell or push to a new shell. (This means arrival of new mail will not
+be immediately apparent but will not cause indiscriminate writing on
+the display). The default is "off".
+
+:entry "display-bad-filenames" "Variable"
+This variable affects only filename completion, in particular, what
+happens when "?" is typed while prompting for a file.  When this
+variable is ON, any files that end with one of the extensions defined
+by the variable "bad-filename-extensions" will be displayed with an
+"!" in front of their names.  When "display-bad-filenames" is OFF the
+files will not be displayed at all.  The default value is on.
+
+:entry "down-list" "Command"
+This is the opposite of "backward-up-list."  It's not clear to me that
+this command serves any useful purpose in life.  Try it out, and let
+me know what you think.
+
+:entry "dstop-process" "Command"
+Send the "dsusp" character to the current process.  This is the
+character that suspends a process on the next read from the terminal.
+Most people have it set to C-Y.  This only works if you have the
+interactive process feature, and if you are in a buffer bound to a
+process.
+
+:entry "edit-word-abbrevs" "Command"
+This creates a buffer with a list of each abbreviation and the phrase
+it expands into, and enters a recursive edit to let you change the
+abbreviations or add some more.  The format of this list is
+"abbreviation:phrase" so if you add some more you should follow that
+format.  It's probably simplest just to copy some already existing
+abbreviations and edit them.  When you are done you type "C-X C-C" to
+exit the recursive edit.
+
+:entry "end-kbd-macro" "Command"
+This stops the definition of the keyboard macro.  Because of a bug in
+JOVE, this must be bound to "C-X )", or some key sequence which is one
+or two characters long.  Anything else will not work properly.
+
+:entry "end-of-file" "Command"
+This moves point forward to the end of the buffer.  This sometimes
+prints the "Point Pushed" message.  If the end of the buffer isn't on
+the screen JOVE will set the mark so you can go back to where you were
+if you want.
+
+:entry "end-of-line" "Command"
+This moves point to the end of the current line.  If the line is too
+long to fit on the screen JOVE will scroll the line to the left to
+make the end of the line visible.  The line will slide back to its
+normal position when you move backward past the leftmost visible
+character or when you move off the line altogether.
+
+:entry "end-of-window" "Command"
+This moves point to the last character in the window.
+
+:entry "eof-process" "Command"
+Sends EOF to the current interactive process.  This only works on
+versions of JOVE running under versions of UNIX with pty's.
+
+:entry "erase-buffer" "Command"
+This erases the contents of the specified buffer.  This is like
+"delete-buffer" except it only erases the contents of the buffer, not
+the buffer itself.  If you try to erase a buffer that needs saving you
+will be asked to confirm it.
+
+:entry "error-format-string" "Variable"
+This is the error format string that is used by "parse-errors" to find
+the error messages in a buffer.  The way it works is by using this
+string as a JOVE regular expression search string, where the \('s and
+\)'s regular expression operators are used to pick out the file name
+and line number from the line containing an error message.  For
+instance, a typical error message might look like this:
+
+        "file.c", line 540: missing semi-colon
+
+For strings of this format, an appropriate value for "error-format-
+string" would be something like this:
+
+        ^"\([^"]*\)", line \([0-9]*\):
+
+What this means is, to find an error message, search for a line
+beginning with a double-quote.  Then it says that all the following
+characters up to another double-quote should be remembered as one
+unit, namely the filename that the error is in (that's why the first
+set of parens are surrounding it).  Then it says that after the
+filename there will be the string ", line " followed by a line number,
+which should be remembered as a single unit (which is why the second
+set of parens is around that).  The only constraints on the error
+messages is that the file name and line number appear on the same
+line, and that the file name appears before the line number.  Most
+compilers seem to do this anyway, so this is not an unreasonable
+restriction.
+
+If you do not know how to use regular expressions then this variable
+will be hard for you to use.  Also note that you can look at the
+default value of this variable by printing it out, but it is a really
+complicated string because it is trying to accommodate the outputs of
+more than one compiler at a time.
+
+:entry "error-window-size" "Variable"
+This is the percentage of the screen to use for the error-window on
+the screen.  When you execute "compile-it," "error-window-size"
+percent of the screen will go to the error window.  If the window
+already exists and is a different size, it is made to be this size.
+The default value is 20%.
+
+:entry "exchange-point-and-mark" "Command"
+This moves point to mark and makes mark the old point.  This is for
+quickly moving from one end of the region to another.
+
+:entry "execute-kbd-macro" "Command"
+This executes the keyboard macro.  If you supply a numeric argument
+the macro is executed that many times.
+
+:entry "execute-macro" "Command"
+This executes a specified macro.  If you supply a numeric argument the
+macro is executed that many times.
+
+:entry "execute-named-command" "Command"
+This is the way to execute a command that isn't bound to any key.
+When you are prompted with ": " you can type the name of the command.
+You don't have to type the entire name.  Once the command is
+unambiguous you can type Space and JOVE will fill in the rest for you.
+If you are not sure of the name of the command, type "?" and JOVE will
+print a list of all the commands that you could possibly match given
+what you've already typed.  If you don't have any idea what the
+command's name is but you know it has something to do with windows
+(for example), you can do "ESC X apropos window" and JOVE will print a
+list of all the commands that are related to windows.  If you find
+yourself constantly executing the same commands this way you probably
+want to bind them to keys so that you can execute them more quickly.
+See the "bind-to-key" command.
+
+:entry "exit-jove" "Command"
+This exits JOVE.  If any buffers need saving JOVE will print a warning
+message and ask for confirmation.  If you leave without saving your
+buffers all your work will be lost.  If you made a mistake and really
+do want to exit then you can.  If you are in a recursive editing level
+"exit-jove" will return you from that.
+
+:entry "expand-environment-variables" "Variable"
+When this variable is on JOVE will try to expand any strings of the
+form "$var" into the value of the environment variable "var" when in
+the minibuffer.  For example, if you type $HOME/.joverc, "$HOME" will
+be replaced with you home directory.  The default value is off.
+
+:entry "file-creation-mode" "Variable"
+This variable has an octal value.  It contains the mode (see
+"chmod(1)" ) with which files should be created.  This mode gets
+modified by your current umask setting (see "umask(1)" ).  The default
+value is usually "0666" or "0644."
+
+:entry "files-should-end-with-newline" "Variable"
+This variable indicates that all files should always have a newline at
+the end.  This is often necessary for line printers and the like.
+When set, if JOVE is writing a file whose last character is not a
+newline, it will add one automatically.
+
+:entry "fill-comment" "Command"
+This command fills in your C comments to make them pretty and
+readable.  This filling is done according the variable "comment-
+format."
+
+     /*
+      * the default format makes comments like this.
+      */
+
+This can be changed by changing the format variable.  Other languages
+may be supported by changing the format variable appropriately.  The
+formatter looks backwards from dot for an open comment symbol.  If
+found, all indentation is done relative the position of the first
+character of the open symbol.  If there is a matching close symbol,
+the entire comment is formatted.  If not, the region between dot and
+the open symbol is reformatted.
+
+:entry "fill-paragraph" "Command"
+This rearranges words between lines so that all the lines in the
+current paragraph extend as close to the right margin as possible,
+ensuring that none of the lines will be greater than the right margin.
+The default value for "right-margin" is 78, but can be changed with
+the "set" and "right-margin-here" commands.  JOVE has a complicated
+algorithm for determining the beginning and end of the paragraph.  In
+the normal case JOVE will give all the lines the same indent as they
+currently have, but if you wish to force a new indent you can supply a
+numeric argument to "fill-paragraph" (e.g., by typing C-U ESC J) and
+JOVE will indent each line to the column specified by the "left-
+margin" variable.  See also the "left-margin" variable and "left-
+margin-here" command.
+
+:entry "fill-region" "Command"
+This is like "fill-paragraph," except it operates on a region instead
+of just a paragraph.
+
+:entry "filter-region" "Command"
+This sends the text in the region to a UNIX command, and replaces the
+region with the output from that command.  For example, if you are
+lazy and don't like to take the time to write properly indented C
+code, you can put the region around your C file and "filter-region" it
+through "cb," the UNIX C beautifier.  If you have a file that contains
+a bunch of lines that need to be sorted you can do that from inside
+JOVE too, by filtering the region through the "sort" UNIX command.
+Before output from the command replaces the region JOVE stores the old
+text in the kill ring, so if you are unhappy with the results you can
+easily get back the old text with "C-Y".
+
+:entry "find-file" "Command"
+This visits a file into its own buffer and then selects that buffer.
+If you've already visited this file in another buffer, that buffer is
+selected.  If the file doesn't yet exist, JOVE will print "(New file)"
+so that you know.
+
+:entry "find-tag" "Command"
+This finds the file that contains the specified tag.  JOVE looks up
+tags by default in the "tags" file in the current directory.  You can
+change the default tag name by setting the "tag-file" variable to
+another name.  If you specify a numeric argument to this command, you
+will be prompted for a tag file.  This is a good way to specify
+another tag file without changing the default.  If the tag cannot be
+found the error is reported and point stays where it is.
+
+:entry "find-tag-at-point" "Command"
+This finds the file that contains the tag that point is currently on.
+See "find-tag."
+
+:entry "first-non-blank" "Command"
+This moves point back to the indent of the current line.
+
+:entry "foreground-color" "Variable"
+This specifies the foreground color of the screen (PC version only).
+The default is 1, which stands for white.  The attribute used for
+writing to the screen is formed by (bg&7)<<4 & (fg&7).
+
+:entry "forward-character" "Command"
+This moves forward over a single character.  If point is at the end of
+the line it moves to the beginning of the next one.
+
+:entry "forward-list" "Command"
+This is like "forward-s-expression" except it moves over lists ONLY.
+What this does is search for the next "(" and then move to the
+matching ")".  This is useful for when you are trying to find
+mismatched parentheses in a program.
+
+:entry "forward-paragraph" "Command"
+This moves point forward to the end of the current or next paragraph.
+Paragraphs are bounded by lines that begin with a Period or Tab, or by
+blank lines; a change in indentation may also signal a break between
+paragraphs, except that JOVE allows the first line of a paragraph to
+be indented differently from the other lines.
+
+:entry "forward-s-expression" "Command"
+This moves point forward over a s-expression.  If the first
+significant character after point is "(", this moves past the matching
+")".  If the character begins an identifier, this moves just past it.
+This is mode dependent, so this will move over atoms in LISP mode and
+C identifiers in C mode.  JOVE also matches "{".
+
+:entry "forward-sentence" "Command"
+This moves point forward to the end of the current or next sentence.
+JOVE considers the end of a sentence to be the characters ".", "!" or
+"?" followed by a Return, or one or more spaces.
+
+:entry "forward-word" "Command"
+This moves point forward to the end of the current or next word.
+
+:entry "fundamental-mode" "Command"
+This sets the major mode to Fundamental.  This affects what JOVE
+considers as characters that make up words.  For instance, Single-
+quote is not part of a word in Fundamental mode, but is in Text mode.
+
+:entry "gather-numeric-argument" "Command"
+This command is one of two ways to specify a numeric argument to a
+command.  It's usually bound to C-U.  Typing C-U once means, Do the
+next command 4 times.  Typing C-U twice will do the next command 16
+times, and so on.  If at any point you type a number, then that number
+will be used instead of 4.  For instance, C-U 3 5 means do the next
+command 35 times.
+
+:entry "goto-line" "Command"
+If a numeric argument is supplied point moves to the beginning of that
+line.  If no argument is supplied one is prompted for.
+
+:entry "goto-window-with-buffer" "Command"
+This command prompts for a buffer name and then selects that buffer.
+If the buffer is currently being displayed in one of the windows, that
+window is selected instead.
+
+:entry "grind-s-expr" "Command"
+When point is positioned on a "(", this re-indents that LISP
+expression.
+
+:entry "grow-window" "Command"
+This makes the current window one line bigger.  This only works when
+there is more than one window and provided there is room to change the
+size.
+
+:entry "handle-tab" "Command"
+This handles indenting to the "right" place in C and Lisp mode, and
+just inserts itself in Text mode.
+
+:entry "i-search-forward" "Command"
+Incremental search.  Like search-forward except that instead of
+prompting for a string and searching for that string all at once, it
+accepts the string one character at a time.  After each character you
+type as part of the search string, it searches for the entire string
+so far.  When you like what it found, type the Return key to finish
+the search.  You can take back a character with DEL and the search
+will back up to the position before that character was typed.  C-G
+aborts the search.
+
+:entry "i-search-reverse" "Command"
+Incremental search.  Like search-reverse except that instead of
+prompting for a string and searching for that string all at once, it
+accepts the string one character at a time.  After each character you
+type as part of the search string, it searches for the entire string
+so far.  When you like what it found, type the Return key to finish
+the search.  You can take back a character with DEL and the search
+will back up to the position before that character was typed.  C-G
+aborts the search.
+
+:entry "i-shell-command" "Command"
+This is like "shell-command" except it lets you continue with your
+editing while the command is running.  This is really useful for long
+running commands with sporadic output.  See the manual for information
+on how to use interactive processes.
+
+:entry "insert-file" "Command"
+This inserts a specified file into the current buffer at point.  Point
+is positioned at the beginning of the inserted file.
+
+:entry "internal-tabstop" "Variable"
+The number of spaces JOVE should print when it displays a tab
+character.  The default value is 8.
+
+:entry "interrupt-character" "Variable"
+This is set to the character that interrupts JOVE (with a signal) no
+matter what JOVE is doing.  It's main use is for interrupting non-
+interactive processes, but it also has uses for debugging.
+Unfortunately there is no way to turn off the interrupt character.
+
+:entry "interrupt-process" "Command"
+This sends the interrupt character (usually C-C) to the interactive
+process in the current buffer.  This is only for versions of JOVE that
+have the interactive processes feature.  This only works when you are
+inside a buffer that's attached to a process.
+
+:entry "kill-next-word" "Command"
+This kills the text from point to the end of the current or next word.
+
+:entry "kill-previous-word" "Command"
+This kills the text from point to the beginning of the current or
+previous word.
+
+:entry "kill-process" "Command"
+This command prompts for a buffer name or buffer number (just as
+select-buffer does) and then sends the process in that buffer a kill
+signal (9).
+
+:entry "kill-region" "Command"
+This deletes the text in the region and saves it on the kill ring.
+Commands that delete text but save it on the kill ring all have the
+word "kill" in their names.  Type "C-Y" to yank back the most recent
+kill.
+
+:entry "kill-s-expression" "Command"
+This kills the text from point to the end of the current or next s-
+expression.
+
+:entry "kill-some-buffers" "Command"
+This goes through all the existing buffers and asks whether or not to
+kill them.  If you decide to kill a buffer, and it turns out that the
+buffer is modified, JOVE will offer to save it first.  This is useful
+for when JOVE runs out of memory to store lines (this only happens on
+PDP-11's) and you have lots of buffers that you are no longer using.
+
+:entry "kill-to-beginning-of-sentence" "Command"
+This kills from point to the beginning of the current or previous
+sentence.
+
+:entry "kill-to-end-of-line" "Command"
+This kills from point to the end of the current line.  When point is
+at the end of the line the line separator is deleted and the next line
+is joined with current one.  If a numeric argument is supplied that
+many lines are killed; if the argument is negative that many lines
+"before" point are killed; if the argument is zero the text from point
+to the beginning of the line is killed.
+
+:entry "kill-to-end-of-sentence" "Command"
+This kills from point to the end of the current or next sentence.  If
+a negative numeric argument is supplied it kills from point to the
+beginning of the current or previous sentence.
+
+:entry "left-margin" "Variable"
+This is how far lines should be indented when auto-indent mode is on,
+or when the "newline-and-indent" command is run (usually by typing
+LineFeed).  It is also used by fill-paragraph and auto-fill mode.  If
+the value is zero (the default) then the left margin is determined
+from the surrounding lines.
+
+:entry "left-margin-here" "Command"
+This sets the "left-margin" variable to the current position of point.
+This is an easy way to say, "Make the left margin begin here," without
+having to count the number of spaces over it actually is.
+
+:entry "lisp-mode" "Command"
+This turns on Lisp mode.  Lisp mode is one of four mutually exclusive
+major modes: Fundamental, Text, C, and Lisp.  In Lisp mode, the
+characters Tab and ) are treated specially, similar to the way they
+are treated in C mode.  Also, Auto Indent mode is affected, and
+handled specially.
+
+:entry "list-buffers" "Command"
+This types out a list containing various information about each
+buffer.  Right now that list looks like this:
+
+      (* means the buffer needs saving)
+      NO  Lines Type        Name           File
+      --  ----- ----        ----           ----
+      1   1     File        Main           [No file]
+      2   1     Scratch   * Minibuf        [No file]
+      3   519   File      * commands.doc   commands.doc
+
+The first column lists the buffer's number.  When JOVE prompts for a
+buffer name you can either type in the full name, or you can simply
+type the buffer's number.  The second column is the number of lines in
+the buffer.  The third says what type of buffer.  There are four
+types: "File", "Scratch", "Process", "I-Process".  "File" is simply a
+buffer that holds a file; "Scratch" is for buffers that JOVE uses
+internally; "Process" is one that holds the output from a UNIX
+command; "I-Process" is one that has an interactive process attached
+to it.  The next column contains the name of the buffer.  And the last
+column is the name of the file that's attached to the buffer.  In this
+case, both Minibuf and commands.doc have been changed but not yet
+saved.  In fact Minibuf won't be saved since it's an internal JOVE
+buffer that I don't even care about.
+
+:entry "list-processes" "Command"
+This makes a list somewhat like "list-buffers" does, except its list
+consists of the current interactive processes.  Right now the list
+looks like this:
+
+      Buffer           Status           Pid    Command
+      ------           ------           ---    -------
+      *shell*          Running          18415shell
+      fgrep            Done             18512   fgrep -n Buffer *.c
+
+The first column has the name of the buffer to which the process is
+attached.  The second has the status of the process; if a process has
+exited normally the status is "Done" as in fgrep; if the process
+exited with an error the status is "Exit N" where N is the value of
+the exit code; if the process was killed by some signal the status is
+the name of the signal that was used; otherwise the process is
+running.  The last column is the name of the command that is being
+run.
+
+:entry "macify" "Variable"
+When this variable is on, JOVE will use the standard Macintosh file-
+selector dialog in place of the traditional JOVE minibuffer. (Mac
+version only)
+
+:entry "mail-check-frequency" "Variable"
+This is how often (in seconds) JOVE should check your mailbox for
+incoming mail.  If you set this to ZERO JOVE won't check for new mail.
+See also the "mailbox" and "disable-biff" variables.
+
+:entry "mailbox" "Variable"
+Set this to the full pathname of your mailbox.  JOVE will look here to
+decide whether or not you have any unread mail.  This defaults to
+/usr/spool/mail/$USER, where $USER is set to your login name.
+
+:entry "make-backup-files" "Variable"
+If this variable is set, then whenever JOVE writes out a file, it will
+move the previous version of the file (if there was one) to
+"#filename".  This is often convenient if you save a file by accident.
+The default value of this variable is "off".  "Note:" this is an
+optional part of JOVE, and your guru may not have it enabled, so it
+may not work.
+
+:entry "make-buffer-unmodified" "Command"
+This makes JOVE think the selected buffer hasn't been changed even if
+it has.  Use this when you accidentally change the buffer but don't
+want it considered changed.  Watch the mode line to see the *
+disappear when you use this command.
+
+:entry "make-keymap" "Command"
+This creates an empty keymap with a name you supply.  That name can be
+used to reference the keymap in other commands, such as bind-keymap-
+to-key.
+
+:entry "make-macro-interactive" "Command"
+This command is meaningful only while you are defining a keyboard
+macro, and when you are in the minibuffer.  Ordinarily, when a command
+in a macro definition requires a trailing text argument (file name,
+search string, etc.), the argument you supply becomes part of the
+macro definition.  If you want to be able to supply a different
+argument each time the macro is used, then while you are defining it,
+you should give the make-macro-interactive command just before typing
+the argument which will be used during the definition process.  Note:
+you must bind this command to a key in order to use it; you can't say
+"ESC X make-macro-interactive".
+
+:entry "mark-threshold" "Variable"
+This variable contains the number of lines point may move by before
+the mark is set.  If, in a search or something, point moves by more
+than this many lines, the mark is set so that you may return easily.
+The default value of this variable is 22 (one screenful, on most
+terminals).
+
+:entry "marks-should-float" "Variable"
+When this variable is "off", the position of a mark is remembered as a
+line number within the buffer and a character number within the line.
+If you add or delete text before the mark, it will no longer point to
+the text you marked originally because that text is no longer at the
+same line and character number.  When this variable is "on", the
+position of a mark is adjusted to compensate for each insertion and
+deletion.  This makes marks much more sensible to use, at the cost of
+slowing down insertion and deletion somewhat.  The default value is
+"on".
+
+:entry "match-regular-expressions" "Variable"
+When set, JOVE will match regular expressions in search patterns.
+This makes special the characters ., *, [, ], ^, and $, and the two-
+character sequences \<, \>, \{, \} and \|.  See the "ed(1)" manual
+page, the tutorial "Advanced Editing in UNIX", and the section above
+"Searching with Regular Expressions" for more information.
+
+:entry "meta-key" "Variable"
+You should set this variable to "on" if your terminal has a real Meta
+key.  If your terminal has such a key, then a key sequence like ESC Y
+can be entered by holding down Meta and typing Y.  NOTE:  In some
+systems, this disables interrupting noninteractive shell commands.
+
+:entry "mode-line" "Variable"
+The format of the mode line can be determined by setting this
+variable.  The items in the line are specified using a format similar
+to that used by printf(3), with the special things being marked as
+"%x".  Digits may be used between the 'x' may be:
+
+          C    check for new mail, and displays "[New mail]" if there
+               is any (see also the mail-check-interval and disable-biff
+               variables)
+          F    the current file name, with leading path stripped
+          M    the current list of major and minor modes
+          b    the current buffer name
+          c    the fill character (-)
+          d    the current directory
+          e    extra space in modeline is distributed evenly
+               among the places %e is used (used for justifying,
+               separating, or centering parts of the modeline)
+          f    the current file name
+          l    the current load average (updated automatically)
+          mxy  x, when the buffer is modified or y, when not
+          n    the current buffer number
+          p    interactive process status for process windows
+          s    space, but only if previous character is not a space
+          t    the current time (updated automatically)
+          w    a '>' for windows which are scrolled left
+          [ ]  the square brackets printed when in a recursive edit
+          ( )  items enclosed in %( ... %) will only be printed on
+               the bottom mode line, rather than copied when the
+               window is split
+
+In addition, any other character is simply copied into the mode line.
+Characters may be escaped with a backslash.  To get a feel for all
+this, try typing "ESC X print mode-line" and compare the result with
+your current mode line.
+
+:entry "mode-line-color" "Variable"
+This specifies the color of the modeline (PC version only).  Its
+default value is 0, and in that case it is drawn in reverse video.  If
+it has any other value, this value is used as the attribute in the
+Bios calls.
+
+:entry "mode-line-should-standout" "Variable"
+If set, the mode line will be printed in reverse video, if your
+terminal supports it.  The default for this variable is "off".
+
+:entry "name-kbd-macro" "Command"
+This copies the keyboard macro and gives it a name freeing up the
+keyboard macro so you can define some more.  Keyboard macros with
+their own names can be bound to keys just like built in commands can.
+See the "define-macro," "source" and "write-macros-to-file" commands.
+
+:entry "newline" "Command"
+This divides the current line at point moving all the text to the
+right of point down onto the newly created line.  Point moves down to
+the beginning of the new line.
+
+:entry "newline-and-backup" "Command"
+This divides the current line at point moving all the text to the
+right of point down onto the newly created line.  The difference
+between this and "newline" is that point does not move down to the
+beginning of the new line.
+
+:entry "newline-and-indent" "Command"
+This behaves the same was as Return does when in Auto Indent mode.
+This makes Auto Indent mode obsolete but it remains in the name of
+backward compatibility.
+
+:entry "next-error" "Command"
+This moves to the next error in the list of errors that were parsed
+with "parse-errors."  In one window the list of errors is shown with
+the current one always at the top.  In another window is the file that
+contains the error.  Point is positioned in this window on the line
+where the error occurred.
+
+:entry "next-line" "Command"
+This moves down to the next line.
+
+:entry "next-page" "Command"
+This displays the next page of the buffer by taking the bottom line of
+the window and redrawing the window with it at the top.  If there
+isn't another page in the buffer JOVE rings the bell.  If a numeric
+argument is supplied the screen is scrolled up that many lines; if the
+argument is negative the screen is scrolled down.
+
+:entry "next-window" "Command"
+This moves into the next window.  Windows live in a circular list so
+when you're in the bottom window and you try to move to the next one
+you are moved to the top window.  It is an error to use this command
+with only one window.
+
+:entry "number-lines-in-window" "Command"
+This displays the line numbers for each line in the buffer being
+displayed.  The number isn't actually part of the text; it's just
+printed before the actual buffer line is.  To turn this off you run
+the command again; it toggles.
+
+:entry "over-write-mode" "Command"
+This turns Over Write mode on (or off if it's currently on) in the
+selected buffer.  When on, this mode changes the way the self-
+inserting characters work.  Instead of inserting themselves and
+pushing the rest of the line over to the right, they replace or over-
+write the existing character.  Also, DEL replaces the character before
+point with a space instead of deleting it.  When Over Write mode is on
+"OvrWt" is displayed on the mode line.
+
+:entry "page-next-window" "Command"
+This displays the next page in the next window.  This is exactly the
+same as "C-X N C-V C-X P".
+
+:entry "paren-flash" "Command"
+This handles the C mode curly brace indentation, the Lisp mode paren
+indentation, and the Show Match mode paren/curly brace/square bracket
+flashing.
+
+:entry "paren-flash-delay" "Variable"
+How long, in tenths of seconds, JOVE should pause on a matching
+parenthesis in "Show" mode.  The default is 5.
+
+:entry "parse-errors" "Command"
+This takes the list of C compilation errors (or output from another
+program in the same format) in the current buffer and parses them for
+use with the "next-error" and "previous-error" and "current-error"
+commands.  This is a very useful tool and helps with compiling C
+programs and when used in conjunction with the "grep" UNIX command
+very helpful in making changes to a bunch of files.  This command
+understands errors produced by cc, cpp, and lint; plus any other
+program with the same format (e.g., "grep -n").  JOVE visits each file
+that has an error and remembers each line that contains an error.  It
+doesn't matter if later you insert or delete some lines in the buffers
+containing errors; JOVE remembers where they are regardless.
+"current-error" is automatically executed after one of the parse
+commands, so you end up at the first error.  See also "error-format-
+string" to make it possible to parse errors of a different format.
+
+:entry "parse-spelling-errors-in-buffer" "Command"
+This parses a list of words in the current buffer and looks them up in
+another buffer that you specify.  This will probably go away soon.
+
+:entry "pause-jove" "Command"
+This stops JOVE and returns control to the parent shell.  This only
+works for users using the C-shell, and on systems that have the job
+control facility.  To return to JOVE you type "fg" to the C-shell.
+
+:entry "physical-tabstop" "Variable"
+How many spaces your terminal prints when it prints a tab character.
+
+:entry "pop-mark" "Command"
+This gets executed when you run "set-mark" with a numeric argument.
+JOVE remembers the last 16 marks and you use "pop-mark" to go backward
+through the ring of marks.  If you execute "pop-mark" enough times you
+will eventually get back to where you started.
+
+:entry "popd" "Command"
+This pops one entry off the directory stack.  Entries are pushed with
+the "pushd" command.  The names were stolen from the C-shell and the
+behavior is the same.
+
+:entry "previous-error" "Command"
+This is the same as "next-error" except it goes to the previous error.
+See "next-error" for documentation.
+
+:entry "previous-line" "Command"
+This moves up to the previous line.
+
+:entry "previous-page" "Command"
+This displays the previous page of the current buffer by taking the
+top line and redrawing the window with it at the bottom.  If a numeric
+argument is supplied the screen is scrolled down that many lines; if
+the argument is negative the screen is scrolled up.
+
+:entry "previous-window" "Command"
+This moves into the next window.  Windows live in a circular list so
+when you're in the top window and you try to move to the previous one
+you are moved to the bottom window.  It is an error to use this
+command with only one window.
+
+:entry "print" "Command"
+This prints the value of a JOVE variable.
+
+:entry "process-bind-keymap-to-key" "Command"
+This is just like "bind-to-key" except that it starts at the process-
+keymap map, instead of the default mainmap.
+
+:entry "process-bind-to-key" "Command"
+This command is identical to bind-to-key, except that it only affects
+your bindings when you are in a buffer attached to a process.  When
+you enter the process buffer, any keys bound with this command will
+automatically take their new values.  When you switch to a non-process
+buffer, the old bindings for those keys will be restored.  For
+example, you might want to execute
+
+     process-bind-to-key stop-process ^Z
+     process-bind-to-key interrupt-process ^C
+
+Then, when you start up an interactive process and switch into that
+buffer, C-Z will execute stop-process and C-C will execute interrupt-
+process.  When you switch back to a non-process buffer, C-Z will go
+back to executing scroll-up (or whatever you have it bound to).
+
+:entry "process-dbx-output" "Command"
+This command only makes sense in a buffer running a shell process.  If
+you are running dbx in a window, JOVE will automatically find the file
+you are currently stepping through and display it in another window.
+The string DBX will appear in the modeline along with the other minor
+modes when this feature is enabled.
+
+:entry "process-newline" "Command"
+This only gets executed when in a buffer that is attached to an
+interactive-process.  JOVE does two different things depending on
+where you are when you hit Return.  When you're at the end of the I-
+Process buffer this does what Return normally does, except it also
+makes the line available to the process.  When point is positioned at
+some other position that line is copied to the end of the buffer (with
+the prompt stripped) and point is moved there with it, so you can then
+edit that line before sending it to the process.  This command "must"
+be bound to the key you usually use to enter shell commands (Return),
+or else you won't be able to enter any.
+
+:entry "process-prompt" "Variable"
+What a prompt looks like from the shell and i-shell-command processes.
+The default is "% ", the default C-shell prompt.  This is actually a
+regular expression search string.  So you can set it to be more than
+one thing at once using the \| operator.  For instance, for LISP
+hackers, the prompt can be
+
+     "% \|-> \|<[0-9]>: ".
+
+
+:entry "process-send-data-no-return" "Command"
+This is like "process-newline" except it sends everything to the
+process without the newline.  Normally, when you type return in a
+process buffer it sends everything you typed including the Return.
+This command just provides a way to send data to the process without
+having to send a newline as well.
+
+:entry "push-shell" "Command"
+This spawns a child shell and relinquishes control to it.  This works
+on any version of UNIX, but this isn't as good as "pause-jove" because
+it takes time to start up the new shell and you get a brand new
+environment every time.  To return to JOVE you type "C-D".
+
+:entry "pushd" "Command"
+This pushes a directory onto the directory stack and cd's into it.  It
+asks for the directory name but if you don't specify one it switches
+the top two entries no the stack.  It purposely behaves the same as
+C-shell's "pushd."
+
+:entry "pwd" "Command"
+This prints the working directory.
+
+:entry "query-replace-string" "Command"
+This replaces the occurrences of a specified string with a specified
+replacement string.  When an occurrence is found point is moved to it
+and then JOVE asks what to do.  The options are:
+
+     Space to replace this occurrence and go on to the next one.
+     Periodto replace this occurrence and then stop.
+     DEL   to skip this occurrence and go on to the next one.
+     C-R   to enter a recursive edit.  This lets you temporarily
+           suspend the replace, do some editing, and then return
+           to continue where you left off.  To continue with the
+           Query Replace type "C-X C-C" as if you were trying to
+           exit JOVE.  Normally you would but when you are in a
+           recursive edit all it does is exit that recursive
+           editing level.
+     C-W   to delete the matched string and then enter a recursive
+           edit.
+     U     to undo all changes to the last modified line.
+     P or !to go ahead and replace the remaining occurrences without
+           asking.
+     Returnto stop the Query Replace.
+
+The search for occurrences starts at point and goes to the end of the
+buffer, so to replace in the entire buffer you must first go to the
+beginning.
+
+:entry "quit-process" "Command"
+This is the same as typing "C-\" (the Quit character) to a normal UNIX
+process, except it sends it to the current process in JOVE.  This is
+only for versions of JOVE that have the interactive processes feature.
+This only works when you are inside a buffer that's attached to a
+process.
+
+:entry "quoted-insert" "Command"
+This lets you insert characters that normally would be executed as
+other JOVE commands.  For example, to insert "C-F" you type "C-Q C-F".
+
+:entry "read-only-mode" "Command"
+Read-only-mode is a minor mode.  It puts a buffer in read-only mode,
+so that any attempts to modify the buffer fail.  When a file is found,
+and it's not got write permission, JOVE automatically puts the buffer
+in read-only mode.  This is very helpful when you are in environments
+which use source control programs like RCS and SCCS.  It prevents
+accidents like making a bunch of changes and only THEN discovering
+that you haven't checked the file out for making changes.  This, like
+other minor modes, toggles.
+
+:entry "read-word-abbrev-file" "Command"
+This reads a specified file that contains a bunch of abbreviation
+definitions, and makes those abbreviations available.  If the selected
+buffer is not already in Word Abbrev mode this command puts it in that
+mode.
+
+:entry "recursive-edit" "Command"
+This enters a recursive editing level.  This isn't really very useful.
+I don't know why it's available for public use.  I think I'll delete
+it some day.
+
+:entry "redraw-display" "Command"
+This centers the line containing point in the window.  If that line is
+already in the middle the window is first cleared and then redrawn.
+If a numeric argument is supplied, the line is positioned at that
+offset from the top of the window.  For example, "ESC 0 C-L" positions
+the line containing point at the top of the window.
+
+:entry "rename-buffer" "Command"
+This lets you rename the current buffer.
+
+:entry "replace-in-region" "Command"
+This is the same as "replace-string" except that it is restricted to
+occurrences between Point and Mark.
+
+:entry "replace-string" "Command"
+This replaces all occurrences of a specified string with a specified
+replacement string.  This is just like "query-replace-string" except
+it replaces without asking.
+
+:entry "right-margin" "Variable"
+Where the right margin is for "Auto Fill" mode and the "justify-
+paragraph" and "justify-region" commands.  The default is 78.
+
+:entry "right-margin-here" "Command"
+This sets the "right-margin" variable to the current position of
+point.  This is an easy way to say, "Make the right margin begin
+here," without having to count the number of spaces over it actually
+is.
+
+:entry "save-file" "Command"
+This saves the current buffer to the associated file.  This makes your
+changes permanent so you should be sure you really want to.  If the
+buffer has not been modified "save-file" refuses to do the save.  If
+you really do want to write the file you can use "C-X C-W" which
+executes "write-file."
+
+:entry "scroll-all-lines" "Variable"
+When this is turned on, the entire window will be scrolled left or
+right when the current line scrolls.  The default value is OFF, which
+will cause JOVE to behave in the familiar way, namely to scroll only
+the current line.
+
+:entry "scroll-down" "Command"
+This scrolls the screen one line down.  If the line containing point
+moves past the bottom of the window point is moved up to the center of
+the window.  If a numeric argument is supplied that many lines are
+scrolled; if the argument is negative the screen is scrolled up
+instead.
+
+:entry "scroll-left" "Command"
+This scrolls the text in the current window 10 character positions to
+the left.  If a numeric argument is specified then the text is
+scrolled that number of character positions.  If the variable
+"scroll-all-lines" is ON then "scroll-left" may actually do nothing if
+the scrolling would cause Point not to be visible.
+
+:entry "scroll-next-page" "Command"
+This continuously scrolls up screen-full lines (PC version only).
+
+:entry "scroll-previous-page" "Command"
+This continuously scrolls down screen-full lines (PC version only).
+
+:entry "scroll-right" "Command"
+This scrolls the text in the current window 10 character positions to
+the right.  If a numeric argument is specified then the text is
+scrolled that number of character positions.  If the variable
+"scroll-all-lines" is ON then "scroll-right" may actually do nothing
+if the scrolling would cause Point not to be visible.
+
+:entry "scroll-step" "Variable"
+How many lines should be scrolled if the "previous-line" or "next-
+line" commands move you off the top or bottom of the screen.  You may
+wish to decrease this variable if you are on a slow terminal.  The
+default value is 0, which means to center the current line in the
+window.  If the value is negative, the behavior is slightly different.
+If you move off the top of the window, and "scroll-step" is, say, -5
+then the new line will be displayed 5 lines from the bottom of the
+window.  If you move off the bottom of the window, the new line will
+be positioned 5 lines from the top of the window.
+
+:entry "scroll-up" "Command"
+This scrolls the screen one line up.  If the line containing point
+moves past the top of the window point is moved down to the center of
+the window.  If a numeric argument is supplied that many lines are
+scrolled; if the argument is negative the screen is scrolled down
+instead.
+
+:entry "search-exit-char" "Variable"
+Set this to the character you want to use to exit incremental search.
+The default is Newline, which makes i-search compatible with normal
+string search.
+
+:entry "search-forward" "Command"
+This searches forward for a specified search string and positions
+point at the end of the string if it's found.  If the string is not
+found point remains unchanged.  This searches from point to the end of
+the buffer, so any matches before point will be missed.
+
+:entry "search-forward-nd" "Command"
+This is just like "search-forward" except that it doesn't assume a
+default search string, and it doesn't set the default search string.
+This is useful for defining macros, when you want to search for
+something, but you don't want it to affect the current default search
+string.
+
+:entry "search-reverse" "Command"
+This searches backward for a specified search string and positions
+point at the beginning if the string if it's found.  If the string is
+not found point remains unchanged.  This searches from point to the
+beginning of the buffer, so any matches after point will be missed.
+
+:entry "search-reverse-nd" "Command"
+This is just like "search-reverse" except that it doesn't assume a
+default search string, and it doesn't set the default search string.
+This is useful for defining macros, when you want to search for
+something, but you don't want it to affect the current default search
+string.
+
+:entry "select-buffer" "Command"
+This selects a new or already existing buffer making it the current
+one.  You can type either the buffer name or number.  If you type in
+the name you need only type the name until it is unambiguous, at which
+point typing Escape or Space will complete it for you.  If you want to
+create a new buffer you can type Return instead of Space, and a new
+empty buffer will be created.
+
+:entry "select-buffer-1" "Command"
+This selects buffer number 0, if it exists (PC version only).
+
+:entry "select-buffer-1" "Command"
+This selects buffer number 1, if it exists (PC version only).
+
+:entry "select-buffer-2" "Command"
+This selects buffer number 2, if it exists (PC version only).
+
+:entry "select-buffer-3" "Command"
+This selects buffer number 3, if it exists (PC version only).
+
+:entry "select-buffer-4" "Command"
+This selects buffer number 4, if it exists (PC version only).
+
+:entry "select-buffer-5" "Command"
+This selects buffer number 5, if it exists (PC version only).
+
+:entry "select-buffer-6" "Command"
+This selects buffer number 6, if it exists (PC version only).
+
+:entry "select-buffer-7" "Command"
+This selects buffer number 7, if it exists (PC version only).
+
+:entry "select-buffer-8" "Command"
+This selects buffer number 8, if it exists (PC version only).
+
+:entry "select-buffer-9" "Command"
+This selects buffer number 9, if it exists (PC version only).
+
+:entry "self-insert" "Command"
+This inserts the character that invoked it into the buffer at point.
+Initially all but a few of the printing characters are bound to
+"self-insert."
+
+:entry "send-typeout-to-buffer" "Variable"
+When this is set JOVE will send output that normally overwrites the
+screen (temporarily) to a buffer instead.  This affects commands like
+"list-buffers," "list-processes," and commands that use completion.
+The default value is "off".
+
+:entry "set" "Command"
+This gives a specified variable a new value.  Occasionally you'll see
+lines like "set this variable to that value to do this".  Well, you
+use the "set" command to do that.
+
+:entry "set-mark" "Command"
+This sets the mark at the current position in the buffer.  It prints
+the message "Point pushed" on the message line.  It says that instead
+of "Mark set" because when you set the mark the previous mark is still
+remembered on a ring of 16 marks.  So "Point pushed" means point is
+pushed onto the ring of marks and becomes the value of "the mark".  To
+go through the ring of marks you type "C-U C-@", or execute the "pop-
+mark" command.  If you type this enough times you will get back to
+where you started.
+
+:entry "shell" "Variable"
+The shell to be used with all the shell commands command.  If your
+SHELL environment variable is set, it is used as the value of "shell;"
+otherwise "/bin/csh" is the default.
+
+:entry "shell" "Command"
+This starts up an interactive shell in a window.  JOVE uses "*shell*"
+as the name of the buffer in which the interacting takes place.  See
+the manual for information on how to use interactive processes.
+
+:entry "shell-command" "Command"
+This runs a UNIX command and places the output from that command in a
+buffer.  JOVE creates a buffer that matches the name of the command
+you specify and then attaches that buffer to a window.  So, when you
+have only one window running this command will cause JOVE to split the
+window and attach the new buffer to that window.  Otherwise, JOVE
+finds the most convenient of the available windows and uses that one
+instead.  If the buffer already exists it is first emptied, except
+that if it's holding a file, not some output from a previous command,
+JOVE prints an error message and refuses to execute the command.  If
+you really want to execute the command you should delete that buffer
+(saving it first, if you like) or use "shell-command-to-buffer," and
+try again.
+
+:entry "shell-command-no-buffer" "Command"
+This is just like "shell-command" except it just runs the command
+without saving the output to any buffer.  It will report the success
+of the command in the usual way.
+
+:entry "shell-command-to-buffer" "Command"
+This is just like "shell-command" except it lets you specify the
+buffer to use instead of JOVE.
+
+:entry "shell-command-with-typeout" "Command"
+This is just like "shell-command" except that instead of saving the
+output to a buffer, and displaying it in a window, this just types out
+the output in the same way that "list-buffers" does.  Actually, how
+this behaves depends on the value of the variable "send-typeout-to-
+buffer."  If it is on then shell-command-with-typeout will behave just
+like "shell-command."
+
+:entry "shell-flags" "Variable"
+This defines the flags that are passed to shell commands.  The default
+is "-c".  See the "shell" variable to change the default shell.
+
+:entry "shift-region-left" "Command"
+This shifts the region left by c-indentation-increment OR by the
+numeric argument, if one is supplied.  If a negative argument is
+supplied the region is shifted the other way.
+
+:entry "shift-region-right" "Command"
+This shifts the region left by c-indentation-increment OR by the
+numeric argument, if one is supplied.  If a negative argument is
+supplied the region is shifted the other way.
+
+:entry "show-match-mode" "Command"
+This turns on Show Match mode (or off if it's currently on) in the
+selected buffer.  This changes "}", ")" and "]" so that when they are
+typed the are inserted as usual, and then the cursor flashes back to
+the matching "{", "(" or "[" (depending on what was typed) for about
+half a second, and then goes back to just after the "}", ")" or "]"
+that invoked the command.  This is useful for typing in complicated
+expressions in a program.  You can change how long the cursor sits on
+the matching paren by setting the "paren-flash-delay" variable in
+tenths of a second.  If the matching "{", "(" or "[" isn't visible,
+the line containing the match is displayed at the bottom of the
+screen.
+
+:entry "shrink-window" "Command"
+This makes the current window one line shorter, if possible.  Windows
+must be at least 2 lines high, one for the text and the other for the
+mode line.
+
+:entry "source" "Command"
+This reads a bunch of JOVE commands from a file.  The format of the
+file is the same as that in your initialization file (your ".joverc")
+in your main directory.  There should be one command per line and it
+should be as though you typed "ESC X" while in JOVE.  For example,
+here's part of my initialization file:
+
+     bind-to-key i-search-reverse ^R
+     bind-to-key i-search-forward ^S
+     bind-to-key pause-jove ^[S
+
+What they do is make "C-R" call the "i-search-reverse" command and
+"C-S" call "i-search-forward" and "ESC S" call "pause-jove."
+
+:entry "spell-buffer" "Command"
+This runs the current buffer through the UNIX "spell" program and
+places the output in buffer "Spell".  Then JOVE lets you edit the list
+of words, expecting you to delete the ones that you don't care about,
+i.e., the ones you know are spelled correctly.  Then the "parse-
+spelling-errors-in-buffer" command comes along and finds all the
+misspelled words and sets things up so the error commands work.
+
+:entry "split-current-window" "Command"
+This splits the current window into two equal parts (providing the
+resulting windows would be big enough) and displays the selected
+buffer in both windows.  Use "C-X 1" to go back to 1 window mode.  If
+a numeric argument is supplied, the window is split "evenly" that many
+times (when possible).
+
+:entry "start-remembering" "Command"
+This is just another name for the "begin-kbd-macro" name.  It is
+included for backward compatibility.
+
+:entry "stop-process" "Command"
+This sends a stop signal (C-Z, for most people) to the current
+process.  It only works if you have the interactive process feature,
+and you are in a buffer attached to a process.
+
+:entry "stop-remembering" "Command"
+This is just another name for the "end-kbd-macro" command.  It is
+included for backward compatibility.
+
+:entry "string-length" "Command"
+This prints the number of characters in the string that point sits in.
+Strings are surrounded by double quotes.  JOVE knows that "\007" is
+considered a single character, namely "C-G", and also knows about
+other common ones, like "\r" (Return) and "\n" (LineFeed).  This is
+mostly useful only for C programmers.
+
+:entry "suspend-jove" "Command"
+This is a synonym for "pause-jove."
+
+:entry "sync-frequency" "Variable"
+The temporary files used by JOVE are forced out to disk every "sync-
+frequency" modifications.  The default is 50, which really makes good
+sense.  Unless your system is very unstable, you probably shouldn't
+fool with this.
+
+:entry "tag-file" "Variable"
+This the name of the file in which JOVE should look up tag
+definitions.  The default value is "./tags".
+
+:entry "text-mode" "Command"
+This sets the major mode to Text.  Currently the other modes are
+Fundamental, C and Lisp mode.
+
+:entry "tmp-file-pathname" "Variable"
+This tells JOVE where to put the tmp files, which is where JOVE stores
+buffers internally.  The default is usually in /tmp, but if you want
+to store them somewhere else, you can set this variable.  If your
+system crashes a lot it might be a good idea to set this variable to
+somewhere other than /tmp because the system removes all the files in
+/tmp upon reboot, and so you would not be able to recover editor
+buffers using the "jove -r" command.
+
+NOTE: In order for this to work correctly you must set this variable
+BEFORE JOVE creates the tmp file.  You can set this in your .joverc
+(the closer to tbe beginning the better), or as soon as you start up
+JOVE before you visit any files.
+
+:entry "transpose-characters" "Command"
+This switches the character before point with the one after point, and
+then moves forward one.  This doesn't work at the beginning of the
+line, and at the end of the line it switches the two characters before
+point.  Since point is moved forward, so that the character that was
+before point is still before point, you can use "C-T" to drag a
+character down the length of a line.  This command pretty quickly
+becomes very useful.
+
+:entry "transpose-lines" "Command"
+This switches the current line with the one above it, and then moves
+down one so that the line that was above point is still above point.
+This, like "transpose-characters," can be used to drag a line down a
+page.
+
+:entry "unbind-key" "Command"
+Use this to unbind "any" key sequence.  You can use this to unbind
+even a prefix command, since this command does not use "key-map
+completion".  For example, "ESC X unbind-key ESC [" unbinds the
+sequence "ESC [".  This is useful for "turning off" something set in
+the system-wide ".joverc" file.
+
+:entry "update-time-frequency" "Variable"
+How often the mode line is updated (and thus the time and load
+average, if you display them).  The default is 30 seconds.
+
+:entry "use-i/d-char" "Variable"
+If your terminal has insert/delete character capability you can tell
+JOVE not to use it by setting this to "off".  In my opinion it is only
+worth using insert/delete character at low baud rates.  WARNING: if
+you set this to "on" when your terminal doesn't have insert/delete
+character capability, you will get weird (perhaps fatal) results.
+
+:entry "version" "Command"
+Displays the version number of this JOVE.
+
+:entry "visible-bell" "Variable"
+Use the terminal's visible bell instead of beeping.  This is set
+automatically if your terminal has the capability.
+
+:entry "visible-spaces-in-window" "Command"
+This displays an underscore character instead of each space in the
+window and displays a greater-than followed by spaces for each tab in
+the window.  The actual text in the buffer is not changed; only the
+screen display is affected.  To turn this off you run the command
+again; it toggles.
+
+:entry "visit-file" "Command"
+This reads a specified file into the current buffer replacing the old
+text.  If the buffer needs saving JOVE will offer to save it for you.
+Sometimes you use this to start over, say if you make lots of changes
+and then change your mind.  If that's the case you don't want JOVE to
+save your buffer and you answer "NO" to the question.
+
+:entry "window-find" "Command"
+This lets you select another buffer in another window three different
+ways.  This waits for another character which can be one of the
+following:
+
+     T    Finds a tag in the other window.
+     ^T   Finds the tag at point in the other window
+     F    Finds a file in the other window.
+     B    Selects a buffer in the other window.
+
+This is just a convenient short hand for "C-X 2" (or "C-X O" if there
+are already two windows) followed by the appropriate sequence for
+invoking each command.  With this, though, there isn't the extra
+overhead of having to redisplay.  In addition, you don't have to
+decide whether to type "C-X 2" or "C-X O" since "C-X 4" does the right
+thing.
+
+:entry "word-abbrev-mode" "Command"
+This turns on Word Abbrev mode (or off if it's currently on) in the
+selected buffer.  Word Abbrev mode lets you specify a word (an
+abbreviation) and a phrase with which JOVE should substitute the
+abbreviation.  You can use this to define words to expand into long
+phrases, e.g., "jove" can expand into "Jonathan's Own Version of
+Emacs"; another common use is defining words that you often misspell
+in the same way, e.g., "thier" => "their" or "teh" => "the".  See the
+information on the "auto-case-abbrev" variable.
+
+There are two kinds of abbreviations: mode specific and global.  If
+you define a Mode specific abbreviation in C mode, it will expand only
+in buffers that are in C mode.  This is so you can have the same
+abbreviation expand to different things depending on your context.
+Global abbreviations expand regardless of the major mode of the
+buffer.  The way it works is this: JOVE looks first in the mode
+specific table, and then in the global table.  Whichever it finds it
+in first is the one that's used in the expansion.  If it doesn't find
+the word it is left untouched. JOVE tries to expand words as they are
+typed, when you type a punctuation character or Space or Return.  If
+you are in Auto Fill mode the expansion will be filled as if you typed
+it yourself.
+
+:entry "wrap-search" "Variable"
+If set, searches will "wrap around" the ends of the buffer instead of
+stopping at the bottom or top.  The default is "off".
+
+:entry "write-file" "Command"
+This saves the current buffer to a specified file, and then makes that
+file the default file name for this buffer.  If you specify a file
+that already exists you are asked to confirm over-writing it.
+
+:entry "write-files-on-make" "Variable"
+When set, all modified files will be written out before calling make
+when the "compile-it" command is executed.  The default is "on".
+
+:entry "write-macros-to-file" "Command"
+This writes the currently defined macros to a specified file in a
+format appropriate for reading them back in with the "source" command.
+The purpose of this command is to allow you to define macros once and
+use them in other instances of JOVE.
+
+:entry "write-modified-files" "Command"
+This saves all the buffers that need saving.  If you supply a numeric
+argument it asks for each buffer whether you really want to save it.
+
+:entry "write-region" "Command"
+This writes the text in the region to a specified file.  If the file
+already exists you are asked to confirm over-writing it.
+
+:entry "write-word-abbrev-file" "Command"
+This writes the currently defined abbreviations to a specified file.
+They can be read back in and automatically defined with "read-word-
+abbrev-file."
+
+:entry "xterm-mouse" "Command"
+This function enables the use of the mouse with \S-2JOVE\fP in an
+xterm window. The function is enabled when 'ansi-codes' is defined and
+the function is bound to <escape><open-square-bracket>M.  Moving the
+mouse and pressing the left button will set the point to the mouse
+position and push it.  Moving the mouse and pressing the right button
+will set the point to the mouse position and yank the region from the
+last mark and the current point.  Moving the mouse and pressing the
+middle button will set the point to the mouse position and paste the
+contents of the mouse button in place. Note that this in a
+\s-2JOVE\fP function and is independent of the normal cut and paste
+operations available under xterm. It is possible to bind these
+operations to SHIFT+the mouse button, so that they will work in
+addition to \s-2JOVE\fP cut and paste.
+
+:entry "yank" "Command"
+This undoes the last kill command.  That is, it inserts the killed
+text at point.  When you do multiple kill commands in a row, they are
+merged so that yanking them back with "C-Y" yanks back all of them.
+
+:entry "yank-pop" "Command"
+This yanks back previous killed text.  JOVE has a kill ring on which
+the last 10 kills are stored.  "yank" yanks a copy of the text at the
+front of the ring.  If you want one of the last ten kills you use "ESC
+Y" which rotates the ring so another different entry is now at the
+front.  You can use "ESC Y" only immediately following a "C-Y" or
+another "ESC Y".  If you supply a negative numeric argument the ring
+is rotated the other way.  If you use this command enough times in a
+row you will eventually get back to where you started.  Experiment
+with this.  It's extremely useful.
diff --git a/usr/src/contrib/jove-4.14.6/doc/cmds.doc.nr b/usr/src/contrib/jove-4.14.6/doc/cmds.doc.nr
new file mode 100644 (file)
index 0000000..f03fdba
--- /dev/null
@@ -0,0 +1,34 @@
+.de bp
+..
+.de NH
+..
+.de IQ
+"\\$1"
+..
+.de dc
+.sp 1
+:entry "\\$1"
+.if '\\$2'(variable)' "Variable"
+.if !'\\$2'(variable)' "Command"
+.br
+..
+.de ID
+.sp 1
+.in +5
+..
+.de DE
+.fi
+.sp 1
+.in -5
+..
+.de DS
+.nf
+.sp 1
+.in +5
+..
+.de UX
+UNIX\c
+..
+.ll 7i
+.na    \" No Adjust: ragged right looks best on fixed-pitch screen
+.nh    \" No Hyphenation: best with ragged
diff --git a/usr/src/contrib/jove-4.14.6/doc/example.rc b/usr/src/contrib/jove-4.14.6/doc/example.rc
new file mode 100644 (file)
index 0000000..2417b01
--- /dev/null
@@ -0,0 +1,24 @@
+if /ua/jonathan/src/jove/lib/isttytype iq120
+       bind-to-key Prefix-1 \\
+       bind-to-key set-mark ^[ 
+       set allow-^S-and-^Q on
+endif
+if /ua/jonathan/src/jove/lib/modemp
+       set mode-line  -%n %m "%f" %((%t%s%C%s%l)%)
+else
+       set mode-line  -%n- %["%f" %m [%b] %]%s%((%t%s%C%s%l)%)%s(%M) %e
+endif
+auto-execute-command show-match .*\.[ch]$
+set comment-format /* %!   %c%! */
+set disable-biff on
+set match-regular-expressions on
+set use-i/d-char off
+bind-to-key backward-paragraph ^[[
+bind-to-key current-error ^X^C
+bind-to-key exit-jove ^X^Z
+bind-to-key find-tag-at-point ^[^T
+bind-to-key grow-window ^Xg
+bind-to-key kill-s-expression ^[^K
+bind-to-key list-processes ^X^L
+bind-to-key scroll-down ^C
+bind-to-key shrink-window ^Xs
diff --git a/usr/src/contrib/jove-4.14.6/doc/ff b/usr/src/contrib/jove-4.14.6/doc/ff
new file mode 100644 (file)
index 0000000..78e1025
--- /dev/null
@@ -0,0 +1,281 @@
+.TH JOVE 1 "12 February 1986"
+.SH NAME
+jove - an interactive display-oriented text editor
+.SH SYNOPSIS
+.nf
+jove [-d directory] [-w] [-t tag] [+[n] file] [-p file] [files]
+jove -r
+.fi
+.SH DESCRIPTION
+JOVE is Jonathan's Own Version of Emacs.  It is based on the original EMACS
+editor written at MIT by Richard Stallman.  Although JOVE is meant to be
+compatible with EMACS, there are some major differences between the two
+editors and you shouldn't rely on their behaving identically.
+.LP
+JOVE works on any reasonable display terminal that is described in the
+.I termcap
+file (see TERMCAP(5) for more details).  When you start up JOVE, it checks
+to see whether you have your
+.I TERM
+environment variable set.  On most systems that will automatically be set up
+for you, but if it's not JOVE will ask you what kind of terminal you are
+using.  To avoid having to type this every time you run JOVE you can set your
+.I TERM
+environment variable yourself.  How you do this depends on which shell you
+are running.  If you are running the C Shell, as most of you are, you type
+.sp 1
+     % setenv TERM
+.I type
+.sp 1
+and with the Bourne Shell, you type
+.sp 1
+     $ TERM=
+.I type
+; export TERM
+.sp 1
+where
+.I type
+is the name of the kind of terminal you are using (e.g., vt100).  If
+neither of these works get somebody to help you.
+.SH INVOKING JOVE
+If you run JOVE with no arguments you will be placed in an empty buffer,
+called
+.I Main.
+Otherwise, any arguments you supply are considered file names and each is
+"given" its own buffer.  Only the first file is actually read in--reading
+other files is deferred until you actually try to use the buffers they are
+attached to.  This is for efficiency's sake: most of the time, when you run
+JOVE on a big list of files, you end up editing only a few of them.
+.LP
+The names of all of the files specified on the command line are saved in a
+buffer, called
+.I *minibuf*.
+The mini-buffer is a special JOVE buffer that is used when JOVE is prompting
+for some input to many commands (for example, when JOVE is prompting for a
+file name).  When you are being prompted for a file name, you can type C-N
+(that's Control-N) and C-P to cycle through the list of files that were
+specified on the command line.  The file name will be inserted where you are
+typing and then you can edit it as if you typed it in yourself.
+.LP
+JOVE recognizes the following switches:
+.TP
+.I -d
+The following argument is taken to be the name of the current directory.
+This is for systems that don't have a version of C shell that automatically
+maintains the
+.I CWD
+environment variable.  If
+.I -d
+is not specified on a system without a modified C shell, JOVE will have to
+figure out the current directory itself, and that can be VERY slow.  You
+can simulate the modified C shell by putting the following lines in your
+C shell initialization file (.cshrc):
+.nf
+.sp 1
+       alias cd        'cd \e!*; setenv CWD $cwd'
+       alias popd      'popd \e!*; setenv CWD $cwd'
+       alias pushd     'pushd \e!*; setenv CWD $cwd'
+.fi
+.TP
+.I +n
+Reads the file, designated by the following argument, and positions point at
+the
+.I n'th
+line instead of the (default) 1'st line.  This can be specified more than
+once but it doesn't make sense to use it twice on the same file; in that
+case the second one wins. If no numeric argument is given after the +,
+the point is positioned at the end of the file.
+.TP
+.I -p
+Parses the error messages in the file designated by the following argument.
+The error messages are assumed to be in a format similar to the C compiler,
+LINT, or GREP output.
+.TP
+.I -t
+Runs the
+.I find-tag 
+command on the string of characters immediately following 
+the -t if there is one (as in -tTagname), or on
+the following argument (as in -t Tagname) otherwise (see ctags(1)).
+.TP
+.I -w
+Divides the window in two.  When this happens, either the same file is
+displayed in both windows, or the second file in the list is read in and
+displayed in its window.
+.SH "RECOVERING BUFFERS AFTER A CRASH"
+The
+.I -r
+option of jove runs the JOVE recover program.  Use this when the system
+crashes, or JOVE crashes, or you accidently get logged out while in JOVE.
+If there are any buffers to be recovered, this will find them.
+.LP
+Recover looks for JOVE buffers that are left around and are
+owned by you.  (You cannot recover other peoples' buffers, obviously.)
+If there were no buffers that were modified at the time of the
+crash or there were but recover can't get its hands on them, you will be
+informed with the message, "There is nothing to recover."  Otherwise,
+recover prints the date and time of the version of the buffers it has,
+and then waits for you type a command.
+.LP
+To get a list of the buffers recover knows about, use the
+.I list
+command.  This will list all the buffers and the files and the number of
+lines associated with them.  Next to each buffer is a number.  When you want
+to recover a buffer, use the
+.I get
+command.  The syntax is
+.I get buffer filename
+where
+.I buffer
+is either the buffer's name or the number at the beginning of the line.  If
+you don't type the buffer name or the filename, recover will prompt you
+for them.
+.LP
+If there are a lot of buffers and you want to recover all of them, use the
+.I recover
+command.  This will recover each buffer to the name of the buffer with ".#"
+prepended to the name (so that the original isn't over-written).  It asks
+for each file and if you want to restore that buffer to that name you type
+"yes".  If you want to recover the file but to a different name, just type
+the new name in.  If you type "no" recover will skip that file and go on
+to the next one.
+.LP
+If you want to look at a buffer before deciding to recover it, use the
+.I print
+command.  The syntax for this is
+.I print buffer
+where
+.I buffer
+again is either its name or the number.  You can type ^C if you want to
+abort printing the file to the terminal, and recover will respond with
+an appropriate message.
+.LP
+When you're done and have all the buffers you want, type the
+.I quit
+command to leave.  You will then be asked whether it's okay to delete the
+tmp files.  Most of the time that's okay and you should type "yes".  When
+you say that, JOVE removes all traces of those buffers and you won't be able
+to look at them again.  (If you recovered some buffers they will still be
+around, so don't worry.)  So, if you're not sure whether you've gotten all
+the buffers, you should answer "no" so that you'll be able to run
+recover again at a later time (presumably after you've figured out
+which ones you want to save).
+.LP
+If you type ^C at any time other than when you're printing a file to the
+terminal, recover will exit without a word.  If you do this but wish you
+hadn't, just type "jove -r" to the shell again, and you will be put back
+with no loss.
+.SH GETTING HELP
+Once in JOVE, there are several commands available to get help.  To execute
+any JOVE command, you type "<ESC> X command-name" followed by <Return>.  To
+get a list of all the JOVE commands you type "<ESC> X" followed by "?".  The
+.I describe-bindings
+command can be used to get a list containing each key, and its associated
+command (that is, the command that gets executed when you type that key).
+If you want to save the list of bindings, you can set the jove variable
+.I send-typeout-to-buffer
+to ON (using the 
+.I set
+command), and then execute the
+.I describe-bindings
+command.  This will create a buffer and put in it the bindings list it
+normally would have printed on the screen.  Then you can save that buffer to
+a file and print it to use as a quick reference card.  (See VARIABLES below.)
+.LP
+Once you know the name of a command, you can find out what it does with the
+.I describe-command
+command, which you can invoke quickly by typing "ESC ?".  The
+.I apropos
+command will give you a list of all the command with a specific string in
+their names.  For example, if you want to know the names of all the
+commands that are concerned with windows, you can run "apropos" with the
+keyword
+.I window.
+.LP
+If you're not familar with the EMACS command set, it would be worth your
+while to use run TEACHJOVE.  Do do that, just type "teachjove" to your shell
+and you will be placed in JOVE in a file which contains directions.  I highly
+recommend this for beginners; you may save yourself a lot of time and
+headaches.
+.SH KEY BINDINGS and VARIABLES
+You can alter the key bindings in JOVE to fit your personal tastes.  That
+is, you can change what a key does every time you strike it.  For example,
+by default the C-N key is bound to the command
+.I next-line
+and so when you type it you move down a line.  If you want to change a
+binding or add a new one, you use the
+.I bind-to-key
+command.  The syntax is "bind-to-key <command> key".
+.LP
+You can also change the way JOVE behaves in little ways by changing the
+value of some variables with the
+.I set
+command.  The syntax is "set <variable> value", where value is a number or a
+string, or "on" or "off", depending on the context.  For example, if you
+want JOVE to make backup files, you set the "make-backup-files" variable to
+"on".  To see the value of a variable, use the "print <variable>" command.
+.SH INITIALIZATION
+JOVE automatically reads commands from an initialization file in your HOME
+directory, called ".joverc".  In this file you can place commands that you
+would normally type in JOVE.  If you like to rearrange the key bindings and
+set some variables every time you get into JOVE, you should put them in your
+initialization file.  Here are a few lines from mine:
+.nf
+       set match-regular-expressions on
+       auto-execute-command auto-fill /tmp/Re\e|.*drft
+       bind-to-key i-search-forward ^\e
+       bind-to-key i-search-reverse ^R
+       bind-to-key find-tag-at-point ^[^T
+       bind-to-key scroll-down ^C
+       bind-to-key grow-window ^Xg
+       bind-to-key shrink-window ^Xs
+.fi
+(Note that the Control Characters can be either two character sequences
+(e.g. ^ and C together as ^C) or the actual control character.  If you want
+to use an ^ by itself you must BackSlash it (e.g., bind-to-key grow-window
+^X\e^ binds grow-window to "^X^").
+.SH SOME MINOR DETAILS
+You should type C-\e instead of C-S in many instances.  For example, the way
+to search for a string is documented as being "C-S" but in reality you
+should type "C-\e".  This is because C-S is the XOFF character (what gets
+sent when you type the NO SCROLL key), and clearly that won't work.  The XON
+character is "C-Q" (what gets sent when you type NO SCROLL again) which is
+documented as the way to do a quoted-insert.  The alternate key for this is
+"C-^" (typed as "C-`" on vt100's and its look-alikes).  If you want to
+enable C-S and C-Q and you know what you are doing, you can put the line:
+.nf
+       set allow-^S-and-^Q on
+.fi
+in your initialization file.
+.LP
+If your terminal has a metakey, JOVE will use it if you turn on the
+"meta-key" variable.  JOVE will automatically turn on "meta-key" if the
+METAKEY environment variable exists.  This is useful for if you have
+different terminals (e.g., one at home and one at work) and one has a
+metakey and the other doesn't.
+.SH FILES
+SHAREDIR/jove.rc - system wide initialization file
+.sp 0
+~/.joverc - personal initialization file
+.sp 0
+TMPDIR - where temporary files are stored
+.sp 0
+SHAREDIR/teach-jove - the interactive tutorial
+.sp 0
+LIBDIR/portsrv - for running shells in windows (pdp11 only)
+.SH SEE ALSO
+.nf
+ed(1) - for a description of regular expressions
+.sp 0
+teachjove(1) - for an interactive JOVE tutorial.
+.fi
+.SH DIAGNOSTICS
+JOVE diagnostics are meant to be self-explanatory, but you are advised
+to seek help whenever you are confused.  You can easily lose a lot of
+work if you don't know EXACTLY what you are doing.
+.SH BUGS
+Lines can't be more than 1024 characters long.
+.sp 1
+Searches can't cross line boundaries.
+.SH AUTHOR
+Jonathan Payne
diff --git a/usr/src/contrib/jove-4.14.6/doc/jove.1 b/usr/src/contrib/jove-4.14.6/doc/jove.1
new file mode 100644 (file)
index 0000000..cf3e43e
--- /dev/null
@@ -0,0 +1,1167 @@
+.\" ditroff -ms
+.de IQ
+\\fI\\$1\\fP
+..
+.de dc
+.NH 2
+\\$1
+.if '\\$2'(variable)' (variable)
+.if !'\\$2'(variable)' (\\$2)
+.LP
+..
+.nr LL 6.5i
+.nr LT 6.5i
+.EH 'USD:17-%''JOVE Manual for UNIX Users'
+.OH 'JOVE Manual for UNIX Users''USD:17-%'
+.LP
+.TL
+JOVE Manual for UNIX Users
+.AU
+Jonathan Payne
+(revised for 4.3BSD by Doug Kingston and Mark Seiden)
+.AI
+.AB no
+.AE
+.NH 1
+Introduction
+.XS \n(PN
+\*(SN Introduction
+.XE
+.LP
+\s-2JOVE\s0*
+.FS
+*\s-2JOVE\s0 stands for Jonathan's Own Version of Emacs.
+.FE
+is an advanced, self-documenting, customizable real-time display editor.
+It (and this tutorial introduction) are based on the original EMACS
+editor and user manual written at M.I.T. by Richard Stallman+.
+.FS
++Although \s-2JOVE\s0 is meant to be compatible with EMACS,
+and indeed many of the basic commands are very similar,
+there are some major differences between the two editors,
+and you should not rely on their behaving identically.
+.FE
+.LP
+\s-2JOVE\s0 is considered a
+.I display 
+editor because normally the text being
+edited is visible on the screen and is updated automatically as you
+type your commands.
+.LP
+It's considered a
+.I real-time 
+editor because the display is updated very
+frequently, usually after each character or pair of characters you type.
+This minimizes the amount of information you must keep in your
+head as you edit.
+.LP
+\s-2JOVE\s0 is 
+.I advanced 
+because it provides facilities that go beyond
+simple insertion and deletion:
+filling of text;
+automatic indentations of programs;
+view more than one file at once;
+and dealing in terms of characters, words, lines, sentences and paragraphs.
+It is much easier
+to type one command meaning "go to the end of the paragraph" than to
+find the desired spot with repetition of simpler commands.
+.LP
+.I Self-documenting 
+means that at almost any time you can easily
+find out what a command does,
+or to find all the commands that pertain to a topic.
+.LP
+.I Customizable
+means that you can change the definition of \s-2JOVE\s0 commands
+in little ways.
+For example, you can rearrange the command set;
+if you prefer to use arrow keys for the four basic cursor motion commands
+(up, down, left and right), you can.
+Another sort of customization is
+writing new commands by combining built in commands.
+.NH 1
+The Organization of the Screen
+.XS \n(PN
+\*(SN The Organization of the Screen
+.XE
+.LP
+\s-2JOVE\s0 divides the screen up into several sections.
+The biggest of these sections is used to display the text you are editing.
+The terminal's cursor shows the position of \fIpoint\fP,
+the location at which editing takes place.
+While the cursor appears to point \fIat\fP a character,
+point should be thought of as between characters;
+it points \fIbefore\fP the character that the cursor appears on top of.
+Terminals have only one cursor,
+and when output is in progress it must appear where the typing is being done.
+This doesn't mean that point is moving;
+it is only that \s-2JOVE\s0 has no way of
+showing you the location of point except when the terminal is idle.
+.LP
+The lines of the screen are usually available for displaying text but
+sometimes are pre-empted by typeout from certain commands (such as a
+listing of all the editor commands).
+Most of the time,
+output from commands like these is only desired for a short period of time,
+usually just long enough to glance at it.
+When you have finished looking at the output,
+you can type Space to make your text reappear.
+(Usually a Space that you type inserts itself, but when there is typeout on
+the screen, it does nothing but get rid of that).
+Any other command executes normally,
+.I after
+redrawing your text.
+.NH 2
+The Message Line
+.XS \n(PN 5n
+\*(SN The Message Line
+.XE
+.LP
+The bottom line on the screen, called the
+\fImessage line\fP,
+is reserved for printing messages and for accepting input from the user,
+such as filenames or search strings.
+When
+\s-2JOVE\s0 
+prompts for input,
+the cursor will temporarily appear on the bottom line, waiting for you
+to type a string.
+When you have finished typing your input, you can
+type a Return to send it to \s-2JOVE\s0.
+If you change your mind about running the command that is waiting for input,
+you can type Control-G to abort,
+and you can continue with your editing.
+.LP
+When \s-2JOVE\s0 is prompting for a filename,
+all the usual editing facilities can be used to fix typos and such;
+in addition, \s-2JOVE\s0 has the following extra functions:
+.IP "^N"
+Insert the next filename from the argument list.
+.IP "^P"
+Insert the previous filename from the argument list.
+.IP "^R"
+Insert the full pathname of the file in the current buffer.
+.LP
+Sometimes you will see \fB--more--\fP on the message line.
+This happens when typeout from a command is too long to fit in the screen.
+It means that if you type a Space the next screenful of typeout will be
+printed.
+If you are not interested,
+typing anything but a Space will cause the rest of the output to be discarded.
+Typing C-G will discard the output and print \fIAborted\fP where the \fB--more--\fP was.
+Typing any other command will discard the rest of the output and
+also execute the command.
+.LP
+The message line and the list of filenames from the shell command that
+invoked \s-2JOVE\s0 are kept in a special buffer called
+\fIMinibuf\fP that can be edited like any other buffer.
+.NH 2
+The Mode Line
+.XS \n(PN 5n
+\*(SN The Mode Line
+.XE
+.LP
+At the bottom of the screen, but above the message line, is the
+\fImode line\fP.  The mode line format looks like this:
+.DS I
+\fBJOVE (major minor)   Buffer: bufr  "file" *\fP
+.DE
+\fImajor\fP is the name of the current \fImajor mode\fP.
+At any time, \s-2JOVE\s0 can be in only one major mode at a time.
+Currently there are only four major modes: \fIFundamental\fP,
+\fIText\fP, \fILisp\fP and \fIC\fP.
+.LP
+\fIminor\fP is a list of the minor modes that are turned on.
+\fBAbbrev\fP means that \fIWord Abbrev\fP mode is on;
+\fBAI\fP means that \fIAuto Indent\fP mode is on;
+\fBFill\fP means that \fIAuto Fill\fP mode is on;
+\fBOvrWt\fP means that \fIOver Write\fP mode is on.
+\fBDef\fP means that you are in the process of defining a keyboard macro.
+This is not really a mode,
+but it's useful to be reminded about it.
+The meanings of these modes are described later in this document.
+.LP
+\fIbufr\fP is the name of the currently selected \fIbuffer\fP.
+Each buffer has its own name and holds a file being edited;
+this is how \s-2JOVE\s0 can hold several files at once.
+But at any given time you are editing only one of them,
+the \fIselected\fP buffer.
+When we speak of what some command does to "the buffer",
+we are talking about the currently selected buffer.
+Multiple buffers makes it easy to switch around between several files,
+and then it is very useful that
+the mode line tells you which one you are editing at any time.  (You
+will see later that it is possible to divide the
+screen into multiple \fIwindows\fP, each showing a different buffer.  If you
+do this, there is a mode line beneath each window.)
+.LP
+\fIfile\fP is the name of the file that you are editing.
+This is the default filename for commands that expect a filename as input.
+.LP
+The asterisk at the end of the mode line means that there are changes in
+the buffer that have not been saved in the file.
+If the file has not been changed since it was read in or saved,
+there is no asterisk.
+.NH 1
+Command Input Conventions
+.XS \n(PN
+\*(SN Command Input Conventions
+.XE
+.LP
+.NH 2
+Notational Conventions for ASCII Characters
+.XS \n(PN 5n
+\*(SN Notational Conventions for ASCII Characters
+.XE
+.LP
+In this manual,
+"Control" characters
+(that is, characters that are typed with the Control key
+and some other key at the same time)
+are represented by "C-" followed by another character.
+Thus,
+C-A is the character you get when you type A with the Control key
+(sometimes labeled CTRL) down.
+Most control characters when present in the \s-2JOVE\s0
+buffer are displayed with a caret; thus, ^A for C-A.
+DEL (or delete) is displayed as ^?, escape as ^[.
+.NH 2
+Command and Filename Completion
+.XS \n(PN 5n
+\*(SN Command and Filename Completion
+.XE
+.LP
+When you are typing the name of a \s-2JOVE\s0 command, you need type only
+enough letters to make the name unambiguous.  At any point in the course of
+typing the name, you can type question mark (?) to see a list of all the
+commands whose names begin with the characters you've already typed; you can
+type Space to have \s-2JOVE\s0 supply as many characters as it can; or you
+can type Return to complete the command if there is only one possibility.
+For example, if you have typed the letters "\fIau\fP" and you then type a
+question mark, you will see the list
+.DS I
+   auto-execute-command
+   auto-execute-macro
+   auto-fill-mode
+   auto-indent-mode
+.DE
+If you type a Return at this point, \s-2JOVE\s0 will complain by ringing
+the bell, because the letters you've typed do not unambiguously specify a
+single command.  But if you type Space, \s-2JOVE\s0 will supply the
+characters "\fIto-\fP" because all commands that begin "\fIau\fP" also
+begin "\fIauto-\fP".  You could then type the letter "\fIf\fP" followed
+by either Space or Return, and \s-2JOVE\s0 would complete the entire
+command.
+.LP
+Whenever \s-2JOVE\s0 is prompting you for a filename, say in the
+\fIfind-file\fP command, you also need only type enough of the name to
+make it unambiguous with respect to files that already exist.  In this
+case, question mark and Space work just as they do in command completion,
+but Return always accepts the name just as you've typed it, because you
+might want to create a new file with a name similar to that of an
+existing file.  The variable \fIbad-filename-extensions\fP contains a
+list of words separated by spaces which are to be considered bad
+filename extensions, and so will not be counted in filename completion.
+The default is ".o" so if you have jove.c and jove.o in the same
+directory, the filename completion will not complain of an ambiguity
+because it will ignore jove.o.
+
+.NH 1
+Commands and Variables
+.XS \n(PN
+\*(SN Commands and Variables
+.XE
+.LP
+\s-2JOVE\s0 is composed of \fIcommands\fP
+which have long names such as
+\fInext-line\fP.
+Then \fIkeys\fP such as C-N are connected to
+commands through the \fIcommand dispatch table\fP.
+When we say that C-N moves the cursor down a line,
+we are glossing over a distinction which is unimportant for ordinary use,
+but essential for simple customization:
+it is the command \fInext-line\fP which knows how to move a down line,
+and C-N moves down a line because it is connected to that command.
+The name for this connection is a \fIbinding\fP; we say that the key
+C-N \fIis bound to\fP the command \fInext-line\fP.
+.LP
+Not all commands are bound to keys.  To invoke a command that isn't bound
+to a key, you can type the sequence ESC X, which is bound to the command
+\fIexecute-named-command\fP.  You will then be able to type the name of
+whatever command you want to execute on the message line.
+.LP
+Sometimes the description of a command will say
+"to change this, set the variable \fImumble\-foo\fP".
+A variable is a name used to remember a value.
+\s-2JOVE\s0 contains variables which are there so that you can change
+them if you want to customize.
+The variable's value is examined by some command,
+and changing that value makes the command behave differently.
+Until you are interesting in customizing \s-2JOVE\s0,
+you can ignore this information.
+.NH 2
+Prefix Characters
+.XS \n(PN 5n
+\*(SN Prefix Characters
+.XE
+.LP
+Because there are more command names than keys,
+\s-2JOVE\s0 provides
+\fIprefix characters\fP to increase the number of commands that can
+be invoked quickly and easily.
+When you type a prefix character \s-2JOVE\s0 will wait
+for another character before deciding what to do.
+If you wait more than a second or so,
+\s-2JOVE\s0 will print the prefix character on the
+message line as a reminder and leave the cursor down there until you type your next
+character.
+There are two prefix characters built into \s-2JOVE\s0:
+Escape and Control-X.
+How the next character is interpreted depends on which
+prefix character you typed.
+For example,
+if you type Escape followed by B you'll run \fIbackward-word\fP,
+but if you type Control-X followed by B you'll run \fIselect-buffer\fP.
+Elsewhere in this manual, the Escape key is indicated as "ESC", which is
+also what \s-2JOVE\s0 displays on the message line for Escape.
+.NH 2
+Help
+.XS \n(PN
+\*(SN Help
+.XE
+.LP
+To get a list of keys and their associated commands,
+you type ESC X \fIdescribe-bindings\fP.
+If you want to describe a single key,
+ESC X \fIdescribe-key\fP will work.  A description of an
+individual command is available by using ESC X \fIdescribe-command\fP,
+and descriptions of variables by using  ESC X \fIdescribe-variable\fP.
+If you can't remember the name of the thing you want to know about,
+ESC X \fIapropos\fP will tell you if a command or variable has a given
+string in its name.  For example, ESC X \fIapropos describe\fP will
+list the names of the four describe commands mentioned briefly in this
+section.
+.NH 1
+Basic Editing Commands
+.XS \n(PN
+\*(SN Basic Editing Commands
+.XE
+.LP
+.NH 2
+Inserting Text
+.XS \n(PN 5n
+\*(SN Inserting Text
+.XE
+.LP
+To insert printing characters into the text you are editing,
+just type them.
+All printing characters you type are inserted into the text at
+the cursor (that is, at \fIpoint\fP),
+and the cursor moves forward.
+Any characters after the cursor move forward too.
+If the text in the buffer is FOOBAR,
+with the cursor before the B,
+then if you type XX,
+you get FOOXXBAR,
+with the cursor still before the B.
+.LP
+To correct text you have just inserted,
+you can use DEL.
+DEL deletes the character \fIbefore\fP the cursor (not the one that the
+cursor is on top of or under; that is the character \fIafter\fP the
+cursor).
+The cursor and all characters after it move backwards.
+Therefore,
+if you typing a printing character and then type DEL,
+they cancel out.
+.LP
+To end a line and start typing a new one,
+type Return.
+Return operates by inserting a \fIline-separator\fP,
+so if you type Return in
+the middle of a line,
+you break the line in two.
+Because a line-separator is just a single character,
+you can type DEL at the
+beginning of a line to delete the line-separator and join it with the
+preceding line.
+.LP
+As a special case, if you type Return at the end of a line and there are
+two or more empty lines just below it, \s-2JOVE\s0 does not insert a
+line-separator but instead merely moves to the next (empty) line.  This
+behavior is convenient when you want to add several lines of text in the
+middle of a buffer.  You can use the Control-O (\fInewline-and-backup\fP)
+command to "open" several empty lines at once; then you can insert the new
+text, filling up these empty lines.  The advantage is that \s-2JOVE\s0 does
+not have to redraw the bottom part of the screen for each Return you type,
+as it would ordinarily.  That "redisplay" can be both slow and distracting.
+.LP
+If you add too many characters to one line,
+without breaking it with Return,
+the line will grow too long to display on one screen line.
+When this happens,
+\s-2JOVE\s0 puts an "!" at the extreme right margin,
+and doesn't bother to display the rest of the line unless the
+cursor happens to be in it.
+The "!" is not part of your text;
+conversely,
+even though you can't see the rest of your line,
+it's still there,
+and if you break the line,
+the "!" will go away.
+.LP
+Direct insertion works for printing characters and space,
+but other
+characters act as editing commands and do not insert themselves.
+If you need to insert a control character,
+Escape,
+or DEL,
+you must first \fIquote\fP it by typing the Control-Q command first.
+.NH 2
+Moving the Cursor
+.XS \n(PN 5n
+\*(SN Moving the Cursor
+.XE
+.LP
+To do more than insert characters,
+you have to know how to move the cursor.
+Here are a few of the commands for doing that.
+.IP "C-A" 15n
+Move to the beginning of the line.
+.IP "C-E" 15n
+Move to the end of the line.
+.IP "C-F" 15n
+Move forward over one character.
+.IP "C-B" 15n
+Move backward over one character.
+.IP "C-N" 15n
+Move down one line,
+vertically.
+If you start in the middle of one line,
+you end in the middle of the next.
+.IP "C-P" 15n
+Move up one line,
+vertically.
+.IP "ESC <" 15n
+Move to the beginning of the entire buffer.
+.IP "ESC >" 15n
+Move to the end of the entire buffer.
+.IP "ESC ," 15n
+Move to the beginning of the visible window.
+.IP "ESC ." 15n
+Move to the end of the visible window.
+.NH 2
+Erasing Text
+.XS \n(PN 5n
+\*(SN Erasing Text
+.XE
+.LP
+.IP "DEL" 15n
+Delete the character before the cursor.
+.IP "C-D" 15n
+Delete the character after the cursor.
+.IP "C-K" 15n
+Kill to the end of the line.
+.LP
+You already know about the DEL key which deletes the character
+before the cursor.
+Another command,
+Control-D,
+deletes the character
+after the cursor,
+causing the rest of the text on the line to shift left.
+If Control-D is typed at the end of a line,
+that line and the next line are joined together.
+.LP
+To erase a larger amount of text,
+use the Control-K command,
+which kills a line at a time.
+If Control-K is done at the beginning or
+middle of a line,
+it kills all the text up to the end of the line.
+If Control-K is done at the end of a line,
+it joins that line and the next line.
+If Control-K is done twice, it kills the rest of the line and the line
+separator also.
+.NH 2
+Files \(em Saving Your Work
+.XS \n(PN 5n
+\*(SN Files \(em Saving Your Work
+.XE
+.LP
+The commands above are sufficient for creating text in the \s-2JOVE\s0 buffer.
+The more advanced \s-2JOVE\s0 commands just make things easier.
+But to keep any text permanently you must put it in a \fIfile\fP.
+Files are the objects which
+.UX
+uses for storing data for a length of time.
+To tell \s-2JOVE\s0 to read text into a file,
+choose a filename,
+such as \fIfoo.bar\fP,
+and type C-X C-R \fIfoo.bar\fP<return>.
+This reads the file \fIfoo.bar\fP so that its contents appear on the screen
+for editing.
+You can make changes,
+and then save the file by typing C-X C-S (save-file).
+This makes the changes permanent and actually changes the file \fIfoo.bar\fP.
+Until then,
+the changes are only inside \s-2JOVE\s0,
+and the file \fIfoo.bar\fP is not really changed.
+If the file \fIfoo.bar\fP doesn't exist,
+and you want to create it,
+read it as if it did exist.
+When you save your text with C-X C-S the file will be created.
+.NH 2
+Exiting and Pausing \(em Leaving \s-2JOVE\s0
+.XS \n(PN 5n
+\*(SN Exiting and Pausing \(em Leaving \s-2JOVE\s0
+.XE
+.LP
+The command C-X C-C (\fIexit-jove\fP) will terminate the \s-2JOVE\s0
+session and return to the shell.  If there are modified but 
+unsaved buffers, \s-2JOVE\s0 will ask you for confirmation, and you
+can abort the command, look at what buffers are
+modified but unsaved using C-X C-B (\fIlist-buffers\fP), save the 
+valuable ones, and then exit.  If what you want to do, on the other hand,
+is \fIpreserve\fP the editing session but return to the shell temporarily
+you can (under Berkeley 
+.UX
+only) issue the command ESC S (\fIpause-jove\fP), do your 
+.UX 
+work within the c-shell, then return to \s-2JOVE\s0 using the 
+\fIfg\fP command to resume editing at the point where you paused.
+For this sort of situation you might consider using an \fIinteractive
+shell\fP (that is, a shell in a \s-2JOVE\s0 window) which lets you use
+editor commands to manipulate your 
+.UX 
+commands (and their output) while never leaving the editor.
+(The interactive shell feature is described below.)
+.NH 2
+Giving Numeric Arguments to \s-2JOVE\s0 Commands
+.XS \n(PN 5n
+\*(SN Giving Numeric Arguments to \s-2JOVE\s0 Commands
+.XE
+.LP
+Any \s-2JOVE\s0 command can be given a \fInumeric argument\fP.
+Some commands interpret the argument as a repetition count.
+For example,
+giving an argument of ten to the C-F command (forward-character) moves forward
+ten characters.
+With these commands,
+no argument is equivalent to an argument of 1.
+.LP
+Some commands use the value of the argument,
+but do something peculiar (or nothing) when there is no argument.
+For example,
+ESC G (\fIgoto-line\fP) with an argument \fBn\fP
+goes to the beginning of the \fBn\fP'th line.
+But ESC G with no argument prompts for the line number.
+Similarly, C-K with an argument kills that many lines, including their line
+separators.  Without an argument, C-K when there is text on the line to the
+right of
+the cursor kills that text; when there is no text after the cursor, C-K
+deletes the line separator.
+.LP
+The fundamental way of specifying an argument is to use ESC followed
+by the digits of the argument, for example, ESC 123 ESC G to go to line
+123. Negative arguments are allowed,
+although not all of the commands know what to do with one.
+.LP
+Typing C-U means do the next command four times.
+Two such C-U's multiply the next command by sixteen.
+Thus,
+C-U C-U C-F moves forward sixteen characters.
+This is a good way to move forward quickly,
+since it moves about 1/4 of a line on most terminals.
+Other useful combinations are:
+C-U C-U C-N (move down a good fraction of the screen),
+C-U C-U C-O (make "a lot" of blank lines),
+and C-U C-K (kill four lines \(em note that typing C-K four times
+would kill 2 lines).
+.LP
+There are other,
+terminal-dependent ways of specifying arguments.
+They have the same effect but may be easier to type.
+If your terminal
+has a numeric keypad which sends something recognizably different from
+the ordinary digits,
+it is possible to program \s-2JOVE\s0 to to allow use of
+the numeric keypad for specifying arguments.
+.NH 2
+The Mark and the Region
+.XS \n(PN 5n
+\*(SN The Mark and the Region
+.XE
+.LP
+In general,
+a command that processes an arbitrary part of the buffer
+must know where to start and where to stop.
+In \s-2JOVE\s0,
+such commands usually operate on the text between point and \fIthe mark\fP.
+This body of text is called \fIthe region\fP.
+To specify a region,
+you set point to one end of it and mark at the other.
+It doesn't matter which one comes earlier in the text.
+.IP "C-@" 15n
+Set the mark where point is.
+.IP "C-X C-X" 15n
+Interchange mark and point.
+.LP
+For example,
+if you wish to convert part of the buffer to all upper-case,
+you can use the C-X C-U command,
+which operates on the text in the region.
+You can first go to the beginning of the text to be capitalized,
+put the mark there, move to the end, and then type C-X C-U.
+Or,
+you can set the mark at the end of the text,
+move to the beginning,
+and then type C-X C-U.
+C-X C-U runs the command \fIcase-region-upper\fP,
+whose name signifies that the region,
+or everything between point and mark,
+is to be capitalized.
+.LP
+The way to set the mark is with the C-@ command or (on some
+terminals) the C-Space command.
+They set the mark where point is.
+Then you can move point away,
+leaving mark behind.  When the mark is set, "[Point pushed]" is printed on
+the message line.
+.LP
+Since terminals have only one cursor,
+there is no way for \s-2JOVE\s0 to show you where the mark is located.
+You have to remember.
+The usual solution to this problem is to set the mark and then use it soon,
+before you forget where it is.
+But you can see where the mark is with
+the command C-X C-X which puts the mark where point was and point
+where mark was.
+The extent of the region is unchanged,
+but the cursor and point are now at the previous location of the mark.
+.NH 2
+The Ring of Marks
+.XS \n(PN 5n
+\*(SN The Ring of Marks
+.XE
+.LP
+Aside from delimiting the region,
+the mark is also useful for remembering a spot that you may want to go back to.
+To make this feature more useful,
+\s-2JOVE\s0 remembers 16 previous locations of the mark.
+Most commands that set the mark push the old mark onto this stack.
+To return to a marked location, use C-U C-@.
+This moves point to where the mark was,
+and restores the mark from the stack of former marks.
+So repeated use of this command moves point to all of the old
+marks on the stack,
+one by one.
+Since the stack is actually a ring,
+enough uses of C-U C-@ bring point back to where it was originally.
+.LP
+Some commands whose primary purpose is to move point a great distance
+take advantage of the stack of marks to give you a way to undo the
+command.
+The best example is ESC <,
+which moves to the beginning of the buffer.
+If there are more than 22 lines between the beginning of
+the buffer and point,
+ESC < sets the mark first,
+so that you can use C-U C-@ or C-X C-X to go back to where you were.
+You can change the number of lines from 22 since it is kept in the variable \fImark-threshold\fP.
+By setting it to 0,
+you can make these commands always set the mark.
+By setting it to a very large number you can prevent these commands from ever
+setting the mark.
+If a command decides to set the mark,
+it prints the message \fI[Point pushed]\fP.
+.NH 2
+Killing and Moving Text
+.XS \n(PN 5n
+\*(SN Killing and Moving Text
+.XE
+.LP
+The most common way of moving or copying text with \s-2JOVE\s0 is to kill it,
+and get it back again in one or more places.
+This is very safe
+because the last several pieces of killed text are all remembered,
+and it is versatile,
+because the many commands for killing syntactic units
+can also be used for moving those units.
+There are also other ways of moving text for special purposes.
+.NH 2
+Deletion and Killing
+.XS \n(PN 5n
+\*(SN Deletion and Killing
+.XE
+.LP
+Most commands which erase text from the buffer save it so that you can
+get it back if you change your mind,
+or move or copy it to other parts of the buffer.
+These commands are known as \fIkill\fP commands.
+The rest of the commands that erase text do not save it;
+they are known as \fIdelete\fP commands.
+The delete commands include C-D and DEL,
+which delete only one character at a time,
+and those commands that delete only spaces or line separators.
+Commands that can destroy significant amounts of nontrivial data generally kill.
+A command's
+name and description will use the words \fIkill\fP or \fIdelete\fP to
+say which one it does.
+.IP "C-D" 20n
+Delete next character.
+.IP "DEL" 20n
+Delete previous character.
+.IP "ESC \e" 20n
+Delete spaces and tabs around point.
+.IP "C-X C-O" 20n
+Delete blank lines around the current line.
+.IP "C-K" 20n
+Kill rest of line or one or more lines.
+.IP "C-W" 20n
+Kill region (from point to the mark).
+.IP "ESC D" 20n
+Kill word.
+.IP "ESC DEL" 20n
+Kill word backwards.
+.IP "ESC K" 20n
+Kill to end of sentence.
+.IP "C-X DEL" 20n
+Kill to beginning of sentence.
+.NH 2
+Deletion
+.XS \n(PN 5n
+\*(SN Deletion
+.XE
+.LP
+The most basic delete commands are C-D and DEL.
+C-D deletes the character after the cursor,
+the one the cursor is "on top of" or "underneath".
+The cursor doesn't move.
+DEL deletes the character before the cursor,
+and moves the cursor back.
+Line separators act like normal characters when deleted.
+Actually,
+C-D and DEL aren't always \fIdelete\fP commands;
+if you give an argument,
+they \fIkill\fP instead.
+This prevents you from losing a great deal of text by typing a large
+argument to a C-D or DEL.
+.LP
+The other delete commands are those which delete only formatting
+characters:
+spaces,
+tabs,
+and line separators.
+ESC \e (\fIdelete-white-space\fP)
+deletes all the spaces and tab characters before and after point.
+C-X C-O (\fIdelete-blank-lines\fP) deletes all blank lines after the current line,
+and if the current line is blank deletes all the blank
+lines preceding the current line as well
+(leaving one blank line, the current line).
+.NH 2
+Killing by Lines
+.XS \n(PN 5n
+\*(SN Killing by Lines
+.XE
+.LP
+The simplest kill command is the C-K command.
+If issued at the beginning of a line,
+it kills all the text on the line,
+leaving it blank.
+If given on a line containing only white space (blanks and tabs)
+the line disappears.
+As a consequence,
+if you go to the front of a non-blank line and type two C-K's,
+the line disappears completely.
+.LP
+More generally,
+C-K kills from point up to the end of the line,
+unless it is at the end of a line.
+In that case,
+it kills the line separator following the line,
+thus merging the next line into the current one.
+Invisible spaces and tabs at the end of the line are ignored when
+deciding which case applies,
+so if point appears to be at the end of the line,
+you can be sure the line separator will be killed.
+.LP
+C-K with an argument of zero kills all the text before
+point on the current line.
+.NH 2
+Other Kill Commands
+.XS \n(PN 5n
+\*(SN Other Kill Commands
+.XE
+.LP
+A kill command which is very general is C-W (\fIkill-region\fP),
+which kills everything between point and the mark.*
+.FS
+*Often users switch this binding from C-W to C-X C-K because it is too
+easy to hit C-W accidentally.
+.FE
+With this command,
+you can kill and save contiguous characters,
+if you first set the mark at one end of them and go to the other end.
+.LP
+Other syntactic units can be killed, too;
+words,
+with ESC DEL and ESC D;
+and, sentences,
+with ESC K and C-X DEL.
+.NH 2
+Un-killing
+.XS \n(PN 5n
+\*(SN Un-killing (Yanking)
+.XE
+.LP
+Un-killing (yanking) is getting back text which was killed.
+The usual way to
+move or copy text is to kill it and then un-kill it one or more times.
+.IP "C-Y" 10n
+Yank (re-insert) last killed text.
+.IP "ESC Y" 10n
+Replace re-inserted killed text with the previously killed text.
+.IP "ESC W" 10n
+Save region as last killed text without killing.
+.LP
+Killed text is pushed onto a \fIring buffer\fP called the \fIkill
+ring\fP that remembers the last 10 blocks of text that were killed.
+(Why it is called a ring buffer will be explained below).
+The command C-Y (\fIyank\fP) reinserts the text of the most recent kill.
+It leaves the cursor at the end of the text,
+and puts the mark at the beginning.
+Thus,
+a single C-Y undoes the C-W.
+.LP
+If you wish to copy a block of text,
+you might want to use ESC W (\fIcopy-region\fP),
+which copies the region into the kill ring without removing it from the buffer.
+This is approximately equivalent to C-W followed by C-Y,
+except that ESC W does not mark the buffer as
+"changed" and does not cause the screen to be rewritten.
+.LP
+There is only one kill ring shared among all the buffers.
+After visiting a new file,
+whatever was last killed in the previous file is still on top of the kill ring.
+This is important for moving text between files.
+.NH 2
+Appending Kills
+.XS \n(PN 5n
+\*(SN Appending Kills
+.XE
+.LP
+Normally,
+each kill command pushes a new block onto the kill ring.
+However,
+two or more kill commands immediately in a row (without any other
+intervening commands) combine their text into a
+single entry on the ring,
+so that a single C-Y command gets it all back as it was before it was killed.
+This means that you don't have to kill all the text in one command;
+you can keep killing line after line,
+or word after word,
+until you have killed it all,
+and you can still get it all back at once.
+.LP
+Commands that kill forward from 
+.I point 
+add onto the end of the previous
+killed text.
+Commands that kill backward from 
+.I point
+add onto the beginning.
+This way,
+any sequence of mixed forward and backward kill
+commands puts all the killed text into one entry without needing rearrangement.
+.NH 2
+Un-killing Earlier Kills
+.XS \n(PN 5n
+\*(SN Un-killing Earlier Kills
+.XE
+.LP
+To recover killed text that is no longer the most recent kill,
+you need the ESC Y (\fIyank-pop\fP) command.
+The ESC Y command can be used
+only after a C-Y (yank) command or another ESC Y.
+It takes the un-killed
+text inserted by the C-Y and replaces it with the text from an earlier
+kill.
+So,
+to recover the text of the next-to-the-last kill,
+you first use C-Y to recover the last kill,
+and then discard it by use of ESC Y to move back to the previous kill.
+.LP
+You can think of all the last few kills as living on a ring.
+After a C-Y command,
+the text at the front of the ring is also present in the buffer.
+ESC Y "rotates" the ring bringing the previous string of text to the front
+and this text replaces the other text in the buffer as well.
+Enough ESC Y commands can rotate any part of the ring to the front,
+so you can get at any killed text so long as it is recent enough
+to be still in the ring.
+Eventually the ring rotates all the way
+around and the most recently killed text comes to the front
+(and into the buffer) again.
+ESC Y with a negative argument rotates the ring backwards.
+.LP
+When the text you are looking for is brought into the buffer,
+you can stop doing ESC Y's and the text will stay there.
+It's really just a copy of what's at the front of the ring,
+so editing it does not change what's in the ring.
+And the ring,
+once rotated,
+stays rotated,
+so that doing another C-Y gets another copy of what you rotated to the
+front with ESC Y.
+.LP
+If you change your
+mind about un-killing,
+C-W gets rid of the un-killed text, even
+after any number of ESC Y's.
+.NH 1
+Searching
+.XS \n(PN
+\*(SN Searching
+.XE
+.LP
+The search commands are useful for finding and moving to arbitrary
+positions in the buffer in one swift motion.
+For example,
+if you just ran the spell program on a paper
+and you want to correct some word,
+you can use the search commands to move directly to that word.  There are
+two flavors of search: \fIstring search\fP and \fIincremental search\fP.
+The former is the default flavor\(emif you want to use incremental search
+you must rearrange the key bindings (see below).
+.NH 2
+Conventional Search
+.XS \n(PN 5n
+\*(SN Conventional Search
+.XE
+.LP
+.IP "C-S" 15n
+Search forward.
+.IP "C-R" 15n
+Search backward.
+.LP
+To search for the string "FOO" you type "C-S FOO<return>".
+If \s-2JOVE\s0 finds
+FOO it moves point to the end of it; otherwise \s-2JOVE\s0 prints an error
+message and leaves point unchanged.
+C-S searches forward from point
+so only occurrences of FOO after point are found.
+To search in the other direction use C-R.
+It is exactly the same as C-S except it searches in the opposite direction,
+and if it finds the string,
+it leaves point at the beginning of it,
+not at the end as in C-S.
+.LP
+While \s-2JOVE\s0 is searching it prints the search string on the message line.
+This is so you know what \s-2JOVE\s0 is doing.
+When the system is heavily loaded and
+editing in exceptionally large buffers,
+searches can take several (sometimes many) seconds.
+.LP
+\s-2JOVE\s0 remembers the last search string you used,
+so if you want to search for the same string you can type "C-S <return>".
+If you mistyped the last search string,
+you can type C-S followed by C-R.
+C-R,
+as usual,
+inserts the default search string into the minibuffer,
+and then you can fix it up.
+.NH 2
+Incremental Search
+.XS \n(PN 5n
+\*(SN Incremental Search
+.XE
+.LP
+This search command is unusual in that is is \fIincremental\fP;
+it begins to search before you have typed the complete search string.
+As you type in the search string,
+\s-2JOVE\s0 shows you where it would be found.
+When you have typed enough characters to identify the place you want,
+you can stop.
+Depending on what you will do next,
+you may or may not need to terminate the search explicitly with a Return first.
+.LP
+The command to search is C-S (\fIi-search-forward\fP).
+C-S reads in characters and positions the cursor at the first
+occurrence of the characters that you have typed so far.
+If you type C-S and then F,
+the cursor moves in the text just after the next "F".
+Type an "O",
+and see the cursor move to after the next "FO".
+After another "O",
+the cursor is after the next "FOO".
+At the same time,
+the "FOO" has echoed on the message line.
+.LP
+If you type a mistaken character,
+you can rub it out.
+After the FOO,
+typing a DEL makes the "O" disappear from the message line,
+leaving only "FO".
+The cursor moves back in the buffer to the "FO".
+Rubbing out the "O" and "F" moves the cursor back to where you
+started the search.
+.LP
+When you are satisfied with the place you have reached,
+you can type a Return,
+which stops searching,
+leaving the cursor where the search brought it.
+Also,
+any command not specially meaningful in searches stops
+the searching and is then executed.
+Thus,
+typing C-A would exit the search and then move to the beginning of the line.
+Return is necessary only if the next character you want to type is a printing
+character,
+DEL,
+Return,
+or another search command,
+since those are the characters that have special meanings inside the search.
+.LP
+Sometimes you search for "FOO" and find it,
+but not the one you hoped to find.
+Perhaps there is a second FOO that you forgot about,
+after the one you just found.
+Then type another C-S and the cursor will find the next FOO.
+This can be done any number of times.
+If you overshoot,
+you can return to previous finds by rubbing out the C-S's.
+.LP
+After you exit a search,
+you can search for the same string again by typing just C-S C-S:
+one C-S command to start the search and then
+another C-S to mean "search again for the same string".
+.LP
+If your string is not found at all,
+the message line says "Failing I-search".
+The cursor is after the place where \s-2JOVE\s0 found as much of
+your string as it could.
+Thus,
+if you search for FOOT and there is no FOOT,
+you might see the cursor after the FOO in FOOL.
+At this point there are several things you can do.
+If your string was mistyped,
+you can rub some of it out and correct it.
+If you like the place you have found,
+you can type Return or some other \s-2JOVE\s0 command
+to "accept what the search offered".
+Or you can type C-G,
+which undoes the search altogether and positions you back where you started
+the search.
+.LP
+You can also type C-R at any time to start searching backwards.
+If a search fails because the place you started was too late in the file,
+you should do this.
+Repeated C-R's keep looking backward for more occurrences of the last search string.
+A C-S starts going forward again.
+C-R's can be rubbed out just like anything else.
+.NH 2
+Searching with Regular Expressions
+.XS \n(PN 5n
+\*(SN Searching with Regular Expressions
+.XE
+.LP
+In addition to the searching facilities described above,
+\s-2JOVE\s0
+can search for patterns using regular expressions.
+The handling of regular expressions in \s-2JOVE\s0 is like that of \fIed(1)\fP
+or \fIvi(1)\fP, but with some notable additions.
+The extra metacharacters understood by \s-2JOVE\s0 are \e<,
+\e>,
+\e\|| and \e\|{.
+The first two of these match the beginnings and endings of words;
+Thus the search pattern,
+"\|\e<Exec" would match all words beginning with the letters "Exec".
+.LP
+An \e\|| signals the beginning of an alternative \(em that is, the
+pattern "foo\e\||bar" would match either "foo" or "bar".  The "curly
+brace" is a way of introducing several sub-alternatives into a pattern.
+It parallels the [] construct of regular expressions, except it specifies
+a list of alternative words instead of just alternative characters.  So
+the pattern "foo\e\|{bar,baz\e\|}bie" matches "foobarbie" or "foobazbie".
+.LP
+\s-2JOVE\s0 only regards metacharacters as special if the variable
+\fImatch-regular-expressions\fP is set to "on".
+The ability to have \s-2JOVE\s0 ignore these characters is useful if
+you're editing a document about patterns and regular expressions or
+when a novice is learning \s-2JOVE\s0.
+.LP
+Another variable that affects searching is \fIcase-ignore-search\fP.  If
+this variable is set to "on" then upper case and lower case letters are
+considered equal.
+.NH 1
+Replacement Commands
+.XS \n(PN
+\*(SN Replacement Commands
+.XE
+.LP
+Global search-and-replace operations are not needed as often in \s-2JOVE\s0
+as they are in other editors,
+but they are available.
+In addition to
+the simple Replace operation which is like that found in most editors,
+there is a Query Replace operation which asks,
+for each occurrence of the pattern,
+whether to replace it.
+.LP
+Within the replacement string, \e\e stands for \e, \e0 stands for
+the string matched by the whole pattern (like & in \fIvi(1)\fP), \e1
+through \e9 have the same meaning as in \fIvi(1)\fP.
+.NH 2
+Global replacement
+.XS \n(PN 5n
+\*(SN Global Replacement
+.XE
+.LP
+To replace every occurrence of FOO after point with BAR,
+you can do, e.g., "ESC R FOO<return>BAR" as the \fIreplace-string\fP command
+is bound to the ESC R.
+Replacement takes place only between point and the end of the buffer
+so if you want to cover the whole buffer you must go to the beginning first.
+.NH 2
+Query Replace
+.XS \n(PN 5n
+\*(SN Query Replace
+.XE
+.LP
+If you want to change only some of the occurrences of FOO,
+not all,
+then the global \fIreplace-string\fP is inappropriate;
+Instead,
+use, e.g., "ESC Q FOO<return>BAR", to run the command \fIquery-replace-string\fP.
+This displays each occurrence of FOO and waits for you to say whether
+to replace it with a BAR.
+The things you can type when you are shown an occurrence of FOO are:
+.IP "Space" 15n
+to replace the FOO.
+.IP "DEL" 15n
+to skip to the next FOO without replacing this one.
+.IP "Return" 15n
+to stop without doing any more replacements.
+.IP "Period" 15n
+to replace this FOO and then stop.
+.IP "! or P" 15n
+to replace all remaining FOO's without asking.
+.IP "C-R or R" 15n
+to enter a recursive editing level,
+in case the FOO needs to be edited rather than just replaced with a BAR.
+When you are done,
+exit the recursive editing level with C-X C-C and the next FOO will
+be displayed.
+.IP "C-W" 15n
+to delete the FOO, and then start editing the buffer.
+When you are finished editing whatever is to replace the FOO,
+exit the recursive editing level with C-X C-C
+and the next FOO will be displayed.
+.IP "U" 15n
+move to the last replacement and undo changes to this line.
+.LP
+Another alternative is using \fIreplace-in-region\fP which is just like
+\fIreplace-string\fP except it searches only within the region.
+.LP
diff --git a/usr/src/contrib/jove-4.14.6/doc/jove.2 b/usr/src/contrib/jove-4.14.6/doc/jove.2
new file mode 100644 (file)
index 0000000..ee420dd
--- /dev/null
@@ -0,0 +1,1122 @@
+.NH 1
+Commands for English Text
+.XS \n(PN
+\*(SN Commands for English Text
+.XE
+.LP
+\s-2JOVE\s0 has many commands that work on the basic units of English text:
+words, sentences and paragraphs.
+.NH 2
+Word Commands
+.XS \n(PN 5n
+\*(SN Word Commands
+.XE
+.LP
+\s-2JOVE\s0 has commands for moving over or operating on words.
+By convention,
+they are all ESC commands.
+.IP "ESC F" 20n
+Move Forward over a word.
+.IP "ESC B" 20n
+Move Backward over a word.
+.IP "ESC D" 20n
+Kill forward to the end of a word.
+.IP "ESC DEL" 20n
+Kill backward to the beginning of a word.
+.LP
+Notice how these commands form a group that parallels the character-
+based commands,
+C-F,
+C-B,
+C-D,
+and DEL.
+.LP
+The commands ESC F and ESC B move forward and backward over words.
+They are thus analogous to Control-F and Control-B,
+which move over single characters.
+Like their Control- analogues,
+ESC F and ESC B move several words if given an argument.
+ESC F with a negative argument moves backward like ESC B,
+and ESC B with a negative argument moves forward.
+Forward motion stops right after the last letter of the word,
+while backward motion stops right before the first letter.
+.LP
+It is easy to kill a word at a time.
+ESC D kills the word after point.
+To be precise,
+it kills everything from point to the place ESC F would move to.
+Thus,
+if point is in the middle of a word,
+only the part after point is killed.
+If some punctuation comes after point,
+and before the next word,
+it is killed along with the word.
+If you wish to kill only the next word but not the punctuation,
+simply do ESC F to get to the end,
+and kill the word backwards with ESC DEL.
+ESC D takes arguments just like ESC F.
+.LP
+ESC DEL kills the word before point.
+It kills everything from point back to where ESC B would move to.
+If point is after the space in "FOO, BAR",
+then "FOO, " is killed.
+If you wish to kill just "FOO",
+then do a ESC B and a ESC D instead of a ESC DEL.
+.NH 2
+Sentence Commands
+.XS \n(PN 5n
+\*(SN Sentence Commands
+.XE
+.LP
+The \s-2JOVE\s0 commands for manipulating sentences and paragraphs are
+mostly ESC commands,
+so as to resemble the word-handling commands.
+.IP "ESC A" 20n
+Move back to the beginning of the sentence.
+.IP "ESC E" 20n
+Move forward to the end of the sentence.
+.IP "ESC K" 20n
+Kill forward to the end of the sentence.
+.IP "C-X DEL" 20n
+Kill back to the beginning of the sentence.
+.LP
+The commands ESC A and ESC E move to the beginning and end of the
+current sentence,
+respectively.
+They were chosen to resemble
+Control-A and Control-E,
+which move to the beginning and end of a line.
+Unlike them,
+ESC A and ESC E if repeated or given numeric arguments
+move over successive sentences.
+\s-2JOVE\s0 considers a sentence to end wherever there is a ".",
+"?", or "!" followed by the end of a line
+or by one or more spaces.
+Neither ESC A nor ESC E moves past the
+end of the line or spaces which delimit the sentence.
+.LP
+Just as C-A and C-E have a kill command,
+C-K,
+to go with them,
+so ESC A and ESC E have a corresponding kill command ESC K which kills from
+point to the end of the sentence.
+With minus one as an argument it
+kills back to the beginning of the sentence.
+Positive arguments serve as a repeat count.
+.LP
+There is a special command,
+C-X DEL for killing back to the beginning of a sentence,
+because this is useful when you change your
+mind in the middle of composing text.
+.NH 2
+Paragraph Commands
+.XS \n(PN 5n
+\*(SN Paragraph Commands
+.XE
+.LP
+The \s-2JOVE\s0 commands for handling paragraphs are
+.IP "ESC [" 20n
+Move back to previous paragraph beginning.
+.IP "ESC ]" 20n
+Move forward to next paragraph end.
+.LP
+ESC [ moves to the beginning of the current or previous paragraph, while
+ESC ] moves to the end of the current or next paragraph.  Paragraphs are
+delimited by lines of differing indent, or lines with text formatter
+commands, or blank lines.  \s-2JOVE\s0 knows how to deal with most indented
+paragraphs correctly, although it can get confused by one- or two-line
+paragraphs delimited only by indentation.
+.NH 2
+Text Indentation Commands
+.XS \n(PN 5n
+\*(SN Text Indentation Commands
+.XE
+.LP
+.IP "Tab" 20n
+Indent "appropriately" in a mode-dependent fashion.
+.IP "LineFeed" 20n
+Is the same as Return,
+except it copies the indent of the line you just left.
+.IP "ESC M" 20n
+Moves to the line's first non-blank character.
+.LP
+.LP
+The way to request indentation is with the Tab command.
+Its precise effect depends on the major mode.
+In \fIText\fP mode,
+it indents to the next tab stop.
+In \fIC\fP mode,
+it indents to the "right" position for C programs.
+.LP
+To move over the indentation on a line,
+do ESC M (\fIfirst-non-blank\fP).
+This command,
+given anywhere on a line,
+positions the cursor at the first non-blank, non-tab character on the line.
+.NH 2
+Text Filling
+.XS \n(PN 5n
+\*(SN Text Filling
+.XE
+.LP
+\fIAuto Fill\fP mode causes text to be \fIfilled\fP
+(broken up into lines that fit in a specified width)
+automatically as you type it in.
+If you alter existing text so that it is no longer properly filled,
+\s-2JOVE\s0 can fill it again if you ask.
+.LP
+Entering \fIAuto Fill\fP mode is done with ESC X \fIauto-fill-mode\fP.
+From then on,
+lines are broken automatically at spaces when they get longer than the
+desired width.
+To leave \fIAuto Fill\fP mode,
+once again execute ESC X \fIauto-fill-mode\fP.
+When \fIAuto Fill\fP mode is in effect,
+the word \fBFill\fP appears in the mode line.
+.LP
+If you edit the middle of a paragraph,
+it may no longer correctly be filled.
+To refill a paragraph,
+use the command ESC J (\fIfill-paragraph\fP).
+It causes the paragraph that point is inside to be filled.
+All the line breaks are removed and new ones inserted where necessary.
+.LP
+The maximum line width for filling is in the variable \fIright-margin\fP.
+Both ESC J and auto-fill make sure that no line exceeds this width.
+The value of \fIright-margin\fP is initially 78.
+.LP
+Normally ESC J figures out the indent of the paragraph and uses that same
+indent when filling.  If you want to change the indent of a paragraph you
+set \fIleft-margin\fP to the new position and type C-U\ ESC\ J.
+\fIfill-paragraph\fP, when supplied a numeric argument, uses the value of
+\fIleft-margin\fP.
+.LP
+If you know where you want to set the right margin but you don't know the
+actual value, move to where you want to set the value and use the
+\fIright-margin-here\fP command.  \fIleft-margin-here\fP does the same
+for the \fIleft-margin\fP variable.
+.NH 2
+Case Conversion Commands
+.XS \n(PN 5n
+\*(SN Case Conversion Commands
+.XE
+.LP
+.IP "ESC L" 15n
+Convert following word to lower case.
+.IP "ESC U" 15n
+Convert following word to upper case.
+.IP "ESC C" 15n
+Capitalize the following word.
+.LP
+.LP
+The word conversion commands are most useful.
+ESC L converts the word after point to lower case,
+moving past it.
+Thus,
+successive ESC L's convert successive words.
+ESC U converts to all capitals instead,
+while ESC C puts the first letter of the word into upper case and the
+rest into lower case.
+All these commands convert several words at once if given an argument.
+They are especially convenient for
+converting a large amount of text from all upper case to mixed case,
+because you can move through the test using ESC L,
+ESC U or ESC C on each word as appropriate.
+.LP
+When given a negative argument,
+the word case conversion commands apply to
+the appropriate number of words before point,
+but do not move point.
+This is convenient when you have just typed a word in the wrong case.
+You can give the case conversion command and continue typing.
+.LP
+If a word case conversion command is given in the middle of a word,
+it applies only to the part of the word which follows the cursor,
+treating it as a whole word.
+.LP
+The other case conversion functions are \fIcase-region-upper\fP and
+\fIcase-region-lower\fP,
+which convert everything between point and mark to the specified case.
+Point and mark remain unchanged.
+.NH 2
+Commands for Fixing Typos
+.XS \n(PN 5n
+\*(SN Commands for Fixing Typos
+.XE
+.LP
+In this section we describe the commands that are especially useful
+for the times when you catch a mistake on your text after you have made it,
+or change your mind while composing text on line.
+.IP "DEL" 25n
+Delete last character.
+.IP "ESC DEL" 25n
+Kill last word.
+.IP "C-X DEL" 25n
+Kill to beginning of sentence.
+.IP "C-T" 25n
+Transpose two characters.
+.IP "C-X C-T" 25n
+Transpose two lines.
+.IP "ESC Minus ESC L" 25n
+Convert last word to lower case.
+.IP "ESC Minus ESC U" 25n
+Convert last word to upper case.
+.IP "ESC Minus ESC C" 25n
+Convert last word to lower case with capital initial.
+.LP
+.NH 2
+Killing Your Mistakes
+.XS \n(PN 5n
+\*(SN Killing Your Mistakes
+.XE
+.LP
+The DEL command is the most important correction command.
+When used among printing (self-inserting) characters,
+it can be thought of as canceling the last character typed.
+.LP
+When your mistake is longer than a couple of characters,
+it might be more convenient to use ESC DEL or C-X DEL.
+ESC DEL kills back to the start of the last word,
+and C-X DEL kills back to the start of the last sentence.
+C-X DEL is particularly useful when
+you are thinking of what to write as you type it,
+in case you change your mind about phrasing.
+ESC DEL and C-X DEL save the killed text for C-Y and ESC Y to retrieve.
+.LP
+ESC DEL is often useful even when you have typed only a few
+characters wrong,
+if you know you are confused in your typing and aren't sure what you typed.
+At such a time,
+you cannot correct with
+DEL except by looking at the screen to see what you did.
+It requires less thought to kill the whole word and start over again,
+especially if the system is heavily loaded.
+.LP
+If you were typing a command or command parameters, C-G will abort the
+command with no further processing.
+.NH 2
+Transposition
+.XS \n(PN 5n
+\*(SN Transposition
+.XE
+.LP
+The common error of transposing two characters can be fixed
+with the C-T (\fItranspose-characters\fP) command.
+Normally,
+C-T transposes the two characters on either side of the cursor
+and moves the cursor forward one character.  Repeating the command
+several times "drags" a character to the right.
+(Remember that \fIpoint\fP is considered to be between two characters,
+even though the visible cursor in your terminal is on only one of them.)
+When given at the end of a line,
+rather than switching the last character of the line with the line separator,
+which would be useless,
+C-T transposes the last two characters on the line.
+So,
+if you catch your transposition error right away,
+you can fix it with just a C-T.
+If you don't catch it so fast,
+you must move the cursor back to between the two characters.
+.LP
+To transpose two lines,
+use the C-X C-T (\fItranspose-lines\fP) command.  The line containing the
+cursor is exchanged with the line above it; the cursor is left at the
+beginning of the line following its original position.
+.NH 2
+Checking and Correcting Spelling
+.XS \n(PN 5n
+\*(SN Checking and Correcting Spelling
+.XE
+.LP
+When you write a paper,
+you should correct its spelling at some point close to finishing it.
+To correct the entire buffer,
+do ESC X \fIspell-buffer\fP.
+This invokes the
+.UX
+.I spell
+program,
+which prints a list of all the misspelled words.
+\s-2JOVE\s0 catches the list and places it in a
+\s-2JOVE\s0 buffer called \fBSpell\fP.
+You are given an opportunity to delete from that buffer any words that
+aren't really errors;
+then \s-2JOVE\s0 looks up each misspelled word and
+remembers where it is in the buffer being corrected.
+Then you can go forward to each misspelled word with C-X C-N (\fInext-error\fP)
+and backward with C-X C-P (\fIprevious-error\fP).
+See the section entitled \fIError Message Parsing\fP.
+.NH 1
+File Handling
+.XS \n(PN
+\*(SN File Handling
+.XE
+.LP
+The basic unit of stored data is the file.
+Each program,
+each paper,
+lives usually in its own file.
+To edit a program or paper,
+the editor must be told the name of the file that contains it.
+This is called \fIvisiting\fP a file.
+To make your changes to the file permanent on disk,
+you must \fIsave\fP the file.
+.NH 2
+Visiting Files
+.XS \n(PN 5n
+\*(SN Visiting Files
+.XE
+.LP
+.IP "C-X C-V" 15n
+Visit a file.
+.IP "C-X C-R" 15n
+Same as C-X C-V.
+.IP "C-X C-S" 15n
+Save the visited file.
+.IP "ESC ~" 15n
+Tell \s-2JOVE\s0 to forget that the buffer has been changed.
+.LP
+.LP
+\fIVisiting\fP a file means copying its contents into \s-2JOVE\s0 where you
+can edit them.
+\s-2JOVE\s0 remembers the name of the file you visited.
+Unless you use the multiple buffer feature of \s-2JOVE\s0,
+you can only be visiting one file at a time.
+The name of the current selected buffer is visible in the mode line.
+.LP
+The changes you make with \s-2JOVE\s0 are made in a copy inside \s-2JOVE\s0.
+The file itself is not changed.
+The changed text is not permanent until you \fIsave\fP it in a file.
+The first time you change the text,
+an asterisk appears at the end of the mode line; this indicates that the text
+contains fresh changes which will be lost unless you save them.
+.LP
+To visit a file,
+use the command C-X C-V.
+Follow the command with the name of the file you wish to visit,
+terminated by a Return.
+You can abort the command by typing C-G,
+or edit the filename with many of the standard \s-2JOVE\s0 commands
+(e.g., C-A, C-E, C-F, ESC F, ESC DEL).
+If the filename you wish to visit is similar to the filename in the
+mode line (the default filename),
+you can type C-R to insert the default and then edit it.
+If you do type a Return to finish the command,
+the new file's text appears on the screen,
+and its name appears in the mode line.
+In addition,
+its name becomes the new default filename.
+.LP
+If you wish to save the file and make your changes permanent,
+type C-X C-S.
+After the save is finished,
+C-X C-S prints the filename and the
+number of characters and lines that it wrote to the file.
+If there are no changes to save (no asterisk at the end of the mode line),
+the file is not saved;
+otherwise the changes saved and the asterisk at the end of
+the mode line will disappear.
+.LP
+What if you want to create a file?  Just visit it.
+\s-2JOVE\s0 prints
+\fI(New file)\fP but aside from that behaves as if you had visited an existing
+empty file.
+If you make any changes and save them,
+the file is created.
+If you visit a nonexistent file unintentionally
+(because you typed the wrong filename),
+go ahead and visit the file you meant.
+If you don't save the unwanted file,
+it is not created.
+.LP
+If you alter one file and then visit another in the same buffer,
+\s-2JOVE\s0 offers to save the old one.
+If you answer YES,
+the old file is saved;
+if you answer NO,
+all the changes you have made to it since the last save are lost.
+You should not type ahead after a file visiting
+command,
+because your type-ahead might answer an unexpected question
+in a way that you would regret.
+.LP
+Sometimes you will change a buffer by accident.
+Even if you undo the effect of the change by editing,
+\s-2JOVE\s0 still knows that "the buffer has been changed".
+You can tell \s-2JOVE\s0 to pretend that there have been no changes with the
+ESC \s+2~\s0 command (\fImake-buffer-unmodified\fP).
+This command simply clears the "modified" flag which
+says that the buffer contains changes which need to be saved.
+Even if
+the buffer really \fIis\fP changed \s-2JOVE\s0 will still act as if it were not.
+.LP
+If \s-2JOVE\s0 is about to save a file and sees that the date of the version
+on disk does not match what \s-2JOVE\s0 last read or wrote,
+\s-2JOVE\s0 notifies you of this fact,
+and asks what to do, because this probably means that something is wrong.
+For example,
+somebody else may have been editing the same file.
+If this is so,
+there is a good chance that your work
+or his work will be lost if you don't take the proper steps.
+You should first find out exactly what is going on.
+If you determine that somebody else has modified the file,
+save your file under a different filename and then DIFF the two files
+to merge the two sets of changes.  (The "patch" command is useful for
+applying the results of context diffs directly).
+Also get in touch with the other person so that the files don't diverge
+any further.
+.NH 2
+How to Undo Drastic Changes to a File
+.XS \n(PN 5n
+\*(SN How to Undo Drastic Changes to a File
+.XE
+.LP
+If you have made several extensive changes to a file and then change
+your mind about them,
+and you haven't yet saved them,
+you can get rid of them by reading in the previous version of the file.
+You can do this with the C-X C-V command,
+to visit the unsaved version of the file.
+.NH 2
+Recovering from system/editor crashes
+.XS \n(PN 5n
+\*(SN Recovering from system/editor crashes
+.XE
+.LP
+JOVE does not have \fIAuto Save\fP mode, but it does provide a way to
+recover your work in the event of a system or editor crash.  JOVE saves
+information about the files you're editing every so many changes to a
+buffer to make recovery possible.  Since a relatively small amount of
+information is involved it's hardly even noticeable when JOVE does this.  The
+variable "sync-frequency" says how often to save the necessary
+information, and the default is every 50 changes.  50 is a very
+reasonable number: if you are writing a paper you will not lose more than
+the last 50 characters you typed, which is less than the average length
+of a line.
+.NH 2
+Miscellaneous File Operations
+.XS \n(PN 5n
+\*(SN Miscellaneous File Operations
+.XE
+.LP
+.LP
+ESC X \fIwrite-file\fP <file><return> writes the contents of the buffer
+into the file <file>,
+and then visits that file.
+It can be thought of as a way of "changing the name" of
+the file you are visiting.
+Unlike C-X C-S,
+\fIwrite-file\fP saves even if the buffer has not been changed.
+C-X C-W is another way of getting this command.
+.LP
+ESC X \fIinsert-file\fP <file><return> inserts the contents of <file> into the
+buffer at point,
+leaving point unchanged before the contents.
+You can also use C-X C-I to get this command.
+.LP
+ESC X \fIwrite-region\fP <file><return> writes the region (the text between
+point and mark) to the specified file.
+It does not set the visited filename.
+The buffer is not changed.
+.LP
+ESC X \fIappend-region\fP <file><return> appends the region to <file>.
+The text is added to the end of <file>.
+.NH 1
+Using Multiple Buffers
+.XS \n(PN
+\*(SN Using Multiple Buffers
+.XE
+.LP
+When we speak of "the buffer",
+which contains the text you are editing,
+we have given the impression that there is only one.
+In fact,
+there may be many of them,
+each with its own body of text.
+At any time only one buffer can be \fIselected\fP and available for editing,
+but it isn't hard to switch to a different one.
+Each buffer individually remembers which file it is visiting,
+what modes are in effect,
+and whether there are any changes that need saving.
+.IP "C-X B" 15n
+Select or create a buffer.
+.IP "C-X C-F" 15n
+Visit a file in its own buffer.
+.IP "C-X C-B" 15n
+List the existing buffers.
+.IP "C-X K" 15n
+Kill a buffer.
+.LP
+Each buffer in \s-2JOVE\s0 has a single name,
+which normally doesn't change.
+A buffer's name can be any length.
+The name of the currently selected buffer
+and the name of the file visited in it
+are visible in the mode line when you are at top level.
+A newly started \s-2JOVE\s0 has only one buffer,
+named \fBMain\fP, unless you specified files to edit in the
+shell command that started \s-2JOVE\s0.
+.NH 2
+Creating and Selecting Buffers
+.XS \n(PN 5n
+\*(SN Creating and Selecting Buffers
+.XE
+.LP
+To create a new buffer,
+you need only think of a name for it (say, FOO)
+and then do C-X B FOO<return>,
+which is the command C-X B (\fIselect-buffer\fP) followed by the name.
+This makes a new,
+empty buffer (if one by that name didn't previously exist) 
+and selects it for editing.
+The new buffer is not visiting any file,
+so if you try to save it you will be asked for the filename to use.
+Each buffer has its own major mode;
+the new buffer's major mode is \fIText\fP mode by default.
+.LP
+To return to buffer FOO later after having switched to another,
+the same command C-X B FOO<return> is used,
+since C-X B can tell whether a buffer named FOO exists already or not.
+C-X B Main<return> reselects the buffer Main that \s-2JOVE\s0 started out with.
+Just C-X B<return> reselects the previous buffer.
+Repeated C-X B<return>'s alternate between the last two buffers selected.
+.LP
+You can also read a file into its own newly created buffer,
+all with one command: C-X C-F (\fIfind-file\fP),
+followed by the filename.
+The name of the buffer is the last element of the file's pathname.
+C-F stands for "Find",
+because if the specified file already resides in a buffer in your \s-2JOVE\s0,
+that buffer is reselected.
+So you need not remember whether you have brought the file in already or not.
+A buffer created by C-X C-F can be reselected later with C-X B or C-X C-F,
+whichever you find more convenient.
+Nonexistent files can be created with C-X C-F just as they can with C-X C-V.
+.NH 2
+Using Existing Buffers
+.XS \n(PN 5n
+\*(SN Using Existing Buffers
+.XE
+.LP
+To get a list of all the buffers that exist,
+do C-X C-B (\fIlist-buffers\fP).
+Each buffer's type,
+name,
+and visited filename is printed.
+An asterisk before the buffer name indicates a
+buffer which contains changes that have not been saved. The number
+that appears at the beginning of a line in a C-X C-B listing is that
+buffer's \fIbuffer number\fP.
+You can select a buffer by typing its number in place of its name.
+If a buffer with that number doesn't already exist,
+a new buffer is created with that number as its name.
+.LP
+If several buffers have modified text in them,
+you should save some of them with C-X C-M (\fIwrite-modified-files\fP).
+This finds all the buffers that need saving and then saves them.
+Saving the buffers this way is much
+easier and more efficient (but more dangerous)
+than selecting each one and typing C-X C-S.
+If you give C-X C-M an argument, \s-2JOVE\s0 will ask for confirmation
+before saving each buffer.
+.LP
+ESC X \fIrename-buffer\fP <new name><return> changes the name of the currently
+selected buffer.
+.LP
+ESC X \fIerase-buffer\fP <buffer name><return> erases the contents of the
+<buffer name> without deleting the buffer entirely.
+.NH 2
+Killing Buffers
+.XS \n(PN 5n
+\*(SN Killing Buffers
+.XE
+.LP
+After you use a \s-2JOVE\s0 for a while,
+it may fill up with buffers which you no longer need.
+Eventually you can reach a point where trying to
+create any more results in an "out of memory" or "out of lines"
+error.
+When this happens you will want to kill some buffers with the
+C-X K (\fIdelete-buffer\fP) command.
+You can kill the buffer FOO by doing C-X K FOO<return>.
+If you type C-X K <return> JOVE will kill the previously selected buffer.
+If you try to kill a buffer that needs saving \s-2JOVE\s0
+will ask you to confirm it.
+.LP
+If you need to kill several buffers, use the command \fIkill-some-buffers\fP.
+This prompts you with the name of each buffer and asks for confirmation
+before killing that buffer.
+.NH 1
+Controlling the Display
+.XS \n(PN
+\*(SN Controlling the Display
+.XE
+.LP
+Since only part of a large file will fit on the screen,
+\s-2JOVE\s0 tries to show the part that is likely to be interesting.
+The display control commands allow you to see a different part of the file.
+.IP "C-L" 15n
+Reposition point at a specified vertical position,
+OR clear and redraw the screen with point in the same place.
+.IP "C-V" 15n
+Scroll forwards (a screen or a few lines).
+.IP "ESC V" 15n
+Scroll backwards.
+.IP "C-Z" 15n
+Scroll forward some lines.
+.IP "ESC Z" 15n
+Scroll backwards some lines.
+.LP
+.LP
+The terminal screen is rarely large enough to display all of your
+file.
+If the whole buffer doesn't fit on the screen,
+\s-2JOVE\s0 shows a contiguous portion of it,
+containing 
+.I point.
+It continues to show approximately the same portion
+until point moves outside of what is displayed;
+then \s-2JOVE\s0 chooses a new portion centered around the new 
+.I point.
+This is \s-2JOVE\s0's guess as to what you are most interested in seeing,
+but if the guess is wrong,
+you can use the display control commands to see a different portion.
+The available screen area through which you can see part of
+the buffer is called \fIthe window\fP,
+and the choice of where in the
+buffer to start displaying is also called \fIthe window\fP.  (When 
+there is only one window, it plus the mode line and the input line take
+up the whole screen).
+.LP
+First we describe how \s-2JOVE\s0 chooses a new window position on its own.
+The goal is usually to place 
+.I point 
+half way down the window.
+This is controlled by the variable \fIscroll-step\fP,
+whose value is the number of
+lines above the bottom or below the top of the window that the line
+containing point is placed.
+A value of 0 (the initial value) means center 
+.I point
+in the window.
+.LP
+The basic display control command is C-L (\fIredraw-display\fP).
+In its simplest form,
+with no argument,
+it tells \s-2JOVE\s0 to choose a new window position,
+centering point half way from the top as usual.
+.LP
+C-L with a positive argument chooses a new window so as to put point
+that many lines from the top.
+An argument of zero puts point on the very top line.
+Point does not move with respect to the text; rather,
+the text and point move rigidly on the screen.
+.LP
+If point stays on the same line,
+the window is first cleared and then redrawn.
+Thus,
+two C-L's in a row are guaranteed to clear the current window.
+ESC C-L will clear and redraw the entire screen.
+.LP
+The \fIscrolling\fP commands C-V,
+ESC V,
+C-Z,
+and ESC Z,
+let you move the whole display up or down a few lines.
+C-V (\fInext-page\fP) with an
+argument shows you that many more lines at the bottom of the screen,
+moving the text and point up together as C-L might.
+C-V with a
+negative argument shows you more lines at the top of the screen,
+as does ESC V (\fIprevious-page\fP) with a positive argument.
+.LP
+To read the buffer a window at a time,
+use the C-V command with no argument.
+It takes the last line at the bottom of the window and puts
+it at the top,
+followed by nearly a whole window of lines not visible before.
+Point is put at the top of the window.
+Thus, each C-V shows the "next page of text",
+except for one line of overlap to provide context.
+To move backward,
+use ESC V without an argument,
+which moves a whole window backwards (again with a line of overlap).
+.LP
+C-Z and ESC Z scroll one line forward and one line backward,
+respectively.
+These are convenient for moving in units of lines
+without having to type a numeric argument.
+.NH 2
+Multiple Windows
+.XS \n(PN 5n
+\*(SN Multiple Windows
+.XE
+.LP
+\s-2JOVE\s0 allows you to split the screen into two or more \fIwindows\fP and
+use them to display parts of different files,
+or different parts of the same file.
+.IP "C-X 2" 15n
+Divide the current window into two smaller ones.
+.IP "C-X 1" 15n
+Delete all windows but the current one.
+.IP "C-X D" 15n
+Delete current window.
+.IP "C-X N" 15n
+Switch to the next window.
+.IP "C-X P" 15n
+Switch to the previous window.
+.IP "C-X O" 15n
+Same as C-X P.
+.IP "C-X ^" 15n
+Make this window bigger.
+.IP "ESC C-V" 15n
+Scroll the other window.
+.LP
+.LP
+When using \fImultiple window\fP mode,
+the text portion of the screen
+is divided into separate parts called \fIwindows\fP,
+which can display different pieces of text.
+Each window can display different files,
+or parts of the same file.
+Only one of the windows is 
+.I active; 
+that is
+the window which the cursor is in.
+Editing normally takes place in that window alone.
+To edit in another window,
+you would give a command to move the cursor to the other window,
+and then edit there.
+.LP
+Each window displays a mode line for the buffer it's displaying.
+This is useful to keep track of which window corresponds with which
+file.  In addition, the mode line serves as a separator between windows.
+By setting the variable \fImode-line-should-standout\fP to "on" you can
+have \s-2JOVE\s0 display the mode-line in reverse video (assuming your
+particular terminal has the reverse video capability).
+.LP
+The command C-X 2 (\fIsplit-current-window\fP) enters multiple window mode.
+A new mode line appears across the middle of the screen,
+dividing the text display area into two halves.
+Both windows contain the same buffer and display the same position in it,
+namely where point was at the time you issued the command.
+The cursor moves to the second window.
+.LP
+To return to viewing only one window,
+use the command C-X 1 (\fIdelete-other-windows\fP).
+The current window expands to fill the whole screen,
+and the other windows disappear until the next C-X 2.
+(The buffers and their contents are unaffected by any of the
+window operations).
+.LP
+While there is more than one window,
+you can use C-X N (\fInext-window\fP) to switch to the next window,
+and C-X P (\fIprevious-window\fP) to switch to the previous one.
+If you are in the bottom window and you type C-X N,
+you will be placed in the top window,
+and the same kind of thing happens when you type C-X P in the top window,
+namely you will be placed in the bottom window.
+C-X O is the same as C-X P.
+It stands for "other window" because when there are only two windows,
+repeated use of this command will switch between the two windows.
+.LP
+Often you will be editing one window while using the other just for reference.
+Then,
+the command ESC C-V (\fIpage-next-window\fP) is very useful.
+It scrolls the next window,
+as if you switched to the next window,
+typed C-V,
+and switched back,
+without your having to do all that.
+With a negative argument,
+ESC C-V will do an ESC V in the next window.
+.LP
+When a window splits,
+both halves are approximately the same size.
+You can redistribute the screen space between the windows with
+the C-X ^ (\fIgrow-window\fP) command.
+It makes the currently selected window grow one line bigger,
+or as many lines as is specified with a numeric argument.
+Use ESC X \fIshrink-window\fP to make the current window smaller.
+.NH 2
+Multiple Windows and Multiple Buffers
+.XS \n(PN 5n
+\*(SN Multiple Windows and Multiple Buffers
+.XE
+.LP
+Buffers can be selected independently in each window.
+The C-X B command selects a new buffer in whichever window contains
+the cursor.
+Other windows' buffers do not change.
+.LP
+You can view the same buffer in more than one window.
+Although the same buffer appears in both windows,
+they have different values of point,
+so you can move around in one window while the other window
+continues to show the same text.
+Then,
+having found one place you wish to refer to, you can go back into the
+other window with C-X O or C-X P to make your changes.
+.LP
+If you have the same buffer in both windows,
+you must beware of trying to visit a different file in one of
+the windows with C-X C-V,
+because if you bring a new file into this buffer,
+it will replaced the old file in \fIboth\fP windows.
+To view different files in different windows,
+you must switch buffers in one of the windows first
+(with C-X B or C-X C-F, perhaps).
+.LP
+A convenient "combination" command for viewing something in another
+window is C-X 4 (\fIwindow-find\fP).
+With this command you can ask to see any specified buffer,
+file or tag in the other window.
+Follow the C-X 4 with either B and a buffer name,
+F and a filename,
+or T and a tag name.
+This switches to the other window and finds there what you specified.
+If you were previously in one-window mode,
+multiple-window mode is entered.
+C-X 4 B is similar to C-X 2 C-X B.
+C-X 4 F is similar to C-X 2 C-X C-F.
+C-X 4 T is similar to C-X 2 C-X
+T.
+The difference is one of efficiency,
+and also that C-X 4 works equally well if you are already using two windows.
+.NH 1
+Processes Under \s-2JOVE\s0
+.XS \n(PN
+\*(SN Processes Under \s-2JOVE\s0
+.XE
+.LP
+Another feature in \s-2JOVE\s0 is its ability to interact with
+.UX
+in a useful way.
+You can run other
+.UX
+commands from \s-2JOVE\s0 and catch their output in \s-2JOVE\s0 buffers.
+In this chapter we will discuss the different
+ways to run and interact with
+.UX
+commands.
+.NH 2
+Non-interactive
+.UX
+commands
+.XS \n(PN 5n
+\*(SN Non-interactive
+.XE
+.LP
+To run a
+.UX
+command from \s-2JOVE\s0 just type "C-X !" followed by the name
+of the command terminated with Return.
+For example,
+to get a list of all the users on the system,
+you do:
+.DS I
+C-X ! who<return>
+.DE
+Then \s-2JOVE\s0 picks a reasonable buffer in which the output from the
+command will be placed.
+E.g.,
+"who" uses a buffer called \fBwho\fP;
+"ps alx" uses \fBps\fP;
+and "fgrep -n foo *.c" uses \fBfgrep\fP.
+If \s-2JOVE\s0
+wants to use a buffer that already exists it first erases the old contents.
+If the buffer it selects holds a file,
+not output from a previous shell command,
+you must first delete that buffer with C-X K.
+.LP
+Once \s-2JOVE\s0 has picked a buffer it puts that buffer in a window so you
+can see the command's output as it is running.
+If there is only one window \s-2JOVE\s0 will automatically make another one.
+Otherwise,
+\s-2JOVE\s0
+tries to pick the most convenient window which isn't the current one.
+.LP
+It's not a good idea to type anything while the command is running.
+There are two reasons for this:
+.IP (i)
+\s-2JOVE\s0 won't see the characters (thus won't execute them) until the
+command finishes,
+so you may forget what you've typed.
+.IP (ii)
+Although \s-2JOVE\s0 won't know what you've typed,
+it 
+.I will
+know that you've typed something,
+and then it will try to be "smart" and not update the
+display until it's interpreted what you've typed.
+But,
+of course,
+\s-2JOVE\s0 won't interpret what you type until the
+.UX
+command completes,
+so you're left with the uneasy feeling you get when you
+don't know what the hell the computer is doing*.
+.FS
+*This is a bug and should be fixed,
+but probably won't be for a while.
+.FE
+.LP
+If you want to interrupt the command for some reason (perhaps you
+mistyped it, or you changed your mind) you can type C-].
+Typing this
+inside \s-2JOVE\s0 while a process is running is the same as typing C-C when
+you are outside \s-2JOVE\s0,
+namely the process stops in a hurry.
+.LP
+When the command finishes, \s-2JOVE\s0 puts you back in the window in which 
+you started.
+Then it prints a message indicating whether or not the command
+completed successfully in its (the command's) opinion.
+That is,
+if the command had what it considers an error
+(or you interrupt it with C-])
+\s-2JOVE\s0 will print an appropriate message.
+
+.NH 2
+Limitations of Non-Interactive Processes
+.XS \n(PN 5n
+\*(SN Limitations of Non-Interactive Processes
+.XE
+.LP
+The reason these are called non-interactive processes is that you
+can't type any input to them; you can't interact with them; they can't
+ask you questions because there is no way for you to answer.
+For example,
+you can't run a command interpreter (a shell), or 
+.I mail
+or 
+.I crypt
+with C-X ! because there is no way to provide it with input.
+Remember that \s-2JOVE\s0 (not the process in the window)
+is listening to your keyboard,
+and \s-2JOVE\s0 waits until the process dies before it looks at
+what you type.
+.LP
+C-X ! is useful for running commands that do some output and then exit.
+For example,
+it's very useful to use with the C compiler to
+catch compilation error messages (see Compiling C Programs),
+or with the \fIgrep\fP commands.
+.NH 2
+Interactive Processes \(em Run a Shell in a Window
+.XS \n(PN 5n
+\*(SN Interactive Processes \(em Run a Shell in a Window
+.XE
+.LP
+Some versions of \s-2JOVE\s0\(dg
+.FS
+\(dg For example, the version provided with 4.3BSD.
+.FE
+have the capability of running interactive
+processes.
+This is more useful than non-interactive processes for
+certain types of jobs:
+.IP (i)
+You can go off and do some editing while the command is running.
+This is useful for commands that do sporadic output and run for fairly long
+periods of time.
+.IP (ii)
+Unlike non-interactive processes,
+you can type input to these.
+In addition,
+you can edit what you type with the power of all the \s-2JOVE\s0
+commands \fIbefore\fP you send the input to the process.
+This is a really important feature,
+and is especially useful for running a shell in a window.
+.IP (iii)
+Because you can continue with normal editing while one of the
+processes is running,
+you can create a bunch of contexts and manage them
+(select them, delete them, or temporarily put them aside)
+with \s-2JOVE\s0's window and buffer mechanisms.
+.LP
+Although we may have given an image of processes being attached to 
+.I windows,
+in fact they are attached to 
+.I buffers.
+Therefore,
+once an \fIi-process\fP is running you can select another buffer into that window,
+or if you wish you can delete the window altogether.
+If you reselect that buffer later it will be up to date.
+That is,
+even though the
+buffer wasn't visible it was still receiving output from the process.
+You don't have to worry about missing anything when the buffer isn't visible.
+.NH 2
+Advantages of Running Processes in \s-2JOVE\s0 Windows.
+.XS \n(PN 5n
+\*(SN Advantages of Running Processes in \s-2JOVE\s0 Windows.
+.XE
+.LP
+There are several advantages to running a shell in a window.
+What you type isn't seen immediately by the process;
+instead \s-2JOVE\s0 waits until
+you type an entire line before passing it on to the process to read.
+This means that before you type <return>
+all of \s-2JOVE\s0's editing
+capabilities are available for fixing errors on your input line.
+If you discover an error at the beginning of the line,
+rather than erasing the whole line and starting over,
+you can simply move to the error,
+correct it,
+move back and continue typing.
+.LP
+Another feature is that you have the entire history of your session in
+a \s-2JOVE\s0 buffer.
+You don't have to worry about output from a command
+moving past the top of the screen.
+If you missed some output you can
+move back through it with ESC V and other commands.
+In addition,
+you can save yourself retyping a command (or a similar one) by sending
+edited versions of previous commands, or edit the output of one command
+to become a list of commands to be executed ("immediate shell scripts").
+.NH 2
+Differences between Normal and I-process Buffers
+.XS \n(PN 5n
+\*(SN Differences between Normal and I-process Buffers
+.XE
+.LP
+\s-2JOVE\s0 behaves differently in several ways when you are in an \fIi-process\fP
+buffer.
+Most obviously, <return> does different things
+depending on both your position in the buffer and on the state of the process.
+In the normal case,
+when point is at the end of the buffer,
+Return does what you'd expect: it inserts a line-separator and then
+sends the line to the process.
+If you are somewhere else in the buffer,
+possibly positioned at a previous command that you want to edit,
+Return will place a copy of that line
+(with the prompt discarded if there is one)
+at the end of the buffer and move you there.
+Then you can edit the line and type Return as in the normal case.
+If the process has died for some reason,
+Return does nothing.
+It doesn't even insert itself.
+If that happens unexpectedly,
+you should type ESC X \fIlist-processes\fP<return>
+to get a list of each process and its state.
+If your process died abnormally,
+\fIlist-processes\fP may help you figure out why.
+.NH 2
+How to Run a Shell in a Window
+.XS \n(PN 5n
+\*(SN How to Run a Shell in a Window
+.XE
+.LP
+Type ESC X \fIshell\fP<return> to start up a shell.
+As with C-X !,
+\s-2JOVE\s0 will
+create a buffer,
+called \fB*shell*\-1\fP,
+and select a window for this new buffer.
+But unlike C-X ! you will be left in the new window.
+Now,
+the shell process is said to be attached to \fBshell\-1\fP.
diff --git a/usr/src/contrib/jove-4.14.6/doc/jove.3 b/usr/src/contrib/jove-4.14.6/doc/jove.3
new file mode 100644 (file)
index 0000000..e760a96
--- /dev/null
@@ -0,0 +1,427 @@
+.NH 1
+Directory Handling
+.XS \n(PN
+\*(SN Directory Handling
+.XE
+.LP
+To save having to use absolute pathnames when you want to edit a nearby file
+\s-2JOVE\s0 allows you to move around the
+.UX
+filesystem just as the c-shell does.
+These commands are:
+.IP "cd dir" 15n
+Change to the specified directory.
+.IP "pushd [dir]"
+Like \fIcd\fP, but save the old directory on the directory stack.
+With no directory argument, simply exchange the top two directories
+on the stack and \fIcd\fP to the new top.
+.IP "popd"
+Take the current directory off the stack and \fIcd\fP to the directory now
+at the top.
+.IP "dirs"
+Display the contents of the directory stack.
+.LP
+The names and behavior of these commands were chosen to mimic those in the c-shell.
+.NH 1
+Editing C Programs
+.XS \n(PN
+\*(SN Editing C Programs
+.XE
+.LP
+This section details the support provided by \s-2JOVE\s0
+for working on C programs.
+.NH 2
+Indentation Commands
+.XS \n(PN 5n
+\*(SN Indentation Commands
+.XE
+.LP
+To save having to lay out C programs "by hand", \s-2JOVE\s0
+has an idea of the correct indentation of a line,
+based on the surrounding context.
+When you are in C Mode, \s-2JOVE\s0 treats tabs specially \(em
+typing a tab at the beginning of a new line means "indent to
+the right place".
+Closing braces are also handled specially, and are indented
+to match the corresponding open brace.
+.NH 2
+Parenthesis and Brace Matching
+.XS \n(PN 5n
+\*(SN Parenthesis and Brace Matching
+.XE
+.LP
+To check that parentheses and braces match the way you think they do,
+turn on \fIShow Match\fP mode (ESC X show-match-mode).  Then, whenever
+you type a close brace or parenthesis, the cursor moves momentarily to
+the matching opener, if it's currently visible.  If it's not visible,
+\s-2JOVE\s0 displays the line containing the matching opener on the message
+line.
+.NH 2
+C Tags
+.XS \n(PN 5n
+\*(SN C Tags
+.XE
+.LP
+Often when you are editing a C program,
+especially someone else's code,
+you see a function call and wonder what that function does.
+You then search for the function within the current file and if you're
+lucky find
+the definition, finally returning to the original spot when you are done.
+However, if are unlucky, the function turns out to be external
+(defined in another file) and
+you have to suspend the edit,
+\fIgrep\fP for the function name in every .c that might contain it,
+and finally visit the appropriate file.
+.LP
+To avoid this diversion or the need to remember which
+function is defined in which file,
+Berkeley 
+.UX
+has a program called \fIctags(1)\fP, which
+takes a set of source files and looks for function
+definitions, producing a file called \fItags\fP as its output.
+.LP
+\s-2JOVE\s0 has a command called C-X T (\fIfind-tag\fP)
+that prompts you for the name of a function (a \fItag\fP), looks up
+the tag reference in the previously constructed tags file, 
+then visits the file containing that tag in a new buffer,
+with point positioned at the definition of the function.
+There is another version of this command, namely \fIfind-tag-at-point\fP,
+that uses the identifier at 
+.I point.
+.LP
+So, when you've added new functions to a module, or moved some old
+ones around, run the \fIctags\fP program to regenerate the \fItags\fP file.
+\s-2JOVE\s0 looks in the file specified in the \fItag-file\fP variable.  The
+default is "./tags", that is, the tag file in the current directory.  If you
+wish to use an alternate tag file, you use C-U\ C-X\ T, and \s-2JOVE\s0 will
+prompt for a file name.  If you find yourself specifying the same file again
+and again, you can set \fItag-file\fP to that file, and run
+\fIfind-tag\fP with no numeric argument.
+.LP
+To begin an editing session looking for a particular tag, use
+the \fI\-t tag\fP command line option to \s-2JOVE\s0.
+For example, say you wanted to look at the file containing the tag
+\fISkipChar\fP, you would invoke \s-2JOVE\s0 as:
+.DS I
+.I
+% jove \-t SkipChar
+.R
+.DE
+.NH 2
+Compiling Your Program
+.XS \n(PN 5n
+\*(SN Compiling Your Program
+.XE
+.LP
+You've typed in a program or altered an existing one and now you
+want to run it through the compiler to check for errors.
+To save having to suspend the edit,
+run the compiler,
+scribble down error messages, and then resume the edit,
+\s-2JOVE\s0 allows you to compile your code while in the editor.
+This is done with the C-X C-E (\fIcompile-it\fP) command.
+If you run \fIcompile-it\fP with no argument
+it runs the
+.UX
+\fImake\fP
+program into a buffer;
+If you need a special command or want to pass arguments to \fImake\fP,
+run \fIcompile-it\fP with any argument (C-U is good enough) and you
+will be prompted for the command to execute.
+.LP
+If any error messages are produced, they are treated specially by \s-2JOVE\s0.
+That treatment is the subject of the next section.
+.NH 2
+Error Message Parsing and Spelling Checking
+.XS \n(PN
+\*(SN Error Message Parsing
+\*(SN Spelling Checking
+.XE
+.LP
+\s-2JOVE\s0 knows how to interpret the error messages from many
+.UX
+commands;
+In particular,
+the messages from \fIcc\fP,
+\fIgrep\fP and \fIlint\fP can be understood.
+After running the \fIcompile-it\fP command,
+the \fIparse-errors\fP command is automatically executed,
+and any errors found are displayed in a new buffer.
+The files whose names are found in parsing the error messages are each
+brought into \s-2JOVE\s0 buffers and the point is positioned at the first error
+in the first file.
+The commands \fIcurrent-error\fP, C-X C-N (\fInext-error\fP), and
+C-X C-P (\fIprevious-error\fP)
+can be used to traverse the list of errors.
+.LP
+If you already have a file called
+\fIerrs\fP containing, say, c compiler messages then you can get \s-2JOVE\s0 to interpret the messages by
+invoking it as:
+.DS I
+.I
+% jove \-p errs
+.R
+.DE
+.LP
+\s-2JOVE\s0 has a special mechanism for checking the the spelling of a document;
+It runs the
+.UX
+spell program into a buffer.
+You then delete from this buffer all those words that are not spelling
+errors and then \s-2JOVE\s0 runs the \fIparse-spelling-errors\fP command to
+yield a list of errors just as in the last section.
+.NH 1
+Simple Customization
+.XS \n(PN
+\*(SN Simple Customization
+.XE
+.LP
+.NH 2
+Major Modes
+.XS \n(PN 5n
+\*(SN Major Modes
+.XE
+.LP
+To help with editing particular types of file, say a paper or a C program,
+\s-2JOVE\s0 has several \fImajor modes\fP.
+These are as follows:
+.NH 3
+Text mode
+.XS \n(PN 10n
+\*(SN Text mode
+.XE
+.LP
+This is the default major mode.  Nothing special is done.
+.NH 3
+C mode
+.XS \n(PN 10n
+\*(SN C mode
+.XE
+.LP
+This mode affects the behavior of the tab and parentheses characters.
+Instead of just inserting the tab, \s-2JOVE\s0 determines
+where the text "ought" to line up for the C language and tabs to that position
+instead.  The same thing happens with the close brace and close parenthesis;
+they are tabbed to the "right" place and then inserted.
+Using the \fIauto-execute-command\fP command, you can make \s-2JOVE\s0 enter
+\fIC Mode\fP whenever you edit a file whose name ends in \fI.c\fP.
+.NH 3
+Lisp mode
+.XS \n(PN 10n
+\*(SN Lisp mode
+.XE
+.LP
+This mode is analogous to \fIC Mode\fP,
+but performs the indentation needed to lay out Lisp programs properly.
+Note also the \fIgrind-s-expr\fP command that prettyprints an
+\fIs-expression\fP and the \fIkill-mode-expression\fP command.
+.NH 2
+Minor Modes
+.XS \n(PN 5n
+\*(SN Minor Modes
+.XE
+.LP
+In addition to the major modes,
+\s-2JOVE\s0 has a set of minor modes.
+These are as follows:
+.NH 3
+Auto Indent
+.XS \n(PN 10n
+\*(SN Auto Indent
+.XE
+.LP
+In this mode,
+\s-2JOVE\s0 indents each line the same way as that above it.  That is,
+the Return key in this mode acts as the Linefeed key ordinarily does.
+.NH 3
+Show Match
+.XS \n(PN 10n
+\*(SN Show Match
+.XE
+.LP
+Move the cursor momentarily to the matching opening parenthesis when a closing
+parenthesis is typed.
+.NH 3
+Auto Fill
+.XS \n(PN 10n
+\*(SN Auto Fill
+.XE
+.LP
+In \fIAuto Fill\fP mode,
+a newline is automatically inserted when the line length
+exceeds the right margin.
+This way,
+you can type a whole paper without having to use the Return key.
+.NH 3
+Over Write
+.XS \n(PN 10n
+\*(SN Over Write
+.XE
+.LP
+In this mode,
+any text typed in will replace the previous contents.
+(The default is for new text to be inserted and "push" the old along.)
+This is useful for editing an already-formatted diagram in which you
+want to change some things without moving other things around on the
+screen.
+.NH 3
+Word Abbrev
+.XS \n(PN 10n
+\*(SN Word Abbrev
+.XE
+.LP
+In this mode, every word you type is compared to a list of word
+abbreviations; whenever you type an abbreviation, it is replaced
+by the text that it abbreviates.
+This can save typing if a particular word or phrase must be entered
+many times.
+The abbreviations and their expansions are held in a file that looks like:
+.DS I
+abbrev:phrase
+.DE
+This file can be set up in your \fI~/.\|joverc\fP with the \fIread-word-abbrev-file\fP command.
+Then, whenever you are editing a buffer in \fIWord Abbrev\fP mode,
+\s-2JOVE\s0 checks for the abbreviations you've given.
+See also the commands
+\fIread-word-abbrev-file\fP,
+\fIwrite-word-abbrev-file\fP,
+\fIedit-word-abbrevs\fP,
+\fIdefine-global-word-abbrev\fP,
+\fIdefine-mode-word-abbrev\fP,
+and \fIbind-macro-to-word-abbrev\fP,
+and the variable \fIauto-case-abbrev\fP.
+.NH 2
+Variables
+.XS \n(PN 5n
+\*(SN Variables
+.XE
+.LP
+\s-2JOVE\s0 can be tailored to suit your needs by changing the
+values of variables.
+A \s-2JOVE\s0 variable can be given a value with the \fIset\fP command,
+and its value displayed with the \fIprint\fP command.
+.LP
+The variables \s-2JOVE\s0 understands are listed along with the commands
+in the alphabetical list at the end of this document.
+.NH 2
+Key Re-binding
+.XS \n(PN 5n
+\*(SN Key Re-binding
+.XE
+.LP
+Many of the commands built into \s-2JOVE\s0 are not bound to
+specific keys.
+The command handler in
+\s-2JOVE\s0 is used to invoke these commands and is activated
+by the \fIexecute-extended-command\fP command (ESC X).
+When the name of a command typed in is unambiguous,
+that command will be executed.
+Since it is very slow to have
+to type in the name of each command every time it is needed,
+\s-2JOVE\s0 makes it possible to \fIbind\fP commands to keys.
+When a command is
+\fIbound\fP to a key any future hits on that key will invoke that command.
+All the printing characters are initially bound to the
+command \fIself-insert\fP.
+Thus, typing any printing character causes it to be inserted into the text.
+Any of the existing commands can be bound to any key.
+(A \fIkey\fP may actually be a \fIcontrol character\fP
+or an \fIescape sequence\fP as explained previously under
+\fICommand Input Conventions\fP).
+.LP
+Since there are more commands than there are keys,
+two keys are treated as \fIprefix\fP commands.
+When a key bound to one of the prefix commands is typed,
+the next character
+typed is interpreted on the basis that it was preceded by one of the
+prefix keys.
+Initially ^X and ESC are the prefix keys and
+many of the built in commands are initially bound to these "two stroke" keys.
+(For historical reasons, the Escape key is often referred to as "Meta").
+.NH 2
+Keyboard Macros
+.XS \n(PN 5n
+\*(SN Keyboard Macros
+.XE
+.LP
+Although \s-2JOVE\s0 has many powerful commands,
+you often find that you have a task that no individual command can do.
+\s-2JOVE\s0 allows you to define your own commands from sequences
+of existing ones "by example";
+Such a sequence is termed a \fImacro\fP.
+The procedure is as follows:
+First you type the \fIstart-remembering\fP command,
+usually bound to C-X (.
+Next you "perform" the commands which as they are being executed are
+also 
+remembered, which will constitute the body of the macro.
+Then you give the \fIstop-remembering\fP command, usually bound to
+C-X ).
+You now have a \fIkeyboard macro\fP.
+To run this command sequence again,
+use the command \fIexecute-keyboard-macro\fP, usually bound to
+C-X E.
+You may find this bothersome to type and re-type,
+so there is a way to bind the macro to a key.
+First,
+you must give the keyboard macro a name using the
+\fIname-keyboard-macro\fP command.
+Then the binding is made with the \fIbind-macro-to-key\fP command.
+We're still not finished because all this hard work will be lost
+if you leave \s-2JOVE\s0.
+What you do is to save your macros into a file
+with the \fIwrite-macros-to-file\fP command.
+To retrieve your macros in the next editing session (but not their bindings),
+you can simply execute the \fIsource\fP command on that file.
+.NH 2
+Initialization Files
+.XS \n(PN 5n
+\*(SN Initialization Files
+.XE
+.LP
+Users will likely want to modify the default key bindings to their liking.
+Since it would be quite annoying to have to set up the bindings
+each time \s-2JOVE\s0 is started up,
+\s-2JOVE\s0 has the ability to read in a "startup" file.
+Whenever \s-2JOVE\s0 is started,
+it reads commands from the file \fI.\|joverc\fP in the user's home directory.
+.LP
+These commands are read as
+if they were typed to the command handler (ESC X) during an edit.
+There can be only one command per line in the startup file.
+Lines that start with ``#'' are comments.
+Lines may be indented.
+.LP
+Sometimes it is useful for a startup file to do different things in
+different circumstances.
+To make this possible, there are two conditional commands:
+\fIif\fP and \fIifenv\fP.
+The \fIif\fP command takes as an operand a shell command, which it runs.
+If the command succeeds, the commands after the \fIif\fP, until a line
+containing \fIelse\fP or \fIendif\fP, are performed.
+Otherwise, these commands are suppressed.
+The commands after any \fIelse\fP, up until an \fIendif\fP, are executed
+only if the shell command failed.
+Conditionals nest in the normal way.
+.LP
+The \fIifenv\fP command takes as operands the name of an environment variable
+and a pattern.
+If the environment variable is defined and its value matches the pattern,
+the \fIif\fP succeeds.
+.LP
+If there is a file \fI/usr/lib/jove/joverc\fP,
+then this file will be read before the user's
+.I .\|joverc
+file.
+This can be used to set up a system-wide default startup mode for
+\s-2JOVE\s0
+that is tailored to the needs of that system.
+.LP
+The \fIsource\fP command can be used to read commands from a specified file
+at any time during an editing session,
+even from inside the \fI.\|joverc\fP file.
+This means that a macro can be used to change the key bindings,
+e.g., to enter a mode,
+by reading from a specified file which contains all the necessary bindings.
diff --git a/usr/src/contrib/jove-4.14.6/doc/jove.4 b/usr/src/contrib/jove-4.14.6/doc/jove.4
new file mode 100644 (file)
index 0000000..a1c1d80
--- /dev/null
@@ -0,0 +1,916 @@
+.bp
+.NH 1
+Alphabetical List of Commands and Variables
+.dc "abort-char" "(variable)"
+This variable defines \s-2JOVE'S\s0 abort characer.  When the abort
+character is typed, the current \s-2JOVE\s0 command is aborted.  The
+default value is C-G.
+.dc "add-lisp-special" "Not Bound"
+This command is to tell \s-2JOVE\s0 what identifiers require special
+indentation in lisp mode.  Lisp functions like defun and let are two of
+the default functions that get treated specially.  This is just a kludge
+to define some of your own.  It prompts for the function name.
+.dc "allow-^S-and-^Q" "(variable)"
+This variable, when set, tells \s-2JOVE\s0 that your terminal does not need
+to use the characters C-S and C-Q for flow control, and that it is
+okay to bind things to them.  This variable should be set depending
+upon what kind of terminal you have.
+.dc "allow-bad-filenames" "(variable)"
+If set, this variable permits filenames to contain "bad" characters
+such as those from the set *&%!"`[]{}.  These files are harder to deal
+with, because the characters mean something to the shell.  The default
+value is "off".
+.dc "append-region" "Not Bound"
+This appends the region to a specified file.  If the file does not
+already exist it is created.
+.dc "apropos" "Not Bound"
+This types out all the commands, variables and macros with the specific
+keyword in their names.  For each command and macro that contains the
+string, the key sequence that can be used to execute the command or macro is
+printed; with variables, the current value is printed.  So, to find all the
+commands that are related to windows, you type
+.DS
+ESC X apropos window<Return>
+.DE
+.dc "auto-case-abbrev" "(variable)"
+When this variable is on (the default), word abbreviations are adjusted for
+case automatically.  For example, if "jove" were the abbreviation for
+"jonathan's own version of emacs", then typing "jove" would give you
+"jonathan's own version of emacs", typing "Jove" would give you "Jonathan's
+own version of emacs", and typing "JOVE" would give you "Jonathan's Own
+Version of Emacs".  When this variable is "off", upper and lower case are
+distinguished when looking for the abbreviation, i.e., in the example above,
+"JOVE" and "Jove" would not be expanded unless they were defined separately.
+.dc "auto-execute-command" "Not Bound"
+This tells \s-2JOVE\s0 to execute a command automatically when a file whose
+name matches a specified pattern is visited.  The first argument is the
+command you want executed and the second is a regular expression
+pattern that specifies the files that apply.  For example, if you want
+to be in show-match-mode when you edit C source files (that is, files
+that end with ".c" or ".h") you can type
+.ID
+ESC X auto-execute-command show-match-mode .*\.[ch]$
+.DE
+.dc "auto-execute-macro" "Not Bound"
+This is like
+.IQ auto-execute-command
+except you use it to execute macros
+automatically instead of built-in commands.
+.dc "auto-fill-mode" "Not Bound"
+This turns on Auto Fill mode (or off if it's currently on) in the
+selected buffer.  When \s-2JOVE\s0 is in Auto Fill mode it automatically
+breaks lines for you when you reach the right margin so you don't have
+to remember to hit Return.  \s-2JOVE\s0 uses 78 as the right margin but you
+can change that by setting the variable
+.IQ right-margin
+to another
+value.  See the
+.IQ set
+command to learn how to do this.
+.dc "auto-indent-mode" "Not Bound"
+This turns on Auto Indent mode (or off if it's currently on) in the
+selected buffer.  When \s-2JOVE\s0 is in Auto Indent mode, Return indents the
+new line to the same position as the line you were just on.  This is
+useful for lining up C code (or any other language (but what else is
+there besides C?)).  This is out of date because of the new command
+called
+.IQ newline-and-indent
+but it remains because of several
+"requests" on the part of, uh, enthusiastic and excitable users, that
+it be left as it is.
+.dc "background-color" "(variable)"
+This specifies the background color of the screen (PC version only).  The
+default value is 0, which stands for black.
+.dc "backward-character" "C-B"
+This moves point backward over a single character.  If point is at the
+beginning of the line it moves to the end of the previous line.
+.dc "backward-list" "ESC C-P"
+This moves backward over a list as opposed to an s-expression.  The
+difference between this and
+.IQ backward-s-expression
+is that this first searchs for a ")" and then moves to the matching "(".
+This is useful when you're trying to find unmatched parens in a program.
+.dc "backward-paragraph" "ESC ["
+This moves point backward to the beginning of the current or previous
+paragraph.  Paragraphs are bounded by lines that begin with a Period or
+Tab, or by blank lines; a change in indentation may also signal a break
+between paragraphs, except that \s-2JOVE\s0 allows the first line of a paragraph
+to be indented differently from the other lines.
+.dc "backward-s-expression" "ESC C-B"
+This moves point backward over a s-expression.  It is just like
+.IQ forward-s-expression
+with a negative argument.
+.dc "backward-sentence" "ESC A"
+This moves point backward to the beginning of the current or previous
+sentence.  \s-2JOVE\s0 considers the end of a sentence to be the characters
+".", "!" or "?" followed by a Return or by one or more spaces.
+.dc "backward-up-list" "ESC C-U"
+This is similar to
+.IQ backward-s-expression
+except it backs up and OUT of the enclosing s-expression.  In other
+words, it moves backward to the "(" that would match a ")" if you were to
+type it right then.
+.dc "backward-word" "ESC B"
+This moves point backward to the beginning of the current or previous
+word.
+.dc "bad-filename-extensions" "(variable)"
+This contains a list of words separated by spaces which are to be
+considered bad filename extensions, and so will not be counted in
+filename completion.  The default is ".o" so if you have jove.c and
+jove.o in the same directory, the filename completion will not complain
+of an ambiguity because it will ignore jove.o.
+.dc "begin-kbd-macro" "C-X ("
+This starts defining the keyboard macro by remembering all your key
+strokes until you execute
+.IQ end-kbd-macro,
+by typing "C-X )".  Because of a bug in \s-2JOVE\s0 you shouldn't
+terminate the macro by typing "ESC X end-kbd-macro";
+.IQ end-kbd-macro
+must be bound to "C-X )" in order to make things work correctly.  To
+execute the remembered key strokes you type "C-X E" which runs the
+.IQ execute-kbd-macro
+command.
+Sometimes you may want a macro to accept different input each time it runs.
+To see how to do this, see the
+.IQ make-macro-interactive
+command.
+.dc "beginning-of-file" "ESC <"
+This moves point backward to the beginning of the buffer.  This sometimes
+prints the "Point Pushed" message.  If the top of the buffer isn't on the
+screen \s-2JOVE\s0 will set the mark so you can go back to where you were
+if you want.
+.dc "beginning-of-line" "C-A"
+This moves point to the beginning of the current line.
+.dc "beginning-of-window" "ESC ,"
+This moves point to the beginning of the current window.  The sequence
+"ESC ," is the same as "ESC <" (beginning of file) except without the shift
+key on the "<", and can thus can easily be remembered.
+.dc "bind-keymap-to-key" "Not Bound"
+This is the way to build nested keymaps.  For example, when \s-2JOVE \s0
+starts up, internally it does a
+.ID
+bind-keymap-to-key ESC-map ^[
+.DE
+To make the arrow keys on vt100's work, you would do the following.
+.ID
+.nf
+make-keymap vt100-map
+bind-keymap-to-key vt100-map ^[[
+bind-to-key next-line ^[[A
+bind-to-key previous-line ^[[B
+bind-to-key forward-character ^[[C
+bind-to-key backward-character ^[[D
+.fi
+.DE
+I may have gotten the escape sequences wrong, but you get the general
+idea.  Theoretically you can use these keymaps to bind arbitrarily long
+key sequences, like those generated by the SUN keyboards, but that is a
+bit of a pain because you will have to generate a bunch of keymaps by
+hand, almost one per key, because of the way the key sequences are
+organized.  Eventually there will be a more general way to have these
+keymaps built for you.
+.dc "bind-macro-to-key" "Not Bound"
+This is like
+.IQ bind-to-key
+except you use it to attach keys to named macros.
+.dc "bind-macro-to-word-abbrev" "Not Bound"
+This command allows you to bind a macro to a previously defined word
+abbreviation.  Whenever you type the abbreviation, it will first be expanded
+as an abbreviation, and then the macro will be executed.  Note that if the
+macro moves around, you should set the mark first (C-@) and then exchange
+the point and mark last (C-X C-X).
+.dc "bind-to-key" "Not Bound"
+This attaches a key to an internal \s-2JOVE\s0 command so that future hits on
+that key invoke that command.  For example, to make "C-W" erase the
+previous word, you type "ESC X bind-to-key kill-previous-word C-W".
+.dc "buffer-position" "Not Bound"
+This displays the current file name, current line number, total number
+of lines, percentage of the way through the file, and the position of
+the cursor in the current line.
+.dc "c-argument-indentation" "(variable)"
+This variable describes how to indent lines which are part of nested
+expressions in C.  The default is -1, which means to indent a continued
+line by lining it up with the first argument of the current expression.
+Otherwise, the line will be indented by c-argument-indentation characters
+past the indent of the first line of the expression.  For example, the
+default value produces:
+.nf
+               Typeout(fmt, itoa(bcount++), line_cnt(b, nbuf),
+                       TypeNames[b->b_type],
+                       IsModified(b) ? "*" : b->b_ntbf ? "+" : NullStr,
+                       buf_width, b->b_name, filename(b));
+.fi
+.dc "c-indentation-increment" "(variable)"
+This defines a set of tabstops independent of the value of
+internal-tabstops and physical-tabstops.  This value will be used in C
+mode, and JOVE will insert the correct number of spaces and Tabs to get
+the right behavior.  For programmers that like to indent with 4 spaces,
+set this value to 4.  Don't set internal-tabstops to 4 because that will
+not work anymore.  Setting internal-tabstops to 4 tells JOVE to display
+Tabs as every 4 spaces.  This will cause your programs to look terrible
+with anyone else who displays the file with normal tabstops at every 8
+characters.  Not to mention printing your program won't look right.  But
+all that aside, if you set c-indentation-increment to 8 (the default),
+and then set internal-tabstops to 4 as well, JOVE will insert TWO Tabs to
+get the indentation to 8, which is clearly not what you want.
+.dc "c-mode" "Not Bound"
+This turns on C mode in the currently selected buffer.  This is one of
+currently four possible major modes:  Fundamental, Text, C, Lisp.
+When in C or Lisp mode, Tab, "}", and ")" behave a little differently
+from usual: They are indented to the "right" place for C (or Lisp)
+programs.  In \s-2JOVE\s0, the "right" place is simply the way the author
+likes it (but I've got good taste).
+.dc "case-character-capitalize" "Not Bound"
+This capitalizes the character after point, i.e., the character under
+the cursor.  If a negative argument is supplied that many characters
+.IQ before
+point are upper cased.
+.dc "case-ignore-search" "(variable)"
+This variable, when set, tells \s-2JOVE\s0 to treat upper and lower case as
+the same when searching.  Thus "jove" and "JOVE" would match, and
+"JoVe" would match either.  The default value of this variable is "off".
+.dc "case-region-lower" "Not Bound"
+This changes all the upper case letters in the region to their lower
+case equivalent.
+.dc "case-region-upper" "Not Bound"
+This changes all the lower case letters in the region to their upper
+case equivalent.
+.dc "case-word-capitalize" "ESC C"
+This capitalizes the current word by making the current letter upper
+case and making the rest of the word lower case.  Point is moved to
+the end of the word.  If point is not positioned on a word it is first
+moved forward to the beginning of the next word.  If a negative
+argument is supplied that many words
+.IQ before
+point are capitalized.
+This is useful for correcting the word just typed without having to
+move point to the beginning of the word yourself.
+.dc "case-word-lower" "ESC L"
+This lower-cases the current word and leaves point at the end of it.
+If point is in the middle of a word the rest of the word is
+converted.  If point is not in a word it is first moved forward to the
+beginning of the next word.  If a negative argument is supplied that
+many words
+.IQ before
+point are converted to lower case.  This is useful
+for correcting the word just typed without having to move point to the
+beginning of the word yourself.
+.dc "case-word-upper" "ESC U"
+This upper-cases the current word and leaves point at the end of it.
+If point is in the middle of a word the rest of the word is
+converted.  If point is not in a word it is first moved forward to the
+beginning of the next word.  If a negative argument is supplied that
+many words
+.IQ before
+point are converted to upper case.  This is useful
+for correcting the word just typed without having to move point to the
+beginning of the word yourself.
+.dc "cd" "Not Bound"
+This changes the current directory.
+.dc "character-to-octal-insert" "Not Bound"
+This inserts a Back-slash followed by the ascii value of the next
+character typed.  For example, "C-G" inserts the string "\e007".
+.dc "clear-and-redraw" "ESC C-L"
+This clears the entire screen and redraws all the windows.  Use this
+when \s-2JOVE\s0 gets confused about what's on the screen, or when the screen
+gets filled with garbage characters or output from another program.
+.dc "comment-format" "(variable)"
+This variable tells \s-2JOVE\s0 how to format your comments when you run the
+command
+.IQ fill-comment.
+Its format is this:
+.ID
+<open pattern>%!<line header>%c<line trailer>%!<close pattern>
+.DE
+The %!, %c, and %! must appear in the format; everything else is optional.
+A newline (represented by %n) may appear in the open or close patterns.  %%
+is the representation for %.  The default comment format is for C comments.
+See
+.IQ fill-comment
+for more.
+.dc "compile-it" "C-X C-E"
+This compiles your program by running the UNIX command "make" into a buffer,
+and automatically parsing the error messages that are created (if any).  See
+the
+.IQ parse-errors
+command.  To compile a C program without "make", use "C-U C-X C-E" and
+\s-2JOVE\s0 will prompt for a command to run instead of make.  (And then
+the command you type will become the default command.)  You can use this
+to parse the output from the C compiler or the "grep" or "lint" programs.
+See also
+.IQ error-format-string
+to make it possible to parse errors of a different format.
+.dc "continue-process" "Not Bound"
+This sends SIGCONT to the current interactive process,
+.IQ if
+the process
+is currently stopped.
+.dc "copy-region" "ESC W"
+This takes all the text in the region and copies it onto the kill ring
+buffer.  This is just like running
+.IQ kill-region
+followed by the
+.IQ yank
+command.  See the
+.IQ kill-region
+and
+.IQ yank
+commands.
+.dc "current-error" "Not Bound"
+This moves to the current error in the list of parsed errors.  See the
+.IQ next-error
+and
+.IQ previous-error
+commands for more detailed
+information.
+.dc "date" "Not Bound"
+This prints the date on the message line.
+.dc "dbx-format-string" "(variable)"
+This is the default regular-expression search string used by JOVE to
+parse output from dbx running in a shell process.  The default format
+string works when you type "where" or while you're stepping through a
+program, or when you reach a breakpoint.  You shouldn't have to change
+this unless you are using gdb or some other symbolic debugger.
+.dc "define-global-word-abbrev" "Not Bound"
+This defines a global abbreviation.
+.dc "define-macro" "Not Bound"
+This provides a different mechanism for defining keyboard macros.
+Instead of gathering keystrokes and storing them into the
+"keyboard-macro" (which is how
+.IQ start-kbd-macro
+works),
+.IQ define-macro
+prompts for a macro name (terminated with Space, or Newline) and then for
+the actual macro body.  If you wish to specify control characters in the
+macro, you may simply insert them (using the
+.IQ quoted-insert
+command) or by inserting the character '^' followed by the appropriate
+letter for that character (e.g., ^A would be the two characters '^'
+followed by 'A').  You may use Back-slash to prevent the '^' from being
+interpreted as part of a control character when you really wish to insert
+one (e.g., a macro body "\e^foo" would insert the string "^foo" into the
+buffer, whereas the body "^foo" would be the same as typing ^F and then
+inserting the string "oo").  See
+.IQ write-macros-to-file
+to see how to save macros.
+.dc "define-mode-word-abbrev" "Not Bound"
+This defines a mode-specific abbreviation.
+.dc "delete-blank-lines" "C-X C-O"
+This deletes all the blank lines around point.  This is useful when you
+previously opened many lines with "C-O" and now wish to delete the
+unused ones.
+.dc "delete-buffer" "C-X K"
+This deletes a buffer and frees up all the memory associated with it.  Be
+careful(!) - once a buffer has been deleted it is gone forever.  \s-2JOVE\s0
+will ask you to confirm if you try to delete a buffer that needs saving.
+This command is useful for when \s-2JOVE\s0 runs out of space to store
+new buffers.
+.dc "delete-current-window" "C-X D"
+This deletes the current window and moves point into one of the
+remaining ones.  It is an error to try to delete the only remaining
+window.
+.dc "delete-macro" "Not Bound"
+This deletes a macro from the list of named macros.  It is an error to
+delete the keyboard-macro.  Once the macro is deleted it is gone forever.
+If you are about to save macros to a file and decide you don't want to save
+a particular one, delete it.
+.dc "delete-next-character" "C-D"
+This deletes the character that's just after point (that is, the
+character under the cursor).  If point is at the end of a line, the
+line separator is deleted and the next line is joined with the current
+one.
+.dc "delete-other-windows" "C-X 1"
+This deletes all the other windows except the current one.  This can be
+thought of as going back into One Window mode.
+.dc "delete-previous-character" "DEL"
+This deletes the character that's just before point (that is, the
+character before the cursor).  If point is at the beginning of the
+line, the line separator is deleted and that line is joined with the
+previous one.
+.dc "delete-white-space" "ESC \e"
+This deletes all the Tabs and Spaces around point.
+.dc "describe-bindings" "Not Bound"
+This types out a list containing each bound key and the command that gets
+invoked every time that key is typed.  To make a wall chart of \s-2JOVE\s0
+commands, set
+.IQ send-typeout-to-buffer
+to "on" and \s-2JOVE\s0 will
+store the key bindings in a buffer which you can save to a file and then
+print.
+.dc "describe-command" "Not Bound"
+This prints some info on a specified command.
+.dc "describe-key" "Not Bound"
+This waits for you to type a key and then tells the name of the
+command that gets invoked every time that key is hit.  Once you have
+the name of the command you can use the
+.IQ describe-command
+command
+to find out exactly what it does.
+.dc "describe-variable" "Not Bound"
+This prints some info on a specified variable.
+.dc "digit" "ESC [0-9]"
+This reads a numeric argument.  When you type "ESC" followed by a
+number, "digit" keeps reading numbers until you type some other
+command.  Then that command is executes with the numeric argument you
+specified.
+.dc "digit-1" "Not Bound"
+This pretends you typed "ESC 1".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-2" "Not Bound"
+This pretends you typed "ESC 2".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-3" "Not Bound"
+This pretends you typed "ESC 3".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-4" "Not Bound"
+This pretends you typed "ESC 4".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-5" "Not Bound"
+This pretends you typed "ESC 5".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-6" "Not Bound"
+This pretends you typed "ESC 6".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-7" "Not Bound"
+This pretends you typed "ESC 7".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-8" "Not Bound"
+This pretends you typed "ESC 8".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-9" "Not Bound"
+This pretends you typed "ESC 9".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "digit-0" "Not Bound"
+This pretends you typed "ESC 0".  This is useful for terminals that
+have keypads that send special sequences for numbers typed on the
+keypad as opposed to numbers typed from the keyboard.  This can save
+having type "ESC" when you want to specify an argument.
+.dc "dirs" "Not Bound"
+This prints out the directory stack.  See the "cd", "pushd", "popd"
+commands for more info.
+.dc "disable-biff" "(variable)"
+When this is set, \s-2JOVE\s0 disables biff when you're editing and enables it
+again when you get out of \s-2JOVE\s0, or when you pause to the parent shell
+or push to a new shell. (This means arrival of new mail will not be
+immediately apparent but will not cause indiscriminate writing on the
+display). The default is "off".
+.dc "display-bad-filenames" "(variable)"
+This variable affects only filename completion, in particular, what
+happens when "?" is typed while prompting for a file.  When this variable
+is ON, any files that end with one of the extensions defined by the
+variable
+.IQ bad-filename-extensions
+will be displayed with an "!" in front of their names.  When
+.IQ display-bad-filenames
+is OFF the files will not be displayed at all.  The default value is on.
+.dc "down-list" "ESC C-D"
+This is the opposite of
+.IQ backward-up-list.
+It's not clear to me that this command serves any useful purpose in
+life.  Try it out, and let me know what you think.
+.dc "dstop-process" "Not Bound"
+Send the "dsusp" character to the current process.  This is the
+character that suspends a process on the next read from the
+terminal.  Most people have it set to C-Y.  This only works if
+you have the interactive process feature, and if you are in a
+buffer bound to a process.
+.dc "edit-word-abbrevs" "Not Bound"
+This creates a buffer with a list of each abbreviation and the phrase
+it expands into, and enters a recursive edit to let you change the
+abbreviations or add some more.  The format of this list is
+"abbreviation:phrase" so if you add some more you should follow that
+format.  It's probably simplest just to copy some already existing
+abbreviations and edit them.  When you are done you type "C-X C-C" to
+exit the recursive edit.
+.dc "end-kbd-macro" "C-X )"
+This stops the definition of the keyboard macro.  Because of a bug in
+\s-2JOVE\s0, this must be bound to "C-X )", or some key sequence which is
+one or two characters long.  Anything else will not work properly.
+.dc "end-of-file" "ESC >"
+This moves point forward to the end of the buffer.  This sometimes
+prints the "Point Pushed" message.  If the end of the buffer isn't on
+the screen \s-2JOVE\s0 will set the mark so you can go back to where you were
+if you want.
+.dc "end-of-line" "C-E"
+This moves point to the end of the current line.  If the line is too
+long to fit on the screen \s-2JOVE\s0 will scroll the line to the left to
+make the end of the line visible.  The line will slide back to its
+normal position when you move backward past the leftmost visible character
+or when you move off the line altogether.
+.dc "end-of-window" "ESC ."
+This moves point to the last character in the window.
+.dc "eof-process" "Not Bound"
+Sends EOF to the current interactive process.  This only works on
+versions of \s-2JOVE\s0 running under versions of UNIX with pty's.
+.dc "erase-buffer" "Not Bound"
+This erases the contents of the specified buffer.  This is like
+.IQ delete-buffer
+except it only erases the contents of the buffer, not
+the buffer itself.  If you try to erase a buffer that needs saving you
+will be asked to confirm it.
+.dc "error-format-string" "(variable)"
+This is the error format string that is used by
+.IQ parse-errors
+to find the error messages in a buffer.  The way it works is by using
+this string as a \s-2JOVE\s0 regular expression search string, where the
+\e('s and \e)'s regular expression operators are used to pick out the
+file name and line number from the line containing an error message.  For
+instance, a typical error message might look like this:
+.sp 1
+       "file.c", line 540: missing semi-colon
+.sp 1
+For strings of this format, an appropriate value for
+.IQ error-format-string
+would be something like this:
+.sp 1
+       ^"\e([^"]*\e)", line \e([0-9]*\e):
+.sp 1
+What this means is, to find an error message, search for a line beginning
+with a double-quote.  Then it says that all the following characters up
+to another double-quote should be remembered as one unit, namely the
+filename that the error is in (that's why the first set of parens are
+surrounding it).  Then it says that after the filename there will be the
+string ", line " followed by a line number, which should be remembered as
+a single unit (which is why the second set of parens is around that).
+The only constraints on the error messages is that the file name and line
+number appear on the same line, and that the file name appears before the
+line number.  Most compilers seem to do this anyway, so this is not an
+unreasonable restriction.
+.sp 1
+If you do not know how to use regular expressions then this variable will
+be hard for you to use.  Also note that you can look at the default
+value of this variable by printing it out, but it is a really complicated
+string because it is trying to accommodate the outputs of more than one
+compiler at a time.
+.dc "error-window-size" "(variable)"
+This is the percentage of the screen to use for the error-window on the
+screen.  When you execute
+.IQ compile-it,
+.IQ error-window-size
+percent of the screen will go to the error window.  If the window already
+exists and is a different size, it is made to be this size.  The default
+value is 20%.
+.dc "exchange-point-and-mark" "C-X C-X"
+This moves point to mark and makes mark the old point.  This is for
+quickly moving from one end of the region to another.
+.dc "execute-kbd-macro" "C-X E"
+This executes the keyboard macro.  If you supply a numeric argument the
+macro is executed that many times.
+.dc "execute-macro" "Not Bound"
+This executes a specified macro.  If you supply a numeric argument the
+macro is executed that many times.
+.dc "execute-named-command" "ESC X"
+This is the way to execute a command that isn't bound to any key.  When
+you are prompted with ": " you can type the name of the command.  You
+don't have to type the entire name.  Once the command is unambiguous you
+can type Space and \s-2JOVE\s0 will fill in the rest for you.  If you are
+not sure of the name of the command, type "?" and \s-2JOVE\s0 will print
+a list of all the commands that you could possibly match given what
+you've already typed.  If you don't have any idea what the command's name
+is but you know it has something to do with windows (for example), you
+can do "ESC X apropos window" and \s-2JOVE\s0 will print a list of all
+the commands that are related to windows.  If you find yourself
+constantly executing the same commands this way you probably want to bind
+them to keys so that you can execute them more quickly.  See the
+.IQ bind-to-key
+command.
+.dc "exit-jove" "C-X C-C"
+This exits \s-2JOVE\s0.  If any buffers need saving \s-2JOVE\s0 will print a warning
+message and ask for confirmation.  If you leave without saving your
+buffers all your work will be lost.  If you made a mistake and really
+do want to exit then you can.  If you are in a recursive editing level
+.IQ exit-jove
+will return you from that.
+.dc "expand-environment-variables" "(variable)"
+When this variable is on JOVE will try to expand any strings of the form
+"$var" into the value of the environment variable "var" when in the
+minibuffer.  For example, if you type $HOME/.joverc, "$HOME" will be
+replaced with you home directory.  The default value is off.
+.dc "file-creation-mode" "(variable)"
+This variable has an octal value.  It contains the mode (see
+.IQ chmod(1)
+) with which files should be created.  This mode gets modified by your
+current umask setting (see
+.IQ umask(1)
+).  The default value is usually
+.IQ 0666
+or
+.IQ 0644.
+.dc "files-should-end-with-newline" "(variable)"
+This variable indicates that all files should always have a newline
+at the end.  This is often necessary for line printers and the like.
+When set, if \s-2JOVE\s0 is writing a file whose last character is not a
+newline, it will add one automatically.
+.dc "fill-comment" "Not Bound"
+This command fills in your C comments to make them pretty and readable.
+This filling is done according the variable
+.IQ comment-format.
+.DS L
+/*
+ * the default format makes comments like this.
+ */
+.DE
+This can be changed by changing the format variable.  Other languages
+may be supported by changing the format variable appropriately.  The
+formatter looks backwards from dot for an open comment symbol.  If 
+found, all indentation is done relative the position of the first character
+of the open symbol.  If there is a matching close symbol, the entire 
+comment is formatted.  If not, the region between dot and the open symbol
+is reformatted.
+.dc "fill-paragraph" "ESC J"
+This rearranges words between lines so that all the lines in the current
+paragraph extend as close to the right margin as possible, ensuring that
+none of the lines will be greater than the right margin.  The default value
+for
+.IQ right-margin
+is 78, but can be changed with the
+.IQ set
+and
+.IQ right-margin-here
+commands.  \s-2JOVE\s0 has a complicated algorithm
+for determining the beginning and end of the paragraph.  In the normal case
+\s-2JOVE\s0 will give all the lines the same indent as they currently have,
+but if you wish to force a new indent you can supply a numeric argument to
+.IQ fill-paragraph
+(e.g., by typing C-U ESC J)
+and \s-2JOVE\s0 will indent each line to the column
+specified by the
+.IQ left-margin
+variable.  See also the
+.IQ left-margin
+variable and
+.IQ left-margin-here
+command.
+.dc "fill-region" "Not Bound"
+This is like
+.IQ fill-paragraph,
+except it operates on a region instead of
+just a paragraph.
+.dc "filter-region" "Not Bound"
+This sends the text in the region to a UNIX command, and replaces the
+region with the output from that command.  For example, if you are
+lazy and don't like to take the time to write properly indented C
+code, you can put the region around your C file and
+.IQ filter-region
+it
+through
+.IQ cb,
+the UNIX C beautifier.  If you have a file that contains
+a bunch of lines that need to be sorted you can do that from inside
+\s-2JOVE\s0 too, by filtering the region through the
+.IQ sort
+UNIX command.
+Before output from the command replaces the region \s-2JOVE\s0 stores the old
+text in the kill ring, so if you are unhappy with the results you can
+easily get back the old text with "C-Y".
+.dc "find-file" "C-X C-F"
+This visits a file into its own buffer and then selects that buffer.
+If you've already visited this file in another buffer, that buffer is
+selected.  If the file doesn't yet exist, \s-2JOVE\s0 will print "(New file)"
+so that you know.
+.dc "find-tag" "C-X T"
+This finds the file that contains the specified tag.  \s-2JOVE\s0 looks up
+tags by default in the "tags" file in the current directory.  You can change
+the default tag name by setting the
+.IQ tag-file
+variable to another
+name.  If you specify a numeric argument to this command, you will be
+prompted for a tag file.  This is a good way to specify another tag file
+without changing the default.  If the tag cannot be found the error is
+reported and point stays where it is.
+.dc "find-tag-at-point" "Not Bound"
+This finds the file that contains the tag that point is currently on.
+See
+.IQ find-tag.
+.dc "first-non-blank" "ESC M"
+This moves point back to the indent of the current line.
+.dc "foreground-color" "(variable)"
+This specifies the foreground color of the screen (PC version only).  The
+default is 1, which stands for white.  The attribute used for writing to
+the screen is formed by (bg&7)<<4 & (fg&7).
+.dc "forward-character" "C-F"
+This moves forward over a single character.  If point is at the end of
+the line it moves to the beginning of the next one.
+.dc "forward-list" "ESC C-N"
+This is like
+.IQ forward-s-expression
+except it moves over lists ONLY.  What this does is search for the next
+"(" and then move to the matching ")".  This is useful for when you are
+trying to find mismatched parentheses in a program.
+.dc "forward-paragraph" "ESC ]"
+This moves point forward to the end of the current or next paragraph.
+Paragraphs are bounded by lines that begin with a Period or Tab, or by blank
+lines; a change in indentation may also signal a break between paragraphs,
+except that \s-2JOVE\s0 allows the first line of a paragraph to be indented
+differently from the other lines.
+.dc "forward-s-expression" "ESC C-F"
+This moves point forward over a s-expression.  If the first significant
+character after point is "(", this moves past the matching ")".  If the
+character begins an identifier, this moves just past it.  This is mode
+dependent, so this will move over atoms in LISP mode and C identifiers in C
+mode.  \s-2JOVE\s0 also matches "{".
+.dc "forward-sentence" "ESC E"
+This moves point forward to the end of the current or next sentence.
+\s-2JOVE\s0 considers the end of a sentence to be the characters ".", "!" or
+"?" followed by a Return, or one or more spaces.
+.dc "forward-word" "ESC F"
+This moves point forward to the end of the current or next word.
+.dc "fundamental-mode" "Not Bound"
+This sets the major mode to Fundamental.  This affects what \s-2JOVE\s0
+considers as characters that make up words.  For instance,
+Single-quote is not part of a word in Fundamental mode, but is in Text
+mode.
+.dc "gather-numeric-argument" "C-U"
+This command is one of two ways to specify a numeric argument to a
+command.  It's usually bound to C-U.  Typing C-U once means, Do the next
+command 4 times.  Typing C-U twice will do the next command 16 times, and
+so on.  If at any point you type a number, then that number will be used
+instead of 4.  For instance, C-U 3 5 means do the next command 35 times.
+.dc "goto-line" "ESC G"
+If a numeric argument is supplied point moves to the beginning of that
+line.  If no argument is supplied one is prompted for.
+.dc "goto-window-with-buffer" "Not Bound"
+This command prompts for a buffer name and then selects that buffer.  If
+the buffer is currently being displayed in one of the windows, that
+window is selected instead.
+.dc "grind-s-expr" "Not Bound"
+When point is positioned on a "(", this re-indents that LISP expression.
+.dc "grow-window" "C-X ^"
+This makes the current window one line bigger.  This only works when
+there is more than one window and provided there is room to change the
+size.
+.dc "handle-tab" "Tab"
+This handles indenting to the "right" place in C and Lisp mode, and
+just inserts itself in Text mode.
+.dc "i-search-forward" "Not Bound"
+Incremental search.  Like search-forward except that instead of prompting
+for a string and searching for that string all at once, it accepts the string
+one character at a time.  After each character you type as part of the search
+string, it searches for the entire string so far.  When you like what it
+found, type the Return key to finish the search.  You can take back a
+character with DEL and the search will back up to the position before
+that character was typed.  C-G aborts the search.
+.dc "i-search-reverse" "Not Bound"
+Incremental search.  Like search-reverse except that instead of prompting
+for a string and searching for that string all at once, it accepts the string
+one character at a time.  After each character you type as part of the search
+string, it searches for the entire string so far.  When you like what it
+found, type the Return key to finish the search.  You can take back a
+character with DEL and the search will back up to the position before
+that character was typed.  C-G aborts the search.
+.dc "i-shell-command" "Not Bound"
+This is like
+.IQ shell-command
+except it lets you continue with your
+editing while the command is running.  This is really useful for long
+running commands with sporadic output.  See the manual for information
+on how to use interactive processes.
+.dc "insert-file" "C-X C-I"
+This inserts a specified file into the current buffer at point.  Point
+is positioned at the beginning of the inserted file.
+.dc "internal-tabstop" "(variable)"
+The number of spaces \s-2JOVE\s0 should print when it displays a tab character.
+The default value is 8.
+.dc "interrupt-character" "(variable)"
+This is set to the character that interrupts JOVE (with a signal) no matter
+what JOVE is doing.  It's main use is for interrupting non-interactive
+processes, but it also has uses for debugging.  Unfortunately there is no
+way to turn off the interrupt character.
+.dc "interrupt-process" "Not Bound"
+This sends the interrupt character (usually C-C) to the interactive process
+in the current buffer.  This is only for versions of \s-2JOVE\s0 that have the
+interactive processes feature.  This only works when you are inside a buffer
+that's attached to a process.
+.dc "kill-next-word" "ESC D"
+This kills the text from point to the end of the current or next word.
+.dc "kill-previous-word" "ESC DEL"
+This kills the text from point to the beginning of the current or
+previous word.
+.dc "kill-process" "Not Bound"
+This command prompts for a buffer name or buffer number (just as
+select-buffer does) and then sends the process in that buffer a
+kill signal (9).
+.dc "kill-region" "C-W"
+This deletes the text in the region and saves it on the kill ring.
+Commands that delete text but save it on the kill ring all have the
+word "kill" in their names.  Type "C-Y" to yank back the most recent
+kill.
+.dc "kill-s-expression" "ESC C-K"
+This kills the text from point to the end of the current or next
+s-expression.
+.dc "kill-some-buffers" "Not Bound"
+This goes through all the existing buffers and asks whether or not to kill
+them.  If you decide to kill a buffer, and it turns out that the buffer is
+modified, \s-2JOVE\s0 will offer to save it first.  This is useful for when \s-2JOVE\s0
+runs out of memory to store lines (this only happens on PDP-11's) and you
+have lots of buffers that you are no longer using.
+.dc "kill-to-beginning-of-sentence" "C-X DEL"
+This kills from point to the beginning of the current or previous
+sentence.
+.dc "kill-to-end-of-line" "C-K"
+This kills from point to the end of the current line.  When point is
+at the end of the line the line separator is deleted and the next line
+is joined with current one.  If a numeric argument is supplied that
+many lines are killed; if the argument is negative that many lines
+.IQ before
+point are killed; if the argument is zero the text from point
+to the beginning of the line is killed.
+.dc "kill-to-end-of-sentence" "ESC K"
+This kills from point to the end of the current or next sentence.  If a
+negative numeric argument is supplied it kills from point to the
+beginning of the current or previous sentence.
+.dc "left-margin" "(variable)"
+This is how far lines should be indented when auto-indent mode is on,
+or when the
+.IQ newline-and-indent
+command is run (usually by typing
+LineFeed).  It is also used by fill-paragraph and auto-fill mode.
+If the value is zero (the default) then the left margin is determined
+from the surrounding lines.
+.dc "left-margin-here" "Not Bound"
+This sets the
+.IQ left-margin
+variable to the current position of
+point.  This is an easy way to say, "Make the left margin begin here,"
+without having to count the number of spaces over it actually is.
+.dc "lisp-mode" "Not Bound"
+This turns on Lisp mode.  Lisp mode is one of four mutually exclusive major
+modes: Fundamental, Text, C, and Lisp.  In Lisp mode, the characters Tab
+and ) are treated specially, similar to the way they are treated in C mode.
+Also, Auto Indent mode is affected, and handled specially.
+.dc "list-buffers" "C-X C-B"
+This types out a list containing various information about each buffer.
+Right now that list looks like this:
+.DS
+.ta \w'NO111'u +\w'Lines1'u +\w'Scratch111'u +\w'*1'u +\w'commands.doc111'u
+\ (* means the buffer needs saving)
+\ NO   Lines   Type            Name    File
+\ --   -----   ----            ----    ----
+\ 1    1       File            Main    [No file]
+\ 2    1       Scratch *       Minibuf [No file]
+\ 3    519     File    *       commands.doc    commands.doc
+.DE
+The first column lists the buffer's number.  When \s-2JOVE\s0 prompts for a
+buffer name you can either type in the full name, or you can simply
+type the buffer's number.  The second column is the number of lines in
+the buffer.  The third says what type of buffer.  There are four
+types: "File", "Scratch", "Process", "I-Process".  "File" is simply a
+buffer that holds a file; "Scratch" is for buffers that \s-2JOVE\s0 uses
+internally; "Process" is one that holds the output from a UNIX
+command; "I-Process" is one that has an interactive process attached to
+it.  The next column contains the name of the buffer.  And the last
+column is the name of the file that's attached to the buffer.  In this
+case, both Minibuf and commands.doc have been changed but not yet
+saved.  In fact Minibuf won't be saved since it's an internal \s-2JOVE\s0
+buffer that I don't even care about.
+.dc "list-processes" "Not Bound"
+This makes a list somewhat like "list-buffers" does, except its
+list consists of the current interactive processes.  Right now the list
+looks like this:
+.DS
+.ta \w'shell-111111111111'u +\w'Running1111111111'u
+\ Buffer       Status  Pid    Command
+\ ------       ------  ---    -------
+\ *shell*      Running 18415   shell
+\ fgrep        Done    18512   fgrep -n Buffer *.c
+.DE
+The first column has the name of the buffer to which the process is
+attached.  The second has the status of the process; if a process has
+exited normally the status is "Done" as in fgrep; if the process
+exited with an error the status is "Exit N" where N is the value of
+the exit code; if the process was killed by some signal the status is
+the name of the signal that was used; otherwise the process is
+running.  The last column is the name of the command that is being run.
+.dc "macify" "(variable)"
+When this variable is on, JOVE will use the standard Macintosh file-selector
+dialog in place of the traditional JOVE minibuffer. (Mac version only)
+.dc "mail-check-frequency" "(variable)"
+This is how often (in seconds) \s-2JOVE\s0 should check your mailbox for
+incoming mail.  If you set this to \s-2ZERO\s0 JOVE won't check for new
+mail.  See also the
+.IQ mailbox
+and
+.IQ disable-biff
+variables.
+.dc "mailbox" "(variable)"
+Set this to the full pathname of your mailbox.  \s-2JOVE\s0 will look here to
+decide whether or not you have any unread mail.  This defaults to
+/usr/spool/mail/$USER, where $USER is set to your login name.
diff --git a/usr/src/contrib/jove-4.14.6/doc/jove.5 b/usr/src/contrib/jove-4.14.6/doc/jove.5
new file mode 100644 (file)
index 0000000..baaa34b
--- /dev/null
@@ -0,0 +1,831 @@
+.dc "make-backup-files" "(variable)"
+If this variable is set, then whenever \s-2JOVE\s0 writes out a file, it will
+move the previous version of the file (if there was one) to "#filename".
+This is often convenient if you save a file by accident.  The default
+value of this variable is "off".
+.IQ Note:
+this is an optional part of
+\s-2JOVE\s0, and your guru may not have it enabled, so it may not work.
+.dc "make-buffer-unmodified" "ESC ~"
+This makes \s-2JOVE\s0 think the selected buffer hasn't been changed even if
+it has.  Use this when you accidentally change the buffer but don't
+want it considered changed.  Watch the mode line to see the * disappear
+when you use this command.  
+.dc "make-keymap" "Not Bound"
+This creates an empty keymap with a name you supply.  That name can be
+used to reference the keymap in other commands, such as
+bind-keymap-to-key.
+.dc "make-macro-interactive" "Not Bound"
+This command is meaningful only while you are defining a keyboard macro,
+and when you are in the minibuffer.  Ordinarily, when a command in a macro
+definition requires a trailing text argument (file name, search string,
+etc.), the argument you supply becomes part of the macro definition.  If
+you want to be able to supply a different argument each time the macro is
+used, then while you are defining it, you should give the
+make-macro-interactive command just before typing the argument which will
+be used during the definition process.  Note: you must bind this command
+to a key in order to use it; you can't say "ESC X make-macro-interactive".
+.dc "mark-threshold" "(variable)"
+This variable contains the number of lines point may move by before
+the mark is set.  If, in a search or something, point moves by more
+than this many lines, the mark is set so that you may return easily.
+The default value of this variable is 22 (one screenful, on most
+terminals).
+.dc "marks-should-float" "(variable)"
+When this variable is "off", the position of a mark is remembered as a line
+number within the buffer and a character number within the line.  If you add
+or delete text before the mark, it will no longer point to the text you
+marked originally because that text is no longer at the same line and
+character number.  When this variable is "on", the position of a mark is
+adjusted to compensate for each insertion and deletion.  This makes marks
+much more sensible to use, at the cost of slowing down insertion and
+deletion somewhat.  The default value is "on".
+.dc "match-regular-expressions" "(variable)"
+When set, \s-2JOVE\s0 will match regular expressions in search patterns.
+This makes special the characters ., *, [, ], ^, and $, and the two-character
+sequences \e<, \e>, \e\|{, \e\|} and \e\||.
+See the
+.IQ ed(1)
+manual page, the tutorial "Advanced Editing in 
+.UX
+", and the section above "Searching with Regular Expressions"
+for more information.
+.dc "meta-key" "(variable)"
+You should set this variable to "on" if your terminal has a real Meta key.
+If your terminal has such a key, then a key sequence like ESC Y can be
+entered by holding down Meta and typing Y.  NOTE:  In some systems, this
+disables interrupting noninteractive shell commands.
+.dc "mode-line" "(variable)"
+The format of the mode line can be determined by setting this variable.
+The items in the line are specified using a format similar to that used by printf(3),
+with the special things being marked as "%x".  Digits may be used between the
+'%' and the 'x' to mean repeat that many times.
+\&'x' may be:
+.DS I
+.ta .5i 1i 1.5i
+       C       check for new mail, and displays "[New mail]" if there
+               is any (see also the mail-check-interval and disable-biff
+               variables)
+       F       the current file name, with leading path stripped
+       M       the current list of major and minor modes
+       b       the current buffer name
+       c       the fill character (-)
+       d       the current directory
+       e       extra space in modeline is distributed evenly
+               among the places %e is used (used for justifying,
+               separating, or centering parts of the modeline)
+       f       the current file name
+       l       the current load average (updated automatically)
+       mxy     x, when the buffer is modified or y, when not
+       n       the current buffer number
+       p       interactive process status for process windows
+       s       space, but only if previous character is not a space
+       t       the current time (updated automatically)
+       w       a '>' for windows which are scrolled left
+       [ ]     the square brackets printed when in a recursive edit
+       ( )     items enclosed in %( ... %) will only be printed on
+               the bottom mode line, rather than copied when the
+               window is split
+.DE
+In addition, any other character is simply copied into the mode line.
+Characters may be escaped with a backslash.  To get a feel for all
+this, try typing "ESC X print mode-line" and compare the result with
+your current mode line.
+.dc "mode-line-color" "(variable)"
+This specifies the color of the modeline (PC version only).  Its default
+value is 0, and in that case it is drawn in reverse video.  If it has any
+other value, this value is used as the attribute in the Bios calls.
+.dc "mode-line-should-standout" "(variable)"
+If set, the mode line will be printed in reverse video, if your
+terminal supports it.  The default for this variable is "off".
+.dc "name-kbd-macro" "Not Bound"
+This copies the keyboard macro and gives it a name freeing up the
+keyboard macro so you can define some more.  Keyboard macros with
+their own names can be bound to keys just like built in commands
+can.  See the
+.IQ define-macro,
+.IQ source
+and
+.IQ write-macros-to-file
+commands.
+.dc "newline" "Return"
+This divides the current line at point moving all the text to the
+right of point down onto the newly created line.  Point moves down to
+the beginning of the new line.
+.dc "newline-and-backup" "C-O"
+This divides the current line at point moving all the text to the
+right of point down onto the newly created line.  The difference
+between this and "newline" is that point does not move down to the
+beginning of the new line.
+.dc "newline-and-indent" "LineFeed"
+This behaves the same was as Return does when in Auto Indent mode.
+This makes Auto Indent mode obsolete but it remains in the name of
+backward compatibility.
+.dc "next-error" "C-X C-N"
+This moves to the next error in the list of errors that were parsed
+with
+.IQ parse-errors.
+In one window the list of errors is shown with the current one always at
+the top.  In another window is the file that contains the error.  Point
+is positioned in this window on the line where the error occurred.
+.dc "next-line" "C-N"
+This moves down to the next line.
+.dc "next-page" "C-V"
+This displays the next page of the buffer by taking the bottom line of
+the window and redrawing the window with it at the top.  If there isn't
+another page in the buffer \s-2JOVE\s0 rings the bell.  If a numeric argument
+is supplied the screen is scrolled up that many lines; if the argument
+is negative the screen is scrolled down.
+.dc "next-window" "C-X N"
+This moves into the next window.  Windows live in a circular list so
+when you're in the bottom window and you try to move to the next one
+you are moved to the top window.  It is an error to use this command
+with only one window.
+.dc "number-lines-in-window" "Not Bound"
+This displays the line numbers for each line in the buffer being
+displayed.  The number isn't actually part of the text; it's just
+printed before the actual buffer line is.  To turn this off you run
+the command again; it toggles.
+.dc "over-write-mode" "Not Bound"
+This turns Over Write mode on (or off if it's currently on) in the selected
+buffer.  When on, this mode changes the way the self-inserting characters
+work.  Instead of inserting themselves and pushing the rest of the line over
+to the right, they replace or over-write the existing character.  Also,
+DEL replaces the character before point with a space instead of deleting
+it.  When Over Write mode is on "OvrWt" is displayed on the mode line.
+.dc "page-next-window" "ESC C-V"
+This displays the next page in the next window.  This is exactly the
+same as "C-X N C-V C-X P".
+.dc "paren-flash" ") } ]"
+This handles the C mode curly brace indentation, the Lisp mode paren
+indentation, and the Show Match mode paren/curly brace/square bracket
+flashing.
+.dc "paren-flash-delay" "(variable)"
+How long, in tenths of seconds, \s-2JOVE\s0 should pause on a matching
+parenthesis in
+.IQ Show Match
+mode.  The default is 5.
+.dc "parse-errors" "Not Bound"
+This takes the list of C compilation errors (or output from another program
+in the same format) in the current buffer and parses them for use with the
+.IQ next-error
+and
+.IQ previous-error
+and
+.IQ current-error
+commands.
+This is a very useful tool and helps with compiling C programs and when used
+in conjunction with the "grep" UNIX command very helpful in making changes
+to a bunch of files.  This command understands errors produced by cc, cpp,
+and lint; plus any other program with the same format (e.g., "grep -n").
+\s-2JOVE\s0 visits each file that has an error and remembers each line that
+contains an error.  It doesn't matter if later you insert or delete
+some lines in the buffers containing errors; \s-2JOVE\s0 remembers where
+they are regardless.
+.IQ current-error
+is automatically executed after one of the parse commands, so you end up
+at the first error.  See also
+.IQ error-format-string
+to make it possible to parse errors of a different format.
+.dc "parse-spelling-errors-in-buffer" "Not Bound"
+This parses a list of words in the current buffer and looks them up in
+another buffer that you specify.  This will probably go away soon.
+.dc "pause-jove" "ESC S"
+This stops \s-2JOVE\s0 and returns control to the parent shell.  This
+only works for users using the C-shell, and on systems that have the
+job control facility.  To return to \s-2JOVE\s0 you type "fg" to the C-shell.
+.dc "physical-tabstop" "(variable)"
+How many spaces your terminal prints when it prints a tab character.
+.dc "pop-mark" "Not Bound"
+This gets executed when you run
+.IQ set-mark
+with a numeric argument.
+\s-2JOVE\s0 remembers the last 16 marks and you use
+.IQ pop-mark
+to go
+backward through the ring of marks.  If you execute
+.IQ pop-mark
+enough
+times you will eventually get back to where you started.
+.dc "popd" "Not Bound"
+This pops one entry off the directory stack.  Entries are pushed with
+the
+.IQ pushd
+command.  The names were stolen from the C-shell and the
+behavior is the same.
+.dc "previous-error" "C-X C-P"
+This is the same as
+.IQ next-error
+except it goes to the previous error.
+See
+.IQ next-error
+for documentation.
+.dc "previous-line" "C-P"
+This moves up to the previous line.
+.dc "previous-page" "ESC V"
+This displays the previous page of the current buffer by taking the top
+line and redrawing the window with it at the bottom.  If a numeric
+argument is supplied the screen is scrolled down that many lines; if
+the argument is negative the screen is scrolled up.
+.dc "previous-window" "C-X P and C-X O"
+This moves into the next window.  Windows live in a circular list so
+when you're in the top window and you try to move to the previous one
+you are moved to the bottom window.  It is an error to use this command
+with only one window.
+.dc "print" "Not Bound"
+This prints the value of a \s-2JOVE\s0 variable.
+.dc "process-bind-keymap-to-key" "Not Bound"
+This is just like "bind-to-key" except that it starts at the
+process-keymap map, instead of the default mainmap.
+.dc "process-bind-to-key" "Not Bound"
+This command is identical to bind-to-key, except that it only affects
+your bindings when you are in a buffer attached to a process.  When
+you enter the process buffer, any keys bound with this command will
+automatically take their new values.  When you switch to a non-process
+buffer, the old bindings for those keys will be restored.  For example,
+you might want to execute
+.DS I
+process-bind-to-key stop-process ^Z
+process-bind-to-key interrupt-process ^C
+.DE
+Then, when you start up an interactive process and switch into that
+buffer, C-Z will execute stop-process and C-C will execute interrupt-
+process.  When you switch back to a non-process buffer, C-Z will go
+back to executing scroll-up (or whatever you have it bound to).
+.dc "process-dbx-output" "Not Bound"
+This command only makes sense in a buffer running a shell process.  If
+you are running dbx in a window, JOVE will automatically find the file
+you are currently stepping through and display it in another window.
+The string DBX will appear in the modeline along with the other minor
+modes when this feature is enabled.
+.dc "process-newline" "Return"
+This only gets executed when in a buffer that is attached to an
+interactive-process.  \s-2JOVE\s0 does two different things depending on where
+you are when you hit Return.  When you're at the end of the I-Process
+buffer this does what Return normally does, except it also makes the
+line available to the process.  When point is positioned at some other
+position that line is copied to the end of the buffer (with the prompt
+stripped) and point is moved there with it, so you can then edit that
+line before sending it to the process.  This command
+.IQ must
+be bound
+to the key you usually use to enter shell commands (Return), or else
+you won't be able to enter any.
+.dc "process-prompt" (variable)
+What a prompt looks like from the shell and i-shell-command
+processes.  The default is "% ", the default C-shell prompt.  This is
+actually a regular expression search string.  So you can set it to be
+more than one thing at once using the \e| operator.  For instance, for
+LISP hackers, the prompt can be
+.DS
+"% \e|-> \e|<[0-9]>: ".
+.DE
+.dc "process-send-data-no-return" "Not Bound"
+This is like
+.IQ process-newline
+except it sends everything to the process without the newline.  Normally,
+when you type return in a process buffer it sends everything you typed
+including the Return.  This command just provides a way to send data to
+the process without having to send a newline as well.
+.dc "push-shell" "Not Bound"
+This spawns a child shell and relinquishes control to it.  This works
+on any version of UNIX, but this isn't as good as
+.IQ pause-jove
+because
+it takes time to start up the new shell and you get a brand new
+environment every time.  To return to \s-2JOVE\s0 you type "C-D".
+.dc "pushd" "Not Bound"
+This pushes a directory onto the directory stack and cd's into it.  It
+asks for the directory name but if you don't specify one it switches
+the top two entries no the stack.  It purposely behaves the same as
+C-shell's
+.IQ pushd.
+.dc "pwd" "Not Bound"
+This prints the working directory.
+.dc "query-replace-string" "ESC Q"
+This replaces the occurrences of a specified string with a specified
+replacement string.  When an occurrence is found point is moved to it
+and then \s-2JOVE\s0 asks what to do.  The options are:
+.DS I
+.ta \w'DEL111'u
+Space  to replace this occurrence and go on to the next one.
+Period to replace this occurrence and then stop.
+DEL    to skip this occurrence and go on to the next one.
+C-R    to enter a recursive edit.  This lets you temporarily
+       suspend the replace, do some editing, and then return
+       to continue where you left off.  To continue with the
+       Query Replace type "C-X C-C" as if you were trying to
+       exit \s-2JOVE\s0.  Normally you would but when you are in a
+       recursive edit all it does is exit that recursive
+       editing level.
+C-W    to delete the matched string and then enter a recursive
+       edit.
+U      to undo all changes to the last modified line.
+P or ! to go ahead and replace the remaining occurrences without
+       asking.
+Return to stop the Query Replace.
+.DE
+The search for occurrences starts at point and goes to the end of the
+buffer, so to replace in the entire buffer you must first go to the
+beginning.
+.dc "quit-process" "Not Bound"
+This is the same as typing "C-\e" (the Quit character) to a normal UNIX
+process, except it sends it to the current process in \s-2JOVE\s0.  This is
+only for versions of \s-2JOVE\s0 that have the interactive processes feature.
+This only works when you are inside a buffer that's attached to a
+process.
+.dc "quoted-insert" "C-Q"
+This lets you insert characters that normally would be executed as
+other \s-2JOVE\s0 commands.  For example, to insert "C-F" you type "C-Q C-F".
+.dc "read-only-mode" "Not Bound"
+Read-only-mode is a minor mode.  It puts a buffer in read-only mode, so
+that any attempts to modify the buffer fail.  When a file is found, and
+it's not got write permission, JOVE automatically puts the buffer in
+read-only mode.  This is very helpful when you are in environments which
+use source control programs like RCS and SCCS.  It prevents accidents
+like making a bunch of changes and only THEN discovering that you haven't
+checked the file out for making changes.  This, like other minor modes,
+toggles.
+.dc "read-word-abbrev-file" "Not Bound"
+This reads a specified file that contains a bunch of abbreviation
+definitions, and makes those abbreviations available.  If the selected
+buffer is not already in Word Abbrev mode this command puts it in
+that mode.
+.dc "recursive-edit" "Not Bound"
+This enters a recursive editing level.  This isn't really very
+useful.  I don't know why it's available for public use.  I think I'll
+delete it some day.
+.dc "redraw-display" "C-L"
+This centers the line containing point in the window.  If that line is
+already in the middle the window is first cleared and then redrawn.
+If a numeric argument is supplied, the line is positioned at that
+offset from the top of the window.  For example, "ESC 0 C-L" positions
+the line containing point at the top of the window.
+.dc "rename-buffer" "Not Bound"
+This lets you rename the current buffer.
+.dc "replace-in-region" "Not Bound"
+This is the same as
+.IQ replace-string
+except that it is restricted
+to occurrences between Point and Mark.
+.dc "replace-string" "ESC R"
+This replaces all occurrences of a specified string with a specified
+replacement string.  This is just like
+.IQ query-replace-string
+except
+it replaces without asking.
+.dc "right-margin" "(variable)"
+Where the right margin is for
+.IQ "Auto Fill"
+mode and the
+.IQ justify-paragraph
+and
+.IQ justify-region
+commands.  The default is 78.
+.dc "right-margin-here" "Not Bound"
+This sets the
+.IQ right-margin
+variable to the current position of
+point.  This is an easy way to say, "Make the right margin begin here,"
+without having to count the number of spaces over it actually is.
+.dc "save-file" "C-X C-S"
+This saves the current buffer to the associated file.  This makes your
+changes permanent so you should be sure you really want to.  If the
+buffer has not been modified
+.IQ save-file
+refuses to do the save.  If
+you really do want to write the file you can use "C-X C-W" which
+executes
+.IQ write-file.
+.dc "scroll-all-lines" "(variable)"
+When this is turned on, the entire window will be scrolled left or right
+when the current line scrolls.  The default value is OFF, which will
+cause \s-2JOVE\s0 to behave in the familiar way, namely to scroll only
+the current line.
+.dc "scroll-down" "ESC Z"
+This scrolls the screen one line down.  If the line containing point
+moves past the bottom of the window point is moved up to the center of
+the window.  If a numeric argument is supplied that many lines are
+scrolled; if the argument is negative the screen is scrolled up
+instead.
+.dc "scroll-left" "Not Bound"
+This scrolls the text in the current window 10 character positions to the
+left.  If a numeric argument is specified then the text is scrolled that
+number of character positions.  If the variable
+.IQ scroll-all-lines
+is ON then
+.IQ scroll-left
+may actually do nothing if the scrolling would cause Point not to be
+visible.
+.dc "scroll-next-page" "Not Bound"
+This continuously scrolls up screen-full lines (PC version only).
+.dc "scroll-previous-page" "Not Bound"
+This continuously scrolls down screen-full lines (PC version only).
+.dc "scroll-right" "Not Bound"
+This scrolls the text in the current window 10 character positions to the
+right.  If a numeric argument is specified then the text is scrolled that
+number of character positions.  If the variable
+.IQ scroll-all-lines
+is ON then
+.IQ scroll-right
+may actually do nothing if the scrolling would cause Point not to be
+visible.
+.dc "scroll-step" "(variable)"
+How many lines should be scrolled if the
+.IQ previous-line
+or
+.IQ next-line
+commands move you off the top or bottom of the screen.  You may wish to
+decrease this variable if you are on a slow terminal.  The default value
+is 0, which means to center the current line in the window.  If the value
+is negative, the behavior is slightly different.  If you move off the top
+of the window, and
+.IQ scroll-step
+is, say, -5 then the new line will be displayed 5 lines from the bottom
+of the window.  If you move off the bottom of the window, the new line
+will be positioned 5 lines from the top of the window.
+.dc "scroll-up" "C-Z"
+This scrolls the screen one line up.  If the line containing point
+moves past the top of the window point is moved down to the center of
+the window.  If a numeric argument is supplied that many lines are
+scrolled; if the argument is negative the screen is scrolled down
+instead.
+.dc "search-exit-char" "(variable)"
+Set this to the character you want to use to exit incremental search.
+The default is Newline, which makes i-search compatible with normal
+string search.
+.dc "search-forward" "C-S"
+This searches forward for a specified search string and positions
+point at the end of the string if it's found.  If the string is not
+found point remains unchanged.  This searches from point to the end of
+the buffer, so any matches before point will be missed.
+.dc "search-forward-nd" "Not Bound"
+This is just like
+.IQ search-forward
+except that it doesn't assume a default search string, and it doesn't set
+the default search string.  This is useful for defining macros, when you
+want to search for something, but you don't want it to affect the current
+default search string.
+.dc "search-reverse" "C-R"
+This searches backward for a specified search string and positions
+point at the beginning if the string if it's found.  If the string is
+not found point remains unchanged.  This searches from point to the
+beginning of the buffer, so any matches after point will be missed.
+.dc "search-reverse-nd" "Not Bound"
+This is just like
+.IQ search-reverse
+except that it doesn't assume a default search string, and it doesn't set
+the default search string.  This is useful for defining macros, when you
+want to search for something, but you don't want it to affect the current
+default search string.
+.dc "select-buffer" "C-X B"
+This selects a new or already existing buffer making it the current
+one.  You can type either the buffer name or number.  If you type in
+the name you need only type the name until it is unambiguous, at which
+point typing Escape or Space will complete it for you.  If you want to
+create a new buffer you can type Return instead of Space, and a new
+empty buffer will be created.
+.dc "select-buffer-1" "<Alt>-0"
+This selects buffer number 0, if it exists (PC version only).
+.dc "select-buffer-1" "<Alt>-1"
+This selects buffer number 1, if it exists (PC version only).
+.dc "select-buffer-2" "<Alt>-2"
+This selects buffer number 2, if it exists (PC version only).
+.dc "select-buffer-3" "<Alt>-3"
+This selects buffer number 3, if it exists (PC version only).
+.dc "select-buffer-4" "<Alt>-4"
+This selects buffer number 4, if it exists (PC version only).
+.dc "select-buffer-5" "<Alt>-5"
+This selects buffer number 5, if it exists (PC version only).
+.dc "select-buffer-6" "<Alt>-6"
+This selects buffer number 6, if it exists (PC version only).
+.dc "select-buffer-7" "<Alt>-7"
+This selects buffer number 7, if it exists (PC version only).
+.dc "select-buffer-8" "<Alt>-8"
+This selects buffer number 8, if it exists (PC version only).
+.dc "select-buffer-9" "<Alt>-9"
+This selects buffer number 9, if it exists (PC version only).
+.dc "self-insert" "Most Printing Characters"
+This inserts the character that invoked it into the buffer at point.
+Initially all but a few of the printing characters are bound to
+.IQ self-insert.
+.dc "send-typeout-to-buffer" "(variable)"
+When this is set \s-2JOVE\s0 will send output that normally overwrites the
+screen (temporarily) to a buffer instead.  This affects commands like
+.IQ list-buffers,
+.IQ list-processes,
+and commands that use completion.  The default value is "off".
+.dc "set" "Not Bound"
+This gives a specified variable a new value.  Occasionally you'll see
+lines like "set this variable to that value to do this".  Well, you
+use the
+.IQ set
+command to do that.
+.dc "set-mark" "C-@"
+This sets the mark at the current position in the buffer.  It prints
+the message "Point pushed" on the message line.  It says that instead
+of "Mark set" because when you set the mark the previous mark is still
+remembered on a ring of 16 marks.  So "Point pushed" means point is
+pushed onto the ring of marks and becomes the value of "the mark".
+To go through the ring of marks you type "C-U C-@", or execute the
+.IQ pop-mark
+command.  If you type this enough times you will get back
+to where you started.
+.dc "shell" "(variable)"
+The shell to be used with all the shell commands command.  If your SHELL
+environment variable is set, it is used as the value of
+.IQ shell;
+otherwise "/bin/csh" is the default.
+.dc "shell" "Not Bound"
+This starts up an interactive shell in a window.  \s-2JOVE\s0 uses
+"*shell*" as the name of the buffer in which the interacting takes
+place.  See the manual for information on how to use interactive
+processes.
+.dc "shell-command" "C-X !"
+This runs a UNIX command and places the output from that command in a
+buffer.  \s-2JOVE\s0 creates a buffer that matches the name of the command
+you specify and then attaches that buffer to a window.  So, when you
+have only one window running this command will cause \s-2JOVE\s0 to split the
+window and attach the new buffer to that window.  Otherwise, \s-2JOVE\s0
+finds the most convenient of the available windows and uses that one
+instead.  If the buffer already exists it is first emptied, except that if
+it's holding a file, not some output from a previous command, \s-2JOVE\s0
+prints an error message and refuses to execute the command.  If you
+really want to execute the command you should delete that buffer
+(saving it first, if you like) or use
+.IQ shell-command-to-buffer,
+and
+try again.
+.dc "shell-command-no-buffer" "Not Bound"
+This is just like
+.IQ shell-command
+except it just runs the command without saving the output to any buffer.
+It will report the success of the command in the usual way.
+.dc "shell-command-to-buffer" "Not Bound"
+This is just like
+.IQ shell-command
+except it lets you specify the
+buffer to use instead of \s-2JOVE\s0.
+.dc "shell-command-with-typeout" "Not Bound"
+This is just like
+.IQ shell-command
+except that instead of saving the output to a buffer, and displaying
+it in a window, this just types out the output in the same way that
+.IQ list-buffers
+does.  Actually, how this behaves depends on the value of the variable
+.IQ send-typeout-to-buffer.
+If it is on then shell-command-with-typeout will behave just like
+.IQ shell-command.
+.dc "shell-flags" "(variable)"
+This defines the flags that are passed to shell commands.  The default is
+"-c".  See the
+.IQ shell
+variable to change the default shell.
+.dc "shift-region-left" "Not Bound"
+This shifts the region left by c-indentation-increment OR by the numeric
+argument, if one is supplied.  If a negative argument is supplied the
+region is shifted the other way.
+.dc "shift-region-right" "Not Bound"
+This shifts the region left by c-indentation-increment OR by the numeric
+argument, if one is supplied.  If a negative argument is supplied the
+region is shifted the other way.
+.dc "show-match-mode" "Not Bound"
+This turns on Show Match mode (or off if it's currently on) in the
+selected buffer.  This changes "}", ")" and "]" so that when they are
+typed the are inserted as usual, and then the cursor flashes back to the
+matching "{", "(" or "[" (depending on what was typed) for about half a
+second, and then goes back to just after the "}", ")" or "]" that invoked
+the command.  This is useful for typing in complicated expressions in a
+program.  You can change how long the cursor sits on the matching paren
+by setting the "paren-flash-delay" variable in tenths of a second.  If
+the matching "{", "(" or "[" isn't visible, the line containing the match
+is displayed at the bottom of the screen.
+.dc "shrink-window" "Not Bound"
+This makes the current window one line shorter, if possible.  Windows
+must be at least 2 lines high, one for the text and the other for the
+mode line.
+.dc "source" "Not Bound"
+This reads a bunch of \s-2JOVE\s0 commands from a file.  The format of the
+file is the same as that in your initialization file (your ".joverc")
+in your main directory.  There should be one command per line and it
+should be as though you typed "ESC X" while in \s-2JOVE\s0.  For example,
+here's part of my initialization file:
+.DS I
+bind-to-key i-search-reverse ^R
+bind-to-key i-search-forward ^S
+bind-to-key pause-jove ^[S
+.DE
+What they do is make "C-R" call the
+.IQ i-search-reverse
+command and
+"C-S" call
+.IQ i-search-forward
+and "ESC S" call
+.IQ pause-jove.
+.dc "spell-buffer" "Not Bound"
+This runs the current buffer through the UNIX
+.IQ spell
+program and places
+the output in buffer "Spell".  Then \s-2JOVE\s0 lets you edit the list of
+words, expecting you to delete the ones that you don't care about, i.e., the
+ones you know are spelled correctly.  Then the
+.IQ parse-spelling-errors-in-buffer
+command comes along and finds all the
+misspelled words and sets things up so the error commands work.
+.dc "split-current-window" "C-X 2"
+This splits the current window into two equal parts (providing the
+resulting windows would be big enough) and displays the selected buffer
+in both windows.  Use "C-X 1" to go back to 1 window mode.  If a numeric
+argument is supplied, the window is split "evenly" that many times (when
+possible).
+.dc "start-remembering" "C-X ("
+This is just another name for the
+.IQ begin-kbd-macro
+name.  It is included for backward compatibility.
+.dc "stop-process" "Not Bound"
+This sends a stop signal (C-Z, for most people) to the current process.
+It only works if you have the interactive process feature, and you are
+in a buffer attached to a process.
+.dc "stop-remembering" "C-X )"
+This is just another name for the
+.IQ end-kbd-macro
+command.  It is included for backward compatibility.
+.dc "string-length" "Not Bound"
+This prints the number of characters in the string that point sits in.
+Strings are surrounded by double quotes.  \s-2JOVE\s0 knows that "\e007" is
+considered a single character, namely "C-G", and also knows about
+other common ones, like "\er" (Return) and "\en" (LineFeed).  This is
+mostly useful only for C programmers.
+.dc "suspend-jove" "ESC S"
+This is a synonym for
+.IQ pause-jove.
+.dc "sync-frequency" "(variable)"
+The temporary files used by \s-2JOVE\s0 are forced out to disk every
+.IQ sync-frequency
+modifications.  The default is 50, which really makes
+good sense.  Unless your system is very unstable, you probably
+shouldn't fool with this.
+.dc "tag-file" "(variable)"
+This the name of the file in which \s-2JOVE\s0 should look up tag
+definitions.  The default value is "./tags".
+.dc "text-mode" "Not Bound"
+This sets the major mode to Text.  Currently the other modes are
+Fundamental, C and Lisp mode.
+.dc "tmp-file-pathname" "(variable)"
+This tells JOVE where to put the tmp files, which is where JOVE stores
+buffers internally.  The default is usually in /tmp, but if you want to
+store them somewhere else, you can set this variable.  If your system
+crashes a lot it might be a good idea to set this variable to somewhere
+other than /tmp because the system removes all the files in /tmp upon
+reboot, and so you would not be able to recover editor buffers using the
+"jove -r" command.
+
+NOTE: In order for this to work correctly you must set this variable
+BEFORE JOVE creates the tmp file.  You can set this in your .joverc (the
+closer to tbe beginning the better), or as soon as you start up JOVE
+before you visit any files.
+.dc "transpose-characters" "C-T"
+This switches the character before point with the one after point, and
+then moves forward one.  This doesn't work at the beginning of the
+line, and at the end of the line it switches the two characters before
+point.  Since point is moved forward, so that the character that was
+before point is still before point, you can use "C-T" to drag a
+character down the length of a line.  This command pretty quickly
+becomes very useful.
+.dc "transpose-lines" "C-X C-T"
+This switches the current line with the one above it, and then moves
+down one so that the line that was above point is still above point.
+This, like
+.IQ transpose-characters,
+can be used to drag a line down a page.
+.dc "unbind-key" "Not Bound"
+Use this to unbind
+.IQ any
+key sequence.  You can use this to unbind even a
+prefix command, since this command does not use "key-map completion".  For
+example, "ESC X unbind-key ESC [" unbinds the sequence "ESC [".  This is
+useful for "turning off" something set in the system-wide ".joverc" file.
+.dc "update-time-frequency" "(variable)"
+How often the mode line is updated (and thus the time and load
+average, if you display them).  The default is 30 seconds.
+.dc "use-i/d-char" "(variable)"
+If your terminal has insert/delete character capability you can tell \s-2JOVE\s0
+not to use it by setting this to "off".  In my opinion it is only worth using
+insert/delete character at low baud rates.  WARNING: if you set this to
+"on" when your terminal doesn't have insert/delete character capability,
+you will get weird (perhaps fatal) results.
+.dc "version" "Not Bound"
+Displays the version number of this \s-2JOVE\s0.
+.dc "visible-bell" "(variable)"
+Use the terminal's visible bell instead of beeping.  This is set
+automatically if your terminal has the capability.
+.dc "visible-spaces-in-window" "Not Bound"
+This displays an underscore character instead of each space in the
+window and displays a greater-than followed by spaces for each tab
+in the window.  The actual text in the buffer is not changed; only
+the screen display is affected.  To turn this off you run the command
+again; it toggles.
+.dc "visit-file" "C-X C-V"
+This reads a specified file into the current buffer replacing the old
+text.  If the buffer needs saving \s-2JOVE\s0 will offer to save it for you.
+Sometimes you use this to start over, say if you make lots of changes
+and then change your mind.  If that's the case you don't want \s-2JOVE\s0 to
+save your buffer and you answer "NO" to the question.
+.dc "window-find" "C-X 4"
+This lets you select another buffer in another window three
+different ways.  This waits for another character which can be one of
+the following:
+.DS I
+.ta .5i 1i 1.5i
+T      Finds a tag in the other window.
+^T     Finds the tag at point in the other window
+F      Finds a file in the other window.
+B      Selects a buffer in the other window.
+.DE
+This is just a convenient short hand for "C-X 2" (or "C-X O" if there are
+already two windows) followed by the appropriate sequence for invoking each
+command.  With this, though, there isn't the extra overhead of having to
+redisplay.  In addition, you don't have to decide whether to type "C-X 2" or
+"C-X O" since "C-X 4" does the right thing.
+.dc "word-abbrev-mode" "Not Bound"
+This turns on Word Abbrev mode (or off if it's currently on) in the
+selected buffer.  Word Abbrev mode lets you specify a word (an
+abbreviation) and a phrase with which \s-2JOVE\s0 should substitute the
+abbreviation.  You can use this to define words to expand into long
+phrases, e.g., "jove" can expand into "Jonathan's Own Version of
+Emacs"; another common use is defining words that you often misspell
+in the same way, e.g., "thier" => "their" or "teh" => "the".  See
+the information on the
+.IQ auto-case-abbrev
+variable.
+.sp 1
+There are two kinds of abbreviations: mode specific and global.  If you
+define a Mode specific abbreviation in C mode, it will expand only in
+buffers that are in C mode.  This is so you can have the same
+abbreviation expand to different things depending on your context.
+Global abbreviations expand regardless of the major mode of the buffer.
+The way it works is this: \s-2JOVE\s0 looks first in the mode specific
+table, and then in the global table.  Whichever it finds it in first is
+the one that's used in the expansion.  If it doesn't find the word it is
+left untouched. \s-2JOVE\s0 tries to expand words as they are typed, when
+you type a punctuation character or Space or Return.  If you are in Auto
+Fill mode the expansion will be filled as if you typed it yourself.
+.dc "wrap-search" "(variable)"
+If set, searches will "wrap around" the ends of the buffer instead
+of stopping at the bottom or top.  The default is "off".
+.dc "write-file" "C-X C-W"
+This saves the current buffer to a specified file, and then makes that
+file the default file name for this buffer.  If you specify a file
+that already exists you are asked to confirm over-writing it.
+.dc "write-files-on-make" "(variable)"
+When set, all modified files will be written out before calling
+make when the
+.IQ compile-it
+command is executed.  The default is "on".
+.dc "write-macros-to-file" "Not Bound"
+This writes the currently defined macros to a specified file in a format
+appropriate for reading them back in with the
+.IQ source
+command.  The purpose of this command is to allow you to define macros
+once and use them in other instances of JOVE.
+.dc "write-modified-files" "C-X C-M"
+This saves all the buffers that need saving.  If you supply a numeric
+argument it asks for each buffer whether you really want to save it.
+.dc "write-region" "Not Bound"
+This writes the text in the region to a specified file.  If the file
+already exists you are asked to confirm over-writing it.
+.dc "write-word-abbrev-file" "Not Bound"
+This writes the currently defined abbreviations to a specified file.
+They can be read back in and automatically defined with
+.IQ read-word-abbrev-file.
+.dc "xterm-mouse" "Not Bound"
+This function enables the use of the mouse with \S-2JOVE\fP in an
+xterm window. The function is enabled when 'ansi-codes' is defined and
+the function is bound to <escape><open-square-bracket>M.
+Moving the mouse and pressing the left button will set the point
+to the mouse position and push it.
+Moving the mouse and pressing the right button will set the point
+to the mouse position and yank the region from the last mark and the
+current point.
+Moving the mouse and pressing the middle button will set the point
+to the mouse position and paste the contents of the mouse button in place.
+Note that this in a \s-2JOVE\fP function and is independent of the normal
+cut and paste operations available under xterm.
+It is possible to bind these operations to SHIFT+the mouse button, so that
+they will work in addition to \s-2JOVE\fP cut and paste.
+.dc "yank" "C-Y"
+This undoes the last kill command.  That is, it inserts the killed
+text at point.  When you do multiple kill commands in a row, they are
+merged so that yanking them back with "C\-Y" yanks back all of them.
+.dc "yank-pop" "ESC Y"
+This yanks back previous killed text.  \s-2JOVE\s0 has a kill ring on which
+the last 10 kills are stored.
+.IQ yank
+yanks a copy of the text at the
+front of the ring.  If you want one of the last ten kills you use "ESC
+Y" which rotates the ring so another different entry is now at the
+front.  You can use "ESC Y" only immediately following a "C-Y" or
+another "ESC Y".  If you supply a negative numeric argument the ring
+is rotated the other way.  If you use this command enough times in a
+row you will eventually get back to where you started.  Experiment
+with this.  It's extremely useful.
diff --git a/usr/src/contrib/jove-4.14.6/doc/jove.nr b/usr/src/contrib/jove-4.14.6/doc/jove.nr
new file mode 100644 (file)
index 0000000..c0e2688
--- /dev/null
@@ -0,0 +1,283 @@
+.hy 0
+.TH JOVE 1 "12 February 1986"
+.ad
+.SH NAME
+jove - an interactive display-oriented text editor
+.SH SYNOPSIS
+.nf
+jove [-d directory] [-w] [-t tag] [+[n] file] [-p file] [files]
+jove -r
+.fi
+.SH DESCRIPTION
+JOVE is Jonathan's Own Version of Emacs.  It is based on the original EMACS
+editor written at MIT by Richard Stallman.  Although JOVE is meant to be
+compatible with EMACS, there are some major differences between the two
+editors and you shouldn't rely on their behaving identically.
+.LP
+JOVE works on any reasonable display terminal that is described in the
+.I termcap
+file (see TERMCAP(5) for more details).  When you start up JOVE, it checks
+to see whether you have your
+.I TERM
+environment variable set.  On most systems that will automatically be set up
+for you, but if it's not JOVE will ask you what kind of terminal you are
+using.  To avoid having to type this every time you run JOVE you can set your
+.I TERM
+environment variable yourself.  How you do this depends on which shell you
+are running.  If you are running the C Shell, as most of you are, you type
+.sp 1
+     % setenv TERM
+.I type
+.sp 1
+and with the Bourne Shell, you type
+.sp 1
+     $ TERM=
+.I type
+; export TERM
+.sp 1
+where
+.I type
+is the name of the kind of terminal you are using (e.g., vt100).  If
+neither of these works get somebody to help you.
+.SH INVOKING JOVE
+If you run JOVE with no arguments you will be placed in an empty buffer,
+called
+.I Main.
+Otherwise, any arguments you supply are considered file names and each is
+"given" its own buffer.  Only the first file is actually read in--reading
+other files is deferred until you actually try to use the buffers they are
+attached to.  This is for efficiency's sake: most of the time, when you run
+JOVE on a big list of files, you end up editing only a few of them.
+.LP
+The names of all of the files specified on the command line are saved in a
+buffer, called
+.I *minibuf*.
+The mini-buffer is a special JOVE buffer that is used when JOVE is prompting
+for some input to many commands (for example, when JOVE is prompting for a
+file name).  When you are being prompted for a file name, you can type C-N
+(that's Control-N) and C-P to cycle through the list of files that were
+specified on the command line.  The file name will be inserted where you are
+typing and then you can edit it as if you typed it in yourself.
+.LP
+JOVE recognizes the following switches:
+.TP
+.I -d
+The following argument is taken to be the name of the current directory.
+This is for systems that don't have a version of C shell that automatically
+maintains the
+.I CWD
+environment variable.  If
+.I -d
+is not specified on a system without a modified C shell, JOVE will have to
+figure out the current directory itself, and that can be VERY slow.  You
+can simulate the modified C shell by putting the following lines in your
+C shell initialization file (.cshrc):
+.nf
+.sp 1
+       alias cd        'cd \e!*; setenv CWD $cwd'
+       alias popd      'popd \e!*; setenv CWD $cwd'
+       alias pushd     'pushd \e!*; setenv CWD $cwd'
+.fi
+.TP
+.I +n
+Reads the file, designated by the following argument, and positions point at
+the
+.I n'th
+line instead of the (default) 1'st line.  This can be specified more than
+once but it doesn't make sense to use it twice on the same file; in that
+case the second one wins. If no numeric argument is given after the +,
+the point is positioned at the end of the file.
+.TP
+.I -p
+Parses the error messages in the file designated by the following argument.
+The error messages are assumed to be in a format similar to the C compiler,
+LINT, or GREP output.
+.TP
+.I -t
+Runs the
+.I find-tag 
+command on the string of characters immediately following 
+the -t if there is one (as in -tTagname), or on
+the following argument (as in -t Tagname) otherwise (see ctags(1)).
+.TP
+.I -w
+Divides the window in two.  When this happens, either the same file is
+displayed in both windows, or the second file in the list is read in and
+displayed in its window.
+.SH "RECOVERING BUFFERS AFTER A CRASH"
+The
+.I -r
+option of jove runs the JOVE recover program.  Use this when the system
+crashes, or JOVE crashes, or you accidently get logged out while in JOVE.
+If there are any buffers to be recovered, this will find them.
+.LP
+Recover looks for JOVE buffers that are left around and are
+owned by you.  (You cannot recover other peoples' buffers, obviously.)
+If there were no buffers that were modified at the time of the
+crash or there were but recover can't get its hands on them, you will be
+informed with the message, "There is nothing to recover."  Otherwise,
+recover prints the date and time of the version of the buffers it has,
+and then waits for you type a command.
+.LP
+To get a list of the buffers recover knows about, use the
+.I list
+command.  This will list all the buffers and the files and the number of
+lines associated with them.  Next to each buffer is a number.  When you want
+to recover a buffer, use the
+.I get
+command.  The syntax is
+.I get buffer filename
+where
+.I buffer
+is either the buffer's name or the number at the beginning of the line.  If
+you don't type the buffer name or the filename, recover will prompt you
+for them.
+.LP
+If there are a lot of buffers and you want to recover all of them, use the
+.I recover
+command.  This will recover each buffer to the name of the buffer with ".#"
+prepended to the name (so that the original isn't over-written).  It asks
+for each file and if you want to restore that buffer to that name you type
+"yes".  If you want to recover the file but to a different name, just type
+the new name in.  If you type "no" recover will skip that file and go on
+to the next one.
+.LP
+If you want to look at a buffer before deciding to recover it, use the
+.I print
+command.  The syntax for this is
+.I print buffer
+where
+.I buffer
+again is either its name or the number.  You can type ^C if you want to
+abort printing the file to the terminal, and recover will respond with
+an appropriate message.
+.LP
+When you're done and have all the buffers you want, type the
+.I quit
+command to leave.  You will then be asked whether it's okay to delete the
+tmp files.  Most of the time that's okay and you should type "yes".  When
+you say that, JOVE removes all traces of those buffers and you won't be able
+to look at them again.  (If you recovered some buffers they will still be
+around, so don't worry.)  So, if you're not sure whether you've gotten all
+the buffers, you should answer "no" so that you'll be able to run
+recover again at a later time (presumably after you've figured out
+which ones you want to save).
+.LP
+If you type ^C at any time other than when you're printing a file to the
+terminal, recover will exit without a word.  If you do this but wish you
+hadn't, just type "jove -r" to the shell again, and you will be put back
+with no loss.
+.SH GETTING HELP
+Once in JOVE, there are several commands available to get help.  To execute
+any JOVE command, you type "<ESC> X command-name" followed by <Return>.  To
+get a list of all the JOVE commands you type "<ESC> X" followed by "?".  The
+.I describe-bindings
+command can be used to get a list containing each key, and its associated
+command (that is, the command that gets executed when you type that key).
+If you want to save the list of bindings, you can set the jove variable
+.I send-typeout-to-buffer
+to ON (using the 
+.I set
+command), and then execute the
+.I describe-bindings
+command.  This will create a buffer and put in it the bindings list it
+normally would have printed on the screen.  Then you can save that buffer to
+a file and print it to use as a quick reference card.  (See VARIABLES below.)
+.LP
+Once you know the name of a command, you can find out what it does with the
+.I describe-command
+command, which you can invoke quickly by typing "ESC ?".  The
+.I apropos
+command will give you a list of all the command with a specific string in
+their names.  For example, if you want to know the names of all the
+commands that are concerned with windows, you can run "apropos" with the
+keyword
+.I window.
+.LP
+If you're not familar with the EMACS command set, it would be worth your
+while to use run TEACHJOVE.  Do do that, just type "teachjove" to your shell
+and you will be placed in JOVE in a file which contains directions.  I highly
+recommend this for beginners; you may save yourself a lot of time and
+headaches.
+.SH KEY BINDINGS and VARIABLES
+You can alter the key bindings in JOVE to fit your personal tastes.  That
+is, you can change what a key does every time you strike it.  For example,
+by default the C-N key is bound to the command
+.I next-line
+and so when you type it you move down a line.  If you want to change a
+binding or add a new one, you use the
+.I bind-to-key
+command.  The syntax is "bind-to-key <command> key".
+.LP
+You can also change the way JOVE behaves in little ways by changing the
+value of some variables with the
+.I set
+command.  The syntax is "set <variable> value", where value is a number or a
+string, or "on" or "off", depending on the context.  For example, if you
+want JOVE to make backup files, you set the "make-backup-files" variable to
+"on".  To see the value of a variable, use the "print <variable>" command.
+.SH INITIALIZATION
+JOVE automatically reads commands from an initialization file in your HOME
+directory, called ".joverc".  In this file you can place commands that you
+would normally type in JOVE.  If you like to rearrange the key bindings and
+set some variables every time you get into JOVE, you should put them in your
+initialization file.  Here are a few lines from mine:
+.nf
+       set match-regular-expressions on
+       auto-execute-command auto-fill /tmp/Re\e|.*drft
+       bind-to-key i-search-forward ^\e
+       bind-to-key i-search-reverse ^R
+       bind-to-key find-tag-at-point ^[^T
+       bind-to-key scroll-down ^C
+       bind-to-key grow-window ^Xg
+       bind-to-key shrink-window ^Xs
+.fi
+(Note that the Control Characters can be either two character sequences
+(e.g. ^ and C together as ^C) or the actual control character.  If you want
+to use an ^ by itself you must BackSlash it (e.g., bind-to-key grow-window
+^X\e^ binds grow-window to "^X^").
+.SH SOME MINOR DETAILS
+You should type C-\e instead of C-S in many instances.  For example, the way
+to search for a string is documented as being "C-S" but in reality you
+should type "C-\e".  This is because C-S is the XOFF character (what gets
+sent when you type the NO SCROLL key), and clearly that won't work.  The XON
+character is "C-Q" (what gets sent when you type NO SCROLL again) which is
+documented as the way to do a quoted-insert.  The alternate key for this is
+"C-^" (typed as "C-`" on vt100's and its look-alikes).  If you want to
+enable C-S and C-Q and you know what you are doing, you can put the line:
+.nf
+       set allow-^S-and-^Q on
+.fi
+in your initialization file.
+.LP
+If your terminal has a metakey, JOVE will use it if you turn on the
+"meta-key" variable.  JOVE will automatically turn on "meta-key" if the
+METAKEY environment variable exists.  This is useful for if you have
+different terminals (e.g., one at home and one at work) and one has a
+metakey and the other doesn't.
+.SH FILES
+SHAREDIR/jove.rc - system wide initialization file
+.sp 0
+~/.joverc - personal initialization file
+.sp 0
+TMPDIR - where temporary files are stored
+.sp 0
+SHAREDIR/teach-jove - the interactive tutorial
+.sp 0
+LIBDIR/portsrv - for running shells in windows (pdp11 only)
+.SH SEE ALSO
+.nf
+ed(1) - for a description of regular expressions
+.sp 0
+teachjove(1) - for an interactive JOVE tutorial.
+.fi
+.SH DIAGNOSTICS
+JOVE diagnostics are meant to be self-explanatory, but you are advised
+to seek help whenever you are confused.  You can easily lose a lot of
+work if you don't know EXACTLY what you are doing.
+.SH BUGS
+Lines can't be more than 1024 characters long.
+.sp 1
+Searches can't cross line boundaries.
+.SH AUTHOR
+Jonathan Payne
diff --git a/usr/src/contrib/jove-4.14.6/doc/jove.qref b/usr/src/contrib/jove-4.14.6/doc/jove.qref
new file mode 100644 (file)
index 0000000..3c0158a
--- /dev/null
@@ -0,0 +1,132 @@
+                                       JOVE Command Quick Reference Guide
+
+--- HELP
+apropos                                        describe-bindings                       describe-command        ESC ?
+describe-key           C-X ?           describe-variable                       execute-named-command   ESC X
+
+
+--- MOVING AROUND
+backward-character     C-B             backward-list           ESC C-P         backward-paragraph      ESC [
+backward-s-expression  ESC C-B         backward-sentence       ESC A           backward-up-list        ESC C-U
+backward-word          ESC B           beginning-of-file       ESC <           beginning-of-line       C-A
+beginning-of-window    ESC ,           current-error                           down-list               ESC C-D
+end-of-file            ESC >           end-of-line             C-E             end-of-window           ESC .
+find-tag               C-X T           find-tag-at-point                       first-non-blank         ESC M
+forward-character      C-F             forward-list            ESC C-N         forward-paragraph       ESC ]
+forward-s-expression   ESC C-F         forward-sentence        ESC E           forward-word            ESC F
+goto-line              ESC G           next-error              C-X C-N         next-line               C-N
+next-page              C-V             previous-error          C-X C-P         previous-line           C-P
+previous-page          ESC V           window-find-tag         C-X 4 t         
+
+--- INSERTING AND DELETING
+delete-blank-lines     C-X C-O         delete-next-char        C-D             delete-previous-char    C-H (DEL)
+delete-white-space     ESC-\           erase-buffer                            handle-tab              C-I (TAB)
+kill-next-word         ESC D           kill-next-word          ESC d           kill-previous-word      ESC ^?
+kill-s-expression      ESC C-K         kill-to-beginning-of-se C-X ^?          kill-to-end-of-line     C-K
+kill-to-end-of-sentence        ESC K           newline                 C-M (RETURN)    newline-and-backup      C-O
+newline-and-indent     C-J             over-write-mode                         quoted-insert           C-^
+
+
+--- SEARCH AND REPLACE
+find-tag               C-X T           find-tag-at-point                       i-search-forward        
+i-search-reverse                       query-replace-string    ESC Q           replace-in-region       
+replace-string         ESC R           search-forward          C-\             search-reverse          C-R
+window-find-tag                C-X 4 t         
+
+--- MARKS AND REGIONS
+append-region                          append-region                           case-region-lower       
+case-region-upper                      copy-region             ESC W           exchange-point-and-mark C-X C-X
+filter-region                          kill-region             C-W             replace-in-region       
+set-mark               C-@ (C-SPACE)   write-region                            yank                    C-Y
+yank-pop               ESC Y           
+
+--- TEXT PROCESSING
+auto-fill-mode                         bind-macro-to-word-abbr                 case-character-capitali 
+case-region-lower                      case-region-upper                       case-word-capitalize    ESC C
+case-word-lower                ESC L           case-word-upper         ESC U           current-error           
+define-global-word-abbr                        define-mode-word-abbrev                 edit-word-abbrevs       
+fill-paragraph         ESC J           fill-region                             left-margin-here        
+next-error             C-X C-N         over-write-mode                         parse-spelling-errors-i 
+previous-error         C-X C-P         read-word-abbrev-file                   right-margin-here       
+spell-buffer                           text-mode                               transpose-characters    C-T
+transpose-lines                C-X C-T         visible-spaces-in-windo                 word-abbrev-mode        
+write-word-abbrev-file                 
+
+--- DISPLAY AND WINDOWS
+clear-and-redraw       ESC C-L         delete-current-window   C-X D           delete-current-window   C-X d
+delete-other-windows   C-X 1           grow-window             C-X ^           next-window             C-X N
+number-lines-in-window                 page-next-window        ESC C-V         previous-window         C-X P
+redraw-display         C-L             scroll-down             ESC Z           scroll-up               C-Z
+shrink-window                          split-current-window    C-X 2           window-find-buffer      C-X 4 b
+window-find-file       C-X 4 f         window-find-tag         C-X 4 t         
+
+--- FILES AND BUFFERS
+append-region                          append-region                           buffer-position         
+delete-buffer          C-X K           delete-buffer           C-X k           erase-buffer            
+find-file              C-X C-F         insert-file             C-X C-I         kill-buffer             C-X K
+list-buffers           C-X C-B         make-buffer-unmodified  ESC ~           read-macros-from-file   
+read-word-abbrev-file                  rename-buffer                           save-file               C-X C-\
+save-file              C-X C-S         select-buffer           C-X B           select-existing-buffer  C-X B
+spell-buffer                           visit-file              C-X C-V         visit-file              C-X C-R
+window-find-buffer     C-X 4 b         window-find-file        C-X 4 f         write-file              C-X C-W
+write-macros-to-file                   write-modified-files    C-X C-M         write-region            
+write-word-abbrev-file                 
+
+--- DIRECTORIES
+cd                                     dirs                                    popd                    
+pushd                                  pwd                                     
+\f
+
+--- PROGRAMMERS
+auto-indent-mode                       backward-s-expression   ESC C-B         c-mode                  
+compile-it(make)       C-X C-E         current-error                           fill-comment            
+forward-s-expression   ESC C-F         grind-s-expr                            kill-s-expression       ESC C-K
+lisp-mode                              next-error              C-X C-N         number-lines-in-window  
+paren-flash            ),],}           parse-errors                            parse-special-errors    
+previous-error         C-X C-P         show-match-mode                         string-length           
+visible-spaces-in-windo                        
+
+--- REPEAT
+digit                  ESC -           digit                   ESC [0-9]       quadruple-numeric-argum C-U
+
+
+--- MACROS
+delete-macro                           execute-keyboard-macro  C-X E           make-macro-interactive  
+make-macro-interactive ESC I           read-macros-from-file                   begin-kbd-macro C-X (
+end-kbd-macro          C-X )           write-macros-to-file                    
+
+--- SHELL
+exit-jove              C-X C-C         i-shell-command                         pause-jove              ESC S
+pause-jove             ESC s           push-shell                              shell                   
+shell-command          C-X !           shell-command-to-buffer                 suspend-jove            
+
+
+--- PROCESSES
+eof-process                            interrupt-process       C-C             kill-process            
+list-processes                         process-bind-to-key                     process-newline         C-M (RETURN)
+process-send-data-no-re                        quit-process                            stop-process            
+
+
+--- MISCELLANEOUS
+auto-execute-command                   auto-execute-macro                      bind-macro-to-key       
+bind-macro-to-word-abbr                        bind-to-key                             character-to-octal-inse 
+date                                   execute-extended-comman ESC X           fundamental-mode        
+print                                  recursive-edit                          ring-the-bell(ABORT)    C-G
+set                                    source                                  unbind-key              
+version                                        
+
+--- VARIABLES
+allow-^S-and-^Q                                allow-bad-filenames                     auto-case-abbrev        
+bad-filename-extensions                        c-indentation-increment                 case-ignore-search      
+comment-format                         disable-biff                            error-window-size       
+file-creation-mode                     files-should-end-with-n                 internal-tabstop        
+left-margin                            mailbox                                 mail-check-frequency    
+make-backup-files                      mark-threshold                          marks-should-float      
+match-regular-expressio                        meta-key                                mode-line               
+mode-line-should-stando                        paren-flash-delay                       physical-tabstop        
+process-prompt                         interrupt-character                     right-margin            
+scroll-step                            search-exit-char                        send-typeout-to-buffer  
+shell                                  shell-flags                             sync-frequency          
+tag-file                               tmp-file-pathname                       update-time-frequency   
+use-i/d-char                           visible-bell                            wrap-search             
+write-files-on-make                    
diff --git a/usr/src/contrib/jove-4.14.6/doc/system.rc b/usr/src/contrib/jove-4.14.6/doc/system.rc
new file mode 100644 (file)
index 0000000..959c7e0
--- /dev/null
@@ -0,0 +1,20 @@
+auto-execute-command auto-fill-mode /tmp/Re\|/tmp/article
+auto-execute-command show-match .*\.[lchyf]$\|.*\.lisp$\|.*\.scm$
+auto-execute-command c-mode .*\.[chy]$
+auto-execute-command lisp-mode .*\.l$\|.*\.lisp$\|.*\.scm$
+bind-to-key pause-jove ^[S
+bind-to-key pause-jove ^[s
+set process-prompt ^[^%$#]*[%$#] 
+process-bind-to-key interrupt-process ^C
+process-bind-to-key process-newline ^M
+make-keymap ansi-codes
+bind-keymap-to-key ansi-codes ^[[
+bind-keymap-to-key ansi-codes ^[O
+bind-to-key previous-line ^[[A
+bind-to-key next-line ^[[B
+bind-to-key forward-character ^[[C
+bind-to-key backward-character ^[[D
+bind-to-key previous-line ^[OA
+bind-to-key next-line ^[OB
+bind-to-key forward-character ^[OC
+bind-to-key backward-character ^[OD
diff --git a/usr/src/contrib/jove-4.14.6/doc/teach-jove b/usr/src/contrib/jove-4.14.6/doc/teach-jove
new file mode 100644 (file)
index 0000000..38e52fb
--- /dev/null
@@ -0,0 +1,902 @@
+                     J O V E   T U T O R I A L 
+
+Welcome to JOVE - an advanced, easy-to-use, user-friendly environment 
+for editing text, programs or anything else you may like to type.
+
+JOVE commands generally involve the CONTROL key (sometimes labelled
+CTRL or CTL) or the META key (generally labelled ESCAPE).  Rather than
+write out META or CONTROL each time we want you to prefix a character,
+we'll use the following abbreviations:
+
+ C-<chr>  means hold the CONTROL key while typing the character <chr>
+         Thus, C-F would be: hold the CONTROL key and type F.
+ M-<chr>  means type the META (ESCAPE) key and release it, then type
+         the character <chr>.  The <chr> can be upper or lower case
+         and it will have the same meaning.
+
+Important note: if you must exit at some point, type C-X C-C.
+The characters ">>" at the left margin indicate directions for you to
+try using a command.  For instance:
+
+>>  Now type C-V (View next screen) to move to the next screen.
+       (go ahead, do it by depressing the control key and V together).
+       From now on, you'll be expected to do this whenever you finish
+       reading the screen.
+
+Note that there is an overlap when going from screen to screen; this
+provides some continuity when moving through the file.
+
+The first thing that you need to know is how to move around from
+place to place in the file.  You already know how to move forward a
+screen, with C-V.  To move backwards a screen, type M-V (depress the
+META key and type V, or type <ESC>V if you don't have a META or EDIT
+key).
+
+>>  Try typing M-V and then C-V to move back and forth a few times.
+
+
+SUMMARY
+-------
+
+The following commands are useful for viewing screenfuls:
+
+       C-V     Move forward one screenful
+       M-V     Move backward one screenful
+       C-L     Center the current line--clear screen and redisplay
+               everything if current line is already at center.
+       
+>> find the cursor and remember what text is near it.
+   Then type a C-L.
+   Find the cursor again and see what text is near it now.
+
+
+BASIC CURSOR CONTROL
+--------------------
+
+Getting from screenful to screenful is useful, but how do you
+reposition yourself within a given screen to a specific place?  There
+are several ways you can do this.  One way (not the best, but the most
+basic) is to use the commands previous, backward, forward and next.
+As you can imagine these commands (which are given to JOVE as C-P,
+C-B, C-F, and C-N respectively) move the cursor from where it
+currently is to a new place in the given direction.  Here, in a more
+graphical form are the commands:
+                         Previous line, C-P
+                                 :
+                                 :
+   Backward, C-B .... Current cursor position .... Forward, C-F
+                                 :
+                                 :
+                         Next line, C-N
+
+You'll probably find it easy to think of these by letter.  P for
+previous, N for next, B for backward and F for forward.  These are the
+basic cursor positioning commands and you'll be using them ALL the
+time so it would be of great benefit if you learn them now.
+
+>> Do a few C-N's to bring the cursor down to this line.
+
+>> Move into the line with C-F's and then up with several C-P's.  See
+   what C-P does when the cursor is in the middle of the line.
+
+Lines are separated by a single Linefeed character, which is what Unix
+calls a Newline.
+
+>> Try to C-B at the beginning of a line.  Do a few more C-B's.
+   Then do C-F's back to the end of the line and beyond.
+
+When you go off the top or bottom of the screen, the text beyond the
+edge is shifted onto the screen so that your instructions can be
+carried out while keeping the cursor on the screen.
+
+>> Try to move the cursor off the bottom of the screen with C-N and
+   see what happens.
+
+If moving by characters is too slow, you can move by words.  M-F
+(Meta-F) moves forward a word and M-B moves back a word.
+
+>> Type a few M-F's and M-B's.  Intersperse them with C-F's and C-B's.
+
+Notice the parallel between C-F and C-B on the one hand, and M-F and
+M-B on the other hand.  Very often Meta characters are used for
+operations related to English text whereas Control characters operate
+on the basic textual units that are independent of what you are
+editing (characters, lines, etc).  There is a similar parallel between
+lines and sentences: C-A and C-E move to the beginning or end of a
+line, and M-A and M-E move to the beginning or end of a sentence.
+
+>> Try a couple of C-A's, and then a couple of C-E's.
+   Try a couple of M-A's, and then a couple of M-E's.
+
+See how repeated C-A's do nothing, but repeated M-A's keep moving
+farther.  Do you think that this is right?
+
+Two other simple cursor motion commands are M-< (Meta Less-than),
+which moves to the beginning of the file, and M-> (Meta Greater-than),
+which moves to the end of the file.  You probably don't need to try
+them, since finding this spot again will be boring.  If you need the
+shift key to type a "<", then you must also use the shift key to type
+M-<.  Otherwise, you would be typing M-, .
+
+The location of the cursor in the text is also called "point".  To
+paraphrase, the cursor shows on the screen where point is located in
+the text.
+
+Here is a summary of simple moving operations including the word and
+sentence moving commands:
+
+       C-F     Move forward a character
+       C-B     Move backward a character
+
+       M-F     Move forward a word
+       M-B     Move backward a word
+
+       C-N     Move to next line
+       C-P     Move to previous line
+
+       C-A     Move to beginning of line
+       C-E     Move to end of line
+
+       M-A     Move back to beginning of sentence
+       M-E     Move forward to end of sentence
+
+       M-<     Go to beginning of file
+       M->     Go to end of file
+
+>> Try all of these commands now a few times for practice.  Since the
+   last two will take you away from this screen, you can come back
+   here with the command C-X C-X (which will be explained later).
+   These are the most often used commands.
+
+Like all other commands in JOVE, these commands can be given arguments
+which cause them to be executed repeatedly.  The way you give a
+command a repeat count is by typing META and then the digits before
+you type the command.  (Remember META is ususally called ESCAPE)
+
+For instance, META 8 C-F moves forward eight characters.
+       
+>> Try giving a suitable argument to C-N or C-P to come as close
+   as you can to this line in one jump.
+
+The only apparent exception to this is the screen moving commands, C-V
+and M-V.  When given an argument, they scroll the screen up or down by
+that many lines, rather than screenfuls.  This proves to be much more
+useful.
+
+>> Try typing M-8 C-V now.
+
+Did it scroll the screen up by 8 lines?  If you would like to scroll
+it down you can give an argument to M-V.
+
+
+
+THE UNIVERSAL ARGUMENT
+----------------------
+   Almost every command in JOVE takes a so-called Universal Argument.
+This argument, although it is interpreted differently in some cases,
+usually means REPEAT.  One important exception to this is with the screen
+moving commands.  In this case, the number refers to the number of LINES
+to scroll, not the number of screens.
+
+   The way you give a command a universal argument is by typing ESC and
+then the number. For example, ESC 10 C-F would move you forward ten
+characters.
+
+>>> Try  giving a suitable argument to C-N or C-P to come as close as you
+    can to this  line  in  one  jump.  Then  try giving the same command, 
+    except make the number negative.
+
+  Another count-giving command is C-U.  This command, when you first type
+it, gives you an argument of 4 (four).  If you type C-U C-U, you will get
+an argument of 16.  Each time C-U is typed, the argument is multiplied by
+four.
+
+>>> Try typing ESC 8 C-V now.
+
+THE GOTO COMMAND
+----------------
+   Now that we've learned about the universal argument, we can  introduce
+another  cursor  positioning  command,  the command to move to a specific
+line.  This command is given by giving a line number via  ESC,  and  then
+typing M-G.
+
+>>> Try  using  the M-< and M-> commands to move to the beginning and the
+    end of the file. Then come back here  using the M-G  command (this is 
+    line 206, so you'd type ESC 206 M-G.)
+
+QUITTING FROM COMMANDS
+----------------------
+
+The character in JOVE used to quit out of all commands which request
+input is C-G.  For example, you can use C-G to discard a numeric
+argument or the beginning of a command that you don't want to finish.
+
+>> Type M-100 to make a numeric arg of 100, then type C-G.  Now type
+   C-F.  How many characters does it move?  If you have typed an <ESC>
+   by mistake, you can get rid of it with a C-G.
+
+
+ERRORS
+------
+
+Sometimes you may do something which JOVE doesn't allow.  If it is
+something simple, such as typing a control key sequence which is not
+associated with any command, JOVE will just beep at you.  Otherwise,
+JOVE will also display an informative error message at the bottom of
+the screen.
+
+Some versions of JOVE do not have all the features described in this
+tutorial implemented yet.  If you come across such an unimplemented
+feature, you may get an error message when you try to use it.  Just
+proceed on to the next section of the tutorial.
+
+
+INSERTING AND DELETING
+----------------------
+
+If you want to type text, just do it.  Characters which you can see,
+such as A, 7, *, etc. are taken by JOVE as text and inserted
+immediately.  Type <Return> (the carriage-return key) to insert a line
+separator.
+
+You can delete the last character you typed by typing <Delete>.
+<Delete> is a key on the keyboard, which may be labeled "Rubout"
+instead of "Delete" on some terminals.  More generally, <Delete>
+deletes the character immediately before the current cursor position.
+
+>> Do this now, type a few characters and then delete them by typing
+   <Delete> a few times.  Don't worry about this file being changed;
+   you won't affect the master tutorial.  This is just a copy of it.
+
+>> Now start typing text until you reach the right margin, and keep
+   typing.  When a line of text gets too big for one line on the
+   screen, the line of text is "continued" off the edge of the screen
+   The exclamation mark at the right margin indicates a line which has
+   been continued.  The line will slide over if you move off the edge
+   on either side.
+
+>> The following line actually goes off the edge.  Trying typing enough
+   C-F's that you move off the right hand end of this line.... This is a long line of text that the JOVE editor extends to the right.
+
+>> Use <Delete>s to delete the text until the line fits on one screen
+   line again.  The continuation "!" will go away.
+
+>> Move the cursor to the beginning of a line and type <Delete>.  This
+   deletes the line separator before the line and merges the line onto
+   the previous line.  The resulting line may be too long to fit, in
+   which case it has a continuation indication.
+
+>> Type <Return> to insert the separator again.
+
+Remember that most JOVE commands can be given a repeat count;  Note
+that this includes characters which insert themselves.
+
+>>  Try that now -- type META 8 * and see what happens.
+
+If you want to create a blank line in between two lines, move to the
+second of the two lines and type C-O.
+
+>>  Try moving to a line and typing C-O now.
+
+You've now learned the most basic way of typing something in JOVE and
+correcting errors.  You can delete by words or lines as well.  Here is
+a summary of the delete operations:
+
+       <Delete>     delete the character just before the cursor
+       C-D          delete the next character after the cursor
+
+       M-<Delete>   kill the word immediately before the cursor
+       M-D          kill the next word after the cursor
+
+       C-K          kill from the cursor position to end of line
+       M-K          kill to the end of the current sentence
+
+Notice that <Delete> and C-D vs M-<Delete> and M-D extend the parallel
+started by C-F and M-F (well, <Delete> isn't really a control
+character, but let's not worry about that).  C-K and M-K are like C-E
+and M-E, sort of, in that lines are opposite sentences.
+
+Now suppose you kill something, and then you decide that you want to
+get it back?  Well, whenever you kill something bigger than a
+character, JOVE saves it for you.  To yank it back, use C-Y.  Note
+that you don't have to be in the same place to do C-Y; This is a good
+way to move text around.  Also note that the difference between
+"Killing" and "Deleting" something is that "Killed" things can be
+yanked back, and "Deleted" things cannot.  Generally, the commands
+that can destroy a lot of text save it, while the ones that attack
+only one character, or nothing but blank lines and spaces, do not save.
+
+For instance, type C-N a couple times to postion the cursor at some
+line on this screen.
+
+>> Do this now, move the cursor and kill that line with C-K.
+
+Note that a single C-K kills the contents of the line, and a second
+C-K kills the line itself, and make all the other lines move up.  If
+you give C-K a repeat count, it kills that many lines AND their
+contents.
+
+The text that has just disappeared is saved so that you can retrieve
+it.  To retrieve the last killed text and put it where the cursor
+currently is, type C-Y.
+
+>> Try it; type C-Y to yank the text back.
+
+Think of C-Y as if you were yanking something back that someone took
+away from you.  Notice that if you do several C-K's in a row the text
+that is killed is all saved together so that one C-Y will yank all of
+the lines.
+
+>> Do this now, type C-K several times.
+
+Now to retrieve that killed text:
+
+>> Type C-Y.  Then move the cursor down a few lines and type C-Y
+   again.  You now see how to copy some text.
+
+What do you do if you have some text you want to yank back, and then
+you kill something else?  C-Y would yank the more recent kill.  But
+the previous text is not lost.  You can get back to it using the M-Y
+command.  After you have done C-Y to get the most recent kill, typing
+M-Y replaces that yanked text with the previous kill.  Typing M-Y
+again and again brings in earlier and earlier kills.  When you have
+reached the text you are looking for, you can just go away and leave
+it there.  If you M-Y enough times, you come back to the starting
+point (the most recent kill).
+
+>> Kill a line, move around, kill another line.  Then do C-Y to get
+   back the second killed line.  Then do M-Y and it will be replaced
+   by the first killed line.  Do more M-Y's and see what you get.
+   Keep doing them until the second kill line comes back, and then a
+   few more.  If you like, you can try giving M-Y positive and negative
+   arguments.
+
+
+FILES
+-----
+
+In order to make the text you edit permanent, you must put it in a
+file.  Otherwise, it will go away when your invocation of JOVE goes
+away.  While you are editing a file in JOVE, your changes are actually
+being made to a private "scratch" copy of the file.  However, the
+changes still don't become permanent until you "save" the file.  This
+is so you can have control to avoid leaving a half-changed file around
+when you don't want to.
+
+If you look near the botton of the screen you will see a line that
+looks like this:
+    JOVE (Text) Buffer: teach-jove "teach-jove" *
+"teach-jove" is the name of the file you are editing.  This is the name
+of your own temporary copy of the text of the JOVE tutorial; the file
+you are now editing.  Whatever file you edit, that file's name will
+appear in that precise spot.
+
+The commands for finding and saving files are unlike the other
+commands you have learned in that they consist of two characters.
+They both start with the character Control-X.  There is a whole series
+of commands that start with Control-X; many of them have to do with
+files, buffers, and related things, and all of them consist of
+Control-X followed by some other character.  As with M- the character
+interpreted the same regardless of case.
+
+Another thing about the command for finding a file is that you have to
+say what file name you want.  We say the command "reads an argument
+from the terminal" (in this case, the argument is the name of the
+file).  After you type the command
+
+       C-X C-F   Find a file
+
+JOVE will ask you for the file name.  You should end the name with
+the Return key.  After this command, you will see the contents of the
+file in your JOVE.  You can edit the contents.  When you wish to make
+the changes permanent, issue the command
+
+       C-X C-S   Save the file
+
+Warning: on many systems JOVE will not be able to process the key C-S.
+In place of C-S, you should type C-\.  It is possible to make C-S work
+but C-\ is guaranteed always to work in place of C-S.
+
+The old version of the file will be replaced.  When the operation is
+finished, JOVE prints the name and number of lines and characters
+saved.
+
+If you forget to save and then edit a different file, JOVE will remind
+you that you made changes that have not been saved and then ask you
+whether you really want to quit.  (If you don't save them, they will
+be thrown away.  That might be what you want!)  You should answer with
+a "Y" to throw the changes away or "N" to abort quitting so you can
+then save the changes.
+
+To make a new file, just edit it "as if" it already existed.  Then
+start typing in the text.  When you ask to "save" the file, JOVE will
+really create the file with the text that you have inserted.  From
+then on, you can consider yourself to be editing an already existing
+file.
+
+It is not easy for you to try out editing a file and continue with the
+tutorial.  But you can always come back into the tutorial by starting
+it over and skipping forward.  So, when you feel ready, you should try
+editing a file named "FOO", putting some text in it, and saving it;
+then exit from JOVE and look at the file to be sure that it worked.
+
+CONCLUSION OF PART ONE
+----------------------
+   This is the end of the first part of  this  tutorial.   You  now  know
+enough to edit a file with JOVE, and save your work.  The second part of
+this tutorial, which starts with the next section,  discusses  searching,
+replacing,  word  processing,  and other modes of JOVE.  You may wish to
+stop here and practice for awhile before you continue.
+
+
+EXTENDING THE COMMAND SET
+-------------------------
+
+There are many, many more JOVE commands than could possibly be put on
+all the control and meta characters.  JOVE gets around this with the X
+(eXtend) command.  This comes in two flavors:
+
+       C-X     Character eXtend.  Followed by one character.
+       M-X     Named command eXtend.  Followed by a long name.
+
+These are commands that are generally useful but used less than the
+commands you have already learned about.  You have already seen two of
+them: the file commands C-X C-F to Find and C-X C-S to Save.  Another
+example is the command to tell JOVE that you'd like to stop editing.
+The command to do this is C-X C-C.
+
+There are many C-X commands.  The ones you need immediately are:
+
+       C-X C-V         Visit file.
+       C-X C-S         Save file.
+       C-X C-C         Quit JOVE.  This does not save your files auto-
+                       matically, though if your files have been modi-
+                       fied, JOVE asks if you really want to quit.  The
+                       standard way to save and exit is C-X C-S C-X C-C.
+
+Named eXtended commands are commands which are used even less
+frequently, or commands which are used only in certain modes.  These
+commands are usually called "commands".  An example is the command
+"apropos", which prompts for a keyword and then gives the names of all
+the commands that apropos for that keyword.  When you type M-X, JOVE
+prompts you at the bottom of the screen with ":" and you should type
+the name of the command you wish to call; in this case, "apropos".
+Just type "apr<Space>" and JOVE will complete the name.  JOVE will ask
+you for a keyword or phrase and you type the string that you want ask
+about.
+
+>> Try typing M-X, followed by "apropos" or "apr" and then Return.
+   Then try typing "file" followed by a Return.
+
+
+MODE LINE
+---------
+
+If JOVE sees that you are typing commands slowly it shows them to you
+at the bottom of the screen in an area called the echo area.  The echo
+area contains the bottom line of the screen.  The line immediately above
+them is called the MODE LINE.  The mode line says something like
+
+   JOVE (Text)  Buffer: [buffername]  "filename" *
+
+This is a very useful "information" line.
+
+The buffername is the name JOVE gave to the buffer, and it is usually
+related to the filename.  You already know what the filename means --
+it is the file you have edited.
+
+The star means that you have made changes to the text.  Right after
+you visit or save a file, there is no star.
+
+The part of the mode line inside the parentheses is to tell you what
+modes you are in.  The default mode is Text which is what you are in
+now.  It is an example of a "major mode".  There are several major
+modes in JOVE for editing different languages and text, such as C
+mode, Lisp mode, Text mode, etc.  At any time one and only one major
+mode is active, and its two-letter code can always be found in the
+mode line just where "Text" is now.  Each major mode makes a few
+commands behave differently.  For example, what JOVE considers as part
+of a valid expression or an identifier differs from one major mode to
+another, since each programming language has a different idea of what
+is a legal identifier.
+
+Major modes are called major because there are also minor modes.  They
+are called minor because they aren't alternatives to the major modes,
+just minor modifications of them.  Each minor mode can be turned on or
+off by itself, regardless of what major mode you are in, and
+regardless of the other minor modes.  So you can use no minor modes,
+or one minor mode, or any combination of several minor modes.
+
+One minor mode which is very useful, especially for editing English
+text, is "Auto Fill" mode.  When this mode is on, JOVE breaks the line
+in between words automatically whenever the line gets too long.  You
+can turn this mode on by doing M-X auto-fill-mode<Return>.  When the
+mode is on, you can turn it off by doing M-X auto-fill-mode<Return>--
+it toggles.
+
+>> Type "M-X auto-fill-mode<Return>" now.  Then insert a line with a
+   bunch of words over again until you see it divide into two lines.
+   You must put in spaces between them because Auto Fill breaks lines
+   only at spaces.  Notice that "Fill" (the code for Auto Fill) appears
+   in the mode line after "Text" to indicate that you are in Text Fill
+   mode.
+
+The margin is usually set at 78 characters, but you can change it with
+the set command.  The margin is kept in a variable just like the mode
+values.
+
+>> Type "M-X set right-margin 20", then type in some text and see
+   JOVE fill lines of 20 characters with it.  Then set the margin
+   back to 72 using M-X set again.
+
+
+SEARCHING
+---------
+
+JOVE can do searches for strings (these are groups of contiguous
+characters or words) either forward through the file or backward
+through it.  To search for the string means that you are trying to
+find that string somewhere in the file.  Remember to use C-\ where it
+says C-S.
+
+>> Now type C-S to start a search.  Type the word 'cursor', then
+   Return.
+
+>> Type C-S Return to find the next occurrence of "cursor".
+
+The C-S starts a search that looks for any occurrence of the search
+string AFTER the current cursor position.  But what if you want to
+search for something earlier in the text?  To do this one should type
+C-R for reverse search.  Everything that applies to C-S applies to C-R
+except that the direction of the search is reversed.
+
+
+REPLACING TEXT
+--------------
+
+>> Move the cursor to the blank line two lines below this one.
+   Then type M-r changed<Return>altered<Return>.
+
+   Notice how this line has changed: you've replaced the word
+   c-h-a-n-g-e-d with "altered" wherever it occurs after the cursor.
+
+The more customary command for replacing strings is the interactive
+command query-replace-search, which has several options.  In essence,
+it shows each occurrence of the first string and asks you if you want to
+replace it or not.  You can also choose to edit around the string, or
+go on and replace all occurrences without asking further.
+
+   This is invoked with M-Q..  When you start up a Query Replace, it
+will prompt you with "From" and "To", for what you want to change, and
+what you want to change it to.  JOVE will then move to the first
+occurence of the "From", and wait for a character.  You can type:
+
+       <SPACE>         Do  the  replacement, and move to next occurrence
+                       of the "From" string.
+       <DEL>           Skip  the  current  "From" string and move to the 
+                       next one.
+       RETURN          Exit the Query Replace now.
+       r               Recursive Edit
+       p               Replace  all  further  occurences  of  the "From" 
+                       string, without asking. 
+
+Recursive edit makes it possible to temporarily supend the Q-R-S, let the
+user go off and do something, and then return to the search after the  he
+is done. The command exit-jove (C-X C-C) returns from the recursive-edit.
+
+GETTING MORE HELP
+-----------------
+
+In this tutorial we have tried to supply just enough information to
+get you started using JOVE.  There is so much available in JOVE that
+it would be impossible to explain it all here.  However, you may want
+to learn more about JOVE since it has numerous desirable features that
+you don't know about yet.  JOVE has a some internal documentation.
+
+The most basic HELP feature is the describe-key command which is
+available by typing C-X ? and then a command character. JOVE prints
+one line line on the bottom of the screen tell what command is bound to
+that key.  You can then get further information on that command
+using...
+
+The describe-command command M-? will prompt for the name of a command
+and print out the section from the manual about that command. When you
+are finished reading it, type a Space or a C-G (quit) to bring your text
+back on the screen.
+
+>> Type C-X ? Control-P.  The message at the bottom of the screen should
+   be something like "C-P is bound to previous-line".
+
+Multi-character commands such as C-X C-C and <ESC>V are also allowed
+after C-X ?.
+
+Now lets get more information about the previous-line command.
+
+>> Type M-? previous-line.  When you are finished reading the
+   output, type a Space.
+
+The "name of the command" is important for people who are customizing
+JOVE.  It is what appears in the JOVE CHART as the documentation for
+the command character.
+
+One other form of help is the "apropos" command.  We have already tried
+using this command in an earlier part of this tutorial, but it should
+be mentioned again here.  Apropos prompts for a word or phrase and
+lists all the commands that contain that string.  If you couldn't
+remember the name of a certain command to read file, you could run the
+apropos command with the keyword "file" and it would list all the
+commands that contain "file".  To run apropos you would type
+
+       M-X apr<Space>file<Return>
+
+Finally, the full set of JOVE manuals are in five parts, and reside in the
+directory /local/src/jove/doc under the names jove.1 to jove.5.  These
+are in TROFF form and can be formatted into a form readable on the terminal
+or line-printer with the commands:
+
+       cd /local/src/jove/doc
+       nroff -ms cmds.doc.nr jove.[1-5]
+
+Besides, someone around you must have a printed version which you can
+borrow! (There's also a copy on the Berkeley Unix 4.3 manuals - in the User
+Supplementary Documents manual (the one with the green spine). There is also
+a chart of JOVE commands, sorted by function, which is handy as a quick
+reference. Ask your local Jove guru for a copy.
+
+CONCLUSION OF PART TWO
+----------------------
+   This concludes section two of the JOVE tutorial.  The  rest  of  this
+tutorial  describes  some of the very advanced features of JOVE, such as
+editing more than one file at once, writing your own macros, windows, and
+initialization  files.   Unless  you're  already  somewhat  familiar with
+JOVE, you should probably wait a little while before starting the  third
+section.
+
+MARKS AND REGIONS
+-----------------
+
+   In  general, a command which processes an arbitrary part of the buffer
+must know where to start and where to  stop.   In  JOVE,  such  commands
+usually  operate  on the text between point (where the cursor is now) and
+"the mark".  This range of text is called "the  region".   To  specify  a
+region, you set point to one end of it and mark at the other.  It doesn't
+matter which one is set first chronologically, or which one comes earlier
+in the text.  Here are some commands for setting the mark:
+
+        C-@         Set the mark where point is.
+        C-<SPACE>   The same.
+        C-X C-X     Interchange mark and point.
+
+   The  most  common  way  to set the mark is with the C-@ command or the
+C-<SPACE> command.  They set the mark where point is.  Then you can  move
+point away, leaving the mark behind.
+
+   Since  terminals  have  only  one cursor, there is no way for JOVE to
+show you where the mark is located.  You have  to  remember.   The  usual
+solution  to this problem is to set the mark and then use it soon, before
+you forget where it is.  But you can see  where  the  mark  is  with  the
+command  C-X  C-X which puts the mark where point was and point where the
+mark was.  The extent of the region is  unchanged,  but  the  cursor  and
+point are now at the previous location of the mark.
+
+   There  are many, many commands which use regions (the area between the
+point and the mark), which we have not  mentioned  here. They can be found
+in the Jove Quick Reference Card.
+
+BUFFERS
+-------
+   When editing a file, JOVE reads the file  into  a  buffer.   This  is
+where the modifcations are done, and when you save the file with C-X C-S,
+the buffer is actually written out to the file.   JOVE  permits  you  to
+have  up  to 100 buffers, so, in essence, you can edit up to 100 files at
+the same time.
+
+   If you want to list the buffers you have, use  the  C-X  C-B  command.
+This  will  display  a  list of the buffers, their numbers and names, and
+whether or not they've been modified.
+
+>>> Do this now, type C-X C-B.  When you're done looking, type a <SPACE>.
+
+   You probably noticed you only have one buffer, named "Main".   If  you
+were  editing  more  than one file, however, you would have more than one
+buffer.  There are two ways to edit more than one file.  The first is  to
+call JOVE with more than one file on the command line.  For example, the
+command
+
+                             jove a b c
+
+would create three buffers (named Main, b, and c),  each  one  containing
+one  file.   The  other  way  is  to use the C-X C-F command (called Find
+File).  This command prompts you for a filename, and then reads that file
+into a new buffer, and puts you into the new buffer.
+
+   To change buffers, use the C-X B command.  JOVE will prompt you for a
+buffer name, and print a name in parentheses.  If you just hit a carriage
+return without typing a buffer name, you will go to the buffer named in
+parentheses.  Another way to change buffers is to give C-X B a NUMBER.
+This goes to the buffer NUMBER, rather than using the buffer name.
+
+>>> Get a piece of paper, and write down the  following  commands.   Then
+    run  them, to  get a feel for playing with buffers.  BE SURE TO WRITE 
+    THEM DOWN! We don't want to get you lost!
+
+                       C-X C-B
+                       <SPACE>
+                       C-X C-F         (type "/etc/motd" to the prompt)
+                       C-X C-B
+                       <SPACE>
+                       C-X B
+                       <RETURN>
+
+   Well, wasn't that fun?  Now you know how  to  get  another  file  into
+another  buffer,  and then "bounce" back and forth.  A nice feature about
+editing more than one file is that you can transfer text from one file to
+the  other.   Just  kill  it in one file, change buffers, and then put it
+back with C-Y.
+
+WINDOWS
+-------
+   What you see on your screen is a "window" into the buffer you are 
+editing. JOVE allows you to have more than one window on your screen, and
+you can therefore look into two, or more buffers at once. You can also look at
+different parts of the same file. The command C-X 2 splits your screen into
+two windows, both looking into the same buffer. The command C-X 4 f will
+display a specified file in the other window, C-X 4 b will display a specified
+buffer in the other window, C-X n moves to the next window on the screen,
+while C-X p moves to the previous window.
+
+>>> Try the command C-X 2, which splits the screen into two windows, and
+    displays the same buffer in both. You'll notice that you are in the new
+    window. Try some commmands in this window, like C-V, or M-V, to move
+    around in the file. Observe that the other window doesn't change its
+    position relative to the buffer. This gives you a way of looking at two
+    parts of the same file. 
+
+>>> Now try to type some text, or change something. You will see the changes
+    affecting the text in the other window as well. That is because both
+    windows are displaying the same buffer, and therefor the same text. Changes
+    in the contents of the buffer have to affect both windows.
+
+>>> Let's now try to edit another file in this window. Give the command 
+    C-X C-F and type the name of file as "/etc/motd". You now have two files
+    on your screen at the same time. 
+
+>>> Type the command M- C-V (Meta followed by C-V) and watch the other window
+    page downward. This is very convenient when doing a variety of tasks, like
+    correcting errors in a file - edit the file, with the list of errors in
+    the other window!
+
+>>> Finally, let's get back to the main window (with this document) by typing
+    C-X p (or C-X n, since there are only two windows). Expand this window 
+    to fill the entire screen by typing C-X 1. 
+
+Enjoyable, wasn't it! There are other commands for shrinking and growing
+windows, but one of the most useful when editing text like this is the command
+which invokes JOVE's interactive spelling checker. It's called spell-buffer.
+It runs the UNIX spell(1) command on the buffer, and puts the errors in
+another buffer in another window, and allows you to edit the list to remove
+the words you know are not errors. Then, type C-X C-C, which usually gets you
+out of JOVE but in this case only gets you out of the spell-edit mode. You can
+now go through the remaining spelling errors word-by-word, and you can correct
+them. The commands for this are C-X C-N (for next error) and C-X C-P (for
+previous error.) 
+
+>>> Try the spell-buffer command now, by going M-X spel <space> and watch.
+Delete a few errors, then type C-X C-C, and do a few C-X C-N's to find some
+errors in this document. We've left a few ! (deliberately, of course!!!)
+    
+
+MACROS
+------
+   A "keyboard macro" is a command defined by the user  to  abbreviate  a
+sequence  of  other commands.  If you discover that you are about to type
+C-N C-D forty times, you can define a keyboard macro to do  C-N  C-D  and
+call  it  with  a  repeat  count  of forty.  The commands which deal with
+keyboard macros are:
+
+        C-X (       Start defining a keyboard macro.
+        C-X )       End the definition of a keyboard macro.
+        C-X E       Execute the most recent keyboard macro.
+
+   You define a keyboard macro while executing the commands which are the
+definition.   Put  differently, as you are defining a keyboard macro, the
+definition is being executed for the first time.  This way, you  can  see
+what  the  effects of your commands are, so that you don't have to figure
+them out in your head.  When you are  finished,  the  keyboard  macro  is
+defined and also has been, in effect, executed once.  You can then do the
+whole thing over again by invoking the macro.
+
+   To start defining a keyboard macro, type the C-X ( command.  From then
+on,  your  commands  continue to be executed, but also become part of the
+definition of the macro.  "Def" appears in the mode line to remind you of
+what  is  going  on.  When you are finished, the C-X ) command terminates
+the definition (without becoming part of it!).
+
+   The macro thus defined can be invoked again with  the  C-X  E  command
+which  may  be  given a repeat count as a numeric argument to execute the
+macro many times.  C-X ) can also be given a repeat count as an argument,
+in  which  case it repeats the macro that many times right after defining
+it, but defining the macro counts as the first repetition  (since  it  is
+executed  as  you define it).  So, giving C-X ) an argument of 2 executes
+the macro immediately one additional time.
+
+   If  you  want  to  perform  an operation on each line, then either you
+should start by positioning point on the line above the first one  to  be
+processed  and  then begin the macro definition with a C-N, or you should
+start on the proper line and end with a C-N.  Either way,  repeating  the
+macro will operate on successive lines.
+
+>>> Place the cursor at the top of the screen and then enter the commands
+    below.  Note that after the first  command, "Def" appears in the mode 
+    line.
+
+                       C-X (
+                       C-A
+                       *****
+                       M-F
+                       M-F
+                       M-F
+                       -----
+                       C-N
+                       C-X )
+
+>>> Notice that as you typed those  commands in, they were executed.  Now   
+    move  the cursor  down a couple of lines, but keep it near the top of 
+    the  screen.  Type the  command C-U C-X E.  This will  execute your 
+    macro 4 times.
+
+   Although not described here, it is possible  to both name  your macros,
+and to save and restore them from files.  See the documentation for this.
+
+INITIALIZATION FILES
+--------------------
+   You can initialize JOVE just the way you like it by putting a file
+named ".joverc" in your home directory.  To see what this file should
+look like, look at the one in the directory /usr/src/local/jove/doc. The
+file system.rc is one such file, the other example is example.rc. It
+should be noted that the commands in this file contain control
+characters, which may make it hard to read.  Use the "cat -v" command
+for this. 
+
+   To  insert control  characters into  a file with JOVE, you should use 
+the C-Q command.  Type C-Q <X> where <X> is the control character. Note that
+C-Q will not work on some terminals, because it, like C-S, is used for
+suspending and restoring the output to the terminal. In that case, use
+the command M-X quo <space> <X>. 
+
+INTERACTIVE SHELLS
+------------------
+
+   One of JOVE's very powerful features is the ability to start up shells
+within the editor, and then use shell commands within the screen editing 
+environment. To execute a command again, just cursor-up to it, change it if
+you want with all the normal editing keys, and hit RETURN once to bring it
+down to your present command line, and again to execute it. We'll bow out
+here suggesting you consult the manual for hard details, or type M-X shell
+<space> if you are the adventurous type! 
+
+CONCLUSION
+----------
+
+Remember, to exit use C-X C-C.
+
+This tutorial is meant to be understandable to all new users, so if
+you found something unclear, don't sit and blame yourself - complain to
+one of the people listed at the end of this document!
+
+You'll probably find that if you use JOVE for a few days you won't
+be able to give it up.  Initially it may give you trouble.  But remember
+that this is the case with any editor, especially one that can do many,
+many things.  And JOVE can do practically everything.
+
+   Hopefully you have enjoyed this tutorial,  and,  more  importantly,  I
+hope you've learned something.  If you use JOVE for about a week, and be
+patient, you will find that it is more convenient  and  friendly  to  use
+than any other editor you've used. I know. I did.
+
+---------------------------------------------------------------------------
+This tutorial was originally written by Richard Stallman for EMACS and
+modified by Doug Kingston and Jonathan Payne for JOVE. The section on windows
+was added by Mark Moraes.  Comments on this document should be sent to
+jpayne@sun.com or to moraes@csri.toronto.edu.
diff --git a/usr/src/contrib/jove-4.14.6/doc/teachjove.nr b/usr/src/contrib/jove-4.14.6/doc/teachjove.nr
new file mode 100644 (file)
index 0000000..d6f9ea9
--- /dev/null
@@ -0,0 +1,22 @@
+.hy 0
+.TH TEACHJOVE 1 "12 February 1986"
+.ad
+.SH NAME
+TEACHJOVE - learn how to use the JOVE editor
+.SH SYNOPSIS
+teachjove
+.SH DESCRIPTION
+TEACHJOVE is a simple program that calls up the JOVE editor on a special
+file that is an interactive tutorial for the JOVE editor.  Once in JOVE
+all you do is follow the instructions and by doing so you will learn all
+about JOVE!  NOTE: TEACHJOVE actually makes a copy of the tutorial in
+your home directory; if you ever want to start over (if you trash the
+file by accident) all you need to do is remove the file "~/teach-jove"
+and run teachjove again.
+.SH FILES
+LIBDIR/teach-jove -- THE special file.
+.SH SEE ALSO
+JOVE(1) - to learn about JOVE in general.
+.fi
+.SH AUTHOR
+Jonathan Payne
diff --git a/usr/src/contrib/jove-4.14.6/extend.c b/usr/src/contrib/jove-4.14.6/extend.c
new file mode 100644 (file)
index 0000000..6d23146
--- /dev/null
@@ -0,0 +1,715 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "fp.h"
+#include "termcap.h"
+#include "ctype.h"
+#include "chars.h"
+#include "disp.h"
+#include "re.h"
+
+#ifdef IPROCS
+# include <signal.h>
+#endif
+
+#ifdef MAC
+# include "mac.h"
+#else
+# ifdef        STDARGS
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+#endif
+
+#ifdef MSDOS
+# include <process.h>
+#endif
+
+private void
+       DefAutoExec proto((struct data_obj *(*proc) ptrproto((const char *))));
+
+private int
+       match proto((char **, char *));
+
+int    InJoverc = 0;
+
+/* Auto execute code */
+
+#define NEXECS 20
+
+private struct {
+       char    *a_pattern;
+       data_obj        *a_cmd;
+} AutoExecs[NEXECS];   /* must be initialized by system to 0 */
+
+private int    ExecIndex = 0;
+
+/* Command auto-execute. */
+
+void
+CAutoExec()
+{
+       DefAutoExec(findcom);
+}
+
+/* Macro auto-execute. */
+
+void
+MAutoExec()
+{
+       DefAutoExec(findmac);
+}
+
+private void
+DefAutoExec(proc)
+data_obj       *(*proc) ptrproto((const char *));
+{
+       data_obj        *d;
+       char    *pattern;
+       int     i;
+
+       if (ExecIndex >= NEXECS)
+               complain("Too many auto-executes, max %d.", NEXECS);
+       if ((d = (*proc)(ProcFmt)) == NULL)
+               return;
+       pattern = do_ask("\r\n", (bool (*) ptrproto((int))) NULL, (char *) NULL, ": %f %s ",
+               d->Name);
+       for (i = 0; i < ExecIndex; i++) {
+           if (AutoExecs[i].a_cmd == d) {
+               char    *ipat = AutoExecs[i].a_pattern;
+
+               if ((pattern == NULL || ipat == NULL)?
+                   (pattern == ipat) : (strcmp(pattern, ipat) == 0))
+                       return;         /* eliminate duplicates */
+           }
+       }
+       AutoExecs[ExecIndex].a_pattern = copystr(pattern);
+       AutoExecs[ExecIndex].a_cmd = d;
+       ExecIndex += 1;
+}
+
+/* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the
+   same kind of file (i.e., match the same pattern) or OLD is NULL and it
+   matches, OR if the pattern is NULL (none was specified) then, we execute
+   the command associated with that kind of file. */
+
+void
+DoAutoExec(new, old)
+register char  *new,
+               *old;
+{
+       register int    i;
+
+       set_arg_value(1);
+       for (i = 0; i < ExecIndex; i++)
+               if ((AutoExecs[i].a_pattern == NULL) ||
+                   ((new != NULL && LookingAt(AutoExecs[i].a_pattern, new, 0)) &&
+                    (old == NULL || !LookingAt(AutoExecs[i].a_pattern, old, 0))))
+                       ExecCmd(AutoExecs[i].a_cmd);
+}
+
+int
+addgetc()
+{
+       int     c;
+
+       if (!InJoverc) {
+               Asking = YES;
+               AskingWidth = strlen(mesgbuf);
+               c = getch();
+               Asking = NO;
+               add_mess("%p ", c);
+       } else {
+               c = getch();
+               if (c == '\n')
+                       return EOF;     /* this isn't part of the sequence */
+               else if (c == '\\') {
+                       if ((c = getch()) == LF)
+                               complain("[Premature end of line]");
+               } else if (c == '^') {
+                       if ((c = getch()) == '?')
+                               c = RUBOUT;
+                       else if (jisalpha(c) || strchr("@[\\]^_", c))
+                               c = CTL(c);
+                       else
+                               complain("[Unknown control character]");
+               }
+       }
+       return c;
+}
+
+void
+Extend()
+{
+       data_obj        *d;
+
+       if ((d = findcom(": ")) != NULL)
+               ExecCmd(d);
+}
+
+/* Read a positive integer from CP.  It must be in base BASE, and
+   complains if it isn't.  If allints is nonzero, all the characters
+   in the string must be integers or we return -1; otherwise we stop
+   reading at the first nondigit. */
+
+int
+chr_to_int(cp, base, allints, result)
+register char  *cp;
+int    base,
+       allints;
+register int   *result;
+{
+       register int    c;
+       int     value = 0,
+               sign;
+
+       if ((c = *cp) == '-') {
+               sign = -1;
+               cp += 1;
+       } else
+               sign = 1;
+       while ((c = *cp++) != '\0') {
+               if (!jisdigit(c)) {
+                       if (allints == YES)
+                               return INT_BAD;
+                       break;
+               }
+               c = c - '0';
+               if (c >= base)
+                       complain("You must specify in base %d.", base);
+               value = value * base + c;
+       }
+       *result = value * sign;
+       return INT_OKAY;
+}
+
+int
+ask_int(prompt, base)
+char   *prompt;
+int    base;
+{
+       char    *val = ask((char *)NULL, prompt);
+       int     value;
+
+       if (chr_to_int(val, base, YES, &value) == INT_BAD)
+               complain("That's not a number!");
+       return value;
+}
+
+void
+vpr_aux(vp, buf, size)
+register const struct variable *vp;
+char   *buf;
+size_t size;
+{
+       switch (vp->v_flags & V_TYPEMASK) {
+       case V_BASE10:
+               swritef(buf, size, "%d", *((int *) vp->v_value));
+               break;
+
+       case V_BASE8:
+               swritef(buf, size, "%o", *((int *) vp->v_value));
+               break;
+
+       case V_BOOL:
+               swritef(buf, size, (*((int *) vp->v_value)) ? "on" : "off");
+               break;
+
+       case V_STRING:
+       case V_FILENAME:
+               swritef(buf, size, "%s", vp->v_value);
+               break;
+
+       case V_CHAR:
+               swritef(buf, size, "%p", *((int *) vp->v_value));
+               break;
+       }
+}
+
+void
+PrVar()
+{
+       struct variable *vp;
+       char    prbuf[256];
+
+       if ((vp = (struct variable *) findvar(ProcFmt)) == NULL)
+               return;
+       vpr_aux(vp, prbuf, sizeof(prbuf));
+       s_mess(": %f %s => %s", vp->Name, prbuf);
+}
+
+void
+SetVar()
+{
+       struct variable *vp;
+       char    prompt[128];
+
+       if ((vp = (struct variable *) findvar(ProcFmt)) == NULL)
+               return;
+       swritef(prompt, sizeof(prompt), ": %f %s ", vp->Name);
+
+       switch (vp->v_flags & V_TYPEMASK) {
+       case V_BASE10:
+       case V_BASE8:
+               *((int *) vp->v_value) = ask_int(prompt,
+                   ((vp->v_flags & V_TYPEMASK) == V_BASE10)? 10 : 8);
+               break;
+
+       case V_BOOL:
+           {
+               char    *def = *((bool *) vp->v_value) ? "off" : "on",
+                       *on_off;
+               bool    value;
+
+               on_off = ask(def, prompt);
+               if (casecmp(on_off, "on") == 0)
+                       value = ON;
+               else if (casecmp(on_off, "off") == 0)
+                       value = OFF;
+               else {
+                       complain("Boolean variables must be ON or OFF.");
+                       /* NOTREACHED */
+               }
+               *((bool *) vp->v_value) = value;
+#ifdef MAC
+               MarkVar(vp,-1,0);       /* mark the menu item */
+#endif
+               s_mess("%s%s", prompt, value ? "on" : "off");
+               break;
+           }
+
+       case V_FILENAME:
+           {
+               char    fbuf[FILESIZE];
+               size_t  pl = strlen(prompt);
+
+               swritef(&prompt[pl], sizeof(prompt)-pl, "(default %s) ",
+                       (char *)vp->v_value);
+               (void) ask_file(prompt, (char *) vp->v_value, fbuf);
+               strcpy((char *) vp->v_value, fbuf);
+               break;
+           }
+
+       case V_STRING:
+           {
+               char    *str;
+
+               /* Do_ask() so you can set string to "" if you so desire. */
+               str = do_ask("\r\n", (bool (*) ptrproto((int))) NULL,
+                       (char *) vp->v_value, prompt);
+               if (str == NULL)
+                       str = NullStr;
+               strcpy((char *) vp->v_value, str);
+               /* ... and hope there is enough room. */
+               break;
+           }
+       case V_CHAR:
+               f_mess(prompt);
+               *((int *) vp->v_value) = addgetc();
+               break;
+
+       }
+       if (vp->v_flags & V_MODELINE)
+               UpdModLine = YES;
+       if (vp->v_flags & V_CLRSCREEN) {
+#ifdef IBMPC
+               setcolor(Fgcolor, Bgcolor);
+#endif /* IBMPC */
+               ClAndRedraw();
+       }
+       if (vp->v_flags & V_TTY_RESET)
+               tty_reset();
+}
+
+/* Command completion - possible is an array of strings, prompt is
+   the prompt to use, and flags are ... well read jove.h.
+
+   If flags are RET_STATE, and the user hits <return> what they typed
+   so far is in the Minibuf string. */
+
+private char   **Possible;
+private int    comp_value,
+               comp_flags;
+
+private bool
+aux_complete(c)
+int    c;
+{
+       int     command,
+               i;
+
+       if (comp_flags & CASEIND) {
+               char    *lp;
+
+               for (lp = linebuf; *lp != '\0'; lp++)
+                       if (jisupper(*lp))
+                               *lp = jtolower(*lp);
+       }
+       switch (c) {
+       case EOF:
+               comp_value = -1;
+               return FALSE;
+
+       case '\r':
+       case '\n':
+               command = match(Possible, linebuf);
+               if (command >= 0) {
+                       comp_value = command;
+                       return FALSE;   /* tells ask to stop */
+               }
+               if (eolp() && bolp()) {
+                       comp_value = NULLSTRING;
+                       return FALSE;
+               }
+               if (comp_flags & RET_STATE) {
+                       comp_value = command;
+                       return FALSE;
+               }
+               if (InJoverc)
+                       complain("[\"%s\" unknown]", linebuf);
+               rbell();
+               break;
+
+       case '\t':
+       case ' ':
+           {
+               int     minmatch = 1000,
+                       maxmatch = 0,
+                       numfound = 0,
+                       lastmatch = -1,
+                       len = strlen(linebuf);
+
+               for (i = 0; Possible[i] != 0; i++) {
+                       int     this_len;
+
+                       this_len = numcomp(Possible[i], linebuf);
+                       maxmatch = max(maxmatch, this_len);
+                       if (this_len >= len) {
+                               if (numfound)
+                                       minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i]));
+                               else
+                                       minmatch = strlen(Possible[i]);
+                               numfound += 1;
+                               lastmatch = i;
+                               if (strcmp(linebuf, Possible[i]) == 0)
+                                       break;
+                       }
+               }
+
+               if (numfound == 0) {
+                       rbell();
+                       if (InJoverc)
+                               complain("[\"%s\" unknown]", linebuf);
+                       /* If we're not in the .joverc then
+                          let's do something helpful for the
+                          user. */
+                       if (maxmatch < len) {
+                               char    *cp;
+
+                               cp = linebuf + maxmatch;
+                               *cp = '\0';
+                               Eol();
+                       }
+                       break;
+               }
+               if (c != '\t' && numfound == 1) {
+                       comp_value = lastmatch;
+                       return FALSE;
+               }
+               null_ncpy(linebuf, Possible[lastmatch], (size_t) minmatch);
+               Eol();
+               if (minmatch == len)    /* No difference */
+                       rbell();
+               break;
+           }
+
+       case '?':
+               {
+               int     len;
+
+               if (InJoverc)
+                       complain((char *)NULL);
+               /* kludge: in case we're using UseBuffers, in which case
+                  linebuf gets written all over */
+               strcpy(Minibuf, linebuf);
+               len = strlen(Minibuf);
+               TOstart("Completion", TRUE);    /* for now ... */
+               for (i = 0; Possible[i]; i++)
+                       if (numcomp(Possible[i], Minibuf) >= len) {
+                               Typeout(Possible[i]);
+                               if (TOabort)
+                                       break;
+                       }
+
+               TOstop();
+               }
+               break;
+       }
+       return TRUE;
+}
+
+int
+complete(possible, prompt, flags)
+register char  *possible[];
+const char     *prompt;
+int    flags;
+{
+       /* protect static "Possible" from being overwritten due to recursion */
+       if (InRealAsk)
+               complain((char *) NULL);
+
+       Possible = possible;
+       comp_flags = flags;
+       (void) do_ask("\r\n \t?", aux_complete, NullStr, prompt);
+       return comp_value;
+}
+
+private int
+match(choices, what)
+register char  **choices,
+               *what;
+{
+       register size_t len;
+       int     i,
+               found = 0,
+               save = ORIGINAL,
+               exactmatch = -1;
+
+       len = strlen(what);
+       if (len == 0)
+               return NULLSTRING;
+       for (i = 0; choices[i]; i++) {
+               if (strncmp(what, choices[i], len) == 0) {
+                       if (choices[i][len] == '\0')
+                               exactmatch = i;
+                       save = i;
+                       found += 1;     /* found one */
+               }
+       }
+
+       if (found > 1) {
+               if (exactmatch != -1)
+                       save = exactmatch;
+               else
+                       save = AMBIGUOUS;
+       }
+
+       return save;
+}
+
+void
+Source()
+{
+       char    *com,
+               buf[FILESIZE];
+
+#ifndef        MSDOS
+       swritef(buf, sizeof(buf), "%s/.joverc", HomeDir);
+#else  /* MSDOS */
+       if (com = getenv("JOVERC"))
+               strcpy(buf, com);
+       else
+               strcpy(buf, Joverc);
+#endif /* MSDOS */
+       com = ask_file((char *)NULL, buf, buf);
+       if (!joverc(buf))
+               complain(IOerr("read", com));
+}
+
+void
+BufPos()
+{
+       register Line   *lp = curbuf->b_first;
+       register int    i,
+                       dotline;
+       long    dotchar,
+               nchars;
+
+       for (i = nchars = 0; lp != NULL; i++, lp = lp->l_next) {
+               if (lp == curline) {
+                       dotchar = nchars + curchar;
+                       dotline = i + 1;
+               }
+               nchars += length(lp) + (lp->l_next != NULL); /* include the NL */
+       }
+
+       s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]",
+              filename(curbuf), dotline, i, dotchar, nchars,
+              (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars),
+              calc_pos(linebuf, curchar),
+              calc_pos(linebuf, (int)strlen(linebuf)));
+}
+
+#ifndef        MAC
+private int
+do_if(cmd)
+char   *cmd;
+{
+       int status;
+       char    *args[12];
+
+       {
+               char    *cp = cmd,
+                       **ap = args;
+
+               for (;;) {
+                       while (*cp == ' ')
+                           cp++;
+                       *ap++ = cp;
+                       if ((cp = strchr(cp, ' ')) == NULL)
+                               break;
+                       *cp++ = '\0';
+               }
+               ap[-1] = NULL;
+       }
+
+#ifndef        MSDOS
+       {
+               int     pid;
+
+               switch (pid = fork()) {
+               case -1:
+                       complain("[Fork failed: if: %s]", strerror(errno));
+                       /*NOTREACHED*/
+
+               case 0:
+                       close(0);       /*      we want reads to fail */
+                       /* close(1);     but not writes or ioctl's
+                       close(2);    */
+                       (void) execvp(args[0], (const char **)args);
+                       _exit(-10);     /* signals exec error (see below) */
+                       /*NOTREACHED*/
+               }
+#ifdef IPROCS
+               SigHold(SIGCHLD);
+#endif
+               dowait(pid, &status);
+#ifdef IPROCS
+               SigRelse(SIGCHLD);
+#endif
+               if (status == -10)
+                       complain("[Exec failed]");
+               if (status < 0)
+                       complain("[Exit %d]", status);
+       }
+#else  /* MSDOS */
+       if ((status = spawnvp(0, args[0], args)) < 0)
+               complain("[Spawn failed: if]");
+#endif /* MSDOS */
+
+       return (status == 0);   /* 0 means successful */
+}
+#endif /* MAC */
+
+bool
+joverc(file)
+char   *file;
+{
+       char    buf[LBSIZE],
+               lbuf[LBSIZE];
+
+       jmp_buf savejmp;
+       volatile int    lnum = 0;
+       File    *volatile fp;
+       volatile bool   eof;
+       volatile unsigned int   /* bitstrings */
+                       finger = 1,
+                       skipping = 0,
+                       inelse = 0;
+
+       fp = open_file(file, buf, F_READ, NO, YES);
+       if (fp == NULL)
+               return NO;      /* joverc returns an integer */
+
+       /* Catch any errors, here, and do the right thing with them,
+          and then restore the error handle to whoever did a setjmp
+          last. */
+
+       InJoverc += 1;
+       push_env(savejmp);
+       if (setjmp(mainjmp)) {
+               Buffer  *savebuf = curbuf;
+
+               SetBuf(do_select((Window *)NULL, "RC errors"));
+               ins_str(sprint("%s:%d:%s", pr_name(file, YES), lnum, lbuf), NO);
+               ins_str(sprint("\t%s\n", mesgbuf), NO);
+               unmodify();
+               SetBuf(savebuf);
+               Asking = NO;
+       }
+       do {
+               /* This peculiar delayed EOF testing allows the last line to
+                * end without a NL.  We add NL later, so we leave room for it.
+                */
+               eof = f_gets(fp, lbuf, sizeof(lbuf)-1);
+               lnum += 1;
+               Inputp = lbuf;
+               while (*Inputp == ' ' || *Inputp == '\t')
+                       Inputp += 1;    /* skip white space */
+               if (*Inputp == '#') {
+                       /* a comment */
+#ifndef        MAC
+               } else if (casencmp(Inputp, "if", (size_t)2) == 0) {
+                       finger <<= 1;
+                       if (finger == 0)
+                               complain("[`if' nested too deeply]");
+                       if (LookingAt("ifenv\\>[ \t]*\\<\\([^ \t][^ \t]*\\)\\>[ \t]\\(.*\\)$", Inputp, 0)) {
+                               if (skipping == 0) {
+                                       char    envname[128],
+                                               envpat[128],
+                                               *envval;
+
+                                       putmatch(1, envname, sizeof envname);
+                                       putmatch(2, envpat, sizeof envpat);
+                                       envval = getenv(envname);
+                                       if (envval==NULL || !LookingAt(envpat, envval, 0))
+                                               skipping |= finger;
+                               }
+                       } else if (LookingAt("if\\>[ \t]*\\(.*\\)$", Inputp, 0)) {
+                               char    cmd[128];
+
+                               putmatch(1, cmd, sizeof cmd);
+                               if (skipping == 0 && !do_if(cmd))
+                                       skipping |= finger;
+                       } else {
+                               complain("[`if' syntax error]");
+                       }
+               } else if (casecmp(Inputp, "else") == 0) {
+                       if (finger == 1 || (inelse & finger))
+                               complain("[Unexpected `else']");
+                       inelse |= finger;
+                       skipping ^= finger;
+               } else if (casecmp(Inputp, "endif") == 0) {
+                       if (finger == 1)
+                               complain("[Unexpected `endif']");
+                       inelse &= ~finger;
+                       skipping &= ~finger;
+                       finger >>= 1;
+#endif
+               } else if (skipping == 0) {
+                       (void) strcat(Inputp, "\n");
+                       Extend();
+                       if (Inputp) {
+                               while (*Inputp == ' ' || *Inputp == '\t')
+                                       Inputp += 1;    /* skip white space */
+                               if (*Inputp!='\0' && *Inputp!='\n')
+                                       complain("[junk at end of line]");
+                       }
+               }
+       } while (!eof);
+
+       f_close(fp);
+       pop_env(savejmp);
+       Inputp = NULL;
+       Asking = NO;
+       InJoverc -= 1;
+       if (finger != 1)
+               complain("[Missing endif]");
+       return YES;
+}
diff --git a/usr/src/contrib/jove-4.14.6/fmt.c b/usr/src/contrib/jove-4.14.6/fmt.c
new file mode 100644 (file)
index 0000000..11886a8
--- /dev/null
@@ -0,0 +1,438 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "fp.h"
+#include "termcap.h"
+#include "ctype.h"
+#include "disp.h"
+
+#ifdef MAC
+# include  "mac.h"
+#else
+# ifdef        STDARGS
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+#endif
+
+private void
+       doformat proto((File *, const char *, va_list)),
+       outld proto((long, int)),
+       pad proto((int, int));
+
+char   mesgbuf[MESG_SIZE];
+
+void
+format(buf, len, fmt, ap)
+char   *buf;
+const char     *fmt;
+size_t len;
+va_list        ap;
+{
+       File    strbuf;
+
+       strbuf.f_ptr = strbuf.f_base = buf;
+       strbuf.f_fd = -1;               /* Not legit for files */
+       strbuf.f_bufsize = strbuf.f_cnt = len;
+       strbuf.f_flags = F_STRING;
+
+       doformat(&strbuf, fmt, ap);
+       jputc('\0', &strbuf);   /* jputc will place this, even if overflow */
+}
+
+#ifdef IBMPC
+int    specialmap = 0, /* ??? never used? -- DHR */
+       specialkey = 0;
+
+#define Empty ""
+
+const char *const altseq[133] = {
+Empty, Empty, Empty, "Ctrl-@", Empty, Empty, Empty, Empty,
+Empty, Empty, Empty, Empty, Empty, Empty, Empty, "Left",
+"Alt-Q", "Alt-W", "Alt-E", "Alt-R", "Alt-T", "Alt-Y", "Alt-U", "Alt-I",
+"Alt-O", "Alt-P", Empty, Empty, Empty, Empty, "Alt-A", "Alt-S",
+"Alt-D", "Alt-F", "Alt-G", "Alt-H", "Alt-J", "Alt-K", "Alt-L", Empty,
+Empty, Empty, Empty, Empty, "Alt-Z", "Alt-X", "Alt-C", "Alt-V",
+"Alt-B", "Alt-N", "Alt-M", Empty, Empty, Empty, Empty, Empty,
+Empty, Empty, Empty, "F1", "F2", "F3", "F4", "F5",
+"F6", "F7", "F8", "F9", "F10", Empty, Empty, "Home",
+"Up", "PageUp", Empty, "Left", Empty, "Right", Empty, "End",
+"Down", "PageDown", "Ins", "Del", "Shift F1", "Shift F2", "Shift F3", "Shift F4",
+"Shift F5", "Shift F6", "Shift F7", "Shift F8", "Shift F9", "Shift F10", "Ctrl F1", "Ctrl F2",
+"Ctrl F3", "Ctrl F4", "Ctrl F5", "Ctrl F6", "Ctrl F7", "Ctrl F8", "Ctrl F9", "Ctrl F10",
+"Alt F1", "Alt F2", "Alt F3", "Alt F4", "Alt F5", "Alt F6", "Alt F7", "Alt F8",
+"Alt F9", "Alt F10", "Ctrl PrtSc", "Ctrl Left", "Ctrl Right", "Ctrl End", "Ctrl PageDown", "Ctrl Home",
+"Alt 1", "Alt 2", "Alt 3", "Alt 4", "Alt 5", "Alt 6", "Alt 7", "Alt 8",
+"Alt 9", "Alt 0", "Alt Minus", "Alt Equals", "Ctrl PageUp"
+};
+#endif
+
+
+private void
+PPchar(c, str, size)
+int    c;
+char   *str;
+size_t size;
+{
+       char    *cp = str;
+
+#ifdef IBMPC
+       if (specialmap || specialkey) {
+               if (c < 0 || c > 132)
+                       c = 0;
+               strcpy(cp, altseq[c]);
+       } else if (c == '\377') {
+               *cp = '\0';     /* this character was invisible */
+       } else
+#endif
+       if (c == '\033') {
+               strcpy(cp, "ESC");
+       } else if (c < ' ') {
+               swritef(cp, size, "C-%c", c + '@');
+       } else if (c == '\177') {
+               strcpy(cp, "^?");
+       } else {
+               swritef(cp, size, "%c", c);
+       }
+}
+
+private struct fmt_state {
+       int     precision,
+               width,
+               leftadj;
+       char    padc;
+       File    *iop;
+} current_fmt;
+
+private void
+putld(d, base)
+long   d;
+int    base;
+{
+       int     len = 1;
+       long    tmpd = d;
+
+       if (current_fmt.width == 0 && current_fmt.precision) {
+               current_fmt.width = current_fmt.precision;
+               current_fmt.padc = '0';
+       }
+       while ((tmpd = (tmpd / base)) != 0)
+               len += 1;
+       if (d < 0)
+               len += 1;
+       if (!current_fmt.leftadj)
+               pad(current_fmt.padc, current_fmt.width - len);
+       if (d < 0) {
+               jputc('-', current_fmt.iop);
+               d = -d;
+       }
+       outld(d, base);
+       if (current_fmt.leftadj)
+               pad(current_fmt.padc, current_fmt.width - len);
+}
+
+private void
+outld(d, base)
+long   d;
+int    base;
+{
+       register long   n;
+       static const char       chars[] = {'0', '1', '2', '3', '4', '5', '6',
+                                   '7', '8', '9', 'a', 'b', 'c', 'd',
+                                   'e', 'f'};
+
+       if ((n = (d / base)) != 0)
+               outld(n, base);
+       jputc((int) (chars[(int) (d % base)]), current_fmt.iop);
+}
+
+private void
+jputs(str)
+char   *str;
+{
+       int     len;
+       register char   *cp;
+
+       if (str == NULL)
+               str = "(null)";
+       len = strlen(str);
+       if (current_fmt.precision == 0 || len < current_fmt.precision)
+               current_fmt.precision = len;
+       else
+               len = current_fmt.precision;
+       cp = str;
+       if (!current_fmt.leftadj)
+               pad(' ', current_fmt.width - len);
+       while (--current_fmt.precision >= 0)
+               jputc(*cp++, current_fmt.iop);
+       if (current_fmt.leftadj)
+               pad(' ', current_fmt.width - len);
+}
+
+private void
+pad(c, amount)
+register int   c,
+               amount;
+{
+       while (--amount >= 0)
+               jputc(c, current_fmt.iop);
+}
+
+private void
+doformat(sp, fmt, ap)
+register File  *sp;
+register const char    *fmt;
+va_list        ap;
+{
+       register char   c;
+       struct fmt_state        prev_fmt;
+
+       prev_fmt = current_fmt;
+       current_fmt.iop = sp;
+
+       while ((c = *fmt++) != '\0') {
+               if (c != '%') {
+                       jputc(c, current_fmt.iop);
+                       continue;
+               }
+
+               current_fmt.padc = ' ';
+               current_fmt.precision = current_fmt.leftadj = current_fmt.width = 0;
+               c = *fmt++;
+               if (c == '-') {
+                       current_fmt.leftadj = YES;
+                       c = *fmt++;
+               }
+               if (c == '0') {
+                       current_fmt.padc = '0';
+                       c = *fmt++;
+               }
+               while (c >= '0' && c <= '9') {
+                       current_fmt.width = current_fmt.width * 10 + (c - '0');
+                       c = *fmt++;
+               }
+               if (c == '*') {
+                       current_fmt.width = va_arg(ap, int);
+                       c = *fmt++;
+               }
+               if (c == '.') {
+                       c = *fmt++;
+                       while (c >= '0' && c <= '9') {
+                               current_fmt.precision = current_fmt.precision * 10 + (c - '0');
+                               c = *fmt++;
+                       }
+                       if (c == '*') {
+                               current_fmt.precision = va_arg(ap, int);
+                               c = *fmt++;
+                       }
+               }
+       reswitch:
+               /* At this point, fmt points at one past the format letter. */
+               switch (c) {
+               case '%':
+                       jputc('%', current_fmt.iop);
+                       break;
+
+               case 'O':
+               case 'D':
+               case 'X':
+                       putld(va_arg(ap, long), (c == 'O') ? 8 :
+                                               (c == 'D') ? 10 : 16);
+                       break;
+
+               case 'b':
+                   {
+                       Buffer  *b = va_arg(ap, Buffer *);
+
+                       jputs(b->b_name);
+                       break;
+                   }
+
+               case 'c':
+                       jputc(va_arg(ap, int), current_fmt.iop);
+                       break;
+
+               case 'o':
+               case 'd':
+               case 'x':
+                       putld((long) va_arg(ap, int), (c == 'o') ? 8 :
+                                               (c == 'd') ? 10 : 16);
+                       break;
+
+               case 'f':       /* current command name gets inserted here! */
+                       jputs(LastCmd->Name);
+                       break;
+
+               case 'l':
+                       c = CharUpcase(*++fmt);
+                       goto reswitch;
+
+               case 'n':
+                       if (va_arg(ap, int) != 1)
+                               jputs("s");
+                       break;
+
+               case 'p':
+                   {
+                       char    cbuf[20];
+
+                       PPchar(va_arg(ap, int), cbuf, sizeof(cbuf));
+                       jputs(cbuf);
+                       break;
+                   }
+
+               case 's':
+                       jputs(va_arg(ap, char *));
+                       break;
+
+               default:
+                       complain("Unknown format directive: \"%%%c\"", c);
+               }
+       }
+       current_fmt = prev_fmt;
+}
+
+#ifdef STDARGS
+char *
+sprint(const char *fmt, ...)
+#else
+/*VARARGS1*/ char *
+sprint(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+       static char     line[100];
+
+       va_init(ap, fmt);
+       format(line, sizeof line, fmt, ap);
+       va_end(ap);
+       return line;
+}
+
+#ifdef STDARGS
+void
+writef(const char *fmt, ...)
+#else
+/*VARARGS1*/ void
+writef(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       va_init(ap, fmt);
+#ifndef        IBMPC
+       doformat(stdout, fmt, ap);
+#else  /* IBMPC */
+       write_em(sprint(fmt, ap));
+       /* doformat(stdout, fmt, ap); */
+#endif /* IBMPC */
+       va_end(ap);
+}
+
+#ifdef STDARGS
+void
+fwritef(File *fp, const char *fmt, ...)
+#else
+/*VARARGS2*/ void
+fwritef(fp, fmt, va_alist)
+       File    *fp;
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       va_init(ap, fmt);
+       doformat(fp, fmt, ap);
+       va_end(ap);
+}
+
+#ifdef STDARGS
+void
+swritef(char *str, size_t size, const char *fmt, ...)
+#else
+/*VARARGS3*/ void
+swritef(str, size, fmt, va_alist)
+       char    *str;
+       size_t  size;
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       va_init(ap, fmt);
+       format(str, size, fmt, ap);
+       va_end(ap);
+}
+
+#ifdef STDARGS
+void
+s_mess(const char *fmt, ...)
+#else
+/*VARARGS1*/ void
+s_mess(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       if (InJoverc)
+               return;
+       va_init(ap, fmt);
+       format(mesgbuf, sizeof mesgbuf, fmt, ap);
+       va_end(ap);
+       message(mesgbuf);
+}
+
+#ifdef STDARGS
+void
+f_mess(const char *fmt, ...)
+#else
+/*VARARGS1*/ void
+f_mess(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       va_init(ap, fmt);
+       format(mesgbuf, sizeof mesgbuf, fmt, ap);
+       va_end(ap);
+       DrawMesg(NO);
+       errormsg = NO;
+       UpdMesg = YES;  /* still needs updating (for convenience) */
+}
+
+#ifdef STDARGS
+void
+add_mess(const char *fmt, ...)
+#else
+/*VARARGS1*/ void
+add_mess(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       int     mesg_len = strlen(mesgbuf);
+       va_list ap;
+
+       if (InJoverc)
+               return;
+       va_init(ap, fmt);
+       format(&mesgbuf[mesg_len], (sizeof mesgbuf) - mesg_len, fmt, ap);
+       va_end(ap);
+       message(mesgbuf);
+}
diff --git a/usr/src/contrib/jove-4.14.6/fp.c b/usr/src/contrib/jove-4.14.6/fp.c
new file mode 100644 (file)
index 0000000..f88cc63
--- /dev/null
@@ -0,0 +1,354 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "fp.h"
+#include "ctype.h"
+#include "termcap.h"
+#include "disp.h"
+
+#ifdef MAC
+#      include "mac.h"
+#else  /* !MAC */
+#      include <sys/stat.h>
+#      ifndef  MSDOS
+#              include <sys/file.h>
+#      else    /* MSDOS */
+#              include <fcntl.h>
+#              include <io.h>
+#      endif   /* MSDOS */
+#endif /* !MAC */
+
+#include <errno.h>
+
+#ifdef RAINBOW
+private int rbwrite proto((int, char *, int));
+#endif
+
+#ifndef        L_SET
+# define L_SET 0
+#endif
+
+#define MAXFILES       20      /* good enough for my purposes */
+
+private File   openfiles[MAXFILES];    /* must be zeroed initially */
+
+File *
+fd_open(name, flags, fd, buffer, buf_size)
+char   *name,
+       *buffer;
+int    flags,
+       fd,
+       buf_size;
+{
+       register File   *fp;
+       register int    i;
+
+       for (fp = openfiles, i = 0; i < MAXFILES; i++, fp++)
+               if (fp->f_flags == 0)
+                       break;
+       if (i == MAXFILES)
+               complain("[Too many open files!]");
+       fp->f_bufsize = buf_size;
+       fp->f_cnt = 0;
+       fp->f_fd = fd;
+       fp->f_flags = flags;
+       if (buffer == NULL) {
+               buffer = emalloc((size_t)buf_size);
+               fp->f_flags |= F_MYBUF;
+       }
+       fp->f_base = fp->f_ptr = buffer;
+       fp->f_name = copystr(name);
+
+       return fp;
+}
+
+void
+gc_openfiles()
+{
+       register File   *fp;
+
+       for (fp = openfiles; fp < &openfiles[MAXFILES]; fp++)
+               if (fp->f_flags != 0 && (fp->f_flags & F_LOCKED) == 0)
+                       f_close(fp);
+}
+
+File *
+f_open(name, flags, buffer, buf_size)
+char   *name,
+       *buffer;
+int    flags,
+       buf_size;
+{
+       register int    fd;
+
+       switch (F_MODE(flags)) {
+       case F_READ:
+               fd = open(name, 0);
+               break;
+
+       case F_APPEND:
+               fd = open(name, 1);
+               if (fd != -1) {
+                       (void) lseek(fd, 0L, 2);
+                       break;
+               }
+               /* FALLTHROUGH */
+       case F_WRITE:
+               fd = creat(name, CreatMode);
+               break;
+
+       default:
+               error("invalid F_MODE");
+               /* NOTREACHED */
+       }
+       if (fd == -1)
+               return NULL;
+#ifdef MSDOS
+       setmode(fd, 0x8000);
+#endif /* MSDOS */
+       return fd_open(name, flags, fd, buffer, buf_size);
+}
+
+void
+f_close(fp)
+File   *fp;
+{
+       if (fp->f_flags & (F_WRITE|F_APPEND)) {
+               flushout(fp);
+#ifdef BSD4_2
+               (void) fsync(fp->f_fd);
+#endif
+       }
+       (void) close(fp->f_fd);
+       if (fp->f_flags & F_MYBUF)
+               free((UnivPtr) fp->f_base);
+       free((UnivPtr) fp->f_name);
+       fp->f_flags = 0;        /* indicates that we're available */
+}
+
+int
+filbuf(fp)
+File   *fp;
+{
+       if (fp->f_flags & (F_EOF|F_ERR))
+               return EOF;
+       fp->f_ptr = fp->f_base;
+#ifndef        MSDOS
+       do {
+#endif /* MSDOS */
+               fp->f_cnt = read(fp->f_fd, (UnivPtr) fp->f_base, (size_t) fp->f_bufsize);
+#ifndef        MSDOS
+       } while (fp->f_cnt == -1 && errno == EINTR);
+#endif /* MSDOS */
+       if (fp->f_cnt == -1) {
+               /* I/O error -- treat as EOF */
+               writef("[Read error: %s]", strerror(errno));
+               fp->f_flags |= F_ERR | F_EOF;
+               return EOF;
+       }
+       if (fp->f_cnt == 0) {
+               fp->f_flags |= F_EOF;
+               return EOF;
+       }
+       io_chars += fp->f_cnt;
+       return jgetc(fp);
+}
+
+void
+putstr(s)
+register char  *s;
+{
+#ifndef        IBMPC
+       register int    c;
+
+       while ((c = *s++) != '\0')
+               jputchar(c);
+#else  /* IBMPC */
+       write_emif(s);
+#endif /* IBMPC */
+}
+
+void
+fputnchar(s, n, fp)
+register char  *s;
+register int   n;
+register File  *fp;
+{
+       while (--n >= 0)
+               jputc(*s++, fp);
+}
+
+void
+flushscreen()
+{
+#ifndef        IBMPC
+       flushout(stdout);
+#endif /* IBMPC */
+}
+
+void
+f_seek(fp, offset)
+register File  *fp;
+off_t  offset;
+{
+       if (fp->f_flags & (F_WRITE|F_APPEND))
+               flushout(fp);
+       fp->f_cnt = 0;          /* next read will filbuf(), next write
+                                  will flush() with no bad effects */
+       lseek(fp->f_fd, (long) offset, L_SET);
+}
+
+void
+flushout(fp)
+register File  *fp;
+{
+       register int    n;
+
+       if (fp->f_flags & (F_READ | F_STRING | F_ERR)) {
+               if (fp->f_flags != F_STRING)
+                       abort();    /* IMPOSSIBLE */
+               /* We just banged into the end of a string.
+                * In the interests of continuing, we will cause
+                * the rest of the output to be be heaped in the
+                * last position.  Surely it will end up as a NUL. UGH!
+                */
+               fp->f_cnt = 1;
+               fp->f_ptr = &fp->f_base[fp->f_bufsize - 1];
+               return;
+       }
+       if (((n = (fp->f_ptr - fp->f_base)) > 0) &&
+#ifndef        RAINBOW
+           (write(fp->f_fd, (UnivPtr) fp->f_base, (size_t)n) != n) &&
+#else
+           (rbwrite(fp->f_fd, fp->f_base, n) != n) &&
+#endif
+           (fp != stdout))
+       {
+               fp->f_flags |= F_ERR;
+               error("[I/O error(%s); file = %s, fd = %d]",
+                       strerror(errno), fp->f_name, fp->f_fd);
+       }
+
+       fp->f_cnt = fp->f_bufsize;
+       fp->f_ptr = fp->f_base;
+}
+
+bool
+f_gets(fp, buf, max)
+register File  *fp;
+char   *buf;
+size_t max;
+{
+       register char   *cp = buf;
+       register int    c;
+       char    *endp = buf + max - 1;
+
+       if (fp->f_flags & F_EOF)
+               return YES;
+       while (((c = jgetc(fp)) != EOF) && (c != '\n')) {
+               if (c == '\0') {
+                       /* We can't store NUL in our buffer, so ignore it.
+                        * Of course, with a little ingenuity we could:
+                        * NUL could be represented by \n!
+                        */
+                       continue;
+               }
+               if (cp >= endp) {
+                       add_mess(" [Line too long]");
+                       rbell();
+                       return YES;
+               }
+               *cp++ = c;
+       }
+       *cp = '\0';
+       if (c == EOF) {
+               if (cp != buf)
+                       add_mess(" [Incomplete last line]");
+               return YES;
+       }
+#ifdef MSDOS
+       /* a CR followed by a LF is treated as a NL.
+        * Bug: the line-buffer is effectively shortened by one character.
+        */
+       if (cp != buf && cp[-1] == '\r')
+               *--cp = '\0';
+#endif /* MSDOS */
+       io_lines += 1;
+       return NO;      /* this means okay */
+}
+
+/* skip to beginning of next line, i.e., next read returns first
+   character of new line */
+
+void
+f_toNL(fp)
+register File  *fp;
+{
+       register int    c;
+
+       if (fp->f_flags & F_EOF)
+               return;
+       do ; while (((c = jgetc(fp)) != EOF) && (c != '\n'));
+       if (c == EOF)
+               fp->f_flags |= F_EOF;
+}
+
+size_t
+f_readn(fp, addr, n)
+register File  *fp;
+register char  *addr;
+size_t n;
+{
+       register size_t nleft;
+
+       for (nleft = n; nleft > 0; nleft--) {
+               int     c = jgetc(fp);
+
+               if (f_eof(fp))
+                       break;
+               *addr++ = c;
+       }
+       return n - nleft;
+}
+
+/* Deals with output to the terminal, setting up the amount of characters
+   to be buffered depending on the output baud rate.  Why it's in a
+   separate file I don't know ... */
+
+private char   one_buf;
+
+int    BufSize = 1;
+
+private File   stdout_File = {1, 1, 1, F_WRITE, &one_buf, &one_buf, (char *)NULL};
+File   *stdout = &stdout_File;
+
+#ifdef RAINBOW
+
+/*
+ * use the Rainbow's video output function
+ */
+
+#include <dos.h>
+
+private int
+rbwrite(fd, buf, cnt)
+char *buf;
+{
+       union REGS vr;
+
+       if (fd != 1) {
+               write(fd, buf, cnt);
+       } else {
+               while (cnt-- > 0) {
+                       vr.x.ax = *buf++;
+                       vr.x.di = 0;
+                       int86(0x18, &vr, &vr);
+               }
+       }
+}
+#endif /* RAINBOW */
diff --git a/usr/src/contrib/jove-4.14.6/fp.h b/usr/src/contrib/jove-4.14.6/fp.h
new file mode 100644 (file)
index 0000000..9393d6d
--- /dev/null
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+extern void    jputchar proto((int c));        /* hidden by macro */
+
+#define jputchar(c)    jputc((c), stdout)
+#define jputc(c, fp)   { while (--(fp)->f_cnt < 0) flushout(fp); *(fp)->f_ptr++ = (c); }
+#define jgetc(fp)      \
+       (((--(fp)->f_cnt < 0) ? filbuf(fp) : (unsigned char) *(fp)->f_ptr++))
+#define f_eof(fp)      ((fp)->f_flags & F_EOF)
+
+typedef struct FileStruct {
+       int     f_cnt,          /* number of characters left in buffer */
+               f_bufsize,      /* size of what f_base points to */
+               f_fd,           /* fildes */
+               f_flags;        /* various flags */
+       char    *f_ptr,         /* current offset */
+               *f_base;        /* pointer to base */
+       char    *f_name;        /* name of open file */
+} File;
+
+#define F_READ         01
+#define F_WRITE                02
+#define F_APPEND       04
+#define F_MODE(x)      ((x)&07)
+#define F_EOF          010
+#define F_STRING       020
+#define F_ERR          040
+#define F_LOCKED       0100    /* don't close this file upon error */
+#define F_MYBUF                0200    /* f_alloc allocated the buffer, so
+                                  f_close knows to free it up */
+#define F_TELLALL      0400    /* whether to display info upon close */
+#define F_READONLY     01000   /* file is read only */
+
+extern long    io_chars;
+extern int     io_lines;
+
+extern File
+       *stdout;
+
+#ifdef VMUNIX
+# define MAXTTYBUF     2048
+#else
+# define MAXTTYBUF     512
+#endif
+
+extern int     BufSize;
+
+extern File
+       *f_open proto((char *name,int flags,char *buffer,int buf_size)),
+       *fd_open proto((char *name,int flags,int fd,char *buffer,int bsize));
+
+extern int
+       filbuf proto((File *fp));
+
+extern size_t
+       f_readn proto((File *fp,char *addr,size_t n));
+
+extern void
+       f_close proto((File *fp)),
+       f_seek proto((File *fp, off_t offset)),
+       f_toNL proto((File *fp)),
+       flushout proto((File *fp)),
+       flushscreen proto((void)),
+       fputnchar proto((char *s,int n,File *fp)),
+       gc_openfiles proto((void)),
+       putstr proto((char *s));
+
+extern bool
+       f_gets proto((File *fp,char *buf,size_t max));
diff --git a/usr/src/contrib/jove-4.14.6/funcdefs.c b/usr/src/contrib/jove-4.14.6/funcdefs.c
new file mode 100644 (file)
index 0000000..229973b
--- /dev/null
@@ -0,0 +1,427 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+
+#ifdef UNIX
+# ifndef       SYSV
+#  include <sgtty.h>
+# endif
+#endif
+
+#ifndef        TXT_TO_C
+
+#ifdef MAC
+#      define WIRED_CMD(c) (c),'\0','\0'       /* for About Jove... */
+#else
+#      define WIRED_CMD(c)     (c)
+#endif /* MAC */
+
+#else  /* TXT_TO_C */
+
+#ifdef MAC
+#      define WIRED_CMD(c) 0,'\0','\0'
+#else
+#      define WIRED_CMD(c)     0
+#endif
+#endif /* TXT_TO_C */
+
+/* Table of commands
+ *
+ * Note: must be kept in alphabetical order (the truth is more complicated).
+ */
+
+const struct cmd       commands[] = {
+#ifdef LISP
+       FUNCTION, "add-lisp-special", WIRED_CMD(AddSpecial),
+#endif
+       FUNCTION, "append-region", WIRED_CMD(AppReg),
+       FUNCTION, "apropos", WIRED_CMD(Apropos),
+       FUNCTION, "auto-execute-command", WIRED_CMD(CAutoExec),
+       FUNCTION, "auto-execute-macro", WIRED_CMD(MAutoExec),
+       DefMinor(Fill), "auto-fill-mode", WIRED_CMD(NULL),
+       DefMinor(Indent), "auto-indent-mode", WIRED_CMD(NULL),
+       FUNCTION, "backward-character", WIRED_CMD(BackChar),
+       FUNCTION, "backward-list", WIRED_CMD(BList),
+       FUNCTION, "backward-paragraph", WIRED_CMD(BackPara),
+       FUNCTION, "backward-s-expression", WIRED_CMD(BSexpr),
+       FUNCTION, "backward-sentence", WIRED_CMD(Bos),
+       FUNCTION, "backward-up-list", WIRED_CMD(BUpList),
+       FUNCTION, "backward-word", WIRED_CMD(BackWord),
+       FUNCTION, "begin-kbd-macro", WIRED_CMD(Remember),
+       FUNCTION, "beginning-of-file", WIRED_CMD(Bof),
+       FUNCTION, "beginning-of-line", WIRED_CMD(Bol),
+       FUNCTION, "beginning-of-window", WIRED_CMD(Bow),
+       FUNCTION, "bind-keymap-to-key", WIRED_CMD(KmBind),
+       FUNCTION, "bind-macro-to-key", WIRED_CMD(BindMac),
+#ifdef ABBREV
+       FUNCTION, "bind-macro-to-word-abbrev", WIRED_CMD(BindMtoW),
+#endif
+       FUNCTION, "bind-to-key", WIRED_CMD(BindAKey),
+       FUNCTION, "buffer-position", WIRED_CMD(BufPos),
+       DefMajor(CMODE), "c-mode", WIRED_CMD(NULL),
+       MODFUNC, "case-character-capitalize", WIRED_CMD(CapChar),
+       MODFUNC, "case-region-lower", WIRED_CMD(CasRegLower),
+       MODFUNC, "case-region-upper", WIRED_CMD(CasRegUpper),
+       MODFUNC, "case-word-capitalize", WIRED_CMD(CapWord),
+       MODFUNC, "case-word-lower", WIRED_CMD(LowWord),
+       MODFUNC, "case-word-upper", WIRED_CMD(UppWord),
+       FUNCTION, "cd", WIRED_CMD(Chdir),
+       MODFUNC, "character-to-octal-insert", WIRED_CMD(ChrToOct),
+       FUNCTION, "clear-and-redraw", WIRED_CMD(ClAndRedraw),
+#ifndef        MAC
+       FUNCTION, "compile-it", WIRED_CMD(MakeErrors),
+#endif
+#ifdef PTYPROCS
+       FUNCTION, "continue-process", WIRED_CMD(ProcCont),
+#endif
+       FUNCTION, "copy-region", WIRED_CMD(CopyRegion),
+#ifndef        MAC
+       FUNCTION, "current-error", WIRED_CMD(ShowErr),
+#endif
+       FUNCTION, "date", WIRED_CMD(prCTIME),
+#ifdef ABBREV
+       FUNCTION, "define-global-word-abbrev", WIRED_CMD(DefGAbbrev),
+#endif
+       FUNCTION, "define-macro", WIRED_CMD(DefKBDMac),
+#ifdef ABBREV
+       FUNCTION, "define-mode-word-abbrev", WIRED_CMD(DefMAbbrev),
+#endif
+       MODFUNC, "delete-blank-lines", WIRED_CMD(DelBlnkLines),
+       FUNCTION, "delete-buffer", WIRED_CMD(BufKill),
+       FUNCTION, "delete-current-window", WIRED_CMD(DelCurWindow),
+       FUNCTION, "delete-macro", WIRED_CMD(DelMacro),
+       MODFUNC, "delete-next-character", WIRED_CMD(DelNChar),
+       FUNCTION, "delete-other-windows", WIRED_CMD(OneWindow),
+       MODFUNC, "delete-previous-character", WIRED_CMD(DelPChar),
+       MODFUNC, "delete-white-space", WIRED_CMD(DelWtSpace),
+       FUNCTION, "describe-bindings", WIRED_CMD(DescBindings),
+       FUNCTION, "describe-command", WIRED_CMD(DescCom),
+       FUNCTION, "describe-key", WIRED_CMD(KeyDesc),
+       FUNCTION, "describe-variable", WIRED_CMD(DescCom),
+       FUNCTION, "digit", WIRED_CMD(Digit),
+       FUNCTION, "digit-0", WIRED_CMD(Digit0),
+       FUNCTION, "digit-1", WIRED_CMD(Digit1),
+       FUNCTION, "digit-2", WIRED_CMD(Digit2),
+       FUNCTION, "digit-3", WIRED_CMD(Digit3),
+       FUNCTION, "digit-4", WIRED_CMD(Digit4),
+       FUNCTION, "digit-5", WIRED_CMD(Digit5),
+       FUNCTION, "digit-6", WIRED_CMD(Digit6),
+       FUNCTION, "digit-7", WIRED_CMD(Digit7),
+       FUNCTION, "digit-8", WIRED_CMD(Digit8),
+       FUNCTION, "digit-9", WIRED_CMD(Digit9),
+       FUNCTION, "dirs", WIRED_CMD(prDIRS),
+       FUNCTION, "down-list", WIRED_CMD(FDownList),
+#ifdef PTYPROCS
+       FUNCTION, "dstop-process", WIRED_CMD(ProcDStop),
+#endif
+#ifdef ABBREV
+       FUNCTION, "edit-word-abbrevs", WIRED_CMD(EditAbbrevs),
+#endif
+       FUNCTION, "end-kbd-macro", WIRED_CMD(Forget),
+       FUNCTION, "end-of-file", WIRED_CMD(Eof),
+       FUNCTION, "end-of-line", WIRED_CMD(Eol),
+       FUNCTION, "end-of-window", WIRED_CMD(Eow),
+#ifdef PTYPROCS
+       FUNCTION, "eof-process", WIRED_CMD(ProcEof),
+#endif
+       FUNCTION, "erase-buffer", WIRED_CMD(BufErase),
+       FUNCTION, "exchange-point-and-mark", WIRED_CMD(PtToMark),
+       FUNCTION, "execute-kbd-macro", WIRED_CMD(ExecMacro),
+       FUNCTION, "execute-macro", WIRED_CMD(RunMacro),
+       FUNCTION, "execute-named-command", WIRED_CMD(Extend),
+       FUNCTION, "exit-jove", WIRED_CMD(Leave),
+#ifdef CMT_FMT
+       MODFUNC, "fill-comment", WIRED_CMD(Comment),
+#endif /* CMT_FMT */
+       MODFUNC, "fill-paragraph", WIRED_CMD(Justify),
+       MODFUNC, "fill-region", WIRED_CMD(RegJustify),
+#ifndef        MAC
+       MODFUNC, "filter-region", WIRED_CMD(FilterRegion),
+#endif
+       FUNCTION, "find-file", WIRED_CMD(FindFile),
+       FUNCTION, "find-tag", WIRED_CMD(FindTag),
+       FUNCTION, "find-tag-at-point", WIRED_CMD(FDotTag),
+       FUNCTION, "first-non-blank", WIRED_CMD(ToIndent),
+       FUNCTION, "forward-character", WIRED_CMD(ForChar),
+       FUNCTION, "forward-list", WIRED_CMD(FList),
+       FUNCTION, "forward-paragraph", WIRED_CMD(ForPara),
+       FUNCTION, "forward-s-expression", WIRED_CMD(FSexpr),
+       FUNCTION, "forward-sentence", WIRED_CMD(Eos),
+       FUNCTION, "forward-word", WIRED_CMD(ForWord),
+       DefMajor(FUNDAMENTAL), "fundamental-mode", WIRED_CMD(NULL),
+       FUNCTION, "gather-numeric-argument", WIRED_CMD(TimesFour),
+       FUNCTION, "goto-line", WIRED_CMD(GoLine),
+       FUNCTION, "goto-window-with-buffer", WIRED_CMD(GotoWind),
+#ifdef LISP
+       MODFUNC, "grind-s-expr", WIRED_CMD(GSexpr),
+#endif
+       FUNCTION, "grow-window", WIRED_CMD(GrowWindowCmd),
+       MODFUNC, "handle-tab", WIRED_CMD(Tab),
+       FUNCTION, "i-search-forward", WIRED_CMD(IncFSearch),
+       FUNCTION, "i-search-reverse", WIRED_CMD(IncRSearch),
+#ifdef IPROCS
+       FUNCTION, "i-shell-command", WIRED_CMD(Iprocess),
+#endif
+       MODFUNC, "insert-file", WIRED_CMD(InsFile),
+#ifdef IPROCS
+       FUNCTION, "interrupt-process", WIRED_CMD(ProcInt),
+#endif
+       MODFUNC, "kill-next-word", WIRED_CMD(DelNWord),
+       MODFUNC, "kill-previous-word", WIRED_CMD(DelPWord),
+#ifdef IPROCS
+       FUNCTION, "kill-process", WIRED_CMD(ProcKill),
+#endif
+       MODFUNC, "kill-region", WIRED_CMD(DelReg),
+       MODFUNC, "kill-s-expression", WIRED_CMD(KillExpr),
+       FUNCTION, "kill-some-buffers", WIRED_CMD(KillSome),
+       MODFUNC, "kill-to-beginning-of-sentence", WIRED_CMD(KillBos),
+       MODFUNC, "kill-to-end-of-line", WIRED_CMD(KillEOL),
+       MODFUNC, "kill-to-end-of-sentence", WIRED_CMD(KillEos),
+       FUNCTION, "left-margin-here", WIRED_CMD(SetLMargin),
+#ifdef LISP
+       DefMajor(LISPMODE), "lisp-mode", WIRED_CMD(NULL),
+#endif
+       FUNCTION, "list-buffers", WIRED_CMD(BufList),
+#ifdef IPROCS
+       FUNCTION, "list-processes", WIRED_CMD(ProcList),
+#endif
+       FUNCTION, "make-buffer-unmodified", WIRED_CMD(NotModified),
+       FUNCTION, "make-keymap", WIRED_CMD(MakeKMap),
+       FUNCTION, "make-macro-interactive", WIRED_CMD(MacInter),
+       FUNCTION, "name-kbd-macro", WIRED_CMD(NameMac),
+       MODFUNC, "newline", WIRED_CMD(Newline),
+       MODFUNC, "newline-and-backup", WIRED_CMD(OpenLine),
+       MODFUNC, "newline-and-indent", WIRED_CMD(LineAI),
+#ifndef        MAC
+       FUNCTION, "next-error", WIRED_CMD(NextError),
+#endif
+       FUNCTION, "next-line", WIRED_CMD(NextLine),
+       FUNCTION, "next-page", WIRED_CMD(NextPage),
+       FUNCTION, "next-window", WIRED_CMD(NextWindow),
+       FUNCTION, "number-lines-in-window", WIRED_CMD(WNumLines),
+       DefMinor(OverWrite), "over-write-mode", WIRED_CMD(NULL),
+       FUNCTION, "page-next-window", WIRED_CMD(PageNWind),
+       MODFUNC, "paren-flash", WIRED_CMD(DoParen),
+#ifndef        MAC
+       FUNCTION, "parse-errors", WIRED_CMD(ErrParse),
+#endif
+#ifdef SPELL
+       FUNCTION, "parse-spelling-errors-in-buffer", WIRED_CMD(SpelWords),
+#endif
+#ifdef JOB_CONTROL
+       FUNCTION, "pause-jove", WIRED_CMD(PauseJove),
+#else
+#      ifndef  MAC
+       FUNCTION, "pause-jove", WIRED_CMD(Push),
+#      endif
+#endif
+       FUNCTION, "pop-mark", WIRED_CMD(PopMark),
+       FUNCTION, "popd", WIRED_CMD(Popd),
+#ifndef        MAC
+       FUNCTION, "previous-error", WIRED_CMD(PrevError),
+#endif
+       FUNCTION, "previous-line", WIRED_CMD(PrevLine),
+       FUNCTION, "previous-page", WIRED_CMD(PrevPage),
+       FUNCTION, "previous-window", WIRED_CMD(PrevWindow),
+       FUNCTION, "print", WIRED_CMD(PrVar),
+#ifdef IPROCS
+       FUNCTION, "process-bind-keymap-to-key", WIRED_CMD(ProcKmBind),
+       FUNCTION, "process-bind-to-key", WIRED_CMD(ProcBind),
+       FUNCTION, "process-dbx-output", WIRED_CMD(DBXpoutput),
+       MODFUNC, "process-newline", WIRED_CMD(ProcNewline),
+       FUNCTION, "process-send-data-no-return", WIRED_CMD(ProcSendData),
+#endif
+#ifndef        MAC
+       FUNCTION, "push-shell", WIRED_CMD(Push),
+#endif
+       FUNCTION, "pushd", WIRED_CMD(Pushd),
+       FUNCTION, "pwd", WIRED_CMD(prCWD),
+       MODFUNC, "query-replace-string", WIRED_CMD(QRepSearch),
+#ifdef IPROCS
+       FUNCTION, "quit-process", WIRED_CMD(ProcQuit),
+#endif
+       MODFUNC, "quoted-insert", WIRED_CMD(QuotChar),
+       DefMinor(ReadOnly), "read-only-mode", WIRED_CMD(NULL),
+#ifdef ABBREV
+       FUNCTION, "read-word-abbrev-file", WIRED_CMD(RestAbbrevs),
+#endif
+       FUNCTION, "recursive-edit", WIRED_CMD(Recur),
+       FUNCTION, "redraw-display", WIRED_CMD(RedrawDisplay),
+       FUNCTION, "rename-buffer", WIRED_CMD(ReNamBuf),
+       MODFUNC, "replace-in-region", WIRED_CMD(RegReplace),
+       MODFUNC, "replace-string", WIRED_CMD(RepSearch),
+       FUNCTION, "right-margin-here", WIRED_CMD(SetRMargin),
+       FUNCTION, "save-file", WIRED_CMD(SaveFile),
+       FUNCTION, "scroll-down", WIRED_CMD(DownScroll),
+       FUNCTION, "scroll-left", WIRED_CMD(ScrollLeft),
+#ifdef MSDOS
+       FUNCTION, "scroll-next-page", WIRED_CMD(PageScrollUp),
+       FUNCTION, "scroll-previous-page", WIRED_CMD(PageScrollDown),
+#endif /* MSDOS */
+       FUNCTION, "scroll-right", WIRED_CMD(ScrollRight),
+       FUNCTION, "scroll-up", WIRED_CMD(UpScroll),
+       FUNCTION, "search-forward", WIRED_CMD(ForSearch),
+       FUNCTION, "search-forward-nd", WIRED_CMD(FSrchND),
+       FUNCTION, "search-reverse", WIRED_CMD(RevSearch),
+       FUNCTION, "search-reverse-nd", WIRED_CMD(RSrchND),
+       FUNCTION, "select-buffer", WIRED_CMD(BufSelect),
+#ifdef MSDOS
+       FUNCTION, "select-buffer-0", WIRED_CMD(Buf0Select),
+       FUNCTION, "select-buffer-1", WIRED_CMD(Buf1Select),
+       FUNCTION, "select-buffer-2", WIRED_CMD(Buf2Select),
+       FUNCTION, "select-buffer-3", WIRED_CMD(Buf3Select),
+       FUNCTION, "select-buffer-4", WIRED_CMD(Buf4Select),
+       FUNCTION, "select-buffer-5", WIRED_CMD(Buf5Select),
+       FUNCTION, "select-buffer-6", WIRED_CMD(Buf6Select),
+       FUNCTION, "select-buffer-7", WIRED_CMD(Buf7Select),
+       FUNCTION, "select-buffer-8", WIRED_CMD(Buf8Select),
+       FUNCTION, "select-buffer-9", WIRED_CMD(Buf9Select),
+#endif /* MSDOS */
+       MODFUNC, "self-insert", WIRED_CMD(SelfInsert),
+       FUNCTION, "set", WIRED_CMD(SetVar),
+       FUNCTION, "set-mark", WIRED_CMD(SetMark),
+#ifdef IPROCS  /* for GNU compatibility */
+       FUNCTION, "shell", WIRED_CMD(ShellProc),
+#endif
+#ifndef        MAC
+       FUNCTION, "shell-command", WIRED_CMD(ShellCom),
+       FUNCTION, "shell-command-no-buffer", WIRED_CMD(ShNoBuf),
+       FUNCTION, "shell-command-to-buffer", WIRED_CMD(ShToBuf),
+       FUNCTION, "shell-command-with-typeout", WIRED_CMD(Shtypeout),
+#endif
+       MODFUNC, "shift-region-left", WIRED_CMD(LRShift),
+       MODFUNC, "shift-region-right", WIRED_CMD(RRShift),
+       DefMinor(ShowMatch), "show-match-mode", WIRED_CMD(NULL),
+       FUNCTION, "shrink-window", WIRED_CMD(ShrWindow),
+       FUNCTION, "source", WIRED_CMD(Source),
+#ifdef SPELL
+       FUNCTION, "spell-buffer", WIRED_CMD(SpelBuffer),
+#endif
+       FUNCTION, "split-current-window", WIRED_CMD(SplitWind),
+       FUNCTION, "start-remembering", WIRED_CMD(Remember),
+#ifdef PTYPROCS
+       FUNCTION, "stop-process", WIRED_CMD(ProcStop),
+#endif
+       FUNCTION, "stop-remembering", WIRED_CMD(Forget),
+       FUNCTION, "string-length", WIRED_CMD(StrLength),
+#ifdef JOB_CONTROL
+       FUNCTION, "suspend-jove", WIRED_CMD(PauseJove),
+#endif
+       DefMajor(TEXT), "text-mode", WIRED_CMD(NULL),
+       MODFUNC, "transpose-characters", WIRED_CMD(TransChar),
+       MODFUNC, "transpose-lines", WIRED_CMD(TransLines),
+       FUNCTION, "unbind-key", WIRED_CMD(UnbindC),
+       FUNCTION, "version", WIRED_CMD(ShowVersion),
+       FUNCTION, "visible-spaces-in-window", WIRED_CMD(WVisSpace),
+       FUNCTION, "visit-file", WIRED_CMD(ReadFile),
+       FUNCTION, "window-find", WIRED_CMD(WindFind),
+#ifdef ABBREV
+       DefMinor(Abbrev), "word-abbrev-mode", WIRED_CMD(NULL),
+#endif
+       FUNCTION, "write-file", WIRED_CMD(WriteFile),
+       FUNCTION, "write-macros-to-file", WIRED_CMD(WriteMacs),
+       FUNCTION, "write-modified-files", WIRED_CMD(WtModBuf),
+       FUNCTION, "write-region", WIRED_CMD(WrtReg),
+#ifdef ABBREV
+       FUNCTION, "write-word-abbrev-file", WIRED_CMD(SaveAbbrevs),
+#endif
+       FUNCTION, "xterm-mouse", WIRED_CMD(XtermMouse),
+       MODFUNC, "yank", WIRED_CMD(Yank),
+       MODFUNC, "yank-pop", WIRED_CMD(YankPop),
+       FUNCTION, NULL, NULL,
+};
+
+#ifndef        TXT_TO_C
+data_obj *
+findcom(prompt)
+const char     *prompt;
+{
+       /* This is for faster startup.  This just reads until a space or a
+          tab or a newline character is reached, and then does a
+          semi-hashed lookup on that string.  This should be much faster
+          than initializing the minibuffer for each line. */
+       if (InJoverc) {
+               char    cmdbuf[128];
+               register const struct cmd       *cmd;
+               register char   *cp = cmdbuf;
+               register int    c;
+               const struct cmd        *which;
+               size_t  cmdlen;
+               bool    found = NO;
+               static const struct cmd *cmdhash[26];
+               static bool     beenhere = NO;
+
+/* special case for prefix commands--only upper case ones */
+#define hash(c)        ((c) - 'a')
+
+               /* initialize the hash table */
+               if (!beenhere) {
+                       char    lastc = '\0';
+
+                       for (cmd = commands; cmd->Name != NULL; cmd++) {
+                               if (lastc != cmd->Name[0]) {
+                                       lastc = cmd->Name[0];
+                                       cmdhash[hash(lastc)] = cmd;
+                               }
+                       }
+                       beenhere = YES;
+               }
+#ifdef MAC
+               menus_off();    /* Block menu choices during input */
+#endif
+               /* gather the cmd name */
+               while (((c = getch()) != EOF) && !strchr(" \t\r\n", c)) {
+                       if (jisupper(c))
+                               c = jtolower(c);
+                       *cp++ = c;
+               }
+               if (c == EOF)
+                       return NULL;
+               *cp = '\0';
+               cmdlen = cp - cmdbuf;
+               if (cmdlen == 0)
+                       return NULL;
+
+               /* look it up (in the reduced search space) */
+               if (jislower(cmdbuf[0])
+               && (cmd = cmdhash[hash(cmdbuf[0])]) != NULL) {
+                   for (; cmd->Name != NULL && cmd->Name[0] == cmdbuf[0]; cmd++) {
+                       if (strncmp(cmd->Name, cmdbuf, cmdlen) == 0) {
+                               if (cmd->Name[cmdlen] == '\0')
+                                       return (data_obj *) cmd;
+                               if (found)
+                                       complain("[\"%s\" ambiguous]", cmdbuf);
+                               found = TRUE;
+                               which = cmd;
+                       }
+                   }
+               }
+               if (!found)
+                       complain("[\"%s\" unknown]", cmdbuf);
+               return (data_obj *) which;
+       } else {
+               static char     *strings[(sizeof commands) / sizeof (commands[0])];
+               static bool     beenhere = NO;
+               register int    com;
+
+               if (!beenhere) {
+                       register char   **strs = strings;
+                       register const struct cmd       *c = commands;
+
+                       do ; while ((*strs++ = (*c++).Name) != NULL);
+                       beenhere = YES;
+               }
+
+               if ((com = complete(strings, prompt, CASEIND)) < 0)
+                       return NULL;
+               return (data_obj *) &commands[com];
+       }
+#undef hash
+}
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/getch.c b/usr/src/contrib/jove-4.14.6/getch.c
new file mode 100644 (file)
index 0000000..8f7adf3
--- /dev/null
@@ -0,0 +1,136 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "tune.h"
+
+#ifdef MSDOS
+
+#include <bios.h>
+#include <dos.h>
+
+#include "jove.h"
+#include "disp.h"
+
+private void waitfun proto((void));
+
+#ifdef IBMPC
+private char last = '\0';
+extern int specialkey;
+#endif
+
+int
+getrawinchar()
+{
+#ifdef IBMPC
+       unsigned scan;
+
+       if (specialkey = last) {
+               scan = last;
+               last = '\0';
+               return scan;
+       }
+
+       while (!rawkey_ready())
+               waitfun();
+
+       scan = _bios_keybrd(_KEYBRD_READ);
+       if ((scan&0xff) == 0) {
+               last = (char) (scan >> 8);
+               return 0xff;
+       }
+       return scan&0xff;
+
+#else  /* !IBMPC */
+#ifdef RAINBOW
+
+       union REGS regs;
+
+       while (!rawkey_ready())
+               waitfun();
+
+       for (;;) {
+               regs.x.di = 2;
+               int86(0x18, &regs, &regs);
+               if (regs.h.al != 0)     /* should never happen, but who knows */
+                       return regs.h.al;
+       }
+#else  /* !RAINBOW */
+
+       while (!rawkey_ready())
+               waitfun();
+       return bdos(0x06, 0x00ff, 0xff) & 0xff;
+#endif /* !RAINBOW */
+#endif /* !IBMPC */
+}
+
+private bool waiting = NO;
+
+bool
+rawkey_ready()
+{
+#ifdef IBMPC
+       if (waiting)
+               return NO;
+       if (last)
+               return YES;
+
+       return _bios_keybrd(_KEYBRD_READY) != 0;
+#else  /* !IBMPC */
+       union REGS regs;
+
+       if (waiting)
+               return NO;
+#ifdef RAINBOW
+       regs.x.di = 4;
+       int86(0x18, &regs, &regs);
+       return regs.h.cl != 0;
+#else  /* !RAINBOW */
+       regs.h.ah = 0x44;               /* ioctl call */
+       regs.x.bx = 0;                  /* stdin file handle */
+       regs.h.al = 0x06;               /* get input status */
+       intdos(&regs, &regs);
+       return regs.h.al & 1;
+#endif /* !RAINBOW */
+#endif /* !IBMPC */
+}
+
+#ifdef IBMPC
+private long timecount, lastcount = 0;
+#else
+private char lastmin = 0;
+#endif
+
+
+private void
+waitfun()
+{
+       if (UpdModLine) {
+               waiting = YES;
+               redisplay();
+               waiting = NO;
+               return;
+       }
+#ifdef IBMPC
+       if (_bios_timeofday(_TIME_GETCLOCK, &timecount) ||  /* after midnight */
+           (timecount > lastcount + 0x444) ) {
+               lastcount = timecount;
+               UpdModLine = YES;
+       }
+#else
+       {
+               struct dostime_t tc;
+
+               _dos_gettime(&tc);
+               if (tc.minute != lastmin) {
+                       UpdModLine = YES;
+                       lastmin = tc.minute;
+               }
+       }
+#endif
+}
+
+#endif /* MSDOS */
diff --git a/usr/src/contrib/jove-4.14.6/insert.c b/usr/src/contrib/jove-4.14.6/insert.c
new file mode 100644 (file)
index 0000000..91d4a4d
--- /dev/null
@@ -0,0 +1,823 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+#include "list.h"
+#include "chars.h"
+#include "disp.h"
+
+private void
+       DoNewline proto((bool indentp));
+
+private Bufpos
+       *lisp_indent proto((void));
+
+/* Make a new line after "after" in buffer "buf", unless "after" is NULL,
+   in which case we insert the new line before first line. */
+
+Line *
+listput(buf, after)
+register Buffer        *buf;
+register Line  *after;
+{
+       register Line   *newline = nbufline();
+
+       newline->l_prev = after;
+       if (after == NULL) {    /* Before the first line */
+               newline->l_next = buf->b_first;
+               buf->b_first = newline;
+       } else {
+               newline->l_next = after->l_next;
+               after->l_next = newline;
+       }
+       if (newline->l_next != NULL)
+               newline->l_next->l_prev = newline;
+       else if (buf != NULL)
+               buf->b_last = newline;
+       if (buf && buf->b_dot == NULL)
+               buf->b_dot = newline;
+       return newline;
+}
+
+/* Divide the current line and move the current line to the next one */
+
+void
+LineInsert(num)
+register int   num;
+{
+       char    newline[LBSIZE];
+       register Line   *newdot,
+                       *olddot;
+       int     oldchar;
+
+       olddot = curline;
+       oldchar = curchar;
+
+       newdot = curline;
+       while (--num >= 0) {
+               newdot = listput(curbuf, newdot);
+               SavLine(newdot, NullStr);
+       }
+
+       modify();
+       if (curchar != 0) {
+               strcpy(newline, &linebuf[curchar]);
+               linebuf[curchar] = '\0';        /* Shorten this line */
+               SavLine(curline, linebuf);
+               strcpy(linebuf, newline);
+       } else {        /* Redisplay optimization */
+               newdot->l_dline = curline->l_dline;
+               SavLine(curline, NullStr);
+       }
+
+       makedirty(curline);
+       curline = newdot;
+       curchar = 0;
+       makedirty(curline);
+       IFixMarks(olddot, oldchar, curline, curchar);
+}
+
+/* Inserts tabs and spaces to move the cursor to column GOAL.  It
+   Uses the most optimal number of tabs and spaces no matter what
+   was there before hand. */
+
+void
+n_indent(goal)
+register int   goal;
+{
+       int     dotcol,
+               incrmt;
+
+       DelWtSpace();
+       dotcol = calc_pos(linebuf, curchar);
+
+       for (;;) {
+               incrmt = (tabstop - (dotcol % tabstop));
+               if (dotcol + incrmt > goal)
+                       break;
+               insert_c('\t', 1);
+               dotcol += incrmt;
+       }
+       if (dotcol != goal)
+               insert_c(' ', (goal - dotcol));
+}
+
+#ifdef ABBREV
+void
+MaybeAbbrevExpand()
+{
+       if (MinorMode(Abbrev) && !ismword(LastKeyStruck) &&
+           !bolp() && ismword(linebuf[curchar - 1]))
+               AbbrevExpand();
+}
+#endif
+
+private void
+Insert(c)
+int    c;
+{
+       if (c == CTL('J'))
+               LineInsert(arg_value());
+       else
+               insert_c(c, arg_value());
+}
+
+void
+SelfInsert()
+{
+#ifdef ABBREV
+       MaybeAbbrevExpand();
+#endif
+       if (LastKeyStruck != CTL('J') && MinorMode(OverWrite)) {
+               register int    num,
+                               i;
+
+               for (i = 0, num = arg_value(); i < num; i++) {
+                       int     pos = calc_pos(linebuf, curchar);
+
+                       if (!eolp()) {
+                               if (linebuf[curchar] == '\t') {
+                                       if ((pos + 1) == ((pos + tabstop) - (pos % tabstop)))
+                                               del_char(FORWARD, 1, NO);
+                               } else
+                                       del_char(FORWARD, 1, NO);
+                       }
+                       insert_c(LastKeyStruck, 1);
+               }
+       } else
+               Insert(LastKeyStruck);
+
+       if (MinorMode(Fill) && (curchar >= RMargin ||
+                              (calc_pos(linebuf, curchar) >= RMargin))) {
+               int margin;
+               Bufpos save;
+
+               if (MinorMode(Indent)) {
+                       DOTsave(&save);
+                       ToIndent();
+                       margin = calc_pos(linebuf, curchar);
+                       SetDot(&save);
+               } else
+                       margin = LMargin;
+               DoJustify(curline, 0, curline,
+                         curchar + (int)strlen(&linebuf[curchar]), YES, margin);
+       }
+}
+
+/* insert character C N times at point */
+void
+insert_c(c, n)
+int    c,
+       n;
+{
+       if (n <= 0)
+               return;
+       modify();
+       makedirty(curline);
+       ins_c(c, linebuf, curchar, n, LBSIZE);
+       IFixMarks(curline, curchar, curline, curchar + n);
+       curchar += n;
+}
+
+/* Tab in to the right place for C mode */
+
+void
+Tab()
+{
+#ifdef LISP
+       if (MajorMode(LISPMODE) && (bolp() || !eolp())) {
+               int     dotchar = curchar;
+               Mark    *m = NULL;
+
+               ToIndent();
+               if (dotchar > curchar)
+                       m = MakeMark(curline, dotchar, M_FLOATER);
+               (void) lisp_indent();
+               if (m) {
+                       ToMark(m);
+                       DelMark(m);
+               } else
+                       ToIndent();
+               return;
+       }
+#endif
+       if (MajorMode(CMODE)) {
+               if (within_indent())
+                       (void) c_indent(NO);
+               else {
+                       int     curpos,
+                               tabbed_pos;
+
+                       skip_wht_space();
+                       curpos = calc_pos(linebuf, curchar);
+                       tabbed_pos = curpos + (CIndIncrmt - (curpos % CIndIncrmt));
+                       n_indent(tabbed_pos);
+               }
+       } else
+               SelfInsert();
+}
+
+void
+QuotChar()
+{
+       int     c,
+               slow = NO;
+
+       c = waitchar(&slow);
+       if (c != CTL('@'))
+               Insert(c);
+}
+
+/* Insert the paren.  If in C mode and c is a '}' then insert the
+   '}' in the "right" place for C indentation; that is indented
+   the same amount as the matching '{' is indented. */
+
+int    PDelay = 5,     /* 1/2 a second */
+       CIndIncrmt = 8;
+
+void
+DoParen()
+{
+       Bufpos  *bp;
+       int     tried = NO,
+               nx,
+               c = LastKeyStruck;
+
+       if (!jisclosep(c)) {
+               SelfInsert();
+               return;
+       }
+
+       if (MajorMode(CMODE) && c == '}' && within_indent()) {
+               bp = c_indent(YES);
+               tried = TRUE;
+       }
+#ifdef LISP
+       if (MajorMode(LISPMODE) && c == ')' && blnkp(linebuf)) {
+               bp = lisp_indent();
+               tried = TRUE;
+       }
+#endif
+       SelfInsert();
+#ifdef MAC
+       if (MinorMode(ShowMatch) && !in_macro()) {
+#else
+       if (MinorMode(ShowMatch) && !charp() && !in_macro()) {
+#endif
+               b_char(1);      /* Back onto the ')' */
+               if (!tried)
+                       bp = m_paren(c, BACKWARD, NO, YES);
+               f_char(1);
+               if (bp != NULL) {
+                       nx = in_window(curwind, bp->p_line);
+                       if (nx != -1) {         /* is visible */
+                               Bufpos  b;
+
+                               DOTsave(&b);
+                               SetDot(bp);
+                               SitFor(PDelay);
+                               SetDot(&b);
+                       } else
+                               s_mess("%s", lcontents(bp->p_line));
+               }
+               mp_error();     /* display error message */
+       }
+}
+
+void
+LineAI()
+{
+       DoNewline(TRUE);
+}
+
+void
+Newline()
+{
+       DoNewline(MinorMode(Indent));
+}
+
+private void
+DoNewline(indentp)
+bool   indentp;
+{
+       Bufpos  save;
+       int     indent;
+
+       /* first we calculate the indent of the current line */
+       DOTsave(&save);
+       ToIndent();
+       indent = calc_pos(linebuf, curchar);
+       SetDot(&save);
+
+#ifdef ABBREV
+       MaybeAbbrevExpand();
+#endif
+       if (
+#ifdef LISP
+           MajorMode(LISPMODE) ||
+#endif
+           indentp || blnkp(linebuf))
+       {
+               DelWtSpace();
+       }
+
+       /* If there is more than 2 blank lines in a row then don't make
+          a newline, just move down one. */
+       if (arg_value() == 1 && eolp() && TwoBlank())
+               SetLine(curline->l_next);
+       else
+               LineInsert(arg_value());
+
+       if (indentp) {
+#ifdef LISP
+           if (MajorMode(LISPMODE))
+               (void) lisp_indent();
+           else
+#endif
+           {
+               Bol();
+               n_indent((LMargin == 0) ? indent : LMargin);
+           }
+       }
+}
+
+void
+ins_str(str, ok_nl)
+register char  *str;
+int    ok_nl;
+{
+       register char   c;
+       Bufpos  save;
+       int     llen;
+
+       if (*str == '\0')
+               return;         /* ain't nothing to insert! */
+       DOTsave(&save);
+       llen = strlen(linebuf);
+       while ((c = *str++) != '\0') {
+               if (c == '\n' || (ok_nl && llen >= LBSIZE - 2)) {
+                       IFixMarks(save.p_line, save.p_char, curline, curchar);
+                       modify();
+                       makedirty(curline);
+                       LineInsert(1);
+                       DOTsave(&save);
+                       llen = strlen(linebuf);
+               }
+               if (c != '\n') {
+                       ins_c(c, linebuf, curchar++, 1, LBSIZE);
+                       llen += 1;
+               }
+       }
+       IFixMarks(save.p_line, save.p_char, curline, curchar);
+       modify();
+       makedirty(curline);
+}
+
+void
+open_lines(n)
+int    n;
+{
+       Bufpos  dot;
+
+       DOTsave(&dot);
+       LineInsert(n);  /* Open the lines... */
+       SetDot(&dot);
+}
+
+void
+OpenLine()
+{
+       open_lines(arg_value());
+}
+
+/* Take the region FLINE/FCHAR to TLINE/TCHAR and insert it at
+   ATLINE/ATCHAR in WHATBUF. */
+
+Bufpos *
+DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf)
+Line   *fline,
+       *tline,
+       *atline;
+int    fchar,
+       tchar,
+       atchar;
+Buffer *whatbuf;
+{
+       register Line   *newline;
+       static Bufpos   bp;
+       char    save[LBSIZE],
+               buf[LBSIZE];
+       Line    *startline = atline;
+       int     startchar = atchar;
+
+       lsave();
+       if (whatbuf)
+               modify();
+       (void) ltobuf(atline, genbuf);
+       strcpy(save, &genbuf[atchar]);
+
+       (void) ltobuf(fline, buf);
+       if (fline == tline)
+               buf[tchar] = '\0';
+
+       linecopy(genbuf, atchar, &buf[fchar]);
+       atline->l_dline = putline(genbuf);
+       makedirty(atline);
+
+       fline = fline->l_next;
+       while (fline != tline->l_next) {
+               newline = listput(whatbuf, atline);
+               newline->l_dline = fline->l_dline;
+               makedirty(newline);
+               fline = fline->l_next;
+               atline = newline;
+               atchar = 0;
+       }
+
+       getline(atline->l_dline, genbuf);
+       atchar += tchar;
+       linecopy(genbuf, atchar, save);
+       atline->l_dline = putline(genbuf);
+       makedirty(atline);
+       IFixMarks(startline, startchar, atline, atchar);
+       bp.p_line = atline;
+       bp.p_char = atchar;
+       this_cmd = YANKCMD;
+       getDOT();                       /* Whatever used to be in linebuf */
+       return &bp;
+}
+
+void
+YankPop()
+{
+       Line    *line,
+               *last;
+       Mark    *mp = CurMark();
+       Bufpos  *dot;
+       int     dir = -1;       /* Direction to rotate the ring */
+
+       if (last_cmd != YANKCMD)
+               complain("Yank something first!");
+
+       lfreelist(reg_delete(mp->m_line, mp->m_char, curline, curchar));
+
+       /* Now must find a recently killed region. */
+
+       if (arg_value() < 0)
+               dir = 1;
+
+       killptr += dir;
+       for (;;) {
+               if (killptr < 0)
+                       killptr = NUMKILLS - 1;
+               else if (killptr >= NUMKILLS)
+                       killptr = 0;
+               if (killbuf[killptr])
+                       break;
+               killptr += dir;
+       }
+
+       this_cmd = YANKCMD;
+
+       line = killbuf[killptr];
+       last = lastline(line);
+       dot = DoYank(line, 0, last, length(last), curline, curchar, curbuf);
+       MarkSet(CurMark(), curline, curchar);
+       SetDot(dot);
+}
+
+/* This is an attempt to reduce the amount of memory taken up by each line.
+   Without this each malloc of a line uses sizeof (line) + sizeof(HEADER)
+   where line is 3 words and HEADER is 1 word.
+   This is going to allocate memory in chucks of CHUNKSIZE * sizeof (line)
+   and divide each chuck into Lines.  A line is free in a chunk when its
+   line->l_dline == NULL_DADDR, so freeline sets l_dline to NULL_DADDR. */
+
+#define CHUNKSIZE      300
+
+struct chunk {
+       struct chunk    *c_nextchunk;   /* Next chunk of lines */
+       int     c_nlines;       /* Number of lines in this chunk (so they
+                                  don't all have to be CHUNKSIZE long). */
+       Line    c_block[1 /* or larger */];     /* Chunk of memory */
+};
+
+private struct chunk   *fchunk = NULL; /* first chunk */
+private Line   *ffline = NULL; /* First free line */
+private Line   *faline = NULL; /* First available line */
+
+private void
+freeline(line)
+register Line  *line;
+{
+       line->l_dline = NULL_DADDR;
+       line->l_next = ffline;
+       if (ffline)
+               ffline->l_prev = line;
+       line->l_prev = NULL;
+       ffline = line;
+}
+
+/* Make sure that there are no dangling references to lines in the free list,
+ * then move them to the end of the avail list.
+ */
+
+private void
+RecycleLines()
+{
+       if (ffline == NULL)
+               return; /* nothing to do */
+
+       ChkErrorLines();
+       /* ChkWindowLines(); -- nothing needs attention */
+       /* ChkBufLines(); -- nothing needs attention */
+
+       if (faline == NULL) {
+               faline = ffline;
+       } else {
+               Line    *laline = lastline(faline);
+
+               laline->l_next = ffline;
+               ffline->l_prev = laline;
+       }
+       ffline = NULL;
+}
+
+void
+lfreelist(first)
+register Line  *first;
+{
+       if (first != NULL)
+               lfreereg(first, lastline(first));
+}
+
+/* Append region from line1 to line2 onto the free list of lines */
+
+void
+lfreereg(line1, line2)
+register Line  *line1,
+               *line2;
+{
+       register Line   *next,
+                       *last = line2->l_next;
+
+       while (line1 != last) {
+               next = line1->l_next;
+               freeline(line1);
+               line1 = next;
+       }
+}
+
+private bool
+newchunk()
+{
+       register Line   *newline;
+       register int    i;
+       struct chunk    *f;
+       int     nlines = CHUNKSIZE;
+       bool    done_gc = NO;
+
+       for (;;) {
+               f = (struct chunk *) malloc(
+                       (sizeof(struct chunk) - sizeof(Line))
+                       + (sizeof(Line) * nlines));
+               if (f != NULL)
+                       break;
+               if (!done_gc) {
+                       GCchunks();
+                       done_gc = YES;
+               } else {
+                       nlines /= 2;
+                       if (nlines <= 0)
+                               return NO;
+               }
+       }
+
+       f->c_nlines = nlines;
+       for (i = 0, newline = f->c_block; i < nlines; newline++, i++) {
+               newline->l_dline = NULL_DADDR;
+               newline->l_next = faline;
+               if (faline)
+                       faline->l_prev = newline;
+               newline->l_prev = NULL;
+               faline = newline;
+       }
+       f->c_nextchunk = fchunk;
+       fchunk = f;
+       return YES;
+}
+
+/* New BUFfer LINE */
+
+Line *
+nbufline()
+{
+       register Line   *newline;
+
+       if (faline == NULL) {
+               RecycleLines();
+               if (faline == NULL) {
+                       if (!newchunk())
+                               complain("[Out of lines] ");
+               }
+       }
+       newline = faline;
+       faline = newline->l_next;
+       if (faline)
+               faline->l_prev = NULL;
+       return newline;
+}
+
+/* Remove the free lines, in chunk c, from the free list because they are
+   no longer free. */
+
+private void
+remfreelines(c)
+register struct chunk  *c;
+{
+       register Line   *lp;
+       register int    i;
+
+       for (lp = c->c_block, i = c->c_nlines; i != 0 ; lp++, i--) {
+               if (lp->l_prev == NULL)
+                       faline = lp->l_next;
+               else
+                       lp->l_prev->l_next = lp->l_next;
+               if (lp->l_next != NULL)
+                       lp->l_next->l_prev = lp->l_prev;
+       }
+}
+
+/* This is used to garbage collect the chunks of lines when malloc fails
+   and we are NOT looking for a new buffer line.  This goes through each
+   chunk, and if every line in a given chunk is not allocated, the entire
+   chunk is `free'd by "free()". */
+
+/* ??? I think that this WILL be called when we are looking for a new
+ * buffer line: nbufline() => newchunk() => GCchunks() -- DHR
+ */
+
+void
+GCchunks()
+{
+       register struct chunk   *cp;
+       struct chunk    *prev = NULL,
+                       *next;
+       register int    i;
+       register Line   *newline;
+
+       RecycleLines();
+       for (cp = fchunk; cp != NULL; cp = next) {
+               next = cp->c_nextchunk;
+               for (i = cp->c_nlines, newline = cp->c_block; ; newline++, i--) {
+                       if (i == 0) {
+                               /* Empty: unlink and free it!!! */
+                               if (prev == NULL)
+                                       fchunk = cp->c_nextchunk;
+                               else
+                                       prev->c_nextchunk = cp->c_nextchunk;
+                               remfreelines(cp);
+                               free((UnivPtr) cp);
+                               break;
+                       }
+                       if (newline->l_dline != NULL_DADDR) {
+                               /* it's a keeper */
+                               prev = cp;
+                               break;
+                       }
+               }
+       }
+}
+
+#ifdef LISP
+
+#include "re.h"
+
+/* Grind S-Expr */
+
+void
+GSexpr()
+{
+       Bufpos  dot,
+               end;
+
+       if (linebuf[curchar] != '(')
+               complain((char *)NULL);
+       DOTsave(&dot);
+       FSexpr();
+       DOTsave(&end);
+       SetDot(&dot);
+       for (;;) {
+               if (curline == end.p_line)
+                       break;
+               line_move(FORWARD, 1, NO);
+               if (!blnkp(linebuf))
+                       (void) lisp_indent();
+       }
+       SetDot(&dot);
+}
+
+/* lisp_indent() indents a new line in Lisp Mode, according to where
+   the matching close-paren would go if we typed that (sort of). */
+
+private List   *specials = NULL;
+
+private void
+init_specials()
+{
+       static char *const words[] = {
+               "case",
+               "def",
+               "dolist",
+               "fluid-let",
+               "lambda",
+               "let",
+               "lexpr",
+               "macro",
+               "named-l",      /* named-let and named-lambda */
+               "nlambda",
+               "prog",
+               "selectq",
+               NULL
+       };
+       char    *const *wordp = words;
+
+       while (*wordp != NULL)
+               list_push(&specials, (UnivPtr) *wordp++);
+}
+
+void
+AddSpecial()
+{
+       char    *word;
+       register List   *lp;
+
+       if (specials == NULL)
+               init_specials();
+       word = ask((char *)NULL, ProcFmt);
+       for (lp = specials; lp != NULL; lp = list_next(lp))
+               if (strcmp((char *) list_data(lp), word) == 0)
+                       return;         /* already in list */
+       (void) list_push(&specials, (UnivPtr) copystr(word));
+}
+
+private Bufpos *
+lisp_indent()
+{
+       Bufpos  *bp,
+               savedot;
+       int     goal;
+
+       bp = m_paren(')', BACKWARD, NO, YES);
+
+       if (bp == NULL)
+               return NULL;
+
+       /* We want to end up
+
+               (atom atom atom ...
+                     ^ here.
+        */
+
+       DOTsave(&savedot);
+       SetDot(bp);
+       f_char(1);
+       if (linebuf[curchar] != '(') {
+               register List   *lp;
+
+               if (specials == NULL)
+                       init_specials();
+               for (lp = specials; lp != NULL; lp = list_next(lp))
+                       if (casencmp((char *) list_data(lp),
+                                    &linebuf[curchar],
+                                    strlen((char *) list_data(lp))) == 0)
+                               break;
+               if (lp == NULL) {       /* not special */
+                       int     c_char = curchar;
+
+                       WITH_TABLE(curbuf->b_major)
+                               f_word(1);
+                       END_TABLE();
+                       if (LookingAt("[ \t]*;\\|[ \t]*$", linebuf, curchar)) {
+                               curchar = c_char;
+                       } else {
+                               while (linebuf[curchar] == ' ')
+                                       curchar += 1;
+                       }
+               } else {
+                       curchar += 1;
+               }
+       }
+       goal = calc_pos(linebuf, curchar);
+       SetDot(&savedot);
+       Bol();
+       n_indent(goal);
+
+       return bp;
+}
+#endif /* LISP */
diff --git a/usr/src/contrib/jove-4.14.6/io.c b/usr/src/contrib/jove-4.14.6/io.c
new file mode 100644 (file)
index 0000000..b711673
--- /dev/null
@@ -0,0 +1,1461 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "list.h"
+#include "fp.h"
+#include "termcap.h"
+#include "ctype.h"
+#include "disp.h"
+#include "scandir.h"
+
+
+#ifdef IPROCS
+# include <signal.h>
+#endif
+
+#ifdef MAC
+# include "mac.h"
+#else
+# include <sys/stat.h>
+#endif
+
+#ifdef UNIX
+# include <sys/file.h>
+#endif
+
+#ifdef MSDOS
+# include <fcntl.h>
+# include <io.h>
+# include <direct.h>
+# include <dos.h>
+#endif /* MSDOS */
+
+#include <errno.h>
+
+private struct block
+       *lookup proto((int /* promoted short */));
+
+private char
+#ifdef MSDOS
+       *fixpath proto((char *)),
+#endif
+       *getblock proto((daddr, bool));
+
+private bool
+       f_getputl proto((struct line *line,struct FileStruct *fp));
+
+private void
+#ifdef MSDOS
+       abspath proto((char *, char *)),
+#endif
+       file_backup proto((char *fname));
+
+#ifdef MSDOS
+private int
+       Dchdir proto((char *));
+#endif
+
+long   io_chars;               /* number of chars in this open_file */
+int    io_lines;               /* number of lines in this open_file */
+
+#ifdef pdp11
+char   *iobuff,
+       *genbuf,
+       *linebuf;
+#else
+char   iobuff[LBSIZE],
+       genbuf[LBSIZE],
+       linebuf[LBSIZE];
+#endif
+
+#ifdef BACKUPFILES
+bool   BkupOnWrite = OFF;
+#endif
+
+#ifndef        MSDOS
+
+#define        Dchdir(to)  chdir(to)
+
+#else  /* MSDOS */
+
+private int                    /* chdir + drive */
+Dchdir(to)
+char *to;
+{
+       unsigned d, dd, n;
+
+       if (to[1] == ':') {
+               d = CharUpcase(to[0]) - 'A';
+               /* ??? only 16 drives? */
+               if (d >= 16)
+                       complain("invalid drive");
+               _dos_getdrive(&dd);
+               if (dd != d)
+                       _dos_setdrive(d, &n);
+               if (to[2] == '\0') {
+                       /* ??? Is this correct? DHR
+                        * Current path on this drive might not be the root.
+                        */
+                       return 0;
+               }
+       }
+       return chdir(to);
+}
+
+private char *
+fixpath(p)
+char *p;
+{
+       char *pp = p;
+
+       while (*p) {
+               if (*p == '\\')
+                       *p = '/';
+               p++;
+       }
+       return strlwr(pp);
+}
+
+
+private void
+abspath(so, dest)
+char *so, *dest;
+{
+       char cwd[FILESIZE], cwdD[3], cwdDIR[FILESIZE], cwdF[9], cwdEXT[5],
+            soD[3], soDIR[FILESIZE], soF[9], soEXT[5];
+       char *drive, *path;
+
+       _splitpath(fixpath(so), soD, soDIR, soF, soEXT);
+       getcwd(cwd, FILESIZE);
+       if (*soD != '\0') {
+               Dchdir(soD);                            /* this is kinda messy  */
+               getcwd(cwdDIR, FILESIZE);       /* should probably just */
+               Dchdir(cwd);                            /* call DOS to do it    */
+               strcpy(cwd, cwdDIR);
+       }
+       (void) fixpath(cwd);
+       if (cwd[strlen(cwd)-1] != '/')
+               strcat(cwd, "/x.x");    /* need dummy filename */
+
+       _splitpath(fixpath(cwd), cwdD, cwdDIR, cwdF, cwdEXT);
+
+       drive = (*soD == '\0') ? cwdD : soD;
+
+       if (*soDIR != '/')
+               path = strcat(cwdDIR, soDIR);
+       else
+               path = soDIR;
+       _makepath(dest, drive, path, soF, soEXT);
+       fixpath(dest);  /* can't do it often enough */
+}
+
+#endif /* MSDOS */
+
+
+void
+close_file(fp)
+File   *fp;
+{
+       if (fp) {
+               if (fp->f_flags & F_TELLALL)
+                       add_mess(" %d lines, %D characters.",
+                                io_lines,
+                                io_chars);
+               f_close(fp);
+       }
+}
+
+/* Write the region from line1/char1 to line2/char2 to FP.  This
+   never CLOSES the file since we don't know if we want to. */
+
+bool   EndWNewline = 1;
+
+void
+putreg(fp, line1, char1, line2, char2, makesure)
+register File  *fp;
+Line   *line1,
+       *line2;
+int    char1,
+       char2;
+bool   makesure;
+{
+       register int    c;
+       register char   *lp;
+
+       if (makesure)
+               (void) fixorder(&line1, &char1, &line2, &char2);
+       while (line1 != line2->l_next) {
+               lp = lcontents(line1) + char1;
+               if (line1 == line2) {
+                       fputnchar(lp, (char2 - char1), fp);
+                       io_chars += (char2 - char1);
+               } else {
+                       while ((c = *lp++) != '\0') {
+                               jputc(c, fp);
+                               io_chars += 1;
+                       }
+               }
+               if (line1 != line2) {
+                       io_lines += 1;
+                       io_chars += 1;
+#ifdef MSDOS
+                       jputc('\r', fp);
+#endif /* MSDOS */
+                       jputc('\n', fp);
+               }
+               line1 = line1->l_next;
+               char1 = 0;
+       }
+       flushout(fp);
+}
+
+private void
+dofread(fp)
+register File  *fp;
+{
+       char    end[LBSIZE];
+       bool    xeof;
+       Line    *savel = curline;
+       int     savec = curchar;
+
+       strcpy(end, linebuf + curchar);
+       xeof = f_gets(fp, linebuf + curchar, (size_t) (LBSIZE - curchar));
+       SavLine(curline, linebuf);
+       while(!xeof) {
+               curline = listput(curbuf, curline);
+               xeof = f_getputl(curline, fp);
+       }
+       getDOT();
+       linecopy(linebuf, (curchar = strlen(linebuf)), end);
+       SavLine(curline, linebuf);
+       IFixMarks(savel, savec, curline, curchar);
+}
+
+void
+read_file(file, is_insert)
+char   *file;
+bool   is_insert;
+{
+       Bufpos  save;
+       File    *fp;
+       int     rdonly;
+
+       if (!is_insert)
+               curbuf->b_ntbf = NO;
+       fp = open_file(file, iobuff, F_READ, NO, NO);
+       if (fp == NULL) {
+               if (!is_insert && errno == ENOENT)
+                       s_mess("(new file)");
+               else
+                       s_mess(IOerr("open", file));
+               return;
+       }
+       rdonly = (fp->f_flags & F_READONLY)? 1 : 0;
+       DOTsave(&save);
+       dofread(fp);
+       if (is_insert && io_chars > 0) {
+               modify();
+               set_mark();
+       }
+       SetDot(&save);
+       getDOT();
+       close_file(fp);
+       /* just guessing that if this is moved here */
+       /* then the bug on SunOS that seems to alter */
+       /* mtime under our feet will disappear */
+       if (!is_insert) {
+               set_ino(curbuf);
+               set_arg_value(rdonly);
+               TogMinor(ReadOnly);
+       }
+}
+
+void
+SaveFile()
+{
+       if (IsModified(curbuf)) {
+               if (curbuf->b_fname == NULL)
+                       WriteFile();
+               else {
+                       filemunge(curbuf->b_fname);
+                       chk_mtime(curbuf, curbuf->b_fname, "save");
+                       file_write(curbuf->b_fname, NO);
+               }
+       } else
+               message("No changes need to be written.");
+}
+
+char   *HomeDir;       /* home directory */
+size_t HomeLen;        /* length of home directory string */
+
+private List           *DirStack = NULL;
+#define dir_name(dp)   ((char *) list_data((dp)))
+#define PWD_PTR                (list_data(DirStack))
+#define PWD            ((char *) PWD_PTR)
+
+char *
+pwd()
+{
+       return (char *) PWD_PTR;
+}
+
+char *
+pr_name(fname, okay_home)
+char   *fname;
+int    okay_home;
+{
+       int     n;
+
+       if (fname != NULL) {
+               n = numcomp(fname, PWD);
+
+               if ((PWD[n] == '\0') && /* Matched to end of PWD */
+                   (fname[n] == '/'))
+                       return fname + n + 1;
+
+               if (okay_home && strcmp(HomeDir, "/") != 0
+               && strncmp(fname, HomeDir, HomeLen) == 0
+               && fname[HomeLen] == '/')
+               {
+                       static char     name_buf[100];
+
+                       swritef(name_buf, sizeof(name_buf),
+                               "~%s", fname + HomeLen);
+                       return name_buf;
+               }
+       }
+       return fname;
+}
+
+void
+Chdir()
+{
+       char    dirbuf[FILESIZE];
+
+#ifdef MSDOS
+       fmask = 0x10;
+#endif
+       (void) ask_file((char *)NULL, PWD, dirbuf);
+#ifdef MSDOS
+       fmask = 0x13;
+#endif
+       if (Dchdir(dirbuf) == -1)
+       {
+               s_mess("cd: cannot change into %s.", dirbuf);
+               return;
+       }
+       UpdModLine = YES;
+       setCWD(dirbuf);
+       prCWD();
+#ifdef MAC
+       Bufchange = YES;
+#endif
+}
+
+#ifdef UNIX
+
+#  ifndef      BSD4_2
+char *
+getwd(buffer)
+char   *buffer;
+{
+       Buffer  *old = curbuf;
+       char    *ret_val;
+
+       SetBuf(do_select((Window *)NULL, "pwd-output"));
+       curbuf->b_type = B_PROCESS;
+       (void) UnixToBuf("pwd-output", (char *)NULL, NO, 0, YES,
+               "/bin/pwd", (char *) NULL);
+       ToFirst();
+       strcpy(buffer, linebuf);
+       SetBuf(old);
+       return buffer;
+}
+#  endif       /* not BSD4_2 */
+
+/* Check if dn is the name of the current working directory
+   and that it is in cannonical form */
+
+bool
+chkCWD(dn)
+char   *dn;
+{
+       char    filebuf[FILESIZE];
+       struct stat     dnstat,
+                       dotstat;
+
+       if (dn[0] != '/')
+               return FALSE;           /* need absolute pathname */
+       PathParse(dn, filebuf);
+       return stat(filebuf, &dnstat) == 0 &&
+              stat(".", &dotstat) == 0 &&
+              dnstat.st_dev == dotstat.st_dev &&
+              dnstat.st_ino == dotstat.st_ino;
+}
+
+#endif /* UNIX */
+
+void
+setCWD(d)
+char   *d;
+{
+       if (DirStack == NULL)
+               list_push(&DirStack, (UnivPtr)NULL);
+       PWD_PTR = (PWD == NULL)
+               ? (UnivPtr) emalloc((size_t) (strlen(d) + 1))
+               : (UnivPtr) freealloc((UnivPtr) PWD, strlen(d) + 1);
+       strcpy(PWD, d);
+}
+
+void
+getCWD()
+{
+       char    *cwd;
+       char    pathname[FILESIZE];
+
+#ifndef        MSDOS
+       cwd = getenv("CWD");
+       if (cwd == NULL || !chkCWD(cwd)) {
+               cwd = getenv("PWD");
+               if (cwd == NULL || !chkCWD(cwd)) {
+#ifdef HAVE_GETWD
+                       cwd = getwd(pathname);
+#else
+                       /* System Vr4, and who else? */
+                       extern char     *getcwd proto((char *, int/*!!!*/));
+
+                       cwd = getcwd(pathname, (int) sizeof(pathname));
+#endif /* HAVE_GETWD */
+               }
+       }
+#else  /* MSDOS */
+       {
+           extern char *getcwd();
+
+           cwd = fixpath(getcwd(pathname, FILESIZE));
+       }
+#endif /* MSDOS */
+       setCWD(cwd);
+}
+
+void
+prDIRS()
+{
+       register List   *lp;
+
+       s_mess(": %f ");
+       for (lp = DirStack; lp != NULL; lp = list_next(lp))
+               add_mess("%s ", pr_name(dir_name(lp), YES));
+}
+
+void
+prCWD()
+{
+       s_mess(": %f => \"%s\"", PWD);
+}
+
+void
+Pushd()
+{
+       char    *newdir,
+               dirbuf[FILESIZE];
+
+#ifdef MSDOS
+       fmask = 0x10;
+#endif
+       newdir = ask_file((char *)NULL, NullStr, dirbuf);
+#ifdef MSDOS
+       fmask = 0x13;
+#endif
+       UpdModLine = YES;
+       if (*newdir == '\0') {  /* Wants to swap top two entries */
+               char    *old_top;
+
+               if (list_next(DirStack) == NULL)
+                       complain("pushd: no other directory.");
+               old_top = PWD;
+               list_data(DirStack) = (UnivPtr) dir_name(list_next(DirStack));
+               list_data(list_next(DirStack)) = (UnivPtr) old_top;
+               (void) Dchdir(PWD);
+       } else {
+               if (Dchdir(dirbuf) == -1)
+               {
+                       s_mess("pushd: cannot change into %s.", dirbuf);
+                       return;
+               }
+               (void) list_push(&DirStack, (UnivPtr)NULL);
+               setCWD(dirbuf);
+       }
+       prDIRS();
+}
+
+void
+Popd()
+{
+       if (list_next(DirStack) == NULL)
+               complain("popd: directory stack is empty.");
+       UpdModLine = YES;
+       free((UnivPtr) list_pop(&DirStack));
+       (void) Dchdir(PWD);     /* If this doesn't work, we's in deep shit. */
+       prDIRS();
+}
+
+private void
+dfollow(file, into)
+char   *file,
+       *into;
+{
+       char    *dp,
+               *sp;
+
+#ifndef        MSDOS
+       if (*file == '/') {             /* Absolute pathname */
+               strcpy(into, "/");
+               file += 1;
+       } else {
+               strcpy(into, PWD);
+       }
+#else  /* MSDOS */
+       char    filefix[FILESIZE];
+
+       abspath(file, filefix);         /* convert to absolute pathname */
+       strcpy(into, filefix);          /* and forget about drives      */
+       into[3] = '\0';
+       into = &(into[2]);
+       file = &(filefix[3]);
+#endif /* MSDOS */
+
+       dp = into + strlen(into);
+       for (;;) {
+               if (*file == '\0')
+                       break;
+               if ((sp = strchr(file, '/')) != NULL)
+                       *sp = '\0';
+               if (*file == '\0' || strcmp(file, ".") == 0) {
+                       /* So it will get to the end of the loop */
+               } else if (strcmp(file, "..") == 0) {
+                       for (;;) {
+                           if (dp == into) {
+                               *dp++ = '/';
+                               break;
+                           }
+                           if (*--dp == '/')
+                               break;
+                       }
+                       *dp = '\0';
+               } else {
+                       if (dp!=into && dp[-1]!='/')
+                           *dp++ = '/';
+                       strcpy(dp, file);
+                       dp += strlen(dp);       /* stay at the end */
+               }
+               if (sp == NULL)
+                   break;
+               file = sp + 1;
+       }
+}
+
+#ifdef UNIX
+
+# ifdef        YP_PASSWD
+
+#include <pwd.h>
+
+private void
+get_hdir(user, buf)
+register char  *user,
+               *buf;
+{
+       struct passwd   *p;
+
+       p = getpwnam(user);
+       endpwent();
+       if (p == NULL) {
+               add_mess(" [unknown user: %s]", user);
+               SitFor(7);
+               complain((char *)NULL);
+               /* NOTREACHED */
+       }
+       strcpy(buf, p->pw_dir);
+}
+
+#else
+
+#include "re.h"
+
+private void
+get_hdir(user, buf)
+register char  *user,
+               *buf;
+{
+       char    fbuf[LBSIZE],
+               pattern[100];
+       register int    u_len;
+       File    *fp;
+
+       u_len = strlen(user);
+       fp = open_file("/etc/passwd", fbuf, F_READ, YES, YES);
+       swritef(pattern, sizeof(pattern),
+               "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user);
+       while (!f_gets(fp, genbuf, LBSIZE))
+               if ((strncmp(genbuf, user, u_len) == 0)
+               && LookingAt(pattern, genbuf, 0)) {
+                       putmatch(1, buf, FILESIZE);
+                       close_file(fp);
+                       return;
+               }
+       close_file(fp);
+       add_mess(" [unknown user: %s]", user);
+       SitFor(7);
+       complain((char *)NULL);
+}
+
+#endif /* YP_PASSWD */
+#endif /* UNIX */
+
+void
+PathParse(name, intobuf)
+char   *name,
+       *intobuf;
+{
+       char    localbuf[FILESIZE];
+
+       intobuf[0] = localbuf[0] = '\0';
+       if (*name == '\0')
+               return;
+       if (*name == '~') {
+               if (name[1] == '/' || name[1] == '\0') {
+                       strcpy(localbuf, HomeDir);
+                       name += 1;
+               }
+#ifdef UNIX    /* may add for mac in future */
+               else {
+                       char    *uendp = strchr(name, '/'),
+                               unamebuf[30];
+
+                       if (uendp == NULL)
+                               uendp = name + strlen(name);
+                       name += 1;
+                       null_ncpy(unamebuf, name, (size_t) (uendp - name));
+                       get_hdir(unamebuf, localbuf);
+                       name = uendp;
+               }
+#endif
+#ifndef        MSDOS
+       } else if (*name == '\\') {
+               /* allow quoting of ~ (but \ is a path separator in MSDOS) */
+               name += 1;
+#endif /* MSDOS */
+       }
+       (void) strcat(localbuf, name);
+       dfollow(localbuf, intobuf);
+}
+
+void
+filemunge(newname)
+char   *newname;
+{
+       struct stat     stbuf;
+
+       if (newname == NULL)
+               return;
+       if (stat(newname, &stbuf))
+               return;
+       if (
+#ifndef        MSDOS
+           ((stbuf.st_dev != curbuf->b_dev) ||
+            (stbuf.st_ino != curbuf->b_ino)) &&
+#endif /* !MSDOS */
+#ifndef        MAC
+           ((stbuf.st_mode & S_IFMT) != S_IFCHR) &&
+#endif /* !MAC */
+           (curbuf->b_fname==NULL || strcmp(newname, curbuf->b_fname) != 0)) {
+               rbell();
+               confirm("\"%s\" already exists; overwrite it? ", newname);
+       }
+}
+
+int    CreatMode = DFLT_MODE;
+
+private void
+DoWriteReg(app)
+bool   app;
+{
+       char    fnamebuf[FILESIZE],
+               *fname;
+       Mark    *mp = CurMark();
+       File    *fp;
+
+       /* Won't get here if there isn't a Mark */
+       fname = ask_file((char *)NULL, (char *)NULL, fnamebuf);
+
+#ifdef BACKUPFILES
+       if (app == NO) {
+               filemunge(fname);
+
+               if (BkupOnWrite)
+                       file_backup(fname);
+       }
+#else
+       if (!app)
+               filemunge(fname);
+#endif
+
+       fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO);
+       putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES);
+       close_file(fp);
+}
+
+void
+WrtReg()
+{
+       DoWriteReg(NO);
+}
+
+void
+AppReg()
+{
+       DoWriteReg(YES);
+}
+
+bool   OkayBadChars = NO;
+
+void
+WriteFile()
+{
+       char    *fname,
+               fnamebuf[FILESIZE];
+#ifdef MAC
+       if (Macmode) {
+               if (!(fname = pfile(fnamebuf)))
+                       return;
+       } else
+#endif /* MAC */
+               fname = ask_file((char *)NULL, curbuf->b_fname, fnamebuf);
+       /* Don't allow bad characters when creating new files. */
+       if (!OkayBadChars
+       && (curbuf->b_fname==NULL || strcmp(curbuf->b_fname, fnamebuf) != 0))
+       {
+#ifdef UNIX
+               static const char       badchars[] = "!$^&*()~`{}\"'\\|<>? ";
+#endif /* UNIX */
+#ifdef MSDOS
+               static const char       badchars[] = "*|<>? ";
+#endif /* MSDOS */
+#ifdef MAC
+               static const char       badchars[] = ":";
+#endif /* MAC */
+               register char   *cp = fnamebuf;
+               register int    c;
+
+               while ((c = *cp++ & CHARMASK) != '\0')  /* avoid sign extension... */
+                       if (c < ' ' || c == '\177' || strchr(badchars, c))
+                               complain("'%p': bad character in filename.", c);
+       }
+
+       chk_mtime(curbuf, fname, "write");
+       filemunge(fname);
+       curbuf->b_type = B_FILE;        /* in case it wasn't before */
+       setfname(curbuf, fname);
+       file_write(fname, NO);
+}
+
+/* Open file FNAME supplying the buffer IO routine with buffer BUF.
+   HOW is F_READ, F_WRITE or F_APPEND.  IFBAD == COMPLAIN means that
+   if we fail at opening the file, call complain.  LOUDNESS says
+   whether or not to print the "reading ..." message on the message
+   line.
+
+   NOTE:  This opens the pr_name(fname, NO) of fname.  That is, FNAME
+         is usually an entire pathname, which can be slow when the
+         pathname is long and there are lots of symbolic links along
+         the way (which has become very common in my experience).  So,
+         this speeds up opens file names in the local directory.  It
+         will not speed up things like "../scm/foo.scm" simple because
+         by the time we get here that's already been expanded to an
+         absolute pathname.  But this is a start.
+   */
+
+File *
+open_file(fname, buf, how, complainifbad, quiet)
+register char  *fname;
+char   *buf;
+register int   how;
+int    complainifbad,
+       quiet;
+{
+       register File   *fp;
+
+       io_chars = 0;
+       io_lines = 0;
+
+       fp = f_open(pr_name(fname, NO), how, buf, LBSIZE);
+       if (fp == NULL) {
+               message(IOerr((how == F_READ) ? "open" : "create", fname));
+               if (complainifbad)
+                       complain((char *)NULL);
+       } else {
+               int     rd_only = FALSE;
+#ifndef        MAC
+               if (access(pr_name(fname, NO), W_OK) == -1 && errno != ENOENT) {
+                       rd_only = TRUE;
+                       fp->f_flags |= F_READONLY;
+               }
+#endif
+               if (!quiet) {
+                       fp->f_flags |= F_TELLALL;
+                       f_mess("\"%s\"%s", pr_name(fname, YES),
+                                  rd_only ? " [Read only]" : NullStr);
+               }
+       }
+       return fp;
+}
+
+#ifndef        MSDOS
+/* Check to see if the file has been modified since it was
+   last written.  If so, make sure they know what they're
+   doing.
+
+   I hate to use another stat(), but to use confirm we gotta
+   do this before we open the file.
+
+   NOTE: This stats FNAME after converting it to a path-relative
+        name.  I can't see why this would cause a problem ...
+   */
+
+void
+chk_mtime(thisbuf, fname, how)
+Buffer *thisbuf;
+char   *fname,
+       *how;
+{
+       struct stat     stbuf;
+       Buffer  *b;
+       static const char       mesg[] = "Shall I go ahead and %s anyway? ";
+
+       if ((thisbuf->b_mtime != 0) &&          /* if we care ... */
+           ((b = file_exists(fname)) != NULL) &&               /* we already have this file */
+           (b == thisbuf) &&                   /* and it's the current buffer */
+           (stat(pr_name(fname, NO), &stbuf) != -1) && /* and we can stat it */
+           (stbuf.st_mtime != b->b_mtime)) {   /* and there's trouble. */
+               rbell();
+               redisplay();    /* Ring that bell! */
+               TOstart("Warning", TRUE);
+               Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname, YES));
+               Typeout("visited or saved.  Probably someone else is editing");
+               Typeout("your file at the same time.");
+               if (how) {
+                       Typeout("");
+                       Typeout("Type \"y\" if I should %s, anyway.", how);
+                       f_mess(mesg, how);
+               }
+               TOstop();
+               if (how)
+                       confirm(mesg, how);
+       }
+}
+
+#endif /* !MSDOS */
+
+void
+file_write(fname, app)
+char   *fname;
+bool   app;
+{
+       File    *fp;
+
+#ifdef BACKUPFILES
+       if (!app && BkupOnWrite)
+               file_backup(fname);
+#endif
+
+       fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO);
+
+       if (EndWNewline) {      /* Make sure file ends with a newLine */
+               Bufpos  save;
+
+               DOTsave(&save);
+               ToLast();
+               if (length(curline))    /* Not a blank Line */
+                       LineInsert(1);
+               SetDot(&save);
+       }
+       putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO);
+       close_file(fp);
+       set_ino(curbuf);
+       unmodify();
+}
+
+void
+ReadFile()
+{
+       Buffer  *bp;
+       char    *fname,
+               fnamebuf[FILESIZE];
+       int     lineno;
+
+#ifdef MAC
+       if (Macmode) {
+               if (!(fname = gfile(fnamebuf)))
+                       return;
+       } else
+#endif /* MAC */
+               fname = ask_file((char *)NULL, curbuf->b_fname, fnamebuf);
+       chk_mtime(curbuf, fname, "read");
+
+       if (IsModified(curbuf)) {
+               char    *y_or_n;
+               int     c;
+
+               for (;;) {
+                       rbell();
+                       y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name);
+                       c = CharUpcase(*y_or_n);
+                       if (c == 'Y' || c == 'N')
+                               break;
+               }
+               if (c == 'Y')
+                       SaveFile();
+       }
+
+       if ((bp = file_exists(fnamebuf)) != NULL &&
+           (bp == curbuf))
+               lineno = pnt_line() - 1;
+       else
+               lineno = 0;
+
+       unmodify();
+       initlist(curbuf);
+       setfname(curbuf, fname);
+       read_file(fname, NO);
+       SetLine(next_line(curbuf->b_first, lineno));
+}
+
+void
+InsFile()
+{
+       char    *fname,
+               fnamebuf[FILESIZE];
+#ifdef MAC
+       if (Macmode) {
+               if (!(fname = gfile(fnamebuf)))
+                       return;
+       } else
+#endif /* MAC */
+               fname = ask_file((char *)NULL, curbuf->b_fname, fnamebuf);
+       read_file(fname, YES);
+}
+
+#include "temp.h"
+
+bool   DOLsave = NO;   /* Do Lsave flag.  If lines aren't being saved
+                          when you think they should have been, this
+                          flag is probably not being set, or is being
+                          cleared before lsave() was called. */
+
+private int    nleft,  /* number of good characters left in current block */
+               tmpfd = -1;
+daddr  DFree = 1;  /* pointer to end of tmp file */
+private char   *tfname;
+
+private void
+tmpinit()
+{
+       char    buf[FILESIZE];
+
+#ifdef MAC
+       swritef(buf, sizeof(buf), "%s/%s", HomeDir, d_tempfile);
+#else
+       swritef(buf, sizeof(buf), "%s/%s", TmpFilePath, d_tempfile);
+#endif
+       tfname = copystr(buf);
+       tfname = mktemp(tfname);
+       (void) close(creat(tfname, 0600));
+#ifndef        MSDOS
+       tmpfd = open(tfname, 2);
+#else  /* MSDOS */
+       tmpfd = open(tfname, 0x8002);   /* MSDOS fix */
+#endif /* MSDOS */
+       if (tmpfd == -1)
+               complain("Warning: cannot create tmp file! %s", strerror(errno));
+}
+
+/* Close tempfile before execing a child process.
+ * Since we might be vforking, we must not change any variables
+ * (in particular tmpfd).
+ */
+void
+tmpclose()
+{
+       if (tmpfd != -1)
+               (void) close(tmpfd);
+}
+
+/* Close and remove tempfile before exiting. */
+
+void
+tmpremove()
+{
+       if (tmpfd != -1) {
+               tmpclose();
+               (void) unlink(tfname);
+       }
+}
+
+/* get a line at `tl' in the tmp file into `buf' which should be LBSIZE
+   long */
+
+int    Jr_Len;         /* length of Just Read Line */
+
+void
+getline(addr, buf)
+daddr  addr;
+register char  *buf;
+{
+       register char   *bp,
+                       *lp;
+
+       lp = buf;
+       bp = getblock(addr >> 1, FALSE);
+       do ; while ((*lp++ = *bp++) != '\0');
+       Jr_Len = (lp - buf) - 1;
+}
+
+/* Put `buf' and return the disk address */
+
+daddr
+putline(buf)
+char   *buf;
+{
+       register char   *bp,
+                       *lp;
+       register int    nl;
+       daddr   free_ptr;
+
+       lp = buf;
+       free_ptr = DFree;
+       bp = getblock(free_ptr, TRUE);
+       nl = nleft;
+       free_ptr = blk_round(free_ptr);
+       while ((*bp = *lp++) != '\0') {
+               if (*bp++ == '\n') {
+                       *--bp = '\0';
+                       break;
+               }
+               if (--nl == 0) {
+                       free_ptr = forward_block(free_ptr);
+                       DFree = free_ptr;
+                       bp = getblock(free_ptr, TRUE);
+                       lp = buf;       /* start over ... */
+                       nl = nleft;
+               }
+       }
+       free_ptr = DFree;
+       DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE);
+                /* (lp - buf) includes the null */
+       return (free_ptr << 1);
+}
+
+/* The theory is that critical section of code inside this procedure
+   will never cause a problem to occur.  Basically, we need to ensure
+   that two blocks are in memory at the same time, but I think that
+   this can never screw up. */
+
+#define lockblock(addr)
+#define unlockblock(addr)
+
+private bool
+f_getputl(line, fp)
+Line   *line;
+register File  *fp;
+{
+       register char   *bp;
+       register int    c,
+                       nl,
+                       room = LBSIZE-1;
+       daddr           free_ptr;
+       char            *base;
+
+       free_ptr = DFree;
+       base = bp = getblock(free_ptr, TRUE);
+       nl = nleft;
+       free_ptr = blk_round(free_ptr);
+       do {
+               /* We can't store NUL in our buffer, so ignore it.
+                * Of course, with a little ingenuity we could:
+                * NUL could be represented by \n!
+                */
+               c = jgetc(fp);
+               if (c == '\0')
+                       continue;
+#ifdef MSDOS
+               if (c == '\r')
+                       continue;
+#endif /* MSDOS */
+               if (c == EOF || c == '\n')
+                       break;
+               if (--nl == 0) {
+                       char    *newbp;
+                       size_t  nbytes;
+
+                       lockblock(free_ptr);
+                       DFree = free_ptr = forward_block(free_ptr);
+                       nbytes = bp - base;
+                       newbp = getblock(free_ptr, TRUE);
+                       nl = nleft;
+                       byte_copy(base, newbp, nbytes);
+                       bp = newbp + nbytes;
+                       base = newbp;
+                       unlockblock(free_ptr);
+               }
+               *bp++ = c;
+       } while (--room > 0);
+       *bp++ = '\0';
+       free_ptr = DFree;
+       DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE);
+       line->l_dline = (free_ptr << 1);
+       if (room == 0) {
+               add_mess(" [Line too long]");
+               rbell();
+               return YES;
+       }
+       if (c == EOF) {
+               if (--bp != base)
+                       add_mess(" [Incomplete last line]");
+               return YES;
+       }
+       io_lines += 1;
+       return NO;
+}
+
+typedef struct block {
+       char    b_dirty;        /* (bool) */
+       short   b_bno;
+       char    b_buf[JBUFSIZ];
+       struct block
+               *b_LRUnext,
+               *b_LRUprev,
+               *b_HASHnext;
+} Block;
+
+#define HASHSIZE       7       /* Primes work best (so I'm told) */
+#define B_HASH(bno)    ((bno) % HASHSIZE)
+
+#ifdef MAC
+private Block  *b_cache,
+#else
+private Block  b_cache[NBUF],
+#endif
+               *bht[HASHSIZE],         /* Block hash table. Must be zero initially */
+               *f_block = NULL,
+               *l_block = NULL;
+private int    max_bno = -1,
+               NBlocks;
+
+private void   (*blkio) ptrproto((Block *, int (*) ptrproto((int, UnivPtr, size_t))));
+
+#ifdef MAC
+public bool
+make_cache()   /* Only 32K of static space on Mac, so... */
+{
+       return (b_cache = (Block *) calloc(NBUF,sizeof(Block))) != NULL;
+}
+#endif /* MAC */
+
+private void
+real_blkio(b, iofcn)
+register Block *b;
+register int   (*iofcn) ptrproto((int, UnivPtr, size_t));
+{
+       (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * JBUFSIZ, 0);
+       if ((*iofcn)(tmpfd, (UnivPtr) b->b_buf, (size_t)JBUFSIZ) != JBUFSIZ)
+               error("[Tmp file %s error: to continue editing would be dangerous]",
+                       (iofcn == read) ? "READ" : "WRITE");
+}
+
+private void
+fake_blkio(b, iofcn)
+register Block *b;
+register int   (*iofcn) ptrproto((int, UnivPtr, size_t));
+{
+       tmpinit();
+       blkio = real_blkio;
+       real_blkio(b, iofcn);
+}
+
+void
+d_cache_init()
+{
+       register Block  *bp,    /* Block pointer */
+                       **hp;   /* Hash pointer */
+       register short  bno;
+
+       for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) {
+               NBlocks += 1;
+               bp->b_dirty = NO;
+               bp->b_bno = bno;
+               if (l_block == NULL)
+                       l_block = bp;
+               bp->b_LRUprev = NULL;
+               bp->b_LRUnext = f_block;
+               if (f_block != NULL)
+                       f_block->b_LRUprev = bp;
+               f_block = bp;
+
+               bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]);
+               *hp = bp;
+       }
+       blkio = fake_blkio;
+}
+
+void
+SyncTmp()
+{
+       register Block  *b;
+#ifdef IBMPC
+       register int    bno = 0;
+
+       /* sync the blocks in order, for file systems that don't allow
+          holes (MSDOS).  Perhaps this benefits floppy-based file systems. */
+
+       for (bno = 0; bno <= max_bno; ) {
+               if ((b = lookup(bno++)) && b->b_dirty) {
+                       (*blkio)(b, write);
+                       b->b_dirty = NO;
+               }
+       }
+#else
+       for (b = f_block; b != NULL; b = b->b_LRUnext)
+               if (b->b_dirty) {
+                       (*blkio)(b, (int (*) ptrproto((int, UnivPtr, size_t)))write);
+                       b->b_dirty = NO;
+               }
+#endif
+}
+
+private Block *
+lookup(bno)
+register short bno;
+{
+       register Block  *bp;
+
+       for (bp = bht[B_HASH(bno)]; bp != NULL; bp = bp->b_HASHnext)
+               if (bp->b_bno == bno)
+                       break;
+       return bp;
+}
+
+private void
+LRUunlink(b)
+register Block *b;
+{
+       if (b->b_LRUprev == NULL)
+               f_block = b->b_LRUnext;
+       else
+               b->b_LRUprev->b_LRUnext = b->b_LRUnext;
+       if (b->b_LRUnext == NULL)
+               l_block = b->b_LRUprev;
+       else
+               b->b_LRUnext->b_LRUprev = b->b_LRUprev;
+}
+
+private Block *
+b_unlink(bp)
+register Block *bp;
+{
+       register Block  *hp,
+                       *prev = NULL;
+
+       LRUunlink(bp);
+       /* Now that we have the block, we remove it from its position
+          in the hash table, so we can THEN put it somewhere else with
+          it's new block assignment. */
+
+       for (hp = bht[B_HASH(bp->b_bno)]; hp != NULL; prev = hp, hp = hp->b_HASHnext)
+               if (hp == bp)
+                       break;
+       if (hp == NULL) {
+               writef("\rBlock %d missing!", bp->b_bno);
+               finish(0);
+       }
+       if (prev)
+               prev->b_HASHnext = hp->b_HASHnext;
+       else
+               bht[B_HASH(bp->b_bno)] = hp->b_HASHnext;
+
+       if (bp->b_dirty) {      /* do, now, the delayed write */
+               (*blkio)(bp, (int (*) ptrproto((int, UnivPtr, size_t)))write);
+               bp->b_dirty = NO;
+       }
+
+       return bp;
+}
+
+/* Get a block which contains at least part of the line with the address
+   atl.  Returns a pointer to the block and sets the global variable
+   nleft (number of good characters left in the buffer). */
+
+private char *
+getblock(atl, IsWrite)
+daddr  atl;
+bool   IsWrite;
+{
+       register int    bno,
+                       off;
+       register Block  *bp;
+       static Block    *lastb = NULL;
+
+       bno = da_to_bno(atl);
+       off = da_to_off(atl);
+       if (da_too_huge(atl))
+               error("Tmp file too large.  Get help!");
+       nleft = JBUFSIZ - off;
+       if (lastb != NULL && lastb->b_bno == bno) {
+               lastb->b_dirty |= IsWrite;
+               return lastb->b_buf + off;
+       }
+
+       /* The requested block already lives in memory, so we move
+          it to the end of the LRU list (making it Most Recently Used)
+          and then return a pointer to it. */
+       if ((bp = lookup(bno)) != NULL) {
+               if (bp != l_block) {
+                       LRUunlink(bp);
+                       if (l_block == NULL)
+                               f_block = l_block = bp;
+                       else
+                               l_block->b_LRUnext = bp;
+                       bp->b_LRUprev = l_block;
+                       l_block = bp;
+                       bp->b_LRUnext = NULL;
+               }
+               if (bp->b_bno > max_bno)
+                       max_bno = bp->b_bno;
+               bp->b_dirty |= IsWrite;
+               lastb = bp;
+               return bp->b_buf + off;
+       }
+
+       /* The block we want doesn't reside in memory so we take the
+          least recently used clean block (if there is one) and use
+          it.  */
+       bp = f_block;
+       if (bp->b_dirty)        /* The best block is dirty ... */
+               SyncTmp();
+
+       bp = b_unlink(bp);
+       if (l_block == NULL)
+               l_block = f_block = bp;
+       else
+               l_block->b_LRUnext = bp;        /* Place it at the end ... */
+       bp->b_LRUprev = l_block;
+       l_block = bp;
+       bp->b_LRUnext = NULL;           /* so it's Most Recently Used */
+
+       bp->b_dirty = IsWrite;
+       bp->b_bno = bno;
+       bp->b_HASHnext = bht[B_HASH(bno)];
+       bht[B_HASH(bno)] = bp;
+
+       /* Get the current contents of the block UNLESS this is a new
+          block that's never been looked at before, i.e., it's past
+          the end of the tmp file. */
+
+       if (bp->b_bno <= max_bno)
+               (*blkio)(bp, read);
+       else
+               max_bno = bno;
+
+       lastb = bp;
+       return bp->b_buf + off;
+}
+
+char *
+lbptr(line)
+Line   *line;
+{
+       return getblock(line->l_dline >> 1, FALSE);
+}
+
+/* save the current contents of linebuf, if it has changed */
+
+void
+lsave()
+{
+       if (curbuf == NULL || !DOLsave) /* Nothing modified recently */
+               return;
+
+       if (strcmp(lbptr(curline), linebuf) != 0)
+               SavLine(curline, linebuf);      /* Put linebuf on the disk. */
+       DOLsave = NO;
+}
+
+#ifdef BACKUPFILES
+private void
+file_backup(fname)
+char *fname;
+{
+#ifndef        MSDOS
+       char    *s;
+       register int    i;
+       int     fd1,
+               fd2;
+       char    tmp1[JBUFSIZ],
+               tmp2[JBUFSIZ];
+       struct stat buf;
+       int     mode;
+
+       strcpy(tmp1, fname);
+       if ((s = strrchr(tmp1, '/')) == NULL)
+               swritef(tmp2, sizeof(tmp2), "#%s~", fname);
+       else {
+               *s++ = '\0';
+               swritef(tmp2, sizeof(tmp2), "%s/#%s~", tmp1, s);
+       }
+
+       if ((fd1 = open(fname, 0)) < 0)
+               return;
+
+       /* create backup file with same mode as input file */
+#ifndef        MAC
+       if (fstat(fd1, &buf) != 0)
+               mode = CreatMode;
+       else
+#endif
+               mode = buf.st_mode;
+
+       if ((fd2 = creat(tmp2, mode)) < 0) {
+               (void) close(fd1);
+               return;
+       }
+       while ((i = read(fd1, (UnivPtr) tmp1, sizeof(tmp1))) > 0)
+               write(fd2, (UnivPtr) tmp1, (size_t) i);
+#ifdef BSD4_2
+       (void) fsync(fd2);
+#endif
+       (void) close(fd2);
+       (void) close(fd1);
+#else  /* MSDOS */
+       char    *dot,
+                       *slash,
+                       tmp[FILESIZE];
+
+       strcpy(tmp, fname);
+       slash = basename(tmp);
+       if (dot = strrchr(slash, '.')) {
+               if (!stricmp(dot,".bak"))
+                       return;
+               *dot = '\0';
+       }
+       strcat(tmp, ".bak");
+       unlink(tmp);
+       rename(fname, tmp);
+#endif /* MSDOS */
+}
+#endif
+
diff --git a/usr/src/contrib/jove-4.14.6/io.h b/usr/src/contrib/jove-4.14.6/io.h
new file mode 100644 (file)
index 0000000..0900129
--- /dev/null
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+extern char    *HomeDir;
+
+extern size_t  HomeLen;
+
+extern bool    DOLsave;        /* Do Lsave flag.  If lines aren't being saved
+                                  when you think they should have been, this
+                                  flag is probably not being set, or is being
+                                  cleared before lsave() was called. */
+
+extern daddr   DFree;  /* pointer to end of tmp file */
+
+extern int     Jr_Len;         /* length of Just Read Line */
+
+extern char
+       *lbptr proto((struct line *line)),
+       *pr_name proto((char *fname,int okay_home)),
+       *pwd proto((void)),
+       *sprint proto((const char *, ...));
+
+extern struct FileStruct
+       *open_file proto((char *fname,char *buf,int how,int complainifbad,int loudness));
+
+extern void
+       setCWD proto((char *d)),
+       getCWD proto((void)),
+       PathParse proto((char *name,char *intobuf)),
+       SyncTmp proto((void)),
+       close_file proto((struct FileStruct *fp)),
+       d_cache_init proto((void)),
+       file_write proto((char *fname, bool app)),
+       filemunge proto((char *newname)),
+       getline proto((daddr addr,char *buf)),
+       lsave proto((void)),
+       putreg proto((struct FileStruct *fp,struct line *line1,int char1,struct line *line2,int char2,bool makesure)),
+       read_file proto((char *file, bool is_insert)),
+       tmpclose proto((void)),
+       tmpremove proto((void)),
+
+       WriteFile proto((void));
+
+extern bool
+       chkCWD proto((char *dn));
+
+extern daddr
+       putline proto((char *buf));
+
+#ifdef MAC
+#define        chk_mtime(thisbuf, fname, how)  { }
+#else
+#ifdef MSDOS
+#define        chk_mtime(thisbuf, fname, how)  { }
+#else
+extern void
+       chk_mtime proto((Buffer *thisbuf, char *fname, char *how));
+#endif
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/iproc-pipes.c b/usr/src/contrib/jove-4.14.6/iproc-pipes.c
new file mode 100644 (file)
index 0000000..a0dfb3b
--- /dev/null
@@ -0,0 +1,290 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* NOTE WELL:
+ * This file is "included" into iproc.c -- it is not compiled separately!
+ */
+
+#include <signal.h>
+#include <sgtty.h>
+#include "wait.h"
+
+#define DEAD   1       /* Dead but haven't informed user yet */
+#define STOPPED        2       /* Job stopped */
+#define RUNNING        3       /* Just running */
+#define NEW    4       /* This process is brand new */
+
+/* If process is dead, flags says how. */
+#define EXITED 1
+#define KILLED 2
+
+#define isdead(p)      ((p) == NULL || proc_state((p)) == DEAD || (p)->p_toproc == -1)
+#define makedead(p)    { proc_state((p)) = DEAD; }
+
+#define proc_buf(p)    ((p)->p_buffer->b_name)
+#define proc_cmd(p)    ((p)->p_name)
+#define proc_state(p)  ((p)->p_state)
+
+private Process        *procs = NULL;
+
+File   *ProcInput;
+int    ProcOutput,
+       kbd_pid = 0,
+       NumProcs = 0;
+
+private Process *
+proc_pid(pid)
+int    pid;
+{
+       register Process        *p;
+
+       for (p = procs; p != NULL; p = p->p_next)
+               if (p->p_portpid == pid)
+                       break;
+
+       return p;
+}
+
+void
+read_proc(pid, nbytes)
+int    pid;
+register int   nbytes;
+{
+       register Process        *p;
+       char    ibuf[512];
+
+       if ((p = proc_pid(pid)) == NULL) {
+               writef("\riproc: unknown pid (%d)", pid);
+               return;
+       }
+
+       if (proc_state(p) == NEW) {
+               int     rpid;
+               /* pid of real child, not of portsrv */
+
+               (void) f_readn(ProcInput, (char *) &rpid, sizeof (int));
+               p->p_pid = rpid;
+               p->p_state = RUNNING;
+               return;
+       }
+
+       if (nbytes == EOF) {            /* okay to clean up this process */
+               union wait      status;
+               int     pid;
+
+               (void) f_readn(ProcInput, &status.w_status, sizeof (int));
+               do {
+                       pid = wait((int *)NULL);
+                       if (pid < 0)
+                               break;
+                       kill_off(pid, status);
+               } while (pid != p->p_portpid);
+               proc_close(p);
+               makedead(p);
+               return;
+       }
+
+       while (nbytes > 0) {
+               size_t n = f_readn(ProcInput, ibuf, min((sizeof ibuf) - 1, nbytes));
+
+               ibuf[n] = '\0'; /* Null terminate for convenience */
+               nbytes -= n;
+               proc_rec(p, ibuf);
+       }
+}
+
+void
+ProcKill()
+{
+       proc_kill(curbuf->b_process, SIGKILL);
+}
+
+void
+ProcInt()
+{
+       proc_kill(curbuf->b_process, SIGINT);
+}
+
+void
+ProcQuit()
+{
+       proc_kill(curbuf->b_process, SIGQUIT);
+}
+
+private void
+proc_close(p)
+Process        *p;
+{
+       if (p->p_toproc >= 0) {
+               (void) close(p->p_toproc);
+               p->p_toproc = -1;       /* writes will fail */
+               NumProcs -= 1;
+       }
+}
+
+void
+proc_write(p, buf, nbytes)
+Process        *p;
+char   *buf;
+size_t nbytes;
+{
+       (void) write(p->p_toproc, buf, nbytes);
+}
+
+
+#ifdef STDARGS
+private void
+proc_strt(char *bufname, int clobber, ...)
+#else
+private /*VARARGS3*/ void
+proc_strt(bufname, clobber, va_alist)
+       char    *bufname;
+       int     clobber;
+       va_dcl
+#endif
+{
+       Window  *owind = curwind;
+       int     toproc[2],
+               pid;
+       Process *newp;
+       Buffer  *newbuf;
+       char    *argv[32],
+               *cp,
+               foo[10],
+               cmdbuf[LBSIZE];
+       int     i;
+       va_list ap;
+
+       isprocbuf(bufname);     /* make sure BUFNAME is either nonexistant
+                                  or is of type B_PROCESS */
+       if (access(Portsrv, X_OK) < 0) {
+               complain("[Couldn't access %s: %s]", Portsrv, strerror(errno));
+               /* NOTREACHED */
+       }
+       dopipe(toproc);
+
+       switch (pid = fork()) {
+       case -1:
+               pipeclose(toproc);
+               complain("[Fork failed: %s]", strerror(errno));
+
+       case 0:
+               argv[0] = "portsrv";
+               va_init(ap, clobber);
+               make_argv(&argv[1], ap);
+               va_end(ap);
+               (void) dup2(toproc[0], 0);
+               (void) dup2(ProcOutput, 1);
+               (void) dup2(ProcOutput, 2);
+               pipeclose(toproc);
+               jcloseall();
+               execv(Portsrv, argv);
+               raw_complain("execl failed: %s\n", strerror(errno));
+               _exit(1);
+       }
+
+       newp = (Process *) malloc(sizeof *newp);
+       /* ??? better check for newp == NULL -- DHR */
+       newp->p_next = procs;
+       newp->p_state = NEW;
+
+       cmdbuf[0] = '\0';
+       va_init(ap, clobber);
+       while (cp = va_arg(ap, char *)) {
+               size_t  pl = strlen(cmdbuf);
+
+               swritef(&cmdbuf[pl], sizeof(cmdbuf)-pl, "%s ", cp);
+       }
+       va_end(ap);
+       va_init(ap, clobber);
+       newp->p_name = copystr(cmdbuf);
+       procs = newp;
+       newp->p_portpid = pid;
+       newp->p_pid = -1;
+
+       newbuf = do_select((Window *)NULL, bufname);
+       newbuf->b_type = B_PROCESS;
+       newp->p_buffer = newbuf;
+       newbuf->b_process = newp;       /* sorta circular, eh? */
+       pop_wind(bufname, clobber, B_PROCESS);
+       ToLast();
+       if (!bolp())
+               LineInsert(1);
+       /* Pop_wind() after everything is set up; important!
+          Bindings won't work right unless newbuf->b_process is already
+          set up BEFORE NEWBUF is first SetBuf()'d. */
+       newp->p_mark = MakeMark(curline, curchar, M_FLOATER);
+       newp->p_dbx_mode = NO;
+
+       newp->p_toproc = toproc[1];
+       newp->p_reason = 0;
+       NumProcs += 1;
+       if (NumProcs == 1)
+               (void) kbd_strt();
+       (void) close(toproc[0]);
+       SetWind(owind);
+}
+
+void
+pinit()
+{
+       int     p[2];
+
+       (void) pipe(p);
+       ProcInput = fd_open("process-input", F_READ|F_LOCKED, p[0],
+                           (char *)NULL, 512);
+       ProcOutput = p[1];
+       if ((kbd_pid = fork()) == -1) {
+               raw_complain("Cannot fork kbd process! %s\n", strerror(errno));
+               finish(SIGHUP);
+       }
+       if (kbd_pid == 0) {
+               signal(SIGINT, SIG_IGN);
+               signal(SIGALRM, SIG_IGN);
+               close(1);
+               dup(ProcOutput);
+               jcloseall();
+               execl(Kbd_Proc, "kbd", (char *)NULL);
+               raw_complain("kbd exec failed: %s\n", strerror(errno));
+               exit(-1);
+       }
+}
+
+private int    kbd_state = OFF;
+
+/* kbd_strt() and kbd_stop() return true if they changed the state
+   of the keyboard process.  E.g., kbd_strt() returns TRUE if the
+   kbd process was previously stopped.  This is so kbd starting and
+   stopping in pairs works - see finish() in jove.c. */
+
+kbd_strt()
+{
+       if (kbd_state == OFF) {
+               kbd_state = ON;
+               kill(kbd_pid, KBDSIG);
+               return TRUE;
+       }
+       return FALSE;
+}
+
+kbd_stop()
+{
+       if (kbd_state == ON) {
+               kbd_state = OFF;
+               kill(kbd_pid, KBDSIG);
+               return TRUE;
+       }
+       return FALSE;
+}
+
+kbd_kill()
+{
+       if (kbd_pid != 0) {
+               kill(kbd_pid, SIGKILL);
+               kbd_pid = 0;
+       }
+}
diff --git a/usr/src/contrib/jove-4.14.6/iproc-ptys.c b/usr/src/contrib/jove-4.14.6/iproc-ptys.c
new file mode 100644 (file)
index 0000000..c9bbc06
--- /dev/null
@@ -0,0 +1,465 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* NOTE WELL:
+ * This file is "included" into iproc.c -- it is not compiled separately!
+ */
+
+#include <sys/time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "ttystate.h"
+#include "wait.h"
+#ifdef BSD386
+#include <sys/ioctl.h>
+#endif
+
+#define DEAD   1       /* dead but haven't informed user yet */
+#define STOPPED        2       /* job stopped */
+#define RUNNING        3       /* just running */
+#define NEW    4       /* brand new, never been ... received no input */
+
+/* If process is dead, flags says how. */
+#define EXITED 1
+#define KILLED 2
+
+#define isdead(p)      ((p) == NULL || proc_state((p)) == DEAD || (p)->p_fd == -1)
+#define makedead(p)    { proc_state((p)) = DEAD; }
+
+#define proc_buf(p)    ((p)->p_buffer->b_name)
+#define proc_cmd(p)    ((p)->p_name)
+#define proc_state(p)  ((p)->p_state)
+
+private Process        *procs = NULL;
+
+fd_set global_fd;
+int    NumProcs = 0;
+
+private Process *
+proc_pid(pid)
+int    pid;
+{
+       register Process        *p;
+
+       for (p = procs; p != NULL; p = p->p_next)
+               if (p->p_pid == pid)
+                       break;
+
+       return p;
+}
+
+void
+read_proc(fd)
+register int   fd;
+{
+       register Process        *p;
+       int     n;
+       char    ibuf[1024];
+
+       for (p = procs; p != NULL; p = p->p_next)
+               if (p->p_fd == fd)
+                       break;
+
+       if (p == NULL) {
+               writef("\riproc: unknown fd %d", fd);
+               return;
+       }
+
+       n = read(fd, (UnivPtr) ibuf, sizeof(ibuf) - 1);
+       if (n == -1 && (errno == EIO || errno == EWOULDBLOCK)) {
+               if (proc_state(p) == NEW)
+                       return;
+               proc_close(p);
+               makedead(p);
+               return;
+       } else {
+               if (proc_state(p) != RUNNING) {
+                       proc_state(p) = RUNNING;
+                       UpdModLine = YES;
+               }
+       }
+       if (n <= 0) {
+               if (n == 0)
+                       strcpy(ibuf, "[Process EOF]");
+               else
+                       swritef(ibuf, sizeof(ibuf),
+                               "\n[pty read error: %d]\n", errno);
+       } else
+               ibuf[n] = '\0';
+       proc_rec(p, ibuf);
+}
+
+void
+ProcKill()
+{
+       register Buffer *b;
+       char    *bname;
+
+       bname = ask_buf(curbuf);
+
+       if ((b = buf_exists(bname)) == NULL)
+               complain("[No such buffer]");
+       if (b->b_process == NULL)
+               complain("%s not tied to a process.", bname);
+       proc_kill(b->b_process, SIGKILL);
+}
+
+void
+ProcCont()
+{
+       Process *p;
+
+       if ((p = curbuf->b_process) == NULL)
+               complain("[No process]");
+       if (p->p_state != DEAD) {
+               proc_kill(p, SIGCONT);
+               UpdModLine = YES;
+               p->p_state = RUNNING;
+       }
+}
+
+private void
+send_p(c)
+char   c;
+{
+       Process *p;
+       char    buf[2];
+
+       if ((p = curbuf->b_process) == NULL)
+               complain("[No process]");
+       ToLast();
+       buf[0] = c;
+       buf[1] = '\0';
+       proc_rec(p, buf);
+       (void) write(p->p_fd, (UnivPtr) &c, (size_t) 1);
+}
+
+void
+ProcEof()
+{
+#ifdef SGTTY
+       send_p(tc[OFF].t_eofc);
+#else
+       send_p(sg[OFF].c_cc[VEOF]);
+#endif
+}
+
+void
+ProcInt()
+{
+#ifdef SGTTY
+       send_p(tc[OFF].t_intrc);
+#else
+       send_p(sg[OFF].c_cc[VINTR]);
+#endif
+
+}
+
+void
+ProcQuit()
+{
+#ifdef SGTTY
+       send_p(tc[OFF].t_quitc);
+#else
+       send_p(sg[OFF].c_cc[VQUIT]);
+#endif
+}
+
+void
+ProcStop()
+{
+#ifdef SGTTY
+       send_p(ls[OFF].t_suspc);
+#else
+       send_p(sg[OFF].c_cc[VSUSP]);
+#endif
+}
+
+void
+ProcDStop()
+{
+#ifdef SGTTY
+       send_p(ls[OFF].t_dsuspc);
+#else
+       send_p(sg[OFF].c_cc[VDSUSP]);
+#endif
+}
+
+private void
+proc_close(p)
+Process *p;
+{
+       SigHold(SIGCHLD);       /* be mutually exclusive */
+
+       if (p->p_fd >= 0) {
+               (void) close(p->p_fd);
+               FD_CLR(p->p_fd, &global_fd);
+               NumProcs -= 1;
+               p->p_fd = -1;
+       }
+
+       SigRelse(SIGCHLD);
+}
+
+private void
+proc_write(p, buf, nbytes)
+Process *p;
+char   *buf;
+size_t nbytes;
+{
+       fd_set  mask;
+
+       FD_ZERO(&mask);
+       FD_SET(p->p_fd, &mask);
+
+       while (write(p->p_fd, (UnivPtr) buf, nbytes) <  0)
+               select(p->p_fd + 1, (fd_set *)0, &mask, (fd_set *)0, (struct timeval *)0);
+}
+
+#ifdef STDARGS
+       private void
+proc_strt(char *bufname, int clobber, ...)
+#else
+       private /*VARARGS2*/ void
+proc_strt(bufname, clobber, va_alist)
+       char    *bufname;
+       int     clobber;
+       va_dcl
+#endif
+{
+       va_list ap;
+       char    *argv[32],
+               *cp;
+       Window *owind = curwind;
+       int     pid;
+       Process *newp;
+       Buffer  *newbuf;
+       int     i,
+               ptyfd = -1,
+               ttyfd,
+               ldisc,
+               lmode;
+       register char   *s,
+                       *t;
+       char    ttybuf[11],
+               ptybuf[11];
+       char    cmdbuf[LBSIZE];
+#if defined(SGTTY) || defined(BRLUNIX)
+#ifdef BRLUNIX
+       struct sg_brl sgt;
+#else
+       struct sgttyb sgt;
+#endif
+#endif
+#ifdef TERMIO
+       struct termio   sgt;
+#endif
+#ifdef TERMIOS
+       struct termios  sgt;
+#endif
+
+#ifdef TIOCGWINSZ
+       struct winsize win;
+#else
+#  ifdef       BTL_BLIT
+#  include <sys/jioctl.h>
+       struct jwinsize jwin;
+#  endif
+#endif
+
+       isprocbuf(bufname);     /* make sure BUFNAME is either nonexistant
+                                  or is of type B_PROCESS */
+       va_init(ap, clobber);
+       make_argv(argv, ap);
+       va_end(ap);
+       if (access(argv[0], X_OK) != 0) {
+               complain("[Couldn't access %s: %s]", argv[0], strerror(errno));
+               /* NOTREACHED */
+       }
+       for (s = "pqrs"; ptyfd<0; s++) {
+               if (*s == '\0')
+                       complain("[Out of ptys!]");
+               for (t = "0123456789abcdef"; *t; t++) {
+                       swritef(ptybuf, sizeof(ptybuf), "/dev/pty%c%c", *s, *t);
+                       if ((ptyfd = open(ptybuf, 2)) >= 0) {
+                               strcpy(ttybuf, ptybuf);
+                               ttybuf[5] = 't';
+                               /* make sure both ends are available */
+                               if ((i = open(ttybuf, 2)) < 0) {
+                                       (void) close(ptyfd);
+                                       ptyfd = -1;
+                               } else {
+                                       (void) close(i);
+                                       break;
+                               }
+                       }
+               }
+       }
+
+#ifdef TIOCGETD
+       (void) ioctl(0, TIOCGETD, (UnivPtr) &ldisc);
+#endif
+#ifdef TIOCLGET
+       (void) ioctl(0, TIOCLGET, (UnivPtr) &lmode);
+#endif
+#ifdef TIOCGWINSZ
+       (void) ioctl(0, TIOCGWINSZ, (UnivPtr) &win);
+#else
+#  ifdef       BTL_BLIT
+       (void) ioctl(0, JWINSIZE, (UnivPtr) &jwin);
+#  endif       /* BTL_BLIT */
+#endif
+
+       SigHold(SIGCHLD);
+#ifdef SIGWINCH
+       SigHold(SIGWINCH);
+#endif
+       switch (pid = fork()) {
+       case -1:
+               (void) close(ptyfd);
+               s_mess("[Fork failed! %s]", strerror(errno));
+               goto fail;
+
+       case 0:
+               SigRelse(SIGCHLD);
+#ifdef SIGWINCH
+               SigRelse(SIGWINCH);
+#endif
+               for (i = 0; i < 32; i++)
+                       (void) close(i);
+
+#ifdef TIOCNOTTY
+               if ((i = open("/dev/tty", 2)) >= 0) {
+                       (void) ioctl(i, TIOCNOTTY, (UnivPtr)NULL);
+                       (void) close(i);
+               }
+#endif
+               if ((ttyfd = open(ttybuf, 2)) < 0)
+                       exit(-1);
+               (void) dup2(ttyfd, 1);
+               (void) dup2(ttyfd, 2);
+
+#ifdef TIOCSETD
+               (void) ioctl(0, TIOCSETD, (UnivPtr) &ldisc);
+#endif
+#ifdef TIOCLSET
+               (void) ioctl(0, TIOCLSET, (UnivPtr) &lmode);
+#endif
+#ifdef TIOCSETC
+               (void) ioctl(0, TIOCSETC, (UnivPtr) &tc[OFF]);
+#endif
+#ifdef TIOCSLTC
+               (void) ioctl(0, TIOCSLTC, (UnivPtr) &ls[OFF]);
+#endif
+
+#ifdef TIOCGWINSZ
+#    ifdef     SIGWINCH
+               (void) signal(SIGWINCH, SIG_IGN);
+#    endif
+               win.ws_row = curwind->w_height;
+               (void) ioctl(0, TIOCSWINSZ, (UnivPtr) &win);
+#else
+#  ifdef       BTL_BLIT
+               jwin.bytesy = curwind->w_height;
+               (void) ioctl(0, JSWINSIZE, (UnivPtr) &jwin);
+#  endif
+#endif
+
+               sgt = sg[OFF];
+#ifdef SGTTY
+               sgt.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE | CBREAK | TANDEM);
+               (void) stty(0, &sgt);
+#else
+               sgt.c_lflag &= ~(ISIG|ICANON|ECHO);
+               sgt.c_lflag |= ISIG|ICANON|IEXTEN;
+#ifndef OCRNL
+#define OCRNL 0
+#endif
+               sgt.c_oflag &= ~(OCRNL|ONLCR);
+# ifdef        TERMIO
+               (void) ioctl(0, TCSETAW, (UnivPtr) &sgt);
+# endif        /* TERMIO */
+
+# ifdef        TERMIOS
+               (void) tcsetattr(0, TCSADRAIN, &sgt);
+# endif /* TERMIOS */
+#endif
+
+               {
+                       int     on = 1;
+
+                       (void) ioctl(0, TIOCREMOTE, (UnivPtr) &on);
+               }
+
+#ifdef TIOCSCTTY
+               (void) setsid();
+               (void) ioctl(0, TIOCSCTTY, 0);
+#else
+               i = getpid();
+               (void) ioctl(0, TIOCSPGRP, (UnivPtr) &i);
+               (void) setpgrp(0, i);
+#endif
+               execv(argv[0], (const char **) &argv[1]);
+               raw_scream("execve failed! %s\n");
+               _exit(errno + 1);
+       }
+
+       newp = (Process *) emalloc(sizeof *newp);
+
+#ifdef O_NDELAY
+       fcntl (ptyfd, F_SETFL, O_NDELAY);
+#endif
+       newp->p_fd = ptyfd;
+       newp->p_pid = pid;
+
+       newbuf = do_select((Window *)NULL, bufname);
+       newbuf->b_type = B_PROCESS;
+       newp->p_buffer = newbuf;
+       newbuf->b_process = newp;       /* sorta circular, eh? */
+       pop_wind(bufname, clobber, B_PROCESS);
+       /* Pop_wind() after everything is set up; important!
+          Bindings won't work right unless newbuf->b_process is already
+          set up BEFORE NEWBUF is first SetBuf()'d. */
+       ToLast();
+       if (!bolp())
+               LineInsert(1);
+
+       cmdbuf[0] = '\0';
+       va_init(ap, clobber);
+       while ((cp = va_arg(ap, char *)) != NULL) {
+               size_t  pl = strlen(cmdbuf);
+
+               swritef(&cmdbuf[pl], sizeof(cmdbuf)-pl, "%s ", cp);
+       }
+       va_end(ap);
+
+       newp->p_name = copystr(cmdbuf);
+       newp->p_state = NEW;
+       newp->p_reason = 0;
+       newp->p_mark = MakeMark(curline, curchar, M_FLOATER);
+       newp->p_dbx_mode = NO;
+
+       newp->p_next = procs;
+       procs = newp;
+       NumProcs += 1;
+       FD_SET(newp->p_fd, &global_fd);
+       SetWind(owind);
+
+fail:
+       SigRelse(SIGCHLD);
+#ifdef SIGWINCH
+       SigRelse(SIGWINCH);
+#endif
+}
+
+void
+pinit()
+{
+       FD_ZERO(&global_fd);
+       FD_SET(0, &global_fd);
+       (void) signal(SIGCHLD, proc_child);
+}
diff --git a/usr/src/contrib/jove-4.14.6/iproc.c b/usr/src/contrib/jove-4.14.6/iproc.c
new file mode 100644 (file)
index 0000000..1f14248
--- /dev/null
@@ -0,0 +1,467 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "re.h"
+#include "ctype.h"
+#include "disp.h"
+#ifdef IPROCS
+# include "fp.h"
+# include "iproc.h"
+#endif
+
+#ifdef STDARGS
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+#ifdef IPROCS
+
+#include <errno.h>
+
+private void
+       proc_rec proto ((Process *, char *)),
+       proc_close proto ((Process *)),
+       proc_kill proto((Process *, int)),
+       SendData proto ((int));
+
+private SIGRESULT
+       proc_child proto((int));
+
+#ifdef PIPEPROCS
+#   include "iproc-pipes.c"
+#else
+#   include "iproc-ptys.c"
+#endif
+
+char   proc_prompt[128] = "% ";
+
+char *
+pstate(p)
+Process        *p;
+{
+       switch (proc_state(p)) {
+       case NEW:
+               return "New";
+
+       case STOPPED:
+               return "Stopped";
+
+       case RUNNING:
+               return "Running";
+
+       case DEAD:
+               if (p->p_howdied == EXITED) {
+                       if (p->p_reason == 0)
+                               return "Done";
+                       return sprint("Exit %d", p->p_reason);
+               }
+               return sprint("Killed %d", p->p_reason);
+
+       default:
+               return "Unknown state";
+       }
+}
+
+void
+KillProcs()
+{
+       register Process        *p;
+       register int    killem = -1;            /* -1 means undetermined */
+       register char   *yorn;
+
+       for (p = procs; p != NULL; p = p->p_next)
+               if (!isdead(p)) {
+                       if (killem == -1) {
+                               yorn = ask("y", "Should I kill your i-processes? ");
+                               killem = (CharUpcase(*yorn) == 'Y');
+                       }
+                       if (killem)
+                               proc_kill(p, SIGKILL);
+               }
+}
+
+void
+pbuftiedp(b)
+register Buffer        *b;
+{
+       register Process        *p = b->b_process;
+
+       if (!isdead(p))
+               complain("Process %s, attached to %b, is %s.",
+                        proc_cmd(p), b, pstate(p));
+}
+
+char   dbx_parse_fmt[128] = "line \\([0-9]*\\) in \\{file,\\} *\"\\([^\"]*\\)\"";
+
+void
+DBXpoutput()
+{
+       if (curbuf->b_process == NULL)
+               complain("[Must be in a process buffer to enable dbx mode]");
+       curbuf->b_process->p_dbx_mode = !curbuf->b_process->p_dbx_mode;
+       UpdModLine = YES;
+}
+
+private void
+watch_input(m)
+Mark   *m;
+{
+       Bufpos  save;
+       char    fname[FILESIZE],
+               lineno[FILESIZE];
+       int     lnum;
+       Window  *savew = curwind;
+       Buffer  *buf;
+
+       DOTsave(&save);
+       ToMark(m);
+       if (dosearch(dbx_parse_fmt, FORWARD, YES) != NULL) {
+               get_FL_info(fname, lineno);
+               buf = do_find((Window *)NULL, fname, YES);
+               pop_wind(buf->b_name, NO, -1);
+               lnum = atoi(lineno);
+               SetLine(next_line(buf->b_first, lnum - 1));
+               SetWind(savew);
+       }
+       SetDot(&save);
+}
+
+/* Process receive: receives the characters in buf, and appends them to
+   the buffer associated with p. */
+
+private void
+proc_rec(p, buf)
+register Process       *p;
+char   *buf;
+{
+       Buffer  *saveb = curbuf;
+       register Window *w;
+       register Mark   *savepoint;
+       int     sameplace = NO,
+               do_disp = NO;
+
+       if (curwind->w_bufp == p->p_buffer)
+               w = curwind;
+       else
+               w = windbp(p->p_buffer);        /* Is this window visible? */
+       if (w != NULL)
+               do_disp = (in_window(w, p->p_mark->m_line) != -1);
+       SetBuf(p->p_buffer);
+       savepoint = MakeMark(curline, curchar, M_FLOATER);
+       ToMark(p->p_mark);              /* where output last stopped */
+       if (savepoint->m_line == curline && savepoint->m_char == curchar)
+               sameplace = YES;
+       ins_str(buf, YES);
+       if (do_disp == YES && p->p_dbx_mode == YES)
+               watch_input(p->p_mark);
+       MarkSet(p->p_mark, curline, curchar);
+       if (!sameplace)
+               ToMark(savepoint);      /* back to where we were */
+       DelMark(savepoint);
+       /* redisplay now, instead of right after the ins_str, so that
+          we don't get a bouncing effect if point is not the same as
+          the process output position */
+       if (do_disp) {
+               w->w_line = curline;
+               w->w_char = curchar;
+               redisplay();
+       }
+       SetBuf(saveb);
+}
+
+private void
+proc_kill(p, sig)
+register Process       *p;
+int    sig;
+{
+       if (isdead(p))
+               return;
+       if (killpg(p->p_pid, sig) == -1)
+               s_mess("Cannot kill %s!", proc_buf(p));
+}
+
+/* Free process CHILD.  Do all the necessary cleaning up (closing fd's,
+   etc.). */
+
+private void
+free_proc(child)
+Process        *child;
+{
+       register Process        *p,
+                               *prev = NULL;
+
+       if (!isdead(child))
+               return;
+       for (p = procs; p != child; prev = p, p = p->p_next)
+               ;
+       if (prev == NULL)
+               procs = child->p_next;
+       else
+               prev->p_next = child->p_next;
+       proc_close(child);              /* if not already closed */
+
+       /* It's possible that the buffer has been given another process
+          between the time CHILD dies and CHILD's death is noticed (via
+          list-processes).  So we only set it the buffer's process to
+          NULL if CHILD is still the controlling process. */
+       if (child->p_buffer->b_process == child) {
+               child->p_buffer->b_process = NULL;
+       }
+       {
+               Buffer  *old = curbuf;
+
+               SetBuf(child->p_buffer);
+               DelMark(child->p_mark);
+               SetBuf(old);
+       }
+       free((UnivPtr) child->p_name);
+       free((UnivPtr) child);
+}
+
+void
+ProcList()
+{
+       register Process        *p,
+                               *next;
+       char    *fmt = "%-15s  %-15s  %-8s %s",
+               pidstr[16];
+
+       if (procs == NULL) {
+               message("[No subprocesses]");
+               return;
+       }
+       TOstart("Process list", TRUE);
+
+       Typeout(fmt, "Buffer", "Status", "Pid ", "Command");
+       Typeout(fmt, "------", "------", "--- ", "-------");
+       for (p = procs; p != NULL; p = next) {
+               next = p->p_next;
+               swritef(pidstr, sizeof(pidstr), "%d", p->p_pid);
+               Typeout(fmt, proc_buf(p), pstate(p), pidstr, p->p_name);
+               if (isdead(p)) {
+                       free_proc(p);
+                       UpdModLine = YES;
+               }
+       }
+       TOstop();
+}
+
+private void
+do_rtp(mp)
+register Mark  *mp;
+{
+       register Process        *p = curbuf->b_process;
+       Line    *line1 = curline,
+               *line2 = mp->m_line;
+       int     char1 = curchar,
+               char2 = mp->m_char;
+       char    *gp;
+       size_t  nbytes;
+
+       if (isdead(p) || p->p_buffer != curbuf)
+               return;
+
+       (void) fixorder(&line1, &char1, &line2, &char2);
+       while (line1 != line2->l_next) {
+               gp = ltobuf(line1, genbuf) + char1;
+               if (line1 == line2)
+                       gp[char2] = '\0';
+               else
+                       strcat(gp, "\n");
+               if ((nbytes = strlen(gp)) != 0)
+                       proc_write(p, gp, nbytes);
+               line1 = line1->l_next;
+               char1 = 0;
+       }
+}
+
+void
+ProcNewline()
+{
+#ifdef ABBREV
+       MaybeAbbrevExpand();
+#endif
+       SendData(YES);
+}
+
+void
+ProcSendData()
+{
+#ifdef ABBREV
+       MaybeAbbrevExpand();
+#endif
+       SendData(NO);
+}
+
+private void
+SendData(newlinep)
+int    newlinep;
+{
+       register Process        *p = curbuf->b_process;
+       register char   *lp,
+                       *gp;    /* JF fix for better prompt handling */
+
+       if (isdead(p))
+               return;
+       /* If the process mark was involved in a big deletion, because
+          the user hit ^W or something, then let's do some magic with
+          the process mark.  Problem is that if the user yanks back the
+          text he deleted, the mark stays at the beginning of the region,
+          and so the next time SendData() is called the entire region
+          will be sent.  That's not good.  So, to deal with that we reset
+          the mark to the last line, after skipping over the prompt, etc. */
+       if (p->p_mark->m_flags & M_BIG_DELETE) {
+               Bufpos  bp;
+
+               p->p_mark->m_flags &= ~M_BIG_DELETE;
+
+               DOTsave(&bp);
+               ToLast();
+               Bol();
+               /* While we're looking at a prompt, and while we're
+                  moving forward.  This is for people who accidently
+                  set their process-prompt to ">*" which will always
+                  match! */
+               while (LookingAt(proc_prompt, linebuf, curchar)
+               && (REeom > curchar))
+                       curchar = REeom;
+               MarkSet(p->p_mark, curline, curchar);
+               SetDot(&bp);
+       }
+
+       if (lastp(curline)) {
+               Eol();
+               if (newlinep)
+                       LineInsert(1);
+               do_rtp(p->p_mark);
+               MarkSet(p->p_mark, curline, curchar);
+       } else {
+               /* Either we're looking at a prompt, or we're not, in
+                  which case we want to strip off the beginning of the
+                  line anything that looks like what the prompt at the
+                  end of the file is.  In other words, if "(dbx) stop in
+                  ProcessNewline" is the line we're on, and the last
+                  line in the buffer is "(dbx) ", then we strip off the
+                  leading "(dbx) " from this line, because we know it's
+                  part of the prompt.  But this only happens if "(dbx) "
+                  isn't one of the process prompts ... follow what I'm
+                  saying? */
+               Bol();
+               if (LookingAt(proc_prompt, linebuf, curchar)) {
+                       do {
+                               curchar = REeom;
+                       } while (LookingAt(proc_prompt, linebuf, curchar)
+                       && (REeom > curchar));
+                       strcpy(genbuf, linebuf + curchar);
+                       Eof();
+                       ins_str(genbuf, NO);
+               } else {
+                       strcpy(genbuf, linebuf + curchar);
+                       Eof();
+                       gp = genbuf;
+                       lp = linebuf;
+                       while (*lp == *gp && *lp != '\0') {
+                               lp += 1;
+                               gp += 1;
+                       }
+                       ins_str(gp, NO);
+               }
+       }
+}
+
+void
+ShellProc()
+{
+       char    *shbuf = "*shell*";
+       register Buffer *b;
+
+       b = buf_exists(shbuf);
+       if (b == NULL || isdead(b->b_process))
+               proc_strt(shbuf, NO, Shell, "-i", (char *)NULL);
+       pop_wind(shbuf, NO, -1);
+}
+
+void
+Iprocess()
+{
+       register char   *command;
+       char    scratch[64],
+               *bnm;
+       int     cnt = 1;
+       Buffer  *bp;
+
+       command = ask(ShcomBuf, ProcFmt);
+       null_ncpy(ShcomBuf, command, (sizeof ShcomBuf) - 1);
+       bnm = MakeName(command);
+       strcpy(scratch, bnm);
+       while ((bp = buf_exists(scratch)) != NULL && !isdead(bp->b_process))
+               swritef(scratch, sizeof(scratch), "%s.%d", bnm, cnt++);
+       proc_strt(scratch, YES, Shell, ShFlags, command, (char *)NULL);
+}
+
+private SIGRESULT
+proc_child(junk)
+int    junk;   /* needed for signal handler; not used */
+{
+       int save_errno = errno; /* Subtle, but necessary! */
+       union wait      w;
+       register int    pid;
+
+       for (;;) {
+#ifndef        WAIT3
+               pid = wait2(&w.w_status, (WNOHANG | WUNTRACED));
+#else
+               pid = wait3(&w, (WNOHANG | WUNTRACED), (struct rusage *)NULL);
+#endif
+               if (pid <= 0)
+                       break;
+               kill_off(pid, w);
+       }
+       errno = save_errno;
+       SIGRETURN;
+}
+
+void
+kill_off(pid, w)
+register int   pid;
+union wait     w;
+{
+       register Process        *child;
+
+       if ((child = proc_pid(pid)) == 0)
+               return;
+
+       UpdModLine = YES;               /* we're changing state ... */
+       if (WIFSTOPPED(w))
+               child->p_state = STOPPED;
+       else {
+               child->p_state = DEAD;
+               if (WIFEXITED(w))
+                       child->p_howdied = EXITED;
+               else if (WIFSIGNALED(w)) {
+                       child->p_reason = w_termsignum(w);
+                       child->p_howdied = KILLED;
+               }
+               {
+                       Buffer  *save = curbuf;
+                       char    mesg[128];
+
+                       /* insert status message now */
+                       swritef(mesg, sizeof(mesg), "[Process %s: %s]\n",
+                               proc_cmd(child),
+                               pstate(child));
+                       SetBuf(child->p_buffer);
+                       ins_str(mesg, NO);
+                       SetBuf(save);
+                       redisplay();
+               }
+       }
+}
+
+#endif /* IPROCS */
diff --git a/usr/src/contrib/jove-4.14.6/iproc.h b/usr/src/contrib/jove-4.14.6/iproc.h
new file mode 100644 (file)
index 0000000..4d096d4
--- /dev/null
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+struct process {
+       Process *p_next;
+#ifdef PIPEPROCS
+       int     p_toproc,       /* read p_fromproc and write p_toproc */
+               p_portpid,      /* pid of child (the portsrv) */
+               p_pid;          /* pid of real child i.e. not portsrv */
+#else
+       int     p_fd,           /* file descriptor of pty? opened r/w */
+               p_pid;          /* pid of child (the shell) */
+#endif
+       Buffer  *p_buffer;      /* add output to end of this buffer */
+       char    *p_name;        /* ... */
+       char    p_state,        /* State */
+               p_howdied,      /* Killed? or Exited? */
+               p_reason;       /* If signaled, p_reason is the signal; else
+                                  it is the the exit code */
+       Mark    *p_mark;        /* where output left us */
+       char    p_dbx_mode;     /* whether to parse output for file/lineno
+                                  pairs */
+};
+
+extern int  NumProcs;
+
+#ifdef PIPEPROCS
+extern File    *ProcInput;
+extern int     kbd_pid;
+#else
+fd_set global_fd;
+#endif
+
+extern void
+#ifdef PIPEPROCS
+       read_proc proto((int, int)),
+#else
+       read_proc proto((int)),
+#endif
+       pinit proto((void)),
+       KillProcs proto((void)),
+       pbuftiedp proto((Buffer *));
+
+extern char *
+       pstate proto((Process *));
diff --git a/usr/src/contrib/jove-4.14.6/jove.c b/usr/src/contrib/jove-4.14.6/jove.c
new file mode 100644 (file)
index 0000000..3a7c0f0
--- /dev/null
@@ -0,0 +1,1571 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* Contains the main loop initializations, and some system dependent
+   type things, e.g. putting terminal in CBREAK mode, etc. */
+
+#include "jove.h"
+#include "fp.h"
+#include "termcap.h"
+#include "ctype.h"
+#include "chars.h"
+#include "disp.h"
+#include "re.h"        /* for find_tag() */
+#include "rec.h"
+#ifdef IPROCS
+# include "iproc.h"
+#endif
+
+#ifdef UNIX
+#include "ttystate.h"
+#endif
+
+#ifdef SCO
+#undef TIOCGWINSZ
+
+#include <sys/stream.h>
+#include <sys/ptem.h>
+#endif
+
+#ifdef MAC
+# include "mac.h"
+#else
+# ifdef        STDARGS
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+# include <sys/stat.h>
+#endif
+
+#include <signal.h>
+#include <errno.h>
+
+#ifdef MSDOS
+# include <process.h>
+#endif /* MSDOS */
+
+#ifndef        MAC
+# include <fcntl.h>
+#endif
+
+#ifdef MSDOS
+private        void    break_off proto((void)),
+               break_rst proto((void));
+#endif
+
+#ifdef MAC
+# define       WINRESIZE       1
+#else
+# ifdef        TIOCGWINSZ
+#   ifdef      SIGWINCH
+#     define   WINRESIZE       1
+#   endif
+# endif
+#endif
+
+private void
+       DoKeys proto((bool firsttime));
+
+#ifdef MSDOS
+extern
+#else
+private
+#endif
+    void
+       UnsetTerm proto((char *)),
+       do_sgtty proto((void));
+
+/* Various tty state structures.
+ * Each is an array, subscripted by one of "OFF" or "ON".
+ */
+
+#ifdef UNIX
+
+# ifdef        TIOCSLTC
+struct ltchars ls[2];
+# endif        /* TIOCSLTC */
+
+# ifdef        TIOCGETC
+struct tchars  tc[2];
+# endif
+
+# ifdef        PASS8                   /* use pass8 instead of raw for meta-key */
+private int    lmword[2];              /* local mode word */
+# endif
+
+# ifdef        BRLUNIX
+struct sg_brl  sg[2];
+#endif
+#ifdef TERMIO
+struct termio  sg[2];
+#endif
+#ifdef TERMIOS
+struct termios sg[2];
+#endif
+#ifdef SGTTY
+struct sgttyb  sg[2];
+#endif
+
+# ifdef        BIFF
+private struct stat    tt_stat;        /* for biff */
+#  ifndef      BSD4_2
+private char   *tt_name = NULL;                /* name of the control tty */
+extern char    *ttyname();             /* for systems w/o fchmod ... */
+#  endif
+private bool   dw_biff = NO;           /* whether or not to fotz at all */
+# endif        /* BIFF */
+#endif /* UNIX */
+
+bool   errormsg;
+char   NullStr[] = "";
+jmp_buf        mainjmp;
+
+
+#ifdef MSDOS
+# define SIGHUP        99
+# define SIGIOT 99
+#endif /* MSDOS */
+
+/* finish() does not return, so it is funny that it returns a non-void
+ * result.  This is because most systems claim that signal(2) deals
+ * with functions of type int ().  ANSI changes this: the function
+ * type must be void (int).  This bridge must soon be crossed.
+ */
+SIGRESULT
+finish(code)
+int    code;
+{
+       int save_errno = errno; /* Subtle, but necessary! */
+       static int      Crashing = 0;   /* we are in the middle of crashing */
+       bool    CoreDump = (code != 0 && code != SIGHUP),
+               DelTmps = YES;          /* Usually we delete them. */
+
+       if (code == SIGINT) {
+               char    c;
+#ifdef PIPEPROCS
+               int     started;
+#endif
+#ifndef        MENLO_JCL
+               (void) signal(code, finish);
+#endif
+               f_mess("Abort (Type 'n' if you're not sure)? ");
+#ifndef        MSDOS
+# ifdef        PIPEPROCS
+               started = kbd_stop();
+# endif
+#ifdef SYSV
+               if (read(0, (UnivPtr) &c, (size_t) 1) != 1)
+#endif
+                       (void) read(0, (UnivPtr) &c, (size_t) 1);
+# ifdef        PIPEPROCS
+               if (started)
+                       (void) kbd_strt();
+# endif
+#else  /* MSDOS */
+               c = getrawinchar();
+#endif /* MSDOS */
+               message(NullStr);
+               if ((c & 0377) != 'y') {
+                       redisplay();
+                       errno = save_errno;
+                       SIGRETURN;
+               }
+       }
+       DisabledRedisplay = YES;
+#ifndef        MAC
+       UnsetTerm(NullStr);
+#endif
+#ifdef PIPEPROCS
+       kbd_kill();             /* kill the keyboard process */
+#endif
+#ifndef        MSDOS
+       if (code != 0) {
+               if (!Crashing) {
+                       Crashing = YES;
+                       lsave();
+                       SyncRec();
+                       writef("JOVE CRASH!! (code %d): %s\n", code,
+                              strerror(errno));
+                       if (ModBufs(YES)) {
+                               writef("Your buffers have been saved.\n");
+                               writef("Use \"jove -r\" to have a look at them.\n");
+                               DelTmps = NO;   /* Don't delete anymore. */
+                       } else
+                               writef("You didn't lose any work.\n");
+               } else
+                       writef("\r\nYou may have lost your work!\n");
+       }
+#endif /* MSDOS */
+       flushscreen();
+       if (DelTmps) {
+#ifdef PTYPROCS
+               (void) signal(SIGCHLD, SIG_IGN);
+#endif
+               tmpremove();
+#ifndef        MSDOS
+               recremove();
+#endif /* MSDOS */
+       }
+#ifdef UNIX
+       if (CoreDump)
+               abort();
+#ifdef PROFILING
+       exit(0);
+#else
+       _exit(0);
+#endif
+#else  /* !UNIX */
+#ifdef MSDOS
+       break_rst();    /* restore previous ctrl-c handling */
+#endif
+       exit(0);
+#endif /* !UNIX */
+       /*NOTREACHED*/
+}
+
+private char   smbuf[20],
+               *bp = smbuf;
+private int    nchars = 0;
+
+private char   peekbuf[10],
+               *peekp = peekbuf;
+
+#if    defined(SYSV) || defined(M_XENIX)
+
+#define        NONBLOCKINGREAD 1
+
+private void
+setblock(fd, on)       /* turn blocking on or off */
+register int   fd;
+bool   on;
+{
+    static int blockf, nonblockf;
+    static bool        first = TRUE;
+
+    if (first) {
+       int flags;
+
+       first = FALSE;
+       if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
+           finish(SIGHUP);
+       blockf = flags & ~O_NDELAY;     /* make sure O_NDELAY is off */
+       nonblockf = flags | O_NDELAY;   /* make sure O_NDELAY is on */
+    }
+    if (fcntl(fd, F_SETFL, on ? blockf : nonblockf) == -1)
+       finish(SIGHUP);
+}
+
+#endif /* defined(SYSV) || defined(M_XENIX) */
+
+private int
+Peekc()
+{
+       return peekp == peekbuf? EOF : *--peekp & 0377;
+}
+
+void
+Ungetc(c)
+int    c;
+{
+       if (peekp != &peekbuf[(sizeof peekbuf) - 1])
+               *peekp++ = c;
+}
+
+bool   InputPending = NO;
+
+char   *Inputp = NULL;
+
+#ifdef PTYPROCS
+int
+jgetchar()
+{
+
+       fd_set          reads;
+       register int    max = getdtablesize();
+       register int    tmp,
+                       nfds;
+       int             c;
+
+       if (nchars <= 0) {
+               /* Get a character from the keyboard, first checking for
+                  any input from a process.  Handle that first, and then
+                  deal with the terminal input. */
+               do {
+                       do {
+                               reads = global_fd;
+                               nfds = select(max, &reads, (fd_set *)0, (fd_set *)0, (struct timeval *)NULL);
+                       } while (nfds < 0 && errno == EINTR);
+
+                       if (nfds == -1)
+                               complain("\rerror in select %ld: %s", global_fd, strerror(errno));
+                       else {
+                               if (FD_ISSET(0, &reads)) {
+                                       nchars = read(0, (UnivPtr) smbuf, sizeof(smbuf));
+                                       FD_CLR(0, &reads);
+                                       nfds--;
+                               }
+                               for (tmp = 1; tmp < max; tmp++) {
+                                       if (FD_ISSET(tmp, &reads)) {
+                                               read_proc(tmp);
+                                               FD_CLR(tmp, &reads);
+                                               if (--nfds == 0)
+                                                       break;
+                                       }
+                               }
+                       }
+               } while (nchars <= 0);
+
+               if (nchars <= 0)
+                       finish(SIGHUP);
+
+               bp = smbuf;
+               InputPending = (nchars > 1);
+       }
+
+       if (((c = *bp) & 0200) && MetaKey) {
+               *bp = (c & CHARMASK);
+               return '\033';
+       }
+       nchars -= 1;
+       return *bp++ & 0377;
+}
+
+#else  /* !PTYPROCS */
+
+int
+jgetchar()
+{
+       register int    c;
+       struct header {
+               int     pid;
+               int     nbytes;
+       } header;
+
+normal:
+       if (nchars <= 0) {
+               bp = smbuf;
+#ifdef MSDOS
+               *bp = getrawinchar();
+               nchars = 1;
+#else  /* !MSDOS */
+# ifdef        IPROCS
+               if (NumProcs > 0) {
+                       for (;;) {
+                               size_t  n = f_readn(ProcInput, (char *) &header,
+                                           sizeof(header));
+
+                               if (n != sizeof(header)) {
+                                       raw_complain("\r\nError reading kbd process, expected %d, got %d bytes\r\n", sizeof header, n);
+                                       finish(SIGHUP);
+                               }
+                               /* data is from the keyboard process */
+                               if (header.pid == kbd_pid) {
+                                       nchars = f_readn(ProcInput, smbuf, header.nbytes);
+                                       if (nchars != header.nbytes) {
+                                               raw_complain("\r\nError reading kbd process, expected %d, got %d bytes.\r\n", header.nbytes, nchars);
+                                               finish(SIGHUP);
+                                       }
+                                       break;
+                               }
+                               read_proc(header.pid, header.nbytes);
+                               if (NumProcs == 0) {
+                                       (void) kbd_stop();
+                                       goto normal;
+                               }
+                       }
+               } else /*...*/
+# endif
+               /*...*/ {
+                       for (;;) {
+                               nchars = read(0, (UnivPtr) smbuf, sizeof smbuf);
+                               if (nchars > 0)
+                                       break;
+# ifdef        SYSV
+                               /* System V seems to allow zero-length results */
+                               if (nchars == 0)
+                                       continue;
+# endif        /* SYSV */
+                               /* retry on interrupt */
+                               if (!(nchars < 0 && errno == EINTR))
+                                       finish(SIGHUP);
+                       }
+               }
+#endif /* !MSDOS */
+               InputPending = nchars > 0;
+       }
+       if (((c = *bp) & 0200) && MetaKey) {
+               *bp = (c & CHARMASK);
+               return '\033';
+       }
+       nchars -= 1;
+       return (*bp++ & CHARMASK);
+}
+
+#endif /* !PTYPROCS */
+
+/* Returns non-zero if a character waiting */
+
+bool
+charp()
+{
+       bool    some = NO;
+
+       if (InJoverc != 0 || nchars > 0 || Inputp != NULL)
+               return YES;
+#ifdef BRLUNIX
+       {
+               static struct sg_brl gttyBuf;
+
+               gtty(0, (char *) &gttyBuf);
+               if (gttyBuf.sg_xflags & INWAIT)
+                       some = YES;
+       }
+#else
+#ifdef FIONREAD
+       {
+               long c;
+
+               if (ioctl(0, FIONREAD, (UnivPtr) &c) == -1)
+                       c = 0;
+               some = (c > 0);
+       }
+#else
+#ifdef NONBLOCKINGREAD
+       setblock(0, OFF);               /* turn blocking off */
+       nchars = read(0, (UnivPtr) smbuf, sizeof smbuf);        /* Is anything there? */
+       setblock(0, ON);                /* turn blocking on */
+       if (nchars > 0)         /* something was there */
+           bp = smbuf;         /* make sure bp points to it */
+       some = (nchars > 0);    /* just say we found something */
+#else
+#ifdef c70
+       some = !empty(0);
+#else
+#ifdef MSDOS
+       some = rawkey_ready();
+#else
+#ifdef MAC
+       some = rawchkc();
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+       return some;
+}
+
+#ifdef BIFF
+private void   biff_init proto((void));
+#endif
+
+#ifdef TERMCAP
+
+private void
+ResetTerm()
+{
+       do_sgtty();             /* this is so if you change baudrate or stuff
+                                  like that, JOVE will notice. */
+       ttyset(ON);
+       putpad(TI, 1);
+       putpad(VS, 1);
+       putpad(KS, 1);
+#ifdef UNIX
+       (void) chkmail(YES);    /* force it to check to we can be accurate */
+#endif
+#ifdef BIFF
+       if (BiffChk != dw_biff)
+               biff_init();
+       /* just in case we changed our minds about whether to deal with
+          biff */
+#endif
+}
+
+private void
+UnsetTerm(mesg)
+char   *mesg;
+{
+       ttyset(OFF);
+#ifdef ID_CHAR
+       INSmode(NO);
+#endif
+       putpad(KE, 1);
+       putpad(VE, 1);
+       Placur(ILI, 0);
+       putpad(CE, 1);
+       if (TE)
+               putpad(TE, 1);
+       if (mesg[0] != '\0')
+               writef("%s\n", mesg);
+       flushscreen();
+}
+#endif /* TERMCAP */
+
+#ifdef JOB_CONTROL
+void
+PauseJove()
+{
+       UnsetTerm(ModBufs(NO) ? "[There are modified buffers]" : NullStr);
+       (void) kill(0, SIGTSTP);
+       ResetTerm();
+       ClAndRedraw();
+}
+#endif
+
+
+#ifndef        MAC
+void
+jcloseall()
+{
+       tmpclose();
+#ifdef UNIX
+       recclose();
+#endif
+#ifdef LOAD_AV
+       closekmem();
+#endif /* LOAD_AV */
+}
+
+void
+Push()
+{
+#ifndef        MSDOS
+       int     pid;
+       SIGRESULT       (*old_quit) ptrproto((int)) = signal(SIGQUIT, SIG_IGN);
+#endif /* !MSDOS */
+       SIGRESULT       (*old_int) ptrproto((int)) = signal(SIGINT, SIG_IGN);
+# ifdef        PIPEPROCS
+       int     started;
+# endif
+
+#ifndef        MSDOS
+#ifdef IPROCS
+       SigHold(SIGCHLD);
+#endif
+#ifdef WINRESIZE
+       SigHold(SIGWINCH);
+#endif
+       alarm((unsigned)0);
+# ifdef        PIPEPROCS
+       started = kbd_stop();
+# endif
+       switch (pid = fork()) {
+       case -1:
+# ifdef        PIPEPROCS
+               if (started)
+                       (void) kbd_strt();
+# endif
+               complain("[Fork failed: %s]", strerror(errno));
+               /*NOTREACHED*/
+
+       case 0:
+               UnsetTerm(ModBufs(NO) ? "[There are modified buffers]" : NullStr);
+#ifdef WINRESIZE
+               SigRelse(SIGWINCH);
+#endif
+#ifdef IPROCS
+               SigRelse(SIGCHLD);
+#endif
+               (void) signal(SIGTERM, SIG_DFL);
+#else  /* MSDOS */
+               UnsetTerm(ModBufs(NO) ? "[There are modified buffers]" : NullStr);
+#endif /* MSDOS */
+               (void) signal(SIGINT, SIG_DFL);
+#ifdef UNIX
+               (void) signal(SIGQUIT, SIG_DFL);
+               jcloseall();
+               /* note that curbuf->bfname may be NULL */
+               execl(Shell, basename(Shell), "-is", pr_name(curbuf->b_fname, NO),
+                       (char *)NULL);
+               raw_complain("[Execl failed: %s]", strerror(errno));
+               _exit(1);
+       }
+#ifdef IPROCS
+       SigRelse(SIGCHLD);
+#endif
+       dowait(pid, (int *) NULL);
+#endif /* UNIX */
+#ifdef MSDOS
+       break_rst();
+       if (spawnl(0, Shell, basename(Shell), (char *)NULL) == -1)
+               message("[Spawn failed]");
+#endif /* MSDOS */
+#ifndef        MAC
+       ResetTerm();
+#endif
+#ifdef WINRESIZE
+       SigRelse(SIGWINCH);
+#endif
+       ClAndRedraw();
+#ifndef        MSDOS
+       (void) signal(SIGQUIT, old_quit);
+#else  /* MSDOS */
+       break_off();
+       getCWD();
+#endif /* MSDOS */
+       (void) signal(SIGINT, old_int);
+#ifdef UNIX
+       if (UpdFreq != 0)
+               (void) alarm((unsigned) (UpdFreq - (time((time_t *)NULL) % UpdFreq)));
+#endif
+# ifdef        PIPEPROCS
+       if (started)
+               (void) kbd_strt();
+# endif
+}
+#endif /* MAC */
+
+bool   OKXonXoff = OFF;        /* ^S and ^Q initially DON'T work */
+int    IntChar = CTL(']');
+
+private void
+ttsize()
+{
+#ifdef UNIX
+#   ifdef      TIOCGWINSZ
+       struct winsize win;
+
+       if (ioctl(0, TIOCGWINSZ, (UnivPtr) &win) == 0) {
+               if (win.ws_col)
+                       CO = win.ws_col;
+               if (win.ws_row)
+                       LI = win.ws_row;
+       }
+#   else       /* !TIOCGWINSZ */
+#      ifdef   BTL_BLIT
+#include <sys/jioctl.h>
+       struct jwinsize jwin;
+
+       if (ioctl(0, JWINSIZE, &jwin) == 0) {
+               if (jwin.bytesx)
+                       CO = jwin.bytesx;
+               if (jwin.bytesy)
+                       LI = jwin.bytesy;
+       }
+#      endif   /* BTL_BLIT */
+#   endif      /* !TIOCGWINSZ */
+#endif /* UNIX */
+#ifdef MAC
+       CO = getCO();   /* see mac.c */
+       LI = getLI();
+       Windchange = YES;
+       clr_page();
+#endif
+       ILI = LI - 1;
+}
+
+#ifdef BIFF
+private void
+biff_init()
+{
+       dw_biff = ((BiffChk) &&
+#   ifndef     BSD4_2
+                  ((tt_name != NULL) || (tt_name = ttyname(0))) &&
+                  (stat(tt_name, &tt_stat) != -1) &&
+#   else
+                  (fstat(0, &tt_stat) != -1) &&
+#   endif
+                  (tt_stat.st_mode & S_IEXEC));        /* he's using biff */
+
+}
+
+private void
+biff(on)
+int    on;
+{
+       if (dw_biff == NO)
+               return;
+#   ifndef     BSD4_2
+       (void) chmod(tt_name, on ? tt_stat.st_mode :
+                                  (tt_stat.st_mode & ~S_IEXEC));
+#   else
+       (void) fchmod(0, on ? tt_stat.st_mode :
+                             (tt_stat.st_mode & ~S_IEXEC));
+#   endif
+}
+
+#endif /* BIFF */
+
+private void
+ttinit()
+{
+#ifdef BIFF
+       biff_init();
+#endif
+#ifdef TIOCSLTC
+       (void) ioctl(0, TIOCGLTC, (UnivPtr) &ls[OFF]);
+       ls[ON] = ls[OFF];
+       ls[ON].t_suspc = (char) -1;
+       ls[ON].t_dsuspc = (char) -1;
+       ls[ON].t_flushc = (char) -1;
+       ls[ON].t_lnextc = (char) -1;
+#endif
+
+#ifdef TIOCGETC
+       /* Change interupt and quit. */
+       (void) ioctl(0, TIOCGETC, (UnivPtr) &tc[OFF]);
+       tc[ON] = tc[OFF];
+       tc[ON].t_intrc = IntChar;
+       tc[ON].t_quitc = (char) -1;
+       if (OKXonXoff) {
+               tc[ON].t_stopc = (char) -1;
+               tc[ON].t_startc = (char) -1;
+       }
+#endif /* TIOCGETC */
+       do_sgtty();
+}
+
+private int    done_ttinit = NO;
+
+#ifndef        MSDOS
+private
+#endif
+void
+do_sgtty()
+{
+#ifdef UNIX
+# ifdef        TERMIO
+       (void) ioctl(0, TCGETA, (char *) &sg[OFF]);
+# endif
+# ifdef TERMIOS
+       (void) tcgetattr(0, &sg[OFF]);
+# endif
+
+# ifdef SGTTY
+       (void) gtty(0, &sg[OFF]);
+# endif        /* SYSV */
+       sg[ON] = sg[OFF];
+
+# ifdef        LPASS8
+       (void) ioctl(0, TIOCLGET, (UnivPtr) &lmword[OFF]);
+       lmword[ON] = lmword[OFF];
+       if (MetaKey)
+               lmword[ON] |= LPASS8;
+# endif
+
+# ifdef LTILDE
+       if (Hazeltine)
+               lmword[ON] &= ~LTILDE;
+# endif
+
+# if defined(TERMIO) || defined(TERMIOS)
+#ifdef TAB3
+       TABS = !((sg[OFF].c_oflag & TAB3) == TAB3);
+#endif
+#ifdef CBAUD
+       ospeed = sg[OFF].c_cflag & CBAUD;
+#endif
+       if (OKXonXoff)
+               sg[ON].c_iflag &= ~(IXON | IXOFF);
+       sg[ON].c_iflag &= ~(INLCR|ICRNL|IGNCR|ISTRIP);
+       /* sg[ON].c_lflag &= ~(ICANON|ECHO); */
+       sg[ON].c_cflag &= ~(CSIZE|PARENB);
+       sg[ON].c_cflag |= CS8;
+       sg[ON].c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
+#ifndef OCRNL
+#define OCRNL 0
+#endif
+       sg[ON].c_oflag &= ~(OCRNL|ONLCR);
+#  ifdef _POSIX_VDISABLE
+       /* The following characters cause signals in System Vr4.
+        * We should perhaps handle them; for now, we suppress them.
+        */
+       sg[ON].c_cc[VQUIT] = _POSIX_VDISABLE;
+#ifdef VSWTCH
+       sg[ON].c_cc[VSWTCH] = _POSIX_VDISABLE;
+#endif
+       sg[ON].c_cc[VSUSP] = _POSIX_VDISABLE;
+       sg[ON].c_cc[VDSUSP] = _POSIX_VDISABLE;
+#  else
+       sg[ON].c_cc[VINTR] = IntChar;
+       sg[ON].c_cc[VQUIT] = (char) -1;
+#  endif /* _POSIX_VDISABLE */
+       sg[ON].c_cc[VMIN] = 1;
+       sg[ON].c_cc[VTIME] = 1;
+# endif /* TERMIO || TERMIOS */
+
+# if defined(SGTTY) || defined(BRLUNIX)
+       TABS = !(sg[OFF].sg_flags & XTABS);
+       sg[ON].sg_flags &= ~XTABS;
+       ospeed = sg[OFF].sg_ospeed;
+#  ifdef       BRLUNIX
+       sg[ON].sg_flags &= ~(ECHO | CRMOD);
+       sg[ON].sg_flags |= CBREAK;
+
+       /* VT100 Kludge: leave STALL on for flow control if DC3DC1 (Yuck.) */
+       sg[ON].sg_xflags &= ~((sg[ON].sg_xflags&DC3DC1 ? 0 : STALL) | PAGE);
+#  else
+       sg[ON].sg_flags &= ~(ECHO | CRMOD);
+#  endif       /* BRLUNIX */
+
+#  ifdef       LPASS8
+       sg[ON].sg_flags |= CBREAK;
+#  else
+       sg[ON].sg_flags |= (MetaKey ? RAW : CBREAK);
+#  endif
+# endif        /* SGTTY */
+#endif /* UNIX */
+
+#ifdef MSDOS
+# ifndef       IBMPC
+       setmode(1, 0x8000);
+# endif        /* IBMPC */
+       TABS = NO;
+#endif /* MSDOS */
+}
+
+void
+tty_reset()
+{
+       if (!done_ttinit)
+               return;
+       ttyset(OFF);    /* go back to original modes */
+       ttinit();
+       ttyset(ON);
+}
+
+/* If n is OFF reset to original modes */
+
+void
+ttyset(n)
+bool   n;
+{
+       if (!done_ttinit && !n) /* Try to reset before we've set! */
+               return;
+#ifdef UNIX
+# ifdef        TERMIO
+       (void) ioctl(0, TCSETAW, (UnivPtr) &sg[n]);
+# endif        /* TERMIO */
+
+# ifdef        TERMIOS
+       (void) tcsetattr(0, TCSADRAIN, &sg[n]);
+# endif /* TERMIOS */
+
+# ifdef        SGTTY
+#  ifdef TIOCSETN
+       (void) ioctl(0, TIOCSETN, (UnivPtr) &sg[n]);
+#  else
+       (void) stty(0, &sg[n]);
+#  endif
+# endif
+
+# ifdef        TIOCGETC
+       (void) ioctl(0, TIOCSETC, (UnivPtr) &tc[n]);
+# endif        /* TIOCSETC */
+# ifdef        TIOCSLTC
+       (void) ioctl(0, TIOCSLTC, (UnivPtr) &ls[n]);
+# endif        /* TIOCSLTC */
+# ifdef        LPASS8
+       (void) ioctl(0, TIOCLSET, (UnivPtr) &lmword[n]);
+# endif
+#endif /* UNIX */
+
+#ifdef MSDOS
+# ifndef       IBMPC
+       setmode(1, n? 0x8000 : 0x4000);
+# endif
+#endif /* MSDOS */
+       done_ttinit = YES;
+#ifdef BIFF
+       biff(!n);
+#endif
+}
+
+int    this_cmd,
+       last_cmd,
+       LastKeyStruck,
+       MetaKey = OFF;
+
+int
+getch()
+{
+       register int    c,
+                       peekc;
+
+       if (Inputp) {
+               if ((c = *Inputp++) != '\0')
+                       return LastKeyStruck = c;
+               Inputp = NULL;
+       }
+
+       if (InJoverc)
+               return EOF;     /* somethings wrong if Inputp runs out while
+                                  we're reading a .joverc file. */
+
+#ifndef        MSDOS
+       if (ModCount >= SyncFreq) {
+               ModCount = 0;
+               SyncRec();
+       }
+#endif /* MSDOS */
+
+       /* If there are no ungetc'd characters,
+          AND we're interactive or we're not executing a macro,
+          we read from the terminal (i.e., jgetchar()).
+          Note: characters only get put in macros from inside this if. */
+       if (((peekc = c = Peekc()) == EOF) &&
+           (Interactive || ((c = mac_getc()) == EOF))) {
+               /* So messages that aren't error messages don't
+                * hang around forever.
+                * Note: this code is duplicated in SitFor()!
+                */
+               if (!UpdMesg && !Asking && mesgbuf[0] != '\0' && !errormsg)
+                       message(NullStr);
+               redisplay();
+#ifdef UNIX
+               inIOread = YES;
+#endif
+               if ((c = jgetchar()) == EOF)
+                       finish(SIGHUP);
+#ifdef UNIX
+               inIOread = NO;
+#endif
+
+               if (!Interactive && InMacDefine)
+                       mac_putc(c);
+       }
+       if (peekc == EOF)       /* don't add_stroke peekc's */
+               add_stroke(c);
+       return LastKeyStruck = c;
+}
+
+#ifdef UNIX
+private void
+dorecover()
+{
+       /* Since recover is a normal cooked mode program, reset the terminal */
+       UnsetTerm(NullStr);
+#ifdef PIPEPROCS
+       kbd_kill();             /* kill the keyboard process */
+#endif
+       execl(Recover, "recover", "-d", TmpFilePath, (char *) NULL);
+       writef("%s: execl failed! %s\n", Recover, strerror(errno));
+       flushscreen();
+       _exit(-1);
+       /* NOTREACHED */
+}
+#endif /* UNIX */
+
+void
+ShowVersion()
+{
+       s_mess("Jonathan's Own Version of Emacs (%s)", version);
+}
+
+private void
+UNIX_cmdline(argc, argv)
+int    argc;
+char   *argv[];
+{
+       int     lineno = 0,
+               nwinds = 1;
+       Buffer  *b;
+
+       ShowVersion();
+       while (argc > 1) {
+               if (argv[1][0] != '-' && argv[1][0] != '+') {
+                       bool    force = (nwinds > 0 || lineno != 0);
+
+#ifdef MSDOS
+                       strlwr(argv[1]);
+#endif
+                       minib_add(argv[1], force);
+                       b = do_find(nwinds > 0 ? curwind : (Window *) NULL,
+                                   argv[1], force);
+                       if (force) {
+                               SetABuf(curbuf);
+                               SetBuf(b);
+                               if (lineno >= 0)
+                                       SetLine(next_line(curbuf->b_first, lineno));
+                               else
+                                       SetLine(curbuf->b_last);
+                               if (nwinds > 1)
+                                       NextWindow();
+                               if (nwinds)
+                                       nwinds -= 1;
+                       }
+                       lineno = 0;
+               } else  switch (argv[1][1]) {
+                       case 'd':
+                               argv += 1;
+                               argc -= 1;
+                               break;
+
+                       case 'j':       /* Ignore .joverc in HOME */
+                               break;
+#ifndef        MAC
+                       case 'p':
+                               argv += 1;
+                               argc -= 1;
+                               if (argv[1] != NULL) {
+                                       SetBuf(do_find(curwind, argv[1], NO));
+                                       ErrParse();
+                                       nwinds = 0;
+                               }
+                               break;
+#endif
+                       case 't':
+                               /* check if syntax is -tTag or -t Tag */
+                               if (argv[1][2] != '\0') {
+                                       find_tag(&(argv[1][2]), YES);
+                               } else {
+                                       argv += 1;
+                                       argc -= 1;
+                                       if (argv[1] != NULL)
+                                               find_tag(argv[1], YES);
+                               }
+                               break;
+
+                       case 'w':
+                               if (argv[1][2] == '\0')
+                                       nwinds += 1;
+                               else {
+                                       int     n;
+
+                                       (void) chr_to_int(&argv[1][2], 10, NO, &n);
+                                       nwinds += -1 + n;
+                               }
+                               (void) div_wind(curwind, nwinds - 1);
+                               break;
+
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               (void) chr_to_int(&argv[1][1], 10, NO, &lineno);
+                               lineno -= 1;
+                               break;
+                       case '\0':
+                               lineno = -1;    /* goto end of file ... */
+                               break;          /* just like some people's */
+               }                               /* favourite editor */
+               argv += 1;
+               argc -= 1;
+       }
+}
+
+void
+raw_scream(m)
+const char     *m;
+{
+       write(2, (UnivConstPtr)m, strlen(m));
+}
+
+#ifdef STDARGS
+void
+error(const char *fmt, ...)
+#else
+/*VARARGS1*/ void
+error(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       if (fmt) {
+               va_init(ap, fmt);
+               format(mesgbuf, sizeof mesgbuf, fmt, ap);
+               va_end(ap);
+               UpdMesg = YES;
+       }
+       rbell();
+       longjmp(mainjmp, ERROR);
+}
+
+#ifdef STDARGS
+void
+complain(const char *fmt, ...)
+#else
+/*VARARGS1*/ void
+complain(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       if (fmt) {
+               va_init(ap, fmt);
+               format(mesgbuf, sizeof mesgbuf, fmt, ap);
+               va_end(ap);
+               UpdMesg = YES;
+       }
+       rbell();
+       longjmp(mainjmp, COMPLAIN);
+}
+
+#ifdef STDARGS
+void
+raw_complain(const char *fmt, ...)
+#else
+/*VARARGS1*/ void
+raw_complain(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       if (fmt) {
+               va_init(ap, fmt);
+               format(mesgbuf, sizeof mesgbuf, fmt, ap);
+               va_end(ap);
+               raw_scream(mesgbuf);
+       }
+}
+
+#ifdef STDARGS
+void
+confirm(const char *fmt, ...)
+#else
+/*VARARGS1*/ void
+confirm(fmt, va_alist)
+       const char      *fmt;
+       va_dcl
+#endif
+{
+       char    *yorn;
+       va_list ap;
+
+       va_init(ap, fmt);
+       format(mesgbuf, sizeof mesgbuf, fmt, ap);
+       va_end(ap);
+       yorn = ask((char *)NULL, mesgbuf);
+       if (*yorn != 'Y' && *yorn != 'y')
+               longjmp(mainjmp, COMPLAIN);
+}
+
+int    RecDepth = 0;
+
+void
+Recur()
+{
+       char    bname[128];
+       Mark    *m;
+
+       swritef(bname, sizeof(bname), "%s", curbuf->b_name);
+       m = MakeMark(curline, curchar, M_FLOATER);
+
+       RecDepth += 1;
+       UpdModLine = YES;
+       DoKeys(NO);     /* NO means not first time */
+       UpdModLine = YES;
+       RecDepth -= 1;
+       SetBuf(do_select(curwind, bname));
+       if (!is_an_arg())
+               ToMark(m);
+       DelMark(m);
+}
+
+#ifdef MAC
+jmp_buf auxjmp;
+#endif
+
+private int    iniargc;        /* main sets these for DoKeys() */
+private char   **iniargv;
+
+private void
+DoKeys(firsttime)
+bool   firsttime;
+{
+       int     c;
+       jmp_buf savejmp;
+
+       push_env(savejmp);
+
+       switch (setjmp(mainjmp)) {
+       case 0:
+               if (firsttime)
+                       UNIX_cmdline(iniargc, iniargv);
+               break;
+
+       case QUIT:
+               if (RecDepth == 0) {
+                       if (ModMacs()) {
+                               rbell();
+                               if (CharUpcase(*ask("No",
+"Some MACROS haven't been saved; leave anyway? ")) != 'Y')
+                                       break;
+                       }
+                       if (ModBufs(NO)) {
+                               rbell();
+                               if (CharUpcase(*ask("No",
+"Some buffers haven't been saved; leave anyway? ")) != 'Y')
+                                       break;
+                       }
+#ifdef IPROCS
+                       KillProcs();
+#endif
+               }
+               pop_env(savejmp);
+               return;
+
+       case ERROR:
+               getDOT();       /* God knows what state linebuf was in */
+               /*FALLTHROUGH*/
+       case COMPLAIN:
+           {
+               gc_openfiles();         /* close any files we left open */
+               errormsg = YES;
+               unwind_macro_stack();
+               Asking = NO;
+               curwind->w_bufp = curbuf;
+               DisabledRedisplay = NO;
+               redisplay();
+               break;
+           }
+       }
+
+       this_cmd = last_cmd = 0;
+
+       for (;;) {
+#ifdef MAC
+               setjmp(auxjmp);
+#endif
+               if (this_cmd != ARG_CMD) {
+                       clr_arg_value();
+                       last_cmd = this_cmd;
+                       init_strokes();
+               }
+#ifdef MAC
+               HiliteMenu(0);
+               EventCmd = NO;
+               menus_on();
+#endif
+               c = getch();
+               if (c == EOF)
+                       continue;
+               dispatch(c);
+       }
+}
+
+private char **
+scanvec(args, str)
+register char  **args,
+               *str;
+{
+       while (*args) {
+               if (strcmp(*args, str) == 0)
+                       return args;
+               args += 1;
+       }
+       return NULL;
+}
+
+#ifdef UNIX
+int    UpdFreq = 30,
+       inIOread = NO;
+
+private SIGRESULT
+updmode(junk)
+int    junk;   /* passed in on signal; of no interest */
+{
+       int save_errno = errno; /* Subtle, but necessary! */
+
+       UpdModLine = YES;
+       if (inIOread)
+               redisplay();
+#ifndef        BSD_SIGS
+       (void) signal(SIGALRM, updmode);
+#endif
+       if (UpdFreq != 0)
+               (void) alarm((unsigned) (UpdFreq - (time((time_t *)NULL) % UpdFreq)));
+       errno = save_errno;
+       SIGRETURN;
+}
+#endif /* UNIX */
+
+#ifdef MSDOS
+# ifndef       IBMPC
+char   ttbuf[JBUFSIZ];
+# endif        /* IBMPC */
+#endif /* MSDOS */
+
+#ifdef WINRESIZE
+#ifndef        MAC
+private
+#endif
+SIGRESULT
+win_reshape(junk)
+int    junk;   /* passed in when invoked by a signal; of no interest */
+{
+       int save_errno = errno; /* Subtle, but necessary! */
+       register int    oldLI;
+       register int newsize, total;
+       register Window *wp;
+
+#ifdef UNIX
+       (void) SigHold(SIGWINCH);
+#endif
+       /*
+        * Save old number of lines.
+        */
+       oldLI = LI;
+
+       /*
+        * Get new line/col info.
+        */
+       ttsize();
+
+       /*
+        * LI has changed, and now holds the
+        * new value.
+        */
+       /*
+        *  Go through the window list, changing each window size in
+        *  proportion to the resize. If a window becomes too small,
+        *  delete it. We keep track of all the excess lines (caused by
+        *  roundoff!), and give them to the current window, as a sop -
+        *  can't be more than one or two lines anyway. This seems fairer
+        *  than just resizing the current window.
+        */
+       wp = fwind;
+       total = 0;
+       do {
+               newsize = LI * wp->w_height / oldLI;
+
+               if (newsize < 2) {
+                       total += wp->w_height;
+                       wp = wp->w_next;
+                       del_wind(wp->w_prev);
+               } else {
+                       wp->w_height = newsize;
+                       total += newsize;
+                       wp = wp->w_next;
+               }
+       } while (wp != fwind);
+
+       curwind->w_height += LI - total - 1;
+
+       /* Make a new screen structure */
+       make_scr();
+       /* Do a 'hard' update on the screen - clear and redraw */
+       cl_scr(YES);
+       flushscreen();
+       redisplay();
+
+#ifdef UNIX
+       (void) SigRelse(SIGWINCH);
+       (void) signal(SIGWINCH, win_reshape);
+#endif
+       errno = save_errno;
+       SIGRETURN;
+}
+#endif
+
+void
+
+#ifdef MAC     /* will get args from user, if option key held during launch */
+main()
+{
+       int argc;
+       char **argv;
+#else
+main(argc, argv)
+int    argc;
+char   *argv[];
+{
+#endif /* MAC */
+       char    *cp;
+       char    ttbuf[MAXTTYBUF];
+#ifdef pdp11
+       /* On the PDP-11, UNIX allocates at least 8K.
+        * In order not to waste this space, we allocate
+        * a bunch of buffers as autos.
+        */
+
+       char    s_iobuff[LBSIZE],
+               s_genbuf[LBSIZE],
+               s_linebuf[LBSIZE];
+
+       iobuff = s_iobuff;
+       genbuf = s_genbuf;
+       linebuf = s_linebuf;
+#endif
+
+#ifdef MAC
+       MacInit();              /* initializes all */
+       {
+               extern bool     make_cache proto((void));
+
+               if (!make_cache())
+                       exit(-1);
+       }
+       argc = getArgs(&argv);
+#endif /* MAC */
+
+       iniargc = argc;
+       iniargv = argv;
+
+       if (setjmp(mainjmp)) {
+               writef("\rAck! I can't deal with error \"%s\" now.\n\r", mesgbuf);
+               finish(SIGIOT); /* some bad signal (not SIGHUP) */
+       }
+
+#ifdef MSDOS
+       /* import the temporary file path from the environment and
+          fix the string, so that we can append a slash safely */
+
+       if (((cp = getenv("TMP")) || (cp = getenv("TMPDIR"))) &&
+           (*cp != '\0')) {
+               strcpy(TmpFilePath, cp);
+               cp = &TmpFilePath[strlen(TmpFilePath)-1];
+               if ((*cp == '/') || (*cp == '\\'))
+                       *cp = '\0';
+       }
+       ShFlags[0] = switchar();
+#endif /* MSDOS */
+
+       getTERM();      /* Get terminal. */
+       if (getenv("METAKEY"))
+               MetaKey = ON;
+       ttsize();
+#ifdef MAC
+       InitEvents();
+#else
+       InitCM();
+#endif
+
+       d_cache_init();         /* initialize the disk buffer cache */
+#ifdef MSDOS
+       if ((cp = getenv("COMSPEC")) && (*cp != '\0')) {
+               strcpy(Shell, cp);
+       }
+       if ((cp = getenv("DESCRIBE")) && (*cp != '\0'))
+          strcpy(CmdDb, cp);
+#else  /* !MSDOS */
+#ifndef        MAC
+       if ((cp = getenv("SHELL"))!=NULL && (*cp != '\0')) {
+               strcpy(Shell, cp);
+       }
+#endif
+#endif /* !MSDOS */
+
+       make_scr();
+       mac_init();     /* Initialize Macros */
+       winit();        /* Initialize Window */
+#ifdef IPROCS
+       pinit();        /* Pipes/process initialization */
+#endif
+       buf_init();
+
+       {
+               char    **argp;
+
+               if ((argp = scanvec(argv, "-d"))!=NULL
+#ifdef UNIX
+                   && chkCWD(argp[1])
+#endif
+                   )
+                       setCWD(argp[1]);
+               else
+                       getCWD();       /* After we setup curbuf in case we have to getwd() */
+       }
+
+       HomeDir = getenv("HOME");
+       if (HomeDir == NULL)
+               HomeDir = "/";
+       HomeLen = strlen(HomeDir);
+
+#ifdef UNIX
+       if ((cp = getenv("MAIL")) != NULL) {
+               strcpy(Mailbox, cp);
+       } else {
+               swritef(Mailbox, sizeof(Mailbox), "%s/%s",
+                       MAILSPOOL, getenv("LOGNAME"));
+       }
+#endif
+
+       InitKeymaps();
+
+       ttinit();       /* initialize terminal (before ~/.joverc) */
+       settout(ttbuf); /* not until we know baudrate */
+#ifndef        MAC
+       ResetTerm();
+#endif
+
+       (void) joverc(Joverc);                  /* system wide .joverc */
+       cp = NULL;
+#ifndef        MAC
+       /* If a JOVERC environment variable is set, then use that instead */
+       if ((cp = getenv("JOVERC"))!=NULL && (*cp != '\0'))
+          (void) joverc(cp);
+#endif /* !MAC */
+       if (!scanvec(argv, "-j") && (!cp || *cp == '\0')) {
+               char    tmpbuf[100];
+
+               swritef(tmpbuf, sizeof(tmpbuf), "%s/.joverc", HomeDir);
+               (void) joverc(tmpbuf);          /* .joverc in home directory */
+       }
+
+#ifndef        MSDOS
+       if (scanvec(argv, "-r"))
+               dorecover();
+       if (scanvec(argv, "-rc"))
+               FullRecover();
+#endif /* MSDOS */
+
+#ifdef MSDOS
+       (void) signal(SIGINT, SIG_IGN);
+       break_off();    /* disable ctrl-c checking */
+#endif /* MSDOS */
+#ifdef UNIX
+       (void) signal(SIGHUP, finish);
+       (void) signal(SIGINT, finish);
+       (void) signal(SIGBUS, finish);
+       (void) signal(SIGSEGV, finish);
+       (void) signal(SIGPIPE, finish);
+       (void) signal(SIGTERM, SIG_IGN);
+# ifdef        WINRESIZE
+       (void) signal(SIGWINCH, win_reshape);
+# endif
+       /* set things up to update the modeline every UpdFreq seconds */
+       (void) signal(SIGALRM, updmode);
+       if (UpdFreq != 0)
+               (void) alarm((unsigned) (UpdFreq - (time((time_t *)NULL) % UpdFreq)));
+#endif /* UNIX */
+       cl_scr(YES);
+       flushscreen();
+       RedrawDisplay();        /* start the redisplay process. */
+       DoKeys(YES);
+       finish(0);
+}
+
+#ifdef MSDOS
+
+#include <dos.h>
+
+private        char break_state;
+
+/* set the break state to off */
+private void
+break_off()
+{
+       union REGS regs;
+
+       regs.h.ah = 0x33;               /* break status */
+       regs.h.al = 0x00;               /* request current state */
+       intdos(&regs, &regs);
+       break_state = regs.h.dl;
+       bdos(0x33, 0, 1);       /* turn off break */
+}
+
+/* reset the break state */
+private void
+break_rst()
+{
+       bdos(0x33, break_state, 1);
+}
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/jove.h b/usr/src/contrib/jove-4.14.6/jove.h
new file mode 100644 (file)
index 0000000..9323ad4
--- /dev/null
@@ -0,0 +1,223 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* jove.h header file to be included by EVERYONE */
+
+#include <setjmp.h>
+#ifndef        TUNED
+# include "tune.h"
+#endif
+
+#ifndef        MAC
+# include <sys/types.h>
+# include <string.h>
+#else
+# include <types.h>
+#endif
+
+/* proto: macro to allow us to prototype any function declaration
+ * without upsetting old compilers.
+ */
+
+#ifdef REALSTDC
+# define    USE_PROTOTYPES  1
+#endif
+
+#ifdef USE_PROTOTYPES
+# define proto(x)        x
+# ifdef        NO_PTRPROTO
+   /* on these systems, a prototype cannot be used for a pointer to function */
+#  define ptrproto(x)          ()
+# else
+#  define ptrproto(x)          x
+# endif
+#else
+# define proto(x)              ()
+# define ptrproto(x)           ()
+#endif
+
+/* There are two ways to handle functions with a variable number of args.
+ * The old portable way uses varargs.h.  The way sanctioned by ANSI X3J11
+ * uses stdarg.h.
+ */
+#ifdef REALSTDC
+#define        STDARGS 1
+# define       va_init(ap, parmN)      { va_start((ap), (parmN)); }
+#else
+# define       va_init(ap, parmN)      { va_start((ap)); }
+#endif
+
+/* ANSI Goodies and their substitutes
+ *
+ * const: readonly type qualifier
+ *
+ * volatile: type qualifier indicating one of two kinds of magic.
+ * 1. This object may be modified by an event unknown to the implementation
+ *    (eg. asynchronous signal or memory-mapped I/O device).
+ * 2. This automatic variable might be modified between a setjmp()
+ *    and a longjmp(), and we wish it to have the correct value after
+ *    the longjmp().  This second meaning is an X3J11 abomination.
+ * So far, only the second meaning is used.
+ *
+ * UnivPtr: universal pointer type
+ *
+ * UnivConstPtr: universal pointer to const
+ */
+
+#ifdef REALSTDC
+
+  typedef void *UnivPtr;
+  typedef const void   *UnivConstPtr;
+
+#else  /* !REALSTDC */
+
+# ifndef const
+#  define      const   /* Only in ANSI C.  Pity */
+# endif
+# ifndef volatile
+#  define      volatile
+# endif
+  typedef char *UnivPtr;
+  typedef const char   *UnivConstPtr;
+
+#endif /* !REALSTDC */
+
+/* According to the ANSI standard for C, any library routine may
+ * be defined as a macro with parameters.  In order to prevent
+ * the expansion of this macro in a declaration of the routine,
+ * ANSI suggests parenthesizing the identifier.  This is a reasonable
+ * and legal approach, even for K&R C.
+ *
+ * A bug in the MIPS compiler used on MIPS, IRIS, and probably other
+ * MIPS R[23]000 based systems, causes the compiler to reject
+ * these declarations (at least at the current time, 1989 August).
+ * To avoid this bug, we conditionally define and use UNMACRO.
+ */
+#ifdef mips
+# define UNMACRO(proc) proc
+#else
+# define UNMACRO(proc) (proc)
+#endif
+
+/* Since we don't use stdio.h, we may have to define NULL and EOF */
+
+#ifndef        NULL
+# define NULL  0
+#endif
+
+#ifndef        EOF
+#define EOF    (-1)
+#endif
+
+#define private                static
+
+typedef int    bool;
+#define NO             0
+#define YES            1
+#define FALSE          0
+#define TRUE           1
+#define OFF            0
+#define ON             1
+
+/* typedef structure definitions */
+#ifdef IPROCS
+typedef struct process Process;
+#endif
+typedef struct window  Window;
+typedef struct position        Bufpos;
+typedef struct mark    Mark;
+typedef struct buffer  Buffer;
+typedef struct line    Line;
+typedef struct iobuf   IOBUF;
+
+#include "buf.h"
+#include "wind.h"
+#include "io.h"
+#include "dataobj.h"
+#include "keymaps.h"
+#include "argcount.h"
+#include "util.h"
+#include "vars.h"
+#include "screen.h"
+
+/* return codes for command completion (all < 0 because >= 0 are
+   legitimate offsets into array of strings */
+
+#define AMBIGUOUS      (-2)    /* matches more than one at this point */
+#define UNIQUE         (-3)    /* matches only one string */
+#define ORIGINAL       (-4)    /* matches no strings at all! */
+#define NULLSTRING     (-5)    /* just hit return without typing anything */
+
+/* values for the `flags' argument to complete */
+#define NOTHING                0       /* opposite of RET_STATE */
+#define RET_STATE      1       /* return state when we hit return */
+#define RCOMMAND       2       /* we are reading a joverc file */
+#define CASEIND                4       /* map all to lower case */
+
+#define FORWARD                1
+#define BACKWARD       (-1)
+
+#define ARG_CMD                1
+#define LINECMD                2
+#define KILLCMD                3       /* so we can merge kills */
+#define YANKCMD                4       /* so we can do ESC Y (yank-pop) */
+
+extern jmp_buf mainjmp;
+
+/* setjmp/longjmp args for DoKeys() mainjmp */
+#define FIRSTCALL      0
+#define ERROR          1
+#define COMPLAIN       2       /* do the error without a getDOT */
+#define QUIT           3       /* leave this level of recursion */
+
+#define INT_OKAY       0
+#define INT_BAD                (-1)
+
+extern char    NullStr[];
+extern char    *ProcFmt;
+
+extern int
+       LastKeyStruck,
+
+       RecDepth,       /* recursion depth */
+       InJoverc;       /* depth in sourcing */
+
+extern bool
+       InMacDefine,    /* are we defining a macro right now? */
+
+       TOabort,        /* flag set by Typeout() */
+
+       errormsg,       /* last message was an error message
+                          so don't erase the error before it
+                          has been read */
+       InputPending,   /* nonzero if there is input waiting to
+                          be processed */
+       Interactive,
+       inIOread,       /* so we know whether we can do a redisplay. */
+
+       Asking,         /* are we on read a string from the terminal? */
+       InRealAsk;      /* are we currently executing real_ask()? */
+
+extern int
+       AskingWidth;    /* width of question being asked */
+
+extern char
+       *Inputp,
+       Minibuf[LBSIZE],
+       ShcomBuf[LBSIZE],
+       *version;
+
+#define MESG_SIZE 128
+extern char    mesgbuf[MESG_SIZE];
+
+#include "externs.h"
+
+#ifndef        W_OK
+# define W_OK  2
+# define X_OK  1
+# define F_OK  0
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/kbd.c b/usr/src/contrib/jove-4.14.6/kbd.c
new file mode 100644 (file)
index 0000000..8be4944
--- /dev/null
@@ -0,0 +1,79 @@
+#include "jove.h"
+#include <signal.h>
+#include <errno.h>
+
+#ifdef PIPEPROCS       /* only needed for systems with iproc-pipes */
+
+#ifdef BSD_SIGS
+# define pause()       sigpause(0L)
+#endif
+
+struct header {
+       int     pid,
+               nbytes;
+       char    buf[10];
+};
+
+#define HEADER_SIZE    (2 * sizeof (int))
+
+/* JOVE sends SIGQUIT whenever it wants the kbd process (this program)
+   to stop competing for input from the keyboard.  JOVE does this when
+   JOVE realizes that there are no more interactive processes running.
+   The reason we go through all this trouble is that JOVE slows down
+   a lot when it's getting its keyboard input via a pipe. */
+
+private SIGRESULT strt_read proto((int));
+
+private SIGRESULT
+hold_read(junk)
+int    junk;   /* passed in when invoked by a signal; of no interest */
+{
+       signal(KBDSIG, strt_read);
+       pause();
+       SIGRETURN;
+}
+
+private SIGRESULT
+strt_read(junk)
+int    junk;
+{
+       signal(KBDSIG, hold_read);
+       SIGRETURN;
+}
+
+int
+main(argc, argv)
+int    argc;
+char   **argv;
+{
+       struct header   header;
+       int     pid,
+               n;
+
+       signal(SIGINT, SIG_IGN);
+       pid = getpid();
+       header.pid = pid;
+
+       hold_read(0);
+       for (;;) {
+               n = read(0, (UnivPtr) header.buf, sizeof (header.buf));
+               if (n == -1) {
+                       if (errno != EINTR)
+                               break;
+                       continue;
+               }
+               header.nbytes = n;
+               write(1, (UnivPtr) &header, HEADER_SIZE + n);
+       }
+       return 0;
+}
+
+#else  /* !PIPEPROCS */
+
+int
+main()
+{
+       return 0;
+}
+
+#endif /* !PIPEPROCS */
diff --git a/usr/src/contrib/jove-4.14.6/keymaps.c b/usr/src/contrib/jove-4.14.6/keymaps.c
new file mode 100644 (file)
index 0000000..ef4e3da
--- /dev/null
@@ -0,0 +1,601 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "list.h"
+#include "fp.h"
+#include "termcap.h"
+#include "chars.h"
+#include "disp.h"
+#include "re.h"
+
+/* Up until now a keymap was an array of pointers to
+   data_obj's.  A data_obj was either a pointer to a built-in
+   command or a keyboard macro.  Now a data_obj can be a
+   pointer to a keymap as well, which is how prefix keys will
+   be handled.
+
+   There will be a way to build keymaps and give them names,
+   and to look those keymaps up by name, attach them to keys.
+   There will be a way to specify a string of key strokes and
+   have a series of keymaps built automatically for those
+   sequences. */
+
+private        void
+       fb_aux proto((data_obj *, struct keymap *, char *, char *, size_t));
+
+private List   *keymaps;               /* list of all keymaps */
+private struct keymap  *mainmap;
+#ifdef IPROCS
+private struct keymap  *procsmap;
+#endif
+
+/* make a new keymap, give it name NAME, initialize the keys array
+   to keys, if nonzero, or make an empty one, otherwise */
+
+private struct keymap *
+km_new(name, keys)
+char   *name;
+data_obj       **keys;
+{
+       struct keymap   *km;
+
+       km = (struct keymap *) emalloc(sizeof *km);
+       (void) list_push(&keymaps, (UnivPtr) km);
+       km->Type = KEYMAP;
+       km->Name = name;
+       if (keys != NULL) {
+               km->k_keys = keys;
+               km->k_alloc_p = NO;
+       } else {
+               km->k_keys = (data_obj **) emalloc(NCHARS * sizeof (data_obj *));
+               byte_zero((UnivPtr) km->k_keys, NCHARS * sizeof (data_obj *));
+               km->k_alloc_p = YES;
+       }
+       return km;
+}
+
+#ifdef NEVER
+
+/* free up a keymap */
+
+private void
+km_destroy(km)
+struct keymap  *km;
+{
+       if (km->k_alloc_p == YES)
+               free((char *) km->k_keys);
+       km->k_keys = NULL;
+       free((char *) km);
+}
+
+/* lookup a keymap by name */
+
+private struct keymap *
+km_lookup(name)
+char   *name;
+{
+       List    *lp;
+
+       for (lp = keymaps; lp != NULL; lp = list_next(lp))
+               if (strcmp(name, ((struct keymap *) list_data(lp))->Name) == 0)
+                       break;
+       if (lp == NULL)
+               return NULL;
+       return (struct keymap *) list_data(lp);
+}
+
+#endif
+
+/* given a map and a key, return the object bound to that key */
+
+#define km_getkey(m, c)        ((m)->k_keys[(c) & CHARMASK])
+
+#ifndef        km_getkey
+data_obj *
+km_getkey(m, c)
+struct keymap  *m;
+int    c;
+{
+       return (m->k_keys[c & CHARMASK]);
+}
+#endif
+
+private void
+km_setkey(m, c, d)
+struct keymap  *m;
+int    c;
+data_obj       *d;
+{
+       m->k_keys[c & CHARMASK] = d;
+}
+
+/* get the currently active keymaps into km_buf */
+
+private int
+get_keymaps(km_buf)
+struct keymap  **km_buf;
+{
+       int     nmaps = 0;
+
+#ifdef IPROCS
+       if (curbuf->b_process != NULL)
+               km_buf[nmaps++] = procsmap;
+#endif
+       if (curbuf->b_map != NULL)
+               km_buf[nmaps++] = curbuf->b_map;
+       km_buf[nmaps++] = mainmap;
+
+       return nmaps;
+}
+
+private struct keymap *
+IsPrefix(cp)
+data_obj       *cp;
+{
+       if (cp == NULL || (cp->Type & TYPEMASK) != KEYMAP)
+               return NULL;
+       return (struct keymap *) cp;
+}
+
+/* Is `c' a prefix character */
+
+int
+PrefChar(c)
+int    c;
+{
+       return (int) IsPrefix(km_getkey(mainmap, c));
+}
+
+void
+UnbindC()
+{
+       char    *keys;
+       struct keymap   *map = mainmap;
+
+       keys = ask((char *)NULL, ProcFmt);
+       for (;;) {
+               if (keys[1] == '\0')
+                       break;
+               if ((map = IsPrefix(km_getkey(map, *keys))) == NULL)
+                       break;
+               keys += 1;
+       }
+       if (keys[1] != '\0')
+               complain("That's not a legitimate key sequence.");
+       km_setkey(map, keys[0], (data_obj *)NULL);
+}
+
+private void
+BindWMap(map, lastkey, cmd)
+struct keymap  *map;
+int    lastkey;
+data_obj       *cmd;
+{
+       struct keymap   *nextmap;
+       int     c;
+
+       c = addgetc();
+       if (c == EOF) {
+               if (lastkey == EOF)
+                       complain("[Empty key sequence]");
+               complain("[Premature end of key sequence]");
+       } else {
+               if ((nextmap = IsPrefix(km_getkey(map, c))) != NULL)
+                       BindWMap(nextmap, c, cmd);
+               else {
+                       km_setkey(map, c, cmd);
+#ifdef MAC
+                       ((struct cmd *) cmd)->c_key = c;        /* see about_j() in mac.c */
+                       if (map->k_keys == MainKeys)
+                               ((struct cmd *) cmd)->c_map = F_MAINMAP;
+                       else if (map->k_keys == EscKeys)
+                               ((struct cmd *) cmd)->c_map = F_PREF1MAP;
+                       else if (map == (struct keymap *) CtlxKeys)
+                               ((struct cmd *) cmd)->c_map = F_PREF2MAP;
+#endif
+               }
+       }
+}
+
+private void
+BindSomething(proc, map)
+data_obj       *(*proc) ptrproto((const char *));
+struct keymap  *map;
+{
+       data_obj        *d;
+
+       if ((d = (*proc)(ProcFmt)) == NULL)
+               return;
+       s_mess(": %f %s ", d->Name);
+       BindWMap(map, EOF, d);
+}
+
+void
+BindAKey()
+{
+       BindSomething(findcom, mainmap);
+}
+
+void
+BindMac()
+{
+       BindSomething(findmac, mainmap);
+}
+
+private void
+DescWMap(map, key)
+struct keymap  *map;
+int    key;
+{
+       data_obj        *cp = km_getkey(map, key);
+       struct keymap   *prefp;
+
+       if (cp == NULL)
+               add_mess("is unbound.");
+       else if ((prefp = IsPrefix(cp)) != NULL)
+               DescWMap(prefp, addgetc());
+       else
+               add_mess("is bound to %s.", cp->Name);
+}
+
+void
+KeyDesc()
+{
+       s_mess(ProcFmt);
+       DescWMap(mainmap, addgetc());
+}
+
+private void
+DescMap(map, pref)
+struct keymap  *map;
+char   *pref;
+{
+       int     c1,
+               c2;
+       char    keydescbuf[40];
+       struct keymap   *prefp;
+
+       for (c1 = 0; c1 < NCHARS; c1 = c2 + 1) {
+               c2 = c1;
+               if (km_getkey(map, c1) == 0)
+                       continue;
+               do ; while (++c2 < NCHARS && km_getkey(map, c1) == km_getkey(map, c2));
+               c2 -= 1;
+               swritef(keydescbuf, sizeof(keydescbuf),
+                       c1==c2? "%s %p" : c1==c2+1? "%s {%p,%p}" : "%s [%p-%p]",
+                       pref, c1, c2);
+               if ((prefp = IsPrefix(km_getkey(map, c1)))!=NULL && (prefp != map))
+                       DescMap(prefp, keydescbuf);
+               else
+                       Typeout("%-18s%s", keydescbuf, km_getkey(map, c1)->Name);
+       }
+}
+
+void
+DescBindings()
+{
+       TOstart("Key Bindings", TRUE);
+       DescMap(mainmap, NullStr);
+       TOstop();
+}
+
+private void
+find_binds(dp, buf, size)
+data_obj       *dp;
+char   *buf;
+size_t size;
+{
+       char    *endp;
+
+       buf[0] = '\0';
+       fb_aux(dp, mainmap, (char *) NULL, buf, size);
+       endp = buf + strlen(buf) - 2;
+       if ((endp > buf) && (strcmp(endp, ", ") == 0))
+               *endp = '\0';
+}
+
+private void
+fb_aux(cp, map, prefix, buf, size)
+register data_obj      *cp;
+struct keymap  *map;
+char   *prefix,
+       *buf;
+size_t size;
+{
+       int     c1,
+               c2;
+       char    *bufp = buf + strlen(buf),
+               prefbuf[20];
+       struct keymap   *prefp;
+
+       for (c1 = 0; c1 < NCHARS; c1 = c2 + 1) {
+               c2 = c1;
+               if (km_getkey(map, c1) == cp) {
+                       do ; while (++c2 < NCHARS && km_getkey(map, c1) == km_getkey(map, c2));
+                       c2 -= 1;
+                       if (prefix)
+                               swritef(bufp, sizeof(buf) - (bufp-buf), "%s ",
+                                       prefix);
+                       bufp += strlen(bufp);
+                       swritef(bufp, size - (bufp-buf),
+                               c1==c2? "%p" : c1==c2+1? "{%p,%p}" : "[%p-%p]",
+                               c1, c2);
+               }
+               if ((prefp = IsPrefix(km_getkey(map, c1)))!=NULL && (prefp != map))  {
+                       swritef(prefbuf, sizeof(prefbuf), "%p", c1);
+                       fb_aux(cp, prefp, prefbuf, bufp, size-(bufp-buf));
+               }
+               bufp += strlen(bufp);
+       }
+}
+
+void
+DescCom()
+{
+       data_obj        *dp;
+       char    pattern[100],
+               *file = CmdDb;
+       const char      *doc_type;
+       static const char var_type[] = "Variable";
+       static const char cmd_type[] = "Command";
+       File    *fp;
+
+       if (!strcmp(LastCmd->Name, "describe-variable")) {
+               doc_type = var_type;
+               dp = (data_obj *) findvar(ProcFmt);
+       } else {
+               doc_type = cmd_type;
+               dp = (data_obj *) findcom(ProcFmt);
+       }
+       if (dp == NULL)
+               return;
+       fp = open_file(file, iobuff, F_READ, YES, YES);
+       Placur(ILI, 0);
+       flushscreen();
+       swritef(pattern, sizeof(pattern), "^:entry \"%s\" \"%s\"$",
+               dp->Name, doc_type);
+       TOstart("Help", TRUE);
+       for (;;) {
+               if (f_gets(fp, genbuf, (size_t)LBSIZE)) {
+                       Typeout("There is no documentation for \"%s\".", dp->Name);
+                       break;
+               }
+               if (genbuf[0] == ':' && LookingAt(pattern, genbuf, 0)) {
+                       /* found it ... let's print it */
+                       if (doc_type == var_type)
+                               Typeout(dp->Name);
+                       else if (doc_type == cmd_type) {
+                               char    binding[128];
+
+                               find_binds(dp, binding, sizeof(binding));
+                               if (blnkp(binding))
+                                       Typeout("To invoke %s, type \"ESC X %s<cr>\".",
+                                               dp->Name, dp->Name);
+                               else
+                                       Typeout("Type \"%s\" to invoke %s.",
+                                               binding, dp->Name);
+                       }
+                       Typeout("");
+                       while (!f_gets(fp, genbuf, (size_t)LBSIZE)
+                       && strncmp(genbuf, ":entry", (size_t)6) != 0) {
+                               Typeout("%s", genbuf);
+                       }
+                       break;
+               }
+       }
+       f_close(fp);
+       TOstop();
+}
+
+
+void
+Apropos()
+{
+       register const struct cmd       *cp;
+       register struct macro   *m;
+       register const struct variable  *v;
+       char    *ans;
+       bool    anyfs = NO,
+               anyvs = NO,
+               anyms = NO;
+       char    buf[256];
+
+       ans = ask((char *)NULL, ": %f (keyword) ");
+       TOstart("Help", TRUE);
+       for (cp = commands; cp->Name != NULL; cp++)
+               if (sindex(ans, cp->Name)) {
+                       if (!anyfs) {
+                               Typeout("Commands");
+                               Typeout("--------");
+                       }
+                       find_binds((data_obj *) cp, buf, sizeof(buf));
+                       if (buf[0])
+                               Typeout(": %-35s (%s)", cp->Name, buf);
+                       else
+                               Typeout(": %s", cp->Name);
+                       anyfs = YES;
+               }
+       if (anyfs)
+               Typeout(NullStr);
+       for (v = variables; v->Name != NULL; v++)
+               if (sindex(ans, v->Name)) {
+                       if (!anyvs) {
+                               Typeout("Variables");
+                               Typeout("---------");
+                       }
+                       anyvs = YES;
+                       vpr_aux(v, buf, sizeof(buf));
+                       Typeout(": set %-26s %s", v->Name, buf);
+               }
+       if (anyvs)
+               Typeout(NullStr);
+       for (m = macros; m != NULL; m = m->m_nextm)
+               if (sindex(ans, m->Name)) {
+                       if (!anyms) {
+                               Typeout("Macros");
+                               Typeout("------");
+                       }
+                       anyms = YES;
+                       find_binds((data_obj *) m, buf, sizeof(buf));
+                       if (buf[0])
+                               Typeout(": %-35s (%s)", m->Name, buf);
+                       else
+                               Typeout(": %-35s %s", "execute-macro", m->Name);
+               }
+       TOstop();
+}
+
+#ifdef NEVER
+private char *
+km_newname()
+{
+       char    buffer[128];
+       static int      km_count = 1;
+
+       swritef(buffer, sizeof(buffer), "keymap-%d", km_count++);
+       return copystr(buffer);
+}
+#endif
+
+void
+InitKeymaps()
+{
+       struct keymap   *km;
+
+       mainmap = km_new(copystr("mainmap"), MainKeys);
+
+       /* setup ESC map */
+       km = km_new(copystr("ESC-map"), EscKeys);
+       km_setkey(mainmap, ESC, (data_obj *) km);
+
+       /* setup Ctlx map */
+       km = km_new(copystr("CTLX-map"), CtlxKeys);
+       km_setkey(mainmap, CTL('X'), (data_obj *) km);
+}
+
+void
+MakeKMap()
+{
+       char    *name;
+
+       name = ask((char *)NULL, ProcFmt);
+       (void) km_new(copystr(name), (data_obj **)NULL);
+}
+
+private data_obj *
+findmap(fmt)
+const char     *fmt;
+{
+       List    *lp;
+       char    *strings[128];
+       int     i;
+
+       for (lp = keymaps, i = 0; lp != NULL; lp = list_next(lp))
+               strings[i++] = ((struct keymap *) list_data(lp))->Name;
+       strings[i] = NULL;
+
+       i = complete(strings, fmt, 0);
+       if (i < 0)
+               return NULL;
+       lp = keymaps;
+       while (--i >= 0)
+               lp = list_next(lp);
+       return (data_obj *) list_data(lp);
+}
+
+#ifdef IPROCS
+private void
+mk_proc_km()
+{
+       procsmap = km_new("process-keymap", (data_obj **)NULL);
+}
+
+void
+ProcBind()
+{
+       data_obj        *d;
+
+       if (procsmap == NULL)
+               mk_proc_km();
+
+       if ((d = findcom(ProcFmt)) == NULL)
+               return;
+       s_mess(": %f %s ", d->Name);
+       BindWMap(procsmap, EOF, d);
+}
+
+void
+ProcKmBind()
+{
+       data_obj        *d;
+
+       if (procsmap == NULL)
+               mk_proc_km();
+       if ((d = findmap(ProcFmt)) == NULL)
+               return;
+       s_mess(": %f %s ", d->Name);
+       BindWMap(procsmap, EOF, d);
+}
+
+#endif
+
+void
+KmBind()
+{
+       BindSomething(findmap, mainmap);
+}
+
+void
+dispatch(c)
+register int   c;
+{
+       data_obj        *cp;
+       struct keymap   *maps[10];      /* never more than 10 active
+                                          maps at a time, I promise */
+       int     nmaps;
+
+       this_cmd = 0;
+       nmaps = get_keymaps(maps);
+
+       for (;;) {
+               int     i,
+                       nvalid,
+                       slow = NO;
+
+               for (i = 0, nvalid = 0; i < nmaps; i++) {
+                       if (maps[i] == NULL)
+                               continue;
+                       cp = km_getkey(maps[i], c);
+                       if (cp != NULL) {
+                               if (obj_type(cp) != KEYMAP) {
+                                       ExecCmd(cp);
+                                       return;
+                               }
+                               nvalid += 1;
+                       }
+                       maps[i] = (struct keymap *) cp;
+               }
+               if (nvalid == 0) {
+                       char    strokes[128];
+
+                       pp_key_strokes(strokes, sizeof (strokes));
+                       s_mess("[%sunbound]", strokes);
+                       rbell();
+                       clr_arg_value();
+                       errormsg = NO;
+                       return;
+               }
+
+               c = waitchar(&slow);
+               if (c == AbortChar) {
+                       message("[Aborted]");
+                       rbell();
+                       return;
+               }
+       }
+}
diff --git a/usr/src/contrib/jove-4.14.6/keymaps.h b/usr/src/contrib/jove-4.14.6/keymaps.h
new file mode 100644 (file)
index 0000000..dbc7564
--- /dev/null
@@ -0,0 +1,34 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+struct keymap {
+       int             Type;           /* keymap type */
+       char            *Name;          /* keymap name */
+       data_obj        **k_keys;       /* keys array */
+       char            k_alloc_p;      /* whether we alloced k_keys */
+};
+
+extern data_obj        *MainKeys[NCHARS],
+               *EscKeys[NCHARS],
+               *CtlxKeys[NCHARS];
+
+#ifdef MAC                                     /* used in About Jove... */
+# define F_MAINMAP '\001'
+# define F_PREF1MAP '\002'
+# define F_PREF2MAP '\003'
+#endif
+
+extern int
+       this_cmd,       /* ... */
+       last_cmd;       /* last command ... to implement appending
+                          to kill buffer */
+
+extern void
+       dispatch proto((int c));
+
+extern int
+       PrefChar proto((int c));        /* Is `c' a prefix character */
diff --git a/usr/src/contrib/jove-4.14.6/keys.txt b/usr/src/contrib/jove-4.14.6/keys.txt
new file mode 100644 (file)
index 0000000..895f436
--- /dev/null
@@ -0,0 +1,804 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* Warning:  You probably shouldn't put ifdefs anywhere *inside* the keymaps
+   definitions.         It'll screw up the stuff in comments (at least), and maybe
+   a few other things. Yes, it *WILL* screw up the comments ... but it's
+   not clear that you care ... */
+
+#include "jove.h"
+
+data_obj *MainKeys[NCHARS] = {
+       "set-mark",                     /* ^@ */
+       "beginning-of-line",            /* ^A */
+       "backward-character",           /* ^B */
+       "unbound",                      /* ^C */
+       "delete-next-character",        /* ^D */
+       "end-of-line",                  /* ^E */
+       "forward-character",            /* ^F */
+       "unbound",                      /* ^G */
+       "delete-previous-character",    /* ^H */
+       "handle-tab",                   /* ^I */
+       "newline-and-indent",           /* ^J */
+       "kill-to-end-of-line",          /* ^K */
+       "redraw-display",               /* ^L */
+       "newline",                      /* ^M */
+       "next-line",                    /* ^N */
+       "newline-and-backup",           /* ^O */
+       "previous-line",                /* ^P */
+       "quoted-insert",                /* ^Q */
+       "search-reverse",               /* ^R */
+       "search-forward",               /* ^S */
+       "transpose-characters",         /* ^T */
+       "gather-numeric-argument",      /* ^U */
+       "next-page",                    /* ^V */
+       "kill-region",                  /* ^W */
+       "unbound",                      /* ^X */
+       "yank",                         /* ^Y */
+       "scroll-up",                    /* ^Z */
+       "unbound",                      /* ^[ */
+       "search-forward",               /* ^\ */
+#ifndef        MSDOS
+       "unbound",                      /* ^] */
+#else  /* MSDOS */
+       "find-tag-at-point",            /* ^] */
+#endif /* MSDOS */
+       "quoted-insert",                /* ^^ */
+       "unbound",                      /* ^_ */
+       "self-insert",                  /*    */
+       "self-insert",                  /* !  */
+       "self-insert",                  /* "  */
+       "self-insert",                  /* #  */
+       "self-insert",                  /* $  */
+       "self-insert",                  /* %  */
+       "self-insert",                  /* &  */
+       "self-insert",                  /* '  */
+       "self-insert",                  /* (  */
+       "paren-flash",                  /* )  */
+       "self-insert",                  /* *  */
+       "self-insert",                  /* +  */
+       "self-insert",                  /* ,  */
+       "self-insert",                  /* -  */
+       "self-insert",                  /* .  */
+       "self-insert",                  /* /  */
+       "self-insert",                  /* 0  */
+       "self-insert",                  /* 1  */
+       "self-insert",                  /* 2  */
+       "self-insert",                  /* 3  */
+       "self-insert",                  /* 4  */
+       "self-insert",                  /* 5  */
+       "self-insert",                  /* 6  */
+       "self-insert",                  /* 7  */
+       "self-insert",                  /* 8  */
+       "self-insert",                  /* 9  */
+       "self-insert",                  /* :  */
+       "self-insert",                  /* ;  */
+       "self-insert",                  /* <  */
+       "self-insert",                  /* =  */
+       "self-insert",                  /* >  */
+       "self-insert",                  /* ?  */
+       "self-insert",                  /* @  */
+       "self-insert",                  /* A  */
+       "self-insert",                  /* B  */
+       "self-insert",                  /* C  */
+       "self-insert",                  /* D  */
+       "self-insert",                  /* E  */
+       "self-insert",                  /* F  */
+       "self-insert",                  /* G  */
+       "self-insert",                  /* H  */
+       "self-insert",                  /* I  */
+       "self-insert",                  /* J  */
+       "self-insert",                  /* K  */
+       "self-insert",                  /* L  */
+       "self-insert",                  /* M  */
+       "self-insert",                  /* N  */
+       "self-insert",                  /* O  */
+       "self-insert",                  /* P  */
+       "self-insert",                  /* Q  */
+       "self-insert",                  /* R  */
+       "self-insert",                  /* S  */
+       "self-insert",                  /* T  */
+       "self-insert",                  /* U  */
+       "self-insert",                  /* V  */
+       "self-insert",                  /* W  */
+       "self-insert",                  /* X  */
+       "self-insert",                  /* Y  */
+       "self-insert",                  /* Z  */
+       "self-insert",                  /* [  */
+       "self-insert",                  /* \  */
+       "paren-flash",                  /* ]  */
+       "self-insert",                  /* ^  */
+       "self-insert",                  /* _  */
+       "self-insert",                  /* `  */
+       "self-insert",                  /* a  */
+       "self-insert",                  /* b  */
+       "self-insert",                  /* c  */
+       "self-insert",                  /* d  */
+       "self-insert",                  /* e  */
+       "self-insert",                  /* f  */
+       "self-insert",                  /* g  */
+       "self-insert",                  /* h  */
+       "self-insert",                  /* i  */
+       "self-insert",                  /* j  */
+       "self-insert",                  /* k  */
+       "self-insert",                  /* l  */
+       "self-insert",                  /* m  */
+       "self-insert",                  /* n  */
+       "self-insert",                  /* o  */
+       "self-insert",                  /* p  */
+       "self-insert",                  /* q  */
+       "self-insert",                  /* r  */
+       "self-insert",                  /* s  */
+       "self-insert",                  /* t  */
+       "self-insert",                  /* u  */
+       "self-insert",                  /* v  */
+       "self-insert",                  /* w  */
+       "self-insert",                  /* x  */
+       "self-insert",                  /* y  */
+       "self-insert",                  /* z  */
+       "self-insert",                  /* {  */
+       "self-insert",                  /* |  */
+       "paren-flash",                  /* }  */
+       "self-insert",                  /* ~  */
+       "delete-previous-character"     /* ^? */
+#ifndef        ASCII7
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+       "self-insert",                  /* ALT- or Option-       */
+#ifdef IBMPC
+       "unbound"                       /* ALT- 255 */
+#else
+       "self-insert"
+#endif /* IBMPC */
+#endif /* !ASCII7 */
+};
+
+data_obj *EscKeys[NCHARS] = {
+       "set-mark",                     /* ^@ */
+       "unbound",                      /* ^A */
+       "backward-s-expression",        /* ^B */
+       "unbound",                      /* ^C */
+       "down-list",                    /* ^D */
+       "unbound",                      /* ^E */
+       "forward-s-expression",         /* ^F */
+       "unbound",                      /* ^G */
+       "unbound",                      /* ^H */
+       "unbound",                      /* ^I */
+       "unbound",                      /* ^J */
+       "kill-s-expression",            /* ^K */
+       "clear-and-redraw",             /* ^L */
+       "unbound",                      /* ^M */
+       "forward-list",                 /* ^N */
+       "unbound",                      /* ^O */
+       "backward-list",                /* ^P */
+       "unbound",                      /* ^Q */
+       "unbound",                      /* ^R */
+       "unbound",                      /* ^S */
+       "unbound",                      /* ^T */
+       "backward-up-list",             /* ^U */
+       "page-next-window",             /* ^V */
+       "unbound",                      /* ^W */
+       "unbound",                      /* ^X */
+       "unbound",                      /* ^Y */
+       "unbound",                      /* ^Z */
+       "unbound",                      /* ^[ */
+       "unbound",                      /* ^\ */
+       "unbound",                      /* ^] */
+       "unbound",                      /* ^^ */
+       "unbound",                      /* ^_ */
+       "unbound",                      /*    */
+       "unbound",                      /* !  */
+       "unbound",                      /* "  */
+       "unbound",                      /* #  */
+       "unbound",                      /* $  */
+       "unbound",                      /* %  */
+       "unbound",                      /* &  */
+       "unbound",                      /* '  */
+       "unbound",                      /* (  */
+       "unbound",                      /* )  */
+       "unbound",                      /* *  */
+       "unbound",                      /* +  */
+       "beginning-of-window",          /* ,  */
+       "digit",                        /* -  */
+       "end-of-window",                /* .  */
+       "unbound",                      /* /  */
+       "digit",                        /* 0  */
+       "digit",                        /* 1  */
+       "digit",                        /* 2  */
+       "digit",                        /* 3  */
+       "digit",                        /* 4  */
+       "digit",                        /* 5  */
+       "digit",                        /* 6  */
+       "digit",                        /* 7  */
+       "digit",                        /* 8  */
+       "digit",                        /* 9  */
+       "unbound",                      /* :  */
+       "unbound",                      /* ;  */
+       "beginning-of-file",            /* <  */
+       "unbound",                      /* =  */
+       "end-of-file",                  /* >  */
+       "describe-command",             /* ?  */
+       "unbound",                      /* @  */
+       "backward-sentence",            /* A  */
+       "backward-word",                /* B  */
+       "case-word-capitalize",         /* C  */
+       "kill-next-word",               /* D  */
+       "forward-sentence",             /* E  */
+       "forward-word",                 /* F  */
+       "goto-line",                    /* G  */
+       "unbound",                      /* H  */
+       "make-macro-interactive",       /* I  */
+       "fill-paragraph",               /* J  */
+       "kill-to-end-of-sentence",      /* K  */
+       "case-word-lower",              /* L  */
+       "first-non-blank",              /* M  */
+       "unbound",                      /* N  */
+       "unbound",                      /* O  */
+       "unbound",                      /* P  */
+       "query-replace-string",         /* Q  */
+       "replace-string",               /* R  */
+       "unbound",                      /* S  */
+       "unbound",                      /* T  */
+       "case-word-upper",              /* U  */
+       "previous-page",                /* V  */
+       "copy-region",                  /* W  */
+       "execute-named-command",        /* X  */
+       "yank-pop",                     /* Y  */
+       "scroll-down",                  /* Z  */
+       "backward-paragraph",           /* [  */
+       "delete-white-space",           /* \  */
+       "forward-paragraph",            /* ]  */
+       "unbound",                      /* ^  */
+       "unbound",                      /* _  */
+       "unbound",                      /* `  */
+       "backward-sentence",            /* a  */
+       "backward-word",                /* b  */
+       "case-word-capitalize",         /* c  */
+       "kill-next-word",               /* d  */
+       "forward-sentence",             /* e  */
+       "forward-word",                 /* f  */
+       "goto-line",                    /* g  */
+       "unbound",                      /* h  */
+       "make-macro-interactive",       /* i  */
+       "fill-paragraph",               /* j  */
+       "kill-to-end-of-sentence",      /* k  */
+       "case-word-lower",              /* l  */
+       "first-non-blank",              /* m  */
+       "unbound",                      /* n  */
+       "unbound",                      /* o  */
+       "unbound",                      /* p  */
+       "query-replace-string",         /* q  */
+       "replace-string",               /* r  */
+       "unbound",                      /* s  */
+       "unbound",                      /* t  */
+       "case-word-upper",              /* u  */
+       "previous-page",                /* v  */
+       "copy-region",                  /* w  */
+       "execute-named-command",        /* x  */
+       "yank-pop",                     /* y  */
+       "scroll-down",                  /* z  */
+       "unbound",                      /* {  */
+       "unbound",                      /* |  */
+       "unbound",                      /* }  */
+       "make-buffer-unmodified",       /* ~  */
+       "kill-previous-word"            /* ^? */
+#ifndef        ASCII7
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound"                       /* ALT- or Option-       */
+#endif /* !ASCII7 */
+};
+
+data_obj       *CtlxKeys[NCHARS] = {
+       "unbound",                      /* ^@ */
+       "unbound",                      /* ^A */
+       "list-buffers",                 /* ^B */
+       "exit-jove",                    /* ^C */
+       "unbound",                      /* ^D */
+       "compile-it",                   /* ^E */
+       "find-file",                    /* ^F */
+       "unbound",                      /* ^G */
+       "unbound",                      /* ^H */
+       "insert-file",                  /* ^I */
+       "unbound",                      /* ^J */
+       "unbound",                      /* ^K */
+       "unbound",                      /* ^L */
+       "write-modified-files",         /* ^M */
+       "next-error",                   /* ^N */
+       "delete-blank-lines",           /* ^O */
+       "previous-error",               /* ^P */
+       "unbound",                      /* ^Q */
+       "visit-file",                   /* ^R */
+       "save-file",                    /* ^S */
+       "transpose-lines",              /* ^T */
+       "unbound",                      /* ^U */
+       "visit-file",                   /* ^V */
+       "write-file",                   /* ^W */
+       "exchange-point-and-mark",      /* ^X */
+       "unbound",                      /* ^Y */
+       "unbound",                      /* ^Z */
+       "unbound",                      /* ^[ */
+       "save-file",                    /* ^\ */
+       "unbound",                      /* ^] */
+       "unbound",                      /* ^^ */
+       "unbound",                      /* ^_ */
+       "unbound",                      /*    */
+       "shell-command",                /* !  */
+       "unbound",                      /* "  */
+       "unbound",                      /* #  */
+       "unbound",                      /* $  */
+       "unbound",                      /* %  */
+       "unbound",                      /* &  */
+       "unbound",                      /* '  */
+       "begin-kbd-macro",              /* (  */
+       "end-kbd-macro",                /* )  */
+       "unbound",                      /* *  */
+       "unbound",                      /* +  */
+       "unbound",                      /* ,  */
+       "unbound",                      /* -  */
+       "unbound",                      /* .  */
+       "unbound",                      /* /  */
+       "unbound",                      /* 0  */
+       "delete-other-windows",         /* 1  */
+       "split-current-window",         /* 2  */
+       "unbound",                      /* 3  */
+       "window-find",                  /* 4  */
+       "unbound",                      /* 5  */
+       "unbound",                      /* 6  */
+       "unbound",                      /* 7  */
+       "unbound",                      /* 8  */
+       "unbound",                      /* 9  */
+       "unbound",                      /* :  */
+       "unbound",                      /* ;  */
+       "unbound",                      /* <  */
+       "unbound",                      /* =  */
+       "unbound",                      /* >  */
+       "describe-key",                 /* ?  */
+       "unbound",                      /* @  */
+       "unbound",                      /* A  */
+       "select-buffer",                /* B  */
+       "unbound",                      /* C  */
+       "delete-current-window",        /* D  */
+       "execute-kbd-macro",            /* E  */
+       "unbound",                      /* F  */
+       "unbound",                      /* G  */
+       "unbound",                      /* H  */
+       "unbound",                      /* I  */
+       "unbound",                      /* J  */
+       "delete-buffer",                /* K  */
+       "unbound",                      /* L  */
+       "unbound",                      /* M  */
+       "next-window",                  /* N  */
+       "previous-window",              /* O  */
+       "previous-window",              /* P  */
+       "unbound",                      /* Q  */
+       "unbound",                      /* R  */
+       "save-file",            /* S  */
+       "find-tag",                     /* T  */
+       "unbound",                      /* U  */
+       "unbound",                      /* V  */
+       "unbound",                      /* W  */
+       "unbound",                      /* X  */
+       "unbound",                      /* Y  */
+       "unbound",                      /* Z  */
+       "unbound",                      /* [  */
+       "unbound",                      /* \  */
+       "unbound",                      /* ]  */
+       "grow-window",                  /* ^  */
+       "unbound",                      /* _  */
+       "unbound",                      /* `  */
+       "unbound",                      /* a  */
+       "select-buffer",                /* b  */
+       "unbound",                      /* c  */
+       "delete-current-window",        /* d  */
+       "execute-kbd-macro",            /* e  */
+       "unbound",                      /* f  */
+       "unbound",                      /* g  */
+       "unbound",                      /* h  */
+       "unbound",                      /* i  */
+       "unbound",                      /* j  */
+       "delete-buffer",                /* k  */
+       "unbound",                      /* l  */
+       "unbound",                      /* m  */
+       "next-window",                  /* n  */
+       "previous-window",              /* o  */
+       "previous-window",              /* p  */
+       "unbound",                      /* q  */
+       "unbound",                      /* r  */
+       "save-file",            /* s  */
+       "find-tag",                     /* t  */
+       "unbound",                      /* u  */
+       "unbound",                      /* v  */
+       "unbound",                      /* w  */
+       "unbound",                      /* x  */
+       "unbound",                      /* y  */
+       "unbound",                      /* z  */
+       "unbound",                      /* {  */
+       "unbound",                      /* |  */
+       "unbound",                      /* }  */
+       "unbound",                      /* ~  */
+       "kill-to-beginning-of-sentence" /* ^? */
+#ifndef        ASCII7
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound",                      /* ALT- or Option-       */
+       "unbound"                       /* ALT- or Option-       */
+#endif /* !ASCII7 */
+};
diff --git a/usr/src/contrib/jove-4.14.6/list.c b/usr/src/contrib/jove-4.14.6/list.c
new file mode 100644 (file)
index 0000000..70f888a
--- /dev/null
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "list.h"
+
+private List *
+list_new()
+{
+       List    *new;
+
+       new = (List *) emalloc(sizeof (List));
+       new->car = NULL;
+       return new;
+}
+
+/* push an object to the beginning of list */
+
+UnivPtr
+list_push(list, element)
+register List  **list;
+UnivPtr element;
+{
+       List    *new;
+
+       new = list_new();
+       new->cdr = *list;
+       new->car = element;
+       *list = new;
+       return element;
+}
+
+UnivPtr
+list_pop(list)
+List   **list;
+{
+       List    *cell;
+       UnivPtr element;
+
+       if (*list == NULL)
+               return NULL;
+       cell = *list;
+       element = cell->car;
+       free((UnivPtr) cell);
+       *list = (*list)->cdr;
+
+       return element;
+}
diff --git a/usr/src/contrib/jove-4.14.6/list.h b/usr/src/contrib/jove-4.14.6/list.h
new file mode 100644 (file)
index 0000000..518ea78
--- /dev/null
@@ -0,0 +1,22 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* generic singly linked list package */
+
+typedef struct cons    List;
+
+struct cons {
+       UnivPtr car;    /* pointer to element */
+       List    *cdr;
+};
+
+#define list_next(lp)  ((lp)->cdr)
+#define list_data(lp)  ((lp)->car)
+
+extern UnivPtr
+       list_push proto((List **, UnivPtr)),
+       list_pop proto((List **));
diff --git a/usr/src/contrib/jove-4.14.6/loadavg.c b/usr/src/contrib/jove-4.14.6/loadavg.c
new file mode 100644 (file)
index 0000000..777632a
--- /dev/null
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+
+#ifdef LOAD_AV
+# if   defined(BSD4_2) && !defined(BSD2_10)
+#   if defined(PURDUE_EE) && (defined(vax) || defined(gould))
+
+void
+closekmem()
+{
+}
+
+int
+get_la()
+{
+       return loadav(0);
+}
+
+#   else       /* !(defined(PURDUE_EE) && (defined(vax) || defined(gould))) */
+
+#ifdef sun
+#   include <sys/param.h>
+#endif
+#include <nlist.h>
+
+/*
+ * struct nlist has different sizes on various machines.  So we
+ * deliberately initialize only the first element.
+ */
+static struct  nlist nl[] = {
+       { "_avenrun" },
+#define        X_AVENRUN       0
+       { "" },
+};
+
+static int     kmem = 0;
+
+void
+closekmem()
+{
+       if (kmem > 0)
+               close(kmem);
+}
+
+int
+get_la()
+{
+#ifdef sun
+       long    avenrun[3];
+#else
+       double  avenrun[3];
+#endif
+       extern long     lseek proto((int, long, int));
+
+       if (kmem == -1) {
+               return 400;     /* So shell commands will say "Chugging" */
+       } else if (kmem == 0) {
+               if ((kmem = open("/dev/kmem", 0)) == -1) {
+                       f_mess("Can't open kmem for load average.");
+                       return 400;
+               }
+               nlist("/vmunix", nl);
+       }
+       lseek(kmem, (long) nl[X_AVENRUN].n_value, 0);
+       read(kmem, (UnivPtr) avenrun, sizeof(avenrun));
+#ifdef sun
+       return (int) (avenrun[0] * 100L / FSCALE);
+#else
+       return (int) (avenrun[0] * 100. + .5);
+#endif
+}
+
+#    endif  /* !(defined(PURDUE_EE) && (defined(vax) || defined(gould))) */
+#  else        /* !(defined(BSD4_2) && !defined(BSD2_10)) */
+
+void
+closekmem()
+{
+}
+
+int
+get_la()
+{
+       short   avg[3];
+
+       gldav(avg);
+       return (int) (avg[0]*100L / 256);
+}
+
+#  endif       /* !(defined(BSD4_2) && !defined(BSD2_10)) */
+#endif /* LOAD_AV */
diff --git a/usr/src/contrib/jove-4.14.6/mac.c b/usr/src/contrib/jove-4.14.6/mac.c
new file mode 100644 (file)
index 0000000..81ad280
--- /dev/null
@@ -0,0 +1,2956 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+
+/* (C) 1986, 1987, 1988 Ken Mitchum. This code is intended only for use with Jove. */
+
+#include "tune.h"
+#ifdef MAC
+#include <MacTypes.h>
+#include "jove.h"
+#include <QuickDraw.h>
+#include <WindowMgr.h>
+#include <FontMgr.h>
+#include <ListMgr.h>
+#include <EventMgr.h>
+#include <ControlMgr.h>
+#include <DialogMgr.h>
+#include <ResourceMgr.h>
+#include <ToolboxUtil.h>
+#include <HFS.h>
+#include <StdFilePkg.h>
+#include <MenuMgr.h>
+#include <pascal.h>
+#include <errno.h>
+#include <SegmentLdr.h>
+#include "mac.h"
+#include "termcap.h"
+
+extern struct menu Menus[NMENUS];
+
+private        EventRecord the_Event;
+
+private void SetBounds proto((void));
+private void Set_std proto((void));
+private void Reset_std proto((void));
+private bool is_dir proto((char *));
+private bool findtext proto((void));
+
+/* keycodes (from Inside MacIntosh I-251). because of changes with
+the MacPlus, there are some duplicate codes between cursor keys and
+keypad keys. these can be deciphered by the corresponding character
+codes, which are different. this table simply translates a keycode
+into a character code that is appropriate. */
+
+#define NOKEY (-1)
+#define RET 0x0D
+#define TAB 0x09
+#define BACKSP 0x08
+#define ENTERL NOKEY   /* left enter key absent on MacPlus */
+#define COMMAND NOKEY  /* will be no translation anyway for these */
+#define SHIFT NOKEY
+#define CAPSLOCK NOKEY
+#define OPTION NOKEY
+#define PADDOT '.'             /* PAD period */
+#define PAD0 '0'
+#define PAD1 '1'
+#define PAD2 '2'
+#define PAD3 '3'
+#define PAD4 '4'
+#define PAD5 '5'
+#define PAD6 '6'
+#define PAD7 '7'
+#define PAD8 '8'
+#define PAD9 '9'
+#define LEFTCURS 'B'           /* jove only, make like commands */
+#define RIGHTCURS 'F'
+#define UPCURS 'P'
+#define DOWNCURS 'N'
+#define PADENTER RET
+#define PADMINUS '-'
+#define CLEAR 0
+
+private char nsh_keycodes[] = {
+       'a','s','d','f','h',                                            /* 0 - 4 */
+       'g','z','x','c','v',                                            /* 5 - 9 */
+       NOKEY,'b','q','w','e',                                  /* 10 - 14 */
+       'r','y','t','1','2',                                    /* 15 - 19 */
+       '3','4','6','5','=',                                    /* 20 - 24 */
+       '9','7','-','8','0',                                    /* 25 - 29 */
+       ']','O','u','[','i',                                    /* 30 - 34 */
+       'p',RET,'l','j','\'',                                   /* 35 - 39 */
+       'k',';','\\',',','/',                                   /* 40 - 44 */
+       'n','m','.',TAB,NOKEY,                                  /* 45 - 49 */
+       '`',BACKSP,ENTERL,NOKEY,NOKEY,                  /* 50 - 54 */
+       COMMAND,SHIFT,CAPSLOCK,OPTION, NOKEY,   /* 55 - 59 */
+       NOKEY,NOKEY,NOKEY,NOKEY,NOKEY,                  /* 60 - 64 */
+       PADDOT,RIGHTCURS,NOKEY,NOKEY,NOKEY,             /* 65 - 69 */
+       LEFTCURS,CLEAR,DOWNCURS,NOKEY,NOKEY,    /* 70 - 74 */
+       NOKEY,PADENTER,UPCURS,PADMINUS,NOKEY,   /* 75 - 79 */
+       NOKEY,NOKEY,PAD0,PAD1,PAD2,                             /* 80 - 84 */
+       PAD3,PAD4,PAD5,PAD6,PAD7,                               /* 85 - 89 */
+       NOKEY,PAD8,PAD9
+};
+
+private char sh_keycodes[] = {
+       'A','S','D','F','H',                                            /* 0 - 4 */
+       'G','Z','X','C','V',                                            /* 5 - 9 */
+       NOKEY,'B','Q','W','E',                                  /* 10 - 14 */
+       'R','Y','T','!','@',                                    /* 15 - 19 */
+       '#','$','^','%','+',                                    /* 20 - 24 */
+       '(','&','_','*',')',                                    /* 25 - 29 */
+       '}','O','U','{','I',                                    /* 30 - 34 */
+       'P',RET,'L','J','\'',                                   /* 35 - 39 */
+       'K',';','|','<','?',                                    /* 40 - 44 */
+       'N','M','>',TAB,NOKEY,                                  /* 45 - 49 */
+       '~',BACKSP,ENTERL,NOKEY,NOKEY,                  /* 50 - 54 */
+       COMMAND,SHIFT,CAPSLOCK,OPTION, NOKEY,   /* 55 - 59 */
+       NOKEY,NOKEY,NOKEY,NOKEY,NOKEY,                  /* 60 - 64 */
+       PADDOT,RIGHTCURS,NOKEY,NOKEY,NOKEY,             /* 65 - 69 */
+       LEFTCURS,CLEAR,DOWNCURS,NOKEY,NOKEY,    /* 70 - 74 */
+       NOKEY,PADENTER,UPCURS,PADMINUS,NOKEY,   /* 75 - 79 */
+       NOKEY,NOKEY,PAD0,PAD1,PAD2,                             /* 80 - 84 */
+       PAD3,PAD4,PAD5,PAD6,PAD7,                               /* 85 - 89 */
+       NOKEY,PAD8,PAD9
+};
+
+
+
+/* tn.h Modified for variable screen size 11/21/87. K. Mitchum */
+
+#define SCREENSIZE (wc->w_rows * ROWSIZE)
+#define FONT monaco
+#define TEXTSIZE 9
+
+#define HEIGHT 11
+#define WIDTH 6
+#define DESCENT 2
+#define TWIDTH CO * WIDTH
+#define THEIGHT LI * HEIGHT
+
+/* window specs */
+
+#define SCROLLWIDTH 16 /* width of scroll bar control in pixels */
+#define WINDWIDTH (wc->w_width - SCROLLWIDTH + 1)      /* local coordinates */
+#define WINDHEIGHT (wc->w_height)      /* local coordinates */
+#define MAXROW (LI - 1)
+#define MAXCOL (CO - 1)
+
+
+/* for keyboard routines */
+#define MCHARS 32      /* must be power of two */
+#define NMASK MCHARS (-1)      /* circular buffer */
+
+
+/***************************************************/
+
+/* these normally reside in "tune.c" which we don't use */
+
+char *CmdDb;   /* see InitMac() */
+char *p_tempfile = ".jrecXXX";
+char *d_tempfile = ".joveXXX";
+char *Joverc = ".joverc";
+
+
+void putcurs(),curset(),putp(),dellines(),inslines();
+
+private Rect LimitRect;        /* bounds we can't move past */
+
+struct wind_config {
+       int w_width;    /* pixel width of the Mac window */
+       int     w_height;
+       int     w_rows; /* rows of characters which fit the window */
+       int     w_cols;
+} wc_std, wc_user, *wc;
+
+private WindowPtr theScreen;
+
+int
+       errno;
+
+bool
+       Windchange,
+       EventCmd,
+       Keyonly,
+       Bufchange,
+       Modechange,
+       Macmode = OFF;
+
+/* Initialization Routines. */
+
+void
+InitBinds()
+{
+       struct cmd *c;
+       data_obj **p;
+       int i;
+
+       p = MainKeys;
+       for (i= 0; i < NCHARS; i++) {
+               c = (struct cmd *) *p;
+               c->c_map = F_MAINMAP;
+               c->c_key = i;
+               p++;
+       }
+
+       p = EscKeys;
+       for (i= 0; i < NCHARS; i++) {
+               c = (struct cmd *) *p;
+               c->c_map = F_PREF1MAP;
+               c->c_key = i;
+               p++;
+       }
+       p = CtlxKeys;
+       for (i= 0; i < NCHARS; i++) {
+               c = (struct cmd *) *p;
+               c->c_map = F_PREF2MAP;
+               c->c_key = i;
+               p++;
+       }
+
+}
+
+private        WindowPtr window;
+private        Rect r;
+private CursHandle cross;
+
+void
+InitEvents()
+{
+       void InitSysMenu();
+
+       window = theScreen;
+       InitSysMenu();
+       SetRect(&r,window->portRect.left,
+       window->portRect.top,
+       window->portRect.right - SCROLLWIDTH,
+       window->portRect.bottom - SCROLLWIDTH);
+       cross = GetCursor(crossCursor);
+}
+
+void
+MacInit()
+{
+       char *gethome();
+       void tn_init();
+
+       tn_init();
+       getdir();
+       gethome();      /* before anyone changes it */
+       CmdDb = malloc(strlen(gethome()) + 10);
+       /* ??? better check for CmdDb == NULL -- DHR */
+       strcpy(CmdDb,gethome());
+       strcat(CmdDb,"/cmds.doc");
+       InitBinds();
+}
+
+
+/* dummy routines. */
+
+int dummy() {}
+
+SIGRESULT
+(*signal(sig,func)) proto((int))
+int sig;
+SIGRESULT (*func) proto((int));
+{
+       return &dummy;
+}
+
+void dorecover() {}
+
+
+/* Surrogate unix-style file i/o routines for Jove. These replace the
+   routines distributed in the libraries. They work with Jove, but may
+   not be general enough for other purposes. */
+
+#include <io.h>
+#define NFILES 10
+
+/* #define fsetup(p) { \
+ *     (p).ioCompletion = 0; \
+ *     (p).ioVRefNum = cur_vol; \
+ *     (p).ioDirID = cur_dir; \
+ *     (p).ioFVersNum = 0; \
+ * }
+ * #define isetup(p) {(p).ioCompletion = 0; (p).ioVRefNum = cur_vol;}
+ */
+
+private int cur_vol;   /* Disk or volume number */
+private long cur_dir;  /* Directory number */
+private int cur_vref;  /* ugh.. Vref for volume + directory */
+
+struct ftab {
+       int inuse;      /* 0 = closed 1 = binary 2 = text*/
+       int refnum;     /* Mac file reference number */
+} ft[NFILES];
+
+private void
+fsetup(p)
+HParmBlkPtr p;
+{
+       byte_zero(p,sizeof(HParamBlockRec));
+       p->fileParam.ioVRefNum = cur_vol;
+       p->fileParam.ioDirID = cur_dir;
+       p->fileParam.ioFVersNum = 0;
+}
+
+private void
+isetup(p)
+HIOParam *p;
+{
+       byte_zero(p,sizeof(HIOParam));
+       p->ioVRefNum = cur_vol;
+}
+
+
+/* Kludge to convert Macintosh error codes to something like Unix. */
+
+private int
+cvt_err(err)   /* some of these don't make sense... */
+int    err;
+{
+       switch(err) {
+       case noErr:     errno = 0; return 0;
+       case dirFulErr:
+       case dskFulErr: errno = ENOSPC; break;
+       case nsvErr:
+       case mFulErr:
+       case tmfoErr:
+       case fnfErr:
+       default:        errno = ENOENT; break;
+       case ioErr:     errno = EIO; break;
+       case bdNamErr:
+       case opWrErr:
+       case paramErr:  errno = EINVAL; break;
+       case fnOpnErr:                          /* dubious... */
+       case rfNumErr:  errno = EBADF; break;
+       case eofErr:                            /* ditto */
+       case posErr:    errno = ESPIPE; break;
+       case wPrErr:    errno = EROFS; break;
+       case fLckdErr:
+       case permErr:   errno = EACCES; break;
+       case fBsyErr:   errno = EBUSY; break;
+       case dupFNErr:  errno = EEXIST; break;
+       case gfpErr:
+       case volOffLinErr:
+       case volOnLinErr:
+       case nsDrvErr:  errno = ENODEV; break;
+       case noMacDskErr:
+       case extFSErr:  errno = EIO; break;
+       case fsRnErr:
+       case badMDBErr:
+       case wrPermErr: errno = EPERM; break;
+       }
+       return -1;
+}
+
+private char *
+cvt_fnm(file)
+char *file;
+{
+       static char nm[255];
+       char *t;
+
+
+       if (*file == '/')
+               strcpy(nm,file + 1);    /* full path */
+       else {
+               if (strchr(file + 1, '/') != NULL)
+                       strcpy(nm,"/"); /* make a partial pathname */
+               else
+                       *nm = '\0';
+               strcat(nm,file);
+       }
+       t = nm;
+       while (*t) {
+               if (*t == '/')
+                       *t = ':';
+               t++;
+       }
+       return nm;
+}
+
+int
+creat(name,perm)       /* permission mode is irrelevant on a Mac */
+char   *name;
+int    perm;
+{
+       int fd, err;
+       char *nm;
+       HParamBlockRec p;
+
+       if (is_dir(name)) {
+               errno = EACCES;
+               return -1;
+       }
+       nm = cvt_fnm(name);     /* convert filename to Mac type name */
+       CtoPstr(nm);
+       for (fd = 0; fd < NFILES && ft[fd].inuse; fd++)
+               ;
+       if (fd == NFILES) {
+               errno = EMFILE;
+               return -1;
+       }
+       fsetup(&p);     /* try to delete it, whether it is there or not. */
+       p.fileParam.ioNamePtr = (StringPtr) nm;
+       if ((err = PBHDelete(&p,0)) != noErr && err != fnfErr)
+               return cvt_err(err);
+       if (do_creat(&p,nm) != 0)
+               return -1;
+       else {
+               ft[fd].inuse++;
+               ft[fd].refnum = p.ioParam.ioRefNum;
+               return fd + 1;
+       }
+}
+
+int
+open(name,mode)
+char   *name;
+int    mode;
+{
+       int fd, err;
+       char *nm;
+       HParamBlockRec p;
+
+       if (is_dir(name)) {
+               errno = EACCES;
+               return -1;
+       }
+
+       nm = cvt_fnm(name);     /* convert filename to Mac type name */
+       CtoPstr(nm);
+       for (fd = 0; fd < NFILES && ft[fd].inuse; fd++)
+               ;
+       if (fd == NFILES) {
+               errno = EMFILE;
+               return -1;
+       }
+       fsetup(&p);
+       switch (mode & 3) {
+       case O_RDONLY:
+               p.ioParam.ioPermssn = fsRdPerm;
+               break;
+       case O_WRONLY:
+               p.ioParam.ioPermssn = fsWrPerm;
+               break;
+       case O_RDWR:
+               p.ioParam.ioPermssn = fsRdWrPerm;
+               break;
+       }
+       p.ioParam.ioNamePtr = (StringPtr) nm;
+       p.ioParam.ioMisc = 0;
+       if ((err = PBHOpen(&p,0)) != noErr && err != fnfErr)
+               return cvt_err(err);
+       if (err == noErr && mode & O_CREAT && mode & O_EXCL) {
+               PBClose(&p,0);
+               errno = EEXIST;
+               return -1;
+       }
+       if (err == fnfErr) {
+               if (mode & O_CREAT) {
+                       if (do_creat(&p,nm) != 0)
+                               return -1;
+               } else {
+                       errno = ENOENT;
+                       return -1;
+               }
+       }
+       ft[fd].inuse++;
+       ft[fd].refnum = p.ioParam.ioRefNum;
+       p.ioParam.ioPosMode =  (mode & O_APPEND)? fsFromLEOF : fsFromStart;
+       p.ioParam.ioPosOffset = 0;
+       if ((err = PBSetFPos(&p,0)) != noErr) {
+               ft[fd].inuse = 0;
+               return cvt_err(err);
+       }
+       errno = 0;
+       return fd + 1;
+}
+
+private int
+do_creat(p,nm)
+HParmBlkPtr p;
+char *nm;
+{
+       int err;
+
+       fsetup(p);
+       p->fileParam.ioNamePtr = (StringPtr) nm;
+       if ((err = PBHCreate(p,0)) != noErr)
+               return cvt_err(err);
+       fsetup(p);
+       p->fileParam.ioNamePtr = (StringPtr) nm;
+       p->fileParam.ioFDirIndex = 0;
+       if ((err = PBHGetFInfo(p,0)) != noErr)
+               return cvt_err(err);
+       p->fileParam.ioDirID = cur_dir;
+       p->fileParam.ioFlFndrInfo.fdType = 'TEXT';
+       p->fileParam.ioFlFndrInfo.fdCreator = 'JV01';
+       p->fileParam.ioFlFndrInfo.fdFlags = 0;
+       p->fileParam.ioFVersNum = 0;
+       if ((err = PBHSetFInfo(p,0)) != noErr)
+               return cvt_err(err);
+       fsetup(p);
+       p->ioParam.ioNamePtr = (StringPtr) nm;
+       p->ioParam.ioPermssn = fsRdWrPerm;
+       p->ioParam.ioMisc = 0;
+       if (cvt_err(PBHOpen(p,0)))
+               return -1;
+       return 0;
+}
+
+
+int
+close(fd)
+int    fd;
+{
+       int err;
+       HParamBlockRec p;
+
+       fsetup(&p);
+       p.ioParam.ioRefNum = ft[--fd].refnum;
+       ft[fd].inuse = 0;
+#ifdef NEVER
+       if (cvt_err(PBFlushFile(&p,0)) < 0)
+               return -1;
+       fsetup(&p);
+#endif
+       if (cvt_err(PBClose(&p,0)) < 0)
+               return -1;
+       fsetup(&p);
+       p.ioParam.ioNamePtr = NULL;
+       if (cvt_err(PBFlushVol(&p,0)) < 0)
+               return -1;
+       return 0;       /* ??? added by DHR */
+}
+
+/* Raw read, except '\n' is translated to '\r'.
+ * Surely this could be done better by having '\n' stand for '\015'
+ * as it is done in OS-9.
+ */
+int
+read(fd,buf,n)
+int    fd;
+char   *buf;
+unsigned       n;
+{
+       int err;
+       IOParam p;
+       if (fd == 0)
+               return con_read(buf,n);
+       if (ft[--fd].inuse == 0) {
+               errno = EBADF;
+               return -1;
+       }
+       isetup(&p);
+       p.ioRefNum = ft[fd].refnum;
+       p.ioBuffer = buf;
+       p.ioReqCount = n;
+       p.ioPosMode = fsFromMark;
+       p.ioPosOffset = 0;
+       if ((err = PBRead(&p,0)) != noErr && err != eofErr)
+               return cvt_err(err);
+       while (n--) {
+               if (*buf == '\r')
+                       *buf = '\n';    /* convert from Mac style */
+               buf++;
+       }
+       errno = 0;
+       return p.ioActCount;
+}
+
+/* Raw write, except '\n' is translated to '\r'.
+ * Surely this could be done better by having '\n' stand for '\015'
+ * as it is done in OS-9.
+ */
+int
+write(fd,buf,n)
+int    fd;
+const char     *buf;
+unsigned       n;
+{
+#ifdef NEVER
+       int err;
+       IOParam p;
+       char *obuf, *s;
+
+       if (fd == 0)
+               return con_write(buf,n);
+
+       s = obuf = malloc(n + 1);
+       if (obuf == NULL)
+               return -1;      /* shouldn't happen... */
+       if (ft[--fd].inuse == 0) {
+               errno = EBADF;
+               free(obuf);
+               return -1;
+       }
+       isetup(&p);
+       p.ioRefNum = ft[fd].refnum;
+       p.ioBuffer = obuf;
+       p.ioReqCount = (long) n;
+       p.ioPosMode = fsFromMark;
+       p.ioPosOffset = 0L;
+       while (n--) {
+               if (*buf == '\n')
+                       *s = '\r';      /* make it look like Mac files */
+               else
+                       *s = *buf;
+               buf++;
+               s++;
+       }
+       if ((err = PBWrite(&p,0)) != noErr) {
+               free(obuf);
+               return -1;
+       }
+       free(obuf);
+       return (int) p.ioActCount;
+#else
+       /* ??? This version is untested! -- DHR
+        * It avoids a malloc for every file write!
+        */
+       if (fd == 0) {
+               return con_write(buf,n);
+       } else {
+               IOParam p;
+               const char      *ebuf = buf + n;
+
+               p.ioRefNum = ft[fd].refnum;
+               p.ioPosMode = fsFromMark;
+               while (buf != ebuf) {
+                       int err;
+
+                       if (*buf == '\n') {
+                               p.ioReqCount = 1
+                               p.ioBuffer = "\r";
+                       } else {
+                               const char      *p = buf
+
+                               while (p != ebuf && *p != '\n')
+                                       p++;
+                               p.ioReqCount = p-buf;
+                               p.ioBuffer = buf;
+                       }
+                       p.ioPosOffset = 0L;     /* bidirectional */
+                       if ((err = PBWrite(&p,0)) != noErr)
+                               return cvt_err(err);
+                       buf += p.ioActCount;
+               }
+               return n;
+       }
+#endif
+}
+
+long
+lseek(fd,offset,type)  /* The Mac version of this doesn't allocate new space. */
+int    fd;
+long   offset;
+unsigned       type;
+{
+       int err;
+       long cur_mark, eof, new_mark;
+       IOParam p;
+
+       if (ft[--fd].inuse == 0) {
+               errno = EBADF;
+               return -1;
+       }
+
+       isetup(&p);
+       p.ioRefNum = ft[fd].refnum;
+       if ((err = PBGetFPos(&p,0)) != noErr)
+               return cvt_err(err);
+       cur_mark = p.ioPosOffset;
+       isetup(&p);
+       p.ioRefNum = ft[fd].refnum;
+       if ((err = PBGetEOF(&p,0)) != noErr)
+               return cvt_err(err);
+       eof = (long) p.ioMisc;
+       switch(type) {
+       case 0:
+               new_mark = offset;
+               break;
+       case 1:
+               new_mark = offset + cur_mark;
+               break;
+       case 2:
+               new_mark = offset + eof;
+               break;
+       }
+       if (new_mark > eof) {           /* need more space in file */
+               isetup(&p);
+               p.ioRefNum = ft[fd].refnum;
+               p.ioMisc = (Ptr) new_mark;
+               if ((err = PBSetEOF(&p,0)) != noErr)
+                       return cvt_err(err);
+#ifdef NEVER
+               if ((err = PBAllocContig(&p,0)) != noErr)
+                       return cvt_err(err);
+#endif
+       }
+       isetup(&p);
+       p.ioRefNum = ft[fd].refnum;
+       p.ioPosOffset = new_mark;
+       p.ioPosMode = fsFromStart;
+       if ((err = PBSetFPos(&p,0)) != noErr)
+               return cvt_err(err);
+       errno = 0;
+       return p.ioPosOffset;
+}
+
+int
+unlink(name)
+char *name;
+{      int fd, err;
+       char *nm;
+       HParamBlockRec p;
+
+       nm = cvt_fnm(name);     /* convert filename to Mac type name */
+       CtoPstr(nm);
+       fsetup(&p);     /* try to delete it, whether it is there or not. */
+       p.fileParam.ioNamePtr = (StringPtr) nm;
+       if ((err = PBHDelete(&p,0)) != noErr && err != fnfErr)
+               return cvt_err(err);
+       return 0;       /* ??? added by DHR */
+}
+
+/* Console read and write routines */
+
+private int
+con_write(buf,size)
+char *buf;
+unsigned  size;
+{
+       while (size--)
+               putp(*buf++);
+       return size;
+}
+
+private int
+con_read(buf,size)
+char *buf;
+unsigned size;
+{
+       unsigned n;
+       int p;
+
+
+       n = 0;
+       do {
+               p = rawgetc();
+#ifdef O_META
+               if (p & 0x7f)
+                       p &= 0x7f;              /* was normal ascii char */
+#endif
+               *buf++ = p;
+               n++;
+       } while (rawchkc() && n <= size);
+       return n;
+}
+
+
+/* This didn't seem to be any place else */
+
+int
+abs(n)
+int n;
+{
+       return n >= 0 ? n : -n;
+
+}
+
+/* Simplified stat() routine emulates what is needed most. */
+
+int
+stat(fname,buf)
+char *fname;
+struct stat *buf;
+{
+       CInfoPBRec p;
+       char *nm;
+
+       nm = cvt_fnm(fname);
+       CtoPstr(nm);
+       byte_zero(&p,sizeof(CInfoPBRec));
+       p.hFileInfo.ioCompletion = 0;
+       p.hFileInfo.ioNamePtr = (StringPtr) nm;
+       p.hFileInfo.ioFVersNum = 0;
+       p.hFileInfo.ioFDirIndex = 0;
+       p.hFileInfo.ioVRefNum = cur_vol;
+       p.hFileInfo.ioDirID = cur_dir;
+
+       switch (PBGetCatInfo(&p,0)) {
+       case noErr:
+               errno = 0;
+               break;
+       case nsvErr:
+       case paramErr:
+       case bdNamErr:
+       case fnfErr:
+               errno = ENOENT;
+               break;
+       case ioErr:
+               errno = EIO;
+               break;
+       default:
+               errno = ENOENT;
+               break;
+       }
+       buf->st_dev = p.hFileInfo.ioVRefNum + 1;        /* don't want 0 */
+       buf->st_ino = p.hFileInfo.ioDirID;
+       buf->st_size = p.hFileInfo.ioFlLgLen;
+       buf->st_mtime = p.hFileInfo.ioFlMdDat;
+       buf->st_mode = (p.hFileInfo.ioFlAttrib & 0x10) ? S_IFDIR : 0;
+       PtoCstr(nm);
+       return errno == 0 ? 0 : -1;
+}
+
+private bool
+is_dir(fname)
+char *fname;
+{
+       struct stat s;
+
+       return (stat(fname,&s) == 0) && (s.st_mode & S_IFDIR);
+}
+
+/* Directory related routines. Jove keeps track of the true Volume (disk) number and
+   directory number, and avoids "Working Directory Reference Numbers", which are
+   confusing. */
+
+private int
+getdir()       /* call this only once, during startup. */
+{
+       WDPBRec p;
+
+       p.ioCompletion = 0;
+       p.ioNamePtr = NULL;
+       if (PBHGetVol(&p,0) != noErr)
+               return -1;      /* BIG trouble */
+       cur_vol = p.ioWDVRefNum;
+       cur_dir = p.ioWDDirID;
+       SFSaveDisk = 0 - cur_vol;       /* these are for SF dialogs */
+       CurDirStore = cur_dir;
+       return 0;       /* ??? added by DHR */
+}
+
+private int
+setdir(vol,dir)
+int    vol;
+long   dir;
+{
+       WDPBRec p;
+
+       p.ioCompletion = 0;
+       p.ioNamePtr = NULL;
+       p.ioVRefNum = vol;
+       p.ioWDDirID = dir;
+       if (PBHSetVol(&p,0) != noErr)
+               return -1;
+       cur_vol = vol;
+       cur_dir = dir;
+       SFSaveDisk = 0 - vol;   /* these are for SF dialogs */
+       CurDirStore = dir;
+
+
+}
+
+int
+chdir(dir)
+char *dir;
+{
+       CInfoPBRec d;
+       WDPBRec p;
+       char *t;
+       char *nm;
+
+       if (strcmp(dir,"/") == 0)
+               return -1;      /* There is no root... */
+       nm = malloc(strlen(dir) + 2);
+       if (nm == NULL)
+               return -1;
+
+       strcpy(nm,dir);
+       t = nm;
+       while (*t) {
+               if (*t == '/')
+                       *t = ':';
+               t++;
+       }
+       t = nm;
+       while (*t == ':')
+               t++;    /*get rid of initial slashes */
+       strcat(nm,":");
+       CtoPstr(t);
+
+       d.dirInfo.ioCompletion = 0;                     /* get the directory number */
+       d.dirInfo.ioNamePtr = (StringPtr) t;
+       d.dirInfo.ioVRefNum = cur_vol;
+       d.dirInfo.ioFDirIndex = 0;
+       d.dirInfo.ioDrDirID = 0;
+       PBGetCatInfo(&d,0);
+       free(nm);
+       if (d.dirInfo.ioResult != noErr
+       || (d.dirInfo.ioFlAttrib & 0x10) == 0
+       || setdir(d.dirInfo.ioVRefNum,d.dirInfo.ioDrDirID) < 0)
+               return -1;
+       return 0;
+}
+
+/* Scandir returns the number of entries or -1 if the directory cannot
+   be opened or malloc fails. */
+
+int
+jscandir(dir, nmptr, qualify, sorter) /* this function has NOT been debugged */
+char   *dir;
+char   ***nmptr;
+int    (*qualify) proto((char *));
+int    (*sorter) proto((UnivConstPtr, UnivConstPtr));
+{
+       CInfoPBRec d;
+       Str255 buf;
+       long DirID;
+       char    **ourarray, *nm, *t;
+       unsigned int    nalloc = 10,
+                       nentries = 0,
+                       index = 1;
+       char *getwd();
+
+       if (strcmp(dir,"/") == 0)
+               return -1;      /* There is no root... */
+       if (strcmp(dir,".") == 0)
+               dir = getwd();
+       nm = malloc(strlen(dir) + 2);
+       if (nm == NULL)
+               return -1;
+
+       strcpy(nm,dir);
+       t = nm;
+       while (*t) {
+               if (*t == '/')
+                       *t = ':';
+               t++;
+       }
+       t = nm;
+       while (*t == ':')
+               t++;    /*get rid of initial slashes */
+       strcat(nm,":");
+       CtoPstr(t);
+
+       byte_zero(&d,sizeof(CInfoPBRec));
+       d.dirInfo.ioCompletion = 0;                     /* get the directory number */
+       d.dirInfo.ioNamePtr = (StringPtr) t;
+       d.dirInfo.ioVRefNum = cur_vol;
+       d.dirInfo.ioFDirIndex = 0;
+       d.dirInfo.ioDrDirID = 0;
+       PBGetCatInfo(&d,0);
+       PtoCstr(t);
+       free(nm);
+       if (d.dirInfo.ioResult != noErr
+       || ((d.dirInfo.ioFlAttrib & 0x10) == 0))
+               return -1;
+       DirID = d.dirInfo.ioDrDirID;
+       ourarray = (char **) emalloc(nalloc * sizeof (char *));
+       for (;;) {
+               byte_zero(&d,sizeof(CInfoPBRec));
+               d.dirInfo.ioCompletion = (long) 0;
+               d.dirInfo.ioVRefNum = cur_vol;
+               d.dirInfo.ioFVersNum = 0;
+               d.dirInfo.ioNamePtr = (StringPtr) buf;
+               d.dirInfo.ioFDirIndex = index++;
+               d.dirInfo.ioVRefNum = cur_vol;
+               d.dirInfo.ioDrDirID = DirID;
+               if (PBGetCatInfo(&d,0) != noErr)
+                       break;  /* we are done, then */
+               PtoCstr((char *) buf);
+#ifdef NEVER
+               if (d.dirInfo.ioFlAttrib & 0x10)
+                       strcat(buf,"/");
+#endif
+               if (qualify != NULL && (*qualify)((char *) buf) == 0)
+                       continue;
+               if (nentries == nalloc)
+                       ourarray = (char **) erealloc((char *) ourarray, (nalloc += 10) * sizeof (char *));
+               ourarray[nentries] = (char *) emalloc(strlen(buf)+1);
+               null_ncpy(ourarray[nentries], (char *) buf, strlen((char *) buf));
+               nentries += 1;
+       }
+       if ((nentries + 1) != nalloc)
+               ourarray = (char **) erealloc((char *) ourarray,
+                       ((nentries + 1) * sizeof (char *)));
+       if (sorter != NULL)
+               qsort((char *) ourarray, nentries, sizeof (char **), sorter);
+       *nmptr = ourarray;
+       ourarray[nentries] = NULL;              /* guaranteed NULL pointer */
+       return nentries;
+}
+
+void
+freedir(dir, nentries)
+char ***dir;
+int nentries;
+{
+       char **ptr = *dir;
+       while (nentries--)
+               free(*ptr++);
+}
+
+int
+alphacomp(a, b)
+UnivConstPtr   a,
+       b;
+{
+       return strcmp(*(const char **)a, *(const char **)b);
+}
+
+bool
+chkCWD(name)   /* eventually, may check validity of cwd */
+char *name;
+{
+       return TRUE;
+}
+
+
+char *
+getwd()
+{
+       CInfoPBRec d;
+       static char ret[255];
+       char nm[50], tmp[255];
+
+       ret[0] = '\0';
+       d.dirInfo.ioDrDirID = cur_dir;
+       for (;;) {
+               d.dirInfo.ioCompletion = 0;
+               d.dirInfo.ioNamePtr = (StringPtr) nm;
+               d.dirInfo.ioVRefNum = cur_vol;
+               d.dirInfo.ioFDirIndex = -1;
+
+               PBGetCatInfo(&d,0);
+               if (d.dirInfo.ioResult != noErr)
+                       return NULL;
+               PtoCstr((char *) nm);
+               strcpy(tmp,ret);
+               strcpy(ret,"/");
+               strcat(ret,nm);
+               strcat(ret,tmp);
+               if (d.dirInfo.ioDrDirID == 2)
+                       break;  /* home directory */
+               d.dirInfo.ioDrDirID = d.dirInfo.ioDrParID;
+       }
+       return ret;
+}
+
+private char *
+gethome()              /* this will be startup directory */
+{
+       static char *ret = NULL;
+
+
+       if (ret == NULL) {
+               char *item = getwd();
+
+               ret = emalloc(strlen(item)+1);
+               strcpy(ret,item);
+       }
+       return ret;
+}
+
+
+
+/* Routines that put up and manipulate the "About Jove" dialog. */
+
+
+/* (ORIGINALLY IN) about_j.c. */
+
+
+#define DLOGNAME "\pABOUT_JDLOG"
+
+#define DONE_ITEM 1
+#define LIST_ITEM 2
+
+
+#define DWIDTH 460             /* there should be an easy way to get this */
+#define DHEIGHT 240            /* from the resource file! */
+
+WindowPtr makedisplay();
+ListHandle makelist();
+
+
+private WindowPtr theWindow;
+private ListHandle theList;
+private Rect theListRect;
+private EventRecord theEvent;
+
+
+
+private void
+about_j()
+{
+       void do_list(), do_events();
+
+       WindowPtr OldWindow;
+
+       GetPort(&OldWindow);
+
+       if ((theWindow = makedisplay()) == 0)
+               return;
+       SetPort(theWindow);
+       if (theList = makelist()) {
+               LActivate(1,theList);
+               do_list();
+               ShowWindow(theWindow);
+               do_events();
+       }
+       SetPort(OldWindow);
+       LDispose(theList);
+       DisposDialog(theWindow);
+}
+
+
+private WindowPtr
+makedisplay()
+{
+       static int dlogid = 0;
+
+       DialogPtr theDialog;
+       Handle theHandle;
+       Handle theResource;
+       Str255 buf;
+       long itemType;
+       Rect theRect;
+       short dh,dv;    /* to center dialog on the screen */
+       Str255 nostring;
+
+       if (dlogid == 0) {
+               if ((theResource = GetNamedResource('DLOG',DLOGNAME)) == 0)
+                       return (WindowPtr)NULL;
+               itemType = 'DLOG';
+               GetResInfo(theResource,&dlogid,&itemType,buf);
+       }
+
+       theDialog = GetNewDialog(dlogid,(long) 0,(WindowPtr) -1);
+       strcpy((char *) nostring,"\p");
+       ParamText("\pMacJove - Copyright (C) 1986, 1987, 1988 J. Payne, K. Gegenfurtner,",
+       "\pK. Mitchum. Portions (C) THINK Technologies, Inc.",nostring,nostring);
+
+       dh = screenBits.bounds.left + (screenBits.bounds.right - DWIDTH) / 2;
+       dv = screenBits.bounds.top  + (screenBits.bounds.bottom - DHEIGHT) / 2;
+       MoveWindow((WindowPtr)theDialog,dh,dv,0);
+       ShowWindow((WindowPtr)theDialog);
+
+
+       GetDItem(theDialog,LIST_ITEM,&itemType,&theHandle,&theRect);
+       theListRect = theRect;
+       theListRect.right -= 15;
+       ((WindowPtr)theDialog)->txFont = FONT;
+       ((WindowPtr)theDialog)->txSize = TEXTSIZE;
+
+       return (WindowPtr) theDialog;
+}
+
+private void
+do_display()           /* draw necessary controls, lines */
+{
+       Rect rViewF;            /* framing rect for list */
+       int offset;
+
+       rViewF = theListRect;
+
+       rViewF.left--;
+       rViewF.top--;
+       rViewF.right++;
+       rViewF.bottom++;
+       FrameRect(&rViewF);
+
+       DrawControls(theWindow);
+
+}
+
+private ListHandle
+makelist()
+{
+       Point csize;
+       Rect dataBounds, rView; /* list boundaries */
+
+       csize.h = csize.v = 0;
+       SetRect(&dataBounds,0,0,1,0);
+       return LNew(&theListRect,&dataBounds,csize,0,theWindow,0,0,0,1);
+}
+
+private void
+do_list()
+{
+       void printbind();
+
+       int row, col;
+       struct cmd *f;
+       Str255 buf;
+       Point theCell;
+
+       theCell.h = 0;
+
+       for (f = commands, row = 0; f->Name; f++, row++) {
+               LAddRow(1,row,theList);
+               theCell.v = row;
+
+               printbind(f,buf);
+               strcat(buf,f->Name);
+               LSetCell(buf,strlen((char *)buf),theCell,theList);
+
+       }
+}
+private void
+printbind(f,buf)
+struct cmd *f;
+char *buf;
+{
+       char c;
+
+       if (f->c_map == 0 || (c = f->c_key) == 0x7f) {
+               strcpy(buf,"        ");
+               return;
+       }
+       switch(f->c_map) {
+       case F_MAINMAP :
+               strcpy(buf,"     ");
+               break;
+
+       case F_PREF1MAP :
+               strcpy(buf," ESC ");
+               break;
+
+       case F_PREF2MAP :
+               strcpy(buf,"  ^X ");
+               break;
+       }
+       if (c < ' ') {
+               buf[5] = '^';           /* control char */
+               c |= 0x40;
+       } else {
+               buf[5] = ' ';
+       }
+       if (c >= 'a' && c<= 'z')
+               c &= 0x5f;
+       buf[6] = c;
+       buf[7] = ' ';
+       buf[8] = '\0';
+}
+
+
+
+private pascal Boolean
+ProcFilter(theDialog,event,itemHit)
+DialogPtr theDialog;
+EventRecord *event;
+int *itemHit;
+{
+       theEvent = *event;
+       if (theEvent.what == keyDown && theEvent.message & charCodeMask == '\r') {
+               *itemHit = 1;
+               return TRUE;
+       }
+       if (theEvent.what == activateEvt && (WindowPtr) theEvent.message == theWindow) {
+               LDoDraw(1,theList);
+               LActivate(1,theList);
+       }
+       if (theEvent.what == updateEvt && (WindowPtr) theEvent.message == theWindow) {
+               BeginUpdate(theWindow);
+               do_display();
+               DrawDialog(theWindow);
+               LUpdate((GrafPtr) theWindow->visRgn,theList);
+               EndUpdate(theWindow);
+       }
+
+       return FALSE;
+}
+
+
+void
+do_events()
+{
+       int item;
+       bool done = NO;
+       Point p;
+
+       while (!done) {
+               ModalDialog(ProcFilter,&item);
+               switch(item) {
+               case DONE_ITEM :
+                       done = YES;
+                       /* ??? fall through? -- DHR */
+               case LIST_ITEM :
+                       p = theEvent.where;
+                       GlobalToLocal(&p);
+                       LClick(p,theEvent.modifiers,theList);
+                       break;
+               }
+       }
+}
+
+/* Window and Control related routines. */
+
+/* (ORIGINALLY IN) tcon.c.
+   control handler routines for Jove. K. Mitchum 12/86 */
+
+
+#define MINC 0
+#define MAXC ((int)100)
+#define INITC 0
+#define EVENTLIST (mDownMask | keyDownMask )
+
+extern long
+GetCRefCon();  /* omitted in ControlMgr.h */
+
+private Point p;
+private intext;        /* mouse down in jove text */
+private bool wc_adjust proto((int, int, struct wind_config *, int));
+
+void
+docontrols()   /* called from redisplay routines */
+{
+       void MakeScrollBar(),
+               AdjustScrollBar(),
+               drawfluff();
+
+       Window *w;
+       int top;
+
+       w = fwind;
+       top = 0;
+       do {
+               if (w->w_control)
+                       HideControl(w->w_control);
+               w = w->w_next;
+       } while (w != fwind);
+       w = fwind;
+       do {
+               w->w_topline = top;
+               if (w->w_control)
+                       AdjustScrollBar(w);
+               else
+                       MakeScrollBar(w);
+               ShowControl(w->w_control);
+               top += w->w_height;
+               w = w->w_next;
+       } while (w != fwind);
+       Windchange = NO;
+       drawfluff();
+}
+
+
+void
+MakeScrollBar(w)       /* set up control */
+Window *w;
+{
+       Rect BarRect;
+       int wheight, wtop;
+
+       WindowPtr window = theScreen;
+       wheight = w->w_height;
+       wtop = w->w_topline;
+       SetRect(&BarRect,window->portRect.right - SCROLLWIDTH + 1,
+               window->portRect.top -2 + wtop * HEIGHT,
+               window->portRect.right +1,
+               window->portRect.top + ((wheight + wtop) * HEIGHT + 1));
+               w->w_control = ((char **) NewControl(window,&BarRect,"/psbar",1,INITC,
+               MINC,MAXC,scrollBarProc,w));
+}
+
+void
+AdjustScrollBar(w)     /* redo existing control */
+Window *w;
+{
+       int wtop,wheight;
+       ControlHandle handle;
+       WindowPtr window;
+
+       handle = (ControlHandle) w->w_control;
+       wtop = w->w_topline;
+       wheight = w->w_height;
+       window = (*handle)->contrlOwner;
+
+       if (handle == 0)
+               return;
+
+       SizeControl(handle,SCROLLWIDTH,wheight * HEIGHT + 1);
+
+       MoveControl(handle,window->portRect.right - SCROLLWIDTH + 1,
+               window->portRect.top -1 + wtop * HEIGHT);
+
+}
+
+void
+SetScrollBar(handle)   /* set value of the bar */
+ControlHandle handle;
+{
+
+       SetCtlValue(handle,ltoc());
+}
+
+private void
+drawfluff()            /* draw controls and dividers */
+{
+       Window *w = fwind;
+
+       DrawControls(theScreen);
+       DrawGrowIcon(theScreen);
+}
+
+void
+RemoveScrollBar(w)
+Window *w;
+{
+       if (w->w_control)
+               DisposeControl(w->w_control);
+       w->w_control = 0;
+
+}
+
+private pascal void
+DScroll(control,part)
+ControlHandle control;
+int part;
+{
+       DownScroll();
+       redisplay();
+}
+
+private pascal void
+UScroll(control,part)
+ControlHandle control;
+int part;
+{
+       UpScroll();
+       redisplay();
+}
+
+private pascal void
+NPage(control,part)
+ControlHandle control;
+int part;
+{      NextPage();
+       redisplay();
+}
+
+private pascal void
+PPage(control,part)
+ControlHandle control;
+int part;
+{      PrevPage();
+       redisplay();
+}
+
+private long npos;     /* number of lines in buffer */
+
+private int
+ltoc() /* calculate ctlvalue for line position */
+{
+       register long ipos;
+       register Line   *lp = curbuf->b_first;
+
+       for (npos = 1; lp ; npos++, lp = lp->l_next)  {
+               if (lp == curline)
+                       ipos = npos;
+       }
+       return (int) ((ipos * MAXC) / npos);
+}
+
+private Line *
+ctol(ctlv)     /* find buffer line for ctlvalue */
+int ctlv;
+{
+extern char *itoa();
+       register long ipos;
+       register Line   *lp = curbuf->b_first;
+
+       ipos = (npos * ctlv)/MAXC;
+       while (ipos-- && lp->l_next)
+               lp = lp->l_next;
+       return lp;
+}
+
+private void
+doWind(event,window)
+EventRecord *event;
+WindowPtr window;
+{
+#define track() TrackControl(whichControl,p,(ProcPtr)NULL)
+
+       ControlHandle whichControl;
+       Window *jwind, *cwind;
+       int notcurwind;
+       int cpart;      /* control part */
+       int oldval,newval,thumb = 0;
+
+       p = event->where;
+       intext = 0;
+       notcurwind = 0;
+       GlobalToLocal(&p);
+
+       if (event->what == mouseDown) {
+               if ((cpart = FindControl(p,window,&whichControl)) == 0)
+                       return;
+               if ((jwind = (Window *) (*whichControl)->contrlRfCon) !=  curwind) {
+                       notcurwind++;
+                       cwind = curwind;
+                       SetWind(jwind);
+               }
+               switch (cpart) {
+               case inUpButton:
+                       TrackControl(whichControl,p,(ProcPtr) DScroll);
+                       break;
+               case inDownButton:
+                       TrackControl(whichControl,p,(ProcPtr) UScroll);
+                       break;
+               case inPageUp:
+                       TrackControl(whichControl,p,(ProcPtr) PPage);
+                       break;
+               case inPageDown:
+                       TrackControl(whichControl,p,(ProcPtr) NPage);
+                       break;
+               case inThumb:
+                       if (track()) {
+                               newval = GetCtlValue(whichControl);
+                               if (newval == MAXC)
+                                       Eof();
+                               else if (newval == MINC)
+                                       Bof();
+                               else
+                                       SetLine(ctol(newval));
+                       }
+                       break;
+               }
+               if (notcurwind) {
+                       SetWind(cwind);
+                       redisplay();
+               }
+               redisplay();    /* again, to set the cursor */
+       }
+       else {
+               if (findtext())
+                       redisplay();
+       }
+}
+
+#define std_state(w) (*((WStateData **)((WindowPeek)((w)))->dataHandle))->stdState
+#define user_state(w) (*((WStateData **)((WindowPeek)((w)))->dataHandle))->userState
+
+private void
+doDrag(event,window)
+EventRecord *event;
+WindowPtr window;
+{
+       Rect old_std;
+
+       old_std = std_state(window);
+
+       DragWindow(window, event->where, &LimitRect);
+       if (wc == &wc_std) {
+               wc_user = wc_std;
+               user_state(theScreen) = std_state(theScreen);
+               ZoomWindow(window,7,1);
+               wc = &wc_user;
+               Reset_std();
+       }
+}
+
+private void
+doGrow(event,window)
+EventRecord *event;
+WindowPtr window;
+{
+       long size;
+
+       /* zero means user didn't change anything */
+       if (size = GrowWindow(window, event->where, &LimitRect)) {
+               if (wc == &wc_std) {
+                       wc_user = wc_std;
+                       user_state(theScreen) = std_state(theScreen);
+                       ZoomWindow(window,7,1);
+                       wc = &wc_user;
+                       Reset_std();
+               }
+               if (wc_adjust(LoWord(size),HiWord(size),wc,0)) {
+                       EraseRect(&window->portRect);
+                       SizeWindow(window,wc->w_width,wc->w_height,TRUE);
+                       win_reshape();  /* no signals here... */
+               }
+       }
+}
+
+private void
+doZoomIn(event,window)
+EventRecord *event;
+WindowPtr window;
+{
+       if (TrackBox(window, event->where, 7)) {
+                       EraseRect(&window->portRect);
+                       ZoomWindow(window,7,1);
+                       wc = &wc_user;
+                       win_reshape();  /* we do our own toggle, not ZoomWindow() */
+               }
+}
+
+private void
+doZoomOut(event,window)
+EventRecord *event;
+WindowPtr window;
+{
+       if (TrackBox(window, event->where, 8)) {
+                       EraseRect(&window->portRect);
+                       ZoomWindow(window,8,1);
+                       wc = &wc_std;
+                       win_reshape();  /* we do our own toggle, not ZoomWindow() */
+               }
+}
+
+private void
+doGoAway(event,window)
+EventRecord *event;
+WindowPtr window;
+{
+       if (TrackGoAway(window, event->where))
+               Leave();
+}
+
+private Window *
+rtowind(row)   /* return jove window row is in */
+int row;
+{
+       Window *w = fwind;
+
+       do {
+               if ((w->w_topline <= row) && ((w->w_height + w->w_topline) > row))
+                       return w;
+               w = w->w_next;
+       } while (w != fwind);
+       return NULL;
+}
+
+private Line *
+windtol(w,row)         /* return line for row in window */
+Window *w;
+int row;
+{
+       Line *l = w->w_top;
+
+       while (row--)
+               if ((l = l->l_next) == NULL)
+                       return NULL;
+       return l;
+}
+
+
+private bool
+findtext()             /* locate and move the point to match the mouse */
+{
+       int row,col;
+       long ticks;
+       EventRecord event;
+       Window *w;
+       Line *l;
+
+       ticks = Ticks;
+       ptoxy(p,&row,&col);
+       if ((w = rtowind(row)) == NULL)
+               return NO;
+       if (w != curwind)
+               SetWind(w);
+       row -= w->w_topline;            /* now have row number in window */
+       if (row >= w->w_height -1)
+               return NO;
+       if ((l = windtol(w,row)) == NULL)
+               return NO;
+       if (l->l_dline == NULL_DADDR)
+               return NO;
+       this_cmd = LINECMD;
+       SetLine(l);             /* Curline is in linebuf now */
+       if (w->w_flags & W_NUMLINES)
+               col -= 8;       /* adjust for line numbers */
+       if (col < 0)
+               col = 0;
+       curchar = how_far(curline, col);
+       do {
+               if (GetNextEvent(mUpMask,&event) && (event.when < ticks + DoubleTime)) {
+                       set_mark();
+                       break;
+               }
+       } while ((Ticks - ticks) < DoubleTime);
+       return YES;
+}
+
+
+private int
+ptoxy(p,row,col)       /* convert Point to terminal x,y coordinate */
+Point p;
+int *row,*col;
+{
+       *row = (p.v / HEIGHT);
+       *col = (p.h / WIDTH );
+       if ((*row > MAXROW) || (*col > MAXCOL))
+               return ERROR;
+       return 0;
+}
+
+/* Event-related routines. The Event loop is CheckEvents(), and is called whenever
+   a console read occurs or a call to charp(). During certain activities, such as ask(),
+   etc. non-keyboard events are ignored. This is set by the variable Keyonly.
+   As an update or activate event generates a call to redisplay(), it is important
+   that redisplay() and related routines NOT check for keyboard characters. */
+
+/* (ORIGINALLY IN) tevent.c
+       event handler for Jove. K Mitchum 12/86 */
+
+
+#define SYS_ID 100
+#define NOFUNC ((void (*)())NULL)
+#define NEVENTS 16
+
+extern void doMouse(),dokeyDown(),doUpdate(),doActivate();
+
+private void p_refresh proto((void));
+
+private MenuHandle SysMenu;
+
+private void (*eventlist[])() =
+{
+       NOFUNC, /* nullEvent */
+       doMouse,/* mouseDown */
+       doMouse, /* mouseUp */
+       dokeyDown, /* keyDown */
+       NOFUNC, /* keyUp */
+       dokeyDown, /* autoKey */
+       doUpdate, /* updateEvt */
+       NOFUNC, /* diskEvt */
+       doActivate, /* activateEvt */
+       NOFUNC, /* not  used */
+       NOFUNC, /* networkEvt = 10 */
+       NOFUNC, /* driverEvt */
+       NOFUNC, /* app1Evt */
+       NOFUNC, /* app2Evt */
+       NOFUNC, /* app3Evt */
+       NOFUNC  /* app4Ev */
+};
+
+
+private void
+CheckEvents()
+{
+       void SetBufMenu(),
+               MarkModes();
+
+       static EventRecord theEvent;
+       static Point Mousep;
+       static long time = 0;
+
+       static void (*fptr)();
+
+
+       if (FrontWindow() == window) {
+               GetMouse(&Mousep);
+               if (PtInRect(Mousep,&r))
+                       SetCursor(*cross);
+               else
+                       SetCursor(&arrow);
+       }
+
+       SystemTask();
+       if (EventCmd && !Keyonly)
+               return;
+       if (Bufchange)
+               SetBufMenu();
+       if (Modechange)
+               MarkModes();
+       while (GetNextEvent(everyEvent,&theEvent)) {
+               if ((theEvent.what < NEVENTS) && (fptr = eventlist[theEvent.what])) {
+                       (*fptr)(&theEvent);
+               }
+               SystemTask();
+       }
+       if ((Ticks - time) > 3600) {
+               time = Ticks;
+               UpdModLine = YES;
+               redisplay();
+       }
+}
+
+private void
+InitSysMenu()
+{
+       void InitLocalMenus();
+
+       SysMenu = NewMenu(SYS_ID,"\p\24");
+       AppendMenu(SysMenu,"\pAbout Jove");
+       AddResMenu(SysMenu,'DRVR');
+       InsertMenu(SysMenu,0);
+       InitLocalMenus();
+       DrawMenuBar();
+}
+
+extern void doWind(),doGoAway(),doSysMenu(),doSysClick(),
+        doDrag(), doGrow(), doZoomIn(), doZoomOut();
+#define NMEVENTS 9
+
+private void (*mouselist[])() =
+{
+       NOFUNC, /* inDesk */
+       doSysMenu, /* inMenuBar */
+       doSysClick, /* inSysWindow */
+       doWind, /* inContent */
+       doDrag, /* inDrag */
+       doGrow, /* inGrow */
+       doGoAway, /* inGoAway */
+       doZoomIn,       /* inZoomIn */
+       doZoomOut       /* inZoomOut */
+};
+
+
+private void
+doMouse(event)
+EventRecord *event;
+{
+       WindowPtr theWindow;
+       int wpart;
+       void (*fptr)();
+
+       if (Keyonly) {
+               if (event->what == mouseDown)
+                       SysBeep(2);
+               return;
+       }
+       wpart = FindWindow(event->where,&theWindow);
+       if ((wpart < NMEVENTS) && (fptr = mouselist[wpart])) {
+               (*fptr)(event,theWindow);
+       }
+
+}
+
+private void
+doSysMenu(event,window)
+EventRecord *event;
+WindowPtr window;
+{
+       void ProcMenu();
+
+       int Menu,Item;
+       long result = MenuSelect(event->where);
+       Menu = (result >> 16) & 0xffff;
+       Item = result & 0xffff;
+       if (Item == 0)
+               return; /* no choice made */
+
+       if (Menu == SYS_ID) {                   /* apple menu */
+               Str255 Name;
+               GrafPtr Port;
+
+               if (Item == 1)
+                       about_j();
+               else {
+                       GetItem(SysMenu,Item,Name);
+                       GetPort(&Port);
+                       OpenDeskAcc(Name);
+                       SetPort(Port);
+               }
+       }
+       else
+               ProcMenu(Menu,Item);
+       HiliteMenu(0);
+       EventCmd = YES;
+       menus_on();
+}
+
+private void
+doSysClick(event,window)
+EventRecord *event;
+WindowPtr window;
+{
+       SystemClick(event,window);
+}
+
+
+private void
+doUpdate(event)
+EventRecord *event;
+{
+       WindowPtr theWindow, oldPort;
+
+       theWindow = (WindowPtr) event->message;
+
+       GetPort(&oldPort);
+       SetPort(theWindow);
+       BeginUpdate(theWindow);
+       p_refresh();
+       drawfluff();
+       EndUpdate(theWindow);
+       SetPort(oldPort);
+}
+
+private void
+doActivate(event)
+EventRecord *event;
+{
+       WindowPtr theWindow;
+       ControlHandle control;
+       int hilite;
+
+       theWindow = (WindowPtr) event->message;
+       SetPort(theWindow);
+       hilite = (event->modifiers & activeFlag)? 0 : 255;
+       for (control = (ControlHandle) (((WindowPeek) theWindow)->controlList)
+       ; (control != 0); control = (*control)->nextControl) {
+                       HiliteControl(control,hilite);
+       }
+}
+
+/* Keyboard routines. The Option key was formerly used as a meta key.
+   However, to take advantage of the full (non-ASCII) character set,
+   this was removed. The corresponding code is ifdeffed O_META. */
+
+/* (ORIGINALLY IN) tkey.c
+   keyboard routines for Macintosh. K Mitchum 12/86 */
+
+extern jmp_buf auxjmp;
+
+private nchars = 0;
+private char charbuf[MCHARS];
+
+/* The following kludges a meta key out of the option key by
+   sending an escape sequence back to the dispatch routines. this is
+   not elegant but it works, and doesn't alter escape sequences for
+   those that prefer them. to remap the control or meta keys,
+   see mackeys.h. */
+
+private void
+dokeyDown(event)
+EventRecord *event;
+{
+       unsigned mods;
+       register c;
+       static int cptr = 0;
+
+       if (MCHARS - nchars < 2)
+               return;
+
+       c  = (char)((event->message)&(charCodeMask));
+
+       mods = event->modifiers;
+
+#ifdef O_META
+       if (mods & (optionKey | cmdKey | controlKey)) {
+#else
+       if (mods & (cmdKey | controlKey)) {
+#endif
+#ifdef NEVER
+               if (mods & shiftKey)
+                       c  = sh_keycodes[(((event->message)&(keyCodeMask))>>8)];
+               else
+                       c  = nsh_keycodes[(((event->message)&(keyCodeMask))>>8)];
+#endif
+#ifdef O_META
+               if (mods & optionKey) {         /* make escape sequence */
+                       if (mods & cmdKey)
+                               c &= 0x1f;
+                       charbuf[cptr++] = '\033';
+                       cptr &= NMASK;          /* zero if necessary */
+                       nchars++;
+               }
+               else
+#endif
+               {       /* command key (control key) */
+                       if ((c == '2') || (c == '\\') || (c == ' '))
+                               c = '\0';       /* so we have a null char */
+                       if (c != '`')
+                               c &= 0x1f;              /* make a control char */
+               }
+       }
+       else {
+               if (c == '`')
+                       c = '\033';     /* for those used to escapes */
+       }
+
+       charbuf[cptr++] = c;
+       cptr &= NMASK;
+       nchars++;
+}
+
+private int
+rawgetc()
+{
+       static int cptr = 0;
+       register int c;
+
+       if (EventCmd)
+               longjmp(auxjmp,1);
+       while (nchars <= 0) {
+               nchars = 0;
+               if (EventCmd)
+                       longjmp(auxjmp,1);
+               CheckEvents();  /* ugh! WAIT for a character */
+       }
+       nchars--;
+       c = charbuf[cptr++];
+       cptr &= NMASK;          /* zero if necessary */
+       return c;
+}
+
+bool
+rawchkc()
+{
+       if (EventCmd)
+               longjmp(auxjmp,1);
+       if (nchars == 0)
+               CheckEvents();  /* this should NOT be necessary! */
+       return nchars > 0;
+}
+
+/* Routines for calling the standard file dialogs, when macify is ON. If the user
+   changes the directory using the file dialogs, Jove's notion of the current directory
+   is updated. */
+
+
+/* (ORIGINALLY IN) tmacf.c. K. Mitchum 12/86.
+   Macify routines for jove. */
+
+int CurrentVol;                        /* see tfile.c */
+
+
+#define TYPES  (-1)
+
+private Point px = {100,100};
+private char pmess[] = "\pSave file as: ";
+
+private pascal Boolean
+Ffilter(p)
+FileParam *p;
+{
+       if (p->ioFlFndrInfo.fdType == 'APPL')
+               return TRUE;
+       PtoCstr((char *) p->ioNamePtr);
+       if (strcmp(p->ioNamePtr,d_tempfile) == 0) {
+               CtoPstr((char *) p->ioNamePtr);
+               return TRUE;
+       }
+       CtoPstr((char *) p->ioNamePtr);
+       return FALSE;
+}
+
+private void
+check_dir()
+{
+       if (cur_vol != 0 - SFSaveDisk || cur_dir != CurDirStore) {
+               setdir(0 - SFSaveDisk, CurDirStore);
+               UpdModLine = YES;       /* make sure jove knows the change */
+               Modechange = YES;
+               setCWD(getwd());
+       }
+}
+
+char *
+gfile(namebuf) /* return a filename to get */
+char *namebuf;
+{
+       SFReply frec;
+       char ans[FILESIZE];
+
+       SFSaveDisk = 0 - cur_vol;       /* in case a Desk Accessory changed them */
+       CurDirStore = cur_dir;
+       SFGetFile(px,0L,Ffilter,TYPES,0L,0L,&frec);
+       check_dir();    /* see if any change, set if so */
+       if (frec.good) {
+               EventRecord theEvent;
+               do; while (GetNextEvent(updateMask,&theEvent) == 0);
+               doUpdate(&theEvent);
+               PtoCstr((char *)frec.fName);
+               strcpy(ans,frec.fName);
+               CtoPstr((char *)frec.fName);
+               PathParse(ans,namebuf);
+               return namebuf;
+       }
+       return (char *)NULL;
+}
+
+char *
+pfile(namebuf)
+char *namebuf;
+{
+       SFReply frec;
+       char *t, *nm;
+       SFSaveDisk = 0 - cur_vol;       /* in case a Desk Accessory changed them */
+       CurDirStore = cur_dir;
+       strncpy(namebuf,filename(curbuf),63);
+       nm = cvt_fnm(namebuf);
+       CtoPstr(nm);
+       SFPutFile(px,pmess,nm,0L,&frec);
+       check_dir();    /* see if any change, set if so */
+       if (frec.good) {
+               EventRecord theEvent;
+               do; while (GetNextEvent(updateMask,&theEvent) == 0);
+               doUpdate(&theEvent);
+               t = (char *)frec.fName;
+               PtoCstr((char *)frec.fName);
+               while (*t == ':')
+                       t++;    /* convert to unix style */
+               nm = t;
+               while (*nm) {
+                       if (*nm == ':')
+                               *nm = '/';
+                       nm++;
+               }
+               PathParse(t,namebuf);
+               return namebuf;
+       }
+       return (char *)NULL;
+}
+
+
+/* getArgs() returns an argument list based on documents clicked on by the user. */
+
+int
+getArgs(avp)
+char ***avp;
+{
+       int argc, nargs, type, old_vol;
+       long old_dir;
+       char **argv;
+       char *pathname;
+       AppFile p;
+       WDPBRec d;
+
+       old_vol = cur_vol;
+       old_dir = cur_dir;
+
+       CountAppFiles(&type,&nargs);
+       if (nargs > 0) {        /* files to open... */
+               argv = (char **) emalloc((nargs + 2) * sizeof(char *));
+               for (argc = 1; argc <= nargs; argc++) {
+                       GetAppFiles(argc,&p);
+                       if (type == 0) {
+                               PtoCstr((char *)p.fName);
+                               d.ioCompletion = 0;
+                               d.ioNamePtr = NULL;
+                               d.ioVRefNum = p.vRefNum;
+                               d.ioWDIndex = 0;
+                               PBGetWDInfo(&d,0);
+                               cur_vol = d.ioWDVRefNum;
+                               cur_dir = d.ioWDDirID;
+                               pathname = getwd();
+                               argv[argc] = emalloc(strlen((char *)p.fName) + strlen(pathname) + 2);
+                               strcpy(argv[argc],pathname);
+                               strcat(argv[argc],"/");
+                               strcat(argv[argc],(char *)p.fName);
+                       }
+                       ClrAppFiles(argc);
+               }
+               if (type != 0)
+                       argc = 1;
+       }
+       else {
+               argv = (char **) emalloc(2 * sizeof(char*));
+               argc = 1;
+       }
+       argv[0] = "jove";
+
+       argv[argc] = NULL;
+       *avp = argv;
+       cur_dir = old_dir;
+       cur_vol = old_vol;
+       return argc;
+}
+
+/* Limited version of getenv() */
+
+char *
+getenv(item)
+char *item;
+{
+       char *ret = NULL, *str = NULL;
+
+       if (strcmp(item,"CWD") == 0)
+               str = getwd();
+       if (strcmp(item,"HOME") == 0)
+               str = gethome();
+       if (str) {
+               ret = emalloc(strlen(str) + 1);
+               strcpy(ret,str);
+       }
+       return ret;
+}
+
+char *
+mktemp(name)
+char *name;
+{
+       return name;
+}
+
+
+/* Menu routines. The menus items are set up in a similar manner as keys, and
+   are bound prior to runtime. See menumaps.txt, which must be run through setmaps.
+   Unlike keys, menu items may be bound to variables, and to buffers. Buffer binding
+   is only done at runtime. */
+
+private void
+InitLocalMenus()
+{
+       void InitMenu(),
+               make_edits();
+
+       int i;
+       for (i = 0; i < NMENUS; i++) {
+               InitMenu(&Menus[i]);
+               if (i == 0)
+                       make_edits(Menus[i].menu_id + 1);
+       }
+}
+
+private void
+InitMenu(M)
+struct menu *M;
+{
+       int i;
+       data_obj *d;
+       char *name;
+
+       if (M->menu_id == 0)
+               return;
+       M->Mn = NewMenu(M->menu_id,CtoPstr(M->Name));
+       PtoCstr(M->Name);
+
+       for (i = 0; i < NMENUITEMS; i++) {
+               d = (M->m[i]);
+               if (d == NULL)
+                       break;  /* last item... */
+               switch (d->Type & TYPEMASK) {
+               case (STRING):
+                       AppendMenu(M->Mn,CtoPstr(d->Name));
+                       PtoCstr(d->Name);
+                       break;
+               case (VARIABLE):
+                       SetItemMark(M->Mn,i + 1, 0x12);
+                       /* ??? fall through? */
+               case (FUNCTION):
+                       CtoPstr(name = ((data_obj *) d)->Name);
+                       AppendMenu(M->Mn,name);
+                       PtoCstr(name);
+                       break;
+               }
+       }
+       InsertMenu(M->Mn,0);
+}
+
+private void
+ProcMenu(menuno,itemno)
+int menuno,itemno;
+{
+       void MacSetVar();
+
+       int i;
+       data_obj *d;
+
+       for (i = 0; i < NMENUS && Menus[i].menu_id != menuno; i++)
+               ;
+       if (i < NMENUS) {       /* found the menu */
+               itemno--;
+               d = Menus[i].m[itemno];
+               switch(d->Type & TYPEMASK) {
+               case FUNCTION:
+                       ExecCmd((data_obj *) d);
+                       break;
+               case BUFFER:
+                       SetABuf(curbuf);
+                       tiewind(curwind,(Buffer *) d);
+                       SetBuf((Buffer *) d);
+                       break;
+               case VARIABLE:
+                       MacSetVar((struct variable *) d,i,itemno);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+
+private void
+make_edits(menu)       /* add dummy edit menu */
+int menu;
+{
+       MenuHandle M;
+       int item;
+       char *fname;
+
+       M = NewMenu((menu),"\pEdit");
+       AppendMenu(M,"\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear;Select All;(-;Show Clipboard");
+       InsertMenu(M,0);
+       DisableItem(M,0);
+}
+
+void
+menus_off()
+{
+       int i;
+       if (Keyonly || EventCmd)
+               return;
+
+#ifdef MENU_DISABLE            /* NOBODY likes this, but it's here if you want it... */
+       DisableItem(SysMenu,0);
+       for (i = 0; i < NMENUS; i++)
+               if (Menus[i].Mn)
+                       DisableItem(Menus[i].Mn,0);
+       DrawMenuBar();
+#endif
+       Keyonly = YES;
+}
+
+void
+menus_on()
+{
+       int i;
+
+       if (!Keyonly)
+               return;
+#ifdef MENU_DISABLE
+       EnableItem(SysMenu,0);
+       for (i = 0; i < NMENUS; i++)
+               if (Menus[i].Mn)
+                       EnableItem(Menus[i].Mn,0);
+       DrawMenuBar();
+#endif
+       Keyonly = NO;
+}
+
+private char *
+BufMPrint(b,i)
+Buffer *b;
+int    i;
+{
+       char *p;
+       char *nm = filename(b);
+       char t[35];
+
+       if (strlen(nm) > 30) {
+               strcpy(t,"...");
+               strcat(t,nm + strlen(nm) - 30);
+       } else
+               strcpy(t,nm);
+       nm = t;
+       while (*nm) {
+               switch(*nm) {   /* ugh... these are metacharacter for Menus */
+               case '/':
+                       *nm = ':';
+                       break;
+               case '^':
+               case '!':
+               case '<':
+               case '(':
+               case ';':
+                       *nm = '.';
+                       break;  /* that will confuse everybody */
+               }
+               nm++;
+       }
+       p = sprint("%-2d %-11s \"%-s\"",i,b->b_name,t);
+       return p;
+}
+
+private void
+SetBufMenu()
+{
+       register Buffer *b;
+       data_obj *d;
+       int i,j,stop;
+       struct menu *M;
+
+       Bufchange = NO;
+       for (i = 0; i < NMENUS && strcmp(Menus[i].Name,"Buffer"); i++)
+               ;
+       if (i < NMENUS) {
+               M = &Menus[i];
+               for (j = 0; j < NMENUITEMS && (d = Menus[i].m[j]) && (d->Type & TYPEMASK) != BUFFER; j++)
+                       ;
+               if (j < NMENUITEMS) {
+                       for (i = j, b = world; i < NMENUITEMS && b != NULL; i++, b = b->b_next) {
+
+                               if (M->m[i] == NULL)
+                                       AppendMenu(M->Mn,CtoPstr(BufMPrint(b,i-j+1)));  /* add the item */
+                               else
+                                       SetItem(M->Mn,i + 1,CtoPstr(BufMPrint(b,i-j+1)));       /* or change it */
+                               M->m[i] = (data_obj *) b;
+                       }
+                       stop = i;
+                       /* out of buffers? */
+                       for (;i < NMENUITEMS && M->m[i];i++) {
+                               DelMenuItem(M->Mn,stop + 1);    /* take off last item */
+                               M->m[i] = NULL;
+                       }
+               }
+       }
+}
+
+private void
+MacSetVar(vp,mnu,itm)  /* Set a variable from the menu */
+struct variable *vp;   /* Liberally taken from SetVar() in extend.c */
+int mnu,itm;
+{
+       void MarkVar();
+
+       char *prompt;
+
+       prompt = sprint("Set %s: ", vp->Name);
+       switch (vp->v_flags & V_TYPEMASK) {
+       case V_BASE10:
+       case V_BASE8:
+           {
+               int     value;
+
+               value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10)
+                                         ? 10 : 8);
+               *(vp->v_value) = value;
+               break;
+           }
+       case V_BOOL:    /* toggle the value */
+               *(vp->v_value) = (*vp->v_value == ON ? OFF : ON);
+               MarkVar(vp,mnu,itm);
+               break;
+       case V_FILENAME:
+       case V_STRING:
+           {
+               char    *str;
+
+               /* Do_ask() so you can set string to "" if you so desire. */
+               str = do_ask("\r\n", (bool (*) ptrproto((int))) NULL, (char *) vp->v_value,
+                       prompt);
+               if (str == NULL)
+                       str = NullStr;
+               strcpy((char *) vp->v_value, str);
+               /* ... and hope there is enough room. */
+               break;
+           }
+       case V_CHAR:
+               f_mess(prompt);
+               *(vp->v_value) = addgetc();
+               break;
+       }
+
+       if (vp->v_flags & V_MODELINE)
+               UpdModLine = YES;
+       if (vp->v_flags & V_CLRSCREEN)
+               ClAndRedraw();
+       if (vp->v_flags & V_TTY_RESET)
+               tty_reset();    /* probably none on a Mac */
+}
+
+private void
+MarkModes()
+{
+       int mnu,itm;
+       data_obj *d;
+
+       Modechange = NO;
+       for (mnu = 0; mnu < NMENUS; mnu++)
+               for (itm = 0; itm < NMENUITEMS; itm++) {
+                       if ((d = Menus[mnu].m[itm]) == NULL)
+                               break;
+                       if ((d->Type & (MAJOR_MODE | MINOR_MODE))
+                       || ((d->Type & TYPEMASK) == BUFFER))
+                       {
+                               bool    checked;
+
+                               if (d->Type & (MAJOR_MODE))
+                                       checked = curbuf->b_major == (d->Type >> 8);
+                               else if (d->Type & (MINOR_MODE))
+                                       checked = (curbuf->b_minor & (d->Type >> 8)) != 0;
+                               else
+                                       checked = d == (data_obj *) curbuf;
+                               CheckItem(Menus[mnu].Mn, itm + 1, checked);
+                       }
+               }
+}
+
+void
+MarkVar(vp,mnu,itm)    /* mark a boolean menu item */
+struct variable *vp;
+int mnu,itm;
+{
+       if (mnu == -1) {                /* we don't know the item... slow */
+               for (mnu = 0; mnu < NMENUS; mnu++) {
+                       for (itm = 0; (itm < NMENUITEMS); itm++) {
+                               if ((struct variable *) (Menus[mnu].m[itm]) == vp) {
+                                       CheckItem(Menus[mnu].Mn, itm + 1,
+                                               *(vp->v_value) == ON);
+                                       return;
+                               }
+                       }
+               }
+       }
+}
+
+private void
+MarkAllVar()   /* slow, but only do it once */
+{
+       int mnu,itm;
+       data_obj *d;
+       for (mnu = 0; mnu < NMENUS; mnu++)
+               for (itm = 0; itm < NMENUITEMS; itm++) {
+                       if ((d = Menus[mnu].m[itm]) == NULL)
+                               break;
+                       if ((d->Type & TYPEMASK) == VARIABLE)
+                               MarkVar((struct variable *)Menus[mnu].m[itm],mnu,itm);
+               }
+}
+
+
+/* Screen routines and driver. The Macinitosh Text Edit routines are not utilized,
+   as they are slow and cumbersome for a terminal emulator. Instead, direct QuickDraw
+   calls are used. The fastest output is obtained writing a line at a time, rather
+   than on a character basis, so the major output routine is writechr(), which takes
+   a pascal-style string as an argument. See do_sputc() in screen.c. */
+
+void
+Placur(line,col)
+int line, col;
+{
+       CapCol = col;
+       CapLine = line;
+       putcurs(line,col,ON);
+}
+
+void
+NPlacur(line,col)
+int line, col;
+{
+       CapCol = col;
+       CapLine = line;
+       putcurs(line,col,OFF);
+}
+
+void
+i_lines(top, bottom, num)
+int top, bottom, num;
+{
+       Placur(bottom - num + 1, 0);
+       dellines(num,bottom);
+       Placur(top, 0);
+       inslines(num,bottom);
+}
+
+void
+d_lines(top, bottom, num)
+int top, bottom, num;
+{
+       Placur(top, 0);
+       dellines(num,bottom);
+       Placur(bottom + 1 - num, 0);
+       inslines(num,bottom);
+}
+
+/* (ORIGINALLY IN) tn.c   */
+/* window driver for MacIntosh using windows. */
+/* K. Mitchum 9/86 */
+
+
+/*#define VARFONT*/
+#ifdef VARFONT
+private height,width,theight,twidth,descent;
+#else
+#define height HEIGHT
+#define width WIDTH
+#define theight THEIGHT
+#define twidth TWIDTH
+#define descent DESCENT
+#endif
+
+private int trow, tcol, insert, cursor;
+private bool tattr;    /* ??? never fetched */
+private Rect cursor_rect;
+private char *p_scr, *p_curs;  /* physical screen and cursor */
+private int p_size;
+
+private Rect  vRect;
+private WindowRecord myWindowRec;
+
+#define active() SetPort(theScreen)
+#define maxadjust(r) OffsetRect((r),0,2);
+
+char *
+conv_p_curs(row,col)
+int    row,
+       col;
+{
+       return p_scr + (row * (CO)) + col;
+}
+
+private void
+INSmode(new)
+bool new;
+{
+       insert = new;
+}
+
+private void
+HLmode(new)
+bool new;
+{
+       tattr = new;
+}
+
+void
+SO_on()
+{
+       HLmode(TRUE);
+}
+
+void
+SO_off()
+{
+       HLmode(FALSE);
+}
+
+
+private void
+tn_init()
+{
+       void INSmode proto((bool)),
+       init_slate();
+
+       HLmode(FALSE);
+       INSmode(OFF);
+       init_slate();
+       ShowPen();
+}
+
+void
+clr_page()     /* clear and home function */
+{
+       Rect r;
+
+       setmem(p_scr,p_size,' ');
+       active();
+       SetRect(&r, 0,0,WINDWIDTH,WINDHEIGHT);
+       EraseRect(&r);
+       cursor = OFF;
+       putcurs(0,0,OFF);       /* ??? "OFF" guess by DHR */
+       drawfluff();
+}
+
+private void
+putcurs(row,col,vis)
+unsigned       row, col;
+bool   vis;
+{
+       active();
+       curset(OFF);
+       trow = row;
+       tcol = col;
+       curset(vis);
+}
+
+private void
+curset(desired)
+bool   desired;
+{
+       p_curs = conv_p_curs(trow,tcol);
+       if (trow == MAXROW)
+               MoveTo(tcol * width, (trow  +1) * height + 2 -descent );
+       else
+               MoveTo(tcol * width, (trow  +1) * height - descent);
+
+       DrawChar(*p_curs);
+
+       if (desired) {
+               SetRect(&cursor_rect, tcol * width, (trow) * height , (tcol + 1) * width - 1, (trow +1) * height -1);
+               if (trow == MAXROW)
+                       maxadjust(&cursor_rect);
+               InvertRect(&cursor_rect);
+       }
+       if (trow == MAXROW)
+               MoveTo(tcol * width, (trow  +1) * height + 2 -descent );
+       else
+               MoveTo(tcol * width, (trow  +1) * height - descent);
+}
+
+
+void
+putp(p)                        /* put one character, advance cursor */
+int p;
+{
+       static Rect r;
+       static RgnHandle updateRgn;
+
+       active();
+       curset(OFF);
+       if (insert) {
+               updateRgn = NewRgn();
+               SetRect(&r, tcol * width, trow * height, WINDWIDTH, (trow +1) * height -1);
+               if (trow == MAXROW)
+                       maxadjust(&r);
+               ScrollRect(&r, width, 0, updateRgn);
+               DisposeRgn(updateRgn);
+       }
+       if (p == '0')
+               p = 0xAF;       /* slashed zero */
+       if (insert)
+               BlockMove(p_curs, p_curs + 1, (long) (MAXCOL - tcol));
+       *p_curs = (char) p;
+       DrawChar(p);
+       if (tcol >= MAXCOL)
+               putcurs(trow,MAXCOL, ON);       /* ??? "ON" guess by DHR */
+       else
+               putcurs(trow,tcol+1, ON);       /* ??? "ON" guess by DHR */
+}
+
+void
+clr_eoln()
+{
+               static Rect r;
+
+               active();
+               cursor = OFF;
+               SetRect(&r, tcol * width, trow * height, WINDWIDTH, (trow +1) * height);
+               if (trow == MAXROW)
+                       maxadjust(&r);
+               EraseRect(&r);
+               setmem(p_curs,CO - tcol, ' ');
+               curset(ON);
+}
+
+private void
+delchars()
+{
+       static Rect r;
+       static RgnHandle updateRgn;
+
+       active();
+       curset(OFF);
+       updateRgn = NewRgn();
+       SetRect(&r, tcol * width, trow * height, twidth - width, (trow +1) * height);
+       if (trow == MAXROW)
+               maxadjust(&r);
+       ScrollRect(&r, 0 - width, 0, updateRgn);
+       DisposeRgn(updateRgn);
+       BlockMove(p_curs + 1, p_curs, (long) (MAXCOL - tcol));
+       *(conv_p_curs(trow,MAXCOL)) = ' ';
+       curset(ON);
+}
+
+private void
+dellines(n,bot)
+int n,bot;
+{
+       Rect r;
+       RgnHandle updateRgn;
+       long len;
+
+       updateRgn = NewRgn();
+       active();
+       curset(OFF);
+       SetRect(&r, 0, ((trow) * height), WINDWIDTH, ((bot + 1) * height));
+       ScrollRect(&r, 0, 0 - (n * height), updateRgn);
+       DisposeRgn(updateRgn);
+       len = ((bot - trow - n + 1) * CO);
+       BlockMove(conv_p_curs((trow + n),0), conv_p_curs(trow,0), len);
+       setmem(conv_p_curs((bot - n + 1),0),(n * CO),' ');
+       putcurs(trow, 0, ON);   /* ??? "ON" guess by DHR */
+}
+
+private void
+inslines(n,bot)
+int n,bot;
+{
+       Rect r;
+       RgnHandle updateRgn;
+       long len;
+
+       updateRgn = NewRgn();
+       active();
+       curset(OFF);
+       SetRect(&r, 0, trow * height, WINDWIDTH, (bot +1) * height);
+       ScrollRect(&r, 0, (n * height), updateRgn);
+       DisposeRgn(updateRgn);
+       len = ((bot - trow - n +1) * CO);
+       BlockMove(conv_p_curs(trow,0), conv_p_curs((trow + n),0), len);
+       setmem(conv_p_curs(trow,0),(n * CO),' ');
+       putcurs(trow,0, ON);    /* ??? "ON" guess by DHR */
+}
+
+void
+writechr(start)
+char *start;   /* actually, a Str255 type string */
+{
+       static Rect r;
+       static RgnHandle updateRgn;
+       register len;
+       register char save;
+
+       len = (int) start[0] & 0xff;            /* adjusted 6/86 K. M. in td.c*/
+
+       active();
+       curset(OFF);
+       if (insert) {
+               updateRgn = NewRgn();
+               SetRect(&r, tcol * width, trow * height, twidth - width * len, (trow +1) * height -1);
+               if (trow == MAXROW)
+                       maxadjust(&r);
+               ScrollRect(&r, width * len, 0, updateRgn);
+               DisposeRgn(updateRgn);
+       }
+       DrawString(start);
+       if (insert)
+               BlockMove(p_curs,p_curs + len, (long) (CO - tcol - len));
+       strncpy(p_curs,start + 1,len);
+       if (tcol >= MAXCOL)
+               putcurs(trow, MAXCOL, ON);      /* ??? "ON" guess by DHR */
+       else
+               putcurs(trow, tcol+len, ON);    /* ??? "ON" guess by DHR */
+}
+
+private Rect myBoundsRect;
+
+private void
+init_slate()
+{
+       FontInfo f;
+
+       char *Name = "Jove ";
+       char *Title;
+
+       InitGraf(&thePort);
+       InitWindows();
+       InitCursor();
+       InitFonts();
+       InitMenus();
+       InitDialogs((ProcPtr)NULL);             /* no restart proc */
+
+       /* figure limiting rectangle for window moves */
+       SetRect(&LimitRect,
+               screenBits.bounds.left + 3,
+               screenBits.bounds.top + 20,
+               screenBits.bounds.right - 3,
+               screenBits.bounds.bottom -3);
+
+       Set_std();
+       SetBounds();
+
+       /* initialize char array for updates */
+       p_scr = emalloc(p_size = wc_std.w_cols * wc_std.w_rows);        /* only once */
+       p_curs = p_scr;
+
+       Title = sprint("%s%s",Name,version);
+       theScreen = NewWindow(&myWindowRec, &myBoundsRect,CtoPstr(Title),
+               1,8,(WindowPtr) -1, 1, 0L);
+
+       /* figure an initial window configuration and adjust it */
+       wc = &wc_std;
+       wc_user = wc_std;       /* initially, only one configuration to toggle */
+       user_state(theScreen) = std_state(theScreen);
+       SetPort(theScreen);
+
+       (theScreen)->txFont = FONT;
+       (theScreen)->txSize = TEXTSIZE;
+
+#ifdef VARFONT
+       GetFontInfo(&f);
+               height = f.ascent+f.descent+f.leading;
+               width = f.widMax;
+               twidth = width * wc->w_cols;
+               theight = height * wc->w_rows;
+               descent = f.descent;
+#endif
+
+       theScreen->txMode = patCopy;
+       theScreen->pnMode = patCopy;
+       PenNormal();
+       cursor = OFF;
+}
+
+private void
+p_refresh()
+{
+       int lineno;
+       char *curs, *buf;
+
+       buf = emalloc(CO + 1);
+       for (lineno = 0; lineno < LI; lineno++) {
+               curs = conv_p_curs(lineno,0);
+               if (lineno == MAXROW)
+                       MoveTo(0, (lineno  +1) * height + 2 -descent );
+               else
+                       MoveTo(0, (lineno  +1) * height - descent);
+               strncpy(buf + 1, curs, CO);
+               buf[0] = (char) CO;
+               DrawString(buf);
+       }
+       putcurs(trow,tcol,OFF);
+       free(buf);
+}
+
+
+private bool
+wc_adjust(w,h,wcf,init)                /* adjust window config to look nice */
+int w, h;
+struct wind_config *wcf;
+int init;
+{
+       static int LIMIT_R, LIMIT_C;
+       int rows, cols;
+
+       if (init) {
+               LIMIT_R = (h - 4) / HEIGHT;
+               LIMIT_C = (w - SCROLLWIDTH - 1) / WIDTH + 1;
+       }
+       if ((w < WIDTH * 40) ||(h < HEIGHT * 10)        /* too small */
+       || ((rows = (h - 4) / HEIGHT) > LIMIT_R)        /* too big */
+       || ((cols = (w - SCROLLWIDTH - 1) / WIDTH + 1) > LIMIT_C))
+               return NO;
+
+       wcf->w_rows = rows;
+       wcf->w_cols = cols;
+       wcf->w_width = wcf->w_cols * WIDTH + 1 + SCROLLWIDTH;
+       wcf->w_height = wcf->w_rows * HEIGHT + 4;
+       return YES;
+}
+
+int
+getCO()        /* so that jove knows params */
+{
+       return wc->w_cols;
+}
+
+int
+getLI()
+{
+       return wc->w_rows;
+}
+
+private void
+SetBounds()
+{
+       SetRect(&myBoundsRect,
+               screenBits.bounds.left + 3,
+               screenBits.bounds.top + 40,
+               screenBits.bounds.left + 3 + wc_std.w_width,
+               screenBits.bounds.top + 40 + wc_std.w_height);
+}
+
+private void
+Set_std()
+{
+       (void) wc_adjust(screenBits.bounds.right - screenBits.bounds.left - 6,
+               screenBits.bounds.bottom - screenBits.bounds.top - 42,
+               &wc_std,1);
+}
+
+private void
+Reset_std()
+{
+       Set_std();
+       std_state(theScreen) = myBoundsRect;
+}
+#endif /* MAC */
diff --git a/usr/src/contrib/jove-4.14.6/mac.h b/usr/src/contrib/jove-4.14.6/mac.h
new file mode 100644 (file)
index 0000000..b695609
--- /dev/null
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* Macintosh related things. K. Mitchum 2/88 */
+
+
+#define NMENUS 6
+#define NMENUITEMS 40  /* This has GOT to be enough! */
+
+typedef data_obj *menumap[NMENUITEMS];
+struct menu {
+       char *Name;
+       int menu_id;
+       MenuHandle Mn;
+       menumap m;
+};
+
+struct stat {
+       int st_dev;             /* volume number */
+       long st_ino;            /* file number on volume */
+       dev_t st_rdev;
+       off_t st_size;          /* logical end of file */
+       int st_mode;
+       time_t st_mtime;        /* last modified */
+};
+
+#define S_IFDIR 2
+
+typedef char *va_list;
+#define va_dcl va_list va_alist;
+#define va_start(l) { (l) = (va_list)&va_alist; }
+#define va_arg(l,m) (((m*)((l) += sizeof(m)))[-1])
+#define va_end(l) { (l) = NULL; }
+
+
+
diff --git a/usr/src/contrib/jove-4.14.6/macros.c b/usr/src/contrib/jove-4.14.6/macros.c
new file mode 100644 (file)
index 0000000..bf83572
--- /dev/null
@@ -0,0 +1,402 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+#include "fp.h"
+#include "chars.h"
+#include "disp.h"
+
+private void
+       pop_macro_stack proto((void));
+
+#define SAVE           01      /* this macro needs saving to a file */
+
+struct macro   *macros = NULL;         /* macros */
+bool   InMacDefine = NO;
+
+private void
+add_mac(new)
+struct macro   *new;
+{
+       register struct macro   *mp,
+                               *prev = NULL;
+
+       for (mp = macros; mp != NULL; prev = mp, mp = mp->m_nextm)
+               if (mp == new)
+                       return;
+
+       if (prev)
+               prev->m_nextm = new;
+       else
+               macros = new;
+       new->m_nextm = NULL;
+       new->Type = MACRO;
+}
+
+private void
+del_mac(mac)
+struct macro   *mac;
+{
+       register struct macro   *m;
+
+       for (m = macros; m != NULL; m = m->m_nextm)
+               if (m->m_nextm == mac) {
+                       m->m_nextm = mac->m_nextm;
+                       break;
+               }
+       free((UnivPtr) mac->Name);
+       free((UnivPtr) mac->m_body);
+       free((UnivPtr) mac);
+}
+
+private struct macro   KeyMacro;       /* Macro used for defining */
+
+/* To execute a macro, we have a "stack" of running macros.  Whenever
+   we execute a macro, we push it on the stack, run it, then pop it
+   from the stack.  */
+struct m_thread {
+       struct m_thread *mt_prev;
+       struct macro    *mt_mp;
+       int     mt_offset,
+               mt_count;
+};
+
+private struct m_thread        *mac_stack = NULL;
+
+private struct m_thread *
+alloc_mthread()
+{
+       return (struct m_thread *) emalloc(sizeof (struct m_thread));
+}
+
+private void
+free_mthread(t)
+struct m_thread        *t;
+{
+       free((UnivPtr) t);
+}
+
+void
+unwind_macro_stack()
+{
+       while (mac_stack != NULL)
+               pop_macro_stack();
+}
+
+private void
+pop_macro_stack()
+{
+       register struct m_thread        *m;
+
+       if ((m = mac_stack) == NULL)
+               return;
+       mac_stack = m->mt_prev;
+       free_mthread(m);
+}
+
+private void
+push_macro_stack(m, count)
+register struct macro  *m;
+int    count;
+{
+       register struct m_thread        *t;
+
+       for (t = mac_stack; t != NULL; t = t->mt_prev)
+               if (t->mt_mp == m)
+                       complain("[Cannot execute macro recusively]");
+       if (count <= 0)
+               complain("[Cannot execute macro a negative number of times]");
+       t = alloc_mthread();
+       t->mt_prev = mac_stack;
+       mac_stack = t;
+       t->mt_offset = 0;
+       t->mt_mp = m;
+       t->mt_count = count;
+}
+
+void
+do_macro(mac)
+struct macro   *mac;
+{
+       push_macro_stack(mac, arg_value());
+}
+
+private struct macro *
+mac_exists(name)
+char   *name;
+{
+       register struct macro   *mp;
+
+       for (mp = macros; mp; mp = mp->m_nextm)
+               if (strcmp(mp->Name, name) == 0)
+                       return mp;
+       return NULL;
+}
+
+void
+mac_init()
+{
+       add_mac(&KeyMacro);
+       KeyMacro.Name = "keyboard-macro";
+       KeyMacro.m_len = 0;
+       KeyMacro.m_buflen = 16;
+       KeyMacro.m_body = emalloc((size_t) KeyMacro.m_buflen);
+}
+
+void
+mac_putc(c)
+int    c;
+{
+       if (KeyMacro.m_len >= KeyMacro.m_buflen) {
+               KeyMacro.m_buflen += 16;
+               KeyMacro.m_body = realloc((UnivPtr) KeyMacro.m_body, (size_t) KeyMacro.m_buflen);
+               if (KeyMacro.m_body == NULL) {
+                       KeyMacro.m_buflen = KeyMacro.m_len = 0;
+                       complain("[Can't allocate storage for keyboard macro]");
+               }
+       }
+       KeyMacro.m_body[KeyMacro.m_len++] = c;
+}
+
+int
+in_macro()
+{
+       return (mac_stack != NULL);
+}
+
+int
+mac_getc()
+{
+       struct m_thread *mthread;
+       struct macro    *m;
+
+       if ((mthread = mac_stack) == NULL)
+               return EOF;
+       m = mthread->mt_mp;
+       if (mthread->mt_offset == m->m_len) {
+               mthread->mt_offset = 0;
+               if (--mthread->mt_count == 0)
+                       pop_macro_stack();
+               return mac_getc();
+       }
+       return m->m_body[mthread->mt_offset++];
+}
+
+void
+NameMac()
+{
+       char    *name;
+       struct macro    *m;
+
+       if (KeyMacro.m_len == 0)
+               complain("[No keyboard macro to name!]");
+       if (in_macro() || InMacDefine)
+               complain("[Can't name while defining/executing]");
+       if ((m = mac_exists(name = ask((char *) NULL, ProcFmt))) == NULL)
+               m = (struct macro *) emalloc(sizeof *m);
+       else {
+               if (strcmp(name, KeyMacro.Name) == 0)
+                       complain("[Can't name it that!]");
+               free((UnivPtr) m->Name);
+               free((UnivPtr) m->m_body);
+       }
+       name = copystr(name);
+       m->Type = KeyMacro.Type;
+       m->m_len = KeyMacro.m_len;
+       m->m_buflen = KeyMacro.m_buflen;
+       m->m_body = emalloc((size_t) m->m_buflen);
+       byte_copy(KeyMacro.m_body, m->m_body, (size_t) m->m_len);
+       m->m_flags = SAVE;
+       m->Name = name;
+       add_mac(m);
+}
+
+void
+RunMacro()
+{
+       struct macro    *m;
+
+       if ((m = (struct macro *) findmac(ProcFmt)) != NULL)
+               do_macro(m);
+}
+
+private void
+pr_putc(c, fp)
+int    c;
+File   *fp;
+{
+       if (c == '\\' || c == '^') {
+               jputc('\\', fp);
+       } else if (jiscntrl(c)) {
+               jputc('^', fp);
+               c = (c == RUBOUT) ? '?' : (c + '@');
+       }
+       jputc(c, fp);
+}
+
+void
+WriteMacs()
+{
+       struct macro    *m;
+       char    *file,
+               filebuf[FILESIZE];
+       File    *fp;
+       int     i;
+
+       file = ask_file((char *)NULL, (char *)NULL, filebuf);
+       fp = open_file(file, iobuff, F_WRITE, YES, YES);
+
+       /* Don't write the keyboard macro which is always the first */
+       for (m = macros->m_nextm; m != NULL; m = m->m_nextm) {
+               fwritef(fp, "define-macro %s ", m->Name);
+               for (i = 0; i < m->m_len; i++)
+                       pr_putc(m->m_body[i], fp);
+               jputc('\n', fp);
+               m->m_flags &= ~SAVE;
+       }
+       close_file(fp);
+}
+
+void
+DefKBDMac()
+{
+       char    *macro_name,
+               *macro_body,
+               nextc,
+               c,
+               macro_buffer[LBSIZE];
+       int     i;
+       struct macro    *m;
+
+       macro_name = do_ask(" \r\n", (bool (*) ptrproto((int))) NULL, (char *) NULL,
+               ProcFmt);
+       if (macro_name == NULL)
+               complain("[No default]");
+       macro_name = copystr(macro_name);
+       if ((m = mac_exists(macro_name)) != NULL)
+               del_mac(m);
+       macro_body = ask((char *)NULL, ": %f %s enter body: ", macro_name);
+       i = 0;
+       while ((c = *macro_body++) != '\0') {
+               if (c == '\\') {
+                       if ((nextc = *macro_body++) == LF)
+                               complain("[Premature end of line]");
+                       c = nextc;
+               } else if (c == '^') {
+                       if ((nextc = *macro_body++) == '?')
+                               c = RUBOUT;
+                       else if (jisalpha(nextc) || strchr("@[\\]^_", nextc))
+                               c = CTL(nextc);
+                       else
+                               complain("Bad control-character: '%c'", nextc);
+               }
+               macro_buffer[i++] = c;
+       }
+       m = (struct macro *) emalloc(sizeof (*m));
+       m->Name = macro_name;
+       m->m_len = m->m_buflen = i;
+       m->m_body = emalloc((size_t) i);
+       m->m_flags = InJoverc ? 0 : SAVE;
+       byte_copy(macro_buffer, m->m_body, (size_t) i);
+       add_mac(m);
+}
+
+void
+Remember()
+{
+       /* We're already executing the macro; ignore any attempts
+          to define the keyboard macro while we are executing. */
+       if (in_macro())
+               return;
+       if (InMacDefine)
+               message("[Already defining ... continue with definition]");
+       else {
+               UpdModLine = YES;
+               InMacDefine = YES;
+               KeyMacro.m_len = 0;
+               message("Defining...");
+       }
+}
+
+void
+Forget()
+{
+       char    *cp;
+       struct macro    *m = &KeyMacro;
+
+       UpdModLine = YES;
+       if (InMacDefine) {
+               message("Keyboard macro defined.");
+               InMacDefine = NO;
+
+               /* try and strip off the key sequence that invoked us */
+               cp = &m->m_body[m->m_len - 2];
+               if (PrefChar(*cp))
+                       m->m_len -= 2;
+               else if (commands[cp[1]].c_proc == Forget)
+                       m->m_len -= 1;
+       } else
+               complain("[end-kbd-macro: not currently defining macro!]");
+}
+
+void
+ExecMacro()
+{
+       do_macro(&KeyMacro);
+}
+
+void
+MacInter()
+{
+       if (Asking)
+               Interactive = YES;
+}
+
+int
+ModMacs()
+{
+       register struct macro   *m;
+
+       for (m = macros->m_nextm; m != NULL; m = m->m_nextm)
+               if (m->m_flags & SAVE)
+                       return YES;
+       return NO;
+}
+
+data_obj *
+findmac(prompt)
+const char     *prompt;
+{
+       char    *strings[100];
+       register char   **strs = strings;
+       register int    com;
+       register struct macro   *m = macros;
+
+       for (; m != NULL; m = m->m_nextm)
+               *strs++ = m->Name;
+       *strs = NULL;
+
+       if ((com = complete(strings, prompt, NOTHING)) < 0)
+               return NULL;
+       m = macros;
+       while (--com >= 0)
+               m = m->m_nextm;
+       return (data_obj *) m;
+}
+
+void
+DelMacro()
+{
+       struct macro    *m;
+
+       if ((m = (struct macro *) findmac(ProcFmt)) == NULL)
+               return;
+       if (m == &KeyMacro)
+               complain("[It's illegal to delete the keyboard-macro!]");
+       del_mac(m);
+}
diff --git a/usr/src/contrib/jove-4.14.6/makedep b/usr/src/contrib/jove-4.14.6/makedep
new file mode 100644 (file)
index 0000000..c9cd469
--- /dev/null
@@ -0,0 +1,211 @@
+funcdefs.o
+/lib/libc.a
+       index.o
+       strncmp.o
+       strcmp.o
+       exit.o
+       _exit.o
+       cleanup.o
+       cerror.o
+Undefined:
+_main
+_AddSpecial
+_AppReg
+_Apropos
+_CAutoExec
+_MAutoExec
+_BackChar
+_BList
+_BackPara
+_BSexpr
+_Bos
+_BUpList
+_BackWord
+_Remember
+_Bof
+_Bol
+_Bow
+_BindAKey
+_KmBind
+_BindMac
+_BindMtoW
+_BufPos
+_CapChar
+_CasRegLower
+_CasRegUpper
+_CapWord
+_LowWord
+_UppWord
+_ChrToOct
+_Chdir
+_ClAndRedraw
+_MakeErrors
+_ProcCont
+_CopyRegion
+_ShowErr
+_prCTIME
+_DBXpoutput
+_DefGAbbrev
+_DefMAbbrev
+_DefKBDMac
+_DelBlnkLines
+_BufKill
+_DelMacro
+_DelNChar
+_OneWindow
+_DelPChar
+_DelWtSpace
+_DelCurWindow
+_DescBindings
+_DescCom
+_KeyDesc
+_Digit
+_Digit1
+_Digit2
+_Digit3
+_Digit4
+_Digit5
+_Digit6
+_Digit7
+_Digit8
+_Digit9
+_Digit0
+_prDIRS
+_FDownList
+_ProcDStop
+_EditAbbrevs
+_Forget
+_Eof
+_Eol
+_Eow
+_ProcEof
+_BufErase
+_PtToMark
+_Extend
+_ExecMacro
+_RunMacro
+_Leave
+_Comment
+_Justify
+_RegJustify
+_FilterRegion
+_FindFile
+_FindTag
+_FDotTag
+_ToIndent
+_ForChar
+_FList
+_ForPara
+_FSexpr
+_Eos
+_ForWord
+_TimesFour
+_GSexpr
+_GoLine
+_GotoWind
+_GrowWindow
+_Tab
+_IncFSearch
+_IncRSearch
+_InsFile
+_ProcInt
+_Iprocess
+_DelNWord
+_DelPWord
+_ProcKill
+_DelReg
+_KillExpr
+_KillSome
+_KillBos
+_KillEOL
+_KillEos
+_SetLMargin
+_BufList
+_ProcList
+_NotModified
+_MakeKMap
+_MacInter
+_NameMac
+_Newline
+_OpenLine
+_LineAI
+_NextError
+_NextLine
+_NextPage
+_NextWindow
+_WNumLines
+_PageNWind
+_DoParen
+_ErrParse
+_SpelWords
+_PauseJove
+_PopMark
+_Popd
+_PrevError
+_PrevLine
+_PrevPage
+_PrevWindow
+_PrVar
+_ProcKmBind
+_ProcBind
+_ProcNewline
+_ProcSendData
+_Push
+_Pushd
+_prCWD
+_QRepSearch
+_ProcQuit
+_QuotChar
+_RestAbbrevs
+_RedrawDisplay
+_Recur
+_ReNamBuf
+_RegReplace
+_RepSearch
+_SetRMargin
+_SaveFile
+_DownScroll
+_ScrollLeft
+_ScrollRight
+_UpScroll
+_ForSearch
+_FSrchND
+_RevSearch
+_RSrchND
+_BufSelect
+_SelfInsert
+_SetVar
+_SetMark
+_ShellProc
+_ShellCom
+_ShNoBuf
+_ShToBuf
+_Shtypeout
+_LRShift
+_RRShift
+_ShrWindow
+_Source
+_SpelBuffer
+_SplitWind
+_ProcStop
+_StrLength
+_TransChar
+_TransLines
+_UnbindC
+_ShowVersion
+_WVisSpace
+_ReadFile
+_WindFind
+_SaveAbbrevs
+_WriteFile
+_WriteMacs
+_WtModBuf
+_WrtReg
+_Yank
+_YankPop
+_InJoverc
+_SyntaxTable
+_CharTable
+_getch
+_complain
+_complete
diff --git a/usr/src/contrib/jove-4.14.6/marks.c b/usr/src/contrib/jove-4.14.6/marks.c
new file mode 100644 (file)
index 0000000..98df15d
--- /dev/null
@@ -0,0 +1,230 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+
+bool   MarksShouldFloat = ON;
+
+Mark *
+MakeMark(line, column, type)
+register Line  *line;
+int    column,
+       type;
+{
+       register Mark   *newmark = (Mark *) emalloc(sizeof *newmark);
+
+       MarkSet(newmark, line, column);
+       newmark->m_next = curbuf->b_marks;
+       newmark->m_flags = type;
+       curbuf->b_marks = newmark;
+       return newmark;
+}
+
+void
+flush_marks(b)
+Buffer *b;
+{
+       register Mark   *m,
+                       *next;
+
+       m = b->b_marks;
+       while (m != NULL) {
+               next = m->m_next;
+               free((UnivPtr) m);
+               m = next;
+       }
+}
+
+void
+DelMark(m)
+register Mark  *m;
+{
+       register Mark   *mp = curbuf->b_marks;
+
+       if (m == mp)
+               curbuf->b_marks = m->m_next;
+       else {
+               while (mp != NULL && mp->m_next != m)
+                       mp = mp->m_next;
+               if (mp == NULL)
+                       complain("Unknown mark!");
+               mp->m_next = m->m_next;
+       }
+       free((UnivPtr) m);
+}
+
+void
+AllMarkSet(b, line, col)
+Buffer *b;
+register Line  *line;
+int    col;
+{
+       register Mark   *mp;
+
+       for (mp = b->b_marks; mp != NULL; mp = mp->m_next)
+               MarkSet(mp, line, col);
+}
+
+void
+MarkSet(m, line, column)
+Mark   *m;
+Line   *line;
+int    column;
+{
+       m->m_line = line;
+       m->m_char = column;
+}
+
+void
+PopMark()
+{
+       int     pmark;
+
+       if (curmark == NULL)
+               return;
+       if (curbuf->b_markring[(curbuf->b_themark + 1) % NMARKS] == NULL) {
+               pmark = curbuf->b_themark;
+               do {
+                       if (--pmark < 0)
+                               pmark = NMARKS - 1;
+               } while (curbuf->b_markring[pmark] != NULL);
+
+               curbuf->b_markring[pmark] = MakeMark(curline,
+                       curchar, MarksShouldFloat ? M_FLOATER : M_FIXED);
+               ToMark(curmark);
+               DelMark(curmark);
+               curmark = NULL;
+       } else
+               PtToMark();
+
+       pmark = curbuf->b_themark - 1;
+       if (pmark < 0)
+               pmark = NMARKS - 1;
+       curbuf->b_themark = pmark;
+}
+
+void
+SetMark()
+{
+       if (is_an_arg())
+               PopMark();
+       else
+               set_mark();
+}
+
+void
+set_mark()
+{
+       do_set_mark(curline, curchar);
+}
+
+void
+do_set_mark(l, c)
+Line   *l;
+int    c;
+{
+       curbuf->b_themark = (curbuf->b_themark + 1) % NMARKS;
+       if (curmark == NULL)
+               curmark = MakeMark(l, c,
+                       MarksShouldFloat ? M_FLOATER : M_FIXED);
+       else
+               MarkSet(curmark, l, c);
+       s_mess("[Point pushed]");
+}
+
+/* Move point to Mark */
+
+void
+ToMark(m)
+Mark   *m;
+{
+       int     len;
+
+       if (m == NULL)
+               return;
+       DotTo(m->m_line, m->m_char);
+       if (curchar > (len = length(curline)))
+               curchar = len;
+}
+
+Mark *
+CurMark()
+{
+       if (curmark == NULL)
+               complain("No mark.");
+       return curmark;
+}
+
+void
+PtToMark()
+{
+       Line    *mline;
+       int     mchar;
+       Mark    *m = CurMark();
+
+       mline = curline;
+       mchar = curchar;
+
+       ToMark(m);
+       MarkSet(m, mline, mchar);
+}
+
+/* Fix marks for after a deletion.  For now, even marks that don't
+   float will actually float, because we can't allow marks to point
+   to non-existant lines. */
+
+void
+DFixMarks(line1, char1, line2, char2)
+register Line  *line1,
+               *line2;
+int    char1,
+       char2;
+{
+       register Mark   *m;
+       Line    *lp;
+
+       if (curbuf->b_marks == NULL)
+               return;
+       for (lp = line1; lp != line2->l_next; lp = lp->l_next) {
+               for (m = curbuf->b_marks; m != NULL; m = m->m_next) {
+                       if (m->m_line == lp
+                       && (lp != line1 || m->m_char > char1))
+                       {
+                               if (lp == line2 && m->m_char >= char2)
+                                       m->m_char -= char2-char1;
+                               else
+                                       m->m_char = char1;
+                               m->m_line = line1;
+                               if (line1 != line2)
+                                       m->m_flags |= M_BIG_DELETE;
+                       }
+               }
+       }
+}
+
+/* Fix marks after an insertion.  Marks that don't float are ignored
+   on insertion, which means PtToMark has to be careful ... */
+
+void
+IFixMarks(line1, char1, line2, char2)
+register Line  *line1,
+               *line2;
+int    char1,
+       char2;
+{
+       register Mark   *m;
+
+       for (m = curbuf->b_marks; m != NULL; m = m->m_next) {
+               if ((m->m_flags & M_FLOATER)
+               && m->m_line == line1
+               && m->m_char > char1)
+               {
+                       m->m_line = line2;
+                       m->m_char += char2 - char1;
+               }
+       }
+}
diff --git a/usr/src/contrib/jove-4.14.6/menumaps.txt b/usr/src/contrib/jove-4.14.6/menumaps.txt
new file mode 100644 (file)
index 0000000..67c4999
--- /dev/null
@@ -0,0 +1,131 @@
+/************************************************************************
+ * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is      *
+ * provided to you without charge, and with no warranty.  You may give *
+ * away copies of JOVE, including sources, provided that this notice is *
+ * included in all the files.                                          *
+ ************************************************************************/
+
+/* menumaps.txt K. Mitchum 1/88. The same warnings apply as in keymaps.txt.
+   You MUST use a version of setmaps compiled with MAC defined for this
+   file to be converted correctly. */
+
+
+#include "jove.h"
+#include "mac.h"
+#MENU
+data_obj MDIV = { STRING, "(-" };
+data_obj MAJM = { STRING, "(Major Modes:" };
+data_obj MINM = { STRING, "(Minor Modes:" };
+data_obj BOOL = { STRING, "(Boolean:" };
+data_obj DECM = { STRING, "(Decimal:" };
+data_obj STRM = { STRING, "(String:" };
+data_obj CHAR = { STRING, "(Character:" };
+#define MENU_DIV &MDIV
+
+struct menu Menus[NMENUS] = {
+"File",101,0, {
+       "visit-file",
+       "find-file",
+       "insert-file",
+       MENU_DIV,
+       "save-file",
+       "write-file",
+       MENU_DIV,
+       "write-modified-files",
+       "write-region",
+       MENU_DIV,
+       "write-macros-to-file",
+       MENU_DIV,
+       "exit-jove",
+       0
+},
+
+"Buffer",103,0, {
+       &MAJM,
+       "c-mode",
+       "fundamental-mode",
+       "lisp-mode",
+       "text-mode",
+       &MINM,
+       "auto-fill-mode",
+       "auto-indent-mode",
+       "over-write-mode",
+       "show-match-mode",
+       "word-abbrev-mode",
+       MENU_DIV,
+       0
+},
+
+"Window",104,0, {
+       "grow-window",
+       "shrink-window",
+       MENU_DIV,
+       "split-current-window",
+       "delete-other-windows",
+       "window-find",
+       MENU_DIV,
+       "number-lines-in-window",
+       0
+},
+
+"Point",105,0, {
+       "set-mark",
+       "exchange-point-and-mark",
+       MENU_DIV,
+       "search-forward",
+       "search-reverse",
+       "i-search-forward",
+       "i-search-reverse",
+       "query-replace-string",
+       "replace-string",
+       MENU_DIV,
+       "find-tag",
+       0
+},
+
+"Command",106,0, {
+       "begin-kbd-macro",
+       "end-kbd-macro",
+       "name-kbd-macro",
+       "execute-kbd-macro",
+       "execute-macro",
+       MENU_DIV,
+       "bind-macro-to-key",
+       "bind-to-key",
+       "describe-key",
+       MENU_DIV,
+       "execute-named-command",
+       0
+},
+
+"Set",107,0, {
+       &BOOL,
+       "allow-bad-filenames",
+       "auto-case-abbrev",
+       "case-ignore-search",
+       "files-should-end-with-newline",
+       "macify",
+       "make-backup-files",
+       "marks-should-float",
+       "match-regular-expressions",
+       "send-typeout-to-buffer",
+       "wrap-search",
+       &DECM,
+       "c-indentation-increment",
+       "internal-tabstop",
+       "left-margin",
+       "mark-threshold",
+       "paren-flash-delay",
+       "right-margin",
+       "scroll-step",
+       "sync-frequency",
+       &STRM,
+       "comment-format",
+       "mode-line",
+       "tag-file",
+       &CHAR,
+       "abort-char",
+       0
+}
+};
+
diff --git a/usr/src/contrib/jove-4.14.6/misc.c b/usr/src/contrib/jove-4.14.6/misc.c
new file mode 100644 (file)
index 0000000..815a107
--- /dev/null
@@ -0,0 +1,350 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+#include "disp.h"
+
+#include <signal.h>
+
+void
+prCTIME()
+{
+       s_mess(": %f %s", get_time((time_t *)NULL, (char *)NULL, 0, -1));
+}
+
+void
+ChrToOct()
+{
+       int     c,
+               slow = NO;
+
+       c = waitchar(&slow);
+       ins_str(sprint("\\%03o", c), NO);
+}
+
+void
+StrLength()
+{
+       static const char       inquotes[] = "Where are the quotes?";
+       char    *first = StrIndex(BACKWARD, linebuf, curchar, '"'),
+               *last = StrIndex(FORWARD, linebuf, curchar + 1, '"'),
+               c;
+       int     numchars = 0;
+
+       if (first == NULL || last == NULL)
+               complain(inquotes);
+       first += 1;
+       while (first < last) {
+               c = *first++;
+               if (c == '\\') {
+                       int     num;
+
+                       if (!jisdigit(*first)) {
+                               first += 1;
+                       } else {
+                               num = 3;
+                               do ; while (num-- && jisdigit(*first++) && first < last);
+                       }
+               }
+               numchars += 1;
+       }
+       s_mess("%d characters", numchars);
+}
+
+/* Transpos cur_char with cur_char - 1 */
+
+void
+TransChar()
+{
+       char    before;
+
+       if (curchar == 0 || (eolp() && curchar == 1))
+               complain((char *)NULL); /* BEEP */
+       if (eolp())
+               b_char(1);
+       before = linebuf[curchar - 1];
+       del_char(BACKWARD, 1, NO);
+       f_char(1);
+       insert_c(before, 1);
+}
+
+/* Switch current line with previous one */
+
+void
+TransLines()
+{
+       daddr   old_prev;
+
+       if (firstp(curline))
+               return;
+       lsave();
+       old_prev = curline->l_prev->l_dline;
+       curline->l_prev->l_dline = curline->l_dline;
+       curline->l_dline = old_prev;
+       getDOT();
+       if (!lastp(curline))
+               line_move(FORWARD, 1, NO);
+       modify();
+}
+
+void
+Leave()
+{
+       longjmp(mainjmp, QUIT);
+}
+
+/* If argument is specified, kill that many lines down.  Otherwise,
+   if we "appear" to be at the end of a line, i.e. everything to the
+   right of the cursor is white space, we delete the line separator
+   as if we were at the end of the line. */
+
+void
+KillEOL()
+{
+       Line    *line2;
+       int     char2;
+       int     num = arg_value();
+
+       if (is_an_arg()) {
+               if (num == 0) { /* Kill to beginning of line */
+                       line2 = curline;
+                       char2 = 0;
+               } else {
+                       line2 = next_line(curline, num);
+                       if ((LineDist(curline, line2) < num) || (line2 == curline))
+                               char2 = length(line2);
+                       else
+                               char2 = 0;
+               }
+       } else if (blnkp(&linebuf[curchar])) {
+               line2 = next_line(curline, 1);
+               if (line2 == curline)
+                       char2 = length(curline);
+               else
+                       char2 = 0;
+       } else {
+               line2 = curline;
+               char2 = length(curline);
+       }
+       reg_kill(line2, char2, NO);
+}
+
+/* kill to beginning of sentence */
+
+void
+KillBos()
+{
+       negate_arg_value();
+       KillEos();
+}
+
+/* Kill to end of sentence */
+
+void
+KillEos()
+{
+       Line    *line1;
+       int     char1;
+
+       line1 = curline;
+       char1 = curchar;
+       Eos();
+       reg_kill(line1, char1, YES);
+}
+
+void
+KillExpr()
+{
+       Line    *line1;
+       int     char1;
+
+       line1 = curline;
+       char1 = curchar;
+       FSexpr();
+       reg_kill(line1, char1, YES);
+}
+
+void
+Yank()
+{
+       Line    *line,
+               *lp;
+       Bufpos  *dot;
+
+       if (killbuf[killptr] == NULL)
+               complain("[Nothing to yank!]");
+       lsave();
+       this_cmd = YANKCMD;
+       line = killbuf[killptr];
+       lp = lastline(line);
+       dot = DoYank(line, 0, lp, length(lp), curline, curchar, curbuf);
+       set_mark();
+       SetDot(dot);
+}
+
+void
+WtModBuf()
+{
+       if (!ModBufs(NO))
+               message("[No buffers need saving]");
+       else
+               put_bufs(is_an_arg());
+}
+
+void
+put_bufs(askp)
+bool   askp;
+{
+       register Buffer *oldb = curbuf,
+                       *b;
+
+       for (b = world; b != NULL; b = b->b_next) {
+               if (!IsModified(b) || b->b_type != B_FILE)
+                       continue;
+               SetBuf(b);      /* Make this current Buffer */
+               if (curbuf->b_fname == NULL) {
+                       char    *newname;
+
+                       newname = ask(NullStr, "Buffer \"%s\" needs a file name; type Return to skip: ", b->b_name);
+                       if (*newname == '\0')
+                               continue;
+                       setfname(b, newname);
+               }
+               if (askp && (yes_or_no_p("Write %s? ", curbuf->b_fname) == NO))
+                       continue;
+               filemunge(curbuf->b_fname);
+               chk_mtime(curbuf, curbuf->b_fname, "save");
+               file_write(curbuf->b_fname, NO);
+       }
+       SetBuf(oldb);
+}
+
+void
+ToIndent()
+{
+       Bol();
+       skip_wht_space();
+}
+
+void
+skip_wht_space()
+{
+       register char   *cp,
+                       c;
+
+       for (cp = linebuf + curchar; (c = *cp)!='\0'; cp++)
+               if (c != ' ' && c != '\t')
+                       break;
+       curchar = cp - linebuf;
+}
+
+/* GoLine -- go to a line, usually wired to goto-line, ESC g or ESC G.
+   If no argument is specified it asks for a line number. */
+void
+GoLine()
+{
+       Line    *newline;
+
+       if (!is_an_arg())
+               set_arg_value(ask_int("Line: ",10));
+       newline = next_line(curbuf->b_first, arg_value() - 1);
+       PushPntp(newline);
+       SetLine(newline);
+}
+
+void
+NotModified()
+{
+       unmodify();
+}
+
+void
+SetLMargin()
+{
+       int     lmarg = calc_pos(linebuf, curchar);
+
+       if (lmarg >= RMargin)
+               complain("[Left margin must be left of right margin]");
+       LMargin = lmarg;
+}
+
+void
+SetRMargin()
+{
+       int     rmarg = calc_pos(linebuf, curchar);
+
+       if (rmarg <= LMargin)
+               complain("[Right margin must be right of left margin]");
+       RMargin = rmarg;
+}
+
+/*
+ *     Mouse support for Xterm
+ *     The Xterm program sends
+ *     Esc [ M
+ *             button + space
+ *             col + space + 1
+ *             row + space + 1
+ */
+static void MoveToCursor(/* int, int */);
+
+void
+XtermMouse()
+{
+       int mouse;
+       int line;
+       int col;
+       int slow = NO;
+       register struct scrimage *sp;
+       char    *msg;
+       
+       mouse = waitchar(&slow) - ' ';
+       col = waitchar(&slow) - ' ' - 1;
+       line = waitchar(&slow) - ' ' - 1;
+
+       sp = &PhysScreen[line];
+
+       while (sp->s_id == NULL)
+               sp = &PhysScreen[--line];
+       if (curwind != sp->s_window)
+               SetWind(sp->s_window);
+       if (sp->s_flags & MODELINE)
+       {
+               switch (mouse)
+               {
+               case 0:
+                       WindSize(curwind, 1);
+                       msg = "[Grow window]";
+                       break;
+               default:
+                       WindSize(curwind, -1);
+                       msg = "[Shrink window]";
+                       break;
+               }
+               s_mess(msg);
+
+       }
+       else
+       {       SetLine(sp->s_lp);
+               curchar = how_far(sp->s_lp, col);
+               switch (mouse)
+               {
+               case 0:                 /* left button */
+                       set_mark();
+                       break;
+               case 1:                 /* paste on middle button */
+                       Yank();
+                       s_mess("[Region pasted]");
+                       break;
+               case 2:                 /* end of region on right button */
+                       CopyRegion();
+                       s_mess("[Region copied]");
+                       break;
+               }
+       }
+}
diff --git a/usr/src/contrib/jove-4.14.6/mjovers.Hqx b/usr/src/contrib/jove-4.14.6/mjovers.Hqx
new file mode 100644 (file)
index 0000000..a2bbc9a
--- /dev/null
@@ -0,0 +1,19 @@
+(This file must be converted with BinHex 4.0)
+
+:#QeUEhCP,R*cFQ-!2j!%5PB`-3#3#!1JIqJ!N!3"!*!$![i!!!(q!*!$SJ%,!3F
+""J%'!3F"#3%(!3J"#3%+!38!"J!'!3S"#`!(#QeUEhCP,R*cFQ0b!J#30Cj)c4F
+!N!B$S!-5!!N!!J#3!c-!N$+L!%e5J!#3$`(!!*!,!`#3"6!!!!)Dd!#3#"!!N"-
+F5PB`-3#3!`&*3diM!*!&J%C548B!N!@!!*!("d&38%`!N!8"!2q3!`#J!!%![q-
+"`+!!!8#2rm&`J!!"8)2rm9b!!!&8Mrr"9)!!!95i!!&8J!!"92q3!e5!!!&8[q-
+"9)!!!952rm&8J!!"9)2rm95!!!&8Mrr"9)!!!95i!!&8J!!"92q3!e6rN!08)!!
+!9$rrrp3)!!!8$rrrp!)!!!3$rrrmrj!$!2q3!`$rN!2!rj!$`2q3!r$rN!2`rj!
+$r2q3!rcrN!2mrj!$r2q3!rcrN!2mrj!$r2q3!rcrN!2mrj!$r2q3!rcrN!2mrj!
+$r2q3!rcrN!2mrj!$r2q3!rcrN!2mrj!$r2q3!r`rrrrm2rrrr!rrrr`2rrrm!rr
+rr!2rrr`!N!1Z!!B!N!@q!A)!dJ'Z"!*25`#3"5J!&!$`!8m!N!F$!"3!$3(##!*
+H-!#3"3m!&!!M!A`)!Pia!*!&+!&H!$F"c!J2B#!p)%963d&345"VCANZ%J#3"6F
+"AJ"'!F`)%N0[E@eKEQ3JB#!p)'!JDf9j,J#3"8X"AJ"Z!F`))80[ER4bEf`J25"
+$EfeYB@jN)'pb)%0[ER4bEf`J5f9j,JJ!N!-9!*!%!33"c!!"!*!)"q3!N!-"!*!
+$![i!!!(q!*!$SJ!"h(B%DJ#3!a`!PJ!&3Nj%6!#3!c*+9M!a!*!$2NC548B!N!0
++5801)`#3!eC%594-!*!$BN4-6dF!N!0Z!)$rr`#3"3(XXJ!!rrm!N!-J!!(Y!J#
+!rrm!N!-N!!(H8J#!rrm!N!-[!!(XpJINrrm!!!%c!!(XeJI3!*!%!H8!!HbL#d&
+#6e98AdT%6%p(Ep3:
diff --git a/usr/src/contrib/jove-4.14.6/move.c b/usr/src/contrib/jove-4.14.6/move.c
new file mode 100644 (file)
index 0000000..29dec2f
--- /dev/null
@@ -0,0 +1,300 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "re.h"
+#include "ctype.h"
+#include "disp.h"
+
+private int    line_pos;
+
+void
+f_char(n)
+register int   n;
+{
+       if (n < 0) {
+               b_char(-n);
+               return;
+       }
+       while (--n >= 0) {
+               if (eolp()) {                   /* Go to the next Line */
+                       if (curline->l_next == NULL)
+                               break;
+                       SetLine(curline->l_next);
+               } else
+                       curchar += 1;
+       }
+}
+
+void
+b_char(n)
+register int   n;
+{
+       if (n < 0) {
+               f_char(-n);
+               return;
+       }
+       while (--n >= 0) {
+               if (bolp()) {
+                       if (curline->l_prev == NULL)
+                               break;
+                       SetLine(curline->l_prev);
+                       Eol();
+               } else
+                       curchar -= 1;
+       }
+}
+
+void
+ForChar()
+{
+       f_char(arg_value());
+}
+
+void
+BackChar()
+{
+       b_char(arg_value());
+}
+
+void
+NextLine()
+{
+       if ((curline == curbuf->b_last) && eolp())
+               complain(NullStr);
+       line_move(FORWARD, arg_value(), YES);
+}
+
+void
+PrevLine()
+{
+       if ((curline == curbuf->b_first) && bolp())
+               complain(NullStr);
+       line_move(BACKWARD, arg_value(), YES);
+}
+
+/* moves to a different line in DIR; LINE_CMD says whether this is
+   being called from NextLine() or PrevLine(), in which case it tries
+   to line up the column with the column of the current line */
+
+void
+line_move(dir, n, line_cmd)
+int    dir,
+       n;
+bool   line_cmd;
+{
+       Line    *(*proc) ptrproto((Line *, int)) =
+               (dir == FORWARD) ? next_line : prev_line;
+       Line    *line;
+
+       line = (*proc)(curline, n);
+       if (line == curline) {
+               if (dir == FORWARD)
+                       Eol();
+               else
+                       Bol();
+               return;
+       }
+
+       if (line_cmd) {
+               this_cmd = LINECMD;
+               if (last_cmd != LINECMD)
+                       line_pos = calc_pos(linebuf, curchar);
+       }
+       SetLine(line);          /* curline is in linebuf now */
+       if (line_cmd)
+               curchar = how_far(curline, line_pos);
+}
+
+/* returns what cur_char should be for that position col */
+
+int
+how_far(line, col)
+Line   *line;
+int    col;
+{
+       register char   *lp;
+       register int    pos,
+                       c;
+       char    *base;
+
+       base = lp = lcontents(line);
+       pos = 0;
+
+       while (pos < col && (c = (*lp & CHARMASK)) != '\0') {
+               if (c == '\t')
+                       pos += (tabstop - (pos % tabstop));
+               else if (jiscntrl(c))
+                       pos += 2;
+               else
+                       pos += 1;
+               lp += 1;
+       }
+
+       return lp - base;
+}
+
+void
+Bol()
+{
+       curchar = 0;
+}
+
+void
+Eol()
+{
+       curchar = length(curline);
+}
+
+void
+Eof()
+{
+       PushPntp(curbuf->b_last);
+       ToLast();
+}
+
+void
+Bof()
+{
+       PushPntp(curbuf->b_first);
+       ToFirst();
+}
+
+/* Move forward (if dir > 0) or backward (if dir < 0) a sentence.  Deals
+   with all the kludgery involved with paragraphs, and moving backwards
+   is particularly yucky. */
+
+private void
+to_sent(dir)
+int    dir;
+{
+       Bufpos  *new,
+               old;
+
+       DOTsave(&old);
+
+       new = dosearch("^[ \t]*$\\|[?.!]", dir, YES);
+       if (new == NULL) {
+               if (dir == BACKWARD)
+                       ToFirst();
+               else
+                       ToLast();
+               return;
+       }
+       SetDot(new);
+       if (dir < 0) {
+               to_word(1);
+               if ((old.p_line == curline && old.p_char <= curchar) ||
+                   (inorder(new->p_line, new->p_char, old.p_line, old.p_char) &&
+                    inorder(old.p_line, old.p_char, curline, curchar))) {
+                       SetDot(new);
+                       to_sent(dir);
+               }
+               return;         /* We're there? */
+       }
+       if (blnkp(linebuf)) {
+               Bol();
+               b_char(1);
+               if (old.p_line == curline && old.p_char >= curchar) {
+                       to_word(1);     /* Oh brother this is painful */
+                       to_sent(1);
+               }
+       } else {
+               curchar = REbom + 1;    /* Just after the [?.!] */
+               if (LookingAt("[\")]  *\\|[\")]$", linebuf, curchar))
+                       curchar += 1;
+               else if (!eolp() && !LookingAt("  *", linebuf, curchar))
+                       to_sent(dir);
+       }
+}
+
+void
+Bos()
+{
+       register int    num = arg_value();
+
+       if (num < 0) {
+               negate_arg_value();
+               Eos();
+               return;
+       }
+
+       while (--num >= 0) {
+               to_sent(-1);
+               if (bobp())
+                       break;
+       }
+}
+
+void
+Eos()
+{
+       register int    num = arg_value();
+
+       if (num < 0) {
+               negate_arg_value();
+               Bos();
+               return;
+       }
+
+       while (--num >= 0) {
+               to_sent(1);
+               if (eobp())
+                       break;
+       }
+}
+
+void
+f_word(num)
+register int   num;
+{
+       register char   c;
+       if (num < 0) {
+               b_word(-num);
+               return;
+       }
+       while (--num >= 0) {
+               to_word(FORWARD);
+               while ((c = linebuf[curchar]) != '\0' && jisword(c))
+                       curchar += 1;
+               if (eobp())
+                       break;
+       }
+       this_cmd = 0;   /* Semi kludge to stop some unfavorable behavior */
+}
+
+void
+b_word(num)
+register int   num;
+{
+       register char   c;
+
+       if (num < 0) {
+               f_word(-num);
+               return;
+       }
+       while (--num >= 0) {
+               to_word(BACKWARD);
+               while (!bolp() && (c = linebuf[curchar - 1], jisword(c)))
+                       curchar -= 1;
+               if (bobp())
+                       break;
+       }
+       this_cmd = 0;
+}
+
+void
+ForWord()
+{
+       f_word(arg_value());
+}
+
+void
+BackWord()
+{
+       b_word(arg_value());
+}
diff --git a/usr/src/contrib/jove-4.14.6/note b/usr/src/contrib/jove-4.14.6/note
new file mode 100644 (file)
index 0000000..d3619ff
--- /dev/null
@@ -0,0 +1,7 @@
+awright, compiled it.  missing } in a SYSV ifdef.  I removed the ifdef
+in question and moved the info in it to sysdep.h.
+
+A typo in iproc-pipes.h, otherwise, seems basically ok.  I'll use
+this binary for a while and see what breaks.
+
+       Mark.
diff --git a/usr/src/contrib/jove-4.14.6/paragraph.c b/usr/src/contrib/jove-4.14.6/paragraph.c
new file mode 100644 (file)
index 0000000..e9921c9
--- /dev/null
@@ -0,0 +1,552 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "disp.h"
+
+private int    get_indent proto((Line *));
+
+/* Thanks to Brian Harvey for this paragraph boundery finding algorithm.
+   It's really quite hairy figuring it out.  This deals with paragraphs that
+   are seperated by blank lines, lines beginning with a Period (assumed to
+   be an nroff command), lines beginning with BackSlash (assumed to be Tex
+   commands).  Also handles paragraphs that are separated by lines of
+   different indent; and it deals with outdented paragraphs, too.  It's
+   really quite nice.  Here's Brian's algorithm.
+
+   Definitions:
+
+   THIS means the line containing the cursor.
+   PREV means the line above THIS.
+   NEXT means the line below THIS.
+
+   BLANK means empty, empty except for spaces and tabs, starts with a period
+   or a backslash, or nonexistent (because the edge of the buffer is
+   reached).  ((BH 12/24/85 A line starting with backslash is blank only if
+   the following line also starts with backslash.  This is so that \noindent
+   is part of a paragraph, but long strings of TeX commands don't get
+   rearranged.  It still isn't perfect but it's better.))
+
+   BSBLANK means BLANK or starts with a backslash.  (BH 12/24/85)
+
+   HEAD means the first (nonblank) line of the paragraph containing THIS.
+   BODY means all other (nonblank) lines of the paragraph.
+   TAIL means the last (nb) line of the paragraph.  (TAIL is part of BODY.)
+
+   HEAD INDENT means the indentation of HEAD.  M-J should preserve this.
+   BODY INDENT means the indentation of BODY.  Ditto.
+
+   Subprocedures:
+
+   TAILRULE(BODYLINE)
+   If BODYLINE is BLANK, the paragraph has only one line, and there is no
+   BODY and therefore no TAIL.  Return.  Otherwise, starting from BODYLINE,
+   move down until you find a line that either is BSBLANK or has a different
+   indentation from BODYLINE.  The line above that different line is TAIL.
+   Return.
+
+   Rules:
+
+   1.  If THIS is BLANK, which command are you doing?  If M-J or M-[, then go
+   up to the first non-BLANK line and start over.  (If there is no non-BLANK
+   line before THIS, ring the bell.)  If M-], then the first non-BLANK line
+   below THIS is HEAD, and the second consecutive non-BSBLANK line (if any) is
+   the beginning of BODY.  (If there is no non-BLANK line after THIS, ring
+   the bell.)  Do TAILRULE(beginning-of-BODY).  Go to rule A.
+
+   2.  If PREV is BLANK or THIS is BSBLANK, then THIS is HEAD, and NEXT (if
+   not BSBLANK) is in BODY.  Do TAILRULE(NEXT).  Go to rule A.
+
+   3.  If NEXT is BSBLANK, then THIS is TAIL, therefore part of BODY.  Go to
+   rule 5 to find HEAD.
+
+   4.  If either NEXT or PREV has the same indentation as THIS, then THIS is
+   part of BODY.  Do TAILRULE(THIS).  Go to rule 5 to find HEAD.  Otherwise,
+   go to rule 6.
+
+   5.  Go up until you find a line that is either BSBLANK or has a different
+   indentation from THIS.  If that line is BLANK, the line below it is HEAD;
+   If that line is non-BLANK, then call that new line THIS for what follows.
+   If THIS is BSBLANK (that is, THIS starts with backslash), THIS is HEAD;
+   otherwise, if (the new) PREV has the same indent as THIS, then (the new)
+   NEXT is HEAD; if PREV has a different indent from THIS, then THIS is
+   HEAD.  Go to rule A.
+
+   6.  If you got here, then both NEXT and PREV are nonblank and are
+   differently indented from THIS.  This is a tricky case and there is no
+   guarantee that you're going to win.  The most straightforward thing to do
+   is assume that we are not using hanging indentation.  In that case:
+   whichever of PREV and THIS is indented further is HEAD.  Do
+   TAILRULE(HEAD+1).  Go to rule A.
+
+   6+.  A more complicated variant would be this: if THIS is indented further
+   than PREV, we are using regular indentation and rule 6 applies.  If PREV
+   is indented further than THIS, look at both NEXT and the line after NEXT.
+   If those two lines are indented equally, and more than THIS, then we are
+   using hanging indent, THIS is HEAD, and NEXT is the first line of BODY.
+   Do TAILRULE(NEXT).  Otherwise, rule 6 applies.
+
+   A.  You now know where HEAD and TAIL are.  The indentation of HEAD is HEAD
+   INDENT; the indentation of TAIL is BODY INDENT.
+
+   B.  If you are trying to M-J, you are now ready to do it.
+
+   C.  If you are trying to M-], leave point after the newline that ends
+   TAIL.  In other words, leave the cursor at the beginning of the line
+   after TAIL.  It is not possible for this to leave point where it started
+   unless it was already at the end of the buffer.
+
+   D.  If you are trying to M-[, if the line before HEAD is not BLANK, then
+   leave point just before HEAD.  That is, leave the cursor at the beginning
+   of HEAD.  If the line before HEAD is BLANK, then leave the cursor at the
+   beginning of that line.  If the cursor didn't move, go up to the first
+   earlier non-BLANK line and start over.
+
+
+   End of Algorithm.  I implemented rule 6+ because it seemed nicer.  */
+
+/*
+ *     Altered to include '--' at the start of the line to mean
+ *     beginning of paragraph this makes formatting the first line
+ *     of mail for mh easier
+ *     Peter C UKC
+ */
+int    RMargin = 78,
+       LMargin = 0;
+private Line   *para_head,
+       *para_tail;
+private int    head_indent,
+       body_indent;
+private bool   use_lmargin;
+
+/* some defines for paragraph boundery checking */
+#define I_EMPTY                (-1)    /* line "looks" empty (spaces and tabs) */
+#define I_PERIOD       (-2)    /* line begins with "." or "\" */
+#define I_BUFEDGE      (-3)    /* line is nonexistent (edge of buffer) */
+
+static bool    bslash;         /* Nonzero if get_indent finds line starting
+                                  with backslash */
+
+private int
+i_blank(lp)
+Line   *lp;
+{
+       return get_indent(lp) < 0;
+}
+
+private bool
+i_bsblank(lp)
+Line   *lp;
+{
+       return i_blank(lp) || bslash;
+}
+
+private int
+get_indent(lp)
+register Line  *lp;
+{
+       Bufpos  save;
+       register int    indent;
+
+       bslash = NO;
+       if (lp == NULL)
+               return I_BUFEDGE;
+       DOTsave(&save);
+       SetLine(lp);
+       if (blnkp(linebuf))
+               indent = I_EMPTY;
+       else if (linebuf[0] == '.' || (linebuf[0] == '-' && linebuf[1] == '-'))
+               indent = I_PERIOD;
+       else if (linebuf[0] == '\\') {
+               /* BH 12/24/85.  Backslash is BLANK only if next line
+                  also starts with Backslash. */
+               bslash = YES;
+               SetLine(lp->l_next);
+               if (linebuf[0] == '\\')
+                       indent = I_PERIOD;
+               else
+                       indent = 0;
+       } else {
+               ToIndent();
+               indent = calc_pos(linebuf, curchar);
+       }
+       SetDot(&save);
+
+       return indent;
+}
+
+private Line *
+tailrule(lp)
+register Line  *lp;
+{
+       int     i;
+
+       i = get_indent(lp);
+       if (i < 0)
+               return lp;      /* one line paragraph */
+       do {
+               if ((get_indent(lp->l_next) != i) || bslash)
+                       /* BH line with backslash is head of next para */
+                       break;
+       } while ((lp = lp->l_next) != NULL);
+       if (lp == NULL)
+               complain((char *) NULL);
+       return lp;
+}
+
+/* Finds the beginning, end and indent of the current paragraph, and sets
+   the above global variables.  HOW says how to behave when we're between
+   paragraphs.  That is, it's either FORWARD or BACKWARD depending on which
+   way we're favoring. */
+
+private void
+find_para(how)
+int    how;
+{
+       Line    *this,
+               *prev,
+               *next,
+               *head = NULL,
+               *body = NULL,
+               *tail = NULL;
+       int     this_indent;
+       Bufpos  orig;           /* remember where we were when we started */
+
+       DOTsave(&orig);
+strt:
+       this = curline;
+       prev = curline->l_prev;
+       next = curline->l_next;
+       this_indent = get_indent(this);
+
+       if (i_blank(this)) {            /* rule 1 */
+               if (how == BACKWARD) {
+                       while (i_blank(curline))
+                               if (firstp(curline))
+                                       complain((char *)NULL);
+                               else
+                                       line_move(BACKWARD, 1, NO);
+                       goto strt;
+               } else {
+                       while (i_blank(curline))
+                               if (lastp(curline))
+                                       complain((char *)NULL);
+                               else
+                                       line_move(FORWARD, 1, NO);
+                       head = curline;
+                       next = curline->l_next;
+                       body = !i_bsblank(next)? next : head;
+               }
+       } else if (i_bsblank(this) || i_blank(prev)) {  /* rule 2 */
+               head = this;
+               if (!i_bsblank(next))
+                       body = next;
+       } else if (i_bsblank(next)) {   /* rule 3 */
+               tail = this;
+               body = this;
+       } else if ((get_indent(next) == this_indent) || /* rule 4 */
+                  (get_indent(prev) == this_indent)) {
+               body = this;
+       } else {                /* rule 6+ */
+               if (get_indent(prev) > this_indent) {
+                       /* hanging indent maybe? */
+                       if ((next != NULL) &&
+                           (get_indent(next) == get_indent(next->l_next))) {
+                               head = this;
+                               body = next;
+                       }
+               }
+               /* Now we handle hanging indent else and the other
+                  case of this_indent > get_indent(prev).  That is,
+                  if we didn't resolve HEAD in the above if, then
+                  we are not a hanging indent. */
+               if (head == NULL) {     /* still don't know */
+                       if (this_indent > get_indent(prev))
+                               head = this;
+                       else
+                               head = prev;
+                       body = head->l_next;
+               }
+       }
+       /* rule 5 -- find the missing parts */
+       if (head == NULL) {    /* haven't found head of paragraph so do so now */
+               Line    *lp;
+               int     i;
+
+               lp = this;
+               do {
+                       i = get_indent(lp->l_prev);
+                       if (i < 0)      /* is blank */
+                               head = lp;
+                       else if (bslash)
+                               head = lp->l_prev;
+                       else if (i != this_indent) {
+                               this = lp->l_prev;
+                               if (get_indent(this->l_prev) == i)
+                                       head = this->l_next;
+                               else
+                                       head = this;
+                       }
+               } while (head == NULL && (lp = lp->l_prev) != NULL);
+               if (lp == NULL)
+                       complain((char *)NULL);
+       }
+       if (body == NULL)               /* this must be a one line paragraph */
+               body = head;
+       if (tail == NULL)
+               tail = tailrule(body);
+       if (tail == NULL || head == NULL || body == NULL)
+               complain("BUG! tail(%d),head(%d),body(%d)!", tail, head, body);
+       para_head = head;
+       para_tail = tail;
+       head_indent = get_indent(head);
+       body_indent = get_indent(body);
+
+       SetDot(&orig);
+}
+
+void
+Justify()
+{
+       use_lmargin = is_an_arg();
+       find_para(BACKWARD);
+       DoJustify(para_head, 0, para_tail, length(para_tail), NO,
+                 use_lmargin ? LMargin : body_indent);
+}
+
+private Line *
+max_line(l1, l2)
+Line   *l1,
+       *l2;
+{
+       return inorder(l1, 0, l2, 0)? l2 : l1;
+}
+
+private Line *
+min_line(l1, l2)
+Line   *l1,
+       *l2;
+{
+       return inorder(l1, 0, l2, 0)? l1 : l2;
+}
+
+void
+RegJustify()
+{
+       Mark    *mp = CurMark(),
+               *tailmark;
+       Line    *l1 = curline,
+               *l2 = mp->m_line;
+       int     c1 = curchar,
+               c2 = mp->m_char;
+       Line    *rl1,
+               *rl2;
+
+       use_lmargin = is_an_arg();
+       (void) fixorder(&l1, &c1, &l2, &c2);
+       do {
+               DotTo(l1, c1);
+               find_para(FORWARD);
+               rl1 = max_line(l1, para_head);
+               rl2 = min_line(l2, para_tail);
+               tailmark = MakeMark(para_tail, 0, M_FLOATER);
+               DoJustify(rl1, (rl1 == l1) ? c1 : 0, rl2,
+                         (rl2 == l2) ? c2 : length(rl2),
+                         NO, use_lmargin ? LMargin : body_indent);
+               l1 = tailmark->m_line->l_next;
+               DelMark(tailmark);
+               c1 = 0;
+       } while (l1 != NULL && l2 != rl2);
+}
+
+void
+do_rfill(ulm)
+bool   ulm;
+{
+       Mark    *mp = CurMark();
+       Line    *l1 = curline,
+               *l2 = mp->m_line;
+       int     c1 = curchar,
+               c2 = mp->m_char;
+
+       use_lmargin = ulm;
+       (void) fixorder(&l1, &c1, &l2, &c2);
+       DoJustify(l1, c1, l2, c2, NO, use_lmargin ? LMargin : 0);
+}
+
+private void
+do_space()
+{
+       int     c1 = curchar,
+               c2 = c1,
+               diff,
+               nspace;
+       char    ch;
+
+       while (c1 > 0 && ((ch = linebuf[c1 - 1]) == ' ' || ch == '\t'))
+               c1 -= 1;
+       while ((ch = linebuf[c2]) == ' ' || ch == '\t')
+               c2 += 1;
+       diff = (c2 - c1);
+       curchar = c2;
+
+       if (diff == 0)
+               return;
+       if (c1 > 0) {
+               int     topunct = c1 - 1;
+
+               nspace = 1;
+               if (diff >= 2) {
+                       while (strchr("\")]", linebuf[topunct])) {
+                               if (topunct == 0)
+                                       break;
+                               topunct -= 1;
+                       }
+                       if (strchr("?!.:", linebuf[topunct]))
+                               nspace = 2;
+               }
+       } else
+               nspace = 0;
+
+       if (diff > nspace)
+               del_char(BACKWARD, (diff - nspace), NO);
+       else if (diff < nspace)
+               insert_c(' ', (nspace - diff));
+}
+
+#ifdef MSDOS
+/*#pragma loop_opt(off) */
+#endif
+
+void
+DoJustify(l1, c1, l2, c2, scrunch, indent)
+Line   *l1,
+       *l2;
+int    c1,
+       c2,
+       indent;
+bool
+       scrunch;
+{
+       int     okay_char = -1;
+       char    *cp;
+       Mark    *savedot = MakeMark(curline, curchar, M_FLOATER),
+               *endmark;
+
+       (void) fixorder(&l1, &c1, &l2, &c2);    /* l1/c1 will be before l2/c2 */
+       DotTo(l1, c1);
+       if (get_indent(l1) >= c1) {
+               if (use_lmargin) {
+                       Bol();
+                       n_indent(indent + (head_indent - body_indent));
+                       use_lmargin = NO;       /* turn this off now */
+               }
+               ToIndent();
+       }
+       endmark = MakeMark(l2, c2, M_FLOATER);
+
+       for (;;) {
+               /* The while loop succeeds at least once, when curchar ==
+                  indent.  So we know that okay_char >= indent when we
+                  exit the loop. */
+               while (calc_pos(linebuf, curchar) < RMargin) {
+                       if (curline == endmark->m_line && curchar >= endmark->m_char)
+                               goto outahere;
+                       okay_char = curchar;
+                       if (eolp()) {
+                               /* delete line separator */
+                               del_char(FORWARD, 1, NO);
+                               ins_str("  ", NO);
+                       } else {
+                               cp = StrIndex(FORWARD, linebuf, curchar + 1, ' ');
+                               if (cp == NULL)
+                                       Eol();
+                               else
+                                       curchar = (cp - linebuf);
+                       }
+                       do_space();
+               }
+               if (okay_char > indent)
+                       curchar = okay_char;
+               if (curline == endmark->m_line && curchar >= endmark->m_char)
+                       goto outahere;
+
+               /* Can't fit in small margin, so if' we're at the end of
+                  the line then we just move to the next line.  Otherwise
+                  we divide the line where we are and start over. */
+               if (eolp()) {
+                       Line    *l = curline;
+
+                       line_move(FORWARD, 1, NO);
+                       if (l == curline)       /* didn't actuall go anywhere */
+                               goto outahere;
+               } else {
+                       DelWtSpace();
+                       LineInsert(1);
+                       if (scrunch && TwoBlank()) {
+                               Eol();
+                               del_char(FORWARD, 1, NO);
+                       }
+               }
+               n_indent(indent);
+       }
+outahere:
+       ToMark(savedot);        /* Back to where we were */
+       DelMark(endmark);       /* Free up marks */
+       DelMark(savedot);
+       this_cmd = last_cmd = 0; /* So everything is under control */
+       f_mess("");
+}
+
+#ifdef MSDOS
+/*#pragma loop_opt() */
+#endif
+
+private void
+DoPara(dir)
+int    dir;
+{
+       register int    num = arg_value(),
+                       first_time = TRUE;
+
+       while (--num >= 0) {
+tryagain:
+               find_para(dir);         /* find paragraph bounderies */
+               if ((dir == BACKWARD) &&
+                   ((!first_time) || ((para_head == curline) && bolp()))) {
+                       if (bobp())
+                               complain((char *)NULL);
+                       b_char(1);
+                       first_time = !first_time;
+                       goto tryagain;
+               }
+               SetLine((dir == BACKWARD) ? para_head : para_tail);
+               if (dir == BACKWARD && !firstp(curline) &&
+                   i_blank(curline->l_prev))
+                       line_move(BACKWARD, 1, NO);
+               else if (dir == FORWARD) {
+                       if (lastp(curline)) {
+                               Eol();
+                               break;
+                       }
+                       /* otherwise */
+                       line_move(FORWARD, 1, NO);
+               }
+       }
+}
+
+void
+BackPara()
+{
+       DoPara(BACKWARD);
+}
+
+void
+ForPara()
+{
+       DoPara(FORWARD);
+}
diff --git a/usr/src/contrib/jove-4.14.6/pcscr.c b/usr/src/contrib/jove-4.14.6/pcscr.c
new file mode 100644 (file)
index 0000000..b2aee4c
--- /dev/null
@@ -0,0 +1,467 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+
+#ifdef IBMPC
+
+/* here come the actual emulation routines     */
+
+#include <dos.h>
+#include <conio.h>
+
+#define BYTE   unsigned char
+#define WORD   unsigned int
+
+#ifdef MAC
+# undef private
+# define private
+#endif
+
+private BYTE near get_mode proto((void));
+
+private WORD
+       near cur_page proto((void)),
+       near get_cur proto((void));
+
+private void
+       near ch_out proto((BYTE, BYTE)),
+       near clr_eop proto((void)),
+       near cur_advance proto((void)),
+       near cur_down proto((void)),
+       near cur_left proto((void)),
+       near cur_right proto((void)),
+       near cur_up proto((void)),
+       near line_feed proto((void)),
+       near set_cur proto((WORD)),
+       near set_mode proto((BYTE)),
+       near wherexy proto((BYTE *, BYTE *));
+
+void   near normfun proto((char)),
+       near scr_win proto((int, BYTE, BYTE, BYTE, BYTE)),
+       near clr_page(),
+       near clr_eoln();
+
+#ifdef MAC
+# undef private
+# define private static
+#endif
+
+#define VIDEO   0x10
+
+#define intr(n, r)     int86((n), (r), (r));
+
+BYTE CHPL=80,
+     LPP=25,
+     CUR_PAGE=0,
+     C_ATTR = 0x07,
+     C_X=0,
+     C_Y=0;
+
+int Fgcolor = 7,
+    Bgcolor = 0,
+       Mdcolor = 0;
+
+void setcolor(fg, bg)
+BYTE fg, bg;
+{
+   C_ATTR = ((bg&0xf)<<4)|(fg&0xf);
+}
+
+private
+WORD near cur_page()
+{
+   union REGS vr;
+
+   vr.h.ah = 0x0f;
+   intr(VIDEO, &vr);
+   return vr.h.bh;
+}
+
+private
+void near set_cur(xy)
+WORD xy;
+{
+   union REGS vr;
+
+   vr.h.bh = CUR_PAGE;
+   vr.h.ah = 0x02;
+   vr.x.dx = xy;
+   intr(VIDEO, &vr);
+}
+
+private
+WORD near get_cur()
+{
+   union REGS vr;
+
+   vr.h.bh = CUR_PAGE;
+   vr.h.ah = 0x03;
+   intr(VIDEO, &vr);
+   return (vr.x.dx);
+}
+
+private
+BYTE near get_mode()
+{
+  union REGS vr;
+
+  vr.h.ah = 0x0f;
+  intr(VIDEO, &vr);
+  return vr.h.al;
+}
+
+BYTE lpp()
+{
+   int far *regen = (int far *) 0x44C;
+   int what;
+   BYTE chpl();
+
+   what = (*regen&0xff00)/2/chpl();
+   return (what > 43 ? 25 : what);
+}
+
+private
+void near set_mode(n)
+BYTE n;
+{
+  union REGS vr;
+
+  vr.h.ah = 0x00;
+  vr.h.al = n;
+  intr(VIDEO, &vr);
+}
+
+#define gotoxy(x,y)    set_cur((x)<<8|((y)&0xff))
+#define cur_mov(x,y)   set_cur((C_X=(x))<<8|((C_Y=(y))&0xff))
+
+private
+void near wherexy( x, y)
+BYTE *x, *y;
+{
+  register WORD xy;
+
+  xy = get_cur();
+  *x = xy>>8;
+  *y = xy&0xff;
+}
+
+#define wherex()       C_X
+#define wherey()       C_Y
+
+void near scr_win(no, ulr, ulc, lrr, lrc)
+int no;
+BYTE ulr, ulc, lrr, lrc;
+{
+  union REGS vr;
+
+  if (no >= 0)
+     vr.h.ah = 0x06;
+  else {
+     vr.h.ah = 0x07;
+     no = - no;
+  }
+  vr.h.al = no;
+  vr.x.cx = ulr<<8 | ulc;
+  vr.x.dx = lrr<<8 | lrc;
+  vr.h.bh = C_ATTR;
+  intr(VIDEO, &vr);
+}
+
+BYTE chpl()
+{
+  union REGS vr;
+
+  vr.h.ah = 0x0f;
+  intr(VIDEO, &vr);
+  return vr.h.ah;
+}
+
+void near
+clr_page()
+{
+       scr_win(0, 0, 0, LPP-1, CHPL-1);
+       gotoxy(C_X = 0, C_Y = 0);
+}
+
+private
+void near cur_right()
+{
+   if (C_Y < CHPL-1)
+      C_Y++;
+   gotoxy(C_X, C_Y);
+}
+
+private
+void near cur_up()
+{
+   if (C_X)
+      C_X--;
+   gotoxy(C_X, C_Y);
+}
+
+private
+void near cur_left()
+{
+   if (C_Y)
+      C_Y--;
+   gotoxy(C_X, C_Y);
+}
+
+private
+void near cur_down()
+{
+   if (C_X < LPP-1)
+      C_X++;
+   gotoxy(C_X, C_Y);
+}
+
+private
+void near ch_out(c, n)
+BYTE c, n;
+{
+  union REGS vr;
+
+  vr.h.ah = 0x09;
+  vr.h.al = c;
+  vr.h.bl = C_ATTR;
+  vr.h.bh = CUR_PAGE;
+  vr.x.cx = n;
+  intr(VIDEO, &vr);
+}
+
+#define wrch(c)                ch_out((c), 1), cur_advance()
+
+#define home_cur()     gotoxy(C_X = 0, C_Y = 0)
+
+void near
+clr_eoln()
+{
+       ch_out(' ', CHPL-wherey());
+}
+
+private
+void near clr_eop()
+{
+  clr_eoln();
+  scr_win(LPP-1-wherex(), wherex()+1, 0, LPP-1, CHPL-1);
+}
+
+void init_43()
+{
+   BYTE far *info = (BYTE far *) 0x487;
+   WORD far *CRTC = (WORD far *) 0x463;
+   union REGS vr;
+   WORD cur;
+
+   CUR_PAGE = cur_page();
+   CHPL = chpl();
+   LPP = lpp();
+
+   if (get_mode()!=3)
+      set_mode(3);
+   cur = get_cur();
+
+   vr.x.ax = 0x1112;
+   vr.h.bl = 0;
+   intr(VIDEO, &vr);
+
+   *info |= 1;
+   vr.x.ax = 0x0100;
+   vr.h.bh = 0;
+   vr.x.cx = 0x0600;
+   intr(VIDEO, &vr);
+
+   outp(*CRTC, 0x14);
+   outp(*CRTC+1, 0x07);
+
+   vr.x.ax = 0x1200;
+   vr.h.bl = 0x20;
+   intr(VIDEO, &vr);
+
+   LPP = lpp();
+
+   set_cur(cur);
+   wherexy(&C_X, &C_Y);
+}
+
+void reset_43()
+{
+   BYTE far *info = (BYTE far *) 0x487;
+   WORD far *CRTC = (WORD far *) 0x463;
+   union REGS vr;
+
+   set_mode(3);
+
+   *info &= 128;
+   vr.x.ax = 0x0100;
+   vr.h.bh = 0x0607;
+   vr.x.cx = 0x0607;
+   intr(VIDEO, &vr);
+
+   outp(*CRTC, 0x14);
+   outp(*CRTC+1, 13);
+
+}
+
+#define scr_up()               scr_win(1, 0, 0, LPP-1, CHPL-1)
+#define back_space()   cur_left()
+
+private
+void near line_feed()
+{
+   if (++C_X > LPP-1) {
+      C_X = LPP-1;
+      scr_up();
+   }
+   gotoxy(C_X, C_Y);
+}
+
+#define BELL_P 0x61                    /* speaker */
+#define BELL_D 0x2dc                   /* 550 hz  */
+#define TIME_P 0x40                    /* timer   */
+#define TINI   182                     /* 10110110b timer initialization */
+
+void dobell(x)
+{
+   unsigned int n = 0x8888;
+   int orgval;
+
+   outp(TIME_P+3, TINI);
+   outp(TIME_P+2, BELL_D&0xff);
+   outp(TIME_P+2, BELL_D>>8);
+   orgval = inp(BELL_P);
+   outp(BELL_P, orgval|3);             /* turn speaker on  */
+   while (--n > 0)
+       outp(BELL_P, orgval);
+}
+
+#define carriage_return()      gotoxy(wherex(), C_Y = 0)
+
+private
+void near cur_advance()
+{
+   if (++C_Y > CHPL-1) {
+      C_Y = 0;
+      if (++C_X > LPP-1) {
+        scr_up();
+        C_X = LPP-1;
+      }
+   }
+   gotoxy(C_X, C_Y);
+}
+
+void init_term()
+{
+   if (lpp() == 43)
+      reset_43();
+   CUR_PAGE = cur_page();
+   CHPL = chpl();
+   LPP = lpp();
+   wherexy(&C_X, &C_Y);
+}
+
+void near normfun();
+
+void write_em(s)
+char *s;
+{
+  while (*s)
+       normfun(*s++);
+}
+
+void write_emif(s)
+char *s;
+{
+  if (s)
+        write_em(s);
+}
+
+void write_emc(s, n)
+char *s;
+int n;
+{
+   while (n--)
+        normfun(*s++);
+}
+
+void near normfun(c)
+char c;
+{
+       switch (c) {
+       case 10: line_feed(); break;
+       case 13: carriage_return(); break;
+       case  8: back_space(); break;
+       case  7: dobell(0); break;
+       case  0: break;
+       default: wrch(c);
+       }
+}
+
+#endif /* IBMPC */
+
+#ifdef IBMPC
+
+/* No cursor optimization on an IBMPC, this simplifies things a lot.
+   Think about it: it would be silly!
+ */
+
+int    phystab = 8;
+
+void
+Placur(line, col)
+{
+       cur_mov(line, col);
+       CapCol = col;
+       CapLine = line;
+}
+
+void
+SO_on()
+{
+       if (Mdcolor)
+               setcolor(Mdcolor&0xf, Mdcolor>>4);
+       else
+               setcolor(Bgcolor, Fgcolor);
+}
+
+void
+SO_off()
+{
+   setcolor(Fgcolor, Bgcolor);
+}
+
+extern bool EGA;
+
+void
+
+UnsetTerm(foo)
+char *foo;
+{
+  extern int ILI;
+
+  Placur(ILI, 0);
+  clr_eoln();
+  if (EGA)
+        reset_43();
+}
+
+
+void
+ResetTerm()
+{
+       if (EGA)
+          init_43();
+       else
+          init_term();
+
+       do_sgtty();             /* this is so if you change baudrate or stuff
+                                  like that, JOVE will notice. */
+       ttyset(ON);
+}
+
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/portsrv.c b/usr/src/contrib/jove-4.14.6/portsrv.c
new file mode 100644 (file)
index 0000000..e974104
--- /dev/null
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* This is a server for jove sub processes.  By the time we get here, our
+   standard output goes to jove's process input. */
+
+#include "jove.h"
+
+#ifdef PIPEPROCS       /* the whole file! */
+
+#include <signal.h>
+#include <sys/ioctl.h>
+#include "wait.h"
+
+private struct header {
+       int     pid;
+       int     nbytes;
+       char    buf[512];
+} header;
+
+private int    tty_fd;
+
+#define HEADSIZE       ((sizeof header.pid) + sizeof (header.nbytes))
+
+private void
+proc_write(ptr, n)
+UnivConstPtr   ptr;
+size_t n;
+{
+       (void) write(1, ptr, n);
+}
+
+private void
+read_pipe(fd)
+int    fd;
+{
+       register size_t n;
+
+       while ((header.nbytes = read(fd, (UnivPtr) header.buf, sizeof header.buf)) > 0) {
+               n = HEADSIZE + header.nbytes;
+               proc_write((UnivConstPtr) &header, n);
+       }
+}
+
+private void
+proc_error(str)
+char   *str;
+{
+       header.pid = getpid();
+       header.nbytes = strlen(str);
+       strcpy(header.buf, str);
+       proc_write((UnivConstPtr) &header, header.nbytes + HEADSIZE);
+       write(tty_fd, str, strlen(str));
+       exit(-2);
+}
+
+/* ARGSUSED */
+int
+main(argc, argv)
+int    argc;
+char   *argv[];
+{
+       int     p[2];
+       int     pid;
+
+       if (pipe(p) == -1)
+               proc_error("Cannot pipe jove portsrv.\n");
+
+       switch (pid = fork()) {
+       case -1:
+               proc_error("portsrv: cannot fork.\n");
+               /*NOTREACHED*/
+
+       case 0:
+               /* We'll intercept childs output in p[0] */
+               (void) dup2(p[1], 1);
+               (void) dup2(p[1], 2);
+               (void) close(p[0]);
+               (void) close(p[1]);
+
+               (void) setpgrp(getpid(), getpid());
+               execv(argv[1], (const char **) &argv[2]);
+               _exit(-4);
+               /*NOTREACHED*/
+
+       default:
+               (void) close(0);
+               tty_fd = open("/dev/tty", 1);
+
+               (void) signal(SIGINT, SIG_IGN);
+               (void) signal(SIGQUIT, SIG_IGN);
+               (void) close(p[1]);
+
+               /* tell jove the pid of the real child as opposed to us */
+               header.pid = getpid();
+               header.nbytes = sizeof (int);
+               *(int *) header.buf = pid;
+               (void) write(1, (char *) &header, sizeof pid + HEADSIZE);
+
+               /* read proc's output and send it to jove */
+               read_pipe(p[0]);
+
+               /* received EOF - wait for child to die and then exit
+                  ourself in the same way so that JOVE knows how the
+                  child died.  This is sort of a kludge, but the alternative
+                  is to write the childs status to JOVE, which seems sorta
+                  yucky, too.
+
+                  Actually, 4 or 5 years later I like that idea much better,
+                  so remind me to implement it that way when I get a chance.
+
+                  7-23-89  Gee thanks, whoever implemented this for me! */
+
+               (void) close(p[0]);
+               header.pid = getpid();
+               header.nbytes = EOF;    /* tell jove we are finished */
+               /* try to exit like our child did ... */
+               {
+                       union wait      status;
+
+                       do ; while (wait(&status) != pid);
+                       *(int *) header.buf = status.w_status;
+               }
+               (void) write(1, (UnivConstPtr) &header, HEADSIZE + sizeof (int));
+       }
+       return 0;
+}
+
+#else  /* !PIPEPROCS */
+int
+main()
+{
+       return 0;
+}
+#endif /* !PIPEPROCS */
diff --git a/usr/src/contrib/jove-4.14.6/proc.c b/usr/src/contrib/jove-4.14.6/proc.c
new file mode 100644 (file)
index 0000000..62ab726
--- /dev/null
@@ -0,0 +1,868 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+#include "fp.h"
+#include "re.h"
+#include "termcap.h"
+#include "disp.h"
+#include "rec.h"
+
+#include <signal.h>
+#ifdef STDARGS
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+#ifdef MSDOS
+# include <io.h>
+# include <process.h>
+# include <sys/stat.h>
+#endif
+
+private void
+       DoShell proto((char *, char *)),
+       com_finish proto((int, char *));
+
+long   SigMask = 0;
+
+/* This disgusting RE search string parses output from the GREP
+   family, from the pdp11 compiler, pcc, and lint.  Jay (HACK)
+   Fenlasen changed this to work for the lint errors. */
+char   ErrFmtStr[256] = "^\\{\",\\}\\([^:\"( \t]*\\)\\{\"\\, line ,:,(\\} *\\([0-9][0-9]*\\)[:)]\
+\\|::  *\\([^(]*\\)(\\([0-9]*\\))$\
+\\|( \\([^(]*\\)(\\([0-9]*\\)) ),";
+
+struct error {
+       Buffer          *er_buf;        /* Buffer error is in */
+       Line            *er_mess,       /* Actual error message */
+                       *er_text;       /* Actual error */
+       int             er_char;        /* char pos of error */
+       struct error    *er_prev,       /* List of errors */
+                       *er_next;
+};
+
+private struct error   *cur_error = NULL,
+               *errorlist = NULL;
+Buffer         *perr_buf = NULL;       /* Buffer with error messages */
+
+bool   WtOnMk = ON;            /* Write the modified files when we make */
+
+/* Eliminate any error records that contain dangling references to Lines.
+ * We only eliminate error structs when either referent is recycled.
+ * If it deleted, we keep it (dormant) in case it will be pasted back
+ * into the same buffer.
+ */
+
+void
+ChkErrorLines()
+{
+       register struct error   *e;
+       struct error    *prev = NULL;
+
+       for (e = errorlist; e != NULL; ) {
+               struct error    *next = e->er_next;
+
+               if (e->er_mess->l_dline == NULL_DADDR
+               || e->er_text->l_dline == NULL_DADDR)
+               {
+                       /* dangling reference: delete */
+                       if (prev == NULL)
+                               errorlist = next;
+                       else
+                               prev->er_next = next;
+                       if (next != NULL)
+                               next->er_prev = prev;
+                       if (cur_error == e)
+                               cur_error = next;
+                       free((UnivPtr)e);
+               } else {
+                       prev = e;
+               }
+               e = next;
+       }
+}
+
+/* Add an error to the end of the list of errors.  This is used for
+   parse-{C,LINT}-errors and for the spell-buffer command */
+
+private struct error *
+AddError(laste, errline, buf, line, charpos)
+struct error   *laste;
+Line   *errline,
+       *line;
+Buffer *buf;
+int    charpos;
+{
+       struct error    *new = (struct error *) emalloc(sizeof *new);
+
+       new->er_prev = laste;
+       if (laste)
+               laste->er_next = new;
+       else {
+               if (errorlist)          /* Free up old errors */
+                       ErrFree();
+               cur_error = errorlist = new;
+       }
+       laste = new;
+       new->er_next = NULL;
+       new->er_buf = buf;
+       new->er_text = line;
+       new->er_char = charpos;
+       new->er_mess = errline;
+
+       return new;
+}
+
+void
+get_FL_info(fname, lineno)
+char   *fname,
+       *lineno;
+{
+       putmatch(1, fname, (size_t)FILESIZE);
+       putmatch(2, lineno, (size_t)FILESIZE);
+
+       /* error had lineno followed fname, so switch the two */
+       if (!jisdigit(lineno[0])) {
+               char    tmp[FILESIZE];
+
+               strcpy(tmp, lineno);
+               strcpy(lineno, fname);
+               strcpy(fname, tmp);
+       }
+}
+
+/* Free up all the errors */
+
+void
+ErrFree()
+{
+       register struct error   *ep;
+
+       for (ep = errorlist; ep != NULL; ep = ep->er_next)
+               free((UnivPtr) ep);
+       errorlist = cur_error = NULL;
+}
+
+/* Parse errors of the form specified in ErrFmtStr in the current
+   buffer.  Do a show error of the first error.  This is neat because this
+   will work for any kind of output that prints a file name and a line
+   number on the same line. */
+
+void
+ErrParse()
+{
+       struct RE_block re_blk;
+       Bufpos  *bp;
+       char    fname[FILESIZE],
+               lineno[FILESIZE];
+       int     lnum,
+               last_lnum = -1;
+       struct error    *ep = NULL;
+       Buffer  *buf,
+               *lastb = NULL;
+       Line    *err_line;
+
+       ErrFree();              /* This is important! */
+       ToFirst();
+       perr_buf = curbuf;
+       REcompile(ErrFmtStr, YES, &re_blk);
+       /* Find a line with a number on it. */
+       while ((bp = docompiled(FORWARD, &re_blk)) != NULL) {
+               SetDot(bp);
+               get_FL_info(fname, lineno);
+               buf = do_find((Window *)NULL, fname, YES);
+               if (buf != lastb) {
+                       lastb = buf;
+                       last_lnum = -1;         /* signals new file */
+                       err_line = buf->b_first;
+               }
+               (void) chr_to_int(lineno, 10, NO, &lnum);
+               if (lnum == last_lnum)  /* one error per line is nicer */
+                       continue;
+               if (last_lnum == -1)
+                       last_lnum = 1;  /* that's where we really are */
+               err_line = next_line(err_line, lnum - last_lnum);
+               ep = AddError(ep, curline, buf, err_line, 0);
+               last_lnum = lnum;
+       }
+       if (cur_error != NULL)
+               ShowErr();
+}
+
+private void
+NeedErrors()
+{
+       if (cur_error == NULL)
+               complain("No errors!");
+}
+
+private bool
+ErrorHasReferents()
+{
+       return inlist(cur_error->er_buf->b_first, cur_error->er_text)
+               && inlist(perr_buf->b_first, cur_error->er_mess);
+}
+
+/* Go the the next error, if there is one.  Put the error buffer in
+   one window and the buffer with the error in another window.
+   It checks to make sure that the error actually exists. */
+
+private void
+ToError(forward)
+bool   forward;
+{
+       register struct error   *e = cur_error;
+       int     num = arg_value();
+
+       NeedErrors();
+       if ((forward? e->er_next : e->er_prev) == NULL)
+               complain("You're at the %s error.", forward ? "last" : "first");
+       while (--num >= 0 || !ErrorHasReferents()) {
+               e = forward ? e->er_next : e->er_prev;
+               if (e == NULL)
+                       break;
+               cur_error = e;
+       }
+       ShowErr();
+}
+
+void
+NextError()
+{
+       ToError(TRUE);
+}
+
+void
+PrevError()
+{
+       ToError(FALSE);
+}
+
+int    EWSize = 20;    /* percentage of screen the error window
+                          should be */
+
+private void
+set_wsize(wsize)
+int    wsize;
+{
+       wsize = (LI * wsize) / 100;
+       if (wsize >= 1 && !one_windp())
+               WindSize(curwind, wsize - (curwind->w_height - 1));
+}
+
+/* Show the current error, i.e. put the line containing the error message
+   in one window, and the buffer containing the actual error in another
+   window. */
+
+void
+ShowErr()
+{
+       Window  *err_wind,
+               *buf_wind;
+
+       NeedErrors();
+       if (!ErrorHasReferents()) {
+               rbell();
+               return;
+       }
+       err_wind = windbp(perr_buf);
+       buf_wind = windbp(cur_error->er_buf);
+
+       if (err_wind && !buf_wind) {
+               SetWind(err_wind);
+               pop_wind(cur_error->er_buf->b_name, NO, -1);
+               buf_wind = curwind;
+       } else if (!err_wind && buf_wind) {
+               SetWind(buf_wind);
+               pop_wind(perr_buf->b_name, NO, -1);
+               err_wind = curwind;
+       } else if (!err_wind && !buf_wind) {
+               pop_wind(perr_buf->b_name, NO, -1);
+               err_wind = curwind;
+               pop_wind(cur_error->er_buf->b_name, NO, -1);
+               buf_wind = curwind;
+       }
+
+       /* Put the current error message at the top of its Window */
+       SetWind(err_wind);
+       SetLine(cur_error->er_mess);
+       SetTop(curwind, (curwind->w_line = cur_error->er_mess));
+       set_wsize(EWSize);
+
+       /* now go to the the line with the error in the other window */
+       SetWind(buf_wind);
+       DotTo(cur_error->er_text, cur_error->er_char);
+}
+
+char   ShcomBuf[LBSIZE];
+
+/* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c"
+   will return the buffer name "fgrep".  */
+
+char *
+MakeName(command)
+char   *command;
+{
+       static char     bnm[50];
+       register char   *cp = bnm,
+                       c;
+
+       do ; while ((c = *command++) != '\0' && (c == ' ' || c == '\t'));
+       do {
+               *cp++ = c;
+       } while ((c = *command++) != '\0' && (c != ' ' && c != '\t'));
+       *cp = '\0';
+       strcpy(bnm, basename(bnm));
+
+       return bnm;
+}
+
+/* Run make, first writing all the modified buffers (if the WtOnMk flag is
+   on), parse the errors, and go the first error. */
+
+private char   make_cmd[LBSIZE] = "make";
+
+void
+MakeErrors()
+{
+       Window  *old = curwind;
+       int     status;
+       bool    compilation;
+
+       if (WtOnMk)
+               put_bufs(FALSE);
+       /* When we're not doing make or cc (i.e., the last command
+          was probably a grep or something) and the user just types
+          C-X C-E, he probably (possibly, hopefully, usually (in my
+          case)) doesn't want to do the grep again but rather wants
+          to do a make again; so we ring the bell and insert the
+          default command and let the person decide. */
+
+       compilation = (sindex("make", make_cmd) || sindex("cc", make_cmd));
+       if (is_an_arg() || !compilation) {
+               if (!compilation) {
+                       rbell();
+                       Inputp = make_cmd;      /* insert the default for the user */
+               }
+               null_ncpy(make_cmd, ask(make_cmd, "Compilation command: "),
+                               sizeof (make_cmd) - 1);
+       }
+       status = UnixToBuf(MakeName(make_cmd), (char *)NULL, YES, EWSize, YES,
+               Shell, ShFlags, make_cmd, (char *)NULL);
+       com_finish(status, make_cmd);
+
+       ErrParse();
+
+       if (!cur_error)
+               SetWind(old);
+}
+
+#ifdef SPELL
+
+private void
+SpelParse(bname)
+char   *bname;
+{
+       Buffer  *buftospel,
+               *wordsb;
+       char    wordspel[100];
+       Bufpos  *bp;
+       struct error    *ep = NULL;
+
+       ErrFree();              /* This is important! */
+
+       buftospel = curbuf;
+       wordsb = buf_exists(bname);
+       perr_buf = wordsb;      /* This is important (buffer containing
+                                  error messages) */
+       SetBuf(wordsb);
+       ToFirst();
+       f_mess("Finding misspelled words ... ");
+       while (!lastp(curline)) {
+               swritef(wordspel, sizeof(wordspel), "\\<%s\\>", linebuf);
+               SetBuf(buftospel);
+               ToFirst();
+               while ((bp = dosearch(wordspel, FORWARD, NO)) != NULL) {
+                       SetDot(bp);
+                       ep = AddError(ep, wordsb->b_dot, buftospel,
+                                         curline, curchar);
+               }
+               SetBuf(wordsb);
+               line_move(FORWARD, 1, NO);
+       }
+       add_mess("Done.");
+       SetBuf(buftospel);
+       ShowErr();
+}
+
+void
+SpelBuffer()
+{
+       char    *Spell = "Spell",
+               com[100];
+       Window  *savewp = curwind;
+
+       if (curbuf->b_fname == NULL)
+               complain("no file name");
+       if (IsModified(curbuf))
+               SaveFile();
+       swritef(com, sizeof(com), "spell %s", curbuf->b_fname);
+       (void) UnixToBuf(Spell, (char *)NULL, YES, EWSize, YES,
+               Shell, ShFlags, com, (char *) NULL);
+       message("[Delete the irrelevant words and then type C-X C-C]");
+       ToFirst();
+       Recur();
+       SetWind(savewp);
+       SpelParse(Spell);
+}
+
+void
+SpelWords()
+{
+       char    *buftospel;
+       Buffer  *wordsb = curbuf;
+
+       if ((buftospel = ask_buf((Buffer *)NULL)) == NULL)
+               return;
+       SetBuf(do_select(curwind, buftospel));
+       SpelParse(wordsb->b_name);
+}
+
+#endif /* SPELL */
+
+void
+ShToBuf()
+{
+       char    bnm[128],
+               cmd[LBSIZE];
+
+       strcpy(bnm, ask((char *)NULL, "Buffer: "));
+       strcpy(cmd, ask(ShcomBuf, "Command: "));
+       DoShell(bnm, cmd);
+}
+
+void
+ShellCom()
+{
+       null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
+       DoShell(MakeName(ShcomBuf), ShcomBuf);
+}
+
+void
+ShNoBuf()
+{
+       int     status;
+
+       null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
+       status = UnixToBuf((char *)NULL, (char *)NULL, NO, 0, NO,
+               Shell, ShFlags, ShcomBuf,
+               curbuf->b_fname, curbuf->b_fname, (char *)NULL);
+       com_finish(status, ShcomBuf);
+}
+
+void
+Shtypeout()
+{
+       int     status;
+
+       null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
+       status = UnixToBuf((char *)NULL, (char *)NULL, YES, 0, NO,
+               Shell, ShFlags, ShcomBuf,
+               curbuf->b_fname, curbuf->b_fname, (char *)NULL);
+       if (status == 0)
+               Typeout("[%s: completed successfully]", ShcomBuf);
+       else
+               Typeout("[%s: exited (%d)]", ShcomBuf, status);
+       TOstop();
+}
+
+/* Run the shell command into `bnm'.  Empty the buffer except when we
+   give a numeric argument, in which case it inserts the output at the
+   current position in the buffer.  */
+
+private void
+DoShell(bnm, command)
+char   *bnm,
+       *command;
+{
+       Window  *savewp = curwind;
+       int     status;
+       char    *fn = pr_name(curbuf->b_fname, NO);
+
+       /* Two copies of the file name are passed to the shell:
+        * The Cshell uses the first as a definition of $1
+        * Most version of the Bourne shell use the second as a definition of $1.
+        */
+       status = UnixToBuf(bnm, (char *)NULL, YES, 0, !is_an_arg(),
+               Shell, ShFlags, command, fn, fn, (char *)NULL);
+       com_finish(status, command);
+       SetWind(savewp);
+}
+
+private void
+com_finish(status, cmd)
+int    status;
+char   *cmd;
+{
+       s_mess("[%s: ", cmd);
+       if (status == 0)
+               add_mess("completed successfully");
+       else
+               add_mess("exited (%d)", status);
+       add_mess("]");
+}
+
+#ifndef        MSDOS
+void
+dowait(pid, status)
+int    pid,
+       *status;
+{
+# ifndef       IPROCS
+
+       int     rpid;
+
+       do ; while ((rpid = wait(status)) != pid);
+# else
+
+# include "wait.h"
+
+       union wait      w;
+       int     rpid;
+
+       for (;;) {
+#  ifndef      WAIT3
+               rpid = wait2(&w.w_status, 0);
+#  else
+               rpid = wait3(&w, 0, (struct rusage *)NULL);
+#  endif
+               if (rpid == -1)
+                       break;
+               else if (rpid == pid) {
+                       if (status)
+                               *status = w.w_status;
+                       break;
+               } else
+                       kill_off(rpid, w);
+       }
+# endif        /* IPROCS */
+}
+#endif /* MSDOS */
+
+/* Run the command to bnm, erase the buffer if clobber is non-zero,
+   and redisplay if disp is non-zero.  Leaves current buffer in `bnm'
+   and leaves any windows it creates lying around.  It's up to the caller
+   to fix everything up after we're done.  (Usually there's nothing to
+   fix up.) */
+
+#ifdef STDARGS
+int
+UnixToBuf(char *bnm, char *InFName, bool disp, int wsize, bool clobber, ...)
+#else
+/*VARARGS5*/ int
+UnixToBuf(bnm, InFName, disp, wsize, clobber, va_alist)
+       char    *bnm, *InFName;
+       bool    disp;
+       int     wsize;
+       bool    clobber;
+       va_dcl
+#endif
+{
+#ifndef        MSDOS
+       int     p[2],
+               pid;
+#else  /* MSDOS */
+       char    pnbuf[FILESIZE];
+       char    *pipename;
+#endif /* MSDOS */
+       int     status;
+       bool    eof;
+       va_list ap;
+       char    *argv[32],
+               *mess;
+       File    *fp;
+       SIGRESULT       (*old_int) proto((int));
+
+       va_init(ap, clobber);
+       make_argv(argv, ap);
+       va_end(ap);
+       if (bnm != NULL && clobber == YES)
+               isprocbuf(bnm);
+       if (access(argv[0], X_OK) != 0) {
+               complain("[Couldn't access %s: %s]", argv[0], strerror(errno));
+               /* NOTREACHED */
+       }
+       if (disp) {
+               if (bnm != NULL) {
+                       message("Starting up...");
+                       pop_wind(bnm, clobber, clobber ? B_PROCESS : B_FILE);
+                       set_wsize(wsize);
+                       redisplay();
+               } else {
+                       TOstart(argv[0], TRUE);
+                       Typeout("Starting up...");
+               }
+       }
+       /* Now I will attempt to describe how I deal with signals during
+          the execution of the shell command.  My desire was to be able
+          to interrupt the shell command AS SOON AS the window pops up.
+          So, if we have BSD_SIGS (i.e., the new signal mechanism) I
+          hold SIGINT, meaning if we interrupt now, we will eventually
+          see the interrupt, but not before we are ready for it.  We
+          fork, the child releases the interrupt, it then sees the
+          interrupt, and so exits.  Meanwhile the parent ignores the
+          signal, so if there was a pending one, it's now lost.
+
+          With no BSD_SIGS, the best behavior you can expect is, when
+          you type ^] too very quickly after the window pops up, it may
+          be ignored.  The behavior BEFORE was that it would interrupt
+          JOVE and then you would have to continue JOVE and wait a
+          little while longer before trying again.  Now that is fixed,
+          in that you just have to type it twice. */
+
+#ifndef        MSDOS
+# ifdef        IPROCS
+       SigHold(SIGCHLD);
+# endif
+# ifdef        BSD_SIGS
+       SigHold(SIGINT);
+# else
+       old_int = signal(SIGINT, SIG_IGN),
+# endif
+       dopipe(p);
+
+#ifdef VFORK
+       pid = vfork();
+#else
+       pid = fork();
+#endif
+
+       if (pid == -1) {
+               pipeclose(p);
+               complain("[Fork failed: %s]", strerror(errno));
+       }
+       if (pid == 0) {
+# ifdef        VFORK
+               /*
+                * We want to release SIGCHLD and SIGINT in the child,
+                * but we can't use SigRelse because that would change
+                * Jove's copy of the SigMask variable (because we're in
+                * a vfork).  So we simply set set the mask directly.
+                * There are several other forks in Jove, but this is
+                * the only one we execute often enough to make it worth
+                * using a vfork.  This assumes a system with vfork also
+                * has BSD signals!
+                */
+               (void) signal(SIGINT, SIG_DFL);
+               (void) sigsetmask(SigMask & ~(sigmask(SIGCHLD)|sigmask(SIGINT)));
+# else /* !VFORK */
+#  ifdef       IPROCS
+               SigRelse(SIGCHLD);   /* don't know if this matters */
+#  endif       /* IPROCS */
+               (void) signal(SIGINT, SIG_DFL);
+#  ifdef       BSD_SIGS
+               SigRelse(SIGINT);
+#  endif       /* BSD_SIGS */
+# endif        /* !VFORK */
+               (void) close(0);
+               (void) open(InFName==NULL? "/dev/null" : InFName, 0);
+               (void) close(1);
+               (void) close(2);
+               (void) dup(p[1]);
+               (void) dup(p[1]);
+               pipeclose(p);
+               jcloseall();
+               execv(argv[0], (const char **) &argv[1]);
+               raw_complain("Execl failed: %s\n", strerror(errno));
+               _exit(1);
+       }
+# ifdef        BSD_SIGS
+       old_int = signal(SIGINT, SIG_IGN);
+# endif
+       (void) close(p[1]);
+       fp = fd_open(argv[1], F_READ, p[0], iobuff, LBSIZE);
+#else  /* MSDOS */
+       {
+               int     oldi = dup(0),
+                       oldo = dup(1),
+                       olde = dup(2);
+               bool    InFailure = FALSE;
+               int     ph;
+
+               swritef(pnbuf, sizeof(pnbuf), "%s/%s", TmpFilePath, "jpXXXXXX");
+               pipename = mktemp(pnbuf);
+               if ((ph = creat(pipename, S_IWRITE|S_IREAD)) < 0)
+                       complain("cannot make pipe for filter: %s", strerror(errno));
+               close(1);
+               close(2);
+               dup(ph);
+               dup(ph);
+
+               close(0);
+               if (InFName == NULL)
+                       if (open(InFName, 0) < 0)
+                               InFailure = TRUE;
+               if (!InFailure)
+                       status = spawnv(0, argv[0], &argv[1]);
+
+               close(0);
+               close(1);
+               close(2);
+               dup(oldi);
+               dup(oldo);
+               dup(olde);
+               close(oldi);
+               close(oldo);
+               close(olde);
+
+               if (InFailure)
+                       complain("[filter input failed]");
+               if (status < 0)
+                       complain("[Spawn failed]");
+               ph = open(pipename, 0);
+               if (ph < 0)
+                       complain("[cannot reopen pipe]", strerror(errno));
+               fp = fd_open(argv[1], F_READ, ph, iobuff, LBSIZE);
+       }
+
+#endif /* MSDOS */
+       do {
+#ifndef        MSDOS
+               inIOread = YES;
+#endif
+               eof = f_gets(fp, genbuf, (size_t)LBSIZE);
+#ifndef        MSDOS
+               inIOread = NO;
+#endif
+               if (bnm != NULL) {
+                       ins_str(genbuf, YES);
+                       if (!eof)
+                               LineInsert(1);
+               } else if (disp)
+                       Typeout("%s", genbuf);
+               if (bnm != NULL && disp && fp->f_cnt <= 0) {
+#ifdef LOAD_AV
+                   {
+                       int     la = get_la();
+
+                       if (la < 200)
+                               mess = "Screaming along...";
+                       else if (la < 500)
+                               mess = "Chugging along...";
+                       else
+                               mess = "Crawling along...";
+                   }
+#else
+                       mess = "Chugging along...";
+#endif /* LOAD_AV */
+                       if (bnm != NULL) {
+                               message(mess);
+                               redisplay();
+                       }
+               }
+       } while (!eof);
+       if (disp)
+               DrawMesg(NO);
+       close_file(fp);
+#ifndef        MSDOS
+       dowait(pid, &status);
+# ifdef        BSD_SIGS
+       (void) SigRelse(SIGINT);
+# endif
+# ifdef        IPROCS
+       SigRelse(SIGCHLD);
+# endif
+#else  /* MSDOS */
+       unlink(pipename);
+       getCWD();
+#endif /* MSDOS */
+       (void) signal(SIGINT, old_int);
+       return status;
+}
+
+/* Send the current region to CMD and insert the output from the
+   command into OUT_BUF. */
+
+private void
+RegToUnix(outbuf, cmd)
+Buffer *outbuf;
+char   *cmd;
+{
+       Mark    *m = CurMark();
+       static char     tnambuf[FILESIZE];
+       char    *tname;
+       Window  *save_wind = curwind;
+       volatile int    status;
+       volatile int    err = NO;
+       File    *volatile fp;
+       jmp_buf sav_jmp;
+
+       swritef(tnambuf, sizeof(tnambuf), "%s/%s", TmpFilePath, "jfXXXXXX");
+       tname = mktemp(tnambuf);
+       fp = open_file(tname, iobuff, F_WRITE, YES, YES);
+       push_env(sav_jmp);
+       if (setjmp(mainjmp) == 0) {
+               putreg(fp, m->m_line, m->m_char, curline, curchar, YES);
+               DelReg();
+               f_close(fp);
+               status = UnixToBuf(outbuf->b_name, tname, NO, 0,
+                       outbuf->b_type==B_SCRATCH, Shell, ShFlags, cmd, (char *)NULL);
+       } else {
+               f_close(fp);
+               err = YES;
+       }
+       pop_env(sav_jmp);
+
+       (void) unlink(tname);
+       SetWind(save_wind);
+       if (!err)
+               com_finish(status, cmd);
+}
+
+void
+FilterRegion()
+{
+       static char     FltComBuf[LBSIZE];
+
+       null_ncpy(FltComBuf, ask(FltComBuf, ": %f (through command) "),
+               (sizeof FltComBuf) - 1);
+       RegToUnix(curbuf, FltComBuf);
+}
+
+void
+isprocbuf(bnm)
+char   *bnm;
+{
+       Buffer  *bp;
+
+       if ((bp = buf_exists(bnm)) != NULL && bp->b_type != B_PROCESS)
+               confirm("Over-write buffer %s? ", bnm);
+}
+
+#ifdef MSDOS
+
+/* ??? how many of these includes are redundant?  Are they needed in RegToUnix()? */
+
+#include <dos.h>
+#include <fcntl.h>
+
+/* ??? Set the DOS path separator character to '/' from '\\' */
+
+char
+switchar()
+{
+  union REGS regs;
+
+  regs.h.ah = 0x37;
+  regs.h.al = 0;
+  intdos(&regs, &regs);
+  return regs.h.dl;
+}
+#endif /* MSDOS */
diff --git a/usr/src/contrib/jove-4.14.6/re.c b/usr/src/contrib/jove-4.14.6/re.c
new file mode 100644 (file)
index 0000000..d7af82d
--- /dev/null
@@ -0,0 +1,974 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* search package */
+
+#include "jove.h"
+#include "re.h"
+#include "ctype.h"
+
+private void
+       search proto((int, bool, bool));
+
+private int
+       do_comp proto((struct RE_block *,int));
+
+private char
+       searchstr[128];         /* global search string */
+
+char   rep_search[128],        /* replace search string */
+       rep_str[128];           /* contains replacement string */
+
+bool   CaseIgnore = OFF,       /* ignore case? */
+       WrapScan = OFF,         /* wrap at end of buffer? */
+       UseRE = OFF;            /* use regular expressions */
+
+#define cind_cmp(a, b) (CharUpcase(a) == CharUpcase(b))
+
+private int    REpeekc;
+private char   *REptr;
+
+private int
+REgetc()
+{
+       int     c;
+
+       if ((c = REpeekc) != -1)
+               REpeekc = -1;
+       else if (*REptr)
+               c = *REptr++;
+       else
+               c = '\0';
+
+       return c;
+}
+
+#define STAR   01      /* Match any number of last RE. */
+#define AT_BOL 2       /* ^ */
+#define AT_EOL 4       /* $ */
+#define AT_BOW 6       /* \< */
+#define AT_EOW 8       /* \> */
+#define OPENP  10      /* \( */
+#define CLOSEP 12      /* \) */
+#define CURLYB 14      /* \{ */
+
+#define NOSTR  14      /* Codes <= NOSTR can't be *'d. */
+
+#define ANYC   (NOSTR+2)               /* . */
+#define NORMC  (ANYC+2)                /* normal character */
+#define CINDC  (NORMC+2)               /* case independent character */
+#define ONE_OF (CINDC+2)               /* [xxx] */
+#define NONE_OF        (ONE_OF+2)      /* [^xxx] */
+#define BACKREF        (NONE_OF+2)     /* \# */
+#define EOP    (BACKREF+2)     /* end of pattern */
+
+/* ONE_OF/NONE_OF is represented as a bit vector.
+ * These symbols parameterize the representation.
+ */
+
+#define        BYTESIZE        8
+#define        SETSIZE         (NCHARS / BYTESIZE)
+#define        SETBYTE(c)      ((c) / BYTESIZE)
+#define        SETBIT(c)       (1 << ((c) % BYTESIZE))
+
+#define NPAR   10      /* [0-9] - 0th is the entire matched string, i.e. & */
+private char   *comp_ptr,
+               **alt_p,
+               **alt_endp;
+
+void
+REcompile(pattern, re, re_blk)
+char   *pattern;
+bool   re;
+struct RE_block        *re_blk;
+{
+       REptr = pattern;
+       REpeekc = -1;
+       comp_ptr = re_blk->r_compbuf;
+       alt_p = re_blk->r_alternates;
+       alt_endp = alt_p + NALTS;
+       *alt_p++ = comp_ptr;
+       re_blk->r_nparens = 0;
+       (void) do_comp(re_blk, re ? OKAY_RE : NORM);
+       *alt_p = NULL;
+
+       re_blk->r_anchored = NO;
+       re_blk->r_firstc = '\0';
+       /* do a little post processing */
+       if (re_blk->r_alternates[1] == NULL) {
+               char    *p;
+
+               p = re_blk->r_alternates[0];
+               for (;;) {
+                       switch (*p) {
+                       case OPENP:
+                       case CLOSEP:
+                               p += 2;
+                               continue;
+
+                       case AT_BOW:
+                       case AT_EOW:
+                               p += 1;
+                               continue;
+
+                       case AT_BOL:
+                               re_blk->r_anchored = YES;
+                               /* don't set firstc -- won't work */
+                               break;
+
+                       case NORMC:
+                       case CINDC:
+                               re_blk->r_firstc = CharUpcase(p[2]);
+                               break;
+
+                       default:
+                               break;
+                       }
+                       break;
+               }
+       }
+}
+
+/* compile the pattern into an internal code */
+
+private int
+do_comp(re_blk, kind)
+struct RE_block        *re_blk;
+int    kind;
+{
+       char    *this_verb,
+               *prev_verb,
+               *start_p,
+               *comp_endp;
+       int     parens[NPAR],
+               *parenp,
+               c,
+               ret_code;
+
+       parenp = parens;
+       this_verb = NULL;
+       ret_code = 1;
+       comp_endp = &re_blk->r_compbuf[COMPSIZE - 6];
+
+       /* wrap the whole expression around (implied) parens */
+       if (kind == OKAY_RE) {
+               *comp_ptr++ = OPENP;
+               *comp_ptr++ = re_blk->r_nparens;
+               *parenp++ = re_blk->r_nparens++;
+       }
+
+       start_p = comp_ptr;
+
+       while ((c = REgetc()) != '\0') {
+               if (comp_ptr > comp_endp) {
+toolong:
+                       complain("Search string too long/complex.");
+               }
+               prev_verb = this_verb;
+               this_verb = comp_ptr;
+
+               if (kind == NORM && strchr(".[*", c) != NULL)
+                       goto defchar;
+               switch (c) {
+               case '\\':
+                       switch (c = REgetc()) {
+                       case '\0':
+                               complain("[Premature end of pattern]");
+                               /*NOTREACHED*/
+
+                       case '{':
+                           {
+                               char    *wcntp;         /* word count */
+
+                               *comp_ptr++ = CURLYB;
+                               wcntp = comp_ptr;
+                               *comp_ptr++ = 0;
+                               for (;;) {
+                                       int     comp_val;
+                                       char    *comp_len;
+
+                                       comp_len = comp_ptr++;
+                                       comp_val = do_comp(re_blk, IN_CB);
+                                       *comp_len = comp_ptr - comp_len;
+                                       (*wcntp) += 1;
+                                       if (comp_val == 0)
+                                               break;
+                               }
+                               break;
+                           }
+
+                       case '}':
+                               if (kind != IN_CB)
+                                       complain("Unexpected \\}.");
+                               ret_code = 0;
+                               goto outahere;
+
+                       case '(':
+                               if (re_blk->r_nparens >= NPAR)
+                                       complain("Too many ('s; max is %d.", NPAR);
+                               *comp_ptr++ = OPENP;
+                               *comp_ptr++ = re_blk->r_nparens;
+                               *parenp++ = re_blk->r_nparens++;
+                               break;
+
+                       case ')':
+                               if (parenp == parens)
+                                       complain("Too many )'s.");
+                               *comp_ptr++ = CLOSEP;
+                               *comp_ptr++ = *--parenp;
+                               break;
+
+                       case '|':
+                               if (alt_p >= alt_endp)
+                                       complain("Too many alternates; max %d.", NALTS);
+                               /* close off previous alternate */
+                               *comp_ptr++ = CLOSEP;
+                               *comp_ptr++ = *--parenp;
+                               *comp_ptr++ = EOP;
+                               *alt_p++ = comp_ptr;
+
+                               /* start a new one */
+                               re_blk->r_nparens = 0;
+                               *comp_ptr++ = OPENP;
+                               *comp_ptr++ = re_blk->r_nparens;
+                               *parenp++ = re_blk->r_nparens++;
+                               start_p = comp_ptr;
+                               break;
+
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               *comp_ptr++ = BACKREF;
+                               *comp_ptr++ = c - '0';
+                               break;
+
+                       case '<':
+                               *comp_ptr++ = AT_BOW;
+                               break;
+
+                       case '>':
+                               *comp_ptr++ = AT_EOW;
+                               break;
+
+                       default:
+                               goto defchar;
+                       }
+                       break;
+
+               case ',':
+                       if (kind != IN_CB)
+                               goto defchar;
+                       goto outahere;
+
+               case '.':
+                       *comp_ptr++ = ANYC;
+                       break;
+
+               case '^':
+                       if (comp_ptr == start_p) {
+                               *comp_ptr++ = AT_BOL;
+                               break;
+                       }
+                       goto defchar;
+
+               case '$':
+                       if ((REpeekc = REgetc()) != '\0' && REpeekc != '\\')
+                               goto defchar;
+                       *comp_ptr++ = AT_EOL;
+                       break;
+
+               case '[':
+                   {
+                       int     chrcnt;
+
+                       *comp_ptr++ = ONE_OF;
+                       if (comp_ptr + SETSIZE >= comp_endp)
+                               goto toolong;
+                       byte_zero(comp_ptr, (size_t) SETSIZE);
+                       if ((REpeekc = REgetc()) == '^') {
+                               *this_verb = NONE_OF;
+                               /* Get it for real this time. */
+                               (void) REgetc();
+                       }
+                       chrcnt = 0;
+                       while ((c = REgetc()) != ']' && c != '\0') {
+                               if (c == '\\') {
+                                       c = REgetc();
+                                       if (c == '\0')
+                                               break;
+                               } else if ((REpeekc = REgetc()) == '-') {
+                                       int     i;
+
+                                       i = c;
+                                       (void) REgetc();     /* reread '-' */
+                                       c = REgetc();
+                                       if (c == '\0')
+                                               break;
+                                       while (i < c) {
+                                               comp_ptr[SETBYTE(i)] |= SETBIT(i);
+                                               i += 1;
+                                       }
+                               }
+                               comp_ptr[SETBYTE(c)] |= SETBIT(c);
+                               chrcnt += 1;
+                       }
+                       if (c == '\0')
+                               complain("Missing ].");
+                       if (chrcnt == 0)
+                               complain("Empty [].");
+                       comp_ptr += SETSIZE;
+                       break;
+                   }
+
+               case '*':
+                       if (prev_verb == NULL || *prev_verb <= NOSTR || (*prev_verb&STAR)!=0)
+                               goto defchar;
+
+                       if (*prev_verb == NORMC || *prev_verb == CINDC) {
+                               char    lastc = comp_ptr[-1];
+
+                               /* The * operator applies only to the
+                                * previous character.  Since we were
+                                * building a string-matching command
+                                * (NORMC or CINDC), we must split it
+                                * up and work with the last character.
+                                *
+                                * Note that the STARed versions of these
+                                * commands do not operate on strings, and
+                                * so do not need or have character counts.
+                                */
+
+                               if (prev_verb[1] == 1) {
+                                       /* Only one char in string:
+                                        * delete old command.
+                                        */
+                                       this_verb = prev_verb;
+                               } else {
+                                       /* Several chars in string:
+                                        * strip off the last.
+                                        * New verb is derived from old.
+                                        */
+                                       prev_verb[1] -= 1;
+                                       this_verb -= 1;
+                                       *this_verb = *prev_verb;
+                               }
+                               comp_ptr = this_verb + 1;
+                               *comp_ptr++ = lastc;
+                       } else {
+                               /* This command is just the previous one,
+                                * whose verb we will modify.
+                                */
+                               this_verb = prev_verb;
+                       }
+                       *this_verb |= STAR;
+                       break;
+               default:
+defchar:
+                       if ((prev_verb == NULL) ||
+                           !(*prev_verb == NORMC || *prev_verb == CINDC)) {
+                               /* create new string command */
+                               *comp_ptr++ = (CaseIgnore) ? CINDC : NORMC;
+                               *comp_ptr++ = 0;
+                       } else {
+                               /* merge this into previous string command */
+                               this_verb = prev_verb;
+                       }
+                       this_verb[1] += 1;
+                       *comp_ptr++ = c;
+                       break;
+               }
+       }
+outahere:
+
+       /* End of pattern, let's do some error checking. */
+       if (kind == OKAY_RE) {
+               *comp_ptr++ = CLOSEP;
+               *comp_ptr++ = *--parenp;
+       }
+       if (parenp != parens)
+               complain("Unmatched ()'s.");
+       if (kind == IN_CB && c == '\0') /* end of pattern with missing \}. */
+               complain("Missing \\}.");
+       *comp_ptr++ = EOP;
+
+       return ret_code;
+}
+
+private char   *pstrtlst[NPAR],        /* index into re_blk->r_lbuf */
+               *pendlst[NPAR],
+               *REbolp,        /* begining-of-line pointer */
+               *locrater,      /* roof of last substitution */
+               *loc1,  /* start of matched text */
+               *loc2;  /* roof of matched text */
+
+int    REbom,          /* beginning and end columns of match */
+       REeom,
+       REdelta;        /* increase in line length due to last re_dosub */
+
+private bool
+backref(n, linep)
+int    n;
+register char  *linep;
+{
+       register char   *backsp,
+                       *backep;
+
+       backsp = pstrtlst[n];
+       backep = pendlst[n];
+       while (*backsp++ == *linep++)
+               if (backsp >= backep)
+                       return YES;
+       return NO;
+}
+
+private bool
+member(comp_ptr, c, af)
+register char  *comp_ptr;
+register int   c;
+bool           af;
+{
+       if (c == '\0')
+               return NO;      /* try to match EOL always fails */
+       if (comp_ptr[SETBYTE(c)] & SETBIT(c))
+               return af;
+       return !af;
+}
+
+private bool
+REmatch(linep, comp_ptr)
+register char  *linep,
+               *comp_ptr;
+{
+       char    *first_p;
+       register int    n;
+
+       for (;;) switch (*comp_ptr++) {
+       case NORMC:
+               n = *comp_ptr++;
+               while (--n >= 0)
+                       if (*linep++ != *comp_ptr++)
+                               return NO;
+               continue;
+
+       case CINDC:     /* case independent comparison */
+               n = *comp_ptr++;
+               while (--n >= 0)
+                       if (!cind_cmp(*linep++, *comp_ptr++))
+                               return NO;
+               continue;
+
+       case EOP:
+               loc2 = linep;
+               REeom = (loc2 - REbolp);
+               return YES;     /* Success! */
+
+       case AT_BOL:
+               if (linep == REbolp && linep != locrater)
+                       continue;
+               return NO;
+
+       case AT_EOL:
+               if (*linep == '\0')
+                       continue;
+               return NO;
+
+       case ANYC:
+               if (*linep++ != '\0')
+                       continue;
+               return NO;
+
+       case AT_BOW:
+               if (linep != locrater && ismword(*linep)
+               && (linep == REbolp || !ismword(linep[-1])))
+                       continue;
+               return NO;
+
+       case AT_EOW:
+               if (linep != locrater && (*linep == '\0' || !ismword(*linep)) &&
+                   (linep != REbolp && ismword(linep[-1])))
+                       continue;
+               return NO;
+
+       case ONE_OF:
+       case NONE_OF:
+               if (member(comp_ptr, *linep++, comp_ptr[-1] == ONE_OF)) {
+                       comp_ptr += SETSIZE;
+                       continue;
+               }
+               return NO;
+
+       case OPENP:
+               pstrtlst[*comp_ptr++] = linep;
+               continue;
+
+       case CLOSEP:
+               pendlst[*comp_ptr++] = linep;
+               continue;
+
+       case BACKREF:
+               if (pstrtlst[n = *comp_ptr++] == NULL) {
+                       s_mess("\\%d was not specified.", n + 1);
+               } else if (backref(n, linep)) {
+                       linep += pendlst[n] - pstrtlst[n];
+                       continue;
+               }
+               return NO;
+
+       case CURLYB:
+           {
+               int     wcnt;
+               bool    any;
+
+               wcnt = *comp_ptr++;
+               any = NO;
+
+               while (--wcnt >= 0) {
+                       if (!any)
+                               any = REmatch(linep, comp_ptr + 1);
+                       comp_ptr += *comp_ptr;
+               }
+               if (!any)
+                       return NO;
+               linep = loc2;
+               continue;
+           }
+
+       case ANYC | STAR:
+               first_p = linep;
+               do ; while (*linep++);
+               goto star;
+
+       case NORMC | STAR:
+               first_p = linep;
+               do ; while (*comp_ptr == *linep++);
+               comp_ptr += 1;
+               goto star;
+
+       case CINDC | STAR:
+               first_p = linep;
+               do ; while (cind_cmp(*comp_ptr, *linep++));
+               comp_ptr += 1;
+               goto star;
+
+       case ONE_OF | STAR:
+       case NONE_OF | STAR:
+               first_p = linep;
+               do ; while (member(comp_ptr, *linep++, comp_ptr[-1] == (ONE_OF | STAR)));
+               comp_ptr += SETSIZE;
+               /* fall through */
+star:
+               /* linep points *after* first unmatched char.
+                * first_p points at where starred element started matching.
+                */
+               while (--linep > first_p) {
+                       if ((*comp_ptr != NORMC || *linep == comp_ptr[2]) &&
+                           REmatch(linep, comp_ptr))
+                               return YES;
+               }
+               continue;
+
+       case BACKREF | STAR:
+               first_p = linep;
+               n = *comp_ptr++;
+               while (backref(n, linep))
+                       linep += pendlst[n] - pstrtlst[n];
+               while (linep > first_p) {
+                       if (REmatch(linep, comp_ptr))
+                               return YES;
+                       linep -= pendlst[n] - pstrtlst[n];
+               }
+               continue;
+
+       default:
+               complain("RE error match (%d).", comp_ptr[-1]);
+       }
+       /* NOTREACHED */
+}
+
+private void
+REreset()
+{
+       register int    i;
+
+       for (i = 0; i < NPAR; i++)
+               pstrtlst[i] = pendlst[i] = NULL;
+}
+
+/* Index LINE at OFFSET.  If lbuf_okay is nonzero it's okay to use linebuf
+   if LINE is the current line.  This should save lots of time in things
+   like paren matching in LISP mode.  Saves all that copying from linebuf
+   to a local buffer.  substitute() is the guy who calls re_lindex with
+   lbuf_okay as NO, since the substitution gets placed in linebuf ...
+   doesn't work too well when the source and destination strings are the
+   same.  I hate all these arguments!
+
+   This code is cumbersome, repetetive for reasons of efficiency.  Fast
+   search is a must as far as I am concerned. */
+
+bool
+re_lindex(line, offset, dir, re_blk, lbuf_okay, crater)
+Line   *line;
+int    offset;
+int    dir;
+struct RE_block        *re_blk;
+int    lbuf_okay;
+int    crater; /* offset of previous substitute (or -1) */
+{
+       register char   *p;
+       register int    firstc = re_blk->r_firstc;
+       register int    anchored = re_blk->r_anchored;
+       char            **alts = re_blk->r_alternates;
+
+       REreset();
+       if (lbuf_okay) {
+               REbolp = lbptr(line);
+               if (offset == -1)
+                       offset = strlen(REbolp);        /* arg! */
+       } else {
+               REbolp = ltobuf(line, re_blk->r_lbuf);
+               if (offset == -1) {     /* Reverse search, find end of line. */
+                       offset = Jr_Len;        /* Just Read Len. */
+               }
+       }
+
+       if (anchored == YES) {
+               if (dir == FORWARD) {
+                       if (offset != 0 || crater != -1)
+                               return NO;
+               } else {
+                       offset = 0;
+               }
+       }
+
+       p = REbolp + offset;
+       locrater = REbolp + crater;
+
+       if (firstc != '\0') {
+               char    *first_alt = *alts;
+
+               if (dir == FORWARD) {
+                       while (CharUpcase(*p) != firstc || !REmatch(p, first_alt))
+                               if (*p++ == '\0')
+                                       return NO;
+               } else {
+                       while (CharUpcase(*p) != firstc || !REmatch(p, first_alt))
+                               if (--p < REbolp)
+                                       return NO;
+               }
+       } else {
+               for (;;) {
+                       register char   **altp = alts;
+
+                       while (*altp != NULL)
+                               if (REmatch(p, *altp++))
+                                       goto success;
+                       if (anchored ||
+                           (dir == FORWARD ? *p++ == '\0' : --p < REbolp))
+                               return NO;
+               }
+success:;
+       }
+       loc1 = p;
+       REbom = loc1 - REbolp;
+
+       return YES;
+}
+
+bool   okay_wrap = NO; /* Do a wrap search ... not when we're
+                          parsing errors ... */
+
+Bufpos *
+dosearch(pattern, dir, re)
+char   *pattern;
+int    dir;
+bool   re;
+{
+       Bufpos  *pos;
+       struct RE_block re_blk;         /* global re-compiled buffer */
+
+       if (bobp() && eobp())   /* Can't match!  There's no buffer. */
+               return NULL;
+
+       REcompile(pattern, re, &re_blk);
+
+       pos = docompiled(dir, &re_blk);
+       return pos;
+}
+
+Bufpos *
+docompiled(dir, re_blk)
+int dir;
+register struct RE_block       *re_blk;
+{
+       static Bufpos   ret;
+       register Line   *lp;
+       register int    offset;
+       int     we_wrapped = NO;
+
+       lsave();
+       /* Search now lsave()'s so it doesn't make any assumptions on
+          whether the the contents of curline/curchar are in linebuf.
+          Nowhere does search write all over linebuf.  However, we have to
+          be careful about what calls we make here, because many of them
+          assume (and rightly so) that curline is in linebuf. */
+
+       lp = curline;
+       offset = curchar;
+       if (dir == BACKWARD) {
+               if (bobp()) {
+                       if (okay_wrap && WrapScan)
+                               goto doit;
+                       return NULL;
+               }
+               /* here we simulate BackChar() */
+               if (bolp()) {
+                       lp = lp->l_prev;
+                       offset = length(lp);
+               } else {
+                       offset -= 1;
+               }
+       } else if (dir==FORWARD && lbptr(lp)[offset]=='\0' && !lastp(lp)) {
+               lp = lp->l_next;
+               offset = 0;
+       }
+
+       do {
+               if (re_lindex(lp, offset, dir, re_blk, YES, -1))
+                       break;
+doit:
+               lp = (dir == FORWARD) ? lp->l_next : lp->l_prev;
+               if (lp == NULL) {
+                       if (okay_wrap && WrapScan) {
+                               lp = (dir == FORWARD) ?
+                                    curbuf->b_first : curbuf->b_last;
+                               we_wrapped = YES;
+                       } else
+                                break;
+               }
+               if (dir == FORWARD)
+                       offset = 0;
+               else
+                       offset = -1;    /* signals re_lindex ... */
+       } while (lp != curline);
+
+       if (lp == curline && we_wrapped)
+               lp = NULL;
+       if (lp == NULL)
+               return NULL;
+       ret.p_line = lp;
+       ret.p_char = (dir == FORWARD) ? REeom : REbom;
+       return &ret;
+}
+
+private char *
+insert(off, endp, which)
+char   *off,
+       *endp;
+int which;
+{
+       register char   *pp;
+       register int    n;
+
+       n = pendlst[which] - pstrtlst[which];
+       pp = pstrtlst[which];
+       while (--n >= 0) {
+               *off++ = *pp++;
+               if (off >= endp)
+                       len_error(ERROR);
+       }
+       return off;
+}
+
+/* Perform the substitution.  If DELP is nonzero the matched string is
+   deleted, i.e., the substitution string is not inserted. */
+
+void
+re_dosub(re_blk, tobuf, delp)
+struct RE_block        *re_blk;
+char   *tobuf;
+int delp;
+{
+       register char   *tp,
+                       *rp;
+       char    *endp;
+
+       tp = tobuf;
+       endp = tp + LBSIZE;
+       rp = re_blk->r_lbuf;
+
+       while (rp < loc1)
+               *tp++ = *rp++;
+
+       if (!delp) {
+               register int    c;
+
+               rp = rep_str;
+               while ((c = *rp++) != '\0') {
+                       if (c == '\\') {
+                               c = *rp++;
+                               if (c >= '0' && c < re_blk->r_nparens + '0') {
+                                       tp = insert(tp, endp, c - '0');
+                                       continue;
+                               }
+                               if (c == '\0') {
+                                       *tp++ = '\\';
+                                       rp--;   /* be sure to hit again */
+                               }
+                       }
+                       *tp++ = c;
+                       if (tp >= endp)
+                               len_error(ERROR);
+               }
+       }
+       rp = loc2;
+       REdelta = -REeom;
+       REeom = tp - tobuf;
+       REdelta += REeom;
+       if (loc1==rp && *rp!='\0') {
+               /* Skip an extra character if the matched text was a null
+                * string, but don't skip over the end of line.  This is to
+                * prevent an infinite number of replacements in the same
+                * position, e.g., replace "^" with "".
+                */
+               REeom += 1;
+       }
+       loc2 = re_blk->r_lbuf + REeom;
+       while ((*tp++ = *rp++) != '\0')
+               if (tp >= endp)
+                       len_error(ERROR);
+}
+
+void
+putmatch(which, buf, size)
+int which;
+char   *buf;
+size_t size;
+{
+       *(insert(buf, buf + size, which)) = '\0';
+}
+
+void
+setsearch(str)
+char   *str;
+{
+       strcpy(searchstr, str);
+}
+
+char *
+getsearch()
+{
+       return searchstr;
+}
+
+void
+RErecur()
+{
+       char    repbuf[sizeof rep_str];
+       Mark    *m = MakeMark(curline, REbom, M_FLOATER);
+
+       message("Type C-X C-C to continue with query replace.");
+
+       byte_copy(rep_str, repbuf, sizeof rep_str);
+       Recur();
+       byte_copy(repbuf, rep_str, sizeof rep_str);
+       if (!is_an_arg())
+               ToMark(m);
+       DelMark(m);
+}
+
+void
+ForSearch()
+{
+       search(FORWARD, UseRE, YES);
+}
+
+void
+RevSearch()
+{
+       search(BACKWARD, UseRE, YES);
+}
+
+void
+FSrchND()
+{
+       search(FORWARD, UseRE, NO);
+}
+
+void
+RSrchND()
+{
+       search(BACKWARD, UseRE, NO);
+}
+
+private void
+search(dir, re, setdefault)
+int    dir;
+bool   re,
+       setdefault;
+{
+       Bufpos  *newdot;
+       char    *s;
+
+       s = ask(searchstr, ProcFmt);
+       if (setdefault)
+               setsearch(s);
+       okay_wrap = YES;
+       newdot = dosearch(s, dir, re);
+       okay_wrap = NO;
+       if (newdot == NULL) {
+               if (WrapScan)
+                       complain("No \"%s\" in buffer.", s);
+               else
+                       complain("No \"%s\" found to %s.", s,
+                                (dir == FORWARD) ? "bottom" : "top");
+       }
+       PushPntp(newdot->p_line);
+       SetDot(newdot);
+}
+
+/* Do we match PATTERN at OFFSET in BUF? */
+
+bool
+LookingAt(pattern, buf, offset)
+char   *pattern,
+       *buf;
+int offset;
+{
+       struct RE_block re_blk;
+       char    **alt = re_blk.r_alternates;
+
+       REcompile(pattern, YES, &re_blk);
+       REreset();
+       locrater = NULL;
+       REbolp = buf;
+
+       while (*alt)
+               if (REmatch(buf + offset, *alt++))
+                       return YES;
+       return NO;
+}
+
+bool
+look_at(expr)
+char   *expr;
+{
+       struct RE_block re_blk;
+
+       REcompile(expr, NO, &re_blk);
+       REreset();
+       locrater = NULL;
+       REbolp = linebuf;
+       if (REmatch(linebuf + curchar, re_blk.r_alternates[0]))
+               return YES;
+       return NO;
+}
diff --git a/usr/src/contrib/jove-4.14.6/re.h b/usr/src/contrib/jove-4.14.6/re.h
new file mode 100644 (file)
index 0000000..f1f05cd
--- /dev/null
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define NALTS          16      /* number of alternate search strings */
+#define COMPSIZE       256
+
+/* kinds of regular expression compiles */
+#define NORM   0       /* nothing special */
+#define OKAY_RE        1       /* allow regular expressions */
+#define IN_CB  2       /* in curly brace; implies OKAY_RE */
+
+struct RE_block {
+       char    r_compbuf[COMPSIZE],
+               *r_alternates[NALTS],
+               r_lbuf[LBSIZE];
+       int     r_nparens,
+               r_firstc,
+               r_anchored;
+};
+
+extern char    rep_search[128],        /* replace search string */
+               rep_str[128];           /* contains replacement string */
+
+extern int     REbom,          /* beginning and end columns of match */
+               REeom,
+               REdelta;        /* increase in line length due to last re_dosub */
+
+extern bool    okay_wrap;      /* Do a wrap search ... not when we're
+                                  parsing errors ... */
+extern char
+       *getsearch proto((void));
+
+extern bool
+       re_lindex proto((struct line *line, int offset, int dir,
+               struct RE_block *re_blk, int lbuf_okay, int crater)),
+       LookingAt proto((char *pattern,char *buf,int offset)),
+       look_at proto((char *expr));
+
+extern Bufpos
+       *docompiled proto((int dir, struct RE_block *re_blk)),
+       *dosearch proto((char *pattern, int dir, bool re));
+
+extern void
+       REcompile proto((char *pattern, bool re, struct RE_block *re_blk)),
+       find_tag proto((char *tag,int localp)),
+       putmatch proto((int which,char *buf,size_t size)),
+       re_dosub proto((struct RE_block *re_blk, char *tobuf, int delp)),
+       setsearch proto((char *str)),
+       RErecur proto((void));
diff --git a/usr/src/contrib/jove-4.14.6/re1.c b/usr/src/contrib/jove-4.14.6/re1.c
new file mode 100644 (file)
index 0000000..3955958
--- /dev/null
@@ -0,0 +1,606 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "fp.h"
+#include "re.h"
+#include "ctype.h"
+#include "chars.h"
+#include "disp.h"
+
+#ifdef MAC
+# include "mac.h"
+#else
+# include <sys/stat.h>
+#endif
+
+private void
+       IncSearch proto((int));
+
+private int
+       isearch proto((int, Bufpos *));
+
+private int
+substitute(re_blk, query, l1, char1, l2, char2)
+struct RE_block        *re_blk;
+Line   *l1,
+       *l2;
+bool   query;
+int    char1,
+       char2;
+{
+       Line    *lp;
+       int     numdone = 0,
+               UNDO_nd = 0,
+               offset = char1;
+       bool    stop = NO;
+       daddr   UNDO_da = NULL_DADDR;
+       Line    *UNDO_lp = NULL;
+
+       lsave();
+
+       for (lp = l1; lp != l2->l_next; lp = lp->l_next) {
+               int     crater = -1;    /* end of last substitution on this line */
+               int     LineDone = NO;  /* already replaced last empty string on line? */
+
+               while (!LineDone
+               && re_lindex(lp, offset, FORWARD, re_blk, NO, crater)
+               && (lp != l2 || REeom <= char2))
+               {
+                       DotTo(lp, REeom);
+                       offset = curchar;
+                       if (query) {
+                               int     c;
+
+                               message("Replace (Type '?' for help)? ");
+reswitch:
+                               redisplay();
+                               c = jgetchar();
+                               if (c == AbortChar)
+                                       return numdone;
+
+                               switch (CharUpcase(c)) {
+                               case '.':
+                                       stop = YES;
+                                       /*FALLTHROUGH*/
+                               case ' ':
+                               case 'Y':
+                                       break;
+
+                               case BS:
+                               case RUBOUT:
+                               case 'N':
+                                       if (REbom == REeom) {
+                                               offset += 1;
+                                               if (linebuf[REeom] == '\0')
+                                                       LineDone = YES;
+                                       }
+                                       continue;
+
+                               case CTL('W'):
+                                       re_dosub(re_blk, linebuf, YES);
+                                       if (lp == l2)
+                                               char2 += REdelta;
+                                       modify();
+                                       numdone += 1;
+                                       curchar = REbom;
+                                       makedirty(curline);
+                                       UNDO_da = curline->l_dline;
+                                       UNDO_lp = curline;
+                                       /*FALLTHROUGH*/
+                               case CTL('R'):
+                               case 'R':
+                                       RErecur();
+                                       UNDO_lp = NULL; /* can't reliably undo this */
+                                       offset = curchar;
+                                       lp = curline;
+                                       continue;
+
+                               case CTL('U'):
+                               case 'U':
+                                       if (UNDO_lp == NULL) {
+                                               rbell();
+                                               goto reswitch;
+                                       }
+                                       if (UNDO_lp == NULL)
+                                               getline(UNDO_da, linebuf);      /* someone ought to */
+                                       lp = UNDO_lp;
+                                       lp->l_dline = UNDO_da;
+                                       makedirty(lp);
+                                       offset = 0;
+                                       numdone = UNDO_nd;
+                                       UNDO_lp = NULL;
+                                       continue;
+
+                               case 'P':
+                               case '!':
+                                       query = FALSE;
+                                       break;
+
+                               case CR:
+                               case LF:
+                               case 'Q':
+                                       return numdone;
+
+                               case CTL('L'):
+                                       RedrawDisplay();
+                                       goto reswitch;
+
+                               default:
+                                       rbell();
+message("Space or Y, Period, Rubout or N, C-R or R, C-W, C-U or U, P or !, Return.");
+                                       goto reswitch;
+                               }
+                       }
+                       if (UNDO_lp != curline) {
+                               UNDO_da = curline->l_dline;
+                               UNDO_lp = curline;
+                               UNDO_nd = numdone;
+                       }
+                       if (REbom == REeom && linebuf[REeom] == '\0')
+                               LineDone = YES;
+                       re_dosub(re_blk, linebuf, NO);
+                       if (lp == l2)
+                               char2 += REdelta;
+                       numdone += 1;
+                       modify();
+                       crater = offset = curchar = REeom;
+                       makedirty(curline);
+                       if (query) {
+                               message(mesgbuf);       /* no blinking */
+                               redisplay();            /* show the change */
+                       }
+                       if (stop)
+                               return numdone;
+               }
+               offset = 0;
+       }
+       return numdone;
+}
+
+/* prompt for search and replacement strings and do the substitution */
+private void
+replace(query, inreg)
+bool   query,
+       inreg;
+{
+       Mark    *m;
+       char    *rep_ptr;
+       Line    *l1 = curline,
+               *l2 = curbuf->b_last;
+       int     char1 = curchar,
+               char2 = length(curbuf->b_last),
+               numdone;
+       struct RE_block re_blk;
+
+       if (inreg) {
+               m = CurMark();
+               l2 = m->m_line;
+               char2 = m->m_char;
+               (void) fixorder(&l1, &char1, &l2, &char2);
+       }
+
+       /* get search string */
+       strcpy(rep_search, ask(rep_search[0] ? rep_search : (char *)NULL, ProcFmt));
+       REcompile(rep_search, UseRE, &re_blk);
+       /* Now the replacement string.  Do_ask() so the user can play with
+          the default (previous) replacement string by typing C-R in ask(),
+          OR, he can just hit Return to replace with nothing. */
+       rep_ptr = do_ask("\r\n", (bool (*) ptrproto((int))) NULL, rep_str,
+               ": %f %s with ", rep_search);
+       if (rep_ptr == NULL)
+               rep_ptr = NullStr;
+       strcpy(rep_str, rep_ptr);
+
+       if ((numdone = substitute(&re_blk, query, l1, char1, l2, char2)) != 0
+       && !inreg)
+       {
+               do_set_mark(l1, char1);
+               add_mess(" ");          /* just making things pretty */
+       } else {
+               message("");
+       }
+       add_mess("(%d substitution%n)", numdone, numdone);
+}
+
+void
+RegReplace()
+{
+       replace(NO, YES);
+}
+
+void
+QRepSearch()
+{
+       replace(YES, NO);
+}
+
+void
+RepSearch()
+{
+       replace(NO, NO);
+}
+
+/* Lookup a tag in tag file FILE.  FILE is assumed to be sorted
+   alphabetically.  The FASTTAGS code, which is implemented with
+   a binary search, depends on this assumption.  If it's not true
+   it is possible to comment out the fast tag code (which is clearly
+   labeled), delete the marked test in the sequential loop, and
+   everything else will just work. */
+
+private bool
+lookup(searchbuf, filebuf, tag, file)
+char   *searchbuf,
+       *filebuf,
+       *tag,
+       *file;
+{
+       register size_t taglen = strlen(tag);
+       char    line[JBUFSIZ],
+               pattern[128];
+       register File   *fp;
+       struct stat     stbuf;
+       bool    success = NO;
+
+       fp = open_file(file, iobuff, F_READ, NO, YES);
+       if (fp == NULL)
+               return NO;
+       swritef(pattern, sizeof(pattern), "^%s[^\t]*\t*\\([^\t]*\\)\t*\\([?/]\\)\\(.*\\)\\2$", tag);
+
+       /* ********BEGIN FAST TAG CODE******** */
+
+       if (stat(file, &stbuf) >= 0) {
+               /* Invariant: if there is a line matching the tag, it
+                * begins somewhere after position lower, and begins
+                * at or before upper.  There is one possible
+                * exception: if lower is 0, the line with the tag
+                * might be the very first line.
+                *
+                * When this loop is done, we seek to lower, advance
+                * past the next newline (unless lower is 0), and fall
+                * into the sequential search.
+                */
+               register off_t  lower = 0;
+               register off_t  upper = stbuf.st_size;
+
+               for (;;) {
+                       off_t   mid;
+                       int     chars_eq;
+
+                       if (upper - lower < JBUFSIZ)
+                               break;  /* small range: search sequentially */
+                       mid = (lower + upper) / 2;
+                       f_seek(fp, mid);        /* mid will not be 0 */
+                       f_toNL(fp);
+                       if (f_gets(fp, line, sizeof line))
+                               break;          /* unexpected: bail out */
+                       chars_eq = numcomp(line, tag);
+                       if (chars_eq == taglen && jiswhite(line[chars_eq])) {
+                               /* we hit the exact line: get out */
+                               lower = mid;
+                               break;
+                       }
+                       if (line[chars_eq] < tag[chars_eq])
+                               lower = mid;    /* line is BEFORE tag */
+                       else
+                               upper = mid;    /* line is AFTER tag */
+               }
+               /* sequentially search from lower */
+               f_seek(fp, lower);
+               if (lower > 0)
+                       f_toNL(fp);
+       }
+
+       /* END FAST TAG CODE */
+
+       while (!f_gets(fp, line, sizeof line)) {
+               int     cmp = line[0] - *tag;
+
+               if (cmp == 0) {
+                       cmp = strncmp(line, tag, taglen);
+                       if (cmp == 0) {
+                               /* we've found the match */
+                               if (!LookingAt(pattern, line, 0)) {
+                                       complain("I thought I saw it!");
+                               } else {
+                                       putmatch(1, filebuf, (size_t)FILESIZE);
+                                       putmatch(3, searchbuf, (size_t)100);
+                                       success = YES;
+                               }
+                               break;
+                       }
+               }
+               if (cmp > 0)
+                       break;  /* failure: gone too far.  PRESUMES ALPHABETIC ORDER */
+       }
+       close_file(fp);
+
+       if (success == NO)
+               s_mess("Can't find tag \"%s\".", tag);
+       return success;
+}
+
+char   TagFile[FILESIZE] = "tags";
+
+void
+find_tag(tag, localp)
+char   *tag;
+int    localp;
+{
+       char    filebuf[FILESIZE],
+               sstr[100],
+               tfbuf[FILESIZE];
+       register Bufpos *bp;
+       register Buffer *b;
+       char    *tagfname;
+
+       if (!localp) {
+               char    prompt[128];
+
+               swritef(prompt, sizeof(prompt), "With tag file (%s default): ", TagFile);
+               tagfname = ask_file(prompt, TagFile, tfbuf);
+       } else
+               tagfname = TagFile;
+       if (!lookup(sstr, filebuf, tag, tagfname))
+               return;
+       set_mark();
+       b = do_find(curwind, filebuf, NO);
+       if (curbuf != b)
+               SetABuf(curbuf);
+       SetBuf(b);
+       if ((bp = dosearch(sstr, BACKWARD, NO)) == NULL &&
+           ((bp = dosearch(sstr, FORWARD, NO)) == NULL))
+               message("Well, I found the file, but the tag is missing.");
+       else
+               SetDot(bp);
+}
+
+void
+FindTag()
+{
+       int     localp = !is_an_arg();
+       char    tag[128];
+
+       strcpy(tag, ask((char *)NULL, ProcFmt));
+       find_tag(tag, localp);
+}
+
+/* Find Tag at Dot. */
+
+void
+FDotTag()
+{
+       int     c1 = curchar,
+               c2 = c1;
+       char    tagname[50];
+
+       if (!ismword(linebuf[curchar]))
+               complain("Not a tag!");
+       while (c1 > 0 && ismword(linebuf[c1 - 1]))
+               c1 -= 1;
+       while (ismword(linebuf[c2]))
+               c2 += 1;
+
+       null_ncpy(tagname, linebuf + c1, (size_t) (c2 - c1));
+       find_tag(tagname, !is_an_arg());
+}
+
+/* I-search returns a code saying what to do:
+   STOP:       We found the match, so unwind the stack and leave
+               where it is.
+   DELETE:     Rubout the last command.
+   BACKUP:     Back up to where the isearch was last NOT failing.
+
+   When a character is typed it is appended to the search string, and
+   then, isearch is called recursively.  When C-S or C-R is typed, isearch
+   is again called recursively. */
+
+#define STOP   1
+#define DELETE 2
+#define BACKUP 3
+#define TOSTART        4
+
+static char    ISbuf[128],
+               *incp = NULL;
+int    SExitChar = CR;
+
+#define cmp_char(a, b) ((a) == (b) || (CaseIgnore && (CharUpcase(a) == CharUpcase(b))))
+
+private Bufpos *
+doisearch(dir, c, failing)
+register int   c,
+               dir;
+bool           failing;
+{
+       static Bufpos   buf;
+       Bufpos  *bp;
+
+       if (c != CTL('S') && c != CTL('R')) {
+               if (failing)
+                       return NULL;
+               DOTsave(&buf);
+               if (dir == FORWARD) {
+                       if (cmp_char(linebuf[curchar], c)) {
+                               buf.p_char = curchar + 1;
+                               return &buf;
+                       }
+               } else {
+                       if (look_at(ISbuf))
+                               return &buf;
+               }
+       }
+       okay_wrap = YES;
+       if ((bp = dosearch(ISbuf, dir, NO)) == NULL)
+               rbell();        /* ring the first time there's no match */
+       okay_wrap = NO;
+       return bp;
+}
+
+void
+IncFSearch()
+{
+       IncSearch(FORWARD);
+}
+
+void
+IncRSearch()
+{
+       IncSearch(BACKWARD);
+}
+
+private void
+IncSearch(dir)
+int    dir;
+{
+       Bufpos  save_env;
+
+       DOTsave(&save_env);
+       ISbuf[0] = '\0';
+       incp = ISbuf;
+       if (isearch(dir, &save_env) == TOSTART)
+               SetDot(&save_env);
+       else {
+               if (LineDist(curline, save_env.p_line) >= MarkThresh)
+                       do_set_mark(save_env.p_line, save_env.p_char);
+       }
+       setsearch(ISbuf);
+}
+
+/* Nicely recursive. */
+
+private int
+isearch(dir, bp)
+int    dir;
+Bufpos *bp;
+{
+       Bufpos  pushbp;
+       int     c,
+               ndir;
+       bool    failing;
+       char    *orig_incp;
+
+       if (bp != NULL) {               /* Move to the new position. */
+               pushbp.p_line = bp->p_line;
+               pushbp.p_char = bp->p_char;
+               SetDot(bp);
+               failing = NO;
+       } else {
+               DOTsave(&pushbp);
+               failing = YES;
+       }
+       orig_incp = incp;
+       ndir = dir;             /* Same direction as when we got here, unless
+                                  we change it with C-S or C-R. */
+       for (;;) {
+               SetDot(&pushbp);
+               message(NullStr);
+               if (failing)
+                       add_mess("Failing ");
+               if (dir == BACKWARD)
+                       add_mess("reverse-");
+               add_mess("I-search: %s", ISbuf);
+               DrawMesg(NO);
+               add_mess(NullStr);      /* tell me this is disgusting ... */
+               c = getch();
+               if (c == SExitChar)
+                       return STOP;
+               if (c == AbortChar) {
+                       /* If we're failing, we backup until we're no longer
+                          failing or we've reached the beginning; else, we
+                          just about the search and go back to the start. */
+                       if (failing)
+                               return BACKUP;
+                       return TOSTART;
+               }
+               switch (c) {
+               case RUBOUT:
+               case BS:
+                       return DELETE;
+
+               case CTL('\\'):
+                       c = CTL('S');
+                       /*FALLTHROUGH*/
+               case CTL('S'):
+               case CTL('R'):
+                       /* If this is the first time through and we have a
+                          search string left over from last time, use that
+                          one now. */
+                       if (incp == ISbuf) {
+                               strcpy(ISbuf, getsearch());
+                               incp = &ISbuf[strlen(ISbuf)];
+                       }
+                       ndir = (c == CTL('S')) ? FORWARD : BACKWARD;
+                       /* If we're failing and we're not changing our
+                          direction, don't recur since there's no way
+                          the search can work. */
+                       if (failing && ndir == dir) {
+                               rbell();
+                               continue;
+                       }
+                       break;
+
+               case '\\':
+                       if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
+                               rbell();
+                               continue;
+                       }
+                       *incp++ = '\\';
+                       add_mess("\\");
+                       /*FALLTHROUGH*/
+               case CTL('Q'):
+               case CTL('^'):
+                       add_mess("");
+                       c = getch() | 0400;
+                       /*FALLTHROUGH*/
+               default:
+                       if (c & 0400)
+                               c &= CHARMASK;
+                       else {
+#ifdef IBMPC
+                               if (c == RUBOUT || c == 0xff ||
+                                   (c < ' ' && c != '\t')
+#else
+                               if (c > RUBOUT || (c < ' ' && c != '\t')
+#endif
+                                   || PrefChar(c)) {
+                                       Ungetc(c);
+                                       return STOP;
+                               }
+                       }
+                       if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
+                               rbell();
+                               continue;
+                       }
+                       *incp++ = c;
+                       *incp = '\0';
+                       break;
+               }
+               add_mess("%s", orig_incp);
+               add_mess(" ...");       /* so we know what's going on */
+               DrawMesg(NO);           /* do it now */
+               switch (isearch(ndir, doisearch(ndir, c, failing))) {
+               case TOSTART:
+                       return TOSTART;
+
+               case STOP:
+                       return STOP;
+
+               case BACKUP:
+                       /* If we're not failing, we just continue to to the
+                          for loop; otherwise we keep returning to the
+                          previous levels until we find one that isn't
+                          failing OR we reach the beginning. */
+                       if (failing)
+                               return BACKUP;
+                       /*FALLTHROUGH*/
+               case DELETE:
+                       incp = orig_incp;
+                       *incp = '\0';
+                       continue;
+               }
+       }
+}
diff --git a/usr/src/contrib/jove-4.14.6/rec.c b/usr/src/contrib/jove-4.14.6/rec.c
new file mode 100644 (file)
index 0000000..d0f1c2d
--- /dev/null
@@ -0,0 +1,186 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "fp.h"
+#include "rec.h"
+
+#ifndef        MAC
+#      include <sys/file.h>
+#endif
+
+private int    rec_fd = -1;
+private char   *recfname;
+private File   *rec_out;
+
+#ifndef        L_SET
+#      define L_SET 0
+#endif
+
+private struct rec_head        Header;
+
+private void
+recinit()
+{
+       char    buf[128];
+
+#ifdef MAC
+       swritef(buf, sizeof(buf), "%s/%s", HomeDir, p_tempfile);
+#else
+       swritef(buf, sizeof(buf), "%s/%s", TmpFilePath, p_tempfile);
+#endif
+       recfname = copystr(buf);
+       recfname = mktemp(recfname);
+       rec_fd = creat(recfname, 0644);
+       if (rec_fd == -1) {
+               complain("Cannot create \"%s\"; recovery disabled.", recfname);
+               return;
+       }
+       /* initialize the record IO */
+       rec_out = fd_open(recfname, F_WRITE|F_LOCKED, rec_fd, iobuff, LBSIZE);
+
+       /* Initialize the record header. */
+       Header.Uid = getuid();
+       Header.Pid = getpid();
+       Header.UpdTime = 0L;
+       Header.Nbuffers = 0;
+       (void) write(rec_fd, (UnivPtr) &Header, sizeof Header);
+}
+
+/* Close recfile before execing a child process.
+ * Since we might be vforking, we must not change any variables
+ * (in particular rec_fd).
+ */
+void
+recclose()
+{
+       if (rec_fd == -1)
+               return;
+       (void) close(rec_fd);
+}
+
+/* Close and remove recfile before exiting. */
+
+
+void
+recremove()
+{
+       if (rec_fd == -1)
+               return;
+       recclose();
+       (void) unlink(recfname);
+}
+
+private void
+putaddr(addr, p)
+daddr  addr;
+register File  *p;
+{
+       register char   *cp = (char *) &addr;
+       register int    nchars = sizeof (daddr);
+
+       while (--nchars >= 0)
+               jputc(*cp++ & 0377, p);
+}
+
+private void
+putn(cp, nbytes)
+register char  *cp;
+register size_t        nbytes;
+{
+       while (nbytes-- > 0)
+               jputc(*cp++ & 0377, rec_out);
+}
+
+/* Write out the line pointers for buffer B. */
+
+private void
+dmppntrs(b)
+register Buffer        *b;
+{
+       register Line   *lp;
+
+       for (lp = b->b_first; lp != NULL; lp = lp->l_next)
+               putaddr(lp->l_dline, rec_out);
+}
+
+/* dump the buffer info and then the actual line pointers. */
+
+private void
+dmp_buf_header(b)
+register Buffer        *b;
+{
+       struct rec_entry        record;
+       register Line   *lp;
+       register int    nlines = 0;
+
+       for (lp = b->b_first; lp != NULL; lp = lp->l_next, nlines++)
+               if (lp == b->b_dot)
+                       record.r_dotline = nlines;
+       strcpy(record.r_fname, b->b_fname ? b->b_fname : NullStr);
+       strcpy(record.r_bname, b->b_name);
+       record.r_nlines = nlines;
+       record.r_dotchar = b->b_char;
+       putn((char *) &record, sizeof record);
+}
+
+/* Goes through all the buffers and syncs them to the disk. */
+
+int    SyncFreq = 50;
+
+void
+SyncRec()
+{
+       register Buffer *b;
+       static bool     beenhere = NO;
+
+       if (!beenhere) {
+               beenhere = YES;
+               recinit();      /* Init recover file. */
+       }
+       if (rec_fd == -1)
+               return;
+       lseek(rec_fd, 0L, L_SET);
+       (void) time(&Header.UpdTime);
+       Header.Nbuffers = 0;
+       for (b = world; b != NULL; b = b->b_next)
+               if (b->b_type == B_SCRATCH || !IsModified(b))
+                       continue;
+               else
+                       Header.Nbuffers += 1;
+       Header.FreePtr = DFree;
+       putn((char *) &Header, sizeof Header);
+       if (Header.Nbuffers != 0) {
+               lsave();        /* this makes things really right */
+               SyncTmp();
+               for (b = world; b != NULL; b = b->b_next)
+                       if (b->b_type == B_SCRATCH || !IsModified(b))
+                               continue;
+                       else
+                               dmp_buf_header(b);
+               for (b = world; b != NULL; b = b->b_next)
+                       if (b->b_type == B_SCRATCH || !IsModified(b))
+                               continue;
+                       else
+                               dmppntrs(b);
+       }
+       flushout(rec_out);
+}
+
+/* Full Recover.  What we have to do is go find the name of the tmp
+   file data/rec pair and use those instead of the ones we would have
+   created eventually.  The rec file has a list of buffers, and then
+   the actual pointers.  Stored for each buffer is the buffer name,
+   the file name, the number of lines, the current line, the current
+   character.  The current modes do not need saving as they will be
+   saved when the file name is set.  If a process was running in a
+   buffer, it will be lost. */
+
+void
+FullRecover()
+{
+}
diff --git a/usr/src/contrib/jove-4.14.6/rec.h b/usr/src/contrib/jove-4.14.6/rec.h
new file mode 100644 (file)
index 0000000..ad82d02
--- /dev/null
@@ -0,0 +1,28 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+struct rec_head {
+       int             Uid,            /* uid of owner */
+                       Pid;            /* pid of jove process */
+       time_t          UpdTime;        /* last time this was updated */
+       int             Nbuffers;       /* number of buffers */
+       daddr           FreePtr;        /* position of DFree */
+};
+
+struct rec_entry {
+       char    r_bname[128],
+               r_fname[128];
+       int     r_nlines,
+               r_dotline,      /* so we can really save the context */
+               r_dotchar;
+};
+
+extern void
+       SyncRec proto((void)),
+       recclose proto((void)),
+       recremove proto((void)),
+       FullRecover proto((void));
diff --git a/usr/src/contrib/jove-4.14.6/recover.c b/usr/src/contrib/jove-4.14.6/recover.c
new file mode 100644 (file)
index 0000000..3044920
--- /dev/null
@@ -0,0 +1,819 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* Recovers JOVE files after a system/editor crash.
+   Usage: recover [-d directory] [-syscrash]
+   The -syscrash option is specified in /etc/rc.  It directs recover to
+   move all the jove tmp files from TMP_DIR (/tmp) to REC_DIR (/usr/preserve).
+   recover -syscrash must be invoked in /ect/rc BEFORE /tmp gets cleared out.
+   (about the same place as expreserve gets invoked to save ed/vi/ex files.
+
+   The -d option lets you specify the directory to search for tmp files when
+   the default isn't the right one.
+
+   Look in Makefile to change the default directories. */
+
+#include <stdio.h>     /* Do stdio first so it doesn't override OUR
+                          definitions. */
+#include "jove.h"
+#include "temp.h"
+#include "rec.h"
+#include "rectune.h"
+#include "wait.h"
+
+#ifdef UNIX
+# include <signal.h>
+# include <sys/file.h>
+# include <pwd.h>
+# include <time.h>
+#endif
+
+#ifdef SYSV
+# include <sys/utsname.h>
+#endif
+
+#ifndef        L_SET
+# define L_SET 0
+# define L_INCR        1
+#endif
+
+extern char    *ctime proto((const time_t *));
+
+private char   blk_buf[JBUFSIZ];
+private int    nleft;
+private FILE   *ptrs_fp;
+private int    data_fd;
+private struct rec_head        Header;
+private long   Nchars,
+       Nlines;
+private char   tty[] = "/dev/tty";
+private int    UserID,
+       Verbose = 0;
+private char   *Directory = NULL;              /* the directory we're looking in */
+
+private struct file_pair {
+       char    *file_data,
+               *file_rec;
+#define INSPECTED      01
+       int     file_flags;
+       struct file_pair        *file_next;
+} *First = NULL;
+
+private struct rec_entry       *buflist[100];  /* system initializes to 0 */
+
+#ifndef F_COMPLETION
+# define F_COMPLETION  /* since scandir.c is surrounded by an ifdef */
+#endif
+
+/* simpler version of one in util.c, needed by scandir.c */
+UnivPtr
+emalloc(size)
+size_t size;
+{
+       register UnivPtr ptr;
+
+       if ((ptr = malloc(size)) == NULL) {
+               fprintf(stderr, "couldn't malloc(%d)\n", size);
+               exit(1);
+       }
+       return ptr;
+}
+           
+/* simpler version of one in util.c, needed by scandir.c */
+UnivPtr
+erealloc(ptr, size)
+UnivPtr ptr;
+size_t size;
+{
+       if ((ptr = realloc(ptr, size)) == NULL) {
+               fprintf(stderr, "couldn't realloc(%d)\n", size);
+               exit(1);
+       }
+       return ptr;
+}
+
+/* duplicated in util.c, needed by scandir.c */
+void
+null_ncpy(to, from, n)
+char   *to,
+       *from;
+size_t n;
+{
+       (void) strncpy(to, from, n);
+       to[n] = '\0';
+}
+
+#define complain printf        /* kludge! needed by scandir.c */
+#include "scandir.c"   /* to get dirent simulation and jscandir */
+
+/* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
+   long. */
+
+private char   *getblock proto((daddr atl));
+
+void
+getline(tl, buf)
+daddr  tl;
+char   *buf;
+{
+       register char   *bp,
+                       *lp;
+       register int    nl;
+
+       lp = buf;
+       bp = getblock(tl >> 1);
+       nl = nleft;
+       tl = blk_round(tl);
+
+       while ((*lp++ = *bp++) != '\0') {
+               if (--nl == 0) {
+                       tl = forward_block(tl);
+                       bp = getblock(tl >> 1);
+                       nl = nleft;
+               }
+       }
+}
+
+private char *
+getblock(atl)
+daddr  atl;
+{
+       int     bno,
+               off;
+       static int      curblock = -1;
+
+       bno = da_to_bno(atl);
+       off = da_to_off(atl);
+       nleft = JBUFSIZ - off;
+
+       if (bno != curblock) {
+               lseek(data_fd, (long) bno * JBUFSIZ, L_SET);
+               read(data_fd, (UnivPtr)blk_buf, (size_t)JBUFSIZ);
+               curblock = bno;
+       }
+       return blk_buf + off;
+}
+
+char *
+copystr(s)
+char   *s;
+{
+       char    *str;
+
+       str = malloc((size_t) (strlen(s) + 1));
+       strcpy(str, s);
+
+       return str;
+}
+
+private char   *CurDir;
+
+/* Scan the DIRNAME directory for jove tmp files, and make a linked list
+   out of them. */
+
+private int    add_name proto((char *));
+
+private void
+get_files(dirname)
+char   *dirname;
+{
+       char **nmptr;
+
+       CurDir = dirname;
+       First = NULL;
+       jscandir(dirname, &nmptr, add_name,
+               (int (*) proto((UnivConstPtr, UnivConstPtr)))NULL);
+}
+
+private int
+add_name(fname)
+char *fname;
+{
+       char    dfile[128],
+               rfile[128];
+       struct file_pair        *fp;
+       struct rec_head         header;
+       int     fd;
+
+       if (strncmp(fname, "jrec", (size_t)4) != 0)
+               return 0;
+       /* If we get here, we found a "recover" tmp file, so now
+          we look for the corresponding "data" tmp file.  First,
+          though, we check to see whether there is anything in
+          the "recover" file.  If it's 0 length, there's no point
+          in saving its name. */
+       (void) sprintf(rfile, "%s/%s", CurDir, fname);
+       (void) sprintf(dfile, "%s/jove%s", CurDir, fname + 4);
+       if ((fd = open(rfile, 0)) != -1) {
+               if ((read(fd, (UnivPtr) &header, sizeof header) != sizeof header)) {
+                       close(fd);
+                       return 0;
+               } else
+                       close(fd);
+       }
+       if (access(dfile, 0) != 0) {
+               fprintf(stderr, "recover: can't find the data file for %s/%s\n", Directory, fname);
+               fprintf(stderr, "so deleting...\n");
+               (void) unlink(rfile);
+               (void) unlink(dfile);
+               return 0;
+       }
+       /* If we get here, we've found both files, so we put them
+          in the list. */
+       fp = (struct file_pair *) malloc (sizeof *fp);
+       if (fp == NULL) {
+               fprintf(stderr, "recover: cannot malloc for file_pair.\n");
+               exit(-1);
+       }
+       fp->file_data = copystr(dfile);
+       fp->file_rec = copystr(rfile);
+       fp->file_flags = 0;
+       fp->file_next = First;
+       First = fp;
+
+       return 1;
+}
+
+private void
+options()
+{
+       printf("Options are:\n");
+       printf("        ?               list options.\n");
+       printf("        get             get a buffer to a file.\n");
+       printf("        list            list known buffers.\n");
+       printf("        print           print a buffer to terminal.\n");
+       printf("        quit            quit and delete jove tmp files.\n");
+       printf("        restore         restore all buffers.\n");
+}
+
+/* Returns a legitimate buffer # */
+
+private void   tellme proto((char *, char *)),
+       list proto((void));
+
+private struct rec_entry **
+getsrc()
+{
+       char    name[128];
+       int     number;
+
+       for (;;) {
+               tellme("Which buffer ('?' for list)? ", name);
+               if (name[0] == '?')
+                       list();
+               else if (name[0] == '\0')
+                       return NULL;
+               else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers)
+                       return &buflist[number];
+               else {
+                       int     i;
+
+                       for (i = 1; i <= Header.Nbuffers; i++)
+                               if (strcmp(buflist[i]->r_bname, name) == 0)
+                                       return &buflist[i];
+                       printf("%s: unknown buffer.\n", name);
+               }
+       }
+}
+
+/* Get a destination file name. */
+
+static char *
+getdest()
+{
+       static char     filebuf[256];
+
+       tellme("Output file: ", filebuf);
+       if (filebuf[0] == '\0')
+               return NULL;
+       return filebuf;
+}
+
+#include "ctype.h"
+
+private char *
+readword(buf)
+char   *buf;
+{
+       int     c;
+       char    *bp = buf;
+
+       do ; while (strchr(" \t\n", c = getchar()));
+
+       do {
+               if (strchr(" \t\n", c))
+                       break;
+               *bp++ = c;
+       } while ((c = getchar()) != EOF);
+       *bp = '\0';
+
+       return buf;
+}
+
+private void
+tellme(quest, answer)
+char   *quest,
+       *answer;
+{
+#ifndef BSD386
+       /* this is naughty anyway */
+       if (stdin->_cnt <= 0) {
+               printf("%s", quest);
+               fflush(stdout);
+       }
+#else
+       printf("%s", quest);
+       fflush(stdout);
+#endif
+       readword(answer);
+}
+
+/* Print the specified file to standard output. */
+
+private jmp_buf        int_env;
+
+private SIGRESULT
+catch(junk)
+int    junk;
+{
+       longjmp(int_env, 1);
+       /*NOTREACHED*/
+}
+
+private void   get proto((struct rec_entry **src, char *dest));
+
+private void
+restore()
+{
+       register int    i;
+       char    tofile[100],
+               answer[30];
+       int     nrecovered = 0;
+
+       for (i = 1; i <= Header.Nbuffers; i++) {
+               (void) sprintf(tofile, "#%s", buflist[i]->r_bname);
+tryagain:
+               printf("Restoring %s to %s, okay?", buflist[i]->r_bname,
+                                                    tofile);
+               tellme(" ", answer);
+               switch (answer[0]) {
+               case 'y':
+                       break;
+
+               case 'n':
+                       continue;
+
+               default:
+                       tellme("What file should I use instead? ", tofile);
+                       goto tryagain;
+               }
+               get(&buflist[i], tofile);
+               nrecovered += 1;
+       }
+       printf("Recovered %d buffers.\n", nrecovered);
+}
+
+private void   dump_file proto((int which, FILE *out));
+
+private void
+get(src, dest)
+struct rec_entry       **src;
+char   *dest;
+{
+       FILE    *outfile;
+
+       if (src == NULL || dest == NULL)
+               return;
+       (void) signal(SIGINT, catch);
+       if (setjmp(int_env) == 0) {
+               if (dest == tty)
+                       outfile = stdout;
+               else {
+                       if ((outfile = fopen(dest, "w")) == NULL) {
+                               printf("recover: cannot create %s.\n", dest);
+                               (void) signal(SIGINT, SIG_DFL);
+                               return;
+                       }
+                       printf("\"%s\"", dest);
+               }
+               dump_file(src - buflist, outfile);
+       } else
+               printf("\nAborted!\n");
+       (void) signal(SIGINT, SIG_DFL);
+       if (dest != tty) {
+               fclose(outfile);
+               printf(" %ld lines, %ld characters.\n", Nlines, Nchars);
+       }
+}
+
+private char **
+scanvec(args, str)
+register char  **args,
+               *str;
+{
+       while (*args) {
+               if (strcmp(*args, str) == 0)
+                       return args;
+               args += 1;
+       }
+       return NULL;
+}
+
+private void
+read_rec(recptr)
+struct rec_entry       *recptr;
+{
+       if (fread((UnivPtr) recptr, sizeof *recptr, (size_t)1, ptrs_fp) != 1)
+               fprintf(stderr, "recover: cannot read record.\n");
+}
+
+private void
+seekto(which)
+int    which;
+{
+       long    offset;
+       int     i;
+
+       offset = sizeof (Header) + (Header.Nbuffers * sizeof (struct rec_entry));
+       for (i = 1; i < which; i++)
+               offset += buflist[i]->r_nlines * sizeof (daddr);
+       fseek(ptrs_fp, offset, L_SET);
+}
+
+private void
+makblist()
+{
+       int     i;
+
+       fseek(ptrs_fp, (long) sizeof (Header), L_SET);
+       for (i = 1; i <= Header.Nbuffers; i++) {
+               if (buflist[i] == NULL)
+                       buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry));
+               read_rec(buflist[i]);
+       }
+       while (buflist[i]) {
+               free((UnivPtr) buflist[i]);
+               buflist[i] = NULL;
+               i += 1;
+       }
+}
+
+private daddr
+getaddr(fp)
+register FILE  *fp;
+{
+       register int    nchars = sizeof (daddr);
+       daddr   addr;
+       register char   *cp = (char *) &addr;
+
+       while (--nchars >= 0)
+               *cp++ = getc(fp);
+
+       return addr;
+}
+
+private void
+dump_file(which, out)
+int    which;
+FILE   *out;
+{
+       register int    nlines;
+       register daddr  addr;
+       char    buf[JBUFSIZ];
+
+       seekto(which);
+       nlines = buflist[which]->r_nlines;
+       Nchars = Nlines = 0L;
+       while (--nlines >= 0) {
+               addr = getaddr(ptrs_fp);
+               getline(addr, buf);
+               Nlines += 1;
+               Nchars += 1 + strlen(buf);
+               fputs(buf, out);
+               if (nlines > 0)
+                       fputc('\n', out);
+       }
+}
+
+/* List all the buffers. */
+
+private void
+list()
+{
+       int     i;
+
+       for (i = 1; i <= Header.Nbuffers; i++)
+               printf("%d) buffer %s  \"%s\" (%d lines)\n", i,
+                       buflist[i]->r_bname,
+                       buflist[i]->r_fname,
+                       buflist[i]->r_nlines);
+}
+
+private void   ask_del proto((char *prompt, struct file_pair *fp));
+
+private int
+doit(fp)
+struct file_pair       *fp;
+{
+       char    answer[30];
+       char    *datafile = fp->file_data,
+               *pntrfile = fp->file_rec;
+
+       ptrs_fp = fopen(pntrfile, "r");
+       if (ptrs_fp == NULL) {
+               if (Verbose)
+                       fprintf(stderr, "recover: cannot read rec file (%s).\n", pntrfile);
+               return 0;
+       }
+       fread((UnivPtr) &Header, sizeof Header, (size_t)1, ptrs_fp);
+       if (Header.Uid != UserID)
+               return 0;
+
+       /* Don't ask about JOVE's that are still running ... */
+#ifdef KILL0
+       if (kill(Header.Pid, 0) == 0)
+               return 0;
+#endif /* KILL0 */
+
+       if (Header.Nbuffers == 0) {
+               printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile);
+               ask_del(" ", fp);
+               return 1;
+       }
+
+       if (Header.Nbuffers < 0) {
+               fprintf(stderr, "recover: %s doesn't look like a jove file.\n", pntrfile);
+               ask_del("Should I delete it? ", fp);
+               return 1;       /* We'll, we sort of found something. */
+       }
+       printf("Found %d buffer%s last updated: %s",
+               Header.Nbuffers,
+               Header.Nbuffers != 1 ? "s" : "",
+               ctime(&Header.UpdTime));
+       data_fd = open(datafile, 0);
+       if (data_fd == -1) {
+               fprintf(stderr, "recover: but I can't read the data file (%s).\n", datafile);
+               ask_del("Should I delete the tmp files? ", fp);
+               return 1;
+       }
+       makblist();
+       list();
+
+       for (;;) {
+               tellme("(Type '?' for options): ", answer);
+               switch (answer[0]) {
+               case '\0':
+                       continue;
+
+               case '?':
+                       options();
+                       break;
+
+               case 'l':
+                       list();
+                       break;
+
+               case 'p':
+                       get(getsrc(), tty);
+                       break;
+
+               case 'q':
+                       ask_del("Shall I delete the tmp files? ", fp);
+                       return 1;
+
+               case 'g':
+                   {   /* So it asks for src first. */
+                       char    *dest;
+                       struct rec_entry        **src;
+
+                       if ((src = getsrc()) == NULL)
+                               break;
+                       dest = getdest();
+                       get(src, dest);
+                       break;
+                   }
+
+               case 'r':
+                       restore();
+                       break;
+
+               default:
+                       printf("I don't know how to \"%s\"!\n", answer);
+                       break;
+               }
+       }
+}
+
+private void   del_files proto((struct file_pair *fp));
+
+private void
+ask_del(prompt, fp)
+char   *prompt;
+struct file_pair       *fp;
+{
+       char    yorn[20];
+
+       tellme(prompt, yorn);
+       if (yorn[0] == 'y')
+               del_files(fp);
+}
+
+private void
+del_files(fp)
+struct file_pair       *fp;
+{
+       (void) unlink(fp->file_data);
+       (void) unlink(fp->file_rec);
+}
+
+
+
+private void
+MailUser(rec)
+struct rec_head *rec;
+{
+#ifdef SYSV
+       struct utsname mach;
+#else
+       char mach[BUFSIZ];
+#endif
+       char mail_cmd[BUFSIZ];
+       char *last_update;
+       char *buf_string;
+       FILE *mail_pipe;
+       struct passwd *pw;
+
+       if ((pw = getpwuid(rec->Uid))== NULL)
+               return;
+#ifdef SYSV
+       if (uname(&mach) < 0)
+               strcpy(mach.sysname, "unknown");
+#else
+       {
+#ifndef BSD386
+               extern int      gethostname proto((const char *, size_t));
+#endif
+
+               gethostname(mach, sizeof(mach));
+       }
+#endif
+       last_update = ctime(&(rec->UpdTime));
+       /* Start up mail */
+       sprintf(mail_cmd, "/bin/mail %s", pw->pw_name);
+       setuid(getuid());
+       if ((mail_pipe = popen(mail_cmd, "w")) == NULL)
+               return;
+       setbuf(mail_pipe, mail_cmd);
+       /* Let's be grammatically correct! */
+       if (rec->Nbuffers == 1)
+               buf_string = "buffer";
+       else
+               buf_string = "buffers";
+       fprintf(mail_pipe, "Subject: System crash\n");
+       fprintf(mail_pipe, " \n");
+       fprintf(mail_pipe, "Jove saved %d %s when the system \"%s\"\n",
+        rec->Nbuffers, buf_string,
+#ifdef SYSV
+        mach.sysname
+#else
+        mach
+#endif
+        );
+       fprintf(mail_pipe, "crashed on %s\n\n", last_update);
+       fprintf(mail_pipe, "You can retrieve the %s using Jove's -r\n",
+        buf_string);
+       fprintf(mail_pipe, "(recover option) i.e. give the command.\n");
+       fprintf(mail_pipe, "\tjove -r\n");
+       fprintf(mail_pipe, "See the Jove manual for more details\n");
+       pclose(mail_pipe);
+}
+
+
+private void
+savetmps()
+{
+       struct file_pair        *fp;
+       union wait      status;
+       int     pid,
+               fd;
+       struct rec_head         header;
+       char    buf[BUFSIZ];
+       char    *fname;
+       struct stat             stbuf;
+
+       if (strcmp(TMP_DIR, REC_DIR) == 0)
+               return;         /* Files are moved to the same place. */
+       get_files(TMP_DIR);
+       for (fp = First; fp != NULL; fp = fp->file_next) {
+               stat(fp->file_data, &stbuf);
+               switch (pid = fork()) {
+               case -1:
+                       fprintf(stderr, "recover: can't fork\n!");
+                       exit(-1);
+                       /*NOTREACHED*/
+
+               case 0:
+                       fprintf(stderr, "Recovering: %s, %s\n", fp->file_data,
+                        fp->file_rec);
+                       if ((fd = open(fp->file_rec, 0)) != -1) {
+                               if ((read(fd, (UnivPtr) &header, sizeof header) != sizeof header)) {
+                                       close(fd);
+                                       return;
+                               } else
+                                       close(fd);
+                       }
+                       MailUser(&header);
+                       execl("/bin/mv", "mv", fp->file_data, fp->file_rec,
+                                 REC_DIR, (char *)NULL);
+                       fprintf(stderr, "recover: cannot execl /bin/mv.\n");
+                       exit(-1);
+                       /*NOTREACHED*/
+
+               default:
+                       do ; while (wait(&status) != pid);
+                       if (status.w_status != 0)
+                               fprintf(stderr, "recover: non-zero status (%d) returned from copy.\n", status.w_status);
+                       fname = fp->file_data + strlen(TMP_DIR);
+                       strcpy(buf, REC_DIR);
+                       strcat(buf, fname);
+                       if (chown(buf, (int) stbuf.st_uid, (int) stbuf.st_gid) != 0)
+                               perror("recover: chown failed.");
+                       fname = fp->file_rec + strlen(TMP_DIR);
+                       strcpy(buf, REC_DIR);
+                       strcat(buf, fname);
+                       if (chown(buf, (int) stbuf.st_uid, (int) stbuf.st_gid) != 0)
+                               perror("recover: chown failed.");
+               }
+       }
+}
+
+private int
+lookup(dir)
+char   *dir;
+{
+       struct file_pair        *fp;
+       int     nfound = 0;
+
+       printf("Checking %s ...\n", dir);
+       Directory = dir;
+       get_files(dir);
+       for (fp = First; fp != NULL; fp = fp->file_next) {
+               nfound += doit(fp);
+               if (ptrs_fp)
+                       (void) fclose(ptrs_fp);
+               if (data_fd > 0)
+                       (void) close(data_fd);
+       }
+       return nfound;
+}
+
+int
+main(argc, argv)
+int    argc;
+char   *argv[];
+{
+       int     nfound;
+       char    **argvp;
+       char    *tmp_dir;
+
+       UserID = getuid();
+
+       if (scanvec(argv, "-help")) {
+               printf("recover: usage: recover [-d directory] [-syscrash]\n");
+               printf("Use \"jove -r\" after JOVE has died for some\n");
+               printf("unknown reason.\n\n");
+               printf("Use \"%s -syscrash\"\n", Recover);
+               printf("when the system is in the process of rebooting.");
+               printf("This is done automatically at reboot time\n");
+               printf("and so most of you don't have to worry about that.\n\n");
+               printf("Use \"recover -d directory\" when the tmp files are store\n");
+               printf("in DIRECTORY instead of the default one (/tmp).\n");
+               exit(0);
+       }
+       if (scanvec(argv, "-v"))
+               Verbose = YES;
+       if (scanvec(argv, "-syscrash")) {
+               printf("Recovering jove files ... ");
+               savetmps();
+               printf("Done.\n");
+               exit(0);
+       }
+       if ((argvp = scanvec(argv, "-uid")) != NULL)
+               UserID = atoi(argvp[1]);
+       if ((argvp = scanvec(argv, "-d")) != NULL)
+               tmp_dir = argvp[1];
+       else
+               tmp_dir = TmpFilePath;
+       /* Check default directory */
+       nfound = lookup(tmp_dir);
+       /* Check whether anything was saved when system died? */
+       if (strcmp(tmp_dir, REC_DIR) != 0)
+               nfound += lookup(REC_DIR);
+       if (nfound == 0)
+               printf("There's nothing to recover.\n");
+       return 0;
+}
diff --git a/usr/src/contrib/jove-4.14.6/scandir.c b/usr/src/contrib/jove-4.14.6/scandir.c
new file mode 100644 (file)
index 0000000..148f400
--- /dev/null
@@ -0,0 +1,228 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/*
+ * This file is used as a compiled module by Jove and also included as
+ * source in recover.c
+ */
+#ifndef TUNED
+# include "jove.h"
+#endif
+#include "scandir.h"
+
+#ifdef F_COMPLETION
+
+#ifdef MSDOS
+# include <dos.h>
+# include <search.h>
+#endif
+
+#ifdef UNIX
+# include <sys/stat.h>
+# ifdef        M_XENIX
+#  include <sys/ndir.h>
+#  ifndef dirent
+#   define dirent direct
+#  endif
+# else
+#  ifdef       DIRENT
+#   include <dirent.h>
+#  else
+#   include <sys/dir.h>
+#   ifndef dirent
+#    define dirent direct
+#   endif
+#  endif       DIRENT
+# endif        /* M_XENIX */
+#endif
+
+#ifdef UNIX
+
+#define DIRSIZE(entry) (strlen((entry)->d_name))
+
+#if !defined(BSD_DIR) && !defined(DIRENT)
+
+typedef struct {
+       int     d_fd;           /* File descriptor for this directory */
+} DIR;
+
+private int
+closedir(dp)
+DIR    *dp;
+{
+       (void) close(dp->d_fd);
+       free((char *) dp);
+       return 0;   /* don't know how to fail */
+}
+
+private DIR *
+opendir(dir)
+char   *dir;
+{
+       DIR     *dp = (DIR *) emalloc(sizeof *dp);
+       struct stat     stbuf;
+
+       if ((dp->d_fd = open(dir, 0)) == -1)
+               return NULL;
+       if ((fstat(dp->d_fd, &stbuf) == -1) || !(stbuf.st_mode & S_IFDIR)) {
+               closedir(dp);
+               return NULL;    /* this isn't a directory! */
+       }
+       return dp;
+}
+
+private dirent *
+readdir(dp)
+DIR    *dp;
+{
+       static dirent   dir;
+
+       do {
+               if (read(dp->d_fd, (UnivPtr) &dir, sizeof dir) != sizeof dir)
+                       return NULL;
+#if    defined(elxsi) && defined(SYSV)
+       /*
+        * Elxsi has a BSD4.2 implementation which may or may not use
+        * `twisted inodes' ...  Anyone able to check?
+        */
+       } while (*(unsigned short *)&dir.d_ino == 0);
+#else
+       } while (dir.d_ino == 0);
+#endif
+
+       return &dir;
+}
+
+#endif /* ! BSD_DIR */
+
+/* Scandir returns the number of entries or -1 if the directory cannoot
+   be opened or malloc fails. */
+
+int
+jscandir(dir, nmptr, qualify, sorter)
+char   *dir;
+char   ***nmptr;
+int    (*qualify) proto((char *));
+int    (*sorter) proto((UnivConstPtr, UnivConstPtr));
+{
+       DIR     *dirp;
+       struct  dirent  *entry;
+       char    **ourarray;
+       unsigned int    nalloc = 10,
+                       nentries = 0;
+
+       if ((dirp = opendir(dir)) == NULL)
+               return -1;
+       ourarray = (char **) emalloc(nalloc * sizeof (char *));
+       while ((entry = readdir(dirp)) != NULL) {
+               if (qualify != NULL && (*qualify)(entry->d_name) == 0)
+                       continue;
+               if (nentries == nalloc) {
+                       ourarray = (char **) realloc((UnivPtr) ourarray, (nalloc += 10) * sizeof (char *));
+                       if (ourarray == NULL)
+                               complain("[Malloc failed: cannot scandir]");
+               }
+               ourarray[nentries] = (char *) emalloc(DIRSIZE(entry) + 1);
+               null_ncpy(ourarray[nentries], entry->d_name, (size_t) DIRSIZE(entry));
+               nentries += 1;
+       }
+       closedir(dirp);
+       if ((nentries + 1) != nalloc)
+               ourarray = (char **) erealloc((UnivPtr) ourarray,
+                                       ((nentries + 1) * sizeof (char *)));
+       if (sorter != NULL)
+               qsort((UnivPtr) ourarray, nentries, sizeof (char **), sorter);
+       *nmptr = ourarray;
+       ourarray[nentries] = NULL;              /* guaranteed NULL pointer */
+
+       return nentries;
+}
+
+#endif /* UNIX */
+
+#ifdef MSDOS
+# define DIRSIZE(entry)        strlen((entry).name)
+
+/* Scandir returns the number of entries or -1 if the directory cannot
+   be opened or malloc fails. */
+
+unsigned int fmask = _A_NORMAL|_A_RDONLY|_A_HIDDEN|_A_SUBDIR;
+
+int
+jscandir(dir, nmptr, qualify, sorter)
+char   *dir;
+char   ***nmptr;
+int    (*qualify) proto((char *));
+int    (*sorter) proto((UnivConstPtr, UnivConstPtr));
+{
+       char dirname[FILESIZE];
+       struct find_t entry;
+       char *ptr;
+       char    **ourarray;
+       unsigned int    nalloc = 10,
+                       nentries = 0;
+
+       strcpy(dirname, dir);
+       ptr = &dirname[strlen(dirname)-1];
+       if ((dirname[1] == ':' && !dirname[2]) || (*ptr == '/') || (*ptr == '\\'))
+          strcat(dirname, "*.*");
+       else
+          strcat(dirname, "/*.*");
+
+       if (_dos_findfirst(dirname, fmask, &entry))
+          return -1;
+       if ((ourarray = (char **) emalloc(nalloc * sizeof (char *))) == NULL)
+       do  {
+               if ((fmask == 0x10) && !(entry.attrib&fmask))
+                       continue;
+               strlwr(entry.name);
+               if (qualify != NULL && (*qualify)(entry.name) == 0)
+                       continue;
+               if (nentries == nalloc) {
+                       ourarray = (char **) realloc((char *) ourarray, (nalloc += 10) * sizeof (char *));
+                       if (ourarray == NULL)
+                               complain("[Malloc failed: cannot scandir]");
+               }
+               ourarray[nentries] = (char *) emalloc(DIRSIZE(entry) + 1);
+               null_ncpy(ourarray[nentries], entry.name, (int) DIRSIZE(entry));
+               nentries++;
+       } while (_dos_findnext(&entry) == 0);
+
+       if ((nentries + 1) != nalloc)
+               ourarray = (char **) erealloc((char *) ourarray,
+                                       ((nentries + 1) * sizeof (char *)));
+       if (sorter != (int (*)())NULL)
+               qsort((char *) ourarray, nentries, sizeof (char **), sorter);
+       *nmptr = ourarray;
+       ourarray[nentries] = NULL;              /* guaranteed NULL pointer */
+
+       return nentries;
+}
+
+#endif /* MSDOS */
+
+void
+freedir(nmptr, nentries)
+char   ***nmptr;
+int    nentries;
+{
+       char    **ourarray = *nmptr;
+
+       while (--nentries >= 0)
+               free((UnivPtr) *ourarray++);
+       free((UnivPtr) *nmptr);
+       *nmptr = NULL;
+}
+
+int
+alphacomp(a, b)
+UnivConstPtr   a,
+       b;
+{
+       return strcmp(*(const char **)a, *(const char **)b);
+}
+#endif /* F_COMPLETION */
diff --git a/usr/src/contrib/jove-4.14.6/scandir.h b/usr/src/contrib/jove-4.14.6/scandir.h
new file mode 100644 (file)
index 0000000..7c397c3
--- /dev/null
@@ -0,0 +1,19 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+extern int
+       alphacomp proto((UnivConstPtr, UnivConstPtr)),
+       jscandir proto((char *dir, char ***nmptr,
+               int (*qualify) proto((char *)),
+               int (*sorter)(UnivConstPtr, UnivConstPtr)));
+
+extern void
+       freedir proto((char * * *nmptr,int nentries));
+
+#ifdef MSDOS
+extern unsigned int    fmask;
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/screen.c b/usr/src/contrib/jove-4.14.6/screen.c
new file mode 100644 (file)
index 0000000..4e306a7
--- /dev/null
@@ -0,0 +1,1098 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "fp.h"
+#include "ctype.h"
+#include "termcap.h"
+#include "disp.h"
+#include <signal.h>
+
+#ifdef MSDOS
+#define SIGHUP 99
+#endif
+
+int    AbortCnt,
+       tabstop = 8;
+bool
+       CanScroll = NO;
+
+#ifdef TERMCAP
+private void
+       (*TTins_line) proto((int, int, int)),
+       (*TTdel_line) proto((int, int, int));
+#endif /* TERMCAP */
+
+struct scrimage
+       *DesiredScreen = NULL,
+       *PhysScreen = NULL;
+
+struct screenline      *Screen = NULL, /* the screen (a bunch of screenline) */
+                       *Curline = NULL;        /* current line */
+
+private struct screenline   *Savelines = NULL; /* another bunch (LI of them) */
+
+
+private char   *cursor;                        /* offset into current Line */
+
+char   *cursend;
+
+int    CapCol,
+       CapLine,
+
+       i_line,
+       i_col;
+
+#ifdef IBMPC
+extern unsigned char   CHPL;
+extern void            near normfun(),
+                       near scr_win(),
+                       near clr_page(),
+                       near clr_eoln();
+
+#endif
+
+void
+make_scr()
+{
+       register int    i;
+       register struct screenline      *ns;
+       register char   *nsp;
+
+       /* In case we are RESHAPING the window! */
+       if (DesiredScreen != NULL)
+               free((UnivPtr) DesiredScreen);
+       if (PhysScreen != NULL)
+               free((UnivPtr) PhysScreen);
+       if (Savelines != NULL)
+               free((UnivPtr) Savelines);
+       if (Screen != NULL) {
+               free((UnivPtr) Screen->s_line); /* free all the screen data */
+               free((UnivPtr) Screen);
+       }
+
+       DesiredScreen = (struct scrimage *) malloc((unsigned) LI * sizeof (struct scrimage));
+       PhysScreen = (struct scrimage *) malloc((unsigned) LI * sizeof (struct scrimage));
+
+       Savelines = (struct screenline *)
+                       malloc((unsigned) LI * sizeof(struct screenline));
+       ns = Screen = (struct screenline *)
+                       malloc((unsigned) LI * sizeof(struct screenline));
+
+       nsp = (char *) malloc((unsigned)CO * LI);
+
+       if (DesiredScreen == NULL
+       || PhysScreen == NULL
+       || Savelines == NULL
+       || ns == NULL
+       || nsp == NULL)
+       {
+               writef("\n\rCannot malloc screen!\n");
+               finish(SIGHUP);
+       }
+
+       for (i = 0; i < LI; i++) {
+               ns->s_line = nsp;
+               nsp += CO;
+               ns->s_length = nsp - 1;         /* End of Line */
+               ns += 1;
+       }
+       cl_scr(0);
+}
+
+void
+clrline(cp1, cp2)
+register char  *cp1,
+               *cp2;
+{
+       while (cp1 <= cp2)
+               *cp1++ = ' ';
+}
+
+
+/* Output one character (if necessary) at the current position */
+
+#ifdef MAC
+
+/* Character output to bit-mapped screen is very expensive. It makes
+   much more sense to write the entire line at once. So, we print all
+   the characters, whether already there or not, once the line is
+   complete.  */
+
+private char sput_buf[256];
+private int sput_len = 0;
+
+private void
+sput_start()
+{
+/*     if (i_line != CapLine || i_col != CapCol) */
+               NPlacur(i_line, i_col);
+       sput_len = 0;
+}
+
+private void
+sput_end()
+{
+       sput_buf[0] = (unsigned char) sput_len;
+       writechr(sput_buf);
+       sput_len = 0;
+}
+
+private void
+sputc(c)
+register int c;
+{
+       if (sput_len < sizeof(sput_buf)) {
+               *cursor++ = c;
+               sput_buf[++sput_len] = (c == '0')? 0xAF /* slashed zero */ : c;
+               CapCol++;
+               i_col++;
+       }
+}
+
+#else  /* !MAC */
+#ifdef IBMPC
+
+private bool force = NO;
+
+private void
+sputc(c)
+register int   c;
+{
+       if (force || (*cursor != c)) {
+               if (i_line != CapLine || i_col != CapCol)
+                       Placur(i_line, i_col);
+               *cursor++ = c;
+               normfun((char) c);
+               AbortCnt -= 1;
+               CapCol += 1;
+       } else {
+               cursor += 1;
+       }
+       i_col += 1;
+}
+
+#else  /* !IBMPC */
+
+#  define sputc(c)     { \
+       if (*cursor != (char) (c)) { \
+               do_sputc(c); \
+       } else { \
+               cursor++; \
+               i_col++; \
+       } \
+}
+
+private void
+do_sputc(c)
+register int   c;
+{
+       if (*cursor != c) {
+# ifdef        ID_CHAR
+               if (IN_INSmode)
+                       INSmode(OFF);
+# endif
+               if (i_line != CapLine || i_col != CapCol)
+                       Placur(i_line, i_col);
+               if (UL && (c & CHARMASK) == '_' && (*cursor & CHARMASK) != ' ')
+                       putstr(" \b");          /* Erase so '_' looks right. */
+               *cursor++ = c;
+               jputchar(c & CHARMASK);
+               AbortCnt -= 1;
+               CapCol += 1;
+       } else {
+               cursor += 1;
+       }
+       i_col += 1;
+}
+
+#endif /* !IBMPC */
+#endif /* !MAC */
+
+void
+cl_eol()
+{
+       if (cursor > cursend)
+               return;
+
+       if (cursor < Curline->s_length) {
+#ifdef TERMCAP
+               if (CE) {
+                       Placur(i_line, i_col);
+                       putpad(CE, 1);
+                       clrline(cursor, Curline->s_length);
+               } else {
+                       /* Ugh.  The slow way for dumb terminals. */
+                       register char *savecp = cursor;
+
+                       while (cursor <= Curline->s_length)
+                               sputc(' ');
+                       cursor = savecp;
+               }
+#else  /* !TERMCAP */
+               Placur(i_line, i_col);
+               clr_eoln();
+               clrline(cursor, Curline->s_length);
+#endif /* !TERMCAP */
+               Curline->s_length = cursor;
+       }
+}
+
+void
+cl_scr(doit)
+bool doit;
+{
+       register int    i;
+       register struct screenline      *sp = Screen;
+
+       for (i = 0; i < LI; i++, sp++) {
+               clrline(sp->s_line, sp->s_length);
+               sp->s_length = sp->s_line;
+               PhysScreen[i].s_id = 0;
+       }
+       if (doit) {
+#ifdef TERMCAP
+               putpad(CL, LI);
+#else  /* !TERMCAP */
+               clr_page();
+#endif /* !TERMCAP */
+               CapCol = CapLine = 0;
+               UpdMesg = YES;
+       }
+}
+
+/* Write `line' at the current position of `cursor'.  Stop when we
+   reach the end of the screen.  Aborts if there is a character
+   waiting.  */
+
+
+bool
+swrite(line, inversep, abortable)
+register char  *line;
+bool   inversep;
+bool   abortable;
+{
+       register int    n = cursend - cursor;
+       bool    aborted = NO;
+
+       if (n > 0) {
+
+               register int    c;
+               int     col = i_col;
+#ifdef MAC
+#              define  spit(c) sputc(c)
+#else  /* !MAC */
+#ifdef IBMPC
+#              define  spit(c) sputc(c)
+#else  /* !IBMPC */
+               int     or_byte = inversep ? 0200 : 0;
+#              define  spit(c) { int temp = (c) | or_byte; sputc(temp); }
+#endif /* !IBMPC */
+#endif /* !MAC */
+
+#ifdef MAC
+               sput_start();   /* Okay, because no interruption possible */
+#endif /* MAC */
+#ifdef IBMPC
+               force = inversep;  /* to force a redraw of the modeline */
+#endif
+               while ((c = *line++) != '\0') {
+#                      define  spot(c) { if (--n <= 0) break; spit(c); col += 1; }
+
+                       if (abortable && AbortCnt < 0) {
+                               AbortCnt = BufSize;
+                               if ((InputPending = charp()) != NO) {
+                                       aborted = YES;
+                                       break;
+                               }
+                       }
+                       if (c == '\t') {
+                               int     nchars;
+
+                               nchars = (tabstop - (col % tabstop));
+                               while (--nchars > 0)
+                                       spot(' ');
+                               c = ' ';
+                       } else if (jiscntrl(c)) {
+                               spot('^');
+                               c = (c == '\177') ? '?' : c + '@';
+#ifdef TERMCAP
+                       } else if (Hazeltine && c == '~') {
+                               c = '`';
+#endif
+#ifdef IBMPC
+                       } else if (c == 255) {
+                               c = 1;
+                       } else if (c == ' ' && inversep) {
+                               c = 255;
+#endif /* IBMPC */
+                       }
+                       spot(c);
+#                      undef   spot
+               }
+               if (n <= 0)
+                       spit(((*line=='\0') && (c!='\t') && !jiscntrl(c))? c : '!');
+               if (cursor > Curline->s_length)
+                       Curline->s_length = cursor;
+#ifdef MAC
+               sput_end();
+#endif /* MAC */
+#ifdef IBMPC
+               force = NO;
+#endif
+#              undef   spit
+       }
+       return !aborted;
+}
+
+/* This is for writing a buffer line to the screen.  This is to
+   minimize the amount of copying from one buffer to another buffer.
+   This gets the info directly from the disk buffers. */
+
+
+bool
+BufSwrite(linenum)
+int linenum;
+{
+       register int    n = cursend - cursor,
+                       col = 0,
+                       c = -1;
+       register char   *bp;
+       int     StartCol = DesiredScreen[linenum].s_offset,
+               visspace = DesiredScreen[linenum].s_window->w_flags & W_VISSPACE;
+       bool    aborted = NO;
+
+       bp = lcontents(DesiredScreen[linenum].s_lp);
+       if (*bp) {
+               for (;;) {
+                       if (col >= StartCol) {
+                               DesiredScreen[linenum].s_offset = col;
+                               break;
+                       }
+
+                       c = *bp++ & CHARMASK;
+                       if (c == '\0')
+                               break;
+                       if (c == '\t')
+                               col += (tabstop - (col % tabstop));
+                       else if (jiscntrl(c))
+                               col += 2;
+                       else
+                               col += 1;
+               }
+       }
+#ifdef MAC
+       sput_start();   /* Okay because we can't be interrupted */
+#endif
+       if (c != '\0') {
+               while ((c = *bp++) != '\0') {
+#                      define spot(c)  { if (--n <= 0) break; sputc(c); col += 1; }
+
+                       if (AbortCnt < 0) {
+                               AbortCnt = BufSize;
+                               if ((InputPending = charp()) != NO) {
+                                       aborted = YES;
+                                       break;
+                               }
+                       }
+                       if (c == '\t') {
+                               int     nchars = (tabstop - (col % tabstop));
+
+                               if (visspace) {
+                                       spot('>');
+                                       nchars -= 1;
+                               }
+                               while (--nchars > 0)
+                                       spot(' ');
+                               c = ' ';
+                       } else if (jiscntrl(c)) {
+                               spot('^');
+                               c = (c == '\177') ? '?' : c + '@';
+                       } else if (c == ' ' && visspace) {
+                               c = '_';
+#ifdef TERMCAP
+                       } else if (Hazeltine && c == '~') {
+                               c = '`';
+#endif
+#ifdef IBMPC
+                       } else if (c == 255) {
+                                  c = 1;
+#endif /* IBMPC */
+                       }
+                       spot(c);
+#                      undef   spot
+               }
+       }
+       if (n <= 0)
+               sputc(((*bp == '\0') && (c != '\t') && !jiscntrl(c))? c : '!');
+       if (cursor > Curline->s_length)
+               Curline->s_length = cursor;
+#ifdef MAC
+       sput_end();
+#endif
+       return !aborted;                /* Didn't abort */
+}
+
+void
+i_set(nline, ncol)
+register int   nline,
+               ncol;
+{
+       Curline = &Screen[nline];
+       cursor = Curline->s_line + ncol;
+       cursend = &Curline->s_line[CO - 1];
+       i_line = nline;
+       i_col = ncol;
+}
+
+#ifdef TERMCAP
+void
+SO_on()
+{
+       /* If there are magic cookies, then WHERE the SO string is
+          printed decides where the SO actually starts on the screen.
+          So it's important to make sure the cursor is positioned there
+          anyway.  I think this is right. */
+       if (SG != 0) {
+               Placur(i_line, i_col);
+               i_col += SG;
+               CapCol += SG;
+       }
+       putpad(SO, 1);
+}
+
+void
+SO_off()
+{
+       /* see comment in SO_on() */
+       if (SG != 0) {
+               Placur(i_line, i_col);
+               i_col += SG;
+               CapCol += SG;
+       }
+       putpad(SE, 1);
+}
+#endif /* TERMCAP */
+
+/* Insert `num' lines a top, but leave all the lines BELOW `bottom'
+   alone (at least they won't look any different when we are done).
+   This changes the screen array AND does the physical changes. */
+
+void
+v_ins_line(num, top, bottom)
+int num,
+    top,
+    bottom;
+{
+       register int    i;
+
+       /* Save the screen pointers. */
+
+       for(i = 0; i < num && top + i <= bottom; i++)
+               Savelines[i] = Screen[bottom - i];
+
+       /* Num number of bottom lines will be lost.
+          Copy everything down num number of times. */
+
+       for (i = bottom; i > top && i-num >= 0; i--)
+               Screen[i] = Screen[i - num];
+
+       /* Restore the saved ones, making them blank. */
+
+       for (i = 0; i < num; i++) {
+               Screen[top + i] = Savelines[i];
+               clrline(Screen[top + i].s_line, Screen[top + i].s_length);
+               Screen[top + i].s_length = Screen[top + i].s_line;
+       }
+
+#ifdef IBMPC
+       scr_win((int) -num, (unsigned char) top, 0, (unsigned char) bottom, CHPL-1);
+#else  /* !IBMPC */
+# ifdef        MAC
+       i_lines(top, bottom, num);
+# else /* !MAC */
+       (*TTins_line)(top, bottom, num);
+# endif        /* !MAC */
+#endif /* !IBMPC */
+}
+
+/* Delete `num' lines starting at `top' leaving the lines below `bottom'
+   alone.  This updates the internal image as well as the physical image.  */
+
+void
+v_del_line(num, top, bottom)
+int num,
+    top,
+    bottom;
+{
+       register int    i,
+                       bot;
+
+       bot = bottom;
+
+       /* Save the lost lines. */
+
+       for (i = 0; i < num && top + i <= bottom; i++)
+               Savelines[i] = Screen[top + i];
+
+       /* Copy everything up num number of lines. */
+
+       for (i = top; num + i <= bottom; i++)
+               Screen[i] = Screen[i + num];
+
+       /* Restore the lost ones, clearing them. */
+
+       for (i = 0; i < num; i++) {
+               Screen[bottom - i] = Savelines[i];
+               clrline(Screen[bot].s_line, Screen[bot].s_length);
+               Screen[bot].s_length = Screen[bot].s_line;
+               bot -= 1;
+       }
+
+#ifdef IBMPC
+       scr_win(num, (unsigned char) top, 0, (unsigned char) bottom, CHPL-1);
+#else  /* !IBMPC */
+# ifdef        MAC
+       d_lines(top, bottom, num);
+# else /* !MAC */
+       (*TTdel_line)(top, bottom, num);
+# endif        /* !MAC */
+#endif /* !IBMPC */
+}
+
+#ifdef TERMCAP /* remainder of this file */
+
+/* The cursor optimization happens here.  You may decide that this
+   is going too far with cursor optimization, or perhaps it should
+   limit the amount of checking to when the output speed is slow.
+   What ever turns you on ...   */
+
+struct cursaddr {
+       int     cm_numchars;
+       void    (*cm_proc) ();
+};
+
+private char   *Cmstr;
+private struct cursaddr        *HorMin,
+                       *VertMin,
+                       *DirectMin;
+
+private void
+       GENi_lines proto((int, int, int)),
+       GENd_lines proto((int, int, int)),
+       ForMotion proto((int)),
+       ForTab proto((int)),
+       BackMotion proto((int)),
+       RetTab proto((int)),
+       DownMotion proto((int)),
+       UpMotion proto((int)),
+       GoDirect proto((int, int)),
+       HomeGo proto((int, int)),
+       BottomUp proto((int, int));
+
+
+private struct cursaddr        WarpHor[] = {
+       0,      ForMotion,
+       0,      ForTab,
+       0,      BackMotion,
+       0,      RetTab
+};
+
+private struct cursaddr        WarpVert[] = {
+       0,      DownMotion,
+       0,      UpMotion
+};
+
+private struct cursaddr        WarpDirect[] = {
+       0,      GoDirect,
+       0,      HomeGo,
+       0,      BottomUp
+};
+
+#undef FORWARD
+#define        FORWARD         0       /* Move forward */
+#define FORTAB         1       /* Forward using tabs */
+#undef BACKWARD
+#define        BACKWARD        2       /* Move backward */
+#define RETFORWARD     3       /* Beginning of line and then tabs */
+#define NUMHOR         4
+
+#define DOWN           0       /* Move down */
+#define UPMOVE         1       /* Move up */
+#define NUMVERT                2
+
+#define DIRECT         0       /* Using CM */
+#define HOME           1       /* HOME */
+#define LOWER          2       /* Lower Line */
+#define NUMDIRECT      3
+
+#define        home()          Placur(0, 0)
+#define LowLine()      { putpad(LL, 1); CapLine = ILI; CapCol = 0; }
+#define PrintHo()      { putpad(HO, 1); CapLine = CapCol = 0; }
+
+int    phystab = 8;
+
+private void
+GoDirect(line, col)
+register int   line,
+               col;
+{
+       putpad(Cmstr, 1);
+       CapLine = line;
+       CapCol = col;
+}
+
+private void
+RetTab(col)
+register int   col;
+{
+       jputchar('\r');
+       CapCol = 0;
+       ForTab(col);
+}
+
+private void
+HomeGo(line, col)
+int line,
+    col;
+{
+       PrintHo();
+       DownMotion(line);
+       ForTab(col);
+}
+
+private void
+BottomUp(line, col)
+register int   line,
+               col;
+{
+       LowLine();
+       UpMotion(line);
+       ForTab(col);
+}
+
+/* Tries to move forward using tabs (if possible).  It tabs to the
+   closest tabstop which means it may go past 'destcol' and backspace
+   to it. */
+
+private void
+ForTab(destcol)
+int    destcol;
+{
+       register int    tabgoal,
+                       ntabs,
+                       tabstp = phystab;
+
+       if (TABS && (tabstp > 0)) {
+               tabgoal = destcol + (tabstp / 2);
+               tabgoal -= (tabgoal % tabstp);
+
+               /* Don't tab to last place or else it is likely to screw up. */
+               if (tabgoal >= CO)
+                       tabgoal -= tabstp;
+
+               ntabs = (tabgoal / tabstp) - (CapCol / tabstp);
+               while (--ntabs >= 0)
+                       jputchar('\t');
+               CapCol = tabgoal;
+       }
+       if (CapCol > destcol)
+               BackMotion(destcol);
+       else if (CapCol < destcol)
+               ForMotion(destcol);
+}
+
+private void
+ForMotion(destcol)
+register int   destcol;
+{
+       register int    nchars = destcol - CapCol;
+       register char   *cp = &Screen[CapLine].s_line[CapCol];
+
+       while (--nchars >= 0)
+               jputchar(*cp++ & CHARMASK);
+       CapCol = destcol;
+}
+
+private void
+BackMotion(destcol)
+register int   destcol;
+{
+       register int    nchars = CapCol - destcol;
+
+       if (BC)
+               while (--nchars >= 0)
+                       putpad(BC, 1);
+       else
+               while (--nchars >= 0)
+                       jputchar('\b');
+       CapCol = destcol;
+}
+
+private void
+DownMotion(destline)
+register int   destline;
+{
+       register int    nlines = destline - CapLine;
+
+       while (--nlines >= 0)
+               putpad(DO, 1);
+       CapLine = destline;
+}
+
+private void
+UpMotion(destline)
+register int   destline;
+{
+       register int    nchars = CapLine - destline;
+
+       while (--nchars >= 0)
+               putpad(UP, 1);
+       CapLine = destline;
+}
+
+#ifdef ID_CHAR
+static int     EIlen;
+#endif
+
+void
+InitCM()
+{
+       HOlen = HO ? strlen(HO) : 1000;
+       LLlen = LL ? strlen(LL) : 1000;
+       UPlen = UP ? strlen(UP) : 1000;
+#ifdef ID_CHAR
+       if (EI)
+               EIlen = strlen(EI);
+#endif
+}
+
+private int ForNum proto((int from, int to));
+
+void
+Placur(line, col)
+int line,
+    col;
+{
+       int     dline,          /* Number of lines to move */
+               dcol;           /* Number of columns to move */
+       register int    best,
+                       i;
+       register struct cursaddr        *cp;
+       int     xtracost = 0;   /* Misc addition to cost. */
+
+#define CursMin(which,addrs,max)       { \
+       for (best = 0, cp = &(addrs)[1], i = 1; i < (max); i++, cp++) \
+               if (cp->cm_numchars < (addrs)[best].cm_numchars) \
+                       best = i; \
+       (which) = &(addrs)[best]; \
+}
+
+       if (line == CapLine && col == CapCol)
+               return;         /* We are already there. */
+
+       dline = line - CapLine;
+       dcol = col - CapCol;
+#ifdef ID_CHAR
+       if (IN_INSmode && MI)
+               xtracost = EIlen + IMlen;
+       /* If we're already in insert mode, it is likely that we will
+          want to be in insert mode again, after the insert. */
+#endif
+
+       /* Number of characters to move horizontally for each case.
+          1: Just move forward by typing the right character on the screen.
+          2: Print the correct number of back spaces.
+          3: Try tabbing to the correct place.
+          4: Try going to the beginning of the line, and then tab. */
+
+       if (dcol == 1 || dcol == 0) {           /* Most common case. */
+               HorMin = &WarpHor[FORWARD];
+               HorMin->cm_numchars = dcol + xtracost;
+       } else {
+               WarpHor[FORWARD].cm_numchars = dcol >= 0 ? dcol + xtracost : 1000;
+               WarpHor[BACKWARD].cm_numchars = dcol < 0 ? -(dcol + xtracost) : 1000;
+               WarpHor[FORTAB].cm_numchars = dcol >= 0 && TABS ?
+                               ForNum(CapCol, col) + xtracost : 1000;
+               WarpHor[RETFORWARD].cm_numchars = (xtracost + 1 + (TABS ? ForNum(0, col) : col));
+
+               /* Which is the shortest of the bunch */
+
+               CursMin(HorMin, WarpHor, NUMHOR);
+       }
+
+       /* Moving vertically is more simple. */
+
+       WarpVert[DOWN].cm_numchars = dline >= 0 ? dline : 1000;
+       WarpVert[UPMOVE].cm_numchars = dline < 0 ? ((-dline) * UPlen) : 1000;
+
+       /* Which of these is simpler */
+       CursMin(VertMin, WarpVert, NUMVERT);
+
+       /* Homing first and lowering first are considered
+          direct motions.
+          Homing first's total is the sum of the cost of homing
+          and the sum of tabbing (if possible) to the right. */
+
+       if (VertMin->cm_numchars + HorMin->cm_numchars <= 3) {
+               DirectMin = &WarpDirect[DIRECT];        /* A dummy ... */
+               DirectMin->cm_numchars = 100;
+       } else {
+               WarpDirect[DIRECT].cm_numchars = CM ?
+                               strlen(Cmstr = tgoto(CM, col, line)) : 1000;
+               WarpDirect[HOME].cm_numchars = HOlen + line +
+                               WarpHor[RETFORWARD].cm_numchars;
+               WarpDirect[LOWER].cm_numchars = LLlen + ((ILI - line) * UPlen) +
+                               WarpHor[RETFORWARD].cm_numchars;
+               CursMin(DirectMin, WarpDirect, NUMDIRECT);
+       }
+
+       if (HorMin->cm_numchars + VertMin->cm_numchars < DirectMin->cm_numchars) {
+               if (line != CapLine)
+                       (*(void (*)ptrproto((int)))VertMin->cm_proc)(line);
+               if (col != CapCol) {
+#ifdef ID_CHAR
+                       if (IN_INSmode) /* We may use real characters ... */
+                               INSmode(OFF);
+#endif
+                       (*(void (*)ptrproto((int)))HorMin->cm_proc)(col);
+               }
+       } else {
+#ifdef ID_CHAR
+               if (IN_INSmode && !MI)
+                       INSmode(OFF);
+#endif
+               (*(void (*)ptrproto((int, int)))DirectMin->cm_proc)(line, col);
+       }
+}
+
+#define abs(x) ((x) >= 0 ? (x) : -(x))
+
+private int
+ForNum(from, to)
+register int   from;
+int to;
+{
+       register int    tabgoal,
+                       tabstp = phystab;
+       int             numchars = 0;
+
+       if (from >= to)
+               return from - to;
+       if (TABS && (tabstp > 0)) {
+               tabgoal = to + (tabstp / 2);
+               tabgoal -= (tabgoal % tabstp);
+               if (tabgoal >= CO)
+                       tabgoal -= tabstp;
+               numchars = (tabgoal / tabstop) - (from / tabstp);
+               from = tabgoal;
+       }
+       return numchars + abs(from - to);
+}
+
+#ifdef WIRED_TERMS
+
+private void
+BGi_lines(top, bottom, num)
+int top,
+    bottom,
+    num;
+{
+       writef("\033[%d;%dr\033[%dL\033[r", top + 1, bottom + 1, num);
+       CapCol = CapLine = 0;
+}
+
+private void
+SUNi_lines(top, bottom, num)
+int top,
+    bottom,
+    num;
+{
+       Placur(bottom - num + 1, 0);
+       writef("\033[%dM", num);
+       Placur(top, 0);
+       writef("\033[%dL", num);
+}
+
+private void
+C100i_lines(top, bottom, num)
+int top,
+    bottom,
+    num;
+{
+       if (num <= 1) {
+               GENi_lines(top, bottom, num);
+               return;
+       }
+       writef("\033v%c%c%c%c", ' ', ' ', ' ' + bottom + 1, ' ' + CO);
+       CapLine = CapCol = 0;
+       Placur(top, 0);
+       while (num--)
+               putpad(AL, ILI - CapLine);
+       writef("\033v%c%c%c%c", ' ', ' ', ' ' + LI, ' ' + CO);
+       CapLine = CapCol = 0;
+}
+
+#endif /* WIRED_TERMS */
+
+private void
+GENi_lines(top, bottom, num)
+int top,
+    bottom,
+    num;
+{
+       register int    i;
+
+       if (CS) {
+               putpad(tgoto(CS, bottom, top), 1);
+               CapCol = CapLine = 0;
+               Placur(top, 0);
+               if (M_SR && (num > 1)) {
+                       char    minibuf[16];
+
+                       sprintf(minibuf, M_SR, num);
+                       putpad(minibuf, bottom - top);
+               } else {
+                       for (i = 0; i < num; i++)
+                               putpad(SR, bottom - top);
+               }
+               putpad(tgoto(CS, ILI, 0), 1);
+               CapCol = CapLine = 0;
+       } else {
+               Placur(bottom - num + 1, 0);
+               if (M_DL && (num > 1)) {
+                       putargpad(M_DL, num, ILI - CapLine);
+               } else {
+                       for (i = 0; i < num; i++)
+                               putpad(DL, ILI - CapLine);
+               }
+               Placur(top, 0);
+               if (M_AL && (num > 1)) {
+                       putargpad(M_AL, num, ILI - CapLine);
+               } else {
+                       for (i = 0; i < num; i++)
+                               putpad(AL, ILI - CapLine);
+               }
+       }
+}
+
+#ifdef WIRED_TERMS
+
+private void
+BGd_lines(top, bottom, num)
+int top,
+    bottom,
+    num;
+{
+       writef("\033[%d;%dr\033[%dM\033[r", top + 1, bottom + 1, num);
+       CapCol = CapLine = 0;
+}
+
+private void
+SUNd_lines(top, bottom, num)
+int top,
+    bottom,
+    num;
+{
+       Placur(top, 0);
+       writef("\033[%dM", num);
+       Placur(bottom + 1 - num, 0);
+       writef("\033[%dL", num);
+}
+
+private void
+C100d_lines(top, bottom, num)
+int top,
+    bottom,
+    num;
+{
+       if (num <= 1) {
+               GENd_lines(top, bottom, num);
+               return;
+       }
+       writef("\033v%c%c%c%c", ' ', ' ', ' ' + bottom + 1, ' ' + CO);
+       CapLine = CapCol = 0;
+       Placur(top, 0);
+       while (num--)
+               putpad(DL, ILI - CapLine);
+       writef("\033v%c%c%c%c", ' ', ' ', ' ' + LI, ' ' + CO);
+       CapLine = CapCol = 0;
+}
+
+#endif /* WIRED_TERMS */
+
+private void
+GENd_lines(top, bottom, num)
+int top,
+    bottom,
+    num;
+{
+       register int    i;
+
+       if (CS) {
+               putpad(tgoto(CS, bottom, top), 1);
+               CapCol = CapLine = 0;
+               Placur(bottom, 0);
+               if (M_SF && (num > 1)) {
+                       char    minibuf[16];
+
+                       sprintf(minibuf, M_SF, num);
+                       putpad(minibuf, bottom - top);
+               } else {
+                       for (i = 0; i < num; i++)
+                               putpad(SF, bottom - top);
+               }
+               putpad(tgoto(CS, ILI, 0), 1);
+               CapCol = CapLine = 0;
+       } else {
+               Placur(top, 0);
+               if (M_DL && (num > 1)) {
+                       putargpad(M_DL, num, ILI - top);
+               } else {
+                       for (i = 0; i < num; i++)
+                               putpad(DL, ILI - top);
+               }
+               Placur(bottom + 1 - num, 0);
+               if (M_AL && (num > 1)) {
+                       putargpad(M_AL, num, ILI - CapLine);
+               } else {
+                       for (i = 0; i < num; i++)
+                               putpad(AL, ILI - CapLine);
+               }
+       }
+}
+
+private const struct ID_lookup {
+       char    *ID_name;
+       void    (*I_proc) proto((int, int, int));       /* proc to insert lines */
+       void    (*D_proc) proto((int, int, int));       /* proc to delete lines */
+} ID_trms[] = {
+       "generic",      GENi_lines,     GENd_lines,     /* This should stay here */
+#ifdef WIRED_TERMS
+       "sun",          SUNi_lines,     SUNd_lines,
+       "bg",           BGi_lines,      BGd_lines,
+       "c1",           C100i_lines,    C100d_lines,
+#endif /* WIRED_TERMS */
+       NULL,           0,              0
+};
+
+void
+IDline_setup(tname)
+char   *tname;
+{
+       register const struct ID_lookup *idp;
+
+       for (idp = &ID_trms[1]; idp->ID_name; idp++)
+               if (strncmp(idp->ID_name, tname, strlen(idp->ID_name)) == 0)
+                       break;
+       if (idp->ID_name == NULL)
+               idp = &ID_trms[0];
+       TTins_line = idp->I_proc;
+       TTdel_line = idp->D_proc;
+}
+
+#endif /* TERMCAP */
diff --git a/usr/src/contrib/jove-4.14.6/screen.h b/usr/src/contrib/jove-4.14.6/screen.h
new file mode 100644 (file)
index 0000000..9f35780
--- /dev/null
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+struct screenline {
+       char    *s_line,
+               *s_length;
+};
+
+extern struct screenline       *Screen,
+                               *Curline;
+
+extern char *cursend;
+
+extern int
+       i_line,
+       i_col,
+       AbortCnt,
+
+       CapLine,        /* cursor line and cursor column */
+       CapCol;
+
+extern bool
+       CanScroll,      /* can this terminal scroll? */
+
+       BufSwrite proto((int linenum)),
+       swrite proto((char *line,bool inversep,bool abortable));
+
+extern void
+       IDline_setup proto((char *tname)),
+       Placur proto((int line,int col)),
+       cl_eol proto((void)),
+       cl_scr proto((bool doit)),
+       clrline proto((char *cp1,char *cp2)),
+       i_set proto((int nline,int ncol)),
+       make_scr proto((void)),
+       v_ins_line proto ((int num, int top, int bottom)),
+       v_del_line proto ((int num, int top, int bottom)),
+       InitCM proto((void)),
+       SO_off proto((void)),
+       SO_on proto((void));
diff --git a/usr/src/contrib/jove-4.14.6/setmaps.c b/usr/src/contrib/jove-4.14.6/setmaps.c
new file mode 100644 (file)
index 0000000..64f02d0
--- /dev/null
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define TXT_TO_C       1       /* must be a number for MAC compiler */
+
+#include <stdio.h>
+
+#include "funcdefs.c"
+
+#ifdef MAC
+#include "vars.c"
+#endif
+
+private int
+matchcmd(choices, what)
+register const struct cmd      choices[];
+register char  *what;
+{
+       register int    i;
+
+       for (i = 0; choices[i].Name != NULL; i++) {
+               if (what[0] == choices[i].Name[0]
+               && strcmp(what, choices[i].Name) == 0)
+                       return i;
+       }
+       return -1;
+}
+
+#ifdef MAC
+matchvar(choices, what)
+register struct variable choices[];
+register char  *what;
+{
+       register int    len;
+       int     i;
+
+       len = strlen(what);
+       for (i = 0; choices[i].Name != NULL; i++) {
+               if (what[0] == choices[i].Name[0]
+               && strcmp(what, choices[i].Name) == 0)
+                       return i;
+       }
+       return -1;
+}
+#endif
+
+static int
+StartsWith(s, pre)
+const char *s, *pre;
+{
+    return strncmp(s, pre, strlen(pre)-1) == 0;
+}
+
+private char *
+PPchar(c)
+int    c;
+{
+       static char     str[16];
+       char    *cp = str;
+
+       if (c & 0200) {
+               c &= ~0200;
+               strcpy(cp, "M-");
+               cp += 2;
+       }
+       if (c == '\033')
+               strcpy(cp, "ESC");
+       else if (c < ' ')
+               (void) sprintf(cp, "C-%c", c + '@');
+       else if (c == '\177')
+               strcpy(cp, "^?");
+       else
+               (void) sprintf(cp, "%c", c);
+       return str;
+}
+
+private void
+extract(into, from)
+char   *into,
+       *from;
+{
+       from += 2;      /* Past tab and first double quote. */
+       while ((*into = *from++) != '"')
+               into += 1;
+       *into = '\0';
+}
+
+
+void
+
+#ifdef MAC
+_main()                /* for Mac, so we can use redirection */
+#else
+main()
+#endif
+{
+       FILE    *ifile,
+               *of;
+       char    line[100],
+               comname[70];
+       int     comnum,
+               ch = 0,
+               savech = -1,
+               errors = 0;
+#ifdef MAC
+       char    *which;
+       bool    inmenu = NO;
+#endif
+
+       ifile = stdin;
+       of = stdout;
+       if (ifile == NULL || of == NULL) {
+               printf("Cannot read input or write output.\n");
+               exit(1);
+       }
+       while (fgets(line, sizeof line, ifile) != NULL) {
+               if (StartsWith(line, "#if")) {
+                       savech = ch;
+                       fprintf(of, line);
+                       continue;
+               } else if (StartsWith(line, "#else")) {
+                       if (savech == -1)
+                               fprintf(stderr, "WARNING: ifdef/endif mismatch!\n");
+                       else
+                               ch = savech;
+                       fprintf(of, line);
+                       continue;
+               } else if (StartsWith(line, "#endif")) {
+                       savech = -1;
+                       fprintf(of, line);
+                       continue;
+#ifdef MAC
+               } else if (StartsWith(line, "#MENU")) {
+                       inmenu = YES;
+                       continue;
+#endif
+               } else if (!StartsWith(line, "\t\"")) {
+                       /* If unrecognized, pass and prepare to start new table */
+                       fprintf(of, line);
+                       ch = 0;
+                       continue;
+               }
+               extract(comname, line);
+               if (strcmp(comname, "unbound") == 0) {
+                       comnum = -1;
+               } else {
+                       comnum = matchcmd(commands, comname);
+#ifdef MAC
+                       which = "commands";
+                       if (comnum < 0 && inmenu) {
+                               comnum = matchvar(variables, comname);
+                               which = "variables";
+                       }
+#endif
+                       if (comnum < 0) {
+                               fprintf(stderr, "Warning: cannot find \"%s\".\n", comname);
+                               errors += 1;
+                       }
+               }
+#ifdef MAC
+               if (inmenu) {
+                       if (comnum < 0)
+                               fprintf(of, "\t(data_obj *) NULL,\n");
+                       else
+                               fprintf(of, "\t(data_obj *) &%s[%d],\n",which, comnum);
+               } else /*...*/
+#endif
+               {
+                       if (comnum < 0)
+                               fprintf(of, "\t(data_obj *) NULL,\t\t/* %s */\n", PPchar(ch));
+                       else
+                               fprintf(of, "\t(data_obj *) &commands[%d],\t/* %s */\n", comnum, PPchar(ch));
+                       ch += 1;
+               }
+       }
+       fclose(of);
+       fclose(ifile);
+       exit(errors);
+}
diff --git a/usr/src/contrib/jove-4.14.6/style.h b/usr/src/contrib/jove-4.14.6/style.h
new file mode 100644 (file)
index 0000000..99a2686
--- /dev/null
@@ -0,0 +1,9 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+
+
diff --git a/usr/src/contrib/jove-4.14.6/sysdep.h b/usr/src/contrib/jove-4.14.6/sysdep.h
new file mode 100644 (file)
index 0000000..56c56ff
--- /dev/null
@@ -0,0 +1,289 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+
+/* Determine if really ANSI C */
+#ifdef __STDC__
+# if   __STDC__ >= 0
+#  define REALSTDC 1
+# endif
+#endif
+
+#ifdef THINK_C
+# define MAC 1
+/* Think C does not have a "defined" preprocessor operator.
+ * This kludge is intended to avoid the problem.
+ * ??? Perhaps Think C has been fixed by now. -- DHR
+ */
+# define defined(x) (x)
+  typedef int size_t;
+#endif
+
+/* The operating system (MSDOS or MAC) must be defined by this point.
+   IBMPC is defined in the Makefile. */
+
+#ifndef        MSDOS
+# ifndef       MAC
+#   define UNIX        1       /* default to UNIX */
+# endif
+#endif
+
+#ifdef MAC
+# define byte_zero(s,n) setmem((s),(n),0)
+# define NBUF 64
+# define JBUFSIZ 1024
+#endif
+
+#ifdef MSDOS
+# ifdef        M_I86LM         /* large memory model */
+#  define NBUF                 64
+# else
+#  define NBUF                 3
+#  define SMALL                1
+# endif
+# define JBUFSIZ               512             /* or 1024 */
+#endif
+
+#ifdef UNIX
+# ifdef        pdp11
+#  define SMALL        1
+#  define JBUFSIZ      512     /* or 1024 */
+#  define NBUF         3
+# else
+#  define VMUNIX       1       /* Virtual Memory UNIX */
+#  define JBUFSIZ      1024
+#  ifdef       iAPX286
+#   define NBUF                48      /* NBUF*JBUFSIZ must be less than 64 kB */
+#  else
+#   define NBUF        64      /* number of disk buffers */
+#  endif       /* iAPX286 */
+# endif
+#endif
+
+#ifdef SVR3
+# define SYSVR3                1       /* system 5, rel. 3 */
+#endif
+
+#ifdef SVR2
+# define SYSVR2                1       /* system 5, rel. 2 */
+#endif
+
+#ifdef BSD
+# define BSD4_2                1       /* Berkeley 4.2 BSD or later */
+#endif
+
+#if    defined(sun) || defined(__sun__)
+# define BSD4_2        1       /* True enough for Jove's purposes */
+/* # define YP_PASSWD  1       /* if you are a sun running the yellow pages */
+# ifdef        SUNOS4  /* gone to void */
+#  define TERMIOS      1       /* uses termio struct for terminal modes */
+#  define DIRENT       1       /* Posix style dirent.h */
+#  define SIGRESULT    void
+#  define SIGRETURN    { return; }
+#ifdef GCC
+#  define POSIX_UNISTD 1       /* prototypes in unistd.h, don't use our own */
+#endif
+# endif
+#endif
+
+#if    defined(BSD386)
+# define BSD4_2        1       /* True enough for Jove's purposes */
+#  define TERMIOS      1       /* uses termio struct for terminal modes */
+#  define DIRENT       1       /* Posix style dirent.h */
+#  define SIGRESULT    void
+#  define SIGRETURN    { return; }
+#  define POSIX_UNISTD 1       /* prototypes in unistd.h, don't use our own */
+#endif
+
+#define KILL0          1       /* kill(pid, 0) returns 0 if proc exists */
+
+#if    defined(ultrix) || defined(__ultrix__)
+# define ULTRIX        1
+# define BSD4_2                1       /* True enough for Jove's purposes */
+# define SIGRESULT  void
+# define SIGRETURN  {return;}
+#endif
+
+/* M_XENIX is defined by the Compiler */
+/* SYSV should be defined for (System III/System V) UNIX systems */
+
+#ifdef SYSVR4
+# define SYSVR3                1
+# define DIRENT                1       /* Posix style dirent.h */
+# define POSIX_UNISTD  1       /* prototypes in unistd.h, don't use our own */
+#endif
+
+#ifdef SYSVR3
+# ifndef       SYSVR2
+#  define SYSVR2       1       /* SYSVR2 is a subset of SYSVR3 */
+# endif
+# define       SIGRESULT       void
+# define       SIGRETURN       { return; }
+# ifndef       SYSVR4
+#  define      SIGCHLD         SIGCLD
+# endif
+#endif
+
+#ifdef SYSVR2
+# ifndef       SYSV
+#  define SYSV 1       /* SYSV is a subset of SYSVR2 */
+# endif
+#endif
+
+#ifdef M_XENIX
+# define iAPX286 1     /* we have segments */
+# define BSD_DIR       1
+#endif
+
+#if defined(SYSTYPE_BSD43) || defined(__SYSTYPE_BSD43)
+# define BSD4_2                1       /* RISCOS4.x on MIPS */
+#endif
+
+#ifdef BSD4_2
+# define byte_copy(from, to, len)      bcopy((UnivConstPtr)(from), (UnivPtr)(to), (size_t)(len))
+# define byte_zero(s, n)       bzero((UnivPtr)(s), (size_t)(n))
+# define strchr        index
+# define strrchr       rindex
+# define BSD_SIGS      1       /* Berkeley style signals */
+# define BSD_WAIT      1       /* Berkeley style sys/wait.h */
+# define WAIT3         1       /* Berkeley style wait3() */
+# define BSD_DIR       1       /* Berkeley style dirent routines */
+# define VFORK         1       /* if you have vfork(2) */
+# define JOB_CONTROL   1       /* if you have job stopping */
+# define MENLO_JCL     1
+# define HAVE_GETWD    1       /* have the getwd() routine */
+# ifndef TERMIOS
+# define SGTTY         1       /* uses SGTTY for terminal modes */
+#endif
+#endif
+
+#ifdef A_UX            /* A/UX on a MacII (Do *not* define "MAC") */
+/* It might be better to define POSIX compatibility and try that. Oh well! */
+# define BSD_WAIT      1       /* Berkeley style sys/wait.h */
+# define BSD_DIR       1       /* Berkeley style dirent routines */
+# define WAIT3         1       /* Berkeley style wait3() */
+# define BSD_SIGS      1       /* Berkeley style signals */
+# define SYSV          1       /* System V everything else */
+# define TERMIO        1       /* uses termio struct for terminal modes */
+#endif
+
+#ifdef AIX     /* from guttman@mashie.ece.jhu.edu via buchanan@cs.ubc.ca */
+# define BSD_DIR
+# define HAVE_GETWD
+# define SYSV
+# define TERMIO        1       /* uses termio struct for terminal modes */
+#endif
+
+#if    (defined(mips) || defined(__mips__)) && !defined(BSD4_2)
+/*
+ * Older MIPS (UMIPS-SYSV, anything other than their 4.3 port before
+ * RISCOS4.x) and SGI 4D OSes (anything before Irix3.3) have BSD style wait,
+ * and directory routines if you link -lbsd and define -I/usr/include/bsd on
+ * the compile line. But they have SysV style signals.  Jove was ported to the
+ * SGI 68K boxes once, but it the mods seem to have been lost.
+ */
+# ifndef       ULTRIX
+   /* Not a DECstation 3100 or suchlike */
+#  define BSD_WAIT     1       /* Berkeley style sys/wait.h */
+#  define BSD_DIR      1       /* Berkeley style dirent routines */
+# else
+#  undef ULTRIX                1       /* Only needed it for this test */
+# endif
+# if   defined(sgi) || defined(__sgi__)
+#  define WAIT3                1       /* Berkeley style wait3() */
+#  define JOB_CONTROL  1       /* if you have job stopping */
+#  define HAVE_GETWD   1
+   /* All the following are for Irix 3.3 onwards */
+#  define BSD_SIGS     1       /* Berkeley style signals */
+#  define DIRENT       1       /* Posix style dirent.h */
+#  define TERMIOS      1       /* new Posix terminal mode management */
+#  ifndef REALSTDC
+#   define REALSTDC    1       /* close enough for Jove's needs */
+#  endif
+#  define HAVE_STRERROR        1       /* have ANSI strerror() */
+#  define POSIX_UNISTD 1       /* prototypes in unistd.h, don't use our own */
+#  define SIGRESULT    void
+#  define SIGRETURN    { return; }
+#  undef SIGCHLD               /* #define SIGCHLD SIGCLD in signal.h */
+# endif
+#endif
+
+#ifndef        BSD4_2
+# define KBDSIG                SIGEMT
+#endif
+
+#if    defined(SYSV) || defined(MSDOS) || defined(M_XENIX)
+# include <memory.h>
+# define byte_copy(from, to, count)    memcpy((UnivPtr)(to), (UnivConstPtr)(from), (size_t)(count))
+# define byte_zero(s, n)               memset((UnivPtr)(s), 0, (size_t)(n))
+#endif
+
+#ifdef UNIX
+# define TERMCAP       1
+# define ASCII7        1
+#endif
+
+#ifdef ASCII7  /* seven bit characters */
+# define NCHARS 0200
+#else
+# define NCHARS 0400
+#endif
+
+#define CHARMASK (NCHARS - 1)
+
+#ifndef        MSDOS
+# define FILESIZE      256
+#else  /* MSDOS */
+# define FILESIZE      64
+#endif /* MSDOS */
+
+#ifndef        SIGRESULT       /* default to old-style */
+# define       SIGRESULT       int
+# define       SIGRETURN       { return 0; }
+#endif
+
+#ifndef        BSD4_2
+# ifdef        MENLO_JCL
+#  define signal       sigset
+# endif        /* MENLO_JCL */
+#endif
+
+#ifdef BSD_SIGS
+extern long    SigMask;
+
+# define SigHold(s)    sigblock(SigMask |= sigmask((s)))
+# define SigRelse(s)   sigsetmask(SigMask &= ~sigmask((s)))
+#else
+# define SigHold(s)    sighold(s)
+# define SigRelse(s)   sigrelse(s)
+# define killpg(pid, sig)      kill(-(pid), (sig))
+#endif
+
+/* On a system which limits JOVE to a very small data segment,
+ * it may be worthwhile limiting daddr to a short.  This reduces
+ * the size of a Line descriptor, but reduces the addressable size
+ * of the temp file.  This is reasonable on a PDP-11 and perhaps
+ * an iAPX*86.
+ */
+
+#ifdef SMALL
+  typedef unsigned short       daddr;
+#else
+  typedef unsigned long        daddr;
+#endif /* SMALL */
+
+#define        NULL_DADDR              ((daddr) 0)
+
+#if !defined(TERMIOS) && !defined(SGTTY)
+# define TERMIO        1       /* uses termio struct for terminal modes */
+#endif
+
+#ifdef SYSV
+# define MAILSPOOL "/usr/mail"
+#else
+# define MAILSPOOL "/usr/spool/mail"
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/tags b/usr/src/contrib/jove-4.14.6/tags
new file mode 100644 (file)
index 0000000..3f40b88
--- /dev/null
@@ -0,0 +1,941 @@
+AbbrevExpand   abbrev.c        /^AbbrevExpand()$/
+AddError       proc.c  /^AddError(laste, errline, buf, line, charpos)$/
+AddLines       disp.c  /^AddLines(at, num)$/
+AddSpecial     insert.c        /^AddSpecial()$/
+AdjustScrollBar        mac.c   /^AdjustScrollBar(w)    \/* redo existing control *\/$/
+AllMarkSet     marks.c /^AllMarkSet(b, line, col)$/
+AppReg io.c    /^AppReg()$/
+Apropos        keymaps.c       /^Apropos()$/
+BGd_lines      screen.c        /^BGd_lines(top, bottom, num)$/
+BGi_lines      screen.c        /^BGi_lines(top, bottom, num)$/
+BList  c.c     /^BList()$/
+BSexpr c.c     /^BSexpr()$/
+BUpList        c.c     /^BUpList()$/
+B_HASH io.c    /^#define B_HASH(bno)   ((bno) % HASHSIZE)$/
+BackChar       move.c  /^BackChar()$/
+BackMotion     screen.c        /^BackMotion(destcol)$/
+BackPara       paragraph.c     /^BackPara()$/
+BackWord       move.c  /^BackWord()$/
+BindAKey       keymaps.c       /^BindAKey()$/
+BindMac        keymaps.c       /^BindMac()$/
+BindMtoW       abbrev.c        /^BindMtoW()$/
+BindSomething  keymaps.c       /^BindSomething(proc, map)$/
+BindWMap       keymaps.c       /^BindWMap(map, lastkey, cmd)$/
+Bof    move.c  /^Bof()$/
+Bol    move.c  /^Bol()$/
+Bos    move.c  /^Bos()$/
+BottomUp       screen.c        /^BottomUp(line, col)$/
+Bow    disp.c  /^Bow()$/
+Buf0Select     buf.c   /^void Buf0Select() { BufNSelect(0); }$/
+Buf1Select     buf.c   /^void Buf1Select() { BufNSelect(1); }$/
+Buf2Select     buf.c   /^void Buf2Select() { BufNSelect(2); }$/
+Buf3Select     buf.c   /^void Buf3Select() { BufNSelect(3); }$/
+Buf4Select     buf.c   /^void Buf4Select() { BufNSelect(4); }$/
+Buf5Select     buf.c   /^void Buf5Select() { BufNSelect(5); }$/
+Buf6Select     buf.c   /^void Buf6Select() { BufNSelect(6); }$/
+Buf7Select     buf.c   /^void Buf7Select() { BufNSelect(7); }$/
+Buf8Select     buf.c   /^void Buf8Select() { BufNSelect(8); }$/
+Buf9Select     buf.c   /^void Buf9Select() { BufNSelect(9); }$/
+BufErase       buf.c   /^BufErase()$/
+BufKill        buf.c   /^BufKill()$/
+BufList        buf.c   /^BufList()$/
+BufMPrint      mac.c   /^BufMPrint(b,i)$/
+BufMinorMode   buf.h   /^#define BufMinorMode(b, x)    (((b)->b_minor & (x)) !/
+BufNSelect     buf.c   /^BufNSelect(n)$/
+BufPos extend.c        /^BufPos()$/
+BufSelect      buf.c   /^BufSelect()$/
+BufSwrite      screen.c        /^BufSwrite(linenum)$/
+C100d_lines    screen.c        /^C100d_lines(top, bottom, num)$/
+C100i_lines    screen.c        /^C100i_lines(top, bottom, num)$/
+CAutoExec      extend.c        /^CAutoExec()$/
+CTL    chars.h /^#define CTL(c)                ((c) & 037)$/
+CalcWind       wind.c  /^CalcWind(w)$/
+CapChar        case.c  /^CapChar()$/
+CapWord        case.c  /^CapWord()$/
+CasRegLower    case.c  /^CasRegLower()$/
+CasRegUpper    case.c  /^CasRegUpper()$/
+CaseReg        case.c  /^CaseReg(up)$/
+CentWind       wind.c  /^CentWind(w)$/
+CharUpcase     ctype.h /^#define       CharUpcase(c)   (RaiseTable[c])$/
+Chdir  io.c    /^Chdir()$/
+CheckEvents    mac.c   /^CheckEvents()$/
+ChkErrorLines  proc.c  /^ChkErrorLines()$/
+ChkWinLines    disp.c  /^ChkWinLines()$/
+ChkWindows     disp.c  /^ChkWindows(line1, line2)$/
+ChrToOct       misc.c  /^ChrToOct()$/
+ClAndRedraw    disp.c  /^ClAndRedraw()$/
+Comment        c.c     /^Comment()$/
+CopyRegion     delete.c        /^CopyRegion()$/
+CurMark        marks.c /^CurMark()$/
+DBXpoutput     iproc.c /^DBXpoutput()$/
+DFixMarks      marks.c /^DFixMarks(line1, char1, line2, char2)$/
+DIRSIZE        scandir.c       /^#define DIRSIZE(entry)        (strlen((entry)->d_name))$/
+DOTsave        util.c  /^DOTsave(buf)$/
+DScroll        mac.c   /^DScroll(control,part)$/
+Dchdir io.c    /^#define       Dchdir(to)  chdir(to)$/
+DeTab  disp.c  /^DeTab(s_offset, buf, outbuf, limit, visspace)$/
+DefAutoExec    extend.c        /^DefAutoExec(proc)$/
+DefGAbbrev     abbrev.c        /^DefGAbbrev()$/
+DefKBDMac      macros.c        /^DefKBDMac()$/
+DefMAbbrev     abbrev.c        /^DefMAbbrev()$/
+DefMajor       dataobj.h       /^#define DefMajor(x)   (FUNCTION|MAJOR_MODE|((x) << 8/
+DefMinor       dataobj.h       /^#define DefMinor(x)   (FUNCTION|MINOR_MODE|((x) << 8/
+DelBlnkLines   delete.c        /^DelBlnkLines()$/
+DelChar        disp.c  /^DelChar(lineno, col, num)$/
+DelCurWindow   wind.c  /^DelCurWindow()$/
+DelLines       disp.c  /^DelLines(at, num)$/
+DelMacro       macros.c        /^DelMacro()$/
+DelMark        marks.c /^DelMark(m)$/
+DelNChar       delete.c        /^DelNChar()$/
+DelNWord       delete.c        /^DelNWord()$/
+DelPChar       delete.c        /^DelPChar()$/
+DelPWord       delete.c        /^DelPWord()$/
+DelReg delete.c        /^DelReg()$/
+DelWtSpace     delete.c        /^DelWtSpace()$/
+DescBindings   keymaps.c       /^DescBindings()$/
+DescCom        keymaps.c       /^DescCom()$/
+DescMap        keymaps.c       /^DescMap(map, pref)$/
+DescWMap       keymaps.c       /^DescWMap(map, key)$/
+Digit  argcount.c      /^Digit()$/
+Digit0 argcount.c      /^Digit0()$/
+Digit1 argcount.c      /^Digit1()$/
+Digit2 argcount.c      /^Digit2()$/
+Digit3 argcount.c      /^Digit3()$/
+Digit4 argcount.c      /^Digit4()$/
+Digit5 argcount.c      /^Digit5()$/
+Digit6 argcount.c      /^Digit6()$/
+Digit7 argcount.c      /^Digit7()$/
+Digit8 argcount.c      /^Digit8()$/
+Digit9 argcount.c      /^Digit9()$/
+DoAutoExec     extend.c        /^DoAutoExec(new, old)$/
+DoIDline       disp.c  /^DoIDline(start)$/
+DoJustify      paragraph.c     /^DoJustify(l1, c1, l2, c2, scrunch, indent)$/
+DoKeys jove.c  /^DoKeys(firsttime)$/
+DoNewline      insert.c        /^DoNewline(indentp)$/
+DoPara paragraph.c     /^DoPara(dir)$/
+DoParen        insert.c        /^DoParen()$/
+DoShell        proc.c  /^DoShell(bnm, command)$/
+DoWriteReg     io.c    /^DoWriteReg(app)$/
+DoYank insert.c        /^DoYank(fline, fchar, tline, tchar, atline, atchar,/
+DotTo  util.c  /^DotTo(line, col)$/
+DownMotion     screen.c        /^DownMotion(destline)$/
+DownScroll     disp.c  /^DownScroll()$/
+DrawMesg       disp.c  /^DrawMesg(abortable)$/
+EVexpand       ask.c   /^EVexpand()$/
+EditAbbrevs    abbrev.c        /^EditAbbrevs()$/
+Eof    move.c  /^Eof()$/
+Eol    move.c  /^Eol()$/
+Eos    move.c  /^Eos()$/
+Eow    disp.c  /^Eow()$/
+ErrFree        proc.c  /^ErrFree()$/
+ErrParse       proc.c  /^ErrParse()$/
+ErrorHasReferents      proc.c  /^ErrorHasReferents()$/
+ExecCmd        util.c  /^ExecCmd(cp)$/
+ExecMacro      macros.c        /^ExecMacro()$/
+Extend extend.c        /^Extend()$/
+FDotTag        re1.c   /^FDotTag()$/
+FDownList      c.c     /^FDownList()$/
+FLine  wind.c  /^FLine(w)$/
+FList  c.c     /^FList()$/
+FSexpr c.c     /^FSexpr()$/
+FSrchND        re.c    /^FSrchND()$/
+F_MODE fp.h    /^#define F_MODE(x)     ((x)&07)$/
+Ffilter        mac.c   /^Ffilter(p)$/
+FillComment    c.c     /^FillComment(format)$/
+FilterRegion   proc.c  /^FilterRegion()$/
+FindCmd        util.c  /^FindCmd(proc)$/
+FindFile       buf.c   /^FindFile()$/
+FindMatch      c.c     /^FindMatch(dir)$/
+FindTag        re1.c   /^FindTag()$/
+ForChar        move.c  /^ForChar()$/
+ForMotion      screen.c        /^ForMotion(destcol)$/
+ForNum screen.c        /^ForNum(from, to)$/
+ForPara        paragraph.c     /^ForPara()$/
+ForSearch      re.c    /^ForSearch()$/
+ForTab screen.c        /^ForTab(destcol)$/
+ForWord        move.c  /^ForWord()$/
+Forget macros.c        /^Forget()$/
+FullRecover    rec.c   /^FullRecover()$/
+GCchunks       insert.c        /^GCchunks()$/
+GENd_lines     screen.c        /^GENd_lines(top, bottom, num)$/
+GENi_lines     screen.c        /^GENi_lines(top, bottom, num)$/
+GSexpr insert.c        /^GSexpr()$/
+GoDirect       screen.c        /^GoDirect(line, col)$/
+GoLine misc.c  /^GoLine()$/
+GotoDot        disp.c  /^GotoDot()$/
+GotoWind       wind.c  /^GotoWind()$/
+GrowWindowCmd  wind.c  /^GrowWindowCmd()$/
+HALF   wind.h  /^#define HALF(wp)      (((wp)->w_height - 1) \/ 2)$/
+HLmode mac.c   /^HLmode(new)$/
+HomeGo screen.c        /^HomeGo(line, col)$/
+IDchar disp.c  /^IDchar(new, lineno, col)$/
+IDcomp disp.c  /^IDcomp(s, t, len)$/
+IDline_setup   screen.c        /^IDline_setup(tname)$/
+IFixMarks      marks.c /^IFixMarks(line1, char1, line2, char2)$/
+INSmode        disp.c  /^INSmode(on)$/
+IOerr  util.c  /^IOerr(err, file)$/
+IncFSearch     re1.c   /^IncFSearch()$/
+IncRSearch     re1.c   /^IncRSearch()$/
+IncSearch      re1.c   /^IncSearch(dir)$/
+InitBinds      mac.c   /^InitBinds()$/
+InitCM screen.c        /^InitCM()$/
+InitEvents     mac.c   /^InitEvents()$/
+InitKeymaps    keymaps.c       /^InitKeymaps()$/
+InitLocalMenus mac.c   /^InitLocalMenus()$/
+InitMenu       mac.c   /^InitMenu(M)$/
+InitSysMenu    mac.c   /^InitSysMenu()$/
+InsChar        disp.c  /^InsChar(lineno, col, num, new)$/
+InsFile        io.c    /^InsFile()$/
+Insert insert.c        /^Insert(c)$/
+Iprocess       iproc.c /^Iprocess()$/
+IsModified     util.h  /^#define IsModified(b) ((b)->b_modified)$/
+IsPrefix       keymaps.c       /^IsPrefix(cp)$/
+Justify        paragraph.c     /^Justify()$/
+KeyDesc        keymaps.c       /^KeyDesc()$/
+KillBos        misc.c  /^KillBos()$/
+KillEOL        misc.c  /^KillEOL()$/
+KillEos        misc.c  /^KillEos()$/
+KillExpr       misc.c  /^KillExpr()$/
+KillProcs      iproc.c /^KillProcs()$/
+KillSome       buf.c   /^KillSome()$/
+KmBind keymaps.c       /^KmBind()$/
+LRShift        c.c     /^LRShift()$/
+LRUunlink      io.c    /^LRUunlink(b)$/
+Leave  misc.c  /^Leave()$/
+LineAI insert.c        /^LineAI()$/
+LineDist       util.c  /^LineDist(nextp, endp)$/
+LineInsert     insert.c        /^LineInsert(num)$/
+LookingAt      re.c    /^LookingAt(pattern, buf, offset)$/
+LowLine        screen.c        /^#define LowLine()     { putpad(LL, 1); CapLine = ILI; /
+LowWord        case.c  /^LowWord()$/
+MAutoExec      extend.c        /^MAutoExec()$/
+META   chars.h /^#define META(c)               ((c) | 0200)$/
+MacInit        mac.c   /^MacInit()$/
+MacInter       macros.c        /^MacInter()$/
+MacSetVar      mac.c   /^MacSetVar(vp,mnu,itm) \/* Set a variable from the m/
+MajorMode      buf.h   /^#define MajorMode(x)  (curbuf->b_major == (x))$/
+MakeErrors     proc.c  /^MakeErrors()$/
+MakeKMap       keymaps.c       /^MakeKMap()$/
+MakeMark       marks.c /^MakeMark(line, column, type)$/
+MakeName       proc.c  /^MakeName(command)$/
+MakeScrollBar  mac.c   /^MakeScrollBar(w)      \/* set up control *\/$/
+MarkAllVar     mac.c   /^MarkAllVar()  \/* slow, but only do it once *\/$/
+MarkModes      mac.c   /^MarkModes()$/
+MarkSet        marks.c /^MarkSet(m, line, column)$/
+MarkVar        mac.c   /^MarkVar(vp,mnu,itm)   \/* mark a boolean menu item *\//
+MaybeAbbrevExpand      insert.c        /^MaybeAbbrevExpand()$/
+MinorMode      buf.h   /^#define MinorMode(x)          BufMinorMode(curbuf, (x))$/
+Mjove  jove.c  /^main()$/
+ModBufs        util.c  /^ModBufs(allp)$/
+ModMacs        macros.c        /^ModMacs()$/
+ModeLine       disp.c  /^ModeLine(w)$/
+NPage  mac.c   /^NPage(control,part)$/
+NPlacur        mac.c   /^NPlacur(line,col)$/
+NameMac        macros.c        /^NameMac()$/
+NeedErrors     proc.c  /^NeedErrors()$/
+Newline        insert.c        /^Newline()$/
+NextError      proc.c  /^NextError()$/
+NextLine       move.c  /^NextLine()$/
+NextPage       disp.c  /^NextPage()$/
+NextWindow     wind.c  /^NextWindow()$/
+NotModified    misc.c  /^NotModified()$/
+NumSimilar     disp.c  /^NumSimilar(s, t, n)$/
+OkayDelete     disp.c  /^OkayDelete(Saved, num, samelength)$/
+OkayInsert     disp.c  /^OkayInsert(Saved, num)$/
+OneWindow      wind.c  /^OneWindow()$/
+OpenLine       insert.c        /^OpenLine()$/
+PPage  mac.c   /^PPage(control,part)$/
+PPchar fmt.c   /^PPchar(c, str, size)$/
+PageNWind      wind.c  /^PageNWind()$/
+PageScrollDown disp.c  /^PageScrollDown()$/
+PageScrollUp   disp.c  /^PageScrollUp()$/
+PathParse      io.c    /^PathParse(name, intobuf)$/
+PauseJove      jove.c  /^PauseJove()$/
+Peekc  jove.c  /^Peekc()$/
+Placur screen.c        /^Placur(line, col)$/
+PopMark        marks.c /^PopMark()$/
+Popd   io.c    /^Popd()$/
+PrVar  extend.c        /^PrVar()$/
+PrefChar       keymaps.c       /^PrefChar(c)$/
+PrevError      proc.c  /^PrevError()$/
+PrevLine       move.c  /^PrevLine()$/
+PrevPage       disp.c  /^PrevPage()$/
+PrevWindow     wind.c  /^PrevWindow()$/
+PrintHo        screen.c        /^#define PrintHo()     { putpad(HO, 1); CapLine = CapCo/
+ProcBind       keymaps.c       /^ProcBind()$/
+ProcCont       iproc-ptys.c    /^ProcCont()$/
+ProcDStop      iproc-ptys.c    /^ProcDStop()$/
+ProcEof        iproc-ptys.c    /^ProcEof()$/
+ProcFilter     mac.c   /^ProcFilter(theDialog,event,itemHit)$/
+ProcInt        iproc-ptys.c    /^ProcInt()$/
+ProcKill       iproc-ptys.c    /^ProcKill()$/
+ProcKmBind     keymaps.c       /^ProcKmBind()$/
+ProcList       iproc.c /^ProcList()$/
+ProcMenu       mac.c   /^ProcMenu(menuno,itemno)$/
+ProcNewline    iproc.c /^ProcNewline()$/
+ProcQuit       iproc-ptys.c    /^ProcQuit()$/
+ProcSendData   iproc.c /^ProcSendData()$/
+ProcStop       iproc-ptys.c    /^ProcStop()$/
+PtToMark       marks.c /^PtToMark()$/
+Push   jove.c  /^Push()$/
+PushPntp       util.c  /^PushPntp(line)$/
+Pushd  io.c    /^Pushd()$/
+QRepSearch     re1.c   /^QRepSearch()$/
+QuotChar       insert.c        /^QuotChar()$/
+REcompile      re.c    /^REcompile(pattern, re, re_blk)$/
+REgetc re.c    /^REgetc()$/
+REmatch        re.c    /^REmatch(linep, comp_ptr)$/
+RErecur        re.c    /^RErecur()$/
+REreset        re.c    /^REreset()$/
+RRShift        c.c     /^RRShift()$/
+RSrchND        re.c    /^RSrchND()$/
+ReNamBuf       buf.c   /^ReNamBuf()$/
+ReadFile       io.c    /^ReadFile()$/
+Recur  jove.c  /^Recur()$/
+RecycleLines   insert.c        /^RecycleLines()$/
+RedrawDisplay  disp.c  /^RedrawDisplay()$/
+RegJustify     paragraph.c     /^RegJustify()$/
+RegReplace     re1.c   /^RegReplace()$/
+RegToUnix      proc.c  /^RegToUnix(outbuf, cmd)$/
+Remember       macros.c        /^Remember()$/
+RemoveScrollBar        mac.c   /^RemoveScrollBar(w)$/
+RepSearch      re1.c   /^RepSearch()$/
+ResetTerm      jove.c  /^ResetTerm()$/
+Reset_std      mac.c   /^Reset_std()$/
+RestAbbrevs    abbrev.c        /^RestAbbrevs()$/
+RetTab screen.c        /^RetTab(col)$/
+RevSearch      re.c    /^RevSearch()$/
+RunMacro       macros.c        /^RunMacro()$/
+SETBIT re.c    /^#define       SETBIT(c)       (1 << ((c) % BYTESIZE))$/
+SETBYTE        re.c    /^#define       SETBYTE(c)      ((c) \/ BYTESIZE)$/
+SIZE   wind.h  /^#define SIZE(wp)      ((wp)->w_height - 1)$/
+SO_off screen.c        /^SO_off()$/
+SO_on  screen.c        /^SO_on()$/
+SUNd_lines     screen.c        /^SUNd_lines(top, bottom, num)$/
+SUNi_lines     screen.c        /^SUNi_lines(top, bottom, num)$/
+SavLine        util.h  /^#define SavLine(a, b) ((a)->l_dline = putline((b))/
+SaveAbbrevs    abbrev.c        /^SaveAbbrevs()$/
+SaveFile       io.c    /^SaveFile()$/
+ScrollLeft     wind.c  /^ScrollLeft()$/
+ScrollRight    wind.c  /^ScrollRight()$/
+SelfInsert     insert.c        /^SelfInsert()$/
+SendData       iproc.c /^SendData(newlinep)$/
+SetABuf        buf.c   /^SetABuf(b)$/
+SetBounds      mac.c   /^SetBounds()$/
+SetBuf buf.c   /^SetBuf(newbuf)$/
+SetBufMenu     mac.c   /^SetBufMenu()$/
+SetDot util.c  /^SetDot(bp)$/
+SetLMargin     misc.c  /^SetLMargin()$/
+SetLine        util.h  /^#define SetLine(line) DotTo((line), 0)$/
+SetMajor       buf.h   /^#define SetMajor(x)   { curbuf->b_major = (x); UpdMo/
+SetMark        marks.c /^SetMark()$/
+SetRMargin     misc.c  /^SetRMargin()$/
+SetScrollBar   mac.c   /^SetScrollBar(handle)  \/* set value of the bar *\/$/
+SetTop wind.c  /^SetTop(w, line)$/
+SetVar extend.c        /^SetVar()$/
+SetWind        wind.c  /^SetWind(new)$/
+Set_std        mac.c   /^Set_std()$/
+ShNoBuf        proc.c  /^ShNoBuf()$/
+ShToBuf        proc.c  /^ShToBuf()$/
+ShellCom       proc.c  /^ShellCom()$/
+ShellProc      iproc.c /^ShellProc()$/
+ShowErr        proc.c  /^ShowErr()$/
+ShowVersion    jove.c  /^ShowVersion()$/
+ShrWindow      wind.c  /^ShrWindow()$/
+Shtypeout      proc.c  /^Shtypeout()$/
+SigHold        sysdep.h        /^# define SigHold(s)   sigblock(SigMask |= sigmask((s/
+SigRelse       sysdep.h        /^# define SigRelse(s)  sigsetmask(SigMask &= ~sigmas/
+SitFor util.c  /^SitFor(delay)$/
+Source extend.c        /^Source()$/
+SpelBuffer     proc.c  /^SpelBuffer()$/
+SpelParse      proc.c  /^SpelParse(bname)$/
+SpelWords      proc.c  /^SpelWords()$/
+SplitWind      wind.c  /^SplitWind()$/
+StrIndex       util.c  /^StrIndex(dir, buf, charpos, what)$/
+StrLength      misc.c  /^StrLength()$/
+SyncRec        rec.c   /^SyncRec()$/
+SyncTmp        io.c    /^SyncTmp()$/
+TOstart        disp.c  /^TOstart(name, auto_newline)$/
+TOstop disp.c  /^TOstop()$/
+Tab    insert.c        /^Tab()$/
+TermError      term.c  /^TermError()$/
+TimesFour      argcount.c      /^TimesFour()$/
+ToError        proc.c  /^ToError(forward)$/
+ToFirst        util.c  /^ToFirst()$/
+ToIndent       misc.c  /^ToIndent()$/
+ToLast util.c  /^ToLast()$/
+ToMark marks.c /^ToMark(m)$/
+TogMinor       buf.c   /^TogMinor(bit)$/
+TransChar      misc.c  /^TransChar()$/
+TransLines     misc.c  /^TransLines()$/
+TwoBlank       util.c  /^TwoBlank()$/
+Typeout        disp.c  /^Typeout(char *fmt, ...)$/
+UNIX_cmdline   jove.c  /^UNIX_cmdline(argc, argv)$/
+UNMACRO        externs.h       /^extern int    UNMACRO(vfork) proto((void));$/
+UScroll        mac.c   /^UScroll(control,part)$/
+UnbindC        keymaps.c       /^UnbindC()$/
+Ungetc jove.c  /^Ungetc(c)$/
+UnixToBuf      proc.c  /^UnixToBuf(char *bnm, char *InFName, bool disp, int/
+UnsetTerm      jove.c  /^UnsetTerm(mesg)$/
+UntilEqual     disp.c  /^UntilEqual(start)$/
+UpMotion       screen.c        /^UpMotion(destline)$/
+UpScroll       disp.c  /^UpScroll()$/
+UpdLine        disp.c  /^UpdLine(linenum)$/
+UpdWindow      disp.c  /^UpdWindow(w, start)$/
+UppWord        case.c  /^UppWord()$/
+WIFEXITED      wait.h  /^# define WIFEXITED(w)         (((w).w_status & 0377) == 0/
+WIFSIGNALED    wait.h  /^# define WIFSIGNALED(w)               ((((w).w_status >> 8) & 0/
+WIFSTOPPED     wait.h  /^# define WIFSTOPPED(w)                (((w).w_status & 0377) == /
+WIRED_CMD      funcdefs.c      /^#     define WIRED_CMD(c) (c),'\\0','\\0'     \/* for About J/
+WITH_TABLE     ctype.h /^#define       WITH_TABLE(x) \\$/
+WNumLines      wind.c  /^WNumLines()$/
+WVisSpace      wind.c  /^WVisSpace()$/
+WindFind       wind.c  /^WindFind()$/
+WindSize       wind.c  /^WindSize(w, inc)$/
+WriteFile      io.c    /^WriteFile()$/
+WriteMacs      macros.c        /^WriteMacs()$/
+WrtReg io.c    /^WrtReg()$/
+WtModBuf       misc.c  /^WtModBuf()$/
+XtermMouse     misc.c  /^XtermMouse()$/
+Yank   misc.c  /^Yank()$/
+YankPop        insert.c        /^YankPop()$/
+about_j        mac.c   /^about_j()$/
+abs    screen.c        /^#define abs(x)        ((x) >= 0 ? (x) : -(x))$/
+abspath        io.c    /^abspath(so, dest)$/
+active mac.c   /^#define active() SetPort(theScreen)$/
+add_mac        macros.c        /^add_mac(new)$/
+add_mess       fmt.c   /^add_mess(const char *fmt, ...)$/
+add_stroke     util.h  /^#define add_stroke(c) { \\$/
+addgetc        extend.c        /^addgetc()$/
+alloc_mthread  macros.c        /^alloc_mthread()$/
+alphacomp      scandir.c       /^alphacomp(a, b)$/
+arg_type       argcount.h      /^#define arg_type()            arg_supplied_p$/
+arg_value      argcount.h      /^#define arg_value()           arg_count$/
+ask    ask.c   /^ask(char *def, char *fmt,...)$/
+ask_buf        buf.c   /^ask_buf(def)$/
+ask_file       ask.c   /^ask_file(prmt, def, buf)$/
+ask_int        extend.c        /^ask_int(prompt, base)$/
+aux_complete   extend.c        /^aux_complete(c)$/
+b_char move.c  /^b_char(n)$/
+b_unlink       io.c    /^b_unlink(bp)$/
+b_word move.c  /^b_word(num)$/
+back_space     pcscr.c /^#define back_space()  cur_left()$/
+backref        re.c    /^backref(n, linep)$/
+backslashed    c.c     /^backslashed(lp, cpos)$/
+bad_extension  ask.c   /^bad_extension(name)$/
+basename       util.c  /^basename(f)$/
+biff   jove.c  /^biff(on)$/
+biff_init      jove.c  /^biff_init()$/
+blk_round      temp.h  /^#define blk_round(addr)               ((daddr) (addr) & ~RND_MA/
+blnkp  util.c  /^blnkp(buf)$/
+bobp   util.h  /^#define bobp()                (firstp(curline) && bolp())$/
+bolp   util.h  /^#define bolp()                (curchar == 0)$/
+break_off      jove.c  /^break_off()$/
+break_rst      jove.c  /^break_rst()$/
+buf_alloc      buf.c   /^buf_alloc()$/
+buf_exists     buf.c   /^buf_exists(name)$/
+buf_init       buf.c   /^buf_init()$/
+bufname        buf.c   /^bufname(b)$/
+byte_copy      util.c  /^byte_copy(from, to, count)$/
+byte_zero      sysdep.h        /^# define byte_zero(s,n) setmem((s),(n),0)$/
+c_indent       c.c     /^c_indent(brace)$/
+calc_pos       disp.c  /^calc_pos(lp, c_char)$/
+carriage_return        pcscr.c /^#define carriage_return()     gotoxy(wherex(), C_Y = 0/
+case_reg       case.c  /^case_reg(line1, char1, line2, char2, up)$/
+case_word      case.c  /^case_word(up)$/
+casecmp        util.c  /^casecmp(s1, s2)$/
+casencmp       util.c  /^casencmp(s1, s2, n)$/
+ch_out pcscr.c /^void near ch_out(c, n)$/
+charp  jove.c  /^charp()$/
+chdir  mac.c   /^chdir(dir)$/
+check_dir      mac.c   /^check_dir()$/
+chkCWD io.c    /^chkCWD(dn)$/
+chk_mtime      io.c    /^chk_mtime(thisbuf, fname, how)$/
+chkmail        disp.c  /^chkmail(force)$/
+chpl   pcscr.c /^BYTE chpl()$/
+chr_to_int     extend.c        /^chr_to_int(cp, base, allints, result)$/
+cind_cmp       re.c    /^#define cind_cmp(a, b)        (CharUpcase(a) == CharUpcas/
+cl_eol screen.c        /^cl_eol()$/
+cl_scr screen.c        /^cl_scr(doit)$/
+close  mac.c   /^close(fd)$/
+close_file     io.c    /^close_file(fp)$/
+closedir       scandir.c       /^closedir(dp)$/
+closekmem      loadavg.c       /^closekmem()$/
+clr_arg_value  argcount.h      /^#define clr_arg_value()               { arg_supplied_p = NO; ar/
+clr_eoln       mac.c   /^clr_eoln()$/
+clr_eop        pcscr.c /^void near clr_eop()$/
+clr_page       mac.c   /^clr_page()    \/* clear and home function *\/$/
+clrline        screen.c        /^clrline(cp1, cp2)$/
+cmp_char       re1.c   /^#define cmp_char(a, b)        ((a) == (b) || (CaseIgnore /
+com_finish     proc.c  /^com_finish(status, cmd)$/
+complain       jove.c  /^complain(const char *fmt, ...)$/
+complete       extend.c        /^complete(possible, prompt, flags)$/
+con_read       mac.c   /^con_read(buf,size)$/
+con_write      mac.c   /^con_write(buf,size)$/
+confirm        jove.c  /^confirm(const char *fmt, ...)$/
+conv_p_curs    mac.c   /^conv_p_curs(row,col)$/
+copystr        util.c  /^copystr(str)$/
+creat  mac.c   /^creat(name,perm)      \/* permission mode is irrelevant /
+ctol   mac.c   /^ctol(ctlv)    \/* find buffer line for ctlvalue *\/$/
+cur_advance    pcscr.c /^void near cur_advance()$/
+cur_down       pcscr.c /^void near cur_down()$/
+cur_left       pcscr.c /^void near cur_left()$/
+cur_mov        pcscr.c /^#define cur_mov(x,y)  set_cur((C_X=(x))<<8|((C_Y=(y/
+cur_page       pcscr.c /^WORD near cur_page()$/
+cur_right      pcscr.c /^void near cur_right()$/
+cur_up pcscr.c /^void near cur_up()$/
+curset mac.c   /^curset(desired)$/
+cvt_err        mac.c   /^cvt_err(err)  \/* some of these don't make sense... /
+cvt_fnm        mac.c   /^cvt_fnm(file)$/
+d_cache_init   io.c    /^d_cache_init()$/
+d_lines        mac.c   /^d_lines(top, bottom, num)$/
+da_to_bno      temp.h  /^#define da_to_bno(addr)               ((daddr) ((addr) >> BNO_S/
+da_to_off      temp.h  /^#define da_to_off(addr)               ((daddr) ((addr) << CH_BI/
+da_too_huge    temp.h  /^#define da_too_huge(addr)     ((daddr) ((addr) >> BNO_/
+def_abbrev     abbrev.c        /^def_abbrev(table)$/
+defb_wind      buf.c   /^defb_wind(b)$/
+define abbrev.c        /^define(table, abbrev, phrase)$/
+defined        sysdep.h        /^# define defined(x) (x)$/
+del_char       delete.c        /^del_char(dir, num, OK_kill)$/
+del_mac        macros.c        /^del_mac(mac)$/
+del_wind       wind.c  /^del_wind(wp)$/
+delchars       mac.c   /^delchars()$/
+dellines       mac.c   /^dellines(n,bot)$/
+dfollow        io.c    /^dfollow(file, into)$/
+dir_name       io.c    /^#define dir_name(dp)  ((char *) list_data((dp)))$/
+disp_opt_init  disp.c  /^disp_opt_init()$/
+dispatch       keymaps.c       /^dispatch(c)$/
+div_wind       wind.c  /^div_wind(wp, n)$/
+dmp_buf_header rec.c   /^dmp_buf_header(b)$/
+dmppntrs       rec.c   /^dmppntrs(b)$/
+doActivate     mac.c   /^doActivate(event)$/
+doDrag mac.c   /^doDrag(event,window)$/
+doGoAway       mac.c   /^doGoAway(event,window)$/
+doGrow mac.c   /^doGrow(event,window)$/
+doMouse        mac.c   /^doMouse(event)$/
+doSysClick     mac.c   /^doSysClick(event,window)$/
+doSysMenu      mac.c   /^doSysMenu(event,window)$/
+doUpdate       mac.c   /^doUpdate(event)$/
+doWind mac.c   /^doWind(event,window)$/
+doZoomIn       mac.c   /^doZoomIn(event,window)$/
+doZoomOut      mac.c   /^doZoomOut(event,window)$/
+do_ask ask.c   /^do_ask(char *delim, bool (*d_proc) proto((int)), c/
+do_cl_eol      disp.c  /^do_cl_eol(linenum)$/
+do_comp        re.c    /^do_comp(re_blk, kind)$/
+do_creat       mac.c   /^do_creat(p,nm)$/
+do_display     mac.c   /^do_display()          \/* draw necessary controls, lines *\//
+do_events      mac.c   /^do_events()$/
+do_expr        c.c     /^do_expr(dir, skip_words)$/
+do_find        buf.c   /^do_find(w, fname, force)$/
+do_if  extend.c        /^do_if(cmd)$/
+do_list        mac.c   /^do_list()$/
+do_macro       macros.c        /^do_macro(mac)$/
+do_rfill       paragraph.c     /^do_rfill(ulm)$/
+do_rtp iproc.c /^do_rtp(mp)$/
+do_select      buf.c   /^do_select(w, name)$/
+do_set_mark    marks.c /^do_set_mark(l, c)$/
+do_sgtty       jove.c  /^do_sgtty()$/
+do_space       paragraph.c     /^do_space()$/
+do_sputc       screen.c        /^do_sputc(c)$/
+dobell disp.c  /^dobell(n)$/
+docompiled     re.c    /^docompiled(dir, re_blk)$/
+docontrols     mac.c   /^docontrols()  \/* called from redisplay routines *\/$/
+doformat       fmt.c   /^doformat(sp, fmt, ap)$/
+dofread        io.c    /^dofread(fp)$/
+doisearch      re1.c   /^doisearch(dir, c, failing)$/
+dokeyDown      mac.c   /^dokeyDown(event)$/
+dopipe util.c  /^dopipe(p)$/
+dorecover      jove.c  /^dorecover()$/
+dosearch       re.c    /^dosearch(pattern, dir, re)$/
+dowait proc.c  /^dowait(pid, status)$/
+drawfluff      mac.c   /^drawfluff()           \/* draw controls and dividers *\/$/
+dummy  mac.c   /^int dummy() {}$/
+dword  delete.c        /^dword(forward)$/
+emalloc        util.c  /^emalloc(size)$/
+eobp   util.h  /^#define eobp()                (lastp(curline) && eolp())$/
+eolp   util.h  /^#define eolp()                (linebuf[curchar] == '\\0')$/
+erealloc       util.c  /^erealloc(ptr, size)$/
+error  jove.c  /^error(const char *fmt, ...)$/
+f_char move.c  /^f_char(n)$/
+f_close        fp.c    /^f_close(fp)$/
+f_complete     ask.c   /^f_complete(c)$/
+f_eof  fp.h    /^#define f_eof(fp)     ((fp)->f_flags & F_EOF)$/
+f_getputl      io.c    /^f_getputl(line, fp)$/
+f_gets fp.c    /^f_gets(fp, buf, max)$/
+f_match        ask.c   /^f_match(file)$/
+f_mess fmt.c   /^f_mess(const char *fmt, ...)$/
+f_open fp.c    /^f_open(name, flags, buffer, buf_size)$/
+f_readn        fp.c    /^f_readn(fp, addr, n)$/
+f_seek fp.c    /^f_seek(fp, offset)$/
+f_toNL fp.c    /^f_toNL(fp)$/
+f_word move.c  /^f_word(num)$/
+fake_blkio     io.c    /^fake_blkio(b, iofcn)$/
+fb_aux keymaps.c       /^fb_aux(cp, map, prefix, buf, size)$/
+fd_open        fp.c    /^fd_open(name, flags, fd, buffer, buf_size)$/
+filbuf fp.c    /^filbuf(fp)$/
+file_backup    io.c    /^file_backup(fname)$/
+file_exists    buf.c   /^file_exists(name)$/
+file_write     io.c    /^file_write(fname, app)$/
+filemunge      io.c    /^filemunge(newname)$/
+filename       util.c  /^filename(b)$/
+fill_in        ask.c   /^fill_in(dir_vec, n)$/
+find_binds     keymaps.c       /^find_binds(dp, buf, size)$/
+find_para      paragraph.c     /^find_para(how)$/
+find_pos       disp.c  /^find_pos(line, c_char)$/
+find_tag       re1.c   /^find_tag(tag, localp)$/
+findcom        funcdefs.c      /^findcom(prompt)$/
+findmac        macros.c        /^findmac(prompt)$/
+findmap        keymaps.c       /^findmap(fmt)$/
+findtext       mac.c   /^findtext()            \/* locate and move the point to match /
+findvar        vars.c  /^findvar(prompt)$/
+finish jove.c  /^finish(code)$/
+firstp util.h  /^#define firstp(line)  ((line) == curbuf->b_first)$/
+fixorder       util.c  /^fixorder(line1, char1, line2, char2)$/
+fixpath        io.c    /^fixpath(p)$/
+flush_marks    marks.c /^flush_marks(b)$/
+flushout       fp.c    /^flushout(fp)$/
+flushscreen    fp.c    /^flushscreen()$/
+format fmt.c   /^format(buf, len, fmt, ap)$/
+forward_block  temp.h  /^#define forward_block(addr)   ((daddr) (addr) + CH_P/
+fputnchar      fp.c    /^fputnchar(s, n, fp)$/
+free_mthread   macros.c        /^free_mthread(t)$/
+free_proc      iproc.c /^free_proc(child)$/
+freealloc      util.c  /^freealloc(obj, size)$/
+freedir        scandir.c       /^freedir(nmptr, nentries)$/
+freeline       insert.c        /^freeline(line)$/
+fsetup mac.c   /^fsetup(p)$/
+fwritef        fmt.c   /^fwritef(File *fp, const char *fmt, ...)$/
+gather_numeric_argument        argcount.c      /^gather_numeric_argument(c)$/
+gc_openfiles   fp.c    /^gc_openfiles()$/
+getArgs        mac.c   /^getArgs(avp)$/
+getCO  mac.c   /^getCO()       \/* so that jove knows params *\/$/
+getCWD io.c    /^getCWD()$/
+getDOT util.h  /^#define getDOT()      getline(curline->l_dline, linebuf/
+getLI  mac.c   /^getLI()$/
+getNMbuf       buf.c   /^getNMbuf()$/
+getTERM        term.c  /^getTERM()$/
+get_FL_info    proc.c  /^get_FL_info(fname, lineno)$/
+get_cur        pcscr.c /^WORD near get_cur()$/
+get_hdir       io.c    /^get_hdir(user, buf)$/
+get_indent     paragraph.c     /^get_indent(lp)$/
+get_keymaps    keymaps.c       /^get_keymaps(km_buf)$/
+get_la loadavg.c       /^get_la()$/
+get_minibuf    ask.c   /^get_minibuf()$/
+get_mode       pcscr.c /^BYTE near get_mode()$/
+get_time       util.c  /^get_time(timep, buf, from, to)$/
+getblock       io.c    /^getblock(atl, IsWrite)$/
+getch  jove.c  /^getch()$/
+getdir mac.c   /^getdir()      \/* call this only once, during startup. */
+getenv mac.c   /^getenv(item)$/
+gethome        mac.c   /^gethome()             \/* this will be startup directory *\/$/
+getline        io.c    /^getline(addr, buf)$/
+getrawinchar   getch.c /^getrawinchar()$/
+getsearch      re.c    /^getsearch()$/
+getwd  io.c    /^getwd(buffer)$/
+gfile  mac.c   /^gfile(namebuf)        \/* return a filename to get *\/$/
+gotoxy pcscr.c /^#define gotoxy(x,y)   set_cur((x)<<8|((y)&0xff))$/
+has_syntax     ctype.h /^#define       has_syntax(c,s) (SyntaxTable[(c)&CHARMASK]/
+hash   abbrev.c        /^hash(a)$/
+home   screen.c        /^#define       home()          Placur(0, 0)$/
+home_cur       pcscr.c /^#define home_cur()    gotoxy(C_X = 0, C_Y = 0)$/
+how_far        move.c  /^how_far(line, col)$/
+i_blank        paragraph.c     /^i_blank(lp)$/
+i_bsblank      paragraph.c     /^i_bsblank(lp)$/
+i_lines        mac.c   /^i_lines(top, bottom, num)$/
+i_set  screen.c        /^i_set(nline, ncol)$/
+in_macro       macros.c        /^in_macro()$/
+in_window      wind.c  /^in_window(windes, line)$/
+init_43        pcscr.c /^void init_43()$/
+init_slate     mac.c   /^init_slate()$/
+init_specials  insert.c        /^init_specials()$/
+init_strokes   util.h  /^#define init_strokes()        { keys_p = key_strokes; *ke/
+init_term      pcscr.c /^void init_term()$/
+initlist       buf.c   /^initlist(b)$/
+inlist util.c  /^inlist(first, what)$/
+inorder        util.c  /^inorder(nextp, char1, endp, char2)$/
+ins_c  util.c  /^ins_c(c, buf, atchar, num, max)$/
+ins_str        insert.c        /^ins_str(str, ok_nl)$/
+insert re.c    /^insert(off, endp, which)$/
+insert_c       insert.c        /^insert_c(c, n)$/
+inslines       mac.c   /^inslines(n,bot)$/
+intr   pcscr.c /^#define intr(n, r)    int86((n), (r), (r));$/
+is_an_arg      argcount.h      /^#define is_an_arg()           (arg_supplied_p != NO)$/
+is_dir mac.c   /^is_dir(fname)$/
+isdead iproc-ptys.c    /^#define isdead(p)     ((p) == NULL || proc_state((p)) /
+isdir  ask.c   /^isdir(name)$/
+isdirty        disp.h  /^#define isdirty(line) ((line)->l_dline & DIRTY)$/
+isearch        re1.c   /^isearch(dir, bp)$/
+isetup mac.c   /^isetup(p)$/
+ismword        ctype.c /^ismword(c)$/
+isprocbuf      proc.c  /^isprocbuf(bnm)$/
+itoa   util.c  /^itoa(num)$/
+jcloseall      jove.c  /^jcloseall()$/
+jgetc  fp.h    /^#define jgetc(fp)     \\$/
+jgetchar       jove.c  /^jgetchar()$/
+jisalpha       ctype.h /^#define       jisalpha(c)     (SyntaxTable[c]&(C_UPPER|C_LOW/
+jisclosep      ctype.h /^#define       jisclosep(c)    ((CharTable[0][c&CHARMASK])&C/
+jiscntrl       ctype.h /^#define       jiscntrl(c)     ((CharTable[0][c&CHARMASK])&C_/
+jisdigit       ctype.h /^#define       jisdigit(c)     (SyntaxTable[c]&C_DIGIT)$/
+jislower       ctype.h /^#define       jislower(c)     (SyntaxTable[c]&C_LOWER)$/
+jisopenp       ctype.h /^#define       jisopenp(c)     ((CharTable[0][c&CHARMASK])&C_/
+jisspace       ctype.h /^#define       jisspace(c)     ((c) == ' ' || (c) == '\\t')$/
+jisupper       ctype.h /^#define       jisupper(c)     (SyntaxTable[c]&C_UPPER)$/
+jiswhite       ctype.h /^#define       jiswhite(c)     (jisspace(c))$/
+jisword        ctype.h /^#define       jisword(c)      (SyntaxTable[c]&C_WORD)$/
+joverc extend.c        /^joverc(file)$/
+jputc  fp.h    /^#define jputc(c, fp)  { while (--(fp)->f_cnt < 0) f/
+jputchar       fp.h    /^#define jputchar(c)   jputc((c), stdout)$/
+jputs  fmt.c   /^jputs(str)$/
+jscandir       scandir.c       /^jscandir(dir, nmptr, qualify, sorter)$/
+jtolower       case.c  /^jtolower(c)$/
+kill_buf       buf.c   /^kill_buf(delbuf)$/
+kill_off       iproc.c /^kill_off(pid, w)$/
+killpg sysdep.h        /^# define killpg(pid, sig)     kill(-(pid), (sig))$/
+km_destroy     keymaps.c       /^km_destroy(km)$/
+km_getkey      keymaps.c       /^#define km_getkey(m, c)       ((m)->k_keys[(c) & CHARMAS/
+km_lookup      keymaps.c       /^km_lookup(name)$/
+km_new keymaps.c       /^km_new(name, keys)$/
+km_newname     keymaps.c       /^km_newname()$/
+km_setkey      keymaps.c       /^km_setkey(m, c, d)$/
+lastline       util.c  /^lastline(lp)$/
+lastp  util.h  /^#define lastp(line)   ((line) == curbuf->b_last)$/
+lbptr  io.c    /^lbptr(line)$/
+lcontents      util.c  /^lcontents(line)$/
+len_error      util.c  /^len_error(flag)$/
+length util.c  /^length(line)$/
+lfreelist      insert.c        /^lfreelist(first)$/
+lfreereg       insert.c        /^lfreereg(line1, line2)$/
+line_cnt       buf.c   /^line_cnt(b, buf, size)$/
+line_feed      pcscr.c /^void near line_feed()$/
+line_move      move.c  /^line_move(dir, n, line_cmd)$/
+linecopy       util.c  /^linecopy(onto, atchar, from)$/
+lisp_indent    insert.c        /^lisp_indent()$/
+list_data      list.h  /^#define list_data(lp) ((lp)->car)$/
+list_new       list.c  /^list_new()$/
+list_next      list.h  /^#define list_next(lp) ((lp)->cdr)$/
+list_pop       list.c  /^list_pop(list)$/
+list_push      list.c  /^list_push(list, element)$/
+listput        insert.c        /^listput(buf, after)$/
+lockblock      io.c    /^#define lockblock(addr)$/
+look_at        re.c    /^look_at(expr)$/
+lookup io.c    /^lookup(bno)$/
+lookup_abbrev  abbrev.c        /^lookup_abbrev(table, abbrev)$/
+lower  case.c  /^lower(p)$/
+lpp    pcscr.c /^BYTE lpp()$/
+lremove        delete.c        /^lremove(line1, line2)$/
+lsave  io.c    /^lsave()$/
+lseek  mac.c   /^lseek(fd,offset,type) \/* The Mac version of this d/
+ltobuf util.c  /^ltobuf(line, buf)$/
+ltoc   mac.c   /^ltoc()        \/* calculate ctlvalue for line position *\/$/
+m_paren        c.c     /^m_paren(p_type, dir, can_mismatch, can_stop)$/
+mac_exists     macros.c        /^mac_exists(name)$/
+mac_getc       macros.c        /^mac_getc()$/
+mac_init       macros.c        /^mac_init()$/
+mac_putc       macros.c        /^mac_putc(c)$/
+mak_buf        buf.c   /^mak_buf()$/
+make_argv      util.c  /^make_argv(argv, ap)$/
+make_cache     io.c    /^make_cache()  \/* Only 32K of static space on Mac, s/
+make_edits     mac.c   /^make_edits(menu)      \/* add dummy edit menu *\/$/
+make_scr       screen.c        /^make_scr()$/
+makedead       iproc-ptys.c    /^#define makedead(p)   { proc_state((p)) = DEAD; }$/
+makedirty      disp.h  /^#define makedirty(line)       { (line)->l_dline |= DIRTY/
+makedisplay    mac.c   /^makedisplay()$/
+makelist       mac.c   /^makelist()$/
+match  extend.c        /^match(choices, what)$/
+max    util.c  /^max(a, b)$/
+max_line       paragraph.c     /^max_line(l1, l2)$/
+maxadjust      mac.c   /^#define maxadjust(r) OffsetRect((r),0,2);$/
+member re.c    /^member(comp_ptr, c, af)$/
+menus_off      mac.c   /^menus_off()$/
+menus_on       mac.c   /^menus_on()$/
+message        disp.c  /^message(str)$/
+min    util.c  /^min(a, b)$/
+min_line       paragraph.c     /^min_line(l1, l2)$/
+minib_add      ask.c   /^minib_add(str, movedown)$/
+mk_proc_km     keymaps.c       /^mk_proc_km()$/
+mkbuflist      buf.c   /^mkbuflist(bnamp, ebnamp)$/
+mktemp mac.c   /^mktemp(name)$/
+mode_app       disp.c  /^mode_app(str)$/
+modify util.c  /^modify()$/
+mp_error       c.c     /^mp_error()$/
+n_indent       insert.c        /^n_indent(goal)$/
+nbufline       insert.c        /^nbufline()$/
+negate_arg_value       argcount.h      /^#define negate_arg_value()    { arg_count = -arg_coun/
+newchunk       insert.c        /^newchunk()$/
+next_line      util.c  /^next_line(line, num)$/
+normfun        pcscr.c /^void near normfun(c)$/
+null_ncpy      util.c  /^null_ncpy(to, from, n)$/
+numcomp        util.c  /^numcomp(s1, s2)$/
+obj_type       dataobj.h       /^#define obj_type(o)   ((o)->Type & TYPEMASK)$/
+one_windp      wind.h  /^#define one_windp()   (fwind->w_next == fwind)$/
+open   mac.c   /^open(name,mode)$/
+open_file      io.c    /^open_file(fname, buf, how, complainifbad, quiet)$/
+open_lines     insert.c        /^open_lines(n)$/
+opendir        scandir.c       /^opendir(dir)$/
+outld  fmt.c   /^outld(d, base)$/
+p_refresh      mac.c   /^p_refresh()$/
+pad    fmt.c   /^pad(c, amount)$/
+parse_cmt_fmt  c.c     /^parse_cmt_fmt(str)$/
+patchup        delete.c        /^patchup(line1, char1, line2, char2)$/
+pbuftiedp      iproc.c /^pbuftiedp(b)$/
+pfile  mac.c   /^pfile(namebuf)$/
+pinit  iproc-ptys.c    /^pinit()$/
+pipeclose      util.c  /^pipeclose(p)$/
+pnt_line       util.c  /^pnt_line()$/
+pop_env        util.c  /^pop_env(savejmp)$/
+pop_macro_stack        macros.c        /^pop_macro_stack()$/
+pop_wind       wind.c  /^pop_wind(name, clobber, btype)$/
+pp_key_strokes util.c  /^pp_key_strokes(buffer, size)$/
+prCTIME        misc.c  /^prCTIME()$/
+prCWD  io.c    /^prCWD()$/
+prDIRS io.c    /^prDIRS()$/
+pr_name        io.c    /^pr_name(fname, okay_home)$/
+pr_putc        macros.c        /^pr_putc(c, fp)$/
+prev_line      util.c  /^prev_line(line, num)$/
+printbind      mac.c   /^printbind(f,buf)$/
+proc_buf       iproc-ptys.c    /^#define proc_buf(p)   ((p)->p_buffer->b_name)$/
+proc_child     iproc.c /^proc_child(junk)$/
+proc_close     iproc-ptys.c    /^proc_close(p)$/
+proc_cmd       iproc-ptys.c    /^#define proc_cmd(p)   ((p)->p_name)$/
+proc_kill      iproc.c /^proc_kill(p, sig)$/
+proc_pid       iproc-ptys.c    /^proc_pid(pid)$/
+proc_rec       iproc.c /^proc_rec(p, buf)$/
+proc_state     iproc-ptys.c    /^#define proc_state(p) ((p)->p_state)$/
+proc_strt      iproc-ptys.c    /^proc_strt(char *bufname, int clobber, ...)$/
+proc_write     iproc-ptys.c    /^proc_write(p, buf, nbytes)$/
+proto  jove.h  /^# define proto(x)        x$/
+pstate iproc.c /^pstate(p)$/
+ptoxy  mac.c   /^ptoxy(p,row,col)      \/* convert Point to terminal x,y /
+ptrproto       jove.h  /^#  define ptrproto(x)         ()$/
+push_env       util.c  /^push_env(savejmp)$/
+push_macro_stack       macros.c        /^push_macro_stack(m, count)$/
+put_bufs       misc.c  /^put_bufs(askp)$/
+putaddr        rec.c   /^putaddr(addr, p)$/
+putargpad      term.c  /^putargpad(str, arg, lines)$/
+putcurs        mac.c   /^putcurs(row,col,vis)$/
+putld  fmt.c   /^putld(d, base)$/
+putline        io.c    /^putline(buf)$/
+putmatch       re.c    /^putmatch(which, buf, size)$/
+putn   rec.c   /^putn(cp, nbytes)$/
+putp   mac.c   /^putp(p)                       \/* put one character, advance cursor *\/$/
+putpad term.c  /^putpad(str, lines)$/
+putreg io.c    /^putreg(fp, line1, char1, line2, char2, makesure)$/
+putstr fp.c    /^putstr(s)$/
+pwd    io.c    /^pwd()$/
+quad_numeric_arg       argcount.c      /^quad_numeric_arg()$/
+raw_complain   jove.c  /^raw_complain(const char *fmt, ...)$/
+raw_scream     jove.c  /^raw_scream(m)$/
+rawchkc        mac.c   /^rawchkc()$/
+rawgetc        mac.c   /^rawgetc()$/
+rawkey_ready   getch.c /^rawkey_ready()$/
+rbell  disp.c  /^rbell()$/
+rbwrite        fp.c    /^rbwrite(fd, buf, cnt)$/
+re_dosub       re.c    /^re_dosub(re_blk, tobuf, delp)$/
+re_indent      c.c     /^re_indent(incr)$/
+re_lindex      re.c    /^re_lindex(line, offset, dir, re_blk, lbuf_okay, cr/
+read   mac.c   /^read(fd,buf,n)$/
+read_file      io.c    /^read_file(file, is_insert)$/
+read_proc      iproc-ptys.c    /^read_proc(fd)$/
+readdir        scandir.c       /^readdir(dp)$/
+real_ask       ask.c   /^real_ask(delim, d_proc, def, prompt)$/
+real_blkio     io.c    /^real_blkio(b, iofcn)$/
+recclose       rec.c   /^recclose()$/
+recinit        rec.c   /^recinit()$/
+recremove      rec.c   /^recremove()$/
+redisplay      disp.c  /^redisplay()$/
+reg_delete     delete.c        /^reg_delete(line1, char1, line2, char2)$/
+reg_kill       delete.c        /^reg_kill(line2, char2, dot_moved)$/
+remfreelines   insert.c        /^remfreelines(c)$/
+replace        re1.c   /^replace(query, inreg)$/
+reset_43       pcscr.c /^void reset_43()$/
+rest_abbrevs   abbrev.c        /^rest_abbrevs(file)$/
+rtowind        mac.c   /^rtowind(row)  \/* return jove window row is in *\/$/
+s_mess fmt.c   /^s_mess(const char *fmt, ...)$/
+save_abbrevs   abbrev.c        /^save_abbrevs(file)$/
+scanvec        jove.c  /^scanvec(args, str)$/
+scr_up pcscr.c /^#define scr_up()              scr_win(1, 0, 0, LPP-1, CHPL-1)$/
+scr_win        pcscr.c /^void near scr_win(no, ulr, ulc, lrr, lrc)$/
+search re.c    /^search(dir, re, setdefault)$/
+send_p iproc-ptys.c    /^send_p(c)$/
+setCWD io.c    /^setCWD(d)$/
+set_arg_value  argcount.h      /^#define set_arg_value(n)      { arg_supplied_p = YES; a/
+set_cur        pcscr.c /^void near set_cur(xy)$/
+set_ino        buf.c   /^set_ino(b)$/
+set_is_an_arg  argcount.h      /^#define set_is_an_arg(there_is)       { arg_supplied_p =/
+set_mark       marks.c /^set_mark()$/
+set_mode       pcscr.c /^void near set_mode(n)$/
+set_wsize      proc.c  /^set_wsize(wsize)$/
+setblock       jove.c  /^setblock(fd, on)      \/* turn blocking on or off *\/$/
+setbname       buf.c   /^setbname(b, name)$/
+setcolor       pcscr.c /^void setcolor(fg, bg)$/
+setdir mac.c   /^setdir(vol,dir)$/
+setfname       buf.c   /^setfname(b, name)$/
+setsearch      re.c    /^setsearch(str)$/
+settout        term.c  /^settout(ttbuf)$/
+signal mac.c   /^(*signal(sig,func)) proto((int))$/
+sindex util.c  /^sindex(pattern, string)$/
+skip_wht_space misc.c  /^skip_wht_space()$/
+slowpoke       util.c  /^slowpoke(junk)$/
+sprint fmt.c   /^sprint(const char *fmt, ...)$/
+sput_end       screen.c        /^sput_end()$/
+sput_start     screen.c        /^sput_start()$/
+sputc  screen.c        /^sputc(c)$/
+stat   mac.c   /^stat(fname,buf)$/
+std_state      mac.c   /^#define std_state(w) (*((WStateData **)((WindowPee/
+strerror       util.c  /^strerror(errnum)$/
+strip_c        c.c     /^strip_c(from, to)$/
+substitute     re1.c   /^substitute(re_blk, query, l1, char1, l2, char2)$/
+switchar       proc.c  /^switchar()$/
+swrite screen.c        /^swrite(line, inversep, abortable)$/
+swritef        fmt.c   /^swritef(char *str, size_t size, const char *fmt, ./
+tailrule       paragraph.c     /^tailrule(lp)$/
+tiewind        util.c  /^tiewind(w, bp)$/
+tmpclose       io.c    /^tmpclose()$/
+tmpinit        io.c    /^tmpinit()$/
+tmpremove      io.c    /^tmpremove()$/
+tn_init        mac.c   /^tn_init()$/
+to_sent        move.c  /^to_sent(dir)$/
+to_word        util.c  /^to_word(dir)$/
+tputc  term.c  /^tputc(c)$/
+ttinit jove.c  /^ttinit()$/
+ttsize jove.c  /^ttsize()$/
+tty_reset      jove.c  /^tty_reset()$/
+ttyset jove.c  /^ttyset(n)$/
+unlink mac.c   /^unlink(name)$/
+unmodify       util.c  /^unmodify()$/
+unwind_macro_stack     macros.c        /^unwind_macro_stack()$/
+updmode        jove.c  /^updmode(junk)$/
+upper  case.c  /^upper(p)$/
+user_state     mac.c   /^#define user_state(w) (*((WStateData **)((WindowPe/
+v_clear        disp.c  /^v_clear(line1, line2)$/
+v_del_line     screen.c        /^v_del_line(num, top, bottom)$/
+v_ins_line     screen.c        /^v_ins_line(num, top, bottom)$/
+va_arg mac.h   /^#define va_arg(l,m) (((m*)((l) += sizeof(m)))[-1])/
+va_end mac.h   /^#define va_end(l) { (l) = NULL; }$/
+va_init        jove.h  /^# define      va_init(ap, parmN)      { va_start((ap), (parm/
+va_start       mac.h   /^#define va_start(l) { (l) = (va_list)&va_alist; }$/
+valid_bp       buf.c   /^valid_bp(bp)$/
+vpr_aux        extend.c        /^vpr_aux(vp, buf, size)$/
+w_nam_typ      wind.c  /^w_nam_typ(name, type)$/
+w_termsignum   wait.h  /^# define w_termsignum(w)      ((w).w_termsig)$/
+wait2  wait.h  /^# define wait2(w, x)          wait(w)$/
+waitchar       util.c  /^waitchar(slow)$/
+waitfun        getch.c /^waitfun()$/
+watch_input    iproc.c /^watch_input(m)$/
+wc_adjust      mac.c   /^wc_adjust(w,h,wcf,init)               \/* adjust window config t/
+wherex pcscr.c /^#define wherex()      C_X$/
+wherexy        pcscr.c /^void near wherexy( x, y)$/
+wherey pcscr.c /^#define wherey()      C_Y$/
+win_reshape    jove.c  /^win_reshape(junk)$/
+windbp wind.c  /^windbp(bp)$/
+windtol        mac.c   /^windtol(w,row)                \/* return line for row in window */
+winit  wind.c  /^winit()$/
+within_indent  util.c  /^within_indent()$/
+wrch   pcscr.c /^#define wrch(c)               ch_out((c), 1), cur_advance()$/
+write  mac.c   /^write(fd,buf,n)$/
+write_em       pcscr.c /^void write_em(s)$/
+write_emc      pcscr.c /^void write_emc(s, n)$/
+write_emif     pcscr.c /^void write_emif(s)$/
+writechr       mac.c   /^writechr(start)$/
+writef fmt.c   /^writef(const char *fmt, ...)$/
+yes_or_no_p    ask.c   /^yes_or_no_p(char *fmt, ...)$/
diff --git a/usr/src/contrib/jove-4.14.6/teachjove.c b/usr/src/contrib/jove-4.14.6/teachjove.c
new file mode 100644 (file)
index 0000000..194bd86
--- /dev/null
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+
+#ifndef        TEACHJOVE
+#    define TEACHJOVE  "/usr/lib/jove/teach-jove"
+#endif
+
+#ifndef        W_OK
+#   define W_OK        2
+#   define F_OK        0
+#endif
+
+#ifdef __STDC__
+#define        proto(x)        x
+#else
+#define        proto(x)        ()
+#endif
+
+extern char    *getenv proto((const char *));
+extern int     access proto((const char *, int));
+extern int     system proto((const char *));
+extern int     execlp proto((const char *, const char *, ...));
+
+int
+main()
+{
+       char    cmd[256],
+               fname[256],
+               *home;
+
+       if ((home = getenv("HOME")) == NULL) {
+               printf("teachjove: cannot find your home!\n");
+               exit(-1);
+       }
+       (void) sprintf(fname, "%s/teach-jove", home);
+       if (access(fname, F_OK) != 0) {
+               (void) sprintf(cmd, "cp %s %s; chmod 644 %s", TEACHJOVE, fname, fname);
+               system(cmd);
+       }
+       (void) execlp("jove", "teachjove", fname, (char *) NULL);
+       printf("teachjove: cannot execl jove!\n");
+       return 1;
+}
+
diff --git a/usr/src/contrib/jove-4.14.6/temp.h b/usr/src/contrib/jove-4.14.6/temp.h
new file mode 100644 (file)
index 0000000..b8d2865
--- /dev/null
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* The tmp file is indexed in chunks of CH_SIZE characters.  CH_SIZE is
+   (1 << CH_BITS).  New lines are added to the end of the tmp file.  The
+   file is not garbage collected because that would be too painful.  As a
+   result, commands like Yank and Kill are really easy; basically all we
+   do is make copies of the disk addresses of the lines (as opposed to
+   the contents).  So, putline(buf) writes BUF to the disk and returns a
+   new disk address.  Getline(addr, buf) is the opposite of putline().
+   f_getputl(line, fp) reads from open FP directly into the tmp file (into
+   the buffer cache (see below)) and stores the address in LINE.  This is
+   used during read_file to minimize compying.
+
+   Lines do NOT cross block bounderies in the tmp file so that accessing
+   the contents of lines can be much faster.  Pointers to offsets into
+   disk buffers are returned instead of copying the contents into local
+   arrays and then using them.  This cuts down on the amount of copying a
+   great deal, at the expense of less efficiency.  The lower bit of disk
+   addresses is used for marking lines as needing redisplay done.
+
+   There is a buffer cache of NBUF buffers (64 on !SMALL machines and the
+   3 on small ones).  The blocks are stored in LRU order and each block
+   is also stored in a hash table by block #.  When a block is requested
+   it can quickly be looked up in the hash table.  If it's not there the
+   LRU block is assigned the new block #.  If it finds that the LRU block
+   is dirty (i.e., has pending IO) it syncs the WHOLE tmp file, i.e.,
+   does all the pending writes.  This works much better on floppy disk
+   systems, like the IBM PC, if the blocks are sorted before sync'ing. */
+
+#ifdef SMALL
+# define CH_BITS               4
+# define MAX_BLOCKS            (1024/JBUFSIZ * 512)
+#else
+# define CH_BITS               0
+# define MAX_BLOCKS            4096    /* basically unlimited */
+#endif /* SMALL */
+
+#if    JBUFSIZ == 512
+# define BNO_SHIFT             (9 - CH_BITS)
+#else
+# if   JBUFSIZ == 1024
+#   define BNO_SHIFT           (10 - CH_BITS)
+# else
+    /* ??? */
+# endif
+#endif
+
+/* CH_SIZE is how big each chunk is.  For each 1 the DFree pointer
+   is incremented we extend the tmp file by CH_SIZE characters.
+   CH_PBLOCK is the # of chunks per block.  RND_MASK is used to mask
+   off the lower order bits of the daddr to round down to the beginning
+   of a block.  OFF_MASK masks off the higher order bits so we can get
+   at the offset into the disk buffer.
+
+   NOTE:  It's pretty important that these numbers be multiples of 2.
+         Be careful if you change things. */
+
+#define CH_SIZE                        ((daddr) 1 << CH_BITS)
+#define CH_PBLOCK              ((daddr) JBUFSIZ / CH_SIZE)
+#define RND_MASK               ((daddr) CH_PBLOCK - 1)
+#define OFF_MASK               ((daddr) JBUFSIZ - 1)
+#define BNO_MASK               ((daddr) MAX_BLOCKS - 1)
+#define blk_round(addr)                ((daddr) (addr) & ~RND_MASK)
+#define forward_block(addr)    ((daddr) (addr) + CH_PBLOCK)
+#define da_to_bno(addr)                ((daddr) ((addr) >> BNO_SHIFT) & BNO_MASK)
+#define da_to_off(addr)                ((daddr) ((addr) << CH_BITS) & OFF_MASK)
+#define da_too_huge(addr)      ((daddr) ((addr) >> BNO_SHIFT) >= MAX_BLOCKS)
diff --git a/usr/src/contrib/jove-4.14.6/term.c b/usr/src/contrib/jove-4.14.6/term.c
new file mode 100644 (file)
index 0000000..9b71085
--- /dev/null
@@ -0,0 +1,376 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "fp.h"
+#include "disp.h"
+#include "ctype.h"
+#include <errno.h>
+
+#ifndef        MAC     /* most of the file... */
+
+# ifdef        STDARGS
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+
+#ifndef        MSDOS
+# ifdef        SYSV
+#   include <termio.h>
+# else
+#   include <sgtty.h>
+# endif        /* SYSV */
+#endif /* MSDOS */
+
+#ifdef IPROCS
+# include <signal.h>
+#endif
+
+#include "termcap.h"
+
+/* Termcap definitions */
+
+#ifndef        IBMPC
+char   *CS,
+       *SO,
+       *SE,
+       *CM,
+       *CL,
+       *CE,
+       *HO,
+       *AL,
+       *DL,
+       *VS,
+       *VE,
+       *KS,
+       *KE,
+       *TI,
+       *TE,
+       *IC,
+       *DC,
+       *IM,
+       *EI,
+       *LL,
+       *M_IC,  /* Insert char with arg */
+       *M_DC,  /* Delete char with arg */
+       *M_AL,  /* Insert line with arg */
+       *M_DL,  /* Delete line with arg */
+       *SF,    /* Scroll forward */
+       *SR,
+       *M_SF,  /* Scroll forward with arg */
+       *M_SR,  /* Scroll back with arg */
+       *SP,    /* Send Cursor Position */
+       *VB,
+       *BL,
+       *IP,    /* insert pad after character inserted */
+       *lPC,
+       *NL,
+       *DO;
+#endif
+
+int    LI,
+       ILI,    /* Internal lines, i.e., 23 of LI is 24. */
+       CO,
+
+       SG,     /* number of magic cookies left by SO and SE */
+
+       UPlen,
+       HOlen,
+       LLlen;
+
+bool
+       XS,     /* whether standout is braindamaged */
+       Hazeltine,      /* Hazeltine tilde kludge */
+       MI,
+       UL,
+       NP,
+       TABS;
+
+#ifdef NEVER
+       /*
+        * Are you sure about this one Jon?  On the SYSV system I tried this
+        * on I got a multiple definition of PC because it was already
+        * defined in -ltermcap.  Similarly for BC and UP ...
+        */
+# ifdef        SYSVR2 /* release 2, at least */
+char   PC;
+# endif        /* SYSVR2 */
+#endif
+
+#ifndef        IBMPC
+private char   tspace[256];
+
+/* The ordering of ts and meas must agree !! */
+private const char     ts[] =
+       "vsvealdlspcssosecmclcehoupbcicimdceillsfsrvbksketiteALDLICDCpcipblnldoSFSR";
+
+private char   **const meas[] = {
+       &VS, &VE, &AL, &DL, &SP, &CS, &SO, &SE,
+       &CM, &CL, &CE, &HO, &UP, &BC, &IC, &IM,
+       &DC, &EI, &LL, &SF, &SR, &VB, &KS, &KE,
+       &TI, &TE, &M_AL, &M_DL, &M_IC, &M_DC,
+       &lPC, &IP, &BL, &NL, &DO, &M_SF, &M_SR, NULL
+};
+
+private void
+TermError()
+{
+       flushscreen();
+       _exit(1);
+}
+
+void
+getTERM()
+{
+       char    termbuf[13],
+               *termname = NULL,
+               *termp = tspace,
+               tbuff[2048];    /* Good grief! */
+       const char      *tsp = ts;
+       int     i;
+
+       termname = getenv("TERM");
+       if ((termname == NULL) || (*termname == '\0') ||
+           (strcmp(termname, "dumb") == 0) ||
+           (strcmp(termname, "unknown") == 0) ||
+           (strcmp(termname, "network") == 0)) {
+               putstr("Enter terminal type (e.g, vt100): ");
+               flushscreen();
+               termbuf[read(0, (UnivPtr) termbuf, sizeof(termbuf)) - 1] = '\0';
+               if (termbuf[0] == '\0')
+                       TermError();
+
+               termname = termbuf;
+       }
+
+       if (tgetent(tbuff, termname) < 1) {
+               writef("[\"%s\" unknown terminal type?]", termname);
+               TermError();
+       }
+       if ((CO = tgetnum("co")) == -1) {
+wimperr:
+               writef("You can't run JOVE on a %s terminal.\n", termname);
+               TermError();
+               /*NOTREACHED*/
+       }
+
+       else if (CO > MAXCOLS)
+               CO = MAXCOLS;
+
+       if ((LI = tgetnum("li")) == -1)
+               goto wimperr;
+
+       if ((SG = tgetnum("sg")) == -1)
+               SG = 0;                 /* Used for mode line only */
+
+       XS = tgetflag("xs")==TRUE;      /* Used for mode line only */
+       Hazeltine = tgetflag("hz")==TRUE;       /* Hazeltine tilde kludge */
+       NP = tgetflag("NP")==TRUE;      /* no pad char flag */
+
+       for (i = 0; meas[i]; i++) {
+               static char     nm[3] = "xx";
+
+               nm[0] = *tsp++;
+               nm[1] = *tsp++;
+               *(meas[i]) = (char *) tgetstr(nm, &termp);
+               if (termp > tspace + sizeof(tspace))
+                       goto wimperr;
+       }
+       if (lPC)
+               PC = *lPC;
+       if (XS)
+               SO = SE = NULL;
+
+       if (CS && !SR)
+               CS = SR = SF = M_SF = M_SR = NULL;
+
+       if (CS && !SF)
+               SF = "\n";
+
+       if (IM && (*IM == '\0'))
+               IM = NULL;
+       else
+               MI = tgetflag("mi")==TRUE;
+
+       UL = tgetflag("ul")==TRUE;
+
+       if (NL == NULL)
+               NL = "\n";
+       else {                  /* strip stupid padding information */
+               while (jisdigit(*NL))
+                       NL += 1;
+               if (*NL == '*')
+                       NL += 1;
+       }
+       if (!DO)
+               DO = NL;
+
+       if (BL == NULL)
+               BL = "\007";
+
+       if (tgetflag("km") == TRUE)             /* has meta-key */
+               MetaKey = ON;
+
+#ifdef ID_CHAR
+       disp_opt_init();
+#endif
+       if ((CanScroll = ((AL && DL) || CS)) != 0)
+               IDline_setup(termname);
+}
+
+#else  /* IBMPC */
+
+void
+InitCM()
+{
+}
+
+bool EGA;
+
+void
+getTERM()
+{
+       char    *getenv(), *tgetstr() ;
+       char    *termname;
+       void    init_43(), init_term();
+       unsigned char lpp(), chpl();
+
+       if (getenv("EGA") != NULL || (!stricmp(getenv("TERM"), "EGA"))) {
+          termname = "ega";
+          init_43();
+          EGA = YES;
+       } else {
+          termname = "ibmpc";
+          init_term();
+          EGA = NO;
+       }
+
+       CO = chpl();
+       LI = lpp();
+
+       SG = 0;                 /* Used for mode line only */
+       XS = NO;                        /* Used for mode line only */
+
+       CanScroll = YES;
+}
+
+#endif /* IBMPC */
+
+#else  /* MAC */
+int    LI,
+       ILI,    /* Internal lines, i.e., 23 of LI is 24. */
+       CO,
+       SG;
+
+bool   TABS;
+
+void getTERM()
+{
+       SG = 0;
+       CanScroll = YES;
+}
+
+#endif /* MAC */
+
+/* put a string with padding */
+
+#ifndef        IBMPC
+private void
+tputc(c)
+int    c;
+{
+       jputchar(c);
+}
+#endif /* IBMPC */
+
+#ifndef        MAC
+void
+putpad(str, lines)
+char   *str;
+int    lines;
+{
+#ifndef        IBMPC
+       if (str)
+               tputs(str, lines, tputc);
+#else  /* IBMPC */
+       write_emif(str);
+#endif /* IBMPC */
+}
+
+void
+putargpad(str, arg, lines)
+char   *str;
+int    arg,
+       lines;
+{
+#ifndef        IBMPC
+       if (str) {
+               tputs(
+#ifdef TERMINFO
+                       tparm(str, arg),
+#else  /* TERMINFO */
+                       tgoto(str, 0, arg),     /* fudge */
+#endif /* TERMINFO */
+                       lines, tputc);
+       }
+#else  /* IBMPC */
+       /* This code is only a guess: I don't know if any M_* termcap
+        * attributes are defined for the PC.  If they are not used,
+        * this routine is not called.  Perhaps this routine should
+        * simply abort.
+        */
+       if (str) {
+               char    buf[16];        /* hope that this is long enough */
+
+               swritef(buf, sizeof(buf), str, arg);    /* hope only %d appears in str */
+               write_em(buf);
+       }
+#endif /* IBMPC */
+}
+
+#endif /* MAC */
+
+/* Determine the number of characters to buffer at each baud rate.  The
+   lower the number, the quicker the response when new input arrives.  Of
+   course the lower the number, the more prone the program is to stop in
+   output.  Decide what matters most to you. This sets BufSize to the right
+   number or chars, and initializes `stdout'.  */
+
+void
+settout(ttbuf)
+char   *ttbuf;
+{
+#ifdef UNIX
+       static const int speeds[] = {
+               1,      /* 0    */
+               1,      /* 50   */
+               1,      /* 75   */
+               1,      /* 110  */
+               1,      /* 134  */
+               1,      /* 150  */
+               1,      /* 200  */
+               2,      /* 300  */
+               4,      /* 600  */
+               8,      /* 1200 */
+               16,     /* 1800 */
+               32,     /* 2400 */
+               128,    /* 4800 */
+               256,    /* 9600 */
+               512,    /* EXTA */
+               1024    /* EXT  */
+       };
+
+       int     speed_chars = speeds[ospeed];
+#else
+       int     speed_chars = 256;
+#endif
+
+       flushscreen();          /* flush the one character buffer */
+       BufSize = min(MAXTTYBUF, speed_chars * max(LI / 24, 1));
+       stdout = fd_open("/dev/tty", F_WRITE|F_LOCKED, 1, ttbuf, BufSize);
+}
diff --git a/usr/src/contrib/jove-4.14.6/termcap.h b/usr/src/contrib/jove-4.14.6/termcap.h
new file mode 100644 (file)
index 0000000..4c76187
--- /dev/null
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define MAXCOLS                256     /* maximum number of columns */
+
+#ifdef TERMCAP
+
+/* termcap definitions */
+
+extern char
+       *CS,    /* If on vt100 */
+       *SO,    /* Start standout */
+       *SE,    /* End standout */
+       *CM,    /* The cursor motion string */
+       *CL,    /* Clear screen */
+       *CE,    /* Clear to end of line */
+       *HO,    /* Home cursor */
+       *AL,    /* Addline (insert line) */
+       *DL,    /* Delete line */
+       *VS,    /* Visual start */
+       *VE,    /* Visual end */
+       *KS,    /* Keypad mode start */
+       *KE,    /* Keypad mode end */
+       *TI,    /* Cursor addressing start */
+       *TE,    /* Cursor addressing end */
+       *IC,    /* Insert char */
+       *DC,    /* Delete char */
+       *IM,    /* Insert mode */
+       *EI,    /* End insert mode */
+       *LL,    /* Last line, first column */
+       *M_IC,  /* Insert char with arg */
+       *M_DC,  /* Delete char with arg */
+       *M_AL,  /* Insert line with arg */
+       *M_DL,  /* Delete line with arg */
+       *SF,    /* Scroll forward */
+       *SR,    /* Scroll reverse */
+       *M_SF,  /* Scroll forwards with arg */
+       *M_SR,  /* Scroll backwards with arg */
+       *SP,    /* Send cursor position */
+       *VB,    /* visible bell */
+       *BL,    /* audible bell */
+       *IP,    /* insert pad after character inserted */
+       *lPC,
+       *NL,    /* newline character (usually \n) */
+       *DO;
+
+extern int
+       LI,             /* number of lines */
+       ILI,            /* number of internal lines */
+       CO,             /* number of columns */
+
+       SG,             /* number of magic cookies left by SO and SE */
+       UPlen,          /* length of the UP string */
+       HOlen,          /* length of Home string */
+       LLlen;          /* length of lower string */
+
+extern bool
+       XS,     /* whether standout is braindamaged */
+       Hazeltine,              /* Hazeltine tilde kludge */
+       MI,             /* okay to move while in insert mode */
+       UL,             /* underscores don't replace chars already on screen */
+       NP,     /* there is No Pad character */ 
+       TABS;           /* whether we are in tabs mode */
+
+extern char
+       PC,
+       *BC,            /* back space */
+       *UP;    /* Scroll reverse, or up */
+
+extern short   ospeed;
+
+#else  /* !TERMCAP */
+
+extern int     /* probably should clean this up */
+       LI,             /* number of lines */
+       ILI,            /* number of internal lines */
+       CO,             /* number of columns */
+       TABS,
+       SG;
+
+#endif /* !TERMCAP */
diff --git a/usr/src/contrib/jove-4.14.6/ttystate.h b/usr/src/contrib/jove-4.14.6/ttystate.h
new file mode 100644 (file)
index 0000000..cb32e45
--- /dev/null
@@ -0,0 +1,49 @@
+/* Various tty state structures.
+ * Each is an array, subscripted by one of "OFF" or "ON".
+ */
+
+#ifdef UNIX
+
+#if defined(SGTTY) || defined(BRLUNIX)
+# include <sgtty.h>
+# ifdef        BRLUNIX
+extern struct sg_brl   sg[2];
+# else
+extern struct sgttyb   sg[2];
+# endif /* BRLUNIX */
+#endif
+
+#ifdef TERMIO
+# include <termio.h>
+# include <sys/ioctl.h>
+extern struct termio   sg[2];
+#endif
+
+#ifdef TERMIOS
+# include <termios.h>
+#ifdef BSD386
+# include <sys/ioctl.h>
+#endif
+extern struct termios  sg[2];
+# ifndef VDSUSP
+#  define VDSUSP       VSUSP   /* non-Posixism in Irix3.3, may exist in others */
+# endif
+#endif
+
+#ifdef SYSVR4
+#undef TIOCSLTC        /* don't let BSD emulation mislead us */
+#endif
+
+# ifdef        TIOCSLTC
+extern struct ltchars  ls[2];
+# endif        /* TIOCSLTC */
+
+#ifdef SYSV
+#undef TIOCGETC        /* not appropriate for System V */
+#endif
+
+# ifdef        TIOCGETC
+extern struct tchars   tc[2];
+# endif
+
+#endif /* UNIX */
diff --git a/usr/src/contrib/jove-4.14.6/tune.dos b/usr/src/contrib/jove-4.14.6/tune.dos
new file mode 100644 (file)
index 0000000..85efc06
--- /dev/null
@@ -0,0 +1,22 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define NOEXTERNS
+
+#include "tune.h"
+
+/* these are variables that can be set with the set command, so they are
+   allocated more memory than they actually need for the defaults */
+char   TmpFilePath[64] = ".",
+       Shell[64] = "command",
+       ShFlags[16] = "-c",
+       CmdDb[64] = "c:/unix/cmds.doc";
+
+/* these guys are not settable */
+char   *d_tempfile = "joveXXXXXX",     /* buffer lines go here */
+       *Joverc = "jove.rc";
+
diff --git a/usr/src/contrib/jove-4.14.6/tune.h b/usr/src/contrib/jove-4.14.6/tune.h
new file mode 100644 (file)
index 0000000..37d024c
--- /dev/null
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#define TUNED          1       /* don't touch this */
+
+#include "sysdep.h"
+
+#ifdef UNIX
+# define SUBPROCS      1       /* only on UNIX systems (NOT INCORPORATED YET) */
+# define IPROCS                1       /* interactive processes */
+# ifdef        BSD4_2
+#   define PTYPROCS    1       /* use pseudo-ttys */
+# else
+#   define PIPEPROCS   1       /* use pipes */
+# endif
+#endif /* UNIX */
+
+#define BACKUPFILES    1       /* enable the backup files code */
+#define F_COMPLETION   1       /* filename completion */
+#define ABBREV         1       /* word abbreviation mode */
+
+#ifdef UNIX
+# define ID_CHAR       1       /* include code to IDchar */
+/* # define WIRED_TERMS 1 */   /* include code for wired terminals */
+#endif
+
+#define LISP           1       /* include the code for Lisp Mode */
+#define CMT_FMT                1       /* include the comment formatting routines */
+
+#ifdef UNIX
+/* Use the load average for various commands.
+ * Do not define LOAD_AV if you lack a load average
+ * system call and kmem is read protected.
+ */
+/* # define LOAD_AV    1 */
+
+# define BIFF          1       /* if you have biff (or the equivalent) */
+# define SPELL         1       /* spell words and buffer commands */
+#endif
+
+#define DFLT_MODE      0666    /* file will be created with this mode */
+
+/* If the compiler does not support void, use -Dvoid=int or
+ * typedef int void;
+ */
+
+/* USE_PROTOTYPE must be defined for compilers that support prototypes
+ * but are NOT ANSI C, i.e. do not have __STDC__ == 1.
+ */
+
+/* NO_PTRPROTO must be defined for compilers that support prototypes,
+ * but do NOT support prototypes for pointers to functions.
+ * It seems that some MSDOS and Mac compilers fall in this category.
+ */
+#ifdef MSDOS
+# define NO_PTRPROTO 1
+#endif
+
+#ifdef MAC
+# define USE_PROTOTYPES        1
+# define NO_PTRPROTO   1
+#endif
+
+/* These are here since they define things in tune.c.  If you add things to
+   tune.c, add them here too, if necessary. */
+
+extern char
+       *d_tempfile,
+       *p_tempfile,
+       *Recover,
+       *Joverc,
+
+#ifdef PIPEPROCS
+       *Portsrv,
+       *Kbd_Proc,
+#endif
+
+#ifdef MSDOS
+       CmdDb[],
+#else
+       *CmdDb,
+#endif
+
+       TmpFilePath[],
+       Shell[],
+       ShFlags[];
diff --git a/usr/src/contrib/jove-4.14.6/tune.template b/usr/src/contrib/jove-4.14.6/tune.template
new file mode 100644 (file)
index 0000000..cd433a1
--- /dev/null
@@ -0,0 +1,28 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+
+char   *d_tempfile = "joveXXXXXX",     /* buffer lines go here */
+       *p_tempfile = "jrecXXXXXX",     /* line pointers go here */
+       *Recover = "LIBDIR/recover",
+       *CmdDb = "SHAREDIR/cmds.doc",
+               /* copy of "cmds.doc" lives in the doc subdirectory */
+
+       *Joverc = "SHAREDIR/jove.rc",
+
+#if defined(IPROCS) && defined(PIPEPROCS)
+       *Portsrv = "LIBDIR/portsrv",
+       *Kbd_Proc = "LIBDIR/kbd",
+#endif
+
+/* these are variables that can be set with the set command, so they are
+   allocated more memory than they actually need for the defaults */
+
+       TmpFilePath[FILESIZE] = "TMPDIR",
+       Shell[FILESIZE] = "SHELL",
+       ShFlags[16] = "-c";
diff --git a/usr/src/contrib/jove-4.14.6/util.c b/usr/src/contrib/jove-4.14.6/util.c
new file mode 100644 (file)
index 0000000..1ab8803
--- /dev/null
@@ -0,0 +1,1049 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+#include "ctype.h"
+#include "termcap.h"
+#include "disp.h"
+#include "fp.h"
+#include <signal.h>
+#include <errno.h>
+
+#ifdef MAC
+# include "mac.h"
+#else
+# ifdef        STDARGS
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+#endif
+
+#ifdef MSDOS
+#include <time.h>
+#endif
+
+#ifndef IBMPC
+const
+#endif
+struct cmd *
+FindCmd(proc)
+register void  (*proc) proto((void));
+{
+       register const struct cmd       *cp;
+
+       for (cp = commands; cp->Name; cp++)
+               if (cp->c_proc == proc)
+                       return cp;
+       return NULL;
+}
+
+bool   Interactive = NO;       /* True when we invoke with the command handler? */
+data_obj       *LastCmd;
+char   *ProcFmt = ": %f ";
+
+void
+ExecCmd(cp)
+register data_obj      *cp;
+{
+       LastCmd = cp;
+       if (cp->Type & MAJOR_MODE) {
+               SetMajor((cp->Type >> 8));
+       } else if (cp->Type & MINOR_MODE) {
+               TogMinor((cp->Type >> 8));
+       } else  switch (cp->Type&TYPEMASK) {
+               case MACRO:
+                       do_macro((struct macro *) cp);
+                       break;
+
+               case FUNCTION:
+                   {
+                       register struct cmd     *cmd = (struct cmd *) cp;
+
+                       if (cmd->c_proc) {
+                               if ((cmd->Type & MODIFIER) &&
+                                   (BufMinorMode(curbuf, ReadOnly))) {
+                                       rbell();
+                                       message("[Buffer is read-only]");
+                               } else
+                                       (*cmd->c_proc)();
+                       }
+                   }
+       }
+}
+
+Line *
+lastline(lp)
+register Line  *lp;
+{
+       register Line   *next;
+
+       while ((next = lp->l_next) != NULL)
+               lp = next;
+       return lp;
+}
+
+char   key_strokes[100],
+       *keys_p = key_strokes;
+
+void
+pp_key_strokes(buffer, size)
+char   *buffer;
+size_t size;
+{
+       char    *buf_end = buffer + size - 1,
+               *kp = key_strokes,
+               c;
+
+       *buffer = '\0';
+       while ((c = *kp++) != '\0') {
+               swritef(buffer, (size_t) (buf_end-buffer), "%p ", c);
+               buffer += strlen(buffer);
+               if (buffer >= buf_end)
+                       break;
+       }
+}
+
+private int    *slowp = NULL;  /* for waitchar() */
+
+private SIGRESULT
+slowpoke(junk)
+int    junk;
+{
+       int save_errno = errno; /* Subtle, but necessary! */
+       char    buffer[100];
+
+       if (slowp)
+               *slowp = YES;
+       pp_key_strokes(buffer, sizeof (buffer));
+       f_mess(buffer);
+       errno = save_errno;
+       SIGRETURN;
+}
+
+#ifdef UNIX
+# ifdef        BSD4_2
+#  define N_SEC        1       /* will be precisely 1 second on 4.2 */
+# else
+#  define N_SEC        2       /* but from 1 to 2 seconds otherwise */
+# endif
+#else  /* !UNIX */
+# define N_SEC 1
+int in_macro();
+#endif /* !UNIX */
+
+int
+waitchar(slow)
+int    *slow;
+{
+       int     c;
+#ifdef UNIX
+       unsigned int    old_time;
+       SIGRESULT       (*oldproc) proto((int));
+#else  /* !UNIX */
+       long sw, time();
+#endif /* !UNIX */
+
+       slowp = slow;
+
+       if (in_macro())         /* make macros faster ... */
+               return getch();
+
+       /* If slow is a valid pointer and it's value is yes, then
+          we know we have already been slow during this sequence,
+          so we just wait for the character and then echo it. */
+       if (slow != NULL && *slow == YES) {
+               c = getch();
+               slowpoke(0);
+               return c;
+       }
+#ifdef UNIX
+       oldproc = signal(SIGALRM, slowpoke);
+
+       if ((old_time = alarm((unsigned) N_SEC)) == 0)
+               old_time = UpdFreq;
+       c = getch();
+       (void) alarm(old_time);
+       (void) signal(SIGALRM, oldproc);
+
+       if (slow != NULL && *slow == YES)
+               slowpoke(0);
+       return c;
+
+#else  /* !UNIX */
+#ifdef MAC
+       Keyonly = YES;
+       if (charp() || in_macro()) {
+               c = getch();    /* to avoid flicker */
+               if (slow != NULL && *slow == YES)
+                       slowpoke();
+               return c;
+       }
+#endif
+       time(&sw);
+       sw += N_SEC;
+       while (time(NULL) <= sw)
+               if (charp() || in_macro())
+                       return getch();
+#ifdef MAC
+       menus_off();
+#endif
+       slowpoke();
+       c = getch();
+       slowpoke();
+
+       return c;
+#endif /* !UNIX */
+}
+
+char *
+StrIndex(dir, buf, charpos, what)
+int    dir;    /* FORWARD or BACKWARD */
+register char  *buf;
+int    charpos;
+register int   what;
+{
+       register char   *cp = &buf[charpos];
+       register int    c;
+
+       if (dir > 0) {
+               while ((c = *cp++) != '\0')
+                       if ((c == what) != '\0')
+                               return (cp - 1);
+       } else {
+               while (cp >= buf && (c = *cp--)!='\0')
+                       if (c == what)
+                               return (cp + 1);
+       }
+       return NULL;
+}
+
+bool
+blnkp(buf)
+register char  *buf;
+{
+       register char   c;
+
+       do ; while ((c = *buf++)!='\0' && (c == ' ' || c == '\t'));
+       return c == 0;  /* It's zero if we got to the end of the Line */
+}
+
+bool
+within_indent()
+{
+       register char   c;
+       register int    i;
+
+       i = curchar;
+       do ; while (--i >= 0 && ((c = linebuf[i]) == ' ' || c == '\t'));
+       return i < 0;           /* it's < 0 if we got to the beginning */
+}
+
+Line *
+next_line(line, num)
+register Line  *line;
+register int   num;
+{
+       if (num < 0)
+               return prev_line(line, -num);
+       if (line)
+               while (--num >= 0 && line->l_next != NULL)
+                       line = line->l_next;
+       return line;
+}
+
+Line *
+prev_line(line, num)
+register Line  *line;
+register int   num;
+{
+       if (num < 0)
+               return next_line(line, -num);
+       if (line)
+               while (--num >= 0 && line->l_prev != NULL)
+                       line = line->l_prev;
+       return line;
+}
+
+void
+DotTo(line, col)
+Line   *line;
+int    col;
+{
+       Bufpos  bp;
+
+       bp.p_line = line;
+       bp.p_char = col;
+       SetDot(&bp);
+}
+
+/* If bp->p_line is != current line, then save current line.  Then set dot
+   to bp->p_line, and if they weren't equal get that line into linebuf.  */
+
+void
+SetDot(bp)
+register Bufpos        *bp;
+{
+       register int    notequal;
+
+       if (bp == NULL)
+               return;
+
+       notequal = bp->p_line != curline;
+       if (notequal)
+               lsave();
+       if (bp->p_line)
+               curline = bp->p_line;
+       if (notequal)
+               getDOT();
+       curchar = bp->p_char;
+       if (curchar > length(curline))
+               curchar = length(curline);
+}
+
+void
+ToLast()
+{
+       SetLine(curbuf->b_last);
+       Eol();
+}
+
+int    MarkThresh = 22;        /* average screen size ... */
+static int     line_diff;
+
+int
+LineDist(nextp, endp)
+register Line  *nextp,
+               *endp;
+{
+       (void) inorder(nextp, 0, endp, 0);
+       return line_diff;
+}
+
+int
+inorder(nextp, char1, endp, char2)
+register Line  *nextp,
+               *endp;
+int    char1,
+       char2;
+{
+       register Line   *prevp = nextp;
+
+       line_diff = 0;
+       if (nextp == endp)
+               return char1 < char2;
+
+       while (nextp && prevp) {
+               nextp = nextp->l_next;
+               prevp = prevp->l_prev;
+               line_diff += 1;
+               if (nextp == endp)
+                       return TRUE;
+               if (prevp == endp)
+                       return FALSE;
+       }
+       while (nextp!=NULL && nextp!=endp) {
+               nextp = nextp->l_next;
+               line_diff += 1;
+       }
+       while (prevp!=NULL && prevp!=endp) {
+               prevp = prevp->l_prev;
+               line_diff += 1;
+       }
+       /* nextp == prevp implies both are NULL: the lines are not ordered */
+       return nextp==prevp? -1 : nextp==endp;
+}
+
+void
+PushPntp(line)
+register Line  *line;
+{
+       if (LineDist(curline, line) >= MarkThresh)
+               set_mark();
+}
+
+void
+ToFirst()
+{
+       SetLine(curbuf->b_first);
+}
+
+int
+length(line)
+Line   *line;
+{
+       return strlen(lcontents(line));
+}
+
+void
+to_word(dir)
+register int   dir;
+{
+       register char   c;
+
+       if (dir == FORWARD) {
+               while ((c = linebuf[curchar]) != '\0' && !jisword(c))
+                       curchar += 1;
+               if (eolp()) {
+                       if (curline->l_next == NULL)
+                               return;
+                       SetLine(curline->l_next);
+                       to_word(dir);
+                       return;
+               }
+       } else {
+               while (!bolp() && (c = linebuf[curchar - 1], !jisword(c)))
+                       curchar -= 1;
+               if (bolp()) {
+                       if (curline->l_prev == NULL)
+                               return;
+                       SetLine(curline->l_prev);
+                       Eol();
+                       to_word(dir);
+               }
+       }
+}
+
+/* Are there any modified buffers?  Allp means include B_PROCESS
+   buffers in the check. */
+
+bool
+ModBufs(allp)
+bool   allp;
+{
+       register Buffer *b;
+
+       for (b = world; b != NULL; b = b->b_next)
+               if (b->b_type != B_SCRATCH
+               && (b->b_type == B_FILE || allp)
+               && IsModified(b))
+                       return YES;
+       return NO;
+}
+
+char *
+filename(b)
+register Buffer        *b;
+{
+       return b->b_fname ? pr_name(b->b_fname, YES) : "[No file]";
+}
+
+char *
+itoa(num)
+register int   num;
+{
+       static char     line[15];
+
+       swritef(line, sizeof(line), "%d", num);
+       return line;
+}
+
+int
+min(a, b)
+register int   a,
+               b;
+{
+       return (a < b) ? a : b;
+}
+
+int
+max(a, b)
+register int   a,
+               b;
+{
+       return (a > b) ? a : b;
+}
+
+void
+tiewind(w, bp)
+register Window        *w;
+register Buffer        *bp;
+{
+       int     not_tied = (w->w_bufp != bp);
+
+       UpdModLine = YES;       /* kludge ... but speeds things up considerably */
+       w->w_line = bp->b_dot;
+       w->w_char = bp->b_char;
+       w->w_bufp = bp;
+       if (not_tied)
+               CalcWind(w);    /* ah, this has been missing since the
+                                  beginning of time! */
+}
+
+char *
+lcontents(line)
+register Line  *line;
+{
+       if (line == curline)
+               return linebuf;
+       else
+               return lbptr(line);
+}
+
+char *
+ltobuf(line, buf)
+Line   *line;
+char   *buf;
+{
+       if (line == curline) {
+               if (buf != linebuf)
+                       strcpy(buf, linebuf);
+               Jr_Len = strlen(linebuf);
+       } else
+               getline(line->l_dline, buf);
+       return buf;
+}
+
+void
+DOTsave(buf)
+Bufpos *buf;
+{
+       buf->p_line = curline;
+       buf->p_char = curchar;
+}
+
+/* Return none-zero if we had to rearrange the order. */
+
+bool
+fixorder(line1, char1, line2, char2)
+register Line  **line1,
+               **line2;
+register int   *char1,
+               *char2;
+{
+       Line    *tline;
+       int     tchar;
+
+       if (inorder(*line1, *char1, *line2, *char2))
+               return NO;
+
+       tline = *line1;
+       tchar = *char1;
+       *line1 = *line2;
+       *char1 = *char2;
+       *line2 = tline;
+       *char2 = tchar;
+
+       return YES;
+}
+
+bool
+inlist(first, what)
+register Line  *first,
+               *what;
+{
+       while (first) {
+               if (first == what)
+                       return YES;
+               first = first->l_next;
+       }
+       return NO;
+}
+
+/* Make `buf' (un)modified and tell the redisplay code to update the modeline
+   if it will need to be changed. */
+
+int    ModCount = 0;
+
+void
+modify()
+{
+       if (!curbuf->b_modified) {
+               UpdModLine = YES;
+               curbuf->b_modified = YES;
+       }
+       DOLsave = YES;
+       if (!Asking)
+               ModCount += 1;
+}
+
+void
+unmodify()
+{
+       if (curbuf->b_modified) {
+               UpdModLine = YES;
+               curbuf->b_modified = NO;
+       }
+}
+
+int
+numcomp(s1, s2)
+register char  *s1,
+               *s2;
+{
+       register int    count = 0;
+
+       while (*s1 != '\0' && *s1++ == *s2++)
+               count += 1;
+       return count;
+}
+
+char *
+copystr(str)
+char   *str;
+{
+       char    *val;
+
+       if (str == NULL)
+               return NULL;
+       val = emalloc((size_t) (strlen(str) + 1));
+
+       strcpy(val, str);
+       return val;
+}
+
+#ifndef        byte_copy
+void
+byte_copy(from, to, count)
+UnivConstPtr   *from;
+UnivPtr                *to;
+register size_t        count;
+{
+       register const char     *p = from;
+       register char           *q = to;
+
+       if (count != 0) {
+           do *q++ = *p++; while (--count != 0);
+       }
+}
+#endif
+
+void
+len_error(flag)
+int    flag;
+{
+       char    *mesg = "[line too long]";
+
+       if (flag == COMPLAIN)
+               complain(mesg);
+       else
+               error(mesg);
+}
+
+/* Insert num number of c's at offset atchar in a linebuf of LBSIZE */
+
+void
+ins_c(c, buf, atchar, num, max)
+int    c;
+char   *buf;
+int    atchar,
+       num,
+       max;
+{
+       register char   *pp, *pp1;
+       register int    len;
+       int     numchars;       /* number of characters to copy forward */
+
+       if (num <= 0)
+               return;
+       len = atchar + strlen(&buf[atchar]);
+       if (len + num >= max)
+               len_error(COMPLAIN);
+       pp = &buf[len + 1];             /* + 1 so we can --pp (not pp--) */
+       pp1 = &buf[len + num + 1];
+       numchars = len - atchar;
+       while (numchars-- >= 0)
+               *--pp1 = *--pp;
+       pp = &buf[atchar];
+       while (--num >= 0)
+               *pp++ = c;
+}
+
+int
+TwoBlank()
+{
+       register Line   *next = curline->l_next;
+
+       return ((next != NULL) &&
+               (*(lcontents(next)) == '\0') &&
+               (next->l_next != NULL) &&
+               (*(lcontents(next->l_next)) == '\0'));
+}
+
+void
+linecopy(onto, atchar, from)
+register char  *onto,
+               *from;
+int    atchar;
+{
+       register char   *endp = &onto[LBSIZE];
+
+       onto += atchar;
+
+       do {
+               if (onto >= endp)
+                       len_error(ERROR);
+       } while ((*onto++ = *from++) != '\0');
+}
+
+char *
+IOerr(err, file)
+char   *err, *file;
+{
+       return sprint("Couldn't %s \"%s\".", err, file);
+}
+
+#ifdef UNIX
+void
+dopipe(p)
+int    *p;
+{
+       if (pipe(p) == -1)
+               complain("[Pipe failed: %s]", strerror(errno));
+}
+
+void
+pipeclose(p)
+int    *p;
+{
+       (void) close(p[0]);
+       (void) close(p[1]);
+}
+#endif /* UNIX */
+
+/* NOSTRICT */
+
+UnivPtr
+emalloc(size)
+size_t size;
+{
+       register UnivPtr        ptr;
+
+       if ((ptr = malloc(size)) == NULL) {
+               /* Try garbage collecting lines */
+               GCchunks();
+               if ((ptr = malloc(size)) == NULL) {
+                       /* Uh ... Oh screw it! */
+                       error("[Out of memory] ");
+                       /* NOTREACHED */
+               }
+       }
+       return ptr;
+}
+
+UnivPtr
+erealloc(ptr, size)
+UnivPtr        ptr;
+size_t size;
+{
+       if ((ptr = realloc(ptr, size)) == NULL) {
+               /* no second chance for realloc! */
+               error("[out of memory]");
+               /* NOTREACHED */
+       }
+       return ptr;
+}
+
+/* Return the basename of file F. */
+
+char *
+basename(f)
+register char  *f;
+{
+       register char   *cp;
+
+       if ((cp = strrchr(f, '/')) != NULL)
+               return cp + 1;
+       else
+#ifdef MSDOS
+               if (cp = strrchr(f, '\\'))
+                       return cp + 1;
+       else
+               if (cp = strrchr(f, ':'))
+                       return cp + 1;
+#endif /* MSDOS */
+               return f;
+}
+
+void
+push_env(savejmp)
+jmp_buf        savejmp;
+{
+       byte_copy((UnivPtr) mainjmp, (UnivPtr) savejmp, sizeof (jmp_buf));
+}
+
+void
+pop_env(savejmp)
+jmp_buf        savejmp;
+{
+       byte_copy((UnivPtr) savejmp, (UnivPtr) mainjmp, sizeof (jmp_buf));
+}
+
+/* get the time buf, designated by *timep, from FROM to TO. */
+char *
+get_time(timep, buf, from, to)
+time_t *timep;
+char   *buf;
+int    from,
+       to;
+{
+       time_t  now;
+       char    *cp;
+
+       if (timep != NULL)
+               now = *timep;
+       else
+               (void) time(&now);
+       cp = ctime(&now) + from;
+#ifndef        MSDOS
+       if (to == -1)
+#else  /* MSDOS */
+       if ((to == -1) && (cp[strlen(cp)-1] == '\n'))
+#endif /* MSDOS */
+               cp[strlen(cp) - 1] = '\0';              /* Get rid of \n */
+       else
+               cp[to - from] = '\0';
+       if (buf) {
+               strcpy(buf, cp);
+               return buf;
+       } else {
+               return cp;
+       }
+}
+
+int
+casecmp(s1, s2)
+register char  *s1,
+               *s2;
+{
+       if (s1==NULL || s2==NULL)
+               return 1;       /* which is not zero ... */
+       while (CharUpcase(*s1) == CharUpcase(*s2++))
+               if (*s1++ == '\0')
+                       return 0;
+       return (*s1 - *--s2);
+}
+
+int
+casencmp(s1, s2, n)
+register char  *s1,
+               *s2;
+register size_t        n;
+{
+       if (s1==NULL || s2==NULL)
+               return 1;       /* which is not zero ... */
+       for (;;) {
+               if (n == 0)
+                       return 0;
+               n--;
+               if (CharUpcase(*s1) != CharUpcase(*s2++))
+                       return *s1 - *--s2;
+               if (*s1++ == '\0')
+                       return 0;
+       }
+}
+
+void
+null_ncpy(to, from, n)
+char   *to,
+       *from;
+size_t n;
+{
+       (void) strncpy(to, from, n);
+       to[n] = '\0';
+}
+
+/* Tries to pause for delay/10 seconds OR until a character is typed
+   at the keyboard.  This works well on BSD4_2 and not so well on the
+   rest. */
+
+#ifdef BSD4_2
+# ifndef       BSD2_10
+#   include <sys/time.h>
+# endif
+#endif
+
+#ifdef MSDOS
+# include <bios.h>
+# include <dos.h>
+#endif
+
+void
+SitFor(delay)
+int    delay;
+{
+#ifdef MAC
+       long    start,
+               end;
+
+#define Ticks ((long *) 0x16A) /* 1/60 sec */
+       Keyonly = YES;
+       redisplay();
+       start = *Ticks;
+
+       end = start + delay * 6;
+       do {
+               if ((InputPending = charp()) != NO)
+                       break;
+       } while (*Ticks < end);
+#undef Ticks
+
+#else  /* !MAC */
+
+#ifndef        MSDOS
+       if (!charp()) {
+#if    defined(BSD4_2) && !defined(BSD2_10)
+               struct timeval  timer;
+               fd_set  readfds;
+
+               FD_ZERO(&readfds);
+               FD_SET(0, &readfds);
+               
+               /* So messages that aren't error messages don't
+                * hang around forever.
+                * Gross that I had to snarf this from getch()
+                */
+               if (!UpdMesg && !Asking && mesgbuf[0] && !errormsg)
+                       message(NullStr);
+               redisplay();
+
+               timer.tv_sec = (delay / 10);
+               timer.tv_usec = (delay % 10) * 100000;
+               select(1, &readfds, (fd_set *)0, (fd_set *)0, &timer);
+#else  /* !(defined(BSD4_2) && !defined(BSD2_10)) */
+               /* Pause by spitting NULs at the terminal.  Ugh! */
+               static const int cps[] = {
+                       0,
+                       5,
+                       7,
+                       11,
+                       13,
+                       15,
+                       20,
+                       30,
+                       60,
+                       120,
+                       180,
+                       240,
+                       480,
+                       960,
+                       1920,
+                       1920,
+               };
+               register int    nchars,
+                               check_cnt;
+
+               nchars = (delay * cps[ospeed]) / 10;
+               check_cnt = BufSize;
+               redisplay();
+               if (!NP) {
+                       while ((--nchars > 0) && !InputPending) {
+                               jputchar(PC);
+                               if (--check_cnt == 0) {
+                                       check_cnt = BufSize;
+                                       InputPending = charp();
+                               }
+                       }
+               }
+#endif /* !(defined(BSD4_2) && !defined(BSD2_10)) */
+       }
+#else  /* MSDOS */
+
+       long    start,
+               end;
+#ifndef        IBMPC
+       struct dostime_t tc;
+#endif
+
+       redisplay();
+#ifdef IBMPC
+       _bios_timeofday(_TIME_GETCLOCK, &start);
+#else
+       _dos_gettime(&tc);
+       start = (long)(tc.hour*60L*60L*10L)+(long)(tc.minute*60L*10L)+
+           (long)(tc.second*10)+(long)(tc.hsecond/10);
+#endif
+       end = (start + delay);
+       do  {
+               if ((InputPending = charp()) != NO)
+                       break;
+#ifdef IBMPC
+               if (_bios_timeofday(_TIME_GETCLOCK, &start))
+                       break;  /* after midnight */
+#else
+               start = (long)(tc.hour*60L*60L*10L)+(long)(tc.minute*60L*10L)+
+                       (long)(tc.second*10)+(long)(tc.hsecond/10);
+#endif
+       } while (start < end);
+#endif /* MSDOS */
+#endif /* !MAC */
+}
+
+bool
+sindex(pattern, string)
+register char  *pattern,
+               *string;
+{
+       register size_t len = strlen(pattern);
+
+       while (*string != '\0') {
+               if (*pattern == *string && strncmp(pattern, string, len) == 0)
+                       return TRUE;
+               string += 1;
+       }
+       return FALSE;
+}
+
+void
+make_argv(argv, ap)
+register char  *argv[];
+va_list        ap;
+{
+       register int    i = 0;
+
+       argv[i++] = va_arg(ap, char *);
+       argv[i++] = basename(argv[0]);
+       do ; while ((argv[i++] = va_arg(ap, char *)) != NULL);
+}
+
+int
+pnt_line()
+{
+       register Line   *lp = curbuf->b_first;
+       register int    i;
+
+       for (i = 0; lp != NULL; i++, lp = lp->l_next)
+               if (lp == curline)
+                       break;
+       return i + 1;
+}
+
+/* Free, then allocate a block.
+ * Like erealloc, except that the previous contents of the block are lost.
+ */
+
+UnivPtr
+freealloc(obj, size)
+register UnivPtr       obj;
+size_t size;
+{
+       register UnivPtr        new = NULL;
+
+       if (obj)
+               new = realloc(obj, size);
+       if (new == NULL)
+               new = emalloc(size);
+       return new;
+}
+
+#ifndef HAVE_STRERROR
+/*
+ * Unix version of strerror - map error number to descriptive string.
+ * ANSI systems should have this.
+ */
+char *
+strerror(errnum)
+int errnum;
+{
+       extern int sys_nerr;
+       extern char *sys_errlist[];
+
+       if (errnum > 0 && errnum < sys_nerr)
+               return(sys_errlist[errnum]);
+       return sprint("Error number %d", errnum);
+}
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/util.h b/usr/src/contrib/jove-4.14.6/util.h
new file mode 100644 (file)
index 0000000..f39a5ce
--- /dev/null
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* some utility functions, as macros, to be included by jove.h */
+
+extern char    key_strokes[100],
+               *keys_p;
+
+extern int     ModCount;
+
+#define init_strokes() { keys_p = key_strokes; *keys_p = '\0'; }
+#define add_stroke(c)  { \
+       if (keys_p < &key_strokes[sizeof (key_strokes) - 1]) { \
+               *keys_p++ = (c); \
+               *keys_p = '\0'; \
+       } \
+}
+
+#define IsModified(b)  ((b)->b_modified)
+#define SavLine(a, b)  ((a)->l_dline = putline((b)))
+#define SetLine(line)  DotTo((line), 0)
+#define bobp()         (firstp(curline) && bolp())
+#define bolp()         (curchar == 0)
+#define eobp()         (lastp(curline) && eolp())
+#define eolp()         (linebuf[curchar] == '\0')
+#define firstp(line)   ((line) == curbuf->b_first)
+#define getDOT()       getline(curline->l_dline, linebuf)
+#define lastp(line)    ((line) == curbuf->b_last)
+
+extern UnivPtr
+       emalloc proto((size_t size)),
+       erealloc proto((UnivPtr ptr, size_t size));
+
+extern char
+       *IOerr proto((char *err, char *file)),
+       *StrIndex proto((int dir,char *buf,int charpos, int what)),
+       *basename proto((char *f)),
+       *copystr proto((char *str)),
+       *filename proto((struct buffer *b)),
+       *get_time proto((time_t *timep,char *buf,int from,int to)),
+       *itoa proto((int num)),
+       *lcontents proto((struct line *line)),
+       *ltobuf proto((struct line *line,char *buf));
+
+extern int
+       LineDist proto((struct line *nextp,struct line *endp)),
+       TwoBlank proto((void)),
+       casecmp proto((char *s1,char *s2)),
+       casencmp proto((char *s1,char *s2, size_t n)),
+       inorder proto((struct line *nextp,int char1,struct line *endp,int char2)),
+       length proto((struct line *line)),
+       max proto((int a,int b)),
+       min proto((int a,int b)),
+       numcomp proto((char *s1,char *s2)),
+       pnt_line proto((void)),
+       waitchar proto((int *slow));
+
+extern bool
+       blnkp proto((char *buf)),
+       within_indent proto((void)),
+       fixorder proto((struct line * *line1,int *char1,struct line * *line2,int *char2)),
+       inlist proto((struct line *first,struct line *what)),
+       sindex proto((char *pattern,char *string)),
+       ModBufs proto((bool allp));
+
+extern void
+       DOTsave proto((struct position *buf)),
+       DotTo proto((struct line *line,int col)),
+       ExecCmd proto((struct data_obj *cp)),
+       PushPntp proto((struct line *line)),
+       SetDot proto((struct position *bp)),
+       ToFirst proto((void)),
+       ToLast proto((void)),
+       ins_c proto((int c,char *buf,int atchar,int num,int max)),
+       len_error proto((int flag)),
+       linecopy proto((char *onto,int atchar,char *from)),
+       make_argv proto((char * *argv,char *ap)),
+       modify proto((void)),
+       SitFor proto((int delay)),
+       null_ncpy proto((char *to, char *from, size_t n)),
+#ifdef UNIX
+       dopipe proto((int *p)),
+       pipeclose proto((int *p)),
+#endif
+       pop_env proto((jmp_buf)),
+       push_env proto((jmp_buf)),
+       to_word proto((int dir)),
+       unmodify proto((void)),
+       pp_key_strokes proto((char *buffer, size_t size));
diff --git a/usr/src/contrib/jove-4.14.6/vars.c b/usr/src/contrib/jove-4.14.6/vars.c
new file mode 100644 (file)
index 0000000..b488270
--- /dev/null
@@ -0,0 +1,137 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#ifndef        TXT_TO_C        /* so that jove.h isn't included twice in setmaps */
+#include "jove.h"
+#endif
+
+#ifndef IBMPC
+const
+#endif
+struct variable        variables[] = {
+       VARIABLE, "abort-char", (UnivPtr) &AbortChar, V_CHAR,
+#ifdef UNIX
+       VARIABLE, "allow-^S-and-^Q", (UnivPtr) &OKXonXoff, V_BOOL|V_TTY_RESET,
+#endif /* UNIX */
+       VARIABLE, "allow-bad-filenames", (UnivPtr) &OkayBadChars, V_BOOL,
+#ifdef ABBREV
+       VARIABLE, "auto-case-abbrev", (UnivPtr) &AutoCaseAbbrev, V_BOOL,
+#endif
+#ifdef IBMPC
+       VARIABLE, "background-color", (UnivPtr) &Bgcolor, V_BASE10|V_CLRSCREEN,
+#endif /* IBMPC */
+#ifdef F_COMPLETION
+       VARIABLE, "bad-filename-extensions", (UnivPtr)BadExtensions, V_STRING,
+#endif
+       VARIABLE, "c-argument-indentation", (UnivPtr) &CArgIndent, V_BASE10,
+       VARIABLE, "c-indentation-increment", (UnivPtr) &CIndIncrmt, V_BASE10,
+       VARIABLE, "case-ignore-search", (UnivPtr) &CaseIgnore, V_BOOL,
+#ifdef CMT_FMT
+       VARIABLE, "comment-format", (UnivPtr)CmtFmt, V_STRING,
+#endif
+#ifdef IPROCS
+       VARIABLE, "dbx-format-string", (UnivPtr)dbx_parse_fmt, V_STRING,
+#endif
+#ifdef BIFF
+       VARIABLE, "disable-biff", (UnivPtr) &BiffChk, V_BOOL,
+#endif
+#ifdef F_COMPLETION
+       VARIABLE, "display-bad-filenames", (UnivPtr) &DispBadFs, V_BOOL,
+#endif
+#ifndef        MAC
+       VARIABLE, "error-format-string", (UnivPtr)ErrFmtStr, V_STRING,
+       VARIABLE, "error-window-size", (UnivPtr) &EWSize, V_BASE10,
+#endif
+       VARIABLE, "expand-environment-variables", (UnivPtr) &DoEVexpand, V_BOOL,
+       VARIABLE, "file-creation-mode", (UnivPtr) &CreatMode, V_BASE8,
+       VARIABLE, "files-should-end-with-newline", (UnivPtr) &EndWNewline, V_BOOL,
+#ifdef IBMPC
+       VARIABLE, "foreground-color", (UnivPtr) &Fgcolor, V_BASE10|V_CLRSCREEN,
+#endif /* IBMPC */
+       VARIABLE, "internal-tabstop", (UnivPtr) &tabstop, V_BASE10|V_CLRSCREEN,
+       VARIABLE, "interrupt-character", (UnivPtr) &IntChar, V_CHAR|V_TTY_RESET,
+       VARIABLE, "left-margin", (UnivPtr) &LMargin, V_BASE10,
+#ifdef MAC
+       VARIABLE, "macify", (UnivPtr) &Macmode, V_BOOL,
+#endif
+#ifdef UNIX
+       VARIABLE, "mail-check-frequency", (UnivPtr) &MailInt, V_BASE10,
+       VARIABLE, "mailbox", (UnivPtr)Mailbox, V_FILENAME,
+#endif /* UNIX */
+#ifdef BACKUPFILES
+       VARIABLE, "make-backup-files", (UnivPtr) &BkupOnWrite, V_BOOL,
+#endif
+       VARIABLE, "mark-threshold", (UnivPtr) &MarkThresh, V_BASE10,
+       VARIABLE, "marks-should-float", (UnivPtr) &MarksShouldFloat, V_BOOL,
+       VARIABLE, "match-regular-expressions", (UnivPtr) &UseRE, V_BOOL,
+       VARIABLE, "meta-key", (UnivPtr) &MetaKey, V_BOOL|V_TTY_RESET,
+       VARIABLE, "mode-line", (UnivPtr)ModeFmt, V_STRING|V_MODELINE,
+#ifdef IBMPC
+       VARIABLE, "mode-line-color", (UnivPtr) &Mdcolor, V_BASE10|V_MODELINE,
+#endif
+       VARIABLE, "mode-line-should-standout", (UnivPtr) &BriteMode, V_BOOL|V_MODELINE,
+       VARIABLE, "paren-flash-delay", (UnivPtr) &PDelay, V_BASE10,
+#ifndef        MAC
+       VARIABLE, "physical-tabstop", (UnivPtr) &phystab, V_BASE10|V_CLRSCREEN,
+#endif
+#ifdef IPROCS
+       VARIABLE, "process-prompt", (UnivPtr)proc_prompt, V_STRING,
+#endif
+       VARIABLE, "right-margin", (UnivPtr) &RMargin, V_BASE10,
+       VARIABLE, "scroll-all-lines", (UnivPtr) &ScrollAll, V_BOOL,
+       VARIABLE, "scroll-step", (UnivPtr) &ScrollStep, V_BASE10,
+       VARIABLE, "search-exit-char", (UnivPtr) &SExitChar, V_CHAR,
+       VARIABLE, "send-typeout-to-buffer", (UnivPtr) &UseBuffers, V_BOOL,
+#ifndef        MAC
+       VARIABLE, "shell", (UnivPtr)Shell, V_FILENAME,
+       VARIABLE, "shell-flags", (UnivPtr)ShFlags, V_STRING,
+#endif
+#ifndef        MSDOS
+       VARIABLE, "sync-frequency", (UnivPtr) &SyncFreq, V_BASE10,
+#endif /* MSDOS */
+       VARIABLE, "tag-file", (UnivPtr)TagFile, V_FILENAME,
+#ifndef        MAC
+       VARIABLE, "tmp-file-pathname", (UnivPtr)TmpFilePath, V_FILENAME,
+#endif
+#ifdef UNIX
+       VARIABLE, "update-time-frequency", (UnivPtr) &UpdFreq, V_BASE10,
+#endif /* UNIX */
+#ifdef ID_CHAR
+       VARIABLE, "use-i/d-char", (UnivPtr) &UseIC, V_BOOL,
+#endif
+       VARIABLE, "visible-bell", (UnivPtr) &VisBell, V_BOOL,
+       VARIABLE, "wrap-search", (UnivPtr) &WrapScan, V_BOOL,
+#ifndef        MAC
+       VARIABLE, "write-files-on-make", (UnivPtr) &WtOnMk, V_BOOL,
+#endif
+       VARIABLE, NULL, NULL, 0
+};
+
+#ifndef        TXT_TO_C
+data_obj *
+findvar(prompt)
+const char     *prompt;
+{
+       static char     *strings[(sizeof variables) / sizeof (struct variable)];
+       static bool     beenhere = FALSE;
+       register int    com;
+
+       if (!beenhere) {
+               register char   **strs = strings;
+               register const struct variable  *v = variables;
+
+               beenhere = TRUE;
+               for (; v->Name; v++)
+                       *strs++ = v->Name;
+               *strs = NULL;
+       }
+
+       if ((com = complete(strings, prompt, NOTHING)) < 0)
+               return NULL;
+       return (data_obj *) &variables[com];
+}
+#endif
diff --git a/usr/src/contrib/jove-4.14.6/vars.h b/usr/src/contrib/jove-4.14.6/vars.h
new file mode 100644 (file)
index 0000000..ab298d8
--- /dev/null
@@ -0,0 +1,151 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+struct variable {
+       int     Type;           /* in this case a variable */
+       char    *Name;          /* name is always second */
+       UnivPtr v_value;
+       int     v_flags;
+};
+
+/* variable types/flags */
+#define V_BASE10       01      /* is integer in base 10 */
+#define V_BASE8                02      /* is integer in base 8 */
+#define V_BOOL         04      /* is a boolean */
+#define V_STRING       010     /* is a string */
+#define V_CHAR         020     /* is a character */
+#define V_FILENAME     040     /* a file name (implies V_STRING) */
+#define V_TYPEMASK     077     /* mask off the extra bits */
+#define V_MODELINE     0100    /* update modeline */
+#define V_CLRSCREEN    0200    /* clear and redraw screen */
+#define V_TTY_RESET    0400    /* redo the tty modes */
+
+extern const struct variable   variables[];
+
+#ifdef MAC
+# ifdef        TXT_TO_C
+int            /* kludge, so setmaps will compile with variables */
+# else
+extern int
+# endif        /* TXT_TO_C */
+#else
+extern int
+#endif /* MAC */
+
+#ifndef        MAC
+       phystab,                /* terminal's tabstop settings */
+#endif
+       tabstop,                /* expand tabs to this number of spaces */
+       RMargin,                /* right margin */
+       LMargin,                /* left margin */
+       ScrollStep,             /* how should we scroll */
+       MarkThresh,             /* moves greater than MarkThresh will SetMark */
+       PDelay,                 /* paren flash delay in tenths of a second */
+       CArgIndent,             /* how to indent arguments to C functions */
+       CIndIncrmt,             /* how much each indentation level pushes
+                                  over in C mode */
+       CreatMode,              /* default mode for creat'ing files */
+       SyncFreq,               /* how often to sync the file pointers */
+       UpdFreq,                /* how often to update modeline */
+       MailInt,                /* mail check interval */
+       SExitChar,              /* type this to stop i-search */
+       AbortChar,              /* cancels command input */
+       IntChar,                /* ttysets this to generate QUIT */
+#ifdef IBMPC
+       Fgcolor,
+       Bgcolor,
+       Mdcolor,
+#endif /* IBMPC */
+#ifndef        MAC
+       EWSize;                 /* size to make the error window */
+#else
+       Macmode;        /* see mac.c */
+#endif /* MAC */
+
+#ifdef MAC
+# ifdef        TXT_TO_C        /* kludge, for setmaps with variables */
+bool
+# else
+extern bool
+# endif        /* TXT_TO_C */
+#else
+extern bool
+#endif /* MAC */
+       OKXonXoff,              /* disable start/stop characters */
+       OkayBadChars,           /* allow bad characters in files created
+                                  by JOVE */
+#ifdef ABBREV
+       AutoCaseAbbrev,         /* automatically do case on abbreviations */
+#endif
+       CaseIgnore,             /* case ignore search */
+#ifdef BIFF
+       BiffChk,                /* turn off/on biff with entering/exiting jove */
+#endif
+#ifdef F_COMPLETION
+       DispBadFs,              /* display filenames with bad extensions? */
+#endif
+       DoEVexpand,             /* treat $foo as environment variable */
+       EndWNewline,            /* end files with a blank line */
+#ifdef MAC
+       Keyonly,
+       Bufchange,
+       Modechange,
+       EventCmd,
+       Windchange,
+       Macmode,
+#endif /* MAC */
+#ifdef BACKUPFILES
+       BkupOnWrite,            /* make backup files when writing */
+#endif
+       MarksShouldFloat,       /* adjust marks on insertion/deletion */
+       UseRE,                  /* use regular expressions in search */
+       MetaKey,                /* this terminal has a meta key */
+       BriteMode,              /* make the mode line inverse? */
+       ScrollAll,              /* we current line scrolls, scroll whole window? */
+       UseBuffers,             /* use buffers with Typeout() */
+#ifdef ID_CHAR
+       UseIC,                  /* whether or not to use i/d char
+                                  processesing */
+#endif
+       VisBell,                /* use visible bell (if possible) */
+#ifndef        MAC
+       WtOnMk,                 /* write files on compile-it command */
+#endif
+       WrapScan;               /* make searches wrap */
+
+
+
+#ifdef MAC
+# ifdef        TXT_TO_C        /* kludge, for setmaps with variables */
+char
+# else
+extern char
+# endif        /* TXT_TO_C */
+#else
+extern char
+#endif /* MAC */
+
+#ifndef        MAC
+       ErrFmtStr[256],         /* format string for parse errors */
+#endif
+#ifdef IPROCS
+       proc_prompt[128],       /* process prompt */
+       dbx_parse_fmt[128],     /* dbx-mode parse string */
+#endif
+#ifdef F_COMPLETION
+       BadExtensions[128],     /* extensions (e.g., ".o" to ignore) */
+#endif
+#ifdef CMT_FMT
+       CmtFmt[80],
+#endif
+       ModeFmt[120],           /* mode line format string */
+#ifdef UNIX
+       Mailbox[FILESIZE],              /* mailbox name */
+#endif /* UNIX */
+       TmpFilePath[FILESIZE],  /* directory/device to store tmp files */
+       TagFile[FILESIZE],              /* default tag file */
+       Shell[FILESIZE];                /* shell to use */
diff --git a/usr/src/contrib/jove-4.14.6/version.c b/usr/src/contrib/jove-4.14.6/version.c
new file mode 100644 (file)
index 0000000..5094c47
--- /dev/null
@@ -0,0 +1,10 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#include "jove.h"
+
+char   *version = "4.14.6 for BSD/386";
diff --git a/usr/src/contrib/jove-4.14.6/wait.h b/usr/src/contrib/jove-4.14.6/wait.h
new file mode 100644 (file)
index 0000000..7a56d63
--- /dev/null
@@ -0,0 +1,24 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+#ifdef BSD_WAIT
+# include <sys/wait.h>
+# define w_termsignum(w)       ((w).w_termsig)
+#else
+# define WIFSTOPPED(w)         (((w).w_status & 0377) == 0177)
+# define WIFEXITED(w)          (((w).w_status & 0377) == 0)
+# define WIFSIGNALED(w)                ((((w).w_status >> 8) & 0377) == 0)
+# define w_termsignum(w)       ((w).w_status & 0177)
+# define wait2(w, x)           wait(w)
+
+union wait {
+       int     w_status;
+};
+#endif
+
+extern void
+       kill_off proto((int, union wait));
diff --git a/usr/src/contrib/jove-4.14.6/wind.c b/usr/src/contrib/jove-4.14.6/wind.c
new file mode 100644 (file)
index 0000000..928a1e0
--- /dev/null
@@ -0,0 +1,543 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+/* This creates/deletes/divides/grows/shrinks windows.  */
+
+#include "jove.h"
+#include "termcap.h"
+#include "chars.h"
+#include "disp.h"
+
+private char   onlyone[] = "You only have one window!",
+               toosmall[] = "Resulting window would be too small.";
+
+Window *curwind,
+       *fwind = NULL;
+
+/* First line in a Window */
+
+int
+FLine(w)
+register Window        *w;
+{
+       register Window *wp = fwind;
+       register int    lineno = -1;
+
+       while (wp != w) {
+               lineno += wp->w_height;
+               wp = wp->w_next;
+               if (wp == fwind)
+                       complain("window?");
+       }
+       return lineno + 1;
+}
+
+/* Delete `wp' from the screen.  If it is the only window left
+   on the screen, then complain.  It gives its body
+   to the next window if there is one, otherwise the previous
+   window gets the body.  */
+
+void
+del_wind(wp)
+register Window        *wp;
+{
+       register Window *prev = wp->w_prev;
+
+       if (one_windp())
+               complain(onlyone);
+
+       prev->w_next = wp->w_next;
+       wp->w_next->w_prev = prev;
+
+       if (fwind == wp) {
+               fwind = wp->w_next;
+               fwind->w_height += wp->w_height;
+               /* Here try to do something intelligent for redisplay() */
+               SetTop(fwind, prev_line(fwind->w_top, wp->w_height));
+               if (curwind == wp)
+                       SetWind(fwind);
+       } else {
+               prev->w_height += wp->w_height;
+               if (curwind == wp)
+                       SetWind(prev);
+       }
+#ifdef MAC
+       RemoveScrollBar(wp);
+       Windchange = YES;
+#endif
+       free((UnivPtr) wp);
+}
+
+/* Divide the window WP N times, or at least once.  Complains if WP is too
+   small to be split into that many pieces.  It returns the new window. */
+
+Window *
+div_wind(wp, n)
+register Window        *wp;
+int    n;
+{
+       register Window *new;
+       int     amt;
+
+       if (n < 1)
+               n = 1;
+       amt = wp->w_height / (n + 1);
+       if (amt < 2)
+               complain(toosmall);
+
+       do {
+               new = (Window *) emalloc(sizeof (Window));
+               new->w_flags = 0;
+               new->w_LRscroll = 0;
+
+               new->w_height = amt;
+               wp->w_height -= amt;
+
+               /* set the lines such that w_line is the center in
+                  each Window */
+               new->w_line = wp->w_line;
+               new->w_char = wp->w_char;
+               new->w_bufp = wp->w_bufp;
+               new->w_top = prev_line(new->w_line, HALF(new));
+
+               /* Link the new window into the list */
+               new->w_prev = wp;
+               new->w_next = wp->w_next;
+               new->w_next->w_prev = new;
+               wp->w_next = new;
+#ifdef MAC
+               new->w_control = NULL;
+#endif
+       } while (--n > 0);
+#ifdef MAC
+       Windchange = YES;
+#endif
+       return new;
+}
+
+/* Initialze the first window setting the bounds to the size of the
+   screen.  There is no buffer with this window.  See parse for the
+   setting of this window. */
+
+void
+winit()
+{
+       register Window *w;
+
+       w = curwind = fwind = (Window *) emalloc(sizeof (Window));
+       w->w_line = w->w_top = NULL;
+       w->w_LRscroll = 0;
+       w->w_flags = 0;
+       w->w_char = 0;
+       w->w_next = w->w_prev = fwind;
+       w->w_height = ILI;
+#ifdef MAC
+       w->w_control = NULL;
+       Windchange = YES;
+#endif
+}
+
+/* Change to previous window. */
+
+void
+PrevWindow()
+{
+       register Window *new = curwind->w_prev;
+
+       if (Asking)
+               complain((char *)NULL);
+       if (one_windp())
+               complain(onlyone);
+       SetWind(new);
+}
+
+/* Make NEW the current Window */
+
+void
+SetWind(new)
+register Window        *new;
+{
+       if (!Asking && curbuf!=NULL) {          /* can you say kludge? */
+               curwind->w_line = curline;
+               curwind->w_char = curchar;
+               curwind->w_bufp = curbuf;
+       }
+       if (new == curwind)
+               return;
+       SetBuf(new->w_bufp);
+       if (!inlist(new->w_bufp->b_first, new->w_line)) {
+               new->w_line = curline;
+               new->w_char = curchar;
+       }
+       DotTo(new->w_line, new->w_char);
+       if (curchar > (int)strlen(linebuf))
+               new->w_char = curchar = strlen(linebuf);
+       curwind = new;
+}
+
+/* delete the current window if it isn't the only one left */
+
+void
+DelCurWindow()
+{
+       SetABuf(curwind->w_bufp);
+       del_wind(curwind);
+}
+
+/* put the current line of `w' in the middle of the window */
+
+void
+CentWind(w)
+register Window        *w;
+{
+       SetTop(w, prev_line(w->w_line, HALF(w)));
+}
+
+int    ScrollStep = 0;         /* full scrolling */
+
+/* Calculate the new topline of the window.  If ScrollStep == 0
+   it means we should center the current line in the window. */
+
+void
+CalcWind(w)
+register Window        *w;
+{
+       register int    up;
+       int     scr_step;
+       Line    *newtop;
+
+       if (ScrollStep == 0) {  /* Means just center it */
+               CentWind(w);
+       } else {
+               up = inorder(w->w_line, 0, w->w_top, 0);
+               if (up == -1) {
+                       CentWind(w);
+                       return;
+               }
+               scr_step = (ScrollStep < 0) ? SIZE(w) + ScrollStep :
+                          ScrollStep - 1;
+               /* up: point is above the screen */
+               newtop = prev_line(w->w_line, up?
+                       scr_step : (SIZE(w) - 1 - scr_step));
+               if (LineDist(newtop, w->w_top) >= SIZE(w) - 1)
+                       CentWind(w);
+               else
+                       SetTop(w, newtop);
+       }
+}
+
+/* This is bound to C-X 4 [BTF].  To make the screen stay the
+   same we have to remember various things, like the current
+   top line in the current window.  It's sorta gross, but it's
+   necessary because of the way this is implemented (i.e., in
+   terms of do_find(), do_select() which manipulate the windows. */
+
+void
+WindFind()
+{
+       register Buffer *obuf = curbuf,
+                       *nbuf;
+       Line    *ltop = curwind->w_top;
+       Bufpos  odot,
+               ndot;
+
+       DOTsave(&odot);
+
+       switch (waitchar((int *)NULL)) {
+       case 't':
+       case 'T':
+               ExecCmd((data_obj *) FindCmd(FindTag));
+               break;
+
+       case CTL('T'):
+               ExecCmd((data_obj *) FindCmd(FDotTag));
+               break;
+
+       case 'b':
+       case 'B':
+               ExecCmd((data_obj *) FindCmd(BufSelect));
+               break;
+
+       case 'f':
+       case 'F':
+               ExecCmd((data_obj *) FindCmd(FindFile));
+               break;
+
+       default:
+               complain("T: find-tag, ^T: find-tag-at-point, F: find-file, B: select-buffer.");
+       }
+
+       nbuf = curbuf;
+       DOTsave(&ndot);
+       SetBuf(obuf);
+       SetDot(&odot);
+       SetTop(curwind, ltop);  /* there! it's as if we did nothing */
+
+       if (one_windp())
+               (void) div_wind(curwind, 1);
+
+       tiewind(curwind->w_next, nbuf);
+       SetWind(curwind->w_next);
+       SetDot(&ndot);
+}
+
+/* Go into one window mode by deleting all the other windows */
+
+void
+OneWindow()
+{
+       while (curwind->w_next != curwind)
+               del_wind(curwind->w_next);
+}
+
+Window *
+windbp(bp)
+register Buffer        *bp;
+{
+
+       register Window *wp = fwind;
+
+       if (bp == NULL)
+               return NULL;
+       do {
+               if (wp->w_bufp == bp)
+                       return wp;
+               wp = wp->w_next;
+       } while (wp != fwind);
+       return NULL;
+}
+
+/* Change window into the next window.  Curwind becomes the new window. */
+
+void
+NextWindow()
+{
+       register Window *new = curwind->w_next;
+
+       if (Asking)
+               complain((char *)NULL);
+       if (one_windp())
+               complain(onlyone);
+       SetWind(new);
+}
+
+/* Scroll the next Window */
+
+void
+PageNWind()
+{
+       if (one_windp())
+               complain(onlyone);
+       NextWindow();
+       NextPage();
+       PrevWindow();
+}
+
+private Window *
+w_nam_typ(name, type)
+register char  *name;
+int    type;
+{
+       register Window *w;
+       register Buffer *b;
+
+       b = buf_exists(name);
+       w = fwind;
+       if (b) do {
+               if (w->w_bufp == b)
+                       return w;
+       } while ((w = w->w_next) != fwind);
+
+       w = fwind;
+       do {
+               if (w->w_bufp->b_type == type)
+                       return w;
+       } while ((w = w->w_next) != fwind);
+
+       return NULL;
+}
+
+/* Put a window with the buffer `name' in it.  Erase the buffer if
+   `clobber' is non-zero. */
+
+void
+pop_wind(name, clobber, btype)
+register char  *name;
+int    clobber;
+int    btype;
+{
+       register Window *wp;
+       register Buffer *newb;
+
+       if ((newb = buf_exists(name)) != NULL)
+               btype = -1;     /* if the buffer exists, don't change
+                                  it's type */
+       if ((wp = w_nam_typ(name, btype)) == NULL) {
+               if (one_windp())
+                       SetWind(div_wind(curwind, 1));
+               else
+                       PrevWindow();
+       } else
+               SetWind(wp);
+
+       newb = do_select((Window *)NULL, name);
+       if (clobber) {
+               initlist(newb);
+               newb->b_modified = NO;
+       }
+       tiewind(curwind, newb);
+       if (btype != -1)
+               newb->b_type = btype;
+       SetBuf(newb);
+}
+
+void
+GrowWindowCmd()
+{
+       WindSize(curwind, abs(arg_value()));
+}
+
+void
+ShrWindow()
+{
+       WindSize(curwind, -abs(arg_value()));
+}
+
+/* Change the size of the window by inc.  First arg is the window,
+   second is the increment. */
+
+void
+WindSize(w, inc)
+register Window        *w;
+register int   inc;
+{
+       if (one_windp())
+               complain(onlyone);
+
+       if (inc == 0)
+               return;
+       else if (inc < 0) {     /* Shrinking this Window. */
+               if (w->w_height + inc < 2)
+                       complain(toosmall);
+               w->w_height += inc;
+               w->w_prev->w_height -= inc;
+       } else {                /* Growing the window. */
+               /* Change made from original code so that growing a window
+                  exactly offsets effect of shrinking a window, i.e.
+                  doing either followed by the other restores original
+                  sizes of all affected windows. */
+               if (w->w_prev->w_height - inc < 2)
+                       complain(toosmall);
+               w->w_height += inc;
+               w->w_prev->w_height -= inc;
+       }
+#ifdef MAC
+       Windchange = YES;
+#endif
+}
+
+/* Set the topline of the window, calculating its number in the buffer.
+   This is for numbering the lines only. */
+
+void
+SetTop(w, line)
+Window *w;
+register Line  *line;
+{
+       register Line   *lp = w->w_bufp->b_first;
+       register int    num = 0;
+
+       w->w_top = line;
+       if (w->w_flags & W_NUMLINES) {
+               while (lp) {
+                       num += 1;
+                       if (line == lp)
+                               break;
+                       lp = lp->l_next;
+               }
+               w->w_topnum = num;
+       }
+}
+
+void
+WNumLines()
+{
+       curwind->w_flags ^= W_NUMLINES;
+       SetTop(curwind, curwind->w_top);
+}
+
+void
+WVisSpace()
+{
+       curwind->w_flags ^= W_VISSPACE;
+       ClAndRedraw();
+}
+
+/* Return the line number that `line' occupies in `windes' */
+
+int
+in_window(windes, line)
+register Window        *windes;
+register Line  *line;
+{
+       register int    i;
+       register Line   *top = windes->w_top;
+
+       for (i = 0; top && i < windes->w_height - 1; i++, top = top->l_next)
+               if (top == line)
+                       return FLine(windes) + i;
+       return -1;
+}
+
+void
+SplitWind()
+{
+       SetWind(div_wind(curwind, is_an_arg() ? (arg_value() - 1) : 1));
+}
+
+/* Goto the window with the named buffer.  If no such window
+   exists, pop one and attach the buffer to it. */
+void
+GotoWind()
+{
+       char    *bname;
+       Window  *w;
+
+       bname = ask_buf(lastbuf);
+       w = curwind->w_next;
+       do {
+               if (w->w_bufp->b_name == bname) {
+                       SetABuf(curbuf);
+                       SetWind(w);
+                       return;
+               }
+               w = w->w_next;
+       } while (w != curwind);
+       SetABuf(curbuf);
+       pop_wind(bname, NO, -1);
+}
+
+void
+ScrollRight()
+{
+       int     amt = (is_an_arg() ? arg_value() : 10);
+
+       if (curwind->w_LRscroll - amt < 0)
+               curwind->w_LRscroll = 0;
+       else
+               curwind->w_LRscroll -= amt;
+       UpdModLine = YES;
+}
+
+void
+ScrollLeft()
+{
+       int     amt = (is_an_arg() ? arg_value() : 10);
+
+       curwind->w_LRscroll += amt;
+       UpdModLine = YES;
+}
diff --git a/usr/src/contrib/jove-4.14.6/wind.h b/usr/src/contrib/jove-4.14.6/wind.h
new file mode 100644 (file)
index 0000000..c1077d6
--- /dev/null
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
+ * is provided to you without charge, and with no warranty.  You may give  *
+ * away copies of JOVE, including sources, provided that this notice is    *
+ * included in all the files.                                              *
+ ***************************************************************************/
+
+struct window {
+       Window  *w_prev,        /* circular list */
+               *w_next;
+       Buffer  *w_bufp;        /* buffer associated with this window */
+       Line    *w_top,         /* top line */
+               *w_line;        /* current line */
+       int     w_char,
+               w_height,       /* window height */
+               w_topnum,       /* line number of the topline */
+               w_dotcol,       /* UpdWindow sets this ... */
+               w_dotline,      /* ... and this */
+               w_flags,
+#define        W_TOPGONE       01
+#define        W_CURGONE       02      /* topline (curline) of window has been deleted
+                                  since the last time a redisplay was called */
+#define W_VISSPACE     04
+#define W_NUMLINES     010
+               w_LRscroll;     /* amount of LeftRight scrolling in window */
+#ifdef MAC
+       int     w_topline;      /* row number of top line in window */
+       char **w_control;       /* scroll bar for window */
+#endif
+};
+
+extern Window  *fwind,         /* first window in list */
+               *curwind;       /* current window */
+
+#define one_windp()    (fwind->w_next == fwind)
+#define HALF(wp)       (((wp)->w_height - 1) / 2)
+#define SIZE(wp)       ((wp)->w_height - 1)
+
+extern int
+       FLine proto((struct window *w)),
+       in_window proto((struct window *windes,struct line *line));
+
+extern Window
+       *div_wind proto((struct window *wp,int n)),
+       *windbp proto((struct buffer *bp));
+
+extern void
+       CalcWind proto((struct window *w)),
+       CentWind proto((struct window *w)),
+       SetTop proto((struct window *w,struct line *line)),
+       SetWind proto((struct window *new)),
+       WindSize proto((struct window *w,int inc)),
+       del_wind proto((struct window *wp)),
+       pop_wind proto((char *name,int clobber,int btype)),
+       tiewind proto((struct window *w,struct buffer *bp)),
+       winit proto((void));