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