home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: Science
/
Science.zip
/
OS2SCALC.ZIP
/
SC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-20
|
23KB
|
1,063 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
* Major mods to run on VMS and AMIGA, 1/17/87
* OS/2 Modifications by Brady Flowers, 7/19/90
*
*/
#include "sc.h"
#ifdef OS2
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <process.h>
#include "curs.h"
#else
extern char *malloc();
#endif
/* default column width */
#define DEFWIDTH 10
#define DEFPREC 2
#define RESCOL 4 /* columns reserved for row numbers */
#define RESROW 3 /* rows reserved for prompt, error, and column numbers */
char curfile[1024];
int showme = 1; /* 1 to display the current cell in the top line */
int batch = 0;
#ifdef OS2
VOID error(char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (batch)
vfprintf(stderr, fmt, args);
else
{
move (1,0);
clrtoeol ();
vprintw(fmt, args);
}
}
static int shell(void);
static int shell()
{
char *comspec;
if (comspec = getenv("COMSPEC"))
{
if (spawnl(P_WAIT, comspec, comspec, "/k (cls & echo Type EXIT to return to spreadsheet)", NULL) == -1)
error("Error executing command processor");
else
return 0;
}
else
error("Cannot locate command processor");
return -1;
}
#else
VOID error(fmt,a,b,c,d,e)
{
if (batch)
fprintf(stderr,fmt,a,b,c,d,e);
else
{
move (1,0);
clrtoeol ();
printw (fmt,a,b,c,d,e);
}
}
#endif
int seenerr;
VOID yyerror (err)
char *err;
{
if (seenerr) return;
seenerr++;
move (1,0);
clrtoeol ();
printw ("%s: %.*s <= %s",err,linelim,line,line+linelim);
}
struct ent *lookat(row,col)
{
register struct ent **p;
if (row < 0)
row = 0;
else if (row > MAXROWS-1)
row = MAXROWS-1;
if (col < 0)
col = 0;
else if (col > MAXCOLS-1)
col = MAXCOLS-1;
p = &tbl[row][col];
if (*p==0)
{
*p = (struct ent *) malloc (sizeof (struct ent));
if (row>maxrow) maxrow = row;
if (col>maxcol) maxcol = col;
(*p)->label = 0;
(*p)->flags = 0;
(*p)->row = row;
(*p)->col = col;
(*p)->expr = 0;
(*p)->v = (double) 0.0;
}
else if ((*p)->flags & is_deleted)
debug("But %s%d has been deleted!", coltoa(col), row);
return *p;
}
/*
* 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)
{
clearent(p);
q = p->next;
free(p);
p = q;
}
to_fix = 0;
}
VOID update()
{
register row,
col;
register struct ent **p;
static lastmx,
lastmy;
static char *under_cursor = " ";
int maxcol;
int maxrow;
int rows;
int cols;
register r;
while (hidden_row[currow]) /* You can't hide the last row or col */
currow++;
while (hidden_col[curcol])
curcol++;
if (curcol < stcol)
stcol = curcol, FullUpdate++;
if (currow < strow)
strow = currow, FullUpdate++;
while (1)
{
register i;
for (i = stcol, cols = 0, col = RESCOL;
(col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++)
{
cols++;
if (hidden_col[i])
continue;
col += fwidth[i];
}
if (curcol >= stcol + cols)
stcol++, FullUpdate++;
else
break;
}
while (1)
{
register i;
for (i = strow, rows = 0, row = RESROW;
row < ROWS && i < MAXROWS; i++)
{
rows++;
if (hidden_row[i])
continue;
row++;
}
if (currow >= strow + rows)
strow++, FullUpdate++;
else
break;
}
maxcol = stcol + cols - 1;
maxrow = strow + rows - 1;
if (FullUpdate)
{
register int i;
move (2, 0);
clrtobot ();
standout();
for (row=RESROW, i=strow; i <= maxrow; i++)
{
if (hidden_row[i])
continue;
move(row,0);
printw("%-*d", RESCOL, i);
row++;
}
move (2,0);
printw("%*s", RESCOL, " ");
for (col=RESCOL, i = stcol; i <= maxcol; i++)
{
if (hidden_col[i])
continue;
move(2, col);
printw("%*s", fwidth[i], coltoa(i));
col += fwidth[i];
}
standend();
}
for (row = strow, r = RESROW; row <= maxrow; row++)
{
register c = RESCOL;
if (hidden_row[row])
continue;
for (p = &tbl[row][col = stcol]; col <= maxcol; col++, p++)
{
if (hidden_col[col])
continue;
if (*p && ((*p) -> flags & is_changed || FullUpdate))
{
char *s;
move (r, c);
(*p) -> flags &= ~is_changed;
if ((*p) -> flags & is_valid)
printw ("%*.*f", fwidth[col], precision[col], (*p) -> v);
if (s = (*p) -> label)
{
char field[1024];
strncpy(field,s,fwidth[col]);
field[fwidth[col]] = 0;
move (r,(*p) -> flags & is_leftflush
? c : c - strlen (field) + fwidth[col]);
addstr(field);
}
}
c += fwidth[col];
}
r++;
}
move(lastmy, lastmx);
if (inch() == '<')
addstr (under_cursor);
lastmy = RESROW;
for (row = strow; row < currow; row++)
if (!hidden_row[row])
lastmy += 1;
lastmx = RESCOL;
for (col = stcol; col <= curcol; col++)
if (!hidden_col[col])
lastmx += fwidth[col];
move(lastmy, lastmx);
*under_cursor = inch();
addstr ("<");
move (0, 0);
clrtoeol ();
if (linelim >= 0)
{
addstr (">> ");
addstr (line);
}
else
{
if (showme)
{
register struct ent *p;
p = tbl[currow][curcol];
if (p && ((p->flags & is_valid) || p->label))
{
if (p->expr || !p->label)
{
linelim = 0;
editexp(currow, curcol);
}
else
{
sprintf(line, "%s", p->label);
}
addstr("[");
addstr (line);
addstr("]");
linelim = -1;
}
else
{
addstr("[]");
}
}
move (lastmy, lastmx);
}
FullUpdate = 0;
}
void quit()
{
endwin ();
#ifdef OS2
exit(0);
#else
exit();
#endif
}
int main (argc, argv)
char **argv;
{
int inloop = 1;
register int c;
int edistate = -1;
int arg = 1;
int narg;
int nedistate = -1;
int running = 1;
{
register i;
for (i = 0; i < MAXCOLS; i++)
{
fwidth[i] = DEFWIDTH;
precision[i] = DEFPREC;
}
}
linelim = -1;
curfile[0]=0;
running = 1;
#ifdef OS2
// Parse the extended OS/2 command line.
{
register char *cp;
for (c = 1; c < argc;)
{
if ((argv[c][0] == '-') || (argv[c][0] == '/'))
{
for (cp = argv[c]+1; *cp; cp++)
{
switch (*cp)
{
case 'b':
batch = 1;
break;
case 'r':
fRemote = 1;
if (isdigit(*(cp+1)))
{
PCrows = atoi(cp+1);
while (isdigit(*++cp));
--cp;
}
break;
}
}
if (c == 1)
{
--argc;
++argv;
}
else
++c;
}
else
++c;
}
}
#else
if (argc > 1 && (! strcmp(argv[1],"-b")))
{
argc--, argv++;
batch = 1;
}
#endif
if (! batch)
{
initscr ();
}
initkbd();
if (argc > 1)
{
strcpy(curfile,argv[1]);
readfile (argv[1],0);
}
modflg = 0;
if (batch) exit(0);
error ("SC 2.1 Type '?' for help.");
FullUpdate++;
while (inloop)
{
running = 1;
while (running)
{
nedistate = -1;
narg = 1;
if (edistate < 0 && linelim < 0 && (changed || FullUpdate))
EvalAll (), changed = 0;
update ();
refresh ();
move (1, 0);
clrtoeol ();
fflush (stdout);
seenerr = 0;
if (((c = nmgetch ()) < ' ') || ( c == 0177 ))
switch (c)
{
case ctl ('z'):
quit();
break;
case ctl ('r'):
FullUpdate++;
touchwin();
clear();
break;
default:
error ("No such command (^%c)", c + 0100);
break;
case ctl ('b'):
while (--arg >= 0)
{
if (curcol)
curcol--;
else
error ("At column A");
while(hidden_col[curcol] && curcol)
curcol--;
}
break;
case ctl ('c'):
running = 0;
break;
case ctl ('f'):
while (--arg >= 0)
{
if (curcol < MAXCOLS - 1)
curcol++;
else
error ("The table can't be any wider");
while(hidden_col[curcol]&&(curcol<MAXCOLS-1))
curcol++;
}
break;
case ctl ('g'):
case ctl ('['):
linelim = -1;
move (1, 0);
clrtoeol ();
break;
case 0177:
case ctl ('h'):
while (--arg>=0) if (linelim > 0)
line[--linelim] = 0;
break;
case ctl ('l'):
FullUpdate++;
break;
case ctl ('m'):
if (linelim < 0)
line[linelim = 0] = 0;
else
{
linelim = 0;
yyparse ();
linelim = -1;
}
break;
case ctl ('n'):
while (--arg >= 0)
{
if (currow < MAXROWS - 1)
currow++;
else
error ("The table can't be any longer");
while (hidden_row[currow] && (currow < MAXROWS - 1))
currow++;
}
break;
case ctl ('p'):
while (--arg >= 0)
{
if (currow)
currow--;
else
error ("At row zero");
while (hidden_row[currow] && currow)
currow--;
}
break;
case ctl ('q'):
break; /* ignore flow control */
case ctl ('s'):
break; /* ignore flow control */
case ctl ('t'):
showme ^= 1;
break;
case ctl ('u'):
narg = arg * 4;
nedistate = 1;
break;
case ctl ('v'): /* insert variable name */
if (linelim > 0)
{
sprintf (line+linelim,"%s%d", coltoa(curcol), currow);
linelim = strlen (line);
}
break;
case ctl ('e'): /* insert variable expression */
if (linelim > 0) editexp(currow,curcol);
break;
case ctl ('a'): /* insert variable value */
if (linelim > 0)
{
struct ent *p = tbl[currow][curcol];
if (p && p -> flags & is_valid)
{
sprintf (line + linelim, "%.*f",
precision[curcol],p -> v);
linelim = strlen (line);
}
}
break;
}
else
if ('0' <= c && c <= '9' && (linelim < 0 || edistate >= 0))
{
if (edistate != 0)
{
if (c == '0') /* just a '0' goes to left col */
curcol = 0;
else
{
nedistate = 0;
narg = c - '0';
}
}
else
{
nedistate = 0;
narg = arg * 10 + (c - '0');
}
}
else
if (linelim >= 0)
{
line[linelim++] = (char)c;
line[linelim] = 0;
}
else
switch (c)
{
case '.':
nedistate = 1;
break;
case ':':
break; /* Be nice to vi users */
case '=':
sprintf(line,"let %s%d = ",coltoa(curcol),currow);
linelim = strlen (line);
break;
case '/':
sprintf(line,"copy [to] %s%d [from] ",
coltoa(curcol), currow);
linelim = strlen (line);
break;
case '$':
curcol = MAXCOLS - 1;
while (!tbl[currow][curcol] && curcol > 0)
curcol--;
break;
#ifdef OS2
case '!':
if (shell() == 0)
{
FullUpdate++;
touchwin();
clear();
}
break;
#endif
case '?':
help ();
break;
case '"':
sprintf (line, "label %s%d = \"",
coltoa(curcol), currow);
linelim = strlen (line);
break;
case '<':
sprintf (line, "leftstring %s%d = \"",
coltoa(curcol), currow);
linelim = strlen (line);
break;
case '>':
sprintf (line, "rightstring %s%d = \"",
coltoa(curcol), currow);
linelim = strlen (line);
break;
case 'e':
editv (currow, curcol);
break;
case 'E':
edits (currow, curcol);
break;
case 'f':
sprintf (line, "format [for column] %s [is] ",
coltoa(curcol));
error("Current format is %d %d",
fwidth[curcol],precision[curcol]);
linelim = strlen (line);
break;
case 'P':
sprintf (line, "put [database into] \"");
if (*curfile)
error("default file is '%s'",curfile);
linelim = strlen (line);
break;
case 'M':
sprintf (line, "merge [database from] \"");
linelim = strlen (line);
break;
case 'G':
sprintf (line, "get [database from] \"");
if (*curfile)
error("default file is '%s'",curfile);
linelim = strlen (line);
break;
case 'W':
sprintf (line, "write [listing to] \"");
linelim = strlen (line);
break;
case 'T': /* tbl output */
sprintf (line, "tbl [listing to] \"");
linelim = strlen (line);
break;
case 'i':
switch (get_qual())
{
case 'r':
insertrow(arg);
break;
case 'c':
insertcol(arg);
break;
default:
break;
}
break;
case 'd':
switch (get_qual())
{
case 'r':
deleterow(arg);
break;
case 'c':
deletecol(arg);
break;
default:
break;
}
break;
case 'v':
switch (get_qual())
{
case 'r':
valueizerow(arg);
break;
case 'c':
valueizecol(arg);
break;
default:
break;
}
break;
case 'p':
{
register qual;
qual = get_qual();
while (arg--)
pullcells(qual);
break;
}
case 'x':
{
register struct ent **p;
register int c;
flush_saved();
for (c = curcol; arg-- && c < MAXCOLS; c++)
{
p = &tbl[currow][c];
if (*p)
{
free_ent(*p);
*p = 0;
}
}
sync_refs();
FullUpdate++;
}
break;
case 'Q':
case 'q':
running = 0;
break;
case 'h':
while (--arg >= 0)
{
if (curcol)
curcol--;
else
error ("At column A");
while(hidden_col[curcol] && curcol)
curcol--;
}
break;
case 'j':
while (--arg >= 0)
{
if (currow < MAXROWS - 1)
currow++;
else
error ("The table can't be any longer");
while (hidden_row[currow]&&(currow<MAXROWS-1))
currow++;
}
break;
case 'k':
while (--arg >= 0)
{
if (currow)
currow--;
else
error ("At row zero");
while (hidden_row[currow] && currow)
currow--;
}
break;
case 'l':
while (--arg >= 0)
{
if (curcol < MAXCOLS - 1)
curcol++;
else
error ("The table can't be any wider");
while(hidden_col[curcol]&&(curcol<MAXCOLS-1))
curcol++;
}
break;
case 'm':
savedrow = currow;
savedcol = curcol;
break;
case 'c':
{
register struct ent *p = tbl[savedrow][savedcol];
register c;
register struct ent *n;
if (!p)
break;
FullUpdate++;
modflg++;
for (c = curcol; arg-- && c < MAXCOLS; c++)
{
n = lookat (currow, c);
clearent(n);
n -> flags = p -> flags;
n -> v = p -> v;
n -> expr = copye(p->expr,
currow - savedrow,
c - savedcol);
n -> label = 0;
if (p -> label)
{
n -> label = (char *)malloc(strlen(p->label)+1);
strcpy (n -> label, p -> label);
}
}
break;
}
case 'z':
switch (get_qual())
{
case 'r':
hiderow(arg);
break;
case 'c':
hidecol(arg);
break;
default:
break;
}
break;
case 's':
switch (get_qual())
{
case 'r':
showrow_op();
break;
case 'c':
showcol_op();
break;
default:
break;
}
break;
case 'a':
switch (get_qual())
{
case 'r':
while (arg--)
duprow();
break;
case 'c':
while (arg--)
dupcol();
break;
default:
break;
}
break;
default:
if ((c & 0177) != 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) */
endwin ();
return 0;
}
int modcheck(endstr)
char *endstr;
{
if (modflg && curfile[0])
{
char ch, lin[100];
move (0, 0);
clrtoeol ();
sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr);
addstr (lin);
refresh();
ch = (char)nmgetch();
if (ch == 'y' || ch == 'Y')
writefile(curfile);
else if (ch == ctl ('g'))
return(1);
}
return(0);
}
VOID writefile(fname)
char *fname;
{
register FILE *f;
register struct ent **p;
register r, c;
char save[1024];
if (*fname == 0) fname = &curfile[0];
strcpy(save,fname);
f = fopen (fname, "w");
if (f == 0)
{
error ("Can't create %s", fname);
return;
}
fprintf (f, "# This data file was generated by the Spreadsheet ");
fprintf (f, "Calculator.\n");
fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
for (c=0; c<MAXCOLS; c++)
if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
for (r=0; r<=maxrow; r++)
{
p = &tbl[r][0];
for (c=0; c<=maxcol; c++, p++)
if (*p)
{
if ((*p)->label)
fprintf (f, "%sstring %s%d = \"%s\"\n",
(*p)->flags&is_leftflush ? "left" : "right",
coltoa(c),r,(*p)->label);
if ((*p)->flags&is_valid)
{
editv (r, c);
fprintf (f, "%s\n",line);
}
}
}
fclose (f);
strcpy(curfile,save);
modflg = 0;
error("File '%s' written.",curfile);
}
VOID readfile(fname,eraseflg)
char *fname; int eraseflg;
{
register FILE *f;
char save[1024];
if (*fname == 0) fname = &curfile[0];
strcpy(save,fname);
if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
f = fopen (save, "r");
if (f == 0)
{
error ("Can't read %s", save);
return;
}
if (eraseflg) erasedb();
while (fgets(line,sizeof line,f))
{
linelim = 0;
if (line[0] != '#') yyparse();
}
fclose (f);
linelim = -1;
modflg++;
if (eraseflg)
{
strcpy(curfile,save);
modflg = 0;
}
EvalAll();
}
VOID erasedb()
{
register r, c;
for (c = 0; c <= maxcol; c++)
{
fwidth[c] = DEFWIDTH;
precision[c] = DEFPREC;
}
for (r = 0; r <= maxrow; r++)
{
register struct ent **p = &tbl[r][0];
for (c = 0; c++ <= maxcol; p++)
if (*p)
{
if ((*p)->expr) efree ((*p) -> expr);
if ((*p)->label) free ((*p) -> label);
free (*p);
*p = 0;
}
}
maxrow = 0;
maxcol = 0;
FullUpdate++;
}