📄 sc.c
字号:
/* 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 BSD42#include <strings.h>#else#ifndef SYSIII#include <string.h>#endif#endif#include <stdio.h>#include "sc.h"char *getenv();#ifdef SYSV3void 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 VMSint VMS_read_raw = 0;#endifint seenerr;voidyyerror(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. */voidfree_ent(p)register struct ent *p;{ p->next = to_fix; to_fix = p; p->flags |= is_deleted;}voidflush_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;voidupdate (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;}voidrepaint(x, y, len)int x, y, len;{ int c; while(len-- > 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -