v20i035: sc - The SC Spreadsheet, release 6.16, Part01/07
Jeff Buhrt
buhrt at prslnk.uucp
Thu Jun 6 03:26:24 AEST 1991
Submitted-by: Jeff Buhrt <prslnk!buhrt at cs.indiana.edu>
Posting-number: Volume 20, Issue 35
Archive-name: sc/part01
This is Sc 6.16, a public domain spreadsheet for Unix.
It has been tested on most flavors of Unix, an Amiga Sc6.16 is being
worked on.
See the README for installation instructions (configure Makefile and
make install), CHANGES for what has happened since Sc6.1
(and Sc6.8 that was on comp.sources.unix).
Some high points new since Sc6.8 are: scqref a quick reference card,
many new features, bug fixes, per cell formatting,
a way of relative addressing cells, many more things.
-Jeff Buhrt
iuvax!prslnk!buhrt
sequent!sawmill!prslnk!buhrt
812-275-0750 work
----
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# Contents: README cmds.c sc.h
# Wrapped by kent at sparky on Wed Jun 5 09:22:19 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 1 (of 7)."'
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3689 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is a much modified version of the public domain spread sheet sc,
Xposted several years ago by Mark Weiser as vc, originally by James Gosling.
X
XCHANGES lists the changes since 6.1 to 6.15.
XCurrent maintainer: {sequent, tippy.cs.purdue.edu}!sawmill!buhrt (Jeff Buhrt)
X
XWhen you get it built, try "sc tutorial.sc" for a simple introduction
Xto the basic commands.
X
XTo print a quick reference card, type the command:
X scqref | [your_printer_commmand]
X
XIf you have the command 'file' that uses /etc/magic add the line:
X38 string Spreadsheet sc file
X
XPsc formats ascii files for use in the spread sheet. If you don't have
Xgetopts, there is a public domain version by Henry Spencer hidden away in
Xthe VMS_NOTES file.
X
XI have modified the Makefile to make it easy for you to call the
Xprogram what you want. Just change "name=sc" and "NAME=SC" to
X"name=myfavoritename" and "NAME=MYFAVORITENAME" and try "make
Xmyfavoritename".
X
XSimilarly, you can make the documentation with "make myfavoritename.man".
X"make install" will make and install the code in EXDIR. The
Xinstallation steps and documentation all key off of the name. The
Xmakefile even changes the name in the nroffable man page. If you don't
Xhave nroff, you will have to change sc.man yourself.
X
XThis release has been tested against a Sequent S81 running DYNIX 3.0.17
X(BSD 4.2):cc, atscc, gcc, AT&T SysV 3.2.2:cc, gcc, ESIX SysV 3.2 Rev D:cc, gcc.
XJust check the Makefile for the system flags. I have heard
Xreports of lots of other machines that work. If you have problems with
Xlex.c, and don't care about arrow keys, define SIMPLE (-DSIMPLE in the
Xmakefile). SIMPLE causes the arrow keys to not be used.
X
XIf you have problems with your yacc saying: too many terminals ...127...
XComment out the gram.c and y.tab.c code in Makefile and uncomment the
Xsection that uses mygram.c and myy.tab.h.
X
XGuidelines for Hackers:
X
XIf you want to send changes you have made to SC, please feel free to do
Xso. If they work :-) and seem worthwhile, I'll put them in. Please
Xrefrain from wholesale "style" or "cleanup" changes. It is easy to add
Xyour changes but it makes it hard to merge in the next guy's stuff if
Xhe used the release as a base. Leave my $Revision: identifiers alone-
Xthey help me track what you used as a base. If you check the code into
Xrcs, delete the "$"s on the Revison lines before you do.
X
XYou may not like 4 space indenting and curly braces on the "if" line, but
Xyour code will look like that before it leaves my hands so you may as well
Xabide by the style in the code when you make your changes. I have also been
Xknown to break things trying to make them look "right". If you do string
Xfunctions, please, PLEASE pay attention to null pointers, use xmalloc,
Xxrealloc, and xfree; and xfree those arguments. And don't forget to
Xdocument your changes in both help.c and sc.doc.
X
XDisclaimer:
X
XStarting 4/4/90: (I will be maintaining Sc for a while at least,
X Robert Bond has been very busy lately)
XSc is not a product of Grauel Enterprises, Inc. It is supplied as
Xis with no warranty, express or implied, as a service to Usenet readers.
XIt is not copyrighted, either. Have at it.
X
XArchives:
X1) (FTP) jpd at usl.edu James Dugal
X pc.usl.edu
X
X2) (UUCP) marc at dumbcat.sf.ca.us (Marco S Hyman)
X dumbcat Any ACU 9600 14157850194 "" \d\r in:--in: nuucp word: guest
X dumbcat Any ACU 2400 14157850194 "" \d\r in:-BREAK-in: nuucp word: guest
X dumbcat Any ACU 1200 14157850194 "" \d\r in:-BREAK-in:-BREAK-in: nuucp word: guest
X Note: dumbcat speaks 9600 at V.32 -- sorry, this is not a Telebit modem.
X (Grab dumbcat!~/INDEX for a complete list)
X
X Jeff Buhrt
X Grauel Enterprises, Inc.
X sequent!sawmill!buhrt
X
END_OF_FILE
if test 3689 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'cmds.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cmds.c'\"
else
echo shar: Extracting \"'cmds.c'\" \(36608 characters\)
sed "s/^X//" >'cmds.c' <<'END_OF_FILE'
X/* SC A Spreadsheet Calculator
X * Command routines
X *
X * original by James Gosling, September 1982
X * modifications by Mark Weiser and Bruce Israel,
X * University of Maryland
X *
X * More mods Robert Bond, 12/86
X *
X * $Revision: 6.16 $
X */
X
X#include <sys/types.h>
X#if defined(BSD42) || defined(BSD43)
X#include <strings.h>
X#else
X#ifndef SYSIII
X#include <string.h>
X#endif
X#endif
X
X#include <curses.h>
X#if defined(BSD42) || defined(BSD43)
X#include <sys/file.h>
X#else
X#include <fcntl.h>
X#endif
X#include "sc.h"
X#include <signal.h>
X#include <errno.h>
X
X#ifdef SYSV3
Xextern void exit();
X#else
Xextern int exit();
X#endif
X
Xvoid openrow();
Xvoid syncref();
Xvoid unspecial();
X
Xextern int errno;
X
X/* a linked list of free [struct ent]'s, uses .next as the pointer */
Xextern struct ent *freeents;
X
X/* a linked list of free [struct enodes]'s, uses .e.o.left as the pointer */
Xextern struct enode *freeenodes;
X
X#define DEFCOLDELIM ':'
X
X/* copy the current row (currow) and place the cursor in the new row */
Xvoid
Xduprow()
X{
X if (currow >= maxrows - 1 || maxrow >= maxrows - 1) {
X if (!growtbl(GROWROW, 0, 0))
X return;
X }
X modflg++;
X currow++;
X openrow (currow);
X for (curcol = 0; curcol <= maxcol; curcol++) {
X register struct ent *p = *ATBL(tbl, currow - 1, curcol);
X if (p) {
X register struct ent *n;
X n = lookat (currow, curcol);
X (void)copyent ( n, p, 1, 0);
X }
X }
X for (curcol = 0; curcol <= maxcol; curcol++) {
X register struct ent *p = *ATBL(tbl, currow, curcol);
X if (p && (p -> flags & is_valid) && !p -> expr)
X break;
X }
X if (curcol > maxcol)
X curcol = 0;
X}
X
X/* copy the current column (curcol) and place the cursor in the new column */
Xvoid
Xdupcol()
X{
X if (curcol >= maxcols - 1 || maxcol >= maxcols - 1) {
X if (!growtbl(GROWCOL, 0, 0))
X return;
X }
X modflg++;
X curcol++;
X opencol (curcol, 1);
X for (currow = 0; currow <= maxrow; currow++) {
X register struct ent *p = *ATBL(tbl, currow, curcol - 1);
X if (p) {
X register struct ent *n;
X n = lookat (currow, curcol);
X copyent ( n, p, 0, 1);
X }
X }
X for (currow = 0; currow <= maxrow; currow++) {
X register struct ent *p = *ATBL(tbl, currow, curcol);
X if (p && (p -> flags & is_valid) && !p -> expr)
X break;
X }
X if (currow > maxrow)
X currow = 0;
X}
X
X/* insert 'arg' rows before currow */
Xvoid
Xinsertrow(arg)
Xregister int arg;
X{
X while (--arg>=0) openrow (currow);
X}
X
X/* delete 'arg' rows starting at currow (deletes from currow downward) */
Xvoid
Xdeleterow(arg)
Xregister int arg;
X{
X flush_saved();
X erase_area(currow, 0, currow + arg - 1, maxcol);
X currow += arg;
X while (--arg>=0) closerow (--currow);
X sync_refs();
X}
X
Xvoid
Xerase_area(sr, sc, er, ec)
Xint sr, sc, er, ec;
X{
X register int r, c;
X register struct ent **pp;
X
X if (sr > er) {
X r = sr; sr = er; er= r;
X }
X
X if (sc > ec) {
X c = sc; sc = ec; ec= c;
X }
X
X if (sr < 0)
X sr = 0;
X if (sc < 0)
X sc = 0;
X checkbounds(&er, &ec);
X
X for (r = sr; r <= er; r++) {
X for (c = sc; c <= ec; c++) {
X pp = ATBL(tbl, r, c);
X if (*pp) {
X free_ent(*pp);
X *pp = (struct ent *)0;
X }
X }
X }
X}
X
X/*
X * deletes the expression associated w/ a cell and turns it into a constant
X * containing whatever was on the screen
X */
Xvoid
Xvalueize_area(sr, sc, er, ec)
Xint sr, sc, er, ec;
X{
X register int r, c;
X register struct ent *p;
X
X if (sr > er) {
X r = sr; sr = er; er= r;
X }
X
X if (sc > ec) {
X c = sc; sc = ec; ec= c;
X }
X
X if (sr < 0)
X sr = 0;
X if (sc < 0)
X sc = 0;
X checkbounds(&er, &ec);
X
X for (r = sr; r <= er; r++) {
X for (c = sc; c <= ec; c++) {
X p = *ATBL(tbl, r, c);
X if (p && p->expr) {
X efree(p->expr);
X p->expr = (struct enode *)0;
X p->flags &= ~is_strexpr;
X }
X }
X }
X
X}
X
Xvoid
Xpullcells(to_insert)
Xint to_insert;
X{
X register struct ent *p, *n;
X register int deltar, deltac;
X int minrow, mincol;
X int mxrow, mxcol;
X int numrows, numcols;
X
X if (! to_fix)
X {
X error ("No data to pull");
X return;
X }
X
X minrow = maxrows;
X mincol = maxcols;
X mxrow = 0;
X mxcol = 0;
X
X for (p = to_fix; p; p = p->next) {
X if (p->row < minrow)
X minrow = p->row;
X if (p->row > mxrow)
X mxrow = p->row;
X if (p->col < mincol)
X mincol = p->col;
X if (p->col > mxcol)
X mxcol = p->col;
X }
X
X numrows = mxrow - minrow + 1;
X numcols = mxcol - mincol + 1;
X deltar = currow - minrow;
X deltac = curcol - mincol;
X
X if (to_insert == 'r') {
X insertrow(numrows);
X deltac = 0;
X } else if (to_insert == 'c') {
X opencol(curcol, numcols);
X deltar = 0;
X }
X
X FullUpdate++;
X modflg++;
X
X for (p = to_fix; p; p = p->next) {
X n = lookat (p->row + deltar, p->col + deltac);
X (void) clearent(n);
X copyent( n, p, deltar, deltac);
X n -> flags = p -> flags & ~is_deleted;
X }
X}
X
Xvoid
Xcolshow_op()
X{
X register int i,j;
X for (i=0; i<maxcols; i++)
X if (col_hidden[i])
X break;
X for(j=i; j<maxcols; j++)
X if (!col_hidden[j])
X break;
X j--;
X if (i>=maxcols)
X error ("No hidden columns to show");
X else {
X (void) sprintf(line,"show %s:", coltoa(i));
X (void) sprintf(line + strlen(line),"%s",coltoa(j));
X linelim = strlen (line);
X }
X}
X
Xvoid
Xrowshow_op()
X{
X register int i,j;
X for (i=0; i<maxrows; i++)
X if (row_hidden[i])
X break;
X for(j=i; j<maxrows; j++)
X if (!row_hidden[j]) {
X break;
X }
X j--;
X
X if (i>=maxrows)
X error ("No hidden rows to show");
X else {
X (void) sprintf(line,"show %d:%d", i, j);
X linelim = strlen (line);
X }
X}
X
X/*
X * Given a row/column command letter, emit a small menu, then read a qualifier
X * character for a row/column command and convert it to 'r' (row), 'c'
X * (column), or 0 (unknown). If ch is 'p', an extra qualifier 'm' is allowed.
X */
X
Xint
Xget_rcqual (ch)
X int ch;
X{
X error ("%sow/column: r: row c: column%s",
X
X (ch == 'i') ? "Insert r" :
X (ch == 'a') ? "Append r" :
X (ch == 'd') ? "Delete r" :
X (ch == 'p') ? "Pull r" :
X (ch == 'v') ? "Values r" :
X (ch == 'z') ? "Zap r" :
X (ch == 's') ? "Show r" : "R",
X
X (ch == 'p') ? " m: merge" : "");
X
X (void) refresh();
X
X switch (nmgetch())
X {
X case 'r':
X case 'l':
X case 'h':
X case ctl('f'):
X case ctl('b'): return ('r');
X
X case 'c':
X case 'j':
X case 'k':
X case ctl('p'):
X case ctl('n'): return ('c');
X
X case 'm': return ((ch == 'p') ? 'm' : 0);
X
X case ESC:
X case ctl('g'): return (ESC);
X
X default: return (0);
X }
X /*NOTREACHED*/
X}
X
Xvoid
Xopenrow (rs)
Xint rs;
X{
X register r, c;
X struct ent **tmprow, **pp;
X
X if (rs > maxrow) maxrow = rs;
X if (maxrow >= maxrows - 1 || rs > maxrows - 1) {
X if (!growtbl(GROWROW, rs, 0))
X return;
X }
X /*
X * save the last active row+1, shift the rows downward, put the last
X * row in place of the first
X */
X tmprow = tbl[++maxrow];
X for (r = maxrow; r > rs; r--) {
X row_hidden[r] = row_hidden[r-1];
X tbl[r] = tbl[r-1];
X pp = ATBL(tbl, r, 0);
X for (c = 0; c < maxcols; c++, pp++)
X if (*pp)
X (*pp)->row = r;
X }
X tbl[r] = tmprow; /* the last row was never used.... */
X FullUpdate++;
X modflg++;
X}
X
X/* delete row r */
Xvoid
Xcloserow (r)
Xregister r;
X{
X register struct ent **pp;
X register c;
X struct ent **tmprow;
X
X if (r > maxrow) return;
X
X /* save the row and empty it out */
X tmprow = tbl[r];
X pp = ATBL(tbl, r, 0);
X for (c=maxcol+1; --c>=0; pp++) {
X if (*pp)
X { free_ent(*pp);
X *pp = (struct ent *)0;
X }
X }
X
X /* move the rows, put the deleted, but now empty, row at the end */
X for (; r < maxrows - 1; r++) {
X row_hidden[r] = row_hidden[r+1];
X tbl[r] = tbl[r+1];
X pp = ATBL(tbl, r, 0);
X for (c = 0; c < maxcols; c++, pp++)
X if (*pp)
X (*pp)->row = r;
X }
X tbl[r] = tmprow;
X
X maxrow--;
X FullUpdate++;
X modflg++;
X}
X
Xvoid
Xopencol (cs, numcol)
Xint cs;
Xint numcol;
X{
X register r;
X register struct ent **pp;
X register c;
X register lim = maxcol-cs+1;
X int i;
X
X if (cs > maxcol)
X maxcol = cs;
X maxcol += numcol;
X
X if ((maxcol >= maxcols - 1) && !growtbl(GROWCOL, 0, maxcol))
X return;
X
X for (i = maxcol; i > cs; i--) {
X fwidth[i] = fwidth[i-numcol];
X precision[i] = precision[i-numcol];
X realfmt[i] = realfmt[i-numcol];
X col_hidden[i] = col_hidden[i-numcol];
X }
X for (c = cs; c - cs < numcol; c++)
X { fwidth[c] = DEFWIDTH;
X precision[c] = DEFPREC;
X realfmt[c] = DEFREFMT;
X }
X
X for (r=0; r<=maxrow; r++) {
X pp = ATBL(tbl, r, maxcol);
X for (c=lim; --c>=0; pp--)
X if (pp[0] = pp[-numcol])
X pp[0]->col += numcol;
X
X pp = ATBL(tbl, r, cs);
X for (c = cs; c - cs < numcol; c++, pp++)
X *pp = (struct ent *)0;
X }
X FullUpdate++;
X modflg++;
X}
X
Xvoid
Xclosecol (cs, numcol)
Xint cs;
Xint numcol;
X{
X register r;
X register struct ent **pp;
X register struct ent *q;
X register c;
X register lim = maxcol-cs;
X int i;
X char buf[50];
X
X if (lim - numcol < -1)
X { (void) sprintf(buf, "Can't delete %d column%s %d columns left", numcol,
X (numcol > 1 ? "s," : ","), lim+1);
X error(buf);
X return;
X }
X flush_saved();
X erase_area(0, curcol, maxrow, curcol + numcol - 1);
X sync_refs();
X
X /* clear then copy the block left */
X lim = maxcols - numcol - 1;
X for (r=0; r<=maxrow; r++) {
X for (c = cs; c - cs < numcol; c++)
X if (q = *ATBL(tbl, r, c))
X free_ent(q);
X
X pp = ATBL(tbl, r, cs);
X for (c=cs; c <= lim; c++, pp++)
X { if (c > lim)
X *pp = (struct ent *)0;
X else
X if (pp[0] = pp[numcol])
X pp[0]->col -= numcol;
X }
X
X c = numcol;
X for (; --c >= 0; pp++)
X *pp = (struct ent *)0;
X }
X
X for (i = cs; i < maxcols - numcol - 1; i++) {
X fwidth[i] = fwidth[i+numcol];
X precision[i] = precision[i+numcol];
X realfmt[i] = realfmt[i+numcol];
X col_hidden[i] = col_hidden[i+numcol];
X }
X for (; i < maxcols - 1; i++) {
X fwidth[i] = DEFWIDTH;
X precision[i] = DEFPREC;
X realfmt[i] = DEFREFMT;
X col_hidden[i] = 0;
X }
X
X maxcol -= numcol;
X FullUpdate++;
X modflg++;
X}
X
Xvoid
Xdoend(rowinc, colinc)
Xint rowinc, colinc;
X{
X register struct ent *p;
X int r, c;
X
X if (VALID_CELL(p, currow, curcol)) {
X r = currow + rowinc;
X c = curcol + colinc;
X if (r >= 0 && r < maxrows &&
X c >= 0 && c < maxcols &&
X !VALID_CELL(p, r, c)) {
X currow = r;
X curcol = c;
X }
X }
X
X if (!VALID_CELL(p, currow, curcol)) {
X switch (rowinc) {
X case -1:
X while (!VALID_CELL(p, currow, curcol) && currow > 0)
X currow--;
X break;
X case 1:
X while (!VALID_CELL(p, currow, curcol) && currow < maxrows-1)
X currow++;
X break;
X case 0:
X switch (colinc) {
X case -1:
X while (!VALID_CELL(p, currow, curcol) && curcol > 0)
X curcol--;
X break;
X case 1:
X while (!VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
X curcol++;
X break;
X }
X break;
X }
X
X error (""); /* clear line */
X return;
X }
X
X switch (rowinc) {
X case -1:
X while (VALID_CELL(p, currow, curcol) && currow > 0)
X currow--;
X break;
X case 1:
X while (VALID_CELL(p, currow, curcol) && currow < maxrows-1)
X currow++;
X break;
X case 0:
X switch (colinc) {
X case -1:
X while (VALID_CELL(p, currow, curcol) && curcol > 0)
X curcol--;
X break;
X case 1:
X while (VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
X curcol++;
X break;
X }
X break;
X }
X if (!VALID_CELL(p, currow, curcol)) {
X currow -= rowinc;
X curcol -= colinc;
X }
X}
X
X/* Modified 9/17/90 THA to handle more formats */
Xvoid
Xdoformat(c1,c2,w,p,r)
Xint c1,c2,w,p,r;
X{
X register int i;
X int crows = 0;
X int ccols = c2;
X
X if (c1 >= maxcols && !growtbl(GROWCOL, 0, c1)) c1 = maxcols-1 ;
X if (c2 >= maxcols && !growtbl(GROWCOL, 0, c2)) c2 = maxcols-1 ;
X
X if (w > COLS - RESCOL - 2) {
X error("Format too large - Maximum = %d", COLS - RESCOL - 2);
X w = COLS-RESCOL-2;
X }
X
X if (p > w) {
X error("Precision too large");
X p = w;
X }
X /* format statement may record format of an as yet unused column
X * which causes it to run off the end of fwidth and precision --
X * causing a bus error later
X */
X checkbounds(&crows, &ccols);
X if (ccols < c2) {
X error("Format statement failed to create implied column %d", c2);
X return;
X }
X
X for(i = c1; i<=c2; i++)
X fwidth[i] = w, precision[i] = p, realfmt[i] = r;
X
X FullUpdate++;
X modflg++;
X}
X
Xvoid
Xprint_options(f)
XFILE *f;
X{
X if(
X autocalc &&
X propagation == 10 &&
X calc_order == BYROWS &&
X !numeric &&
X prescale == 1.0 &&
X !extfunc &&
X showcell &&
X showtop &&
X tbl_style == 0
X )
X return; /* No reason to do this */
X
X (void) fprintf(f, "set");
X if(!autocalc)
X (void) fprintf(f," !autocalc");
X if(propagation != 10)
X (void) fprintf(f, " iterations = %d", propagation);
X if(calc_order != BYROWS )
X (void) fprintf(f, " bycols");
X if (numeric)
X (void) fprintf(f, " numeric");
X if (prescale != 1.0)
X (void) fprintf(f, " prescale");
X if (extfunc)
X (void) fprintf(f, " extfun");
X if (!showcell)
X (void) fprintf(f, " !cellcur");
X if (!showtop)
X (void) fprintf(f, " !toprow");
X if (tbl_style)
X (void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" :
X tbl_style == LATEX ? "latex" :
X tbl_style == SLATEX ? "slatex" :
X tbl_style == TEX ? "tex" : "0" );
X (void) fprintf(f, "\n");
X}
X
Xvoid
Xprintfile (fname, r0, c0, rn, cn)
Xchar *fname;
Xint r0, c0, rn, cn;
X{
X FILE *f;
X static char *pline = NULL; /* only malloc once, malloc is slow */
X static unsigned fbufs_allocated = 0;
X int plinelim;
X int pid;
X int fieldlen, nextcol;
X register row, col;
X register struct ent **pp;
X char *xmalloc();
X char *xrealloc();
X
X if ((strcmp(fname, curfile) == 0) &&
X !yn_ask("Confirm that you want to destroy the data base: (y,n)")) {
X return;
X }
X
X if (!pline && (pline = xmalloc((unsigned)(FBUFLEN *
X ++fbufs_allocated))) == (char *)NULL)
X { error("Malloc failed in printfile()");
X return;
X }
X
X if ((f = openout(fname, &pid)) == (FILE *)0)
X { error ("Can't create file \"%s\"", fname);
X return;
X }
X for (row=r0;row<=rn; row++) {
X register c = 0;
X
X if (row_hidden[row])
X continue;
X
X pline[plinelim=0] = '\0';
X for (pp = ATBL(tbl, row, col=c0); col<=cn;
X pp += nextcol-col, col = nextcol, c += fieldlen) {
X
X nextcol = col+1;
X if (col_hidden[col]) {
X fieldlen = 0;
X continue;
X }
X
X fieldlen = fwidth[col];
X if (*pp) {
X char *s;
X
X /*
X * dynamically allocate pline, making sure we are not
X * attempting to write 'out of bounds'.
X */
X while(c > (fbufs_allocated * FBUFLEN)) {
X if((pline = xrealloc
X ((char *)pline,
X (unsigned)(FBUFLEN * ++fbufs_allocated)))
X == NULL) {
X error ("Realloc failed in printfile()");
X return;
X }
X }
X while (plinelim<c) pline[plinelim++] = ' ';
X plinelim = c;
X if ((*pp)->flags&is_valid) {
X while(plinelim + fwidth[col] >
X (fbufs_allocated * FBUFLEN)) {
X if((pline = ((char *)xrealloc
X ((char *)pline,
X (unsigned)(FBUFLEN * ++fbufs_allocated))))
X == NULL) {
X error ("Realloc failed in printfile()");
X return;
X }
X }
X if ((*pp)->cellerror)
X (void) sprintf (pline+plinelim, "%*s",
X fwidth[col],
X ((*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID"));
X else
X {
X if ((*pp)->format) {
X char field[FBUFLEN];
X format ((*pp)->format, (*pp)->v, field,
X sizeof(field));
X (void) sprintf (pline+plinelim, "%*s", fwidth[col],
X field);
X } else {
X char field[FBUFLEN];
X (void) engformat(realfmt[col], fwidth[col],
X precision[col], (*pp) -> v,
X field, sizeof(field));
X (void) sprintf (pline+plinelim, "%*s", fwidth[col],
X field);
X }
X }
X plinelim += strlen (pline+plinelim);
X }
X if (s = (*pp)->label) {
X int slen;
X char *start, *last;
X register char *fp;
X struct ent *nc;
X
X /* Figure out if the label slops over to a blank field */
X slen = strlen(s);
X while (slen > fieldlen && nextcol <= cn &&
X !((nc = lookat(row,nextcol))->flags & is_valid) &&
X !(nc->label)) {
X
X if (!col_hidden[nextcol])
X fieldlen += fwidth[nextcol];
X
X nextcol++;
X }
X if (slen > fieldlen)
X slen = fieldlen;
X
X while(c + fieldlen + 2 > (fbufs_allocated * FBUFLEN)) {
X if((pline = ((char *)xrealloc
X ((char *)pline,
X (unsigned)(FBUFLEN * ++fbufs_allocated))))
X == NULL) {
X error ("xrealloc failed in printfile()");
X return;
X }
X }
X
X /* Now justify and print */
X start = (*pp)->flags & is_leftflush ? pline + c
X : pline + c + fieldlen - slen;
X last = pline + c + fieldlen;
X fp = plinelim < c ? pline + plinelim : pline + c;
X while (fp < start)
X *fp++ = ' ';
X while (slen--)
X *fp++ = *s++;
X if (!((*pp)->flags & is_valid) || fieldlen != fwidth[col])
X while(fp < last)
X *fp++ = ' ';
X if (plinelim < fp - pline)
X plinelim = fp - pline;
X }
X }
X }
X pline[plinelim++] = '\n';
X pline[plinelim] = '\0';
X (void) fputs (pline, f);
X }
X
X closeout(f, pid);
X}
X
Xvoid
Xtblprintfile (fname, r0, c0, rn, cn)
Xchar *fname;
Xint r0, c0, rn, cn;
X{
X FILE *f;
X int pid;
X register row, col;
X register struct ent **pp;
X char coldelim = DEFCOLDELIM;
X
X if ((strcmp(fname, curfile) == 0) &&
X !yn_ask("Confirm that you want to destroy the data base: (y,n)"))
X return;
X
X if ((f = openout(fname, &pid)) == (FILE *)0)
X { error ("Can't create file \"%s\"", fname);
X return;
X }
X
X if ( tbl_style == TBL ) {
X fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname);
X fprintf(f,"tab(%c);\n",coldelim);
X for (col=c0;col<=cn; col++) fprintf(f," n");
X fprintf(f, ".\n");
X }
X else if ( tbl_style == LATEX ) {
X fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname);
X for (col=c0;col<=cn; col++) fprintf(f,"c");
X fprintf(f, "}\n");
X coldelim = '&';
X }
X else if ( tbl_style == SLATEX ) {
X fprintf(f,"%% ** %s spreadsheet output\n!begin<tabular><",progname);
X for (col=c0;col<=cn; col++) fprintf(f,"c");
X fprintf(f, ">\n");
X coldelim = '&';
X }
X else if ( tbl_style == TEX ) {
X fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n",
X progname, cn-c0+1);
X coldelim = '&';
X }
X
X for (row=r0; row<=rn; row++) {
X if ( tbl_style == TEX )
X (void) fprintf (f, "\\+");
X
X for (pp = ATBL(tbl, row, col=c0); col<=cn; col++, pp++) {
X if (*pp) {
X char *s;
X if ((*pp)->flags&is_valid) {
X if ((*pp)->cellerror) {
X (void) fprintf (f, "%*s",
X fwidth[col],
X ((*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID"));
X }
X else
X if ((*pp)->format) {
X char field[FBUFLEN];
X
X (void) format ((*pp)->format, (*pp)->v, field,
X sizeof(field));
X unspecial (f, field, coldelim);
X } else {
X char field[FBUFLEN];
X (void) engformat(realfmt[col], fwidth[col],
X precision[col], (*pp) -> v,
X field, sizeof(field));
X unspecial (f, field, coldelim);
X }
X }
X if (s = (*pp)->label) {
X unspecial (f, s, coldelim);
X }
X }
X if ( col < cn )
X (void) fprintf(f,"%c", coldelim);
X }
X if ( tbl_style == LATEX ) {
X if ( row < rn ) (void) fprintf (f, "\\\\");
X }
X else if ( tbl_style == SLATEX ) {
X if ( row < rn ) (void) fprintf (f, "!!");
X }
X else if ( tbl_style == TEX ) {
X (void) fprintf (f, "\\cr");
X }
X (void) fprintf (f,"\n");
X }
X
X if ( tbl_style == TBL )
X (void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname);
X else if ( tbl_style == LATEX )
X (void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname);
X else if ( tbl_style == SLATEX )
X (void) fprintf (f,"!end<tabular>\n%% ** end of %s spreadsheet output\n", progname);
X else if ( tbl_style == TEX )
X (void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname);
X
X closeout(f, pid);
X}
X
X/* unspecial (backquote) things that are special chars in a table */
Xvoid
Xunspecial(f, str, delim)
XFILE *f;
Xchar *str;
Xint delim;
X{
X while (*str)
X { if (((tbl_style == LATEX) || (tbl_style == SLATEX) ||
X (tbl_style == TEX)) &&
X ((*str == delim) || (*str == '$') || (*str == '#') ||
X (*str == '%') || (*str == '{') || (*str == '}') ||
X (*str == '[') || (*str == ']') || (*str == '&')))
X putc('\\', f);
X putc(*str, f);
X str++;
X }
X}
X
Xstruct enode *
Xcopye (e, Rdelta, Cdelta)
Xregister struct enode *e;
Xint Rdelta, Cdelta;
X{
X register struct enode *ret;
X
X if (e == (struct enode *)0) {
X ret = (struct enode *)0;
X } else if (e->op & REDUCE) {
X int newrow, newcol;
X if (freeenodes)
X { ret = freeenodes;
X freeenodes = ret->e.o.left;
X }
X else
X ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
X ret->op = e->op;
X newrow=e->e.r.left.vf & FIX_ROW ? e->e.r.left.vp->row :
X e->e.r.left.vp->row+Rdelta;
X newcol=e->e.r.left.vf & FIX_COL ? e->e.r.left.vp->col :
X e->e.r.left.vp->col+Cdelta;
X ret->e.r.left.vp = lookat (newrow, newcol);
X ret->e.r.left.vf = e->e.r.left.vf;
X newrow=e->e.r.right.vf & FIX_ROW ? e->e.r.right.vp->row :
X e->e.r.right.vp->row+Rdelta;
X newcol=e->e.r.right.vf & FIX_COL ? e->e.r.right.vp->col :
X e->e.r.right.vp->col+Cdelta;
X ret->e.r.right.vp = lookat (newrow, newcol);
X ret->e.r.right.vf = e->e.r.right.vf;
X } else {
X if (freeenodes)
X { ret = freeenodes;
X freeenodes = ret->e.o.left;
X }
X else
X ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
X ret->op = e->op;
X switch (ret->op) {
X case 'v':
X {
X int newrow, newcol;
X newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
X e->e.v.vp->row+Rdelta;
X newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
X e->e.v.vp->col+Cdelta;
X ret->e.v.vp = lookat (newrow, newcol);
X ret->e.v.vf = e->e.v.vf;
X break;
X }
X case 'k':
X ret->e.k = e->e.k;
X break;
X case 'f':
X ret->e.o.right = copye (e->e.o.right,0,0);
X ret->e.o.left = (struct enode *)0;
X break;
X case '$':
X ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
X (void) strcpy(ret->e.s, e->e.s);
X break;
X default:
X ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
X ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
X break;
X }
X }
X return ret;
X}
X
X/*
X
X * sync_refs and syncref are used to remove references to
X * deleted struct ents. Note that the deleted structure must still
X * be hanging around before the call, but not referenced by an entry
X * in tbl. Thus the free_ent, fix_ent calls in sc.c
X */
Xvoid
Xsync_refs ()
X{
X register i,j;
X register struct ent *p;
X sync_ranges();
X for (i=0; i<=maxrow; i++)
X for (j=0; j<=maxcol; j++)
X if ((p = *ATBL(tbl, i, j)) && p->expr)
X syncref(p->expr);
X}
X
Xvoid
Xsyncref(e)
Xregister struct enode *e;
X{
X if (e == (struct enode *)0)
X return;
X else if (e->op & REDUCE) {
X e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col);
X e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col);
X } else {
X switch (e->op) {
X case 'v':
X e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
X break;
X case 'k':
X break;
X case '$':
X break;
X default:
X syncref(e->e.o.right);
X syncref(e->e.o.left);
X break;
X }
X }
X}
X
X/* mark a row as hidden */
Xvoid
Xhiderow(arg)
Xint arg;
X{
X register int r1;
X register int r2;
X
X r1 = currow;
X r2 = r1 + arg - 1;
X if (r1 < 0 || r1 > r2) {
X error ("Invalid range");
X return;
X }
X if (r2 >= maxrows-1)
X { if (!growtbl(GROWROW, arg+1, 0))
X { error("You can't hide the last row");
X return;
X }
X }
X FullUpdate++;
X modflg++;
X while (r1 <= r2)
X row_hidden[r1++] = 1;
X}
X
X/* mark a column as hidden */
Xvoid
Xhidecol(arg)
Xint arg;
X{
X register int c1;
X register int c2;
X
X c1 = curcol;
X c2 = c1 + arg - 1;
X if (c1 < 0 || c1 > c2) {
X error ("Invalid range");
X return;
X }
X if (c2 >= maxcols-1)
X { if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
X { error("You can't hide the last col");
X return;
X }
X }
X FullUpdate++;
X modflg++;
X while (c1 <= c2)
X col_hidden[c1++] = 1;
X}
X
X/* mark a row as not-hidden */
Xvoid
Xshowrow(r1, r2)
Xint r1, r2;
X{
X if (r1 < 0 || r1 > r2) {
X error ("Invalid range");
X return;
X }
X if (r2 > maxrows-1) {
X r2 = maxrows-1;
X }
X FullUpdate++;
X modflg++;
X while (r1 <= r2)
X row_hidden[r1++] = 0;
X}
X
X/* mark a column as not-hidden */
Xvoid
Xshowcol(c1, c2)
Xint c1, c2;
X{
X if (c1 < 0 || c1 > c2) {
X error ("Invalid range");
X return;
X }
X if (c2 > maxcols-1) {
X c2 = maxcols-1;
X }
X FullUpdate++;
X modflg++;
X while (c1 <= c2)
X col_hidden[c1++] = 0;
X}
X
X/* Open the output file, setting up a pipe if needed */
XFILE *
Xopenout(fname, rpid)
Xchar *fname;
Xint *rpid;
X{
X int pipefd[2];
X int pid;
X FILE *f;
X char *efname;
X
X while (*fname && (*fname == ' ')) /* Skip leading blanks */
X fname++;
X
X if (*fname != '|') { /* Open file if not pipe */
X *rpid = 0;
X
X efname = findhome(fname);
X#ifdef DOBACKUPS
X if (!backup_file(efname) &&
X (yn_ask("Could not create backup copy, Save anyhow?: (y,n)") != 1))
X return(0);
X#endif
X return(fopen(efname, "w"));
X }
X
X fname++; /* Skip | */
X if ( pipe (pipefd) < 0) {
X error("Can't make pipe to child");
X *rpid = 0;
X return(0);
X }
X
X deraw();
X#ifdef VMS
X fprintf(stderr, "No son tasks available yet under VMS--sorry\n");
X#else /* VMS */
X
X if ((pid=fork()) == 0) /* if child */
X {
X (void) close (0); /* close stdin */
X (void) close (pipefd[1]);
X (void) dup (pipefd[0]); /* connect to pipe input */
X (void) signal (SIGINT, SIG_DFL); /* reset */
X (void) execl ("/bin/sh", "sh", "-c", fname, 0);
X exit (-127);
X }
X else /* else parent */
X {
X *rpid = pid;
X if ((f = fdopen (pipefd[1], "w")) == (FILE *)0)
X {
X (void) kill (pid, -9);
X error ("Can't fdopen output");
X (void) close (pipefd[1]);
X *rpid = 0;
X return(0);
X }
X }
X#endif /* VMS */
X return(f);
X}
X
X/* close a file opened by openout(), if process wait for return */
Xvoid
Xcloseout(f, pid)
XFILE *f;
Xint pid;
X{
X int temp;
X
X (void) fclose (f);
X if (pid) {
X while (pid != wait(&temp)) /**/;
X (void) printf("Press RETURN to continue ");
X (void) fflush(stdout);
X (void) nmgetch();
X goraw();
X }
X}
X
Xvoid
Xcopyent(n,p,dr,dc)
X register struct ent *n, *p;
X int dr, dc;
X{
X if(!n||!p){error("internal error");return;}
X n -> v = p -> v;
X n -> flags = p -> flags;
X n -> expr = copye (p -> expr, dr, dc);
X n -> label = (char *)0;
X if (p -> label) {
X n -> label = xmalloc ((unsigned) (strlen (p -> label) + 1));
X (void) strcpy (n -> label, p -> label);
X }
X n -> format = 0;
X if (p -> format) {
X n -> format = xmalloc ((unsigned) (strlen (p -> format) + 1));
X (void) strcpy (n -> format, p -> format);
X }
X}
X
Xvoid
Xwrite_fd (f, r0, c0, rn, cn)
Xregister FILE *f;
Xint r0, c0, rn, cn;
X{
X register struct ent **pp;
X register r, c;
X
X (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
X (void) fprintf (f, "Calculator.\n");
X (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
X print_options(f);
X for (c=0; c<maxcols; c++)
X if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC || realfmt[c] != DEFREFMT )
X (void) fprintf (f, "format %s %d %d %d\n",coltoa(c),fwidth[c],precision[c],realfmt[c]);
X for (c=c0; c<cn; c++) {
X if (col_hidden[c]) {
X (void) fprintf(f, "hide %s\n", coltoa(c));
X }
X }
X for (r=r0; r<=rn; r++) {
X if (row_hidden[r]) {
X (void) fprintf(f, "hide %d\n", r);
X }
X }
X
X write_range(f);
X
X if (mdir)
X (void) fprintf(f, "mdir \"%s\"\n", mdir);
X for (r=r0; r<=rn; r++) {
X pp = ATBL(tbl, r, c0);
X for (c=c0; c<=cn; c++, pp++)
X if (*pp) {
X if ((*pp)->label) {
X edits(r,c);
X (void) fprintf(f, "%s\n",line);
X }
X if ((*pp)->flags&is_valid) {
X editv (r, c);
X (void) fprintf (f, "%s\n",line);
X }
X if ((*pp)->format) {
X editfmt (r, c);
X (void) fprintf (f, "%s\n",line);
X }
X }
X }
X if (rndinfinity)
X fprintf(f, "set rndinfinity\n");
X}
X
Xint
Xwritefile (fname, r0, c0, rn, cn)
Xchar *fname;
Xint r0, c0, rn, cn;
X{
X register FILE *f;
X char save[PATHLEN];
X int pid;
X
X#ifndef VMS
X if (Crypt) {
X return (cwritefile(fname, r0, c0, rn, cn));
X }
X#endif /* VMS */
X
X if (*fname == '\0') fname = curfile;
X
X (void) strcpy(save,fname);
X
X if ((f= openout(fname, &pid)) == (FILE *)0)
X { error ("Can't create file \"%s\"", fname);
X return (-1);
X }
X
X write_fd(f, r0, c0, rn, cn);
X
X closeout(f, pid);
X
X if (!pid) {
X (void) strcpy(curfile, save);
X modflg = 0;
X error("File \"%s\" written.",curfile);
X }
X
X return (0);
X}
X
Xvoid
Xreadfile (fname,eraseflg)
Xchar *fname;
Xint eraseflg;
X{
X register FILE *f;
X char save[PATHLEN];
X int tempautolabel;
X
X tempautolabel = autolabel; /* turn off auto label when */
X autolabel = 0; /* when reading a file */
X
X if (*fname == '*' && mdir) {
X (void) strcpy(save, mdir);
X *fname = '/';
X (void) strcat(save, fname);
X } else {
X if (*fname == '\0')
X fname = curfile;
X (void) strcpy(save,fname);
X }
X
X#ifndef VMS
X if (Crypt) {
X creadfile(save, eraseflg);
X return;
X }
X#endif /* VMS */
X
X if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
X
X if ((f = fopen(findhome(save), "r")) == (FILE *)0)
X { error ("Can't read file \"%s\"", save);
X return;
X }
X
X if (eraseflg) erasedb ();
X
X loading++;
X while (fgets(line, sizeof(line), f)) {
X linelim = 0;
X if (line[0] != '#') (void) yyparse ();
X }
X --loading;
X (void) fclose (f);
X linelim = -1;
X modflg++;
X if (eraseflg) {
X (void) strcpy(curfile,save);
X modflg = 0;
X }
X autolabel = tempautolabel;
X EvalAll();
X}
X
X/* erase the database (tbl, etc.) */
Xvoid
Xerasedb ()
X{
X register r, c;
X for (c = 0; c<=maxcol; c++) {
X fwidth[c] = DEFWIDTH;
X precision[c] = DEFPREC;
X realfmt[c] = DEFREFMT;
X }
X
X for (r = 0; r<=maxrow; r++) {
X register struct ent **pp = ATBL(tbl, r, 0);
X for (c=0; c++<=maxcol; pp++)
X if (*pp) {
X if ((*pp)->expr) efree ((*pp) -> expr);
X if ((*pp)->label) xfree ((char *)((*pp) -> label));
X (*pp)->next = freeents; /* save [struct ent] for reuse */
X freeents = *pp;
X *pp = (struct ent *)0;
X }
X }
X maxrow = 0;
X maxcol = 0;
X clean_range();
X FullUpdate++;
X}
X
X/* moves curcol back one displayed column */
Xvoid
Xbackcol(arg)
X int arg;
X{
X while (--arg>=0) {
X if (curcol)
X curcol--;
X else
X {error ("At column A"); break;}
X while(col_hidden[curcol] && curcol)
X curcol--;
X }
X}
X
X/* moves curcol forward one displayed column */
Xvoid
Xforwcol(arg)
X int arg;
X{
X while (--arg>=0) {
X if (curcol < maxcols - 1)
X curcol++;
X else
X if (!growtbl(GROWCOL, 0, arg)) /* get as much as needed */
X break;
X else
X curcol++;
X while(col_hidden[curcol]&&(curcol<maxcols-1))
X curcol++;
X }
X}
X
X/* moves currow forward one displayed row */
Xvoid
Xforwrow(arg)
X int arg;
X{
X while (--arg>=0) {
X if (currow < maxrows - 1)
X currow++;
X else
X if (!growtbl(GROWROW, arg, 0)) /* get as much as needed */
X break;
X else
X currow++;
X while (row_hidden[currow]&&(currow<maxrows-1))
X currow++;
X }
X}
X
X/* moves currow backward one displayed row */
Xvoid
Xbackrow(arg)
X int arg;
X{
X while (--arg>=0) {
X if (currow)
X currow--;
X else
X {error ("At row zero"); break;}
X while (row_hidden[currow] && currow)
X currow--;
X }
X}
X
X
X/*
X * Show a cell's label string or expression value. May overwrite value if
X * there is one already displayed in the cell. Created from old code in
X * update(), copied with minimal changes.
X */
X
Xvoid
Xshowstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c)
X char *string; /* to display */
X int leftflush; /* or rightflush */
X int hasvalue; /* is there a numeric value? */
X int row, col; /* spreadsheet location */
X int *nextcolp; /* value returned through it */
X int mxcol; /* last column displayed? */
X int *fieldlenp; /* value returned through it */
X int r, c; /* screen row and column */
X{
X register int nextcol = *nextcolp;
X register int fieldlen = *fieldlenp;
X
X char field[FBUFLEN];
X int slen;
X char *start, *last;
X register char *fp;
X struct ent *nc;
X
X /* This figures out if the label is allowed to
X slop over into the next blank field */
X
X slen = strlen (string);
X while ((slen > fieldlen) && (nextcol <= mxcol) &&
X !((nc = lookat (row, nextcol)) -> flags & is_valid) &&
X !(nc->label)) {
X
X if (! col_hidden [nextcol])
X fieldlen += fwidth [nextcol];
X
X nextcol++;
X }
X if (slen > fieldlen)
X slen = fieldlen;
X
X /* Now justify and print */
X start = leftflush ? field : field + fieldlen - slen;
X last = field+fieldlen;
X fp = field;
X while (fp < start)
X *fp++ = ' ';
X while (slen--)
X *fp++ = *string++;
X if ((! hasvalue) || fieldlen != fwidth[col])
X while (fp < last)
X *fp++ = ' ';
X *fp = '\0';
X#ifdef VMS
X mvaddstr(r, c, field); /* this is a macro */
X#else
X (void) mvaddstr(r, c, field);
X#endif
X
X *nextcolp = nextcol;
X *fieldlenp = fieldlen;
X}
X
Xint
Xetype(e)
Xregister struct enode *e;
X{
X if (e == (struct enode *)0)
X return NUM;
X switch (e->op) {
X case O_SCONST: case '#': case DATE: case FMT: case STINDEX:
X case EXT: case SVAL: case SUBSTR:
X return (STR);
X
X case '?':
X case IF:
X return(etype(e->e.o.right->e.o.left));
X
X case 'f':
X return(etype(e->e.o.right));
X
X case O_VAR: {
X register struct ent *p;
X p = e->e.v.vp;
X if (p->expr)
X return(p->flags & is_strexpr ? STR : NUM);
X else if (p->label)
X return(STR);
X else
X return(NUM);
X }
X
X default:
X return(NUM);
X }
X}
X
X/* return 1 if yes given, 0 otherwise */
Xint
Xyn_ask(msg)
Xchar *msg;
X{ char ch;
X
X (void) move (0, 0);
X (void) clrtoeol ();
X (void) addstr (msg);
X (void) refresh();
X ch = nmgetch();
X if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
X if (ch == ctl('g') || ch == ESC)
X return(-1);
X error("y or n response required");
X return (-1);
X }
X if (ch == 'y' || ch == 'Y')
X return(1);
X else
X return(0);
X}
X
X/* expand a ~ in a path to your home directory */
X#include <pwd.h>
Xchar *
Xfindhome(path)
Xchar *path;
X{
X static char *HomeDir = NULL;
X extern char *getenv();
X
X if (*path == '~')
X { char *pathptr;
X char tmppath[PATHLEN];
X
X if (HomeDir == NULL)
X { HomeDir = getenv("HOME");
X if (HomeDir == NULL)
X HomeDir = "/";
X }
X pathptr = path + 1;
X if ((*pathptr == '/') || (*pathptr == '\0'))
X { strcpy(tmppath, HomeDir);
X }
X else
X { struct passwd *pwent;
X extern struct passwd *getpwnam();
X char *namep;
X char name[50];
X
X namep = name;
X while ((*pathptr != '\0') && (*pathptr != '/'))
X *(namep++) = *(pathptr++);
X *namep = '\0';
X if ((pwent = getpwnam(name)) == NULL)
X { (void) sprintf(path, "Can't find user %s", name);
X return(NULL);
X }
X strcpy(tmppath, pwent->pw_dir);
X }
X
X strcat(tmppath, pathptr);
X strcpy(path, tmppath);
X }
X return(path);
X}
X
X#ifdef DOBACKUPS
X#include <sys/stat.h>
X
X/*
X * make a backup copy of a file, use the same mode and name in the format
X * [path/]#file~
X * return 1 if we were successful, 0 otherwise
X */
Xint
Xbackup_file(path)
Xchar *path;
X{
X struct stat statbuf;
X char fname[PATHLEN];
X char tpath[PATHLEN];
X#ifdef sequent
X static char *buf = NULL;
X static unsigned buflen = 0;
X#else
X char buf[BUFSIZ];
X#endif
X char *tpp;
X int infd, outfd;
X int count;
X
X /* tpath will be the [path/]file ---> [path/]#file~ */
X strcpy(tpath, path);
X if ((tpp = strrchr(tpath, '/')) == NULL)
X tpp = tpath;
X else
X tpp++;
X strcpy(fname, tpp);
X (void) sprintf(tpp, "#%s~", fname);
X
X if (stat(path, &statbuf) == 0)
X {
X /* if we know the optimum block size, use it */
X#ifdef sequent
X if ((statbuf.st_blksize > buflen) || (buf == NULL))
X { buflen = statbuf.st_blksize;
X if ((buf = xrealloc(buf, buflen)) == (char *)0)
X { buflen = 0;
X return(0);
X }
X }
X#endif
X
X if ((infd = open(path, O_RDONLY, 0)) < 0)
X return(0);
X
X if ((outfd = open(tpath, O_TRUNC|O_WRONLY|O_CREAT,
X statbuf.st_mode)) < 0)
X return(0);
X
X#ifdef sequent
X while((count = read(infd, buf, statbuf.st_blksize)) > 0)
X#else
X while((count = read(infd, buf, sizeof(buf))) > 0)
X#endif
X { if (write(outfd, buf, count) != count)
X { count = -1;
X break;
X }
X }
X close(infd);
X close(outfd);
X
X return((count < 0) ? 0 : 1);
X }
X else
X if (errno == ENOENT)
X return(1);
X return(0);
X}
X#endif
END_OF_FILE
if test 36608 -ne `wc -c <'cmds.c'`; then
echo shar: \"'cmds.c'\" unpacked with wrong size!
fi
# end of 'cmds.c'
fi
if test -f 'sc.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sc.h'\"
else
echo shar: Extracting \"'sc.h'\" \(9929 characters\)
sed "s/^X//" >'sc.h' <<'END_OF_FILE'
X/* SC A Table Calculator
X * Common definitions
X *
X * original by James Gosling, September 1982
X * modified by Mark Weiser and Bruce Israel,
X * University of Maryland
X * R. Bond 12/86
X * More mods by Alan Silverstein, 3-4/88, see list of changes.
X * $Revision: 6.16 $
X *
X */
X
X#define ATBL(tbl, row, col) (*(tbl + row) + (col))
X
X#define MINROWS 100 /* minimum size at startup */
X#define MINCOLS 30
X#define ABSMAXCOLS 702 /* absolute cols: ZZ (base 26) */
X
X#define RESCOL 4 /* columns reserved for row numbers */
X#define RESROW 3 /* rows reserved for prompt, error, and column numbers */
X
X#define DEFWIDTH 10 /* Default column width and precision */
X#define DEFPREC 2
X#define DEFREFMT 0 /* Make default format fixed point THA 10/14/90 */
X
X#define HISTLEN 10 /* Number of history entries for vi emulation */
X#ifdef PSC
X# define error(msg) fprintf(stderr, msg);
X#else
X# define error (void)move(1,0), (void)clrtoeol(), (void) printw
X#endif
X#define FBUFLEN 1024 /* buffer size for a single field */
X#define PATHLEN 1024 /* maximum path length */
X
X#ifndef A_CHARTEXT /* Should be defined in curses.h */
X# ifdef INTERNATIONAL
X# define A_CHARTEXT 0xff
X# else
X# define A_CHARTEXT 0x7f
X# endif
X#endif
X
X#if (defined(BSD42) || defined(BSD43)) && !defined(strrchr)
X#define strrchr rindex
X#endif
X
X#if (defined(BSD42) || defined(BSD43)) && !defined(strchr)
X#define strchr index
X#endif
X
X#ifdef SYSV4
Xsize_t strlen();
X#endif
X
X#ifndef FALSE
X# define FALSE 0
X# define TRUE 1
X#endif /* !FALSE */
X
X/*
X * ent_ptr holds the row/col # and address type of a cell
X *
X * vf is the type of cell address, 0 non-fixed, or bitwise OR of FIX_ROW or
X * FIX_COL
X * vp : we just use vp->row or vp->col, vp may be a new cell just for holding
X * row/col (say in gram.y) or a pointer to an existing cell
X */
Xstruct ent_ptr {
X int vf;
X struct ent *vp;
X};
X
X/* holds the beginning/ending cells of a range */
Xstruct range_s {
X struct ent_ptr left, right;
X};
X
X/*
X * Some not too obvious things about the flags:
X * is_valid means there is a valid number in v.
X * label set means it points to a valid constant string.
X * is_strexpr set means expr yields a string expression.
X * If is_strexpr is not set, and expr points to an expression tree, the
X * expression yields a numeric expression.
X * So, either v or label can be set to a constant.
X * Either (but not both at the same time) can be set from an expression.
X */
X
X#define VALID_CELL(p, r, c) ((p = *ATBL(tbl, r, c)) && \
X ((p->flags & is_valid) || p->label))
X
X/* info for each cell, only alloc'd when something is stored in a cell */
Xstruct ent {
X double v; /* v && label are set in EvalAll() */
X char *label;
X struct enode *expr; /* cell's contents */
X short flags;
X short row, col;
X struct ent *next; /* next deleted ent (pulled, deleted cells) */
X char *format; /* printf format for this cell */
X char cellerror; /* error in a cell? */
X};
X
X/* stores a range (left, right) */
Xstruct range {
X struct ent_ptr r_left, r_right;
X char *r_name; /* possible name for this range */
X struct range *r_next, *r_prev; /* chained ranges */
X int r_is_range;
X};
X
X#define FIX_ROW 1
X#define FIX_COL 2
X
X/* stores type of operation this cell will preform */
Xstruct enode {
X int op;
X union {
X double k; /* constant # */
X struct ent_ptr v; /* ref. another cell */
X struct range_s r; /* op is on a range */
X char *s; /* string part of a cell */
X struct { /* other cells use to eval()/seval() */
X struct enode *left, *right;
X } o;
X } e;
X};
X
X/* op values */
X#define O_VAR 'v'
X#define O_CONST 'k'
X#define O_ECONST 'E' /* constant cell w/ an error */
X#define O_SCONST '$'
X#define REDUCE 0200 /* Or'ed into OP if operand is a range */
X
X#define OP_BASE 256
X#define ACOS OP_BASE + 0
X#define ASIN OP_BASE + 1
X#define ATAN OP_BASE + 2
X#define CEIL OP_BASE + 3
X#define COS OP_BASE + 4
X#define EXP OP_BASE + 5
X#define FABS OP_BASE + 6
X#define FLOOR OP_BASE + 7
X#define HYPOT OP_BASE + 8
X#define LOG OP_BASE + 9
X#define LOG10 OP_BASE + 10
X#define POW OP_BASE + 11
X#define SIN OP_BASE + 12
X#define SQRT OP_BASE + 13
X#define TAN OP_BASE + 14
X#define DTR OP_BASE + 15
X#define RTD OP_BASE + 16
X#define MIN OP_BASE + 17
X#define MAX OP_BASE + 18
X#define RND OP_BASE + 19
X#define HOUR OP_BASE + 20
X#define MINUTE OP_BASE + 21
X#define SECOND OP_BASE + 22
X#define MONTH OP_BASE + 23
X#define DAY OP_BASE + 24
X#define YEAR OP_BASE + 25
X#define NOW OP_BASE + 26
X#define DATE OP_BASE + 27
X#define FMT OP_BASE + 28
X#define SUBSTR OP_BASE + 29
X#define STON OP_BASE + 30
X#define EQS OP_BASE + 31
X#define EXT OP_BASE + 32
X#define ELIST OP_BASE + 33 /* List of expressions */
X#define LMAX OP_BASE + 34
X#define LMIN OP_BASE + 35
X#define NVAL OP_BASE + 36
X#define SVAL OP_BASE + 37
X#define PV OP_BASE + 38
X#define FV OP_BASE + 39
X#define PMT OP_BASE + 40
X#define STINDEX OP_BASE + 41
X#define LOOKUP OP_BASE + 42
X#define ATAN2 OP_BASE + 43
X#define INDEX OP_BASE + 44
X#define DTS OP_BASE + 45
X#define TTS OP_BASE + 46
X#define ABS OP_BASE + 47
X#define HLOOKUP OP_BASE + 48
X#define VLOOKUP OP_BASE + 49
X#define ROUND OP_BASE + 50
X#define IF OP_BASE + 51
X#define MYROW OP_BASE + 52
X#define MYCOL OP_BASE + 53
X#define COLTOA OP_BASE + 54
X
X/* flag values */
X#define is_valid 0001
X#define is_changed 0002
X#define is_strexpr 0004
X#define is_leftflush 0010
X#define is_deleted 0020
X
X/* cell error (1st generation (ERROR) or 2nd+ (INVALID)) */
X#define CELLOK 0
X#define CELLERROR 1
X#define CELLINVALID 2
X
X#define ctl(c) ((c)&037)
X#define ESC 033
X#define DEL 0177
X
X/* calculation order */
X#define BYCOLS 1
X#define BYROWS 2
X
X/* tblprint style output for: */
X#define TBL 1 /* 'tbl' */
X#define LATEX 2 /* 'LaTeX' */
X#define TEX 3 /* 'TeX' */
X#define SLATEX 4 /* 'SLaTeX' (Scandinavian LaTeX) */
X
X/* Types for etype() */
X#define NUM 1
X#define STR 2
X
X#define GROWAMT 30 /* default minimum amount to grow */
X
X#define GROWNEW 1 /* first time table */
X#define GROWROW 2 /* add rows */
X#define GROWCOL 3 /* add columns */
X#define GROWBOTH 4 /* grow both */
Xextern struct ent ***tbl; /* data table ref. in vmtbl.c and ATBL() */
X
Xextern char curfile[];
Xextern int strow, stcol;
Xextern int currow, curcol;
Xextern int savedrow, savedcol;
Xextern int FullUpdate;
Xextern int maxrow, maxcol;
Xextern int maxrows, maxcols; /* # cells currently allocated */
Xextern int *fwidth;
Xextern int *precision;
Xextern int *realfmt;
Xextern char *col_hidden;
Xextern char *row_hidden;
Xextern char line[FBUFLEN];
Xextern int linelim;
Xextern int changed;
Xextern struct ent *to_fix;
Xextern int showsc, showsr;
X
Xextern FILE *openout();
Xextern char *coltoa();
Xextern char *findhome();
Xextern char *r_name();
Xextern char *strrchr();
Xextern char *v_name();
Xextern char *xmalloc();
Xextern char *xrealloc();
Xextern int are_ranges();
Xextern int atocol();
Xextern int cwritefile();
Xextern int engformat();
Xextern int etype();
Xextern int fork();
Xextern int format();
Xextern int get_rcqual();
Xextern int growtbl();
Xextern int modcheck();
Xextern int nmgetch();
Xextern int writefile();
Xextern int yn_ask();
Xextern struct enode *copye();
Xextern struct enode *new();
Xextern struct enode *new_const();
Xextern struct enode *new_range();
Xextern struct enode *new_str();
Xextern struct enode *new_var();
Xextern struct ent *lookat();
Xextern struct range *find_range();
Xextern void EvalAll();
Xextern void add_range();
Xextern void backcol();
Xextern void backrow();
Xextern void checkbounds();
Xextern void clearent();
Xextern void clean_range();
Xextern void closecol();
Xextern void closeout();
Xextern void closerow();
Xextern void colshow_op();
Xextern void copy();
Xextern void copyent();
Xextern void creadfile();
Xextern void deleterow();
Xextern void del_range();
Xextern void deraw();
Xextern void diesave();
Xextern void doend();
Xextern void doformat();
Xextern void dupcol();
Xextern void duprow();
Xextern void editexp();
Xextern void editfmt();
Xextern void edit_mode();
Xextern void edits();
Xextern void editv();
Xextern void efree();
Xextern void erase_area();
Xextern void erasedb();
Xextern void eraser();
Xextern void fill();
Xextern void flush_saved();
Xextern void format_cell();
Xextern void forwcol();
Xextern void forwrow();
Xextern void free_ent();
Xextern void go_last();
Xextern void goraw();
Xextern void help();
Xextern void hide_col();
Xextern void hide_row();
Xextern void hidecol();
Xextern void hiderow();
Xextern void initkbd();
Xextern void ins_string();
Xextern void insert_mode();
Xextern void insertrow();
Xextern void kbd_again();
Xextern void label();
Xextern void let();
Xextern void list_range();
Xextern void moveto();
Xextern void num_search();
Xextern void opencol();
Xextern void printfile();
Xextern void pullcells();
Xextern void readfile();
Xextern void resetkbd();
Xextern void rowshow_op();
Xextern void setauto();
Xextern void setiterations();
Xextern void setorder();
Xextern void showcol();
Xextern void showdr();
Xextern void showrow();
Xextern void showstring();
Xextern void signals();
Xextern void slet();
Xextern void startshow();
Xextern void str_search();
Xextern void sync_ranges();
Xextern void sync_refs();
Xextern void tblprintfile();
Xextern void valueize_area();
Xextern void write_fd();
Xextern void write_line();
Xextern void write_range();
Xextern void xfree();
Xextern void yyerror();
X#ifdef DOBACKUPS
Xextern int backup_file();
X#endif
X
Xextern int modflg;
Xextern int Crypt;
Xextern char *mdir;
Xextern double prescale;
Xextern int extfunc;
Xextern int propagation;
Xextern int calc_order;
Xextern int autocalc;
Xextern int autolabel;
Xextern int numeric;
Xextern int showcell;
Xextern int showtop;
Xextern int loading;
Xextern int getrcqual;
Xextern int tbl_style;
Xextern int rndinfinity;
Xextern char *progname;
X
X#if BSD42 || SYSIII
X
X#ifndef cbreak
X#define cbreak crmode
X#define nocbreak nocrmode
X#endif
X
X#endif
X
X#if defined(BSD42) || defined(BSD43) && !defined(ultrix)
X#define memcpy(dest, source, len) bcopy(source, dest, (unsigned int)len);
X#define memset(dest, zero, len) bzero((dest), (unsigned int)(len));
X#endif
END_OF_FILE
if test 9929 -ne `wc -c <'sc.h'`; then
echo shar: \"'sc.h'\" unpacked with wrong size!
fi
# end of 'sc.h'
fi
echo shar: End of archive 1 \(of 7\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 7 archives.
rm -f ark[1-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.
More information about the Comp.sources.misc
mailing list