[net.sources] Sc 3.1 - 2 of 2 spread sheet

rgb@nscpdc.UUCP (01/27/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	sc.h
#	sc.c
#	lex.c
#	gram.y
#	interp.c
# This archive created: Mon Jan 26 19:36:31 1987
# By:	Robert Bond (NSC Portland, Oregon)
echo shar: extracting sc.h '(1515 characters)'
cat << \SHAR_EOF > sc.h
/*	VC	A Table Calculator
 *		Common definitions
 *
 *		original by James Gosling, September 1982
 *		modified by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 */



#define MAXROWS 200
#define MAXCOLS 40
#define error move(1,0), clrtoeol(), printw

struct ent {
    double v;
    char *label;
    struct enode *expr;
    short flags;
    short row, col;
    struct ent *next;
};


struct enode {
    int op;
    union {
	double k;
	struct ent *v;
	struct {
	    struct enode *left, *right;
	} o;
    } e;
};

/* op values */
#define O_VAR 'v'
#define O_CONST 'k'
#define O_REDUCE(c) (c+0200)

#define ACOS 0
#define ASIN 1
#define ATAN 2
#define CEIL 3
#define COS 4
#define EXP 5 
#define FABS 6 
#define FLOOR 7
#define HYPOT 8
#define LOG 9
#define LOG10 10
#define POW 11
#define SIN 12
#define SQRT 13
#define TAN 14
#define DTR 15
#define RTD 16
#define MIN 17
#define MAX 18

/* flag values */
#define is_valid     0001
#define is_changed   0002
#define is_lchanged  0004
#define is_leftflush 0010
#define is_deleted   0020

#define ctl(c) ('c'&037)

struct ent *tbl[MAXROWS][MAXCOLS];

int strow, stcol;
int currow, curcol;
int savedrow, savedcol;
int FullUpdate;
int maxrow, maxcol;
int fwidth[MAXCOLS];
int precision[MAXCOLS];
char hidden_col[MAXCOLS];
char hidden_row[MAXROWS];
char line[1000];
int linelim;
int changed;
struct ent *to_fix;
struct enode *new();
struct enode *new_const();
struct enode *new_var();
struct ent *lookat();
struct enode *copye();
char *coltoa();

int modflg;
SHAR_EOF
if test 1515 -ne "`wc -c sc.h`"
then
echo shar: error transmitting sc.h '(should have been 1515 characters)'
fi
echo shar: extracting sc.c '(18976 characters)'
cat << \SHAR_EOF > sc.c
/*	SC	A Spreadsheet Calculator
 *		Main driver
 *
 *		original by James Gosling, September 1982
 *		modifications by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 *
 */


#include <signal.h>
#include <curses.h>

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

#include <stdio.h>
#include "sc.h"

#if BSD42 || SYSIII
#define	cbreak		crmode
#define	nocbreak	nocrmode
#endif

char *malloc();

/* default column width */

#define DEFWIDTH 10
#define DEFPREC   2

#define RESCOL 4  /* columns reserved for row numbers */
#define RESROW 3  /* rows reserved for prompt, error, and column numbers */

char curfile[1024];

int linelim = -1;
int showme = 1;  /* 1 to display the current cell in the top line */
char *rev = "$Revision: 3.1 $";

int seenerr;

yyerror (err)
char *err; {
    if (seenerr) return;
    seenerr++;
    move (1,0);
    clrtoeol ();
    printw ("%s: %.*s<=%s",err,linelim,line,line+linelim);
}

struct ent *
lookat(row,col){
    register struct ent **p;
    if (row < 0)
	row = 0;
    else if (row > MAXROWS-1) 
	row = MAXROWS-1;
    if (col < 0) 
	col = 0;
    else if (col > MAXCOLS-1)
	col = MAXCOLS-1;
    p = &tbl[row][col];
    if (*p==0) {
	*p = (struct ent *) malloc ((unsigned) sizeof (struct ent));
	if (row>maxrow) maxrow = row;
	if (col>maxcol) maxcol = col;
	(*p)->label = 0;
	(*p)->flags = 0;
	(*p)->row = row;
	(*p)->col = col;
	(*p)->expr = 0;
	(*p)->v = (double) 0.0;
    }
    return *p;
}

/*
 * This structure is used to keep ent structs around before they
 * are deleted to allow the sync_refs routine a chance to fix the
 * variable references.
 * We also use it as a last-deleted buffer for the 'p' command.
 */

free_ent(p)
register struct ent *p;
{
    p->next = to_fix;
    to_fix = p;
    p->flags |= is_deleted;
}

flush_saved()
{
    register struct ent *p;
    register struct ent *q;

    if (!(p = to_fix))
	return;
    while (p) {
	clearent(p);
	q = p->next;
	free ((char *)p);
	p = q;
    }
    to_fix = 0;
}

update () {
    register    row,
                col;
    register struct ent **p;
    static  lastmx,
            lastmy;
    static  char *under_cursor = " ";
    int     maxcol;
    int     maxrow;
    int     rows;
    int     cols;
    register r;

    while (hidden_row[currow])   /* You can't hide the last row or col */
	currow++;
    while (hidden_col[curcol])
	curcol++;
    if (curcol < stcol)
	stcol = curcol, FullUpdate++;
    if (currow < strow)
	strow = currow, FullUpdate++;
    while (1) {
	register    i;
	for (i = stcol, cols = 0, col = RESCOL;
	     (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
	    cols++;
	    if (hidden_col[i])
		continue;
	    col += fwidth[i];
	}
	if (curcol >= stcol + cols)
	    stcol++, FullUpdate++;
	else
	    break;
    }
    while (1) {
	register    i;
	for (i = strow, rows = 0, row = RESROW;
	     row < LINES && i < MAXROWS; i++) {
	    rows++;
	    if (hidden_row[i])
		continue;
	    row++;
	}
	if (currow >= strow + rows)
	    strow++, FullUpdate++;
	else
	    break;
    }
    maxcol = stcol + cols - 1;
    maxrow = strow + rows - 1;
    if (FullUpdate) {
	register int i;
	move (2, 0);
	clrtobot ();
	standout();
	for (row=RESROW, i=strow; i <= maxrow; i++) {
	    if (hidden_row[i]) 
		continue;
	    move(row,0);
	    printw("%-*d", RESCOL, i);
	    row++;
	}
	move (2,0);
	printw("%*s", RESCOL, " ");
	for (col=RESCOL, i = stcol; i <= maxcol; i++) {
	    if (hidden_col[i])
		continue;
	    move(2, col);
	    printw("%*s", fwidth[i], coltoa(i));
	    col += fwidth[i];
	}
	standend();
    }
    for (row = strow, r = RESROW; row <= maxrow; row++) {
	register    c = RESCOL;
	if (hidden_row[row])
	    continue;
	for (p = &tbl[row][col = stcol]; col <= maxcol; col++, p++) {
	    if (hidden_col[col])
		continue;
	    if (*p && ((*p) -> flags & is_changed || FullUpdate)) {
		char   *s;
		move (r, c);
		(*p) -> flags &= ~is_changed;
		if ((*p) -> flags & is_valid)
		    printw ("%*.*f", fwidth[col], precision[col], (*p) -> v);
		if (s = (*p) -> label) {
		    char field[1024];

		    strncpy(field,s,fwidth[col]);
		    field[fwidth[col]] = 0;
		    mvaddstr (r,
			    (*p) -> flags & is_leftflush
			    ? c : c - strlen (field) + fwidth[col],
			    field);
		}
	    }
	    c += fwidth[col];
	}
	r++;
    }
    
    move(lastmy, lastmx);
    if (inch() == '<')
        addstr (under_cursor);
    lastmy =  RESROW;
    for (row = strow; row < currow; row++)
	if (!hidden_row[row])
		lastmy += 1;
    lastmx = RESCOL;
    for (col = stcol; col <= curcol; col++)
	if (!hidden_col[col])
		lastmx += fwidth[col];
    move(lastmy, lastmx);
    *under_cursor = inch();
    addstr ("<");
    move (0, 0);
    clrtoeol ();
    if (linelim >= 0) {
	addstr (">> ");
	addstr (line);
    } else {
	if (showme) {
	    register struct ent *p;
	    p = tbl[currow][curcol];
	    if (p && ((p->flags & is_valid) || p->label)) {
		if (p->expr || !p->label) {
		    linelim = 0;
		    editexp(currow, curcol);
		} else {
		    sprintf(line, "%s", p->label);
		}
		addstr("[");
		addstr (line);
		addstr("]");
		linelim = -1;
	    } else {
		addstr("[]");
	    }
	}
	move (lastmy, lastmx);
    }
    FullUpdate = 0;
}

main (argc, argv)
char  **argv; {
    int     inloop = 1;
    register int   c;
    int     edistate = -1;
    int     arg = 1;
    int     narg;
    int     nedistate;
    int	    running;
    char    revmsg[80];
    char    *revi;
    {
	register    i;
	for (i = 0; i < MAXCOLS; i++) {
	    fwidth[i] = DEFWIDTH;
	    precision[i] = DEFPREC;
	}
    }
    curfile[0]=0;
    running = 1;

    signals();
    initscr ();
    clear ();
    cbreak();
    nonl();
    noecho ();
    initkbd();
    if (argc > 1) {
	strcpy(curfile,argv[1]);
	readfile (argv[1],0);
    }
    modflg = 0;
    strcpy(revmsg, argv[0]);
    for (revi=rev; *revi++ != ':';);
    strcat(revmsg, revi);
    revi = revmsg+strlen(revmsg);
    *--revi = 0;
    strcat(revmsg,"Type '?' for help.");
    error (revmsg);
    FullUpdate++;
    while (inloop) { running = 1;
    while (running) {
	nedistate = -1;
	narg = 1;
	if (edistate < 0 && linelim < 0 && (changed || FullUpdate))
	    EvalAll (), changed = 0;
	update ();
	refresh ();
	move (1, 0);
	clrtoeol ();
	fflush (stdout);
	seenerr = 0;
	if (((c = nmgetch ()) < ' ') || ( c == 0177 ))
	    switch (c) {
#if defined(BSD42) || defined (BSD43)
		case ctl (z):
		    nocrmode ();
		    nl ();
		    echo ();
		    kill(getpid(),SIGTSTP);

		    /* the pc stops here */

		    crmode ();
		    nonl ();
		    noecho ();
		    break;
#endif
		case ctl (r):
		case ctl (l):
		    FullUpdate++;
		    clearok(stdscr,1);
		    break;
		default:
		    error ("No such command  (^%c)", c + 0100);
		    break;
		case ctl (b):
		    while (--arg>=0) {
			if (curcol)
			    curcol--;
			else
			    error ("At column A");
			while(hidden_col[curcol] && curcol)
			    curcol--;
		    }
		    break;
		case ctl (c):
		    running = 0;
		    break;
		case ctl (f):
		    while (--arg>=0) {
			if (curcol < MAXCOLS - 1)
			    curcol++;
			else
			    error ("The table can't be any wider");
			while(hidden_col[curcol]&&(curcol<MAXCOLS-1))
			    curcol++;
		    }
		    break;
		case ctl (g):
		case ctl ([):
		    linelim = -1;
		    move (1, 0);
		    clrtoeol ();
		    break;
		case 0177:
		case ctl (h):
		    while (--arg>=0) if (linelim > 0)
			line[--linelim] = 0;
		    break;
		case ctl (m):
		case ctl (j):
		    if (linelim < 0)
			line[linelim = 0] = 0;
		    else {
			linelim = 0;
			yyparse ();
			linelim = -1;
		    }
		    break;
		case ctl (n):
		    while (--arg>=0) {
			if (currow < MAXROWS - 1)
			    currow++;
			else
			    error ("The table can't be any longer");
			while (hidden_row[currow] && (currow < MAXROWS - 1))
			    currow++;
		    }
		    break;
		case ctl (p):
		    while (--arg>=0) {
			if (currow)
			    currow--;
			else
			    error ("At row zero");
			while (hidden_row[currow] && currow)
			    currow--;
		    }
		    break;
		case ctl (q):
		    break;	/* ignore flow control */
		case ctl (s):
		    break;	/* ignore flow control */
		case ctl (t):
		    showme ^= 1;
		    break;
		case ctl (u):
		    narg = arg * 4;
		    nedistate = 1;
		    break;
		case ctl (v):	/* insert variable name */
		    if (linelim > 0) {
			sprintf (line+linelim,"%s%d", coltoa(curcol), currow);
			linelim = strlen (line);
		    }
		    break;
		case ctl (e):	/* insert variable expression */
		    if (linelim > 0) editexp(currow,curcol);
		    break;
		case ctl (a):	/* insert variable value */
		    if (linelim > 0) {
			struct ent *p = tbl[currow][curcol];

			if (p && p -> flags & is_valid) {
			    sprintf (line + linelim, "%.*f",
					precision[curcol],p -> v);
			    linelim = strlen (line);
			}
		    }
		    break;
		}
	else
	    if ('0' <= c && c <= '9' && (linelim < 0 || edistate >= 0)) {
		if (edistate != 0) {
		    if (c == '0')      /* just a '0' goes to left col */
			curcol = 0;
		    else {
		        nedistate = 0;
		        narg = c - '0';
		    }
		} else {
		    nedistate = 0;
		    narg = arg * 10 + (c - '0');
		}
	    }
	    else
		if (linelim >= 0) {
		    line[linelim++] = c;
		    line[linelim] = 0;
		}
		else
		    switch (c) {
			case '.':
			    nedistate = 1;
			    break;
			case ':':
			    break;	/* Be nice to vi users */
			case '=':
			    sprintf(line,"let %s%d = ",coltoa(curcol),currow);
			    linelim = strlen (line);
			    break;
			case '/':
			    switch (nmgetch()) {
			    case 'c':
				sprintf(line,"copy [to] %s%d [from] ", 
					  coltoa(curcol), currow);
				linelim = strlen(line);
				break;
			    case 'x':
				sprintf(line,"erase [v:v] ");
				linelim = strlen(line);
				break;
			    case 'f':
				sprintf(line,"fill [v:v start inc] ");
				linelim = strlen(line);
				break;
			   default:
				error("Invalid region operation");
			    }
			    break;
			case '$':
			    curcol = MAXCOLS - 1;
			    while (!tbl[currow][curcol] && curcol > 0)
				curcol--;
			    break;
			case '#':
			    currow = MAXROWS - 1;
			    while (!tbl[currow][curcol] && currow > 0)
				currow--;
			    break;
			case '^':
			    currow = 0;
			    break;
			case '?':
			    help ();
			    break;
			case '"':
			    sprintf (line, "label %s%d = \"",
						coltoa(curcol), currow);
			    linelim = strlen (line);
			    break;
			case '<':
			    sprintf (line, "leftstring %s%d = \"",
				    coltoa(curcol), currow);
			    linelim = strlen (line);
			    break;
			case '>':
			    sprintf (line, "rightstring %s%d = \"",
				    coltoa(curcol), currow);
			    linelim = strlen (line);
			    break;
			case 'e':
			    editv (currow, curcol);
			    break;
			case 'E':
			    edits (currow, curcol);
			    break;
			case 'f':
			    sprintf (line, "format [for column] %s [is] ",
					coltoa(curcol));
			    error("Current format is %d %d",
					fwidth[curcol],precision[curcol]);
			    linelim = strlen (line);
			    break;
			case 'g':
			    sprintf (line, "goto [v] ");
			    linelim = strlen (line);
			    break;
			case 'P':
			    sprintf (line, "put [database into] \"");
			    if (*curfile)
			    error("default file is '%s'",curfile);
			    linelim = strlen (line);
			    break;
			case 'M':
			    sprintf (line, "merge [database from] \"");
			    linelim = strlen (line);
			    break;
			case 'G':
			    sprintf (line, "get [database from] \"");
			    if (*curfile)
			    error("default file is '%s'",curfile);
			    linelim = strlen (line);
			    break;
			case 'W':
			    sprintf (line, "write [listing to] \"");
			    linelim = strlen (line);
			    break;
			case 'T':	/* tbl output */
			    sprintf (line, "tbl [listing to] \"");
			    linelim = strlen (line);
			    break;
			case 'i':
			    switch (get_qual()) {
			    case 'r':
				insertrow(arg);
				break;
			    case 'c':
				insertcol(arg);
				break;
			    default:
				error("Invalid insert command");
				break;
			    }
			    break;
			case 'd':
			    switch (get_qual()) {
			    case 'r':
				deleterow(arg);
				break;
			    case 'c':
				deletecol(arg);
				break;
			    default:
				error("Invalid delete command");
				break;
			    }
			    break;
			case 'v':
			    switch (get_qual()) {
			    case 'r':
				rowvalueize(arg);
				modflg++;
				break;
			    case 'c':
				colvalueize(arg);
				modflg++;
				break;
			    default:
				error("Invalid value command");
				break;
			    }
			    break;
			case 'p':
			    {
			    register qual;
			    qual = get_qual();
			    while (arg--)
			        pullcells(qual);
			    break;
			    }
			case 'x':
			    {
			    register struct ent **p;
			    register int c;
			    flush_saved();
			    for (c = curcol; arg-- && c < MAXCOLS; c++) {
				p = &tbl[currow][c];
				if (*p) {
			            free_ent(*p);
			            *p = 0;
				}
			    }
			    sync_refs();
			    FullUpdate++;
			    }
			    break;
			case 'Q':
			case 'q':
			    running = 0;
			    break;
			case 'h':
			    while (--arg>=0) {
				if (curcol)
				    curcol--;
				else
				    error ("At column A");
				while(hidden_col[curcol] && curcol)
				    curcol--;
			    }
			    break;
			case 'j':
			    while (--arg>=0) {
				if (currow < MAXROWS - 1)
				    currow++;
				else
				    error ("The table can't be any longer");
				while (hidden_row[currow]&&(currow<MAXROWS-1))
				    currow++;
			    }
			    break;
			case 'k':
			    while (--arg>=0) {
				if (currow)
				    currow--;
				else
				    error ("At row zero");
				while (hidden_row[currow] && currow)
				    currow--;
			    }
			    break;
			case 'l':
			    while (--arg>=0) {
				if (curcol < MAXCOLS - 1)
				    curcol++;
				else
				    error ("The table can't be any wider");
				while(hidden_col[curcol]&&(curcol<MAXCOLS-1))
				    curcol++;
			    }
			    break;
			case 'm':
			    savedrow = currow;
			    savedcol = curcol;
			    break;
			case 'c': {
			    register struct ent *p = tbl[savedrow][savedcol];
			    register c;
			    register struct ent *n;
			    if (!p)
				break;
			    FullUpdate++;
			    modflg++;
			    for (c = curcol; arg-- && c < MAXCOLS; c++) {
				n = lookat (currow, c);
				clearent(n);
				n -> flags = p -> flags;
				n -> v = p -> v;
				n -> expr = copye(p->expr,
					    currow - savedrow,
					    c - savedcol);
				n -> label = 0;
				if (p -> label) {
				    n -> label =
				       malloc((unsigned)(strlen(p->label)+1));
				strcpy (n -> label, p -> label);
				}
			    }
			    break;
			}
			case 'z':
			    switch (get_qual()) {
			    case 'r':
				hiderow(arg);
				break;
			    case 'c':
				hidecol(arg);
				break;
			    default:
				error("Invalid zap command");
				break;
			    }
			    break;
			case 's':
			    switch (get_qual()) {
			    case 'r':
				rowshow_op();
				break;
			    case 'c':
				colshow_op();
				break;
			    default:
				error("Invalid show command");
				break;
			    }
			    break;
			case 'a':
			    switch (get_qual()) {
			    case 'r':
				while (arg--)
				    duprow();
				break;
			    case 'c':
				while (arg--)
				    dupcol();
				break;
			    default:
				error("Invalid add row/col command");
				break;
			    }
			    break;
			default:
			    if ((c & 0177) != c)
				error("Weird character, decimal '%d'.\n",
					(int) c);
			    else error ("No such command  (%c)", c);
			    break;
		    }
	edistate = nedistate;
	arg = narg;
    }				/* while (running) */
    inloop = modcheck(" before exiting");
    }				/*  while (inloop) */
    move (LINES - 1, 0);
    clrtoeol();
    refresh ();
    nocbreak();
    nl();
    echo ();
    resetkbd();
    endwin ();
}

signals()
{
    int quit();
    int timeout();

    signal(SIGINT, SIG_IGN);
    signal(SIGQUIT, quit);
    signal(SIGPIPE, quit);
    signal(SIGTERM, quit);
    signal(SIGALRM, timeout);
    signal(SIGFPE, quit);
    signal(SIGBUS, quit);
}

quit()
{
    move (LINES - 1, 0);
    clrtoeol();
    refresh();
    nocbreak();
    nl();
    echo();
    resetkbd();
    endwin();
    exit(1);
}

modcheck(endstr) char *endstr; {
    if (modflg && curfile[0]) {
	char ch, lin[100];

	move (0, 0);
	clrtoeol ();
	sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr);
	addstr (lin);
	refresh();
	ch = nmgetch();
 	if (ch != 'n' && ch != 'N')
 	    if (writefile(curfile) < 0)
 		return (1);
	else if (ch == ctl (g) || ch == ctl([)) return(1);
    } else if (modflg) {
	char ch, lin[100];

	move (0, 0);
	clrtoeol ();
	sprintf (lin,"Do you want a chance to save the data? ");
	addstr (lin);
	refresh();
	ch = nmgetch();
	if (ch == 'n' || ch == 'N') return(0);
	else return(1);
      }
    return(0);
}

    
writefile (fname)
char *fname; {
    register FILE *f;
    register struct ent **p;
    register r, c;
    char save[1024];

    if (*fname == 0) fname = &curfile[0];

    strcpy(save,fname);

    f = fopen (fname, "w");
    if (f==0) {
	error ("Can't create %s", fname);
	return (-1);
    }

    fprintf (f, "# This data file was generated by the Spreadsheet ");
    fprintf (f, "Calculator.\n");
    fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
    for (c=0; c<MAXCOLS; c++)
	if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
	    fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
    for (r=0; r<=maxrow; r++) {
	p = &tbl[r][0];
	for (c=0; c<=maxcol; c++, p++)
	    if (*p) {
		if ((*p)->label)
		    fprintf (f, "%sstring %s%d = \"%s\"\n",
				(*p)->flags&is_leftflush ? "left" : "right",
				coltoa(c),r,(*p)->label);
		if ((*p)->flags&is_valid) {
		    editv (r, c);
		    fprintf (f, "%s\n",line);
		}
	    }
    }
    fclose (f);
    strcpy(curfile,save);

    modflg = 0;
    error("File '%s' written.",curfile);
    return (0);
}

readfile (fname,eraseflg)
char *fname; int eraseflg; {
    register FILE *f;
    char save[1024];

    if (*fname == 0) fname = &curfile[0];
    strcpy(save,fname);

    if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;

    f = fopen (save, "r");
    if (f==0) {
	error ("Can't read %s", save);
	return;
    }

    if (eraseflg) erasedb ();

    while (fgets(line,sizeof line,f)) {
	linelim = 0;
	if (line[0] != '#') yyparse ();
    }
    fclose (f);
    linelim = -1;
    modflg++;
    if (eraseflg) {
	strcpy(curfile,save);
	modflg = 0;
    }
    EvalAll();
}

erasedb () {
    register r, c;
    for (c = 0; c<=maxcol; c++) {
	fwidth[c] = DEFWIDTH;
	precision[c] = DEFPREC;
    }

    for (r = 0; r<=maxrow; r++) {
	register struct ent **p = &tbl[r][0];
	for (c=0; c++<=maxcol; p++)
	    if (*p) {
		if ((*p)->expr) efree ((*p) -> expr);
		if ((*p)->label) free ((*p) -> label);
		free ((char *)*p);
		*p = 0;
	    }
    }
    maxrow = 0;
    maxcol = 0;
    FullUpdate++;
}

#if DEBUG
debugout(g,fmt,args) FILE *g; char *fmt; {
    int op;

    if (g == 0) g = fopen("debug","a"),op = 1;
    if (g == 0) return;

    _doprnt(fmt, &args, g);

    fflush(g);
    if (op) fclose(g);
}
#endif
SHAR_EOF
if test 18976 -ne "`wc -c sc.c`"
then
echo shar: error transmitting sc.c '(should have been 18976 characters)'
fi
echo shar: extracting lex.c '(9305 characters)'
cat << \SHAR_EOF > lex.c
/*	SC	A Spreadsheet Calculator
 *		Lexical analyser
 *
 *		original by James Gosling, September 1982
 *		modifications by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 *
 */



#if defined(BSD42) || defined(BSD43)
#include <sys/ioctl.h>
#endif 

#include <curses.h>
#include <signal.h>
#include <setjmp.h>
#include "sc.h"
#include <ctype.h>

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

#include "y.tab.h"

char *strtof();
char *malloc();

jmp_buf wakeup;

struct key {
    char *key;
    int val;
};

struct key experres[] = {
#include "experres.h"
    0, 0};

struct key statres[] = {
#include "statres.h"
    0, 0};

#define ctl(x) ('x'&037)

yylex () {
    register char *p = line+linelim;
    int ret;
    while (isspace(*p)) p++;
    if (*p==0) ret = -1;
    else if (isalpha(*p)) {
	char *tokenst = p;
	register tokenl;
	register struct key *tbl;
	while (isalpha(*p)) p++;
	if ((tokenl = p-tokenst) <= 2) {
	    register  col;  /* a COL is 1 or 2 char alpha (and not pi or ln!) */
	    if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'i') {
		ret = K_PI;
	    } else if (tokenl == 2 && tokenst[0] == 'l' && tokenst[1] == 'n') {
		ret = K_LN;
	    } else {
		ret = COL;
		col = ((tokenst[0] & 0137) - 'A');
		if (p == tokenst+2)
		    col = (col + 1)*26 + ((tokenst[1] & 0137) - 'A');
		yylval.ival =  col;
	    }
	} else {
	    ret = WORD;
	    tokenl = p-tokenst;
	    for (tbl = linelim ? experres : statres; tbl->key; tbl++)
		    if (((tbl->key[0]^tokenst[0])&0137)==0
		     && tbl->key[tokenl]==0) {
			register i = 1;
			while (i<tokenl && ((tokenst[i]^tbl->key[i])&0137)==0)
			    i++;
			if (i>=tokenl) {
			    ret = tbl->val;
			    break;
			}
		    }
	    if (ret==WORD) { 
		linelim = p-line;
		yyerror ("Unintelligible word");
	    }
	}
    } else if ((*p == '.') || isdigit(*p)) {
	register long v = 0;
	char *nstart = p;
	if (*p != '.') {
	    do v = v*10 + (*p-'0');
	    while (isdigit(*++p));
	}
	if (*p=='.' || *p == 'e' || *p == 'E') {
	    ret = FNUMBER;
	    p = strtof(nstart, &yylval.fval);
	} else {
            if((int)v != v)
            {
                ret = FNUMBER;
                yylval.fval = v;
            }
            else
            {
 
                ret = NUMBER;
                yylval.ival = v;
            }
	}
    } else if (*p=='"') {
	/* This storage is never freed.  Oh well.  -MDW */
	char *ptr;
        ptr = p+1;
        while(*ptr && *ptr++ != '"');
        ptr = malloc((unsigned)(ptr-p));
	yylval.sval = ptr;
	p += 1;
	while (*p && *p!='"') *ptr++ = *p++;
	*ptr = 0;
	if (*p) p += 1;
	ret = STRING;
    } else if (*p=='[') {
	while (*p && *p!=']') p++;
	if (*p) p++;
	linelim = p-line;
	return yylex();
    } else ret = *p++;
    linelim = p-line;
    return ret;
}

#ifdef SIMPLE

initkbd()
{}

resetkbd()
{}

nmgetch()
{
    return (getchar() & 0x7f);
}

#else /*SIMPLE*/

#if defined(BSD42) || defined (SYSIII) || defined(BSD43)

#define N_KEY 4

struct key_map {
    char *k_str;
    char k_val;
    char k_index;
}; 

struct key_map km[N_KEY];

char keyarea[N_KEY*10];

char *tgetstr();
char *getenv();

#ifdef TIOCSLTC
struct ltchars old_chars, new_chars;
#endif

char dont_use[] = {
    ctl(z), ctl(r), ctl(l), ctl(b), ctl(c), ctl(f), ctl(g), ctl([),
    ctl(h), ctl(m), ctl(j), ctl(n), ctl(p), ctl(q), ctl(s), ctl(t),
    ctl(u), ctl(v), ctl(e), ctl(a), 0,
};

initkbd()
{
    register struct key_map *kp;
    register i,j;
    char *ks;
    char *p = keyarea;
    static char buf[1024]; /* Why do I have to do this again? */

    if (tgetent(buf, getenv("TERM")) <= 0)
	return;

    km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl(b);
    km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl(f);
    km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl(p);
    km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl(n);
    ks = tgetstr("ks",&p);
    if (ks) 
	printf("%s",ks);

    /* Unmap arrow keys which conflict with our ctl keys   */
    /* Ignore unset, longer than length 1, and 1-1 mapped keys */

    for (i = 0; i < N_KEY; i++) {
	kp = &km[i];
	if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val))
	    for (j = 0; dont_use[j] != 0; j++)
	        if (kp->k_str[0] == dont_use[j]) {
		     kp->k_str = (char *)0;
		     break;
		}
    }


#ifdef TIOCSLTC
    ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars);
    new_chars = old_chars;
    if (old_chars.t_lnextc == ctl(v))
	new_chars.t_lnextc = -1;
    if (old_chars.t_rprntc == ctl(r))
	new_chars.t_rprntc = -1;
    ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
#endif
}

