[alt.sources.amiga] sc Part 1 of 9

sie@fulcrum.bt.co.uk (Simon Raybould) (03/20/91)

This is a port of SC to the amiga.

SC is a PD spread sheet calculator with many features found
in commercial packages. I am not the author of this code,
I only ported it onto the amiga. The original authors name
can be found in the code and docs.


I compiled it with my curses library which is available via
ftp and on fish 391 or there abouts.
I also linked in my unix library which I haven't released into
the public domain because I don't consider it complete in any
sense of the word.

I have include uuencoded binaries of the 'sc' and 'psc'
executables.

If anyone has trouble writing the necessary UNIX system calls
then I will post an ALPHA version of my unix support stuff.
I am fairly sure that most people will have already written
their own UNIX support stuff or will be able to painlessly add
the required code to this code.


Simon J Raybould    (sie@fulcrum.bt.co.uk)            //              {o.o}
                                                    \X/AMIGA           \-/
===========================================================================
British Telecom Fulcrum, Fordrough Lane, Birmingham, B9 5LD, ENGLAND.


              O /
---------------X-------------- cut here --------------------------------------
              O \

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 03/20/1991 12:12 UTC by sie@lister
# Source directory /usrc/sie/tmp
#
# existing files will NOT be overwritten unless -c is specified
#
# This is part 1 of a multipart archive                                    
# do not concatenate these parts, unpack them in order with /bin/sh        
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    452 -rw-rw-rw- Makefile.amiga
#   5088 -rw-rw-rw- changes
#  30912 -rw-rw-rw- cmds.c
#   3640 -rw-rw-rw- crypt.c
#     50 -rw-rw-rw- eres.sed
#   1265 -rw-rw-rw- experres.h
#  81234 -rw-rw-rw- gram.c
#  12082 -rw-rw-rw- gram.y
#  16990 -rw-rw-rw- help.c
#  48439 -rw-rw-rw- interp.c
#  13674 -rw-rw-rw- lex.c
#    983 -rw-rw-rw- manifest
#   5741 -rw-rw-rw- psc.c
#   2147 -rw-rw-rw- psc.doc
#     95 -rw-rw-rw- psc.lnk
#  19322 -rw-r--r-- psc.uue
#   4655 -rw-rw-rw- pvmtbl.c
#   5604 -rw-rw-rw- range.c
#   3004 -rw-rw-rw- readme
#  33867 -rw-rw-rw- sc.c
#  45229 -rw-rw-rw- sc.doc
#   8426 -rw-rw-rw- sc.h
#      0 -rw-r--r-- sc.shr
# 194254 -rw-r--r-- sc.uue
#     50 -rw-rw-rw- sres.sed
#    399 -rw-rw-rw- statres.h
#   3738 -rw-rw-rw- todo
#   4292 -rw-rw-rw- tutorial.sc
#    148 -rw-rw-rw- version.c
#  10617 -rw-rw-rw- vi.c
#   4341 -rw-rw-rw- vms_notes
#   4643 -rw-rw-rw- vmtbl.c
#    686 -rw-rw-rw- xmalloc.c
#   2377 -rw-rw-rw- y.tab.h
#
if test -r _shar_seq_.tmp; then
	echo 'Must unpack archives in sequence!'
	echo Please unpack part `cat _shar_seq_.tmp` next
	exit 1
fi
# ============= Makefile.amiga ==============
if test -f 'Makefile.amiga' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile.amiga (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting Makefile.amiga (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile.amiga' &&
CC= lc
CFLAGS= -cw
LM= lib:lcm.lib
LCURSES= lib:curses.lib
LIBS= lib:unix.lib lib:lc.lib lib:amiga.lib
OBJS=sc.o interp.o cmds.o crypt.o range.o help.o vi.o gram.o \
X	lex.o vmtbl.o version.o xmalloc.o
X
all: SC psc
X
SC:$(OBJS)
X	blink lib:c.o $(OBJS) to $@ LIB $(LCURSES) $(LM) $(LIBS)
X
psc:	psc.o pvmtbl.o
X	blink lib:c.o psc.o pvmtbl.o to $@ LIB $(LIBS)
X
gram.o:	gram.y
X	bison -d -y gram.y
X	-delete gram.c
X	rename y.tab.c gram.c
X	$(CC) $(CFLAGS) gram.c
SHAR_EOF
chmod 0666 Makefile.amiga ||
echo 'restore of Makefile.amiga failed'
Wc_c="`wc -c < 'Makefile.amiga'`"
test 452 -eq "$Wc_c" ||
	echo 'Makefile.amiga: original size 452, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= changes ==============
if test -f 'changes' -a X"$1" != X"-c"; then
	echo 'x - skipping changes (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting changes (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'changes' &&
CHANGES BETWEEN 6.1 and 6.7
X
Dave Lewis - 
X	Found and fixed a null pointer derefrece in the 'R' command.
X
Rob McMahon -
X	Changed the ctl() macro to work with ANSI style compilers.
X	Cleaned up some non-readonly text problems.
X
Rick Linck -
X	Fixed a bug in lex.c - Ann Arbor Ambassadors have long ks and ke
X	termcap entries.
X
Sam Drake -
X	A fix for undefined C_* symbols in AIX.
X
Peter Brower -
X	Cleaned up the INTERNATIONAL ifdefs with more portable code.
X
Glen Ditchfield
X	Cleaned up a problem in crypt.c when the encrypted file shrank.
X
Bob Bond -
X	Vi style editing for the command line.
X	A bug in range name aliases.
X
Jeff Buhrt -
X	-Added "~" filename expansion.
X	-702 columns (A-ZZ) and unlimited rows/cells based on max. memory
X	-fixed a few bugs
X	-slightly decreased CPU usage
X	-MAKES backup copies of files
X	-understands ~$HOME stuff
X
CHANGES BETWEEN 5.1 and 6.1:
X
Andy Valencia -
X	xmalloc aligns data to a double boundary.
X
Lawrence Cipriani -
X	Fixed a bug in the "do you want to save this" sequence.
X
Soren Lundsgaard -
X	A null pointer derefrence.
X
Rick Perry -
X	Cleaned up a problem with modchk() in sc.c.
X
Gregory Bond -
X	Added code for multi argument versions of @min and @max.
X
Tad Mannes -
X	Added code to save/restore hidden rows and columns when the
X	data base is saved or restored.
X
Marius Olafsson -
X	INTERNATIONAL changes.  Allows full 8 bit characters (if
X	curses supports them.)
X
Kurt Horton -
X	Added support for @pv, @fv and @pmt financial functins.
X	Tested lots of different systems, linting.
X
John Campbell -
X	Support for VMS.  See VMS_NOTES.
X
Peter King -
X	 User selection of row or column order for recalculation.
X		Also affects order of traversing regions in /f and /r
X	 User setting of automatic or manual recalculation.
X	 User setting of number of times to try recalculation.
X	 + and - commands when in non-numeric mode to do 
X		increment and decrement operations.
X	@index, @stindex, @atan2, @lookup  functions.
X	Save/restore options.
X	Support for TeX, LaTeX, and better support for tbl in "T" cmd.
X	Provision of a copyent function to copy entries (same code repeated
X		in several locations)
X	Forwrow, backrow, forwcol, backcol functions to replace
X		repeated code
X	Correct interpretation of ESCAPE or ^G as an abort when in a 
X		two character command such as 'ar' or 'ac'
X	Cleanup in eval() - catches non-trap function errors.
X
Bob Bond - 
X       Added search options to "g".
X       Added supression of hidden columns to "W"
X       Added the mod operator "%"
X       New help functions.
X       Constant prescale "$"
X       Added string matching to @lookup.
X       Some more bug fixes.
X       Testing, integration, documentation.
X
Alan Silverstein-
X	Greatly revised the manual entry.
X	Added menus for ^E command and row/column commands, which
X	involved a bunch of code cleanup.
X
X	Changed top row display to clearly indicate string labels
X	versus number parts, and to distinguish string functions from
X	constant labels.
X
X	When the character cursor is on a cell (not topline), ^H
X	(backspace) is like ^B (move back one cell), rather than being
X	ignored.
X
X	When the character cursor is on a cell (not topline), ^I (tab)
X	is like ^F (move forward one cell), rather than being ignored.
X	^R is no longer identical with ^L.  Now ^R highlights all cells
X	which should be entered by a user because they contain constant
X	numeric values (not the result of a numeric expression).
X
X	Added a ^X command, similar to ^R, which highlights cells which
X	have expressions.  It also displays the expressions in the
X	highlighted cells as left-justified strings, instead of the
X	label and/or value of the cell.
X
X	Added indirection functions (@nval() and @sval()) for simple
X	table lookups.  Given a column name and row number, they return
X	the numeric or string value of the selected cell.
X
X	Added external functions (@ext()) for non-trivial
X	computations.  Given a command name and argument, it calls the
X	command and reads back one output line.
X
X	Added a ^T,e command to toggle enabling of external functions.
X
X	Changed ^T,t to only control the top line display, and added
X	^T,c to control current cell highlighting.  (Separated the
X	functions.)
X
X	"!" (shell escape) gives a vi-style warning if there were any
X	changes since the last write.  (No change to manual entry.)
X
X	Fixed some startup, error, and prompt messages to be cleaner
X	and/or more consistent.  (No changes to manual entry.)
X
X	Fixed a bug:  If @substr() upper bound (third parameter) is
X	past the end of the string operand, return the substring
X	through the end of the string, rather than returning a null
X	string.
X
X	Fixed a bug:  Reset SIGINT to default after forking before
X	calling shell escape program and before starting pipeline (for
X	commands which support this).  Didn't reset SIGINT before
X	calling crypt and external functions because in both cases it
X	should be irrelevant.  (No change to manual entry.)
X
CHANGES BETWEEN 6.1 and 6.2:
X
X
Chris Cole-
X	Compatibility with Lotus 1-2-3
X		a) @hlookup(expr,range,expr)
X		b) @vlookup(expr,range,expr)
X		c) @round(expr,expr)
X		d) @if(expr,expr,expr)
X		e) @abs(expr)
SHAR_EOF
chmod 0666 changes ||
echo 'restore of changes failed'
Wc_c="`wc -c < 'changes'`"
test 5088 -eq "$Wc_c" ||
	echo 'changes: original size 5088, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cmds.c ==============
