xref: /csrg-svn/contrib/sc/interp.c (revision 45325)
1*45325Sbostic /*	SC	A Spreadsheet Calculator
2*45325Sbostic  *		Expression interpreter and assorted support routines.
3*45325Sbostic  *
4*45325Sbostic  *		original by James Gosling, September 1982
5*45325Sbostic  *		modified by Mark Weiser and Bruce Israel,
6*45325Sbostic  *			University of Maryland
7*45325Sbostic  *
8*45325Sbostic  *              More mods Robert Bond, 12/86
9*45325Sbostic  *		More mods by Alan Silverstein, 3-4/88, see list of changes.
10*45325Sbostic  *		$Revision: 6.8 $
11*45325Sbostic  */
12*45325Sbostic 
13*45325Sbostic #define DEBUGDTS 1		/* REMOVE ME */
14*45325Sbostic /* #define EXPRTREE	/* expr. dependency tree stuff, not ready yet */
15*45325Sbostic 
16*45325Sbostic #ifdef aiws
17*45325Sbostic #undef _C_func			/* Fixes for undefined symbols on AIX */
18*45325Sbostic #endif
19*45325Sbostic 
20*45325Sbostic #ifdef IEEE_MATH
21*45325Sbostic #include <ieeefp.h>
22*45325Sbostic #endif /* IEEE_MATH */
23*45325Sbostic 
24*45325Sbostic #include <math.h>
25*45325Sbostic #include <signal.h>
26*45325Sbostic #include <setjmp.h>
27*45325Sbostic #include <stdio.h>
28*45325Sbostic 
29*45325Sbostic extern int errno;		/* set by math functions */
30*45325Sbostic #ifdef BSD42
31*45325Sbostic #include <strings.h>
32*45325Sbostic #include <sys/time.h>
33*45325Sbostic #ifndef strchr
34*45325Sbostic #define strchr index
35*45325Sbostic #endif
36*45325Sbostic #else
37*45325Sbostic #include <time.h>
38*45325Sbostic #ifndef SYSIII
39*45325Sbostic #include <string.h>
40*45325Sbostic #endif
41*45325Sbostic #endif
42*45325Sbostic 
43*45325Sbostic #include <curses.h>
44*45325Sbostic #include "sc.h"
45*45325Sbostic 
46*45325Sbostic #if defined(BSD42) || defined(BSD43)
47*45325Sbostic char *re_comp();
48*45325Sbostic #endif
49*45325Sbostic #if defined(SYSV2) || defined(SYSV3)
50*45325Sbostic char *regcmp();
51*45325Sbostic char *regex();
52*45325Sbostic #endif
53*45325Sbostic 
54*45325Sbostic #ifdef SIGVOID
55*45325Sbostic     void quit();
56*45325Sbostic #else
57*45325Sbostic     int quit();
58*45325Sbostic #endif
59*45325Sbostic 
60*45325Sbostic /* Use this structure to save the the last 'g' command */
61*45325Sbostic 
62*45325Sbostic struct go_save {
63*45325Sbostic 	int g_type;
64*45325Sbostic 	double g_n;
65*45325Sbostic 	char *g_s;
66*45325Sbostic 	int  g_row;
67*45325Sbostic 	int  g_col;
68*45325Sbostic } gs;
69*45325Sbostic 
70*45325Sbostic /* g_type can be: */
71*45325Sbostic 
72*45325Sbostic #define G_NONE 0			/* Starting value - must be 0*/
73*45325Sbostic #define G_NUM 1
74*45325Sbostic #define G_STR 2
75*45325Sbostic #define G_CELL 3
76*45325Sbostic 
77*45325Sbostic #define ISVALID(r,c)	((r)>=0 && (r)<maxrows && (c)>=0 && (c)<maxcols)
78*45325Sbostic 
79*45325Sbostic extern FILE *popen();
80*45325Sbostic 
81*45325Sbostic jmp_buf fpe_save;
82*45325Sbostic int	exprerr;	/* Set by eval() and seval() if expression errors */
83*45325Sbostic double  prescale = 1.0;	/* Prescale for constants in let() */
84*45325Sbostic int	extfunc  = 0;	/* Enable/disable external functions */
85*45325Sbostic int     loading = 0;	/* Set when readfile() is active */
86*45325Sbostic double fn1_eval();
87*45325Sbostic double fn2_eval();
88*45325Sbostic struct	ent *firstev = (struct ent *)0;	/* first expr in the eval list */
89*45325Sbostic 
90*45325Sbostic #define PI (double)3.14159265358979323846
91*45325Sbostic #define dtr(x) ((x)*(PI/(double)180.0))
92*45325Sbostic #define rtd(x) ((x)*(180.0/(double)PI))
93*45325Sbostic 
finfunc(fun,v1,v2,v3)94*45325Sbostic double finfunc(fun,v1,v2,v3)
95*45325Sbostic int fun;
96*45325Sbostic double v1,v2,v3;
97*45325Sbostic {
98*45325Sbostic  	double answer,p;
99*45325Sbostic 
100*45325Sbostic  	p = fn2_eval(pow, 1 + v2, v3);
101*45325Sbostic 
102*45325Sbostic  	switch(fun)
103*45325Sbostic  	{
104*45325Sbostic  	case PV:
105*45325Sbostic  		answer = v1 * (1 - 1/p) / v2;
106*45325Sbostic  		break;
107*45325Sbostic  	case FV:
108*45325Sbostic  		answer = v1 * (p - 1) / v2;
109*45325Sbostic  		break;
110*45325Sbostic  	case PMT:
111*45325Sbostic  		answer = v1 * v2 / (1 - 1/p);
112*45325Sbostic  		break;
113*45325Sbostic 	default:
114*45325Sbostic 		error("Unknown function in finfunc");
115*45325Sbostic 		return((double)0);
116*45325Sbostic 	}
117*45325Sbostic 	return(answer);
118*45325Sbostic }
119*45325Sbostic 
120*45325Sbostic char *
dostindex(val,minr,minc,maxr,maxc)121*45325Sbostic dostindex( val, minr, minc, maxr, maxc)
122*45325Sbostic double val;
123*45325Sbostic int minr, minc, maxr, maxc;
124*45325Sbostic {
125*45325Sbostic     register r,c;
126*45325Sbostic     register struct ent *p;
127*45325Sbostic     char *pr;
128*45325Sbostic     int x;
129*45325Sbostic 
130*45325Sbostic     x = (int) val;
131*45325Sbostic     r = minr; c = minc;
132*45325Sbostic     p = (struct ent *)0;
133*45325Sbostic     if ( minr == maxr ) { /* look along the row */
134*45325Sbostic 	c = minc + x - 1;
135*45325Sbostic 	if (c <= maxc && c >=minc)
136*45325Sbostic 	    p = *ATBL(tbl, r, c);
137*45325Sbostic     } else if ( minc == maxc ) { /* look down the column */
138*45325Sbostic 	r = minr + x - 1;
139*45325Sbostic 	if (r <= maxr && r >=minr)
140*45325Sbostic 	    p = *ATBL(tbl, r, c);
141*45325Sbostic     } else {
142*45325Sbostic 	error ("range specified to @stindex");
143*45325Sbostic 	return((char *)0);
144*45325Sbostic     }
145*45325Sbostic 
146*45325Sbostic     if (p && p->label) {
147*45325Sbostic 	pr = xmalloc((unsigned)(strlen(p->label)+1));
148*45325Sbostic 	(void)strcpy(pr, p->label);
149*45325Sbostic 	return (pr);
150*45325Sbostic      } else
151*45325Sbostic 	return((char *)0);
152*45325Sbostic }
153*45325Sbostic 
154*45325Sbostic double
doindex(val,minr,minc,maxr,maxc)155*45325Sbostic doindex( val, minr, minc, maxr, maxc)
156*45325Sbostic double val;
157*45325Sbostic int minr, minc, maxr, maxc;
158*45325Sbostic {
159*45325Sbostic     double v;
160*45325Sbostic     register r,c;
161*45325Sbostic     register struct ent *p;
162*45325Sbostic     int x;
163*45325Sbostic 
164*45325Sbostic     x = (int) val;
165*45325Sbostic     v = (double)0;
166*45325Sbostic     r = minr; c = minc;
167*45325Sbostic     if ( minr == maxr ) { /* look along the row */
168*45325Sbostic 	c = minc + x - 1;
169*45325Sbostic 	if (c <= maxc && c >=minc
170*45325Sbostic 		&& (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
171*45325Sbostic 					return p->v;
172*45325Sbostic 	}
173*45325Sbostic     else if ( minc == maxc ){ /* look down the column */
174*45325Sbostic 	r = minr + x - 1;
175*45325Sbostic 	if (r <= maxr && r >=minr
176*45325Sbostic 		&& (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
177*45325Sbostic 					return p->v;
178*45325Sbostic 	}
179*45325Sbostic     else error(" range specified to @index");
180*45325Sbostic     return v;
181*45325Sbostic }
182*45325Sbostic 
183*45325Sbostic double
dolookup(val,minr,minc,maxr,maxc,offr,offc)184*45325Sbostic dolookup( val, minr, minc, maxr, maxc, offr, offc)
185*45325Sbostic struct enode * val;
186*45325Sbostic int minr, minc, maxr, maxc, offr, offc;
187*45325Sbostic {
188*45325Sbostic     double v, ret = (double)0;
189*45325Sbostic     register r,c;
190*45325Sbostic     register struct ent *p = (struct ent *)0;
191*45325Sbostic     int incr,incc,fndr,fndc;
192*45325Sbostic     char *s;
193*45325Sbostic 
194*45325Sbostic     incr = (offc != 0); incc = (offr != 0);
195*45325Sbostic     if (etype(val) == NUM) {
196*45325Sbostic 	v = eval(val);
197*45325Sbostic 	for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
198*45325Sbostic 	    if ( (p = *ATBL(tbl, r, c)) && p->flags&is_valid ) {
199*45325Sbostic 		if (p->v <= v) {
200*45325Sbostic 		    fndr = incc ? (minr + offr) : r;
201*45325Sbostic 		    fndc = incr ? (minc + offc) : c;
202*45325Sbostic 		    if (ISVALID(fndr,fndc))
203*45325Sbostic 			p = *ATBL(tbl, fndr, fndc);
204*45325Sbostic 		    else error(" range specified to @[hv]lookup");
205*45325Sbostic 		    if ( p && p->flags&is_valid)
206*45325Sbostic 			ret = p->v;
207*45325Sbostic 		} else break;
208*45325Sbostic 	    }
209*45325Sbostic 	}
210*45325Sbostic     } else {
211*45325Sbostic 	s = seval(val);
212*45325Sbostic 	for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
213*45325Sbostic 	    if ( (p = *ATBL(tbl, r, c)) && p->label ) {
214*45325Sbostic 		if (strcmp(p->label,s) == 0) {
215*45325Sbostic 		    fndr = incc ? (minr + offr) : r;
216*45325Sbostic 		    fndc = incr ? (minc + offc) : c;
217*45325Sbostic 		    if (ISVALID(fndr,fndc))
218*45325Sbostic 			p = *ATBL(tbl, fndr, fndc);
219*45325Sbostic 		    else error(" range specified to @[hv]lookup");
220*45325Sbostic 		    break;
221*45325Sbostic 		}
222*45325Sbostic 	    }
223*45325Sbostic 	}
224*45325Sbostic 	if ( p && p->flags&is_valid)
225*45325Sbostic 	    ret = p->v;
226*45325Sbostic 	xfree(s);
227*45325Sbostic     }
228*45325Sbostic     return ret;
229*45325Sbostic }
230*45325Sbostic 
231*45325Sbostic double
docount(minr,minc,maxr,maxc)232*45325Sbostic docount(minr, minc, maxr, maxc)
233*45325Sbostic int minr, minc, maxr, maxc;
234*45325Sbostic {
235*45325Sbostic     int v;
236*45325Sbostic     register r,c;
237*45325Sbostic     register struct ent *p;
238*45325Sbostic 
239*45325Sbostic     v = 0;
240*45325Sbostic     for (r = minr; r<=maxr; r++)
241*45325Sbostic 	for (c = minc; c<=maxc; c++)
242*45325Sbostic 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
243*45325Sbostic 		v++;
244*45325Sbostic     return v;
245*45325Sbostic }
246*45325Sbostic 
247*45325Sbostic double
dosum(minr,minc,maxr,maxc)248*45325Sbostic dosum(minr, minc, maxr, maxc)
249*45325Sbostic int minr, minc, maxr, maxc;
250*45325Sbostic {
251*45325Sbostic     double v;
252*45325Sbostic     register r,c;
253*45325Sbostic     register struct ent *p;
254*45325Sbostic 
255*45325Sbostic     v = (double)0;
256*45325Sbostic     for (r = minr; r<=maxr; r++)
257*45325Sbostic 	for (c = minc; c<=maxc; c++)
258*45325Sbostic 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
259*45325Sbostic 		v += p->v;
260*45325Sbostic     return v;
261*45325Sbostic }
262*45325Sbostic 
263*45325Sbostic double
doprod(minr,minc,maxr,maxc)264*45325Sbostic doprod(minr, minc, maxr, maxc)
265*45325Sbostic int minr, minc, maxr, maxc;
266*45325Sbostic {
267*45325Sbostic     double v;
268*45325Sbostic     register r,c;
269*45325Sbostic     register struct ent *p;
270*45325Sbostic 
271*45325Sbostic     v = 1;
272*45325Sbostic     for (r = minr; r<=maxr; r++)
273*45325Sbostic 	for (c = minc; c<=maxc; c++)
274*45325Sbostic 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
275*45325Sbostic 		v *= p->v;
276*45325Sbostic     return v;
277*45325Sbostic }
278*45325Sbostic 
279*45325Sbostic double
doavg(minr,minc,maxr,maxc)280*45325Sbostic doavg(minr, minc, maxr, maxc)
281*45325Sbostic int minr, minc, maxr, maxc;
282*45325Sbostic {
283*45325Sbostic     double v;
284*45325Sbostic     register r,c,count;
285*45325Sbostic     register struct ent *p;
286*45325Sbostic 
287*45325Sbostic     v = (double)0;
288*45325Sbostic     count = 0;
289*45325Sbostic     for (r = minr; r<=maxr; r++)
290*45325Sbostic 	for (c = minc; c<=maxc; c++)
291*45325Sbostic 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
292*45325Sbostic 		v += p->v;
293*45325Sbostic 		count++;
294*45325Sbostic 	    }
295*45325Sbostic 
296*45325Sbostic     if (count == 0)
297*45325Sbostic 	return ((double) 0);
298*45325Sbostic 
299*45325Sbostic     return (v / (double)count);
300*45325Sbostic }
301*45325Sbostic 
302*45325Sbostic double
dostddev(minr,minc,maxr,maxc)303*45325Sbostic dostddev(minr, minc, maxr, maxc)
304*45325Sbostic int minr, minc, maxr, maxc;
305*45325Sbostic {
306*45325Sbostic     double lp, rp, v, nd;
307*45325Sbostic     register r,c,n;
308*45325Sbostic     register struct ent *p;
309*45325Sbostic 
310*45325Sbostic     n = 0;
311*45325Sbostic     lp = 0;
312*45325Sbostic     rp = 0;
313*45325Sbostic     for (r = minr; r<=maxr; r++)
314*45325Sbostic 	for (c = minc; c<=maxc; c++)
315*45325Sbostic 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
316*45325Sbostic 		v = p->v;
317*45325Sbostic 		lp += v*v;
318*45325Sbostic 		rp += v;
319*45325Sbostic 		n++;
320*45325Sbostic 	    }
321*45325Sbostic 
322*45325Sbostic     if ((n == 0) || (n == 1))
323*45325Sbostic 	return ((double) 0);
324*45325Sbostic     nd = (double)n;
325*45325Sbostic     return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
326*45325Sbostic }
327*45325Sbostic 
328*45325Sbostic double
domax(minr,minc,maxr,maxc)329*45325Sbostic domax(minr, minc, maxr, maxc)
330*45325Sbostic int minr, minc, maxr, maxc;
331*45325Sbostic {
332*45325Sbostic     double v = (double)0;
333*45325Sbostic     register r,c,count;
334*45325Sbostic     register struct ent *p;
335*45325Sbostic 
336*45325Sbostic     count = 0;
337*45325Sbostic     for (r = minr; r<=maxr; r++)
338*45325Sbostic 	for (c = minc; c<=maxc; c++)
339*45325Sbostic 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
340*45325Sbostic 		if (!count) {
341*45325Sbostic 		    v = p->v;
342*45325Sbostic 		    count++;
343*45325Sbostic 		} else if (p->v > v)
344*45325Sbostic 		    v = p->v;
345*45325Sbostic 	    }
346*45325Sbostic 
347*45325Sbostic     if (count == 0)
348*45325Sbostic 	return ((double) 0);
349*45325Sbostic 
350*45325Sbostic     return (v);
351*45325Sbostic }
352*45325Sbostic 
353*45325Sbostic double
domin(minr,minc,maxr,maxc)354*45325Sbostic domin(minr, minc, maxr, maxc)
355*45325Sbostic int minr, minc, maxr, maxc;
356*45325Sbostic {
357*45325Sbostic     double v = (double)0;
358*45325Sbostic     register r,c,count;
359*45325Sbostic     register struct ent *p;
360*45325Sbostic 
361*45325Sbostic     count = 0;
362*45325Sbostic     for (r = minr; r<=maxr; r++)
363*45325Sbostic 	for (c = minc; c<=maxc; c++)
364*45325Sbostic 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
365*45325Sbostic 		if (!count) {
366*45325Sbostic 		    v = p->v;
367*45325Sbostic 		    count++;
368*45325Sbostic 		} else if (p->v < v)
369*45325Sbostic 		    v = p->v;
370*45325Sbostic 	    }
371*45325Sbostic 
372*45325Sbostic     if (count == 0)
373*45325Sbostic 	return ((double) 0);
374*45325Sbostic 
375*45325Sbostic     return (v);
376*45325Sbostic }
377*45325Sbostic 
378*45325Sbostic #define sec_min 60
379*45325Sbostic #define sec_hr  3600L
380*45325Sbostic #define sec_day 86400L
381*45325Sbostic #define sec_yr  31471200L     /* 364.25 days/yr */
382*45325Sbostic #define sec_mo  2622600L       /* sec_yr/12: sort of an average */
383*45325Sbostic int mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
384*45325Sbostic 
385*45325Sbostic double
dodts(mo,day,yr)386*45325Sbostic dodts(mo, day, yr)
387*45325Sbostic int mo, day, yr;
388*45325Sbostic {
389*45325Sbostic     long trial;
390*45325Sbostic     register struct tm *tp;
391*45325Sbostic     register int i;
392*45325Sbostic     register long jdate;
393*45325Sbostic 
394*45325Sbostic     mdays[1] = 28 + (yr%4 == 0);
395*45325Sbostic 
396*45325Sbostic     if (mo < 1 || mo > 12 || day < 1 || day > mdays[--mo] ||
397*45325Sbostic 		yr > 1999 || yr < 1970) {
398*45325Sbostic 	error("@dts: invalid argument");
399*45325Sbostic 	return(0.0);
400*45325Sbostic     }
401*45325Sbostic 
402*45325Sbostic     jdate = day-1;
403*45325Sbostic     for (i=0; i<mo; i++)
404*45325Sbostic 	    jdate += mdays[i];
405*45325Sbostic     for (i = 1970; i < yr; i++)
406*45325Sbostic 	    jdate += 365 + (i%4 == 0);
407*45325Sbostic 
408*45325Sbostic     trial = jdate * sec_day;
409*45325Sbostic 
410*45325Sbostic     yr -= 1900;
411*45325Sbostic 
412*45325Sbostic     tp = localtime(&trial);
413*45325Sbostic 
414*45325Sbostic     if (tp->tm_year != yr) {
415*45325Sbostic 	    /*
416*45325Sbostic 	    * We may fail this test once a year because of time zone
417*45325Sbostic 	     * and daylight savings time errors.  This bounces the
418*45325Sbostic 	     * trial time past the boundary.  The error introduced is
419*45325Sbostic 	     * corrected below.
420*45325Sbostic 	     */
421*45325Sbostic 	    trial += sec_day*(yr - tp->tm_year);
422*45325Sbostic 	    tp = localtime(&trial);
423*45325Sbostic     }
424*45325Sbostic     if (tp->tm_mon != mo) {
425*45325Sbostic 	    /* We may fail this test once a month.  */
426*45325Sbostic 	    trial += sec_day*(mo - tp->tm_mon);
427*45325Sbostic 	    tp = localtime(&trial);
428*45325Sbostic     }
429*45325Sbostic     if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec != day) {
430*45325Sbostic 	trial -= (tp->tm_mday - day)*sec_day +  tp->tm_hour*sec_hr
431*45325Sbostic 		 + tp->tm_min*sec_min + tp->tm_sec;
432*45325Sbostic     }
433*45325Sbostic 
434*45325Sbostic #ifdef DEBUGDTS
435*45325Sbostic     tp = localtime(&trial);
436*45325Sbostic     if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec +
437*45325Sbostic 	tp->tm_year + tp->tm_mon != yr+mo+day)
438*45325Sbostic 		error("Dts broke down");
439*45325Sbostic #endif
440*45325Sbostic 
441*45325Sbostic     return ((double)trial);
442*45325Sbostic }
443*45325Sbostic 
444*45325Sbostic double
dotts(hr,min,sec)445*45325Sbostic dotts(hr, min, sec)
446*45325Sbostic int hr, min, sec;
447*45325Sbostic {
448*45325Sbostic     if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) {
449*45325Sbostic 	error ("@tts: Invalid argument");
450*45325Sbostic 	return ((double)0);
451*45325Sbostic     }
452*45325Sbostic     return ((double)(sec+min*60+hr*3600));
453*45325Sbostic }
454*45325Sbostic 
455*45325Sbostic double
dotime(which,when)456*45325Sbostic dotime(which, when)
457*45325Sbostic int which;
458*45325Sbostic double when;
459*45325Sbostic {
460*45325Sbostic 	long time();
461*45325Sbostic 
462*45325Sbostic 	static long t_cache;
463*45325Sbostic 	static struct tm tm_cache;
464*45325Sbostic 	struct tm *tp;
465*45325Sbostic 	long tloc;
466*45325Sbostic 
467*45325Sbostic 	if (which == NOW)
468*45325Sbostic 	    return (double)time((long *)0);
469*45325Sbostic 
470*45325Sbostic 	tloc = (long)when;
471*45325Sbostic 
472*45325Sbostic 	if (tloc != t_cache) {
473*45325Sbostic 	    tp = localtime(&tloc);
474*45325Sbostic 	    tm_cache = *tp;
475*45325Sbostic 	    tm_cache.tm_mon += 1;
476*45325Sbostic 	    tm_cache.tm_year += 1900;
477*45325Sbostic 	    t_cache = tloc;
478*45325Sbostic 	}
479*45325Sbostic 
480*45325Sbostic 	switch (which) {
481*45325Sbostic 	    case HOUR: return((double)(tm_cache.tm_hour));
482*45325Sbostic 	    case MINUTE: return((double)(tm_cache.tm_min));
483*45325Sbostic 	    case SECOND: return((double)(tm_cache.tm_sec));
484*45325Sbostic 	    case MONTH: return((double)(tm_cache.tm_mon));
485*45325Sbostic 	    case DAY: return((double)(tm_cache.tm_mday));
486*45325Sbostic 	    case YEAR: return((double)(tm_cache.tm_year));
487*45325Sbostic 	}
488*45325Sbostic 	/* Safety net */
489*45325Sbostic 	return ((double)0);
490*45325Sbostic }
491*45325Sbostic 
492*45325Sbostic double
doston(s)493*45325Sbostic doston(s)
494*45325Sbostic char *s;
495*45325Sbostic {
496*45325Sbostic     char *strtof();
497*45325Sbostic     double v;
498*45325Sbostic 
499*45325Sbostic     if (!s)
500*45325Sbostic 	return((double)0);
501*45325Sbostic 
502*45325Sbostic     (void)strtof(s, &v);
503*45325Sbostic     xfree(s);
504*45325Sbostic     return(v);
505*45325Sbostic }
506*45325Sbostic 
507*45325Sbostic double
doeqs(s1,s2)508*45325Sbostic doeqs(s1, s2)
509*45325Sbostic char *s1, *s2;
510*45325Sbostic {
511*45325Sbostic     double v;
512*45325Sbostic 
513*45325Sbostic     if (!s1 && !s2)
514*45325Sbostic 	return((double)1.0);
515*45325Sbostic 
516*45325Sbostic     if (!s1 || !s2)
517*45325Sbostic 	v = 0.0;
518*45325Sbostic     else if (strcmp(s1, s2) == 0)
519*45325Sbostic 	v = 1.0;
520*45325Sbostic     else
521*45325Sbostic 	v = 0.0;
522*45325Sbostic 
523*45325Sbostic     if (s1)
524*45325Sbostic     	xfree(s1);
525*45325Sbostic 
526*45325Sbostic     if (s2)
527*45325Sbostic     	xfree(s2);
528*45325Sbostic 
529*45325Sbostic     return(v);
530*45325Sbostic }
531*45325Sbostic 
532*45325Sbostic 
533*45325Sbostic /*
534*45325Sbostic  * Given a string representing a column name and a value which is a column
535*45325Sbostic  * number, return a pointer to the selected cell's entry, if any, else 0.  Use
536*45325Sbostic  * only the integer part of the column number.  Always free the string.
537*45325Sbostic  */
538*45325Sbostic 
539*45325Sbostic struct ent *
getent(colstr,rowdoub)540*45325Sbostic getent (colstr, rowdoub)
541*45325Sbostic     char *colstr;
542*45325Sbostic     double rowdoub;
543*45325Sbostic {
544*45325Sbostic     int collen;		/* length of string */
545*45325Sbostic     int row, col;	/* integer values   */
546*45325Sbostic     struct ent *ep = (struct ent *)0;	/* selected entry   */
547*45325Sbostic 
548*45325Sbostic     if (((row = (int) floor (rowdoub)) >= 0)
549*45325Sbostic      && (row < maxrows)				/* in range */
550*45325Sbostic      && ((collen = strlen (colstr)) <= 2)	/* not too long */
551*45325Sbostic      && ((col = atocol (colstr, collen)) >= 0)
552*45325Sbostic      && (col < maxcols))			/* in range */
553*45325Sbostic     {
554*45325Sbostic 	ep = *ATBL(tbl, row, col);
555*45325Sbostic     }
556*45325Sbostic 
557*45325Sbostic     xfree (colstr);
558*45325Sbostic     return (ep);
559*45325Sbostic }
560*45325Sbostic 
561*45325Sbostic 
562*45325Sbostic /*
563*45325Sbostic  * Given a string representing a column name and a value which is a column
564*45325Sbostic  * number, return the selected cell's numeric value, if any.
565*45325Sbostic  */
566*45325Sbostic 
567*45325Sbostic double
donval(colstr,rowdoub)568*45325Sbostic donval (colstr, rowdoub)
569*45325Sbostic     char *colstr;
570*45325Sbostic     double rowdoub;
571*45325Sbostic {
572*45325Sbostic     struct ent *ep;
573*45325Sbostic 
574*45325Sbostic     return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ?
575*45325Sbostic 	    (ep -> v) : (double)0);
576*45325Sbostic }
577*45325Sbostic 
578*45325Sbostic 
579*45325Sbostic /*
580*45325Sbostic  *	The list routines (e.g. dolmax) are called with an LMAX enode.
581*45325Sbostic  *	The left pointer is a chain of ELIST nodes, the right pointer
582*45325Sbostic  *	is a value.
583*45325Sbostic  */
584*45325Sbostic double
dolmax(ep)585*45325Sbostic dolmax(ep)
586*45325Sbostic struct enode *ep;
587*45325Sbostic {
588*45325Sbostic 	register int count = 0;
589*45325Sbostic 	register double maxval = 0; /* Assignment to shut up lint */
590*45325Sbostic 	register struct enode *p;
591*45325Sbostic 	register double v;
592*45325Sbostic 
593*45325Sbostic 	for (p = ep; p; p = p->e.o.left) {
594*45325Sbostic 		v = eval(p->e.o.right);
595*45325Sbostic 		if (!count || v > maxval) {
596*45325Sbostic 			maxval = v; count++;
597*45325Sbostic 		}
598*45325Sbostic 	}
599*45325Sbostic 	if (count) return maxval;
600*45325Sbostic 	else return (double)0;
601*45325Sbostic }
602*45325Sbostic 
603*45325Sbostic double
dolmin(ep)604*45325Sbostic dolmin(ep)
605*45325Sbostic struct enode *ep;
606*45325Sbostic {
607*45325Sbostic 	register int count = 0;
608*45325Sbostic 	register double minval = 0; /* Assignment to shut up lint */
609*45325Sbostic 	register struct enode *p;
610*45325Sbostic 	register double v;
611*45325Sbostic 
612*45325Sbostic 	for (p = ep; p; p = p->e.o.left) {
613*45325Sbostic 		v = eval(p->e.o.right);
614*45325Sbostic 		if (!count || v < minval) {
615*45325Sbostic 			minval = v; count++;
616*45325Sbostic 		}
617*45325Sbostic 	}
618*45325Sbostic 	if (count) return minval;
619*45325Sbostic 	else return (double)0;
620*45325Sbostic }
621*45325Sbostic 
622*45325Sbostic double
eval(e)623*45325Sbostic eval(e)
624*45325Sbostic register struct enode *e;
625*45325Sbostic {
626*45325Sbostic     if (e == (struct enode *)0) return (double)0;
627*45325Sbostic     switch (e->op) {
628*45325Sbostic 	case '+':	return (eval(e->e.o.left) + eval(e->e.o.right));
629*45325Sbostic 	case '-':	return (eval(e->e.o.left) - eval(e->e.o.right));
630*45325Sbostic 	case '*':	return (eval(e->e.o.left) * eval(e->e.o.right));
631*45325Sbostic 	case '/':       return (eval(e->e.o.left) / eval(e->e.o.right));
632*45325Sbostic 	case '%':     {	double num, denom;
633*45325Sbostic 			num = floor(eval(e->e.o.left));
634*45325Sbostic 			denom = floor(eval (e->e.o.right));
635*45325Sbostic 			return denom ? num - floor(num/denom)*denom : (double)0; }
636*45325Sbostic 	case '^':	return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right)));
637*45325Sbostic 	case '<':	return (eval(e->e.o.left) < eval(e->e.o.right));
638*45325Sbostic 	case '=':	return (eval(e->e.o.left) == eval(e->e.o.right));
639*45325Sbostic 	case '>':	return (eval(e->e.o.left) > eval(e->e.o.right));
640*45325Sbostic 	case '&':	return (eval(e->e.o.left) && eval(e->e.o.right));
641*45325Sbostic 	case '|':	return (eval(e->e.o.left) || eval(e->e.o.right));
642*45325Sbostic 	case IF:
643*45325Sbostic 	case '?':	return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
644*45325Sbostic 						: eval(e->e.o.right->e.o.right);
645*45325Sbostic 	case 'm':	return (-eval(e->e.o.right));
646*45325Sbostic 	case 'f':	return (eval(e->e.o.right));
647*45325Sbostic 	case '~':	return (eval(e->e.o.right) == 0.0);
648*45325Sbostic 	case 'k':	return (e->e.k);
649*45325Sbostic 	case 'v':	return (e->e.v.vp->v);
650*45325Sbostic 	case INDEX:
651*45325Sbostic 	case LOOKUP:
652*45325Sbostic 	case HLOOKUP:
653*45325Sbostic 	case VLOOKUP:
654*45325Sbostic 	    {	register r,c;
655*45325Sbostic 		register maxr, maxc;
656*45325Sbostic 		register minr, minc;
657*45325Sbostic 		maxr = e->e.o.right->e.r.right.vp -> row;
658*45325Sbostic 		maxc = e->e.o.right->e.r.right.vp -> col;
659*45325Sbostic 		minr = e->e.o.right->e.r.left.vp -> row;
660*45325Sbostic 		minc = e->e.o.right->e.r.left.vp -> col;
661*45325Sbostic 		if (minr>maxr) r = maxr, maxr = minr, minr = r;
662*45325Sbostic 		if (minc>maxc) c = maxc, maxc = minc, minc = c;
663*45325Sbostic 		switch(e->op){
664*45325Sbostic 		case LOOKUP:
665*45325Sbostic 		    return dolookup(e->e.o.left, minr, minc, maxr, maxc,
666*45325Sbostic 				     minr==maxr, minc==maxc);
667*45325Sbostic 		case HLOOKUP:
668*45325Sbostic 	            return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
669*45325Sbostic 			(int) eval(e->e.o.left->e.o.right), 0);
670*45325Sbostic 		case VLOOKUP:
671*45325Sbostic 	            return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
672*45325Sbostic 			0, (int) eval(e->e.o.left->e.o.right));
673*45325Sbostic 		case INDEX:
674*45325Sbostic 		    return doindex(eval(e->e.o.left), minr, minc, maxr, maxc);
675*45325Sbostic 		}
676*45325Sbostic 	    }
677*45325Sbostic 	case REDUCE | '+':
678*45325Sbostic  	case REDUCE | '*':
679*45325Sbostic  	case REDUCE | 'a':
680*45325Sbostic  	case REDUCE | 'c':
681*45325Sbostic  	case REDUCE | 's':
682*45325Sbostic 	case REDUCE | MAX:
683*45325Sbostic 	case REDUCE | MIN:
684*45325Sbostic 	    {	register r,c;
685*45325Sbostic 		register maxr, maxc;
686*45325Sbostic 		register minr, minc;
687*45325Sbostic 		maxr = e->e.r.right.vp -> row;
688*45325Sbostic 		maxc = e->e.r.right.vp -> col;
689*45325Sbostic 		minr = e->e.r.left.vp -> row;
690*45325Sbostic 		minc = e->e.r.left.vp -> col;
691*45325Sbostic 		if (minr>maxr) r = maxr, maxr = minr, minr = r;
692*45325Sbostic 		if (minc>maxc) c = maxc, maxc = minc, minc = c;
693*45325Sbostic 	        switch (e->op) {
694*45325Sbostic 	            case REDUCE | '+': return dosum(minr, minc, maxr, maxc);
695*45325Sbostic  	            case REDUCE | '*': return doprod(minr, minc, maxr, maxc);
696*45325Sbostic  	            case REDUCE | 'a': return doavg(minr, minc, maxr, maxc);
697*45325Sbostic  	            case REDUCE | 'c': return docount(minr, minc, maxr, maxc);
698*45325Sbostic  	            case REDUCE | 's': return dostddev(minr, minc, maxr, maxc);
699*45325Sbostic  	            case REDUCE | MAX: return domax(minr, minc, maxr, maxc);
700*45325Sbostic  	            case REDUCE | MIN: return domin(minr, minc, maxr, maxc);
701*45325Sbostic 		}
702*45325Sbostic 	    }
703*45325Sbostic 	case ABS:	 return (fn1_eval( fabs, eval(e->e.o.right)));
704*45325Sbostic 	case ACOS:	 return (fn1_eval( acos, eval(e->e.o.right)));
705*45325Sbostic 	case ASIN:	 return (fn1_eval( asin, eval(e->e.o.right)));
706*45325Sbostic 	case ATAN:	 return (fn1_eval( atan, eval(e->e.o.right)));
707*45325Sbostic 	case ATAN2:	 return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right)));
708*45325Sbostic 	case CEIL:	 return (fn1_eval( ceil, eval(e->e.o.right)));
709*45325Sbostic 	case COS:	 return (fn1_eval( cos, eval(e->e.o.right)));
710*45325Sbostic 	case EXP:	 return (fn1_eval( exp, eval(e->e.o.right)));
711*45325Sbostic 	case FABS:	 return (fn1_eval( fabs, eval(e->e.o.right)));
712*45325Sbostic 	case FLOOR:	 return (fn1_eval( floor, eval(e->e.o.right)));
713*45325Sbostic 	case HYPOT:	 return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right)));
714*45325Sbostic 	case LOG:	 return (fn1_eval( log, eval(e->e.o.right)));
715*45325Sbostic 	case LOG10:	 return (fn1_eval( log10, eval(e->e.o.right)));
716*45325Sbostic 	case POW:	 return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right)));
717*45325Sbostic 	case SIN:	 return (fn1_eval( sin, eval(e->e.o.right)));
718*45325Sbostic 	case SQRT:	 return (fn1_eval( sqrt, eval(e->e.o.right)));
719*45325Sbostic 	case TAN:	 return (fn1_eval( tan, eval(e->e.o.right)));
720*45325Sbostic 	case DTR:	 return (dtr(eval(e->e.o.right)));
721*45325Sbostic 	case RTD:	 return (rtd(eval(e->e.o.right)));
722*45325Sbostic 	case RND:	 {
723*45325Sbostic 			    double temp;
724*45325Sbostic 			    temp = eval(e->e.o.right);
725*45325Sbostic 			    return(temp-floor(temp) < 0.5 ?
726*45325Sbostic 					     floor(temp) : ceil(temp));
727*45325Sbostic 			}
728*45325Sbostic  	case ROUND:	{
729*45325Sbostic 			    double temp = eval(e->e.o.left);
730*45325Sbostic 			    int prec = (int) eval(e->e.o.right), scal = 1;
731*45325Sbostic 			    while (prec-- > 0) scal *= 10;
732*45325Sbostic 			    temp *= scal;
733*45325Sbostic 			    temp = ((temp-floor(temp)) < 0.5 ?
734*45325Sbostic 				    floor(temp) : ceil(temp));
735*45325Sbostic 			    return(temp / scal);
736*45325Sbostic 			}
737*45325Sbostic 	case FV:
738*45325Sbostic 	case PV:
739*45325Sbostic 	case PMT:	return(finfunc(e->op,eval(e->e.o.left),
740*45325Sbostic 				   eval(e->e.o.right->e.o.left),
741*45325Sbostic 				      eval(e->e.o.right->e.o.right)));
742*45325Sbostic 	case HOUR:	 return (dotime(HOUR, eval(e->e.o.right)));
743*45325Sbostic 	case MINUTE:	 return (dotime(MINUTE, eval(e->e.o.right)));
744*45325Sbostic 	case SECOND:	 return (dotime(SECOND, eval(e->e.o.right)));
745*45325Sbostic 	case MONTH:	 return (dotime(MONTH, eval(e->e.o.right)));
746*45325Sbostic 	case DAY:	 return (dotime(DAY, eval(e->e.o.right)));
747*45325Sbostic 	case YEAR:	 return (dotime(YEAR, eval(e->e.o.right)));
748*45325Sbostic 	case NOW:	 return (dotime(NOW, (double)0.0));
749*45325Sbostic 	case DTS:	 return (dodts((int)eval(e->e.o.left),
750*45325Sbostic 				 (int)eval(e->e.o.right->e.o.left),
751*45325Sbostic 				 (int)eval(e->e.o.right->e.o.right)));
752*45325Sbostic 	case TTS:	 return (dotts((int)eval(e->e.o.left),
753*45325Sbostic 				 (int)eval(e->e.o.right->e.o.left),
754*45325Sbostic 				 (int)eval(e->e.o.right->e.o.right)));
755*45325Sbostic 	case STON:	 return (doston(seval(e->e.o.right)));
756*45325Sbostic 	case EQS:        return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
757*45325Sbostic 	case LMAX:	 return dolmax(e);
758*45325Sbostic 	case LMIN:	 return dolmin(e);
759*45325Sbostic 	case NVAL:       return (donval(seval(e->e.o.left),eval(e->e.o.right)));
760*45325Sbostic 	default:	 error ("Illegal numeric expression");
761*45325Sbostic 			 exprerr = 1;
762*45325Sbostic     }
763*45325Sbostic     return((double)0.0);
764*45325Sbostic }
765*45325Sbostic 
766*45325Sbostic #ifdef SIGVOID
767*45325Sbostic void
768*45325Sbostic #endif
eval_fpe(signo)769*45325Sbostic eval_fpe(signo) /* Trap for FPE errors in eval */
770*45325Sbostic int signo;
771*45325Sbostic {
772*45325Sbostic #ifdef IEEE_MATH
773*45325Sbostic 	(void)fpsetsticky((fp_except)0); 		/* Clear exception */
774*45325Sbostic #endif /* IEEE_MATH */
775*45325Sbostic 	longjmp(fpe_save, 1);
776*45325Sbostic }
777*45325Sbostic 
778*45325Sbostic double fn1_eval(fn, arg)
779*45325Sbostic double (*fn)();
780*45325Sbostic double arg;
781*45325Sbostic {
782*45325Sbostic 	double res;
783*45325Sbostic 	errno = 0;
784*45325Sbostic 	res = (*fn)(arg);
785*45325Sbostic 	if(errno)
786*45325Sbostic 	  eval_fpe(0);
787*45325Sbostic 
788*45325Sbostic 	return res;
789*45325Sbostic }
790*45325Sbostic 
791*45325Sbostic double fn2_eval(fn, arg1, arg2)
792*45325Sbostic double (*fn)();
793*45325Sbostic double arg1, arg2;
794*45325Sbostic {
795*45325Sbostic 	double res;
796*45325Sbostic 	errno = 0;
797*45325Sbostic 	res = (*fn)(arg1, arg2);
798*45325Sbostic 	if(errno)
799*45325Sbostic 	    eval_fpe(0);
800*45325Sbostic 
801*45325Sbostic 	return res;
802*45325Sbostic }
803*45325Sbostic 
804*45325Sbostic /*
805*45325Sbostic  * Rules for string functions:
806*45325Sbostic  * Take string arguments which they xfree.
807*45325Sbostic  * All returned strings are assumed to be xalloced.
808*45325Sbostic  */
809*45325Sbostic 
810*45325Sbostic char *
docat(s1,s2)811*45325Sbostic docat(s1, s2)
812*45325Sbostic register char *s1, *s2;
813*45325Sbostic {
814*45325Sbostic     register char *p;
815*45325Sbostic     char *arg1, *arg2;
816*45325Sbostic 
817*45325Sbostic     if (!s1 && !s2)
818*45325Sbostic 	return((char *)0);
819*45325Sbostic     arg1 = s1 ? s1 : "";
820*45325Sbostic     arg2 = s2 ? s2 : "";
821*45325Sbostic     p = xmalloc((unsigned)(strlen(arg1)+strlen(arg2)+1));
822*45325Sbostic     (void) strcpy(p, arg1);
823*45325Sbostic     (void) strcat(p, arg2);
824*45325Sbostic     if (s1)
825*45325Sbostic         xfree(s1);
826*45325Sbostic     if (s2)
827*45325Sbostic         xfree(s2);
828*45325Sbostic     return(p);
829*45325Sbostic }
830*45325Sbostic 
831*45325Sbostic char *
dodate(tloc)832*45325Sbostic dodate(tloc)
833*45325Sbostic long tloc;
834*45325Sbostic {
835*45325Sbostic     char *tp;
836*45325Sbostic     char *p;
837*45325Sbostic 
838*45325Sbostic     tp = ctime(&tloc);
839*45325Sbostic     tp[24] = '\0';
840*45325Sbostic     p = xmalloc((unsigned)25);
841*45325Sbostic     (void) strcpy(p, tp);
842*45325Sbostic     return(p);
843*45325Sbostic }
844*45325Sbostic 
845*45325Sbostic 
846*45325Sbostic char *
dofmt(fmtstr,v)847*45325Sbostic dofmt(fmtstr, v)
848*45325Sbostic char *fmtstr;
849*45325Sbostic double v;
850*45325Sbostic {
851*45325Sbostic     char buff[FBUFLEN];
852*45325Sbostic     char *p;
853*45325Sbostic 
854*45325Sbostic     if (!fmtstr)
855*45325Sbostic 	return((char *)0);
856*45325Sbostic     (void)sprintf(buff, fmtstr, v);
857*45325Sbostic     p = xmalloc((unsigned)(strlen(buff)+1));
858*45325Sbostic     (void) strcpy(p, buff);
859*45325Sbostic     xfree(fmtstr);
860*45325Sbostic     return(p);
861*45325Sbostic }
862*45325Sbostic 
863*45325Sbostic 
864*45325Sbostic /*
865*45325Sbostic  * Given a command name and a value, run the command with the given value and
866*45325Sbostic  * read and return its first output line (only) as an allocated string, always
867*45325Sbostic  * a copy of prevstr, which is set appropriately first unless external
868*45325Sbostic  * functions are disabled, in which case the previous value is used.  The
869*45325Sbostic  * handling of prevstr and freeing of command is tricky.  Returning an
870*45325Sbostic  * allocated string in all cases, even if null, insures cell expressions are
871*45325Sbostic  * written to files, etc.
872*45325Sbostic  */
873*45325Sbostic 
874*45325Sbostic #ifdef VMS
875*45325Sbostic char *
doext(command,value)876*45325Sbostic doext(command, value)
877*45325Sbostic char *command;
878*45325Sbostic double value;
879*45325Sbostic {
880*45325Sbostic     error("Warning: External functions unavailable on VMS");
881*45325Sbostic     if (command)
882*45325Sbostic 	xfree(command);
883*45325Sbostic     return (strcpy (xmalloc((unsigned) 1), "\0"));
884*45325Sbostic }
885*45325Sbostic 
886*45325Sbostic #else /* VMS */
887*45325Sbostic 
888*45325Sbostic char *
doext(command,value)889*45325Sbostic doext (command, value)
890*45325Sbostic char   *command;
891*45325Sbostic double value;
892*45325Sbostic {
893*45325Sbostic     static char *prevstr = (char *)0;	/* previous result */
894*45325Sbostic     char buff[FBUFLEN];		/* command line/return, not permanently alloc */
895*45325Sbostic 
896*45325Sbostic     if (!prevstr) {
897*45325Sbostic 	prevstr = xmalloc((unsigned)1);
898*45325Sbostic 	*prevstr = '\0';
899*45325Sbostic     }
900*45325Sbostic     if (!extfunc)    {
901*45325Sbostic 	error ("Warning: external functions disabled; using %s value",
902*45325Sbostic 		prevstr ? "previous" : "null");
903*45325Sbostic 
904*45325Sbostic 	if (command) xfree (command);
905*45325Sbostic     } else {
906*45325Sbostic 	if (prevstr) xfree (prevstr);		/* no longer needed */
907*45325Sbostic 	prevstr = '\0';
908*45325Sbostic 
909*45325Sbostic 	if ((! command) || (! *command)) {
910*45325Sbostic 	    error ("Warning: external function given null command name");
911*45325Sbostic 	    if (command) xfree (command);
912*45325Sbostic 	} else {
913*45325Sbostic 	    FILE *pp;
914*45325Sbostic 
915*45325Sbostic 	    (void) sprintf (buff, "%s %g", command, value); /* build cmd line */
916*45325Sbostic 	    xfree (command);
917*45325Sbostic 
918*45325Sbostic 	    error ("Running external function...");
919*45325Sbostic 	    (void) refresh();
920*45325Sbostic 
921*45325Sbostic 	    if ((pp = popen (buff, "r")) == (FILE *) NULL)	/* run it */
922*45325Sbostic 		error ("Warning: running \"%s\" failed", buff);
923*45325Sbostic 	    else {
924*45325Sbostic 		if (fgets (buff, sizeof(buff)-1, pp) == NULL)	/* one line */
925*45325Sbostic 		    error ("Warning: external function returned nothing");
926*45325Sbostic 		else {
927*45325Sbostic 		    char *cp;
928*45325Sbostic 
929*45325Sbostic 		    error ("");				/* erase notice */
930*45325Sbostic 		    buff[sizeof(buff)-1] = '\0';
931*45325Sbostic 
932*45325Sbostic 		    if (cp = strchr (buff, '\n'))	/* contains newline */
933*45325Sbostic 			*cp = '\0';			/* end string there */
934*45325Sbostic 
935*45325Sbostic 		    (void) strcpy (prevstr =
936*45325Sbostic 			 xmalloc ((unsigned) (strlen (buff) + 1)), buff);
937*45325Sbostic 			 /* save alloc'd copy */
938*45325Sbostic 		}
939*45325Sbostic 		(void) pclose (pp);
940*45325Sbostic 
941*45325Sbostic 	    } /* else */
942*45325Sbostic 	} /* else */
943*45325Sbostic     } /* else */
944*45325Sbostic     return (strcpy (xmalloc ((unsigned) (strlen (prevstr) + 1)), prevstr));
945*45325Sbostic }
946*45325Sbostic 
947*45325Sbostic #endif /* VMS */
948*45325Sbostic 
949*45325Sbostic 
950*45325Sbostic /*
951*45325Sbostic  * Given a string representing a column name and a value which is a column
952*45325Sbostic  * number, return the selected cell's string value, if any.  Even if none,
953*45325Sbostic  * still allocate and return a null string so the cell has a label value so
954*45325Sbostic  * the expression is saved in a file, etc.
955*45325Sbostic  */
956*45325Sbostic 
957*45325Sbostic char *
dosval(colstr,rowdoub)958*45325Sbostic dosval (colstr, rowdoub)
959*45325Sbostic     char *colstr;
960*45325Sbostic     double rowdoub;
961*45325Sbostic {
962*45325Sbostic     struct ent *ep;
963*45325Sbostic     char *label;
964*45325Sbostic 
965*45325Sbostic     label = (ep = getent (colstr, rowdoub)) ? (ep -> label) : "";
966*45325Sbostic     return (strcpy (xmalloc ((unsigned) (strlen (label) + 1)), label));
967*45325Sbostic }
968*45325Sbostic 
969*45325Sbostic 
970*45325Sbostic /*
971*45325Sbostic  * Substring:  Note that v1 and v2 are one-based to users, but zero-based
972*45325Sbostic  * when calling this routine.
973*45325Sbostic  */
974*45325Sbostic 
975*45325Sbostic char *
dosubstr(s,v1,v2)976*45325Sbostic dosubstr(s, v1, v2)
977*45325Sbostic char *s;
978*45325Sbostic register int v1,v2;
979*45325Sbostic {
980*45325Sbostic     register char *s1, *s2;
981*45325Sbostic     char *p;
982*45325Sbostic 
983*45325Sbostic     if (!s)
984*45325Sbostic 	return((char *)0);
985*45325Sbostic 
986*45325Sbostic     if (v2 >= strlen (s))		/* past end */
987*45325Sbostic 	v2 =  strlen (s) - 1;		/* to end   */
988*45325Sbostic 
989*45325Sbostic     if (v1 < 0 || v1 > v2) {		/* out of range, return null string */
990*45325Sbostic 	xfree(s);
991*45325Sbostic 	p = xmalloc((unsigned)1);
992*45325Sbostic 	p[0] = '\0';
993*45325Sbostic 	return(p);
994*45325Sbostic     }
995*45325Sbostic     s2 = p = xmalloc((unsigned)(v2-v1+2));
996*45325Sbostic     s1 = &s[v1];
997*45325Sbostic     for(; v1 <= v2; s1++, s2++, v1++)
998*45325Sbostic 	*s2 = *s1;
999*45325Sbostic     *s2 = '\0';
1000*45325Sbostic     xfree(s);
1001*45325Sbostic     return(p);
1002*45325Sbostic }
1003*45325Sbostic 
1004*45325Sbostic char *
seval(se)1005*45325Sbostic seval(se)
1006*45325Sbostic register struct enode *se;
1007*45325Sbostic {
1008*45325Sbostic     register char *p;
1009*45325Sbostic 
1010*45325Sbostic     if (se == (struct enode *)0) return (char *)0;
1011*45325Sbostic     switch (se->op) {
1012*45325Sbostic 	case O_SCONST: p = xmalloc((unsigned)(strlen(se->e.s)+1));
1013*45325Sbostic 		     (void) strcpy(p, se->e.s);
1014*45325Sbostic 		     return(p);
1015*45325Sbostic 	case O_VAR:    {
1016*45325Sbostic 			struct ent *ep;
1017*45325Sbostic 			ep = se->e.v.vp;
1018*45325Sbostic 
1019*45325Sbostic 			if (!ep->label)
1020*45325Sbostic 			    return((char *)0);
1021*45325Sbostic 			p = xmalloc((unsigned)(strlen(ep->label)+1));
1022*45325Sbostic 			(void) strcpy(p, ep->label);
1023*45325Sbostic 			return(p);
1024*45325Sbostic 		     }
1025*45325Sbostic 	case '#':    return(docat(seval(se->e.o.left), seval(se->e.o.right)));
1026*45325Sbostic 	case 'f':    return(seval(se->e.o.right));
1027*45325Sbostic 	case IF:
1028*45325Sbostic 	case '?':    return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
1029*45325Sbostic 					     : seval(se->e.o.right->e.o.right));
1030*45325Sbostic 	case DATE:   return(dodate((long)(eval(se->e.o.right))));
1031*45325Sbostic 	case FMT:    return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
1032*45325Sbostic  	case STINDEX:
1033*45325Sbostic  		{	register r,c;
1034*45325Sbostic  		register maxr, maxc;
1035*45325Sbostic  		register minr, minc;
1036*45325Sbostic  		maxr = se->e.o.right->e.r.right.vp -> row;
1037*45325Sbostic  		maxc = se->e.o.right->e.r.right.vp -> col;
1038*45325Sbostic  		minr = se->e.o.right->e.r.left.vp -> row;
1039*45325Sbostic  		minc = se->e.o.right->e.r.left.vp -> col;
1040*45325Sbostic  		if (minr>maxr) r = maxr, maxr = minr, minr = r;
1041*45325Sbostic  		if (minc>maxc) c = maxc, maxc = minc, minc = c;
1042*45325Sbostic  	        return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc);
1043*45325Sbostic 		}
1044*45325Sbostic 	case EXT:    return(doext(seval(se->e.o.left), eval(se->e.o.right)));
1045*45325Sbostic 	case SVAL:   return(dosval(seval(se->e.o.left), eval(se->e.o.right)));
1046*45325Sbostic 	case SUBSTR: return(dosubstr(seval(se->e.o.left),
1047*45325Sbostic 			    (int)eval(se->e.o.right->e.o.left) - 1,
1048*45325Sbostic 			    (int)eval(se->e.o.right->e.o.right) - 1));
1049*45325Sbostic 	default:
1050*45325Sbostic 		     error ("Illegal string expression");
1051*45325Sbostic 		     exprerr = 1;
1052*45325Sbostic 		     return((char *)0);
1053*45325Sbostic 	}
1054*45325Sbostic }
1055*45325Sbostic 
1056*45325Sbostic /*
1057*45325Sbostic  * The graph formed by cell expressions which use other cells's values is not
1058*45325Sbostic  * evaluated "bottom up".  The whole table is merely re-evaluated cell by cell,
1059*45325Sbostic  * top to bottom, left to right, in RealEvalAll().  Each cell's expression uses
1060*45325Sbostic  * constants in other cells.  However, RealEvalAll() notices when a cell gets a
1061*45325Sbostic  * new numeric or string value, and reports if this happens for any cell.
1062*45325Sbostic  * EvalAll() repeats calling RealEvalAll() until there are no changes or the
1063*45325Sbostic  * evaluation count expires.
1064*45325Sbostic  */
1065*45325Sbostic 
1066*45325Sbostic int propagation = 10;	/* max number of times to try calculation */
1067*45325Sbostic 
1068*45325Sbostic void
setiterations(i)1069*45325Sbostic setiterations(i)
1070*45325Sbostic int i;
1071*45325Sbostic {
1072*45325Sbostic 	if(i<1) {
1073*45325Sbostic 		error("iteration count must be at least 1");
1074*45325Sbostic 		propagation = 1;
1075*45325Sbostic 		}
1076*45325Sbostic 	else propagation = i;
1077*45325Sbostic }
1078*45325Sbostic 
1079*45325Sbostic void
EvalAll()1080*45325Sbostic EvalAll () {
1081*45325Sbostic       int lastcnt, repct = 0;
1082*45325Sbostic 
1083*45325Sbostic      while ((lastcnt = RealEvalAll()) && (repct++ <= propagation));
1084*45325Sbostic      if((propagation>1)&& (lastcnt >0 ))
1085*45325Sbostic  	    error("Still changing after %d iterations",propagation-1);
1086*45325Sbostic }
1087*45325Sbostic 
1088*45325Sbostic /*
1089*45325Sbostic  * Evaluate all cells which have expressions and alter their numeric or string
1090*45325Sbostic  * values.  Return the number of cells which changed.
1091*45325Sbostic  */
1092*45325Sbostic 
1093*45325Sbostic int
RealEvalAll()1094*45325Sbostic RealEvalAll () {
1095*45325Sbostic     register int i,j;
1096*45325Sbostic     int chgct = 0;
1097*45325Sbostic     register struct ent *p;
1098*45325Sbostic 
1099*45325Sbostic     (void) signal(SIGFPE, eval_fpe);
1100*45325Sbostic #ifdef EXPRTREE
1101*45325Sbostic     for (p = firstev; p; p = p->evnext)
1102*45325Sbostic 	    RealEvalOne(p, &chgct);
1103*45325Sbostic #else
1104*45325Sbostic     if(calc_order == BYROWS ) {
1105*45325Sbostic 	for (i=0; i<=maxrow; i++)
1106*45325Sbostic 	    for (j=0; j<=maxcol; j++)
1107*45325Sbostic 		if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
1108*45325Sbostic     }
1109*45325Sbostic     else if ( calc_order == BYCOLS ) {
1110*45325Sbostic 	for (j=0; j<=maxcol; j++)
1111*45325Sbostic 	{   for (i=0; i<=maxrow; i++)
1112*45325Sbostic 		if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
1113*45325Sbostic 	}
1114*45325Sbostic     }
1115*45325Sbostic     else error("Internal error calc_order");
1116*45325Sbostic #endif
1117*45325Sbostic 
1118*45325Sbostic     (void) signal(SIGFPE, quit);
1119*45325Sbostic     return(chgct);
1120*45325Sbostic }
1121*45325Sbostic 
1122*45325Sbostic void
1123*45325Sbostic #ifdef EXPRTREE
RealEvalOne(p,chgct)1124*45325Sbostic RealEvalOne(p, chgct)
1125*45325Sbostic register struct ent *p;
1126*45325Sbostic int *chgct;
1127*45325Sbostic #else
1128*45325Sbostic RealEvalOne(p, i, j, chgct)
1129*45325Sbostic register struct ent *p;
1130*45325Sbostic int i, j, *chgct;
1131*45325Sbostic #endif
1132*45325Sbostic {
1133*45325Sbostic 	if (p->flags & is_strexpr) {
1134*45325Sbostic 	    char *v;
1135*45325Sbostic 	    if (setjmp(fpe_save)) {
1136*45325Sbostic #ifdef EXPRTREE
1137*45325Sbostic 		error("Floating point exception %s", v_name(p->row, p->col));
1138*45325Sbostic #else
1139*45325Sbostic 		error("Floating point exception %s", v_name(i, j));
1140*45325Sbostic #endif
1141*45325Sbostic 		v = "";
1142*45325Sbostic 	    } else {
1143*45325Sbostic 		v = seval(p->expr);
1144*45325Sbostic 	    }
1145*45325Sbostic 	    if (!v && !p->label) /* Everything's fine */
1146*45325Sbostic 		return;
1147*45325Sbostic 	    if (!p->label || !v || strcmp(v, p->label) != 0) {
1148*45325Sbostic 		(*chgct)++;
1149*45325Sbostic 		p->flags |= is_changed;
1150*45325Sbostic 		changed++;
1151*45325Sbostic 	    }
1152*45325Sbostic 	    if(p->label)
1153*45325Sbostic 		xfree(p->label);
1154*45325Sbostic 	    p->label = v;
1155*45325Sbostic 	} else {
1156*45325Sbostic 	    double v;
1157*45325Sbostic 	    if (setjmp(fpe_save)) {
1158*45325Sbostic #ifdef EXPRTREE
1159*45325Sbostic 		error("Floating point exception %s", v_name(p->row, p->col));
1160*45325Sbostic #else
1161*45325Sbostic 		error("Floating point exception %s", v_name(i, j));
1162*45325Sbostic #endif
1163*45325Sbostic 		v = (double)0.0;
1164*45325Sbostic 	    } else {
1165*45325Sbostic 		v = eval (p->expr);
1166*45325Sbostic 	    }
1167*45325Sbostic 	    if (v != p->v) {
1168*45325Sbostic 		p->v = v; (*chgct)++;
1169*45325Sbostic 		p->flags |= is_changed|is_valid;
1170*45325Sbostic 		changed++;
1171*45325Sbostic 	    }
1172*45325Sbostic 	}
1173*45325Sbostic }
1174*45325Sbostic 
1175*45325Sbostic struct enode *
new(op,a1,a2)1176*45325Sbostic new(op, a1, a2)
1177*45325Sbostic int	op;
1178*45325Sbostic struct enode *a1, *a2;
1179*45325Sbostic {
1180*45325Sbostic     register struct enode *p;
1181*45325Sbostic     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
1182*45325Sbostic     p->op = op;
1183*45325Sbostic     p->e.o.left = a1;
1184*45325Sbostic     p->e.o.right = a2;
1185*45325Sbostic     return p;
1186*45325Sbostic }
1187*45325Sbostic 
1188*45325Sbostic struct enode *
new_var(op,a1)1189*45325Sbostic new_var(op, a1)
1190*45325Sbostic int	op;
1191*45325Sbostic struct ent_ptr a1;
1192*45325Sbostic {
1193*45325Sbostic     register struct enode *p;
1194*45325Sbostic     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
1195*45325Sbostic     p->op = op;
1196*45325Sbostic     p->e.v = a1;
1197*45325Sbostic     return p;
1198*45325Sbostic }
1199*45325Sbostic 
1200*45325Sbostic struct enode *
new_range(op,a1)1201*45325Sbostic new_range(op, a1)
1202*45325Sbostic int	op;
1203*45325Sbostic struct range_s a1;
1204*45325Sbostic {
1205*45325Sbostic     register struct enode *p;
1206*45325Sbostic     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
1207*45325Sbostic     p->op = op;
1208*45325Sbostic     p->e.r = a1;
1209*45325Sbostic     return p;
1210*45325Sbostic }
1211*45325Sbostic 
1212*45325Sbostic struct enode *
new_const(op,a1)1213*45325Sbostic new_const(op, a1)
1214*45325Sbostic int	op;
1215*45325Sbostic double a1;
1216*45325Sbostic {
1217*45325Sbostic     register struct enode *p;
1218*45325Sbostic     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
1219*45325Sbostic     p->op = op;
1220*45325Sbostic     p->e.k = a1;
1221*45325Sbostic     return p;
1222*45325Sbostic }
1223*45325Sbostic 
1224*45325Sbostic struct enode *
new_str(s)1225*45325Sbostic new_str(s)
1226*45325Sbostic char *s;
1227*45325Sbostic {
1228*45325Sbostic     register struct enode *p;
1229*45325Sbostic 
1230*45325Sbostic     p = (struct enode *) xmalloc ((unsigned)sizeof(struct enode));
1231*45325Sbostic     p->op = O_SCONST;
1232*45325Sbostic     p->e.s = s;
1233*45325Sbostic     return(p);
1234*45325Sbostic }
1235*45325Sbostic 
1236*45325Sbostic void
copy(dv1,dv2,v1,v2)1237*45325Sbostic copy(dv1, dv2, v1, v2)
1238*45325Sbostic struct ent *dv1, *dv2, *v1, *v2;
1239*45325Sbostic {
1240*45325Sbostic     int minsr, minsc;
1241*45325Sbostic     int maxsr, maxsc;
1242*45325Sbostic     int mindr, mindc;
1243*45325Sbostic     int maxdr, maxdc;
1244*45325Sbostic     int vr, vc;
1245*45325Sbostic     int r, c;
1246*45325Sbostic 
1247*45325Sbostic     mindr = dv1->row;
1248*45325Sbostic     mindc = dv1->col;
1249*45325Sbostic     maxdr = dv2->row;
1250*45325Sbostic     maxdc = dv2->col;
1251*45325Sbostic     if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
1252*45325Sbostic     if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
1253*45325Sbostic     maxsr = v2->row;
1254*45325Sbostic     maxsc = v2->col;
1255*45325Sbostic     minsr = v1->row;
1256*45325Sbostic     minsc = v1->col;
1257*45325Sbostic     if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
1258*45325Sbostic     if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
1259*45325Sbostic     checkbounds(&maxdr, &maxdc);
1260*45325Sbostic 
1261*45325Sbostic     erase_area(mindr, mindc, maxdr, maxdc);
1262*45325Sbostic     if (minsr == maxsr && minsc == maxsc) {
1263*45325Sbostic 	/* Source is a single cell */
1264*45325Sbostic 	for(vr = mindr; vr <= maxdr; vr++)
1265*45325Sbostic 	    for (vc = mindc; vc <= maxdc; vc++)
1266*45325Sbostic 		copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
1267*45325Sbostic     } else if (minsr == maxsr) {
1268*45325Sbostic 	/* Source is a single row */
1269*45325Sbostic 	for (vr = mindr; vr <= maxdr; vr++)
1270*45325Sbostic 	    copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
1271*45325Sbostic     } else if (minsc == maxsc) {
1272*45325Sbostic 	/* Source is a single column */
1273*45325Sbostic 	for (vc = mindc; vc <= maxdc; vc++)
1274*45325Sbostic 	    copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
1275*45325Sbostic     } else {
1276*45325Sbostic 	/* Everything else */
1277*45325Sbostic 	copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
1278*45325Sbostic     }
1279*45325Sbostic     sync_refs();
1280*45325Sbostic }
1281*45325Sbostic 
1282*45325Sbostic void
copyrtv(vr,vc,minsr,minsc,maxsr,maxsc)1283*45325Sbostic copyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
1284*45325Sbostic int vr, vc, minsr, minsc, maxsr, maxsc;
1285*45325Sbostic {
1286*45325Sbostic     register struct ent *p;
1287*45325Sbostic     register struct ent *n;
1288*45325Sbostic     register int sr, sc;
1289*45325Sbostic     register int dr, dc;
1290*45325Sbostic 
1291*45325Sbostic     for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
1292*45325Sbostic 	for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
1293*45325Sbostic 	    if (p = *ATBL(tbl, sr, sc))
1294*45325Sbostic 	    {	n = lookat (dr, dc);
1295*45325Sbostic 		(void) clearent(n);
1296*45325Sbostic 		copyent( n, p, dr - sr, dc - sc);
1297*45325Sbostic 	    }
1298*45325Sbostic 	    else
1299*45325Sbostic 	    if (n = *ATBL(tbl, dr, dc))
1300*45325Sbostic 		(void) clearent(n);
1301*45325Sbostic 	}
1302*45325Sbostic }
1303*45325Sbostic 
1304*45325Sbostic void
eraser(v1,v2)1305*45325Sbostic eraser(v1, v2)
1306*45325Sbostic struct ent *v1, *v2;
1307*45325Sbostic {
1308*45325Sbostic 	FullUpdate++;
1309*45325Sbostic 	flush_saved();
1310*45325Sbostic 	erase_area(v1->row, v1->col, v2->row, v2->col);
1311*45325Sbostic 	sync_refs();
1312*45325Sbostic }
1313*45325Sbostic 
1314*45325Sbostic /* Goto subroutines */
1315*45325Sbostic 
1316*45325Sbostic void
g_free()1317*45325Sbostic g_free()
1318*45325Sbostic {
1319*45325Sbostic     switch (gs.g_type) {
1320*45325Sbostic     case G_STR: xfree(gs.g_s); break;
1321*45325Sbostic     default: break;
1322*45325Sbostic     }
1323*45325Sbostic     gs.g_type = G_NONE;
1324*45325Sbostic }
1325*45325Sbostic 
1326*45325Sbostic void
go_last()1327*45325Sbostic go_last()
1328*45325Sbostic {
1329*45325Sbostic     switch (gs.g_type) {
1330*45325Sbostic     case G_NONE:
1331*45325Sbostic 		error("Nothing to repeat"); break;
1332*45325Sbostic     case G_NUM:
1333*45325Sbostic 		num_search(gs.g_n);
1334*45325Sbostic 		break;
1335*45325Sbostic     case  G_CELL:
1336*45325Sbostic 		moveto(gs.g_row, gs.g_col);
1337*45325Sbostic 	    	break;
1338*45325Sbostic     case  G_STR:
1339*45325Sbostic 		gs.g_type = G_NONE;	/* Don't free the string */
1340*45325Sbostic    	    	str_search(gs.g_s);
1341*45325Sbostic 	   	break;
1342*45325Sbostic 
1343*45325Sbostic     default: error("go_last: internal error");
1344*45325Sbostic     }
1345*45325Sbostic }
1346*45325Sbostic 
1347*45325Sbostic void
moveto(row,col)1348*45325Sbostic moveto(row, col)
1349*45325Sbostic int row, col;
1350*45325Sbostic {
1351*45325Sbostic     currow = row;
1352*45325Sbostic     curcol = col;
1353*45325Sbostic     g_free();
1354*45325Sbostic     gs.g_type = G_CELL;
1355*45325Sbostic     gs.g_row = currow;
1356*45325Sbostic     gs.g_col = curcol;
1357*45325Sbostic }
1358*45325Sbostic 
1359*45325Sbostic void
num_search(n)1360*45325Sbostic num_search(n)
1361*45325Sbostic double n;
1362*45325Sbostic {
1363*45325Sbostic     register struct ent *p;
1364*45325Sbostic     register int r,c;
1365*45325Sbostic     int	endr, endc;
1366*45325Sbostic 
1367*45325Sbostic     g_free();
1368*45325Sbostic     gs.g_type = G_NUM;
1369*45325Sbostic     gs.g_n = n;
1370*45325Sbostic 
1371*45325Sbostic     if (currow > maxrow)
1372*45325Sbostic 	endr = maxrow ? maxrow-1 : 0;
1373*45325Sbostic     else
1374*45325Sbostic 	endr = currow;
1375*45325Sbostic     if (curcol > maxcol)
1376*45325Sbostic 	endc = maxcol ? maxcol-1 : 0;
1377*45325Sbostic     else
1378*45325Sbostic 	endc = curcol;
1379*45325Sbostic     r = endr;
1380*45325Sbostic     c = endc;
1381*45325Sbostic     do {
1382*45325Sbostic 	if (c < maxcol)
1383*45325Sbostic 	    c++;
1384*45325Sbostic 	else {
1385*45325Sbostic 	    if (r < maxrow) {
1386*45325Sbostic 		while(++r < maxrow && row_hidden[r]) /* */;
1387*45325Sbostic 		c = 0;
1388*45325Sbostic 	    } else {
1389*45325Sbostic 		r = 0;
1390*45325Sbostic 		c = 0;
1391*45325Sbostic 	    }
1392*45325Sbostic 	}
1393*45325Sbostic 	if (r == endr && c == endc) {
1394*45325Sbostic 	    error("Number not found");
1395*45325Sbostic 	    return;
1396*45325Sbostic 	}
1397*45325Sbostic 	p = *ATBL(tbl, r, c);
1398*45325Sbostic     } while(col_hidden[c] || !p || p && (!(p->flags & is_valid)
1399*45325Sbostic                                         || (p->flags&is_valid) && p->v != n));
1400*45325Sbostic     currow = r;
1401*45325Sbostic     curcol = c;
1402*45325Sbostic }
1403*45325Sbostic 
1404*45325Sbostic void
str_search(s)1405*45325Sbostic str_search(s)
1406*45325Sbostic char *s;
1407*45325Sbostic {
1408*45325Sbostic     register struct ent *p;
1409*45325Sbostic     register int r,c;
1410*45325Sbostic     int	endr, endc;
1411*45325Sbostic     char *tmp;
1412*45325Sbostic 
1413*45325Sbostic #if defined(BSD42) || defined(BSD43)
1414*45325Sbostic     if ((tmp = re_comp(s)) != (char *)0) {
1415*45325Sbostic 	xfree(s);
1416*45325Sbostic 	error(tmp);
1417*45325Sbostic 	return;
1418*45325Sbostic     }
1419*45325Sbostic #endif
1420*45325Sbostic #if defined(SYSV2) || defined(SYSV3)
1421*45325Sbostic     if ((tmp = regcmp(s, (char *)0)) == (char *)0) {
1422*45325Sbostic 	xfree(s);
1423*45325Sbostic 	error("Invalid search string");
1424*45325Sbostic 	return;
1425*45325Sbostic     }
1426*45325Sbostic #endif
1427*45325Sbostic     g_free();
1428*45325Sbostic     gs.g_type = G_STR;
1429*45325Sbostic     gs.g_s = s;
1430*45325Sbostic     if (currow > maxrow)
1431*45325Sbostic 	endr = maxrow ? maxrow-1 : 0;
1432*45325Sbostic     else
1433*45325Sbostic 	endr = currow;
1434*45325Sbostic     if (curcol > maxcol)
1435*45325Sbostic 	endc = maxcol ? maxcol-1 : 0;
1436*45325Sbostic     else
1437*45325Sbostic 	endc = curcol;
1438*45325Sbostic     r = endr;
1439*45325Sbostic     c = endc;
1440*45325Sbostic     do {
1441*45325Sbostic 	if (c < maxcol)
1442*45325Sbostic 	    c++;
1443*45325Sbostic 	else {
1444*45325Sbostic 	    if (r < maxrow) {
1445*45325Sbostic 		while(++r < maxrow && row_hidden[r]) /* */;
1446*45325Sbostic 		c = 0;
1447*45325Sbostic 	    } else {
1448*45325Sbostic 		r = 0;
1449*45325Sbostic 		c = 0;
1450*45325Sbostic 	    }
1451*45325Sbostic 	}
1452*45325Sbostic 	if (r == endr && c == endc) {
1453*45325Sbostic 	    error("String not found");
1454*45325Sbostic #if defined(SYSV2) || defined(SYSV3)
1455*45325Sbostic 	    free(tmp);
1456*45325Sbostic #endif
1457*45325Sbostic 	    return;
1458*45325Sbostic 	}
1459*45325Sbostic 	p = *ATBL(tbl, r, c);
1460*45325Sbostic     } while(col_hidden[c] || !p || p && (!(p->label)
1461*45325Sbostic #if defined(BSD42) || defined(BSD43)
1462*45325Sbostic 		  			|| (re_exec(p->label) == 0)));
1463*45325Sbostic #else
1464*45325Sbostic #if defined(SYSV2) || defined(SYSV3)
1465*45325Sbostic                                        || (regex(tmp, p->label) == (char *)0)));
1466*45325Sbostic #else
1467*45325Sbostic                                        || (strcmp(s, p->label) != 0)));
1468*45325Sbostic #endif
1469*45325Sbostic #endif
1470*45325Sbostic     currow = r;
1471*45325Sbostic     curcol = c;
1472*45325Sbostic #if defined(SYSV2) || defined(SYSV3)
1473*45325Sbostic     free(tmp);
1474*45325Sbostic #endif
1475*45325Sbostic }
1476*45325Sbostic 
1477*45325Sbostic void
fill(v1,v2,start,inc)1478*45325Sbostic fill (v1, v2, start, inc)
1479*45325Sbostic struct ent *v1, *v2;
1480*45325Sbostic double start, inc;
1481*45325Sbostic {
1482*45325Sbostic     register r,c;
1483*45325Sbostic     register struct ent *n;
1484*45325Sbostic     int maxr, maxc;
1485*45325Sbostic     int minr, minc;
1486*45325Sbostic 
1487*45325Sbostic     maxr = v2->row;
1488*45325Sbostic     maxc = v2->col;
1489*45325Sbostic     minr = v1->row;
1490*45325Sbostic     minc = v1->col;
1491*45325Sbostic     if (minr>maxr) r = maxr, maxr = minr, minr = r;
1492*45325Sbostic     if (minc>maxc) c = maxc, maxc = minc, minc = c;
1493*45325Sbostic     checkbounds(&maxr, &maxc);
1494*45325Sbostic     if (minr < 0) minr = 0;
1495*45325Sbostic     if (minr < 0) minr = 0;
1496*45325Sbostic 
1497*45325Sbostic     FullUpdate++;
1498*45325Sbostic     if( calc_order == BYROWS ) {
1499*45325Sbostic     for (r = minr; r<=maxr; r++)
1500*45325Sbostic 	for (c = minc; c<=maxc; c++) {
1501*45325Sbostic 	    n = lookat (r, c);
1502*45325Sbostic 	    (void) clearent(n);
1503*45325Sbostic 	    n->v = start;
1504*45325Sbostic 	    start += inc;
1505*45325Sbostic 	    n->flags |= (is_changed|is_valid);
1506*45325Sbostic 	}
1507*45325Sbostic     }
1508*45325Sbostic     else if ( calc_order == BYCOLS ) {
1509*45325Sbostic     for (c = minc; c<=maxc; c++)
1510*45325Sbostic 	for (r = minr; r<=maxr; r++) {
1511*45325Sbostic 	    n = lookat (r, c);
1512*45325Sbostic 	    (void) clearent(n);
1513*45325Sbostic 	    n->v = start;
1514*45325Sbostic 	    start += inc;
1515*45325Sbostic 	    n->flags |= (is_changed|is_valid);
1516*45325Sbostic 	}
1517*45325Sbostic     }
1518*45325Sbostic     else error(" Internal error calc_order");
1519*45325Sbostic     changed++;
1520*45325Sbostic }
1521*45325Sbostic 
1522*45325Sbostic void
let(v,e)1523*45325Sbostic let (v, e)
1524*45325Sbostic struct ent *v;
1525*45325Sbostic struct enode *e;
1526*45325Sbostic {
1527*45325Sbostic     double val;
1528*45325Sbostic 
1529*45325Sbostic     exprerr = 0;
1530*45325Sbostic     (void) signal(SIGFPE, eval_fpe);
1531*45325Sbostic     if (setjmp(fpe_save)) {
1532*45325Sbostic 	error ("Floating point exception in cell %s", v_name(v->row, v->col));
1533*45325Sbostic 	val = (double)0.0;
1534*45325Sbostic     } else {
1535*45325Sbostic 	val = eval(e);
1536*45325Sbostic     }
1537*45325Sbostic     (void) signal(SIGFPE, quit);
1538*45325Sbostic     if (exprerr) {
1539*45325Sbostic 	efree((struct ent *)0, e);
1540*45325Sbostic 	return;
1541*45325Sbostic     }
1542*45325Sbostic     if (constant(e)) {
1543*45325Sbostic 	if (!loading)
1544*45325Sbostic 	    v->v = val * prescale;
1545*45325Sbostic 	else
1546*45325Sbostic 	    v->v = val;
1547*45325Sbostic 	if (!(v->flags & is_strexpr)) {
1548*45325Sbostic             efree(v, v->expr);
1549*45325Sbostic 	    v->expr = (struct enode *)0;
1550*45325Sbostic 	}
1551*45325Sbostic 	efree((struct ent *)0, e);
1552*45325Sbostic         v->flags |= (is_changed|is_valid);
1553*45325Sbostic         changed++;
1554*45325Sbostic         modflg++;
1555*45325Sbostic 	return;
1556*45325Sbostic     }
1557*45325Sbostic     efree (v, v->expr);
1558*45325Sbostic     v->expr = e;
1559*45325Sbostic     v->flags |= (is_changed|is_valid);
1560*45325Sbostic     v->flags &= ~is_strexpr;
1561*45325Sbostic 
1562*45325Sbostic #ifdef EXPRTREE
1563*45325Sbostic     totoptree(v);
1564*45325Sbostic #endif
1565*45325Sbostic     changed++;
1566*45325Sbostic     modflg++;
1567*45325Sbostic }
1568*45325Sbostic 
1569*45325Sbostic void
slet(v,se,flushdir)1570*45325Sbostic slet (v, se, flushdir)
1571*45325Sbostic struct ent *v;
1572*45325Sbostic struct enode *se;
1573*45325Sbostic int flushdir;
1574*45325Sbostic {
1575*45325Sbostic     char *p;
1576*45325Sbostic 
1577*45325Sbostic     exprerr = 0;
1578*45325Sbostic     (void) signal(SIGFPE, eval_fpe);
1579*45325Sbostic     if (setjmp(fpe_save)) {
1580*45325Sbostic 	error ("Floating point exception in cell %s", v_name(v->row, v->col));
1581*45325Sbostic 	p = "";
1582*45325Sbostic     } else {
1583*45325Sbostic 	p = seval(se);
1584*45325Sbostic     }
1585*45325Sbostic     (void) signal(SIGFPE, quit);
1586*45325Sbostic     if (exprerr) {
1587*45325Sbostic 	efree((struct ent *)0, se);
1588*45325Sbostic 	return;
1589*45325Sbostic     }
1590*45325Sbostic     if (constant(se)) {
1591*45325Sbostic 	label(v, p, flushdir);
1592*45325Sbostic 	if (p)
1593*45325Sbostic 	    xfree(p);
1594*45325Sbostic 	efree((struct ent *)0, se);
1595*45325Sbostic 	if (v->flags & is_strexpr) {
1596*45325Sbostic             efree (v, v->expr);
1597*45325Sbostic 	    v->expr = (struct enode *)0;
1598*45325Sbostic 	    v->flags &= ~is_strexpr;
1599*45325Sbostic 	}
1600*45325Sbostic 	return;
1601*45325Sbostic     }
1602*45325Sbostic     efree (v, v->expr);
1603*45325Sbostic     v->expr = se;
1604*45325Sbostic     v->flags |= (is_changed|is_strexpr);
1605*45325Sbostic     if (flushdir<0) v->flags |= is_leftflush;
1606*45325Sbostic     else v->flags &= ~is_leftflush;
1607*45325Sbostic 
1608*45325Sbostic #ifdef EXPRTREE
1609*45325Sbostic     totoptree();
1610*45325Sbostic #endif
1611*45325Sbostic     FullUpdate++;
1612*45325Sbostic     changed++;
1613*45325Sbostic     modflg++;
1614*45325Sbostic }
1615*45325Sbostic 
1616*45325Sbostic #ifdef EXPRTREE
1617*45325Sbostic /*
1618*45325Sbostic  * put an expression in the expression tree, only the top of each branch is
1619*45325Sbostic  * in the firstev list
1620*45325Sbostic  */
1621*45325Sbostic totoptree(v)
1622*45325Sbostic struct	ent *v;
1623*45325Sbostic {
1624*45325Sbostic     int	right;
1625*45325Sbostic     int	left;
1626*45325Sbostic     if (!v->expr)
1627*45325Sbostic 	return;
1628*45325Sbostic 
1629*45325Sbostic #ifdef notdef
1630*45325Sbostic     right = FALSE;
1631*45325Sbostic     left = FALSE;
1632*45325Sbostic     switch(v->expr->op)
1633*45325Sbostic     {
1634*45325Sbostic 		/* no real expression */
1635*45325Sbostic 	case 'v':
1636*45325Sbostic 		if (v->expr->o.v->evnext)
1637*45325Sbostic 			evdel(v->expr->o.v);
1638*45325Sbostic 	case 'k':
1639*45325Sbostic 	case LMAX:
1640*45325Sbostic 	case LMIN:
1641*45325Sbostic 	case NOW:
1642*45325Sbostic 	case O_SCONST:
1643*45325Sbostic 	case O_VAR:
1644*45325Sbostic 	default:
1645*45325Sbostic 		return;
1646*45325Sbostic 
1647*45325Sbostic 		/* left && right */
1648*45325Sbostic 	case '#':
1649*45325Sbostic 	case '%':
1650*45325Sbostic 	case '&':
1651*45325Sbostic 	case '*':
1652*45325Sbostic 	case '+':
1653*45325Sbostic 	case '-':
1654*45325Sbostic 	case '/':
1655*45325Sbostic 	case '<':
1656*45325Sbostic 	case '=':
1657*45325Sbostic 	case '>':
1658*45325Sbostic 	case '?':
1659*45325Sbostic 	case '^':
1660*45325Sbostic 	case '|':
1661*45325Sbostic 	case ATAN2:
1662*45325Sbostic 	case DTS:
1663*45325Sbostic 	case EQS:
1664*45325Sbostic 	case EXT:
1665*45325Sbostic 	case FMT:
1666*45325Sbostic 	case FV:
1667*45325Sbostic 	case HYPOT:
1668*45325Sbostic 	case IF:
1669*45325Sbostic 	case NVAL:
1670*45325Sbostic 	case PMT:
1671*45325Sbostic 	case POW:
1672*45325Sbostic 	case PV:
1673*45325Sbostic 	case REDUCE | '*':
1674*45325Sbostic 	case REDUCE | '+':
1675*45325Sbostic 	case REDUCE | 'a':
1676*45325Sbostic 	case REDUCE | 'c':
1677*45325Sbostic 	case REDUCE | 's':
1678*45325Sbostic 	case REDUCE | MAX:
1679*45325Sbostic 	case REDUCE | MIN:
1680*45325Sbostic 	case ROUND:
1681*45325Sbostic 	case STINDEX:
1682*45325Sbostic 	case SUBSTR:
1683*45325Sbostic 	case SVAL:
1684*45325Sbostic 	case TTS:
1685*45325Sbostic 		left = right = TRUE;
1686*45325Sbostic 		break;
1687*45325Sbostic 		/* right only */
1688*45325Sbostic 	case 'f':
1689*45325Sbostic 	case 'm':
1690*45325Sbostic 	case '~':
1691*45325Sbostic 	case ABS:
1692*45325Sbostic 	case ACOS:
1693*45325Sbostic 	case ASIN:
1694*45325Sbostic 	case ATAN:
1695*45325Sbostic 	case CEIL:
1696*45325Sbostic 	case COS:
1697*45325Sbostic 	case DATE:
1698*45325Sbostic 	case DAY:
1699*45325Sbostic 	case DTR:
1700*45325Sbostic 	case EXP:
1701*45325Sbostic 	case FABS:
1702*45325Sbostic 	case FLOOR:
1703*45325Sbostic 	case HLOOKUP:
1704*45325Sbostic 	case HOUR:
1705*45325Sbostic 	case IF:
1706*45325Sbostic 	case INDEX:
1707*45325Sbostic 	case LOG10:
1708*45325Sbostic 	case LOG:
1709*45325Sbostic 	case LOOKUP:
1710*45325Sbostic 	case MINUTE:
1711*45325Sbostic 	case MONTH:
1712*45325Sbostic 	case RND:
1713*45325Sbostic 	case RTD:
1714*45325Sbostic 	case SECOND:
1715*45325Sbostic 	case SIN:
1716*45325Sbostic 	case SQRT:
1717*45325Sbostic 	case STON:
1718*45325Sbostic 	case TAN:
1719*45325Sbostic 	case VLOOKUP:
1720*45325Sbostic 	case YEAR:
1721*45325Sbostic 		right = TRUE;
1722*45325Sbostic 		break;
1723*45325Sbostic     }
1724*45325Sbostic 	/* for now insert at the beginning of the list */
1725*45325Sbostic     v->evnext = firstev;
1726*45325Sbostic     v->evprev = (struct ent *)0;
1727*45325Sbostic     if (firstev)
1728*45325Sbostic 	firstev->evprev = v;
1729*45325Sbostic     firstev = v;
1730*45325Sbostic #endif
1731*45325Sbostic     firstev = v;
1732*45325Sbostic }
1733*45325Sbostic #endif /* EXPRTREE*/
1734*45325Sbostic 
1735*45325Sbostic void
hide_row(arg)1736*45325Sbostic hide_row(arg)
1737*45325Sbostic int arg;
1738*45325Sbostic {
1739*45325Sbostic     if (arg < 0) {
1740*45325Sbostic 	error("Invalid Range");
1741*45325Sbostic 	return;
1742*45325Sbostic     }
1743*45325Sbostic     if (arg >= maxrows-1)
1744*45325Sbostic     {
1745*45325Sbostic 	if (!growtbl(GROWROW, arg+1, 0))
1746*45325Sbostic 	{	error("You can't hide the last row");
1747*45325Sbostic 		return;
1748*45325Sbostic 	}
1749*45325Sbostic     }
1750*45325Sbostic     FullUpdate++;
1751*45325Sbostic     row_hidden[arg] = 1;
1752*45325Sbostic }
1753*45325Sbostic 
1754*45325Sbostic void
hide_col(arg)1755*45325Sbostic hide_col(arg)
1756*45325Sbostic int arg;
1757*45325Sbostic {
1758*45325Sbostic     if (arg < 0) {
1759*45325Sbostic 	error("Invalid Range");
1760*45325Sbostic 	return;
1761*45325Sbostic     }
1762*45325Sbostic     if (arg >= maxcols-1)
1763*45325Sbostic     {	if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
1764*45325Sbostic 	{	error("You can't hide the last col");
1765*45325Sbostic 		return;
1766*45325Sbostic 	}
1767*45325Sbostic     }
1768*45325Sbostic     FullUpdate++;
1769*45325Sbostic     col_hidden[arg] = 1;
1770*45325Sbostic }
1771*45325Sbostic 
1772*45325Sbostic void
clearent(v)1773*45325Sbostic clearent (v)
1774*45325Sbostic struct ent *v;
1775*45325Sbostic {
1776*45325Sbostic     if (!v)
1777*45325Sbostic 	return;
1778*45325Sbostic     label(v,"",-1);
1779*45325Sbostic     v->v = (double)0;
1780*45325Sbostic     if (v->expr)
1781*45325Sbostic 	efree(v, v->expr);
1782*45325Sbostic     v->expr = (struct enode *)0;
1783*45325Sbostic     v->flags |= (is_changed);
1784*45325Sbostic     v->flags &= ~(is_valid);
1785*45325Sbostic     changed++;
1786*45325Sbostic     modflg++;
1787*45325Sbostic }
1788*45325Sbostic 
1789*45325Sbostic /*
1790*45325Sbostic  * Say if an expression is a constant (return 1) or not.
1791*45325Sbostic  */
1792*45325Sbostic int
constant(e)1793*45325Sbostic constant (e)
1794*45325Sbostic     register struct enode *e;
1795*45325Sbostic {
1796*45325Sbostic     return ((e == (struct enode *)0)
1797*45325Sbostic 	 || ((e -> op) == O_CONST)
1798*45325Sbostic 	 || ((e -> op) == O_SCONST)
1799*45325Sbostic 	 || (((e -> op) != O_VAR)
1800*45325Sbostic 	  && (((e -> op) & REDUCE) != REDUCE)
1801*45325Sbostic 	  && constant (e -> e.o.left)
1802*45325Sbostic 	  && constant (e -> e.o.right)
1803*45325Sbostic 	  && (e -> op != EXT)	 /* functions look like constants but aren't */
1804*45325Sbostic 	  && (e -> op != NVAL)
1805*45325Sbostic 	  && (e -> op != SVAL)
1806*45325Sbostic 	  && (e -> op != NOW)));
1807*45325Sbostic }
1808*45325Sbostic 
1809*45325Sbostic void
efree(v,e)1810*45325Sbostic efree (v, e)
1811*45325Sbostic struct ent *v;
1812*45325Sbostic struct enode *e;
1813*45325Sbostic {
1814*45325Sbostic     if (e) {
1815*45325Sbostic 	if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
1816*45325Sbostic 		&& (e->op & REDUCE) != REDUCE) {
1817*45325Sbostic 	    efree(v, e->e.o.left);
1818*45325Sbostic 	    efree(v, e->e.o.right);
1819*45325Sbostic 	}
1820*45325Sbostic 	if (e->op == O_SCONST && e->e.s)
1821*45325Sbostic 	    xfree(e->e.s);
1822*45325Sbostic 	xfree ((char *)e);
1823*45325Sbostic 
1824*45325Sbostic #ifdef EXPRTREE
1825*45325Sbostic 	/* delete this cell from the eval list */
1826*45325Sbostic 	if (v)
1827*45325Sbostic 	{	if (v->evprev)
1828*45325Sbostic 			v->evprev->evnext = v->evnext;
1829*45325Sbostic 		if (v->evnext)
1830*45325Sbostic 			v->evnext->evprev = v->evprev;
1831*45325Sbostic 	}
1832*45325Sbostic #endif /* EXPRTREE */
1833*45325Sbostic     }
1834*45325Sbostic }
1835*45325Sbostic 
1836*45325Sbostic void
label(v,s,flushdir)1837*45325Sbostic label (v, s, flushdir)
1838*45325Sbostic register struct ent *v;
1839*45325Sbostic register char *s;
1840*45325Sbostic int	flushdir;
1841*45325Sbostic {
1842*45325Sbostic     if (v) {
1843*45325Sbostic 	if (flushdir==0 && v->flags&is_valid) {
1844*45325Sbostic 	    register struct ent *tv;
1845*45325Sbostic 	    if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
1846*45325Sbostic 		v = tv, flushdir = 1;
1847*45325Sbostic 	    else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
1848*45325Sbostic 		v = tv, flushdir = -1;
1849*45325Sbostic 	    else flushdir = -1;
1850*45325Sbostic 	}
1851*45325Sbostic 	if (v->label) xfree((char *)(v->label));
1852*45325Sbostic 	if (s && s[0]) {
1853*45325Sbostic 	    v->label = xmalloc ((unsigned)(strlen(s)+1));
1854*45325Sbostic 	    (void) strcpy (v->label, s);
1855*45325Sbostic 	} else
1856*45325Sbostic 	    v->label = (char *)0;
1857*45325Sbostic 	if (flushdir<0) v->flags |= is_leftflush;
1858*45325Sbostic 	else v->flags &= ~is_leftflush;
1859*45325Sbostic 	FullUpdate++;
1860*45325Sbostic 	modflg++;
1861*45325Sbostic     }
1862*45325Sbostic }
1863*45325Sbostic 
1864*45325Sbostic void
decodev(v)1865*45325Sbostic decodev (v)
1866*45325Sbostic struct ent_ptr v;
1867*45325Sbostic {
1868*45325Sbostic 	register struct range *r;
1869*45325Sbostic 
1870*45325Sbostic 	if (!v.vp) (void)sprintf (line+linelim,"VAR?");
1871*45325Sbostic 	else if ((r = find_range((char *)0, 0, v.vp, v.vp)) && !r->r_is_range)
1872*45325Sbostic 	    (void)sprintf(line+linelim, "%s", r->r_name);
1873*45325Sbostic 	else
1874*45325Sbostic 	    (void)sprintf (line+linelim, "%s%s%s%d",
1875*45325Sbostic 			v.vf & FIX_COL ? "$" : "",
1876*45325Sbostic 			coltoa(v.vp->col),
1877*45325Sbostic 			v.vf & FIX_ROW ? "$" : "",
1878*45325Sbostic 			v.vp->row);
1879*45325Sbostic 	linelim += strlen (line+linelim);
1880*45325Sbostic }
1881*45325Sbostic 
1882*45325Sbostic char *
coltoa(col)1883*45325Sbostic coltoa(col)
1884*45325Sbostic int col;
1885*45325Sbostic {
1886*45325Sbostic     static char rname[3];
1887*45325Sbostic     register char *p = rname;
1888*45325Sbostic 
1889*45325Sbostic     if (col > 25) {
1890*45325Sbostic 	*p++ = col/26 + 'A' - 1;
1891*45325Sbostic 	col %= 26;
1892*45325Sbostic     }
1893*45325Sbostic     *p++ = col+'A';
1894*45325Sbostic     *p = '\0';
1895*45325Sbostic     return(rname);
1896*45325Sbostic }
1897*45325Sbostic 
1898*45325Sbostic /*
1899*45325Sbostic  *	To make list elements come out in the same order
1900*45325Sbostic  *	they were entered, we must do a depth-first eval
1901*45325Sbostic  *	of the ELIST tree
1902*45325Sbostic  */
1903*45325Sbostic static void
decompile_list(p)1904*45325Sbostic decompile_list(p)
1905*45325Sbostic struct enode *p;
1906*45325Sbostic {
1907*45325Sbostic 	if (!p) return;
1908*45325Sbostic 	decompile_list(p->e.o.left);	/* depth first */
1909*45325Sbostic         decompile(p->e.o.right, 0);
1910*45325Sbostic 	line[linelim++] = ',';
1911*45325Sbostic }
1912*45325Sbostic 
1913*45325Sbostic void
decompile(e,priority)1914*45325Sbostic decompile(e, priority)
1915*45325Sbostic register struct enode *e;
1916*45325Sbostic int	priority;
1917*45325Sbostic {
1918*45325Sbostic     register char *s;
1919*45325Sbostic     if (e) {
1920*45325Sbostic 	int mypriority;
1921*45325Sbostic 	switch (e->op) {
1922*45325Sbostic 	default: mypriority = 99; break;
1923*45325Sbostic 	case '?': mypriority = 1; break;
1924*45325Sbostic 	case ':': mypriority = 2; break;
1925*45325Sbostic 	case '|': mypriority = 3; break;
1926*45325Sbostic 	case '&': mypriority = 4; break;
1927*45325Sbostic 	case '<': case '=': case '>': mypriority = 6; break;
1928*45325Sbostic 	case '+': case '-': case '#': mypriority = 8; break;
1929*45325Sbostic 	case '*': case '/': case '%': mypriority = 10; break;
1930*45325Sbostic 	case '^': mypriority = 12; break;
1931*45325Sbostic 	}
1932*45325Sbostic 	if (mypriority<priority) line[linelim++] = '(';
1933*45325Sbostic 	switch (e->op) {
1934*45325Sbostic 	case 'f':	for (s="fixed "; line[linelim++] = *s++;);
1935*45325Sbostic 			linelim--;
1936*45325Sbostic 			decompile (e->e.o.right, 30);
1937*45325Sbostic 			break;
1938*45325Sbostic 	case 'm':	line[linelim++] = '-';
1939*45325Sbostic 			decompile (e->e.o.right, 30);
1940*45325Sbostic 			break;
1941*45325Sbostic 	case '~':	line[linelim++] = '~';
1942*45325Sbostic 			decompile (e->e.o.right, 30);
1943*45325Sbostic 			break;
1944*45325Sbostic 	case 'v':	decodev (e->e.v);
1945*45325Sbostic 			break;
1946*45325Sbostic 	case 'k':	(void)sprintf (line+linelim,"%.15g",e->e.k);
1947*45325Sbostic 			linelim += strlen (line+linelim);
1948*45325Sbostic 			break;
1949*45325Sbostic 	case '$':	(void)sprintf (line+linelim, "\"%s\"", e->e.s);
1950*45325Sbostic 			linelim += strlen(line+linelim);
1951*45325Sbostic 			break;
1952*45325Sbostic 
1953*45325Sbostic 	case REDUCE | '+': range_arg( "@sum(", e); break;
1954*45325Sbostic 	case REDUCE | '*': range_arg( "@prod(", e); break;
1955*45325Sbostic 	case REDUCE | 'a': range_arg( "@avg(", e); break;
1956*45325Sbostic 	case REDUCE | 'c': range_arg( "@count(", e); break;
1957*45325Sbostic 	case REDUCE | 's': range_arg( "@stddev(", e); break;
1958*45325Sbostic 	case REDUCE | MAX: range_arg( "@max(", e); break;
1959*45325Sbostic 	case REDUCE | MIN: range_arg( "@min(", e); break;
1960*45325Sbostic 
1961*45325Sbostic 	case ABS:		one_arg( "@abs(", e); break;
1962*45325Sbostic 	case ACOS:	one_arg( "@acos(", e); break;
1963*45325Sbostic 	case ASIN:	one_arg( "@asin(", e); break;
1964*45325Sbostic 	case ATAN:	one_arg( "@atan(", e); break;
1965*45325Sbostic 	case ATAN2:	two_arg( "@atan2(", e); break;
1966*45325Sbostic 	case CEIL:	one_arg( "@ceil(", e); break;
1967*45325Sbostic 	case COS:	one_arg( "@cos(", e); break;
1968*45325Sbostic 	case EXP:	one_arg( "@exp(", e); break;
1969*45325Sbostic 	case FABS:	one_arg( "@fabs(", e); break;
1970*45325Sbostic 	case FLOOR:	one_arg( "@floor(", e); break;
1971*45325Sbostic 	case HYPOT:	two_arg( "@hypot(", e); break;
1972*45325Sbostic 	case LOG:	one_arg( "@ln(", e); break;
1973*45325Sbostic 	case LOG10:	one_arg( "@log(", e); break;
1974*45325Sbostic 	case POW:	two_arg( "@pow(", e); break;
1975*45325Sbostic 	case SIN:	one_arg( "@sin(", e); break;
1976*45325Sbostic 	case SQRT:	one_arg( "@sqrt(", e); break;
1977*45325Sbostic 	case TAN:	one_arg( "@tan(", e); break;
1978*45325Sbostic 	case DTR:	one_arg( "@dtr(", e); break;
1979*45325Sbostic 	case RTD:	one_arg( "@rtd(", e); break;
1980*45325Sbostic 	case RND:	one_arg( "@rnd(", e); break;
1981*45325Sbostic 	case ROUND:	two_arg( "@round(", e); break;
1982*45325Sbostic 	case HOUR:	one_arg( "@hour(", e); break;
1983*45325Sbostic 	case MINUTE:	one_arg( "@minute(", e); break;
1984*45325Sbostic 	case SECOND:	one_arg( "@second(", e); break;
1985*45325Sbostic 	case MONTH:	one_arg( "@month(", e); break;
1986*45325Sbostic 	case DAY:	one_arg( "@day(", e); break;
1987*45325Sbostic 	case YEAR:	one_arg( "@year(", e); break;
1988*45325Sbostic 	case DATE:	one_arg( "@date(", e); break;
1989*45325Sbostic 	case DTS:	three_arg( "@dts(", e); break;
1990*45325Sbostic 	case TTS:	three_arg( "@tts(", e); break;
1991*45325Sbostic 	case STON:	one_arg( "@ston(", e); break;
1992*45325Sbostic 	case FMT:	two_arg( "@fmt(", e); break;
1993*45325Sbostic 	case EQS:	two_arg( "@eqs(", e); break;
1994*45325Sbostic 	case NOW:	for ( s = "@now"; line[linelim++] = *s++;);
1995*45325Sbostic 			linelim--;
1996*45325Sbostic 			break;
1997*45325Sbostic 	case LMAX:	list_arg("@max(", e); break;
1998*45325Sbostic 	case LMIN: 	list_arg("@min(", e); break;
1999*45325Sbostic 	case FV:	three_arg("@fv(", e); break;
2000*45325Sbostic 	case PV:	three_arg("@pv(", e); break;
2001*45325Sbostic 	case PMT:	three_arg("@pmt(", e); break;
2002*45325Sbostic 	case NVAL:	two_arg("@nval(", e); break;
2003*45325Sbostic 	case SVAL:	two_arg("@sval(", e); break;
2004*45325Sbostic 	case EXT:	two_arg("@ext(", e); break;
2005*45325Sbostic 	case SUBSTR:	three_arg("@substr(", e); break;
2006*45325Sbostic 	case STINDEX:	index_arg("@stindex(", e); break;
2007*45325Sbostic 	case INDEX:	index_arg("@index(", e); break;
2008*45325Sbostic 	case LOOKUP:	index_arg("@lookup(", e); break;
2009*45325Sbostic 	case HLOOKUP:	two_arg_index("@hlookup(", e); break;
2010*45325Sbostic 	case VLOOKUP:	two_arg_index("@vlookup(", e); break;
2011*45325Sbostic 	case IF:	three_arg("@if(", e); break;
2012*45325Sbostic 	default:	decompile (e->e.o.left, mypriority);
2013*45325Sbostic 			line[linelim++] = e->op;
2014*45325Sbostic 			decompile (e->e.o.right, mypriority+1);
2015*45325Sbostic 			break;
2016*45325Sbostic 	}
2017*45325Sbostic 	if (mypriority<priority) line[linelim++] = ')';
2018*45325Sbostic     } else line[linelim++] = '?';
2019*45325Sbostic }
2020*45325Sbostic 
2021*45325Sbostic void
index_arg(s,e)2022*45325Sbostic index_arg(s, e)
2023*45325Sbostic char *s;
2024*45325Sbostic struct enode *e;
2025*45325Sbostic {
2026*45325Sbostic     for (; line[linelim++] = *s++;);
2027*45325Sbostic     linelim--;
2028*45325Sbostic     decompile( e-> e.o.left, 0 );
2029*45325Sbostic     range_arg(", ", e->e.o.right);
2030*45325Sbostic }
2031*45325Sbostic 
2032*45325Sbostic void
two_arg_index(s,e)2033*45325Sbostic two_arg_index(s, e)
2034*45325Sbostic char *s;
2035*45325Sbostic struct enode *e;
2036*45325Sbostic {
2037*45325Sbostic     for (; line[linelim++] = *s++;);
2038*45325Sbostic     linelim--;
2039*45325Sbostic     decompile( e->e.o.left->e.o.left, 0 );
2040*45325Sbostic     range_arg(",", e->e.o.right);
2041*45325Sbostic     linelim--;
2042*45325Sbostic     line[linelim++] = ',';
2043*45325Sbostic     decompile( e->e.o.left->e.o.right, 0 );
2044*45325Sbostic     line[linelim++] = ')';
2045*45325Sbostic }
2046*45325Sbostic 
2047*45325Sbostic void
list_arg(s,e)2048*45325Sbostic list_arg(s, e)
2049*45325Sbostic char *s;
2050*45325Sbostic struct enode *e;
2051*45325Sbostic {
2052*45325Sbostic     for (; line[linelim++] = *s++;);
2053*45325Sbostic     linelim--;
2054*45325Sbostic 
2055*45325Sbostic     decompile (e->e.o.right, 0);
2056*45325Sbostic     line[linelim++] = ',';
2057*45325Sbostic     decompile_list(e->e.o.left);
2058*45325Sbostic     line[linelim - 1] = ')';
2059*45325Sbostic }
2060*45325Sbostic 
2061*45325Sbostic void
one_arg(s,e)2062*45325Sbostic one_arg(s, e)
2063*45325Sbostic char *s;
2064*45325Sbostic struct enode *e;
2065*45325Sbostic {
2066*45325Sbostic     for (; line[linelim++] = *s++;);
2067*45325Sbostic     linelim--;
2068*45325Sbostic     decompile (e->e.o.right, 0);
2069*45325Sbostic     line[linelim++] = ')';
2070*45325Sbostic }
2071*45325Sbostic 
2072*45325Sbostic void
two_arg(s,e)2073*45325Sbostic two_arg(s,e)
2074*45325Sbostic char *s;
2075*45325Sbostic struct enode *e;
2076*45325Sbostic {
2077*45325Sbostic     for (; line[linelim++] = *s++;);
2078*45325Sbostic     linelim--;
2079*45325Sbostic     decompile (e->e.o.left, 0);
2080*45325Sbostic     line[linelim++] = ',';
2081*45325Sbostic     decompile (e->e.o.right, 0);
2082*45325Sbostic     line[linelim++] = ')';
2083*45325Sbostic }
2084*45325Sbostic 
2085*45325Sbostic void
three_arg(s,e)2086*45325Sbostic three_arg(s,e)
2087*45325Sbostic char *s;
2088*45325Sbostic struct enode *e;
2089*45325Sbostic {
2090*45325Sbostic     for (; line[linelim++] = *s++;);
2091*45325Sbostic     linelim--;
2092*45325Sbostic     decompile (e->e.o.left, 0);
2093*45325Sbostic     line[linelim++] = ',';
2094*45325Sbostic     decompile (e->e.o.right->e.o.left, 0);
2095*45325Sbostic     line[linelim++] = ',';
2096*45325Sbostic     decompile (e->e.o.right->e.o.right, 0);
2097*45325Sbostic     line[linelim++] = ')';
2098*45325Sbostic }
2099*45325Sbostic 
2100*45325Sbostic void
range_arg(s,e)2101*45325Sbostic range_arg(s,e)
2102*45325Sbostic char *s;
2103*45325Sbostic struct enode *e;
2104*45325Sbostic {
2105*45325Sbostic     struct range *r;
2106*45325Sbostic 
2107*45325Sbostic     for (; line[linelim++] = *s++;);
2108*45325Sbostic     linelim--;
2109*45325Sbostic     if ((r = find_range((char *)0, 0, e->e.r.left.vp,
2110*45325Sbostic 			     e->e.r.right.vp)) && r->r_is_range) {
2111*45325Sbostic 	(void)sprintf(line+linelim, "%s", r->r_name);
2112*45325Sbostic 	linelim += strlen(line+linelim);
2113*45325Sbostic     } else {
2114*45325Sbostic 	decodev (e->e.r.left);
2115*45325Sbostic 	line[linelim++] = ':';
2116*45325Sbostic 	decodev (e->e.r.right);
2117*45325Sbostic     }
2118*45325Sbostic     line[linelim++] = ')';
2119*45325Sbostic }
2120*45325Sbostic 
2121*45325Sbostic void
editv(row,col)2122*45325Sbostic editv (row, col)
2123*45325Sbostic int row, col;
2124*45325Sbostic {
2125*45325Sbostic     register struct ent *p;
2126*45325Sbostic 
2127*45325Sbostic     p = lookat (row, col);
2128*45325Sbostic     (void)sprintf (line, "let %s = ", v_name(row, col));
2129*45325Sbostic     linelim = strlen(line);
2130*45325Sbostic     if (p->flags & is_strexpr || p->expr == 0) {
2131*45325Sbostic 	(void)sprintf (line+linelim, "%.15g", p->v);
2132*45325Sbostic 	linelim += strlen (line+linelim);
2133*45325Sbostic     } else {
2134*45325Sbostic         editexp(row,col);
2135*45325Sbostic     }
2136*45325Sbostic }
2137*45325Sbostic 
2138*45325Sbostic void
editexp(row,col)2139*45325Sbostic editexp(row,col)
2140*45325Sbostic int row, col;
2141*45325Sbostic {
2142*45325Sbostic     register struct ent *p;
2143*45325Sbostic 
2144*45325Sbostic     p = lookat (row, col);
2145*45325Sbostic     decompile (p->expr, 0);
2146*45325Sbostic     line[linelim] = '\0';
2147*45325Sbostic }
2148*45325Sbostic 
2149*45325Sbostic void
edits(row,col)2150*45325Sbostic edits (row, col)
2151*45325Sbostic int row, col;
2152*45325Sbostic {
2153*45325Sbostic     register struct ent *p;
2154*45325Sbostic 
2155*45325Sbostic     p = lookat (row, col);
2156*45325Sbostic     (void)sprintf (line, "%sstring %s = ",
2157*45325Sbostic 			((p->flags&is_leftflush) ? "left" : "right"),
2158*45325Sbostic 			v_name(row, col));
2159*45325Sbostic     linelim = strlen(line);
2160*45325Sbostic     if (p->flags & is_strexpr && p->expr) {
2161*45325Sbostic 	editexp(row, col);
2162*45325Sbostic     } else if (p->label) {
2163*45325Sbostic         (void)sprintf (line+linelim, "\"%s\"", p->label);
2164*45325Sbostic         linelim += strlen (line+linelim);
2165*45325Sbostic     } else {
2166*45325Sbostic         (void)sprintf (line+linelim, "\"");
2167*45325Sbostic         linelim += 1;
2168*45325Sbostic     }
2169*45325Sbostic }
2170