resetkbd()
{
#ifdef TIOCSLTC
    ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars);
#endif
}

nmgetch() 
{
    register int c;
    register struct key_map *kp;
    register struct key_map *biggest;
    register int i;
    int almost;
    int maybe;

    static char dumpbuf[10];
    static char *dumpindex;

    int timeout();

    if (dumpindex && *dumpindex)
	    return (*dumpindex++);

    c = getchar() & 0x7f;
    biggest = 0;
    almost = 0;

    for (kp = &km[0]; kp < &km[N_KEY]; kp++) {
	if (!kp->k_str)
	    continue;
	if (c == kp->k_str[kp->k_index]) {
	    almost = 1;
	    kp->k_index++;
	    if (kp->k_str[kp->k_index] == 0) {
		c = kp->k_val;
       	        for (kp = &km[0]; kp < &km[N_KEY]; kp++)
	            kp->k_index = 0;
	        return(c);
	    }
	}
	if (!biggest && kp->k_index)
	    biggest = kp;
        else if (kp->k_index && biggest->k_index < kp->k_index)
	    biggest = kp;
    }

    if (almost) { 

        signal(SIGALRM, timeout);
        alarm(1);

	if (setjmp(wakeup) == 0) { 
	    maybe = nmgetch();
	    alarm(0);
	    return(maybe);
	}

    }
    
    if (biggest) {
	for (i = 0; i<biggest->k_index; i++) 
	    dumpbuf[i] = biggest->k_str[i];
	dumpbuf[i++] = c;
	dumpbuf[i] = 0;
	dumpindex = &dumpbuf[1];
       	for (kp = &km[0]; kp < &km[N_KEY]; kp++)
	    kp->k_index = 0;
	return (dumpbuf[0]);
    }

    return(c);
}