if test -f 'cmds.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cmds.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cmds.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cmds.c' &&
/*	SC	A Spreadsheet Calculator
X *		Command routines
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 *
X *		$Revision: 6.8 $
X */
X
#include <curses.h>
#if defined(BSD42) || defined(BSD43)
#include <sys/file.h>
#else
#include <fcntl.h>
#endif
#include "sc.h"
#include <signal.h>
#include <errno.h>
X
#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif
X
#ifdef SYSV3
extern void exit();
#else
extern int exit();
#endif
X
extern	int	errno;
X
#define DEFCOLDELIM ':'
X
void
duprow()
{
X    if (currow >= maxrows - 1 || maxrow >= maxrows - 1) {
X	if (!growtbl(GROWROW, 0, 0))
X		return;
X    }
X    modflg++;
X    currow++;
X    openrow (currow);
X    for (curcol = 0; curcol <= maxcol; curcol++) {
X	register struct ent *p = *ATBL(tbl, currow - 1, curcol);
X	if (p) {
X	    register struct ent *n;
X	    n = lookat (currow, curcol);
X	    (void)copyent ( n, p, 1, 0);
X	}
X    }
X    for (curcol = 0; curcol <= maxcol; curcol++) {
X	register struct ent *p = *ATBL(tbl, currow, curcol);
X	if (p && (p -> flags & is_valid) && !p -> expr)
X	    break;
X    }
X    if (curcol > maxcol)
X	curcol = 0;
}
X
void
dupcol() 
{
X    if (curcol >= maxcols - 1 || maxcol >= maxcols - 1) {
X	if (!growtbl(GROWCOL, 0, 0))
X		return;
X    }
X    modflg++;
X    curcol++;
X    opencol (curcol, 1);
X    for (currow = 0; currow <= maxrow; currow++) {
X	register struct ent *p = *ATBL(tbl, currow, curcol - 1);
X	if (p) {
X	    register struct ent *n;
X	    n = lookat (currow, curcol);
X	    copyent ( n, p, 0, 1);
X	}
X    }
X    for (currow = 0; currow <= maxrow; currow++) {
X	register struct ent *p = *ATBL(tbl, currow, curcol);
X	if (p && (p -> flags & is_valid) && !p -> expr)
X	    break;
X    }
X    if (currow > maxrow)
X	currow = 0;
}
X
void
insertrow(arg)
register int arg;
{
X    while (--arg>=0) openrow (currow);
}
X
void
deleterow(arg)
register int arg;
{
X    flush_saved();
X    erase_area(currow, 0, currow + arg - 1, maxcol);
X    currow += arg;
X    while (--arg>=0) closerow (--currow);
X    sync_refs();
}
X
void
rowvalueize(arg)
register int arg;
{
X    valueize_area(currow, 0, currow + arg - 1, maxcol);
}
X
void
colvalueize(arg)
register int arg;
{
X    valueize_area(0, curcol, maxrow, curcol + arg - 1);
}
X
void
erase_area(sr, sc, er, ec)
int sr, sc, er, ec;
{
X    register int r, c;
X    register struct ent **pp;
X
X    if (sr > er) {
X	r = sr; sr = er; er= r;	
X    }
X
X    if (sc > ec) {
X	c = sc; sc = ec; ec= c;	
X    }
X
X    if (sr < 0)
X	sr = 0; 
X    if (sc < 0)
X	sc = 0;
X    checkbounds(&er, &ec);
X
X    for (r = sr; r <= er; r++) {
X	for (c = sc; c <= ec; c++) {
X	    pp = ATBL(tbl, r, c);
X	    if (*pp) {
X		free_ent(*pp);
X		*pp = (struct ent *)0;
X	    }
X	}
X    }
}
X
void
valueize_area(sr, sc, er, ec)
int sr, sc, er, ec;
{
X    register int r, c;
X    register struct ent *p;
X
X    if (sr > er) {
X	r = sr; sr = er; er= r;	
X    }
X
X    if (sc > ec) {
X	c = sc; sc = ec; ec= c;	
X    }
X
X    if (sr < 0)
X	sr = 0; 
X    if (sc < 0)
X	sc = 0;
X    checkbounds(&er, &ec);
X
X    for (r = sr; r <= er; r++) {
X	for (c = sc; c <= ec; c++) {
X	    p = *ATBL(tbl, r, c);
X	    if (p && p->expr) {
X		efree(p, p->expr);
X		p->expr = (struct enode *)0;
X		p->flags &= ~is_strexpr;
X	    }
X	}
X    }
X
}
X
void
pullcells(to_insert)
int to_insert;
{
X    register struct ent *p, *n;
X    register int deltar, deltac;
X    int minrow, mincol;
X    int mxrow, mxcol;
X    int numrows, numcols;
X
X    if (! to_fix)
X    {
X	error ("No data to pull");
X	return;
X    }
X
X    minrow = maxrows; 
X    mincol = maxcols;
X    mxrow = 0;
X    mxcol = 0;
X
X    for (p = to_fix; p; p = p->next) {
X	if (p->row < minrow)
X	    minrow = p->row;
X	if (p->row > mxrow)
X	    mxrow = p->row;
X	if (p->col < mincol)
X	    mincol = p->col;
X	if (p->col > mxcol)
X	    mxcol = p->col;
X    }
X
X    numrows = mxrow - minrow + 1;
X    numcols = mxcol - mincol + 1;
X    deltar = currow - minrow;
X    deltac = curcol - mincol;
X
X    if (to_insert == 'r') {
X	insertrow(numrows);
X	deltac = 0;
X    } else if (to_insert == 'c') {
X	opencol(curcol, numcols);
X	deltar = 0;
X    }
X
X    FullUpdate++;
X    modflg++;
X
X    for (p = to_fix; p; p = p->next) {
X	n = lookat (p->row + deltar, p->col + deltac);
X	(void) clearent(n);
X	copyent( n, p, deltar, deltac);
X	n -> flags = p -> flags & ~is_deleted;
X    }
}
X
void
colshow_op()
{
X    register int i,j;
X    for (i=0; i<maxcols; i++)
X	if (col_hidden[i]) 
X	    break;
X    for(j=i; j<maxcols; j++)
X	if (!col_hidden[j])
X	    break;
X    j--;
X    if (i>=maxcols)
X	error ("No hidden columns to show");
X    else {
X	(void) sprintf(line,"show %s:", coltoa(i));
X	(void) sprintf(line + strlen(line),"%s",coltoa(j));
X	linelim = strlen (line);
X    }
}
X
void
rowshow_op()
{
X    register int i,j;
X    for (i=0; i<maxrows; i++)
X	if (row_hidden[i]) 
X	    break;
X    for(j=i; j<maxrows; j++)
X	if (!row_hidden[j]) {
X	    break;
X	}
X    j--;
X
X    if (i>=maxrows)
X	error ("No hidden rows to show");
X    else {
X	(void) sprintf(line,"show %d:%d", i, j);
X        linelim = strlen (line);
X    }
}
X
/*
X * Given a row/column command letter, emit a small menu, then read a qualifier
X * character for a row/column command and convert it to 'r' (row), 'c'
X * (column), or 0 (unknown).  If ch is 'p', an extra qualifier 'm' is allowed.
X */
X
int
get_rcqual (ch)
X    int ch;
{
X    error ("%sow/column:  r: row  c: column%s",
X
X	    (ch == 'i') ? "Insert r" :
X	    (ch == 'a') ? "Append r" :
X	    (ch == 'd') ? "Delete r" :
X	    (ch == 'p') ? "Pull r" :
X	    (ch == 'v') ? "Values r" :
X	    (ch == 'z') ? "Zap r" :
X	    (ch == 's') ? "Show r" : "R",
X
X	    (ch == 'p') ? "  m: merge" : "");
X
X    (void) refresh();
X
X    switch (nmgetch())
X    {
X	case 'r':
X	case 'l':
X	case 'h':
X	case ctl('f'):
X	case ctl('b'):	return ('r');
X
X	case 'c':
X	case 'j':
X	case 'k':
X	case ctl('p'):
X	case ctl('n'):	return ('c');
X
X	case 'm':	return ((ch == 'p') ? 'm' : 0);
X
X	case ESC:
X	case ctl('g'):	return (ESC);
X
X	default:	return (0);
X    }
X    /*NOTREACHED*/
}
X
void
openrow (rs)
int	rs;
{
X    register	r, c;
X    struct ent	**tmprow, **pp;
X
X    if (rs > maxrow) maxrow = rs;
X    if (maxrow >= maxrows - 1 || rs > maxrows - 1) {
X	if (!growtbl(GROWROW, rs, 0))
X		return;
X    }
X	/*
X	 * save the last active row+1, shift the rows downward, put the last
X	 * row in place of the first
X	 */
X    tmprow = tbl[++maxrow];
X    for (r = maxrow; r > rs; r--) {
X	row_hidden[r] = row_hidden[r-1];
X	tbl[r] = tbl[r-1];
X	pp = ATBL(tbl, r, 0);
X	for (c = 0; c < maxcols; c++, pp++)
X		if (*pp)
X			(*pp)->row = r;
X    }
X    tbl[r] = tmprow;	/* the last row was never used.... */
X    FullUpdate++;
X    modflg++;
}
X
void
closerow (r)
register r;
{
X    register struct ent **pp;
X    register c;
X    struct ent	**tmprow;
X
X    if (r > maxrow) return;
X
X    /* save the row and empty it out */
X    tmprow = tbl[r];
X    pp = ATBL(tbl, r, 0);
X    for (c=maxcol+1; --c>=0; pp++) {
X	if (*pp)
X	{	free_ent(*pp);
X		*pp = (struct ent *)0;
X	}
X    }
X
X    /* move the rows, put the deleted row at the end */
X    for (; r < maxrows - 1; r++) {
X	row_hidden[r] = row_hidden[r+1];
X	tbl[r] = tbl[r+1];
X	pp = ATBL(tbl, r, 0);
X	for (c = 0; c < maxcols; c++, pp++)
X		if (*pp)
X			(*pp)->row = r;
X    }
X    tbl[r] = tmprow;
X
X    maxrow--;
X    FullUpdate++;
X    modflg++;
}
X
void
opencol (cs, numcol)
int	cs;
int	numcol;
{
X    register r;
X    register struct ent **pp;
X    register c;
X    register lim = maxcol-cs+1;
X    int i;
X
X    if (cs > maxcol)
X	maxcol = cs;
X    maxcol += numcol;
X
X    if ((maxcol >= maxcols - 1) && !growtbl(GROWCOL, 0, maxcol))
X		return;
X
X    for (i = maxcol; i > cs; i--) {
X	fwidth[i] = fwidth[i-numcol];
X	precision[i] = precision[i-numcol];
X	col_hidden[i] = col_hidden[i-numcol];
X    }
X    for (c = cs; c - cs < numcol; c++)
X    {	fwidth[c] = DEFWIDTH;
X	precision[c] =  DEFPREC;
X    }
X	
X    for (r=0; r<=maxrow; r++) {
X	pp = ATBL(tbl, r, maxcol);
X	for (c=lim; --c>=0; pp--)
X	    if (pp[0] = pp[-numcol])
X		pp[0]->col += numcol;
X
X	pp = ATBL(tbl, r, cs);
X	for (c = cs; c - cs < numcol; c++, pp++)
X		*pp = (struct ent *)0;
X    }
X    FullUpdate++;
X    modflg++;
}
X
void
closecol (cs, numcol)
int cs;
int	numcol;
{
X    register r;
X    register struct ent **pp;
X    register struct ent *q;
X    register c;
X    register lim = maxcol-cs;
X    int i;
X    char buf[50];
X
X    if (lim - numcol < -1)
X    {	sprintf(buf, "Can't delete %d column%s %d columns left", numcol,
X			(numcol > 1 ? "s," : ","), lim+1);
X	error(buf);
X	return;
X    }
X    flush_saved();
X    erase_area(0, curcol, maxrow, curcol + numcol - 1);
X    sync_refs();
X
X    /* clear then copy the block left */
X    lim = maxcols - numcol - 1;
X    for (r=0; r<=maxrow; r++) {
X	for (c = cs; c - cs < numcol; c++)
X		if (q = *ATBL(tbl, r, c))
X			free_ent(q);
X
X	pp = ATBL(tbl, r, cs);
X	for (c=cs; c <= lim; c++, pp++)
X	{   if (c > lim)
X		*pp = (struct ent *)0;
X	    else
X	    if (pp[0] = pp[numcol])
X		pp[0]->col -= numcol;
X	}
X
X	c = numcol;
X	for (; --c >= 0; pp++)		
X		*pp = (struct ent *)0;
X    }
X
X    for (i = cs; i < maxcols - numcol - 1; i++) {
X	fwidth[i] = fwidth[i+numcol];
X	precision[i] = precision[i+numcol];
X	col_hidden[i] = col_hidden[i+numcol];
X    }
X    for (; i < maxcols - 1; i++) {
X	fwidth[i] = DEFWIDTH;
X	precision[i] = DEFPREC;
X	col_hidden[i] = 0;
X    }
X
X    maxcol -= numcol;
X    FullUpdate++;
X    modflg++;
}
X
void
doend(rowinc, colinc)
int rowinc, colinc;
{
X    register struct ent *p;
X    int r, c;
X
X    if (VALID_CELL(p, currow, curcol)) {
X	r = currow + rowinc;
X	c = curcol + colinc;
X	if (r >= 0 && r < maxrows && 
X	    c >= 0 && c < maxcols &&
X	    !VALID_CELL(p, r, c)) {
X		currow = r;
X		curcol = c;
X	}
X    }
X
X    if (!VALID_CELL(p, currow, curcol)) {
X        switch (rowinc) {
X        case -1:
X	    while (!VALID_CELL(p, currow, curcol) && currow > 0)
X		currow--;
X	    break;
X        case  1:
X	    while (!VALID_CELL(p, currow, curcol) && currow < maxrows-1)
X		currow++;
X	    break;
X        case  0:
X            switch (colinc) {
X 	    case -1:
X	        while (!VALID_CELL(p, currow, curcol) && curcol > 0)
X		    curcol--;
X	        break;
X 	    case  1:
X	        while (!VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
X		    curcol++;
X	        break;
X	    }
X            break;
X        }
X
X	error ("");	/* clear line */
X	return;
X    }
X
X    switch (rowinc) {
X    case -1:
X	while (VALID_CELL(p, currow, curcol) && currow > 0)
X	    currow--;
X	break;
X    case  1:
X	while (VALID_CELL(p, currow, curcol) && currow < maxrows-1)
X	    currow++;
X	break;
X    case  0:
X	switch (colinc) {
X	case -1:
X	    while (VALID_CELL(p, currow, curcol) && curcol > 0)
X		curcol--;
X	    break;
X	case  1:
X	    while (VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
X		curcol++;
X	    break;
X	}
X	break;
X    }
X    if (!VALID_CELL(p, currow, curcol)) {
X        currow -= rowinc;
X        curcol -= colinc;
X    }
}
X
void
doformat(c1,c2,w,p)
int c1,c2,w,p;
{
X    register int i;
X
X    if (w > COLS - RESCOL - 2) {
X	error("Format too large - Maximum = %d", COLS - RESCOL - 2);
X	w = COLS-RESCOL-2;
X    }
X
X    if (p > w) {
X	error("Precision too large");
X	p = w;
X    }
X
X    for(i = c1; i<=c2; i++)
X	fwidth[i] = w, precision[i] = p;
X
X    FullUpdate++;
X    modflg++;
}
X
void
print_options(f)
FILE *f;
{
X    if(
X       autocalc &&
X       propagation == 10 &&
X       calc_order == BYROWS &&
X       !numeric &&
X       prescale == 1.0 &&
X       !extfunc &&
X       showcell &&
X       showtop &&
X       tbl_style == 0
X      )
X		return;		/* No reason to do this */
X
X    (void) fprintf(f, "set");
X    if(!autocalc) 
X	(void) fprintf(f," !autocalc");
X    if(propagation != 10)
X	(void) fprintf(f, " iterations = %d", propagation);
X    if(calc_order != BYROWS )
X	(void) fprintf(f, " bycols");
X    if (numeric)
X	(void) fprintf(f, " numeric");
X    if (prescale != 1.0)
X	(void) fprintf(f, " prescale");
X    if (extfunc)
X	(void) fprintf(f, " extfun");
X    if (!showcell)
X	(void) fprintf(f, " !cellcur");
X    if (!showtop)
X	(void) fprintf(f, " !toprow");
X    if (tbl_style)
X	(void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" :
X					tbl_style == LATEX ? "latex" :
X					tbl_style == TEX ? "tex" : "0" );
X    (void) fprintf(f, "\n");
}
X
void
printfile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
X    FILE *f;
X    char pline[FBUFLEN];
X    int plinelim;
X    int pid;
X    int fieldlen, nextcol;
X    register row, col;
X    register struct ent **pp;
X
X    if ((strcmp(fname, curfile) == 0) &&
X	!yn_ask("Confirm that you want to destroy the data base: (y,n)"))
X	return;
X
X    if ((f = openout(fname, &pid)) == (FILE *)0)
X    {	error ("Can't create file \"%s\"", fname);
X	return;
X    }
X    for (row=r0;row<=rn; row++) {
X	register c = 0;
X
X	if (row_hidden[row])
X	    continue;
X
X	pline[plinelim=0] = '\0';
X	for (pp = ATBL(tbl, row, col=c0); col<=cn;
X	        pp += nextcol-col, col = nextcol, c += fieldlen) {
X
X	    nextcol = col+1;
X	    if (col_hidden[col]) {
X		fieldlen = 0;
X		continue;
X	    }
X
X	    fieldlen = fwidth[col];
X	    if (*pp) {
X		char *s;
X
X		while (plinelim<c) pline[plinelim++] = ' ';
X		plinelim = c;
X		if ((*pp)->flags&is_valid) {
X		    (void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
X		                                precision[col], (*pp)->v);
X		    plinelim += strlen (pline+plinelim);
X		}
X		if (s = (*pp)->label) {
X		    int slen;
X		    char *start, *last;
X		    register char *fp;
X		    struct ent *nc;
X
X		    /* Figure out if the label slops over to a blank field */
X		    slen = strlen(s);
X		    while (slen > fieldlen && nextcol <= cn &&
X			    !((nc = lookat(row,nextcol))->flags & is_valid) &&
X			    !(nc->label)) {
X			
X	                if (!col_hidden[nextcol])
X		 	    fieldlen += fwidth[nextcol];
X
X			nextcol++;
X		    }
X		    if (slen > fieldlen)
X			slen = fieldlen;
X		    
X		    /* Now justify and print */
X		    start = (*pp)->flags & is_leftflush ? pline + c
X					: pline + c + fieldlen - slen;
X		    last = pline + c + fieldlen;
X		    fp = plinelim < c ? pline + plinelim : pline + c;
X		    while (fp < start)
X			*fp++ = ' ';
X		    while (slen--)
X			*fp++ = *s++;
X		    if (!((*pp)->flags & is_valid) || fieldlen != fwidth[col])
X			while(fp < last)
X			    *fp++ = ' ';
X		    if (plinelim < fp - pline)
X			plinelim = fp - pline;
X		}
X	    }
X	}
X	pline[plinelim++] = '\n';
X	pline[plinelim] = '\0';
X	(void) fputs (pline, f);
X    }
X
X    closeout(f, pid);
}
X
void
tblprintfile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
X    FILE *f;
X    int pid;
X    register row, col;
X    register struct ent **pp;
X    char coldelim = DEFCOLDELIM;
X
X    if ((strcmp(fname, curfile) == 0) &&
X	!yn_ask("Confirm that you want to destroy the data base: (y,n)"))
X	    return;
X
X    if ((f = openout(fname, &pid)) == (FILE *)0)
X    {	error ("Can't create file \"%s\"", fname);
X	return;
X    }
X
X    if ( tbl_style == TBL ) {
X	fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname);
X	fprintf(f,"tab(%c);\n",coldelim);
X	for (col=c0;col<=cn; col++) fprintf(f," n");
X	fprintf(f, ".\n");
X	}
X    else if ( tbl_style == LATEX ) {
X	fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname);
X	for (col=c0;col<=cn; col++) fprintf(f,"c");
X	fprintf(f, "}\n");
X	coldelim = '&';
X	}
X    else if ( tbl_style == TEX ) {
X	fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n",
X		progname, cn-c0+1);
X	coldelim = '&';
X	}
X
X    for (row=r0; row<=rn; row++) {
X	if ( tbl_style == TEX )
X	    (void) fprintf (f, "\\+");
X	
X	for (pp = ATBL(tbl, row, col=c0); col<=cn; col++, pp++) {
X	    if (*pp) {
X		char *s;
X		if ((*pp)->flags&is_valid) {
X		    (void) fprintf (f,"%.*f",precision[col],
X				(*pp)->v);
X		}
X		if (s = (*pp)->label) {
X	            (void) fprintf (f,"%s",s);
X		}
X	    }
X	    if ( col < cn )
X		(void) fprintf(f,"%c",coldelim);
X	}
X	if ( tbl_style == LATEX ) {
X	    if ( row < rn ) (void) fprintf (f, "\\\\");
X	    }
X	else if ( tbl_style == TEX ) {
X	    (void) fprintf (f, "\\cr");
X	    }
X	(void) fprintf (f,"\n");
X    }
X
X    if ( tbl_style == TBL )
X    (void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname);
X    else if ( tbl_style == LATEX )
X    (void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname);
X    else if ( tbl_style == TEX )
X    (void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname);
X
X    closeout(f, pid);
}
X
struct enode *
copye (e, Rdelta, Cdelta)
register struct enode *e;
int Rdelta, Cdelta;
{
X    register struct enode *ret;
X
X    if (e == (struct enode *)0) {
X        ret = (struct enode *)0;
X    } else if (e->op & REDUCE) {
X	int newrow, newcol;
X	ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
X	ret->op = e->op;
X	newrow=e->e.r.left.vf & FIX_ROW ? e->e.r.left.vp->row :
X					  e->e.r.left.vp->row+Rdelta;
X	newcol=e->e.r.left.vf & FIX_COL ? e->e.r.left.vp->col :
X					  e->e.r.left.vp->col+Cdelta;
X	ret->e.r.left.vp = lookat (newrow, newcol);
X	ret->e.r.left.vf = e->e.r.left.vf;
X	newrow=e->e.r.right.vf & FIX_ROW ? e->e.r.right.vp->row :
X					   e->e.r.right.vp->row+Rdelta;
X	newcol=e->e.r.right.vf & FIX_COL ? e->e.r.right.vp->col :
X					   e->e.r.right.vp->col+Cdelta;
X	ret->e.r.right.vp = lookat (newrow, newcol);
X	ret->e.r.right.vf = e->e.r.right.vf;
X    } else {
X	ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
X	ret->op = e->op;
X	switch (ret->op) {
X	case 'v':
X		{
X		    int newrow, newcol;
X		    newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
X						 e->e.v.vp->row+Rdelta;
X		    newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
X						 e->e.v.vp->col+Cdelta;
X		    ret->e.v.vp = lookat (newrow, newcol);
X		    ret->e.v.vf = e->e.v.vf;
X		    break;
X		}
X	case 'k':
X		ret->e.k = e->e.k;
X		break;
X	case 'f':
X		ret->e.o.right = copye (e->e.o.right,0,0);
X		ret->e.o.left = (struct enode *)0;
X 		break;
X	case '$':
X		ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
X		(void) strcpy(ret->e.s, e->e.s);
X		break;
X	default:
X		ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
X		ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
X		break;
X	}
X    }
X    return ret;
}
X
/*
X * sync_refs and syncref are used to remove references to
X * deleted struct ents.  Note that the deleted structure must still
X * be hanging around before the call, but not referenced by an entry
X * in tbl.  Thus the free_ent, fix_ent calls in sc.c
X */
void
sync_refs ()
{
X    register i,j;
X    register struct ent *p;
X    sync_ranges();
X    for (i=0; i<=maxrow; i++)
X	for (j=0; j<=maxcol; j++)
X	    if ((p = *ATBL(tbl, i, j)) && p->expr)
X		syncref(p->expr);
}
X
void
syncref(e)
register struct enode *e;
{
X    if (e == (struct enode *)0)
X	return;
X    else if (e->op & REDUCE) {
X 	e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col);
X 	e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col);
X    } else {
X	switch (e->op) {
X	case 'v':
X		e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
X		break;
X	case 'k':
X		break;
X	case '$':
X		break;
X	default:
X		syncref(e->e.o.right);
X		syncref(e->e.o.left);
X		break;
X	}
X    }
}
X
void
hiderow(arg)
int arg;
{
X    register int r1;
X    register int r2;
X
X    r1 = currow;
X    r2 = r1 + arg - 1;
X    if (r1 < 0 || r1 > r2) {
X	error ("Invalid range");
X	return;
X    }
X    if (r2 >= maxrows-1)
X    {	if (!growtbl(GROWROW, arg+1, 0))
X	{	error("You can't hide the last row");
X		return;
X	}
X    }
X    FullUpdate++;
X    modflg++;
X    while (r1 <= r2)
X	row_hidden[r1++] = 1;
}
X
void
hidecol(arg)
int arg;
{
X    register int c1;
X    register int c2;
X
X    c1 = curcol;
X    c2 = c1 + arg - 1;
X    if (c1 < 0 || c1 > c2) {
X	error ("Invalid range");
X	return;
X    }
X    if (c2 >= maxcols-1)
X    {	if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
X	{	error("You can't hide the last col");
X		return;
X	}
X    }
X    FullUpdate++;
X    modflg++;
X    while (c1 <= c2)
X	col_hidden[c1++] = 1;
}
X
void
showrow(r1, r2)
int r1, r2;
{
X    if (r1 < 0 || r1 > r2) {
X	error ("Invalid range");
X	return;
X    }
X    if (r2 > maxrows-1) {
X	r2 = maxrows-1;
X    }
X    FullUpdate++;
X    modflg++;
X    while (r1 <= r2)
X	row_hidden[r1++] = 0;
}
X
void
showcol(c1, c2)
int c1, c2;
{
X    if (c1 < 0 || c1 > c2) {
X	error ("Invalid range");
X	return;
X    }
X    if (c2 > maxcols-1) {
X	c2 = maxcols-1;
X    }
X    FullUpdate++;
X    modflg++;
X    while (c1 <= c2)
X	col_hidden[c1++] = 0;
}
X
/* Open the output file, setting up a pipe if needed */
X
FILE *
openout(fname, rpid)
char *fname;
int *rpid;
{
X    int pipefd[2];
X    int pid;
X    FILE *f;
X    char *efname;
X
X    while (*fname && (*fname == ' '))  /* Skip leading blanks */
X	fname++;
X
X    if (*fname != '|') {		/* Open file if not pipe */
X	*rpid = 0;
X	
X	efname = findhome(fname);
#ifdef DOBACKUPS
X	if (!backup_file(efname) &&
X	    (yn_ask("Could not create backup copy, Save anyhow?: (y,n)") != 1))
X		return(0);
#endif
X	return(fopen(efname, "w"));
X    }
X
X    fname++;				/* Skip | */
X    if ( pipe (pipefd) < 0) {
X	error("Can't make pipe to child");
X	*rpid = 0;
X	return(0);
X    }
X
X    deraw();
#ifdef VMS
X    fprintf(stderr, "No son tasks available yet under VMS--sorry\n");
#else /* VMS */
X
X    if ((pid=fork()) == 0)			  /* if child  */
X    {
X	(void) close (0);			  /* close stdin */
X	(void) close (pipefd[1]);
X	(void) dup (pipefd[0]);		  /* connect to pipe input */
X	(void) signal (SIGINT, SIG_DFL);	  /* reset */
X	(void) execl ("/bin/sh", "sh", "-c", fname, 0);
X	exit (-127);
X    }
X    else				  /* else parent */
X    {
X	*rpid = pid;
X	if ((f = fdopen (pipefd[1], "w")) == (FILE *)0)
X	{
X	    (void) kill (pid, -9);
X	    error ("Can't fdopen output");
X	    (void) close (pipefd[1]);
X	    *rpid = 0;
X	    return(0);
X	}
X    }
#endif /* VMS */
X    return(f);
}
X
void
closeout(f, pid)
FILE *f;
int pid;
{
X    int temp;
X
X    (void) fclose (f);
X    if (pid) {
X         while (pid != wait(&temp)) /**/;
X	 (void) printf("Press RETURN to continue ");
X	 (void) fflush(stdout);
X	 (void) nmgetch();
X	 goraw();
X    }
}
X
void
copyent(n,p,dr,dc)
X	    register struct ent *n, *p;
X	    int dr, dc;
{
X    if(!n||!p){error("internal error");return;}
X    n -> v = p -> v;
X    n -> flags = p -> flags;
X    n -> expr = copye (p -> expr, dr, dc);
X    n -> label = (char *)0;
X    if (p -> label) {
X	n -> label = (char *)
X		xmalloc  ((unsigned) (strlen (p -> label) + 1));
X	(void) strcpy (n -> label, p -> label);
X    }
}
X
void
write_fd (f, r0, c0, rn, cn)
register FILE *f;
int r0, c0, rn, cn;
{
X    register struct ent **pp;
X    register r, c;
X
X    (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
X    (void) fprintf (f, "Calculator.\n");
X    (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
X    print_options(f);
X    for (c=0; c<maxcols; c++)
X	if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
X	    (void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
X    for (c=c0; c<cn; c++) {
X        if (col_hidden[c]) {
X            (void) fprintf(f, "hide %s\n", coltoa(c));
X        }
X    }
X    for (r=r0; r<=rn; r++) {
X	if (row_hidden[r]) {
X	    (void) fprintf(f, "hide %d\n", r);
X	}
X    }
X
X    write_range(f);
X
X    if (mdir) 
X	    (void) fprintf(f, "mdir \"%s\"\n", mdir);
X    for (r=r0; r<=rn; r++) {
X	pp = ATBL(tbl, r, c0);
X	for (c=c0; c<=cn; c++, pp++)
X	    if (*pp) {
X		if ((*pp)->label) {
X		    edits(r,c);
X		    (void) fprintf(f, "%s\n",line);
X		}
X		if ((*pp)->flags&is_valid) {
X		    editv (r, c);
X		    (void) fprintf (f, "%s\n",line);
X		}
X	    }
X    }
}
X
int
writefile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
X    register FILE *f;
X    char save[PATHLEN];
X    int pid;
X
#ifndef VMS
X    if (Crypt) {
X	return (cwritefile(fname, r0, c0, rn, cn));
X    }
#endif /* VMS */
X
X    if (*fname == '\0') fname = curfile;
X
X    (void) strcpy(save,fname);
X
X    if ((f= openout(fname, &pid)) == (FILE *)0)
X    {	error ("Can't create file \"%s\"", fname);
X	return (-1);
X    }
X
X    write_fd(f, r0, c0, rn, cn);
X    
X    closeout(f, pid);
X
X    if (!pid) {
X        (void) strcpy(curfile, save);
X        modflg = 0;
X        error("File \"%s\" written.",curfile);
X    }
X
X    return (0);
}
X
void
readfile (fname,eraseflg)
char *fname;
int eraseflg;
{
X    register FILE *f;
X    char save[PATHLEN];
X
X    if (*fname == '*' && mdir) { 
X       (void) strcpy(save, mdir);
X       *fname = '/';
X       (void) strcat(save, fname);
X    } else {
X        if (*fname == '\0')
X	    fname = curfile;
X        (void) strcpy(save,fname);
X    }
X
#ifndef VMS
X    if (Crypt)  {
X	creadfile(save, eraseflg);
X	return;
X    }
#endif /* VMS */
X
X    if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
X
X    if ((f = fopen(findhome(save), "r")) == (FILE *)0)
X    {	error ("Can't read file \"%s\"", save);
X	return;
X    }
X
X    if (eraseflg) erasedb ();
X
X    loading++;
X    while (fgets(line,sizeof line,f)) {
X	linelim = 0;
X	if (line[0] != '#') (void) yyparse ();
X    }
X    --loading;
X    (void) fclose (f);
X    linelim = -1;
X    modflg++;
X    if (eraseflg) {
X	(void) strcpy(curfile,save);
X	modflg = 0;
X    }
X    EvalAll();
}
X
void
erasedb ()
{
X    register r, c;
X    for (c = 0; c<=maxcol; c++) {
X	fwidth[c] = DEFWIDTH;
X	precision[c] = DEFPREC;
X    }
X
X    for (r = 0; r<=maxrow; r++) {
X	register struct ent **pp = ATBL(tbl, r, 0);
X	for (c=0; c++<=maxcol; pp++)
X	    if (*pp) {
X		if ((*pp)->expr) efree (*pp, (*pp) -> expr);
X		if ((*pp)->label) xfree ((char *)((*pp) -> label));
X		xfree ((char *)(*pp));
X		*pp = (struct ent *)0;
X	    }
X    }
X    maxrow = 0;
X    maxcol = 0;
X    clean_range();
X    FullUpdate++;
}
X
void
backcol(arg)
X	int arg;
{
X    while (--arg>=0) {
X	if (curcol)
X	    curcol--;
X	else
X	    {error ("At column A"); break;}
X	while(col_hidden[curcol] && curcol)
X	    curcol--;
X    }
}
X
void
forwcol(arg)
X	int arg;
{
X    while (--arg>=0) {
X	if (curcol < maxcols - 1)
X	    curcol++;
X	else
X	if (!growtbl(GROWCOL, 0, arg))	/* get as much as needed */
X		break;
X	while(col_hidden[curcol]&&(curcol<maxcols-1))
X	    curcol++;
X    }
}
X
void
forwrow(arg)
X	int arg;
{
X    while (--arg>=0) {
X	if (currow < maxrows - 1)
X	    currow++;
X	else
X	if (!growtbl(GROWROW, arg, 0))	/* get as much as needed */
X		break;
X	while (row_hidden[currow]&&(currow<maxrows-1))
X	    currow++;
X    }
}
X
void
backrow(arg)
X	int arg;
{
X    while (--arg>=0) {
X	if (currow)
X	    currow--;
X	else
X	    {error ("At row zero"); break;}
X	while (row_hidden[currow] && currow)
X	    currow--;
X    }
}
X
X
/*
X * Show a cell's label string or expression value.  May overwrite value if
X * there is one already displayed in the cell.  Created from old code in
X * update(), copied with minimal changes.
X */
X
void
showstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c)
X    char *string;	/* to display */
X    int leftflush;	/* or rightflush */
X    int hasvalue;	/* is there a numeric value? */
X    int row, col;	/* spreadsheet location */
X    int *nextcolp;	/* value returned through it */
X    int mxcol;		/* last column displayed? */
X    int *fieldlenp;	/* value returned through it */
X    int r, c;		/* screen row and column */
{
X    register int nextcol  = *nextcolp;
X    register int fieldlen = *fieldlenp;
X
X    char field[FBUFLEN];
X    int  slen;
X    char *start, *last;
X    register char *fp;
X    struct ent *nc;
X
X    /* This figures out if the label is allowed to
X       slop over into the next blank field */
X
X    slen = strlen (string);
X    while ((slen > fieldlen) && (nextcol <= mxcol) &&
X	   !((nc = lookat (row, nextcol)) -> flags & is_valid) &&
X	   !(nc->label)) {
X
X	if (! col_hidden [nextcol])
X	    fieldlen += fwidth [nextcol];
X
X	nextcol++;
X    }
X    if (slen > fieldlen)
X	slen = fieldlen;
X
X    /* Now justify and print */
X    start = leftflush ? field : field + fieldlen - slen;
X    last = field+fieldlen;
X    fp = field;
X    while (fp < start)
X	*fp++ = ' ';
X    while (slen--)
X	*fp++ = *string++;
X    if ((! hasvalue) || fieldlen != fwidth[col]) 
X	while (fp < last)
X	    *fp++ = ' ';
X    *fp = '\0';
#ifdef VMS
X    mvaddstr(r, c, field);	/* this is a macro */
#else
X    (void) mvaddstr(r, c, field);
#endif
X
X    *nextcolp  = nextcol;
X    *fieldlenp = fieldlen;
}
X
int
etype(e)
register struct enode *e;
{
X    if (e == (struct enode *)0)
X	return NUM;
X    switch (e->op) {
X    case O_SCONST: case '#': case DATE: case FMT: case STINDEX:
X    case EXT: case SVAL: case SUBSTR:
X        return (STR);
X
X    case '?':
X    case IF:
X        return(etype(e->e.o.right->e.o.left));
X
X    case 'f':
X        return(etype(e->e.o.right));
X
X    case O_VAR: {
X	register struct ent *p;
X	p = e->e.v.vp;
X	if (p->expr) 
X	    return(p->flags & is_strexpr ? STR : NUM);
X	else if (p->label)
X	    return(STR);
X	else
X	    return(NUM);
X	}
X
X    default:
X	return(NUM);
X    }
}
X
/* return 1 if yes given, 0 otherwise */
int
yn_ask(msg)
char	*msg;
{	char ch;
X
X	(void) move (0, 0);
X	(void) clrtoeol ();
X	(void) addstr (msg);
X	(void) refresh();
X	ch = nmgetch();
X	if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
X		if (ch == ctl('g') || ch == ESC)
X			return(-1);
X		error("y or n response required");
X		return (-1);
X	}
X	if (ch == 'y' || ch == 'Y')
X		return(1);
X	else
X		return(0);
}
X
#ifdef AMIGA
#include <unix.h>
#else
#include <pwd.h>
#endif
X
char	*
findhome(path)
char	*path;
{
X	static	char	*HomeDir = NULL;
X	extern	char	*getenv();
X
X	if (*path == '~')
X	{	char	*pathptr;
X		char	tmppath[PATHLEN];
X
X		if (HomeDir == NULL)
X		{	HomeDir = getenv("HOME");
X			if (HomeDir == NULL)
X				HomeDir = "/";
X		}
X		pathptr = path + 1;
X		if ((*pathptr == '/') || (*pathptr == '\0'))
X		{	strcpy(tmppath, HomeDir);
X		}
X		else
X		{	struct	passwd *pwent;
X			extern	struct	passwd *getpwnam();
X			char	*namep;
X			char	name[50];
X
X			namep = name;
X			while ((*pathptr != '\0') && (*pathptr != '/'))
X				*(namep++) = *(pathptr++);
X			*namep = '\0';
X			if ((pwent = getpwnam(name)) == NULL)
X			{	sprintf(path, "Can't find user %s", name);
X				return(NULL);
X			}
X			strcpy(tmppath, pwent->pw_dir);
X		}
X
X		strcat(tmppath, pathptr);
X		strcpy(path, tmppath);
X	}
X	return(path);
}
X
#ifdef DOBACKUPS
#include <sys/types.h>
#include <sys/stat.h>
X
/*
X * make a backup copy of a file, use the same mode and name in the format
X * [path/]#file~
X * return 1 if we were successful, 0 otherwise
X */
int
backup_file(path)
char	*path;
{
X	struct	stat	statbuf;
X	char	fname[PATHLEN];
X	char	tpath[PATHLEN];
#ifdef sequent
X	char	*buf;
#else
X	char	buf[BUFSIZ];
#endif
X	char	*tpp;
X	int	infd, outfd;
X	int	count;
X
X	/* tpath will be the [path/]file ---> [path/]#file~ */
X	strcpy(tpath, path);
X	if ((tpp = strrchr(tpath, '/')) == NULL)
X		tpp = tpath;
X	else
X		tpp++;
X	strcpy(fname, tpp);
X	sprintf(tpp, "#%s~", fname);
X
X	if (stat(path, &statbuf) == 0)
X	{
#ifdef sequent
X		if ((buf = xmalloc(statbuf.st_blksize)) == (char *)0)
X			return(0);
#endif
X
X		if ((infd = open(path, O_RDONLY, 0)) < 0)
X		{
#ifdef sequent
X			xfree(buf);
#endif
X			return(0);
X		}
X		if ((outfd = open(tpath, O_TRUNC|O_WRONLY|O_CREAT,
X					statbuf.st_mode)) < 0)
X		{
#ifdef sequent
X			xfree(buf);
#endif
X			return(0);
X		}
#ifdef sequent
X		while((count = read(infd, buf, statbuf.st_blksize)) > 0)
#else
X		while((count = read(infd, buf, sizeof(buf))) > 0)
#endif
X		{	if (write(outfd, buf, count) != count)
X			{	count = -1;
X				break;
X			}
X		}
X		close(infd);
X		close(outfd);
#ifdef sequent
X		xfree(buf);
#endif
X		return((count < 0) ? 0 : 1);
X	}
X	else
X	if (errno == ENOENT)
X		return(1);
X	return(0);
}
#endif
SHAR_EOF
chmod 0666 cmds.c ||
echo 'restore of cmds.c failed'
Wc_c="`wc -c < 'cmds.c'`"
test 30912 -eq "$Wc_c" ||
	echo 'cmds.c: original size 30912, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= crypt.c ==============
