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