/* 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.8 $ */ #include #if defined(BSD42) || defined(BSD43) #include #else #include #endif #include "sc.h" #include #include #ifdef BSD42 #include #else #ifndef SYSIII #include #endif #endif #ifdef SYSV3 extern void exit(); #else extern int exit(); #endif extern int errno; #define DEFCOLDELIM ':' void duprow() { if (currow >= maxrows - 1 || maxrow >= maxrows - 1) { if (!growtbl(GROWROW, 0, 0)) return; } modflg++; currow++; openrow (currow); for (curcol = 0; curcol <= maxcol; curcol++) { register struct ent *p = *ATBL(tbl, currow - 1, curcol); if (p) { register struct ent *n; n = lookat (currow, curcol); (void)copyent ( n, p, 1, 0); } } for (curcol = 0; curcol <= maxcol; curcol++) { register struct ent *p = *ATBL(tbl, currow, curcol); if (p && (p -> flags & is_valid) && !p -> expr) break; } if (curcol > maxcol) curcol = 0; } void dupcol() { if (curcol >= maxcols - 1 || maxcol >= maxcols - 1) { if (!growtbl(GROWCOL, 0, 0)) return; } modflg++; curcol++; opencol (curcol, 1); for (currow = 0; currow <= maxrow; currow++) { register struct ent *p = *ATBL(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 = *ATBL(tbl, currow, curcol); if (p && (p -> flags & is_valid) && !p -> expr) break; } if (currow > maxrow) currow = 0; } void insertrow(arg) register int arg; { while (--arg>=0) openrow (currow); } void deleterow(arg) register int arg; { flush_saved(); erase_area(currow, 0, currow + arg - 1, maxcol); currow += arg; while (--arg>=0) closerow (--currow); sync_refs(); } void rowvalueize(arg) register int arg; { valueize_area(currow, 0, currow + arg - 1, maxcol); } void colvalueize(arg) register int arg; { valueize_area(0, curcol, maxrow, curcol + arg - 1); } void erase_area(sr, sc, er, ec) int sr, sc, er, ec; { register int r, c; register struct ent **pp; 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; checkbounds(&er, &ec); for (r = sr; r <= er; r++) { for (c = sc; c <= ec; c++) { pp = ATBL(tbl, r, c); if (*pp) { free_ent(*pp); *pp = (struct ent *)0; } } } } void 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; checkbounds(&er, &ec); for (r = sr; r <= er; r++) { for (c = sc; c <= ec; c++) { p = *ATBL(tbl, r, c); if (p && p->expr) { efree(p, p->expr); p->expr = (struct enode *)0; p->flags &= ~is_strexpr; } } } } void 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') { opencol(curcol, 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; } } void colshow_op() { register int i,j; for (i=0; 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); } } void rowshow_op() { register int i,j; for (i=0; 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. */ int 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*/ } void openrow (rs) int rs; { register r, c; struct ent **tmprow, **pp; if (rs > maxrow) maxrow = rs; if (maxrow >= maxrows - 1 || rs > maxrows - 1) { if (!growtbl(GROWROW, rs, 0)) return; } /* * save the last active row+1, shift the rows downward, put the last * row in place of the first */ tmprow = tbl[++maxrow]; for (r = maxrow; r > rs; r--) { row_hidden[r] = row_hidden[r-1]; tbl[r] = tbl[r-1]; pp = ATBL(tbl, r, 0); for (c = 0; c < maxcols; c++, pp++) if (*pp) (*pp)->row = r; } tbl[r] = tmprow; /* the last row was never used.... */ FullUpdate++; modflg++; } void closerow (r) register r; { register struct ent **pp; register c; struct ent **tmprow; if (r > maxrow) return; /* save the row and empty it out */ tmprow = tbl[r]; pp = ATBL(tbl, r, 0); for (c=maxcol+1; --c>=0; pp++) { if (*pp) { free_ent(*pp); *pp = (struct ent *)0; } } /* move the rows, put the deleted row at the end */ for (; r < maxrows - 1; r++) { row_hidden[r] = row_hidden[r+1]; tbl[r] = tbl[r+1]; pp = ATBL(tbl, r, 0); for (c = 0; c < maxcols; c++, pp++) if (*pp) (*pp)->row = r; } tbl[r] = tmprow; maxrow--; FullUpdate++; modflg++; } void opencol (cs, numcol) int cs; int numcol; { register r; register struct ent **pp; register c; register lim = maxcol-cs+1; int i; if (cs > maxcol) maxcol = cs; maxcol += numcol; if ((maxcol >= maxcols - 1) && !growtbl(GROWCOL, 0, maxcol)) return; for (i = maxcol; i > cs; i--) { fwidth[i] = fwidth[i-numcol]; precision[i] = precision[i-numcol]; col_hidden[i] = col_hidden[i-numcol]; } for (c = cs; c - cs < numcol; c++) { fwidth[c] = DEFWIDTH; precision[c] = DEFPREC; } for (r=0; r<=maxrow; r++) { pp = ATBL(tbl, r, maxcol); for (c=lim; --c>=0; pp--) if (pp[0] = pp[-numcol]) pp[0]->col += numcol; pp = ATBL(tbl, r, cs); for (c = cs; c - cs < numcol; c++, pp++) *pp = (struct ent *)0; } FullUpdate++; modflg++; } void closecol (cs, numcol) int cs; int numcol; { register r; register struct ent **pp; register struct ent *q; register c; register lim = maxcol-cs; int i; char buf[50]; if (lim - numcol < -1) { sprintf(buf, "Can't delete %d column%s %d columns left", numcol, (numcol > 1 ? "s," : ","), lim+1); error(buf); return; } flush_saved(); erase_area(0, curcol, maxrow, curcol + numcol - 1); sync_refs(); /* clear then copy the block left */ lim = maxcols - numcol - 1; for (r=0; r<=maxrow; r++) { for (c = cs; c - cs < numcol; c++) if (q = *ATBL(tbl, r, c)) free_ent(q); pp = ATBL(tbl, r, cs); for (c=cs; c <= lim; c++, pp++) { if (c > lim) *pp = (struct ent *)0; else if (pp[0] = pp[numcol]) pp[0]->col -= numcol; } c = numcol; for (; --c >= 0; pp++) *pp = (struct ent *)0; } for (i = cs; i < maxcols - numcol - 1; i++) { fwidth[i] = fwidth[i+numcol]; precision[i] = precision[i+numcol]; col_hidden[i] = col_hidden[i+numcol]; } for (; i < maxcols - 1; i++) { fwidth[i] = DEFWIDTH; precision[i] = DEFPREC; col_hidden[i] = 0; } maxcol -= numcol; FullUpdate++; modflg++; } void 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; } } void 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++; } void 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"); } void printfile (fname, r0, c0, rn, cn) char *fname; int r0, c0, rn, cn; { FILE *f; char pline[FBUFLEN]; int plinelim; int pid; int fieldlen, nextcol; register row, col; register struct ent **pp; if ((strcmp(fname, curfile) == 0) && !yn_ask("Confirm that you want to destroy the data base: (y,n)")) return; if ((f = openout(fname, &pid)) == (FILE *)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 (pp = ATBL(tbl, row, col=c0); col<=cn; pp += nextcol-col, col = nextcol, c += fieldlen) { nextcol = col+1; if (col_hidden[col]) { fieldlen = 0; continue; } fieldlen = fwidth[col]; if (*pp) { char *s; while (plinelimflags&is_valid) { (void)sprintf (pline+plinelim,"%*.*f",fwidth[col], precision[col], (*pp)->v); plinelim += strlen (pline+plinelim); } if (s = (*pp)->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 = (*pp)->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 (!((*pp)->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); } void tblprintfile (fname, r0, c0, rn, cn) char *fname; int r0, c0, rn, cn; { FILE *f; int pid; register row, col; register struct ent **pp; char coldelim = DEFCOLDELIM; if ((strcmp(fname, curfile) == 0) && !yn_ask("Confirm that you want to destroy the data base: (y,n)")) return; if ((f = openout(fname, &pid)) == (FILE *)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 (pp = ATBL(tbl, row, col=c0); col<=cn; col++, pp++) { if (*pp) { char *s; if ((*pp)->flags&is_valid) { (void) fprintf (f,"%.*f",precision[col], (*pp)->v); } if (s = (*pp)->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 == (struct enode *)0) { ret = (struct enode *)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 = (struct enode *)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 */ void 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 = *ATBL(tbl, i, j)) && p->expr) syncref(p->expr); } void syncref(e) register struct enode *e; { if (e == (struct enode *)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; } } } void 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-1) { if (!growtbl(GROWROW, arg+1, 0)) { error("You can't hide the last row"); return; } } FullUpdate++; modflg++; while (r1 <= r2) row_hidden[r1++] = 1; } void 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-1) { if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1)) { error("You can't hide the last col"); return; } } FullUpdate++; modflg++; while (c1 <= c2) col_hidden[c1++] = 1; } void showrow(r1, r2) int r1, r2; { if (r1 < 0 || r1 > r2) { error ("Invalid range"); return; } if (r2 > maxrows-1) { r2 = maxrows-1; } FullUpdate++; modflg++; while (r1 <= r2) row_hidden[r1++] = 0; } void showcol(c1, c2) int c1, c2; { if (c1 < 0 || c1 > c2) { error ("Invalid range"); return; } if (c2 > maxcols-1) { c2 = maxcols-1; } FullUpdate++; modflg++; 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; char *efname; while (*fname && (*fname == ' ')) /* Skip leading blanks */ fname++; if (*fname != '|') { /* Open file if not pipe */ *rpid = 0; efname = findhome(fname); #ifdef DOBACKUPS if (!backup_file(efname) && (yn_ask("Could not create backup copy, Save anyhow?: (y,n)") != 1)) return(0); #endif return(fopen(efname, "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; if ((f = fdopen (pipefd[1], "w")) == (FILE *)0) { (void) kill (pid, -9); error ("Can't fdopen output"); (void) close (pipefd[1]); *rpid = 0; return(0); } } #endif /* VMS */ return(f); } void 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(); } } void 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 = (char *)0; if (p -> label) { n -> label = (char *) xmalloc ((unsigned) (strlen (p -> label) + 1)); (void) strcpy (n -> label, p -> label); } } void write_fd (f, r0, c0, rn, cn) register FILE *f; int r0, c0, rn, cn; { register struct ent **pp; 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; clabel) { edits(r,c); (void) fprintf(f, "%s\n",line); } if ((*pp)->flags&is_valid) { editv (r, c); (void) fprintf (f, "%s\n",line); } } } } int writefile (fname, r0, c0, rn, cn) char *fname; int r0, c0, rn, cn; { register FILE *f; char save[PATHLEN]; int pid; #ifndef VMS if (Crypt) { return (cwritefile(fname, r0, c0, rn, cn)); } #endif /* VMS */ if (*fname == '\0') fname = curfile; (void) strcpy(save,fname); if ((f= openout(fname, &pid)) == (FILE *)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); } void readfile (fname,eraseflg) char *fname; int eraseflg; { register FILE *f; char save[PATHLEN]; if (*fname == '*' && mdir) { (void) strcpy(save, mdir); *fname = '/'; (void) strcat(save, fname); } else { if (*fname == '\0') fname = curfile; (void) strcpy(save,fname); } #ifndef VMS if (Crypt) { creadfile(save, eraseflg); return; } #endif /* VMS */ if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return; if ((f = fopen(findhome(save), "r")) == (FILE *)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(); } void 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 **pp = ATBL(tbl, r, 0); for (c=0; c++<=maxcol; pp++) if (*pp) { if ((*pp)->expr) efree (*pp, (*pp) -> expr); if ((*pp)->label) xfree ((char *)((*pp) -> label)); xfree ((char *)(*pp)); *pp = (struct ent *)0; } } maxrow = 0; maxcol = 0; clean_range(); FullUpdate++; } void backcol(arg) int arg; { while (--arg>=0) { if (curcol) curcol--; else {error ("At column A"); break;} while(col_hidden[curcol] && curcol) curcol--; } } void forwcol(arg) int arg; { while (--arg>=0) { if (curcol < maxcols - 1) curcol++; else if (!growtbl(GROWCOL, 0, arg)) /* get as much as needed */ break; while(col_hidden[curcol]&&(curcol=0) { if (currow < maxrows - 1) currow++; else if (!growtbl(GROWROW, arg, 0)) /* get as much as needed */ break; while (row_hidden[currow]&&(currow=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. */ void 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[FBUFLEN]; 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; } int etype(e) register struct enode *e; { if (e == (struct enode *)0) return NUM; switch (e->op) { case O_SCONST: case '#': case DATE: case FMT: case STINDEX: case EXT: case SVAL: case SUBSTR: return (STR); case '?': case IF: return(etype(e->e.o.right->e.o.left)); case 'f': return(etype(e->e.o.right)); 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); } } /* return 1 if yes given, 0 otherwise */ int yn_ask(msg) char *msg; { char ch; (void) move (0, 0); (void) clrtoeol (); (void) addstr (msg); (void) refresh(); ch = nmgetch(); if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) { if (ch == ctl('g') || ch == ESC) return(-1); error("y or n response required"); return (-1); } if (ch == 'y' || ch == 'Y') return(1); else return(0); } #include char * findhome(path) char *path; { static char *HomeDir = NULL; extern char *getenv(); if (*path == '~') { char *pathptr; char tmppath[PATHLEN]; if (HomeDir == NULL) { HomeDir = getenv("HOME"); if (HomeDir == NULL) HomeDir = "/"; } pathptr = path + 1; if ((*pathptr == '/') || (*pathptr == '\0')) { strcpy(tmppath, HomeDir); } else { struct passwd *pwent; extern struct passwd *getpwnam(); char *namep; char name[50]; namep = name; while ((*pathptr != '\0') && (*pathptr != '/')) *(namep++) = *(pathptr++); *namep = '\0'; if ((pwent = getpwnam(name)) == NULL) { sprintf(path, "Can't find user %s", name); return(NULL); } strcpy(tmppath, pwent->pw_dir); } strcat(tmppath, pathptr); strcpy(path, tmppath); } return(path); } #ifdef DOBACKUPS #include #include /* * make a backup copy of a file, use the same mode and name in the format * [path/]#file~ * return 1 if we were successful, 0 otherwise */ int backup_file(path) char *path; { struct stat statbuf; char fname[PATHLEN]; char tpath[PATHLEN]; #ifdef sequent char *buf; #else char buf[BUFSIZ]; #endif char *tpp; int infd, outfd; int count; /* tpath will be the [path/]file ---> [path/]#file~ */ strcpy(tpath, path); if ((tpp = strrchr(tpath, '/')) == NULL) tpp = tpath; else tpp++; strcpy(fname, tpp); sprintf(tpp, "#%s~", fname); if (stat(path, &statbuf) == 0) { #ifdef sequent if ((buf = xmalloc(statbuf.st_blksize)) == (char *)0) return(0); #endif if ((infd = open(path, O_RDONLY, 0)) < 0) { #ifdef sequent xfree(buf); #endif return(0); } if ((outfd = open(tpath, O_TRUNC|O_WRONLY|O_CREAT, statbuf.st_mode)) < 0) { #ifdef sequent xfree(buf); #endif return(0); } #ifdef sequent while((count = read(infd, buf, statbuf.st_blksize)) > 0) #else while((count = read(infd, buf, sizeof(buf))) > 0) #endif { if (write(outfd, buf, count) != count) { count = -1; break; } } close(infd); close(outfd); #ifdef sequent xfree(buf); #endif return((count < 0) ? 0 : 1); } else if (errno == ENOENT) return(1); return(0); } #endif