rsalz@bbn.com (Rich Salz) (02/05/88)
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@uunet.uu.net.