[comp.sources.misc] v20i040: sc - The SC Spreadsheet, release 6.16, Part06/07

buhrt@cs.indiana.edu (Jeff Buhrt) (06/06/91)

Submitted-by: Jeff Buhrt <prslnk!buhrt@cs.indiana.edu>
Posting-number: Volume 20, Issue 40
Archive-name: sc/part06

#! /bin/sh
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  Makefile TODO gram.y lex.c vi.c
# Wrapped by kent@sparky on Wed Jun  5 09:22:20 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 6 (of 7)."'
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
  echo shar: Extracting \"'Makefile'\" \(10303 characters\)
  sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile $Revision: 6.16 $
X#
X# 1) Select the proper EXDIR (path), MANDIR, MANEXT, LIBDIR, SIGVOID,
X#	RE_COMP/REGCMP, and DFLT_PAGER. Most of the other things aren't
X#	normally changed (see the comments with each)
X# 2) Select the proper machine/compiler/OS section of code
X# 3) make install
X# 4) If you have the command 'file' that uses /etc/magic add the line:
X#	38	string		Spreadsheet	sc file
X
X
X# Specify the name of the program.
X# All documentation and installation keys on this value.
X# 
Xname=sc
XNAME=SC
X
X# This is where the install step puts it.
X#EXDIR=/site/bin
XEXDIR=/usr/local/bin
X
X# This is where the man page goes.
X#MANDIR=/usr/local/src/man/man1	# reno
X#MANEXT=1			# reno
XMANDIR=/usr/man/manl
XMANEXT=l
X
X# This is where the library file (tutorial) goes.
X#LIBDIR=/usr/local/share/$(name) # reno
XLIBDIR=/usr/local/lib/$(name)
X
X# Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up
XSIMPLE=
X#SIMPLE=-DSIMPLE
X
X# Set BROKENCURSES if your curses has the nl/nonl bug
X# if it does and you don't set BROKENCURSES, the display will
X# be staggered across the screen. Also try IDLOKBAD below.
XBROKENCURSES=
X#BROKENCURSES=-DBROKENCURSES
X
X# Set DOBACKUPS if you would like a backup copy of a source file on a save
X#DOBACKUPS=
XDOBACKUPS=-DDOBACKUPS
X
X# Set INTERNATIONAL if you need 8 bit characters.  You should
X# not set this if you are running 5.3.0.  I think it is OK in 5.3.1.
X#INTERNATIONAL=-DINTERNATIONAL
XINTERNATIONAL=
X
X# Set SIGVOID if signal routines are type void.
X# use: SIGVOID=-DSIGVOID for:
X#	System 5.3, SunOS 4.X, VMS, BSD4.4 (reno), and ANSI C Compliant systems
X# use: SIGVOID=		for:
X#  BSD systems (excluding reno, BSD4.4), and the UNIXPC 'cc'
XSIGVOID=-DSIGVOID
X#SIGVOID=
X
X# Set IEEE_MATH if you need setsticky() calls in your signal handlers
X#
X#IEEE_MATH=-DIEEE_MATH
XIEEE_MATH=
X
X# Set RINT=-DRINT if you do not have rint() in math.h
X# Set RINT=	on/with (they have rint):
X#	SunOS 4.0.3c compiler
X#	BSD4.4 (reno)
X#RINT=
XRINT=-DRINT
X
X# Set RE_COMP if you have the re_comp/re_exec regular expression routines
X# (most BSD based systems do).
X#RE_COMP=-DRE_COMP
XRE_COMP=
X
X# Set REGCMP if you have the regcmp/regex regular expression routines
X# (most System V based systems do)
XREGCMP=-DREGCMP
X#REGCMP=
X
X# This is the name of a pager like "more".
X# "pg" may be appropriate for SYSV.
XDFLT_PAGER=-DDFLT_PAGER=\"less\"
X#DFLT_PAGER=-DDFLT_PAGER=\"more\"	# generic && reno
X
X# this is the name to save back ups in
XSAVE=-DSAVENAME=\"$(NAME).SAVE\"
X
X# path to crypt
XCRYPT=-DCRYPT_PATH=\"/bin/crypt\"
X#CRYPT=CRYPT_PATH=\"/usr/local/bin/crypt\"
X
X# flags for lint
XLINTFLAGS=-abchxv
X
X# *** SPECIAL NOTES ***
X# For ULTRIX: define the BSD4.2 section and SIGVOID above
X#	tdw@cl.cam.ac.uk tested on Ultrix 3.1C-0
X# HP-UX 7.0: Do NOT use -O
X#	(known broken, try sc's boolean operators if you wish)
X#
X# **** SYSV curses bugs... ****
X# Try setting IDLOKBAD to fix (with an empty spreadsheet):
X#	a) Redrawing the bottom half of the screen when you
X#	 	move between row 9 <-> 10
X#	b) the highlighted row labels being trash when you
X#		move between row 9 <-> 10
X#	c) On an xterm on Esix Rev. D+ from eating lines
X#		 -goto (or move) a few lines (or more) past the bottom
X#		 of the screen, goto (or move) to the top line on the
X#		 screen, move upward and the current line is deleted, the
X#		 others move up even when they should not, check by
X#		 noticing the rows become 2, 3, 40, 41, 42... (etc).
X#	Known systems/terminfos w/ curses problems:
X#	{Esix Rev. D+, AT&T SysV3.2.1}:at386-m,xterm, HP-UX7.0:(not sure)
XIDLOKBAD=-DIDLOKBAD
X#IDLOKBAD=
X
X# IF you have problems w/ your yacc and don't have, say, bison...
X# look just below for '### YACC PROBLEMS ###' and reverse the define to
X# use the included, pre-yacc'd copy. First try below.
X#YACC=yacc
XYACC=bison -y
X
X#### SYSTEM DEFINES ####
X
X# Use this for system AIX V3.1
X#CFLAGS= -O -DSYSV2 -DCHTYPE=int -DNLS
X#LDFLAGS=
X#LIB=-lm -lPW -lcurses
X
X# Use this for system V.2
X#CFLAGS= -O -DSYSV2 
X#LDFLAGS=
X#LIB=-lm -lPW -lcurses
X# with gcc on a Sequent also use:
X#CC=att gcc
X#CFLAGS=  -DSYSV2 -g -pipe -traditional
X
X# Use this for system V.3
XCFLAGS=  -DSYSV3 -O
XLDFLAGS= -s
XLIB=-lm -lcurses -lPW
X# with gcc also use:
X#CC=gcc
X#CFLAGS=  -DSYSV3 -O -pipe
XYACC=bison -y
X
X# Use this for system V.4
X#CFLAGS=  -DSYSV4 -DSYSV3 -O
X#LDFLAGS= -s
X#LIB=-lm -lcurses -lgen
X# with gcc also use:
X#CC=gcc
X#CFLAGS=  -DSYSV3 -O -pipe
X
X# Microport
X#CFLAGS= -DSYSV2 -O -DUPORT -Ml
X#LDFLAGS=-Ml
X#LIB=-lm -lcurses -lPW
X
X# Use this for BSD 4.2
X#CFLAGS= -O -DBSD42
X#LDFLAGS=
X#LIB=-lm -lcurses -ltermcap
X
X# Use this for Sequent boxes
X#CC=atscc
X#CFLAGS=-O -DBSD42
X#LDFLAGS= 
X#LIB=-lm -lcurses  -ltermcap
X#PSCLIB=-lseq
X# with gcc also use:
X#CC=gcc
X#CFLAGS= -O -DBSD42 -pipe
X
X# Use this for BSD 4.3
X#CFLAGS= -O -DBSD43
X#LDFLAGS=
X#LIB=-lm -lcurses -ltermcap
X
X# Use this for SunOS 4.X if you have the System V package installed.
X# This will link with the System V curses which is preferable to the
X# BSD curses (especially helps scrolling on slow (9600bps or less)
X# serial lines).
X#
X# Be sure to define SIGVOID and RE_COMP above.
X# 
X#CC=/usr/5bin/cc
X#CFLAGS= -O -DSYSV3 
X#LDFLAGS=
X#LIB=-lm -lcurses 
X
X# Use this for system III (XENIX)
X#CFLAGS= -O -DSYSIII
X#LDFLAGS= -i
X#LIB=-lm -lcurses -ltermcap
X
X# Use this for XENIX Version 2.3
X#CFLAGS= -O -SSYSIII -DXENIX2_3
X#LDFLAGS= -i
X#LIB=-lm -lcurses -ltermcap
X
X# Use this for VENIX
X#CFLAGS= -DVENIX -DBSD42 -DV7
X#LDFLAGS= -z -i 
X#LIB=-lm -lcurses -ltermcap
X
X# For SCO Unix V rel. 3.2.0
X#       -compile using rcc, cc does not cope with gram.c
X#       -edit /usr/include/curses.h, rcc does not understand #error
X#       -link: make CC=cc, rcc's loader gets unresolved __cclass, __range
X#               (rather strange,?)
X#CC=rcc
X#CC=cc
X#CC=gcc -fstrength-reduce
X#SIGVOID=-DSIGVOID
X#CFLAGS= -O -DSYSV3
X#LDFLAGS=
X#LIB=-lm -lcurses -ltinfo -lPW
X#YACC=yacc -Sm10000
X
X# Use this for SCO Unix 3.2.2 and ODT 1.1
X#CC=cc
X#CFLAGS= -O -DSYSV3
X#LDFLAGS=
X#LIB=-lm -lcurses -lPW -lmalloc -lc_s
X#YACC=yacc -Sm10000
X
X# All of the source files
XSRC=Makefile cmds.c crypt.c eres.sed format.c gram.y help.c interp.c \
X	lex.c psc.c range.c sc.c sc.h screen.c sres.sed version.c \
X	vi.c vmtbl.c xmalloc.c
X
X# The objects
XOBJS=cmds.o crypt.o format.o gram.o help.o interp.o lex.o range.o sc.o \
X	screen.o version.o vi.o vmtbl.o xmalloc.o
X
X# The documents in the Archive
XDOCS=README CHANGES sc.doc psc.doc tutorial.sc VMS_NOTES
X
Xall:	$(name) p$(name) $(name)qref
X
X$(name):$(PAR) 	$(OBJS)
X	$(CC) ${LDFLAGS} ${OBJS} ${LIB} -o $(name)
X
X### YACC PROBLEMS ###
X# IF you have problems w/ your yacc and don't have, say, bison...
X# for systems that don't allow you to increase the number of terminals
X# (mostly AT&T) (this will include a Berkeley yacc built gram.c and
X# y.tab.h) use:
X#gram.c:	mygram.c
X#	cp mygram.c gram.c
X#y.tab.h:	
X#	cp myy.tab.h y.tab.h 
X#
X# Otherwise (most systems)
Xgram.c:	gram.y
X	$(YACC) -d gram.y; mv y.tab.c gram.c
Xy.tab.h:	gram.y
X
X
Xp$(name):	psc.c pvmtbl.o pxmalloc.o
X	$(CC) ${LDFLAGS} -o p$(name) psc.c pvmtbl.o pxmalloc.o ${PSCLIB}
X
Xqhelp.c: help.c
X	-rm -f qhelp.c
X	ln help.c qhelp.c
X
X$(name)qref:	qhelp.c
X	$(CC) $(LDFLAGS) -DQREF -DSCNAME=\"$(name)\" -o $(name)qref qhelp.c
X
Xpvmtbl.c: vmtbl.c
X	-rm -f pvmtbl.c
X	ln vmtbl.c pvmtbl.c
X
Xpvmtbl.o: sc.h pvmtbl.c
X	$(CC) ${CFLAGS} -c -DPSC pvmtbl.c
X
Xpxmalloc.c: xmalloc.c
X	-rm -f pxmalloc.c
X	ln xmalloc.c pxmalloc.c
X
Xpxmalloc.o: sc.h pxmalloc.c
X	$(CC) ${CFLAGS} -c -DPSC pxmalloc.c
X
Xlex.o:	sc.h y.tab.h gram.o lex.c
X	$(CC) ${CFLAGS} ${SIMPLE} ${IEEE_MATH} ${SIGVOID} -c lex.c
X
Xsc.o:	sc.h sc.c
X	$(CC) ${CFLAGS} ${DFLT_PAGER} ${SIGVOID} ${SAVE} -c sc.c
X
Xscreen.o:	sc.h screen.c
X	$(CC) ${CFLAGS} ${BROKENCURSES} ${INTERNATIONAL} ${SIGVOID} -c screen.c
X
Xinterp.o:	interp.c sc.h
X	$(CC) ${CFLAGS} ${IEEE_MATH} ${SIGVOID} ${RINT} ${RE_COMP} ${REGCMP} -c interp.c
X
Xgram.o:	sc.h y.tab.h
X
Xcmds.o: cmds.c sc.h
X	$(CC) ${CFLAGS} ${DOBACKUPS} -c cmds.c
X
Xcrypt.o: crypt.c sc.h
X	$(CC) ${CFLAGS} ${CRYPT} ${DOBACKUPS} -c crypt.c
X
Xrange.o: range.c sc.h
X
Xhelp.o: help.c sc.h
X
Xformat.o: format.c
X
Xvi.o: vi.c sc.h
X
Xgram.o:	sc.h y.tab.h gram.c
X	$(CC) ${CFLAGS} -c gram.c
X	sed<gram.y >experres.h -f eres.sed;sed < gram.y > statres.h -f sres.sed
X
Xclean:
X	rm -f *.o *res.h y.tab.h $(name) p$(name) debug core gram.c $(name).1 \
X	$(name).man p$(name).man p$(name).1 y.output $(name)qref
X
Xshar: ${SRC} ${DOCS}
X	shar -c -m 64000 -f shar ${DOCS} ${SRC}
X
Xsshar: ${SRC}
X	shar -c -m 1000000 -f shar ${SRC}
X
Xlint: sc.h sc.c lex.c gram.c interp.c cmds.c crypt.c range.c help.c \
X 	vi.c version.c xmalloc.c format.c vmtbl.c
X	lint ${LINTFLAGS} ${CFLAGS} ${SIMPLE} sc.c lex.c gram.c interp.c \
X 	cmds.c crypt.c range.c help.c vi.c version.c xmalloc.c format.c \
X 	vmtbl.c -lcurses -lm 
X	make lintqref
X
Xlintqref: help.c
X	lint ${LINTFLAGS} ${CFLAGS} ${SIMPLE} -DQREF help.c
X
Xlintpsc: psc.c vmtbl.c
X	lint ${LINTFLAGS} ${CFLAGS} ${SIMPLE} -DPSC psc.c vmtbl.c
X
Xinspect: sc.h sc.c lex.c gram.c interp.c cmds.c crypt.c
X	/bruces/ianj/bin/i386/inspect -abv -t 8 sc.c lex.c gram.c interp.c \
X	cmds.c crypt.c range.c xmalloc.c help.c vi.c
X
Xprint: sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c 
X	prc sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c | lpr
X
X$(name).1:	sc.doc
X	sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g \
X	   -e s%#LIBDIR#%$(LIBDIR)%g sc.doc >  $(name).1
X
X$(name).man:	$(name).1
X	nroff -man $(name).1 > $(name).man
X
Xlaser:	$(name).1
X	itpf -x -Pim2 -man $(name).1
X
Xp$(name).1:	psc.doc
X	sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g psc.doc >  p$(name).1
X
Xp$(name).man:	p$(name).1
X	nroff -man p$(name).1 > p$(name).man
X
Xinstall: $(EXDIR)/$(name) $(EXDIR)/$(name)qref $(EXDIR)/p$(name) \
X	 $(LIBDIR)/tutorial $(MANDIR)/$(name).$(MANEXT)
X
X$(EXDIR)/$(name): $(name)
X	cp $(name) $(EXDIR)
X	strip $(EXDIR)/$(name)
X
X$(EXDIR)/$(name)qref: $(name)qref
X	cp $(name)qref $(EXDIR)
X	strip $(EXDIR)/$(name)qref
X
X$(EXDIR)/p$(name): p$(name)
X	cp p$(name) $(EXDIR)
X	strip $(EXDIR)/p$(name)
X
X$(LIBDIR)/tutorial: tutorial.sc $(LIBDIR)
X	cp tutorial.sc $(LIBDIR)/tutorial.$(name)
X
X$(LIBDIR):
X	mkdir $(LIBDIR)
X
X$(MANDIR)/$(name).$(MANEXT): $(name).1
X	cp $(name).1 $(MANDIR)/$(name).$(MANEXT)
X
Xdiffs: ${SRC}
X	for i in ${SRC} ${DOCS} ;\
X		do \
X		rcsdiff -c -r6.11 $$i ;\
X		done
X
X# THA 10/14/90  Added code to make a patchfile
Xpatchfile: ${SRC} ${DOCS}
X	rm -f patchfile
X	for i in ${SRC} ${DOCS} ;\
X		do \
X		diffc $$i /users/toma/sc/sc6.12/$$i >> patchfile ;\
X		done
END_OF_FILE
  if test 10303 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
  fi
  # end of 'Makefile'
