xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision 186:2094fda9fa81)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  * eval.c -- constraint evaluation module
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * this module evaluates constraints.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include "alloc.h"
380Sstevel@tonic-gate #include "out.h"
390Sstevel@tonic-gate #include "stable.h"
400Sstevel@tonic-gate #include "literals.h"
410Sstevel@tonic-gate #include "lut.h"
420Sstevel@tonic-gate #include "tree.h"
430Sstevel@tonic-gate #include "ptree.h"
440Sstevel@tonic-gate #include "itree.h"
450Sstevel@tonic-gate #include "eval.h"
460Sstevel@tonic-gate #include "config.h"
470Sstevel@tonic-gate #include "platform.h"
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static struct node *eval_dup(struct node *np, struct lut *ex,
510Sstevel@tonic-gate 			    struct node *epnames[]);
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * begins_with -- return true if rhs path begins with everything in lhs path
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate static int
570Sstevel@tonic-gate begins_with(struct node *lhs, struct node *rhs)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate 	int lnum;
600Sstevel@tonic-gate 	int rnum;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	if (lhs == NULL)
630Sstevel@tonic-gate 		return (1);	/* yep -- it all matched */
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	if (rhs == NULL)
660Sstevel@tonic-gate 		return (0);	/* nope, ran out of rhs first */
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str);
690Sstevel@tonic-gate 	ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str);
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	if (lhs->u.name.s != rhs->u.name.s)
720Sstevel@tonic-gate 		return (0);	/* nope, different component names */
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	if (lhs->u.name.child && lhs->u.name.child->t == T_NUM)
750Sstevel@tonic-gate 		lnum = (int)lhs->u.name.child->u.ull;
760Sstevel@tonic-gate 	else
770Sstevel@tonic-gate 		out(O_DIE, "begins_with: unexpected lhs child");
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	if (rhs->u.name.child && rhs->u.name.child->t == T_NUM)
800Sstevel@tonic-gate 		rnum = (int)rhs->u.name.child->u.ull;
810Sstevel@tonic-gate 	else
820Sstevel@tonic-gate 		out(O_DIE, "begins_with: unexpected rhs child");
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	if (lnum != rnum)
850Sstevel@tonic-gate 		return (0);	/* nope, instance numbers were different */
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	return (begins_with(lhs->u.name.next, rhs->u.name.next));
880Sstevel@tonic-gate }
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  * evaluate a variety of functions and place result in valuep.  return 1 if
920Sstevel@tonic-gate  * function evaluation was successful; 0 if otherwise (e.g., the case of an
930Sstevel@tonic-gate  * invalid argument to the function)
940Sstevel@tonic-gate  */
950Sstevel@tonic-gate /*ARGSUSED*/
960Sstevel@tonic-gate static int
970Sstevel@tonic-gate eval_func(struct node *funcnp, struct lut *ex, struct node *epnames[],
980Sstevel@tonic-gate     struct node *np, struct lut **globals,
990Sstevel@tonic-gate     struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate 	const char *funcname = funcnp->u.func.s;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	if (funcname == L_within) {
1040Sstevel@tonic-gate 		/* within()'s are not really constraints -- always true */
1050Sstevel@tonic-gate 		valuep->t = UINT64;
1060Sstevel@tonic-gate 		valuep->v = 1;
1070Sstevel@tonic-gate 		return (1);
1080Sstevel@tonic-gate 	} else if (funcname == L_is_under) {
1090Sstevel@tonic-gate 		struct node *lhs;
1100Sstevel@tonic-gate 		struct node *rhs;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 		if (np->u.expr.left->t == T_NAME)
1130Sstevel@tonic-gate 			lhs = np->u.expr.left;
1140Sstevel@tonic-gate 		else if (np->u.expr.left->u.func.s == L_fru)
1150Sstevel@tonic-gate 			lhs = eval_fru(np->u.expr.left->u.func.arglist);
1160Sstevel@tonic-gate 		else if (np->u.expr.left->u.func.s == L_asru)
1170Sstevel@tonic-gate 			lhs = eval_asru(np->u.expr.left->u.func.arglist);
1180Sstevel@tonic-gate 		else
1190Sstevel@tonic-gate 			out(O_DIE, "is_under: unexpected lhs type: %s",
1200Sstevel@tonic-gate 			    ptree_nodetype2str(np->u.expr.left->t));
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 		if (np->u.expr.right->t == T_NAME)
1230Sstevel@tonic-gate 			rhs = np->u.expr.right;
1240Sstevel@tonic-gate 		else if (np->u.expr.right->u.func.s == L_fru)
1250Sstevel@tonic-gate 			rhs = eval_fru(np->u.expr.right->u.func.arglist);
1260Sstevel@tonic-gate 		else if (np->u.expr.right->u.func.s == L_asru)
1270Sstevel@tonic-gate 			rhs = eval_asru(np->u.expr.right->u.func.arglist);
1280Sstevel@tonic-gate 		else
1290Sstevel@tonic-gate 			out(O_DIE, "is_under: unexpected rhs type: %s",
1300Sstevel@tonic-gate 			    ptree_nodetype2str(np->u.expr.right->t));
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 		/* eval_dup will expand wildcards, iterators, etc... */
1330Sstevel@tonic-gate 		lhs = eval_dup(lhs, ex, epnames);
1340Sstevel@tonic-gate 		rhs = eval_dup(rhs, ex, epnames);
1350Sstevel@tonic-gate 		valuep->t = UINT64;
1360Sstevel@tonic-gate 		valuep->v = begins_with(lhs, rhs);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 		out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under(");
1390Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs);
1400Sstevel@tonic-gate 		out(O_ALTFP|O_VERB2|O_NONL, ",");
1410Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs);
1420Sstevel@tonic-gate 		out(O_ALTFP|O_VERB2, ") returned %d", (int)valuep->v);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 		tree_free(lhs);
1450Sstevel@tonic-gate 		tree_free(rhs);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 		return (1);
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	if (try)
1510Sstevel@tonic-gate 		return (0);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	if (funcname == L_fru) {
1540Sstevel@tonic-gate 		valuep->t = NODEPTR;
1550Sstevel@tonic-gate 		valuep->v = (unsigned long long)eval_fru(np);
1560Sstevel@tonic-gate 		return (1);
1570Sstevel@tonic-gate 	} else if (funcname == L_asru) {
1580Sstevel@tonic-gate 		valuep->t = NODEPTR;
1590Sstevel@tonic-gate 		valuep->v = (unsigned long long)eval_asru(np);
1600Sstevel@tonic-gate 		return (1);
1610Sstevel@tonic-gate 	} else if (funcname == L_call) {
1620Sstevel@tonic-gate 		return (! platform_call(np, globals, croot, arrowp, valuep));
1630Sstevel@tonic-gate 	} else if (funcname == L_is_connected) {
1640Sstevel@tonic-gate 		return (! config_is_connected(np, croot, valuep));
1650Sstevel@tonic-gate 	} else if (funcname == L_is_on) {
1660Sstevel@tonic-gate 		return (! config_is_on(np, croot, valuep));
1670Sstevel@tonic-gate 	} else if (funcname == L_is_present) {
1680Sstevel@tonic-gate 		return (! config_is_present(np, croot, valuep));
1690Sstevel@tonic-gate 	} else if (funcname == L_is_type) {
1700Sstevel@tonic-gate 		return (! config_is_type(np, croot, valuep));
1710Sstevel@tonic-gate 	} else if (funcname == L_confprop) {
1720Sstevel@tonic-gate 		return (! config_confprop(np, croot, valuep));
1730Sstevel@tonic-gate 	} else if (funcname == L_envprop) {
1740Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
1750Sstevel@tonic-gate 		    "eval_func: %s not yet supported", funcname);
1760Sstevel@tonic-gate 	} else if (funcname == L_payloadprop) {
1770Sstevel@tonic-gate 		outfl(O_ALTFP|O_VERB|O_NONL, np->file, np->line,
1780Sstevel@tonic-gate 		    "payloadprop(\"%s\") ", np->u.quote.s);
1790Sstevel@tonic-gate 		if (funcnp->u.func.cachedval != NULL) {
1800Sstevel@tonic-gate 			*valuep = *(struct evalue *)(funcnp->u.func.cachedval);
181*186Sdb35262 
182*186Sdb35262 			switch (valuep->t) {
183*186Sdb35262 			case UINT64:
184*186Sdb35262 			case NODEPTR:
185*186Sdb35262 				out(O_ALTFP|O_VERB, "cached: %llu", valuep->v);
186*186Sdb35262 				break;
187*186Sdb35262 			case STRING:
188*186Sdb35262 				out(O_ALTFP|O_VERB, "cached: \"%s\"",
189*186Sdb35262 				    (char *)valuep->v);
190*186Sdb35262 				break;
191*186Sdb35262 			default:
192*186Sdb35262 				out(O_ALTFP|O_VERB, "undefined");
193*186Sdb35262 				break;
194*186Sdb35262 			}
195*186Sdb35262 
1960Sstevel@tonic-gate 			return (1);
1970Sstevel@tonic-gate 		} else if (platform_payloadprop(np, valuep)) {
1980Sstevel@tonic-gate 			/* platform_payloadprop() returned false, pass it on */
1990Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, "failed.");
2000Sstevel@tonic-gate 			return (0);
2010Sstevel@tonic-gate 		} else {
2020Sstevel@tonic-gate 			/* got back true, cache the value */
2030Sstevel@tonic-gate 			funcnp->u.func.cachedval =
2040Sstevel@tonic-gate 			    MALLOC(sizeof (struct evalue));
2050Sstevel@tonic-gate 			*(struct evalue *)(funcnp->u.func.cachedval) =
2060Sstevel@tonic-gate 			    *valuep;
207*186Sdb35262 
208*186Sdb35262 			switch (valuep->t) {
209*186Sdb35262 			case UINT64:
210*186Sdb35262 			case NODEPTR:
211*186Sdb35262 				out(O_ALTFP|O_VERB, "cached: %llu", valuep->v);
212*186Sdb35262 				break;
213*186Sdb35262 			case STRING:
214*186Sdb35262 				out(O_ALTFP|O_VERB, "cached: \"%s\"",
215*186Sdb35262 				    (char *)valuep->v);
216*186Sdb35262 				break;
217*186Sdb35262 			default:
218*186Sdb35262 				out(O_ALTFP|O_VERB, "undefined");
219*186Sdb35262 				break;
220*186Sdb35262 			}
221*186Sdb35262 
2220Sstevel@tonic-gate 			return (1);
2230Sstevel@tonic-gate 		}
2240Sstevel@tonic-gate 	} else
2250Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
2260Sstevel@tonic-gate 		    "eval_func: unexpected func: %s", funcname);
2270Sstevel@tonic-gate 	/*NOTREACHED*/
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate static struct node *
2310Sstevel@tonic-gate eval_wildcardedname(struct node *np, struct lut *ex, struct node *epnames[])
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	struct node *npstart, *npend, *npref, *newnp;
2340Sstevel@tonic-gate 	struct node *np1, *np2, *retp;
2350Sstevel@tonic-gate 	int i;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if (epnames == NULL || epnames[0] == NULL)
2380Sstevel@tonic-gate 		return (NULL);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	for (i = 0; epnames[i] != NULL; i++) {
2410Sstevel@tonic-gate 		if (tree_namecmp(np, epnames[i]) == 0)
2420Sstevel@tonic-gate 			return (NULL);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/*
2460Sstevel@tonic-gate 	 * get to this point if np does not match any of the entries in
2470Sstevel@tonic-gate 	 * epnames.  check if np is a path that must preceded by a wildcard
2480Sstevel@tonic-gate 	 * portion.  for this case we must first determine which epnames[]
2490Sstevel@tonic-gate 	 * entry should be used for wildcarding.
2500Sstevel@tonic-gate 	 */
2510Sstevel@tonic-gate 	npstart = NULL;
2520Sstevel@tonic-gate 	for (i = 0; epnames[i] != NULL; i++) {
2530Sstevel@tonic-gate 		for (npref = epnames[i]; npref; npref = npref->u.name.next) {
2540Sstevel@tonic-gate 			if (npref->u.name.s == np->u.name.s) {
2550Sstevel@tonic-gate 				for (np1 = npref, np2 = np;
2560Sstevel@tonic-gate 				    np1 != NULL && np2 != NULL;
2570Sstevel@tonic-gate 				    np1 = np1->u.name.next,
2580Sstevel@tonic-gate 					    np2 = np2->u.name.next) {
2590Sstevel@tonic-gate 					if (np1->u.name.s != np2->u.name.s)
2600Sstevel@tonic-gate 						break;
2610Sstevel@tonic-gate 				}
2620Sstevel@tonic-gate 				if (np2 == NULL) {
2630Sstevel@tonic-gate 					npstart = epnames[i];
2640Sstevel@tonic-gate 					npend = npref;
2650Sstevel@tonic-gate 					if (np1 == NULL)
2660Sstevel@tonic-gate 						break;
2670Sstevel@tonic-gate 				}
2680Sstevel@tonic-gate 			}
2690Sstevel@tonic-gate 		}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 		if (npstart != NULL)
2720Sstevel@tonic-gate 			break;
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if (npstart == NULL) {
2760Sstevel@tonic-gate 		/* no match; np is not a path to be wildcarded */
2770Sstevel@tonic-gate 		return (NULL);
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/*
2810Sstevel@tonic-gate 	 * dup (npstart -- npend) which is the wildcarded portion.  all
2820Sstevel@tonic-gate 	 * children should be T_NUMs.
2830Sstevel@tonic-gate 	 */
2840Sstevel@tonic-gate 	retp = NULL;
2850Sstevel@tonic-gate 	for (npref = npstart;
2860Sstevel@tonic-gate 	    ! (npref == NULL || npref == npend);
2870Sstevel@tonic-gate 	    npref = npref->u.name.next) {
2880Sstevel@tonic-gate 		newnp = newnode(T_NAME, np->file, np->line);
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 		newnp->u.name.t = npref->u.name.t;
2910Sstevel@tonic-gate 		newnp->u.name.s = npref->u.name.s;
2920Sstevel@tonic-gate 		newnp->u.name.last = newnp;
2930Sstevel@tonic-gate 		newnp->u.name.it = npref->u.name.it;
2940Sstevel@tonic-gate 		newnp->u.name.cp = npref->u.name.cp;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 		ASSERT(npref->u.name.child != NULL);
2970Sstevel@tonic-gate 		ASSERT(npref->u.name.child->t == T_NUM);
2980Sstevel@tonic-gate 		newnp->u.name.child = newnode(T_NUM, np->file, np->line);
2990Sstevel@tonic-gate 		newnp->u.name.child->u.ull = npref->u.name.child->u.ull;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 		if (retp == NULL) {
3020Sstevel@tonic-gate 			retp = newnp;
3030Sstevel@tonic-gate 		} else {
3040Sstevel@tonic-gate 			retp->u.name.last->u.name.next = newnp;
3050Sstevel@tonic-gate 			retp->u.name.last = newnp;
3060Sstevel@tonic-gate 		}
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	ASSERT(retp != NULL);
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	/* now append the nonwildcarded portion */
3120Sstevel@tonic-gate 	retp = tree_name_append(retp, eval_dup(np, ex, NULL));
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	return (retp);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate static struct node *
3180Sstevel@tonic-gate eval_dup(struct node *np, struct lut *ex, struct node *epnames[])
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate 	struct node *newnp;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (np == NULL)
3230Sstevel@tonic-gate 		return (NULL);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	switch (np->t) {
3260Sstevel@tonic-gate 	case T_GLOBID:
3270Sstevel@tonic-gate 		return (tree_globid(np->u.globid.s, np->file, np->line));
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	case T_ASSIGN:
3300Sstevel@tonic-gate 	case T_CONDIF:
3310Sstevel@tonic-gate 	case T_CONDELSE:
3320Sstevel@tonic-gate 	case T_NE:
3330Sstevel@tonic-gate 	case T_EQ:
3340Sstevel@tonic-gate 	case T_LT:
3350Sstevel@tonic-gate 	case T_LE:
3360Sstevel@tonic-gate 	case T_GT:
3370Sstevel@tonic-gate 	case T_GE:
3380Sstevel@tonic-gate 	case T_BITAND:
3390Sstevel@tonic-gate 	case T_BITOR:
3400Sstevel@tonic-gate 	case T_BITXOR:
3410Sstevel@tonic-gate 	case T_BITNOT:
3420Sstevel@tonic-gate 	case T_LSHIFT:
3430Sstevel@tonic-gate 	case T_RSHIFT:
3440Sstevel@tonic-gate 	case T_LIST:
3450Sstevel@tonic-gate 	case T_AND:
3460Sstevel@tonic-gate 	case T_OR:
3470Sstevel@tonic-gate 	case T_NOT:
3480Sstevel@tonic-gate 	case T_ADD:
3490Sstevel@tonic-gate 	case T_SUB:
3500Sstevel@tonic-gate 	case T_MUL:
3510Sstevel@tonic-gate 	case T_DIV:
3520Sstevel@tonic-gate 	case T_MOD:
3530Sstevel@tonic-gate 		return (tree_expr(np->t,
3540Sstevel@tonic-gate 				    eval_dup(np->u.expr.left, ex, epnames),
3550Sstevel@tonic-gate 				    eval_dup(np->u.expr.right, ex, epnames)));
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	case T_NAME: {
3580Sstevel@tonic-gate 		struct iterinfo *iterinfop;
3590Sstevel@tonic-gate 		struct node *newchild = NULL;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 		iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
3620Sstevel@tonic-gate 		if (iterinfop != NULL) {
3630Sstevel@tonic-gate 			/* explicit iterator; not part of pathname */
3640Sstevel@tonic-gate 			newnp = newnode(T_NUM, np->file, np->line);
3650Sstevel@tonic-gate 			newnp->u.ull = iterinfop->num;
3660Sstevel@tonic-gate 			return (newnp);
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 		/* see if np is a path with wildcard portion */
3700Sstevel@tonic-gate 		newnp = eval_wildcardedname(np, ex, epnames);
3710Sstevel@tonic-gate 		if (newnp != NULL)
3720Sstevel@tonic-gate 			return (newnp);
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		/* turn off wildcarding for child */
3750Sstevel@tonic-gate 		newchild = eval_dup(np->u.name.child, ex, NULL);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 		if (newchild != NULL) {
3780Sstevel@tonic-gate 			if (newchild->t != T_NUM) {
3790Sstevel@tonic-gate 				/*
3800Sstevel@tonic-gate 				 * not a number, eh?  we must resolve this
3810Sstevel@tonic-gate 				 * to a number.
3820Sstevel@tonic-gate 				 */
3830Sstevel@tonic-gate 				struct evalue value;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 				if (eval_expr(newchild, ex, epnames,
3860Sstevel@tonic-gate 				    NULL, NULL, NULL, 1, &value) == 0 ||
3870Sstevel@tonic-gate 				    value.t != UINT64) {
3880Sstevel@tonic-gate 					outfl(O_DIE, np->file, np->line,
3890Sstevel@tonic-gate 					    "eval_dup: could not resolve "
3900Sstevel@tonic-gate 					    "iterator of %s", np->u.name.s);
3910Sstevel@tonic-gate 				}
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 				tree_free(newchild);
3940Sstevel@tonic-gate 				newchild = newnode(T_NUM, np->file, np->line);
3950Sstevel@tonic-gate 				newchild->u.ull = value.v;
3960Sstevel@tonic-gate 			}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 			newnp = newnode(np->t, np->file, np->line);
3990Sstevel@tonic-gate 			newnp->u.name.s = np->u.name.s;
4000Sstevel@tonic-gate 			newnp->u.name.it = np->u.name.it;
4010Sstevel@tonic-gate 			newnp->u.name.cp = np->u.name.cp;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 			newnp->u.name.last = newnp;
4040Sstevel@tonic-gate 			newnp->u.name.child = newchild;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 			if (np->u.name.next != NULL) {
4070Sstevel@tonic-gate 				/* turn off wildcarding for next */
4080Sstevel@tonic-gate 				return (tree_name_append(newnp,
4090Sstevel@tonic-gate 					eval_dup(np->u.name.next, ex, NULL)));
4100Sstevel@tonic-gate 			} else {
4110Sstevel@tonic-gate 				return (newnp);
4120Sstevel@tonic-gate 			}
4130Sstevel@tonic-gate 		} else {
4140Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
4150Sstevel@tonic-gate 			    "eval_dup: internal error: \"%s\" is neither "
4160Sstevel@tonic-gate 			    "an iterator nor a pathname", np->u.name.s);
4170Sstevel@tonic-gate 		}
4180Sstevel@tonic-gate 		/*NOTREACHED*/
4190Sstevel@tonic-gate 		break;
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	case T_FUNC:
4230Sstevel@tonic-gate 		return (tree_func(np->u.func.s,
4240Sstevel@tonic-gate 		    eval_dup(np->u.func.arglist, ex, epnames),
4250Sstevel@tonic-gate 		    np->file, np->line));
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	case T_QUOTE:
4280Sstevel@tonic-gate 		newnp = newnode(T_QUOTE, np->file, np->line);
4290Sstevel@tonic-gate 		newnp->u.quote.s = np->u.quote.s;
4300Sstevel@tonic-gate 		return (newnp);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	case T_NUM:
4330Sstevel@tonic-gate 		newnp = newnode(T_NUM, np->file, np->line);
4340Sstevel@tonic-gate 		newnp->u.ull = np->u.ull;
4350Sstevel@tonic-gate 		return (newnp);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	default:
4380Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
4390Sstevel@tonic-gate 		    "eval_dup: unexpected node type: %s",
4400Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 	/*NOTREACHED*/
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate /*
4460Sstevel@tonic-gate  * eval_potential -- see if constraint is potentially true
4470Sstevel@tonic-gate  *
4480Sstevel@tonic-gate  * this function is used at instance tree creation time to see if
4490Sstevel@tonic-gate  * any constraints are already known to be false.  if this function
4500Sstevel@tonic-gate  * returns false, then the constraint will always be false and there's
4510Sstevel@tonic-gate  * no need to include the propagation arrow in the instance tree.
4520Sstevel@tonic-gate  *
4530Sstevel@tonic-gate  * if this routine returns true, either the constraint is known to
4540Sstevel@tonic-gate  * be always true (so there's no point in attaching the constraint
4550Sstevel@tonic-gate  * to the propagation arrow in the instance tree), or the constraint
4560Sstevel@tonic-gate  * contains "deferred" expressions like global variables or poller calls
4570Sstevel@tonic-gate  * and so it must be evaluated during calls to fme_eval().  in this last
4580Sstevel@tonic-gate  * case, where a constraint needs to be attached to the propagation arrow
4590Sstevel@tonic-gate  * in the instance tree, this routine returns a newly created constraint
4600Sstevel@tonic-gate  * in *newc where all the non-deferred things have been filled in.
4610Sstevel@tonic-gate  *
4620Sstevel@tonic-gate  * so in summary:
4630Sstevel@tonic-gate  *
4640Sstevel@tonic-gate  *	return of false: constraint can never be true, *newc will be NULL.
4650Sstevel@tonic-gate  *
4660Sstevel@tonic-gate  *	return of true with *newc unchanged: constraint will always be true.
4670Sstevel@tonic-gate  *
4680Sstevel@tonic-gate  *	return of true with *newc changed: use new constraint in *newc.
4690Sstevel@tonic-gate  *
4700Sstevel@tonic-gate  * the lookup table for all explicit iterators, ex, is passed in.
4710Sstevel@tonic-gate  *
4720Sstevel@tonic-gate  * *newc can either be NULL on entry, or if can contain constraints from
4730Sstevel@tonic-gate  * previous calls to eval_potential() (i.e. for building up an instance
4740Sstevel@tonic-gate  * tree constraint from several potential constraints).  if *newc already
4750Sstevel@tonic-gate  * contains constraints, anything added to it will be joined by adding
4760Sstevel@tonic-gate  * a T_AND node at the top of *newc.
4770Sstevel@tonic-gate  */
4780Sstevel@tonic-gate int
4790Sstevel@tonic-gate eval_potential(struct node *np, struct lut *ex, struct node *epnames[],
4800Sstevel@tonic-gate 	    struct node **newc)
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate 	struct node *newnp;
4830Sstevel@tonic-gate 	struct evalue value;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	if (eval_expr(np, ex, epnames, NULL, NULL, NULL, 1, &value) == 0) {
4860Sstevel@tonic-gate 		/*
4870Sstevel@tonic-gate 		 * couldn't eval expression because
4880Sstevel@tonic-gate 		 * it contains deferred items.  make
4890Sstevel@tonic-gate 		 * a duplicate expression with all the
4900Sstevel@tonic-gate 		 * non-deferred items expanded.
4910Sstevel@tonic-gate 		 */
4920Sstevel@tonic-gate 		newnp = eval_dup(np, ex, epnames);
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		if (*newc == NULL) {
4950Sstevel@tonic-gate 			/*
4960Sstevel@tonic-gate 			 * constraint is potentially true if deferred
4970Sstevel@tonic-gate 			 * expression in newnp is true.  *newc was NULL
4980Sstevel@tonic-gate 			 * so new constraint is just the one in newnp.
4990Sstevel@tonic-gate 			 */
5000Sstevel@tonic-gate 			*newc = newnp;
5010Sstevel@tonic-gate 			return (1);
5020Sstevel@tonic-gate 		} else {
5030Sstevel@tonic-gate 			/*
5040Sstevel@tonic-gate 			 * constraint is potentially true if deferred
5050Sstevel@tonic-gate 			 * expression in newnp is true.  *newc already
5060Sstevel@tonic-gate 			 * contained a constraint so add an AND with the
5070Sstevel@tonic-gate 			 * constraint in newnp.
5080Sstevel@tonic-gate 			 */
5090Sstevel@tonic-gate 			*newc = tree_expr(T_AND, *newc, newnp);
5100Sstevel@tonic-gate 			return (1);
5110Sstevel@tonic-gate 		}
5120Sstevel@tonic-gate 	} else if (value.t == UNDEFINED) {
5130Sstevel@tonic-gate 		/* constraint can never be true */
5140Sstevel@tonic-gate 		return (0);
5150Sstevel@tonic-gate 	} else if (value.t == UINT64 && value.v == 0) {
5160Sstevel@tonic-gate 		/* constraint can never be true */
5170Sstevel@tonic-gate 		return (0);
5180Sstevel@tonic-gate 	} else {
5190Sstevel@tonic-gate 		/* constraint is always true (nothing deferred to eval) */
5200Sstevel@tonic-gate 		return (1);
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate static int
5250Sstevel@tonic-gate check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
5260Sstevel@tonic-gate 		struct node *np)
5270Sstevel@tonic-gate {
5280Sstevel@tonic-gate 	if (dtype != UNDEFINED && lp->t != dtype) {
5290Sstevel@tonic-gate 		outfl(O_OK, np->file, np->line,
5300Sstevel@tonic-gate 			"invalid datatype of argument for operation %s",
5310Sstevel@tonic-gate 			ptree_nodetype2str(np->t));
5320Sstevel@tonic-gate 		return (1);
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if (rp != NULL && lp->t != rp->t) {
5360Sstevel@tonic-gate 		outfl(O_OK, np->file, np->line,
5370Sstevel@tonic-gate 			"mismatch in datatype of arguments for operation %s",
5380Sstevel@tonic-gate 			ptree_nodetype2str(np->t));
5390Sstevel@tonic-gate 		return (1);
5400Sstevel@tonic-gate 	}
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	return (0);
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate /*
5460Sstevel@tonic-gate  * eval_expr -- evaluate expression into *valuep
5470Sstevel@tonic-gate  *
5480Sstevel@tonic-gate  * the meaning of the return value depends on the input value of try.
5490Sstevel@tonic-gate  *
5500Sstevel@tonic-gate  * for try == 1: if any deferred items are encounted, bail out and return
5510Sstevel@tonic-gate  * false.  returns true if we made it through entire expression without
5520Sstevel@tonic-gate  * hitting any deferred items.
5530Sstevel@tonic-gate  *
5540Sstevel@tonic-gate  * for try == 0: return true if all operations were performed successfully.
5550Sstevel@tonic-gate  * return false if otherwise.  for example, any of the following conditions
5560Sstevel@tonic-gate  * will result in a false return value:
5570Sstevel@tonic-gate  *   - attempted use of an uninitialized global variable
5580Sstevel@tonic-gate  *   - failure in function evaluation
5590Sstevel@tonic-gate  *   - illegal arithmetic operation (argument out of range)
5600Sstevel@tonic-gate  */
5610Sstevel@tonic-gate int
5620Sstevel@tonic-gate eval_expr(struct node *np, struct lut *ex, struct node *epnames[],
5630Sstevel@tonic-gate 	struct lut **globals, struct config *croot, struct arrow *arrowp,
5640Sstevel@tonic-gate 	int try, struct evalue *valuep)
5650Sstevel@tonic-gate {
5660Sstevel@tonic-gate 	struct evalue *gval;
5670Sstevel@tonic-gate 	struct evalue lval;
5680Sstevel@tonic-gate 	struct evalue rval;
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	if (np == NULL) {
5710Sstevel@tonic-gate 		valuep->t = UINT64;
5720Sstevel@tonic-gate 		valuep->v = 1;	/* no constraint means "true" */
5730Sstevel@tonic-gate 		return (1);
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	valuep->t = UNDEFINED;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	switch (np->t) {
5790Sstevel@tonic-gate 	case T_GLOBID:
5800Sstevel@tonic-gate 		if (try)
5810Sstevel@tonic-gate 			return (0);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		/*
5840Sstevel@tonic-gate 		 * only handle case of getting (and not setting) the value
5850Sstevel@tonic-gate 		 * of a global variable
5860Sstevel@tonic-gate 		 */
5870Sstevel@tonic-gate 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
5880Sstevel@tonic-gate 		if (gval == NULL) {
5890Sstevel@tonic-gate 			valuep->t = UNDEFINED;
5900Sstevel@tonic-gate 			return (0);
5910Sstevel@tonic-gate 		} else {
5920Sstevel@tonic-gate 			valuep->t = gval->t;
5930Sstevel@tonic-gate 			valuep->v = gval->v;
5940Sstevel@tonic-gate 			return (1);
5950Sstevel@tonic-gate 		}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	case T_ASSIGN:
5980Sstevel@tonic-gate 		if (try)
5990Sstevel@tonic-gate 			return (0);
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		/*
6020Sstevel@tonic-gate 		 * first evaluate rhs, then try to store value in lhs which
6030Sstevel@tonic-gate 		 * should be a global variable
6040Sstevel@tonic-gate 		 */
6050Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
6060Sstevel@tonic-gate 			    arrowp, try, &rval))
6070Sstevel@tonic-gate 			return (0);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 		ASSERT(np->u.expr.left->t == T_GLOBID);
6100Sstevel@tonic-gate 		gval = lut_lookup(*globals,
6110Sstevel@tonic-gate 				(void *)np->u.expr.left->u.globid.s, NULL);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		if (gval == NULL) {
6140Sstevel@tonic-gate 			gval = MALLOC(sizeof (*gval));
6150Sstevel@tonic-gate 			*globals = lut_add(*globals,
6160Sstevel@tonic-gate 					(void *) np->u.expr.left->u.globid.s,
6170Sstevel@tonic-gate 					gval, NULL);
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 		gval->t = rval.t;
6210Sstevel@tonic-gate 		gval->v = rval.v;
6220Sstevel@tonic-gate 		valuep->t = rval.t;
6230Sstevel@tonic-gate 		valuep->v = rval.v;
6240Sstevel@tonic-gate 		return (1);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	case T_EQ:
6270Sstevel@tonic-gate #define	IMPLICIT_ASSIGN_IN_EQ
6280Sstevel@tonic-gate #ifdef IMPLICIT_ASSIGN_IN_EQ
6290Sstevel@tonic-gate 		/*
6300Sstevel@tonic-gate 		 * if lhs is an uninitialized global variable, perform
6310Sstevel@tonic-gate 		 * an assignment.
6320Sstevel@tonic-gate 		 *
6330Sstevel@tonic-gate 		 * one insidious side effect of implicit assignment is
6340Sstevel@tonic-gate 		 * that the "==" operator does not return a Boolean if
6350Sstevel@tonic-gate 		 * implicit assignment was performed.
6360Sstevel@tonic-gate 		 */
6370Sstevel@tonic-gate 		if (try == 0 &&
6380Sstevel@tonic-gate 		    np->u.expr.left->t == T_GLOBID &&
6390Sstevel@tonic-gate 		    (gval = lut_lookup(*globals,
6400Sstevel@tonic-gate 			(void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
6410Sstevel@tonic-gate 			if (!eval_expr(np->u.expr.right, ex, epnames, globals,
6420Sstevel@tonic-gate 					croot, arrowp, try, &rval))
6430Sstevel@tonic-gate 				return (0);
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 			gval = MALLOC(sizeof (*gval));
6460Sstevel@tonic-gate 			*globals = lut_add(*globals,
6470Sstevel@tonic-gate 					(void *) np->u.expr.left->u.globid.s,
6480Sstevel@tonic-gate 					gval, NULL);
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 			gval->t = rval.t;
6510Sstevel@tonic-gate 			gval->v = rval.v;
6520Sstevel@tonic-gate 			valuep->t = rval.t;
6530Sstevel@tonic-gate 			valuep->v = rval.v;
6540Sstevel@tonic-gate 			return (1);
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate #endif  /* IMPLICIT_ASSIGN_IN_EQ */
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
6590Sstevel@tonic-gate 				arrowp, try, &lval))
6600Sstevel@tonic-gate 			return (0);
6610Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
6620Sstevel@tonic-gate 				arrowp, try, &rval))
6630Sstevel@tonic-gate 			return (0);
6640Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
6650Sstevel@tonic-gate 			return (0);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 		valuep->t = UINT64;
6680Sstevel@tonic-gate 		valuep->v = (lval.v == rval.v);
6690Sstevel@tonic-gate 		return (1);
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	case T_LT:
6720Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
6730Sstevel@tonic-gate 				arrowp, try, &lval))
6740Sstevel@tonic-gate 			return (0);
6750Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
6760Sstevel@tonic-gate 				arrowp, try, &rval))
6770Sstevel@tonic-gate 			return (0);
6780Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
6790Sstevel@tonic-gate 			return (0);
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		valuep->t = UINT64;
6820Sstevel@tonic-gate 		valuep->v = (lval.v < rval.v);
6830Sstevel@tonic-gate 		return (1);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	case T_LE:
6860Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
6870Sstevel@tonic-gate 				arrowp, try, &lval))
6880Sstevel@tonic-gate 			return (0);
6890Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
6900Sstevel@tonic-gate 				arrowp, try, &rval))
6910Sstevel@tonic-gate 			return (0);
6920Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
6930Sstevel@tonic-gate 			return (0);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 		valuep->t = UINT64;
6960Sstevel@tonic-gate 		valuep->v = (lval.v <= rval.v);
6970Sstevel@tonic-gate 		return (1);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	case T_GT:
7000Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
7010Sstevel@tonic-gate 				arrowp, try, &lval))
7020Sstevel@tonic-gate 			return (0);
7030Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
7040Sstevel@tonic-gate 				arrowp, try, &rval))
7050Sstevel@tonic-gate 			return (0);
7060Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
7070Sstevel@tonic-gate 			return (0);
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 		valuep->t = UINT64;
7100Sstevel@tonic-gate 		valuep->v = (lval.v > rval.v);
7110Sstevel@tonic-gate 		return (1);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	case T_GE:
7140Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
7150Sstevel@tonic-gate 				arrowp, try, &lval))
7160Sstevel@tonic-gate 			return (0);
7170Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
7180Sstevel@tonic-gate 				arrowp, try, &rval))
7190Sstevel@tonic-gate 			return (0);
7200Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
7210Sstevel@tonic-gate 			return (0);
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 		valuep->t = UINT64;
7240Sstevel@tonic-gate 		valuep->v = (lval.v >= rval.v);
7250Sstevel@tonic-gate 		return (1);
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	case T_BITAND:
7280Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
7290Sstevel@tonic-gate 				arrowp, try, &lval))
7300Sstevel@tonic-gate 			return (0);
7310Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
7320Sstevel@tonic-gate 				arrowp, try, &rval))
7330Sstevel@tonic-gate 			return (0);
7340Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
7350Sstevel@tonic-gate 			return (0);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 		valuep->t = lval.t;
7380Sstevel@tonic-gate 		valuep->v = (lval.v & rval.v);
7390Sstevel@tonic-gate 		return (1);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	case T_BITOR:
7420Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
7430Sstevel@tonic-gate 				arrowp, try, &lval))
7440Sstevel@tonic-gate 			return (0);
7450Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
7460Sstevel@tonic-gate 				arrowp, try, &rval))
7470Sstevel@tonic-gate 			return (0);
7480Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
7490Sstevel@tonic-gate 			return (0);
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 		valuep->t = lval.t;
7520Sstevel@tonic-gate 		valuep->v = (lval.v | rval.v);
7530Sstevel@tonic-gate 		return (1);
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	case T_BITXOR:
7560Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
7570Sstevel@tonic-gate 				arrowp, try, &lval))
7580Sstevel@tonic-gate 			return (0);
7590Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
7600Sstevel@tonic-gate 				arrowp, try, &rval))
7610Sstevel@tonic-gate 			return (0);
7620Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
7630Sstevel@tonic-gate 			return (0);
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 		valuep->t = lval.t;
7660Sstevel@tonic-gate 		valuep->v = (lval.v ^ rval.v);
7670Sstevel@tonic-gate 		return (1);
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	case T_BITNOT:
7700Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
7710Sstevel@tonic-gate 				arrowp, try, &lval))
7720Sstevel@tonic-gate 			return (0);
7730Sstevel@tonic-gate 		ASSERT(np->u.expr.right == NULL);
7740Sstevel@tonic-gate 		if (check_expr_args(&lval, NULL, UINT64, np))
7750Sstevel@tonic-gate 			return (0);
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 		valuep->t = UINT64;
7780Sstevel@tonic-gate 		valuep->v = ~ lval.v;
7790Sstevel@tonic-gate 		return (1);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	case T_LSHIFT:
7820Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
7830Sstevel@tonic-gate 				arrowp, try, &lval))
7840Sstevel@tonic-gate 			return (0);
7850Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
7860Sstevel@tonic-gate 				arrowp, try, &rval))
7870Sstevel@tonic-gate 			return (0);
7880Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
7890Sstevel@tonic-gate 			return (0);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 		valuep->t = UINT64;
7920Sstevel@tonic-gate 		valuep->v = (lval.v << rval.v);
7930Sstevel@tonic-gate 		return (1);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	case T_RSHIFT:
7960Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
7970Sstevel@tonic-gate 				arrowp, try, &lval))
7980Sstevel@tonic-gate 			return (0);
7990Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
8000Sstevel@tonic-gate 				arrowp, try, &rval))
8010Sstevel@tonic-gate 			return (0);
8020Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
8030Sstevel@tonic-gate 			return (0);
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 		valuep->t = UINT64;
8060Sstevel@tonic-gate 		valuep->v = (lval.v >> rval.v);
8070Sstevel@tonic-gate 		return (1);
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	case T_CONDIF: {
8100Sstevel@tonic-gate 		struct node *retnp;
8110Sstevel@tonic-gate 		int dotrue = 0;
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 		/*
8140Sstevel@tonic-gate 		 * evaluate
8150Sstevel@tonic-gate 		 *	expression ? stmtA [ : stmtB ]
8160Sstevel@tonic-gate 		 *
8170Sstevel@tonic-gate 		 * first see if expression is true or false, then determine
8180Sstevel@tonic-gate 		 * if stmtA (or stmtB, if it exists) should be evaluated.
8190Sstevel@tonic-gate 		 *
8200Sstevel@tonic-gate 		 * "dotrue = 1" means stmtA should be evaluated.
8210Sstevel@tonic-gate 		 */
8220Sstevel@tonic-gate 		if (eval_expr(np->u.expr.left, ex, epnames, globals, croot,
8230Sstevel@tonic-gate 				arrowp, try, &lval) &&
8240Sstevel@tonic-gate 		    lval.t != UNDEFINED && lval.v != 0)
8250Sstevel@tonic-gate 			dotrue = 1;
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 		ASSERT(np->u.expr.right != NULL);
8280Sstevel@tonic-gate 		if (np->u.expr.right->t == T_CONDELSE) {
8290Sstevel@tonic-gate 			if (dotrue)
8300Sstevel@tonic-gate 				retnp = np->u.expr.right->u.expr.left;
8310Sstevel@tonic-gate 			else
8320Sstevel@tonic-gate 				retnp = np->u.expr.right->u.expr.right;
8330Sstevel@tonic-gate 		} else {
8340Sstevel@tonic-gate 			/* no ELSE clause */
8350Sstevel@tonic-gate 			if (dotrue)
8360Sstevel@tonic-gate 				retnp = np->u.expr.right;
8370Sstevel@tonic-gate 			else {
8380Sstevel@tonic-gate 				valuep->t = UINT64;
8390Sstevel@tonic-gate 				valuep->v = 0;
8400Sstevel@tonic-gate 				return (0);
8410Sstevel@tonic-gate 			}
8420Sstevel@tonic-gate 		}
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 		if (!eval_expr(retnp, ex, epnames, globals, croot,
8450Sstevel@tonic-gate 			    arrowp, try, valuep))
8460Sstevel@tonic-gate 			return (0);
8470Sstevel@tonic-gate 		return (1);
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	case T_CONDELSE:
8510Sstevel@tonic-gate 		/*
8520Sstevel@tonic-gate 		 * shouldn't get here, since T_CONDELSE is supposed to be
8530Sstevel@tonic-gate 		 * evaluated as part of T_CONDIF
8540Sstevel@tonic-gate 		 */
8550Sstevel@tonic-gate 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
8560Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
8570Sstevel@tonic-gate 		return (0);
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	case T_NE:
8600Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
8610Sstevel@tonic-gate 				arrowp, try, &lval))
8620Sstevel@tonic-gate 			return (0);
8630Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
8640Sstevel@tonic-gate 				arrowp, try, &rval))
8650Sstevel@tonic-gate 			return (0);
8660Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
8670Sstevel@tonic-gate 			return (0);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 		valuep->t = UINT64;
8700Sstevel@tonic-gate 		valuep->v = (lval.v != rval.v);
8710Sstevel@tonic-gate 		return (1);
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	case T_LIST:
8740Sstevel@tonic-gate 	case T_AND:
8750Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
8760Sstevel@tonic-gate 				arrowp, try, valuep))
8770Sstevel@tonic-gate 			return (0);
8780Sstevel@tonic-gate 		if (valuep->v == 0) {
8790Sstevel@tonic-gate 			valuep->t = UINT64;
8800Sstevel@tonic-gate 			return (1);
8810Sstevel@tonic-gate 		}
8820Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
8830Sstevel@tonic-gate 				arrowp, try, valuep))
8840Sstevel@tonic-gate 			return (0);
8850Sstevel@tonic-gate 		valuep->t = UINT64;
8860Sstevel@tonic-gate 		valuep->v = valuep->v == 0 ? 0 : 1;
8870Sstevel@tonic-gate 		return (1);
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	case T_OR:
8900Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
8910Sstevel@tonic-gate 				arrowp, try, valuep))
8920Sstevel@tonic-gate 			return (0);
8930Sstevel@tonic-gate 		if (valuep->v != 0) {
8940Sstevel@tonic-gate 			valuep->t = UINT64;
8950Sstevel@tonic-gate 			valuep->v = 1;
8960Sstevel@tonic-gate 			return (1);
8970Sstevel@tonic-gate 		}
8980Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
8990Sstevel@tonic-gate 				arrowp, try, valuep))
9000Sstevel@tonic-gate 			return (0);
9010Sstevel@tonic-gate 		valuep->t = UINT64;
9020Sstevel@tonic-gate 		valuep->v = valuep->v == 0 ? 0 : 1;
9030Sstevel@tonic-gate 		return (1);
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	case T_NOT:
9060Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9070Sstevel@tonic-gate 				arrowp, try, valuep))
9080Sstevel@tonic-gate 			return (0);
9090Sstevel@tonic-gate 		valuep->t = UINT64;
9100Sstevel@tonic-gate 		valuep->v = ! valuep->v;
9110Sstevel@tonic-gate 		return (1);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	case T_ADD:
9140Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9150Sstevel@tonic-gate 				arrowp, try, &lval))
9160Sstevel@tonic-gate 			return (0);
9170Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9180Sstevel@tonic-gate 				arrowp, try, &rval))
9190Sstevel@tonic-gate 			return (0);
9200Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
9210Sstevel@tonic-gate 			return (0);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 		valuep->t = lval.t;
9240Sstevel@tonic-gate 		valuep->v = lval.v + rval.v;
9250Sstevel@tonic-gate 		return (1);
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	case T_SUB:
9280Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9290Sstevel@tonic-gate 				arrowp, try, &lval))
9300Sstevel@tonic-gate 			return (0);
9310Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9320Sstevel@tonic-gate 				arrowp, try, &rval))
9330Sstevel@tonic-gate 			return (0);
9340Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
9350Sstevel@tonic-gate 			return (0);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 		/* since valuep is unsigned, return false if lval.v < rval.v */
9380Sstevel@tonic-gate 		if (lval.v < rval.v) {
9390Sstevel@tonic-gate 			out(O_ERR, "eval_expr: T_SUB result is out of range");
9400Sstevel@tonic-gate 			valuep->t = UNDEFINED;
9410Sstevel@tonic-gate 			return (0);
9420Sstevel@tonic-gate 		}
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 		valuep->t = lval.t;
9450Sstevel@tonic-gate 		valuep->v = lval.v - rval.v;
9460Sstevel@tonic-gate 		return (1);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	case T_MUL:
9490Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9500Sstevel@tonic-gate 				arrowp, try, &lval))
9510Sstevel@tonic-gate 			return (0);
9520Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9530Sstevel@tonic-gate 				arrowp, try, &rval))
9540Sstevel@tonic-gate 			return (0);
9550Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
9560Sstevel@tonic-gate 			return (0);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		valuep->t = lval.t;
9590Sstevel@tonic-gate 		valuep->v = lval.v * rval.v;
9600Sstevel@tonic-gate 		return (1);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	case T_DIV:
9630Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9640Sstevel@tonic-gate 				arrowp, try, &lval))
9650Sstevel@tonic-gate 			return (0);
9660Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9670Sstevel@tonic-gate 				arrowp, try, &rval))
9680Sstevel@tonic-gate 			return (0);
9690Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
9700Sstevel@tonic-gate 			return (0);
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 		/* return false if dividing by zero */
9730Sstevel@tonic-gate 		if (rval.v == 0) {
9740Sstevel@tonic-gate 			out(O_ERR, "eval_expr: T_DIV division by zero");
9750Sstevel@tonic-gate 			valuep->t = UNDEFINED;
9760Sstevel@tonic-gate 			return (0);
9770Sstevel@tonic-gate 		}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 		valuep->t = lval.t;
9800Sstevel@tonic-gate 		valuep->v = lval.v / rval.v;
9810Sstevel@tonic-gate 		return (1);
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	case T_MOD:
9840Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9850Sstevel@tonic-gate 				arrowp, try, &lval))
9860Sstevel@tonic-gate 			return (0);
9870Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9880Sstevel@tonic-gate 				arrowp, try, &rval))
9890Sstevel@tonic-gate 			return (0);
9900Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
9910Sstevel@tonic-gate 			return (0);
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 		/* return false if dividing by zero */
9940Sstevel@tonic-gate 		if (rval.v == 0) {
9950Sstevel@tonic-gate 			out(O_ERR, "eval_expr: T_MOD division by zero");
9960Sstevel@tonic-gate 			valuep->t = UNDEFINED;
9970Sstevel@tonic-gate 			return (0);
9980Sstevel@tonic-gate 		}
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 		valuep->t = lval.t;
10010Sstevel@tonic-gate 		valuep->v = lval.v % rval.v;
10020Sstevel@tonic-gate 		return (1);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	case T_NAME:
10050Sstevel@tonic-gate 		if (try) {
10060Sstevel@tonic-gate 			struct iterinfo *iterinfop;
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 			/*
10090Sstevel@tonic-gate 			 * at itree_create() time, we can expand simple
10100Sstevel@tonic-gate 			 * iterators.  anything else we'll punt on.
10110Sstevel@tonic-gate 			 */
10120Sstevel@tonic-gate 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
10130Sstevel@tonic-gate 			if (iterinfop != NULL) {
10140Sstevel@tonic-gate 				/* explicit iterator; not part of pathname */
10150Sstevel@tonic-gate 				valuep->t = UINT64;
10160Sstevel@tonic-gate 				valuep->v = (unsigned long long)iterinfop->num;
10170Sstevel@tonic-gate 				return (1);
10180Sstevel@tonic-gate 			}
10190Sstevel@tonic-gate 			return (0);
10200Sstevel@tonic-gate 		}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 		/* return address of struct node */
10230Sstevel@tonic-gate 		valuep->t = NODEPTR;
10240Sstevel@tonic-gate 		valuep->v = (unsigned long long)np;
10250Sstevel@tonic-gate 		return (1);
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	case T_QUOTE:
10280Sstevel@tonic-gate 		valuep->t = STRING;
10290Sstevel@tonic-gate 		valuep->v = (unsigned long long)np->u.quote.s;
10300Sstevel@tonic-gate 		return (1);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	case T_FUNC:
10330Sstevel@tonic-gate 		return (eval_func(np, ex, epnames, np->u.func.arglist,
10340Sstevel@tonic-gate 				globals, croot, arrowp, try, valuep));
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	case T_NUM:
10370Sstevel@tonic-gate 		valuep->t = UINT64;
10380Sstevel@tonic-gate 		valuep->v = np->u.ull;
10390Sstevel@tonic-gate 		return (1);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	default:
10420Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
10430Sstevel@tonic-gate 		    "eval_expr: unexpected node type: %s",
10440Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 	/*NOTREACHED*/
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate /*
10500Sstevel@tonic-gate  * eval_fru() and eval_asru() don't do much, but are called from a number
10510Sstevel@tonic-gate  * of places.
10520Sstevel@tonic-gate  */
10530Sstevel@tonic-gate struct node *
10540Sstevel@tonic-gate eval_fru(struct node *np)
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate 	ASSERT(np->t == T_NAME);
10570Sstevel@tonic-gate 	return (np);
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate struct node *
10610Sstevel@tonic-gate eval_asru(struct node *np)
10620Sstevel@tonic-gate {
10630Sstevel@tonic-gate 	ASSERT(np->t == T_NAME);
10640Sstevel@tonic-gate 	return (np);
10650Sstevel@tonic-gate }
1066