rsalz@uunet.uu.net (Rich Salz) (03/22/89)
Submitted-by: Robert Bond <sequent!rgb> Posting-number: Volume 18, Issue 48 Archive-name: sc6.1/part04 # 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: # ./xmalloc.c # ./cmds.c # ./range.c # ./help.c # ./eres.sed # ./sres.sed # ./Makefile # ./psc.c # if `test ! -s ./xmalloc.c` then echo "Extracting ./xmalloc.c" cat > ./xmalloc.c << '\SHAR\EOF\' /* * A safer saner malloc, for careless programmers * $Revision: 6.1 $ */ #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(double))) == NULL) fatal("xmalloc: no memory"); *((int *) ptr) = 12345; /* magic number */ return(ptr + sizeof(double)); } xfree(p) char *p; { if (p == NULL) fatal("xfree: NULL"); p -= sizeof(double); 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 670 ] then echo `wc -c ./xmalloc.c | awk '{print "Got " $1 ", Expected " 670}'` fi if `test ! -s ./cmds.c` then echo "Extracting ./cmds.c" cat > ./cmds.c << '\SHAR\EOF\' /* SC A Spreadsheet Calculator * Command routines * * original by James Gosling, September 1982 * modifications by Mark Weiser and Bruce Israel, * University of Maryland * * More mods Robert Bond, 12/86 * * $Revision: 6.1 $ */ #include <curses.h> #include "sc.h" #include <signal.h> #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII #include <string.h> #endif #endif #ifdef SYSV3 extern void exit(); #else extern int exit(); #endif #define DEFCOLDELIM ':' 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); copyent ( n, p, 1, 0); } } 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); copyent ( n, p, 0, 1); } } 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) register int arg; { while (--arg>=0) openrow (currow); } deleterow(arg) register int arg; { flush_saved(); erase_area(currow, 0, currow + arg - 1, maxcol); currow += arg; while (--arg>=0) closerow (--currow); sync_refs(); } insertcol(arg) register int arg; { while (--arg>=0) opencol(curcol); } deletecol(arg) register int arg; { flush_saved(); erase_area(0, curcol, maxrow, curcol + arg - 1); curcol += arg; while (--arg>=0) closecol (--curcol); sync_refs(); } rowvalueize(arg) register int arg; { valueize_area(currow, 0, currow + arg - 1, maxcol); } colvalueize(arg) register int 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) int to_insert; { register struct ent *p, *n; register int deltar, deltac; int minrow, mincol; int mxrow, mxcol; int numrows, numcols; if (! to_fix) { error ("No data to pull"); 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); copyent( n, p, deltar, deltac); n -> flags = p -> flags & ~is_deleted; } } 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) error ("No hidden columns to show"); else { (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) error ("No hidden rows to show"); else { (void) sprintf(line,"show %d:%d", i, j); linelim = strlen (line); } } /* * Given a row/column command letter, emit a small menu, then read a qualifier * character for a row/column command and convert it to 'r' (row), 'c' * (column), or 0 (unknown). If ch is 'p', an extra qualifier 'm' is allowed. */ get_rcqual (ch) int ch; { error ("%sow/column: r: row c: column%s", (ch == 'i') ? "Insert r" : (ch == 'a') ? "Append r" : (ch == 'd') ? "Delete r" : (ch == 'p') ? "Pull r" : (ch == 'v') ? "Values r" : (ch == 'z') ? "Zap r" : (ch == 's') ? "Show r" : "R", (ch == 'p') ? " m: merge" : ""); (void) refresh(); switch (nmgetch()) { case 'r': case 'l': case 'h': case ctl(f): case ctl(b): return ('r'); case 'c': case 'j': case 'k': case ctl(p): case ctl(n): return ('c'); case 'm': return ((ch == 'p') ? 'm' : 0); case ESC: case ctl (g): return (ESC); default: return (0); } /*NOTREACHED*/ } openrow (rs) int 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) int 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) int 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) int 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; } error (""); /* clear line */ 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++; } print_options(f) FILE *f; { if( autocalc && propagation == 10 && calc_order == BYROWS && !numeric && prescale == 1.0 && !extfunc && showcell && showtop && tbl_style == 0 ) return; /* No reason to do this */ (void) fprintf(f, "set"); if(!autocalc) (void) fprintf(f," !autocalc"); if(propagation != 10) (void) fprintf(f, " iterations = %d", propagation); if(calc_order != BYROWS ) (void) fprintf(f, " bycols"); if (numeric) (void) fprintf(f, " numeric"); if (prescale != 1.0) (void) fprintf(f, " prescale"); if (extfunc) (void) fprintf(f, " extfun"); if (!showcell) (void) fprintf(f, " !cellcur"); if (!showtop) (void) fprintf(f, " !toprow"); if (tbl_style) (void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" : tbl_style == LATEX ? "latex" : tbl_style == TEX ? "tex" : "0" ); (void) fprintf(f, "\n"); } printfile (fname, r0, c0, rn, cn) char *fname; int r0, c0, rn, cn; { 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 file \"%s\"", fname); return; } for (row=r0;row<=rn; row++) { register c = 0; if (row_hidden[row]) continue; pline[plinelim=0] = '\0'; for (p = &tbl[row][col=c0]; col<=cn; p += nextcol-col, col = nextcol, c += fieldlen) { nextcol = col+1; if (col_hidden[col]) { fieldlen = 0; continue; } fieldlen = fwidth[col]; 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)) { if (!col_hidden[nextcol]) 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; } } } pline[plinelim++] = '\n'; pline[plinelim] = 0; (void) fputs (pline, f); } closeout(f, pid); } tblprintfile (fname, r0, c0, rn, cn) char *fname; int r0, c0, rn, cn; { FILE *f; 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 file \"%s\"", fname); return; } if ( tbl_style == TBL ) { fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname); fprintf(f,"tab(%c);\n",coldelim); for (col=c0;col<=cn; col++) fprintf(f," n"); fprintf(f, ".\n"); } else if ( tbl_style == LATEX ) { fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname); for (col=c0;col<=cn; col++) fprintf(f,"c"); fprintf(f, "}\n"); coldelim = '&'; } else if ( tbl_style == TEX ) { fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n", progname, cn-c0+1); coldelim = '&'; } for (row=r0; row<=rn; row++) { if ( tbl_style == TEX ) (void) fprintf (f, "\\+"); 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); } } if ( col < cn ) (void) fprintf(f,"%c",coldelim); } if ( tbl_style == LATEX ) { if ( row < rn ) (void) fprintf (f, "\\\\"); } else if ( tbl_style == TEX ) { (void) fprintf (f, "\\cr"); } (void) fprintf (f,"\n"); } if ( tbl_style == TBL ) (void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname); else if ( tbl_style == LATEX ) (void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname); else if ( tbl_style == TEX ) (void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname); closeout(f, pid); } struct enode * copye (e, Rdelta, Cdelta) register struct enode *e; int Rdelta, Cdelta; { register struct enode *ret; if (e==0) { ret = 0; } else if (e->op & REDUCE) { int newrow, newcol; ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode)); ret->op = e->op; 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; } 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; 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 if (e->op & REDUCE) { 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); } 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; default: syncref(e->e.o.right); syncref(e->e.o.left); break; } } } hiderow(arg) int 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) int 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 column"); return; } FullUpdate++; while (c1 <= c2) col_hidden[c1++] = 1; } showrow(r1, r2) int 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) int 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(); #ifdef VMS fprintf(stderr, "No son tasks available yet under VMS--sorry\n"); #else /* VMS */ if ((pid=fork()) == 0) /* if child */ { (void) close (0); /* close stdin */ (void) close (pipefd[1]); (void) dup (pipefd[0]); /* connect to pipe input */ (void) signal (SIGINT, SIG_DFL); /* reset */ (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); } } #endif /* VMS */ 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(); } } copyent(n,p,dr,dc) register struct ent *n, *p; int dr, dc; { if(!n||!p){error("internal error");return;} n -> v = p -> v; n -> flags = p -> flags; n -> expr = copye (p -> expr, dr, dc); n -> label = 0; if (p -> label) { n -> label = (char *) xmalloc ((unsigned) (strlen (p -> label) + 1)); (void) strcpy (n -> label, p -> label); } } write_fd (f, r0, c0, rn, cn) register FILE *f; int r0, c0, rn, cn; { register struct ent **p; register r, c; (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"); print_options(f); 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]); for (c=c0; c<cn; c++) { if (col_hidden[c]) { (void) fprintf(f, "hide %s\n", coltoa(c)); } } for (r=r0; r<=rn; r++) { if (row_hidden[r]) { (void) fprintf(f, "hide %d\n", r); } } write_range(f); if (mdir) (void) fprintf(f, "mdir \"%s\"\n", mdir); for (r=r0; r<=rn; r++) { p = &tbl[r][c0]; 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); } } } } writefile (fname, r0, c0, rn, cn) char *fname; int r0, c0, rn, cn; { register FILE *f; char save[1024]; int pid; #ifndef VMS if (Crypt) { return (cwritefile(fname, r0, c0, rn, cn)); } #endif /* VMS */ if (*fname == 0) fname = &curfile[0]; (void) strcpy(save,fname); f = openout(fname, &pid); if (f == 0) { error ("Can't create file \"%s\"", fname); return (-1); } write_fd(f, r0, c0, rn, cn); closeout(f, pid); if (!pid) { (void) strcpy(curfile, save); modflg = 0; error("File \"%s\" written.",curfile); } return (0); } readfile (fname,eraseflg) char *fname; int eraseflg; { register FILE *f; char save[1024]; if (*fname == '*' && mdir) { (void) strcpy(save, mdir); *fname = '/'; (void) strcat(save, fname); } else { if (*fname == 0) fname = &curfile[0]; (void) strcpy(save,fname); } #ifndef VMS if (Crypt) { creadfile(save, eraseflg); return; } #endif /* VMS */ if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return; f = fopen (save, "r"); if (f==0) { error ("Can't read file \"%s\"", save); return; } if (eraseflg) erasedb (); loading++; while (fgets(line,sizeof line,f)) { linelim = 0; if (line[0] != '#') (void) yyparse (); } --loading; (void) fclose (f); linelim = -1; modflg++; if (eraseflg) { (void) strcpy(curfile,save); modflg = 0; } EvalAll(); } erasedb () { register r, c; for (c = 0; c<=maxcol; c++) { fwidth[c] = DEFWIDTH; precision[c] = DEFPREC; } for (r = 0; r<=maxrow; r++) { register struct ent **p = &tbl[r][0]; for (c=0; c++<=maxcol; p++) if (*p) { if ((*p)->expr) efree ((*p) -> expr); if ((*p)->label) xfree ((char *)((*p) -> label)); xfree ((char *)(*p)); *p = 0; } } maxrow = 0; maxcol = 0; clean_range(); FullUpdate++; } backcol(arg) int arg; { while (--arg>=0) { if (curcol) curcol--; else {error ("At column A"); break;} while(col_hidden[curcol] && curcol) curcol--; } } forwcol(arg) int arg; { while (--arg>=0) { if (curcol < MAXCOLS - 1) curcol++; else {error ("The table can't be any wider"); break;} while(col_hidden[curcol]&&(curcol<MAXCOLS-1)) curcol++; } } forwrow(arg) int arg; { while (--arg>=0) { if (currow < MAXROWS - 1) currow++; else {error ("The table can't be any longer"); break;} while (row_hidden[currow]&&(currow<MAXROWS-1)) currow++; } } backrow(arg) int arg; { while (--arg>=0) { if (currow) currow--; else {error ("At row zero"); break;} while (row_hidden[currow] && currow) currow--; } } /* * Show a cell's label string or expression value. May overwrite value if * there is one already displayed in the cell. Created from old code in * update(), copied with minimal changes. */ showstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c) char *string; /* to display */ int leftflush; /* or rightflush */ int hasvalue; /* is there a numeric value? */ int row, col; /* spreadsheet location */ int *nextcolp; /* value returned through it */ int mxcol; /* last column displayed? */ int *fieldlenp; /* value returned through it */ int r, c; /* screen row and column */ { register int nextcol = *nextcolp; register int fieldlen = *fieldlenp; char field[1024]; int slen; char *start, *last; register char *fp; struct ent *nc; /* This figures out if the label is allowed to slop over into the next blank field */ slen = strlen (string); while ((slen > fieldlen) && (nextcol <= mxcol) && !((nc = lookat (row, nextcol)) -> flags & is_valid) && !(nc->label)) { if (! col_hidden [nextcol]) fieldlen += fwidth [nextcol]; nextcol++; } if (slen > fieldlen) slen = fieldlen; /* Now justify and print */ start = leftflush ? field : field + fieldlen - slen; last = field+fieldlen; fp = field; while (fp < start) *fp++ = ' '; while (slen--) *fp++ = *string++; if ((! hasvalue) || fieldlen != fwidth[col]) while (fp < last) *fp++ = ' '; *fp = 0; #ifdef VMS mvaddstr(r, c, field); /* this is a macro */ #else (void) mvaddstr(r, c, field); #endif *nextcolp = nextcol; *fieldlenp = fieldlen; } etype(e) register struct enode *e; { if (e==0) return 0; switch (e->op) { case '+': case '-': case '*': case '/': case '%': case '^': case '<': case '=': case '>': case '&': case '|': case 'm': case '~': case 'k': case INDEX: case REDUCE | '+': case REDUCE | '*': case REDUCE | 'a': case REDUCE | 's': case REDUCE | MAX: case REDUCE | MIN: case ACOS: case ASIN: case ATAN: case ATAN2: case CEIL: case COS: case EXP: case FABS: case FLOOR: case HYPOT: case LOG: case LOG10: case POW: case SIN: case SQRT: case TAN: case DTR: case RTD: case RND: case FV: case PV: case PMT: case HOUR: case MINUTE: case SECOND: case MONTH: case DAY: case YEAR: case NOW: case STON: case EQS: case LMAX: case LMIN: case NVAL: case LOOKUP: return (NUM); case O_SCONST: case '#': case DATE: case FMT: case STINDEX: case EXT: case SVAL: case SUBSTR: return (STR); case 'f': case '?': return(etype(e->e.o.left)); case O_VAR: { register struct ent *p; p = e->e.v.vp; if (p->expr) return(p->flags & is_strexpr ? STR : NUM); else if (p->label) return(STR); else return(NUM); } default: return(NUM); } } \SHAR\EOF\ else echo "will not over write ./cmds.c" fi if [ `wc -c ./cmds.c | awk '{printf $1}'` -ne 27705 ] then echo `wc -c ./cmds.c | awk '{print "Got " $1 ", Expected " 27705}'` 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 * * $Revision: 6.1 $ */ #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; (void) fprintf(f, "%-30s %s\n\n","Name","Definition"); 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); } } are_ranges() { return (rng_base != 0); } \SHAR\EOF\ else echo "will not over write ./range.c" fi if [ `wc -c ./range.c | awk '{printf $1}'` -ne 5535 ] then echo `wc -c ./range.c | awk '{print "Got " $1 ", Expected " 5535}'` fi if `test ! -s ./help.c` then echo "Extracting ./help.c" cat > ./help.c << '\SHAR\EOF\' /* * Help functions for sc * R. Bond, 1988 * $Revision: 6.2 $ */ #include <curses.h> #include "sc.h" char *intro[] = { " ", " Overview:", " ", " A: This overview", " B: Options", " C: Cursor movement commands", " D: Cell entry and editing commands", " E: File commands", " F: Row and column commands", " G: Range commands", " H: Miscellaneous commands", " I: Variable names/Expressions", " J: Range functions", " K: Numeric functions", " L: String functions", " M: Financial functions", " N: Time and date functions", " ", " Q: Return to main spreadsheet", 0 }; char *options[] = { " ", " B: Options", " ", " ^To Toggle options. Toggle one option selected by o:", " ", " a Recalculate automatically or on ``@'' commands.", " c Current cell highlighting enable/disable.", " e External function execution enable/disable.", " n If enabled, a digit starts a numeric value.", " t Top line display enable/disable.", " x Encrypt/decrypt database and listing files.", " $ Dollar prescale. If enabled, all numeric constants.", " (not expressions) entered are multipled by 0.01.", " ", " S Set options. Options include:", " ", " byrows Recalculate in row order. (default)", " bycols Recalculate in column order.", " iterations=n Set the number of iterations allowed. (10)", " tblstyle=xx Set ``T'' output style to:", " 0 (none), tex, latex, or tbl.", 0 }; char *cursor[] = { " ", " C: Cell cursor movement (always OK):", " ", " ^N ^P ^B ^F Down, up, back, forward", " ^Ed Go to end of range. Follow ^E by a direction indicator", " such as ^P or j.", " Arrow keys (if the terminal and termcap support them.)", " ", " Cell cursor movement if no prompt active:", " j,k,l,h Down, up, right, left", " SPACE Forward", " ^H Back", " TAB Forward, otherwise starts/ends a range", " ^ Up to row 0 of the current column.", " # Down to the last valid row of the current column.", " 0 Back to column A. Preface with ^U if numeric mode.", " $ Forward to the last valid column of the current row.", " b Back then up to the previous valid cell.", " w Forward then down to the next valid cell.", " g Go to a cell. Cell name, range name, quoted string,", " or a number specify which cell.", 0 }; char *cell[] = { " ", " D: Cell entry and editing commands:", " ", " = Enter a numeric constant or expression.", " < Enter a left justified string or string expression.", " \",> Enter a right justified string or string expression.", " e Edit the current cell's numeric value.", " E Edit the current cell's string part.", " x Clear the current cell.", " c Copy the last marked cell to the current cell.", " m Mark a cell to be used as the source for ``c''", " + Increment numeric part", " - Decrement numeric part", " ", " In numeric mode, a decimal digit, ``+'', ``-'', and ``.'' all start", " a new numeric constant or expression.", 0 }; char *file[] = { " ", " E: File commands:", " ", " G Get a new database from a file. ", " M Merge a new file into the current database.", " P Put the current database into a file.", " W Write a listing of the current database into a file in", " a form that matches its appearance on the screen.", " T Write a listing of the current database to a file, but", " put delimiters between each pair of fields.", " Optionally brackets output with control lines for ``tbl'',", " ``LaTeX'', or ``TeX''.", " ", " If encryption mode is set, file I/O will be encrypted/decrypted.", " ``\"| program\"'' for a file name will pipe (unencrypted) output to", " a program for Put, Write and Table. If a cell name is used", " as the file name, the cell's string part will be used as the", " file name.", 0 }; char *row[] = { " ", " F: Row and column commands:", " ", " ir, ic Insert a new, empty row (column)", " ar, ac Append a new copy of the current row (column)", " dr, dc Delete the current row (column)", " pr, pc, pm Pull deleted cells back into the spreadsheet", " Insert rows, columns or merge the cells.", " vr, vc Remove expressions from the affected rows (columns),", " leaving only the values.", " zr, zc Hide (``zap'') the current row (column)", " sr, sc Show hidden rows (columns)", " f Set the output format to be used with the values of", " each cell in this column. Enter field width and", " number of fractional digits. A preceding count can be", " used to change more than one column.", " ", " Commands which move or copy cells also modify the row and column ", " references in the new cell expressions. Use ``fixed'' or the", " ``$'' style cell reference to supress the change.", 0 }; char *range[] = { " ", " G: Range commands:", " ", " /x Clear a range. ", " /v Remove the expressions from a range of cells, leaving ", " just the values.", " /c Copy a source range to a destination range.", " /f Fill a range with constant values starting with a given", " value and increasing by a given increment.", " /d Assign a name to a cell or a range of cells. Give the", " the name, surrounded by quotes, and either a cell name such", " as ``A10'' or a range such as ``a1:b20''.", " /s Shows the currently defined range names. Pipe output to", " sort, then to less.", " /u Use this command to undefine a previously defined range", " name.", " ", " Range operations affect a rectangular region on the screen", " defined by the upper left and lower right cells in the region.", " A range is specified by giving the cell names separated by ``:'',", " such as ``a20:k52''. Another way to refer to a range is to use", " a name previously defined using ``/d''.", 0 }; char *misc[] = { " ", " H: Miscellaneous commands:", " ", " Q q ^C Exit from the program.", " ^G ESC Abort entry of the current command.", " ? Help", " ! Shell escape. Enter a command to run. ``!!'' repeats", " the last command. Just ``!'' starts an interactive shell.", " ^L Redraw the screen.", " ^R Redraw the screen. Highlight cells with values but no", " expressions.", " ^X Redraw the screen. Show formulas, not values.", " @ Recalculate the spreadsheet.", " ^V Type, in the command line, the name of the current cell.", " ^W Type, in the command line, the current cell's expression.", " ^A Type, in the command line, the current cell's numeric value.", " TAB When the character cursor is on the top line TAB can be used", " to start or stop the display of the default range.", 0 }; char *var[] = { " ", " I: Variable names:", " ", " K20 Row and column can vary on copies.", " $K$20 Row and column stay fixed on copies.", " $K20 Row can vary; column stays fixed on copies.", " K$20 Row stays fixed; column can vary on copies.", " fixed holds following expession fixed on copies.", " Cells and ranges can also be assigned a symbolic name via the", " range command ``/d''.", " ", " Expressions:", " -e Negation e<=e Less than or equal", " e+e Addition e=e Equal", " e-e Subtraction e!=e Not Equal", " e*e Multiplication e>=e Greater than or equal", " e/e Division e>e Greater than", " e%e Modulo e<e Less than", " e^e Exponentiation e&e Boolean operator AND.", " ~e Boolean operator NOT e|e Boolean operator OR", " e?e1:e2 Conditional: If the e is non zero then then e1, otherwise e2.", " Terms may be constants, variable names, and parenthesized expressions.", 0 }; char *rangef[] = { " ", " J: Range functions:", " ", " @sum(r) Sum all valid cells in the range.", " @prod(r) Multiply together all valid cells in the range.", " @avg(r) Average all valid cells in range.", " @max(r) Return the maximum value in the range.", " @min(r) Return the minimum value in the range.", " See also the numeric versions of max and min.", " @stddev(r) Return the sample standard deviation of ", " the cells in the range.", " @index(e,r) Return the numeric value of the cell at index e", " into range r.", " @stindex(e,r) Return the string value of the cell at index e", " into range r.", " @lookup(e,r) Search through the range r for a value that", " matches e. The value returned is that from the", " next row and the same column as the match, if", " the range was a single row, or the value from", " the next column and the same row as the match if", " the range was a single column.", 0 }; char *numericf[] = { " ", " K: Numeric functions:", " ", " @atan2(e1,e2) Arc tangent of e1/e2.", " @ceil(e) Smallest integer not less than e.", " @eqs(se1,se2) 1 if string expr se1 has the same value as se2.", " @exp(e) Exponential function of e.", " @fabs(e) Absolute value of e.", " @floor(e) The largest integer not greater than e.", " @hypot(x,y) Sqrt(x*x+y*y).", " @max(e1,e2,...) The maximum of the values of the e's.", " @min(e1,e2,...) The minimum of the values of the e's", " @nval(se,e) The numeric value of a named cell.", " pi A constant quite close to pi.", " @pow(e1,e2) e1 raised to the power of e2.", " @rnd(e) Round e to the nearest integer.", " @sqrt(e) Square root of e.", " @ston(se) Convert string expr se to a numeric", " @ln(e) @log(e) Natural/base 10 logarithm of e.", " @dtr(e) @rtd(e) Convert degrees to/from radians.", " @cos(e) @sin(e) @tan(e) Trig functions of radian arguments.", " @asin(e) @acos(e) @atan(e) Inverse trig function.", 0 }; char *stringf[] = { " ", " L: String functions:", " ", " # Concatenate strings. For example, the", " string expression ``A0 # \"zy dog\"'' yields", " ``the lazy dog'' if A0 is ``the la''.", " @substr(se,e1,e2) Extract characters e1 through e2 from the", " string expression se. For example,", " ``@substr(\"Nice jacket\" 4, 7)'' yields ", " ``e jac''.", " @fmt(se,e) Convert a number to a string using sprintf(3).", " For example, ``@fmt(\"*%6.3f*\",10.5)'' yields", " ``*10.500*''. Use formats are e, E, f, g, and G.", " @sval(se,e) Return the string value of a cell selected by name.", " @ext(se,e) Call an external function (program or", " script). Convert e to a string and append it", " to the command line as an argument. @ext yields", " a string: the first line printed to standard", " output by the command.", " String expressions are made up of constant strings (characters", " surrounded by quotes), variables, and string functions.", 0 }; char *finf[] = { " ", " M: Financial functions:", " ", " @pmt(e1,e2,e3) @pmt(60000,.01,360) computes the monthly", " payments for a $60000 mortgage at 12%", " annual interest (.01 per month) for 30", " years (360 months).", " ", " @fv(e1,e2,e3) @fv(100,.005,36) computes the future value", " for of 36 monthly payments of $100 at 6%", " interest (.005 per month). It answers the", " question: ``How much will I have in 2", " years if I deposit $100 per month in a", " savings account paying 6% interest com-", " pounded monthly?''", " ", " @pv(e1,e2,e3) @pv(1000,.015,36) computes the present", " value of an a ordinary annuity of 36", " monthly payments of $1000 at 18% annual", " interest. It answers the question: ``How", " much can I borrow at 18% for 30 years if I", " pay $1000 per month?''", 0 }; char *timef[] = { " ", " N: Time and date functions:", " ", " @now Return the current time encoded as the", " number of seconds since December 31, 1969,", " midnight, GMT.", " ", " All of the following take an argument expressed in seconds:", " ", " @date(e) Convert the time in seconds to a date", " string 24 characters long in the following", " form: ``Sun Sep 16 01:03:52 1973''. Note", " that you can extract pieces of this fixed format", " string with @substr.", " @year(e) Return the year. Valid years begin with 1970.", " @month(e) Return the month: 1 (Jan) to 12 (Dec).", " @day(e) Return the day of the month: 1 to 31.", " @hour(e) Return the number of hours since midnight: 0 to 23.", " @minute(e) Return the number of minutes since the", " last full hour: 0 to 59.", " @second(e) Return the number of seconds since the", " last full minute: 0 to 59.", 0 }; help() { int option; char **ns = intro; while((option = pscreen(ns)) != 'q' && option != 'Q') { switch (option) { case 'a': case 'A': ns = intro; break; case 'b': case 'B': ns = options; break; case 'c': case 'C': ns = cursor; break; case 'd': case 'D': ns = cell; break; case 'e': case 'E': ns = file; break; case 'f': case 'F': ns = row; break; case 'g': case 'G': ns = range; break; case 'h': case 'H': ns = misc; break; case 'i': case 'I': ns = var; break; case 'j': case 'J': ns = rangef; break; case 'k': case 'K': ns = numericf; break; case 'l': case 'L': ns = stringf; break; case 'm': case 'M': ns = finf; break; case 'n': case 'N': ns = timef; break; default: ns = intro; break; } } FullUpdate++; (void) move(1,0); (void) clrtobot(); } pscreen(screen) char *screen[]; { int line; int dbline; (void) move(1,0); (void) clrtobot(); dbline = 1; for (line = 0; screen[line]; line++) { (void) move(dbline++, 4); (void) addstr (screen[line]); (void) clrtoeol(); } (void) move(0,0); (void) printw("Which Screen? [a-n, q]"); (void) clrtoeol(); (void) refresh(); return(nmgetch()); } \SHAR\EOF\ else echo "will not over write ./help.c" fi if [ `wc -c ./help.c | awk '{printf $1}'` -ne 15538 ] then echo `wc -c ./help.c | awk '{print "Got " $1 ", Expected " 15538}'` 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=/h/rgb/bin/sym # This is where the man page goes. MANDIR=/usr/man/man1 # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up #SIMPLE=-DSIMPLE # Set INTERNATIONAL if you need 8 bit characters. You should # not set this if you are running 5.3.0. I think it is OK in 5.3.1. #INTERNATIONAL=-DINTERNATIONAL # Set SIGVOID if signal routines are type void. System 5.3, VMS and ANSI C # Compliant systems use this. Most BSD systems do not. #SIGVOID=-DSIGVOID # This is the name of a pager like "more" If the line is commented out # then "more" will be used. "pg" may be appropriate for SYSV PAGER=-DDFLT_PAGER=\"less\" # Use this for system V.2 # CFLAGS= -O -DSYSV2 $(SIGVOID) # LDFLAGS= # LIB=-lm -lcurses -lPW # Use this for system V.3 CFLAGS= -O -DSYSV3 -DSIGVOID LDFLAGS= LIB=-lm -lcurses -lPW # Use this for BSD 4.2 #CFLAGS= -O -DBSD42 $(SIGVOID) #LDFLAGS= #LIB=-lm -lcurses -ltermcap # Use this for BSD 4.3 #CFLAGS= -O -DBSD43 $(SIGVOID) #LDFLAGS= #LIB=-lm -lcurses -ltermcap # Use this for system III (XENIX) #CFLAGS= -O -DSYSIII $(SIGVOID) #LDFLAGS= -i #LIB=-lm -lcurses -ltermcap # Use this for VENIX #CFLAGS= -DVENIX -DBSD42 -DV7 $(SIGVOID) #LDFLAGS= -z -i #LIB=-lm -lcurses -ltermcap # All of the source files SRC=sc.h sc.c lex.c gram.y interp.c crypt.c xmalloc.c cmds.c range.c help.c \ eres.sed sres.sed Makefile psc.c # The objects OBJS=sc.o interp.o cmds.o crypt.o xmalloc.o range.o help.o lex.o gram.o # The documents in the Archive DOCS=README CHANGES sc.doc psc.doc tutorial.sc VMS_NOTES BSD_BUGS $(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} ${INTERNATIONAL} -c lex.c sc.o: sc.h sc.c $(CC) ${CFLAGS} ${INTERNATIONAL} $(PAGER) -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 help.o: help.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 help.c -lcurses -lm inspect: sc.h sc.c lex.c gram.c interp.c cmds.c crypt.c /bruces/ianj/bin/i386/inspect -abv -t 8 sc.c lex.c gram.c interp.c \ cmds.c crypt.c range.c xmalloc.c help.c 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} ${DOCS} ;\ do \ rcsdiff -c -r5.1 $$i ;\ done \SHAR\EOF\ else echo "will not over write ./Makefile" fi if [ `wc -c ./Makefile | awk '{printf $1}'` -ne 3645 ] then echo `wc -c ./Makefile | awk '{print "Got " $1 ", Expected " 3645}'` 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 * $Revision: 6.1 $ */ #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; #ifdef SYSV3 extern void exit(); #else extern int exit(); #endif 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 5408 ] then echo `wc -c ./psc.c | awk '{print "Got " $1 ", Expected " 5408}'` fi echo "Finished archive 4 of 4" # if you want to concatenate archives, remove anything after this line exit -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.