fi
if test -f 'TODO' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'TODO'\"
else
  echo shar: Extracting \"'TODO'\" \(1297 characters\)
  sed "s/^X//" >'TODO' <<'END_OF_FILE'
X
Xtodo:
X1) autobackup of things typed in.
X	idea: each cell change output to a stdio open file
X		in the save format, fflush() every so often...
X		(diffs w/r to the original file)
X2) lock/freeze (glue down) a section of the screen (the rest of the screen
X	scrolls but a row/column/block stays fixed on the screen)
X3) (seems ok, but check) FIX the insert/delete row functions.
X	a) column of equations (EX: E50 = E49+D50)
X	b) insert a few rows, look at the equations below the insert point
X	c) delete the inserted rows
X	d) The equations should now be the same as in (a), but they are not...
X4) make sure ISVALID should <not> be used in place of checkbounds
X	in interp.c
X5) hide range
X6) block moving into range
X7) chain cells w/ equations into a linked list or dependency tree
X	-have a top level eval, eval and UPDATE all lower nodes
X8) an option to go into a ^R like <mode>
X	++data entry fields (highlight entry cells)....
X	++only allow entry in these cells....
X10) don't redraw the whole screen all the time 
X	(only cells that change, (in addition to what is in 'fixed #9'))
X11) add uemacs keybinding stuff
X12) add uemacs macro language
X13) add uemacs command completion
X14) insertrow should be openrow w/ a count arg (limits looping)
X15) on a Get if the buffer hasn't been written, ask to overwrite
END_OF_FILE
  if test 1297 -ne `wc -c <'TODO'`; then
    echo shar: \"'TODO'\" unpacked with wrong size!
  fi
  # end of 'TODO'
fi
if test -f 'gram.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'gram.y'\"
else
  echo shar: Extracting \"'gram.y'\" \(13277 characters\)
  sed "s/^X//" >'gram.y' <<'END_OF_FILE'