if test -f 'crypt.c' -a X"$1" != X"-c"; then
	echo 'x - skipping crypt.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting crypt.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'crypt.c' &&
/*
X * Encryption utilites
X * Bradley Williams	
X * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams
X * $Revision: 6.8 $
X */
X
#include <stdio.h>
#include <curses.h>
X
#if defined(BSD42) || defined(BSD43)
#include <sys/file.h>
#else
#include <fcntl.h>
#endif
X
#include "sc.h"
X
char        *strcpy();
X
#ifdef SYSV3
void exit();
#endif
X
int         Crypt = 0;
X
creadfile (save, eraseflg)
char *save;
int  eraseflg;
{
X    register FILE *f;
X    int pipefd[2];
X    int fildes;
X    int pid;
X
X    if (eraseflg && strcmp(save, curfile) && modcheck(" first")) return;
X
X    if ((fildes = open(findhome(save), O_RDONLY, 0)) < 0)
X    {
X	error ("Can't read file \"%s\"", save);
X	return;
X    }
X
X    if (eraseflg) erasedb ();
X
X    if (pipe(pipefd) < 0) {
X	error("Can't make pipe to child");
X	return;
X    }
X
X    deraw();
X    if ((pid=fork()) == 0)			  /* if child  */
X    {
X	(void) close (0);		  /* close stdin */
X	(void) close (1);		  /* close stdout */
X	(void) close (pipefd[0]);	  /* close pipe input */
X	(void) dup (fildes);		  /* standard in from file */
X	(void) dup (pipefd[1]);		  /* connect to pipe */
X	(void) fprintf (stderr, " ");
X	(void) execl ("/bin/sh", "sh", "-c", "crypt", (char *)0);
X	exit (-127);
X    }
X    else				  /* else parent */
X    {
X	(void) close (fildes);
X	(void) close (pipefd[1]);	  /* close pipe output */
X	if ((f = fdopen (pipefd[0], "r")) == (FILE *)0)
X	{
X	    (void) kill (pid, -9);
X	    error ("Can't fdopen file \"%s\"", save);
X	    (void) close (pipefd[0]);
X	    return;
X	}
X    }
X
X    loading++;
X    while (fgets(line,sizeof line,f)) {
X	linelim = 0;
X	if (line[0] != '#') (void) yyparse ();
X    }
X    --loading;
X    (void) fclose (f);
X    (void) close (pipefd[0]);
X    while (pid != wait(&fildes)) /**/;
X    goraw();
X    linelim = -1;
X    modflg++;
X    if (eraseflg) {
X	(void) strcpy (curfile, save);
X	modflg = 0;
X    }
X    EvalAll();
}
X
cwritefile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
X    register FILE *f;
X    int pipefd[2];
X    int fildes;
X    int pid;
X    char save[PATHLEN];
X    char *fn;
X    char *busave;
X
X    if (*fname == '\0') fname = &curfile[0];
X
X    fn = fname;
X    while (*fn && (*fn == ' '))  /* Skip leading blanks */
X	fn++;
X
X    if ( *fn == '|' ) {
X	error ("Can't have encrypted pipe");
X	return(-1);
X	}
X
X    (void) strcpy(save,fname);
X
X    busave = findhome(save);
#ifdef DOBACKUPS
X    if (!backup_file(busave) &&
X	(yn_ask("Could not create backup copy, Save anyhow?: (y,n)") != 1))
X		return(0);
#endif
X    if ((fildes = open (busave, O_TRUNC|O_WRONLY|O_CREAT, 0600)) < 0)
X    {
X	error ("Can't create file \"%s\"", save);
X	return(-1);
X    }
X
X    if (pipe (pipefd) < 0) {
X	error ("Can't make pipe to child\n");
X	return(-1);
X    }
X
X    deraw();
X    if ((pid=fork()) == 0)			  /* if child  */
X    {
X	(void) close (0);			  /* close stdin */
X	(void) close (1);			  /* close stdout */
X	(void) close (pipefd[1]);		  /* close pipe output */
X	(void) dup (pipefd[0]);			  /* connect to pipe input */
X	(void) dup (fildes);			  /* standard out to file */
X	(void) fprintf (stderr, " ");
X	(void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
X	exit (-127);
X    }
X    else				  /* else parent */
X    {
X	(void) close (fildes);
X	(void) close (pipefd[0]);		  /* close pipe input */
X	f = fdopen (pipefd[1], "w");
X	if (f == 0)
X	{
X	    (void) kill (pid, -9);
X	    error ("Can't fdopen file \"%s\"", save);
X	    (void) close (pipefd[1]);
X	    return(-1);
X	}
X    }
X
X    write_fd(f, r0, c0, rn, cn);
X
X    (void) fclose (f);
X    (void) close (pipefd[1]);
X    while (pid != wait(&fildes)) /**/;
X    (void) strcpy(curfile,save);
X
X    modflg = 0;
X    error ("File \"%s\" written", curfile);
X    goraw();
X    return(0);
}
X
SHAR_EOF
chmod 0666 crypt.c ||
echo 'restore of crypt.c failed'
Wc_c="`wc -c < 'crypt.c'`"
test 3640 -eq "$Wc_c" ||
	echo 'crypt.c: original size 3640, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= eres.sed ==============
