home *** CD-ROM | disk | FTP | other *** search
- /* 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
- * More mods by Alan Silverstein, 3-4/88, see list of changes.
- * Currently supported by pur-phy!sawmill!buhrt (Jeff Buhrt)
- * $Revision: 6.8 $
- *
- */
-
-
- #include <signal.h>
- #include <curses.h>
- #include <ctype.h>
-
- #ifdef AMIGA
- #include <unix.h>
- #endif
-
- #ifdef BSD42
- #include <strings.h>
- #else
- #ifndef SYSIII
- #include <string.h>
- #endif
- #endif
-
- #include <stdio.h>
- #include "sc.h"
-
- char *getenv();
-
- #ifdef SYSV3
- void exit();
- #endif
-
- #ifndef DFLT_PAGER
- #define DFLT_PAGER "more" /* more is probably more widespread than less */
- #endif /* DFLT_PAGER */
-
- #define MAXCMD 160 /* for ! command below */
-
- extern char *rev;
-
- /* Globals defined in sc.h */
-
- struct ent ***tbl;
- int strow, stcol;
- int currow, curcol;
- int savedrow, savedcol;
- int FullUpdate;
- int maxrow, maxcol;
- int maxrows, maxcols;
- int *fwidth;
- int *precision;
- char *col_hidden;
- char *row_hidden;
- char line[FBUFLEN];
- int changed;
- struct ent *to_fix;
- int modflg;
- int numeric;
- char *mdir;
- int showsc, showsr; /* Starting cell for highlighted range */
- char mode_ind = '.';
-
- char curfile[PATHLEN];
- char revmsg[80];
-
- int linelim = -1;
-
- int showtop = 1; /* Causes current cell value display in top line */
- int showcell = 1; /* Causes current cell to be highlighted */
- int showrange = 0; /* Causes ranges to be highlighted */
- int showneed = 0; /* Causes cells needing values to be highlighted */
- int showexpr = 0; /* Causes cell exprs to be displayed, highlighted */
-
- int autocalc = 1 ; /* 1 to calculate after each update */
- int calc_order = BYROWS;
- int tbl_style = 0; /* headers for T command output */
-
- int lastmx, lastmy; /* Screen address of the cursor */
- int lastcol; /* Spreadsheet Column the cursor was in last */
- char under_cursor[] = " "; /* Data under the < cursor */
-
- #ifdef VMS
- int VMS_read_raw = 0;
- #endif
-
- int seenerr;
-
- void
- yyerror(err)
- char *err; {
- if (seenerr) return;
- seenerr++;
- (void) move(1,0);
- (void) clrtoeol();
- (void) printw("%s: %.*s<=%s",err,linelim,line,line+linelim);
- }
-
- struct ent *
- lookat(row,col)
- int row, col;
- {
- register struct ent **pp;
-
- checkbounds(&row, &col);
- pp = ATBL(tbl, row, col);
- if (*pp == (struct ent *)0) {
- *pp = (struct ent *) xmalloc((unsigned)sizeof(struct ent));
- if (row>maxrow) maxrow = row;
- if (col>maxcol) maxcol = col;
- (*pp)->label = (char *)0;
- (*pp)->row = row;
- (*pp)->col = col;
- (*pp)->flags = 0;
- (*pp)->expr = (struct enode *)0;
- (*pp)->v = (double) 0.0;
- (*pp)->evnext = (struct ent *)0;
- }
- return *pp;
- }
-
- /*
- * This structure is used to keep ent structs around before they
- * are deleted to allow the sync_refs routine a chance to fix the
- * variable references.
- * We also use it as a last-deleted buffer for the 'p' command.
- */
-
- void
- free_ent(p)
- register struct ent *p;
- {
- p->next = to_fix;
- to_fix = p;
- p->flags |= is_deleted;
- }
-
- void
- flush_saved()
- {
- register struct ent *p;
- register struct ent *q;
-
- if (!(p = to_fix))
- return;
- while (p) {
- (void) clearent(p);
- q = p->next;
- xfree((char *)p);
- p = q;
- }
- to_fix = 0;
- }
-
- /*
- * standout last time in update()?
- * At this point we will let curses do work
- */
- int standlast = FALSE;
-
- void
- update (anychanged)
- int anychanged; /* did any cell really change in value? */
- {
- register row,
- col;
- register struct ent **pp;
- int mxcol;
- int mxrow;
- int rows;
- int cols;
- int minsr, minsc, maxsr, maxsc;
- register r;
- register i;
-
- while (row_hidden[currow]) /* You can't hide the last row or col */
- currow++;
- while (col_hidden[curcol])
- curcol++;
- /* First see if the last display still covers curcol */
- if (stcol <= curcol) {
- for (i = stcol, cols = 0, col = RESCOL;
- (col + fwidth[i]) < COLS-1 && i < maxcols; i++) {
- cols++;
- if (col_hidden[i])
- continue;
- col += fwidth[i];
- }
- }
- while (stcol + cols - 1 < curcol || curcol < stcol) {
- FullUpdate++;
- if (stcol - 1 == curcol) { /* How about back one? */
- stcol--;
- } else if (stcol + cols == curcol) { /* Forward one? */
- stcol++;
- } else {
- /* Try to put the cursor in the center of the screen */
- col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL;
- stcol = curcol;
- for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) {
- stcol--;
- if (col_hidden[i])
- continue;
- col -= fwidth[i];
- }
- }
- /* Now pick up the counts again */
- for (i = stcol, cols = 0, col = RESCOL;
- (col + fwidth[i]) < COLS-1 && i < maxcols; i++) {
- cols++;
- if (col_hidden[i])
- continue;
- col += fwidth[i];
- }
- }
- /* Now - same process on the rows */
- if (strow <= currow) {
- for (i = strow, rows = 0, row=RESROW; row<LINES && i<maxrows; i++) {
- rows++;
- if (row_hidden[i])
- continue;
- row++;
- }
- }
- while (strow + rows - 1 < currow || currow < strow) {
- FullUpdate++;
- if (strow - 1 == currow) { /* How about up one? */
- strow--;
- } else if (strow + rows == currow) { /* Down one? */
- strow++;
- } else {
- /* Try to put the cursor in the center of the screen */
- row = (LINES - RESROW) / 2 + RESROW;
- strow = currow;
- for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
- strow--;
- if (row_hidden[i])
- continue;
- row--;
- }
- }
- /* Now pick up the counts again */
- for (i = strow, rows = 0, row=RESROW; row<LINES && i<maxrows; i++) {
- rows++;
- if (row_hidden[i])
- continue;
- row++;
- }
- }
- mxcol = stcol + cols - 1;
- mxrow = strow + rows - 1;
- if (FullUpdate || standlast) {
- (void) move(2, 0);
- (void) clrtobot();
- (void) standout();
- for (row=RESROW, i=strow; i <= mxrow; i++) {
- if (row_hidden[i])
- continue;
- (void) move(row,0);
- if (maxrows < 1000)
- (void) printw("%-*d", RESCOL-1, i);
- else
- (void) printw("%-*d", RESCOL, i);
- row++;
- }
- (void) move(2,0);
- (void) printw("%*s", RESCOL, " ");
-
- for (col=RESCOL, i = stcol; i <= mxcol; i++) {
- register int k;
- if (col_hidden[i])
- continue;
- (void) move(2, col);
- k = fwidth[i]/2;
- if (k == 0)
- (void) printw("%1s", coltoa(i));
- else
- (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
- col += fwidth[i];
- }
- (void) standend();
- }
-
- /* Get rid of cursor standout on the cell at previous cursor position */
- if (showcell)
- { (void) move(lastmx, lastmy);
- repaint(lastmx, lastmy, fwidth[lastcol]);
- }
-
- if (showrange) {
- minsr = showsr < currow ? showsr : currow;
- minsc = showsc < curcol ? showsc : curcol;
- maxsr = showsr > currow ? showsr : currow;
- maxsc = showsc > curcol ? showsc : curcol;
-
- if (showtop) {
- (void) move(1,0);
- (void) clrtoeol();
- (void) printw("Default range: %s",
- r_name(minsr, minsc, maxsr, maxsc));
- }
- }
-
- /* Repaint the visible screen */
- if (showrange || anychanged || FullUpdate || standlast)
- {
- /* may be reset in loop, if not next time we will do a FullUpdate */
- if (standlast)
- { FullUpdate = TRUE;
- standlast = FALSE;
- }
- for (row = strow, r = RESROW; row <= mxrow; row++) {
- register c = RESCOL;
- int do_stand = 0;
- int fieldlen;
- int nextcol;
-
- if (row_hidden[row])
- continue;
- for (pp = ATBL(tbl, row, col = stcol); col <= mxcol;
- pp += nextcol - col, col = nextcol, c += fieldlen) {
-
- nextcol = col+1;
- if (col_hidden[col]) {
- fieldlen = 0;
- continue;
- }
-
- fieldlen = fwidth[col];
-
- /*
- * Set standout if:
- *
- * - showing ranges, and not showing cells which need to be filled
- * in, and not showing cell expressions, and in a range, OR
- *
- * - if showing cells which need to be filled in and this one is
- * of that type (has a value and doesn't have an expression,
- * or it is a string expression), OR
- *
- * - if showing cells which have expressions and this one does.
- */
-
- if ((showrange && (! showneed) && (! showexpr)
- && (row >= minsr) && (row <= maxsr)
- && (col >= minsc) && (col <= maxsc))
- || (showneed && (*pp) && ((*pp) -> flags & is_valid)
- && (((*pp) -> flags & is_strexpr) || !((*pp) -> expr)))
- || (showexpr && (*pp) && ((*pp) -> expr)))
- {
- (void) move(r, c);
- (void) standout();
- standlast++;
- if (!*pp) /* no cell, but standing out */
- { (void) printw("%*s", fwidth[col], " ");
- (void) standend();
- continue;
- }
- else
- do_stand = 1;
- }
- else
- do_stand = 0;
-
- if ((*pp) && ((*pp) -> flags & is_changed || FullUpdate) || do_stand) {
- if (do_stand) {
- (*pp) -> flags |= is_changed;
- } else {
- (void) move(r, c);
- (*pp) -> flags &= ~is_changed;
- }
-
- /*
- * Show expression; takes priority over other displays:
- */
-
- if (showexpr && ((*pp) -> expr)) {
- linelim = 0;
- editexp(row, col); /* set line to expr */
- linelim = -1;
- showstring(line, /* leftflush = */ 1, /* hasvalue = */ 0,
- row, col, & nextcol, mxcol, & fieldlen, r, c);
- }
- else {
-
- /*
- * Show cell's numeric value:
- */
-
- if ((*pp) -> flags & is_valid) {
- char field[FBUFLEN];
- (void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*pp)->v);
- if(strlen(field) > fwidth[col]) {
- for(i = 0; i<fwidth[col]; i++)
- (void)addch('*');
- } else {
- (void)addstr(field);
- }
- }
-
- /*
- * Show cell's label string:
- */
-
- if ((*pp) -> label) {
- showstring((*pp) -> label,
- (*pp) -> flags & is_leftflush,
- (*pp) -> flags & is_valid,
- row, col, & nextcol, mxcol,
- & fieldlen, r, c);
- }
- else /* repaint a blank cell: */
- if ((do_stand || !FullUpdate) &&
- ((*pp)->flags & is_changed) &&
- !((*pp)->flags & is_valid) && !(*pp)->label) {
- (void) printw("%*s", fwidth[col], " ");
- }
- } /* else */
-
- if (do_stand) {
- (void) standend();
- do_stand = 0;
- }
- }
- }
- r++;
- }
- }
-
- (void) move(lastmy, lastmx+fwidth[lastcol]);
- if((inch() & A_CHARTEXT ) == '<')
- (void) addstr(under_cursor);
-
- lastmy = RESROW;
- for (row = strow; row < currow; row++)
- if (!row_hidden[row])
- lastmy += 1;
- lastmx = RESCOL;
- for (col = stcol; col < curcol; col++)
- if (!col_hidden[col])
- lastmx += fwidth[col];
- lastcol = curcol;
- if (showcell && (! showneed) && (! showexpr)) {
- (void) move(lastmy, lastmx);
- (void) standout();
- repaint(lastmx, lastmy, fwidth[lastcol]);
- (void) standend();
- }
- (void) move(lastmy, lastmx+fwidth[lastcol]);
- *under_cursor = (inch() & A_CHARTEXT );
- (void) addstr("<");
-
- (void) move(0, 0);
- (void) clrtoeol();
- if (linelim >= 0) {
- (void) addch(mode_ind);
- (void) addstr("> ");
- (void) addstr(line);
- (void) move(0, linelim+3);
- } else {
- if (showtop) { /* show top line */
- register struct ent *p1;
- int printed = 0; /* printed something? */
-
- (void) printw("%s%d ", coltoa(curcol), currow);
-
- if (p1 = *ATBL(tbl, currow, curcol)) {
- if (p1 -> expr) {
- /* has expr of some type */
- linelim = 0;
- editexp(currow, curcol); /* set line to expr */
- linelim = -1;
- }
-
- /*
- * Display string part of cell:
- */
-
- if ((p1 -> expr) && (p1 -> flags & is_strexpr)) {
- (void) addstr((p1 -> flags & is_leftflush) ? "<{" : ">{");
- (void) addstr(line);
- (void) addstr("} "); /* and this '}' is for vi % */
- printed = 1;
-
- } else if (p1 -> label) {
- /* has constant label only */
- (void) addstr ((p1 -> flags & is_leftflush) ? "<\"" : ">\"");
- (void) addstr (p1 -> label);
- (void) addstr ("\" ");
- printed = 1;
- }
-
- /*
- * Display value part of cell:
- */
-
- if (p1 -> flags & is_valid) {
- /* has value or num expr */
- if ((! (p1 -> expr)) || (p1 -> flags & is_strexpr))
- (void) sprintf (line, "%.15g", p1 -> v);
-
- (void) addstr ("[");
- (void) addstr (line);
- (void) addstr ("]");
- printed = 1;
- }
- }
- if (! printed)
- (void) addstr ("[]");
- }
- (void) move (lastmy, lastmx + fwidth[lastcol]);
- }
- if (revmsg[0]) {
- (void) move(0, 0);
- (void) clrtoeol (); /* get rid of topline display */
- (void) printw(revmsg);
- revmsg[0] = '\0'; /* don't show it again */
- (void) move (lastmy, lastmx + fwidth[lastcol]);
- }
- FullUpdate = FALSE;
- }
-
- void
- repaint(x, y, len)
- int x, y, len;
- {
- int c;
-
- while(len-- > 0) {
- (void) move(y,x);
- c = inch() & A_CHARTEXT;
- (void) addch(c);
- x++;
- }
- }
-
- char *progname;
-
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- int inloop = 1;
- register int c;
- int edistate = -1;
- int arg = 1;
- int narg;
- int nedistate;
- int running;
- char *revi;
- int anychanged = FALSE;
-
- /*
- * Keep command line options around until the file is read so the
- * command line overrides file options
- */
-
- int Mopt = 0;
- int Nopt = 0;
- int Copt = 0;
- int Ropt = 0;
-
- int tempx, tempy; /* Temp versions of curx, cury */
-
- if ((revi = strrchr(argv[0], '/')) != NULL)
- progname = revi+1;
- else
- progname = argv[0];
-
- while (argc > 1 && argv[1][0] == '-') {
- argv++;
- argc--;
- switch (argv[0][1]) {
- case 'x':
- #ifdef VMS
- (void) fprintf(stderr, "Crypt not available for VMS\n");
- exit(1);
- #else
- Crypt = 1;
- #endif
- break;
- case 'm':
- Mopt = 1;
- break;
- case 'n':
- Nopt = 1;
- break;
- case 'c':
- Copt = 1;
- break;
- case 'r':
- Ropt = 1;
- break;
- default:
- (void) fprintf(stderr,"%s: unrecognized option: \"%c\"\n",
- progname,argv[0][1]);
- exit(1);
- }
- }
-
- *curfile ='\0';
-
- signals();
- (void) initscr();
-
- /* setup the spreadsheet arrays, initscr() will get the screen size */
- if (!growtbl(GROWNEW, 0, 0))
- { endwin();
- exit(1);
- }
-
- (void) clear();
- #ifdef VMS
- VMS_read_raw = 1;
- #else
- nonl();
- noecho ();
- cbreak();
- #endif
- initkbd();
- scrollok(stdscr, 1);
-
- /*
- * Build revision message for later use:
- */
-
- (void) strcpy (revmsg, progname);
- for (revi = rev; (*revi++) != ':'; ); /* copy after colon */
- (void) strcat (revmsg, revi);
- revmsg [strlen (revmsg) - 2] = 0; /* erase last character */
- (void) strcat (revmsg, ": Type '?' for help.");
-
- if (argc > 1) {
- (void) strcpy(curfile,argv[1]);
- readfile (argv[1], 0);
- }
-
- if (Mopt)
- autocalc = 0;
- if (Nopt)
- numeric = 1;
- if (Copt)
- calc_order = BYCOLS;
- if (Ropt)
- calc_order = BYROWS;
-
- modflg = 0;
- #ifdef VENIX
- setbuf (stdin, NULL);
- #endif
- FullUpdate++;
- while (inloop) { running = 1;
- while (running) {
- nedistate = -1;
- narg = 1;
- if (edistate < 0 && linelim < 0 && autocalc && (changed || FullUpdate))
- { EvalAll ();
- if (changed) /* if EvalAll changed or was before */
- anychanged = TRUE;
- changed = 0;
- }
- else /* any cells change? */
- if (changed)
- anychanged = TRUE;
-
- update(anychanged);
- anychanged = FALSE;
- #ifndef SYSV3
- (void) refresh(); /* 5.3 does a refresh in getch */
- #endif
- c = nmgetch();
- getyx(stdscr, tempy, tempx);
- (void) move (1, 0);
- (void) clrtoeol ();
- (void) move(tempy, tempx);
- (void) fflush (stdout);
- seenerr = 0;
- showneed = 0; /* reset after each update */
- showexpr = 0;
-
- /* if ((c < ' ') || ( c == DEL )) how about international here ? PB */
- if ( iscntrl(c) )
- switch (c) {
- #ifdef SIGTSTP
- case ctl('z'):
- (void) deraw();
- (void) kill(0, SIGTSTP); /* Nail process group */
-
- /* the pc stops here */
-
- (void) goraw();
- break;
- #endif
- case ctl('r'):
- showneed = 1;
- case ctl('l'):
- FullUpdate++;
- (void) clearok(stdscr,1);
- break;
- case ctl('x'):
- FullUpdate++;
- showexpr = 1;
- (void) clearok(stdscr,1);
- break;
- default:
- error ("No such command (^%c)", c + 0100);
- break;
- case ctl('b'):
- backcol(arg);
- break;
- case ctl('c'):
- running = 0;
- break;
-
- case ctl('e'):
-
- switch (nmgetch()) {
- case ctl('p'): case 'k': doend (-1, 0); break;
- case ctl('n'): case 'j': doend ( 1, 0); break;
- case ctl('b'): case 'h':
- case ctl('h'): doend ( 0,-1); break;
- case ctl('f'): case 'l':
- case ctl('i'): case ' ': doend ( 0, 1); break;
-
- case ESC:
- case ctl('g'):
- break;
-
- default:
- error("Invalid ^E command");
- break;
- }
-
- break;
-
- case ctl('f'):
- forwcol(arg);
- break;
-
- case ctl('g'):
- showrange = 0;
- linelim = -1;
- (void) move (1, 0);
- (void) clrtoeol ();
- break;
-
- case ESC: /* ctl('[') */
- write_line(ESC);
- break;
-
- case ctl('d'):
- write_line(ctl('d'));
- break;
-
- case DEL:
- case ctl('h'):
- if (linelim < 0) { /* not editing line */
- backcol(arg); /* treat like ^B */
- break;
- }
- write_line(ctl('h'));
- break;
-
- case ctl('i'): /* tab */
- if (linelim < 0) { /* not editing line */
- forwcol(arg);
- break;
- }
- if (!showrange) {
- startshow();
- } else {
- showdr();
- linelim = strlen(line);
- line[linelim++] = ' ';
- line[linelim] = 0;
- showrange = 0;
- }
- linelim = strlen (line);
- break;
-
- case ctl('m'):
- case ctl('j'):
- write_line(ctl('m'));
- break;
-
- case ctl('n'):
- forwrow(arg);
- break;
-
- case ctl('p'):
- backrow(arg);
- break;
-
- case ctl('q'):
- break; /* ignore flow control */
-
- case ctl('s'):
- break; /* ignore flow control */
-
- case ctl('t'):
- error(
- "Toggle: a:auto c:cell e:ext funcs n:numeric t:top x:encrypt $:pre-scale");
- (void) refresh();
-
- switch (nmgetch()) {
- case 'a': case 'A':
- case 'm': case 'M':
- autocalc ^= 1;
- error("Automatic recalculation %sabled.",
- autocalc ? "en":"dis");
- break;
- case 'n': case 'N':
- numeric = (! numeric);
- error ("Numeric input %sabled.",
- numeric ? "en" : "dis");
- break;
- case 't': case 'T':
- showtop = (! showtop);
- repaint(lastmx, lastmy, fwidth[lastcol]);
- error ("Top line %sabled.", showtop ? "en" : "dis");
- break;
- case 'c': case 'C':
- showcell = (! showcell);
- repaint(lastmx, lastmy, fwidth[lastcol]);
- error ("Cell highlighting %sabled.",
- showcell ? "en" : "dis");
- break;
- case 'x': case 'X':
- Crypt = (! Crypt);
- error ("Encryption %sabled.", Crypt? "en" : "dis");
- break;
- case '$':
- if (prescale == 1.0) {
- error ("Prescale enabled.");
- prescale = 0.01;
- } else {
- prescale = 1.0;
- error ("Prescale disabled.");
- }
- break;
- case 'e': case 'E':
- extfunc = (! extfunc);
- error ("External functions %sabled.",
- extfunc? "en" : "dis");
- break;
- case ESC:
- case ctl('g'):
- --modflg; /* negate the modflg++ */
- break;
- default:
- error ("Invalid toggle command");
- --modflg; /* negate the modflg++ */
- }
- FullUpdate++;
- modflg++;
- break;
-
- case ctl('u'):
- narg = arg * 4;
- nedistate = 1;
- break;
-
- case ctl('v'): /* insert variable name */
- if (linelim > 0)
- ins_string(v_name(currow, curcol));
- break;
-
- case ctl('w'): /* insert variable expression */
- if (linelim > 0) {
- char *temp, *temp1;
- int templim;
-
- temp = strcpy(xmalloc((unsigned)(strlen(line)+1)),line);
- templim = linelim;
- editexp(currow,curcol);
- temp1= strcpy(xmalloc((unsigned)(strlen(line)+1)),line);
- strcpy(line, temp);
- linelim = templim;
- ins_string(temp1);
- xfree(temp);
- xfree(temp1);
- }
- break;
-
- case ctl('a'): /* insert variable value */
- if (linelim > 0) {
- struct ent *p = *ATBL(tbl, currow, curcol);
- char temp[100];
-
- if (p && p -> flags & is_valid) {
- (void) sprintf (temp, "%.*f",
- precision[curcol],p -> v);
- ins_string(temp);
- }
- }
- break;
-
- } /* End of the control char switch stmt */
- else if (isdigit(c) && ((numeric && edistate >= 0) ||
- (!numeric && (linelim < 0 || edistate >= 0)))) {
- /* we got a leading number */
- if (edistate != 0) {
- /* First char of the count */
- if (c == '0') /* just a '0' goes to left col */
- curcol = 0;
- else {
- nedistate = 0;
- narg = c - '0';
- }
- } else {
- /* Succeeding count chars */
- nedistate = 0;
- narg = arg * 10 + (c - '0');
- }
- } else if (linelim >= 0) {
- /* Editing line */
- switch(c) {
- case ')':
- if (showrange) {
- showdr();
- showrange = 0;
- linelim = strlen (line);
- }
- break;
- default:
- break;
- }
- write_line(c);
-
- } else if (!numeric && ( c == '+' || c == '-' ) ) {
- /* increment/decrement ops */
- register struct ent *p = *ATBL(tbl, currow, curcol);
- if (!p)
- continue;
- if (p->expr && !(p->flags & is_strexpr)) {
- error("Can't increment/decrement a formula\n");
- continue;
- }
- FullUpdate++;
- modflg++;
- if( c == '+' )
- p -> v += (double) arg;
- else
- p -> v -= (double) arg;
- } else
- /* switch on a normal command character */
- switch (c) {
- case ':':
- break; /* Be nice to vi users */
-
- case '@':
- EvalAll ();
- changed = 0;
- anychanged = TRUE;
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case '-': case '.': case '+':
- (void) sprintf(line,"let %s = %c",
- v_name(currow, curcol), c);
- linelim = strlen (line);
- insert_mode();
- break;
-
- case '=':
- (void) sprintf(line,"let %s = ",
- v_name(currow, curcol));
- linelim = strlen (line);
- insert_mode();
- break;
-
- case '!':
- {
- /*
- * "! command" executes command
- * "!" forks a shell
- * "!!" repeats last command
- */
- #ifdef VMS
- error("Not implemented on VMS");
- #else /* VMS */
- char *shl;
- int pid, temp;
- char cmd[MAXCMD];
- static char lastcmd[MAXCMD];
-
- if (!(shl = getenv("SHELL")))
- shl = "/bin/sh";
-
- deraw();
- (void) fputs("! ", stdout);
- (void) fflush(stdout);
- (void) fgets(cmd, MAXCMD, stdin);
- cmd[strlen(cmd) - 1] = '\0'; /* clobber \n */
- if(strcmp(cmd,"!") == 0) /* repeat? */
- (void) strcpy(cmd, lastcmd);
- else
- (void) strcpy(lastcmd, cmd);
-
- if (modflg)
- {
- (void) puts ("[No write since last change]");
- (void) fflush (stdout);
- }
-
- if (!(pid = fork()))
- {
- (void) signal (SIGINT, SIG_DFL); /* reset */
- if(strlen(cmd))
- (void)execl(shl,shl,"-c",cmd,(char *)0);
- else
- (void) execl(shl, shl, (char *)0);
- exit(-127);
- }
-
- while (pid != wait(&temp));
-
- (void) printf("Press RETURN to continue ");
- (void)nmgetch();
- goraw();
- #endif /* VMS */
- break;
- }
-
- /*
- * Range commands:
- */
-
- case '/':
- error (
- "Range: x:erase v:value c:copy f:fill d:define s:show u:undefine");
- (void) refresh();
-
- switch (nmgetch()) {
- case 'c':
- (void) sprintf(line,"copy [dest_range src_range] ");
- linelim = strlen(line);
- startshow();
- insert_mode();
- break;
- case 'x':
- (void) sprintf(line,"erase [range] ");
- linelim = strlen(line);
- startshow();
- insert_mode();
- break;
- case 'v':
- (void) sprintf(line, "value [range] ");
- linelim = strlen(line);
- startshow();
- insert_mode();
- break;
- case 'f':
- (void) sprintf(line,"fill [range start inc] ");
- linelim = strlen(line);
- startshow();
- insert_mode();
- break;
- case 'd':
- (void) sprintf(line,"define [string range] \"");
- linelim = strlen(line);
- startshow();
- insert_mode();
- modflg++;
- break;
- case 'u':
- (void) sprintf(line,"undefine [range] ");
- linelim = strlen(line);
- insert_mode();
- modflg++;
- break;
- case 's':
- if(are_ranges())
- {
- FILE *f;
- int pid;
- char px[MAXCMD] ;
- char *pager;
-
- (void) strcpy(px, "| sort | ");
- if(!(pager = getenv("PAGER")))
- pager = DFLT_PAGER;
- (void) strcat(px,pager);
- f = openout(px, &pid);
- if (!f) {
- error("Can't open pipe to sort");
- break;
- }
- list_range(f);
- closeout(f, pid);
- }
- else error("No ranges defined");
- break;
-
- case ESC:
- case ctl('g'):
- break;
- default:
- error("Invalid region command");
- break;
- }
- break;
-
- /*
- * Row/column commands:
- */
-
- case 'i':
- case 'a':
- case 'd':
- case 'p':
- case 'v':
- case 'z':
- case 's':
- {
- register rcqual;
-
- if (! (rcqual = get_rcqual (c))) {
- error ("Invalid row/column command");
- break;
- }
-
- error (""); /* clear line */
-
- if ( rcqual == ESC || rcqual == ctl('g'))
- break;
-
- switch (c) {
-
- case 'i':
- if (rcqual == 'r') insertrow(arg);
- else opencol(curcol, arg);
- break;
-
- case 'a':
- if (rcqual == 'r') while (arg--) duprow();
- else while (arg--) dupcol();
- break;
-
- case 'd':
- if (rcqual == 'r') deleterow(arg);
- else closecol(curcol, arg);
- break;
-
- case 'p':
- while (arg--) pullcells(rcqual);
- break;
-
- case 'v':
- if (rcqual == 'r') rowvalueize(arg);
- else colvalueize(arg);
- modflg = 1;
- break;
-
- case 'z':
- if (rcqual == 'r') hiderow(arg);
- else hidecol(arg);
- break;
-
- case 's':
- /* special case; no repeat count */
-
- if (rcqual == 'r') rowshow_op();
- else colshow_op();
- break;
- }
- break;
- }
-
- case '$':
- {
- register struct ent *p;
-
- curcol = maxcols - 1;
- while (!VALID_CELL(p, currow, curcol) && curcol > 0)
- curcol--;
- break;
- }
- case '#':
- {
- register struct ent *p;
-
- currow = maxrows - 1;
- while (!VALID_CELL(p, currow, curcol) && currow > 0)
- currow--;
- break;
- }
- case 'w':
- {
- register struct ent *p;
-
- while (--arg>=0) {
- do {
- if (curcol < maxcols - 1)
- curcol++;
- else {
- if (currow < maxrows - 1) {
- while(++currow < maxrows - 1 &&
- row_hidden[currow]) /* */;
- curcol = 0;
- } else {
- error("At end of table");
- break;
- }
- }
- } while(col_hidden[curcol] ||
- !VALID_CELL(p, currow, curcol));
- }
- break;
- }
- case 'b':
- {
- register struct ent *p;
-
- while (--arg>=0) {
- do {
- if (curcol)
- curcol--;
- else {
- if (currow) {
- while(--currow &&
- row_hidden[currow]) /* */;
- curcol = maxcols - 1;
- } else {
- error ("At start of table");
- break;
- }
- }
- } while(col_hidden[curcol] ||
- !VALID_CELL(p, currow, curcol));
- }
- break;
- }
- case '^':
- currow = 0;
- break;
- case '?':
- help();
- break;
- case '"':
- (void) sprintf (line, "label %s = \"",
- v_name(currow, curcol));
- linelim = strlen (line);
- insert_mode();
- break;
- case '<':
- (void) sprintf (line, "leftstring %s = \"",
- v_name(currow, curcol));
- linelim = strlen (line);
- insert_mode();
- break;
- case '>':
- (void) sprintf (line, "rightstring %s = \"",
- v_name(currow, curcol));
- linelim = strlen (line);
- insert_mode();
- break;
- case 'e':
- editv (currow, curcol);
- edit_mode();
- break;
- case 'E':
- edits (currow, curcol);
- edit_mode();
- break;
- case 'f':
- if (arg == 1)
- (void) sprintf (line, "format [for column] %s ",
- coltoa(curcol));
- else {
- (void) sprintf(line, "format [for columns] %s:",
- coltoa(curcol));
- (void) sprintf(line+strlen(line), "%s ",
- coltoa(curcol+arg-1));
- }
- error("Current format is %d %d",
- fwidth[curcol],precision[curcol]);
- linelim = strlen (line);
- insert_mode();
- break;
- case 'g':
- (void) sprintf (line, "goto [v] ");
- linelim = strlen (line);
- insert_mode();
- break;
- case 'P':
- (void) sprintf (line, "put [\"dest\" range] \"");
- if (*curfile)
- error ("Default path is \"%s\"",curfile);
- linelim = strlen (line);
- insert_mode();
- break;
- case 'M':
- (void) sprintf (line, "merge [\"source\"] \"");
- linelim = strlen (line);
- insert_mode();
- break;
- case 'R':
- if (mdir)
- (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir);
- else
- (void) sprintf (line,"merge [\"macro_file\"] \"");
- linelim = strlen (line);
- insert_mode();
- break;
- case 'D':
- (void) sprintf (line, "mdir [\"macro_directory\"] \"");
- linelim = strlen (line);
- insert_mode();
- break;
- case 'G':
- (void) sprintf (line, "get [\"source\"] \"");
- if (*curfile)
- error ("Default file is \"%s\"",curfile);
- linelim = strlen (line);
- insert_mode();
- break;
- case 'W':
- (void) sprintf (line, "write [\"dest\" range] \"");
- linelim = strlen (line);
- insert_mode();
- break;
- case 'S': /* set options */
- (void) sprintf (line, "set ");
- error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)");
- linelim = strlen (line);
- insert_mode();
- break;
- case 'T': /* tbl output */
- (void) sprintf (line, "tbl [\"dest\" range] \"");
- linelim = strlen (line);
- insert_mode();
- break;
- case 'x':
- {
- register struct ent **pp;
- register int c1;
-
- flush_saved();
- if(calc_order == BYROWS) {
- for (c1 = curcol; arg-- && c1 < maxcols; c1++) {
- pp = ATBL(tbl, currow, c1);
- if (*pp) {
- free_ent(*pp);
- *pp = (struct ent *)0;
- }
- }
- }
- else {
- for (c1 = currow; arg-- && c1 < maxrows; c1++) {
- pp = ATBL(tbl, c1, curcol);
- if (*pp) {
- free_ent(*pp);
- *pp = (struct ent *)0;
- }
- }
- }
- sync_refs();
- modflg++;
- FullUpdate++;
- }
- break;
- case 'Q':
- case 'q':
- running = 0;
- break;
- case 'h':
- backcol(arg);
- break;
- case 'j':
- forwrow(arg);
- break;
- case 'k':
- backrow(arg);
- break;
- case ' ':
- case 'l':
- forwcol(arg);
- break;
- case 'm':
- savedrow = currow;
- savedcol = curcol;
- break;
- case 'c': {
- register struct ent *p = *ATBL(tbl, savedrow, savedcol);
- register c1;
- register struct ent *n;
- if (!p)
- break;
- FullUpdate++;
- modflg++;
- for (c1 = curcol; arg-- && c1 < maxcols; c1++) {
- n = lookat (currow, c1);
- (void) clearent(n);
- copyent( n, p, currow - savedrow, c1 - savedcol);
- }
- break;
- }
- default:
- if ((toascii(c)) != c)
- error ("Weird character, decimal %d\n",
- (int) c);
- else
- error ("No such command (%c)", c);
- break;
- }
- edistate = nedistate;
- arg = narg;
- } /* while (running) */
- inloop = modcheck(" before exiting");
- } /* while (inloop) */
- deraw();
- endwin();
- #ifdef VMS /* Unit VMS "fixes" exit we should say 1 here */
- exit(1);
- #else
- exit(0);
- #endif
- /*NOTREACHED*/
- }
-
- void
- startshow()
- {
- showrange = 1;
- showsr = currow;
- showsc = curcol;
- }
-
- void
- showdr()
- {
- int minsr, minsc, maxsr, maxsc;
-
- minsr = showsr < currow ? showsr : currow;
- minsc = showsc < curcol ? showsc : curcol;
- maxsr = showsr > currow ? showsr : currow;
- maxsc = showsc > curcol ? showsc : curcol;
- (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
- }
-
- void
- setorder(i)
- int i;
- {
- if((i == BYROWS)||(i == BYCOLS))
- calc_order = i;
- else
- error("Not yet implemented");
- }
-
- void
- setauto(i)
- int i;
- {
- autocalc = i;
- }
-
-
- #ifdef VMS
-
- goraw()
- {
- VMS_read_raw = 1;
- FullUpdate++;
- }
-
- deraw()
- {
- (void) move (LINES - 1, 0);
- (void) clrtoeol();
- (void) refresh();
- VMS_read_raw = 0;
- }
-
- #else /* VMS */
- void
- goraw()
- {
- #if SYSV2 || SYSV3
- fixterm();
- #else /* SYSV2 || SYSV3 */
- cbreak();
- nonl();
- noecho ();
- #endif /* SYSV2 || SYSV3 */
- kbd_again();
- (void) clear();
- FullUpdate++;
- }
-
- void
- deraw()
- {
- (void) move (LINES - 1, 0);
- (void) clrtoeol();
- (void) refresh();
- #if SYSV2 || SYSV3
- resetterm();
- #else
- nocbreak();
- nl();
- echo();
- #endif
- resetkbd();
- }
-
- #endif /* VMS */
-
- void
- signals()
- {
- #ifdef SIGVOID
- void quit();
- void time_out();
- void dump_me();
- #else
- int quit();
- int time_out();
- int dump_me();
- #endif
-
- (void) signal(SIGINT, SIG_IGN);
- (void) signal(SIGQUIT, dump_me);
- (void) signal(SIGPIPE, quit);
- (void) signal(SIGTERM, quit);
- (void) signal(SIGALRM, time_out);
- (void) signal(SIGFPE, quit);
- (void) signal(SIGBUS, quit);
- }
-
- #ifdef SIGVOID
- void
- #endif
- quit()
- {
- diesave();
- deraw();
- resetkbd();
- endwin();
- exit(1);
- }
-
- #ifdef SIGVOID
- void
- #endif
- dump_me()
- {
- diesave();
- deraw();
- abort();
- }
-
- /* try to save the current spreadsheet if we can */
- diesave()
- { char path[PATHLEN];
- if (modcheck(" before Spreadsheet dies") == 1)
- { sprintf(path, "~/SC.SAVE");
- if (writefile(path, 0, 0, maxrow, maxcol) < 0)
- if (writefile("/tmp/SC.SAVE", 0, 0, maxrow, maxcol) < 0)
- error("Couldn't save current spreadsheet, Sorry");
- }
- }
-
- int
- modcheck(endstr)
- char *endstr;
- {
- if (modflg && curfile[0]) {
- int yn_ans;
- char lin[100];
-
- (void) sprintf (lin,"File \"%s\" is modified, save%s? ",curfile,endstr);
- if ((yn_ans = yn_ask(lin)) < 0)
- return(1);
- else
- if (yn_ans == 1)
- { if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
- return (1);
- }
- } else if (modflg) {
- int yn_ans;
-
- if ((yn_ans = yn_ask("Do you want a chance to save the data? ")) < 0)
- return(1);
- else
- return(yn_ans);
- }
- return(0);
- }
-