X/*	SC	A Spreadsheet Calculator
X *		Command and expression parser
X *
X *		original by James Gosling, September 1982
X *		modified by Mark Weiser and Bruce Israel,
X *			University of Maryland
X *
X * 		more mods Robert Bond 12/86
X *
X *		More mods by Alan Silverstein, 3/88, see list of changes.
X *
X *		$Revision: 6.16 $
X */
X
X
X
X%{
X#include <curses.h>
X#include "sc.h"
X
X#define ENULL (struct enode *)0
X
Xchar *strcpy();
X%}
X
X%union {
X    int ival;
X    double fval;
X    struct ent_ptr ent;
X    struct enode *enode;
X    char *sval;
X    struct range_s rval;
X}
X
X%type <ent> var
X%type <fval> num
X%type <rval> range
X%type <rval> var_or_range
X%type <sval> strarg
X%type <enode> e term expr_list
X%token <sval> STRING
X%token <ival> NUMBER
X%token <fval> FNUMBER
X%token <rval> RANGE
X%token <rval> VAR
X%token <sval> WORD
X%token <ival> COL
X%token S_FORMAT
X%token S_FMT
X%token S_LABEL
X%token S_LEFTSTRING
X%token S_RIGHTSTRING
X%token S_GET
X%token S_PUT
X%token S_MERGE
X%token S_LET
X%token S_WRITE
X%token S_TBL
X%token S_COPY
X%token S_SHOW
X%token S_ERASE
X%token S_FILL
X%token S_GOTO
X%token S_DEFINE
X%token S_UNDEFINE
X%token S_VALUE
X%token S_MDIR
X%token S_HIDE
X%token S_SET
X
X%token K_ERROR
X%token K_INVALID
X%token K_FIXED
X%token K_SUM
X%token K_PROD
X%token K_AVG
X%token K_STDDEV
X%token K_COUNT
X%token K_ABS
X%token K_ACOS
X%token K_ASIN
X%token K_ATAN
X%token K_ATAN2
X%token K_CEIL
X%token K_COS
X%token K_EXP
X%token K_FABS
X%token K_FLOOR
X%token K_HYPOT
X%token K_LN
X%token K_LOG
X%token K_PI
X%token K_POW
X%token K_SIN
X%token K_SQRT
X%token K_TAN
X%token K_DTR
X%token K_RTD
X%token K_MAX
X%token K_MIN
X%token K_RND
X%token K_ROUND
X%token K_IF
X
X%token K_PV
X%token K_FV
X%token K_PMT
X
X%token K_HOUR
X%token K_MINUTE
X%token K_SECOND
X%token K_MONTH
X%token K_DAY
X%token K_YEAR
X%token K_NOW
X%token K_DATE
X%token K_DTS
X%token K_TTS
X%token K_FMT
X%token K_SUBSTR
X%token K_STON
X%token K_EQS
X%token K_EXT
X%token K_NVAL
X%token K_SVAL
X%token K_LOOKUP
X%token K_HLOOKUP
X%token K_VLOOKUP
X%token K_INDEX
X%token K_STINDEX
X%token K_AUTO
X%token K_AUTOCALC
X%token K_BYROWS
X%token K_BYCOLS
X%token K_ITERATIONS
X%token K_NUMERIC
X%token K_PRESCALE
X%token K_EXTFUN
X%token K_CELLCUR
X%token K_TOPROW
X%token K_TBLSTYLE
X%token K_TBL
X%token K_LATEX
X%token K_SLATEX
X%token K_TEX
X%token K_RNDINFINITY
X%token K_MYROW
X%token K_MYCOL
X%token K_COLTOA
X
X%left '?' ':'
X%left '|'
X%left '&'
X%nonassoc '<' '=' '>' '!'
X%left '+' '-' '#'
X%left '*' '/' '%'
X%left '^'
X
X%%
Xcommand:	S_LET var_or_range '=' e
X				{ let($2.left.vp, $4); }
X	|	S_LABEL var_or_range '=' e
X				{ slet($2.left.vp, $4, 0); }
X	|	S_LEFTSTRING var_or_range '=' e
X				{ slet($2.left.vp, $4, -1); }
X	|	S_RIGHTSTRING var_or_range '=' e
X				{ slet($2.left.vp, $4, 1); }
X	|	S_FORMAT COL ':' COL NUMBER NUMBER NUMBER
X				{ doformat($2,$4,$5,$6,$7); }
X	|	S_FORMAT COL NUMBER NUMBER NUMBER
X				{ doformat($2,$2,$3,$4,$5); }
X        |       S_FORMAT COL ':' COL NUMBER NUMBER
X                                { doformat($2,$4,$5,$6, 0); }
X        |       S_FORMAT COL NUMBER NUMBER
X                                { doformat($2,$2,$3,$4, 0); }
X	|	S_GET strarg	{  /* This tmp hack is because readfile
X				    * recurses back through yyparse. */
X				  char *tmp;
X				  tmp = $2;
X				  readfile (tmp, 1);
X				  xfree(tmp);
X				}
X	|	S_MERGE strarg	{
X				  char *tmp;
X				  tmp = $2;
X				  readfile (tmp, 0);
X				  xfree(tmp);
X				}
X	|	S_MDIR strarg	
X				{ if (mdir) xfree(mdir); mdir = $2; }
X	|       S_PUT strarg range
X				{ (void) writefile($2, ($3.left.vp)->row, 
X			 	($3.left.vp)->col, ($3.right.vp)->row,
X			 	($3.right.vp)->col);
X			 	xfree($2); }
X	|	S_PUT strarg	
X				{ (void) writefile ($2, 0, 0, maxrow, maxcol);
X			 	xfree($2); }
X	|       S_WRITE strarg range { (void) printfile($2, ($3.left.vp)->row, 
X			 ($3.left.vp)->col, ($3.right.vp)->row,
X			 ($3.right.vp)->col);
X			 xfree($2); }
X	|	S_WRITE strarg	{ (void) printfile ($2, 0, 0, maxrow, maxcol);
X			 xfree($2); }
X	|       S_TBL strarg range { (void) tblprintfile($2, ($3.left.vp)->row, 
X			 ($3.left.vp)->col, ($3.right.vp)->row,
X			 ($3.right.vp)->col);
X			 xfree($2); }
X	|	S_TBL strarg	{ (void)tblprintfile ($2, 0, 0, maxrow, maxcol);
X			 xfree($2); }
X	|       S_SHOW COL ':' COL
X					{ showcol( $2, $4); }
X	|       S_SHOW NUMBER ':' NUMBER
X					{ showrow( $2, $4); }
X 	|	S_HIDE COL
X 					{ hide_col( $2 ); }
X 	|	S_HIDE NUMBER
X 					{ hide_row( $2 ); }
X	|	S_COPY range var_or_range 
X					{ copy($2.left.vp,$2.right.vp,
X					$3.left.vp,$3.right.vp); }
X	|	S_ERASE       
X					{ eraser(lookat(showsr, showsc),
X				        lookat(currow, curcol)); }
X	|	S_ERASE var_or_range 
X					{ eraser($2.left.vp, $2.right.vp); }
X	|	S_VALUE       { valueize_area(showsr, showsc, currow, curcol);
X				 modflg++; }
X	|	S_VALUE var_or_range { valueize_area(($2.left.vp)->row,
X					($2.left.vp)->col,
X					($2.right.vp)->row,
X					($2.right.vp)->col); modflg++; }
X	|	S_FILL num num  { fill(lookat(showsr, showsc),
X				      lookat(currow, curcol), $2, $3); }
X	|	S_FILL var_or_range num num
X				{ fill($2.left.vp, $2.right.vp, $3, $4); }
X	|	S_FMT var_or_range STRING
X				{ format_cell($2.left.vp, $2.right.vp, $3); }
X	|	S_GOTO var_or_range {moveto($2.left.vp->row, $2.left.vp->col);}
X	|       S_GOTO num		{ num_search($2, 0); }
X	|       S_GOTO errlist
X	|       S_GOTO STRING		{ str_search($2); }
X	|	S_GOTO			{ go_last(); }
X	|	S_DEFINE strarg       { struct ent_ptr arg1, arg2;
X					arg1.vp = lookat(showsr, showsc);
X					arg1.vf = 0;
X					arg2.vp = lookat(currow, curcol);
X					arg2.vf = 0;
X                                        if (arg1.vp == arg2.vp)
X                                           add_range($2, arg2, arg2, 0);
X                                        else
X                                           add_range($2, arg1, arg2, 1); }
X
X	|	S_DEFINE strarg range	{ add_range($2, $3.left, $3.right, 1); }
X	|	S_DEFINE strarg var	{ add_range($2, $3, $3, 0); }
X	|	S_UNDEFINE var_or_range	{ del_range($2.left.vp, $2.right.vp); }
X 	|	S_SET setlist
X	|	/* nothing */
X	|	error;
X
Xterm: 		var			{ $$ = new_var(O_VAR, $1); }
X	|	K_FIXED term		{ $$ = new ('f', ENULL, $2); }
X	|       '@' K_SUM '(' var_or_range ')' 
X				{ $$ = new_range(REDUCE | '+', $4); }
X	|       '@' K_PROD '(' var_or_range ')' 
X				{ $$ = new_range (REDUCE | '*', $4); }
X	|       '@' K_AVG '(' var_or_range ')' 
X				{ $$ = new_range (REDUCE | 'a', $4); }
X	|       '@' K_STDDEV '(' var_or_range ')' 
X				{ $$ = new_range (REDUCE | 's', $4); }
X	|       '@' K_COUNT '(' var_or_range ')' 
X				{ $$ = new_range (REDUCE | 'c', $4); }
X	|       '@' K_MAX '(' var_or_range ')' 
X				{ $$ = new_range (REDUCE | MAX, $4); }
X	|	'@' K_MAX '(' e ',' expr_list ')'
X				{ $$ = new(LMAX, $6, $4); }
X	|       '@' K_MIN '(' var_or_range ')' 
X				{ $$ = new_range (REDUCE | MIN, $4); }
X	|	'@' K_MIN '(' e ',' expr_list ')'
X				{ $$ = new(LMIN, $6, $4); }
X	| '@' K_ABS '(' e ')'		{ $$ = new(ABS, ENULL, $4); }
X	| '@' K_ACOS '(' e ')'		{ $$ = new(ACOS, ENULL, $4); }
X	| '@' K_ASIN '(' e ')'		{ $$ = new(ASIN, ENULL, $4); }
X	| '@' K_ATAN '(' e ')'		{ $$ = new(ATAN, ENULL, $4); }
X	| '@' K_ATAN2 '(' e ',' e ')'	{ $$ = new(ATAN2, $4, $6); }
X	| '@' K_CEIL '(' e ')'		{ $$ = new(CEIL, ENULL, $4); }
X	| '@' K_COS '(' e ')'		{ $$ = new(COS, ENULL, $4); }
X	| '@' K_EXP '(' e ')'		{ $$ = new(EXP, ENULL, $4); }
X	| '@' K_FABS '(' e ')'		{ $$ = new(FABS, ENULL, $4); }
X	| '@' K_FLOOR '(' e ')'		{ $$ = new(FLOOR, ENULL, $4); }
X	| '@' K_HYPOT '(' e ',' e ')'	{ $$ = new(HYPOT, $4, $6); }
X	| '@' K_LN '(' e ')'		{ $$ = new(LOG, ENULL, $4); }
X	| '@' K_LOG '(' e ')'		{ $$ = new(LOG10, ENULL, $4); }
X	| '@' K_POW '(' e ',' e ')'	{ $$ = new(POW, $4, $6); }
X	| '@' K_SIN '(' e ')'		{ $$ = new(SIN, ENULL, $4); }
X	| '@' K_SQRT '(' e ')'		{ $$ = new(SQRT, ENULL, $4); }
X	| '@' K_TAN '(' e ')'		{ $$ = new(TAN, ENULL, $4); }
X	| '@' K_DTR '(' e ')'		{ $$ = new(DTR, ENULL, $4); }
X	| '@' K_RTD '(' e ')'		{ $$ = new(RTD, ENULL, $4); }
X	| '@' K_RND '(' e ')'		{ $$ = new(RND, ENULL, $4); }
X	| '@' K_ROUND '(' e ',' e ')'	{ $$ = new(ROUND, $4, $6); }
X	| '@' K_IF  '(' e ',' e ',' e ')' { $$ = new(IF,  $4,new(',',$6,$8)); }
X
X	| '@' K_PV  '(' e ',' e ',' e ')' { $$ = new(PV,  $4,new(':',$6,$8)); }
X 	| '@' K_FV  '(' e ',' e ',' e ')' { $$ = new(FV,  $4,new(':',$6,$8)); }
X 	| '@' K_PMT '(' e ',' e ',' e ')' { $$ = new(PMT, $4,new(':',$6,$8)); }
X 
X	| '@' K_HOUR '(' e ')'		{ $$ = new(HOUR,ENULL, $4); }
X	| '@' K_MINUTE '(' e ')'	{ $$ = new(MINUTE,ENULL, $4); }
X	| '@' K_SECOND '(' e ')'	{ $$ = new(SECOND,ENULL, $4); }
X	| '@' K_MONTH '(' e ')'		{ $$ = new(MONTH,ENULL,$4); }
X	| '@' K_DAY '(' e ')'		{ $$ = new(DAY, ENULL, $4); }
X	| '@' K_YEAR '(' e ')'		{ $$ = new(YEAR, ENULL, $4); }
X	| '@' K_NOW			{ $$ = new(NOW, ENULL, ENULL);}
X	| '@' K_DTS '(' e ',' e ',' e ')'
X					{ $$ = new(DTS, $4, new(',', $6, $8));}
X	| '@' K_TTS '(' e ',' e ',' e ')'
X					{ $$ = new(TTS, $4, new(',', $6, $8));}
X	| '@' K_STON '(' e ')'		{ $$ = new(STON, ENULL, $4); }
X	| '@' K_EQS '(' e ',' e ')'	{ $$ = new (EQS, $4, $6); }
X	| '@' K_DATE '(' e ')'		{ $$ = new(DATE, ENULL, $4); }
X	| '@' K_FMT  '(' e ',' e ')'	{ $$ = new(FMT, $4, $6); }
X	| '@' K_INDEX  '(' e ',' var_or_range ')'
X		 { $$ = new(INDEX, $4, new_range(REDUCE | INDEX, $6)); }
X	| '@' K_LOOKUP  '(' e ',' var_or_range ')'
X		 { $$ = new(LOOKUP, $4, new_range(REDUCE | LOOKUP, $6)); }
X	| '@' K_HLOOKUP  '(' e ',' var_or_range ',' e ')'
X		 { $$ = new(HLOOKUP, new(',', $4, $8),
X		    new_range(REDUCE | HLOOKUP, $6)); }
X	| '@' K_VLOOKUP  '(' e ',' var_or_range ',' e ')'
X		 { $$ = new(VLOOKUP, new(',', $4, $8),
X		    new_range(REDUCE | VLOOKUP, $6)); }
X	| '@' K_STINDEX  '(' e ',' var_or_range ')'
X		 { $$ = new(STINDEX, $4, new_range(REDUCE | STINDEX, $6)); }
X	| '@' K_EXT  '(' e ',' e ')'	{ $$ = new(EXT, $4, $6); }
X	| '@' K_NVAL '(' e ',' e ')'	{ $$ = new(NVAL, $4, $6); }
X	| '@' K_SVAL '(' e ',' e ')'	{ $$ = new(SVAL, $4, $6); }
X	| '@' K_SUBSTR '(' e ',' e ',' e ')'
X				{ $$ = new(SUBSTR, $4, new(',', $6, $8)); }
X	|	'(' e ')'	{ $$ = $2; }
X	|	'+' term	{ $$ = $2; }
X	|	'-' term	{ $$ = new ('m', ENULL, $2); }
X	|	NUMBER		{ $$ = new_const(O_CONST, (double) $1); }
X	|	FNUMBER		{ $$ = new_const(O_CONST, $1); }
X	|	K_PI { $$ = new_const(O_CONST, (double)3.14159265358979323846); }
X	|	STRING	        { $$ = new_str($1); }
X	|	'~' term	{ $$ = new ('~', ENULL, $2); }
X	|	'!' term	{ $$ = new ('~', ENULL, $2); }
X	| '@' K_MYROW			{ $$ = new(MYROW, ENULL, ENULL);}
X	| '@' K_MYCOL			{ $$ = new(MYCOL, ENULL, ENULL);}
X	| '@' K_COLTOA '(' e ')'	{ $$ = new(COLTOA, ENULL, $4);}
X	;
X
X/* expressions */
Xe:		e '+' e		{ $$ = new ('+', $1, $3); }
X	|	e '-' e		{ $$ = new ('-', $1, $3); }
X	|	e '*' e		{ $$ = new ('*', $1, $3); }
X	|	e '/' e		{ $$ = new ('/', $1, $3); }
X	|	e '%' e		{ $$ = new ('%', $1, $3); }
X	|	e '^' e		{ $$ = new ('^', $1, $3); }
X	|	term
X	|	e '?' e ':' e	{ $$ = new ('?', $1, new(':', $3, $5)); }
X	|	e '<' e		{ $$ = new ('<', $1, $3); }
X	|	e '=' e		{ $$ = new ('=', $1, $3); }
X	|	e '>' e		{ $$ = new ('>', $1, $3); }
X	|	e '&' e		{ $$ = new ('&', $1, $3); }
X	|	e '|' e		{ $$ = new ('|', $1, $3); }
X	|	e '<' '=' e	{ $$ = new ('~', ENULL, new ('>', $1, $4)); }
X	|	e '!' '=' e	{ $$ = new ('~', ENULL, new ('=', $1, $4)); }
X	|	e '>' '=' e	{ $$ = new ('~', ENULL, new ('<', $1, $4)); }
X	|	e '#' e		{ $$ = new ('#', $1, $3); }
X	;
X
Xexpr_list:	e		{ $$ = new(ELIST, ENULL, $1); }
X	|	expr_list ',' e	{ $$ = new(ELIST, $1, $3); }
X	;
X
Xrange:		var ':' var	{ $$.left = $1; $$.right = $3; }
X	| 	RANGE		{ $$ = $1; }
X	;
X
Xvar:		COL NUMBER	{ $$.vp = lookat($2 , $1); $$.vf = 0; }
X	|	'$' COL NUMBER	{ $$.vp = lookat($3 , $2);
X					$$.vf = FIX_COL; }
X	|	COL '$' NUMBER	{ $$.vp = lookat($3 , $1);
X					$$.vf = FIX_ROW; }
X	|	'$' COL '$' NUMBER { $$.vp = lookat($4 , $2);
X					$$.vf = FIX_ROW | FIX_COL; }
X	|	VAR		{ $$ = $1.left; }
X	;
X
Xvar_or_range:	range		{ $$ = $1; }
X	|	var		{ $$.left = $1; $$.right = $1; }
X	;
X
Xnum:		NUMBER		{ $$ = (double) $1; }
X	|	FNUMBER		{ $$ = $1; }
X	|	'-' num		{ $$ = -$2; }
X	|	'+' num		{ $$ = $2; }
X	;
X
Xstrarg:		STRING		{ $$ = $1; }
X	|	var		{
X				    char *s, *s1;
X				    s1 = $1.vp->label;
X				    if (!s1)
X					s1 = "NULL_STRING";
X				    s = xmalloc((unsigned)strlen(s1)+1);
X				    (void) strcpy(s, s1);
X				    $$ = s;
X				}
X  	;
X
X/* allows >=1 'setitem's to be listed in the same 'set' command */
Xsetlist :
X	|	setlist	setitem
X	;
X
X/* things that you can 'set' */
Xsetitem	:	K_AUTO		{ setauto(1); }
X	|	K_AUTOCALC	{ setauto(1); }
X	|	'~' K_AUTO	{ setauto(0); }
X	|	'~' K_AUTOCALC	{ setauto(0); }
X	|	'!' K_AUTO	{ setauto(0); }
X	|	'!' K_AUTOCALC	{ setauto(0); }
X	|	K_BYCOLS	{ setorder(BYCOLS); }
X	|	K_BYROWS	{ setorder(BYROWS); }
X	|	K_NUMERIC	{ numeric = 1; }
X	|	'!' K_NUMERIC	{ numeric = 0; }
X	|	K_PRESCALE	{ prescale = 0.01; }
X	|	'!' K_PRESCALE	{ prescale = 1.0; }
X	|	K_EXTFUN	{ extfunc = 1; }
X	|	'!' K_EXTFUN	{ extfunc = 0; }
X	|	K_CELLCUR	{ showcell = 1; }
X	|	'!' K_CELLCUR	{ showcell = 0; }
X	|	K_TOPROW	{ showtop = 1; }
X	|	'!' K_TOPROW	{ showtop = 0; }
X	|	K_ITERATIONS '=' NUMBER	{ setiterations($3); }
X	|	K_TBLSTYLE '=' NUMBER	{ tbl_style = $3; }
X	|	K_TBLSTYLE '=' K_TBL	{ tbl_style = TBL; }
X	|	K_TBLSTYLE '=' K_LATEX	{ tbl_style = LATEX; }
X	|	K_TBLSTYLE '=' K_SLATEX	{ tbl_style = SLATEX; }
X	|	K_TBLSTYLE '=' K_TEX	{ tbl_style = TEX; }
X	|	K_RNDINFINITY		{ rndinfinity = 1; FullUpdate++; }
X	|	'!' K_RNDINFINITY	{ rndinfinity = 0; FullUpdate++; }
X  	;
X
X/* types of errors, to 'goto' */
Xerrlist :	K_ERROR		{ num_search((double)0, CELLERROR); }
X	|	K_INVALID	{ num_search((double)0, CELLINVALID); }
X	;
END_OF_FILE
  if test 13277 -ne `wc -c <'gram.y'`; then
    echo shar: \"'gram.y'\" unpacked with wrong size!
  fi
  # end of 'gram.y'
