ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.21
Committed: Mon Oct 27 10:19:31 2003 UTC (20 years, 6 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.20: +2 -1 lines
Log Message:
Added gethomedir.c and various compatibility fixes.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: caldefn.c,v 2.20 2003/07/27 22:12:01 schorsch Exp $";
3 #endif
4 /*
5 * Store variable definitions.
6 *
7 * 7/1/85 Greg Ward
8 *
9 * 11/11/85 Added conditional compiles (OUTCHAN) for control output.
10 *
11 * 4/2/86 Added conditional compiles for function definitions (FUNCTION).
12 *
13 * 1/15/88 Added clock for caching of variable values.
14 *
15 * 11/16/88 Added VARDEF structure for hard linking.
16 *
17 * 5/31/90 Added conditional compile (REDEFW) for redefinition warning.
18 *
19 * 4/23/91 Added ':' assignment for constant expressions
20 *
21 * 8/7/91 Added optional context path to append to variable names
22 *
23 * 5/17/2001 Fixed clock counter wrapping behavior
24 *
25 * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
26 */
27
28 #include "copyright.h"
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #include "rterror.h"
35 #include "rtmisc.h"
36 #include "calcomp.h"
37
38 #ifndef NHASH
39 #define NHASH 521 /* hash size (a prime!) */
40 #endif
41
42 #define hash(s) (shash(s)%NHASH)
43
44 #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
45
46 static double dvalue(char *name, EPNODE *d);
47
48 #define MAXCLOCK (1L<<31) /* clock wrap value */
49
50 unsigned long eclock = 0; /* value storage timer */
51
52 #define MAXCNTX 1023 /* maximum context length */
53
54 static char context[MAXCNTX+1]; /* current context path */
55
56 static VARDEF *hashtbl[NHASH]; /* definition list */
57 static int htndx; /* index for */
58 static VARDEF *htpos; /* ...dfirst() and */
59 static EPNODE *ochpos; /* ...dnext */
60 static EPNODE *outchan;
61
62 EPNODE *curfunc = NULL;
63 #define dname(ep) ((ep)->v.kid->type == SYM ? \
64 (ep)->v.kid->v.name : \
65 (ep)->v.kid->v.kid->v.name)
66
67
68 void
69 fcompile( /* get definitions from a file */
70 char *fname
71 )
72 {
73 FILE *fp;
74
75 if (fname == NULL)
76 fp = stdin;
77 else if ((fp = fopen(fname, "r")) == NULL) {
78 eputs(fname);
79 eputs(": cannot open\n");
80 quit(1);
81 }
82 initfile(fp, fname, 0);
83 while (nextc != EOF)
84 getstatement();
85 if (fname != NULL)
86 fclose(fp);
87 }
88
89
90 void
91 scompile( /* get definitions from a string */
92 char *str,
93 char *fn,
94 int ln
95 )
96 {
97 initstr(str, fn, ln);
98 while (nextc != EOF)
99 getstatement();
100 }
101
102
103 double
104 varvalue( /* return a variable's value */
105 char *vname
106 )
107 {
108 return(dvalue(vname, dlookup(vname)));
109 }
110
111
112 double
113 evariable( /* evaluate a variable */
114 EPNODE *ep
115 )
116 {
117 register VARDEF *dp = ep->v.ln;
118
119 return(dvalue(dp->name, dp->def));
120 }
121
122
123 void
124 varset( /* set a variable's value */
125 char *vname,
126 int assign,
127 double val
128 )
129 {
130 char *qname;
131 register EPNODE *ep1, *ep2;
132 /* get qualified name */
133 qname = qualname(vname, 0);
134 /* check for quick set */
135 if ((ep1 = dlookup(qname)) != NULL && ep1->v.kid->type == SYM) {
136 ep2 = ep1->v.kid->sibling;
137 if (ep2->type == NUM) {
138 ep2->v.num = val;
139 ep1->type = assign;
140 return;
141 }
142 }
143 /* hand build definition */
144 ep1 = newnode();
145 ep1->type = assign;
146 ep2 = newnode();
147 ep2->type = SYM;
148 ep2->v.name = savestr(vname);
149 addekid(ep1, ep2);
150 ep2 = newnode();
151 ep2->type = NUM;
152 ep2->v.num = val;
153 addekid(ep1, ep2);
154 dremove(qname);
155 dpush(qname, ep1);
156 }
157
158
159 void
160 dclear( /* delete variable definitions of name */
161 char *name
162 )
163 {
164 register EPNODE *ep;
165
166 while ((ep = dpop(name)) != NULL) {
167 if (ep->type == ':') {
168 dpush(name, ep); /* don't clear constants */
169 return;
170 }
171 epfree(ep);
172 }
173 }
174
175
176 void
177 dremove( /* delete all definitions of name */
178 char *name
179 )
180 {
181 register EPNODE *ep;
182
183 while ((ep = dpop(name)) != NULL)
184 epfree(ep);
185 }
186
187
188 int
189 vardefined( /* return non-zero if variable defined */
190 char *name
191 )
192 {
193 register EPNODE *dp;
194
195 return((dp = dlookup(name)) != NULL && dp->v.kid->type == SYM);
196 }
197
198
199 char *
200 setcontext( /* set a new context path */
201 register char *ctx
202 )
203 {
204 register char *cpp;
205
206 if (ctx == NULL)
207 return(context); /* just asking */
208 while (*ctx == CNTXMARK)
209 ctx++; /* skip past marks */
210 if (!*ctx) {
211 context[0] = '\0'; /* empty means clear context */
212 return(context);
213 }
214 cpp = context; /* start context with mark */
215 *cpp++ = CNTXMARK;
216 do { /* carefully copy new context */
217 if (cpp >= context+MAXCNTX)
218 break; /* just copy what we can */
219 if (isid(*ctx))
220 *cpp++ = *ctx++;
221 else {
222 *cpp++ = '_'; ctx++;
223 }
224 } while (*ctx);
225 while (cpp[-1] == CNTXMARK) /* cannot end in context mark */
226 cpp--;
227 *cpp = '\0';
228 return(context);
229 }
230
231
232 char *
233 pushcontext( /* push on another context */
234 char *ctx
235 )
236 {
237 char oldcontext[MAXCNTX+1];
238 register int n;
239
240 strcpy(oldcontext, context); /* save old context */
241 setcontext(ctx); /* set new context */
242 n = strlen(context); /* tack on old */
243 if (n+strlen(oldcontext) > MAXCNTX) {
244 strncpy(context+n, oldcontext, MAXCNTX-n);
245 context[MAXCNTX] = '\0';
246 } else
247 strcpy(context+n, oldcontext);
248 return(context);
249 }
250
251
252 char *
253 popcontext(void) /* pop off top context */
254 {
255 register char *cp1, *cp2;
256
257 if (!context[0]) /* nothing left to pop */
258 return(context);
259 cp2 = context; /* find mark */
260 while (*++cp2 && *cp2 != CNTXMARK)
261 ;
262 cp1 = context; /* copy tail to front */
263 while ( (*cp1++ = *cp2++) )
264 ;
265 return(context);
266 }
267
268
269 char *
270 qualname( /* get qualified name */
271 register char *nam,
272 int lvl
273 )
274 {
275 static char nambuf[RMAXWORD+1];
276 register char *cp = nambuf, *cpp;
277 /* check for explicit local */
278 if (*nam == CNTXMARK)
279 if (lvl > 0) /* only action is to refuse search */
280 return(NULL);
281 else
282 nam++;
283 else if (nam == nambuf) /* check for repeat call */
284 return(lvl > 0 ? NULL : nam);
285 /* copy name to static buffer */
286 while (*nam) {
287 if (cp >= nambuf+RMAXWORD)
288 goto toolong;
289 *cp++ = *nam++;
290 }
291 /* check for explicit global */
292 if (cp > nambuf && cp[-1] == CNTXMARK) {
293 if (lvl > 0)
294 return(NULL);
295 *--cp = '\0';
296 return(nambuf); /* already qualified */
297 }
298 cpp = context; /* else skip the requested levels */
299 while (lvl-- > 0) {
300 if (!*cpp)
301 return(NULL); /* return NULL if past global level */
302 while (*++cpp && *cpp != CNTXMARK)
303 ;
304 }
305 while (*cpp) { /* copy context to static buffer */
306 if (cp >= nambuf+RMAXWORD)
307 goto toolong;
308 *cp++ = *cpp++;
309 }
310 toolong:
311 *cp = '\0';
312 return(nambuf); /* return qualified name */
313 }
314
315
316 int
317 incontext( /* is qualified name in current context? */
318 register char *qn
319 )
320 {
321 if (!context[0]) /* global context accepts all */
322 return(1);
323 while (*qn && *qn != CNTXMARK) /* find context mark */
324 qn++;
325 return(!strcmp(qn, context));
326 }
327
328
329 void
330 chanout( /* set output channels */
331 void (*cs)(int n, double v)
332 )
333 {
334 register EPNODE *ep;
335
336 for (ep = outchan; ep != NULL; ep = ep->sibling)
337 (*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
338
339 }
340
341
342 void
343 dcleanup( /* clear definitions (0->vars,1->output,2->consts) */
344 int lvl
345 )
346 {
347 register int i;
348 register VARDEF *vp;
349 register EPNODE *ep;
350 /* if context is global, clear all */
351 for (i = 0; i < NHASH; i++)
352 for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
353 if (incontext(vp->name)) {
354 if (lvl >= 2)
355 dremove(vp->name);
356 else
357 dclear(vp->name);
358 }
359 if (lvl >= 1) {
360 for (ep = outchan; ep != NULL; ep = ep->sibling)
361 epfree(ep);
362 outchan = NULL;
363 }
364 }
365
366
367 EPNODE *
368 dlookup( /* look up a definition */
369 char *name
370 )
371 {
372 register VARDEF *vp;
373
374 if ((vp = varlookup(name)) == NULL)
375 return(NULL);
376 return(vp->def);
377 }
378
379
380 VARDEF *
381 varlookup( /* look up a variable */
382 char *name
383 )
384 {
385 int lvl = 0;
386 register char *qname;
387 register VARDEF *vp;
388 /* find most qualified match */
389 while ((qname = qualname(name, lvl++)) != NULL)
390 for (vp = hashtbl[hash(qname)]; vp != NULL; vp = vp->next)
391 if (!strcmp(vp->name, qname))
392 return(vp);
393 return(NULL);
394 }
395
396
397 VARDEF *
398 varinsert( /* get a link to a variable */
399 char *name
400 )
401 {
402 register VARDEF *vp;
403 int hv;
404
405 if ((vp = varlookup(name)) != NULL) {
406 vp->nlinks++;
407 return(vp);
408 }
409 vp = (VARDEF *)emalloc(sizeof(VARDEF));
410 vp->lib = liblookup(name);
411 if (vp->lib == NULL) /* if name not in library */
412 name = qualname(name, 0); /* use fully qualified version */
413 hv = hash(name);
414 vp->name = savestr(name);
415 vp->nlinks = 1;
416 vp->def = NULL;
417 vp->next = hashtbl[hv];
418 hashtbl[hv] = vp;
419 return(vp);
420 }
421
422
423 void
424 libupdate( /* update library links */
425 char *fn
426 )
427 {
428 register int i;
429 register VARDEF *vp;
430 /* if fn is NULL then relink all */
431 for (i = 0; i < NHASH; i++)
432 for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
433 if (vp->lib != NULL || fn == NULL || !strcmp(fn, vp->name))
434 vp->lib = liblookup(vp->name);
435 }
436
437
438 void
439 varfree( /* release link to variable */
440 register VARDEF *ln
441 )
442 {
443 register VARDEF *vp;
444 int hv;
445
446 if (--ln->nlinks > 0)
447 return; /* still active */
448
449 hv = hash(ln->name);
450 vp = hashtbl[hv];
451 if (vp == ln)
452 hashtbl[hv] = vp->next;
453 else {
454 while (vp->next != ln) /* must be in list */
455 vp = vp->next;
456 vp->next = ln->next;
457 }
458 freestr(ln->name);
459 efree((char *)ln);
460 }
461
462
463 EPNODE *
464 dfirst(void) /* return pointer to first definition */
465 {
466 htndx = 0;
467 htpos = NULL;
468 ochpos = outchan;
469 return(dnext());
470 }
471
472
473 EPNODE *
474 dnext(void) /* return pointer to next definition */
475 {
476 register EPNODE *ep;
477 register char *nm;
478
479 while (htndx < NHASH) {
480 if (htpos == NULL)
481 htpos = hashtbl[htndx++];
482 while (htpos != NULL) {
483 ep = htpos->def;
484 nm = htpos->name;
485 htpos = htpos->next;
486 if (ep != NULL && incontext(nm))
487 return(ep);
488 }
489 }
490 if ((ep = ochpos) != NULL)
491 ochpos = ep->sibling;
492 return(ep);
493 }
494
495
496 EPNODE *
497 dpop( /* pop a definition */
498 char *name
499 )
500 {
501 register VARDEF *vp;
502 register EPNODE *dp;
503
504 if ((vp = varlookup(name)) == NULL || vp->def == NULL)
505 return(NULL);
506 dp = vp->def;
507 vp->def = dp->sibling;
508 varfree(vp);
509 return(dp);
510 }
511
512
513 void
514 dpush( /* push on a definition */
515 char *nm,
516 register EPNODE *ep
517 )
518 {
519 register VARDEF *vp;
520
521 vp = varinsert(nm);
522 ep->sibling = vp->def;
523 vp->def = ep;
524 }
525
526
527 void
528 addchan( /* add an output channel assignment */
529 EPNODE *sp
530 )
531 {
532 int ch = sp->v.kid->v.chan;
533 register EPNODE *ep, *epl;
534
535 for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
536 if (ep->v.kid->v.chan >= ch) {
537 if (epl != NULL)
538 epl->sibling = sp;
539 else
540 outchan = sp;
541 if (ep->v.kid->v.chan > ch)
542 sp->sibling = ep;
543 else {
544 sp->sibling = ep->sibling;
545 epfree(ep);
546 }
547 return;
548 }
549 if (epl != NULL)
550 epl->sibling = sp;
551 else
552 outchan = sp;
553 sp->sibling = NULL;
554
555 }
556
557
558 void
559 getstatement(void) /* get next statement */
560 {
561 register EPNODE *ep;
562 char *qname;
563 register VARDEF *vdef;
564
565 if (nextc == ';') { /* empty statement */
566 scan();
567 return;
568 }
569 if (esupport&E_OUTCHAN &&
570 nextc == '$') { /* channel assignment */
571 ep = getchan();
572 addchan(ep);
573 } else { /* ordinary definition */
574 ep = getdefn();
575 qname = qualname(dname(ep), 0);
576 if (esupport&E_REDEFW && (vdef = varlookup(qname)) != NULL) {
577 if (vdef->def != NULL && epcmp(ep, vdef->def)) {
578 wputs(qname);
579 if (vdef->def->type == ':')
580 wputs(": redefined constant expression\n");
581 else
582 wputs(": redefined\n");
583 } else if (ep->v.kid->type == FUNC && vdef->lib != NULL) {
584 wputs(qname);
585 wputs(": definition hides library function\n");
586 }
587 }
588 if (ep->type == ':')
589 dremove(qname);
590 else
591 dclear(qname);
592 dpush(qname, ep);
593 }
594 if (nextc != EOF) {
595 if (nextc != ';')
596 syntax("';' expected");
597 scan();
598 }
599 }
600
601
602 EPNODE *
603 getdefn(void)
604 /* A -> SYM = E1 */
605 /* SYM : E1 */
606 /* FUNC(SYM,..) = E1 */
607 /* FUNC(SYM,..) : E1 */
608 {
609 register EPNODE *ep1, *ep2;
610
611 if (!isalpha(nextc) && nextc != CNTXMARK)
612 syntax("illegal variable name");
613
614 ep1 = newnode();
615 ep1->type = SYM;
616 ep1->v.name = savestr(getname());
617
618 if (esupport&E_FUNCTION && nextc == '(') {
619 ep2 = newnode();
620 ep2->type = FUNC;
621 addekid(ep2, ep1);
622 ep1 = ep2;
623 do {
624 scan();
625 if (!isalpha(nextc))
626 syntax("illegal variable name");
627 ep2 = newnode();
628 ep2->type = SYM;
629 ep2->v.name = savestr(getname());
630 addekid(ep1, ep2);
631 } while (nextc == ',');
632 if (nextc != ')')
633 syntax("')' expected");
634 scan();
635 curfunc = ep1;
636 }
637
638 if (nextc != '=' && nextc != ':')
639 syntax("'=' or ':' expected");
640
641 ep2 = newnode();
642 ep2->type = nextc;
643 scan();
644 addekid(ep2, ep1);
645 addekid(ep2, getE1());
646
647 if (ep1->type == SYM && ep1->sibling->type != NUM) {
648 ep1 = newnode();
649 ep1->type = TICK;
650 ep1->v.tick = 0;
651 addekid(ep2, ep1);
652 ep1 = newnode();
653 ep1->type = NUM;
654 addekid(ep2, ep1);
655 }
656 curfunc = NULL;
657
658 return(ep2);
659 }
660
661
662 EPNODE *
663 getchan(void) /* A -> $N = E1 */
664 {
665 register EPNODE *ep1, *ep2;
666
667 if (nextc != '$')
668 syntax("missing '$'");
669 scan();
670
671 ep1 = newnode();
672 ep1->type = CHAN;
673 ep1->v.chan = getinum();
674
675 if (nextc != '=')
676 syntax("'=' expected");
677 scan();
678
679 ep2 = newnode();
680 ep2->type = '=';
681 addekid(ep2, ep1);
682 addekid(ep2, getE1());
683
684 return(ep2);
685 }
686
687
688
689 /*
690 * The following routines are for internal use only:
691 */
692
693
694 static double /* evaluate a variable */
695 dvalue(char *name, EPNODE *d)
696 {
697 register EPNODE *ep1, *ep2;
698
699 if (d == NULL || d->v.kid->type != SYM) {
700 eputs(name);
701 eputs(": undefined variable\n");
702 quit(1);
703 }
704 ep1 = d->v.kid->sibling; /* get expression */
705 if (ep1->type == NUM)
706 return(ep1->v.num); /* return if number */
707 ep2 = ep1->sibling; /* check time */
708 if (eclock >= MAXCLOCK)
709 eclock = 1; /* wrap clock counter */
710 if (ep2->v.tick < MAXCLOCK &&
711 (ep2->v.tick == 0) | (ep2->v.tick != eclock)) {
712 ep2->v.tick = d->type == ':' ? MAXCLOCK : eclock;
713 ep2 = ep2->sibling;
714 ep2->v.num = evalue(ep1); /* needs new value */
715 } else
716 ep2 = ep2->sibling; /* else reuse old value */
717
718 return(ep2->v.num);
719 }