--- ray/src/common/caldefn.c 1992/05/15 16:38:49 2.2
+++ ray/src/common/caldefn.c 2003/02/22 02:07:21 2.12
@@ -1,9 +1,6 @@
-/* Copyright (c) 1991 Regents of the University of California */
-
#ifndef lint
-static char SCCSid[] = "$SunId$ LBL";
+static const char RCSid[] = "$Id: caldefn.c,v 2.12 2003/02/22 02:07:21 greg Exp $";
#endif
-
/*
* Store variable definitions.
*
@@ -22,48 +19,108 @@ static char SCCSid[] = "$SunId$ LBL";
* 4/23/91 Added ':' assignment for constant expressions
*
* 8/7/91 Added optional context path to append to variable names
+ *
+ * 5/17/2001 Fixed clock counter wrapping behavior
+ *
+ * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
*/
+/* ====================================================================
+ * The Radiance Software License, Version 1.0
+ *
+ * Copyright (c) 1990 - 2002 The Regents of the University of California,
+ * through Lawrence Berkeley National Laboratory. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes Radiance software
+ * (http://radsite.lbl.gov/)
+ * developed by the Lawrence Berkeley National Laboratory
+ * (http://www.lbl.gov/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
+ * and "The Regents of the University of California" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact radiance@radsite.lbl.gov.
+ *
+ * 5. Products derived from this software may not be called "Radiance",
+ * nor may "Radiance" appear in their name, without prior written
+ * permission of Lawrence Berkeley National Laboratory.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of Lawrence Berkeley National Laboratory. For more
+ * information on Lawrence Berkeley National Laboratory, please see
+ * .
+ */
+
#include
+#include
+
#include
#include "calcomp.h"
-#ifndef NHASH
-#define NHASH 521 /* hash size (a prime!) */
+#ifndef NHASH
+#define NHASH 521 /* hash size (a prime!) */
#endif
-#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
+#define hash(s) (shash(s)%NHASH)
-extern char *ecalloc(), *savestr(), *strcpy();
+#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
-static int hash();
-
static double dvalue();
-long eclock = -1; /* value storage timer */
+#define MAXCLOCK (1L<<31) /* clock wrap value */
-static char context[MAXWORD+1]; /* current context path */
+unsigned long eclock = 0; /* value storage timer */
+#define MAXCNTX 1023 /* maximum context length */
+
+static char context[MAXCNTX+1]; /* current context path */
+
static VARDEF *hashtbl[NHASH]; /* definition list */
static int htndx; /* index for */
static VARDEF *htpos; /* ...dfirst() and */
-#ifdef OUTCHAN
static EPNODE *ochpos; /* ...dnext */
static EPNODE *outchan;
-#endif
-#ifdef FUNCTION
-EPNODE *curfunc;
-#define dname(ep) ((ep)->v.kid->type == SYM ? \
+EPNODE *curfunc = NULL;
+#define dname(ep) ((ep)->v.kid->type == SYM ? \
(ep)->v.kid->v.name : \
(ep)->v.kid->v.kid->v.name)
-#else
-#define dname(ep) ((ep)->v.kid->v.name)
-#endif
+void
fcompile(fname) /* get definitions from a file */
char *fname;
{
@@ -84,6 +141,7 @@ char *fname;
}
+void
scompile(str, fn, ln) /* get definitions from a string */
char *str;
char *fn;
@@ -105,7 +163,7 @@ char *vname;
double
evariable(ep) /* evaluate a variable */
-EPNODE *ep;
+EPNODE *ep;
{
register VARDEF *dp = ep->v.ln;
@@ -113,10 +171,11 @@ EPNODE *ep;
}
+void
varset(vname, assign, val) /* set a variable's value */
char *vname;
int assign;
-double val;
+double val;
{
char *qname;
register EPNODE *ep1, *ep2;
@@ -147,6 +206,7 @@ double val;
}
+void
dclear(name) /* delete variable definitions of name */
char *name;
{
@@ -162,6 +222,7 @@ char *name;
}
+void
dremove(name) /* delete all definitions of name */
char *name;
{
@@ -172,6 +233,7 @@ char *name;
}
+int
vardefined(name) /* return non-zero if variable defined */
char *name;
{
@@ -189,15 +251,16 @@ register char *ctx;
if (ctx == NULL)
return(context); /* just asking */
+ while (*ctx == CNTXMARK)
+ ctx++; /* skip past marks */
if (!*ctx) {
- context[0] = '\0'; /* clear context */
+ context[0] = '\0'; /* empty means clear context */
return(context);
}
- cpp = context; /* else copy it (carefully!) */
- if (*ctx != CNTXMARK)
- *cpp++ = CNTXMARK; /* make sure there's a mark */
- do {
- if (cpp >= context+MAXWORD)
+ cpp = context; /* start context with mark */
+ *cpp++ = CNTXMARK;
+ do { /* carefully copy new context */
+ if (cpp >= context+MAXCNTX)
break; /* just copy what we can */
if (isid(*ctx))
*cpp++ = *ctx++;
@@ -205,17 +268,56 @@ register char *ctx;
*cpp++ = '_'; ctx++;
}
} while (*ctx);
+ while (cpp[-1] == CNTXMARK) /* cannot end in context mark */
+ cpp--;
*cpp = '\0';
return(context);
}
char *
+pushcontext(ctx) /* push on another context */
+char *ctx;
+{
+ extern char *strncpy(), *strcpy();
+ char oldcontext[MAXCNTX+1];
+ register int n;
+
+ strcpy(oldcontext, context); /* save old context */
+ setcontext(ctx); /* set new context */
+ n = strlen(context); /* tack on old */
+ if (n+strlen(oldcontext) > MAXCNTX) {
+ strncpy(context+n, oldcontext, MAXCNTX-n);
+ context[MAXCNTX] = '\0';
+ } else
+ strcpy(context+n, oldcontext);
+ return(context);
+}
+
+
+char *
+popcontext() /* pop off top context */
+{
+ register char *cp1, *cp2;
+
+ if (!context[0]) /* nothing left to pop */
+ return(context);
+ cp2 = context; /* find mark */
+ while (*++cp2 && *cp2 != CNTXMARK)
+ ;
+ cp1 = context; /* copy tail to front */
+ while (*cp1++ = *cp2++)
+ ;
+ return(context);
+}
+
+
+char *
qualname(nam, lvl) /* get qualified name */
register char *nam;
int lvl;
{
- static char nambuf[MAXWORD+1];
+ static char nambuf[MAXWORD+1];
register char *cp = nambuf, *cpp;
/* check for explicit local */
if (*nam == CNTXMARK)
@@ -256,16 +358,19 @@ toolong:
}
+int
incontext(qn) /* is qualified name in current context? */
register char *qn;
{
+ if (!context[0]) /* global context accepts all */
+ return(1);
while (*qn && *qn != CNTXMARK) /* find context mark */
qn++;
return(!strcmp(qn, context));
}
-#ifdef OUTCHAN
+void
chanout(cs) /* set output channels */
int (*cs)();
{
@@ -275,9 +380,9 @@ int (*cs)();
(*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
}
-#endif
+void
dcleanup(lvl) /* clear definitions (0->vars,1->output,2->consts) */
int lvl;
{
@@ -287,18 +392,16 @@ int lvl;
/* if context is global, clear all */
for (i = 0; i < NHASH; i++)
for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
- if (!context[0] || incontext(vp->name))
+ if (incontext(vp->name))
if (lvl >= 2)
dremove(vp->name);
else
dclear(vp->name);
-#ifdef OUTCHAN
if (lvl >= 1) {
for (ep = outchan; ep != NULL; ep = ep->sibling)
epfree(ep);
outchan = NULL;
}
-#endif
}
@@ -309,7 +412,7 @@ char *name;
register VARDEF *vp;
if ((vp = varlookup(name)) == NULL)
- return(NULL);
+ return(NULL);
return(vp->def);
}
@@ -318,10 +421,10 @@ VARDEF *
varlookup(name) /* look up a variable */
char *name;
{
- int lvl = 0;
+ int lvl = 0;
register char *qname;
register VARDEF *vp;
- /* find most qualified match */
+ /* find most qualified match */
while ((qname = qualname(name, lvl++)) != NULL)
for (vp = hashtbl[hash(qname)]; vp != NULL; vp = vp->next)
if (!strcmp(vp->name, qname))
@@ -335,33 +438,27 @@ varinsert(name) /* get a link to a variable */
char *name;
{
register VARDEF *vp;
- register LIBR *libp;
- int hv;
+ int hv;
if ((vp = varlookup(name)) != NULL) {
vp->nlinks++;
return(vp);
}
-#ifdef FUNCTION
- libp = liblookup(name);
-#else
- libp = NULL;
-#endif
- if (libp == NULL) /* if name not in library */
+ vp = (VARDEF *)emalloc(sizeof(VARDEF));
+ vp->lib = liblookup(name);
+ if (vp->lib == NULL) /* if name not in library */
name = qualname(name, 0); /* use fully qualified version */
hv = hash(name);
- vp = (VARDEF *)emalloc(sizeof(VARDEF));
vp->name = savestr(name);
vp->nlinks = 1;
vp->def = NULL;
- vp->lib = libp;
vp->next = hashtbl[hv];
hashtbl[hv] = vp;
return(vp);
}
-#ifdef FUNCTION
+void
libupdate(fn) /* update library links */
char *fn;
{
@@ -373,26 +470,26 @@ char *fn;
if (vp->lib != NULL || fn == NULL || !strcmp(fn, vp->name))
vp->lib = liblookup(vp->name);
}
-#endif
+void
varfree(ln) /* release link to variable */
-register VARDEF *ln;
+register VARDEF *ln;
{
register VARDEF *vp;
- int hv;
+ int hv;
if (--ln->nlinks > 0)
- return; /* still active */
+ return; /* still active */
hv = hash(ln->name);
vp = hashtbl[hv];
if (vp == ln)
- hashtbl[hv] = vp->next;
+ hashtbl[hv] = vp->next;
else {
- while (vp->next != ln) /* must be in list */
- vp = vp->next;
- vp->next = ln->next;
+ while (vp->next != ln) /* must be in list */
+ vp = vp->next;
+ vp->next = ln->next;
}
freestr(ln->name);
efree((char *)ln);
@@ -404,9 +501,7 @@ dfirst() /* return pointer to first definition */
{
htndx = 0;
htpos = NULL;
-#ifdef OUTCHAN
ochpos = outchan;
-#endif
return(dnext());
}
@@ -418,23 +513,19 @@ dnext() /* return pointer to next definition */
register char *nm;
while (htndx < NHASH) {
- if (htpos == NULL)
- htpos = hashtbl[htndx++];
- while (htpos != NULL) {
- ep = htpos->def;
+ if (htpos == NULL)
+ htpos = hashtbl[htndx++];
+ while (htpos != NULL) {
+ ep = htpos->def;
nm = htpos->name;
- htpos = htpos->next;
- if (ep != NULL && incontext(nm))
- return(ep);
- }
+ htpos = htpos->next;
+ if (ep != NULL && incontext(nm))
+ return(ep);
+ }
}
-#ifdef OUTCHAN
if ((ep = ochpos) != NULL)
- ochpos = ep->sibling;
+ ochpos = ep->sibling;
return(ep);
-#else
- return(NULL);
-#endif
}
@@ -446,7 +537,7 @@ char *name;
register EPNODE *dp;
if ((vp = varlookup(name)) == NULL || vp->def == NULL)
- return(NULL);
+ return(NULL);
dp = vp->def;
vp->def = dp->sibling;
varfree(vp);
@@ -454,9 +545,10 @@ char *name;
}
+void
dpush(nm, ep) /* push on a definition */
char *nm;
-register EPNODE *ep;
+register EPNODE *ep;
{
register VARDEF *vp;
@@ -466,11 +558,11 @@ register EPNODE *ep;
}
-#ifdef OUTCHAN
+void
addchan(sp) /* add an output channel assignment */
-EPNODE *sp;
+EPNODE *sp;
{
- int ch = sp->v.kid->v.chan;
+ int ch = sp->v.kid->v.chan;
register EPNODE *ep, *epl;
for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
@@ -494,9 +586,9 @@ EPNODE *sp;
sp->sibling = NULL;
}
-#endif
+void
getstatement() /* get next statement */
{
register EPNODE *ep;
@@ -507,31 +599,24 @@ getstatement() /* get next statement */
scan();
return;
}
-#ifdef OUTCHAN
- if (nextc == '$') { /* channel assignment */
+ if (esupport&E_OUTCHAN &&
+ nextc == '$') { /* channel assignment */
ep = getchan();
addchan(ep);
- } else
-#endif
- { /* ordinary definition */
+ } else { /* ordinary definition */
ep = getdefn();
qname = qualname(dname(ep), 0);
-#ifdef REDEFW
- if ((vdef = varlookup(qname)) != NULL)
- if (vdef->def != NULL) {
+ if (esupport&E_REDEFW && (vdef = varlookup(qname)) != NULL)
+ if (vdef->def != NULL && epcmp(ep, vdef->def)) {
wputs(qname);
if (vdef->def->type == ':')
wputs(": redefined constant expression\n");
else
wputs(": redefined\n");
- }
-#ifdef FUNCTION
- else if (ep->v.kid->type == FUNC && vdef->lib != NULL) {
+ } else if (ep->v.kid->type == FUNC && vdef->lib != NULL) {
wputs(qname);
wputs(": definition hides library function\n");
}
-#endif
-#endif
if (ep->type == ':')
dremove(qname);
else
@@ -549,7 +634,7 @@ getstatement() /* get next statement */
EPNODE *
getdefn() /* A -> SYM = E1 */
/* SYM : E1 */
- /* FUNC(SYM,..) = E1 */
+ /* FUNC(SYM,..) = E1 */
/* FUNC(SYM,..) : E1 */
{
register EPNODE *ep1, *ep2;
@@ -561,8 +646,7 @@ getdefn() /* A -> SYM = E1 */
ep1->type = SYM;
ep1->v.name = savestr(getname());
-#ifdef FUNCTION
- if (nextc == '(') {
+ if (esupport&E_FUNCTION && nextc == '(') {
ep2 = newnode();
ep2->type = FUNC;
addekid(ep2, ep1);
@@ -580,9 +664,7 @@ getdefn() /* A -> SYM = E1 */
syntax("')' expected");
scan();
curfunc = ep1;
- } else
- curfunc = NULL;
-#endif
+ }
if (nextc != '=' && nextc != ':')
syntax("'=' or ':' expected");
@@ -593,25 +675,21 @@ getdefn() /* A -> SYM = E1 */
addekid(ep2, ep1);
addekid(ep2, getE1());
- if (
-#ifdef FUNCTION
- ep1->type == SYM &&
-#endif
- ep1->sibling->type != NUM) {
+ if (ep1->type == SYM && ep1->sibling->type != NUM) {
ep1 = newnode();
ep1->type = TICK;
- ep1->v.tick = -1;
+ ep1->v.tick = 0;
addekid(ep2, ep1);
ep1 = newnode();
ep1->type = NUM;
addekid(ep2, ep1);
}
+ curfunc = NULL;
return(ep2);
}
-#ifdef OUTCHAN
EPNODE *
getchan() /* A -> $N = E1 */
{
@@ -636,7 +714,6 @@ getchan() /* A -> $N = E1 */
return(ep2);
}
-#endif
@@ -648,7 +725,7 @@ getchan() /* A -> $N = E1 */
static double
dvalue(name, d) /* evaluate a variable */
char *name;
-EPNODE *d;
+EPNODE *d;
{
register EPNODE *ep1, *ep2;
@@ -661,25 +738,15 @@ EPNODE *d;
if (ep1->type == NUM)
return(ep1->v.num); /* return if number */
ep2 = ep1->sibling; /* check time */
- if (ep2->v.tick < 0 || ep2->v.tick < eclock) {
- ep2->v.tick = d->type == ':' ? 1L<<30 : eclock;
+ if (eclock >= MAXCLOCK)
+ eclock = 1; /* wrap clock counter */
+ if (ep2->v.tick < MAXCLOCK &&
+ ep2->v.tick == 0 | ep2->v.tick != eclock) {
+ ep2->v.tick = d->type == ':' ? MAXCLOCK : eclock;
ep2 = ep2->sibling;
ep2->v.num = evalue(ep1); /* needs new value */
} else
ep2 = ep2->sibling; /* else reuse old value */
return(ep2->v.num);
-}
-
-
-static int
-hash(s) /* hash a string */
-register char *s;
-{
- register int rval = 0;
-
- while (*s)
- rval += *s++;
-
- return(rval % NHASH);
}