#endif

#ifdef SYSV

initkbd()
{
    keypad(stdscr, TRUE);
}

resetkbd()
{}

nmgetch()
{
    register int c;

    c = getch();
    switch (c) {
    case KEY_LEFT:  c = ctl(b); break;
    case KEY_RIGHT: c = ctl(f); break;
    case KEY_UP:    c = ctl(p); break;
    case KEY_DOWN:  c = ctl(n); break;
    default:   c = c & 0x7f; 
    }
    return (c);
}

#endif /* SYSV */

#endif /* SIMPLE */

timeout()
{
    longjmp(wakeup, -1);
}

int dbline;

/*VARARGS*/
void
debug (str)
char *str;
{
	mvprintw (2+(dbline++%22),80-70,str);
	clrtoeol();
}

/*
 * This converts a floating point number of the form
 * [s]ddd[.d*][esd*]  where s can be a + or - and e is E or e.
 * to floating point. 
 * p is advanced.
 */

char *
strtof(p, res)
register char *p;
double *res;
{
    double acc;
    int sign;
    double fpos;
    int exp;
    int exps;

    acc = 0.0;
    sign = 1;
    exp = 0;
    exps = 1;
    if (*p == '+')
        p++;
    else if (*p == '-') {
        p++;
        sign = -1;
    }
    while (isdigit(*p)) {
        acc = acc * 10.0 + (double)(*p - '0');
        p++;
    }
    if (*p == 'e' || *p == 'E') {
	    p++;
        if (*p == '+')
	    p++;
        else if (*p == '-') {
	    p++;
	    exps = -1;
        }
        while(isdigit(*p)) {
	    exp = exp * 10 + (*p - '0');
	    p++;
        }
    }
    if (*p == '.') {
	fpos = 1.0/10.0;
	p++;
	while(isdigit(*p)) {
	    acc += (*p - '0') * fpos;
	    fpos *= 1.0/10.0;
	    p++;
	}
    }
    if (*p == 'e' || *p == 'E') {
	exp = 0;
	exps = 1;
        p++;
	if (*p == '+')
	    p++;
	else if (*p == '-') {
	    p++;
	    exps = -1;
	}
	while(isdigit(*p)) {
	    exp = exp * 10 + (*p - '0');
	    p++;
	}
    }
    if (exp) {
	if (exps > 0)
	    while (exp--)
		acc *= 10.0;
	else
	    while (exp--)
		acc *= 1.0/10.0;
    }
    if (sign > 0)
        *res = acc;
    else
	*res = -acc;

    return(p);
}