fi
if test -f 'lex.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lex.c'\"
else
  echo shar: Extracting \"'lex.c'\" \(13772 characters\)
  sed "s/^X//" >'lex.c' <<'END_OF_FILE'
X/*	SC	A Spreadsheet Calculator
X *		Lexical analyser
X *
X *		original by James Gosling, September 1982
X *		modifications by Mark Weiser and Bruce Israel,
X *			University of Maryland
X *
X *              More mods Robert Bond, 12/86
X *		More mods by Alan Silverstein, 3/88, see list of changes.
X *		$Revision: 6.16 $
X *
X */
X
X
X#include <sys/types.h>
X#ifdef BSD42
X#include <strings.h>
X#else
X#ifndef SYSIII
X#include <string.h>
X#endif
X#endif
X
X#if defined(BSD42) || defined(BSD43)
X#include <sys/ioctl.h>
X#endif 
X
X#ifdef IEEE_MATH
X#include <ieeefp.h>
X#endif /* IEEE_MATH */
X
X#include <curses.h>
X#include <signal.h>
X#include <setjmp.h>
X#include "sc.h"
X#include <ctype.h>
X
X#ifdef VMS
X#include "gram_tab.h"
Xtypedef union {
X    int ival;
X    double fval;
X    struct ent *ent;
X    struct enode *enode;
X    char *sval;
X    struct range_s rval;
X} YYSTYPE;
Xextern YYSTYPE yylval;
Xextern int VMS_read_raw;   /*sigh*/
X#else	/* VMS */
X#include "y.tab.h"
X#endif /* VMS */
X
Xchar *strtof();
X
Xjmp_buf wakeup;
Xjmp_buf fpe_buf;
X
X#ifdef SIGVOID
Xvoid
X#endif
Xfpe_trap(signo)
Xint signo;
X{
X#if defined(i386) && !defined(M_XENIX)
X	asm("	fnclex");
X	asm("	fwait");
X#else
X#ifdef IEEE_MATH
X	(void)fpsetsticky((fp_except)0);	/* Clear exception */
X#endif /* IEEE_MATH */
X#ifdef PC
X	_fpreset();
X#endif
X#endif
X    longjmp(fpe_buf, 1);
X}
X
Xstruct key {
X    char *key;
X    int val;
X};
X
Xstruct key experres[] = {
X#include "experres.h"
X    0, 0};
X
Xstruct key statres[] = {
X#include "statres.h"
X    0, 0};
X
Xint
Xyylex ()
X{
X    register char *p = line+linelim;
X    int ret;
X    while (isspace(*p)) p++;
X    if (*p == '\0') ret = -1;
X    else if (isalpha(*p)) {
X	char *tokenst = p;
X	register tokenl;
X	register struct key *tblp;
X	tokenl = 0;
X	/*
X	 * This picks up either 1 or 2 alpha characters (a column) or
X	 * tokens with at least three leading alphas and '_' or digits
X	 * (a function or token or command or a range name)
X	*/
X	while (isalpha(*p) || ((*p == '_') || isdigit(*p)) && (tokenl > 2)) {
X	    p++;
X	    tokenl++;
X	}
X	if (tokenl <= 2) { /* a COL is 1 or 2 char alpha
X		(but not pi, ln, fv, pv, if -- this should be fixed!) */
X	    if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'i') {
X		ret = K_PI;
X	    } else if (tokenl == 2 && tokenst[0] == 'l' && tokenst[1] == 'n') {
X		ret = K_LN;
X	    } else if (tokenl == 2 && tokenst[0] == 'f' && tokenst[1] == 'v') {
X		ret = K_FV;
X	    } else if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'v') {
X		ret = K_PV;
X	    } else if (tokenl == 2 && tokenst[0] == 'i' && tokenst[1] == 'f') {
X		ret = K_IF;
X
X	    } else {
X		ret = COL;
X		yylval.ival = atocol (tokenst, tokenl);
X	    }
X	} else {
X	    ret = WORD;
X	    for (tblp = linelim ? experres : statres; tblp->key; tblp++)
X		    if (((tblp->key[0]^tokenst[0])&0137)==0
X		     && tblp->key[tokenl]==0) {
X			register i = 1;
X			while (i<tokenl && ((tokenst[i]^tblp->key[i])&0137)==0)
X			    i++;
X			if (i>=tokenl) {
X			    ret = tblp->val;
X			    break;
X			}
X		    }
X	    if (ret==WORD) { 
X		struct range *r;
X		if (r = find_range(tokenst, tokenl,
X				   (struct ent *)0, (struct ent *)0)) {
X		    yylval.rval.left = r->r_left;
X		    yylval.rval.right = r->r_right;
X		    if (r->r_is_range)
X		        ret = RANGE;
X		    else
X			ret = VAR;
X		} else {
X		    linelim = p-line;
X		    yyerror ("Unintelligible word");
X		}
X	    }
X	}
X    } else if ((*p == '.') || isdigit(*p)) {
X#ifdef SIGVOID
X	void (*sig_save)();
X#else
X	int (*sig_save)();
X#endif
X	double v = 0.0;
X	int temp;
X	char *nstart = p;
X
X	sig_save = signal(SIGFPE, fpe_trap);
X	if (setjmp(fpe_buf)) {
X	    (void) signal(SIGFPE, sig_save);
X	    yylval.fval = v;
X	    error("Floating point exception\n");
X	    return FNUMBER;
X	}
X
X	if (*p != '.') {
X	    do v = v*10.0 + (double) ((unsigned) *p - '0');
X	    while (isdigit(*++p));
X	}
X	if (*p=='.' || *p == 'e' || *p == 'E') {
X	    ret = FNUMBER;
X	    p = strtof(nstart, &yylval.fval);
X	} else {
X	    /* A NUMBER must hold at least MAXROW and MAXCOL */
X	    /* This is consistent with a short row and col in struct ent */
X	    if (v > (double)32767 || v < (double)-32768) {
X		ret = FNUMBER;
X		yylval.fval = v;
X	    } else {
X		temp = (int)v;
X		if((double)temp != v) {
X		    ret = FNUMBER;
X		    yylval.fval = v;
X		} else {
X		    ret = NUMBER;
X		    yylval.ival = temp;
X		}
X	    }
X	}
X	(void) signal(SIGFPE, sig_save);
X    } else if (*p=='"') {
X	char *ptr;
X        ptr = p+1;
X        while(*ptr && *ptr++ != '"');
X        ptr = xmalloc((unsigned)(ptr-p));
X	yylval.sval = ptr;
X	p += 1;
X	while (*p && *p!='"') *ptr++ = *p++;
X	*ptr = 0;
X	if (*p) p += 1;
X	ret = STRING;
X    } else if (*p=='[') {
X	while (*p && *p!=']') p++;
X	if (*p) p++;
X	linelim = p-line;
X	return yylex();
X    } else ret = *p++;
X    linelim = p-line;
X    return ret;
X}
X
X
X/*
X * Given a token string starting with a symbolic column name and its valid
X * length, convert column name ("A"-"Z" or "AA"-"ZZ") to a column number (0-N).
X * Never mind if the column number is illegal (too high).  The procedure's name
X * and function are the inverse of coltoa().
X * 
X * Case-insensitivity is done crudely, by ignoring the 040 bit.
X */
X
Xint
Xatocol (string, len)
X	char	*string;
X	int	len;
X{
X	register int col;
X
X	col = (string [0] & 0137) - 'A';
X
X	if (len == 2)		/* has second char */
X	    col = ((col + 1) * 26) + ((string [1] & 0137) - 'A');
X
X	return (col);
X}
X
X
X#ifdef SIMPLE
X
Xvoid
Xinitkbd()
X{}
X
Xvoid
Xkbd_again()
X{}
X
Xvoid
Xresetkbd()
X{}
X
X#ifndef VMS
X
Xint
Xnmgetch()
X{
X    return (toascii(getchar()));
X}
X
X#else /* VMS */
X
Xint
Xnmgetch()
X/*
X   This is not perfect, it doesn't move the cursor when goraw changes
X   over to deraw, but it works well enough since the whole sc package
X   is incredibly stable (loop constantly positions cursor).
X
X   Question, why didn't the VMS people just implement cbreak?
X
X   NOTE: During testing it was discovered that the DEBUGGER and curses
X   and this method of reading would collide (the screen was not updated
X   when continuing from screen mode in the debugger).
X*/
X{
X    short c;
X    static int key_id=0;
X    int status;
X#define VMScheck(a) {if (~(status = (a)) & 1) VMS_MSG (status);}
X
X    if (VMS_read_raw) {
X      VMScheck(smg$read_keystroke (&stdkb->_id, &c, 0, 0, 0));
X    }
X    else
X       c = getchar();
X
X    switch (c) {
X    case SMG$K_TRM_LEFT:  c = ctl('b'); break;
X    case SMG$K_TRM_RIGHT: c = ctl('f'); break;
X    case SMG$K_TRM_UP:    c = ctl('p'); break;
X    case SMG$K_TRM_DOWN:  c = ctl('n'); break;
X    default:   c = c & 0x7f;
X    }
X    return (c);
X}
X
X
XVMS_MSG (status)
Xint status;
X/*
X   Routine to put out the VMS operating system error (if one occurs).
X*/
X{
X#include <descrip.h>
X   char errstr[81], buf[120];
X   $DESCRIPTOR(errdesc, errstr);
X   short int length;
X#define err_out(msg) fprintf (stderr,msg)
X
X/* Check for no error or standard error */
X
X   if (~status & 1) {
X      status = status & 0x8000 ? status & 0xFFFFFFF : status & 0xFFFF;
X      if (SYS$GETMSG(status, &length, &errdesc, 1, 0) == SS$_NORMAL) {
X	 errstr[length] = '\0';
X	 (void) sprintf (buf, "<0x%x> %s", status, errdesc.dsc$a_pointer);
X	 err_out (buf);
X      }
X      else
X         err_out ("System error");
X   }
X}
X#endif /* VMS */
X
X#else /*SIMPLE*/
X
X#if defined(BSD42) || defined (SYSIII) || defined(BSD43)
X
X#define N_KEY 4
X
Xstruct key_map {
X    char *k_str;
X    char k_val;
X    char k_index;
X}; 
X
Xstruct key_map km[N_KEY];
X
Xchar keyarea[N_KEY*30];
X
Xchar *tgetstr();
Xchar *getenv();
Xchar *ks;
Xchar ks_buf[20];
Xchar *ke;
Xchar ke_buf[20];
X
X#ifdef TIOCSLTC
Xstruct ltchars old_chars, new_chars;
X#endif
X
Xchar dont_use[] = {
X	ctl('['), ctl('a'), ctl('b'), ctl('c'), ctl('e'), ctl('f'), ctl('g'), ctl('h'),
X	ctl('i'), ctl('j'),  ctl('l'), ctl('m'), ctl('n'), ctl('p'), ctl('q'),
X	ctl('r'), ctl('s'), ctl('t'), ctl('u'), ctl('v'),  ctl('w'), ctl('x'),
X	ctl('z'), 0
X};
X
Xvoid
Xcharout(c)
Xint c;
X{
X	(void)putchar(c);
X}
X
Xvoid
Xinitkbd()
X{
X    register struct key_map *kp;
X    register i,j;
X    char *p = keyarea;
X    char *ktmp;
X    static char buf[1024]; /* Why do I have to do this again? */
X
X    if (!(ktmp = getenv("TERM"))) {
X	(void) fprintf(stderr, "TERM environment variable not set\n");
X	exit (1);
X    }
X    if (tgetent(buf, ktmp) <= 0)
X	return;
X
X    km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl('b');
X    km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl('f');
X    km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl('p');
X    km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl('n');
X    ktmp = tgetstr("ks",&p);
X    if (ktmp)  {
X	(void) strcpy(ks_buf, ktmp);
X	ks = ks_buf;
X	tputs(ks, 1, charout);
X    }
X    ktmp = tgetstr("ke",&p);
X    if (ktmp)  {
X	(void) strcpy(ke_buf, ktmp);
X	ke = ke_buf;
X    }
X
X    /* Unmap arrow keys which conflict with our ctl keys   */
X    /* Ignore unset, longer than length 1, and 1-1 mapped keys */
X
X    for (i = 0; i < N_KEY; i++) {
X	kp = &km[i];
X	if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val))
X	    for (j = 0; dont_use[j] != 0; j++)
X	        if (kp->k_str[0] == dont_use[j]) {
X		     kp->k_str = (char *)0;
X		     break;
X		}
X    }
X
X
X#ifdef TIOCSLTC
X    (void)ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars);
X    new_chars = old_chars;
X    if (old_chars.t_lnextc == ctl('v'))
X	new_chars.t_lnextc = -1;
X    if (old_chars.t_rprntc == ctl('r'))
X	new_chars.t_rprntc = -1;
X    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
X#endif
X}
X
Xvoid
Xkbd_again()
X{
X    if (ks) 
X	tputs(ks, 1, charout);
X
X#ifdef TIOCSLTC
X    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
X#endif
X}
X
Xvoid
Xresetkbd()
X{
X    if (ke) 
X	tputs(ke, 1, charout);
X
X#ifdef TIOCSLTC
X    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars);
X#endif
X}
X
Xint
Xnmgetch() 
X{
X    register int c;
X    register struct key_map *kp;
X    register struct key_map *biggest;
X    register int i;
X    int almost;
X    int maybe;
X
X    static char dumpbuf[10];
X    static char *dumpindex;
X
X#ifdef SIGVOID
X    void time_out();
X#else
X    int time_out();
X#endif
X
X    if (dumpindex && *dumpindex)
X	    return (*dumpindex++);
X
X    c = toascii(getchar());
X    biggest = 0;
X    almost = 0;
X
X    for (kp = &km[0]; kp < &km[N_KEY]; kp++) {
X	if (!kp->k_str)
X	    continue;
X	if (c == kp->k_str[kp->k_index]) {
X	    almost = 1;
X	    kp->k_index++;
X	    if (kp->k_str[kp->k_index] == 0) {
X		c = kp->k_val;
X	        for (kp = &km[0]; kp < &km[N_KEY]; kp++)
X	            kp->k_index = 0;
X	        return(c);
X	    }
X	}
X	if (!biggest && kp->k_index)
X	    biggest = kp;
X        else if (kp->k_index && biggest->k_index < kp->k_index)
X	    biggest = kp;
X    }
X
X    if (almost) { 
X        (void) signal(SIGALRM, time_out);
X        (void) alarm(1);
X
X	if (setjmp(wakeup) == 0) { 
X	    maybe = nmgetch();
X	    (void) alarm(0);
X	    return(maybe);
X	}
X    }
X    
X    if (biggest) {
X	for (i = 0; i<biggest->k_index; i++) 
X	    dumpbuf[i] = biggest->k_str[i];
X	if (!almost)
X	    dumpbuf[i++] = c;
X	dumpbuf[i] = '\0';
X	dumpindex = &dumpbuf[1];
X	for (kp = &km[0]; kp < &km[N_KEY]; kp++)
X	    kp->k_index = 0;
X	return (dumpbuf[0]);
X    }
X
X    return(c);
X}
X
X#endif
X
X#if defined(SYSV2) || defined(SYSV3)
X
Xvoid
Xinitkbd()
X{
X    keypad(stdscr, TRUE);
X}
X
Xvoid
Xkbd_again()
X{
X    keypad(stdscr, TRUE);
X}
X
Xvoid
Xresetkbd()
X{
X    keypad(stdscr, FALSE);
X}
X
Xint
Xnmgetch()
X{
X    register int c;
X
X    c = getch();
X    switch (c) {
X    case KEY_LEFT:  c = ctl('b'); break;
X    case KEY_RIGHT: c = ctl('f'); break;
X    case KEY_UP:    c = ctl('p'); break;
X    case KEY_DOWN:  c = ctl('n'); break;
X    case KEY_BACKSPACE:  c = ctl('h'); break;
X#ifdef KEY_C1
X/* This stuff works for a wyse wy75 in ANSI mode under 5.3.  Good luck. */
X/* It is supposed to map the curses keypad back to the numeric equiv. */
X    case KEY_C1:    c = '0'; break;
X    case KEY_A1:    c = '1'; break;
X    case KEY_B2:    c = '2'; break;
X    case KEY_A3:    c = '3'; break;
X    case KEY_F(5):  c = '4'; break;
X    case KEY_F(6):  c = '5'; break;
X    case KEY_F(7):  c = '6'; break;
X    case KEY_F(9):  c = '7'; break;
X    case KEY_F(10): c = '8'; break;
X    case KEY_F0:    c = '9'; break;
X    case KEY_C3:    c = '.'; break;
X    case KEY_ENTER: c = ctl('m'); break;
X#endif
X    default:   c = toascii(c); 
X    break;
X    }
X    return (c);
X}
X
X#endif /* SYSV2 || SYSV3 */
X
X#endif /* SIMPLE */
X
X#ifdef SIGVOID
Xvoid
X#else
Xint
X#endif
Xtime_out(signo)
Xint signo;
X{
X    longjmp(wakeup, 1);
X}
X
X/*
X * This converts a floating point number of the form
X * [s]ddd[.d*][esd*]  where s can be a + or - and e is E or e.
X * to floating point. 
X * p is advanced.
X */
X
Xchar *
Xstrtof(p, res)
Xregister char *p;
Xdouble *res;
X{
X    double acc;
X    int sign;
X    double fpos;
X    int exp;
X    int exps;
X#ifdef SIGVOID
X    void (*sig_save)();
X#else
X    int (*sig_save)();
X#endif
X    sig_save = signal(SIGFPE, fpe_trap);
X    if (setjmp(fpe_buf)) {
X	error("Floating point exception\n");
X	*res = 0.0; 
X        (void) signal(SIGFPE, sig_save);
X	return(p);
X    }
X    acc = 0.0;
X    sign = 1;
X    exp = 0;
X    exps = 1;
X    if (*p == '+')
X        p++;
X    else if (*p == '-') {
X        p++;
X        sign = -1;
X    }
X    while (isdigit(*p)) {
X        acc = acc * 10.0 + (double)(*p - '0');
X        p++;
X    }
X    if (*p == 'e' || *p == 'E') {
X	    p++;
X        if (*p == '+')
X	    p++;
X        else if (*p == '-') {
X	    p++;
X	    exps = -1;
X        }
X        while(isdigit(*p)) {
X	    exp = exp * 10 + (*p - '0');
X	    p++;
X        }
X    }
X    if (*p == '.') {
X	fpos = 1.0/10.0;
X	p++;
X	while(isdigit(*p)) {
X	    acc += (*p - '0') * fpos;
X	    fpos *= 1.0/10.0;
X	    p++;
X	}
X    }
X    if (*p == 'e' || *p == 'E') {
X	exp = 0;
X	exps = 1;
X        p++;
X	if (*p == '+')
X	    p++;
X	else if (*p == '-') {
X	    p++;
X	    exps = -1;
X	}
X	while(isdigit(*p)) {
X	    exp = exp * 10 + (*p - '0');
X	    p++;
X	}
X    }
X    if (exp) {
X	if (exps > 0)
X	    while (exp--)
X		acc *= 10.0;
X	else
X	    while (exp--)
X		acc *= 1.0/10.0;
X    }
X    if (sign > 0)
X        *res = acc;
X    else
X	*res = -acc;
X
X    (void) signal(SIGFPE, sig_save);
X    return(p);
X}
END_OF_FILE
  if test 13772 -ne `wc -c <'lex.c'`; then
    echo shar: \"'lex.c'\" unpacked with wrong size!
  fi
  # end of 'lex.c'
