v13i018: SC spreadsheet program, version 5.1, Part03/03

Rich Salz rsalz at bbn.com
Fri Feb 5 08:13:50 AEST 1988


Submitted-by: nscpdc.nsc.com!rgb
Posting-number: Volume 13, Issue 18
Archive-name: sc5.1/part03

# This is a shell archive.  Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have default permissions).
# This archive contains the following files:
#	./interp.c
#	./cmds.c
#	./crypt.c
#	./xmalloc.c
#	./range.c
#	./eres.sed
#	./sres.sed
#	./Makefile
#	./cvt.sed
#	./psc.c
#
if `test ! -s ./interp.c`
then
echo "Extracting ./interp.c"
cat > ./interp.c << '\SHAR\EOF\'
/*	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 <signal.h>
#include <setjmp.h>
#include <stdio.h>

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

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

extern char curfile[];

jmp_buf fpe_save;
int	exprerr;	/* Set by eval() and seval() if expression errors */

#ifdef SYSV3
void exit();
#endif
#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
dostddev(minr, minc, maxr, maxc)
int minr, minc, maxr, maxc;
{
    double lp, rp, v, nd;
    register r,c,n;
    register struct ent *p;

    n = 0;
    lp = 0;
    rp = 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;
		lp += v*v;
		rp += v;
		n++;
	    }

    if ((n == 0) || (n == 1)) 
	return ((double) 0);
    nd = (double)n;
    return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
}

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

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

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

    return (v);
}

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

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

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

    return (v);
}

double
dotime(which, when)
int which;
double when;
{
	long time();

	static long t_cache;
	static struct tm *tp;
	long tloc;

	if (which == NOW) 
	    return (double)time((long *)0);

	tloc = (long)when;

	if (tloc != t_cache) {
	    tp = localtime(&tloc);
	    tp->tm_mon += 1;
	    tp->tm_year += 1900;
	    t_cache = tloc;
	}

	switch (which) {
		case HOUR: return((double)(tp->tm_hour));
		case MINUTE: return((double)(tp->tm_min));
		case SECOND: return((double)(tp->tm_sec));
		case MONTH: return((double)(tp->tm_mon));
		case DAY: return((double)(tp->tm_mday));
		case YEAR: return((double)(tp->tm_year));
	}
	/* Safety net */
	return (0.0);
}

double
doston(s)
char *s;
{
    char *strtof();
    double v;

    if (!s)
	return((double)0.0);

    (void)strtof(s, &v);
    xfree(s);
    return(v);
}

double
doeqs(s1, s2)
char *s1, *s2;
{
    double v;

    if (strcmp(s1, s2) == 0)
	v = 1.0;
    else
	v = 0.0;

    if (s1)
    	xfree(s1);

    if (s2)
    	xfree(s2);

    return(v);
}

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 (eval(e->e.o.right) == 0.0);
	case 'k':	return (e->e.k);
	case 'v':	return (e->e.v.vp->v);
	case O_REDUCE('+'):
 	case O_REDUCE('*'):
 	case O_REDUCE('a'):
 	case O_REDUCE('s'):
	case O_REDUCE(MAX):
	case O_REDUCE(MIN):
	    {	register r,c;
		register maxr, maxc;
		register minr, minc;
		maxr = e->e.r.right.vp -> row;
		maxc = e->e.r.right.vp -> col;
		minr = e->e.r.left.vp -> row;
		minc = e->e.r.left.vp -> 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 O_REDUCE('s'): return dostddev(minr, minc, maxr, maxc);
 	            case O_REDUCE(MAX): return domax(minr, minc, maxr, maxc);
 	            case O_REDUCE(MIN): return domin(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:	 { double arg = eval(e->e.o.right);
			   return arg ? log(arg) : 0; }
	case LOG10:	 { double arg = eval(e->e.o.right);
			   return arg ? log10(arg) : 0; }
	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 RND:	 {
			    double temp;
			    temp = eval(e->e.o.right);
			    return(temp-floor(temp) < 0.5 ?
					     floor(temp) : ceil(temp));
			 }
	case HOUR:	 return (dotime(HOUR, eval(e->e.o.right)));
	case MINUTE:	 return (dotime(MINUTE, eval(e->e.o.right)));
	case SECOND:	 return (dotime(SECOND, eval(e->e.o.right)));
	case MONTH:	 return (dotime(MONTH, eval(e->e.o.right)));
	case DAY:	 return (dotime(DAY, eval(e->e.o.right)));
	case YEAR:	 return (dotime(YEAR, eval(e->e.o.right)));
	case NOW:	 return (dotime(NOW, (double)0.0));
	case STON:	 return (doston(seval(e->e.o.right)));
	case EQS:        return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
	default:	 error("Illegal Numeric Expression");
			 exprerr = 1;
			 return((double)0.0);
    }
}

/* 
 * Rules for string functions:
 * Take string arguments which they xfree.
 * All returned strings are assumed to be xalloced.
 */

char *
docat(s1, s2)
register char *s1, *s2;
{
    register char *p;

    p = xmalloc((unsigned)(strlen(s1)+strlen(s2)+1));
    (void) strcpy(p, s1);
    (void) strcat(p, s2);
    if (s1)
        xfree(s1);
    if (s2)
        xfree(s2);
    return(p);
}

char *
dodate(tloc)
long tloc;
{
    char *tp;
    char *p;

    tp = ctime(&tloc);
    tp[24] = 0;
    p = xmalloc((unsigned)25);
    (void) strcpy(p, tp);
    return(p);
}

char *
dofmt(fmtstr, v)
char *fmtstr;
double v;
{
    char buff[1024];
    char *p;

    if (!fmtstr)
	return(0);
    (void)sprintf(buff, fmtstr, v);
    p = xmalloc((unsigned)(strlen(buff)+1));
    (void) strcpy(p, buff);
    xfree(fmtstr);
    return(p);
}

char *
dosubstr(s, v1, v2)
char *s;
register int v1,v2;
{
    register char *s1, *s2;
    char *p;

    if (!s)
	return(0);

    if (v1 < 0 || v2 < v1 || strlen(s) <= v2 ) {
	xfree(s);
	p = xmalloc((unsigned)1);
	p[0] = 0;
	return(p);
    }
    s2 = p = xmalloc((unsigned)(v2-v1+2));
    s1 = &s[v1];
    for(; v1 <= v2; s1++, s2++, v1++)
	*s2 = *s1;
    *s2 = 0;
    xfree(s);
    return(p);
}

char *
seval(se)
register struct enode *se;
{
    register char *p;

    if (se==0) return 0;
    switch (se->op) {
	case O_SCONST: p = xmalloc((unsigned)(strlen(se->e.s)+1));
		     (void) strcpy(p, se->e.s);
		     return(p);
	case O_VAR:    {
			struct ent *ep;

			ep = se->e.v.vp;
			p = xmalloc((unsigned)(strlen(ep->label)+1));
			(void) strcpy(p, ep->label);
			return(p);
		     }
	case '#':    return(docat(seval(se->e.o.left), seval(se->e.o.right)));
	case 'f':    return(seval(se->e.o.right));
	case '?':    return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
					     : seval(se->e.o.right->e.o.right));
	case DATE:   return(dodate((long)(eval(se->e.o.right))));
	case FMT:    return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
	case SUBSTR: return(dosubstr(seval(se->e.o.left),
			    (int)eval(se->e.o.right->e.o.left) - 1,
			    (int)eval(se->e.o.right->e.o.right) - 1));
	default:
		     error("Illegal String Expression");
		     exprerr = 1;
		     return(0);
	}
}

#define MAXPROP 7

