home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dr. CD ROM (Annual Premium Edition)
/
premium.zip
/
premium
/
IBMOS2_1
/
SC621.ZIP
/
sc621
/
sc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-11
|
33KB
|
1,455 lines
/* 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: 6.21 $
*
*/
#include <sys/types.h>
#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"
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) || defined(__OS2__)
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(__OS2__) || !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(__OS2__) && defined(CRYPT_PATH)
error(
"Toggle: a:auto,c:cell,e:ext funcs,n:numeric,t:top,x:encrypt,$:pre-scale,<MORE>");
#else /* no encryption available */
error(
"Toggle: a:auto,c:cell,e:ext funcs,n:numeric,t:top,$:pre-scale,<MORE>");
#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(__OS2__) || !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 defined(VMS) || defined(MSDOS) || defined(__OS2__)
error("Not implemented");
#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),<MORE>");
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) && !defined(__OS2__)
(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);
}