help () {
    move(2,0);
    clrtobot();
    dbline = 0;
    debug ("Cursor:     ^n j next row       ^p k prev. row  ESC ^g erase cmd");
    debug ("            ^f l fwd col        ^b h back col    ^l ^r redraw screen");
    debug ("               0 col A             $ last col        g goto ");
    debug ("               ^ row 0             # last row");
    debug ("Cell:      \" < > enter label       = enter value     x clear cell");
    debug ("               c copy cell         m mark cell      ^t line 1 on/off");  
    debug ("              ^a type value       ^e type expr.     ^v type vbl name");
    debug ("Row, Col:  ar ac dup           ir ic insert      sr sc show");
    debug ("           dr dc delete        zr zc hide        pr pc pull");
    debug ("           vr vc value only        f format");
    debug ("Region:       /c copy             /x clear          /f fill");
    debug ("File:          G get database      M merge database  T write tbl fmt");
    debug ("               P put database      W write listing");
    debug ("Misc:        Q q quit             pm pull (merge)");
    debug ("Expr:      +-*/^ arithmetic     ?e:e conditional   & | booleans");
    debug ("           < = > relations     <= >= relations      != relations");
    debug ("                 @sum(v1:v2)         @avg(v1:v2)       @prod(v1:v2)");
    debug ("                 @func(e) - lots of other math functions");
}
SHAR_EOF
if test 9305 -ne "`wc -c lex.c`"
then
echo shar: error transmitting lex.c '(should have been 9305 characters)'
fi
echo shar: extracting gram.y '(4962 characters)'
cat << \SHAR_EOF > gram.y
/*	SC	A Spreadsheet Calculator
 *		Command and expression parser
 *
 *		original by James Gosling, September 1982
 *		modified by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 * 		more mods Robert Bond 12/86
 *
 */