EvalAll () {
    int repct = 0;

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


#ifdef SYSV3
void
#endif
eval_fpe() /* Trap for FPE errors in eval */
{
	longjmp(fpe_save, 1);
}

int 
RealEvalAll () {
    register i,j;
    int chgct = 0;
    register struct ent *p;
#ifdef SYSV3
    void quit();
#else
    int quit();
#endif

    (void) signal(SIGFPE, eval_fpe);
    for (i=0; i<=maxrow; i++)
	for (j=0; j<=maxcol; j++)
	    if ((p=tbl[i][j]) && p->expr) {
		if (p->flags & is_strexpr) {
		    char *v;
		    if (setjmp(fpe_save)) {
			error("Floating point exception %s", v_name(i,j));
			v = "";
		    } else {
		        v = seval(p->expr);
		    }
		    if (strcmp(v, p->label) != 0) {
			chgct++;
		        p->flags |= is_changed;
		    }
		    if(p->label)
			xfree(p->label);
		    p->label = v;
		} else {
		    double v;
		    if (setjmp(fpe_save)) {
			error("Floating point exception %s", v_name(i,j));
			v = 0.0;
		    } else {
		        v = eval (p->expr);
		    }
		    if (v != p->v) {
			p->v = v; chgct++;
			p->flags |= (is_changed|is_valid);
		    }
		}
	    }
    (void) signal(SIGFPE, quit);
    return(chgct);
}

struct enode *
new(op, a1, a2)
struct enode *a1, *a2;
{
    register struct enode *p;
    p = (struct enode *) xmalloc ((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_ptr a1;
{
    register struct enode *p;
    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.v = a1;
    return p;
}

struct enode *
new_range(op, a1)
struct range_s a1;
{
    register struct enode *p;
    p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
    p->op = op;
    p->e.r = a1;
    return p;
}

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

struct enode *
new_str(s)
char *s;
{
    register struct enode *p;

    p = (struct enode *) xmalloc ((unsigned)sizeof(struct enode));
    p->op = O_SCONST;
    p->e.s = s;
    return(p);
}

copy(dv1, dv2, v1, v2)
struct ent *dv1, *dv2, *v1, *v2;
{
    int minsr, minsc;
    int maxsr, maxsc;
    int mindr, mindc;
    int maxdr, maxdc;
    int vr, vc;
    int r, c;

    mindr = dv1->row;
    mindc = dv1->col;
    maxdr = dv2->row;
    maxdc = dv2->col;
    if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
    if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
    maxsr = v2->row;
    maxsc = v2->col;
    minsr = v1->row;
    minsc = v1->col;
    if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
    if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
    if (maxdr >= MAXROWS  || 
           maxdc >= MAXCOLS) {
	error ("The table can't be any bigger");
	return;
    }
    erase_area(mindr, mindc, maxdr, maxdc);
    if (minsr == maxsr && minsc == maxsc) {
	/* Source is a single cell */
	for(vr = mindr; vr <= maxdr; vr++)
	    for (vc = mindc; vc <= maxdc; vc++)
		copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
    } else if (minsr == maxsr) {
	/* Source is a single row */
	for (vr = mindr; vr <= maxdr; vr++)
	    copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
    } else if (minsc == maxsc) {
	/* Source is a single column */
	for (vc = mindc; vc <= maxdc; vc++)
	    copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
    } else {
	/* Everything else */
	copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
    }
    sync_refs();
}

copyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
int vr, vc, minsr, minsc, maxsr, maxsc;
{
    register struct ent *p;
    register struct ent *n;
    register int sr, sc;
    register int dr, dc;

    for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
	for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
	    n = lookat (dr, dc);
	    (void) clearent(n);
	    if (p = tbl[sr][sc]) {
		n -> v = p -> v;
		n -> flags = p -> flags;
		n -> expr = copye(p->expr, dr - sr, dc - sc);
		n -> label = 0;
		if (p -> label) {
		    n -> label = xmalloc ((unsigned)(strlen (p -> label) + 1));
		    (void) 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);
	sync_refs();
}

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 = minc; c<=maxc; c++) {
	    n = lookat (r, c);
	    (void) clearent(n);
	    n->v = start;
	    start += inc;
	    n->flags |= (is_changed|is_valid);
	}
}

let (v, e)
struct ent *v;
struct enode *e;
{
    double val;

    exprerr = 0;
    (void) signal(SIGFPE, eval_fpe);
    if (setjmp(fpe_save)) {
	error("Floating point exception %s", v_name(v->row, v->col));
	val = 0.0;
    } else {
	val = eval(e);
    }
    (void) signal(SIGFPE, quit);
    if (exprerr) {
	efree(e);
	return;
    }
    if (constant(e)) {
	v->v = val;
	if (!(v->flags & is_strexpr)) {
            efree (v->expr);
	    v->expr = 0;
	}
	efree(e);
        v->flags |= (is_changed|is_valid);
        changed++;
        modflg++;
	return;
    }
    efree (v->expr);
    v->expr = e;
    v->flags |= (is_changed|is_valid);
    v->flags &= ~is_strexpr;
    changed++;
    modflg++;
}

slet (v, se, flushdir)
struct ent *v;
struct enode *se;
int flushdir;
{
    char *p;

    exprerr = 0;
    (void) signal(SIGFPE, eval_fpe);
    if (setjmp(fpe_save)) {
	error("Floating point exception %s", v_name(v->row, v->col));
	p = "";
    } else {
	p = seval(se);
    }
    (void) signal(SIGFPE, quit);
    if (exprerr) {
	efree(se);
	return;
    }
    if (constant(se)) {
	label(v, p, flushdir);
	if (p)
	    xfree(p);
	efree(se);
	if (v->flags & is_strexpr) {
            efree (v->expr);
	    v->expr = 0;
	    v->flags &= ~is_strexpr;
	}
	return;
    }
    efree (v->expr);
    v->expr = se;
    v->flags |= (is_changed|is_strexpr);
    if (flushdir<0) v->flags |= is_leftflush;
    else v->flags &= ~is_leftflush;
    FullUpdate++;
    changed++;
    modflg++;
}

clearent (v)
struct ent *v; {
    if (!v)
	return;
    label(v,"",-1);
    v->v = 0;
    if (v->expr)
	efree(v->expr);
    v->expr = 0;
    v->flags |= (is_changed);
    v->flags &= ~(is_valid);
    changed++;
    modflg++;
}

constant(e)
register struct enode *e; {
    return e==0 || e->op == O_CONST || e->op == O_SCONST
	|| (e->op != O_VAR
	 && (e->op&~0177) != O_REDUCE(0)
	 && constant (e->e.o.left)
	 && constant(e->e.o.right)
	 && e->op != NOW);
}

efree (e)
register struct enode *e; {
    if (e) {
	if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
		&& (e->op&~0177) != O_REDUCE(0)) {
	    efree(e->e.o.left);
	    efree(e->e.o.right);
	}
	if (e->op == O_SCONST && e->e.s)
	    xfree(e->e.s);
	xfree ((char *)e);
    }
}

label (v, s, flushdir)
register struct ent *v;
register char *s; {
    if (v) {
	if (flushdir==0 && v->flags&is_valid) {
	    register struct ent *tv;
	    if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
		v = tv, flushdir = 1;
	    else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
		v = tv, flushdir = -1;
	    else flushdir = -1;
	}
	if (v->label) xfree((char *)(v->label));
	if (s && s[0]) {
	    v->label = xmalloc ((unsigned)(strlen(s)+1));
	    (void) strcpy (v->label, s);
	} else
	    v->label = 0;
	if (flushdir<0) v->flags |= is_leftflush;
	else v->flags &= ~is_leftflush;
	FullUpdate++;
	modflg++;
    }
}

decodev (v)
struct ent_ptr v; 
{
	register struct range *r;

	if (!v.vp) (void)sprintf (line+linelim,"VAR?");
	else if (r = find_range((char *)0, 0, v.vp, v.vp))
	    (void)sprintf(line+linelim, "%s", r->r_name);
	else
	    (void)sprintf (line+linelim, "%s%s%s%d",
			v.vf & FIX_COL ? "$" : "",
			coltoa(v.vp->col),
			v.vf & FIX_ROW ? "$" : "",
			v.vp->row);
	linelim += strlen (line+linelim);
}

char *
coltoa(col)
int col;
{
    static char rname[3];
    register char *p = rname;

    if (col > 25) {
	*p++ = col/26 + 'A' - 1;
	col %= 26;
    }
    *p++ = col+'A';
    *p = 0;
    return(rname);
}

decompile(e, priority)
register struct enode *e; {
    register char *s;
    if (e) {
	int mypriority;
	switch (e->op) {
	default: mypriority = 99; break;
	case '?': mypriority = 1; break;
	case ':': mypriority = 2; break;
	case '|': mypriority = 3; break;
	case '&': mypriority = 4; break;
	case '<': case '=': case '>': mypriority = 6; break;
	case '+': case '-': case '#': mypriority = 8; break;
	case '*': case '/': mypriority = 10; break;
	case '^': mypriority = 12; break;
	}
	if (mypriority<priority) line[linelim++] = '(';
	switch (e->op) {
	case 'f':	{ 
			    for (s="fixed "; line[linelim++] = *s++;);
			    linelim--;
			    decompile (e->e.o.right, 30);
			    break;
			}
	case 'm':	line[linelim++] = '-';
			decompile (e->e.o.right, 30);
			break;
	case '~':	line[linelim++] = '~';
			decompile (e->e.o.right, 30);
			break;
	case 'v':	decodev (e->e.v);
			break;
	case 'k':	(void)sprintf (line+linelim,"%.15g",e->e.k);
			linelim += strlen (line+linelim);
			break;
	case '$':	(void)sprintf (line+linelim, "\"%s\"", e->e.s);
			linelim += strlen(line+linelim);
			break;
	case O_REDUCE('+'):
			s = "@sum("; goto more;
	case O_REDUCE('*'):
			s = "@prod("; goto more;
	case O_REDUCE('s'):
			s = "@stddev("; goto more;
	case O_REDUCE(MAX):
			s = "@max("; goto more;
	case O_REDUCE(MIN):
			s = "@min("; goto more;
	case O_REDUCE('a'):
			s = "@avg("; /* fall though to more; */
	more:		{
			struct range *r;

			for (; line[linelim++] = *s++;);
			linelim--;
			if (r = find_range((char *)0, 0, e->e.r.left.vp,
						 e->e.r.right.vp)) {
			    (void)sprintf(line+linelim, "%s", r->r_name);
			    linelim += strlen(line+linelim);
			} else {
			    decodev (e->e.r.left);
			    line[linelim++] = ':';
			    decodev (e->e.r.right);
			}
			line[linelim++] = ')';
			break;
			}
	case ACOS:	s = "@acos("; goto more1;
	case ASIN:	s = "@asin("; goto more1;
	case ATAN:	s = "@atan("; goto more1;
	case CEIL:	s = "@ceil("; goto more1;
	case COS:	s = "@cos("; goto more1;
	case EXP:	s = "@exp("; goto more1;
	case FABS:	s = "@fabs("; goto more1;
	case FLOOR:	s = "@floor("; goto more1;
	case HYPOT:	s = "@hypot("; goto more2;
	case LOG:	s = "@ln("; goto more1;
	case LOG10:	s = "@log("; goto more1;
	case POW:	s = "@pow("; goto more2;
	case SIN:	s = "@sin("; goto more1;
	case SQRT:	s = "@sqrt("; goto more1;
	case TAN:	s = "@tan("; goto more1;
	case DTR:	s = "@dtr("; goto more1;
	case RTD:	s = "@rtd("; goto more1;
	case RND:	s = "@rnd("; goto more1;
	case HOUR:	s = "@hour("; goto more1;
	case MINUTE:	s = "@minute("; goto more1;
	case SECOND:	s = "@second("; goto more1;
	case MONTH:	s = "@month("; goto more1;
	case DAY:	s = "@day("; goto more1;
	case YEAR:	s = "@year("; goto more1;
	case DATE:	s = "@date("; goto more1;
	case STON:	s = "@ston("; goto more1;
	case FMT:	s = "@fmt("; goto more2;
	case EQS:	s = "@eqs("; goto more2;
	more1:		for (; line[linelim++] = *s++;);
			linelim--;
			decompile (e->e.o.right, 0);
			line[linelim++] = ')';
			break;
	more2:		for (; line[linelim++] = *s++;);
			linelim--;
			decompile (e->e.o.left, 0);
			line[linelim++] = ',';
			decompile (e->e.o.right, 0);
			line[linelim++] = ')';
			break;
	case NOW:	s = "@now"; goto more0;
	more0:		for (; line[linelim++] = *s++;);
			linelim--;
			break;
	case SUBSTR:	s = "@substr(";
			for (; line[linelim++] = *s++;);
			linelim--;
			decompile (e->e.o.left, 0);
			line[linelim++] = ',';
			decompile (e->e.o.right->e.o.left, 0);
			line[linelim++] = ',';
			decompile (e->e.o.right->e.o.right, 0);
			line[linelim++] = ')';
			break;

	default:	decompile (e->e.o.left, mypriority);
			line[linelim++] = e->op;
			decompile (e->e.o.right, mypriority+1);
			break;
	}
	if (mypriority<priority) line[linelim++] = ')';
    } else line[linelim++] = '?';
}

editv (row, col) {
    register struct ent *p;

    p = lookat (row, col);
    (void)sprintf (line, "let %s = ", v_name(row, col));
    linelim = strlen(line);
    if (p->flags & is_strexpr || p->expr == 0) {
	(void)sprintf (line+linelim, "%.15g", p->v);
	linelim += strlen (line+linelim);
    } else {
        editexp(row,col);
    }
}

editexp(row,col) {
    register struct ent *p;

    p = lookat (row, col);
    decompile (p->expr, 0);
    line[linelim] = 0;
}

edits (row, col) {
    register struct ent *p;

    p = lookat (row, col);
    (void)sprintf (line, "%sstring %s = ",
			((p->flags&is_leftflush) ? "left" : "right"),
			v_name(row, col));
    linelim = strlen(line);
    if (p->flags & is_strexpr && p->expr) {
	editexp(row, col);
    } else {
        (void)sprintf (line+linelim, "\"%s\"", p->label);
        linelim += strlen (line+linelim);
    }
}

printfile (fname, r0, c0, rn, cn)
char *fname;
{
    FILE *f;
    char pline[1000];
    int plinelim;
    int pid;
    int fieldlen, nextcol;
    register row, col;
    register struct ent **p;
    char ch, lin[100];

    if (strcmp(fname, curfile) == 0) {
	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,
		"Confirm that you want to destroy the data base: (y,n)");
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if (ch != 'y' && ch != 'Y') 
	    return;
    }

    f = openout(fname, &pid);

    if (f==0) {
	error ("Can't create %s", fname);
	return;
    }
    for (row=r0;row<=rn; row++) {
	register c = 0;
	pline[plinelim=0] = '\0';
	for (p = &tbl[row][col=c0]; col<=cn;
	        p += nextcol-col, col = nextcol, c += fieldlen) {

	    fieldlen = fwidth[col];
	    nextcol = col+1;
	    if (*p) {
		char *s;

		while (plinelim<c) pline[plinelim++] = ' ';
		plinelim = c;
		if ((*p)->flags&is_valid) {
		    (void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
		                                precision[col], (*p)->v);
		    plinelim += strlen (pline+plinelim);
		}
		if (s = (*p)->label) {
		    int slen;
		    char *start, *last;
		    register char *fp;
		    struct ent *nc;

		    /* Figure out if the label slops over to a blank field */
		    slen = strlen(s);
		    while (slen > fieldlen && nextcol <= cn &&
			    !((nc = lookat(row,nextcol))->flags & is_valid) &&
			    !(nc->label)) {
			
			fieldlen += fwidth[nextcol];
			nextcol++;
		    }
		    if (slen > fieldlen)
			slen = fieldlen;
		    
		    /* Now justify and print */
		    start = (*p)->flags & is_leftflush ? pline + c
					: pline + c + fieldlen - slen;
		    last = pline + c + fieldlen;
		    fp = plinelim < c ? pline + plinelim : pline + c;
		    while (fp < start)
			*fp++ = ' ';
		    while (slen--)
			*fp++ = *s++;
		    if (!((*p)->flags & is_valid) || fieldlen != fwidth[col])
			while(fp < last)
			    *fp++ = ' ';
		    if (plinelim < fp - pline)
			plinelim = fp - pline;
		}
	    }
	}
	(void) fprintf (f,"%.*s\n",plinelim,pline);
    }

    closeout(f, pid);
}

tblprintfile (fname, r0, c0, rn, cn)
char *fname;
{
    FILE *f;
    char pline[1000];
    int pid;
    register row, col;
    register struct ent **p;
    char coldelim = DEFCOLDELIM;
    char ch, lin[100];

    if (strcmp(fname, curfile) == 0) {
	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,
		"Confirm that you want to destroy the data base: (y,n)");
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if (ch != 'y' && ch != 'Y') 
	    return;
    }

    f = openout(fname, &pid);

    if (f==0) {
	error ("Can't create %s", fname);
	return;
    }
    for (row=r0; row<=rn; row++) {
	for (p = &tbl[row][col=c0]; col<=cn; col++, p++) {
	    if (*p) {
		char *s;
		if ((*p)->flags&is_valid) {
		    (void) fprintf (f,"%.*f",precision[col],
				(*p)->v);
		}
		if (s = (*p)->label) {
	            (void) fprintf (f,"%s",s);
		}
	    }
	    (void) fprintf(f,"%c",coldelim);
	}
	(void) fprintf (f,"\n",pline);
    }

    closeout(f, pid);
}

