ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.33
Committed: Thu Aug 14 23:32:28 2025 UTC (3 hours, 2 minutes ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.32: +29 -12 lines
Log Message:
perf: Added warnings to trigger on infinite recursion

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: calfunc.c,v 2.32 2024/09/16 17:31:14 greg Exp $";
3 #endif
4 /*
5 * calfunc.c - routines for calcomp using functions.
6 *
7 * If VARIABLE is not set, only library functions
8 * can be accessed.
9 *
10 * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
11 */
12
13 #include "copyright.h"
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <math.h>
20
21 #include "rterror.h"
22 #include "calcomp.h"
23
24 /* bits in argument flag (better be right!) */
25 #define AFLAGSIZ (8*sizeof(unsigned long))
26 #define ALISTSIZ 10 /* maximum saved argument list */
27
28 typedef struct activation {
29 char *name; /* function name */
30 struct activation *prev; /* previous activation */
31 double *ap; /* argument list */
32 unsigned long an; /* computed argument flags */
33 EPNODE *fun; /* argument function */
34 } ACTIVATION; /* an activation record */
35
36 static ACTIVATION *curact = NULL;
37 static unsigned long curdepth = 0, next_dreport = 100;
38
39 static double libfunc(char *fname, VARDEF *vp);
40 static void report_depth(char *nm);
41
42 #ifndef MAXLIB
43 #define MAXLIB 64 /* maximum number of library functions */
44 #endif
45
46 static double l_if(char *), l_select(char *);
47 static double l_min(char *), l_max(char *);
48 static double l_rand(char *);
49 static double l_floor(char *), l_ceil(char *);
50 static double l_sqrt(char *);
51 static double l_sin(char *), l_cos(char *), l_tan(char *);
52 static double l_asin(char *), l_acos(char *), l_atan(char *), l_atan2(char *);
53 static double l_exp(char *), l_log(char *), l_log10(char *);
54
55 /* functions must be listed alphabetically */
56 static ELIBR library[MAXLIB] = {
57 { "acos", 1, ':', l_acos },
58 { "asin", 1, ':', l_asin },
59 { "atan", 1, ':', l_atan },
60 { "atan2", 2, ':', l_atan2 },
61 { "ceil", 1, ':', l_ceil },
62 { "cos", 1, ':', l_cos },
63 { "exp", 1, ':', l_exp },
64 { "floor", 1, ':', l_floor },
65 { "if", 3, ':', l_if },
66 { "log", 1, ':', l_log },
67 { "log10", 1, ':', l_log10 },
68 { "max", 1, ':', l_max },
69 { "min", 1, ':', l_min },
70 { "rand", 1, ':', l_rand },
71 { "select", 1, ':', l_select },
72 { "sin", 1, ':', l_sin },
73 { "sqrt", 1, ':', l_sqrt },
74 { "tan", 1, ':', l_tan },
75 };
76
77 static int libsize = 18;
78
79 #define resolve(ep) ((ep)->type==VAR?(ep)->v.ln:eargf((ep)->v.chan))
80
81
82 int
83 fundefined( /* return # of req'd arguments for function */
84 char *fname
85 )
86 {
87 ELIBR *lp;
88 VARDEF *vp;
89
90 if ((vp = varlookup(fname)) != NULL && vp->def != NULL
91 && vp->def->v.kid->type == FUNC)
92 return(nekids(vp->def->v.kid) - 1);
93 lp = vp != NULL ? vp->lib : eliblookup(fname);
94 if (lp == NULL)
95 return(0);
96 return(lp->nargs);
97 }
98
99
100 double
101 funvalue( /* return a function value to the user */
102 char *fname,
103 int n,
104 double *a
105 )
106 {
107 ACTIVATION act;
108 VARDEF *vp;
109 double rval;
110 /* push environment */
111 act.name = fname;
112 act.prev = curact;
113 act.ap = a;
114 if (n < AFLAGSIZ)
115 act.an = (1L<<n)-1;
116 else {
117 act.an = ~0;
118 if (n > AFLAGSIZ)
119 wputs("Excess arguments in funvalue()\n");
120 }
121 act.fun = NULL;
122 curact = &act;
123 if (++curdepth >= next_dreport)
124 report_depth(act.name);
125
126 if ((vp = varlookup(fname)) == NULL || vp->def == NULL
127 || vp->def->v.kid->type != FUNC)
128 rval = libfunc(fname, vp);
129 else
130 rval = evalue(vp->def->v.kid->sibling);
131
132 curact = act.prev; curdepth--; /* pop environment */
133 return(rval);
134 }
135
136
137 void
138 funset( /* set a library function */
139 char *fname,
140 int nargs,
141 int assign,
142 double (*fptr)(char *)
143 )
144 {
145 int oldlibsize = libsize;
146 char *cp;
147 ELIBR *lp;
148 /* check for context */
149 for (cp = fname; *cp; cp++)
150 ;
151 if (cp == fname)
152 return;
153 while (cp[-1] == CNTXMARK) {
154 *--cp = '\0';
155 if (cp == fname) return;
156 }
157 if ((lp = eliblookup(fname)) == NULL) { /* insert */
158 if (fptr == NULL)
159 return; /* nothing! */
160 if (libsize >= MAXLIB) {
161 eputs("Too many library functons!\n");
162 quit(1);
163 }
164 for (lp = &library[libsize]; lp > library; lp--)
165 if (strcmp(lp[-1].fname, fname) > 0)
166 lp[0] = lp[-1];
167 else
168 break;
169 libsize++;
170 }
171 if (fptr == NULL) { /* delete */
172 while (lp < &library[libsize-1]) {
173 lp[0] = lp[1];
174 lp++;
175 }
176 libsize--;
177 } else { /* or assign */
178 lp[0].fname = fname; /* string must be static! */
179 lp[0].nargs = nargs;
180 lp[0].atyp = assign;
181 lp[0].f = fptr;
182 }
183 if (libsize != oldlibsize)
184 elibupdate(fname); /* relink library */
185 }
186
187
188 int
189 nargum(void) /* return number of available arguments */
190 {
191 int n;
192
193 if (curact == NULL)
194 return(0);
195 if (curact->fun == NULL) {
196 for (n = 0; (1L<<n) & curact->an; n++)
197 ;
198 return(n);
199 }
200 return(nekids(curact->fun) - 1);
201 }
202
203
204 double
205 argument(int n) /* return nth argument for active function */
206 {
207 ACTIVATION *actp = curact;
208 EPNODE *ep;
209 double aval;
210
211 if (!actp | (--n < 0)) {
212 eputs("Bad call to argument!\n");
213 quit(1);
214 }
215 if ((n < AFLAGSIZ) & actp->an >> n) /* already computed? */
216 return(actp->ap[n]);
217
218 if (!actp->fun || !(ep = ekid(actp->fun, n+1))) {
219 eputs(actp->name);
220 eputs("(): too few arguments\n");
221 quit(1);
222 }
223 curact = actp->prev; curdepth--; /* previous context */
224 aval = evalue(ep); /* compute argument */
225 curact = actp; curdepth++; /* put back calling context */
226 if (n < ALISTSIZ) { /* save value if room */
227 actp->ap[n] = aval;
228 actp->an |= 1L<<n;
229 }
230 return(aval);
231 }
232
233
234 VARDEF *
235 eargf(int n) /* return function def for nth argument */
236 {
237 ACTIVATION *actp;
238 EPNODE *ep;
239
240 for (actp = curact; actp != NULL; actp = actp->prev) {
241
242 if (n <= 0)
243 break;
244
245 if (actp->fun == NULL)
246 goto badarg;
247
248 if ((ep = ekid(actp->fun, n)) == NULL) {
249 eputs(actp->name);
250 eputs("(): too few arguments\n");
251 quit(1);
252 }
253 if (ep->type == VAR)
254 return(ep->v.ln); /* found it */
255
256 if (ep->type != ARG)
257 goto badarg;
258
259 n = ep->v.chan; /* try previous context */
260 }
261 eputs("Bad call to eargf!\n");
262 quit(1);
263
264 badarg:
265 eputs(actp->name);
266 eputs("(): argument not a function\n");
267 quit(1);
268 return NULL; /* pro forma return */
269 }
270
271
272 char *
273 eargfun(int n) /* return function name for nth argument */
274 {
275 return(eargf(n)->name);
276 }
277
278
279 double
280 efunc(EPNODE *ep) /* evaluate a function */
281 {
282 ACTIVATION act;
283 double alist[ALISTSIZ];
284 double rval;
285 VARDEF *dp;
286 /* push environment */
287 dp = resolve(ep->v.kid);
288 act.name = dp->name;
289 act.prev = curact;
290 act.ap = alist;
291 act.an = 0;
292 act.fun = ep;
293 curact = &act;
294 if (++curdepth >= next_dreport)
295 report_depth(act.name);
296
297 if (dp->def == NULL || dp->def->v.kid->type != FUNC)
298 rval = libfunc(act.name, dp);
299 else
300 rval = evalue(dp->def->v.kid->sibling);
301
302 curact = act.prev; curdepth--; /* pop environment */
303 return(rval);
304 }
305
306
307 double
308 eargument( /* evaluate an argument */
309 EPNODE *ep
310 )
311 {
312 if ((ep->v.chan <= AFLAGSIZ) & curact->an >> (ep->v.chan-1))
313 return(curact->ap[ep->v.chan-1]);
314
315 return(argument(ep->v.chan));
316 }
317
318
319 ELIBR *
320 eliblookup(char *fname) /* look up a library function */
321 {
322 int upper, lower;
323 int cm, i;
324
325 lower = 0;
326 upper = cm = libsize;
327
328 while ((i = (lower + upper) >> 1) != cm) {
329 cm = strcmp(fname, library[i].fname);
330 if (cm > 0)
331 lower = i;
332 else if (cm < 0)
333 upper = i;
334 else
335 return(&library[i]);
336 cm = i;
337 }
338 return(NULL);
339 }
340
341
342 /*
343 * The following routines are for internal use:
344 */
345
346
347 static void
348 report_depth(char *nm) /* report current function call depth */
349 {
350 char msg[64];
351
352 sprintf(msg, "%s(): depth level at %lu\n", nm, next_dreport);
353 wputs(msg);
354 next_dreport *= 10;
355 }
356
357
358 static double
359 libfunc( /* execute library function */
360 char *fname,
361 VARDEF *vp
362 )
363 {
364 ELIBR *lp;
365 double d;
366 int lasterrno;
367
368 if (vp != NULL)
369 lp = vp->lib;
370 else
371 lp = eliblookup(fname);
372 if (lp == NULL) {
373 eputs(fname);
374 eputs("(): undefined function\n");
375 quit(1);
376 }
377 lasterrno = errno;
378 errno = 0;
379 d = (*lp->f)(lp->fname);
380 #ifdef isnan
381 if (errno == 0) {
382 if (isnan(d))
383 errno = EDOM;
384 else if (isinf(d))
385 errno = ERANGE;
386 }
387 #endif
388 if ((errno == EDOM) | (errno == ERANGE)) {
389 wputs(fname);
390 if (errno == EDOM)
391 wputs("(): domain error\n");
392 else if (errno == ERANGE)
393 wputs("(): range error\n");
394 else
395 wputs("(): error in call\n");
396 return(0.0);
397 }
398 errno = lasterrno;
399 return(d);
400 }
401
402
403 /*
404 * Library functions:
405 */
406
407
408 static double
409 l_if(char *nm) /* if(cond, then, else) conditional expression */
410 /* cond evaluates true if greater than zero */
411 {
412 if (argument(1) > 0.0)
413 return(argument(2));
414 else
415 return(argument(3));
416 }
417
418
419 static double
420 l_select(char *nm) /* return argument #(A1+1) */
421 {
422 int narg = nargum();
423 double a1 = argument(1);
424 int n = (int)(a1 + .5);
425
426 if ((a1 < -.5) | (n >= narg)) {
427 errno = EDOM;
428 return(0.0);
429 }
430 if (!n) /* asking max index? */
431 return(narg-1);
432 return(argument(n+1));
433 }
434
435
436 static double
437 l_max(char *nm) /* general maximum function */
438 {
439 int n = nargum();
440 double vmax = argument(1);
441
442 while (n > 1) {
443 double v = argument(n--);
444 if (vmax < v)
445 vmax = v;
446 }
447 return(vmax);
448 }
449
450
451 static double
452 l_min(char *nm) /* general minimum function */
453 {
454 int n = nargum();
455 double vmin = argument(1);
456
457 while (n > 1) {
458 double v = argument(n--);
459 if (vmin > v)
460 vmin = v;
461 }
462 return(vmin);
463 }
464
465
466 static double
467 l_rand(char *nm) /* random function between 0 and 1 */
468 {
469 double x;
470
471 x = argument(1);
472 x *= 1.0/(1.0 + x*x) + 2.71828182845904;
473 x += .785398163397447 - floor(x);
474 x = 1e5 / x;
475 return(x - floor(x));
476 }
477
478
479 static double
480 l_floor(char *nm) /* return largest integer not greater than arg1 */
481 {
482 return(floor(argument(1)));
483 }
484
485
486 static double
487 l_ceil(char *nm) /* return smallest integer not less than arg1 */
488 {
489 return(ceil(argument(1)));
490 }
491
492
493 static double
494 l_sqrt(char *nm)
495 {
496 return(sqrt(argument(1)));
497 }
498
499
500 static double
501 l_sin(char *nm)
502 {
503 return(sin(argument(1)));
504 }
505
506
507 static double
508 l_cos(char *nm)
509 {
510 return(cos(argument(1)));
511 }
512
513
514 static double
515 l_tan(char *nm)
516 {
517 return(tan(argument(1)));
518 }
519
520
521 static double
522 l_asin(char *nm)
523 {
524 return(asin(argument(1)));
525 }
526
527
528 static double
529 l_acos(char *nm)
530 {
531 return(acos(argument(1)));
532 }
533
534
535 static double
536 l_atan(char *nm)
537 {
538 return(atan(argument(1)));
539 }
540
541
542 static double
543 l_atan2(char *nm)
544 {
545 return(atan2(argument(1), argument(2)));
546 }
547
548
549 static double
550 l_exp(char *nm)
551 {
552 return(exp(argument(1)));
553 }
554
555
556 static double
557 l_log(char *nm)
558 {
559 return(log(argument(1)));
560 }
561
562
563 static double
564 l_log10(char *nm)
565 {
566 return(log10(argument(1)));
567 }