if test -f 'eres.sed' -a X"$1" != X"-c"; then
	echo 'x - skipping eres.sed (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting eres.sed (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'eres.sed' &&
/%token.*K_/!d
/%token.*K_\(.*\)/s//	"\1",	K_\1,/
SHAR_EOF
chmod 0666 eres.sed ||
echo 'restore of eres.sed failed'
Wc_c="`wc -c < 'eres.sed'`"
test 50 -eq "$Wc_c" ||
	echo 'eres.sed: original size 50, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= experres.h ==============
if test -f 'experres.h' -a X"$1" != X"-c"; then
	echo 'x - skipping experres.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting experres.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'experres.h' &&
X	"FIXED",	K_FIXED,
X	"SUM",	K_SUM,
X	"PROD",	K_PROD,
X	"AVG",	K_AVG,
X	"STDDEV",	K_STDDEV,
X	"COUNT",	K_COUNT,
X	"ABS",	K_ABS,
X	"ACOS",	K_ACOS,
X	"ASIN",	K_ASIN,
X	"ATAN",	K_ATAN,
X	"ATAN2",	K_ATAN2,
X	"CEIL",	K_CEIL,
X	"COS",	K_COS,
X	"EXP",	K_EXP,
X	"FABS",	K_FABS,
X	"FLOOR",	K_FLOOR,
X	"HYPOT",	K_HYPOT,
X	"LN",	K_LN,
X	"LOG",	K_LOG,
X	"PI",	K_PI,
X	"POW",	K_POW,
X	"SIN",	K_SIN,
X	"SQRT",	K_SQRT,
X	"TAN",	K_TAN,
X	"DTR",	K_DTR,
X	"RTD",	K_RTD,
X	"MAX",	K_MAX,
X	"MIN",	K_MIN,
X	"RND",	K_RND,
X	"ROUND",	K_ROUND,
X	"IF",	K_IF,
X	"PV",	K_PV,
X	"FV",	K_FV,
X	"PMT",	K_PMT,
X	"HOUR",	K_HOUR,
X	"MINUTE",	K_MINUTE,
X	"SECOND",	K_SECOND,
X	"MONTH",	K_MONTH,
X	"DAY",	K_DAY,
X	"YEAR",	K_YEAR,
X	"NOW",	K_NOW,
X	"DATE",	K_DATE,
X	"DTS",	K_DTS,
X	"TTS",	K_TTS,
X	"FMT",	K_FMT,
X	"SUBSTR",	K_SUBSTR,
X	"STON",	K_STON,
X	"EQS",	K_EQS,
X	"EXT",	K_EXT,
X	"NVAL",	K_NVAL,
X	"SVAL",	K_SVAL,
X	"LOOKUP",	K_LOOKUP,
X	"HLOOKUP",	K_HLOOKUP,
X	"VLOOKUP",	K_VLOOKUP,
X	"INDEX",	K_INDEX,
X	"STINDEX",	K_STINDEX,
X	"AUTO",	K_AUTO,
X	"AUTOCALC",	K_AUTOCALC,
X	"BYROWS",	K_BYROWS,
X	"BYCOLS",	K_BYCOLS,
X	"BYGRAPH",	K_BYGRAPH,
X	"ITERATIONS",	K_ITERATIONS,
X	"NUMERIC",	K_NUMERIC,
X	"PRESCALE",	K_PRESCALE,
X	"EXTFUN",	K_EXTFUN,
X	"CELLCUR",	K_CELLCUR,
X	"TOPROW",	K_TOPROW,
X	"TBLSTYLE",	K_TBLSTYLE,
X	"TBL",	K_TBL,
X	"LATEX",	K_LATEX,
X	"TEX",	K_TEX,
SHAR_EOF
chmod 0666 experres.h ||
echo 'restore of experres.h failed'
Wc_c="`wc -c < 'experres.h'`"
test 1265 -eq "$Wc_c" ||
	echo 'experres.h: original size 1265, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= gram.c ==============