%{
#include <curses.h>
#include "sc.h"
%}

%union {
    int ival;
    double fval;
    struct ent *ent;
    struct enode *enode;
    char *sval;
}

%type <ent> var
%type <fval> num
%type <enode> e term
%token <sval> STRING
%token <ival> NUMBER
%token <fval> FNUMBER
%token <sval> WORD
%token <ival> COL
%token S_FORMAT
%token S_LABEL
%token S_LEFTSTRING
%token S_RIGHTSTRING
%token S_GET
%token S_PUT
%token S_MERGE
%token S_LET
%token S_WRITE
%token S_TBL
%token S_PROGLET
%token S_COPY
%token S_SHOW
%token S_ERASE
%token S_FILL
%token S_GOTO

%token K_FIXED
%token K_SUM
%token K_PROD
%token K_AVG
%token K_ACOS
%token K_ASIN
%token K_ATAN
%token K_CEIL
%token K_COS
%token K_EXP
%token K_FABS
%token K_FLOOR
%token K_HYPOT
%token K_LN
%token K_LOG
%token K_PI
%token K_POW
%token K_SIN
%token K_SQRT
%token K_TAN
%token K_DTR
%token K_RTD
%token K_MAX
%token K_MIN

%left '?' ':'
%left '|'
%left '&'
%nonassoc '<' '=' '>'
%left '+' '-'
%left '*' '/'
%left '^'

%%
command:	S_LET var '=' e	{ let ($2, $4); }
	|	S_LABEL var '=' STRING
				{ label ($2, $4, 0); }
	|	S_LEFTSTRING var '=' STRING
				{ label ($2, $4, -1); }
	|	S_RIGHTSTRING var '=' STRING
				{ label ($2, $4, 1); }
	|	S_FORMAT COL NUMBER NUMBER
				{ fwidth[$2] = $3;
				  FullUpdate++;
				  modflg++;
				  precision[$2] = $4; }
	|	S_GET STRING	{ readfile ($2,1); }
	|	S_MERGE STRING	{ readfile ($2,0); }
	|	S_PUT STRING	{ (void) writefile ($2); }
	|	S_WRITE STRING	{ printfile ($2); }
	|	S_TBL STRING	{ tblprintfile ($2); }
	|       S_SHOW COL ':' COL  { showcol( $2, $4); }
	|       S_SHOW NUMBER ':' NUMBER  { showrow( $2, $4); }
	|	S_COPY var var ':' var { copy($2, $3, $5); }
	|	S_ERASE var ':' var { eraser($2, $4); }
	|	S_FILL var ':' var num num { fill($2, $4, $5, $6); }
	|	S_GOTO var	 {moveto($2); }
	|	/* nothing */
	|	error;

term: 		var		{ $$ = new_var('v', $1); }
	|	K_FIXED term	{ $$ = new ('f', (struct enode *)0, $2); }
	|       '@' K_SUM '(' var ':' var ')' 
				{ $$ = new (O_REDUCE('+'),
				(struct enode *)$4, (struct enode *)$6); }
	|       '@' K_PROD '(' var ':' var ')' 
				{ $$ = new (O_REDUCE('*'),
				(struct enode *)$4, (struct enode *)$6); }
	|       '@' K_AVG '(' var ':' var ')' 
				{ $$ = new (O_REDUCE('a'),
				(struct enode *)$4, (struct enode *)$6); }
	| '@' K_ACOS '(' e ')'	{ $$ = new(ACOS, (struct enode *)0, $4); }
	| '@' K_ASIN '(' e ')'	{ $$ = new(ASIN, (struct enode *)0, $4); }
	| '@' K_ATAN '(' e ')'	{ $$ = new(ATAN, (struct enode *)0, $4); }
	| '@' K_CEIL '(' e ')'	{ $$ = new(CEIL, (struct enode *)0, $4); }
	| '@' K_COS '(' e ')'	{ $$ = new(COS, (struct enode *)0, $4); }
	| '@' K_EXP '(' e ')'	{ $$ = new(EXP, (struct enode *)0, $4); }
	| '@' K_FABS '(' e ')'	{ $$ = new(FABS, (struct enode *)0, $4); }
	| '@' K_FLOOR '(' e ')'	{ $$ = new(FLOOR, (struct enode *)0, $4); }
	| '@' K_HYPOT '(' e ',' e ')'	{ $$ = new(HYPOT, $4, $6); }
	| '@' K_LN '(' e ')'	{ $$ = new(LOG, (struct enode *)0, $4); }
	| '@' K_LOG '(' e ')'	{ $$ = new(LOG10, (struct enode *)0, $4); }
	| '@' K_POW '(' e ',' e ')'	{ $$ = new(POW, $4, $6); }
	| '@' K_SIN '(' e ')'	{ $$ = new(SIN, (struct enode *)0, $4); }
	| '@' K_SQRT '(' e ')'	{ $$ = new(SQRT, (struct enode *)0, $4); }
	| '@' K_TAN '(' e ')'	{ $$ = new(TAN, (struct enode *)0, $4); }
	| '@' K_DTR '(' e ')'	{ $$ = new(DTR, (struct enode *)0, $4); }
	| '@' K_RTD '(' e ')'	{ $$ = new(RTD, (struct enode *)0, $4); }
	| '@' K_MAX '(' e ',' e ')'	{ $$ = new(MAX, $4, $6); }
	| '@' K_MIN '(' e ',' e ')'	{ $$ = new(MIN, $4, $6); }
	|	'(' e ')'	{ $$ = $2; }
	|	'+' term	{ $$ = $2; }
	|	'-' term	{ $$ = new ('m', (struct enode *)0, $2); }
	|	NUMBER		{ $$ = new_const('k', (double) $1); }
	|	FNUMBER		{ $$ = new_const('k', $1); }
	|	K_PI	{ $$ = new_const('k', (double)3.14159265358979323846); }
	|	'~' term	{ $$ = new ('~', (struct enode *)0, $2); }
	|	'!' term	{ $$ = new ('~', (struct enode *)0, $2); }
	;

