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