home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-03-02 | 60.4 KB | 2,637 lines |
- Newsgroups: comp.sources.misc
- From: art@cs.ualberta.ca (Art Mulder)
- Subject: v35i088: ss - Simple Spreadsheet program, v1.2b, Part02/11
- Message-ID: <1993Feb22.152326.21284@sparky.imd.sterling.com>
- X-Md4-Signature: 1c73db2cc7d4b58e03f24f033df360f3
- Date: Mon, 22 Feb 1993 15:23:26 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: art@cs.ualberta.ca (Art Mulder)
- Posting-number: Volume 35, Issue 88
- Archive-name: ss/part02
- Environment: curses, sunos, sysv, ultrix, sgi, dec, mips, sun
-
- #! /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".
- # Contents: ss_12b/interp.c ss_12b/xmalloc.c
- # Wrapped by kent@sparky on Sat Feb 20 16:01:01 1993
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 2 (of 11)."'
- if test -f 'ss_12b/interp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ss_12b/interp.c'\"
- else
- echo shar: Extracting \"'ss_12b/interp.c'\" \(55653 characters\)
- sed "s/^X//" >'ss_12b/interp.c' <<'END_OF_FILE'
- X/* SC A Spreadsheet Calculator
- X * Expression interpreter and assorted support routines.
- X *
- X * original by James Gosling, September 1982
- X * modified by Mark Weiser and Bruce Israel,
- X * University of Maryland
- X *
- X * More mods Robert Bond, 12/86
- X * More mods by Alan Silverstein, 3-4/88, see list of changes.
- X * $Revision: 6.21 $
- X */
- X
- X#ifndef lint
- X static char Sccsid[] = "%W% %G%";
- X#endif
- X
- X#define DEBUGDTS 1 /* REMOVE ME */
- X
- X#include <sys/types.h>
- X#ifdef aiws
- X#undef _C_func /* Fixes for undefined symbols on AIX */
- X#endif
- X
- X#ifdef IEEE_MATH
- X#include <ieeefp.h>
- X#endif /* IEEE_MATH */
- X
- X#include <math.h>
- X#include <signal.h>
- X#include <setjmp.h>
- X#include <stdio.h>
- X#include <ctype.h>
- X
- Xextern int errno; /* set by math functions */
- X#ifdef BSD42
- X#include <strings.h>
- X#include <sys/time.h>
- X#ifndef strchr
- X#define strchr index
- X#endif
- X#else
- X#include <time.h>
- X#ifndef SYSIII
- X#include <string.h>
- X#endif
- X#endif
- X
- X#include "curses_stuff.h"
- X#include "ss.h"
- X
- X#if defined(RE_COMP)
- Xchar *re_comp();
- X#endif
- X#if defined(REGCMP)
- Xchar *regcmp();
- Xchar *regex();
- X#endif
- X
- XVOID_OR_INT doquit();
- X
- X/* Use this structure to save the the last 'g' command */
- Xstruct go_save {
- X int g_type;
- X double g_n;
- X char *g_s;
- X int g_row;
- X int g_col;
- X int errsearch;
- X} gs;
- X
- X/* g_type can be: */
- X#define G_NONE 0 /* Starting value - must be 0*/
- X#define G_NUM 1
- X#define G_STR 2
- X#define G_CELL 3
- X
- X#define ISVALID(r,c) ((r)>=0 && (r)<maxrows && (c)>=0 && (c)<maxcols)
- X
- Xextern FILE *popen();
- X
- Xjmp_buf fpe_save;
- Xint exprerr; /* Set by eval() and seval() if expression errors */
- Xdouble prescale = 1.0; /* Prescale for constants in let() */
- Xint extfunc = 0; /* Enable/disable external functions */
- Xint loading = 0; /* Set when readfile() is active */
- Xint gmyrow, gmycol; /* globals used to implement @myrow, @mycol cmds */
- X
- X/* a linked list of free [struct enodes]'s, uses .e.o.left as the pointer */
- Xstruct enode *freeenodes = NULL;
- X
- Xchar *seval();
- Xdouble dolookup();
- Xdouble eval();
- Xdouble fn1_eval();
- Xdouble fn1_seval();
- Xdouble fn2_eval();
- Xint RealEvalAll();
- Xint constant();
- Xvoid RealEvalOne();
- Xvoid copyrtv();
- Xvoid decompile();
- Xvoid index_arg();
- Xvoid list_arg();
- Xvoid one_arg();
- Xvoid range_arg();
- Xvoid three_arg();
- Xvoid two_arg();
- Xvoid two_arg_index();
- X
- Xint repct = 1; /* Make repct a global variable so that the
- X function @numiter can access it */
- X
- Xdouble rint();
- Xint cellerror = CELLOK; /* is there an error in this cell */
- X
- X#ifndef PI
- X#define PI (double)3.14159265358979323846
- X#endif
- X#define dtr(x) ((x)*(PI/(double)180.0))
- X#define rtd(x) ((x)*(180.0/(double)PI))
- X
- Xdouble finfunc(fun,v1,v2,v3)
- Xint fun;
- Xdouble v1,v2,v3;
- X{
- X double answer,p;
- X
- X p = fn2_eval(pow, 1 + v2, v3);
- X
- X switch(fun)
- X {
- X case PV:
- X if (v2)
- X answer = v1 * (1 - 1/p) / v2;
- X else
- X { cellerror = CELLERROR;
- X answer = (double)0;
- X }
- X break;
- X case FV:
- X if (v2)
- X answer = v1 * (p - 1) / v2;
- X else
- X { cellerror = CELLERROR;
- X answer = (double)0;
- X }
- X break;
- X case PMT:
- X /* CHECK IF ~= 1 - 1/1 */
- X if (p && p != (double)1)
- X answer = v1 * v2 / (1 - 1/p);
- X else
- X { cellerror = CELLERROR;
- X answer = (double)0;
- X }
- X
- X break;
- X default:
- X error("Unknown function in finfunc");
- X cellerror = CELLERROR;
- X return((double)0);
- X }
- X return(answer);
- X}
- X
- Xchar *
- Xdostindex( val, minr, minc, maxr, maxc)
- Xdouble val;
- Xint minr, minc, maxr, maxc;
- X{
- X register r,c;
- X register struct ent *p;
- X char *pr;
- X int x;
- X
- X x = (int) val;
- X r = minr; c = minc;
- X p = (struct ent *)0;
- X if ( minr == maxr ) { /* look along the row */
- X c = minc + x - 1;
- X if (c <= maxc && c >=minc)
- X p = *ATBL(tbl, r, c);
- X } else if ( minc == maxc ) { /* look down the column */
- X r = minr + x - 1;
- X if (r <= maxr && r >=minr)
- X p = *ATBL(tbl, r, c);
- X } else {
- X error ("range specified to @stindex");
- X cellerror = CELLERROR;
- X return((char *)0);
- X }
- X
- X if (p && p->label) {
- X pr = Malloc((unsigned)(strlen(p->label)+1));
- X Strcpy(pr, p->label);
- X if (p->cellerror)
- X cellerror = CELLINVALID;
- X return (pr);
- X } else
- X return((char *)0);
- X}
- X
- Xdouble
- Xdoindex( val, minr, minc, maxr, maxc)
- Xdouble val;
- Xint minr, minc, maxr, maxc;
- X{
- X double v;
- X register r,c;
- X register struct ent *p;
- X int x;
- X
- X x = (int) val;
- X v = (double)0;
- X r = minr; c = minc;
- X if ( minr == maxr ) { /* look along the row */
- X c = minc + x - 1;
- X if (c <= maxc && c >=minc
- X && (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
- X { if (p->cellerror)
- X cellerror = CELLINVALID;
- X return p->v;
- X }
- X }
- X else if ( minc == maxc ){ /* look down the column */
- X r = minr + x - 1;
- X if (r <= maxr && r >=minr
- X && (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
- X { if (p->cellerror)
- X cellerror = CELLINVALID;
- X return p->v;
- X }
- X }
- X else {
- X error(" range specified to @index");
- X cellerror = CELLERROR;
- X }
- X return v;
- X}
- X
- Xdouble
- Xdolookup( val, minr, minc, maxr, maxc, offr, offc)
- Xstruct enode * val;
- Xint minr, minc, maxr, maxc, offr, offc;
- X{
- X double v, ret = (double)0;
- X register r,c;
- X register struct ent *p = (struct ent *)0;
- X int incr,incc,fndr,fndc;
- X char *s;
- X
- X incr = (offc != 0); incc = (offr != 0);
- X if (etype(val) == NUM) {
- X cellerror = CELLOK;
- X v = eval(val);
- X for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
- X if ( (p = *ATBL(tbl, r, c)) && p->flags&is_valid ) {
- X if (p->v <= v) {
- X fndr = incc ? (minr + offr) : r;
- X fndc = incr ? (minc + offc) : c;
- X if (ISVALID(fndr,fndc))
- X p = *ATBL(tbl, fndr, fndc);
- X else {
- X error(" range specified to @[hv]lookup");
- X cellerror = CELLERROR;
- X }
- X if ( p && p->flags&is_valid)
- X { if (p->cellerror)
- X cellerror = CELLINVALID;
- X ret = p->v;
- X }
- X } else break;
- X }
- X }
- X } else {
- X cellerror = CELLOK;
- X s = seval(val);
- X for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
- X if ( (p = *ATBL(tbl, r, c)) && p->label ) {
- X if (strcmp(p->label,s) == 0) {
- X fndr = incc ? (minr + offr) : r;
- X fndc = incr ? (minc + offc) : c;
- X if (ISVALID(fndr,fndc))
- X { p = *ATBL(tbl, fndr, fndc);
- X if (p->cellerror)
- X cellerror = CELLINVALID;
- X }
- X else {
- X error(" range specified to @[hv]lookup");
- X cellerror = CELLERROR;
- X }
- X break;
- X }
- X }
- X }
- X if ( p && p->flags&is_valid)
- X ret = p->v;
- X Free(s);
- X }
- X return ret;
- X}
- X
- Xdouble
- Xdocount(minr, minc, maxr, maxc)
- Xint minr, minc, maxr, maxc;
- X{
- X int v;
- X register r,c;
- X register struct ent *p;
- X
- X v = 0;
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++)
- X if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
- X { if (p->cellerror)
- X cellerror = CELLINVALID;
- X v++;
- X }
- X return v;
- X}
- X
- Xdouble
- Xdosum(minr, minc, maxr, maxc)
- Xint minr, minc, maxr, maxc;
- X{
- X double v;
- X register r,c;
- X register struct ent *p;
- X
- X v = (double)0;
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++)
- X if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
- X { if (p->cellerror)
- X cellerror = CELLINVALID;
- X v += p->v;
- X }
- X return v;
- X}
- X
- Xdouble
- Xdoprod(minr, minc, maxr, maxc)
- Xint minr, minc, maxr, maxc;
- X{
- X double v;
- X register r,c;
- X register struct ent *p;
- X
- X v = 1;
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++)
- X if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
- X { if (p->cellerror)
- X cellerror = CELLINVALID;
- X v *= p->v;
- X }
- X return v;
- X}
- X
- Xdouble
- Xdoavg(minr, minc, maxr, maxc)
- Xint minr, minc, maxr, maxc;
- X{
- X double v;
- X register r,c,count;
- X register struct ent *p;
- X
- X v = (double)0;
- X count = 0;
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++)
- X if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
- X if (p->cellerror)
- X cellerror = CELLINVALID;
- X
- X v += p->v;
- X count++;
- X }
- X
- X if (count == 0)
- X return ((double) 0);
- X
- X return (v / (double)count);
- X}
- X
- Xdouble
- Xdostddev(minr, minc, maxr, maxc)
- Xint minr, minc, maxr, maxc;
- X{
- X double lp, rp, v, nd;
- X register r,c,n;
- X register struct ent *p;
- X
- X n = 0;
- X lp = 0;
- X rp = 0;
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++)
- X if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
- X if (p->cellerror)
- X cellerror = CELLINVALID;
- X
- X v = p->v;
- X lp += v*v;
- X rp += v;
- X n++;
- X }
- X
- X if ((n == 0) || (n == 1))
- X return ((double) 0);
- X nd = (double)n;
- X return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
- X}
- X
- Xdouble
- Xdomax(minr, minc, maxr, maxc)
- Xint minr, minc, maxr, maxc;
- X{
- X double v = (double)0;
- X register r,c,count;
- X register struct ent *p;
- X
- X count = 0;
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++)
- X if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
- X if (p->cellerror)
- X cellerror = CELLINVALID;
- X
- X if (!count) {
- X v = p->v;
- X count++;
- X } else if (p->v > v)
- X v = p->v;
- X }
- X
- X if (count == 0)
- X return ((double) 0);
- X
- X return (v);
- X}
- X
- Xdouble
- Xdomin(minr, minc, maxr, maxc)
- Xint minr, minc, maxr, maxc;
- X{
- X double v = (double)0;
- X register r,c,count;
- X register struct ent *p;
- X
- X count = 0;
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++)
- X if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
- X if (p->cellerror)
- X cellerror = CELLINVALID;
- X
- X if (!count) {
- X v = p->v;
- X count++;
- X } else if (p->v < v)
- X v = p->v;
- X }
- X
- X if (count == 0)
- X return ((double) 0);
- X
- X return (v);
- X}
- X
- X#define sec_min 60
- X#define sec_hr 3600L
- X#define sec_day 86400L
- X#define sec_yr 31471200L /* 364.25 days/yr */
- X#define sec_mo 2622600L /* sec_yr/12: sort of an average */
- Xint mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- X
- Xdouble
- Xdodts(mo, day, yr)
- Xint mo, day, yr;
- X{
- X long trial;
- X register struct tm *tp;
- X register int i;
- X register long jdate;
- X
- X mdays[1] = 28 + (yr%4 == 0);
- X
- X if (mo < 1 || mo > 12 || day < 1 || day > mdays[--mo] ||
- X yr > 1999 || yr < 1970) {
- X error("@dts: invalid argument");
- X cellerror = CELLERROR;
- X return(0.0);
- X }
- X
- X jdate = day-1;
- X for (i=0; i<mo; i++)
- X jdate += mdays[i];
- X for (i = 1970; i < yr; i++)
- X jdate += 365 + (i%4 == 0);
- X
- X trial = jdate * sec_day;
- X
- X yr -= 1900;
- X
- X tp = localtime(&trial);
- X
- X if (tp->tm_year != yr) {
- X /*
- X * We may fail this test once a year because of time zone
- X * and daylight savings time errors. This bounces the
- X * trial time past the boundary. The error introduced is
- X * corrected below.
- X */
- X trial += sec_day*(yr - tp->tm_year);
- X tp = localtime(&trial);
- X }
- X if (tp->tm_mon != mo) {
- X /* We may fail this test once a month. */
- X trial += sec_day*(mo - tp->tm_mon);
- X tp = localtime(&trial);
- X }
- X if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec != day) {
- X trial -= (tp->tm_mday - day)*sec_day + tp->tm_hour*sec_hr
- X + tp->tm_min*sec_min + tp->tm_sec;
- X }
- X
- X#ifdef DEBUGDTS
- X tp = localtime(&trial);
- X if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec +
- X tp->tm_year + tp->tm_mon != yr+mo+day)
- X { error("Dts broke down");
- X cellerror = CELLERROR;
- X }
- X#endif
- X
- X return ((double)trial);
- X}
- X
- Xdouble
- Xdotts(hr, min, sec)
- Xint hr, min, sec;
- X{
- X if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) {
- X error ("@tts: Invalid argument");
- X cellerror = CELLERROR;
- X return ((double)0);
- X }
- X return ((double)(sec+min*60+hr*3600));
- X}
- X
- Xdouble
- Xdotime(which, when)
- Xint which;
- Xdouble when;
- X{
- X long time();
- X
- X static long t_cache;
- X static struct tm tm_cache;
- X struct tm *tp;
- X long tloc;
- X
- X if (which == NOW)
- X return (double)time((long *)0);
- X
- X tloc = (long)when;
- X
- X if (tloc != t_cache) {
- X tp = localtime(&tloc);
- X tm_cache = *tp;
- X tm_cache.tm_mon += 1;
- X tm_cache.tm_year += 1900;
- X t_cache = tloc;
- X }
- X
- X switch (which) {
- X case HOUR: return((double)(tm_cache.tm_hour));
- X case MINUTE: return((double)(tm_cache.tm_min));
- X case SECOND: return((double)(tm_cache.tm_sec));
- X case MONTH: return((double)(tm_cache.tm_mon));
- X case DAY: return((double)(tm_cache.tm_mday));
- X case YEAR: return((double)(tm_cache.tm_year));
- X }
- X /* Safety net */
- X cellerror = CELLERROR;
- X return ((double)0);
- X}
- X
- Xdouble
- Xdoston(s)
- Xchar *s;
- X{
- X#ifndef _AIX
- X char *strtof();
- X#endif
- X double v;
- X
- X if (!s)
- X return((double)0);
- X
- X Strtof(s, &v);
- X Free(s);
- X return(v);
- X}
- X
- Xdouble
- Xdoeqs(s1, s2)
- Xchar *s1, *s2;
- X{
- X double v;
- X
- X if (!s1 && !s2)
- X return((double)1.0);
- X
- X if (!s1 || !s2)
- X v = 0.0;
- X else if (strcmp(s1, s2) == 0)
- X v = 1.0;
- X else
- X v = 0.0;
- X
- X if (s1)
- X Free(s1);
- X
- X if (s2)
- X Free(s2);
- X
- X return(v);
- X}
- X
- X
- X/*
- X * Given a string representing a column name and a value which is a column
- X * number, return a pointer to the selected cell's entry, if any, else NULL.
- X * Use only the integer part of the column number. Always free the string.
- X */
- X
- Xstruct ent *
- Xgetent (colstr, rowdoub)
- X char *colstr;
- X double rowdoub;
- X{
- X int collen; /* length of string */
- X int row, col; /* integer values */
- X struct ent *p = (struct ent *)0; /* selected entry */
- X
- X if (!colstr)
- X { cellerror = CELLERROR;
- X return((struct ent *)0);
- X }
- X
- X if (((row = (int) floor (rowdoub)) >= 0)
- X && (row < maxrows) /* in range */
- X && ((collen = strlen (colstr)) <= 2) /* not too long */
- X && ((col = atocol (colstr, collen)) >= 0)
- X && (col < maxcols)) /* in range */
- X {
- X p = *ATBL(tbl, row, col);
- X if ((p != NULL) && p->cellerror)
- X cellerror = CELLINVALID;
- X }
- X Free (colstr);
- X return (p);
- X}
- X
- X
- X/*
- X * Given a string representing a column name and a value which is a column
- X * number, return the selected cell's numeric value, if any.
- X */
- X
- Xdouble
- Xdonval (colstr, rowdoub)
- X char *colstr;
- X double rowdoub;
- X{
- X struct ent *ep;
- X
- X return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ?
- X (ep -> v) : (double)0);
- X}
- X
- X
- X/*
- X * The list routines (e.g. dolmax) are called with an LMAX enode.
- X * The left pointer is a chain of ELIST nodes, the right pointer
- X * is a value.
- X */
- Xdouble
- Xdolmax(ep)
- Xstruct enode *ep;
- X{
- X register int count = 0;
- X register double maxval = 0; /* Assignment to shut up lint */
- X register struct enode *p;
- X register double v;
- X
- X cellerror = CELLOK;
- X for (p = ep; p; p = p->e.o.left) {
- X v = eval(p->e.o.right);
- X if (!count || v > maxval) {
- X maxval = v; count++;
- X }
- X }
- X if (count) return maxval;
- X else return (double)0;
- X}
- X
- Xdouble
- Xdolmin(ep)
- Xstruct enode *ep;
- X{
- X register int count = 0;
- X register double minval = 0; /* Assignment to shut up lint */
- X register struct enode *p;
- X register double v;
- X
- X cellerror = CELLOK;
- X for (p = ep; p; p = p->e.o.left) {
- X v = eval(p->e.o.right);
- X if (!count || v < minval) {
- X minval = v; count++;
- X }
- X }
- X if (count) return minval;
- X else return (double)0;
- X}
- X
- Xdouble
- Xeval(e)
- Xregister struct enode *e;
- X{
- X if (e == (struct enode *)0)
- X { cellerror = CELLINVALID;
- X return (double)0;
- X }
- X switch (e->op) {
- X case '+': return (eval(e->e.o.left) + eval(e->e.o.right));
- X case '-': return (eval(e->e.o.left) - eval(e->e.o.right));
- X case '*': return (eval(e->e.o.left) * eval(e->e.o.right));
- X case '/': { double num, denom;
- X num = eval(e->e.o.left);
- X denom = eval(e->e.o.right);
- X if (denom)
- X/* if (1) /* to test num div 0 */
- X return(num/denom);
- X else
- X { cellerror = CELLERROR;
- X return((double) 0);
- X }
- X }
- X case '%': { double num, denom;
- X num = floor(eval(e->e.o.left));
- X denom = floor(eval (e->e.o.right));
- X if (denom)
- X return(num - floor(num/denom)*denom);
- X else
- X { cellerror = CELLERROR;
- X return((double) 0);
- X }
- X }
- X case '^': return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right)));
- X case '<': return (eval(e->e.o.left) < eval(e->e.o.right));
- X case '=': return (eval(e->e.o.left) == eval(e->e.o.right));
- X case '>': return (eval(e->e.o.left) > eval(e->e.o.right));
- X case '&': return (eval(e->e.o.left) && eval(e->e.o.right));
- X case '|': return (eval(e->e.o.left) || eval(e->e.o.right));
- X case IF:
- X case '?': return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
- X : eval(e->e.o.right->e.o.right);
- X case 'm': return (-eval(e->e.o.right));
- X case 'f': return (eval(e->e.o.right));
- X case '~': return (eval(e->e.o.right) == 0.0);
- X case O_CONST: return (e->e.k);
- X case O_VAR: if (e->e.v.vp->cellerror)
- X cellerror = CELLINVALID;
- X return (e->e.v.vp->v);
- X case INDEX:
- X case LOOKUP:
- X case HLOOKUP:
- X case VLOOKUP:
- X { register r,c;
- X register maxr, maxc;
- X register minr, minc;
- X maxr = e->e.o.right->e.r.right.vp -> row;
- X maxc = e->e.o.right->e.r.right.vp -> col;
- X minr = e->e.o.right->e.r.left.vp -> row;
- X minc = e->e.o.right->e.r.left.vp -> col;
- X if (minr>maxr) r = maxr, maxr = minr, minr = r;
- X if (minc>maxc) c = maxc, maxc = minc, minc = c;
- X switch(e->op){
- X case LOOKUP:
- X return dolookup(e->e.o.left, minr, minc, maxr, maxc,
- X minr==maxr, minc==maxc);
- X case HLOOKUP:
- X return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
- X (int) eval(e->e.o.left->e.o.right), 0);
- X case VLOOKUP:
- X return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
- X 0, (int) eval(e->e.o.left->e.o.right));
- X case INDEX:
- X return doindex(eval(e->e.o.left), minr, minc, maxr, maxc);
- X }
- X }
- X case (REDUCE | '+') :
- X case (REDUCE | '*') :
- X case (REDUCE | 'a') :
- X case (REDUCE | 'c') :
- X case (REDUCE | 's') :
- X case (REDUCE | MAX) :
- X case (REDUCE | MIN) :
- X { register r,c;
- X register maxr, maxc;
- X register minr, minc;
- X maxr = e->e.r.right.vp -> row;
- X maxc = e->e.r.right.vp -> col;
- X minr = e->e.r.left.vp -> row;
- X minc = e->e.r.left.vp -> col;
- X if (minr>maxr) r = maxr, maxr = minr, minr = r;
- X if (minc>maxc) c = maxc, maxc = minc, minc = c;
- X switch (e->op) {
- X case REDUCE | '+': return dosum(minr, minc, maxr, maxc);
- X case REDUCE | '*': return doprod(minr, minc, maxr, maxc);
- X case REDUCE | 'a': return doavg(minr, minc, maxr, maxc);
- X case REDUCE | 'c': return docount(minr, minc, maxr, maxc);
- X case REDUCE | 's': return dostddev(minr, minc, maxr, maxc);
- X case REDUCE | MAX: return domax(minr, minc, maxr, maxc);
- X case REDUCE | MIN: return domin(minr, minc, maxr, maxc);
- X }
- X }
- X case ABS: return (fn1_eval( fabs, eval(e->e.o.right)));
- X case ACOS: return (fn1_eval( acos, eval(e->e.o.right)));
- X case ASIN: return (fn1_eval( asin, eval(e->e.o.right)));
- X case ATAN: return (fn1_eval( atan, eval(e->e.o.right)));
- X case ATAN2: return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right)));
- X case CEIL: return (fn1_eval( ceil, eval(e->e.o.right)));
- X case COS: return (fn1_eval( cos, eval(e->e.o.right)));
- X case EXP: return (fn1_eval( exp, eval(e->e.o.right)));
- X case FABS: return (fn1_eval( fabs, eval(e->e.o.right)));
- X case FLOOR: return (fn1_eval( floor, eval(e->e.o.right)));
- X case HYPOT: return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right)));
- X case LOG: return (fn1_eval( log, eval(e->e.o.right)));
- X case LOG10: return (fn1_eval( log10, eval(e->e.o.right)));
- X case POW: return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right)));
- X case SIN: return (fn1_eval( sin, eval(e->e.o.right)));
- X case SQRT: return (fn1_eval( sqrt, eval(e->e.o.right)));
- X case TAN: return (fn1_eval( tan, eval(e->e.o.right)));
- X case DTR: return (dtr(eval(e->e.o.right)));
- X case RTD: return (rtd(eval(e->e.o.right)));
- X case RND:
- X if (rndinfinity)
- X { double temp = eval(e->e.o.right);
- X return(temp-floor(temp) < 0.5 ?
- X floor(temp) : ceil(temp));
- X }
- X else
- X return rint(eval(e->e.o.right));
- X case ROUND:
- X { int prec = (int) eval(e->e.o.right);
- X double scal = 1;
- X if (0 < prec)
- X do scal *= 10; while (0 < --prec);
- X else if (prec < 0)
- X do scal /= 10; while (++prec < 0);
- X
- X if (rndinfinity)
- X { double temp = eval(e->e.o.left);
- X temp *= scal;
- X temp = ((temp-floor(temp)) < 0.5 ?
- X floor(temp) : ceil(temp));
- X return(temp / scal);
- X }
- X else
- X return(rint(eval(e->e.o.left) * scal) / scal);
- X }
- X case FV:
- X case PV:
- X case PMT: return(finfunc(e->op,eval(e->e.o.left),
- X eval(e->e.o.right->e.o.left),
- X eval(e->e.o.right->e.o.right)));
- X case HOUR: return (dotime(HOUR, eval(e->e.o.right)));
- X case MINUTE: return (dotime(MINUTE, eval(e->e.o.right)));
- X case SECOND: return (dotime(SECOND, eval(e->e.o.right)));
- X case MONTH: return (dotime(MONTH, eval(e->e.o.right)));
- X case DAY: return (dotime(DAY, eval(e->e.o.right)));
- X case YEAR: return (dotime(YEAR, eval(e->e.o.right)));
- X case NOW: return (dotime(NOW, (double)0.0));
- X case DTS: return (dodts((int)eval(e->e.o.left),
- X (int)eval(e->e.o.right->e.o.left),
- X (int)eval(e->e.o.right->e.o.right)));
- X case TTS: return (dotts((int)eval(e->e.o.left),
- X (int)eval(e->e.o.right->e.o.left),
- X (int)eval(e->e.o.right->e.o.right)));
- X case STON: return (doston(seval(e->e.o.right)));
- X case EQS: return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
- X case LMAX: return dolmax(e);
- X case LMIN: return dolmin(e);
- X case NVAL: return (donval(seval(e->e.o.left),eval(e->e.o.right)));
- X case MYROW: return ((double) gmyrow);
- X case MYCOL: return ((double) gmycol);
- X case NUMITER: return ((double) repct);
- X default: error ("Illegal numeric expression");
- X exprerr = 1;
- X }
- X cellerror = CELLERROR;
- X return((double)0.0);
- X}
- X
- XVOID_OR_INT eval_fpe() /* Trap for FPE errors in eval */
- X{
- X#if defined(i386) && !defined(M_XENIX)
- X asm(" fnclex");
- X asm(" fwait");
- X#else
- X#ifdef IEEE_MATH
- X (void)fpsetsticky((fp_except)0); /* Clear exception */
- X#endif /* IEEE_MATH */
- X#ifdef PC
- X _fpreset();
- X#endif
- X#endif
- X /* re-establish signal handler for next time */
- X Signal(SIGFPE, eval_fpe);
- X longjmp(fpe_save, 1);
- X}
- X
- Xdouble fn1_eval(fn, arg)
- Xdouble (*fn)();
- Xdouble arg;
- X{
- X double res;
- X errno = 0;
- X res = (*fn)(arg);
- X if(errno)
- X cellerror = CELLERROR;
- X
- X return res;
- X}
- X
- Xdouble fn2_eval(fn, arg1, arg2)
- Xdouble (*fn)();
- Xdouble arg1, arg2;
- X{
- X double res;
- X errno = 0;
- X res = (*fn)(arg1, arg2);
- X if(errno)
- X cellerror = CELLERROR;
- X
- X return res;
- X}
- X
- X/*
- X * Rules for string functions:
- X * Take string arguments which they Free.
- X * All returned strings are assumed to be xalloced.
- X */
- X
- Xchar *
- Xdocat(s1, s2)
- Xregister char *s1, *s2;
- X{
- X register char *p;
- X char *arg1, *arg2;
- X
- X if (!s1 && !s2)
- X return((char *)0);
- X arg1 = s1 ? s1 : "";
- X arg2 = s2 ? s2 : "";
- X p = Malloc((unsigned)(strlen(arg1)+strlen(arg2)+1));
- X Strcpy(p, arg1);
- X Strcat(p, arg2);
- X if (s1)
- X Free(s1);
- X if (s2)
- X Free(s2);
- X return(p);
- X}
- X
- Xchar *
- Xdodate(tloc)
- Xlong tloc;
- X{
- X char *tp;
- X char *p;
- X
- X tp = ctime(&tloc);
- X tp[24] = '\0';
- X p = Malloc((unsigned)25);
- X Strcpy(p, tp);
- X return(p);
- X}
- X
- X
- Xchar *
- Xdofmt(fmtstr, v)
- Xchar *fmtstr;
- Xdouble v;
- X{
- X char buff[FBUFLEN];
- X char *p;
- X
- X if (!fmtstr)
- X return((char *)0);
- X Sprintf(buff, fmtstr, v);
- X p = Malloc((unsigned)(strlen(buff)+1));
- X Strcpy(p, buff);
- X Free(fmtstr);
- X return(p);
- X}
- X
- X
- X/*
- X * Given a command name and a value, run the command with the given value and
- X * read and return its first output line (only) as an allocated string, always
- X * a copy of prevstr, which is set appropriately first unless external
- X * functions are disabled, in which case the previous value is used. The
- X * handling of prevstr and freeing of command is tricky. Returning an
- X * allocated string in all cases, even if null, insures cell expressions are
- X * written to files, etc.
- X */
- X
- X#if defined(VMS) || defined(MSDOS)
- Xchar *
- Xdoext(command, value)
- Xchar *command;
- Xdouble value;
- X{
- X error("Warning: External functions unavailable on VMS");
- X cellerror = CELLERROR; /* not sure if this should be a cellerror */
- X if (command)
- X Free(command);
- X return (strcpy (Malloc((unsigned) 1), "\0"));
- X}
- X
- X#else /* VMS */
- X
- Xchar *
- Xdoext (command, value)
- Xchar *command;
- Xdouble value;
- X{
- X static char *prevstr = (char *)0; /* previous result */
- X static unsigned prevlen = 0;
- X char buff[FBUFLEN]; /* command line/return, not permanently alloc */
- X extern char *strchr();
- X
- X if (!extfunc) {
- X error ("Warning: external functions disabled; using %s value",
- X ((prevstr == NULL) || (*prevstr == '\0')) ?
- X "null" : "previous");
- X
- X if (command) Free (command);
- X } else {
- X if ((! command) || (! *command)) {
- X error ("Warning: external function given null command name");
- X cellerror = CELLERROR;
- X if (command) Free (command);
- X } else {
- X FILE *pp;
- X
- X Sprintf (buff, "%s %g", command, value); /* build cmd line */
- X Free (command);
- X
- X error ("Running external function...");
- X Refresh();
- X
- X if ((pp = popen (buff, "r")) == (FILE *) NULL) { /* run it */
- X error ("Warning: running \"%s\" failed", buff);
- X cellerror = CELLERROR;
- X }
- X else {
- X if (fgets (buff, sizeof(buff)-1, pp) == NULL) /* one line */
- X error ("Warning: external function returned nothing");
- X else {
- X char *cp;
- X
- X error (""); /* erase notice */
- X buff[sizeof(buff)-1] = '\0';
- X
- X if (cp = strchr (buff, '\n')) /* contains newline */
- X *cp = '\0'; /* end string there */
- X
- X if (strlen(buff) + 1 > prevlen)
- X { prevlen = strlen(buff) + 40;
- X prevstr = Realloc(prevstr, prevlen);
- X }
- X Strcpy (prevstr, buff);
- X /* save alloc'd copy */
- X }
- X (void) pclose (pp);
- X
- X } /* else */
- X } /* else */
- X } /* else */
- X if (prevstr)
- X return (strcpy (Malloc ((unsigned) (strlen (prevstr) + 1)), prevstr));
- X else
- X return (strcpy(Malloc((unsigned)1), ""));
- X}
- X
- X#endif /* VMS */
- X
- X
- X/*
- X * Given a string representing a column name and a value which is a column
- X * number, return the selected cell's string value, if any. Even if none,
- X * still allocate and return a null string so the cell has a label value so
- X * the expression is saved in a file, etc.
- X */
- X
- Xchar *
- Xdosval (colstr, rowdoub)
- X char *colstr;
- X double rowdoub;
- X{
- X struct ent *ep;
- X char *llabel;
- X
- X llabel = (ep = getent (colstr, rowdoub)) ? (ep -> label) : "";
- X return (strcpy (Malloc ((unsigned) (strlen (llabel) + 1)), llabel));
- X}
- X
- X
- X/*
- X * Substring: Note that v1 and v2 are one-based to users, but zero-based
- X * when calling this routine.
- X */
- X
- Xchar *
- Xdosubstr(s, v1, v2)
- Xchar *s;
- Xregister int v1,v2;
- X{
- X register char *s1, *s2;
- X char *p;
- X
- X if (!s)
- X return((char *)0);
- X
- X if (v2 >= strlen (s)) /* past end */
- X v2 = strlen (s) - 1; /* to end */
- X
- X if (v1 < 0 || v1 > v2) { /* out of range, return null string */
- X Free(s);
- X p = Malloc((unsigned)1);
- X p[0] = '\0';
- X return(p);
- X }
- X s2 = p = Malloc((unsigned)(v2-v1+2));
- X s1 = &s[v1];
- X for(; v1 <= v2; s1++, s2++, v1++)
- X *s2 = *s1;
- X *s2 = '\0';
- X Free(s);
- X return(p);
- X}
- X
- X/*
- X * character casing: make upper case, make lower case
- X */
- X
- Xchar *
- Xdocase( acase, s)
- Xint acase;
- Xchar *s;
- X{
- X char *p = s;
- X
- X if (s == NULL)
- X return(NULL);
- X
- X if( acase == UPPER ) {
- X while( *p != '\0' ) {
- X if( islower(*p) )
- X *p = toupper(*p);
- X p++;
- X }
- X }
- X else if ( acase == LOWER ) {
- X while( *p != '\0' ) {
- X if (isupper(*p))
- X *p = tolower(*p);
- X p++;
- X }
- X }
- X return (s);
- X}
- X
- X/*
- X * make proper capitals of every word in a string
- X * if the string has mixed case we say the string is lower
- X * and we will upcase only first letters of words
- X * if the string is all upper we will lower rest of words.
- X */
- X
- Xchar *
- Xdocapital( s )
- Xchar *s;
- X{
- X char *p;
- X int skip = 1;
- X int AllUpper = 1;
- X
- X if (s == NULL)
- X return(NULL);
- X for( p = s; *p != '\0' && AllUpper != 0; p++ )
- X if( isalpha(*p) && islower(*p) ) AllUpper = 0;
- X for (p = s; *p != '\0'; p++) {
- X if (!isalnum(*p))
- X skip = 1;
- X else
- X if (skip == 1) {
- X skip = 0;
- X if (islower(*p))
- X *p = toupper(*p);
- X }
- X else /* if the string was all upper before */
- X if (isupper(*p) && AllUpper != 0)
- X *p = tolower(*p);
- X }
- X return(s);
- X}
- X
- Xchar *
- Xseval(se)
- Xregister struct enode *se;
- X{
- X register char *p;
- X
- X if (se == (struct enode *)0) return (char *)0;
- X switch (se->op) {
- X case O_SCONST: p = Malloc((unsigned)(strlen(se->e.s)+1));
- X Strcpy(p, se->e.s);
- X return(p);
- X case O_VAR: {
- X struct ent *ep;
- X ep = se->e.v.vp;
- X
- X if (!ep->label)
- X return((char *)0);
- X p = Malloc((unsigned)(strlen(ep->label)+1));
- X Strcpy(p, ep->label);
- X return(p);
- X }
- X case '#': return(docat(seval(se->e.o.left), seval(se->e.o.right)));
- X case 'f': return(seval(se->e.o.right));
- X case IF:
- X case '?': return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
- X : seval(se->e.o.right->e.o.right));
- X case DATE: return(dodate((long)(eval(se->e.o.right))));
- X case FMT: return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
- X case UPPER: return(docase(UPPER, seval(se->e.o.right)));
- X case LOWER: return(docase(LOWER, seval(se->e.o.right)));
- X case CAPITAL:return(docapital(seval(se->e.o.right)));
- X case STINDEX:
- X { register r,c;
- X register maxr, maxc;
- X register minr, minc;
- X maxr = se->e.o.right->e.r.right.vp -> row;
- X maxc = se->e.o.right->e.r.right.vp -> col;
- X minr = se->e.o.right->e.r.left.vp -> row;
- X minc = se->e.o.right->e.r.left.vp -> col;
- X if (minr>maxr) r = maxr, maxr = minr, minr = r;
- X if (minc>maxc) c = maxc, maxc = minc, minc = c;
- X return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc);
- X }
- X case EXT: return(doext(seval(se->e.o.left), eval(se->e.o.right)));
- X case SVAL: return(dosval(seval(se->e.o.left), eval(se->e.o.right)));
- X case SUBSTR: return(dosubstr(seval(se->e.o.left),
- X (int)eval(se->e.o.right->e.o.left) - 1,
- X (int)eval(se->e.o.right->e.o.right) - 1));
- X case COLTOA: return(strcpy(Malloc((unsigned)10),
- X coltoa((int)eval(se->e.o.right)+1)));
- X default:
- X error ("Illegal string expression");
- X exprerr = 1;
- X return(NULL);
- X }
- X}
- X
- X/*
- X * The graph formed by cell expressions which use other cells's values is not
- X * evaluated "bottom up". The whole table is merely re-evaluated cell by cell,
- X * top to bottom, left to right, in RealEvalAll(). Each cell's expression uses
- X * constants in other cells. However, RealEvalAll() notices when a cell gets a
- X * new numeric or string value, and reports if this happens for any cell.
- X * EvalAll() repeats calling RealEvalAll() until there are no changes or the
- X * evaluation count expires.
- X */
- X
- Xint propagation = 10; /* max number of times to try calculation */
- X
- Xvoid
- Xsetiterations(i)
- Xint i;
- X{
- X if(i<1) {
- X error("iteration count must be at least 1");
- X propagation = 1;
- X }
- X else propagation = i;
- X}
- X
- Xvoid
- XEvalAll () {
- X int lastcnt;
- X
- X repct = 1;
- X Signal(SIGFPE, eval_fpe);
- X
- X while ((lastcnt = RealEvalAll()) && (++repct <= propagation));
- X if((propagation>1)&& (lastcnt >0 ))
- X error("Still changing after %d iterations",propagation-1);
- X
- X Signal(SIGFPE, doquit);
- X}
- X
- X/*
- X * Evaluate all cells which have expressions and alter their numeric or string
- X * values. Return the number of cells which changed.
- X */
- X
- Xint
- XRealEvalAll () {
- X register int i,j;
- X int chgct = 0;
- X register struct ent *p;
- X
- X if(calc_order == BYROWS ) {
- X for (i=0; i<=maxrow; i++)
- X for (j=0; j<=maxcol; j++)
- X if ((p = *ATBL(tbl,i,j)) && !(p->flags&is_locked) && p->expr) RealEvalOne(p,i,j,&chgct);
- X }
- X else if ( calc_order == BYCOLS ) {
- X for (j=0; j<=maxcol; j++)
- X { for (i=0; i<=maxrow; i++)
- X if ((p = *ATBL(tbl,i,j)) && !(p->flags&is_locked) && p->expr) RealEvalOne(p,i,j,&chgct);
- X }
- X }
- X else error("Internal error calc_order");
- X
- X return(chgct);
- X}
- X
- Xvoid
- XRealEvalOne(p, i, j, chgct)
- Xregister struct ent *p;
- Xint i, j, *chgct;
- X{
- X if (p->flags & is_strexpr) {
- X char *v;
- X if (setjmp(fpe_save)) {
- X error("Floating point exception %s", v_name(i, j));
- X cellerror = CELLERROR;
- X v = "";
- X } else {
- X cellerror = CELLOK;
- X v = seval(p->expr);
- X }
- X p->cellerror = cellerror;
- X if (!v && !p->label) /* Everything's fine */
- X return;
- X if (!p->label || !v || strcmp(v, p->label) != 0 || cellerror) {
- X (*chgct)++;
- X p->flags |= is_changed;
- X changed++;
- X }
- X if(p->label)
- X Free(p->label);
- X p->label = v;
- X } else {
- X double v;
- X if (setjmp(fpe_save)) {
- X error("Floating point exception %s", v_name(i, j));
- X cellerror = CELLERROR;
- X v = (double)0.0;
- X } else {
- X cellerror = CELLOK;
- X gmyrow=i; gmycol=j;
- X v = eval (p->expr);
- X }
- X if ((p->cellerror = cellerror) || (v != p->v)) {
- X p->v = v;
- X if (!cellerror) /* don't keep eval'ing a error */
- X (*chgct)++;
- X p->flags |= is_changed|is_valid;
- X changed++;
- X }
- X }
- X}
- X
- Xstruct enode *
- Xnew(op, a1, a2)
- Xint op;
- Xstruct enode *a1, *a2;
- X{
- X register struct enode *p;
- X if (freeenodes)
- X { p = freeenodes;
- X freeenodes = p->e.o.left;
- X }
- X else
- X p = (struct enode *) Malloc ((unsigned)sizeof (struct enode));
- X p->op = op;
- X p->e.o.left = a1;
- X p->e.o.right = a2;
- X return p;
- X}
- X
- Xstruct enode *
- Xnew_var(op, a1)
- Xint op;
- Xstruct ent_ptr a1;
- X{
- X register struct enode *p;
- X if (freeenodes)
- X { p = freeenodes;
- X freeenodes = p->e.o.left;
- X }
- X else
- X p = (struct enode *) Malloc ((unsigned)sizeof (struct enode));
- X p->op = op;
- X p->e.v = a1;
- X return p;
- X}
- X
- Xstruct enode *
- Xnew_range(op, a1)
- Xint op;
- Xstruct range_s a1;
- X{
- X register struct enode *p;
- X if (freeenodes)
- X { p = freeenodes;
- X freeenodes = p->e.o.left;
- X }
- X else
- X p = (struct enode *) Malloc ((unsigned)sizeof (struct enode));
- X p->op = op;
- X p->e.r = a1;
- X return p;
- X}
- X
- Xstruct enode *
- Xnew_const(op, a1)
- Xint op;
- Xdouble a1;
- X{
- X register struct enode *p;
- X if (freeenodes) /* reuse an already free'd enode */
- X { p = freeenodes;
- X freeenodes = p->e.o.left;
- X }
- X else
- X p = (struct enode *) Malloc ((unsigned)sizeof (struct enode));
- X p->op = op;
- X p->e.k = a1;
- X return p;
- X}
- X
- Xstruct enode *
- Xnew_str(s)
- Xchar *s;
- X{
- X register struct enode *p;
- X
- X if (freeenodes) /* reuse an already free'd enode */
- X { p = freeenodes;
- X freeenodes = p->e.o.left;
- X }
- X else
- X p = (struct enode *) Malloc ((unsigned)sizeof(struct enode));
- X p->op = O_SCONST;
- X p->e.s = s;
- X return(p);
- X}
- X
- Xvoid
- Xcopy(dv1, dv2, v1, v2)
- Xstruct ent *dv1, *dv2, *v1, *v2;
- X{
- X int minsr, minsc;
- X int maxsr, maxsc;
- X int mindr, mindc;
- X int maxdr, maxdc;
- X int vr, vc;
- X int r, c;
- X
- X mindr = dv1->row;
- X mindc = dv1->col;
- X maxdr = dv2->row;
- X maxdc = dv2->col;
- X if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
- X if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
- X maxsr = v2->row;
- X maxsc = v2->col;
- X minsr = v1->row;
- X minsc = v1->col;
- X if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
- X if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
- X checkbounds(&maxdr, &maxdc);
- X
- X erase_area(mindr, mindc, maxdr, maxdc);
- X if (minsr == maxsr && minsc == maxsc) {
- X /* Source is a single cell */
- X for(vr = mindr; vr <= maxdr; vr++)
- X for (vc = mindc; vc <= maxdc; vc++)
- X copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
- X } else if (minsr == maxsr) {
- X /* Source is a single row */
- X for (vr = mindr; vr <= maxdr; vr++)
- X copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
- X } else if (minsc == maxsc) {
- X /* Source is a single column */
- X for (vc = mindc; vc <= maxdc; vc++)
- X copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
- X } else {
- X /* Everything else */
- X copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
- X }
- X sync_refs();
- X}
- X
- Xvoid
- Xcopyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
- Xint vr, vc, minsr, minsc, maxsr, maxsc;
- X{
- X register struct ent *p;
- X register struct ent *n;
- X register int sr, sc;
- X register int dr, dc;
- X
- X for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
- X for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
- X if (p = *ATBL(tbl, sr, sc))
- X { n = lookat (dr, dc);
- X if (n->flags&is_locked) continue;
- X clearent(n);
- X copyent( n, p, dr - sr, dc - sc);
- X }
- X else
- X if (n = *ATBL(tbl, dr, dc))
- X clearent(n);
- X }
- X}
- X
- X/* ERASE a Range of cells */
- Xvoid
- Xeraser(v1, v2)
- Xstruct ent *v1, *v2;
- X{
- X FullUpdate++;
- X flush_saved();
- X erase_area(v1->row, v1->col, v2->row, v2->col);
- X sync_refs();
- X}
- X
- X/* Goto subroutines */
- X
- Xvoid
- Xg_free()
- X{
- X switch (gs.g_type) {
- X case G_STR: Free(gs.g_s); break;
- X default: break;
- X }
- X gs.g_type = G_NONE;
- X gs.errsearch = 0;
- X}
- X
- X/* repeat the last goto command */
- Xvoid
- Xgo_last()
- X{
- X switch (gs.g_type) {
- X case G_NONE:
- X error("Nothing to repeat"); break;
- X case G_NUM:
- X num_search(gs.g_n, gs.errsearch);
- X break;
- X case G_CELL:
- X moveto(gs.g_row, gs.g_col);
- X break;
- X case G_STR:
- X gs.g_type = G_NONE; /* Don't free the string */
- X str_search(gs.g_s);
- X break;
- X
- X default: error("go_last: internal error");
- X }
- X}
- X
- X/* place the cursor on a given cell */
- Xvoid
- Xmoveto(row, col)
- Xint row, col;
- X{
- X currow = row;
- X curcol = col;
- X g_free();
- X gs.g_type = G_CELL;
- X gs.g_row = currow;
- X gs.g_col = curcol;
- X}
- X
- X/*
- X * 'goto' either a given number,'error', or 'invalid' starting at currow,curcol
- X */
- Xvoid
- Xnum_search(n, errsearch)
- Xdouble n;
- Xint errsearch;
- X{
- X register struct ent *p;
- X register int r,c;
- X int endr, endc;
- X
- X g_free();
- X gs.g_type = G_NUM;
- X gs.g_n = n;
- X gs.errsearch = errsearch;
- X
- X if (currow > maxrow)
- X endr = maxrow ? maxrow-1 : 0;
- X else
- X endr = currow;
- X if (curcol > maxcol)
- X endc = maxcol ? maxcol-1 : 0;
- X else
- X endc = curcol;
- X r = endr;
- X c = endc;
- X do {
- X if (c < maxcol)
- X c++;
- X else {
- X if (r < maxrow) {
- X while(++r < maxrow && row_hidden[r]) /* */;
- X c = 0;
- X } else {
- X r = 0;
- X c = 0;
- X }
- X }
- X if (r == endr && c == endc) {
- X if (errsearch)
- X error("no %s cell found", errsearch == CELLERROR ? "ERROR" :
- X "INVALID");
- X else
- X error("Number not found");
- X return;
- X }
- X p = *ATBL(tbl, r, c);
- X } while (col_hidden[c] || !p || !(p->flags & is_valid)
- X || (!errsearch && (p->v != n))
- X || (errsearch && !((p->cellerror == errsearch) ||
- X (p->cellerror == errsearch)))); /* CELLERROR vs CELLINVALID */
- X
- X currow = r;
- X curcol = c;
- X}
- X
- X/* 'goto' a cell containing a matching string */
- Xvoid
- Xstr_search(s)
- Xchar *s;
- X{
- X register struct ent *p;
- X register int r,c;
- X int endr, endc;
- X char *tmp;
- X
- X#if defined(RE_COMP)
- X if ((tmp = re_comp(s)) != (char *)0) {
- X Free(s);
- X error(tmp);
- X return;
- X }
- X#endif
- X#if defined(REGCMP)
- X if ((tmp = regcmp(s, (char *)0)) == (char *)0) {
- X Free(s);
- X cellerror = CELLERROR;
- X error("Invalid search string");
- X return;
- X }
- X#endif
- X g_free();
- X gs.g_type = G_STR;
- X gs.g_s = s;
- X if (currow > maxrow)
- X endr = maxrow ? maxrow-1 : 0;
- X else
- X endr = currow;
- X if (curcol > maxcol)
- X endc = maxcol ? maxcol-1 : 0;
- X else
- X endc = curcol;
- X r = endr;
- X c = endc;
- X do {
- X if (c < maxcol)
- X c++;
- X else {
- X if (r < maxrow) {
- X while(++r < maxrow && row_hidden[r]) /* */;
- X c = 0;
- X } else {
- X r = 0;
- X c = 0;
- X }
- X }
- X if (r == endr && c == endc) {
- X error("String not found");
- X#if defined(REGCMP)
- X free(tmp);
- X#endif
- X return;
- X }
- X p = *ATBL(tbl, r, c);
- X } while(col_hidden[c] || !p || !(p->label)
- X#if defined(RE_COMP)
- X || (re_exec(p->label) == 0));
- X#else
- X#if defined(REGCMP)
- X || (regex(tmp, p->label) == (char *)0));
- X#else
- X || (strcmp(s, p->label) != 0));
- X#endif
- X#endif
- X currow = r;
- X curcol = c;
- X#if defined(REGCMP)
- X free(tmp);
- X#endif
- X}
- X
- X/* fill a range with constants */
- Xvoid
- Xfill (v1, v2, start, inc)
- Xstruct ent *v1, *v2;
- Xdouble start, inc;
- X{
- X register r,c;
- X register struct ent *n;
- X int maxr, maxc;
- X int minr, minc;
- X
- X maxr = v2->row;
- X maxc = v2->col;
- X minr = v1->row;
- X minc = v1->col;
- X if (minr>maxr) r = maxr, maxr = minr, minr = r;
- X if (minc>maxc) c = maxc, maxc = minc, minc = c;
- X checkbounds(&maxr, &maxc);
- X if (minr < 0) minr = 0;
- X if (minc < 0) minc = 0;
- X
- X FullUpdate++;
- X if( calc_order == BYROWS ) {
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++) {
- X n = lookat (r, c);
- X if (n->flags&is_locked) continue;
- X clearent(n);
- X n->v = start;
- X start += inc;
- X n->flags |= (is_changed|is_valid);
- X }
- X }
- X else if ( calc_order == BYCOLS ) {
- X for (c = minc; c<=maxc; c++)
- X for (r = minr; r<=maxr; r++) {
- X n = lookat (r, c);
- X clearent(n);
- X n->v = start;
- X start += inc;
- X n->flags |= (is_changed|is_valid);
- X }
- X }
- X else error(" Internal error calc_order");
- X changed++;
- X}
- X
- X/* lock a range of cells */
- X
- Xvoid
- Xlock_cells (v1, v2)
- Xstruct ent *v1, *v2;
- X{
- X register r,c;
- X register struct ent *n;
- X int maxr, maxc;
- X int minr, minc;
- X
- X maxr = v2->row;
- X maxc = v2->col;
- X minr = v1->row;
- X minc = v1->col;
- X if (minr>maxr) r = maxr, maxr = minr, minr = r;
- X if (minc>maxc) c = maxc, maxc = minc, minc = c;
- X checkbounds(&maxr, &maxc);
- X if (minr < 0) minr = 0;
- X if (minc < 0) minc = 0;
- X
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++) {
- X n = lookat (r, c);
- X n->flags |= is_locked;
- X }
- X}
- X
- X/* unlock a range of cells */
- X
- Xvoid
- Xunlock_cells (v1, v2)
- Xstruct ent *v1, *v2;
- X{
- X register r,c;
- X register struct ent *n;
- X int maxr, maxc;
- X int minr, minc;
- X
- X maxr = v2->row;
- X maxc = v2->col;
- X minr = v1->row;
- X minc = v1->col;
- X if (minr>maxr) r = maxr, maxr = minr, minr = r;
- X if (minc>maxc) c = maxc, maxc = minc, minc = c;
- X checkbounds(&maxr, &maxc);
- X if (minr < 0) minr = 0;
- X if (minc < 0) minc = 0;
- X
- X for (r = minr; r<=maxr; r++)
- X for (c = minc; c<=maxc; c++) {
- X n = lookat (r, c);
- X n->flags &= ~is_locked;
- X }
- X}
- X
- X/* set the numeric part of a cell */
- Xvoid
- Xlet (v, e)
- Xstruct ent *v;
- Xstruct enode *e;
- X{
- X double val;
- X unsigned isconstant = constant(e);
- X
- X if (loading && !isconstant)
- X val = (double)0.0;
- X else
- X {
- X exprerr = 0;
- X Signal(SIGFPE, eval_fpe);
- X if (setjmp(fpe_save)) {
- X error ("Floating point exception in cell %s", v_name(v->row, v->col));
- X val = (double)0.0;
- X cellerror = CELLERROR;
- X } else {
- X cellerror = CELLOK;
- X val = eval(e);
- X }
- X if (v->cellerror != cellerror)
- X { v->flags |= is_changed;
- X changed++; modflg++;
- X FullUpdate++;
- X v->cellerror = cellerror;
- X }
- X Signal(SIGFPE, doquit);
- X if (exprerr) {
- X efree(e);
- X return;
- X }
- X }
- X
- X if (isconstant) {
- X /* prescale input unless it has a decimal */
- X#if defined(IEEE_MATH) && !defined(NO_FMOD)
- X if (!loading && (prescale < (double)0.9999999) &&
- X (fmod(val, (double)1.0) == (double)0))
- X#else
- X if (!loading && (prescale < (double)0.9999999) &&
- X ((val - floor(val)) == (double)0))
- X#endif
- X val *= prescale;
- X
- X v->v = val;
- X
- X if (!(v->flags & is_strexpr)) {
- X efree(v->expr);
- X v->expr = (struct enode *)0;
- X }
- X efree(e);
- X }
- X else
- X {
- X efree(v->expr);
- X v->expr = e;
- X v->flags &= ~is_strexpr;
- X }
- X
- X changed++; modflg++;
- X v->flags |= (is_changed|is_valid);
- X}
- X
- Xvoid
- Xslet (v, se, flushdir)
- Xstruct ent *v;
- Xstruct enode *se;
- Xint flushdir;
- X{
- X char *p;
- X
- X exprerr = 0;
- X Signal(SIGFPE, eval_fpe);
- X if (setjmp(fpe_save)) {
- X error ("Floating point exception in cell %s", v_name(v->row, v->col));
- X cellerror = CELLERROR;
- X p = "";
- X } else {
- X cellerror = CELLOK;
- X p = seval(se);
- X }
- X if (v->cellerror != cellerror)
- X { v->flags |= is_changed;
- X changed++; modflg++;
- X FullUpdate++;
- X v->cellerror = cellerror;
- X }
- X Signal(SIGFPE, doquit);
- X if (exprerr) {
- X efree(se);
- X return;
- X }
- X if (constant(se)) {
- X label(v, p, flushdir);
- X if (p)
- X Free(p);
- X efree(se);
- X if (v->flags & is_strexpr) {
- X efree(v->expr);
- X v->expr = (struct enode *)0;
- X v->flags &= ~is_strexpr;
- X }
- X return;
- X }
- X efree(v->expr);
- X v->expr = se;
- X v->flags |= (is_changed|is_strexpr);
- X if (flushdir<0) v->flags |= is_leftflush;
- X
- X if (flushdir==0)
- X v->flags |= is_label;
- X else v->flags &= ~is_label;
- X
- X FullUpdate++;
- X changed++;
- X modflg++;
- X}
- X
- Xvoid
- Xformat_cell(v1, v2, s)
- Xstruct ent *v1, *v2;
- Xchar *s;
- X{
- X register r,c;
- X register struct ent *n;
- X int maxr, maxc;
- X int minr, minc;
- X
- X maxr = v2->row;
- X maxc = v2->col;
- X minr = v1->row;
- X minc = v1->col;
- X if (minr>maxr) r = maxr, maxr = minr, minr = r;
- X if (minc>maxc) c = maxc, maxc = minc, minc = c;
- X checkbounds(&maxr, &maxc);
- X if (minr < 0) minr = 0;
- X if (minc < 0) minc = 0;
- X
- X FullUpdate++;
- X modflg++;
- X for (r = minr; r <= maxr; r++)
- X for (c = minc; c <= maxc; c++) {
- X n = lookat (r, c);
- X if (n->flags&is_locked) {
- X error("Cell %s%d is locked", coltoa(n->col), n->row);
- X continue;
- X }
- X if (n->format)
- X Free(n->format);
- X n->format = 0;
- X if (s && *s != '\0')
- X n->format = strcpy(Malloc((unsigned)(strlen(s)+1)), s);
- X n->flags |= is_changed;
- X }
- X}
- X
- Xvoid
- Xhide_row(arg)
- Xint arg;
- X{
- X if (arg < 0) {
- X error("Invalid Range");
- X return;
- X }
- X if (arg >= maxrows-1)
- X {
- X if (!growtbl(GROWROW, arg+1, 0))
- X { error("You can't hide the last row");
- X return;
- X }
- X }
- X FullUpdate++;
- X row_hidden[arg] = 1;
- X}
- X
- Xvoid
- Xhide_col(arg)
- Xint arg;
- X{
- X if (arg < 0) {
- X error("Invalid Range");
- X return;
- X }
- X if (arg >= 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 col_hidden[arg] = TRUE;
- X}
- X
- Xvoid
- Xclearent (v)
- Xstruct ent *v;
- X{
- X if (!v)
- X return;
- X label(v,"",-1);
- X v->v = (double)0;
- X if (v->expr)
- X efree(v->expr);
- X v->expr = (struct enode *)0;
- X if (v->format)
- X Free(v->format);
- X v->format = (char *)0;
- X v->flags |= (is_changed);
- X v->flags &= ~(is_valid);
- X changed++;
- X modflg++;
- X}
- X
- X/*
- X * Say if an expression is a constant (return 1) or not.
- X */
- Xint
- Xconstant (e)
- X register struct enode *e;
- X{
- X return (
- X e == (struct enode *)0
- X || e -> op == O_CONST
- X || e -> op == O_SCONST
- X || (
- X e -> op != O_VAR
- X && (e -> op & REDUCE) != REDUCE
- X && constant (e -> e.o.left)
- X && constant (e -> e.o.right)
- X && e -> op != EXT /* functions look like constants but aren't */
- X && e -> op != NVAL
- X && e -> op != SVAL
- X && e -> op != NOW
- X && e -> op != MYROW
- X && e -> op != MYCOL
- X && e -> op != NUMITER
- X )
- X );
- X}
- X
- Xvoid
- Xefree (e)
- Xstruct enode *e;
- X{
- X if (e) {
- X if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
- X && (e->op & REDUCE) != REDUCE) {
- X efree(e->e.o.left);
- X efree(e->e.o.right);
- X }
- X if (e->op == O_SCONST && e->e.s)
- X Free(e->e.s);
- X e->e.o.left = freeenodes;
- X freeenodes = e;
- X }
- X}
- X
- Xvoid
- Xlabel (v, s, flushdir)
- Xregister struct ent *v;
- Xregister char *s;
- Xint flushdir;
- X{
- X if (v) {
- X if (flushdir==0 && v->flags&is_valid) {
- X register struct ent *tv;
- X if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
- X v = tv, flushdir = 1;
- X else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
- X v = tv, flushdir = -1;
- X else flushdir = -1;
- X }
- X if (v->label) Free((char *)(v->label));
- X if (s && s[0]) {
- X v->label = Malloc ((unsigned)(strlen(s)+1));
- X Strcpy (v->label, s);
- X } else
- X v->label = (char *)0;
- X if (flushdir<0) v->flags |= is_leftflush;
- X else v->flags &= ~is_leftflush;
- X if (flushdir==0) v->flags |= is_label;
- X else v->flags &= ~is_label;
- X FullUpdate++;
- X modflg++;
- X }
- X}
- X
- Xvoid
- Xdecodev (v)
- Xstruct ent_ptr v;
- X{
- X register struct range *r;
- X
- X if (!v.vp) Sprintf (line+linelim,"VAR?");
- X else if ((r = find_range((char *)0, 0, v.vp, v.vp)) && !r->r_is_range)
- X Sprintf(line+linelim, "%s", r->r_name);
- X else
- X Sprintf (line+linelim, "%s%s%s%d",
- X v.vf & FIX_COL ? "$" : "",
- X coltoa(v.vp->col),
- X v.vf & FIX_ROW ? "$" : "",
- X v.vp->row);
- X linelim += strlen (line+linelim);
- X}
- X
- Xchar *
- Xcoltoa(col)
- Xint col;
- X{
- X static char rname[3];
- X register char *p = rname;
- X
- X if (col > 25) {
- X *p++ = col/26 + 'A' - 1;
- X col %= 26;
- X }
- X *p++ = col+'A';
- X *p = '\0';
- X return(rname);
- X}
- X
- X/*
- X * To make list elements come out in the same order
- X * they were entered, we must do a depth-first eval
- X * of the ELIST tree
- X */
- Xstatic void
- Xdecompile_list(p)
- Xstruct enode *p;
- X{
- X if (!p) return;
- X decompile_list(p->e.o.left); /* depth first */
- X decompile(p->e.o.right, 0);
- X line[linelim++] = ',';
- X}
- X
- Xvoid
- Xdecompile(e, priority)
- Xregister struct enode *e;
- Xint priority;
- X{
- X register char *s;
- X if (e) {
- X int mypriority;
- X switch (e->op) {
- X default: mypriority = 99; break;
- X case '?': mypriority = 1; break;
- X case ':': mypriority = 2; break;
- X case '|': mypriority = 3; break;
- X case '&': mypriority = 4; break;
- X case '<': case '=': case '>': mypriority = 6; break;
- X case '+': case '-': case '#': mypriority = 8; break;
- X case '*': case '/': case '%': mypriority = 10; break;
- X case '^': mypriority = 12; break;
- X }
- X if (mypriority<priority) line[linelim++] = '(';
- X switch (e->op) {
- X case 'f': for (s="fixed "; line[linelim++] = *s++;);
- X linelim--;
- X decompile (e->e.o.right, 30);
- X break;
- X case 'm': line[linelim++] = '-';
- X decompile (e->e.o.right, 30);
- X break;
- X case '~': line[linelim++] = '~';
- X decompile (e->e.o.right, 30);
- X break;
- X case O_VAR: decodev (e->e.v);
- X break;
- X case O_CONST: Sprintf (line+linelim,"%.15g",e->e.k);
- X linelim += strlen (line+linelim);
- X break;
- X case O_SCONST: Sprintf (line+linelim, "\"%s\"", e->e.s);
- X linelim += strlen(line+linelim);
- X break;
- X
- X case REDUCE | '+': range_arg( "@sum(", e); break;
- X case REDUCE | '*': range_arg( "@prod(", e); break;
- X case REDUCE | 'a': range_arg( "@avg(", e); break;
- X case REDUCE | 'c': range_arg( "@count(", e); break;
- X case REDUCE | 's': range_arg( "@stddev(", e); break;
- X case REDUCE | MAX: range_arg( "@max(", e); break;
- X case REDUCE | MIN: range_arg( "@min(", e); break;
- X
- X case ABS: one_arg( "@abs(", e); break;
- X case ACOS: one_arg( "@acos(", e); break;
- X case ASIN: one_arg( "@asin(", e); break;
- X case ATAN: one_arg( "@atan(", e); break;
- X case ATAN2: two_arg( "@atan2(", e); break;
- X case CEIL: one_arg( "@ceil(", e); break;
- X case COS: one_arg( "@cos(", e); break;
- X case EXP: one_arg( "@exp(", e); break;
- X case FABS: one_arg( "@fabs(", e); break;
- X case FLOOR: one_arg( "@floor(", e); break;
- X case HYPOT: two_arg( "@hypot(", e); break;
- X case LOG: one_arg( "@ln(", e); break;
- X case LOG10: one_arg( "@log(", e); break;
- X case POW: two_arg( "@pow(", e); break;
- X case SIN: one_arg( "@sin(", e); break;
- X case SQRT: one_arg( "@sqrt(", e); break;
- X case TAN: one_arg( "@tan(", e); break;
- X case DTR: one_arg( "@dtr(", e); break;
- X case RTD: one_arg( "@rtd(", e); break;
- X case RND: one_arg( "@rnd(", e); break;
- X case ROUND: two_arg( "@round(", e); break;
- X case HOUR: one_arg( "@hour(", e); break;
- X case MINUTE: one_arg( "@minute(", e); break;
- X case SECOND: one_arg( "@second(", e); break;
- X case MONTH: one_arg( "@month(", e); break;
- X case DAY: one_arg( "@day(", e); break;
- X case YEAR: one_arg( "@year(", e); break;
- X case DATE: one_arg( "@date(", e); break;
- X case UPPER: one_arg( "@upper(", e); break;
- X case LOWER: one_arg( "@lower(", e); break;
- X case CAPITAL: one_arg( "@capital(", e); break;
- X case DTS: three_arg( "@dts(", e); break;
- X case TTS: three_arg( "@tts(", e); break;
- X case STON: one_arg( "@ston(", e); break;
- X case FMT: two_arg( "@fmt(", e); break;
- X case EQS: two_arg( "@eqs(", e); break;
- X case NOW: for ( s = "@now"; line[linelim++] = *s++;);
- X linelim--;
- X break;
- X case LMAX: list_arg("@max(", e); break;
- X case LMIN: list_arg("@min(", e); break;
- X case FV: three_arg("@fv(", e); break;
- X case PV: three_arg("@pv(", e); break;
- X case PMT: three_arg("@pmt(", e); break;
- X case NVAL: two_arg("@nval(", e); break;
- X case SVAL: two_arg("@sval(", e); break;
- X case EXT: two_arg("@ext(", e); break;
- X case SUBSTR: three_arg("@substr(", e); break;
- X case STINDEX: index_arg("@stindex(", e); break;
- X case INDEX: index_arg("@index(", e); break;
- X case LOOKUP: index_arg("@lookup(", e); break;
- X case HLOOKUP: two_arg_index("@hlookup(", e); break;
- X case VLOOKUP: two_arg_index("@vlookup(", e); break;
- X case IF: three_arg("@if(", e); break;
- X case MYROW: for ( s = "@myrow"; line[linelim++] = *s++;);
- X linelim--;
- X break;
- X case MYCOL: for ( s = "@mycol"; line[linelim++] = *s++;);
- X linelim--;
- X break;
- X case COLTOA: one_arg( "@coltoa(", e); break;
- X case NUMITER: for ( s = "@numiter"; line[linelim++] = *s++;);
- X linelim--;
- X break;
- X default: decompile (e->e.o.left, mypriority);
- X line[linelim++] = e->op;
- X decompile (e->e.o.right, mypriority+1);
- X break;
- X }
- X if (mypriority<priority) line[linelim++] = ')';
- X } else line[linelim++] = '?';
- X}
- X
- Xvoid
- Xindex_arg(s, e)
- Xchar *s;
- Xstruct enode *e;
- X{
- X for (; line[linelim++] = *s++;);
- X linelim--;
- X decompile( e-> e.o.left, 0 );
- X range_arg(", ", e->e.o.right);
- X}
- X
- Xvoid
- Xtwo_arg_index(s, e)
- Xchar *s;
- Xstruct enode *e;
- X{
- X for (; line[linelim++] = *s++;);
- X linelim--;
- X decompile( e->e.o.left->e.o.left, 0 );
- X range_arg(",", e->e.o.right);
- X linelim--;
- X line[linelim++] = ',';
- X decompile( e->e.o.left->e.o.right, 0 );
- X line[linelim++] = ')';
- X}
- X
- Xvoid
- Xlist_arg(s, e)
- Xchar *s;
- Xstruct enode *e;
- X{
- X for (; line[linelim++] = *s++;);
- X linelim--;
- X
- X decompile (e->e.o.right, 0);
- X line[linelim++] = ',';
- X decompile_list(e->e.o.left);
- X line[linelim - 1] = ')';
- X}
- X
- Xvoid
- Xone_arg(s, e)
- Xchar *s;
- Xstruct enode *e;
- X{
- X for (; line[linelim++] = *s++;);
- X linelim--;
- X decompile (e->e.o.right, 0);
- X line[linelim++] = ')';
- X}
- X
- Xvoid
- Xtwo_arg(s,e)
- Xchar *s;
- Xstruct enode *e;
- X{
- X for (; line[linelim++] = *s++;);
- X linelim--;
- X decompile (e->e.o.left, 0);
- X line[linelim++] = ',';
- X decompile (e->e.o.right, 0);
- X line[linelim++] = ')';
- X}
- X
- Xvoid
- Xthree_arg(s,e)
- Xchar *s;
- Xstruct enode *e;
- X{
- X for (; line[linelim++] = *s++;);
- X linelim--;
- X decompile (e->e.o.left, 0);
- X line[linelim++] = ',';
- X decompile (e->e.o.right->e.o.left, 0);
- X line[linelim++] = ',';
- X decompile (e->e.o.right->e.o.right, 0);
- X line[linelim++] = ')';
- X}
- X
- Xvoid
- Xrange_arg(s,e)
- Xchar *s;
- Xstruct enode *e;
- X{
- X struct range *r;
- X
- X for (; line[linelim++] = *s++;);
- X linelim--;
- X if ((r = find_range((char *)0, 0, e->e.r.left.vp,
- X e->e.r.right.vp)) && r->r_is_range) {
- X Sprintf(line+linelim, "%s", r->r_name);
- X linelim += strlen(line+linelim);
- X } else {
- X decodev (e->e.r.left);
- X line[linelim++] = ':';
- X decodev (e->e.r.right);
- X }
- X line[linelim++] = ')';
- X}
- X
- Xvoid
- Xeditfmt (row, col)
- Xint row, col;
- X{
- X register struct ent *p;
- X
- X p = lookat (row, col);
- X if (p->format) {
- X Sprintf (line, "fmt %s \"%s\"", v_name(row, col), p->format);
- X linelim = strlen(line);
- X }
- X}
- X
- Xvoid
- Xeditv (row, col)
- Xint row, col;
- X{
- X register struct ent *p;
- X
- X p = lookat (row, col);
- X Sprintf (line, "let %s = ", v_name(row, col));
- X linelim = strlen(line);
- X if (p->flags & is_strexpr || p->expr == 0) {
- X Sprintf (line+linelim, "%.15g", p->v);
- X linelim += strlen (line+linelim);
- X } else {
- X editexp(row,col);
- X }
- X}
- X
- Xvoid
- Xeditexp(row,col)
- Xint row, col;
- X{
- X register struct ent *p;
- X
- X p = lookat (row, col);
- X decompile (p->expr, 0);
- X line[linelim] = '\0';
- X}
- X
- Xvoid
- Xedits (row, col)
- Xint row, col;
- X{
- X register struct ent *p;
- X
- X p = lookat (row, col);
- X if( p->flags&is_label )
- X Sprintf( line, "label %s = ", v_name(row, col));
- X else
- X Sprintf (line, "%sstring %s = ",
- X ((p->flags&is_leftflush) ? "left" : "right"),
- X v_name(row, col));
- X linelim = strlen(line);
- X if (p->flags & is_strexpr && p->expr) {
- X editexp(row, col);
- X } else if (p->label) {
- X Sprintf (line+linelim, "\"%s\"", p->label);
- X linelim += strlen (line+linelim);
- X } else {
- X Sprintf (line+linelim, "\"");
- X linelim += 1;
- X }
- X}
- X
- X#ifdef RINT
- X/* round-to-even, also known as ``banker's rounding''.
- X With round-to-even, a number exactly halfway between two values is
- X rounded to whichever is even; e.g. rnd(0.5)=0, rnd(1.5)=2,
- X rnd(2.5)=2, rnd(3.5)=4. This is the default rounding mode for
- X IEEE floating point, for good reason: it has better numeric
- X properties. For example, if X+Y is an integer,
- X then X+Y = rnd(X)+rnd(Y) with round-to-even,
- X but not always with sc's rounding (which is
- X round-to-positive-infinity). I ran into this problem when trying to
- X split interest in an account to two people fairly.
- X*/
- Xdouble rint(d) double d;
- X{
- X /* as sent */
- X double fl = floor(d), fr = d-fl;
- X return
- X fr<0.5 || fr==0.5 && fl==floor(fl/2)*2 ? fl : ceil(d);
- X}
- X#endif
- END_OF_FILE
- if test 55653 -ne `wc -c <'ss_12b/interp.c'`; then
- echo shar: \"'ss_12b/interp.c'\" unpacked with wrong size!
- fi
- # end of 'ss_12b/interp.c'
- fi
- if test -f 'ss_12b/xmalloc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ss_12b/xmalloc.c'\"
- else
- echo shar: Extracting \"'ss_12b/xmalloc.c'\" \(1434 characters\)
- sed "s/^X//" >'ss_12b/xmalloc.c' <<'END_OF_FILE'
- X/*
- X * A safer saner malloc, for careless programmers
- X * $Revision: 6.21 $
- X */
- X
- X#ifndef lint
- X static char Sccsid[] = "%W% %G%";
- X#endif
- X
- X#include <stdio.h>
- X#include "curses_stuff.h"
- X#include "ss.h"
- X
- Xextern char *malloc();
- Xextern char *realloc();
- Xextern void free();
- Xvoid fatal();
- X
- X#ifdef SYSV3
- Xextern void free();
- Xextern void exit();
- X#endif
- X
- X#define MAGIC (double)1234567890.12344
- X
- Xchar *
- Xscxmalloc(n)
- Xunsigned n;
- X{
- X register char *ptr;
- X
- X if ((ptr = malloc(n + sizeof(double))) == NULL)
- X fatal("scxmalloc: no memory");
- X *((double *) ptr) = MAGIC; /* magic number */
- X return(ptr + sizeof(double));
- X}
- X
- X/* we make sure realloc will do a malloc if needed */
- Xchar *
- Xscxrealloc(ptr, n)
- Xchar *ptr;
- Xunsigned n;
- X{
- X if (ptr == NULL)
- X return(scxmalloc(n));
- X
- X ptr -= sizeof(double);
- X if (*((double *) ptr) != MAGIC)
- X fatal("scxrealloc: storage not scxmalloc'ed");
- X
- X if ((ptr = realloc(ptr, n + sizeof(double))) == NULL)
- X fatal("scxmalloc: no memory");
- X *((double *) ptr) = MAGIC; /* magic number */
- X return(ptr + sizeof(double));
- X}
- X
- Xvoid
- Xscxfree(p)
- Xchar *p;
- X{
- X if (p == NULL)
- X fatal("scxfree: NULL");
- X p -= sizeof(double);
- X if (*((double *) p) != MAGIC)
- X fatal("scxfree: storage not malloc'ed");
- X free(p);
- X}
- X
- X#ifdef PSC
- Xvoid
- Xfatal(str)
- Xchar *str;
- X{
- X (void) fprintf(stderr,"%s\n", str);
- X exit(1);
- X}
- X#else
- Xvoid
- Xfatal(str)
- Xchar *str;
- X{
- X deraw();
- X (void) fprintf(stderr,"%s\n", str);
- X diesave();
- X exit(1);
- X}
- X#endif /* PSC */
- END_OF_FILE
- if test 1434 -ne `wc -c <'ss_12b/xmalloc.c'`; then
- echo shar: \"'ss_12b/xmalloc.c'\" unpacked with wrong size!
- fi
- # end of 'ss_12b/xmalloc.c'
- fi
- echo shar: End of archive 2 \(of 11\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-