xref: /original-bsd/contrib/sc/interp.c (revision 7596ee73)
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 
29 extern 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)
47 char *re_comp();
48 #endif
49 #if defined(SYSV2) || defined(SYSV3)
50 char *regcmp();
51 char *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 
62 struct 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 
79 extern FILE *popen();
80 
81 jmp_buf fpe_save;
82 int	exprerr;	/* Set by eval() and seval() if expression errors */
83 double  prescale = 1.0;	/* Prescale for constants in let() */
84 int	extfunc  = 0;	/* Enable/disable external functions */
85 int     loading = 0;	/* Set when readfile() is active */
86 double fn1_eval();
87 double fn2_eval();
88 struct	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 
94 double finfunc(fun,v1,v2,v3)
95 int fun;
96 double 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 
120 char *
121 dostindex( val, minr, minc, maxr, maxc)
122 double val;
123 int 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 
154 double
155 doindex( val, minr, minc, maxr, maxc)
156 double val;
157 int 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 
183 double
184 dolookup( val, minr, minc, maxr, maxc, offr, offc)
185 struct enode * val;
186 int 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 
231 double
232 docount(minr, minc, maxr, maxc)
233 int 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 
247 double
248 dosum(minr, minc, maxr, maxc)
249 int 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 
263 double
264 doprod(minr, minc, maxr, maxc)
265 int 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 
279 double
280 doavg(minr, minc, maxr, maxc)
281 int 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 
302 double
303 dostddev(minr, minc, maxr, maxc)
304 int 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 
328 double
329 domax(minr, minc, maxr, maxc)
330 int 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 
353 double
354 domin(minr, minc, maxr, maxc)
355 int 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 */
383 int mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
384 
385 double
386 dodts(mo, day, yr)
387 int 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 
444 double
445 dotts(hr, min, sec)
446 int 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 
455 double
456 dotime(which, when)
457 int which;
458 double 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 
492 double
493 doston(s)
494 char *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 
507 double
508 doeqs(s1, s2)
509 char *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 
539 struct ent *
540 getent (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 
567 double
568 donval (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  */
584 double
585 dolmax(ep)
586 struct 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 
603 double
604 dolmin(ep)
605 struct 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 
622 double
623 eval(e)
624 register 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
767 void
768 #endif
769 eval_fpe(signo) /* Trap for FPE errors in eval */
770 int 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 
778 double fn1_eval(fn, arg)
779 double (*fn)();
780 double 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 
791 double fn2_eval(fn, arg1, arg2)
792 double (*fn)();
793 double 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 
810 char *
811 docat(s1, s2)
812 register 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 
831 char *
832 dodate(tloc)
833 long 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 
846 char *
847 dofmt(fmtstr, v)
848 char *fmtstr;
849 double 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
875 char *
876 doext(command, value)
877 char *command;
878 double 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 
888 char *
889 doext (command, value)
890 char   *command;
891 double 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 
957 char *
958 dosval (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 
975 char *
976 dosubstr(s, v1, v2)
977 char *s;
978 register 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 
1004 char *
1005 seval(se)
1006 register 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 
1066 int propagation = 10;	/* max number of times to try calculation */
1067 
1068 void
1069 setiterations(i)
1070 int 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 
1079 void
1080 EvalAll () {
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 
1093 int
1094 RealEvalAll () {
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 
1122 void
1123 #ifdef EXPRTREE
1124 RealEvalOne(p, chgct)
1125 register struct ent *p;
1126 int *chgct;
1127 #else
1128 RealEvalOne(p, i, j, chgct)
1129 register struct ent *p;
1130 int 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 
1175 struct enode *
1176 new(op, a1, a2)
1177 int	op;
1178 struct 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 
1188 struct enode *
1189 new_var(op, a1)
1190 int	op;
1191 struct 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 
1200 struct enode *
1201 new_range(op, a1)
1202 int	op;
1203 struct 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 
1212 struct enode *
1213 new_const(op, a1)
1214 int	op;
1215 double 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 
1224 struct enode *
1225 new_str(s)
1226 char *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 
1236 void
1237 copy(dv1, dv2, v1, v2)
1238 struct 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 
1282 void
1283 copyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
1284 int 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 
1304 void
1305 eraser(v1, v2)
1306 struct 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 
1316 void
1317 g_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 
1326 void
1327 go_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 
1347 void
1348 moveto(row, col)
1349 int 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 
1359 void
1360 num_search(n)
1361 double 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 
1404 void
1405 str_search(s)
1406 char *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 
1477 void
1478 fill (v1, v2, start, inc)
1479 struct ent *v1, *v2;
1480 double 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 
1522 void
1523 let (v, e)
1524 struct ent *v;
1525 struct 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 
1569 void
1570 slet (v, se, flushdir)
1571 struct ent *v;
1572 struct enode *se;
1573 int 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  */
1621 totoptree(v)
1622 struct	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 
1735 void
1736 hide_row(arg)
1737 int 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 
1754 void
1755 hide_col(arg)
1756 int 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 
1772 void
1773 clearent (v)
1774 struct 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  */
1792 int
1793 constant (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 
1809 void
1810 efree (v, e)
1811 struct ent *v;
1812 struct 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 
1836 void
1837 label (v, s, flushdir)
1838 register struct ent *v;
1839 register char *s;
1840 int	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 
1864 void
1865 decodev (v)
1866 struct 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 
1882 char *
1883 coltoa(col)
1884 int 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  */
1903 static void
1904 decompile_list(p)
1905 struct 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 
1913 void
1914 decompile(e, priority)
1915 register struct enode *e;
1916 int	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 
2021 void
2022 index_arg(s, e)
2023 char *s;
2024 struct 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 
2032 void
2033 two_arg_index(s, e)
2034 char *s;
2035 struct 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 
2047 void
2048 list_arg(s, e)
2049 char *s;
2050 struct 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 
2061 void
2062 one_arg(s, e)
2063 char *s;
2064 struct enode *e;
2065 {
2066     for (; line[linelim++] = *s++;);
2067     linelim--;
2068     decompile (e->e.o.right, 0);
2069     line[linelim++] = ')';
2070 }
2071 
2072 void
2073 two_arg(s,e)
2074 char *s;
2075 struct 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 
2085 void
2086 three_arg(s,e)
2087 char *s;
2088 struct 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 
2100 void
2101 range_arg(s,e)
2102 char *s;
2103 struct 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 
2121 void
2122 editv (row, col)
2123 int 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 
2138 void
2139 editexp(row,col)
2140 int 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 
2149 void
2150 edits (row, col)
2151 int 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 }
2170