if test -f 'gram.c' -a X"$1" != X"-c"; then
	echo 'x - skipping gram.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting gram.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'gram.c' &&
X
/*  A Bison parser, made from gram.y  */
X
#define	STRING	258
#define	NUMBER	259
#define	FNUMBER	260
#define	RANGE	261
#define	VAR	262
#define	WORD	263
#define	COL	264
#define	S_FORMAT	265
#define	S_LABEL	266
#define	S_LEFTSTRING	267
#define	S_RIGHTSTRING	268
#define	S_GET	269
#define	S_PUT	270
#define	S_MERGE	271
#define	S_LET	272
#define	S_WRITE	273
#define	S_TBL	274
#define	S_COPY	275
#define	S_SHOW	276
#define	S_ERASE	277
#define	S_FILL	278
#define	S_GOTO	279
#define	S_DEFINE	280
#define	S_UNDEFINE	281
#define	S_VALUE	282
#define	S_MDIR	283
#define	S_HIDE	284
#define	S_SET	285
#define	K_FIXED	286
#define	K_SUM	287
#define	K_PROD	288
#define	K_AVG	289
#define	K_STDDEV	290
#define	K_COUNT	291
#define	K_ABS	292
#define	K_ACOS	293
#define	K_ASIN	294
#define	K_ATAN	295
#define	K_ATAN2	296
#define	K_CEIL	297
#define	K_COS	298
#define	K_EXP	299
#define	K_FABS	300
#define	K_FLOOR	301
#define	K_HYPOT	302
#define	K_LN	303
#define	K_LOG	304
#define	K_PI	305
#define	K_POW	306
#define	K_SIN	307
#define	K_SQRT	308
#define	K_TAN	309
#define	K_DTR	310
#define	K_RTD	311
#define	K_MAX	312
#define	K_MIN	313
#define	K_RND	314
#define	K_ROUND	315
#define	K_IF	316
#define	K_PV	317
#define	K_FV	318
#define	K_PMT	319
#define	K_HOUR	320
#define	K_MINUTE	321
#define	K_SECOND	322
#define	K_MONTH	323
#define	K_DAY	324
#define	K_YEAR	325
#define	K_NOW	326
#define	K_DATE	327
#define	K_DTS	328
#define	K_TTS	329
#define	K_FMT	330
#define	K_SUBSTR	331
#define	K_STON	332
#define	K_EQS	333
#define	K_EXT	334
#define	K_NVAL	335
#define	K_SVAL	336
#define	K_LOOKUP	337
#define	K_HLOOKUP	338
#define	K_VLOOKUP	339
#define	K_INDEX	340
#define	K_STINDEX	341
#define	K_AUTO	342
#define	K_AUTOCALC	343
#define	K_BYROWS	344
#define	K_BYCOLS	345
#define	K_BYGRAPH	346
#define	K_ITERATIONS	347
#define	K_NUMERIC	348
#define	K_PRESCALE	349
#define	K_EXTFUN	350
#define	K_CELLCUR	351
#define	K_TOPROW	352
#define	K_TBLSTYLE	353
#define	K_TBL	354
#define	K_LATEX	355
#define	K_TEX	356
X
#line 17 "gram.y"
X
#include <curses.h>
#include "sc.h"
X
#define ENULL (struct enode *)0
X
char *strcpy();
X
#line 26 "gram.y"
typedef union {
X    int ival;
X    double fval;
X    struct ent_ptr ent;
X    struct enode *enode;
X    char *sval;
X    struct range_s rval;
} YYSTYPE;
X
#ifndef YYLTYPE
typedef
X  struct yyltype
X    {
X      int timestamp;
X      int first_line;
X      int first_column;
X      int last_line;
X      int last_column;
X      char *text;
X   }
X  yyltype;
X
#define YYLTYPE yyltype
#endif
X
#define	YYACCEPT	return(0)
#define	YYABORT	return(1)
#define	YYERROR	return(1)
#include <stdio.h>
X
#ifdef __STDC__
#define CONST const
#else
#define CONST
#endif
X
X
X
#define	YYFINAL		473
#define	YYFLAG		-32768
#define	YYNTBASE	123
X
#define YYTRANSLATE(x) ((unsigned)(x) <= 356 ? yytranslate[x] : 134)
X
static CONST char yytranslate[] = {     0,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,   109,     2,   112,   122,   115,   105,     2,   118,
X   119,   113,   110,   120,   111,     2,   114,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,   103,     2,   106,
X   107,   108,   102,   117,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,   116,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,   104,     2,   121,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
X     2,     2,     2,     2,     2,     1,     2,     3,     4,     5,
X     6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
X    16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
X    26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
X    36,    37,    38,    39,    40,    41,    42,    43,    44,    45,
X    46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
X    56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
X    66,    67,    68,    69,    70,    71,    72,    73,    74,    75,
X    76,    77,    78,    79,    80,    81,    82,    83,    84,    85,
X    86,    87,    88,    89,    90,    91,    92,    93,    94,    95,
X    96,    97,    98,    99,   100,   101
};
X
static CONST short yyrline[] = {     0,
X   153,   155,   157,   159,   161,   163,   165,   172,   178,   180,
X   185,   188,   192,   194,   198,   200,   202,   204,   206,   208,
X   211,   214,   216,   218,   222,   224,   226,   227,   228,   229,
X   230,   237,   238,   239,   240,   241,   242,   244,   245,   246,
X   248,   250,   252,   254,   256,   258,   260,   262,   264,   265,
X   266,   267,   268,   269,   270,   271,   272,   273,   274,   275,
X   276,   277,   278,   279,   280,   281,   282,   283,   284,   285,
X   287,   288,   289,   291,   292,   293,   294,   295,   296,   297,
X   298,   300,   302,   303,   304,   305,   306,   308,   310,   313,
X   316,   318,   319,   320,   321,   323,   324,   325,   326,   327,
X   328,   329,   330,   331,   334,   335,   336,   337,   338,   339,
X   340,   341,   342,   343,   344,   345,   346,   347,   348,   349,
X   350,   353,   354,   357,   358,   361,   362,   364,   366,   368,
X   371,   372,   375,   376,   377,   378,   381,   382,   393,   394,
X   397,   398,   399,   400,   401,   402,   403,   404,   405,   406,
X   407,   408,   409,   410,   411,   412,   413,   414,   415,   416,
X   417,   418,   419,   420
};
X
static CONST char * yytname[] = {     0,
"error","$illegal.","STRING","NUMBER","FNUMBER","RANGE","VAR","WORD","COL","S_FORMAT",
"S_LABEL","S_LEFTSTRING","S_RIGHTSTRING","S_GET","S_PUT","S_MERGE","S_LET","S_WRITE","S_TBL","S_COPY",
"S_SHOW","S_ERASE","S_FILL","S_GOTO","S_DEFINE","S_UNDEFINE","S_VALUE","S_MDIR","S_HIDE","S_SET",
"K_FIXED","K_SUM","K_PROD","K_AVG","K_STDDEV","K_COUNT","K_ABS","K_ACOS","K_ASIN","K_ATAN",
"K_ATAN2","K_CEIL","K_COS","K_EXP","K_FABS","K_FLOOR","K_HYPOT","K_LN","K_LOG","K_PI",
"K_POW","K_SIN","K_SQRT","K_TAN","K_DTR","K_RTD","K_MAX","K_MIN","K_RND","K_ROUND",
"K_IF","K_PV","K_FV","K_PMT","K_HOUR","K_MINUTE","K_SECOND","K_MONTH","K_DAY","K_YEAR",
"K_NOW","K_DATE","K_DTS","K_TTS","K_FMT","K_SUBSTR","K_STON","K_EQS","K_EXT","K_NVAL",
"K_SVAL","K_LOOKUP","K_HLOOKUP","K_VLOOKUP","K_INDEX","K_STINDEX","K_AUTO","K_AUTOCALC","K_BYROWS","K_BYCOLS",
"K_BYGRAPH","K_ITERATIONS","K_NUMERIC","K_PRESCALE","K_EXTFUN","K_CELLCUR","K_TOPROW","K_TBLSTYLE","K_TBL","K_LATEX",
"K_TEX","'?'","':'","'|'","'&'","'<'","'='","'>'","'!'","'+'",
"'-'","'#'","'*'","'/'","'%'","'^'","'@'","'('","')'","','",
"'~'","'$'","command"
};
X
static CONST short yyr1[] = {     0,
X   123,   123,   123,   123,   123,   123,   123,   123,   123,   123,
X   123,   123,   123,   123,   123,   123,   123,   123,   123,   123,
X   123,   123,   123,   123,   123,   123,   123,   123,   123,   123,
X   123,   123,   123,   123,   123,   123,   123,   124,   124,   124,
X   124,   124,   124,   124,   124,   124,   124,   124,   124,   124,
X   124,   124,   124,   124,   124,   124,   124,   124,   124,   124,
X   124,   124,   124,   124,   124,   124,   124,   124,   124,   124,
X   124,   124,   124,   124,   124,   124,   124,   124,   124,   124,
X   124,   124,   124,   124,   124,   124,   124,   124,   124,   124,
X   124,   124,   124,   124,   124,   124,   124,   124,   124,   124,
X   124,   124,   124,   124,   125,   125,   125,   125,   125,   125,
X   125,   125,   125,   125,   125,   125,   125,   125,   125,   125,
X   125,   126,   126,   127,   127,   128,   128,   128,   128,   128,
X   129,   129,   130,   130,   130,   130,   131,   131,   132,   132,
X   133,   133,   133,   133,   133,   133,   133,   133,   133,   133,
X   133,   133,   133,   133,   133,   133,   133,   133,   133,   133,
X   133,   133,   133,   133
};
X
static CONST short yyr2[] = {     0,
X     4,     4,     4,     4,     6,     4,     2,     2,     2,     3,
X     2,     3,     2,     3,     2,     4,     4,     2,     2,     3,
X     1,     2,     1,     2,     3,     4,     2,     2,     2,     1,
X     2,     3,     3,     2,     2,     0,     1,     1,     2,     5,
X     5,     5,     5,     5,     5,     7,     5,     7,     5,     5,
X     5,     5,     7,     5,     5,     5,     5,     5,     7,     5,
X     5,     7,     5,     5,     5,     5,     5,     5,     7,     9,
X     9,     9,     9,     5,     5,     5,     5,     5,     5,     2,
X     9,     9,     5,     7,     5,     7,     7,     7,     9,     9,
X     7,     7,     7,     7,     9,     3,     2,     2,     1,     1,
X     1,     1,     2,     2,     3,     3,     3,     3,     3,     3,
X     1,     5,     3,     3,     3,     3,     3,     4,     4,     4,
X     3,     1,     3,     3,     1,     2,     3,     3,     4,     1,
X     1,     1,     1,     1,     2,     2,     1,     1,     0,     2,
X     1,     1,     2,     2,     2,     2,     1,     1,     1,     1,
X     2,     1,     2,     1,     2,     1,     2,     1,     2,     3,
X     3,     3,     3,     3
};
X
static CONST short yydefact[] = {     0,
X    37,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,    21,     0,    30,     0,     0,    23,     0,
X     0,   139,     0,   125,   130,     0,     0,   131,   132,     0,
X     0,     0,   137,   138,     7,    11,     8,     0,    13,    15,
X     0,     0,     0,     0,    22,   133,   134,     0,     0,     0,
X     0,    29,    27,    28,    31,    34,    24,     9,    19,    18,
X    35,     0,     0,   126,     0,     0,     0,     0,     0,     0,
X    10,     0,    12,    14,    20,     0,     0,   136,   135,     0,
X    25,    32,    33,   141,   142,   148,   147,   149,     0,   150,
X   152,   154,   156,   158,     0,     0,     0,   140,     6,     0,
X   128,   127,     0,   124,   102,    99,   100,     0,   101,     0,
X     0,     0,     0,     0,     0,   111,     2,    38,     3,     4,
X     1,    17,    16,    26,     0,     0,   145,   146,   151,   153,
X   155,   157,   159,   143,   144,     0,   129,    39,   104,    97,
X    98,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,    80,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,   103,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,   160,   161,   162,   163,   164,     5,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X    96,     0,   117,   116,     0,   113,   114,     0,   115,     0,
X   105,   106,   121,   107,   108,   109,   110,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,    38,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,   118,   120,   119,    40,    41,    42,
X    43,    44,    49,    50,    51,    52,     0,    54,    55,    56,
X    57,    58,     0,    60,    61,     0,    63,    64,    65,    66,
X    67,     0,    45,     0,    47,    68,     0,     0,     0,     0,
X     0,    74,    75,    76,    77,    78,    79,    85,     0,     0,
X     0,     0,    83,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,   112,     0,     0,     0,   122,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,     0,     0,     0,    53,    59,    62,
X    46,     0,    48,    69,     0,     0,     0,     0,     0,     0,
X    86,     0,    84,    92,    93,    94,    88,     0,     0,    87,
X    91,   123,     0,     0,     0,     0,     0,     0,     0,     0,
X     0,    70,    71,    72,    73,    81,    82,    95,    89,    90,
X     0,     0,     0
};
X
static CONST short yydefgoto[] = {   471,
X   116,   407,   408,    28,   118,    30,    51,    35,    61,    98
};
X
static CONST short yypact[] = {   486,
-32768,    20,    71,    71,    71,    42,    42,    42,    71,    42,
X    42,    71,    58,    71,    98,    85,    42,    71,    71,    42,
X   118,-32768,     6,-32768,-32768,    23,    30,-32768,   -60,   -54,
X   -32,   -28,-32768,-32768,-32768,    71,-32768,   -26,    71,    71,
X    71,   -60,   -20,   -18,-32768,-32768,-32768,    14,    14,    14,
X    14,-32768,-32768,-32768,    71,-32768,-32768,-32768,-32768,-32768,
X   355,    95,    97,-32768,   104,    44,    52,    51,    51,    51,
-32768,    51,-32768,-32768,-32768,   106,   105,-32768,-32768,    14,
-32768,-32768,   -60,-32768,-32768,-32768,-32768,-32768,     9,-32768,
-32768,-32768,-32768,-32768,    28,   168,   -22,-32768,-32768,   119,
-32768,-32768,   134,-32768,-32768,-32768,-32768,    51,-32768,    51,
X    51,    51,   292,    51,    51,-32768,  1646,-32768,  1646,  1646,
X  1646,-32768,-32768,-32768,   135,    80,-32768,-32768,-32768,-32768,
-32768,-32768,-32768,-32768,-32768,   138,-32768,-32768,-32768,-32768,
-32768,    31,    35,    38,    45,    47,    57,    69,    72,    73,
X    74,    76,    79,    81,    84,    87,    88,    93,    94,    96,
X   129,   139,   142,   196,   197,   198,   199,   201,   202,   204,
X   224,   268,   270,   271,   272,   273,   274,   275,   276,-32768,
X   283,   284,   285,   286,   287,   289,   290,   293,   294,   295,
X   301,   307,   308,   309,   310,   925,-32768,    51,    51,    51,
X    19,    51,    37,    91,    51,    51,    51,    51,    51,    51,
X    51,-32768,-32768,-32768,-32768,-32768,-32768,    71,    71,    71,
X    71,    71,    51,    51,    51,    51,    51,    51,    51,    51,
X    51,    51,    51,    51,    51,    51,    51,    51,    51,    51,
X    51,    67,    67,    51,    51,    51,    51,    51,    51,    51,
X    51,    51,    51,    51,    51,    51,    51,    51,    51,    51,
X    51,    51,    51,    51,    51,    51,    51,    51,    51,    51,
-32768,  1631,  1658,  1669,    51,   269,   269,    51,   269,    51,
X    18,    18,    18,   313,   313,   313,-32768,   291,   311,   312,
X   317,   322,   941,   957,   973,   989,   415,  1005,  1021,  1037,
X  1053,  1069,   432,  1085,  1101,   449,  1117,  1133,  1149,  1165,
X  1181,   466,   -56,   335,   483,   336,  1197,   500,   517,   534,
X   551,   568,  1213,  1229,  1245,  1261,  1277,  1293,  1309,   585,
X   602,   619,   636,  1325,   653,   670,   687,   704,   721,   738,
X   755,   772,   789,    51,   269,   269,   269,-32768,-32768,-32768,
-32768,-32768,-32768,-32768,-32768,-32768,    51,-32768,-32768,-32768,
-32768,-32768,    51,-32768,-32768,    51,-32768,-32768,-32768,-32768,
-32768,    51,-32768,    51,-32768,-32768,    51,    51,    51,    51,
X    51,-32768,-32768,-32768,-32768,-32768,-32768,-32768,    51,    51,
X    51,    51,-32768,    51,    51,    51,    51,    71,    71,    71,
X    71,    71,   117,  1341,  1357,  1373,  1646,    32,    63,  1389,
X   806,   823,   840,   857,   874,   891,  1405,   908,  1421,  1437,
X  1453,  1469,   337,   338,   339,   341,   342,-32768,-32768,-32768,
-32768,    51,-32768,-32768,    51,    51,    51,    51,    51,    51,
-32768,    51,-32768,-32768,-32768,-32768,-32768,    51,    51,-32768,
-32768,  1646,  1485,  1501,  1517,  1533,  1549,  1565,  1581,  1597,
X  1613,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
X   457,   462,-32768
};
X
static CONST short yypgoto[] = {-32768,
X   -15,    43,    89,   131,    -3,    16,    70,   193,-32768,-32768
};
X
X
#define	YYLAST		1785
X
X
static CONST short yytable[] = {    29,
X    29,    29,    34,    34,    34,    29,    34,    34,    42,    62,
X    29,    29,    29,    34,    29,    29,    34,    46,    47,    31,
X    32,   105,   106,   107,    38,    25,    64,    26,    23,    45,
X    50,    53,    42,    56,    57,    42,    42,    29,    66,   105,
X   106,   107,    67,    25,    33,    26,    67,   102,    25,   108,
X    26,    83,    68,   105,   106,   107,    75,    25,    25,    26,
X    26,    43,  -132,   104,   134,   135,    44,   108,   109,   105,
X   106,   107,    24,    25,    69,    26,    24,    25,    70,    26,
X    72,   108,    76,   213,    77,    54,   109,    52,    46,    47,
X    24,    25,   138,    26,   139,   140,   141,   108,    99,   197,
X   109,    46,    47,    24,    25,   100,    26,   101,    63,   122,
X   117,   119,   120,   123,   121,   125,   109,    78,    79,    80,
X    81,    59,   136,    48,    49,   275,    60,   110,   111,   112,
X   208,   209,   210,   211,   126,   113,   114,   137,   212,   115,
X    27,   217,    41,   278,    65,   110,   111,   112,   218,   124,
X   431,   432,   219,   113,   114,   220,   196,   115,    27,   110,
X   111,   112,   221,    27,   222,   103,    71,   113,   114,    73,
X    74,   115,    27,    27,   223,   110,   111,   112,   214,   215,
X   216,   433,   432,   113,   114,    82,   224,   115,    27,   225,
X   226,   227,    27,   228,    48,    49,   229,   280,   230,    36,
X    37,   231,    39,    40,   232,   233,    27,    48,    49,    55,
X   234,   235,    58,   236,    29,    29,    29,    29,    29,    27,
X   199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
X   209,   210,   211,   288,   289,   290,   291,   292,   313,   313,
X   272,   273,   274,   276,   277,   279,   237,   281,   282,   283,
X   284,   285,   286,   287,   127,   128,   238,   314,   316,   239,
X   129,   130,   131,   132,   133,   293,   294,   295,   296,   297,
X   298,   299,   300,   301,   302,   303,   304,   305,   306,   307,
X   308,   309,   310,   311,   312,   315,   317,   318,   319,   320,
X   321,   322,   323,   324,   325,   326,   327,   328,   329,   330,
X   331,   332,   333,   334,   335,   336,   337,   338,   339,   340,
X   341,   342,   343,   240,   241,   242,   243,   345,   244,   245,
X   346,   246,   347,   142,   143,   144,   145,   146,   147,   148,
X   149,   150,   151,   152,   153,   154,   155,   156,   157,   158,
X   159,   247,   160,   161,   162,   163,   164,   165,   166,   167,
X   168,   169,   170,   171,   172,   173,   174,   175,   176,   177,
X   178,   179,   180,   181,   182,   183,   184,   185,   186,   187,
X   188,   189,   190,   191,   192,   193,   194,   195,   205,   206,
X   207,   208,   209,   210,   211,   248,   403,   249,   250,   251,
X   252,   253,   254,   255,    29,    29,    29,    29,    29,   404,
X   256,   257,   258,   259,   260,   405,   261,   262,   406,   348,
X   263,   264,   265,   423,   424,   425,   426,   427,   266,   410,
X   411,   412,   413,   414,   267,   268,   269,   270,   211,   349,
X   350,   415,   416,   417,   418,   351,   419,   420,   421,   422,
X   352,    84,    85,    86,    87,    88,    89,    90,    91,    92,
X    93,    94,    95,   373,   375,   447,   472,   448,   449,   450,
X   451,   473,   409,    96,     0,     0,     0,     0,     0,     0,
X     0,     0,     0,     0,   452,    97,     0,   453,   454,   455,
X   456,   457,   458,     0,   459,   -36,     1,     0,     0,     0,
X   460,   461,     0,     0,     0,     2,     3,     4,     5,     6,
X     7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
X    17,    18,    19,    20,    21,    22,   198,     0,   199,   200,
X   201,   202,   203,   204,   205,   206,   207,   208,   209,   210,
X   211,     0,     0,   198,   357,   199,   200,   201,   202,   203,
X   204,   205,   206,   207,   208,   209,   210,   211,     0,     0,
X   198,   363,   199,   200,   201,   202,   203,   204,   205,   206,
X   207,   208,   209,   210,   211,     0,     0,   198,   366,   199,
X   200,   201,   202,   203,   204,   205,   206,   207,   208,   209,
X   210,   211,     0,     0,   198,   372,   199,   200,   201,   202,
X   203,   204,   205,   206,   207,   208,   209,   210,   211,     0,
X     0,   198,   374,   199,   200,   201,   202,   203,   204,   205,
X   206,   207,   208,   209,   210,   211,     0,     0,   198,   377,
X   199,   200,   201,   202,   203,   204,   205,   206,   207,   208,
X   209,   210,   211,     0,     0,   198,   378,   199,   200,   201,
X   202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
X     0,     0,   198,   379,   199,   200,   201,   202,   203,   204,
X   205,   206,   207,   208,   209,   210,   211,     0,     0,   198,
X   380,   199,   200,   201,   202,   203,   204,   205,   206,   207,
X   208,   209,   210,   211,     0,     0,   198,   381,   199,   200,
X   201,   202,   203,   204,   205,   206,   207,   208,   209,   210,
X   211,     0,     0,   198,   389,   199,   200,   201,   202,   203,
X   204,   205,   206,   207,   208,   209,   210,   211,     0,     0,
X   198,   390,   199,   200,   201,   202,   203,   204,   205,   206,
X   207,   208,   209,   210,   211,     0,     0,   198,   391,   199,
X   200,   201,   202,   203,   204,   205,   206,   207,   208,   209,
X   210,   211,     0,     0,   198,   392,   199,   200,   201,   202,
X   203,   204,   205,   206,   207,   208,   209,   210,   211,     0,
X     0,   198,   394,   199,   200,   201,   202,   203,   204,   205,
X   206,   207,   208,   209,   210,   211,     0,     0,   198,   395,
SHAR_EOF
true || echo 'restore of gram.c failed'
fi
echo 'End of  part 1'
echo 'File gram.c is continued in part 2'
echo 2 > _shar_seq_.tmp
exit 0
--
Simon J Raybould    (sie@fulcrum.bt.co.uk)            //              {o.o}
                                                    \X/AMIGA           \-/
===========================================================================
British Telecom Fulcrum, Fordrough Lane, Birmingham, B9 5LD, ENGLAND.