struct enode *
copye (e, Rdelta, Cdelta)
register struct enode *e; {
    register struct enode *ret;
    if (e==0) ret = 0;
    else {
	ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
	ret->op = e->op;
	switch (ret->op) {
	case 'v':
		{
		    int newrow, newcol;
		    newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
						 e->e.v.vp->row+Rdelta;
		    newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
						 e->e.v.vp->col+Cdelta;
		    ret->e.v.vp = lookat (newrow, newcol);
		    ret->e.v.vf = e->e.v.vf;
		    break;
		}
	case 'k':
		ret->e.k = e->e.k;
		break;
	case 'f':
		ret->e.o.right = copye (e->e.o.right,0,0);
		ret->e.o.left = 0;
 		break;
	case '$':
		ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
		(void) strcpy(ret->e.s, e->e.s);
		break;
 	case O_REDUCE('+'):
 	case O_REDUCE('*'):
 	case O_REDUCE('a'):
 	case O_REDUCE('s'):
 	case O_REDUCE(MAX):
 	case O_REDUCE(MIN):
		{
		    int newrow, newcol;
		    newrow=e->e.r.left.vf & FIX_ROW ?e->e.r.left.vp->row :
						     e->e.r.left.vp->row+Rdelta;
		    newcol=e->e.r.left.vf & FIX_COL ?e->e.r.left.vp->col :
						     e->e.r.left.vp->col+Cdelta;
		    ret->e.r.left.vp = lookat (newrow, newcol);
		    ret->e.r.left.vf = e->e.r.left.vf;
		    newrow=e->e.r.right.vf & FIX_ROW ?e->e.r.right.vp->row :
						    e->e.r.right.vp->row+Rdelta;
		    newcol=e->e.r.right.vf & FIX_COL ?e->e.r.right.vp->col :
						    e->e.r.right.vp->col+Cdelta;
		    ret->e.r.right.vp = lookat (newrow, newcol);
		    ret->e.r.right.vf = e->e.r.right.vf;
		    break;
		}
	default:
		ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
		ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
		break;
	}
    }
    return ret;
}

/*
 * sync_refs and syncref are used to remove references to
 * deleted struct ents.  Note that the deleted structure must still
 * be hanging around before the call, but not referenced by an entry
 * in tbl.  Thus the free_ent, fix_ent calls in sc.c
 */

