/* 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 sequent!sawmill!buhrt (Jeff Buhrt) * $Revision: 1.1.1.1 $ * */ #include #include #include #include #ifdef BSD42 #include #else #ifndef SYSIII #include #endif #endif #include #include "sc.h" extern char *getenv(); extern void startdisp(), stopdisp(); #ifdef SYSV3 void exit(); #endif #ifndef SAVENAME #define SAVENAME "SC.SAVE" /* file name to use for emergency saves */ #endif /* SAVENAME */ #ifndef DFLT_PAGER #define DFLT_PAGER "more" /* more is probably more widespread than less */ #endif /* DFLT_PAGER */ #define MAXCMD 160 /* for ! command below */ /* Globals defined in sc.h */ struct ent ***tbl; int strow = 0, stcol = 0; int currow = 0, curcol = 0; int savedrow, savedcol; int FullUpdate = 0; int ClearScreen = 0; /* don't try to be smart */ int maxrow, maxcol; int maxrows, maxcols; int *fwidth; int *precision; int *realfmt; 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 */ #ifdef RIGHT_CBUG int wasforw = FALSE; #endif void update(); void repaint(); 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 autolabel = 1; /* If room, causes label to be created after a define*/ int calc_order = BYROWS; int tbl_style = 0; /* headers for T command output */ int rndinfinity = 0; int numeric_field = 0; /* Started the line editing with a number */ int craction = 0; /* 1 for down, 2 for right */ int rowlimit = -1; int collimit = -1; #ifdef SIGWINCH int hitwinch = 0; /* got a SIGWINCH? */ #endif extern int lastmx, lastmy; /* Screen address of the cursor */ extern int lastcol, lcols; /* Spreadsheet Column the cursor was in last */ /* a linked list of free [struct ent]'s, uses .next as the pointer */ struct ent *freeents = NULL; extern int seenerr; extern char *rev; #ifdef VMS int VMS_read_raw = 0; #endif /* return a pointer to a cell's [struct ent *], creating if needed */ 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) { if (freeents != NULL) { *pp = freeents; freeents = freeents->next; } else *pp = (struct ent *) scxmalloc((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)->format = (char *)0; (*pp)->cellerror = CELLOK; (*pp)->next = NULL; } 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; p->flags &= ~is_locked; } /* free deleted cells */ void flush_saved() { register struct ent *p; register struct ent *q; if (!(p = to_fix)) return; while (p) { (void) clearent(p); q = p->next; p->next = freeents; /* put this ent on the front of freeents */ freeents = p; p = q; } to_fix = NULL; } 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 defined(MSDOS) if ((revi = strrchr(argv[0], '\\')) != NULL) #else #ifdef VMS if ((revi = strrchr(argv[0], ']')) != NULL) #else if ((revi = strrchr(argv[0], '/')) != NULL) #endif #endif progname = revi+1; else progname = argv[0]; while (argc > 1 && argv[1][0] == '-') { argv++; argc--; switch (argv[0][1]) { case 'x': #if defined(VMS) || defined(MSDOS) || !defined(CRYPT_PATH) (void) fprintf(stderr, "Crypt not available\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; case 'C': craction = CRCOLS; break; case 'R': craction = CRROWS; break; default: (void) fprintf(stderr,"%s: unrecognized option: \"%c\"\n", progname,argv[0][1]); exit(1); } } *curfile ='\0'; startdisp(); signals(); /* setup the spreadsheet arrays, initscr() will get the screen size */ if (!growtbl(GROWNEW, 0, 0)) { stopdisp(); exit(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; #ifdef SIGWINCH /* got a SIGWINCH? */ if (hitwinch) { hitwinch = 0; stopdisp(); startdisp(); FullUpdate++; } #endif update(anychanged); anychanged = FALSE; #ifndef SYSV3 /* HP/Ux 3.1 this may not be wanted */ (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; /* * there seems to be some question about what to do w/ the iscntrl * some BSD systems are reportedly broken as well */ /* if ((c < ' ') || ( c == DEL )) how about international here ? PB */ #if pyr if ( iscntrl(c) || (c >= 011 && c <= 015) ) /* iscntrl broken in OSx4.1 */ #else if (isascii(c) && (iscntrl(c) || (c == 020)) ) /* iscntrl broken in OSx4.1 */ #endif 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++; ClearScreen++; (void) clearok(stdscr,1); /* Centering the display with cursor for middle */ if(currow > (LINES-RESROW)/2) strow = currow - ((LINES-RESROW)/2); break; case ctl('x'): FullUpdate++; showexpr = 1; (void) clearok(stdscr,1); break; default: error ("No such command (^%c)", c + 0100); break; case ctl('b'): if (numeric_field) { write_line(ctl('m')); numeric_field = 0; } 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'): if (numeric_field) { write_line(ctl('m')); numeric_field = 0; } forwcol(arg); #ifdef RIGHT_CBUG wasforw++; #endif 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'): numeric_field = 0; write_line(ctl('m')); switch(craction) { case CRROWS: if ((rowlimit >= 0) && (currow >= rowlimit)) { forwcol(1); currow = 0; } else { forwrow(1); } break; case CRCOLS: if ((collimit >= 0) && (curcol >= collimit)) { forwrow(1); curcol = 0; } else { forwcol(1); } break; default: break; } break; case ctl('n'): if (numeric_field) { write_line(ctl('m')); numeric_field = 0; } forwrow(arg); break; case ctl('p'): if (numeric_field) { write_line(ctl('m')); numeric_field = 0; } backrow(arg); break; case ctl('q'): break; /* ignore flow control */ case ctl('s'): break; /* ignore flow control */ case ctl('t'): #if !defined(VMS) && !defined(MSDOS) && defined(CRYPT_PATH) error( "Toggle: a:auto,c:cell,e:ext funcs,n:numeric,t:top,x:encrypt,$:pre-scale,"); #else /* no encryption available */ error( "Toggle: a:auto,c:cell,e:ext funcs,n:numeric,t:top,$:pre-scale,"); #endif (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); 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': #if defined(VMS) || defined(MSDOS) || !defined(CRYPT_PATH) error ("Encryption not available."); #else Crypt = (! Crypt); error ("Encryption %sabled.", Crypt? "en" : "dis"); #endif break; case 'l': case 'L': autolabel = (! autolabel); error ("Autolabel %sabled.", autolabel? "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; case 'r': case 'R': ++craction; if(craction >= 3) craction = 0; switch(craction) { default: craction = 0; /* fall through */ case 0: error("No action after new line"); break; case CRROWS: error("Down row after new line"); break; case CRCOLS: error("Right column after new line"); break; } break; case 'z': case 'Z': rowlimit = currow; collimit = curcol; error("Row and column limits set"); 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) { static char *temp = NULL, *temp1 = NULL; static unsigned templen = 0; int templim; /* scxrealloc will scxmalloc if needed */ if (strlen(line)+1 > templen) { templen = strlen(line)+40; temp = scxrealloc(temp, templen); temp1= scxrealloc(temp1, templen); } strcpy(temp, line); templim = linelim; linelim = 0; /* reset line to empty */ editexp(currow,curcol); strcpy(temp1, line); strcpy(line, temp); linelim = templim; ins_string(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 (isascii(c) && 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 '+': if (locked_cell(currow, curcol)) break; numeric_field = 1; (void) sprintf(line,"let %s = %c", v_name(currow, curcol), c); linelim = strlen (line); insert_mode(); break; case '=': if (locked_cell(currow, curcol)) break; (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 */ #if VMS || MSDOS error("Not implemented on VMS or MS-DOS"); #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 "); fflush(stdout); (void)nmgetch(); goraw(); #endif /* VMS */ break; } /* * Range commands: */ case '/': error ( "Range: x:erase v:value c:copy f:fill d:def l:lock U:unlock s:show u:undef F:fmt"); (void) refresh(); switch (nmgetch()) { case 'l': (void) sprintf(line,"lock [range] "); linelim = strlen(line); startshow(); insert_mode(); break; case 'U': (void) sprintf(line,"unlock [range] "); linelim = strlen(line); startshow(); insert_mode(); break; 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 'F': (void) sprintf(line, "fmt [range \"format\"] "); linelim = strlen(line); startshow(); insert_mode(); 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; /* * turn an area starting at currow/curcol into * constants vs expressions - not reversable */ case 'v': if (rcqual == 'r') valueize_area(currow, 0, currow + arg - 1, maxcol); else valueize_area(0, curcol, maxrow, curcol + arg - 1); 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 '"': if (!locked_cell(currow, curcol)) { (void) sprintf (line, "label %s = \"", v_name(currow, curcol)); linelim = strlen (line); insert_mode(); } break; case '<': if (!locked_cell(currow, curcol)) { (void) sprintf (line, "leftstring %s = \"", v_name(currow, curcol)); linelim = strlen (line); insert_mode(); } break; case '>': if (!locked_cell(currow, curcol)) { (void) sprintf (line, "rightstring %s = \"", v_name(currow, curcol)); linelim = strlen (line); insert_mode(); } break; case 'e': if (!locked_cell(currow, curcol)) { editv (currow, curcol); edit_mode(); } break; case 'E': if (!locked_cell(currow, curcol)) { 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 %d", fwidth[curcol],precision[curcol],realfmt[curcol]); linelim = strlen (line); insert_mode(); break; case 'F': { register struct ent *p = *ATBL(tbl, currow, curcol); if (p && p->format) { (void) sprintf(line, "fmt [format] %s \"%s", v_name(currow, curcol), p->format); edit_mode(); } else { (void) sprintf(line, "fmt [format] %s \"", v_name(currow, curcol)); insert_mode(); } linelim = strlen(line); 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] \""); if (*curfile) error ("Default file is \"%s.asc\"",curfile); linelim = strlen (line); insert_mode(); break; case 'S': /* set options */ (void) sprintf (line, "set "); error("Options:byrows,bycols,iterations=n,tblstyle=(0|tbl|latex|slatex|tex|frame),"); linelim = strlen (line); insert_mode(); break; case 'T': /* tbl output */ (void) sprintf (line, "tbl [\"dest\" range] \""); if (*curfile && tbl_style == 0) error ("Default file is \"%s.cln\"",curfile); else if (*curfile && tbl_style == TBL) error ("Default file is \"%s.tbl\"",curfile); else if (*curfile && tbl_style == LATEX) error ("Default file is \"%s.lat\"",curfile); else if (*curfile && tbl_style == SLATEX) error ("Default file is \"%s.stx\"",curfile); else if (*curfile && tbl_style == TEX) error ("Default file is \"%s.tex\"",curfile); 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) && !locked_cell(currow, curcol)) { if (*pp) { free_ent(*pp); *pp = (struct ent *)0; } } } } else { for (c1 = currow; arg-- && c1 < maxrows; c1++) { pp = ATBL(tbl, c1, curcol); if ((*pp) && !locked_cell(currow, 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 'H': backcol((curcol-stcol+1)+1); break; #ifdef KEY_NPAGE case KEY_NPAGE: /* page precedente */ #endif case 'J': forwrow(LINES-RESROW-(currow-strow)+1); break; #ifdef KEY_PPAGE case KEY_PPAGE: /* page suivante */ #endif case 'K': backrow((currow-strow+1)+3); break; #ifdef KEY_HOME case KEY_HOME: currow = 0; curcol = 0; FullUpdate++; break; #endif case 'L': forwcol(lcols -(curcol-stcol)+1); 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) */ stopdisp(); #ifdef VMS /* Until VMS "fixes" exit we should say 1 here */ exit(1); #else exit(0); #endif /*NOTREACHED*/ } /* show the current range (see ^I), we are moving around to define a range */ void startshow() { showrange = 1; showsr = currow; showsc = curcol; } /* insert the range we defined by moving around the screen, see startshow() */ 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)); } /* set the calculation order */ void setorder(i) int i; { if((i == BYROWS)||(i == BYCOLS)) calc_order = i; } void setauto(i) int i; { autocalc = i; } void signals() { #ifdef SIGVOID void doquit(); void time_out(); void dump_me(); #ifdef SIGWINCH void winchg(); #endif #else int doquit(); int time_out(); int dump_me(); #ifdef SIGWINCH int winchg(); #endif #endif (void) signal(SIGINT, SIG_IGN); #if !defined(MSDOS) (void) signal(SIGQUIT, dump_me); (void) signal(SIGPIPE, doquit); (void) signal(SIGALRM, time_out); (void) signal(SIGBUS, doquit); #endif (void) signal(SIGTERM, doquit); (void) signal(SIGFPE, doquit); #ifdef SIGWINCH (void) signal(SIGWINCH, winchg); #endif } #ifdef SIGWINCH #ifdef SIGVOID void #else int #endif winchg() { hitwinch++; (void) signal(SIGWINCH, winchg); } #endif #ifdef SIGVOID void #else int #endif doquit() { diesave(); stopdisp(); exit(1); } #ifdef SIGVOID void #else int #endif dump_me() { diesave(); deraw(); abort(); } /* try to save the current spreadsheet if we can */ void diesave() { char path[PATHLEN]; if (modcheck(" before Spreadsheet dies") == 1) { (void) sprintf(path, "~/%s", SAVENAME); if (writefile(path, 0, 0, maxrow, maxcol) < 0) { (void) sprintf(path, "/tmp/%s", SAVENAME); if (writefile(path, 0, 0, maxrow, maxcol) < 0) error("Couldn't save current spreadsheet, Sorry"); } } } /* check if tbl was modified and ask to save */ 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); } /* Returns 1 if cell is locked, 0 otherwise */ int locked_cell (r, c) int r, c; { struct ent *p = *ATBL(tbl, r, c); if (p && (p->flags & is_locked)) { error("Cell %s%d is locked", coltoa(c), r) ; return(1); } return(0); } /* Check if area contains locked cells */ int any_locked_cells(r1, c1, r2, c2) int r1, c1, r2, c2 ; { int r, c; struct ent *p ; for (r=r1; r<=r2; r++) for (c=c1; c<=c2; c++) { p = *ATBL(tbl, r, c); if (p && (p->flags & is_locked)) return(1); } return(0); }