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  *              More mods by Peter Doemel, 2/93: support for REG_COMP
11  *		$Revision: 1.1 $
12  */
13 
14 #include <config.h>
15 #include <curses.h>
16 
17 #ifdef HAVE_X11_X_H
18 #include <X11/Xlib.h>
19 #include <X11/Xutil.h>
20 #endif /* HAVE_X11_X_H */
21 
22 #include <sys/types.h>
23 #ifdef aiws
24 #undef _C_func			/* Fixes for undefined symbols on AIX */
25 #endif
26 
27 #ifdef IEEE_MATH
28 #include <ieeefp.h>
29 #endif /* IEEE_MATH */
30 
31 #include <math.h>
32 #include <signal.h>
33 #include <setjmp.h>
34 #include <ctype.h>
35 
36 #ifdef __DragonFly__
37 #include <errno.h>
38 #else
39 extern int errno;		/* set by math functions */
40 #endif
41 
42 #include "sc.h"
43 
44 #ifdef HAVE_X11_X_H
45 # include "scXstuff.h"
46 #endif /* HAVE_X11_X_H */
47 
48 #if defined(RE_COMP)
49 char *re_comp();
50 #endif
51 #if defined(REGCMP)
52 char *regcmp();
53 char *regex();
54 #endif
55 
56 #if defined(REG_COMP) /* Peter Doemel, 10-Feb-1993 */
57 #include <regex.h>
58 # if NeedFunctionPrototypes
59   int regcomp(regex_t *preg, const char *pattern, int cflags);
60   int regexec(const regex_t *preg, const char *string, size_t nmatch,
61               regmatch_t pmatch[], int eflags);
62   void regfree(regex_t *preg);
63   char *regerrmsg(interrcode);
64 # else
65   char *regerrmsg();
66 # endif
67 #endif
68 
69 
70 /* Use this structure to save the the last 'g' command */
71 struct go_save {
72 	int g_type;
73 	double g_n;
74 	char *g_s;
75 	int  g_row;
76 	int  g_col;
77 	int  errsearch;
78 } gs;
79 
80 /* g_type can be: */
81 #define G_NONE 0			/* Starting value - must be 0*/
82 #define G_NUM 1
83 #define G_STR 2
84 #define G_CELL 3
85 
86 #define ISVALID(r,c)	((r)>=0 && (r)<maxrows && (c)>=0 && (c)<maxcols)
87 
88 jmp_buf fpe_save;
89 int	exprerr;	/* Set by eval() and seval() if expression errors */
90 double  prescale = 1.0;	/* Prescale for constants in let() */
91 int	extfunc  = 0;	/* Enable/disable external functions */
92 int     loading = 0;	/* Set when readfile() is active */
93 int	gmyrow, gmycol;	/* globals used to implement @myrow, @mycol cmds */
94 
95 /* a linked list of free [struct enodes]'s, uses .e.o.left as the pointer */
96 struct enode *freeenodes = NULL;
97 
98 static int	RealEvalAll PROTO((void));
99 static void	RealEvalOne PROTO((struct ent *, int, int, int *));
100 static int	constant PROTO((struct enode *));
101 static void	copyrtv PROTO((int, int, int, int, int, int));
102 static void	decodev PROTO((struct ent_ptr));
103 static void	decompile PROTO((struct enode *, int));
104 static void	decompile_list PROTO((struct enode *));
105 static double	doavg PROTO((int, int, int, int));
106 static char *	docapital PROTO((char *));
107 static char *	docase PROTO((int, char *));
108 static char *	docat PROTO((char *, char *));
109 static double	docount PROTO((int, int, int, int));
110 static char *	dodate PROTO((long));
111 static double	doeqs PROTO((char *, char *));
112 static char *	doext PROTO((char *, double));
113 static char *	dofmt PROTO((char *, double));
114 static double	doindex PROTO((double, int, int, int, int));
115 static double	dolookup PROTO((struct enode *, int, int, int, int, int, int));
116 static double	dolmax PROTO((struct enode *));
117 static double	dolmin PROTO((struct enode *));
118 static double	doprod PROTO((int, int, int, int));
119 static double	domax PROTO((int, int, int, int));
120 static double	domin PROTO((int, int, int, int));
121 static double	donval PROTO((char *, double));
122 static double	dostddev PROTO((int, int, int, int));
123 static char *	dostindex PROTO((double, int, int, int, int));
124 static char *	dosubstr PROTO((char *, int, int));
125 static double	dosum PROTO((int, int, int, int));
126 static char *	dosval PROTO((char *, double));
127 static double	doston PROTO((char *));
128 static double	dotime PROTO((int, double));
129 static double	dotts PROTO((int, int, int));
130 static double	eval PROTO((struct enode *));
131 static RETSIGTYPE eval_fpe PROTO((int));	/* Trap for FPE errors in eval */
132 static double	finfunc PROTO((int, double, double, double));
133 static double	fn1_eval PROTO((double (*)(), double));
134 static double	fn2_eval PROTO((double (*)(), double, double));
135 static struct ent *getent PROTO((char *, double));
136 static void	g_free PROTO((void));
137 static void	index_arg PROTO((char *, struct enode *));
138 static void	list_arg PROTO((char *, struct enode *));
139 static void	one_arg PROTO((char *, struct enode *));
140 static void	range_arg PROTO((char *, struct enode *));
141 static char *	seval PROTO((struct enode *));
142 #ifdef  RINT  /* Otherwise we use the one in math.h */
143        double	rint PROTO((double));
144 #endif
145 static void	three_arg PROTO((char *, struct enode *));
146 static void	two_arg PROTO((char *, struct enode *));
147 static void	two_arg_index PROTO((char *, struct enode *));
148 
149 int	cellerror = CELLOK;	/* is there an error in this cell */
150 
151 #define dtr(x) ((x)*(PI/(double)180.0))
152 #define rtd(x) ((x)*(180.0/(double)PI))
153 
154 static double
finfunc(fun,v1,v2,v3)155 finfunc(fun,v1,v2,v3)
156 int fun;
157 double v1,v2,v3;
158 {
159  	double answer,p;
160 
161  	p = fn2_eval(pow, 1 + v2, v3);
162 
163  	switch(fun)
164  	{
165  	case PV:
166 		if (v2)
167 			answer = v1 * (1 - 1/p) / v2;
168 		else
169 		{	cellerror = CELLERROR;
170 			answer = (double)0;
171 		}
172  		break;
173  	case FV:
174 		if (v2)
175 			answer = v1 * (p - 1) / v2;
176 		else
177 		{	cellerror = CELLERROR;
178 			answer = (double)0;
179 		}
180  		break;
181  	case PMT:
182 		/* CHECK IF ~= 1 - 1/1 */
183 		if (p && p != (double)1)
184 			answer = v1 * v2 / (1 - 1/p);
185 		else
186 		{	cellerror = CELLERROR;
187 			answer = (double)0;
188 		}
189 
190  		break;
191 	default:
192 		scerror("Unknown function in finfunc");
193 		cellerror = CELLERROR;
194 		return((double)0);
195 	}
196 	return(answer);
197 }
198 
199 static char *
dostindex(val,minr,minc,maxr,maxc)200 dostindex( val, minr, minc, maxr, maxc)
201 double val;
202 int minr, minc, maxr, maxc;
203 {
204     register r,c;
205     register struct ent *p;
206     char *pr;
207     int x;
208 
209     x = (int) val;
210     r = minr; c = minc;
211     p = (struct ent *)0;
212     if ( minr == maxr ) { /* look along the row */
213 	c = minc + x - 1;
214 	if (c <= maxc && c >=minc)
215 	    p = *ATBL(tbl, r, c);
216     } else if ( minc == maxc ) { /* look down the column */
217 	r = minr + x - 1;
218 	if (r <= maxr && r >=minr)
219 	    p = *ATBL(tbl, r, c);
220     } else {
221 	scerror("range specified to @stindex");
222 	cellerror = CELLERROR;
223 	return((char *)0);
224     }
225 
226     if (p && p->label) {
227 	pr = scxmalloc((unsigned)(strlen(p->label)+1));
228 	(void) strcpy(pr, p->label);
229 	if (p->cellerror)
230 		cellerror = CELLINVALID;
231 	return (pr);
232      } else
233 	return((char *)0);
234 }
235 
236 static double
doindex(val,minr,minc,maxr,maxc)237 doindex( val, minr, minc, maxr, maxc)
238 double val;
239 int minr, minc, maxr, maxc;
240 {
241     double v;
242     register r,c;
243     register struct ent *p;
244     int x;
245 
246     x = (int) val;
247     v = (double)0;
248     r = minr; c = minc;
249     if ( minr == maxr ) { /* look along the row */
250 	c = minc + x - 1;
251 	if (c <= maxc && c >=minc
252 		&& (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
253 	{	if (p->cellerror)
254 			cellerror = CELLINVALID;
255 		return p->v;
256 	}
257     }
258     else if ( minc == maxc ){ /* look down the column */
259 	r = minr + x - 1;
260 	if (r <= maxr && r >=minr
261 		&& (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
262 	{	if (p->cellerror)
263 			cellerror = CELLINVALID;
264 		return p->v;
265 	}
266     }
267     else {
268 	scerror(" range specified to @index");
269 	cellerror = CELLERROR;
270     }
271     return v;
272 }
273 
274 static double
dolookup(val,minr,minc,maxr,maxc,offr,offc)275 dolookup( val, minr, minc, maxr, maxc, offr, offc)
276 struct enode * val;
277 int minr, minc, maxr, maxc, offr, offc;
278 {
279     double v, ret = (double)0;
280     register r,c;
281     register struct ent *p = (struct ent *)0;
282     int incr,incc,fndr,fndc;
283     char *s;
284 
285     incr = (offc != 0); incc = (offr != 0);
286     if (etype(val) == NUM) {
287 	cellerror = CELLOK;
288 	v = eval(val);
289 	for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
290 	    if ( (p = *ATBL(tbl, r, c)) && p->flags&is_valid ) {
291 		if (p->v <= v) {
292 		    fndr = incc ? (minr + offr) : r;
293 		    fndc = incr ? (minc + offc) : c;
294 		    if (ISVALID(fndr,fndc))
295 			p = *ATBL(tbl, fndr, fndc);
296 		    else {
297 			scerror(" range specified to @[hv]lookup");
298 			cellerror = CELLERROR;
299 		    }
300 		    if ( p && p->flags&is_valid)
301 		    {	if (p->cellerror)
302 				cellerror = CELLINVALID;
303 			ret = p->v;
304 		    }
305 		} else break;
306 	    }
307 	}
308     } else {
309 	cellerror = CELLOK;
310 	s = seval(val);
311 	for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
312 	    if ( (p = *ATBL(tbl, r, c)) && p->label ) {
313 		if (strcmp(p->label,s) == 0) {
314 		    fndr = incc ? (minr + offr) : r;
315 		    fndc = incr ? (minc + offc) : c;
316 		    if (ISVALID(fndr,fndc))
317 		    {	p = *ATBL(tbl, fndr, fndc);
318 			if (p->cellerror)
319 				cellerror = CELLINVALID;
320 		    }
321 		    else {
322 			scerror(" range specified to @[hv]lookup");
323 			cellerror = CELLERROR;
324 		    }
325 		    break;
326 		}
327 	    }
328 	}
329 	if ( p && p->flags&is_valid)
330 	    ret = p->v;
331 	scxfree(s);
332     }
333     return ret;
334 }
335 
336 static double
docount(minr,minc,maxr,maxc)337 docount(minr, minc, maxr, maxc)
338 int minr, minc, maxr, maxc;
339 {
340     int v;
341     register r,c;
342     register struct ent *p;
343 
344     v = 0;
345     for (r = minr; r<=maxr; r++)
346 	for (c = minc; c<=maxc; c++)
347 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
348 	    {	if (p->cellerror)
349 			cellerror = CELLINVALID;
350 		v++;
351 	    }
352     return v;
353 }
354 
355 static double
dosum(minr,minc,maxr,maxc)356 dosum(minr, minc, maxr, maxc)
357 int minr, minc, maxr, maxc;
358 {
359     double v;
360     register r,c;
361     register struct ent *p;
362 
363     v = (double)0;
364     for (r = minr; r<=maxr; r++)
365 	for (c = minc; c<=maxc; c++)
366 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
367 	    {	if (p->cellerror)
368 			cellerror = CELLINVALID;
369 		v += p->v;
370 	    }
371     return v;
372 }
373 
374 static double
doprod(minr,minc,maxr,maxc)375 doprod(minr, minc, maxr, maxc)
376 int minr, minc, maxr, maxc;
377 {
378     double v;
379     register r,c;
380     register struct ent *p;
381 
382     v = 1;
383     for (r = minr; r<=maxr; r++)
384 	for (c = minc; c<=maxc; c++)
385 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
386 	    {	if (p->cellerror)
387 			cellerror = CELLINVALID;
388 		v *= p->v;
389 	    }
390     return v;
391 }
392 
393 static double
doavg(minr,minc,maxr,maxc)394 doavg(minr, minc, maxr, maxc)
395 int minr, minc, maxr, maxc;
396 {
397     double v;
398     register r,c,count;
399     register struct ent *p;
400 
401     v = (double)0;
402     count = 0;
403     for (r = minr; r<=maxr; r++)
404 	for (c = minc; c<=maxc; c++)
405 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
406 		if (p->cellerror)
407 			cellerror = CELLINVALID;
408 
409 		v += p->v;
410 		count++;
411 	    }
412 
413     if (count == 0)
414 	return ((double) 0);
415 
416     return (v / (double)count);
417 }
418 
419 static double
dostddev(minr,minc,maxr,maxc)420 dostddev(minr, minc, maxr, maxc)
421 int minr, minc, maxr, maxc;
422 {
423     double lp, rp, v, nd;
424     register r,c,n;
425     register struct ent *p;
426 
427     n = 0;
428     lp = 0;
429     rp = 0;
430     for (r = minr; r<=maxr; r++)
431 	for (c = minc; c<=maxc; c++)
432 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
433 		if (p->cellerror)
434 			cellerror = CELLINVALID;
435 
436 		v = p->v;
437 		lp += v*v;
438 		rp += v;
439 		n++;
440 	    }
441 
442     if ((n == 0) || (n == 1))
443 	return ((double) 0);
444     nd = (double)n;
445     return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
446 }
447 
448 static double
domax(minr,minc,maxr,maxc)449 domax(minr, minc, maxr, maxc)
450 int minr, minc, maxr, maxc;
451 {
452     double v = (double)0;
453     register r,c,count;
454     register struct ent *p;
455 
456     count = 0;
457     for (r = minr; r<=maxr; r++)
458 	for (c = minc; c<=maxc; c++)
459 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
460 		if (p->cellerror)
461 			cellerror = CELLINVALID;
462 
463 		if (!count) {
464 		    v = p->v;
465 		    count++;
466 		} else if (p->v > v)
467 		    v = p->v;
468 	    }
469 
470     if (count == 0)
471 	return ((double) 0);
472 
473     return (v);
474 }
475 
476 static double
domin(minr,minc,maxr,maxc)477 domin(minr, minc, maxr, maxc)
478 int minr, minc, maxr, maxc;
479 {
480     double v = (double)0;
481     register r,c,count;
482     register struct ent *p;
483 
484     count = 0;
485     for (r = minr; r<=maxr; r++)
486 	for (c = minc; c<=maxc; c++)
487 	    if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
488 		if (p->cellerror)
489 			cellerror = CELLINVALID;
490 
491 		if (!count) {
492 		    v = p->v;
493 		    count++;
494 		} else if (p->v < v)
495 		    v = p->v;
496 	    }
497 
498     if (count == 0)
499 	return ((double) 0);
500 
501     return (v);
502 }
503 
504 #define sec_min 60
505 #define sec_hr  3600L
506 #define sec_day 86400L
507 #define sec_yr  31471200L     /* 364.25 days/yr */
508 #define sec_mo  2622600L       /* sec_yr/12: sort of an average */
509 int mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
510 
511 double
dodts(mo,day,yr)512 dodts(mo, day, yr)
513 int mo, day, yr;
514 {
515     long trial;
516     register struct tm *tp;
517     register int i;
518     register long jdate;
519 
520     mdays[1] = 28 + (yr%4 == 0);
521 
522     if (mo < 1 || mo > 12 || day < 1 || day > mdays[--mo] ||
523 		yr > 2099 || yr < 1970) {
524 	scerror("@dts: invalid argument");
525 	cellerror = CELLERROR;
526 	return(0.0);
527     }
528 
529     jdate = day-1;
530     for (i=0; i<mo; i++)
531 	    jdate += mdays[i];
532     for (i = 1970; i < yr; i++)
533 	    jdate += 365 + (i%4 == 0);
534 
535     trial = jdate * sec_day;
536 
537     yr -= 1900;
538 
539     tp = localtime(&trial);
540 
541     if (tp->tm_year != yr) {
542 	    /*
543 	    * We may fail this test once a year because of time zone
544 	     * and daylight savings time errors.  This bounces the
545 	     * trial time past the boundary.  The error introduced is
546 	     * corrected below.
547 	     */
548 	    trial += sec_day*(yr - tp->tm_year);
549 	    tp = localtime(&trial);
550     }
551     if (tp->tm_mon != mo) {
552 	    /* We may fail this test once a month.  */
553 	    trial += sec_day*(mo - tp->tm_mon);
554 	    tp = localtime(&trial);
555     }
556     if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec != day) {
557 	trial -= (tp->tm_mday - day)*sec_day +  tp->tm_hour*sec_hr
558 		 + tp->tm_min*sec_min + tp->tm_sec;
559     }
560 
561     return ((double)trial);
562 }
563 
564 static double
dotts(hr,min,sec)565 dotts(hr, min, sec)
566 int hr, min, sec;
567 {
568     if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) {
569 	scerror("@tts: Invalid argument");
570 	cellerror = CELLERROR;
571 	return ((double)0);
572     }
573     return ((double)(sec+min*60+hr*3600));
574 }
575 
576 static double
dotime(which,when)577 dotime(which, when)
578 int which;
579 double when;
580 {
581 	static long t_cache;
582 	static struct tm tm_cache;
583 	struct tm *tp;
584 	long tloc;
585 
586 	if (which == NOW)
587 	    return (double)time((long *)0);
588 	tloc = (long)when;
589 
590 	if (tloc != t_cache) {
591 	    tp = localtime(&tloc);
592 	    tm_cache = *tp;
593 	    tm_cache.tm_mon += 1;
594 	    tm_cache.tm_year += 1900;
595 	    t_cache = tloc;
596 	}
597 
598 	switch (which) {
599 	    case HOUR: return((double)(tm_cache.tm_hour));
600 	    case MINUTE: return((double)(tm_cache.tm_min));
601 	    case SECOND: return((double)(tm_cache.tm_sec));
602 	    case MONTH: return((double)(tm_cache.tm_mon));
603 	    case DAY: return((double)(tm_cache.tm_mday));
604 	    case YEAR: return((double)(tm_cache.tm_year));
605 	}
606 	/* Safety net */
607 	cellerror = CELLERROR;
608 	return ((double)0);
609 }
610 
611 static double
doston(s)612 doston(s)
613 char *s;
614 {
615     double v;
616 
617     if (!s)
618 	return((double)0);
619 
620     v = atof(s);
621     /* (void)strtof(s, &v); */
622     scxfree(s);
623     return(v);
624 }
625 
626 static double
doeqs(s1,s2)627 doeqs(s1, s2)
628 char *s1, *s2;
629 {
630     double v;
631 
632     if (!s1 && !s2)
633 	return((double)1.0);
634 
635     if (!s1 || !s2)
636 	v = 0.0;
637     else if (strcmp(s1, s2) == 0)
638 	v = 1.0;
639     else
640 	v = 0.0;
641 
642     if (s1)
643     	scxfree(s1);
644 
645     if (s2)
646     	scxfree(s2);
647 
648     return(v);
649 }
650 
651 
652 /*
653  * Given a string representing a column name and a value which is a column
654  * number, return a pointer to the selected cell's entry, if any, else NULL.
655  * Use only the integer part of the column number.  Always free the string.
656  */
657 
658 static struct ent *
getent(colstr,rowdoub)659 getent (colstr, rowdoub)
660     char *colstr;
661     double rowdoub;
662 {
663     int collen;		/* length of string */
664     int row, col;	/* integer values   */
665     struct ent *p = (struct ent *)0;	/* selected entry   */
666 
667     if (!colstr)
668     {	cellerror = CELLERROR;
669 	return((struct ent *)0);
670     }
671 
672     if (((row = (int) floor (rowdoub)) >= 0)
673      && (row < maxrows)				/* in range */
674      && ((collen = strlen (colstr)) <= 2)	/* not too long */
675      && ((col = atocol (colstr, collen)) >= 0)
676      && (col < maxcols))			/* in range */
677     {
678 	p = *ATBL(tbl, row, col);
679 	if ((p != NULL) && p->cellerror)
680 		cellerror = CELLINVALID;
681     }
682     scxfree (colstr);
683     return (p);
684 }
685 
686 
687 /*
688  * Given a string representing a column name and a value which is a column
689  * number, return the selected cell's numeric value, if any.
690  */
691 
692 static double
donval(colstr,rowdoub)693 donval (colstr, rowdoub)
694     char *colstr;
695     double rowdoub;
696 {
697     struct ent *ep;
698 
699     return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ?
700 	    (ep -> v) : (double)0);
701 }
702 
703 
704 /*
705  *	The list routines (e.g. dolmax) are called with an LMAX enode.
706  *	The left pointer is a chain of ELIST nodes, the right pointer
707  *	is a value.
708  */
709 static double
dolmax(ep)710 dolmax(ep)
711 struct enode *ep;
712 {
713 	register int count = 0;
714 	register double maxval = 0; /* Assignment to shut up lint */
715 	register struct enode *p;
716 	register double v;
717 
718 	cellerror = CELLOK;
719 	for (p = ep; p; p = p->e.o.left) {
720 		v = eval(p->e.o.right);
721 		if (!count || v > maxval) {
722 			maxval = v; count++;
723 		}
724 	}
725 	if (count) return maxval;
726 	else return (double)0;
727 }
728 
729 static double
dolmin(ep)730 dolmin(ep)
731 struct enode *ep;
732 {
733 	register int count = 0;
734 	register double minval = 0; /* Assignment to shut up lint */
735 	register struct enode *p;
736 	register double v;
737 
738 	cellerror = CELLOK;
739 	for (p = ep; p; p = p->e.o.left) {
740 		v = eval(p->e.o.right);
741 		if (!count || v < minval) {
742 			minval = v; count++;
743 		}
744 	}
745 	if (count) return minval;
746 	else return (double)0;
747 }
748 
749 static double
eval(e)750 eval(e)
751 register struct enode *e;
752 {
753     if (e == (struct enode *)0)
754     {	cellerror = CELLINVALID;
755 	return (double)0;
756     }
757     switch (e->op) {
758 	case '+':	return (eval(e->e.o.left) + eval(e->e.o.right));
759 	case '-':	return (eval(e->e.o.left) - eval(e->e.o.right));
760 	case '*':	return (eval(e->e.o.left) * eval(e->e.o.right));
761 	case '/':     { double num, denom;
762 			num = eval(e->e.o.left);
763 			denom = eval(e->e.o.right);
764 			if (denom)
765 /*			if (1) */
766 				/* to test num div 0 */
767 				return(num/denom);
768 			else
769 			{	cellerror = CELLERROR;
770 				return((double) 0);
771 			}
772 	}
773 	case '%':     {	double num, denom;
774 			num = floor(eval(e->e.o.left));
775 			denom = floor(eval (e->e.o.right));
776 			if (denom)
777 				return(num - floor(num/denom)*denom);
778 			else
779 			{	cellerror = CELLERROR;
780 				return((double) 0);
781 			}
782 	}
783 	case '^':	return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right)));
784 	case '<':	return (eval(e->e.o.left) < eval(e->e.o.right));
785 	case '=':	return (eval(e->e.o.left) == eval(e->e.o.right));
786 	case '>':	return (eval(e->e.o.left) > eval(e->e.o.right));
787 	case '&':	return (eval(e->e.o.left) && eval(e->e.o.right));
788 	case '|':	return (eval(e->e.o.left) || eval(e->e.o.right));
789 	case IF:
790 	case '?':	return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
791 						: eval(e->e.o.right->e.o.right);
792 	case 'm':	return (-eval(e->e.o.right));
793 	case 'f':	return (eval(e->e.o.right));
794 	case '~':	return (eval(e->e.o.right) == 0.0);
795 	case O_CONST:	return (e->e.k);
796 	case O_VAR:	if (e->e.v.vp->cellerror)
797 				cellerror = CELLINVALID;
798 			return (e->e.v.vp->v);
799 	case INDEX:
800 	case LOOKUP:
801 	case HLOOKUP:
802 	case VLOOKUP:
803 	    {	int r,c;
804 		int maxr, maxc;
805 		int minr, minc;
806 		maxr = e->e.o.right->e.r.right.vp -> row;
807 		maxc = e->e.o.right->e.r.right.vp -> col;
808 		minr = e->e.o.right->e.r.left.vp -> row;
809 		minc = e->e.o.right->e.r.left.vp -> col;
810 		if (minr>maxr) r = maxr, maxr = minr, minr = r;
811 		if (minc>maxc) c = maxc, maxc = minc, minc = c;
812 		switch(e->op){
813 		case LOOKUP:
814 		    return dolookup(e->e.o.left, minr, minc, maxr, maxc,
815 				     minr==maxr, minc==maxc);
816 		case HLOOKUP:
817 	            return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
818 			(int) eval(e->e.o.left->e.o.right), 0);
819 		case VLOOKUP:
820 	            return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
821 			0, (int) eval(e->e.o.left->e.o.right));
822 		case INDEX:
823 		    return doindex(eval(e->e.o.left), minr, minc, maxr, maxc);
824 		}
825 	    }
826 	case REDUCE | '+':	/* sum */
827  	case REDUCE | '*':	/* prod */
828  	case REDUCE | 'a':	/* avg */
829  	case REDUCE | 'c':	/* count */
830  	case REDUCE | 's':	/* stddev */
831 	case REDUCE | IRR:	/* internal rate of return */
832 	case REDUCE | MAXR:	/* max-range */
833 	case REDUCE | MINR:	/* min-range */
834 	    {	int r,c;
835 		int maxr, maxc;
836 		int minr, minc;
837 		maxr = e->e.r.right.vp -> row;
838 		maxc = e->e.r.right.vp -> col;
839 		minr = e->e.r.left.vp -> row;
840 		minc = e->e.r.left.vp -> col;
841 		if (minr>maxr) r = maxr, maxr = minr, minr = r;
842 		if (minc>maxc) c = maxc, maxc = minc, minc = c;
843 	        switch (e->op & ~REDUCE) {
844 	            case '+': return dosum(minr, minc, maxr, maxc);
845  	            case '*': return doprod(minr, minc, maxr, maxc);
846  	            case 'a': return doavg(minr, minc, maxr, maxc);
847  	            case 'c': return docount(minr, minc, maxr, maxc);
848  	            case 's': return dostddev(minr, minc, maxr, maxc);
849 		    case IRR: return doirr(minr, minc, maxr, maxc);
850  	            case MAXR: return domax(minr, minc, maxr, maxc);
851  	            case MINR: return domin(minr, minc, maxr, maxc);
852 		}
853 	    }
854 	case ABS:	 return (fn1_eval( fabs, eval(e->e.o.right)));
855 	case ACOS:	 return (fn1_eval( acos, eval(e->e.o.right)));
856 	case ASIN:	 return (fn1_eval( asin, eval(e->e.o.right)));
857 	case ATAN:	 return (fn1_eval( atan, eval(e->e.o.right)));
858 	case ATAN2:	 return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right)));
859 	case CEIL:	 return (fn1_eval( ceil, eval(e->e.o.right)));
860 	case COS:	 return (fn1_eval( cos, eval(e->e.o.right)));
861 	case EXP:	 return (fn1_eval( exp, eval(e->e.o.right)));
862 	case FABS:	 return (fn1_eval( fabs, eval(e->e.o.right)));
863 	case FLOOR:	 return (fn1_eval( floor, eval(e->e.o.right)));
864 	case HYPOT:	 return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right)));
865 	case LOG:	 return (fn1_eval( log, eval(e->e.o.right)));
866 	case LOG10:	 return (fn1_eval( log10, eval(e->e.o.right)));
867 	case POW:	 return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right)));
868 	case SIN:	 return (fn1_eval( sin, eval(e->e.o.right)));
869 	case SQRT:	 return (fn1_eval( sqrt, eval(e->e.o.right)));
870 	case TAN:	 return (fn1_eval( tan, eval(e->e.o.right)));
871 	case DTR:	 return (dtr(eval(e->e.o.right)));
872 	case RTD:	 return (rtd(eval(e->e.o.right)));
873 	case RND:
874 		if (rndinfinity)
875 		{	double temp = eval(e->e.o.right);
876 			return(temp-floor(temp) < 0.5 ?
877 					floor(temp) : ceil(temp));
878 		}
879 		else
880 			return rint(eval(e->e.o.right));
881  	case ROUND:
882 		{	int prec = (int) eval(e->e.o.right);
883 			double	scal = 1;
884 			if (0 < prec)
885 				do scal *= 10; while (0 < --prec);
886 			else if (prec < 0)
887 				do scal /= 10; while (++prec < 0);
888 
889 			if (rndinfinity)
890 			{	double temp = eval(e->e.o.left);
891 				temp *= scal;
892 				temp = ((temp-floor(temp)) < 0.5 ?
893 						floor(temp) : ceil(temp));
894 				return(temp / scal);
895 			}
896 			else
897 				return(rint(eval(e->e.o.left) * scal) / scal);
898 		}
899 	case FV:
900 	case PV:
901 	case PMT:	return(finfunc(e->op,eval(e->e.o.left),
902 				   eval(e->e.o.right->e.o.left),
903 				      eval(e->e.o.right->e.o.right)));
904 	case HOUR:	return (dotime(HOUR, eval(e->e.o.right)));
905 	case MINUTE:	return (dotime(MINUTE, eval(e->e.o.right)));
906 	case SECOND:	return (dotime(SECOND, eval(e->e.o.right)));
907 	case MONTH:	return (dotime(MONTH, eval(e->e.o.right)));
908 	case DAY:	return (dotime(DAY, eval(e->e.o.right)));
909 	case YEAR:	return (dotime(YEAR, eval(e->e.o.right)));
910 	case NOW:	return (dotime(NOW, (double)0.0));
911 	case DTS:	return (dodts((int)eval(e->e.o.left),
912 				 (int)eval(e->e.o.right->e.o.left),
913 				 (int)eval(e->e.o.right->e.o.right)));
914 	case TTS:	return (dotts((int)eval(e->e.o.left),
915 				 (int)eval(e->e.o.right->e.o.left),
916 				 (int)eval(e->e.o.right->e.o.right)));
917 	case STON:	return (doston(seval(e->e.o.right)));
918 	case EQS:       return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
919 	case LMAX:	return dolmax(e);
920 	case LMIN:	return dolmin(e);
921 	case NVAL:      return (donval(seval(e->e.o.left),eval(e->e.o.right)));
922 	case MYROW:	return ((double) gmyrow);
923 	case MYCOL:	return ((double) gmycol);
924 	case NUMITER:	return ((double) repct);
925 	default:	scerror("Illegal numeric expression");
926 			exprerr = 1;
927     }
928     cellerror = CELLERROR;
929     return((double)0.0);
930 }
931 
932 static RETSIGTYPE   /* static added by Bob Parbs 12-92 */
eval_fpe(sig)933 eval_fpe(sig) /* Trap for FPE errors in eval */
934 int	sig;
935 {
936 #if defined(i386) && !defined(M_XENIX)
937 	/*asm("	fnclex");*/
938 	/*asm("	fwait");*/
939 #else
940 #ifdef IEEE_MATH
941 	(void)fpsetsticky((fp_except)0);	/* Clear exception */
942 #endif /* IEEE_MATH */
943 #ifdef PC
944 	_fpreset();
945 #endif
946 #endif
947 	/* re-establish signal handler for next time */
948 	(void) signal(SIGFPE, eval_fpe);
949 	longjmp(fpe_save, 1);
950 }
951 
952 static double
953 fn1_eval(fn, arg)
954 double (*fn)();
955 double arg;
956 {
957 	double res;
958 	errno = 0;
959 	res = (*fn)(arg);
960 	if(errno)
961 		cellerror = CELLERROR;
962 
963 	return res;
964 }
965 
966 static double
967 fn2_eval(fn, arg1, arg2)
968 double (*fn)();
969 double arg1, arg2;
970 {
971 	double res;
972 	errno = 0;
973 	res = (*fn)(arg1, arg2);
974 	if(errno)
975 		cellerror = CELLERROR;
976 
977 	return res;
978 }
979 
980 /*
981  * Rules for string functions:
982  * Take string arguments which they scxfree.
983  * All returned strings are assumed to be xalloced.
984  */
985 
986 static char *
docat(s1,s2)987 docat(s1, s2)
988 register char *s1, *s2;
989 {
990     register char *p;
991     char *arg1, *arg2;
992 
993     if (!s1 && !s2)
994 	return((char *)0);
995     arg1 = s1 ? s1 : "";
996     arg2 = s2 ? s2 : "";
997     p = scxmalloc((unsigned)(strlen(arg1)+strlen(arg2)+1));
998     (void) strcpy(p, arg1);
999     (void) strcat(p, arg2);
1000     if (s1)
1001         scxfree(s1);
1002     if (s2)
1003         scxfree(s2);
1004     return(p);
1005 }
1006 
1007 static char *
dodate(tloc)1008 dodate(tloc)
1009 long tloc;
1010 {
1011     char *tp;
1012     char *p;
1013 
1014     tp = ctime(&tloc);
1015     tp[24] = '\0';
1016     p = scxmalloc((unsigned)25);
1017     (void) strcpy(p, tp);
1018     return(p);
1019 }
1020 
1021 
1022 static char *
dofmt(fmtstr,v)1023 dofmt(fmtstr, v)
1024 char *fmtstr;
1025 double v;
1026 {
1027     char buff[FBUFLEN];
1028     char *p;
1029 
1030     if (!fmtstr)
1031 	return((char *)0);
1032     (void) sprintf(buff, fmtstr, v);
1033     p = scxmalloc((unsigned)(strlen(buff)+1));
1034     (void) strcpy(p, buff);
1035     scxfree(fmtstr);
1036     return(p);
1037 }
1038 
1039 
1040 /*
1041  * Given a command name and a value, run the command with the given value and
1042  * read and return its first output line (only) as an allocated string, always
1043  * a copy of prevstr, which is set appropriately first unless external
1044  * functions are disabled, in which case the previous value is used.  The
1045  * handling of prevstr and freeing of command is tricky.  Returning an
1046  * allocated string in all cases, even if null, insures cell expressions are
1047  * written to files, etc.
1048  */
1049 
1050 #if defined(VMS) || defined(MSDOS)
1051 static char *
doext(command,value)1052 doext(command, value)
1053 char *command;
1054 double value;
1055 {
1056     scerror("Warning: External functions unavailable on VMS");
1057     cellerror = CELLERROR;	/* not sure if this should be a cellerror */
1058     if (command)
1059 	scxfree(command);
1060     return (strcpy (scxmalloc((unsigned) 1), "\0"));
1061 }
1062 
1063 #else /* VMS */
1064 
1065 static char *
doext(command,value)1066 doext (command, value)
1067 char   *command;
1068 double value;
1069 {
1070     static char *prevstr = (char *)0;	/* previous result */
1071     static unsigned	prevlen = 0;
1072     char buff[FBUFLEN];		/* command line/return, not permanently alloc */
1073 
1074     if (!extfunc)    {
1075 	sprintf(stringbuf, "Warning: external functions disabled; using %s value",
1076 		((prevstr == NULL) || (*prevstr == '\0')) ?
1077 			"null" : "previous");
1078 	scerror(stringbuf);
1079 
1080 	if (command)
1081 		scxfree (command);
1082     } else {
1083 	if ((! command) || (! *command)) {
1084 	    scerror("Warning: external function given null command name");
1085 	    cellerror = CELLERROR;
1086 	    if (command) scxfree (command);
1087 	} else {
1088 	    FILE *pp;
1089 
1090 	    (void) sprintf (buff, "%s %g", command, value); /* build cmd line */
1091 	    scxfree (command);
1092 
1093 	    scerror("Running external function...");
1094 	    if (!using_X)
1095 		(void) refresh();
1096 
1097 	    if ((pp = popen (buff, "r")) == (FILE *) NULL) {	/* run it */
1098 		sprintf(stringbuf, "Warning: running \"%s\" failed", buff);
1099 		scerror(stringbuf);
1100 		cellerror = CELLERROR;
1101 	    }
1102 	    else {
1103 		if (fgets (buff, sizeof(buff)-1, pp) == NULL)	/* one line */
1104 		    scerror("Warning: external function returned nothing");
1105 		else {
1106 		    char *cp;
1107 
1108 		    scerror("");				/* erase notice */
1109 		    buff[sizeof(buff)-1] = '\0';
1110 
1111 		    if ((cp = strchr (buff, '\n')) != NULL)/*contains newline*/
1112 			*cp = '\0';			/* end string there */
1113 
1114 		    if (strlen(buff) + 1 > prevlen)
1115 		    {	prevlen = strlen(buff) + 40;
1116 			prevstr = scxrealloc(prevstr, prevlen);
1117 		    }
1118 		    (void) strcpy (prevstr, buff);
1119 			 /* save alloc'd copy */
1120 		}
1121 		(void) pclose (pp);
1122 
1123 	    } /* else */
1124 	} /* else */
1125     } /* else */
1126     if (prevstr)
1127 	return (strcpy (scxmalloc ((unsigned) (strlen (prevstr) + 1)), prevstr));
1128     else
1129 	return (strcpy(scxmalloc((unsigned)1), ""));
1130 }
1131 
1132 #endif /* VMS */
1133 
1134 
1135 /*
1136  * Given a string representing a column name and a value which is a column
1137  * number, return the selected cell's string value, if any.  Even if none,
1138  * still allocate and return a null string so the cell has a label value so
1139  * the expression is saved in a file, etc.
1140  */
1141 
1142 static char *
dosval(colstr,rowdoub)1143 dosval (colstr, rowdoub)
1144     char *colstr;
1145     double rowdoub;
1146 {
1147     struct ent *ep;
1148     char *llabel;
1149 
1150     llabel = (ep = getent (colstr, rowdoub)) ? (ep -> label) : "";
1151     return (strcpy (scxmalloc ((unsigned) (strlen (llabel) + 1)), llabel));
1152 }
1153 
1154 
1155 /*
1156  * Substring:  Note that v1 and v2 are one-based to users, but zero-based
1157  * when calling this routine.
1158  */
1159 
1160 static char *
dosubstr(s,v1,v2)1161 dosubstr(s, v1, v2)
1162 char *s;
1163 register int v1,v2;
1164 {
1165     register char *s1, *s2;
1166     char *p;
1167 
1168     if (!s)
1169 	return((char *)0);
1170 
1171     if (v2 >= (int)strlen (s))		/* past end */
1172 	v2 =  strlen (s) - 1;		/* to end   */
1173 
1174     if (v1 < 0 || v1 > v2) {		/* out of range, return null string */
1175 	scxfree(s);
1176 	p = scxmalloc((unsigned)1);
1177 	p[0] = '\0';
1178 	return(p);
1179     }
1180     s2 = p = scxmalloc((unsigned)(v2-v1+2));
1181     s1 = &s[v1];
1182     for(; v1 <= v2; s1++, s2++, v1++)
1183 	*s2 = *s1;
1184     *s2 = '\0';
1185     scxfree(s);
1186     return(p);
1187 }
1188 
1189 /*
1190  * character casing: make upper case, make lower case
1191  */
1192 
1193 static char *
docase(acase,s)1194 docase( acase, s)
1195 int acase;
1196 char *s;
1197 {
1198     char *p = s;
1199 
1200     if (s == NULL)
1201 	return(NULL);
1202 
1203     if( acase == UPPER ) {
1204         while( *p != '\0' ) {
1205            if( islower(*p) )
1206 		*p = toupper(*p);
1207 	   p++;
1208 	}
1209     }
1210     else if ( acase == LOWER ) {
1211 	while( *p != '\0' ) {
1212 	    if (isupper(*p))
1213 		*p = tolower(*p);
1214 	    p++;
1215 	}
1216     }
1217     return (s);
1218 }
1219 
1220 /*
1221  * make proper capitals of every word in a string
1222  * if the string has mixed case we say the string is lower
1223  *	and we will upcase only first letters of words
1224  * if the string is all upper we will lower rest of words.
1225  */
1226 
1227 static char *
docapital(s)1228 docapital( s )
1229 char *s;
1230 {
1231     char *p;
1232     int skip = 1;
1233     int AllUpper = 1;
1234 
1235     if (s == NULL)
1236 	return(NULL);
1237     for( p = s; *p != '\0' && AllUpper != 0; p++ )
1238 	if( isalpha(*p) && islower(*p) )  AllUpper = 0;
1239     for (p = s; *p != '\0'; p++) {
1240 	if (!isalnum(*p))
1241 		skip = 1;
1242 	else
1243 	if (skip == 1) {
1244 		skip = 0;
1245 		if (islower(*p))
1246 			*p = toupper(*p);
1247 	}
1248 	else	/* if the string was all upper before */
1249         if (isupper(*p) && AllUpper != 0)
1250 		*p = tolower(*p);
1251     }
1252     return(s);
1253 }
1254 
1255 static char *
seval(se)1256 seval(se)
1257 register struct enode *se;
1258 {
1259     register char *p;
1260 
1261     if (se == (struct enode *)0) return (char *)0;
1262     switch (se->op) {
1263 	case O_SCONST: p = scxmalloc((unsigned)(strlen(se->e.s)+1));
1264 		     (void) strcpy(p, se->e.s);
1265 		     return(p);
1266 	case O_VAR:    {
1267 			struct ent *ep;
1268 			ep = se->e.v.vp;
1269 
1270 			if (!ep->label)
1271 			    return((char *)0);
1272 			p = scxmalloc((unsigned)(strlen(ep->label)+1));
1273 			(void) strcpy(p, ep->label);
1274 			return(p);
1275 		     }
1276 	case '#':    return(docat(seval(se->e.o.left), seval(se->e.o.right)));
1277 	case 'f':    return(seval(se->e.o.right));
1278 	case IF:
1279 	case '?':    return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
1280 					     : seval(se->e.o.right->e.o.right));
1281 	case DATE:   return(dodate((long)(eval(se->e.o.right))));
1282 	case FMT:    return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
1283 	case UPPER:  return(docase(UPPER, seval(se->e.o.right)));
1284 	case LOWER:  return(docase(LOWER, seval(se->e.o.right)));
1285 	case CAPITAL:return(docapital(seval(se->e.o.right)));
1286  	case STINDEX:
1287  		{	register r,c;
1288  		register maxr, maxc;
1289  		register minr, minc;
1290  		maxr = se->e.o.right->e.r.right.vp -> row;
1291  		maxc = se->e.o.right->e.r.right.vp -> col;
1292  		minr = se->e.o.right->e.r.left.vp -> row;
1293  		minc = se->e.o.right->e.r.left.vp -> col;
1294  		if (minr>maxr) r = maxr, maxr = minr, minr = r;
1295  		if (minc>maxc) c = maxc, maxc = minc, minc = c;
1296  	        return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc);
1297 		}
1298 	case EXT:    return(doext(seval(se->e.o.left), eval(se->e.o.right)));
1299 	case SVAL:   return(dosval(seval(se->e.o.left), eval(se->e.o.right)));
1300 	case SUBSTR: return(dosubstr(seval(se->e.o.left),
1301 			    (int)eval(se->e.o.right->e.o.left) - 1,
1302 			    (int)eval(se->e.o.right->e.o.right) - 1));
1303 	case COLTOA: return(strcpy(scxmalloc((unsigned)10),
1304 				   coltoa((int)eval(se->e.o.right)+1)));
1305 	default:
1306 		     scerror("Illegal string expression");
1307 		     exprerr = 1;
1308 		     return(NULL);
1309 	}
1310 }
1311 
1312 /*
1313  * The graph formed by cell expressions which use other cells's values is not
1314  * evaluated "bottom up".  The whole table is merely re-evaluated cell by cell,
1315  * top to bottom, left to right, in RealEvalAll().  Each cell's expression uses
1316  * constants in other cells.  However, RealEvalAll() notices when a cell gets a
1317  * new numeric or string value, and reports if this happens for any cell.
1318  * EvalAll() repeats calling RealEvalAll() until there are no changes or the
1319  * evaluation count expires.
1320  */
1321 
1322 int propagation = 10;	/* max number of times to try calculation */
1323 int repct = 1;		/* Make repct a global variable so that the
1324 				function @numiter can access it */
1325 
1326 void
setiterations(i)1327 setiterations(i)
1328 int i;
1329 {
1330 	if(i<1) {
1331 		scerror("iteration count must be at least 1");
1332 		propagation = 1;
1333 		}
1334 	else propagation = i;
1335 }
1336 
1337 void
EvalAll()1338 EvalAll () {
1339      int lastcnt;
1340 
1341      repct = 1;
1342      (void) signal(SIGFPE, eval_fpe);
1343 
1344      while ((lastcnt = RealEvalAll()) && (++repct <= propagation));
1345      if((propagation>1)&& (lastcnt >0 ))
1346      {  sprintf(stringbuf, "Still changing after %d iterations",propagation-1);
1347 	scerror(stringbuf);
1348      }
1349 
1350     (void) signal(SIGFPE, doquit);
1351 }
1352 
1353 /*
1354  * Evaluate all cells which have expressions and alter their numeric or string
1355  * values.  Return the number of cells which changed.
1356  */
1357 
1358 static int
RealEvalAll()1359 RealEvalAll () {
1360     register int i,j;
1361     int chgct = 0;
1362     register struct ent *p;
1363 
1364     if(calc_order == BYROWS ) {
1365 	for (i=0; i<=maxrow; i++)
1366 	    for (j=0; j<=maxcol; j++)
1367 		if ((p = *ATBL(tbl,i,j)) && !(p->flags&is_locked) && p->expr) RealEvalOne(p,i,j,&chgct);
1368     }
1369     else if ( calc_order == BYCOLS ) {
1370 	for (j=0; j<=maxcol; j++)
1371 	{   for (i=0; i<=maxrow; i++)
1372 		if ((p = *ATBL(tbl,i,j)) && !(p->flags&is_locked) && p->expr) RealEvalOne(p,i,j,&chgct);
1373 	}
1374     }
1375     else scerror("Internal error calc_order");
1376 
1377     return(chgct);
1378 }
1379 
1380 static void                /* static added by Bob Parbs 12-92 */
RealEvalOne(p,i,j,chgct)1381 RealEvalOne(p, i, j, chgct)
1382 register struct ent *p;
1383 int i, j, *chgct;
1384 {
1385 	if (p->flags & is_strexpr) {
1386 	    char *v;
1387 	    if (setjmp(fpe_save)) {
1388 		sprintf(stringbuf, "Floating point exception %s", v_name(i, j));
1389 		scerror(stringbuf);
1390 		cellerror = CELLERROR;
1391 		v = "";
1392 	    } else {
1393 		cellerror = CELLOK;
1394 		v = seval(p->expr);
1395 	    }
1396 	    p->cellerror = cellerror;
1397 	    if (!v && !p->label) /* Everything's fine */
1398 		return;
1399 	    if (!p->label || !v || strcmp(v, p->label) != 0 || cellerror) {
1400 		(*chgct)++;
1401 		p->flags |= is_changed;
1402 		changed++;
1403 	    }
1404 	    if(p->label)
1405 		scxfree(p->label);
1406 	    p->label = v;
1407 	} else {
1408 	    double v;
1409 	    if (setjmp(fpe_save)) {
1410 		sprintf(stringbuf, "Floating point exception %s", v_name(i, j));
1411 		scerror(stringbuf);
1412 		cellerror = CELLERROR;
1413 		v = (double)0.0;
1414 	    } else {
1415 		cellerror = CELLOK;
1416 		gmyrow=i; gmycol=j;
1417 		v = eval (p->expr);
1418 	    }
1419 	    /*
1420 	    if ((p->cellerror = cellerror) || (v != p->v)) {
1421 		p->v = v;
1422 		if (!cellerror)*/	/* don't keep eval'ing a error */
1423 	    /*		(*chgct)++;
1424 		p->flags |= is_changed|is_valid;
1425 		changed++;
1426 	    }
1427 	    */
1428 	    if ( (p->cellerror = cellerror) || (p->v == 0 && v != 0)
1429 			    || (fabs((v - p->v)/p->v) > 1e-8) ) {
1430 		p->v = v;
1431 		if (!cellerror)         /* don't keep eval'ing a error */
1432 	        (*chgct)++;
1433 	        p->flags |= is_changed|is_valid;
1434 		changed++;
1435 		}
1436 	}
1437 }
1438 
1439 struct enode *
new(op,a1,a2)1440 new(op, a1, a2)
1441 int	op;
1442 struct enode *a1, *a2;
1443 {
1444     register struct enode *p;
1445     if (freeenodes)
1446     {	p = freeenodes;
1447 	freeenodes = p->e.o.left;
1448     }
1449     else
1450 	p = (struct enode *) scxmalloc ((unsigned)sizeof (struct enode));
1451     p->op = op;
1452     p->e.o.left = a1;
1453     p->e.o.right = a2;
1454     return p;
1455 }
1456 
1457 struct enode *
new_var(op,a1)1458 new_var(op, a1)
1459 int	op;
1460 struct ent_ptr a1;
1461 {
1462     register struct enode *p;
1463     if (freeenodes)
1464     {	p = freeenodes;
1465 	freeenodes = p->e.o.left;
1466     }
1467     else
1468 	p = (struct enode *) scxmalloc ((unsigned)sizeof (struct enode));
1469     p->op = op;
1470     p->e.v = a1;
1471     return p;
1472 }
1473 
1474 struct enode *
new_range(op,a1)1475 new_range(op, a1)
1476 int	op;
1477 struct range_s a1;
1478 {
1479     register struct enode *p;
1480     if (freeenodes)
1481     {	p = freeenodes;
1482 	freeenodes = p->e.o.left;
1483     }
1484     else
1485 	p = (struct enode *) scxmalloc ((unsigned)sizeof (struct enode));
1486     p->op = op;
1487     p->e.r = a1;
1488     return p;
1489 }
1490 
1491 struct enode *
new_const(op,a1)1492 new_const(op, a1)
1493 int	op;
1494 double a1;
1495 {
1496     register struct enode *p;
1497     if (freeenodes)	/* reuse an already free'd enode */
1498     {	p = freeenodes;
1499 	freeenodes = p->e.o.left;
1500     }
1501     else
1502 	p = (struct enode *) scxmalloc ((unsigned)sizeof (struct enode));
1503     p->op = op;
1504     p->e.k = a1;
1505     return p;
1506 }
1507 
1508 struct enode *
new_str(s)1509 new_str(s)
1510 char *s;
1511 {
1512     register struct enode *p;
1513 
1514     if (freeenodes)	/* reuse an already free'd enode */
1515     {	p = freeenodes;
1516 	freeenodes = p->e.o.left;
1517     }
1518     else
1519 	p = (struct enode *) scxmalloc ((unsigned)sizeof(struct enode));
1520     p->op = O_SCONST;
1521     p->e.s = s;
1522     return(p);
1523 }
1524 
1525 /*
1526  * copy from v1:v2 to dv1:dv2
1527  *
1528  * -special case where dv2, the destination max is empty,
1529  * in which case force the destination to conform to the source.
1530  */
1531 void
copy(dv1,dv2,v1,v2)1532 copy(dv1, dv2, v1, v2)
1533 struct ent *dv1, *dv2, *v1, *v2;
1534 {
1535     int minsr, minsc;
1536     int maxsr, maxsc;
1537     int mindr, mindc;
1538     int maxdr, maxdc;
1539     int vr, vc;
1540     int r, c;
1541 
1542     mindr = dv1->row;
1543     mindc = dv1->col;
1544     maxdr = dv2->row;
1545     maxdc = dv2->col;
1546     if (mindr>maxdr)  r = maxdr, maxdr = mindr, mindr = r;
1547     if (mindc>maxdc)  c = maxdc, maxdc = mindc, mindc = c;
1548     maxsr = v2->row;
1549     maxsc = v2->col;
1550     minsr = v1->row;
1551     minsc = v1->col;
1552     if (minsr>maxsr)  r = maxsr, maxsr = minsr, minsr = r;
1553     if (minsc>maxsc)  c = maxsc, maxsc = minsc, minsc = c;
1554     mindr = dv1->row;
1555     mindc = dv1->col;
1556     if (dv2) {
1557 	maxdr = dv2->row;
1558 	maxdc = dv2->col;
1559     }
1560     else {
1561 	/* special case, conform the destination to the source */
1562 	maxdr = mindr + maxsr - minsr;
1563 	maxdc = mindc + maxsc - minsc;
1564     }
1565     if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
1566     if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
1567     checkbounds(&maxdr, &maxdc);
1568 
1569 	/* needed to make sure overlaps work */
1570 /*    flush_saved();
1571     erase_and_pull(mindr, mindc, maxdr, maxdc, 0, 1);
1572 */
1573     if (minsr == maxsr && minsc == maxsc) {
1574 	/* Source is a single cell */
1575 	for(vr = mindr; vr <= maxdr; vr++)
1576 	    for (vc = mindc; vc <= maxdc; vc++)
1577 		copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
1578     } else if (minsr == maxsr) {
1579 	/* Source is a single row */
1580 	for (vr = mindr; vr <= maxdr; vr++)
1581 	    copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
1582     } else if (minsc == maxsc) {
1583 	/* Source is a single column */
1584 	for (vc = mindc; vc <= maxdc; vc++)
1585 	    copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
1586     } else {
1587 	/* Everything else */
1588 	copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
1589     }
1590     sync_refs();
1591 }
1592 
1593 static void
copyrtv(vr,vc,minsr,minsc,maxsr,maxsc)1594 copyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
1595 int vr, vc, minsr, minsc, maxsr, maxsc;
1596 {
1597     register struct ent *p;
1598     register struct ent *n;
1599     int 	sr, sc;		/* source row/col */
1600     int		sdc, ssc;
1601     int 	dr, dc;		/* destination row/col */
1602     register	rsteps, csteps;
1603     int		scsteps;
1604     register	rinc, cinc;
1605 
1606     if (vr == minsr && vc == minsc)
1607 	return;	/* copying onto itself. */
1608     rsteps = maxsr - minsr + 1;
1609     csteps = maxsc - minsc + 1;
1610     rinc = cinc = 1;
1611     dr = vr; dc = vc;
1612     sr = minsr; sc = minsc;
1613     if (dr > sr) {
1614 	sr += rsteps - 1;
1615 	dr += rsteps - 1;
1616 	rinc = -1;
1617     }
1618     if (dc > sc) {
1619 	sc += csteps - 1;
1620 	dc += csteps - 1;
1621 	cinc = -1;
1622     }
1623     ssc = sc; sdc = dc; scsteps = csteps;
1624 
1625     for (; --rsteps >= 0; sr += rinc, dr += rinc)
1626     {
1627     	for (csteps = scsteps, sc = ssc, dc = sdc;
1628 	       --csteps >= 0; sc += cinc, dc += cinc)
1629 	{
1630 	    if ((p = *ATBL(tbl, sr, sc)) != NULL)
1631 	    {	n = lookat (dr, dc);
1632 		if (n->flags&is_locked) continue;
1633 		(void) clearent(n);
1634 		copyent( n, p, dr - sr, dc - sc);
1635 	    }
1636 	    else if ((n = *ATBL(tbl, dr, dc)) != NULL)
1637 		(void) clearent(n);
1638 	}
1639     }
1640 }
1641 
1642 
1643 /* ERASE a Range of cells */
1644 void
eraser(v1,v2)1645 eraser(v1, v2)
1646 struct ent *v1, *v2;
1647 {
1648 	FullUpdate++;
1649 	flush_saved();
1650 	erase_area(v1->row, v1->col, v2->row, v2->col);
1651 	sync_refs();
1652 }
1653 
1654 /* Goto subroutines */
1655 
1656 static void             /* static added by Bob Parbs 12-92 */
g_free()1657 g_free()
1658 {
1659     switch (gs.g_type) {
1660     case G_STR: scxfree(gs.g_s); break;
1661     default: break;
1662     }
1663     gs.g_type = G_NONE;
1664     gs.errsearch = 0;
1665 }
1666 
1667 /* repeat the last goto command */
1668 void
go_last()1669 go_last()
1670 {
1671     switch (gs.g_type) {
1672     case G_NONE:
1673 		scerror("Nothing to repeat"); break;
1674     case G_NUM:
1675 		num_search(gs.g_n, gs.errsearch);
1676 		break;
1677     case  G_CELL:
1678 		moveto(gs.g_row, gs.g_col);
1679 	    	break;
1680     case  G_STR:
1681 		gs.g_type = G_NONE;	/* Don't free the string */
1682    	    	str_search(gs.g_s);
1683 	   	break;
1684 
1685     default: scerror("go_last: internal error");
1686     }
1687 }
1688 
1689 /* place the cursor on a given cell */
1690 void
moveto(row,col)1691 moveto(row, col)
1692 int row, col;
1693 {
1694     currow = row;
1695     curcol = col;
1696     g_free();
1697     gs.g_type = G_CELL;
1698     gs.g_row = currow;
1699     gs.g_col = curcol;
1700 }
1701 
1702 /*
1703  * 'goto' either a given number,'error', or 'invalid' starting at currow,curcol
1704  */
1705 void
num_search(n,errsearch)1706 num_search(n, errsearch)
1707 double n;
1708 int	errsearch;
1709 {
1710     register struct ent *p;
1711     register int r,c;
1712     int	endr, endc;
1713 
1714     g_free();
1715     gs.g_type = G_NUM;
1716     gs.g_n = n;
1717     gs.errsearch = errsearch;
1718 
1719     if (currow > maxrow)
1720 	endr = maxrow ? maxrow-1 : 0;
1721     else
1722 	endr = currow;
1723     if (curcol > maxcol)
1724 	endc = maxcol ? maxcol-1 : 0;
1725     else
1726 	endc = curcol;
1727     r = endr;
1728     c = endc;
1729     do {
1730 	if (c < maxcol)
1731 	    c++;
1732 	else {
1733 	    if (r < maxrow) {
1734 		while(++r < maxrow && row_hidden[r]) /* */;
1735 		c = 0;
1736 	    } else {
1737 		r = 0;
1738 		c = 0;
1739 	    }
1740 	}
1741 	if (r == endr && c == endc) {
1742 	    if (errsearch)
1743 	    {	sprintf(stringbuf, "no %s cell found",
1744 			errsearch == CELLERROR ? "ERROR" : "INVALID");
1745 		scerror(stringbuf);
1746 	    }
1747 	    else
1748 		scerror("Number not found");
1749 	    return;
1750 	}
1751 	p = *ATBL(tbl, r, c);
1752     } while (col_hidden[c] || !p || !(p->flags & is_valid)
1753 	|| (!errsearch && (p->v != n))
1754 	|| (errsearch && !((p->cellerror == errsearch) ||
1755 		(p->cellerror == errsearch))));	/* CELLERROR vs CELLINVALID */
1756 
1757     currow = r;
1758     curcol = c;
1759 }
1760 
1761 #if defined(REG_COMP) /* Peter Doemel, 10-Feb-1993 */
1762 char *
regerrmsg(errcode)1763 regerrmsg(errcode)
1764 int errcode;
1765 {
1766     switch(errcode) {
1767       case REG_NOMATCH:
1768           return "regexec() failed to match.";
1769       case REG_ECOLLATE:
1770           return "Invalid collation element referenced.";
1771       case REG_EESCAPE:
1772           return "Trailing \\ in pattern.";
1773       case REG_ENEWLINE:
1774           return "<newline> found before end of pattern and REG_NEWLINE flag not set.";
1775       case REG_ESUBREG:
1776           return "Number in \\digit invalid or in error.";
1777       case REG_EBRACK:
1778           return "[ ] imbalance.";
1779       case REG_EPAREN:
1780           return "\\( \\) imbalance in basic regular expression or ( ) imbalance in extended regular expression.";
1781       case REG_EBRACE:
1782           return "\\{ \\} imbalance.";
1783       case REG_ERANGE:
1784           return "Invalid endpoint in range statement.";
1785       case REG_ESPACE:
1786           return "Out of memory for compiled pattern.";
1787       case REG_EMEM:
1788           return "Out of memory while matching expression.";
1789 /*    case REG_EBADRPT:
1790           return "Misuse of *, +, or ? in extended regular expression."; */
1791       case REG_ECTYPE:
1792           return "Invalid character class type named.";
1793       case REG_ENSUB:
1794           return "Too many parenthesis pairs or nesting level too deep.";
1795       case REG_EABRACE:
1796           return "Number too large in \\{ \\} construct.";
1797       case REG_EBBRACE:
1798           return "Invalid number in \\{ \\} construct.";
1799       case REG_ECBRACE:
1800           return "More than two numbers in \\{ \\} construct.";
1801       case REG_EDBRACE:
1802           return "First number exceeds second in \\{ \\} construct.";
1803       case REG_ENOSEARCH:
1804           return "No remembered search string.";
1805       case REG_EDUPOPER:
1806           return "Duplication operator in illegal position.";
1807       case REG_ENOEXPR:
1808           return "No expression within ( ) or on one side of an |.";
1809       default:
1810           return "regerrmsg: INVALID ERRORCODE";
1811     }
1812 }
1813 #endif
1814 
1815 /* 'goto' a cell containing a matching string */
1816 
1817 void
str_search(s)1818 str_search(s)
1819 char *s;
1820 {
1821     register struct ent *p;
1822     register int r,c;
1823     int	endr, endc;
1824 #if defined(RE_COMP) || defined(REGCMP)
1825     char *tmp;
1826 #endif
1827 
1828 #if defined(REG_COMP) /* Peter Doemel, 10-Feb-1993 */
1829     int status;
1830     regex_t preg;
1831 
1832     if ((status = regcomp(&preg, s, 0)) != 0) {
1833        scxfree(s);
1834        cellerror = CELLERROR;
1835        scerror(regerrmsg(status));
1836        return;
1837     }
1838 #endif
1839 
1840 #if defined(RE_COMP)
1841     if ((tmp = re_comp(s)) != (char *)0) {
1842 	scxfree(s);
1843 	scerror(tmp);
1844 	return;
1845     }
1846 #endif
1847 #if defined(REGCMP)
1848     if ((tmp = regcmp(s, (char *)0)) == (char *)0) {
1849 	scxfree(s);
1850 	cellerror = CELLERROR;
1851 	scerror("Invalid search string");
1852 	return;
1853     }
1854 #endif
1855     g_free();
1856     gs.g_type = G_STR;
1857     gs.g_s = s;
1858     if (currow > maxrow)
1859 	endr = maxrow ? maxrow-1 : 0;
1860     else
1861 	endr = currow;
1862     if (curcol > maxcol)
1863 	endc = maxcol ? maxcol-1 : 0;
1864     else
1865 	endc = curcol;
1866     r = endr;
1867     c = endc;
1868     do {
1869 	if (c < maxcol)
1870 	    c++;
1871 	else {
1872 	    if (r < maxrow) {
1873 		while(++r < maxrow && row_hidden[r]) /* */;
1874 		c = 0;
1875 	    } else {
1876 		r = 0;
1877 		c = 0;
1878 	    }
1879 	}
1880 	if (r == endr && c == endc) {
1881 	    scerror("String not found");
1882 #if defined(REG_COMP) /* Peter Doemel, 10-Feb-1993 */
1883         regfree(&preg);
1884 #elif defined(REGCMP)
1885 	    free(tmp);
1886 #endif
1887 	    return;
1888 	}
1889 	p = *ATBL(tbl, r, c);
1890     } while(col_hidden[c] || !p || !(p->label)
1891 
1892 #if defined(REG_COMP) /* Peter Doemel, 10-Feb-1993 */
1893                         || (regexec(&preg, p->label, (size_t)0, NULL, 0) != 0));
1894 #elif defined(RE_COMP)
1895                         || (re_exec(p->label) == 0));
1896 #elif defined(REGCMP)
1897                         || (regex(tmp, p->label) == (char *)0));
1898 #else
1899 			|| (strcmp(s, p->label) != 0));
1900 #endif
1901     currow = r;
1902     curcol = c;
1903 #if defined(REG_COMP) /* Peter Doemel, 10-Feb-1993 */
1904     regfree(&preg);
1905 #elif defined(REGCMP)
1906     free(tmp);
1907 #endif
1908 }
1909 
1910 /* fill a range with constants */
1911 void
fill(v1,v2,start,inc)1912 fill (v1, v2, start, inc)
1913 struct ent *v1, *v2;
1914 double start, inc;
1915 {
1916     register r,c;
1917     register struct ent *n;
1918     int maxr, maxc;
1919     int minr, minc;
1920 
1921     maxr = v2->row;
1922     maxc = v2->col;
1923     minr = v1->row;
1924     minc = v1->col;
1925     if (minr>maxr) r = maxr, maxr = minr, minr = r;
1926     if (minc>maxc) c = maxc, maxc = minc, minc = c;
1927     checkbounds(&maxr, &maxc);
1928     if (minr < 0) minr = 0;
1929     if (minc < 0) minc = 0;
1930 
1931     FullUpdate++;
1932     flush_saved();
1933     /* save the contents */
1934 /*    erase_and_pull(minr, minc, maxr, maxc, 0, 1);*/
1935     if( calc_order == BYROWS ) {
1936     for (r = minr; r<=maxr; r++)
1937 	for (c = minc; c<=maxc; c++) {
1938 	    n = lookat (r, c);
1939 	    if (n->flags&is_locked) continue;
1940 	    (void) clearent(n);
1941 	    n->v = start;
1942 	    start += inc;
1943 	    n->flags |= (is_changed|is_valid);
1944 	}
1945     }
1946     else if ( calc_order == BYCOLS ) {
1947     for (c = minc; c<=maxc; c++)
1948 	for (r = minr; r<=maxr; r++) {
1949 	    n = lookat (r, c);
1950 	    (void) clearent(n);
1951 	    n->v = start;
1952 	    start += inc;
1953 	    n->flags |= (is_changed|is_valid);
1954 	}
1955     }
1956     else scerror(" Internal error calc_order");
1957     sync_refs();
1958     changed++;
1959 }
1960 
1961 /* lock a range of cells */
1962 
1963 void
lock_cells(v1,v2)1964 lock_cells (v1, v2)
1965 struct ent *v1, *v2;
1966 {
1967     register r,c;
1968     register struct ent *n;
1969     int maxr, maxc;
1970     int minr, minc;
1971 
1972     maxr = v2->row;
1973     maxc = v2->col;
1974     minr = v1->row;
1975     minc = v1->col;
1976     if (minr>maxr) r = maxr, maxr = minr, minr = r;
1977     if (minc>maxc) c = maxc, maxc = minc, minc = c;
1978     checkbounds(&maxr, &maxc);
1979     if (minr < 0) minr = 0;
1980     if (minc < 0) minc = 0;
1981 
1982     for (r = minr; r<=maxr; r++)
1983 	for (c = minc; c<=maxc; c++) {
1984 	    n = lookat (r, c);
1985 	    n->flags |= is_locked;
1986 	}
1987 }
1988 
1989 /* unlock a range of cells */
1990 
1991 void
unlock_cells(v1,v2)1992 unlock_cells (v1, v2)
1993 struct ent *v1, *v2;
1994 {
1995     register r,c;
1996     register struct ent *n;
1997     int maxr, maxc;
1998     int minr, minc;
1999 
2000     maxr = v2->row;
2001     maxc = v2->col;
2002     minr = v1->row;
2003     minc = v1->col;
2004     if (minr>maxr) r = maxr, maxr = minr, minr = r;
2005     if (minc>maxc) c = maxc, maxc = minc, minc = c;
2006     checkbounds(&maxr, &maxc);
2007     if (minr < 0) minr = 0;
2008     if (minc < 0) minc = 0;
2009 
2010     for (r = minr; r<=maxr; r++)
2011 	for (c = minc; c<=maxc; c++) {
2012 	    n = lookat (r, c);
2013 	    n->flags &= ~is_locked;
2014 	}
2015 }
2016 
2017 /* set the numeric part of a cell */
2018 void
let(v,e)2019 let (v, e)
2020 struct ent *v;
2021 struct enode *e;
2022 {
2023     double val;
2024     unsigned isconstant = constant(e);
2025 
2026     if (loading && !isconstant)
2027 	val = (double)0.0;
2028     else
2029     {
2030 	exprerr = 0;
2031 	(void) signal(SIGFPE, eval_fpe);
2032 	if (setjmp(fpe_save)) {
2033 	    sprintf(stringbuf, "Floating point exception in cell %s", v_name(v->row, v->col));
2034 	    scerror(stringbuf);
2035 	    val = (double)0.0;
2036 	    cellerror = CELLERROR;
2037 	} else {
2038 	    cellerror = CELLOK;
2039 	    val = eval(e);
2040 	}
2041 	if (v->cellerror != cellerror)
2042 	{	v->flags |= is_changed;
2043 		changed++;	modflg++;
2044 		FullUpdate++;
2045 		v->cellerror = cellerror;
2046 	}
2047 	(void) signal(SIGFPE, doquit);
2048 	if (exprerr) {
2049 	    efree(e);
2050 	    return;
2051 	}
2052     }
2053 
2054     if (isconstant) {
2055 	/* prescale input unless it has a decimal */
2056 #if defined(IEEE_MATH) && !defined(NO_FMOD)
2057 	if (!loading && (prescale < (double)0.9999999) &&
2058 				(fmod(val, (double)1.0) == (double)0))
2059 #else
2060 	if (!loading && (prescale < (double)0.9999999) &&
2061 			((val - floor(val)) == (double)0))
2062 #endif
2063 	    val *= prescale;
2064 
2065 	v->v = val;
2066 
2067 	if (!(v->flags & is_strexpr)) {
2068             efree(v->expr);
2069 	    v->expr = (struct enode *)0;
2070 	}
2071 	efree(e);
2072     }
2073     else
2074     {
2075 	efree(v->expr);
2076 	v->expr = e;
2077 	v->flags &= ~is_strexpr;
2078     }
2079 
2080     changed++; modflg++;
2081     v->flags |= (is_changed|is_valid);
2082 }
2083 
2084 void
slet(v,se,flushdir)2085 slet (v, se, flushdir)
2086 struct ent *v;
2087 struct enode *se;
2088 int flushdir;
2089 {
2090     char *p;
2091 
2092     exprerr = 0;
2093     (void) signal(SIGFPE, eval_fpe);
2094     if (setjmp(fpe_save)) {
2095 	sprintf(stringbuf, "Floating point exception in cell %s", v_name(v->row, v->col));
2096 	scerror(stringbuf);
2097 	cellerror = CELLERROR;
2098 	p = "";
2099     } else {
2100 	cellerror = CELLOK;
2101 	p = seval(se);
2102     }
2103     if (v->cellerror != cellerror)
2104     {	v->flags |= is_changed;
2105 	changed++;	modflg++;
2106 	FullUpdate++;
2107 	v->cellerror = cellerror;
2108     }
2109     (void) signal(SIGFPE, doquit);
2110     if (exprerr) {
2111 	efree(se);
2112 	return;
2113     }
2114     if (constant(se)) {
2115 	label(v, p, flushdir);
2116 	if (p)
2117 	    scxfree(p);
2118 	efree(se);
2119 	if (v->flags & is_strexpr) {
2120             efree(v->expr);
2121 	    v->expr = (struct enode *)0;
2122 	    v->flags &= ~is_strexpr;
2123 	}
2124 	return;
2125     }
2126     efree(v->expr);
2127     v->expr = se;
2128     v->flags |= (is_changed|is_strexpr);
2129     if (flushdir<0) v->flags |= is_leftflush;
2130 
2131     if (flushdir==0)
2132 	v->flags |= is_label;
2133     else v->flags &= ~is_label;
2134 
2135     FullUpdate++;
2136     changed++;
2137     modflg++;
2138 }
2139 
2140 void
format_cell(v1,v2,s)2141 format_cell(v1, v2, s)
2142 struct ent *v1, *v2;
2143 char *s;
2144 {
2145     register r,c;
2146     register struct ent *n;
2147     int maxr, maxc;
2148     int minr, minc;
2149 
2150     maxr = v2->row;
2151     maxc = v2->col;
2152     minr = v1->row;
2153     minc = v1->col;
2154     if (minr>maxr) r = maxr, maxr = minr, minr = r;
2155     if (minc>maxc) c = maxc, maxc = minc, minc = c;
2156     checkbounds(&maxr, &maxc);
2157     if (minr < 0) minr = 0;
2158     if (minc < 0) minc = 0;
2159 
2160     FullUpdate++;
2161 	modflg++;
2162     for (r = minr; r <= maxr; r++)
2163 	for (c = minc; c <= maxc; c++) {
2164 	    n = lookat (r, c);
2165 	    if (n->flags&is_locked) {
2166 		sprintf(stringbuf, "Cell %s%d is locked", coltoa(n->col), n->row);
2167 		scerror(stringbuf);
2168 		continue;
2169 	    }
2170 	    if (n->format)
2171 		scxfree(n->format);
2172 	    n->format = 0;
2173 	    if (s && *s != '\0')
2174 		n->format = strcpy(scxmalloc((unsigned)(strlen(s)+1)), s);
2175 	    n->flags |= is_changed;
2176        }
2177 }
2178 
2179 void
hide_row(arg)2180 hide_row(arg)
2181 int arg;
2182 {
2183     if (arg < 0) {
2184 	scerror("Invalid Range");
2185 	return;
2186     }
2187     if (arg >= maxrows-1)
2188     {
2189 	if (!growtbl(GROWROW, arg+1, 0))
2190 	{	scerror("You can't hide the last row");
2191 		return;
2192 	}
2193     }
2194     FullUpdate++;
2195     row_hidden[arg] = 1;
2196 }
2197 
2198 void
hide_col(arg)2199 hide_col(arg)
2200 int arg;
2201 {
2202     if (arg < 0) {
2203 	scerror("Invalid Range");
2204 	return;
2205     }
2206     if (arg >= maxcols-1)
2207     {	if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
2208 	{	scerror("You can't hide the last col");
2209 		return;
2210 	}
2211     }
2212     FullUpdate++;
2213     col_hidden[arg] = TRUE;
2214 }
2215 
2216 void
clearent(v)2217 clearent (v)
2218 struct ent *v;
2219 {
2220     if (!v)
2221 	return;
2222     label(v,"",-1);
2223     v->v = (double)0;
2224     if (v->expr)
2225 	efree(v->expr);
2226     v->expr = (struct enode *)0;
2227     if (v->format)
2228 	scxfree(v->format);
2229     v->format = (char *)0;
2230     v->flags |= (is_changed);
2231     v->flags &= ~(is_valid);
2232     changed++;
2233     modflg++;
2234 }
2235 
2236 /*
2237  * Say if an expression is a constant (return 1) or not.
2238  */
2239 static int                   /* static added by Bob Parbs 12-92 */
constant(e)2240 constant (e)
2241     register struct enode *e;
2242 {
2243     return (
2244 	 e == (struct enode *)0
2245 	 || e -> op == O_CONST
2246 	 || e -> op == O_SCONST
2247 	 || (
2248 	     e -> op != O_VAR
2249 	     && (e -> op & REDUCE) != REDUCE
2250 	     && constant (e -> e.o.left)
2251 	     && constant (e -> e.o.right)
2252 	     && e -> op != EXT	 /* functions look like constants but aren't */
2253 	     && e -> op != NVAL
2254 	     && e -> op != SVAL
2255 	     && e -> op != NOW
2256 	     && e -> op != MYROW
2257 	     && e -> op != MYCOL
2258 	     && e -> op != NUMITER
2259 	)
2260     );
2261 }
2262 
2263 void
efree(e)2264 efree (e)
2265 struct enode *e;
2266 {
2267     if (e) {
2268 	if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
2269 		&& (e->op & REDUCE) != REDUCE) {
2270 	    efree(e->e.o.left);
2271 	    efree(e->e.o.right);
2272 	}
2273 	if (e->op == O_SCONST && e->e.s)
2274 	    scxfree(e->e.s);
2275 	e->e.o.left = freeenodes;
2276 	freeenodes = e;
2277     }
2278 }
2279 
2280 void
label(v,s,flushdir)2281 label (v, s, flushdir)
2282 register struct ent *v;
2283 register char *s;
2284 int	flushdir;
2285 {
2286     if (v) {
2287 	if (flushdir==0 && v->flags&is_valid) {
2288 	    register struct ent *tv;
2289 	    if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
2290 		v = tv, flushdir = 1;
2291 	    else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
2292 		v = tv, flushdir = -1;
2293 	    else flushdir = -1;
2294 	}
2295 	if (v->label) scxfree((char *)(v->label));
2296 	if (s && s[0]) {
2297 	    v->label = scxmalloc ((unsigned)(strlen(s)+1));
2298 	    (void) strcpy (v->label, s);
2299 	} else
2300 	    v->label = (char *)0;
2301 	if (flushdir<0) v->flags |= is_leftflush;
2302 	else v->flags &= ~is_leftflush;
2303 	if (flushdir==0) v->flags |= is_label;
2304 	else v->flags &= ~is_label;
2305 	FullUpdate++;
2306 	modflg++;
2307     }
2308 }
2309 
2310 static void
decodev(v)2311 decodev (v)
2312 struct ent_ptr v;
2313 {
2314 	register struct range *r;
2315 
2316 	if (!v.vp) (void) sprintf (line+linelim,"VAR?");
2317 	else if ((r = find_range((char *)0, 0, v.vp, v.vp)) && !r->r_is_range)
2318 	    (void) sprintf(line+linelim, "%s", r->r_name);
2319 	else
2320 	    (void) sprintf (line+linelim, "%s%s%s%d",
2321 			v.vf & FIX_COL ? "$" : "",
2322 			coltoa(v.vp->col),
2323 			v.vf & FIX_ROW ? "$" : "",
2324 			v.vp->row);
2325 	linelim += strlen (line+linelim);
2326 }
2327 
2328 char *
coltoa(col)2329 coltoa(col)
2330 int col;
2331 {
2332     static char rname[3];
2333     register char *p = rname;
2334 
2335     if (col > 25) {
2336 	*p++ = col/26 + 'A' - 1;
2337 	col %= 26;
2338     }
2339     *p++ = col+'A';
2340     *p = '\0';
2341     return(rname);
2342 }
2343 
2344 /*
2345  *	To make list elements come out in the same order
2346  *	they were entered, we must do a depth-first eval
2347  *	of the ELIST tree
2348  */
2349 static void
decompile_list(p)2350 decompile_list(p)
2351 struct enode *p;
2352 {
2353 	if (!p) return;
2354 	decompile_list(p->e.o.left);	/* depth first */
2355         decompile(p->e.o.right, 0);
2356 	line[linelim++] = ',';
2357 }
2358 
2359 static void               /* static added by Bob Parbs 12-92 */
decompile(e,priority)2360 decompile(e, priority)
2361 register struct enode *e;
2362 int	priority;
2363 {
2364     register char *s;
2365     if (e) {
2366 	int mypriority;
2367 	switch (e->op) {
2368 	default: mypriority = 99; break;
2369 	case '?': mypriority = 1; break;
2370 	case ':': mypriority = 2; break;
2371 	case '|': mypriority = 3; break;
2372 	case '&': mypriority = 4; break;
2373 	case '<': case '=': case '>': mypriority = 6; break;
2374 	case '+': case '-': case '#': mypriority = 8; break;
2375 	case '*': case '/': case '%': mypriority = 10; break;
2376 	case '^': mypriority = 12; break;
2377 	}
2378 	if (mypriority<priority) line[linelim++] = '(';
2379 	switch (e->op) {
2380 	case 'f':	for (s="fixed "; (line[linelim++] = *s++););
2381 			linelim--;
2382 			decompile (e->e.o.right, 30);
2383 			break;
2384 	case 'm':	line[linelim++] = '-';
2385 			decompile (e->e.o.right, 30);
2386 			break;
2387 	case '~':	line[linelim++] = '~';
2388 			decompile (e->e.o.right, 30);
2389 			break;
2390 	case O_VAR:	decodev (e->e.v);
2391 			break;
2392 	case O_CONST:	(void) sprintf (line+linelim,"%.15g",e->e.k);
2393 			linelim += strlen (line+linelim);
2394 			break;
2395 	case O_SCONST:	(void) sprintf (line+linelim, "\"%s\"", e->e.s);
2396 			linelim += strlen(line+linelim);
2397 			break;
2398 
2399 	case REDUCE | '+': range_arg( "@sum(", e); break;
2400 	case REDUCE | '*': range_arg( "@prod(", e); break;
2401 	case REDUCE | 'a': range_arg( "@avg(", e); break;
2402 	case REDUCE | 'c': range_arg( "@count(", e); break;
2403 	case REDUCE | 's': range_arg( "@stddev(", e); break;
2404 	case (REDUCE | IRR): range_arg("@irr(", e); break;
2405 	case (REDUCE | MAXR): range_arg( "@max(", e); break;
2406 	case (REDUCE | MINR): range_arg( "@min(", e); break;
2407 
2408 	case ABS:		one_arg( "@abs(", e); break;
2409 	case ACOS:	one_arg( "@acos(", e); break;
2410 	case ASIN:	one_arg( "@asin(", e); break;
2411 	case ATAN:	one_arg( "@atan(", e); break;
2412 	case ATAN2:	two_arg( "@atan2(", e); break;
2413 	case CEIL:	one_arg( "@ceil(", e); break;
2414 	case COS:	one_arg( "@cos(", e); break;
2415 	case EXP:	one_arg( "@exp(", e); break;
2416 	case FABS:	one_arg( "@fabs(", e); break;
2417 	case FLOOR:	one_arg( "@floor(", e); break;
2418 	case HYPOT:	two_arg( "@hypot(", e); break;
2419 	case LOG:	one_arg( "@ln(", e); break;
2420 	case LOG10:	one_arg( "@log(", e); break;
2421 	case POW:	two_arg( "@pow(", e); break;
2422 	case SIN:	one_arg( "@sin(", e); break;
2423 	case SQRT:	one_arg( "@sqrt(", e); break;
2424 	case TAN:	one_arg( "@tan(", e); break;
2425 	case DTR:	one_arg( "@dtr(", e); break;
2426 	case RTD:	one_arg( "@rtd(", e); break;
2427 	case RND:	one_arg( "@rnd(", e); break;
2428 	case ROUND:	two_arg( "@round(", e); break;
2429 	case HOUR:	one_arg( "@hour(", e); break;
2430 	case MINUTE:	one_arg( "@minute(", e); break;
2431 	case SECOND:	one_arg( "@second(", e); break;
2432 	case MONTH:	one_arg( "@month(", e); break;
2433 	case DAY:	one_arg( "@day(", e); break;
2434 	case YEAR:	one_arg( "@year(", e); break;
2435 	case DATE:	one_arg( "@date(", e); break;
2436 	case UPPER:	one_arg( "@upper(", e); break;
2437 	case LOWER:	one_arg( "@lower(", e); break;
2438 	case CAPITAL:	one_arg( "@capital(", e); break;
2439 	case DTS:	three_arg( "@dts(", e); break;
2440 	case TTS:	three_arg( "@tts(", e); break;
2441 	case STON:	one_arg( "@ston(", e); break;
2442 	case FMT:	two_arg( "@fmt(", e); break;
2443 	case EQS:	two_arg( "@eqs(", e); break;
2444 	case NOW:	for ( s = "@now"; (line[linelim++] = *s++););
2445 			linelim--;
2446 			break;
2447 	case LMAX:	list_arg("@max(", e); break;
2448 	case LMIN: 	list_arg("@min(", e); break;
2449 	case FV:	three_arg("@fv(", e); break;
2450 	case PV:	three_arg("@pv(", e); break;
2451 	case PMT:	three_arg("@pmt(", e); break;
2452 	case NVAL:	two_arg("@nval(", e); break;
2453 	case SVAL:	two_arg("@sval(", e); break;
2454 	case EXT:	two_arg("@ext(", e); break;
2455 	case SUBSTR:	three_arg("@substr(", e); break;
2456 	case STINDEX:	index_arg("@stindex(", e); break;
2457 	case INDEX:	index_arg("@index(", e); break;
2458 	case LOOKUP:	index_arg("@lookup(", e); break;
2459 	case HLOOKUP:	two_arg_index("@hlookup(", e); break;
2460 	case VLOOKUP:	two_arg_index("@vlookup(", e); break;
2461 	case IF:	three_arg("@if(", e); break;
2462 	case MYROW:	for ( s = "@myrow"; (line[linelim++] = *s++););
2463 			linelim--;
2464 			break;
2465 	case MYCOL:	for ( s = "@mycol"; (line[linelim++] = *s++););
2466 			linelim--;
2467 			break;
2468 	case COLTOA:	one_arg( "@coltoa(", e); break;
2469 	case NUMITER:	for ( s = "@numiter"; (line[linelim++] = *s++););
2470                         linelim--;
2471                         break;
2472 /* FIXME-test this code (also what is the matrix priority (in gram.y) */
2473 	case MATRIX_ADD:	three_arg("@matrix_add(", e); break;
2474 	case MATRIX_SUB:	three_arg("@matrix_sub(", e); break;
2475 	case MATRIX_INV:	two_arg("@matrix_inv(", e); break;
2476 	case MATRIX_MULT:	three_arg("@matrix_mult(", e); break;
2477 	case MATRIX_TRANS:	two_arg("@matrix_trans(", e); break;
2478 	case IRR:
2479 			scerror("IRR");
2480 	default:	decompile (e->e.o.left, mypriority);
2481 			line[linelim++] = e->op;
2482 			decompile (e->e.o.right, mypriority+1);
2483 			break;
2484 	}
2485 	if (mypriority<priority) line[linelim++] = ')';
2486     } else line[linelim++] = '?';
2487 }
2488 
2489 static void
index_arg(s,e)2490 index_arg(s, e)
2491 char *s;
2492 struct enode *e;
2493 {
2494     for (; (line[linelim++] = *s++););
2495     linelim--;
2496     decompile( e-> e.o.left, 0 );
2497     range_arg(", ", e->e.o.right);
2498 }
2499 
2500 static void
two_arg_index(s,e)2501 two_arg_index(s, e)
2502 char *s;
2503 struct enode *e;
2504 {
2505     for (; (line[linelim++] = *s++););
2506     linelim--;
2507     decompile( e->e.o.left->e.o.left, 0 );
2508     range_arg(",", e->e.o.right);
2509     linelim--;
2510     line[linelim++] = ',';
2511     decompile( e->e.o.left->e.o.right, 0 );
2512     line[linelim++] = ')';
2513 }
2514 
2515 static void
list_arg(s,e)2516 list_arg(s, e)
2517 char *s;
2518 struct enode *e;
2519 {
2520     for (; (line[linelim++] = *s++););
2521     linelim--;
2522 
2523     decompile (e->e.o.right, 0);
2524     line[linelim++] = ',';
2525     decompile_list(e->e.o.left);
2526     line[linelim - 1] = ')';
2527 }
2528 
2529 static void
one_arg(s,e)2530 one_arg(s, e)
2531 char *s;
2532 struct enode *e;
2533 {
2534     for (; (line[linelim++] = *s++););
2535     linelim--;
2536     decompile (e->e.o.right, 0);
2537     line[linelim++] = ')';
2538 }
2539 
2540 static void
two_arg(s,e)2541 two_arg(s,e)
2542 char *s;
2543 struct enode *e;
2544 {
2545     for (; (line[linelim++] = *s++););
2546     linelim--;
2547     decompile (e->e.o.left, 0);
2548     line[linelim++] = ',';
2549     decompile (e->e.o.right, 0);
2550     line[linelim++] = ')';
2551 }
2552 
2553 static void
three_arg(s,e)2554 three_arg(s,e)
2555 char *s;
2556 struct enode *e;
2557 {
2558     for (; (line[linelim++] = *s++););
2559     linelim--;
2560     decompile (e->e.o.left, 0);
2561     line[linelim++] = ',';
2562     decompile (e->e.o.right->e.o.left, 0);
2563     line[linelim++] = ',';
2564     decompile (e->e.o.right->e.o.right, 0);
2565     line[linelim++] = ')';
2566 }
2567 
2568 static void
range_arg(s,e)2569 range_arg(s,e)
2570 char *s;
2571 struct enode *e;
2572 {
2573     struct range *r;
2574 
2575     for (; (line[linelim++] = *s++););
2576     linelim--;
2577     if ((r = find_range((char *)0, 0, e->e.r.left.vp,
2578 			     e->e.r.right.vp)) && r->r_is_range) {
2579 	(void) sprintf(line+linelim, "%s", r->r_name);
2580 	linelim += strlen(line+linelim);
2581     } else {
2582 	decodev (e->e.r.left);
2583 	line[linelim++] = ':';
2584 	decodev (e->e.r.right);
2585     }
2586     line[linelim++] = ')';
2587 }
2588 
2589 void
editfmt(row,col)2590 editfmt (row, col)
2591 int row, col;
2592 {
2593     register struct ent *p;
2594 
2595     p = lookat (row, col);
2596     if (p->format) {
2597         (void) sprintf (line, "fmt %s \"%s\"", v_name(row, col), p->format);
2598 	linelim = strlen(line);
2599     }
2600 }
2601 
2602 void
editv(row,col)2603 editv (row, col)
2604 int row, col;
2605 {
2606     register struct ent *p;
2607 
2608     p = lookat (row, col);
2609     (void) sprintf (line, "let %s = ", v_name(row, col));
2610     linelim = strlen(line);
2611     if (p->flags & is_strexpr || p->expr == 0) {
2612 	(void) sprintf (line+linelim, "%.15g", p->v);
2613 	linelim += strlen (line+linelim);
2614     } else {
2615         editexp(row,col);
2616     }
2617 }
2618 
2619 void
editexp(row,col)2620 editexp(row,col)
2621 int row, col;
2622 {
2623     register struct ent *p;
2624 
2625     p = lookat (row, col);
2626     decompile (p->expr, 0);
2627     line[linelim] = '\0';
2628 }
2629 
2630 void
edits(row,col)2631 edits (row, col)
2632 int row, col;
2633 {
2634     register struct ent *p;
2635 
2636     p = lookat (row, col);
2637     if( p->flags&is_label )
2638 	(void) sprintf( line, "label %s = ", v_name(row, col));
2639     else
2640     (void) sprintf (line, "%sstring %s = ",
2641 			((p->flags&is_leftflush) ? "left" : "right"),
2642 			v_name(row, col));
2643     linelim = strlen(line);
2644     if (p->flags & is_strexpr && p->expr) {
2645 	editexp(row, col);
2646     } else if (p->label) {
2647         (void) sprintf (line+linelim, "\"%s\"", p->label);
2648         linelim += strlen (line+linelim);
2649     } else {
2650         (void) sprintf (line+linelim, "\"");
2651         linelim += 1;
2652     }
2653 }
2654