sync_refs () {
    register i,j;
    register struct ent *p;
    sync_ranges();
    for (i=0; i<=maxrow; i++)
	for (j=0; j<=maxcol; j++)
	    if ((p=tbl[i][j]) && p->expr)
		syncref(p->expr);
}


syncref(e)
register struct enode *e;
{
    if (e==0)
	return;
    else {
	switch (e->op) {
	case 'v':
		e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
		break;
	case 'k':
		break;
	case '$':
		break;
 	case O_REDUCE('+'):
 	case O_REDUCE('*'):
 	case O_REDUCE('a'):
 	case O_REDUCE('s'):
 	case O_REDUCE(MAX):
 	case O_REDUCE(MIN):
 		e->e.r.right.vp = lookat ( e->e.r.right.vp->row,
 		                                  e->e.r.right.vp->col);
 		e->e.r.left.vp = lookat ( e->e.r.left.vp->row,
 		                                 e->e.r.left.vp->col);
		break;
	default:
		syncref(e->e.o.right);
		syncref(e->e.o.left);
		break;
	}
    }
}

hiderow(arg)
{
    register int r1;
    register int r2;

    r1 = currow;
    r2 = r1 + arg - 1;
    if (r1 < 0 || r1 > r2) {
	error("Invalid Range");
	return;
    }
    if (r2 > MAXROWS-2) {
	error("You can't hide the last row");
	return;
    }
    FullUpdate++;
    while (r1 <= r2)
	row_hidden[r1++] = 1;
}

hidecol(arg)
{
    register int c1;
    register int c2;

    c1 = curcol;
    c2 = c1 + arg - 1;
    if (c1 < 0 || c1 > c2) {
	error("Invalid Range");
	return;
    }
    if (c2 > MAXCOLS-2) {
	error("You can't hide the last col");
	return;
    }
    FullUpdate++;
    while (c1 <= c2)
	col_hidden[c1++] = 1;
}

showrow(r1, r2)
{
    if (r1 < 0 || r1 > r2) {
	error("Invalid Range");
	return;
    }
    if (r2 > MAXROWS-1) {
	r2 = MAXROWS-1;
    }
    FullUpdate++;
    while (r1 <= r2)
	row_hidden[r1++] = 0;
}

showcol(c1, c2)
{
    if (c1 < 0 || c1 > c2) {
	error("Invalid Range");
	return;
    }
    if (c2 > MAXCOLS-1) {
	c2 = MAXCOLS-1;
    }
    FullUpdate++;
    while (c1 <= c2)
	col_hidden[c1++] = 0;
}

/* Open the output file, setting up a pipe if needed */

FILE *
openout(fname, rpid)
char *fname;
int *rpid;
{
    int pipefd[2];
    int pid;
    FILE *f;

    while (*fname && (*fname == ' '))  /* Skip leading blanks */
	fname++;

    if (*fname != '|') {		/* Open file if not pipe */
	*rpid = 0;
	return(fopen(fname, "w"));
    }

    fname++;				/* Skip | */
    if ( pipe (pipefd) < 0) {
	error("Can't make pipe to child");
	*rpid = 0;
	return(0);
    }

    deraw();
    if ((pid=fork()) == 0)			  /* if child  */
    {
	(void) close (0);			  /* close stdin */
	(void) close (pipefd[1]);
	(void) dup (pipefd[0]);		  /* connect to pipe input */
	(void) execl ("/bin/sh", "sh", "-c", fname, 0);
	exit (-127);
    }
    else				  /* else parent */
    {
	*rpid = pid;
	f = fdopen (pipefd[1], "w");
	if (f == 0)
	{
	    (void) kill (pid, -9);
	    error ("Can't fdopen output");
	    (void) close (pipefd[1]);
	    *rpid = 0;
	    return(0);
	}
    }
    return(f);
}

closeout(f, pid)
FILE *f;
int pid;
{
    int temp;

    (void) fclose (f);
    if (pid) {
         while (pid != wait(&temp)) /**/;
	 (void) printf("Press <return> to continue");
	 (void) fflush(stdout);
	 (void) nmgetch();
	 goraw();
    }
}
\SHAR\EOF\
else
  echo "will not over write ./interp.c"
fi
if [ `wc -c ./interp.c | awk '{printf $1}'` -ne 31137 ]
then
echo `wc -c ./interp.c | awk '{print "Got " $1 ", Expected " 31137}'`
fi
if `test ! -s ./cmds.c`
then
echo "Extracting ./cmds.c"
cat > ./cmds.c << '\SHAR\EOF\'
/*	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 <curses.h>
#include "sc.h"

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

duprow()
{
    if (currow >= MAXROWS - 1 || maxrow >= MAXROWS - 1) {
	error ("The table can't be any bigger");
	return;
    }
    modflg++;
    currow++;
    openrow (currow);
    for (curcol = 0; curcol <= maxcol; curcol++) {
	register struct ent *p = tbl[currow - 1][curcol];
	if (p) {
	    register struct ent *n;
	    n = lookat (currow, curcol);
	    n -> v = p -> v;
	    n -> flags = p -> flags;
	    n -> expr = copye (p -> expr, 1, 0);
	    n -> label = 0;
	    if (p -> label) {
		n -> label = (char *)
			     xmalloc ((unsigned)(strlen (p -> label) + 1));
		(void) strcpy (n -> label, p -> label);
	    }
	}
    }
    for (curcol = 0; curcol <= maxcol; curcol++) {
	register struct ent *p = tbl[currow][curcol];
	if (p && (p -> flags & is_valid) && !p -> expr)
	    break;
    }
    if (curcol > maxcol)
	curcol = 0;
}

dupcol() 
{
    if (curcol >= MAXCOLS - 1 || maxcol >= MAXCOLS - 1) {
	error ("The table can't be any wider");
	return;
    }
    modflg++;
    curcol++;
    opencol (curcol);
    for (currow = 0; currow <= maxrow; currow++) {
	register struct ent *p = tbl[currow][curcol - 1];
	if (p) {
	    register struct ent *n;
	    n = lookat (currow, curcol);
	    n -> v = p -> v;
	    n -> flags = p -> flags;
	    n -> expr = copye (p -> expr, 0, 1);
	    n -> label = 0;
	    if (p -> label) {
		n -> label = (char *)
			     xmalloc ((unsigned) (strlen (p -> label) + 1));
		(void) strcpy (n -> label, p -> label);
	    }
	}
    }
    for (currow = 0; currow <= maxrow; currow++) {
	register struct ent *p = tbl[currow][curcol];
	if (p && (p -> flags & is_valid) && !p -> expr)
	    break;
    }
    if (currow > maxrow)
	currow = 0;
}

insertrow(arg)
{
    while (--arg>=0) openrow (currow);
}

deleterow(arg)
{
    flush_saved();
    erase_area(currow, 0, currow + arg - 1, maxcol);
    currow += arg;
    while (--arg>=0) closerow (--currow);
    sync_refs();
}

insertcol(arg)
{
    while (--arg>=0) opencol(curcol);
}

deletecol(arg)
{
    flush_saved();
    erase_area(0, curcol, maxrow, curcol + arg - 1);
    curcol += arg;
    while (--arg>=0) closecol (--curcol);
    sync_refs();
}

rowvalueize(arg)
{
    valueize_area(currow, 0, currow + arg - 1, maxcol);
}

colvalueize(arg)
{
    valueize_area(0, curcol, maxrow, curcol + arg - 1);
}

erase_area(sr, sc, er, ec)
int sr, sc, er, ec;
{
    register int r, c;
    register struct ent **p;

    if (sr > er) {
	r = sr; sr = er; er= r;	
    }

    if (sc > ec) {
	c = sc; sc = ec; ec= c;	
    }

    if (sr < 0)
	sr = 0; 
    if (sc < 0)
	sc = 0;
    if (er >= MAXROWS)
	er = MAXROWS-1;
    if (ec >= MAXCOLS)
	ec = MAXCOLS-1;

    for (r = sr; r <= er; r++) {
	for (c = sc; c <= ec; c++) {
	    p = &tbl[r][c];
	    if (*p) {
		free_ent(*p);
		*p = 0;
	    }
	}
    }

}

valueize_area(sr, sc, er, ec)
int sr, sc, er, ec;
{
    register int r, c;
    register struct ent *p;

    if (sr > er) {
	r = sr; sr = er; er= r;	
    }

    if (sc > ec) {
	c = sc; sc = ec; ec= c;	
    }

    if (sr < 0)
	sr = 0; 
    if (sc < 0)
	sc = 0;
    if (er >= MAXROWS)
	er = MAXROWS-1;
    if (ec >= MAXCOLS)
	ec = MAXCOLS-1;

    for (r = sr; r <= er; r++) {
	for (c = sc; c <= ec; c++) {
	    p = tbl[r][c];
	    if (p && p->expr) {
		efree(p->expr);
		p->expr = 0;
		p->flags &= ~is_strexpr;
	    }
	}
    }

}

pullcells(to_insert)
{
    register struct ent *p, *n;
    register int deltar, deltac;
    int minrow, mincol;
    int mxrow, mxcol;
    int numrows, numcols;

    if (!to_fix)
	return;

    switch (to_insert) {
    case 'm':
    case 'r':
    case 'c':
	break;
    default:
	error("Invalid pull command");
	return;
    }

    minrow = MAXROWS; 
    mincol = MAXCOLS;
    mxrow = 0;
    mxcol = 0;

    for (p = to_fix; p; p = p->next) {
	if (p->row < minrow)
	    minrow = p->row;
	if (p->row > mxrow)
	    mxrow = p->row;
	if (p->col < mincol)
	    mincol = p->col;
	if (p->col > mxcol)
	    mxcol = p->col;
    }

    numrows = mxrow - minrow + 1;
    numcols = mxcol - mincol + 1;
    deltar = currow - minrow;
    deltac = curcol - mincol;

    if (to_insert == 'r') {
	insertrow(numrows);
	deltac = 0;
    } else if (to_insert == 'c') {
	insertcol(numcols);
	deltar = 0;
    }

    FullUpdate++;
    modflg++;

    for (p = to_fix; p; p = p->next) {
	n = lookat (p->row + deltar, p->col + deltac);
	(void) clearent(n);
	n -> flags = p -> flags & ~is_deleted;
	n -> v = p -> v;
	n -> expr = copye(p->expr, deltar, deltac);
	n -> label = 0;
	if (p -> label) {
	    n -> label = (char *)
			 xmalloc((unsigned)(strlen(p->label)+1));
	    (void) strcpy (n -> label, p -> label);
	}
    }
}

colshow_op()
{
    register int i,j;
    for (i=0; i<MAXCOLS; i++)
	if (col_hidden[i]) 
	    break;
    for(j=i; j<MAXCOLS; j++)
	if (!col_hidden[j])
	    break;
    j--;
    if (i<MAXCOLS) {
	(void) sprintf(line,"show %s:", coltoa(i));
	(void) sprintf(line + strlen(line),"%s",coltoa(j));
	linelim = strlen (line);
    }
}

rowshow_op()
{
    register int i,j;
    for (i=0; i<MAXROWS; i++)
	if (row_hidden[i]) 
	    break;
    for(j=i; j<MAXROWS; j++)
	if (!row_hidden[j]) {
	    break;
	}
    j--;
    if (i<MAXROWS) {
	(void) sprintf(line,"show %d:%d", i, j);
        linelim = strlen (line);
    }
}

get_qual()
{
    register int c;

    c = nmgetch();
    switch (c) {
    case 'c':
    case 'j':
    case 'k':
    case ctl(p):
    case ctl(n):
	return('c');
    case 'r':
    case 'l':
    case 'h':
    case ctl(f):
    case ctl(b):
	return('r');
    default:
	return(c);
    }
    /*NOTREACHED*/
}