e:		e '+' e		{ $$ = new ('+', $1, $3); }
	|	e '-' e		{ $$ = new ('-', $1, $3); }
	|	e '*' e		{ $$ = new ('*', $1, $3); }
	|	e '/' e		{ $$ = new ('/', $1, $3); }
	|	e '^' e		{ $$ = new ('^', $1, $3); }
	|	term
	|	e '?' e ':' e	{ $$ = new ('?', $1, new(':', $3, $5)); }
	|	e '<' e		{ $$ = new ('<', $1, $3); }
	|	e '=' e		{ $$ = new ('=', $1, $3); }
	|	e '>' e		{ $$ = new ('>', $1, $3); }
	|	e '&' e		{ $$ = new ('&', $1, $3); }
	|	e '|' e		{ $$ = new ('|', $1, $3); }
	|	e '<' '=' e	{ $$ = new ('~', (struct enode *)0,
						new ('>', $1, $4)); }
	|	e '!' '=' e	{ $$ = new ('~', (struct enode *)0, 
						new ('=', $1, $4)); }
	|	e '>' '=' e	{ $$ = new ('~', (struct enode *)0, 
						new ('<', $1, $4)); }
	;

var:		COL NUMBER	{ $$ = lookat($2 , $1); };

num:		NUMBER		{ $$ = (double) $1; }
	|	FNUMBER		{ $$ = $1; }
	|	'-' num		{ $$ = -$2; }
	|	'+' num		{ $$ = $2; }
	;
SHAR_EOF
if test 4962 -ne "`wc -c gram.y`"
then
echo shar: error transmitting gram.y '(should have been 4962 characters)'
fi
echo shar: extracting interp.c '(17239 characters)'
cat << \SHAR_EOF > interp.c
/*	SC	A Spreadsheet Calculator
 *		Expression interpreter and assorted support routines.
 *
 *		original by James Gosling, September 1982
 *		modified by Mark Weiser and Bruce Israel, 
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 */

#include <math.h>
#include <stdio.h>

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

#include <curses.h>
#include "sc.h"
#define DEFCOLDELIM ':'

char *malloc();
#define PI (double)3.14159265358979323846
#define dtr(x) ((x)*(PI/(double)180.0))
#define rtd(x) ((x)*(180.0/(double)PI))

double dosum(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c;
    register struct ent *p;

    v = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid)
		v += p->v;
    return v;
}

double doprod(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c;
    register struct ent *p;

    v = 1;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid)
		v *= p->v;
    return v;
}

double doavg(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c,count;
    register struct ent *p;

    v = 0;
    count = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid) {
		v += p->v;
		count++;
	    }

    if (count == 0) 
	return ((double) 0);

    return (v / (double)count);
}