fi
if test -f 'vi.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vi.c'\"
else
  echo shar: Extracting \"'vi.c'\" \(13015 characters\)
  sed "s/^X//" >'vi.c' <<'END_OF_FILE'
X/*	SC	A Spreadsheet Calculator
X *
X *	One line vi emulation
X *	$Revision: 6.16 $
X */
X
X#include <sys/types.h>
X#ifdef BSD42
X#include <strings.h>
X#else
X#ifndef SYSIII
X#include <string.h>
X#endif
X#endif
X
X#include <signal.h>
X#include <curses.h>
X
Xextern	char	*strchr();
X
X#include <stdio.h>
X#include <ctype.h>
X#include "sc.h"
X
X#define istext(a) (isalnum(a) || ((a) == '_'))
X
Xstatic	void append_line();
Xstatic	void back_hist();
Xstatic	int  back_line();
Xstatic	int  back_word();
Xstatic	void back_space();
Xstatic	void change_cmd();
Xstatic	void col_0();
Xstatic	void cr_line();
Xstatic	void delete_cmd();
Xstatic	void del_chars();
Xstatic	void del_in_line();
Xstatic	void del_to_end();
Xstatic	void dotcmd();
Xstatic	int  find_char();
Xstatic	void for_hist();
Xstatic	int  for_line();
Xstatic	int  for_word();
Xstatic	void ins_in_line();
Xstatic	void last_col();
Xstatic	void rep_char();
Xstatic	void replace_in_line();
Xstatic	void replace_mode();
Xstatic	void restore_it();
Xstatic	void savedot();
Xstatic	void save_hist();
Xstatic	void search_again();
Xstatic	void search_hist();
Xstatic	void search_mode();
Xstatic	void stop_edit();
Xstatic	int  to_char();
Xstatic	void u_save();
X
Xextern int showrange;
Xextern char mode_ind;		/* Mode indicator */
X
X/* values for mode below */
X
X#define INSERT_MODE	0	/* Insert mode */
X#define EDIT_MODE       1	/* Edit mode */
X#define REP_MODE        2	/* Replace mode */
X#define SEARCH_MODE	3	/* Get arguments for '/' command */
X
X#define	DOTLEN		200
X
Xstatic int mode = INSERT_MODE;
Xstruct	hist {
X	unsigned	int	len;
X	char	*histline;
X} history[HISTLEN];
X
Xstatic int histp = -1;
Xstatic int lasthist = -1;
Xstatic int endhist = -1;
Xstatic char *last_search = NULL;
Xstatic char *undo_line = NULL;
Xstatic int undo_lim;
Xstatic char dotb[DOTLEN];
Xstatic int doti = 0;
Xstatic int do_dot = 0;
X
Xvoid
Xwrite_line(c)
Xint c;
X{
X    if (mode == EDIT_MODE) {
X	switch(c) {
X	case (ctl('h')):	linelim = back_line();		break;
X	case (ctl('m')):  cr_line();			break;
X	case ESC:	stop_edit();			break;
X	case '+':	for_hist();			break;
X	case '-':	back_hist();			break;
X	case '$':	last_col();			break;
X	case '.':	dotcmd();			break;
X	case '/':	search_mode();			break;
X	case '0':	col_0();			break;
X	case 'D':	u_save(c);del_to_end();		break;
X	case 'I':	u_save(c);col_0();insert_mode();break;
X	case 'R':	replace_mode();			break;
X	case 'X':	u_save(c); back_space();	break;
X	case 'a':	u_save(c); append_line();	break;
X	case 'b':	linelim = back_word();		break;
X	case 'c':	u_save(c); change_cmd();	break;
X	case 'd':	u_save(c); delete_cmd();	break;
X	case 'f':	linelim = find_char();		break;
X	case 'h':	linelim = back_line();		break;
X	case 'i':	u_save(c); insert_mode();	break;
X	case 'j':	for_hist();			break;
X	case 'k':	back_hist();			break;
X	case 'l':	linelim = for_line(0);		break;
X	case 'n':	search_again();			break;
X	case 'q':	stop_edit();			break;
X	case 'r':	u_save(c); rep_char();		break;
X	case 't':	linelim = to_char();		break;
X	case 'u':	restore_it();			break;
X	case 'w':	linelim = for_word(0);		break;
X	case 'x':	u_save(c); del_in_line();	break;
X	default:	break;
X	}
X    } else if (mode == INSERT_MODE) { 
X	savedot(c);
X	switch(c) {
X	case (ctl('h')):	back_space();			break;
X	case (ctl('m')):  cr_line();			break;
X	case ESC:	edit_mode();			break;
X	default:	ins_in_line(c);			break;
X	}
X    } else if (mode == SEARCH_MODE) {
X	switch(c) {
X	case (ctl('h')):	back_space();			break;
X	case (ctl('m')):  search_hist();			break;
X	case ESC:	edit_mode();			break;
X	default:	ins_in_line(c);			break;
X	}
X   } else if (mode == REP_MODE) {
X	savedot(c);
X	switch(c) {
X	case (ctl('h')):	back_space();			break;
X	case (ctl('m')):  cr_line();			break;
X	case ESC:	edit_mode();			break;
X	default:	replace_in_line(c);		break;
X	}
X    }
X}
X
Xvoid
Xedit_mode()
X{
X    mode = EDIT_MODE;
X    mode_ind = 'e';
X    histp = -1;
X    if (linelim < 0)	/* -1 says stop editing, ...so we still aren't */
X	return;
X    if (line[linelim] == '\0')
X	linelim = back_line();
X}
X
Xvoid
Xinsert_mode()
X{
X    mode_ind = 'i';
X    mode = INSERT_MODE;
X}
X
Xstatic	void
Xsearch_mode()
X{
X    line[0] = '/';
X    line[1] = '\0';
X    linelim = 1;
X    histp = -1;
X    mode_ind = '/';
X    mode = SEARCH_MODE;
X}
X
Xstatic	void
Xreplace_mode()
X{
X    mode_ind = 'R';
X    mode = REP_MODE;
X}
X
X/* dot command functions.  Saves info so we can redo on a '.' command */
X
Xstatic	void
Xsavedot(c)
Xint c;
X{
X    if (do_dot || (c == '\n'))
X	return;
X
X    if (doti < DOTLEN-1)
X    {
X	dotb[doti++] = c;
X	dotb[doti] = '\0';
X    }
X}
X
Xstatic int dotcalled = 0;
X
Xstatic	void
Xdotcmd()
X{
X    int c;
X
X    if (dotcalled)	/* stop recursive calling of dotcmd() */
X	return;
X    do_dot = 1;
X    doti = 0;
X    while(dotb[doti] != '\0') {
X	c = dotb[doti++];
X	dotcalled = 1;
X	write_line(c);
X    }
X    do_dot = 0;
X    doti = 0;
X    dotcalled = 0;
X}
X
Xint
Xvigetch()
X{
X    int c;
X
X    if(do_dot) {
X	if (dotb[doti] != '\0') {
X	    return(dotb[doti++]);
X	} else {
X	    do_dot = 0;
X	    doti = 0;
X	    return(nmgetch());
X	}
X    }
X    c = nmgetch();
X    savedot(c);
X    return(c);
X}
X
X/* saves the current line for possible use by an undo cmd */
Xstatic	void
Xu_save(c)
Xint c;
X{   static	unsigned	undolen = 0;
X
X    if (strlen(line)+1 > undolen)
X    {	undolen = strlen(line)+40;
X
X	undo_line = xrealloc(undo_line, undolen);
X    }
X    (void) strcpy(undo_line, line);
X
X    undo_lim = linelim;
X
X    /* reset dot command if not processing it. */
X
X    if (!do_dot) {
X        doti = 0;
X	savedot(c);
X    }
X}
X
X/* Restores the current line saved by u_save() */
Xstatic	void
Xrestore_it()
X{
X    static	char *tempc = NULL;
X    static	unsigned templen = 0;
X    int		tempi;
X
X    if ((undo_line == NULL) || (*undo_line == '\0')) 
X	return;
X
X    if (strlen(line)+1 > templen)
X    {	templen = strlen(line)+40;
X	tempc = xrealloc(tempc, templen);
X    }
X
X    strcpy(tempc, line);
X    tempi = linelim;
X    (void) strcpy(line, undo_line);
X    linelim = undo_lim;
X    strcpy(undo_line, tempc);
X    undo_lim = tempi;
X}
X
X/* This command stops the editing process. */
Xstatic	void
Xstop_edit()
X{
X    showrange = 0;
X    linelim = -1;
X    (void) move(1, 0);
X    (void) clrtoeol();
X}
X
X/*
X * Motion commands.  Forward motion commands take an argument
X * which, when set, cause the forward motion to continue onto
X * the null at the end of the line instead of stopping at the
X * the last character of the line.
X */
Xstatic	int
Xfor_line(stop_null)
Xint stop_null;
X{
X    if (linelim >= 0 && line[linelim] != '\0' && 
X    		        (line[linelim+1] != '\0' || stop_null))
X	return(linelim+1);
X    else
X	return(linelim);
X}
X
Xstatic	int
Xfor_word(stop_null)
Xint stop_null;
X{
X    register int c;
X    register int cpos;
X
X    cpos = linelim;
X
X    if (line[cpos] == ' ') {
X	while (line[cpos] == ' ')
X	    cpos++;
X	if (cpos > 0 && line[cpos] == '\0')
X	    --cpos;
X	return(cpos);
X    }
X
X    if (istext(line[cpos])) {
X    	while ((c = line[cpos]) && istext(c)) 
X		cpos++;
X    } else {
X	while ((c = line[cpos]) && !istext(c) && c != ' ')
X		cpos++;
X    }
X
X    while (line[cpos] == ' ')
X        cpos++;
X
X    if (cpos > 0 && line[cpos] == '\0' && !stop_null) 
X        --cpos;
X
X    return(cpos);
X}
X
Xstatic	int
Xback_line()
X{
X    if (linelim)
X        return(linelim-1);
X    else
X	return(0);
X}
X
Xstatic	int
Xback_word()
X{
X    register int c;
X    register int cpos;
X
X    cpos = linelim;
X
X    if (line[cpos] == ' ') {
X	/* Skip white space */
X        while (cpos > 0 && line[cpos] == ' ')
X	    --cpos;
X    } else if (cpos > 0 && (line[cpos-1] == ' ' 
X		     ||  istext(line[cpos]) && !istext(line[cpos-1])
X		     || !istext(line[cpos]) &&  istext(line[cpos-1]))) {
X	/* Started on the first char of a word - back up to prev. word */
X	--cpos;
X        while (cpos > 0 && line[cpos] == ' ')
X	    --cpos;
X    }
X
X    /* Skip across the word - goes 1 too far */
X    if (istext(line[cpos])) {
X    	while (cpos > 0 && (c = line[cpos]) && istext(c)) 
X		--cpos;
X    } else {
X	while (cpos > 0 && (c = line[cpos]) && !istext(c) && c != ' ')
X		--cpos;
X    }
X
X    /* We are done - fix up the one too far */
X    if (cpos > 0 && line[cpos] && line[cpos+1]) 
X	cpos++;
X
X    return(cpos);
X}
X
X/* Text manipulation commands */
X
Xstatic	void
Xdel_in_line()
X{
X    register int len, i;
X
X    if (linelim >= 0) {
X	len = strlen(line);
X	if (linelim == len && linelim > 0)
X	    linelim--;
X	for (i = linelim; i < len; i++)
X	    line[i] = line[i+1];
X    }
X    if (linelim > 0 && line[linelim] == '\0')
X	--linelim;
X}
X
Xstatic	void
Xins_in_line(c)
Xint c;
X{
X    register int i, len;
X
X    if (linelim < 0)
X    {	*line = '\0';
X	linelim = 0;
X    }
X    len = strlen(line);
X    for (i = len; i >= linelim; --i)
X	line[i+1] = line[i];
X    line[linelim++] = c;
X    line[len+1] = '\0';
X}
X
Xvoid
Xins_string(s)
Xchar *s;
X{
X    while (*s)
X	ins_in_line(*s++);
X}
X
Xstatic	void
Xappend_line()
X{
X    register int i;
X
X    i = linelim;
X    if (i >= 0 && line[i])
X	linelim++;
X    insert_mode();
X}
X
Xstatic	void
Xrep_char()
X{
X    int c;
X
X    if (linelim < 0)
X    {	linelim = 0;
X	*line = '\0';
X    }
X    c = vigetch();
X    if (line[linelim] != '\0') {
X    	line[linelim] = c;
X    } else {
X	line[linelim] = c;
X	line[linelim+1] = '\0';
X    }
X}
X
Xstatic	void
Xreplace_in_line(c)
Xint	c;
X{
X    register int len;
X
X    if (linelim < 0)
X    {	linelim = 0;
X	*line = '\0';
X    }
X    len = strlen(line);
X    line[linelim++] = c;
X    if (linelim > len)
X	line[linelim] = '\0';
X}
X
Xstatic	void
Xback_space()
X{
X    if (linelim == 0)
X	return;
X
X    if (line[linelim] == '\0') {
X	linelim = back_line();
X	del_in_line();
X	linelim = strlen(line);
X    } else {
X	linelim = back_line();
X	del_in_line();
X    }
X}
X
Xint
Xget_motion()
X{
X    int c;
X
X    c = vigetch();
X    switch (c) {
X    case 'b':	return(back_word());
X    case 'f':	return(find_char()+1);
X    case 'h':	return(back_line());
X    case 'l':	return(for_line(1));
X    case 't':	return(to_char()+1);
X    case 'w':	return(for_word(1));
X    default:	return(linelim);
X    }
X}
X
Xstatic	void
Xdelete_cmd()
X{
X    int cpos;
X
X    cpos = get_motion();
X    del_chars(cpos, linelim);
X}
X
Xstatic	void
Xchange_cmd()
X{
X    delete_cmd();
X    insert_mode();
X}
X
Xstatic	void
Xdel_chars(first, last)
Xregister int first, last;
X{
X    int temp;
X
X    if (first == last)
X	return;
X
X    if (last < first) {
X	temp = last; last = first; first = temp;
X    }
X
X    linelim = first;
X    while(first < last) {
X	del_in_line();
X	--last;
X    }
X}
X
Xstatic	void
Xdel_to_end()
X{
X    if (linelim < 0)
X	return;
X    line[linelim] = '\0';
X    linelim = back_line();
X}
X
Xstatic	void
Xcr_line()
X{
X    insert_mode();
X    if (linelim != -1) {
X	showrange = 0;
X	save_hist();
X	linelim = 0;
X	(void) yyparse ();
X	linelim = -1;
X    }
X    else	/* '\n' alone will put you into insert mode */
X    {	*line = '\0';
X	linelim = 0;
X    }
X}
X
X/* History functions */
X
Xstatic	void
Xsave_hist()
X{
X    if (lasthist < 0)
X    {	lasthist = 0;
X    }
X    else
X	lasthist = (lasthist + 1) % HISTLEN;
X
X    if (lasthist > endhist)
X	endhist = lasthist;
X
X    if (history[lasthist].len < strlen(line)+1)
X    {	history[lasthist].len = strlen(line)+40;
X	history[lasthist].histline = xrealloc(history[lasthist].histline,
X					      history[lasthist].len);
X    }
X    (void) strcpy(history[lasthist].histline, line);
X}
X
Xstatic	void
Xback_hist()
X{
X    if (histp == -1)
X	histp = lasthist;
X    else
X    if (histp == 0)
X    {	if (endhist != lasthist)
X		histp = endhist;
X    }
X    else
X    if (histp != ((lasthist + 1) % (endhist + 1)))
X	histp--;
X
X    if (lasthist < 0)
X	line[linelim = 0] = '\0';
X    else {
X    	(void) strcpy(line, history[histp].histline);
X	linelim = 0;
X    }
X}
X
Xstatic	void
Xsearch_hist()
X{
X    static	unsigned lastsrchlen = 0;
X
X    if(linelim < 1) {
X	linelim = 0;
X	edit_mode();
X	return;
X    }
X
X    if (strlen(line)+1 > lastsrchlen)
X    {	lastsrchlen = strlen(line)+40;
X	last_search = xrealloc(last_search, lastsrchlen);
X    }
X    (void)strcpy(last_search, line+1);
X    search_again();
X    mode = EDIT_MODE;
X}
X
Xstatic	void
Xsearch_again()
X{
X    int found_it;
X    int do_next;
X    int prev_histp;
X    char *look_here;
X
X    prev_histp = histp;
X    if ((last_search == NULL) || (*last_search == '\0'))
X	return;
X
X    do {
X	back_hist();
X	if (prev_histp == histp)
X	    break;
X	prev_histp = histp;
X	look_here = line;
X	found_it = do_next = 0;
X	while ((look_here = strchr(look_here, last_search[0])) &&
X						!found_it && !do_next) {
X
X	    if (strncmp(look_here, last_search, strlen(last_search)) == 0)
X		found_it++;
X	    else if (look_here < line + strlen(line) - 1)
X	        look_here++;
X	    else
X		do_next++;
X	}
X    } while (!found_it);
X}
X
Xstatic	void
Xfor_hist()
X{
X    if (histp == -1)
X	histp = lasthist;
X    else
X    if (histp != lasthist)
X	histp = (histp + 1) % (endhist + 1);
X
X    if (lasthist < 0)
X	line[linelim = 0] = '\0';
X    else {
X	(void) strcpy(line, history[histp].histline);
X	linelim = 0;
X    }
X}
X
Xstatic	void
Xcol_0()
X{
X    linelim = 0;
X}
X
Xstatic	void
Xlast_col()
X{
X    linelim = strlen(line);
X    if (linelim > 0)
X	--linelim;
X}
X
Xstatic	int
Xfind_char()
X{
X    register int c;
X    register int i;
X
X
X    c = vigetch();
X    i = linelim;
X    while(line[i] && line[i] != c)
X	i++;
X    if (!line[i])
X	i = linelim;
X    return(i);
X}
X
Xstatic	int
Xto_char()
X{
X    register int i;
X
X    i = find_char();
X    if (i > 0 && i != linelim)
X	--i;
X
X    return(i);
X}
END_OF_FILE
  if test 13015 -ne `wc -c <'vi.c'`; then
    echo shar: \"'vi.c'\" unpacked with wrong size!
  fi
  # end of 'vi.c'
fi
echo shar: End of archive 6 \(of 7\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 7 archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.