openrow (rs) {
    register    r;
    register struct ent **p;
    register    c;
    register	i;

    if (rs > maxrow) maxrow = rs;
    if (maxrow >= MAXROWS - 1 || rs > MAXROWS - 1) {
	error ("The table can't be any longer");
	return;
    }
    for (i = maxrow+1; i > rs; i--) {
	row_hidden[i] = row_hidden[i-1];
    }
    for (r = ++maxrow; r > rs; r--)
	for (c = maxcol + 1, p = &tbl[r][0]; --c >= 0; p++)
	    if (p[0] = p[-MAXCOLS])
		p[0] -> row++;
    p = &tbl[rs][0];
    for (c = maxcol + 1; --c >= 0;)
	*p++ = 0;
    FullUpdate++;
    modflg++;
}

closerow (r)
register r; {
    register struct ent **p;
    register c;
    register int i;

    if (r > maxrow) return;

    p = &tbl[r][0];
    for (c=maxcol+1; --c>=0; ) {
	if (*p)
	    free_ent(*p);
	*p++ = 0;
    }

    for (i = r; i < MAXROWS - 1; i++) {
	row_hidden[i] = row_hidden[i+1];
    }

    while (r<maxrow) {
	for (c = maxcol+1, p = &tbl[r][0]; --c>=0; p++)
	    if (p[0] = p[MAXCOLS])
		p[0]->row--;
	r++;
    }

    p = &tbl[maxrow][0];
    for (c=maxcol+1; --c>=0; ) *p++ = 0;
    maxrow--;
    FullUpdate++;
    modflg++;
}

opencol (cs) {
    register r;
    register struct ent **p;
    register c;
    register lim = maxcol-cs+1;
    int i;

    if (cs > maxcol) maxcol = cs;
    if (maxcol >= MAXCOLS - 1 || cs > MAXCOLS - 1) {
	error ("The table can't be any wider");
	return;
    }
    for (i = maxcol+1; i > cs; i--) {
	fwidth[i] = fwidth[i-1];
	precision[i] = precision[i-1];
	col_hidden[i] = col_hidden[i-1];
    }
    /* fwidth[cs] = DEFWIDTH;
    precision[i] =  DEFPREC;  */

    for (r=0; r<=maxrow; r++) {
	p = &tbl[r][maxcol+1];
	for (c=lim; --c>=0; p--)
	    if (p[0] = p[-1])
		p[0]->col++;
	p[0] = 0;
    }
    maxcol++;
    FullUpdate++;
    modflg++;
}

closecol (cs) {
    register r;
    register struct ent **p;
    register struct ent *q;
    register c;
    register lim = maxcol-cs;
    int i;

    if (lim < 0) return;

    for (r=0; r<=maxrow; r++)
	if (q = tbl[r][cs]) {
	    free_ent(q);
	}

    for (r=0; r<=maxrow; r++) {
	p = &tbl[r][cs];
	for (c=lim; --c>=0; p++)
	    if (p[0] = p[1])
		p[0]->col--;
	p[0] = 0;
    }

    for (i = cs; i < MAXCOLS - 1; i++) {
	fwidth[i] = fwidth[i+1];
	precision[i] = precision[i+1];
	col_hidden[i] = col_hidden[i+1];
    }

    maxcol--;
    FullUpdate++;
    modflg++;
}

doend(rowinc, colinc)
{
    register struct ent *p;
    int r, c;

    if (VALID_CELL(p, currow, curcol)) {
	r = currow + rowinc;
	c = curcol + colinc;
	if (r >= 0 && r < MAXROWS && 
	    c >= 0 && c < MAXCOLS &&
	    !VALID_CELL(p, r, c)) {
		currow = r;
		curcol = c;
	}
    }

    if (!VALID_CELL(p, currow, curcol)) {
        switch (rowinc) {
        case -1:
	    while (!VALID_CELL(p, currow, curcol) && currow > 0)
		currow--;
	    break;
        case  1:
	    while (!VALID_CELL(p, currow, curcol) && currow < MAXROWS-1)
		currow++;
	    break;
        case  0:
            switch (colinc) {
 	    case -1:
	        while (!VALID_CELL(p, currow, curcol) && curcol > 0)
		    curcol--;
	        break;
 	    case  1:
	        while (!VALID_CELL(p, currow, curcol) && curcol < MAXCOLS-1)
		    curcol++;
	        break;
	    }
            break;
        }
	return;
    }

    switch (rowinc) {
    case -1:
	while (VALID_CELL(p, currow, curcol) && currow > 0)
	    currow--;
	break;
    case  1:
	while (VALID_CELL(p, currow, curcol) && currow < MAXROWS-1)
	    currow++;
	break;
    case  0:
	switch (colinc) {
	case -1:
	    while (VALID_CELL(p, currow, curcol) && curcol > 0)
		curcol--;
	    break;
	case  1:
	    while (VALID_CELL(p, currow, curcol) && curcol < MAXCOLS-1)
		curcol++;
	    break;
	}
	break;
    }
    if (!VALID_CELL(p, currow, curcol)) {
        currow -= rowinc;
        curcol -= colinc;
    }
}

doformat(c1,c2,w,p)
int c1,c2,w,p;
{
    register int i;

    if (w > COLS - RESCOL - 2) {
	error("Format too large - Maximum = %d", COLS - RESCOL - 2);
	w = COLS-RESCOL-2;
    }

    if (p > w) {
	error("Precision too large");
	p = w;
    }

    for(i = c1; i<=c2; i++)
	fwidth[i] = w, precision[i] = p;

    FullUpdate++;
    modflg++;
}
\SHAR\EOF\
else
  echo "will not over write ./cmds.c"
fi
if [ `wc -c ./cmds.c | awk '{printf $1}'` -ne 9940 ]
then
echo `wc -c ./cmds.c | awk '{print "Got " $1 ", Expected " 9940}'`
fi
if `test ! -s ./crypt.c`
then
echo "Extracting ./crypt.c"
cat > ./crypt.c << '\SHAR\EOF\'
/*
 * Encryption utilites
 * Bradley Williams	
 * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams
 */

#include <stdio.h>
#include <curses.h>

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

#include "sc.h"

extern char curfile[];
char        *strcpy();
#ifdef SYSV3
void exit();
#endif

int         Crypt = 0;

#define DEFWIDTH 10
#define DEFPREC   2