double eval(e)
register struct enode *e; {
    if (e==0) return 0;
    switch (e->op) {
	case '+':	return (eval(e->e.o.left) + eval(e->e.o.right));
	case '-':	return (eval(e->e.o.left) - eval(e->e.o.right));
	case '*':	return (eval(e->e.o.left) * eval(e->e.o.right));
	case '/':     {	double denom = eval (e->e.o.right);
			return denom ? eval(e->e.o.left) / denom : 0; }
	case '^':	return (pow(eval(e->e.o.left), eval(e->e.o.right)));
	case '<':	return (eval(e->e.o.left) < eval(e->e.o.right));
	case '=':	return (eval(e->e.o.left) == eval(e->e.o.right));
	case '>':	return (eval(e->e.o.left) > eval(e->e.o.right));
	case '&':	return (eval(e->e.o.left) && eval(e->e.o.right));
	case '|':	return (eval(e->e.o.left) || eval(e->e.o.right));
	case '?':	return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
						 : eval(e->e.o.right->e.o.right);
	case 'm':	return (-eval(e->e.o.right));
	case 'f':	return (eval(e->e.o.right));
	case '~':	return ((double)!(int)eval(e->e.o.right));
	case 'k':	return (e->e.k);
	case 'v':	return (e->e.v->v);
	case O_REDUCE('+'):
 	case O_REDUCE('*'):
 	case O_REDUCE('a'):
	    {	register r,c;
		register maxr, maxc;
		register minr, minc;
		maxr = ((struct ent *) e->e.o.right) -> row;
		maxc = ((struct ent *) e->e.o.right) -> col;
		minr = ((struct ent *) e->e.o.left) -> row;
		minc = ((struct ent *) e->e.o.left) -> col;
		if (minr>maxr) r = maxr, maxr = minr, minr = r;
		if (minc>maxc) c = maxc, maxc = minc, minc = c;
	        switch (e->op) {
	            case O_REDUCE('+'): return dosum(minr, minc, maxr, maxc);
 	            case O_REDUCE('*'): return doprod(minr, minc, maxr, maxc);
 	            case O_REDUCE('a'): return doavg(minr, minc, maxr, maxc);
		}
	    }
	case ACOS:	 return (acos(eval(e->e.o.right)));
	case ASIN:	 return (asin(eval(e->e.o.right)));
	case ATAN:	 return (atan(eval(e->e.o.right)));
	case CEIL:	 return (ceil(eval(e->e.o.right)));
	case COS:	 return (cos(eval(e->e.o.right)));
	case EXP:	 return (exp(eval(e->e.o.right)));
	case FABS:	 return (fabs(eval(e->e.o.right)));
	case FLOOR:	 return (floor(eval(e->e.o.right)));
	case HYPOT:	 return (hypot(eval(e->e.o.left), eval(e->e.o.right)));
	case LOG:	 return (log(eval(e->e.o.right)));
	case LOG10:	 return (log10(eval(e->e.o.right)));
	case POW:	 return (pow(eval(e->e.o.left), eval(e->e.o.right)));
	case SIN:	 return (sin(eval(e->e.o.right)));
	case SQRT:	 return (sqrt(eval(e->e.o.right)))   ^t line 1 on/off");  
    debug ("              ^a type value       ^e type expr.     ^v type vbl name");
    debug ("Row, Col:  ar ac dup           ir ic insert      sr sc show");
    debug ("           dr dc delete        zr zc hide        pr pc pull");
    debug ("           vr vc value only        f format");
    debug ("Region:       /c copy             /x clear          /f fill");
    debug ("File:          G get database      M merge database  T write tbl fmt");
    debug ("               P put database      W write listing");
    debug ("Misc:        Q q quit             pm pull (merge)");
    debug ("Expr:      +-*/^ arithmetic     ?e:e conditional   & | booleans");
    debug ("           < = > relations     <= >= relations      != relations");
    debug ("                 @sum(v1:v2)         @avg(v1:v2)       @prod(v1:v2)");
    debug ("                 @func(e) - lots of other math functions");
}
SHAR_EOF
if test 9305 -ne "`wc -c lex.c`"
then
echo shar: error transmitting lex.c '(should have been 9305 characters)'
fi
echo shar: extracting gram.y '(4962 characters)'
cat << \SHAR_EOF > gram.y
/*	SC	A Spreadsheet Calculator
 *		Command and expression parser
 *
 *		original by James Gosling, September 1982
 *		modified by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 * 		more mods Robert Bond 12/86
 *
 */



%{
#include <curses.h>
#include "sc.h"
%}

%union {
    int ival;
    double fval;
    struct ent *ent;
    struct enode *enode;
    char *sval;
}

%type <ent> var
%type <fval> num
%type <enode> e term
%token <sval> STRING
%token <ival> NUMBER
%token <fval> FNUMBER
%token <sval> WORD
%token <ival> COL
%token S_FORMAT
%token S_LABEL
%token S_LEFTSTRING
%token S_RIGHTSTRING
%token S_GET
%token S_PUT
%token S_MERGE
%token S_LET
%token S_WRITE
%token S_TBL
%token S_PROGLET
%token S_COPY
%token S_SHOW
%token S_ERASE
%token S_FILL
%token S_GOTO

%token K_FIXED
%token K_SUM
%token K_PROD
%token K_AVG
%token K_ACOS
%token K_ASIN
%token K_ATAN
%token K_CEIL
%token K_COS
%token K_EXP
%token K_FABS
%token K_FLOOR
%token K_HYPOT
%token K_LN
%token K_LOG
%token K_PI
%token K_POW
%token K_SIN
%token K_SQRT
%token K_TAN
%token K_DTR
%token K_RTD
%token K_MAX
%token K_MIN

%left '?' ':'
%left '|'
%left '&'
%nonassoc '<' '=' '>'
%left '+' '-'
%left '*' '/'
%left '^'

%%
command:	S_LET var '=' e	{ let ($2, $4); }
	|	S_LABEL var '=' STRING
				{ label ($2, $4, 0); }
	|	S_LEFTSTRING var '=' STRING
				{ label ($2, $4, -1); }
	|	S_RIGHTSTRING var '=' STRING
				{ label ($2, $4, 1); }
	|	S_FORMAT COL NUMBER NUMBER
				{ fwidth[$2] = $3;
				  FullUpdate++;
				  modflg++;
				  precision[$2] = $4; }
	|	S_GET STRING	{ readfile ($2,1); }
	|	S_MERGE STRING	{ readfile ($2,0); }
	|	S_PUT STRING	{ (void) writefile ($2); }
	|	S_WRITE STRING	{ printfile ($2); }
	|	S_TBL STRING	{ tblprintfile ($2); }
	|       S_SHOW COL ':' COL  { showcol( $2, $4); }
	|       S_SHOW NUMBER ':' NUMBER  { showrow( $2, $4); }
	|	S_COPY var var ':' var { copy($2, $3, $5); }
	|	S_ERASE var ':' var { eraser($2, $4); }
	|	S_FILL var ':' var num num { fill($2, $4, $5, $6); }
	|	S_GOTO var	 {moveto($2); }
	|	/* nothing */
	|	error;

term: 		var		{ $$ = new_var('v', $1); }
	|	K_FIXED term	{ $$ = new ('f', (struct enode *)0, $2); }
	|       '@' K_SUM '(' var ':' var ')' 
				{ $$ = new (O_REDUCE('+'),
				(struct enode *)$4, (struct enode *)$6); }
	|       '@' K_PROD '(' var ':' var ')' 
				{ $$ = new (O_REDUCE('*'),
				(struct enode *)$4, (struct enode *)$6); }
	|       '@' K_AVG '(' var ':' var ')' 
				{ $$ = new (O_REDUCE('a'),
				(struct enode *)$4, (struct enode *)$6); }
	| '@' K_ACOS '(' e ')'	{ $$ = new(ACOS, (struct enode *)0, $4); }
	| '@' K_ASIN '(' e ')'	{ $$ = new(ASIN, (struct enode *)0, $4); }
	| '@' K_ATAN '(' e ')'	{ $$ = new(ATAN, (struct enode *)0, $4); }
	| '@' K_CEIL '(' e ')'	{ $$ = new(CEIL, (struct enode *)0, $4); }
	| '@' K_COS '(' e ')'	{ $$ = new(COS, (struct enode *)0, $4); }
	| '@' K_EXP '(' e ')'	{ $$ = new(EXP, (struct enode *)0, $4); }
	| '@' K_FABS '(' e ')'	{ $$ = new(FABS, (struct enode *)0, $4); }
	| '@' K_FLOOR '(' e ')'	{ $$ = new(FLOOR, (struct enode *)0, $4); }
	| '@' K_HYPOT '(' e ',' e ')'	{ $$ = new(HYPOT, $4, $6); }
	| '@' K_LN '(' e ')'	{ $$ = new(LOG, (struct enode *)0, $4); }
	| '@' K_LOG '(' e ')'	{ $$ = new(LOG10, (struct enode *)0, $4); }
	| '@' K_POW '(' e ',' e ')'	{ $$ = new(POW, $4, $6); }
	| '@' K_SIN '(' e ')'	{ $$ = new(SIN, (struct enode *)0, $4); }
	| '@' K_SQRT '(' e ')'	{ $$ = new(SQRT, (struct enode *)0, $4); }
	| '@' K_TAN '(' e ')'	{ $$ = new(TAN, (struct enode *)0, $4); }
	| '@' K_DTR '(' e ')'	{ $$ = new(DTR, (struct enode *)0, $4); }
	| '@' K_RTD '(' e ')'	{ $$ = new(RTD, (struct enode *)0, $4); }
	| '@' K_MAX '(' e ',' e ')'	{ $$ = new(MAX, $4, $6); }
	| '@' K_MIN '(' e ',' e ')'	{ $$ = new(MIN, $4, $6); }
	|	'(' e ')'	{ $$ = $2; }
	|	'+' term	{ $$ = $2; }
	|	'-' term	{ $$ = new ('m', (struct enode *)0, $2); }
	|	NUMBER		{ $$ = new_const('k', (double) $1); }
	|	FNUMBER		{ $$ = new_const('k', $1); }
	|	K_PI	{ $$ = new_const('k', (double)3.14159265358979323846); }
	|	'~' term	{ $$ = new ('~', (struct enode *)0, $2); }
	|	'!' term	{ $$ = new ('~', (struct enode *)0, $2); }
	;

e:		e '+' e		{ $$ = new ('+', $1, $3); }
	|	e '-' e		{ $$ = new ('-', $1, $3); }
	|	e '*' e		{ $$ = new ('*', $1, $3); }
	|	e '/' e		{ $$ = new ('/', $1, $3); }
	|	e '^' e		{ $$ = new ('^', $1, $3); }
	|	term
	|	e '?' e ':' e	{ $$ = new ('?', $1, new(':', $3, $5)); }
	|	e '<' e		{ $$ = new ('<', $1, $3); }
	|	e '=' e		{ $$ = new ('=', $1, $3); }
	|	e '>' e		{ $$ = new ('>', $1, $3); }
	|	e '&' e		{ $$ = new ('&', $1, $3); }
	|	e '|' e		{ $$ = new ('|', $1, $3); }
	|	e '<' '=' e	{ $$ = new ('~', (struct enode *)0,
						new ('>', $1, $4)); }
	|	e '!' '=' e	{ $$ = new ('~', (struct enode *)0, 
						new ('=', $1, $4)); }
	|	e '>' '=' e	{ $$ = new ('~', (struct enode *)0, 
						new ('<', $1, $4)); }
	;

var:		COL NUMBER	{ $$ = lookat($2 , $1); };

num:		NUMBER		{ $$ = (double) $1; }
	|	FNUMBER		{ $$ = $1; }
	|	'-' num		{ $$ = -$2; }
	|	'+' num		{ $$ = $2; }
	;
SHAR_EOF
if test 4962 -ne "`wc -c gram.y`"
then
echo shar: error transmitting gram.y '(should have been 4962 characters)'
fi
echo shar: extracting interp.c '(17239 characters)'
cat << \SHAR_EOF > interp.c
/*	SC	A Spreadsheet Calculator
 *		Expression interpreter and assorted support routines.
 *
 *		original by James Gosling, September 1982
 *		modified by Mark Weiser and Bruce Israel, 
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 */

#include <math.h>
#include <stdio.h>

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

#include <curses.h>
#include "sc.h"
#define DEFCOLDELIM ':'

char *malloc();
#define PI (double)3.14159265358979323846
#define dtr(x) ((x)*(PI/(double)180.0))
#define rtd(x) ((x)*(180.0/(double)PI))

double dosum(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c;
    register struct ent *p;

    v = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid)
		v += p->v;
    return v;
}

