v18i048: SC spreadsheet, version 6.1, Part04/04
Rich Salz
rsalz at uunet.uu.net
Wed Mar 22 07:18:30 AEST 1989
Submitted-by: Robert Bond <sequent!rgb>
Posting-number: Volume 18, Issue 48
Archive-name: sc6.1/part04
# This is a shell archive. Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have default permissions).
# This archive contains the following files:
# ./xmalloc.c
# ./cmds.c
# ./range.c
# ./help.c
# ./eres.sed
# ./sres.sed
# ./Makefile
# ./psc.c
#
if `test ! -s ./xmalloc.c`
then
echo "Extracting ./xmalloc.c"
cat > ./xmalloc.c << '\SHAR\EOF\'
/*
* A safer saner malloc, for careless programmers
* $Revision: 6.1 $
*/
#include <stdio.h>
#include <curses.h>
extern char *malloc();
#ifdef SYSV3
extern void free();
extern void exit();
#endif
char *
xmalloc(n)
unsigned n;
{
register char *ptr;
if ((ptr = malloc(n + sizeof(double))) == NULL)
fatal("xmalloc: no memory");
*((int *) ptr) = 12345; /* magic number */
return(ptr + sizeof(double));
}
xfree(p)
char *p;
{
if (p == NULL)
fatal("xfree: NULL");
p -= sizeof(double);
if (*((int *) p) != 12345)
fatal("xfree: storage not malloc'ed");
free(p);
}
fatal(str)
char *str;
{
deraw();
(void) fprintf(stderr,"%s\n", str);
exit(1);
}
\SHAR\EOF\
else
echo "will not over write ./xmalloc.c"
fi
if [ `wc -c ./xmalloc.c | awk '{printf $1}'` -ne 670 ]
then
echo `wc -c ./xmalloc.c | awk '{print "Got " $1 ", Expected " 670}'`
fi
if `test ! -s ./cmds.c`
then
echo "Extracting ./cmds.c"
cat > ./cmds.c << '\SHAR\EOF\'
/* SC A Spreadsheet Calculator
* Command routines
*
* original by James Gosling, September 1982
* modifications by Mark Weiser and Bruce Israel,
* University of Maryland
*
* More mods Robert Bond, 12/86
*
* $Revision: 6.1 $
*/
#include <curses.h>
#include "sc.h"
#include <signal.h>
#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif
#ifdef SYSV3
extern void exit();
#else
extern int exit();
#endif
#define DEFCOLDELIM ':'
duprow()
{
if (currow >= MAXROWS - 1 || maxrow >= MAXROWS - 1) {
error ("The table can't be any bigger");
return;
}
modflg++;
currow++;
openrow (currow);
for (curcol = 0; curcol <= maxcol; curcol++) {
register struct ent *p = tbl[currow - 1][curcol];
if (p) {
register struct ent *n;
n = lookat (currow, curcol);
copyent ( n, p, 1, 0);
}
}
for (curcol = 0; curcol <= maxcol; curcol++) {
register struct ent *p = tbl[currow][curcol];
if (p && (p -> flags & is_valid) && !p -> expr)
break;
}
if (curcol > maxcol)
curcol = 0;
}
dupcol()
{
if (curcol >= MAXCOLS - 1 || maxcol >= MAXCOLS - 1) {
error ("The table can't be any wider");
return;
}
modflg++;
curcol++;
opencol (curcol);
for (currow = 0; currow <= maxrow; currow++) {
register struct ent *p = tbl[currow][curcol - 1];
if (p) {
register struct ent *n;
n = lookat (currow, curcol);
copyent ( n, p, 0, 1);
}
}
for (currow = 0; currow <= maxrow; currow++) {
register struct ent *p = tbl[currow][curcol];
if (p && (p -> flags & is_valid) && !p -> expr)
break;
}
if (currow > maxrow)
currow = 0;
}
insertrow(arg)
register int arg;
{
while (--arg>=0) openrow (currow);
}
deleterow(arg)
register int arg;
{
flush_saved();
erase_area(currow, 0, currow + arg - 1, maxcol);
currow += arg;
while (--arg>=0) closerow (--currow);
sync_refs();
}
insertcol(arg)
register int arg;
{
while (--arg>=0) opencol(curcol);
}
deletecol(arg)
register int arg;
{
flush_saved();
erase_area(0, curcol, maxrow, curcol + arg - 1);
curcol += arg;
while (--arg>=0) closecol (--curcol);
sync_refs();
}
rowvalueize(arg)
register int arg;
{
valueize_area(currow, 0, currow + arg - 1, maxcol);
}
colvalueize(arg)
register int arg;
{
valueize_area(0, curcol, maxrow, curcol + arg - 1);
}
erase_area(sr, sc, er, ec)
int sr, sc, er, ec;
{
register int r, c;
register struct ent **p;
if (sr > er) {
r = sr; sr = er; er= r;
}
if (sc > ec) {
c = sc; sc = ec; ec= c;
}
if (sr < 0)
sr = 0;
if (sc < 0)
sc = 0;
if (er >= MAXROWS)
er = MAXROWS-1;
if (ec >= MAXCOLS)
ec = MAXCOLS-1;
for (r = sr; r <= er; r++) {
for (c = sc; c <= ec; c++) {
p = &tbl[r][c];
if (*p) {
free_ent(*p);
*p = 0;
}
}
}
}
valueize_area(sr, sc, er, ec)
int sr, sc, er, ec;
{
register int r, c;
register struct ent *p;
if (sr > er) {
r = sr; sr = er; er= r;
}
if (sc > ec) {
c = sc; sc = ec; ec= c;
}
if (sr < 0)
sr = 0;
if (sc < 0)
sc = 0;
if (er >= MAXROWS)
er = MAXROWS-1;
if (ec >= MAXCOLS)
ec = MAXCOLS-1;
for (r = sr; r <= er; r++) {
for (c = sc; c <= ec; c++) {
p = tbl[r][c];
if (p && p->expr) {
efree(p->expr);
p->expr = 0;
p->flags &= ~is_strexpr;
}
}
}
}
pullcells(to_insert)
int to_insert;
{
register struct ent *p, *n;
register int deltar, deltac;
int minrow, mincol;
int mxrow, mxcol;
int numrows, numcols;
if (! to_fix)
{
error ("No data to pull");
return;
}
minrow = MAXROWS;
mincol = MAXCOLS;
mxrow = 0;
mxcol = 0;
for (p = to_fix; p; p = p->next) {
if (p->row < minrow)
minrow = p->row;
if (p->row > mxrow)
mxrow = p->row;
if (p->col < mincol)
mincol = p->col;
if (p->col > mxcol)
mxcol = p->col;
}
numrows = mxrow - minrow + 1;
numcols = mxcol - mincol + 1;
deltar = currow - minrow;
deltac = curcol - mincol;
if (to_insert == 'r') {
insertrow(numrows);
deltac = 0;
} else if (to_insert == 'c') {
insertcol(numcols);
deltar = 0;
}
FullUpdate++;
modflg++;
for (p = to_fix; p; p = p->next) {
n = lookat (p->row + deltar, p->col + deltac);
(void) clearent(n);
copyent( n, p, deltar, deltac);
n -> flags = p -> flags & ~is_deleted;
}
}
colshow_op()
{
register int i,j;
for (i=0; i<MAXCOLS; i++)
if (col_hidden[i])
break;
for(j=i; j<MAXCOLS; j++)
if (!col_hidden[j])
break;
j--;
if (i>=MAXCOLS)
error ("No hidden columns to show");
else {
(void) sprintf(line,"show %s:", coltoa(i));
(void) sprintf(line + strlen(line),"%s",coltoa(j));
linelim = strlen (line);
}
}
rowshow_op()
{
register int i,j;
for (i=0; i<MAXROWS; i++)
if (row_hidden[i])
break;
for(j=i; j<MAXROWS; j++)
if (!row_hidden[j]) {
break;
}
j--;
if (i>=MAXROWS)
error ("No hidden rows to show");
else {
(void) sprintf(line,"show %d:%d", i, j);
linelim = strlen (line);
}
}
/*
* Given a row/column command letter, emit a small menu, then read a qualifier
* character for a row/column command and convert it to 'r' (row), 'c'
* (column), or 0 (unknown). If ch is 'p', an extra qualifier 'm' is allowed.
*/
get_rcqual (ch)
int ch;
{
error ("%sow/column: r: row c: column%s",
(ch == 'i') ? "Insert r" :
(ch == 'a') ? "Append r" :
(ch == 'd') ? "Delete r" :
(ch == 'p') ? "Pull r" :
(ch == 'v') ? "Values r" :
(ch == 'z') ? "Zap r" :
(ch == 's') ? "Show r" : "R",
(ch == 'p') ? " m: merge" : "");
(void) refresh();
switch (nmgetch())
{
case 'r':
case 'l':
case 'h':
case ctl(f):
case ctl(b): return ('r');
case 'c':
case 'j':
case 'k':
case ctl(p):
case ctl(n): return ('c');
case 'm': return ((ch == 'p') ? 'm' : 0);
case ESC:
case ctl (g): return (ESC);
default: return (0);
}
/*NOTREACHED*/
}
openrow (rs)
int rs;
{
register r;
register struct ent **p;
register c;
register i;
if (rs > maxrow) maxrow = rs;
if (maxrow >= MAXROWS - 1 || rs > MAXROWS - 1) {
error ("The table can't be any longer");
return;
}
for (i = maxrow+1; i > rs; i--) {
row_hidden[i] = row_hidden[i-1];
}
for (r = ++maxrow; r > rs; r--)
for (c = maxcol + 1, p = &tbl[r][0]; --c >= 0; p++)
if (p[0] = p[-MAXCOLS])
p[0] -> row++;
p = &tbl[rs][0];
for (c = maxcol + 1; --c >= 0;)
*p++ = 0;
FullUpdate++;
modflg++;
}
closerow (r)
register r;
{
register struct ent **p;
register c;
register int i;
if (r > maxrow) return;
p = &tbl[r][0];
for (c=maxcol+1; --c>=0; ) {
if (*p)
free_ent(*p);
*p++ = 0;
}
for (i = r; i < MAXROWS - 1; i++) {
row_hidden[i] = row_hidden[i+1];
}
while (r<maxrow) {
for (c = maxcol+1, p = &tbl[r][0]; --c>=0; p++)
if (p[0] = p[MAXCOLS])
p[0]->row--;
r++;
}
p = &tbl[maxrow][0];
for (c=maxcol+1; --c>=0; ) *p++ = 0;
maxrow--;
FullUpdate++;
modflg++;
}
opencol (cs)
int cs;
{
register r;
register struct ent **p;
register c;
register lim = maxcol-cs+1;
int i;
if (cs > maxcol) maxcol = cs;
if (maxcol >= MAXCOLS - 1 || cs > MAXCOLS - 1) {
error ("The table can't be any wider");
return;
}
for (i = maxcol+1; i > cs; i--) {
fwidth[i] = fwidth[i-1];
precision[i] = precision[i-1];
col_hidden[i] = col_hidden[i-1];
}
/* fwidth[cs] = DEFWIDTH;
precision[i] = DEFPREC; */
for (r=0; r<=maxrow; r++) {
p = &tbl[r][maxcol+1];
for (c=lim; --c>=0; p--)
if (p[0] = p[-1])
p[0]->col++;
p[0] = 0;
}
maxcol++;
FullUpdate++;
modflg++;
}
closecol (cs)
int cs;
{
register r;
register struct ent **p;
register struct ent *q;
register c;
register lim = maxcol-cs;
int i;
if (lim < 0) return;
for (r=0; r<=maxrow; r++)
if (q = tbl[r][cs]) {
free_ent(q);
}
for (r=0; r<=maxrow; r++) {
p = &tbl[r][cs];
for (c=lim; --c>=0; p++)
if (p[0] = p[1])
p[0]->col--;
p[0] = 0;
}
for (i = cs; i < MAXCOLS - 1; i++) {
fwidth[i] = fwidth[i+1];
precision[i] = precision[i+1];
col_hidden[i] = col_hidden[i+1];
}
maxcol--;
FullUpdate++;
modflg++;
}
doend(rowinc, colinc)
int rowinc, colinc;
{
register struct ent *p;
int r, c;
if (VALID_CELL(p, currow, curcol)) {
r = currow + rowinc;
c = curcol + colinc;
if (r >= 0 && r < MAXROWS &&
c >= 0 && c < MAXCOLS &&
!VALID_CELL(p, r, c)) {
currow = r;
curcol = c;
}
}
if (!VALID_CELL(p, currow, curcol)) {
switch (rowinc) {
case -1:
while (!VALID_CELL(p, currow, curcol) && currow > 0)
currow--;
break;
case 1:
while (!VALID_CELL(p, currow, curcol) && currow < MAXROWS-1)
currow++;
break;
case 0:
switch (colinc) {
case -1:
while (!VALID_CELL(p, currow, curcol) && curcol > 0)
curcol--;
break;
case 1:
while (!VALID_CELL(p, currow, curcol) && curcol < MAXCOLS-1)
curcol++;
break;
}
break;
}
error (""); /* clear line */
return;
}
switch (rowinc) {
case -1:
while (VALID_CELL(p, currow, curcol) && currow > 0)
currow--;
break;
case 1:
while (VALID_CELL(p, currow, curcol) && currow < MAXROWS-1)
currow++;
break;
case 0:
switch (colinc) {
case -1:
while (VALID_CELL(p, currow, curcol) && curcol > 0)
curcol--;
break;
case 1:
while (VALID_CELL(p, currow, curcol) && curcol < MAXCOLS-1)
curcol++;
break;
}
break;
}
if (!VALID_CELL(p, currow, curcol)) {
currow -= rowinc;
curcol -= colinc;
}
}
doformat(c1,c2,w,p)
int c1,c2,w,p;
{
register int i;
if (w > COLS - RESCOL - 2) {
error("Format too large - Maximum = %d", COLS - RESCOL - 2);
w = COLS-RESCOL-2;
}
if (p > w) {
error("Precision too large");
p = w;
}
for(i = c1; i<=c2; i++)
fwidth[i] = w, precision[i] = p;
FullUpdate++;
modflg++;
}
print_options(f)
FILE *f;
{
if(
autocalc &&
propagation == 10 &&
calc_order == BYROWS &&
!numeric &&
prescale == 1.0 &&
!extfunc &&
showcell &&
showtop &&
tbl_style == 0
)
return; /* No reason to do this */
(void) fprintf(f, "set");
if(!autocalc)
(void) fprintf(f," !autocalc");
if(propagation != 10)
(void) fprintf(f, " iterations = %d", propagation);
if(calc_order != BYROWS )
(void) fprintf(f, " bycols");
if (numeric)
(void) fprintf(f, " numeric");
if (prescale != 1.0)
(void) fprintf(f, " prescale");
if (extfunc)
(void) fprintf(f, " extfun");
if (!showcell)
(void) fprintf(f, " !cellcur");
if (!showtop)
(void) fprintf(f, " !toprow");
if (tbl_style)
(void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" :
tbl_style == LATEX ? "latex" :
tbl_style == TEX ? "tex" : "0" );
(void) fprintf(f, "\n");
}
printfile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
FILE *f;
char pline[1000];
int plinelim;
int pid;
int fieldlen, nextcol;
register row, col;
register struct ent **p;
char ch, lin[100];
if (strcmp(fname, curfile) == 0) {
(void) move (0, 0);
(void) clrtoeol ();
(void) sprintf (lin,
"Confirm that you want to destroy the data base: (y,n)");
(void) addstr (lin);
(void) refresh();
ch = nmgetch();
if (ch != 'y' && ch != 'Y')
return;
}
f = openout(fname, &pid);
if (f==0) {
error ("Can't create file \"%s\"", fname);
return;
}
for (row=r0;row<=rn; row++) {
register c = 0;
if (row_hidden[row])
continue;
pline[plinelim=0] = '\0';
for (p = &tbl[row][col=c0]; col<=cn;
p += nextcol-col, col = nextcol, c += fieldlen) {
nextcol = col+1;
if (col_hidden[col]) {
fieldlen = 0;
continue;
}
fieldlen = fwidth[col];
if (*p) {
char *s;
while (plinelim<c) pline[plinelim++] = ' ';
plinelim = c;
if ((*p)->flags&is_valid) {
(void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
precision[col], (*p)->v);
plinelim += strlen (pline+plinelim);
}
if (s = (*p)->label) {
int slen;
char *start, *last;
register char *fp;
struct ent *nc;
/* Figure out if the label slops over to a blank field */
slen = strlen(s);
while (slen > fieldlen && nextcol <= cn &&
!((nc = lookat(row,nextcol))->flags & is_valid) &&
!(nc->label)) {
if (!col_hidden[nextcol])
fieldlen += fwidth[nextcol];
nextcol++;
}
if (slen > fieldlen)
slen = fieldlen;
/* Now justify and print */
start = (*p)->flags & is_leftflush ? pline + c
: pline + c + fieldlen - slen;
last = pline + c + fieldlen;
fp = plinelim < c ? pline + plinelim : pline + c;
while (fp < start)
*fp++ = ' ';
while (slen--)
*fp++ = *s++;
if (!((*p)->flags & is_valid) || fieldlen != fwidth[col])
while(fp < last)
*fp++ = ' ';
if (plinelim < fp - pline)
plinelim = fp - pline;
}
}
}
pline[plinelim++] = '\n';
pline[plinelim] = 0;
(void) fputs (pline, f);
}
closeout(f, pid);
}
tblprintfile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
FILE *f;
int pid;
register row, col;
register struct ent **p;
char coldelim = DEFCOLDELIM;
char ch, lin[100];
if (strcmp(fname, curfile) == 0) {
(void) move (0, 0);
(void) clrtoeol ();
(void) sprintf (lin,
"Confirm that you want to destroy the data base: (y,n)");
(void) addstr (lin);
(void) refresh();
ch = nmgetch();
if (ch != 'y' && ch != 'Y')
return;
}
f = openout(fname, &pid);
if (f==0) {
error ("Can't create file \"%s\"", fname);
return;
}
if ( tbl_style == TBL ) {
fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname);
fprintf(f,"tab(%c);\n",coldelim);
for (col=c0;col<=cn; col++) fprintf(f," n");
fprintf(f, ".\n");
}
else if ( tbl_style == LATEX ) {
fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname);
for (col=c0;col<=cn; col++) fprintf(f,"c");
fprintf(f, "}\n");
coldelim = '&';
}
else if ( tbl_style == TEX ) {
fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n",
progname, cn-c0+1);
coldelim = '&';
}
for (row=r0; row<=rn; row++) {
if ( tbl_style == TEX )
(void) fprintf (f, "\\+");
for (p = &tbl[row][col=c0]; col<=cn; col++, p++) {
if (*p) {
char *s;
if ((*p)->flags&is_valid) {
(void) fprintf (f,"%.*f",precision[col],
(*p)->v);
}
if (s = (*p)->label) {
(void) fprintf (f,"%s",s);
}
}
if ( col < cn )
(void) fprintf(f,"%c",coldelim);
}
if ( tbl_style == LATEX ) {
if ( row < rn ) (void) fprintf (f, "\\\\");
}
else if ( tbl_style == TEX ) {
(void) fprintf (f, "\\cr");
}
(void) fprintf (f,"\n");
}
if ( tbl_style == TBL )
(void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname);
else if ( tbl_style == LATEX )
(void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname);
else if ( tbl_style == TEX )
(void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname);
closeout(f, pid);
}
struct enode *
copye (e, Rdelta, Cdelta)
register struct enode *e;
int Rdelta, Cdelta;
{
register struct enode *ret;
if (e==0) {
ret = 0;
} else if (e->op & REDUCE) {
int newrow, newcol;
ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
ret->op = e->op;
newrow=e->e.r.left.vf & FIX_ROW ? e->e.r.left.vp->row :
e->e.r.left.vp->row+Rdelta;
newcol=e->e.r.left.vf & FIX_COL ? e->e.r.left.vp->col :
e->e.r.left.vp->col+Cdelta;
ret->e.r.left.vp = lookat (newrow, newcol);
ret->e.r.left.vf = e->e.r.left.vf;
newrow=e->e.r.right.vf & FIX_ROW ? e->e.r.right.vp->row :
e->e.r.right.vp->row+Rdelta;
newcol=e->e.r.right.vf & FIX_COL ? e->e.r.right.vp->col :
e->e.r.right.vp->col+Cdelta;
ret->e.r.right.vp = lookat (newrow, newcol);
ret->e.r.right.vf = e->e.r.right.vf;
} else {
ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
ret->op = e->op;
switch (ret->op) {
case 'v':
{
int newrow, newcol;
newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
e->e.v.vp->row+Rdelta;
newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
e->e.v.vp->col+Cdelta;
ret->e.v.vp = lookat (newrow, newcol);
ret->e.v.vf = e->e.v.vf;
break;
}
case 'k':
ret->e.k = e->e.k;
break;
case 'f':
ret->e.o.right = copye (e->e.o.right,0,0);
ret->e.o.left = 0;
break;
case '$':
ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
(void) strcpy(ret->e.s, e->e.s);
break;
default:
ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
break;
}
}
return ret;
}
/*
* sync_refs and syncref are used to remove references to
* deleted struct ents. Note that the deleted structure must still
* be hanging around before the call, but not referenced by an entry
* in tbl. Thus the free_ent, fix_ent calls in sc.c
*/
sync_refs ()
{
register i,j;
register struct ent *p;
sync_ranges();
for (i=0; i<=maxrow; i++)
for (j=0; j<=maxcol; j++)
if ((p=tbl[i][j]) && p->expr)
syncref(p->expr);
}
syncref(e)
register struct enode *e;
{
if (e==0)
return;
else if (e->op & REDUCE) {
e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col);
e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col);
} else {
switch (e->op) {
case 'v':
e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
break;
case 'k':
break;
case '$':
break;
default:
syncref(e->e.o.right);
syncref(e->e.o.left);
break;
}
}
}
hiderow(arg)
int arg;
{
register int r1;
register int r2;
r1 = currow;
r2 = r1 + arg - 1;
if (r1 < 0 || r1 > r2) {
error ("Invalid range");
return;
}
if (r2 > MAXROWS-2) {
error ("You can't hide the last row");
return;
}
FullUpdate++;
while (r1 <= r2)
row_hidden[r1++] = 1;
}
hidecol(arg)
int arg;
{
register int c1;
register int c2;
c1 = curcol;
c2 = c1 + arg - 1;
if (c1 < 0 || c1 > c2) {
error ("Invalid range");
return;
}
if (c2 > MAXCOLS-2) {
error ("You can't hide the last column");
return;
}
FullUpdate++;
while (c1 <= c2)
col_hidden[c1++] = 1;
}
showrow(r1, r2)
int r1, r2;
{
if (r1 < 0 || r1 > r2) {
error ("Invalid range");
return;
}
if (r2 > MAXROWS-1) {
r2 = MAXROWS-1;
}
FullUpdate++;
while (r1 <= r2)
row_hidden[r1++] = 0;
}
showcol(c1, c2)
int c1, c2;
{
if (c1 < 0 || c1 > c2) {
error ("Invalid range");
return;
}
if (c2 > MAXCOLS-1) {
c2 = MAXCOLS-1;
}
FullUpdate++;
while (c1 <= c2)
col_hidden[c1++] = 0;
}
/* Open the output file, setting up a pipe if needed */
FILE *
openout(fname, rpid)
char *fname;
int *rpid;
{
int pipefd[2];
int pid;
FILE *f;
while (*fname && (*fname == ' ')) /* Skip leading blanks */
fname++;
if (*fname != '|') { /* Open file if not pipe */
*rpid = 0;
return(fopen(fname, "w"));
}
fname++; /* Skip | */
if ( pipe (pipefd) < 0) {
error("Can't make pipe to child");
*rpid = 0;
return(0);
}
deraw();
#ifdef VMS
fprintf(stderr, "No son tasks available yet under VMS--sorry\n");
#else /* VMS */
if ((pid=fork()) == 0) /* if child */
{
(void) close (0); /* close stdin */
(void) close (pipefd[1]);
(void) dup (pipefd[0]); /* connect to pipe input */
(void) signal (SIGINT, SIG_DFL); /* reset */
(void) execl ("/bin/sh", "sh", "-c", fname, 0);
exit (-127);
}
else /* else parent */
{
*rpid = pid;
f = fdopen (pipefd[1], "w");
if (f == 0)
{
(void) kill (pid, -9);
error ("Can't fdopen output");
(void) close (pipefd[1]);
*rpid = 0;
return(0);
}
}
#endif /* VMS */
return(f);
}
closeout(f, pid)
FILE *f;
int pid;
{
int temp;
(void) fclose (f);
if (pid) {
while (pid != wait(&temp)) /**/;
(void) printf("Press RETURN to continue ");
(void) fflush(stdout);
(void) nmgetch();
goraw();
}
}
copyent(n,p,dr,dc)
register struct ent *n, *p;
int dr, dc;
{
if(!n||!p){error("internal error");return;}
n -> v = p -> v;
n -> flags = p -> flags;
n -> expr = copye (p -> expr, dr, dc);
n -> label = 0;
if (p -> label) {
n -> label = (char *)
xmalloc ((unsigned) (strlen (p -> label) + 1));
(void) strcpy (n -> label, p -> label);
}
}
write_fd (f, r0, c0, rn, cn)
register FILE *f;
int r0, c0, rn, cn;
{
register struct ent **p;
register r, c;
(void) fprintf (f, "# This data file was generated by the Spreadsheet ");
(void) fprintf (f, "Calculator.\n");
(void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
print_options(f);
for (c=0; c<MAXCOLS; c++)
if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
(void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
for (c=c0; c<cn; c++) {
if (col_hidden[c]) {
(void) fprintf(f, "hide %s\n", coltoa(c));
}
}
for (r=r0; r<=rn; r++) {
if (row_hidden[r]) {
(void) fprintf(f, "hide %d\n", r);
}
}
write_range(f);
if (mdir)
(void) fprintf(f, "mdir \"%s\"\n", mdir);
for (r=r0; r<=rn; r++) {
p = &tbl[r][c0];
for (c=c0; c<=cn; c++, p++)
if (*p) {
if ((*p)->label) {
edits(r,c);
(void) fprintf(f, "%s\n",line);
}
if ((*p)->flags&is_valid) {
editv (r, c);
(void) fprintf (f, "%s\n",line);
}
}
}
}
writefile (fname, r0, c0, rn, cn)
char *fname;
int r0, c0, rn, cn;
{
register FILE *f;
char save[1024];
int pid;
#ifndef VMS
if (Crypt) {
return (cwritefile(fname, r0, c0, rn, cn));
}
#endif /* VMS */
if (*fname == 0) fname = &curfile[0];
(void) strcpy(save,fname);
f = openout(fname, &pid);
if (f == 0) {
error ("Can't create file \"%s\"", fname);
return (-1);
}
write_fd(f, r0, c0, rn, cn);
closeout(f, pid);
if (!pid) {
(void) strcpy(curfile, save);
modflg = 0;
error("File \"%s\" written.",curfile);
}
return (0);
}
readfile (fname,eraseflg)
char *fname;
int eraseflg;
{
register FILE *f;
char save[1024];
if (*fname == '*' && mdir) {
(void) strcpy(save, mdir);
*fname = '/';
(void) strcat(save, fname);
} else {
if (*fname == 0)
fname = &curfile[0];
(void) strcpy(save,fname);
}
#ifndef VMS
if (Crypt) {
creadfile(save, eraseflg);
return;
}
#endif /* VMS */
if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
f = fopen (save, "r");
if (f==0) {
error ("Can't read file \"%s\"", save);
return;
}
if (eraseflg) erasedb ();
loading++;
while (fgets(line,sizeof line,f)) {
linelim = 0;
if (line[0] != '#') (void) yyparse ();
}
--loading;
(void) fclose (f);
linelim = -1;
modflg++;
if (eraseflg) {
(void) strcpy(curfile,save);
modflg = 0;
}
EvalAll();
}
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) xfree ((char *)((*p) -> label));
xfree ((char *)(*p));
*p = 0;
}
}
maxrow = 0;
maxcol = 0;
clean_range();
FullUpdate++;
}
backcol(arg)
int arg;
{
while (--arg>=0) {
if (curcol)
curcol--;
else
{error ("At column A"); break;}
while(col_hidden[curcol] && curcol)
curcol--;
}
}
forwcol(arg)
int arg;
{
while (--arg>=0) {
if (curcol < MAXCOLS - 1)
curcol++;
else
{error ("The table can't be any wider"); break;}
while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
curcol++;
}
}
forwrow(arg)
int arg;
{
while (--arg>=0) {
if (currow < MAXROWS - 1)
currow++;
else
{error ("The table can't be any longer"); break;}
while (row_hidden[currow]&&(currow<MAXROWS-1))
currow++;
}
}
backrow(arg)
int arg;
{
while (--arg>=0) {
if (currow)
currow--;
else
{error ("At row zero"); break;}
while (row_hidden[currow] && currow)
currow--;
}
}
/*
* Show a cell's label string or expression value. May overwrite value if
* there is one already displayed in the cell. Created from old code in
* update(), copied with minimal changes.
*/
showstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c)
char *string; /* to display */
int leftflush; /* or rightflush */
int hasvalue; /* is there a numeric value? */
int row, col; /* spreadsheet location */
int *nextcolp; /* value returned through it */
int mxcol; /* last column displayed? */
int *fieldlenp; /* value returned through it */
int r, c; /* screen row and column */
{
register int nextcol = *nextcolp;
register int fieldlen = *fieldlenp;
char field[1024];
int slen;
char *start, *last;
register char *fp;
struct ent *nc;
/* This figures out if the label is allowed to
slop over into the next blank field */
slen = strlen (string);
while ((slen > fieldlen) && (nextcol <= mxcol) &&
!((nc = lookat (row, nextcol)) -> flags & is_valid) &&
!(nc->label)) {
if (! col_hidden [nextcol])
fieldlen += fwidth [nextcol];
nextcol++;
}
if (slen > fieldlen)
slen = fieldlen;
/* Now justify and print */
start = leftflush ? field : field + fieldlen - slen;
last = field+fieldlen;
fp = field;
while (fp < start)
*fp++ = ' ';
while (slen--)
*fp++ = *string++;
if ((! hasvalue) || fieldlen != fwidth[col])
while (fp < last)
*fp++ = ' ';
*fp = 0;
#ifdef VMS
mvaddstr(r, c, field); /* this is a macro */
#else
(void) mvaddstr(r, c, field);
#endif
*nextcolp = nextcol;
*fieldlenp = fieldlen;
}
etype(e)
register struct enode *e;
{
if (e==0) return 0;
switch (e->op) {
case '+': case '-': case '*': case '/': case '%': case '^':
case '<': case '=': case '>': case '&': case '|': case 'm':
case '~': case 'k': case INDEX:
case REDUCE | '+': case REDUCE | '*': case REDUCE | 'a':
case REDUCE | 's': case REDUCE | MAX: case REDUCE | MIN:
case ACOS: case ASIN: case ATAN: case ATAN2: case CEIL:
case COS: case EXP: case FABS: case FLOOR: case HYPOT:
case LOG: case LOG10: case POW: case SIN: case SQRT:
case TAN: case DTR: case RTD: case RND: case FV: case PV:
case PMT: case HOUR: case MINUTE: case SECOND: case MONTH:
case DAY: case YEAR: case NOW: case STON: case EQS:
case LMAX: case LMIN: case NVAL: case LOOKUP:
return (NUM);
case O_SCONST: case '#': case DATE: case FMT: case STINDEX:
case EXT: case SVAL: case SUBSTR:
return (STR);
case 'f': case '?':
return(etype(e->e.o.left));
case O_VAR: {
register struct ent *p;
p = e->e.v.vp;
if (p->expr)
return(p->flags & is_strexpr ? STR : NUM);
else if (p->label)
return(STR);
else
return(NUM);
}
default:
return(NUM);
}
}
\SHAR\EOF\
else
echo "will not over write ./cmds.c"
fi
if [ `wc -c ./cmds.c | awk '{printf $1}'` -ne 27705 ]
then
echo `wc -c ./cmds.c | awk '{print "Got " $1 ", Expected " 27705}'`
fi
if `test ! -s ./range.c`
then
echo "Extracting ./range.c"
cat > ./range.c << '\SHAR\EOF\'
/* SC A Spreadsheet Calculator
* Range Manipulations
*
* Robert Bond, 4/87
*
* $Revision: 6.1 $
*/
#include <stdio.h>
#include <curses.h>
#include <ctype.h>
#include "sc.h"
#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif
static struct range *rng_base;
add_range(name, left, right, is_range)
char *name;
struct ent_ptr left, right;
int is_range;
{
struct range *r;
register char *p;
int len;
int minr,minc,maxr,maxc;
int minrf, mincf, maxrf, maxcf;
if (left.vp->row < right.vp->row) {
minr = left.vp->row; minrf = left.vf & FIX_ROW;
maxr = right.vp->row; maxrf = right.vf & FIX_ROW;
} else {
minr = right.vp->row; minrf = right.vf & FIX_ROW;
maxr = left.vp->row; maxrf = right.vf & FIX_ROW;
}
if (left.vp->col < right.vp->col) {
minc = left.vp->col; mincf = left.vf & FIX_COL;
maxc = right.vp->col; maxcf = right.vf & FIX_COL;
} else {
minc = right.vp->col; mincf = right.vf & FIX_COL;
maxc = left.vp->col; maxcf = left.vf & FIX_COL;
}
left.vp = lookat(minr, minc);
left.vf = minrf | mincf;
right.vp = lookat(maxr, maxc);
right.vf = maxrf | maxcf;
if (find_range(name, strlen(name), (struct ent *)0, (struct ent *)0)) {
error("Error: range name already defined");
xfree(name);
return;
}
if (strlen(name) <= 2) {
error("Invalid range name - too short");
xfree(name);
return;
}
for(p=name, len=0; *p; p++, len++)
if (!((isalpha(*p) && (len<=2)) ||
((isdigit(*p) || isalpha(*p) || (*p == '_')) && (len>2)))) {
error("Invalid range name - illegal combination");
xfree(name);
return;
}
r = (struct range *)xmalloc((unsigned)sizeof(struct range));
r->r_name = name;
r->r_left = left;
r->r_right = right;
r->r_next = rng_base;
r->r_prev = 0;
r->r_is_range = is_range;
if (rng_base)
rng_base->r_prev = r;
rng_base = r;
}
del_range(left, right)
struct ent *left, *right;
{
register struct range *r;
int minr,minc,maxr,maxc;
minr = left->row < right->row ? left->row : right->row;
minc = left->col < right->col ? left->col : right->col;
maxr = left->row > right->row ? left->row : right->row;
maxc = left->col > right->col ? left->col : right->col;
left = lookat(minr, minc);
right = lookat(maxr, maxc);
if (!(r = find_range((char *)0, 0, left, right)))
return;
if (r->r_next)
r->r_next->r_prev = r->r_prev;
if (r->r_prev)
r->r_prev->r_next = r->r_next;
else
rng_base = r->r_next;
xfree((char *)(r->r_name));
xfree((char *)r);
}
clean_range()
{
register struct range *r;
register struct range *nextr;
r = rng_base;
rng_base = 0;
while (r) {
nextr = r->r_next;
xfree((char *)(r->r_name));
xfree((char *)r);
r = nextr;
}
}
/* Match on name or lmatch, rmatch */
struct range *
find_range(name, len, lmatch, rmatch)
char *name;
int len;
struct ent *lmatch;
struct ent *rmatch;
{
struct range *r;
register char *rp, *np;
register int c;
if (name) {
for (r = rng_base; r; r = r->r_next) {
for (np = name, rp = r->r_name, c = len;
c && *rp && (*rp == *np);
rp++, np++, c--) /* */;
if (!c && !*rp)
return(r);
}
return(0);
}
for (r = rng_base; r; r= r->r_next) {
if ((lmatch == r->r_left.vp) && (rmatch == r->r_right.vp))
return(r);
}
return(0);
}
sync_ranges()
{
register struct range *r;
r = rng_base;
while(r) {
r->r_left.vp = lookat(r->r_left.vp->row, r->r_left.vp->col);
r->r_right.vp = lookat(r->r_right.vp->row, r->r_right.vp->col);
r = r->r_next;
}
}
write_range(f)
FILE *f;
{
register struct range *r;
for (r = rng_base; r; r = r->r_next) {
(void) fprintf(f, "define \"%s\" %s%s%s%d",
r->r_name,
r->r_left.vf & FIX_COL ? "$":"",
coltoa(r->r_left.vp->col),
r->r_left.vf & FIX_ROW ? "$":"",
r->r_left.vp->row);
if (r->r_is_range)
(void) fprintf(f, ":%s%s%s%d\n",
r->r_right.vf & FIX_COL ? "$":"",
coltoa(r->r_right.vp->col),
r->r_right.vf & FIX_ROW ? "$":"",
r->r_right.vp->row);
else
(void) fprintf(f, "\n");
}
}
list_range(f)
FILE *f;
{
register struct range *r;
(void) fprintf(f, "%-30s %s\n\n","Name","Definition");
for (r = rng_base; r; r = r->r_next) {
(void) fprintf(f, "%-30s %s%s%s%d",
r->r_name,
r->r_left.vf & FIX_COL ? "$":"",
coltoa(r->r_left.vp->col),
r->r_left.vf & FIX_ROW ? "$":"",
r->r_left.vp->row);
if (r->r_is_range)
(void) fprintf(f, ":%s%s%s%d\n",
r->r_right.vf & FIX_COL ? "$":"",
coltoa(r->r_right.vp->col),
r->r_right.vf & FIX_ROW ? "$":"",
r->r_right.vp->row);
else
(void) fprintf(f, "\n");
}
}
char *
v_name(row, col)
int row, col;
{
struct ent *v;
struct range *r;
static char buf[20];
v = lookat(row, col);
if (r = find_range((char *)0, 0, v, v)) {
return(r->r_name);
} else {
(void) sprintf(buf, "%s%d", coltoa(col), row);
return(buf);
}
}
char *
r_name(r1, c1, r2, c2)
int r1, c1, r2, c2;
{
struct ent *v1, *v2;
struct range *r;
static char buf[100];
v1 = lookat(r1, c1);
v2 = lookat(r2, c2);
if (r = find_range((char *)0, 0, v1, v2)) {
return(r->r_name);
} else {
(void) sprintf(buf, "%s", v_name(r1, c1));
(void) sprintf(buf+strlen(buf), ":%s", v_name(r2, c2));
return(buf);
}
}
are_ranges()
{
return (rng_base != 0);
}
\SHAR\EOF\
else
echo "will not over write ./range.c"
fi
if [ `wc -c ./range.c | awk '{printf $1}'` -ne 5535 ]
then
echo `wc -c ./range.c | awk '{print "Got " $1 ", Expected " 5535}'`
fi
if `test ! -s ./help.c`
then
echo "Extracting ./help.c"
cat > ./help.c << '\SHAR\EOF\'
/*
* Help functions for sc
* R. Bond, 1988
* $Revision: 6.2 $
*/
#include <curses.h>
#include "sc.h"
char *intro[] = {
" ",
" Overview:",
" ",
" A: This overview",
" B: Options",
" C: Cursor movement commands",
" D: Cell entry and editing commands",
" E: File commands",
" F: Row and column commands",
" G: Range commands",
" H: Miscellaneous commands",
" I: Variable names/Expressions",
" J: Range functions",
" K: Numeric functions",
" L: String functions",
" M: Financial functions",
" N: Time and date functions",
" ",
" Q: Return to main spreadsheet",
0
};
char *options[] = {
" ",
" B: Options",
" ",
" ^To Toggle options. Toggle one option selected by o:",
" ",
" a Recalculate automatically or on ``@'' commands.",
" c Current cell highlighting enable/disable.",
" e External function execution enable/disable.",
" n If enabled, a digit starts a numeric value.",
" t Top line display enable/disable.",
" x Encrypt/decrypt database and listing files.",
" $ Dollar prescale. If enabled, all numeric constants.",
" (not expressions) entered are multipled by 0.01.",
" ",
" S Set options. Options include:",
" ",
" byrows Recalculate in row order. (default)",
" bycols Recalculate in column order.",
" iterations=n Set the number of iterations allowed. (10)",
" tblstyle=xx Set ``T'' output style to:",
" 0 (none), tex, latex, or tbl.",
0
};
char *cursor[] = {
" ",
" C: Cell cursor movement (always OK):",
" ",
" ^N ^P ^B ^F Down, up, back, forward",
" ^Ed Go to end of range. Follow ^E by a direction indicator",
" such as ^P or j.",
" Arrow keys (if the terminal and termcap support them.)",
" ",
" Cell cursor movement if no prompt active:",
" j,k,l,h Down, up, right, left",
" SPACE Forward",
" ^H Back",
" TAB Forward, otherwise starts/ends a range",
" ^ Up to row 0 of the current column.",
" # Down to the last valid row of the current column.",
" 0 Back to column A. Preface with ^U if numeric mode.",
" $ Forward to the last valid column of the current row.",
" b Back then up to the previous valid cell.",
" w Forward then down to the next valid cell.",
" g Go to a cell. Cell name, range name, quoted string,",
" or a number specify which cell.",
0
};
char *cell[] = {
" ",
" D: Cell entry and editing commands:",
" ",
" = Enter a numeric constant or expression.",
" < Enter a left justified string or string expression.",
" \",> Enter a right justified string or string expression.",
" e Edit the current cell's numeric value.",
" E Edit the current cell's string part.",
" x Clear the current cell.",
" c Copy the last marked cell to the current cell.",
" m Mark a cell to be used as the source for ``c''",
" + Increment numeric part",
" - Decrement numeric part",
" ",
" In numeric mode, a decimal digit, ``+'', ``-'', and ``.'' all start",
" a new numeric constant or expression.",
0
};
char *file[] = {
" ",
" E: File commands:",
" ",
" G Get a new database from a file. ",
" M Merge a new file into the current database.",
" P Put the current database into a file.",
" W Write a listing of the current database into a file in",
" a form that matches its appearance on the screen.",
" T Write a listing of the current database to a file, but",
" put delimiters between each pair of fields.",
" Optionally brackets output with control lines for ``tbl'',",
" ``LaTeX'', or ``TeX''.",
" ",
" If encryption mode is set, file I/O will be encrypted/decrypted.",
" ``\"| program\"'' for a file name will pipe (unencrypted) output to",
" a program for Put, Write and Table. If a cell name is used",
" as the file name, the cell's string part will be used as the",
" file name.",
0
};
char *row[] = {
" ",
" F: Row and column commands:",
" ",
" ir, ic Insert a new, empty row (column)",
" ar, ac Append a new copy of the current row (column)",
" dr, dc Delete the current row (column)",
" pr, pc, pm Pull deleted cells back into the spreadsheet",
" Insert rows, columns or merge the cells.",
" vr, vc Remove expressions from the affected rows (columns),",
" leaving only the values.",
" zr, zc Hide (``zap'') the current row (column)",
" sr, sc Show hidden rows (columns)",
" f Set the output format to be used with the values of",
" each cell in this column. Enter field width and",
" number of fractional digits. A preceding count can be",
" used to change more than one column.",
" ",
" Commands which move or copy cells also modify the row and column ",
" references in the new cell expressions. Use ``fixed'' or the",
" ``$'' style cell reference to supress the change.",
0
};
char *range[] = {
" ",
" G: Range commands:",
" ",
" /x Clear a range. ",
" /v Remove the expressions from a range of cells, leaving ",
" just the values.",
" /c Copy a source range to a destination range.",
" /f Fill a range with constant values starting with a given",
" value and increasing by a given increment.",
" /d Assign a name to a cell or a range of cells. Give the",
" the name, surrounded by quotes, and either a cell name such",
" as ``A10'' or a range such as ``a1:b20''.",
" /s Shows the currently defined range names. Pipe output to",
" sort, then to less.",
" /u Use this command to undefine a previously defined range",
" name.",
" ",
" Range operations affect a rectangular region on the screen",
" defined by the upper left and lower right cells in the region.",
" A range is specified by giving the cell names separated by ``:'',",
" such as ``a20:k52''. Another way to refer to a range is to use",
" a name previously defined using ``/d''.",
0
};
char *misc[] = {
" ",
" H: Miscellaneous commands:",
" ",
" Q q ^C Exit from the program.",
" ^G ESC Abort entry of the current command.",
" ? Help",
" ! Shell escape. Enter a command to run. ``!!'' repeats",
" the last command. Just ``!'' starts an interactive shell.",
" ^L Redraw the screen.",
" ^R Redraw the screen. Highlight cells with values but no",
" expressions.",
" ^X Redraw the screen. Show formulas, not values.",
" @ Recalculate the spreadsheet.",
" ^V Type, in the command line, the name of the current cell.",
" ^W Type, in the command line, the current cell's expression.",
" ^A Type, in the command line, the current cell's numeric value.",
" TAB When the character cursor is on the top line TAB can be used",
" to start or stop the display of the default range.",
0
};
char *var[] = {
" ",
" I: Variable names:",
" ",
" K20 Row and column can vary on copies.",
" $K$20 Row and column stay fixed on copies.",
" $K20 Row can vary; column stays fixed on copies.",
" K$20 Row stays fixed; column can vary on copies.",
" fixed holds following expession fixed on copies.",
" Cells and ranges can also be assigned a symbolic name via the",
" range command ``/d''.",
" ",
" Expressions:",
" -e Negation e<=e Less than or equal",
" e+e Addition e=e Equal",
" e-e Subtraction e!=e Not Equal",
" e*e Multiplication e>=e Greater than or equal",
" e/e Division e>e Greater than",
" e%e Modulo e<e Less than",
" e^e Exponentiation e&e Boolean operator AND.",
" ~e Boolean operator NOT e|e Boolean operator OR",
" e?e1:e2 Conditional: If the e is non zero then then e1, otherwise e2.",
" Terms may be constants, variable names, and parenthesized expressions.",
0
};
char *rangef[] = {
" ",
" J: Range functions:",
" ",
" @sum(r) Sum all valid cells in the range.",
" @prod(r) Multiply together all valid cells in the range.",
" @avg(r) Average all valid cells in range.",
" @max(r) Return the maximum value in the range.",
" @min(r) Return the minimum value in the range.",
" See also the numeric versions of max and min.",
" @stddev(r) Return the sample standard deviation of ",
" the cells in the range.",
" @index(e,r) Return the numeric value of the cell at index e",
" into range r.",
" @stindex(e,r) Return the string value of the cell at index e",
" into range r.",
" @lookup(e,r) Search through the range r for a value that",
" matches e. The value returned is that from the",
" next row and the same column as the match, if",
" the range was a single row, or the value from",
" the next column and the same row as the match if",
" the range was a single column.",
0
};
char *numericf[] = {
" ",
" K: Numeric functions:",
" ",
" @atan2(e1,e2) Arc tangent of e1/e2.",
" @ceil(e) Smallest integer not less than e.",
" @eqs(se1,se2) 1 if string expr se1 has the same value as se2.",
" @exp(e) Exponential function of e.",
" @fabs(e) Absolute value of e.",
" @floor(e) The largest integer not greater than e.",
" @hypot(x,y) Sqrt(x*x+y*y).",
" @max(e1,e2,...) The maximum of the values of the e's.",
" @min(e1,e2,...) The minimum of the values of the e's",
" @nval(se,e) The numeric value of a named cell.",
" pi A constant quite close to pi.",
" @pow(e1,e2) e1 raised to the power of e2.",
" @rnd(e) Round e to the nearest integer.",
" @sqrt(e) Square root of e.",
" @ston(se) Convert string expr se to a numeric",
" @ln(e) @log(e) Natural/base 10 logarithm of e.",
" @dtr(e) @rtd(e) Convert degrees to/from radians.",
" @cos(e) @sin(e) @tan(e) Trig functions of radian arguments.",
" @asin(e) @acos(e) @atan(e) Inverse trig function.",
0
};
char *stringf[] = {
" ",
" L: String functions:",
" ",
" # Concatenate strings. For example, the",
" string expression ``A0 # \"zy dog\"'' yields",
" ``the lazy dog'' if A0 is ``the la''.",
" @substr(se,e1,e2) Extract characters e1 through e2 from the",
" string expression se. For example,",
" ``@substr(\"Nice jacket\" 4, 7)'' yields ",
" ``e jac''.",
" @fmt(se,e) Convert a number to a string using sprintf(3).",
" For example, ``@fmt(\"*%6.3f*\",10.5)'' yields",
" ``*10.500*''. Use formats are e, E, f, g, and G.",
" @sval(se,e) Return the string value of a cell selected by name.",
" @ext(se,e) Call an external function (program or",
" script). Convert e to a string and append it",
" to the command line as an argument. @ext yields",
" a string: the first line printed to standard",
" output by the command.",
" String expressions are made up of constant strings (characters",
" surrounded by quotes), variables, and string functions.",
0
};
char *finf[] = {
" ",
" M: Financial functions:",
" ",
" @pmt(e1,e2,e3) @pmt(60000,.01,360) computes the monthly",
" payments for a $60000 mortgage at 12%",
" annual interest (.01 per month) for 30",
" years (360 months).",
" ",
" @fv(e1,e2,e3) @fv(100,.005,36) computes the future value",
" for of 36 monthly payments of $100 at 6%",
" interest (.005 per month). It answers the",
" question: ``How much will I have in 2",
" years if I deposit $100 per month in a",
" savings account paying 6% interest com-",
" pounded monthly?''",
" ",
" @pv(e1,e2,e3) @pv(1000,.015,36) computes the present",
" value of an a ordinary annuity of 36",
" monthly payments of $1000 at 18% annual",
" interest. It answers the question: ``How",
" much can I borrow at 18% for 30 years if I",
" pay $1000 per month?''",
0
};
char *timef[] = {
" ",
" N: Time and date functions:",
" ",
" @now Return the current time encoded as the",
" number of seconds since December 31, 1969,",
" midnight, GMT.",
" ",
" All of the following take an argument expressed in seconds:",
" ",
" @date(e) Convert the time in seconds to a date",
" string 24 characters long in the following",
" form: ``Sun Sep 16 01:03:52 1973''. Note",
" that you can extract pieces of this fixed format",
" string with @substr.",
" @year(e) Return the year. Valid years begin with 1970.",
" @month(e) Return the month: 1 (Jan) to 12 (Dec).",
" @day(e) Return the day of the month: 1 to 31.",
" @hour(e) Return the number of hours since midnight: 0 to 23.",
" @minute(e) Return the number of minutes since the",
" last full hour: 0 to 59.",
" @second(e) Return the number of seconds since the",
" last full minute: 0 to 59.",
0
};
help()
{
int option;
char **ns = intro;
while((option = pscreen(ns)) != 'q' && option != 'Q') {
switch (option) {
case 'a': case 'A': ns = intro; break;
case 'b': case 'B': ns = options; break;
case 'c': case 'C': ns = cursor; break;
case 'd': case 'D': ns = cell; break;
case 'e': case 'E': ns = file; break;
case 'f': case 'F': ns = row; break;
case 'g': case 'G': ns = range; break;
case 'h': case 'H': ns = misc; break;
case 'i': case 'I': ns = var; break;
case 'j': case 'J': ns = rangef; break;
case 'k': case 'K': ns = numericf; break;
case 'l': case 'L': ns = stringf; break;
case 'm': case 'M': ns = finf; break;
case 'n': case 'N': ns = timef; break;
default: ns = intro; break;
}
}
FullUpdate++;
(void) move(1,0);
(void) clrtobot();
}
pscreen(screen)
char *screen[];
{
int line;
int dbline;
(void) move(1,0);
(void) clrtobot();
dbline = 1;
for (line = 0; screen[line]; line++) {
(void) move(dbline++, 4);
(void) addstr (screen[line]);
(void) clrtoeol();
}
(void) move(0,0);
(void) printw("Which Screen? [a-n, q]");
(void) clrtoeol();
(void) refresh();
return(nmgetch());
}
\SHAR\EOF\
else
echo "will not over write ./help.c"
fi
if [ `wc -c ./help.c | awk '{printf $1}'` -ne 15538 ]
then
echo `wc -c ./help.c | awk '{print "Got " $1 ", Expected " 15538}'`
fi
if `test ! -s ./eres.sed`
then
echo "Extracting ./eres.sed"
cat > ./eres.sed << '\SHAR\EOF\'
/%token.*K_/!d
/%token.*K_\(.*\)/s// "\1", K_\1,/
\SHAR\EOF\
else
echo "will not over write ./eres.sed"
fi
if [ `wc -c ./eres.sed | awk '{printf $1}'` -ne 50 ]
then
echo `wc -c ./eres.sed | awk '{print "Got " $1 ", Expected " 50}'`
fi
if `test ! -s ./sres.sed`
then
echo "Extracting ./sres.sed"
cat > ./sres.sed << '\SHAR\EOF\'
/%token.*S_/!d
/%token.*S_\(.*\)/s// "\1", S_\1,/
\SHAR\EOF\
else
echo "will not over write ./sres.sed"
fi
if [ `wc -c ./sres.sed | awk '{printf $1}'` -ne 50 ]
then
echo `wc -c ./sres.sed | awk '{print "Got " $1 ", Expected " 50}'`
fi
if `test ! -s ./Makefile`
then
echo "Extracting ./Makefile"
cat > ./Makefile << '\SHAR\EOF\'
# Specify the name of the program.
# All documentation and installation keys on this value.
#
name=sc
NAME=SC
# This is where the install step puts it.
EXDIR=/h/rgb/bin/sym
# This is where the man page goes.
MANDIR=/usr/man/man1
# Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up
#SIMPLE=-DSIMPLE
# Set INTERNATIONAL if you need 8 bit characters. You should
# not set this if you are running 5.3.0. I think it is OK in 5.3.1.
#INTERNATIONAL=-DINTERNATIONAL
# Set SIGVOID if signal routines are type void. System 5.3, VMS and ANSI C
# Compliant systems use this. Most BSD systems do not.
#SIGVOID=-DSIGVOID
# This is the name of a pager like "more" If the line is commented out
# then "more" will be used. "pg" may be appropriate for SYSV
PAGER=-DDFLT_PAGER=\"less\"
# Use this for system V.2
# CFLAGS= -O -DSYSV2 $(SIGVOID)
# LDFLAGS=
# LIB=-lm -lcurses -lPW
# Use this for system V.3
CFLAGS= -O -DSYSV3 -DSIGVOID
LDFLAGS=
LIB=-lm -lcurses -lPW
# Use this for BSD 4.2
#CFLAGS= -O -DBSD42 $(SIGVOID)
#LDFLAGS=
#LIB=-lm -lcurses -ltermcap
# Use this for BSD 4.3
#CFLAGS= -O -DBSD43 $(SIGVOID)
#LDFLAGS=
#LIB=-lm -lcurses -ltermcap
# Use this for system III (XENIX)
#CFLAGS= -O -DSYSIII $(SIGVOID)
#LDFLAGS= -i
#LIB=-lm -lcurses -ltermcap
# Use this for VENIX
#CFLAGS= -DVENIX -DBSD42 -DV7 $(SIGVOID)
#LDFLAGS= -z -i
#LIB=-lm -lcurses -ltermcap
# All of the source files
SRC=sc.h sc.c lex.c gram.y interp.c crypt.c xmalloc.c cmds.c range.c help.c \
eres.sed sres.sed Makefile psc.c
# The objects
OBJS=sc.o interp.o cmds.o crypt.o xmalloc.o range.o help.o lex.o gram.o
# The documents in the Archive
DOCS=README CHANGES sc.doc psc.doc tutorial.sc VMS_NOTES BSD_BUGS
$(name): $(OBJS)
$(CC) ${CFLAGS} ${LDFLAGS} ${OBJS} ${LIB} -o $(name)
diff_to_sc: diff_to_sc.c
$(CC) ${CFLAGS} -o dtv diff_to_sc.c
p$(name): psc.c
$(CC) ${CFLAGS} -o p$(name) psc.c
cp p$(name) $(EXDIR)/p$(name)
lex.o: sc.h y.tab.h gram.o
$(CC) ${CFLAGS} ${SIMPLE} ${INTERNATIONAL} -c lex.c
sc.o: sc.h sc.c
$(CC) ${CFLAGS} ${INTERNATIONAL} $(PAGER) -c sc.c
interp.o: interp.c sc.h
gram.o: sc.h y.tab.h
cmds.o: cmds.c sc.h
crypt.o: crypt.c sc.h
range.o: range.c sc.h
help.o: help.c sc.h
y.tab.h: gram.y
gram.o: sc.h y.tab.h gram.c
$(CC) ${CFLAGS} -c gram.c
sed<gram.y >experres.h -f eres.sed;sed < gram.y > statres.h -f sres.sed
gram.c: gram.y
$(YACC) -d gram.y; mv y.tab.c gram.c
clean:
rm -f *.o *res.h y.tab.h $(name) p$(name) debug core gram.c $(name).1 \
$(name).man p$(name).man p$(name).1 y.output
shar: ${SRC} ${DOCS}
shar -c -m 64000 -f shar ${DOCS} ${SRC}
lint: sc.h sc.c lex.c gram.c interp.c cmds.c crypt.c
lint ${CFLAGS} ${SIMPLE} sc.c lex.c gram.c interp.c cmds.c crypt.c \
range.c xmalloc.c help.c -lcurses -lm
inspect: sc.h sc.c lex.c gram.c interp.c cmds.c crypt.c
/bruces/ianj/bin/i386/inspect -abv -t 8 sc.c lex.c gram.c interp.c \
cmds.c crypt.c range.c xmalloc.c help.c
print: sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c
prc sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c | lpr
$(name).1: sc.doc
sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g sc.doc > $(name).1
$(name).man: $(name).1
nroff -man $(name).1 > $(name).man
p$(name).1: psc.doc
sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g psc.doc > p$(name).1
p$(name).man: p$(name).1
nroff -man p$(name).1 > p$(name).man
install: $(EXDIR)/$(name)
inst-man: $(MANDIR)/$(name).1
$(EXDIR)/$(name): $(name)
-mv $(EXDIR)/$(name) $(EXDIR)/$(name).old
strip $(name)
cp $(name) $(EXDIR)
$(MANDIR)/$(name).1: $(name).1
cp $(name).1 $(MANDIR)
diffs: ${SRC}
for i in ${SRC} ${DOCS} ;\
do \
rcsdiff -c -r5.1 $$i ;\
done
\SHAR\EOF\
else
echo "will not over write ./Makefile"
fi
if [ `wc -c ./Makefile | awk '{printf $1}'` -ne 3645 ]
then
echo `wc -c ./Makefile | awk '{print "Got " $1 ", Expected " 3645}'`
fi
if `test ! -s ./psc.c`
then
echo "Extracting ./psc.c"
cat > ./psc.c << '\SHAR\EOF\'
/* Sc parse routine
*
* usage psc options
* options:
* -L Left justify strings. Default is right justify.
* -r Assemble data into rows first, not columns.
* -R n Increment by n between rows
* -C n Increment by n between columns
* -n n Length of the row (column) should be n.
* -s v Top left location in the spreadsheet should be v; eg, k5
* -d c Use c as the delimiter between the fields.
* -k Keep all delimiters - Default is strip multiple delimiters to 1.
*
* Author: Robert Bond
* $Revision: 6.1 $
*/
#include <ctype.h>
#include <stdio.h>
#include "sc.h"
#define END 0
#define NUM 1
#define ALPHA 2
#define SPACE 3
#define EOL 4
extern char *optarg;
extern int optind;
char *coltoa();
char *progname;
#ifdef SYSV3
extern void exit();
#else
extern int exit();
#endif
int colfirst = 0;
int r0 = 0;
int c0 = 0;
int rinc = 1;
int cinc = 1;
int leftadj = 0;
int len = 20000;
char delim1 = ' ';
char delim2 = '\t';
int strip_delim = 1;
int fwidth[MAXCOLS];
int precision[MAXCOLS];
char token[1000];
main(argc, argv)
int argc;
char **argv;
{
int curlen;
int curcol, coff;
int currow, roff;
int first;
int c;
register effr, effc;
int i,j;
register char *p;
progname = argv[0];
while ((c = getopt(argc, argv, "rLks:R:C:n:d:")) != EOF) {
switch(c) {
case 'r':
colfirst = 1;
break;
case 'L':
leftadj = 1;
break;
case 's':
c0 = getcol(optarg);
r0 = getrow(optarg);
break;
case 'R':
rinc = atoi(optarg);
break;
case 'C':
cinc = atoi(optarg);
break;
case 'n':
len = atoi(optarg);
break;
case 'd':
delim1 = optarg[0];
delim2 = 0;
break;
case 'k':
strip_delim = 0;
break;
default:
(void) fprintf(stderr,"Usage: %s [-rkL] [-s v] [-R i] [-C i] [-n i] [-d c]\n", progname);
exit(1);
}
}
if (optind < argc) {
(void) fprintf(stderr,"Usage: %s [-rL] [-s v] [-R i] [-C i] [-n i] [-d c]\n", progname);
exit(1);
}
curlen = 0;
curcol = c0; coff = 0;
currow = r0; roff = 0;
first = 1;
while(1) {
effr = currow+roff;
effc = curcol+coff;
switch(scan()) {
case END:
for (i = 0; i<MAXCOLS; i++) {
if (precision[i])
(void) printf("format %s %d %d\n", coltoa(i), precision[i]+1,
fwidth[i]);
}
exit(0);
case NUM:
first = 0;
(void) printf("let %s%d = %s\n", coltoa(effc), effr, token);
if (effc > MAXCOLS-1)
(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
else {
i = 0;
j = 0;
p = token;
while (*p && *p != '.') {
p++; i++;
}
if (*p) {
p++; i++;
}
while (*p) {
p++; i++; j++;
}
if (precision[effc] < i)
precision[effc] = i;
if (fwidth[effc] < j)
fwidth[effc] = j;
}
break;
case ALPHA:
first = 0;
if (leftadj)
(void) printf("leftstring %s%d = \"%s\"\n", coltoa(effc),effr,token);
else
(void) printf("rightstring %s%d = \"%s\"\n",coltoa(effc),effr,token);
if (effc > MAXCOLS-1)
(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
else {
i = strlen(token);
if (i > precision[effc])
precision[effc] = i;
}
break;
case SPACE:
if (first && strip_delim)
break;
if (colfirst)
roff++;
else
coff++;
break;
case EOL:
curlen++;
roff = 0;
coff = 0;
first = 1;
if (colfirst) {
if (curlen >= len) {
curcol = c0;
currow += rinc;
curlen = 0;
} else {
curcol += cinc;
}
} else {
if (curlen >= len) {
currow = r0;
curcol += cinc;
curlen = 0;
} else {
currow += rinc;
}
}
break;
}
}
}
scan()
{
register int c;
register char *p;
p = token;
c = getchar();
if (c == EOF)
return(END);
if (c == '\n')
return(EOL);
if (c == delim1 || c == delim2) {
if (strip_delim) {
while ((c = getchar()) && (c == delim1 || c == delim2))
;
(void)ungetc(c, stdin);
}
return(SPACE);
}
if (c == '\"') {
while ((c = getchar()) && c != '\"' && c != '\n' && c != EOF)
*p++ = c;
if (c != '\"')
(void)ungetc(c, stdin);
*p = 0;
return(ALPHA);
}
while (c != delim1 && c != delim2 && c!= '\n' && c != EOF) {
*p++ = c;
c = getchar();
}
*p = 0;
(void)ungetc(c, stdin);
p = token;
c = *p;
if (isdigit(c) || c == '.' || c == '-' || c == '+') {
while(isdigit(c) || c == '.' || c == '-' || c == '+' || c == 'e'
|| c == 'E') {
c = *p++;
}
if (c == 0)
return(NUM);
else
return(ALPHA);
}
return(ALPHA);
}
getcol(p)
char *p;
{
register col;
if (!p)
return(0);
while(*p && !isalpha(*p))
p++;
if (!*p)
return(0);
col = ((*p & 0137) - 'A');
if (isalpha(*++p))
col = (col + 1)*26 + ((*p & 0137) - 'A');
return(col);
}
getrow(p)
char *p;
{
int row;
if (!p)
return(0);
while(*p && !isdigit(*p))
p++;
if (!*p)
return(0);
if (sscanf(p, "%d", &row) != 1)
return(0);
return(row);
}
char *
coltoa(col)
int col;
{
static char rname[3];
register char *p = rname;
if (col < 0 || col > 25*26)
(void) fprintf(stderr,"coltoa: invalid col: %d", col);
if (col > 25) {
*p++ = col/26 + 'A' - 1;
col %= 26;
}
*p++ = col+'A';
*p = 0;
return(rname);
}
\SHAR\EOF\
else
echo "will not over write ./psc.c"
fi
if [ `wc -c ./psc.c | awk '{printf $1}'` -ne 5408 ]
then
echo `wc -c ./psc.c | awk '{print "Got " $1 ", Expected " 5408}'`
fi
echo "Finished archive 4 of 4"
# if you want to concatenate archives, remove anything after this line
exit
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list