creadfile (save, eraseflg)
char *save;
{
    register FILE *f;
    int pipefd[2];
    int fildes;
    int pid;

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

    fildes = open (save, O_RDONLY, 0);
    if (fildes < 0)
    {
	error ("Can't read %s", save);
	return;
    }

    if (eraseflg) erasedb ();

    if (pipe(pipefd) < 0) {
	error("Can't make pipe to child");
	return;
    }

    deraw();
    if ((pid=fork()) == 0)			  /* if child  */
    {
	(void) close (0);		  /* close stdin */
	(void) close (1);		  /* close stdout */
	(void) close (pipefd[0]);	  /* close pipe input */
	(void) dup (fildes);		  /* standard in from file */
	(void) dup (pipefd[1]);		  /* connect to pipe */
	(void) fprintf (stderr, " ");
	(void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
	exit (-127);
    }
    else				  /* else parent */
    {
	(void) close (fildes);
	(void) close (pipefd[1]);	  /* close pipe output */
	f = fdopen (pipefd[0], "r");
	if (f == 0)
	{
	    (void) kill (pid, -9);
	    error ("Can't fdopen file %s", save);
	    (void) close (pipefd[0]);
	    return;
	}
    }

    while (fgets(line,sizeof line,f)) {
	linelim = 0;
	if (line[0] != '#') (void) yyparse ();
    }
    (void) fclose (f);
    (void) close (pipefd[0]);
    while (pid != wait(&fildes)) /**/;
    goraw();
    linelim = -1;
    modflg++;
    if (eraseflg) {
	(void) strcpy (curfile, save);
	modflg = 0;
    }
    EvalAll();
}

cwritefile (fname, r0, c0, rn, cn)
char *fname;
{
    register FILE *f;
    register struct ent **p;
    register r, c;
    int pipefd[2];
    int fildes;
    int pid;
    char save[1024];

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

    (void) strcpy(save,fname);

    fildes = open (save, O_WRONLY|O_CREAT, 0600);
    if (fildes < 0)
    {
	error ("Can't create %s", save);
	return(-1);
    }

    if (pipe (pipefd) < 0) {
	error ("Can't make pipe to child\n");
	return(-1);
    }

    deraw();
    if ((pid=fork()) == 0)			  /* if child  */
    {
	(void) close (0);			  /* close stdin */
	(void) close (1);			  /* close stdout */
	(void) close (pipefd[1]);		  /* close pipe output */
	(void) dup (pipefd[0]);			  /* connect to pipe input */
	(void) dup (fildes);			  /* standard out to file */
	(void) fprintf (stderr, " ");
	(void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
	exit (-127);
    }
    else				  /* else parent */
    {
	(void) close (fildes);
	(void) close (pipefd[0]);		  /* close pipe input */
	f = fdopen (pipefd[1], "w");
	if (f == 0)
	{
	    (void) kill (pid, -9);
	    error ("Can't fdopen file %s", save);
	    (void) close (pipefd[1]);
	    return(-1);
	}
    }

    (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
    (void) fprintf (f, "Calculator.\n");
    (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
    for (c=0; c<MAXCOLS; c++)
	if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
	    (void)fprintf(f,"format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
    write_range(f);
    if (mdir)
	(void) fprintf(f, "mdir \"%s\"\n", mdir);
    for (r=r0; r<=rn; r++) {
	p = &tbl[r][0];
	for (c=c0; c<=cn; c++, p++)
	    if (*p) {
		if ((*p)->label) {
		    edits(r, c);
		    (void) fprintf(f, "%s\n", line);
		}
		if ((*p)->flags&is_valid) {
		    editv(r, c);
		    (void) fprintf (f, "%s\n",line);
		}
	    }
    }
    (void) fclose (f);
    (void) close (pipefd[1]);
    while (pid != wait(&fildes)) /**/;
    (void) strcpy(curfile,save);

    modflg = 0;
    error("File '%s' written.",curfile);
    goraw();
    return(0);
}
\SHAR\EOF\
else
  echo "will not over write ./crypt.c"
fi
if [ `wc -c ./crypt.c | awk '{printf $1}'` -ne 3930 ]
then
echo `wc -c ./crypt.c | awk '{print "Got " $1 ", Expected " 3930}'`
fi
if `test ! -s ./xmalloc.c`
then
echo "Extracting ./xmalloc.c"
cat > ./xmalloc.c << '\SHAR\EOF\'
/*
 * A safer saner malloc, for careless programmers
 */

#include <stdio.h>
#include <curses.h>

extern char *malloc();
#ifdef SYSV3
extern void free();
extern void exit();
#endif

char *
xmalloc(n)
unsigned n;
{
register char *ptr;

if ((ptr = malloc(n + sizeof(int))) == NULL)
    fatal("xmalloc: no memory");
*((int *) ptr) = 12345;		/* magic number */
return(ptr + sizeof(int));
}

xfree(p)
char *p;
{
if (p == NULL)
    fatal("xfree: NULL");
p -= sizeof(int);
if (*((int *) p) != 12345)
    fatal("xfree: storage not malloc'ed");
free(p);
}

fatal(str)
char *str;
{
    deraw();
    (void) fprintf(stderr,"%s\n", str);
    exit(1);
}
\SHAR\EOF\
else
  echo "will not over write ./xmalloc.c"
fi
if [ `wc -c ./xmalloc.c | awk '{printf $1}'` -ne 640 ]
then
echo `wc -c ./xmalloc.c | awk '{print "Got " $1 ", Expected " 640}'`
fi
if `test ! -s ./range.c`
then
echo "Extracting ./range.c"
cat > ./range.c << '\SHAR\EOF\'

/*	SC	A Spreadsheet Calculator
 *		Range Manipulations
 *
 *              Robert Bond, 4/87
 *
 */

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

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

static struct range *rng_base;

add_range(name, left, right, is_range)
char *name;
struct ent_ptr left, right;
int is_range;
{
    struct range *r;
    register char *p;
    int len;
    int minr,minc,maxr,maxc;
    int minrf, mincf, maxrf, maxcf;

    if (left.vp->row < right.vp->row) {
	minr = left.vp->row; minrf = left.vf & FIX_ROW;
	maxr = right.vp->row; maxrf = right.vf & FIX_ROW;
    } else {
	minr = right.vp->row; minrf = right.vf & FIX_ROW;
	maxr = left.vp->row; maxrf = right.vf & FIX_ROW;
    } 

    if (left.vp->col < right.vp->col) {
	minc = left.vp->col; mincf = left.vf & FIX_COL;
	maxc = right.vp->col; maxcf = right.vf & FIX_COL;
    } else {
	minc = right.vp->col; mincf = right.vf & FIX_COL;
	maxc = left.vp->col; maxcf = left.vf & FIX_COL;
    } 

    left.vp = lookat(minr, minc);
    left.vf = minrf | mincf;
    right.vp = lookat(maxr, maxc);
    right.vf = maxrf | maxcf;

    if (find_range(name, strlen(name), (struct ent *)0, (struct ent *)0)) {
	error("Error: range name already defined");
	xfree(name);
	return;
    }

    if (strlen(name) <= 2) {
	error("Invalid range name - too short");
	xfree(name);
	return;
    }

    for(p=name, len=0; *p; p++, len++)
	if (!((isalpha(*p) && (len<=2)) ||
	    ((isdigit(*p) || isalpha(*p) || (*p == '_')) && (len>2)))) {
	    error("Invalid range name - illegal combination");
	    xfree(name);
	    return;
        }

    r = (struct range *)xmalloc((unsigned)sizeof(struct range));
    r->r_name = name;
    r->r_left = left;
    r->r_right = right;
    r->r_next = rng_base;
    r->r_prev = 0;
    r->r_is_range = is_range;
    if (rng_base)
        rng_base->r_prev = r;
    rng_base = r;
}

del_range(left, right)
struct ent *left, *right;
{
    register struct range *r;
    int minr,minc,maxr,maxc;

    minr = left->row < right->row ? left->row : right->row;
    minc = left->col < right->col ? left->col : right->col;
    maxr = left->row > right->row ? left->row : right->row;
    maxc = left->col > right->col ? left->col : right->col;

    left = lookat(minr, minc);
    right = lookat(maxr, maxc);

    if (!(r = find_range((char *)0, 0, left, right))) 
	return;

    if (r->r_next)
        r->r_next->r_prev = r->r_prev;
    if (r->r_prev)
        r->r_prev->r_next = r->r_next;
    else
	rng_base = r->r_next;
    xfree((char *)(r->r_name));
    xfree((char *)r);
}

clean_range()
{
    register struct range *r;
    register struct range *nextr;

    r = rng_base;
    rng_base = 0;

    while (r) {
	nextr = r->r_next;
	xfree((char *)(r->r_name));
	xfree((char *)r);
	r = nextr;
    }
}

/* Match on name or lmatch, rmatch */

struct range *
find_range(name, len, lmatch, rmatch)
char *name;
int len;
struct ent *lmatch;
struct ent *rmatch;
{
    struct range *r;
    register char *rp, *np;
    register int c;

    if (name) {
	for (r = rng_base; r; r = r->r_next) {
	    for (np = name, rp = r->r_name, c = len;
		 c && *rp && (*rp == *np);
		 rp++, np++, c--) /* */;
	    if (!c && !*rp)
		return(r);
	}
	return(0);
    }

    for (r = rng_base; r; r= r->r_next) {
	if ((lmatch == r->r_left.vp) && (rmatch == r->r_right.vp)) 
	    return(r);
    }
    return(0);
}

sync_ranges()
{
    register struct range *r;

    r = rng_base;
    while(r) {
	r->r_left.vp = lookat(r->r_left.vp->row, r->r_left.vp->col);
	r->r_right.vp = lookat(r->r_right.vp->row, r->r_right.vp->col);
	r = r->r_next;
    }
}

write_range(f)
FILE *f;
{
    register struct range *r;

    for (r = rng_base; r; r = r->r_next) {
	(void) fprintf(f, "define \"%s\" %s%s%s%d",
			r->r_name,
			r->r_left.vf & FIX_COL ? "$":"",
			coltoa(r->r_left.vp->col), 
			r->r_left.vf & FIX_ROW ? "$":"",
			r->r_left.vp->row);
	if (r->r_is_range)
	    (void) fprintf(f, ":%s%s%s%d\n",
			    r->r_right.vf & FIX_COL ? "$":"",
			    coltoa(r->r_right.vp->col), 
			    r->r_right.vf & FIX_ROW ? "$":"",
			    r->r_right.vp->row);
	else
	    (void) fprintf(f, "\n");
    }
}

list_range(f)
FILE *f;
{
    register struct range *r;

    for (r = rng_base; r; r = r->r_next) {
	(void) fprintf(f, "%-30s %s%s%s%d",
			    r->r_name,
			    r->r_left.vf & FIX_COL ? "$":"",
			    coltoa(r->r_left.vp->col), 
			    r->r_left.vf & FIX_ROW ? "$":"",
			    r->r_left.vp->row);
	if (r->r_is_range)
	    (void) fprintf(f, ":%s%s%s%d\n",
			    r->r_right.vf & FIX_COL ? "$":"",
			    coltoa(r->r_right.vp->col), 
			    r->r_right.vf & FIX_ROW ? "$":"",
			    r->r_right.vp->row);
	else
	    (void) fprintf(f, "\n");
    }
}

char *
v_name(row, col)
int row, col;
{
    struct ent *v;
    struct range *r;
    static char buf[20];

    v = lookat(row, col);
    if (r = find_range((char *)0, 0, v, v)) {
	return(r->r_name);
    } else {
        (void) sprintf(buf, "%s%d", coltoa(col), row);
	return(buf);
    }
}

char *
r_name(r1, c1, r2, c2)
int r1, c1, r2, c2;
{
    struct ent *v1, *v2;
    struct range *r;
    static char buf[100];

    v1 = lookat(r1, c1);
    v2 = lookat(r2, c2);
    if (r = find_range((char *)0, 0, v1, v2)) {
	return(r->r_name);
    } else {
        (void) sprintf(buf, "%s", v_name(r1, c1));
	(void) sprintf(buf+strlen(buf), ":%s", v_name(r2, c2));
	return(buf);
    }
}
\SHAR\EOF\
else
  echo "will not over write ./range.c"
fi
if [ `wc -c ./range.c | awk '{printf $1}'` -ne 5412 ]
then
echo `wc -c ./range.c | awk '{print "Got " $1 ", Expected " 5412}'`
fi
if `test ! -s ./eres.sed`
then
echo "Extracting ./eres.sed"
cat > ./eres.sed << '\SHAR\EOF\'
/%token.*K_/!d
/%token.*K_\(.*\)/s//	"\1",	K_\1,/
\SHAR\EOF\
else
  echo "will not over write ./eres.sed"
fi
if [ `wc -c ./eres.sed | awk '{printf $1}'` -ne 50 ]
then
echo `wc -c ./eres.sed | awk '{print "Got " $1 ", Expected " 50}'`
fi
if `test ! -s ./sres.sed`
then
echo "Extracting ./sres.sed"
cat > ./sres.sed << '\SHAR\EOF\'
/%token.*S_/!d
/%token.*S_\(.*\)/s//	"\1",	S_\1,/
\SHAR\EOF\
else
  echo "will not over write ./sres.sed"
fi
if [ `wc -c ./sres.sed | awk '{printf $1}'` -ne 50 ]
then
echo `wc -c ./sres.sed | awk '{print "Got " $1 ", Expected " 50}'`
fi
if `test ! -s ./Makefile`
then
echo "Extracting ./Makefile"
cat > ./Makefile << '\SHAR\EOF\'

# Specify the name of the program.
# All documentation and installation keys on this value.
# 
name=sc
NAME=SC

# This is where the install step puts it.
EXDIR=/a/rgb/bin

# This is where the man page goes.
MANDIR=/usr/man/man1

# All of the source files
SRC=sc.h sc.c lex.c gram.y interp.c cmds.c crypt.c xmalloc.c range.c eres.sed\
	sres.sed Makefile cvt.sed psc.c

# The documents in the Archive
DOCS=README sc.doc psc.doc tutorial.sc

# Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up
#SIMPLE=-DSIMPLE

# Use this for system V.2
#CFLAGS= -O -DSYSV2
#LDFLAGS=
#LIB=-lm -lcurses

# Use this for system V.3
#CFLAGS= -O -DSYSV3
#LDFLAGS=
#LIB=-lm -lcurses

# Use this for BSD 4.2
#CFLAGS= -O -DBSD42
#LDFLAGS=
#LIB=-lm -lcurses -ltermcap

# Use this for BSD 4.3
CFLAGS= -O -DBSD43
LDFLAGS=
LIB=-lm -lcurses -ltermcap

# Use this for system III (XENIX)
#CFLAGS= -O -DSYSIII
#LDFLAGS= -i
#LIB=-lm -lcurses -ltermcap

# Use this for VENIX
#CFLAGS= -DVENIX -DBSD42 -DV7
#LDFLAGS= -z -i 
#LIB=-lm -lcurses -ltermcap

# The objects
OBJS=sc.o lex.o gram.o interp.o cmds.o crypt.o xmalloc.o range.o

$(name):	$(OBJS)
	cc ${CFLAGS} ${LDFLAGS} ${OBJS} ${LIB} -o $(name)

diff_to_sc:	diff_to_sc.c
	cc ${CFLAGS} -o dtv diff_to_sc.c

p$(name):	psc.c
	cc ${CFLAGS} -o p$(name) psc.c
	cp p$(name) $(EXDIR)/p$(name)

lex.o:	sc.h y.tab.h gram.o
	cc ${CFLAGS} ${SIMPLE} -c lex.c

sc.o:	sc.h sc.c
	cc ${CFLAGS} ${QUICK} -c sc.c

interp.o:	interp.c sc.h

gram.o:	sc.h y.tab.h

cmds.o: cmds.c sc.h

crypt.o: crypt.c sc.h

range.o: range.c sc.h

y.tab.h:	gram.y

gram.o:	sc.h y.tab.h gram.c
	cc ${CFLAGS} -c gram.c
	sed<gram.y >experres.h -f eres.sed;sed < gram.y > statres.h -f sres.sed

gram.c:	gram.y
	yacc -d gram.y; mv y.tab.c gram.c

clean:
	rm -f *.o *res.h y.tab.h $(name) p$(name) debug core gram.c $(name).1 \
	$(name).man p$(name).man p$(name).1 y.output

shar: ${SRC} ${DOCS}
	shar -c -m 64000 -f shar ${DOCS} ${SRC}

lint: sc.h sc.c lex.c gram.c interp.c cmds.c crypt.c
	lint ${CFLAGS} ${SIMPLE} sc.c lex.c gram.c interp.c cmds.c crypt.c \
	range.c xmalloc.c -lcurses -lm

print: sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c 
	prc sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c | lpr

$(name).1:	sc.doc
	sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g sc.doc >  $(name).1

$(name).man:	$(name).1
	nroff -man $(name).1 > $(name).man

p$(name).1:	psc.doc
	sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g psc.doc >  p$(name).1

p$(name).man:	p$(name).1
	nroff -man p$(name).1 > p$(name).man

install: $(EXDIR)/$(name)

inst-man: $(MANDIR)/$(name).1

$(EXDIR)/$(name): $(name)
	-mv $(EXDIR)/$(name) $(EXDIR)/$(name).old
	strip $(name)
	cp $(name) $(EXDIR)

$(MANDIR)/$(name).1: $(name).1
	cp $(name).1 $(MANDIR)

diffs: ${SRC}
	for i in ${SRC} ;\
		do \
		rcsdiff -c $$i ;\
		done
\SHAR\EOF\
else
  echo "will not over write ./Makefile"
fi
if [ `wc -c ./Makefile | awk '{printf $1}'` -ne 2787 ]
then
echo `wc -c ./Makefile | awk '{print "Got " $1 ", Expected " 2787}'`
fi
if `test ! -s ./cvt.sed`
then
echo "Extracting ./cvt.sed"
cat > ./cvt.sed << '\SHAR\EOF\'
s!+/\(r.*c.*:r.*c[0-9]*\)!@sum(\1)!
s/\(r[0-9]*\)\(c[0-9]*\)/\2\1/g
s/c10/k/g
s/c11/l/g
s/c12/m/g
s/c13/n/g
s/c14/o/g
s/c15/p/g
s/c16/q/g
s/c17/r/g
s/c18/s/g
s/c19/t/g
s/c20/u/g
s/c21/v/g
s/c22/w/g
s/c23/x/g
s/c24/y/g
s/c25/z/g
s/c26/aa/g
s/c27/ab/g
s/c28/ac/g
s/c29/ad/g
s/c30/ae/g
s/c31/af/g
s/c32/ag/g
s/c33/ah/g
s/c34/ai/g
s/c35/aj/g
s/c36/ak/g
s/c37/al/g
s/c38/am/g
s/c39/an/g
s/c0/a/g
s/c1/b/g
s/c2/c/g
s/c3/d/g
s/c4/e/g
s/c5/f/g
s/c6/g/g
s/c7/h/g
s/c8/i/g
s/c9/j/g
s/r\([0-9][0-9]*\)/\1/g
s/format 10/format k/g
s/format 11/format l/g
s/format 12/format m/g
s/format 13/format n/g
s/format 14/format o/g
s/format 15/format p/g
s/format 16/format q/g
s/format 17/format r/g
s/format 18/format s/g
s/format 19/format t/g
s/format 20/format u/g
s/format 21/format v/g
s/format 22/format w/g
s/format 23/format x/g
s/format 24/format y/g
s/format 25/format z/g
s/format 26/format aa/g
s/format 27/format ab/g
s/format 28/format ac/g
s/format 29/format ad/g
s/format 30/format ae/g
s/format 31/format af/g
s/format 32/format ag/g
s/format 33/format ah/g
s/format 34/format ai/g
s/format 35/format aj/g
s/format 36/format ak/g
s/format 37/format al/g
s/format 38/format am/g
s/format 39/format an/g
s/format 0/format a/g
s/format 1/format b/g
s/format 2/format c/g
s/format 3/format d/g
s/format 4/format e/g
s/format 5/format f/g
s/format 6/format g/g
s/format 7/format h/g
s/format 8/format i/g
s/format 9/format j/g
\SHAR\EOF\
else
  echo "will not over write ./cvt.sed"
fi
if [ `wc -c ./cvt.sed | awk '{printf $1}'` -ne 1420 ]
then
echo `wc -c ./cvt.sed | awk '{print "Got " $1 ", Expected " 1420}'`
fi
if `test ! -s ./psc.c`
then
echo "Extracting ./psc.c"
cat > ./psc.c << '\SHAR\EOF\'
/* Sc parse routine
 *
 * usage psc options
 * options:
 *   -L		Left justify strings.  Default is right justify.
 *   -r		Assemble data into rows first, not columns.
 *   -R	n	Increment by n between rows 
 *   -C n	Increment by n between columns
 *   -n n	Length of the row (column) should be n.
 *   -s v	Top left location in the spreadsheet should be v; eg, k5
 *   -d c       Use c as the delimiter between the fields.
 *   -k         Keep all delimiters - Default is strip multiple delimiters to 1.
 *   
 *  Author: Robert Bond
 */

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

#define END 0
#define NUM 1
#define ALPHA 2
#define SPACE 3
#define EOL 4

extern char *optarg;
extern int   optind;
char *coltoa();
char *progname;

int colfirst = 0;
int r0 = 0;
int c0 = 0;
int rinc = 1;
int cinc = 1;
int leftadj = 0;
int len = 20000;
char delim1 = ' ';
char delim2 = '\t';
int strip_delim = 1;
int fwidth[MAXCOLS];
int precision[MAXCOLS];

char token[1000];

main(argc, argv)
int argc;
char **argv;
{
    int curlen;
    int curcol, coff;
    int currow, roff;
    int first;
    int c;
    register effr, effc;
    int i,j;
    register char *p;

    progname = argv[0];
    while ((c = getopt(argc, argv, "rLks:R:C:n:d:")) != EOF) {
	switch(c) {
	case 'r':
	    colfirst = 1;
	    break;
	case 'L':
	    leftadj = 1;
	    break;
	case 's':
	    c0 = getcol(optarg);
	    r0 = getrow(optarg);
	    break;
	case 'R':
	    rinc = atoi(optarg);
	    break;
	case 'C':
	    cinc = atoi(optarg);
	    break;
	case 'n':
	    len = atoi(optarg);
	    break;
	case 'd':
	    delim1 = optarg[0];
	    delim2 = 0;
	    break;
	case 'k':
	    strip_delim = 0;
	    break;
	default:
	    (void) fprintf(stderr,"Usage: %s [-rkL] [-s v] [-R i] [-C i] [-n i] [-d c]\n", progname);
	    exit(1);
        }
    }

    if (optind < argc) {
	    (void) fprintf(stderr,"Usage: %s [-rL] [-s v] [-R i] [-C i] [-n i] [-d c]\n", progname);
	    exit(1);
    }

    curlen = 0;
    curcol = c0; coff = 0;
    currow = r0; roff = 0;
    first = 1;

    while(1) {

	effr = currow+roff;
	effc = curcol+coff;

	switch(scan()) {
	case END:
	    for (i = 0; i<MAXCOLS; i++) {
		if (precision[i])
		    (void) printf("format %s %d %d\n", coltoa(i), precision[i]+1,
			fwidth[i]);
	    }
	    exit(0);
	case NUM:
	    first = 0;
	    (void) printf("let %s%d = %s\n", coltoa(effc), effr, token);
	    if (effc > MAXCOLS-1)
		(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
	    else {
		i = 0;
		j = 0;
		p = token;
		while (*p && *p != '.') {
		    p++; i++;
		}
		if (*p) {
		    p++; i++;
		}
		while (*p) {
		    p++; i++; j++;
		}
		if (precision[effc] < i)
		    precision[effc] = i;
		if (fwidth[effc] < j)
		    fwidth[effc] = j;
	    }
	    break;
	case ALPHA:
	    first = 0;
	    if (leftadj)
		(void) printf("leftstring %s%d = \"%s\"\n", coltoa(effc),effr,token); 
	    else
		(void) printf("rightstring %s%d = \"%s\"\n",coltoa(effc),effr,token); 
	    if (effc > MAXCOLS-1)
		(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
	    else {
		i = strlen(token);
		if (i > precision[effc])
		    precision[effc] = i;
	    }
	    break;
	case SPACE:
	    if (first && strip_delim)
		break;
	    if (colfirst)
		roff++;
	    else
		coff++;
	    break;
	case EOL:
	    curlen++;
	    roff = 0;
	    coff = 0;
	    first = 1;
	    if (colfirst) {
		if (curlen >= len) {
		    curcol = c0;
		    currow += rinc;
		    curlen = 0;
		} else {
		    curcol += cinc;
		}
	    } else {
		if (curlen >= len) {
		    currow = r0;
		    curcol += cinc;
		    curlen = 0;
		} else {
		    currow += rinc;
		}
	    }
	    break;
	}
    }
}

scan()
{
    register int c;
    register char *p;

    p = token;
    c = getchar();

    if (c == EOF)
	return(END);

    if (c == '\n')
	return(EOL);

    if (c == delim1 || c == delim2) {
        if (strip_delim) {
	    while ((c = getchar()) && (c == delim1 || c == delim2))
	        ;
	    (void)ungetc(c, stdin);
	} 
	return(SPACE);
    }

    if (c == '\"') {
	while ((c = getchar()) && c != '\"' && c != '\n' && c != EOF)
	    *p++ = c;
	if (c != '\"')
	    (void)ungetc(c, stdin);
	*p = 0;
	return(ALPHA);
    }

    while (c != delim1 && c != delim2 && c!= '\n' && c != EOF) {
	*p++ = c;
	c = getchar();
    }
    *p = 0;
    (void)ungetc(c, stdin);

    p = token;
    c = *p;
    if (isdigit(c) || c == '.' || c == '-' || c == '+') {
	while(isdigit(c) || c == '.' || c == '-' || c == '+' || c == 'e'
	    || c == 'E') {
		c = *p++;
	}
	if (c == 0)
	    return(NUM);
	else
	    return(ALPHA);
    }

    return(ALPHA);
}
    
getcol(p)
char *p;
{
    register  col;

    if (!p)
	return(0);
    while(*p && !isalpha(*p)) 
	p++; 
    if (!*p)
	return(0);
    col = ((*p & 0137) - 'A');
    if (isalpha(*++p)) 
	col = (col + 1)*26 + ((*p & 0137) - 'A');
    return(col);
}

getrow(p)
char *p;
{
    int row;

    if (!p)
	return(0);
    while(*p && !isdigit(*p))
	p++; 
    if (!*p)
	return(0);
    if (sscanf(p, "%d", &row) != 1)
	return(0);
    return(row);
}

char *
coltoa(col)
int col;
{
    static char rname[3];
    register char *p = rname;

    if (col < 0 || col > 25*26) 
	(void) fprintf(stderr,"coltoa: invalid col: %d", col);

    if (col > 25) {
	*p++ = col/26 + 'A' - 1;
	col %= 26;
    }
    *p++ = col+'A';
    *p = 0;
    return(rname);
}

\SHAR\EOF\
else
  echo "will not over write ./psc.c"
fi
if [ `wc -c ./psc.c | awk '{printf $1}'` -ne 5321 ]
then
echo `wc -c ./psc.c | awk '{print "Got " $1 ", Expected " 5321}'`
fi
echo "Finished archive 3 of 3"
# if you want to concatenate archives, remove anything after this line
exit
-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list