double doprod(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c;
    register struct ent *p;

    v = 1;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid)
		v *= p->v;
    return v;
}

double doavg(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double v;
    register r,c,count;
    register struct ent *p;

    v = 0;
    count = 0;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++)
	    if ((p = tbl[r][c]) && p->flags&is_valid) {
		v += p->v;
		count++;
	    }

    if (count == 0) 
	return ((double) 0);

    return (v / (double)count);
}

double eval(e)
register struct enode *e; {
    if (e==0) return 0;
    switch (e->op) {
	case '+':	return (eval(e->e.o.left) + eval(e->e.o.right));
	case '-':	return (eval(e->e.o.left) - eval(e->e.o.right));
	case '*':	return (eval(e->e.o.left) * eval(e->e.o.right));
	case '/':     {	double denom = eval (e->e.o.right);
			return denom ? eval(e->e.o.left) / denom : 0; }
	case '^':	return (pow(eval(e->e.o.left), eval(e->e.o.right)));
	case '<':	return (eval(e->e.o.left) < eval(e->e.o.right));
	case '=':	return (eval(e->e.o.left) == eval(e->e.o.right));
	case '>':	return (eval(e->e.o.left) > eval(e->e.o.right));
	case '&':	return (eval(e->e.o.left) && eval(e->e.o.right));
	case '|':	return (eval(e->e.o.left) || eval(e->e.o.right));
	case '?':	return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
						 : eval(e->e.o.right->e.o.right);
	case 'm':	return (-eval(e->e.o.right));
	case 'f':	return (eval(e->e.o.right));
	case '~':	return ((double)!(int)eval(e->e.o.right));
	case 'k':	return (e->e.k);
	case 'v':	return (e->e.v->v);
	case O_REDUCE('+'):
 	case O_REDUCE('*'):
 	case O_REDUCE('a'):
	    {	register r,c;
		register maxr, maxc;
		register minr, minc;
		maxr = ((struct ent *) e->e.o.right) -> row;
		maxc = ((struct ent *) e->e.o.right) -> col;
		minr = ((struct ent *) e->e.o.left) -> row;
		minc = ((struct ent *) e->e.o.left) -> col;
		if (minr>maxr) r = maxr, maxr = minr, minr = r;
		if (minc>maxc) c = maxc, maxc = minc, minc = c;
	        switch (e->op) {
	            case O_REDUCE('+'): return dosum(minr, minc, maxr, maxc);
 	            case O_REDUCE('*'): return doprod(minr, minc, maxr, maxc);
 	            case O_REDUCE('a'): return doavg(minr, minc, maxr, maxc);
		}
	    }
	case ACOS:	 return (acos(eval(e->e.o.right)));
	case ASIN:	 return (asin(eval(e->e.o.right)));
	case ATAN:	 return (atan(eval(e->e.o.right)));
	case CEIL:	 return (ceil(eval(e->e.o.right)));
	case COS:	 return (cos(eval(e->e.o.right)));
	case EXP:	 return (exp(eval(e->e.o.right)));
	case FABS:	 return (fabs(eval(e->e.o.right)));
	case FLOOR:	 return (floor(eval(e->e.o.right)));
	case HYPOT:	 return (hypot(eval(e->e.o.left), eval(e->e.o.right)));
	case LOG:	 return (log(eval(e->e.o.right)));
	case LOG10:	 return (log10(eval(e->e.o.right)));
	case POW:	 return (pow(eval(e->e.o.left), eval(e->e.o.right)));
	case SIN:	 return (sin(eval(e->e.o.right)));
	case SQRT:	 return (sqrt(eval(e->e.o.right)));
	case TAN:	 return (tan(eval(e->e.o.right)));
	case DTR:	 return (dtr(eval(e->e.o.right)));
	case RTD:	 return (rtd(eval(e->e.o.right)));
	case MIN:	 {
			     double left, right;
			     left = eval(e->e.o.left);
			     right = eval(e->e.o.right);
			     return (left < right ? left : right);
			 }
	case MAX:	 {
			     double left, right;
			     left = eval(e->e.o.left);
			     right = eval(e->e.o.right);
			     return (left > right ? left : right);
			 }
    }
    return((double) 0.0); 	/* safety net */
}

#define MAXPROP 7

EvalAll () {
    int repct = 0;

    while (RealEvalAll() && (repct++ <= MAXPROP));
}

int RealEvalAll () {
    register i,j;
    int chgct = 0;
    register struct ent *p;
    for (i=0; i<=maxrow; i++)
	for (j=0; j<=maxcol; j++)
	    if ((p=tbl[i][j]) && p->expr) {
		double v = eval (p->expr);
		if (v != p->v) {
		    p->v = v; chgct++;
		    p->flags |= (is_changed|is_valid);
		}
	    }
    return(chgct);
}

struct enode *new(op, a1, a2)
struct enode *a1, *a2;
{
    register struct enode *p = (struct enode *) malloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.o.left = a1;
    p->e.o.right = a2;
    return p;
}

struct enode *new_var(op, a1)
struct ent *a1;
{
    register struct enode *p = (struct enode *) malloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.v = a1;
    return p;
}

struct enode *new_const(op, a1)
double a1;
{
    register struct enode *p = (struct enode *) malloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.k = a1;
    return p;
}

copy (dv, v1, v2)
struct ent *dv, *v1, *v2;
{
    register r,c;
    register struct ent *p;
    register struct ent *n;
    register deltar, deltac;
    int maxr, maxc;
    int minr, minc;
    int dr, dc;

    dr = dv->row;
    dc = dv->col;
    maxr = v2->row;
    maxc = v2->col;
    minr = v1->row;
    minc = v1->col;
    if (minr>maxr) r = maxr, maxr = minr, minr = r;
    if (minc>maxc) c = maxc, maxc = minc, minc = c;
    if (dr+maxr-minr >= MAXROWS  || 
           dc+maxc-minc >= MAXCOLS) {
	error ("The table can't be any bigger");
	return;
    }
    deltar = dr-minr;
    deltac = dc-minc;
    FullUpdate++;
    for (r = minr; r<=maxr; r++)
	for (c = minc; c<=maxc; c++) {
	    n = lookat (r+deltar, c+deltac);
	    clearent(n);
	    if (p = tbl[r][c]) {
		n -> v = p -> v;
		n -> flags = p -> flags;
		n -> expr = copye(p->expr, deltar, deltac);
		n -> label = 0;
		if (p -> label) {
		    n -> label = malloc ((unsigned)(strlen (p -> label) + 1));
		    strcpy (n -> label, p -> label);
		}
	    }
	}
}

eraser(v1, v2)
struct ent *v1, *v2;
{
	FullUpdate++;
	flush_saved();
	erase_area(v1->row, v1->col, v2->row, v2->col);
}

moveto(v)
struct ent *v;
{
    currow = v->row;
    curcol = v->col;
}

fill (v1, v2, start, inc)
struct ent *v1, *v2;
double start, inc;
{
    register r,c;
    register struct ent *n;
    int maxr, maxc;
    int minr, minc;

    maxr = v2->row;
    maxc = v2->col;
    minr = v1->row;
    minc = v1->col;
    if (minr>maxr) r = maxr, maxr = minr, minr = r;
    if (minc>maxc) c = maxc, maxc = minc, minc = c;
    if (maxr >= MAXROWS) maxr = MAXROWS-1;
    if (maxc >= MAXCOLS) maxc = MAXCOLS-1;
    if (minr < 0) minr = 0;
    if (minr < 0) minr = 0;

    FullUpdate++;
    for (r = minr; r<=maxr; r++)
	for (c