xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision 3159:2750b6a8d8c0)
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
51717Swesolows  * Common Development and Distribution License (the "License").
61717Swesolows  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211717Swesolows 
220Sstevel@tonic-gate /*
231414Scindi  * Copyright 2006 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"
451414Scindi #include "ipath.h"
460Sstevel@tonic-gate #include "eval.h"
470Sstevel@tonic-gate #include "config.h"
480Sstevel@tonic-gate #include "platform.h"
491414Scindi #include "fme.h"
501414Scindi #include "stats.h"
510Sstevel@tonic-gate 
520Sstevel@tonic-gate static struct node *eval_dup(struct node *np, struct lut *ex,
531414Scindi     struct node *epnames[]);
541414Scindi static int check_expr_args(struct evalue *lp, struct evalue *rp,
551414Scindi     enum datatype dtype, struct node *np);
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * begins_with -- return true if rhs path begins with everything in lhs path
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate static int
610Sstevel@tonic-gate begins_with(struct node *lhs, struct node *rhs)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	int lnum;
640Sstevel@tonic-gate 	int rnum;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	if (lhs == NULL)
670Sstevel@tonic-gate 		return (1);	/* yep -- it all matched */
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	if (rhs == NULL)
700Sstevel@tonic-gate 		return (0);	/* nope, ran out of rhs first */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str);
730Sstevel@tonic-gate 	ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str);
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	if (lhs->u.name.s != rhs->u.name.s)
760Sstevel@tonic-gate 		return (0);	/* nope, different component names */
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	if (lhs->u.name.child && lhs->u.name.child->t == T_NUM)
790Sstevel@tonic-gate 		lnum = (int)lhs->u.name.child->u.ull;
800Sstevel@tonic-gate 	else
810Sstevel@tonic-gate 		out(O_DIE, "begins_with: unexpected lhs child");
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	if (rhs->u.name.child && rhs->u.name.child->t == T_NUM)
840Sstevel@tonic-gate 		rnum = (int)rhs->u.name.child->u.ull;
850Sstevel@tonic-gate 	else
860Sstevel@tonic-gate 		out(O_DIE, "begins_with: unexpected rhs child");
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	if (lnum != rnum)
890Sstevel@tonic-gate 		return (0);	/* nope, instance numbers were different */
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	return (begins_with(lhs->u.name.next, rhs->u.name.next));
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * evaluate a variety of functions and place result in valuep.  return 1 if
960Sstevel@tonic-gate  * function evaluation was successful; 0 if otherwise (e.g., the case of an
970Sstevel@tonic-gate  * invalid argument to the function)
980Sstevel@tonic-gate  */
990Sstevel@tonic-gate /*ARGSUSED*/
1000Sstevel@tonic-gate static int
1010Sstevel@tonic-gate eval_func(struct node *funcnp, struct lut *ex, struct node *epnames[],
1020Sstevel@tonic-gate     struct node *np, struct lut **globals,
1030Sstevel@tonic-gate     struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate 	const char *funcname = funcnp->u.func.s;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	if (funcname == L_within) {
1080Sstevel@tonic-gate 		/* within()'s are not really constraints -- always true */
1090Sstevel@tonic-gate 		valuep->t = UINT64;
1100Sstevel@tonic-gate 		valuep->v = 1;
1110Sstevel@tonic-gate 		return (1);
1120Sstevel@tonic-gate 	} else if (funcname == L_is_under) {
1130Sstevel@tonic-gate 		struct node *lhs;
1140Sstevel@tonic-gate 		struct node *rhs;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 		if (np->u.expr.left->t == T_NAME)
1170Sstevel@tonic-gate 			lhs = np->u.expr.left;
1180Sstevel@tonic-gate 		else if (np->u.expr.left->u.func.s == L_fru)
1190Sstevel@tonic-gate 			lhs = eval_fru(np->u.expr.left->u.func.arglist);
1200Sstevel@tonic-gate 		else if (np->u.expr.left->u.func.s == L_asru)
1210Sstevel@tonic-gate 			lhs = eval_asru(np->u.expr.left->u.func.arglist);
1220Sstevel@tonic-gate 		else
1230Sstevel@tonic-gate 			out(O_DIE, "is_under: unexpected lhs type: %s",
1240Sstevel@tonic-gate 			    ptree_nodetype2str(np->u.expr.left->t));
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 		if (np->u.expr.right->t == T_NAME)
1270Sstevel@tonic-gate 			rhs = np->u.expr.right;
1280Sstevel@tonic-gate 		else if (np->u.expr.right->u.func.s == L_fru)
1290Sstevel@tonic-gate 			rhs = eval_fru(np->u.expr.right->u.func.arglist);
1300Sstevel@tonic-gate 		else if (np->u.expr.right->u.func.s == L_asru)
1310Sstevel@tonic-gate 			rhs = eval_asru(np->u.expr.right->u.func.arglist);
1320Sstevel@tonic-gate 		else
1330Sstevel@tonic-gate 			out(O_DIE, "is_under: unexpected rhs type: %s",
1340Sstevel@tonic-gate 			    ptree_nodetype2str(np->u.expr.right->t));
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 		/* eval_dup will expand wildcards, iterators, etc... */
1370Sstevel@tonic-gate 		lhs = eval_dup(lhs, ex, epnames);
1380Sstevel@tonic-gate 		rhs = eval_dup(rhs, ex, epnames);
1390Sstevel@tonic-gate 		valuep->t = UINT64;
1400Sstevel@tonic-gate 		valuep->v = begins_with(lhs, rhs);
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 		out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under(");
1430Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs);
1440Sstevel@tonic-gate 		out(O_ALTFP|O_VERB2|O_NONL, ",");
1450Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs);
1460Sstevel@tonic-gate 		out(O_ALTFP|O_VERB2, ") returned %d", (int)valuep->v);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 		tree_free(lhs);
1490Sstevel@tonic-gate 		tree_free(rhs);
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 		return (1);
1522869Sgavinm 	} else if (funcname == L_confprop || funcname == L_confprop_defined) {
1532318Sstephh 		struct config *cp;
1542318Sstephh 		struct node *lhs;
1552318Sstephh 		char *path;
1562318Sstephh 		const char *s;
1572318Sstephh 
1582318Sstephh 		if (np->u.expr.left->u.func.s == L_fru)
1592318Sstephh 			lhs = eval_fru(np->u.expr.left->u.func.arglist);
1602318Sstephh 		else if (np->u.expr.left->u.func.s == L_asru)
1612318Sstephh 			lhs = eval_asru(np->u.expr.left->u.func.arglist);
1622318Sstephh 		else
1632869Sgavinm 			out(O_DIE, "%s: unexpected lhs type: %s",
1642869Sgavinm 			    funcname, ptree_nodetype2str(np->u.expr.left->t));
1652318Sstephh 
1662318Sstephh 		/* for now s will point to a quote [see addconfigprop()] */
1672318Sstephh 		ASSERT(np->u.expr.right->t == T_QUOTE);
1682318Sstephh 
1692318Sstephh 		/* eval_dup will expand wildcards, iterators, etc... */
1702318Sstephh 		lhs = eval_dup(lhs, ex, epnames);
1712318Sstephh 		path = ipath2str(NULL, ipath(lhs));
1722318Sstephh 		cp = config_lookup(croot, path, 0);
1732318Sstephh 		tree_free(lhs);
1742869Sgavinm 		if (cp == NULL) {
1752869Sgavinm 			out(O_ALTFP|O_VERB3, "%s: path %s not found",
1762869Sgavinm 			    funcname, path);
1772869Sgavinm 			FREE((void *)path);
1782869Sgavinm 			if (funcname == L_confprop_defined) {
1792869Sgavinm 				valuep->v = 0;
1802869Sgavinm 				valuep->t = UINT64;
1812869Sgavinm 				return (1);
1822869Sgavinm 			} else {
1832869Sgavinm 				return (0);
1842869Sgavinm 			}
1852869Sgavinm 		}
1862318Sstephh 		s = config_getprop(cp, np->u.expr.right->u.quote.s);
1872869Sgavinm 		if (s == NULL) {
1882869Sgavinm 			out(O_ALTFP|O_VERB3, "%s: \"%s\" not found for path %s",
1892869Sgavinm 			    funcname, np->u.expr.right->u.quote.s, path);
1902869Sgavinm 			FREE((void *)path);
1912869Sgavinm 			if (funcname == L_confprop_defined) {
1922869Sgavinm 				valuep->v = 0;
1932869Sgavinm 				valuep->t = UINT64;
1942869Sgavinm 				return (1);
1952869Sgavinm 			} else {
1962869Sgavinm 				return (0);
1972869Sgavinm 			}
1982869Sgavinm 		}
1992869Sgavinm 
2002869Sgavinm 		if (funcname == L_confprop) {
2012869Sgavinm 			valuep->v = (uintptr_t)stable(s);
2022869Sgavinm 			valuep->t = STRING;
2032869Sgavinm 			out(O_ALTFP|O_VERB3, "%s(\"%s\", \"%s\") = \"%s\"",
2042869Sgavinm 			    funcname, path, np->u.expr.right->u.quote.s,
2052869Sgavinm 			    (char *)(uintptr_t)valuep->v);
2062869Sgavinm 		} else {
2072869Sgavinm 			valuep->v = 1;
2082869Sgavinm 			valuep->t = UINT64;
2092869Sgavinm 		}
2102869Sgavinm 		FREE((void *)path);
2112318Sstephh 		return (1);
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	if (try)
2150Sstevel@tonic-gate 		return (0);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	if (funcname == L_fru) {
2180Sstevel@tonic-gate 		valuep->t = NODEPTR;
2191717Swesolows 		valuep->v = (uintptr_t)eval_fru(np);
2200Sstevel@tonic-gate 		return (1);
2210Sstevel@tonic-gate 	} else if (funcname == L_asru) {
2220Sstevel@tonic-gate 		valuep->t = NODEPTR;
2231717Swesolows 		valuep->v = (uintptr_t)eval_asru(np);
2240Sstevel@tonic-gate 		return (1);
2251414Scindi 	} else if (funcname == L_defined) {
2261414Scindi 		ASSERTeq(np->t, T_GLOBID, ptree_nodetype2str);
2271414Scindi 		valuep->t = UINT64;
2281414Scindi 		valuep->v = (lut_lookup(*globals,
2291414Scindi 		    (void *)np->u.globid.s, NULL) != NULL);
2301414Scindi 		return (1);
2310Sstevel@tonic-gate 	} else if (funcname == L_call) {
2320Sstevel@tonic-gate 		return (! platform_call(np, globals, croot, arrowp, valuep));
2330Sstevel@tonic-gate 	} else if (funcname == L_is_connected) {
2340Sstevel@tonic-gate 		return (! config_is_connected(np, croot, valuep));
2350Sstevel@tonic-gate 	} else if (funcname == L_is_on) {
2360Sstevel@tonic-gate 		return (! config_is_on(np, croot, valuep));
2370Sstevel@tonic-gate 	} else if (funcname == L_is_present) {
2380Sstevel@tonic-gate 		return (! config_is_present(np, croot, valuep));
2390Sstevel@tonic-gate 	} else if (funcname == L_is_type) {
2400Sstevel@tonic-gate 		return (! config_is_type(np, croot, valuep));
2410Sstevel@tonic-gate 	} else if (funcname == L_envprop) {
2420Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
2430Sstevel@tonic-gate 		    "eval_func: %s not yet supported", funcname);
2440Sstevel@tonic-gate 	} else if (funcname == L_payloadprop) {
2451414Scindi 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
2460Sstevel@tonic-gate 		    "payloadprop(\"%s\") ", np->u.quote.s);
247186Sdb35262 
2481414Scindi 		if (platform_payloadprop(np, valuep)) {
2491414Scindi 			/* platform_payloadprop() returned false */
2502869Sgavinm 			out(O_ALTFP|O_VERB, "payloadprop \"%s\" not found.",
2512869Sgavinm 			    np->u.quote.s);
2521414Scindi 			return (0);
2531414Scindi 		} else {
254186Sdb35262 			switch (valuep->t) {
255186Sdb35262 			case UINT64:
256186Sdb35262 			case NODEPTR:
2571414Scindi 				out(O_ALTFP|O_VERB2, "found: %llu", valuep->v);
258186Sdb35262 				break;
259186Sdb35262 			case STRING:
2601414Scindi 				out(O_ALTFP|O_VERB2, "found: \"%s\"",
2611717Swesolows 				    (char *)(uintptr_t)valuep->v);
262186Sdb35262 				break;
263186Sdb35262 			default:
2641414Scindi 				out(O_ALTFP|O_VERB2, "found: undefined");
265186Sdb35262 				break;
266186Sdb35262 			}
2671414Scindi 			return (1);
2681414Scindi 		}
2691414Scindi 	} else if (funcname == L_setpayloadprop) {
2701414Scindi 		struct evalue *payloadvalp;
2711414Scindi 
2721414Scindi 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
2731414Scindi 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
2741414Scindi 		    ptree_nodetype2str(np->u.expr.left->t));
2751414Scindi 
2761414Scindi 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
2771414Scindi 		    "setpayloadprop: %s: %s=",
2781414Scindi 		    arrowp->tail->myevent->enode->u.event.ename->u.name.s,
2791414Scindi 		    np->u.expr.left->u.quote.s);
2801414Scindi 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
2811414Scindi 
2821414Scindi 		/*
2831414Scindi 		 * allocate a struct evalue to hold the payload property's
2841414Scindi 		 * value, unless we've been here already, in which case we
2851414Scindi 		 * might calculate a different value, but we'll store it
2861414Scindi 		 * in the already-allocated struct evalue.
2871414Scindi 		 */
2881414Scindi 		if ((payloadvalp = (struct evalue *)lut_lookup(
2891414Scindi 		    arrowp->tail->myevent->payloadprops,
2901414Scindi 		    (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) {
2911414Scindi 			payloadvalp = MALLOC(sizeof (*payloadvalp));
2921414Scindi 		}
2931414Scindi 
2941414Scindi 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
2951414Scindi 		    arrowp, try, payloadvalp)) {
2961414Scindi 			out(O_ALTFP|O_VERB2, " (cannot eval, using zero)");
2971414Scindi 			payloadvalp->t = UINT64;
2981414Scindi 			payloadvalp->v = 0;
2991414Scindi 		} else {
3001414Scindi 			if (payloadvalp->t == UINT64)
3011414Scindi 				out(O_ALTFP|O_VERB2,
3021414Scindi 				    " (%llu)", payloadvalp->v);
3031414Scindi 			else
3041717Swesolows 				out(O_ALTFP|O_VERB2, " (\"%s\")",
3051717Swesolows 				    (char *)(uintptr_t)payloadvalp->v);
3061414Scindi 		}
3071414Scindi 
3081414Scindi 		/* add to table of payload properties for current problem */
3091414Scindi 		arrowp->tail->myevent->payloadprops =
3101414Scindi 		    lut_add(arrowp->tail->myevent->payloadprops,
3111414Scindi 		    (void *)np->u.expr.left->u.quote.s,
3121414Scindi 		    (void *)payloadvalp, NULL);
3131414Scindi 
3141414Scindi 		/* function is always true */
3151414Scindi 		valuep->t = UINT64;
3161414Scindi 		valuep->v = 1;
3171414Scindi 		return (1);
3181414Scindi 	} else if (funcname == L_payloadprop_defined) {
3191414Scindi 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
3201414Scindi 		    "payloadprop_defined(\"%s\") ", np->u.quote.s);
3211414Scindi 
3221414Scindi 		if (platform_payloadprop(np, NULL)) {
3231414Scindi 			/* platform_payloadprop() returned false */
3241414Scindi 			valuep->v = 0;
3252869Sgavinm 			out(O_ALTFP|O_VERB2, "payloadprop_defined: \"%s\" "
3262869Sgavinm 			    "not defined.", np->u.quote.s);
3271414Scindi 		} else {
3281414Scindi 			valuep->v = 1;
3291414Scindi 			out(O_ALTFP|O_VERB2, "found.");
3301414Scindi 		}
3311414Scindi 		valuep->t = UINT64;
3321414Scindi 		return (1);
3331414Scindi 	} else if (funcname == L_payloadprop_contains) {
3341414Scindi 		int nvals;
3351414Scindi 		struct evalue *vals;
3361414Scindi 		struct evalue cmpval;
3371414Scindi 
3381414Scindi 		ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t));
3391414Scindi 		ASSERTinfo(np->u.expr.left->t == T_QUOTE,
3401414Scindi 		    ptree_nodetype2str(np->u.expr.left->t));
3411414Scindi 
3421414Scindi 		outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line,
3431414Scindi 		    "payloadprop_contains(\"%s\", ",
3441414Scindi 		    np->u.expr.left->u.quote.s);
3451414Scindi 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right);
3462869Sgavinm 		out(O_ALTFP|O_VERB2|O_NONL, ") ");
3471414Scindi 
3481414Scindi 		/* evaluate the expression we're comparing against */
3491414Scindi 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
3501414Scindi 		    arrowp, try, &cmpval)) {
3511414Scindi 			out(O_ALTFP|O_VERB2|O_NONL,
3521414Scindi 			    "(cannot eval, using zero) ");
3531414Scindi 			cmpval.t = UINT64;
3541414Scindi 			cmpval.v = 0;
3551414Scindi 		} else {
3562869Sgavinm 			switch (cmpval.t) {
3572869Sgavinm 			case UNDEFINED:
3582869Sgavinm 				out(O_ALTFP|O_VERB2, "(undefined type)");
3592869Sgavinm 				break;
3602869Sgavinm 
3612869Sgavinm 			case UINT64:
3621414Scindi 				out(O_ALTFP|O_VERB2,
3631414Scindi 				    "(%llu) ", cmpval.v);
3642869Sgavinm 				break;
3652869Sgavinm 
3662869Sgavinm 			case STRING:
3671414Scindi 				out(O_ALTFP|O_VERB2,
3681717Swesolows 				    "(\"%s\") ", (char *)(uintptr_t)cmpval.v);
3692869Sgavinm 				break;
3702869Sgavinm 
3712869Sgavinm 			case NODEPTR:
3722869Sgavinm 				out(O_ALTFP|O_VERB2|O_NONL, "(");
3732869Sgavinm 				ptree_name_iter(O_ALTFP|O_VERB2|O_NONL,
3742869Sgavinm 				    (struct node *)(uintptr_t)(cmpval.v));
3752869Sgavinm 				out(O_ALTFP|O_VERB2, ") ");
3762869Sgavinm 				break;
3772869Sgavinm 			}
3781414Scindi 		}
3791414Scindi 
3801414Scindi 		/* get the payload values and check for a match */
3811414Scindi 		vals = platform_payloadprop_values(np->u.expr.left->u.quote.s,
3821414Scindi 		    &nvals);
3831414Scindi 		valuep->t = UINT64;
3841414Scindi 		valuep->v = 0;
3851414Scindi 		if (nvals == 0) {
3861414Scindi 			out(O_ALTFP|O_VERB2, "not found.");
3871414Scindi 		} else {
3881414Scindi 			struct evalue preval;
3891414Scindi 			int i;
3901414Scindi 
3911414Scindi 			out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals);
3921414Scindi 
3931414Scindi 			for (i = 0; i < nvals; i++) {
3941414Scindi 
3951414Scindi 				preval.t = vals[i].t;
3961414Scindi 				preval.v = vals[i].v;
3971414Scindi 
3981414Scindi 				if (check_expr_args(&vals[i], &cmpval,
3991414Scindi 				    UNDEFINED, np))
4001414Scindi 					continue;
4011414Scindi 
4021414Scindi 				/*
4031414Scindi 				 * If we auto-converted the value to a
4041414Scindi 				 * string, we need to free the
4051414Scindi 				 * original tree value.
4061414Scindi 				 */
4071414Scindi 				if (preval.t == NODEPTR &&
4081717Swesolows 				    ((struct node *)(uintptr_t)(preval.v))->t ==
4091717Swesolows 				    T_NAME) {
4101717Swesolows 					tree_free((struct node *)(uintptr_t)
4111717Swesolows 					    preval.v);
4121414Scindi 				}
4131414Scindi 
4141414Scindi 				if (vals[i].v == cmpval.v) {
4151414Scindi 					valuep->v = 1;
4161414Scindi 					break;
4171414Scindi 				}
4181414Scindi 			}
419186Sdb35262 
4201414Scindi 			if (valuep->v)
4211414Scindi 				out(O_ALTFP|O_VERB2, "match.");
4221414Scindi 			else
4231414Scindi 				out(O_ALTFP|O_VERB2, "no match.");
424186Sdb35262 
4251414Scindi 			for (i = 0; i < nvals; i++) {
4261414Scindi 				if (vals[i].t == NODEPTR) {
4271717Swesolows 					tree_free((struct node *)(uintptr_t)
4281717Swesolows 					    vals[i].v);
4291414Scindi 					break;
4301414Scindi 				}
431186Sdb35262 			}
4321414Scindi 			FREE(vals);
4331414Scindi 		}
4341414Scindi 		return (1);
4351414Scindi 	} else if (funcname == L_confcall) {
4361414Scindi 		return (!platform_confcall(np, globals, croot, arrowp, valuep));
4371414Scindi 	} else if (funcname == L_count) {
4381414Scindi 		struct stats *statp;
4391423Sgavinm 		struct istat_entry ent;
440186Sdb35262 
4411414Scindi 		ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
4421414Scindi 
4431423Sgavinm 		ent.ename = np->u.event.ename->u.name.s;
4441423Sgavinm 		ent.ipath = ipath(np->u.event.epname);
4451423Sgavinm 
4461414Scindi 		valuep->t = UINT64;
4471414Scindi 		if ((statp = (struct stats *)
4481423Sgavinm 		    lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL)
4491414Scindi 			valuep->v = 0;
4501414Scindi 		else
4511414Scindi 			valuep->v = stats_counter_value(statp);
4521414Scindi 
4531414Scindi 		return (1);
4540Sstevel@tonic-gate 	} else
4550Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
4560Sstevel@tonic-gate 		    "eval_func: unexpected func: %s", funcname);
4570Sstevel@tonic-gate 	/*NOTREACHED*/
4581717Swesolows 	return (0);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate static struct node *
4620Sstevel@tonic-gate eval_wildcardedname(struct node *np, struct lut *ex, struct node *epnames[])
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate 	struct node *npstart, *npend, *npref, *newnp;
4650Sstevel@tonic-gate 	struct node *np1, *np2, *retp;
4660Sstevel@tonic-gate 	int i;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	if (epnames == NULL || epnames[0] == NULL)
4690Sstevel@tonic-gate 		return (NULL);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	for (i = 0; epnames[i] != NULL; i++) {
4720Sstevel@tonic-gate 		if (tree_namecmp(np, epnames[i]) == 0)
4730Sstevel@tonic-gate 			return (NULL);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	/*
4770Sstevel@tonic-gate 	 * get to this point if np does not match any of the entries in
4780Sstevel@tonic-gate 	 * epnames.  check if np is a path that must preceded by a wildcard
4790Sstevel@tonic-gate 	 * portion.  for this case we must first determine which epnames[]
4800Sstevel@tonic-gate 	 * entry should be used for wildcarding.
4810Sstevel@tonic-gate 	 */
4820Sstevel@tonic-gate 	npstart = NULL;
4830Sstevel@tonic-gate 	for (i = 0; epnames[i] != NULL; i++) {
4840Sstevel@tonic-gate 		for (npref = epnames[i]; npref; npref = npref->u.name.next) {
4850Sstevel@tonic-gate 			if (npref->u.name.s == np->u.name.s) {
4860Sstevel@tonic-gate 				for (np1 = npref, np2 = np;
4870Sstevel@tonic-gate 				    np1 != NULL && np2 != NULL;
4880Sstevel@tonic-gate 				    np1 = np1->u.name.next,
4890Sstevel@tonic-gate 					    np2 = np2->u.name.next) {
4900Sstevel@tonic-gate 					if (np1->u.name.s != np2->u.name.s)
4910Sstevel@tonic-gate 						break;
4920Sstevel@tonic-gate 				}
4930Sstevel@tonic-gate 				if (np2 == NULL) {
4940Sstevel@tonic-gate 					npstart = epnames[i];
4950Sstevel@tonic-gate 					npend = npref;
4960Sstevel@tonic-gate 					if (np1 == NULL)
4970Sstevel@tonic-gate 						break;
4980Sstevel@tonic-gate 				}
4990Sstevel@tonic-gate 			}
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 		if (npstart != NULL)
5030Sstevel@tonic-gate 			break;
5040Sstevel@tonic-gate 	}
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	if (npstart == NULL) {
5070Sstevel@tonic-gate 		/* no match; np is not a path to be wildcarded */
5080Sstevel@tonic-gate 		return (NULL);
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	/*
5120Sstevel@tonic-gate 	 * dup (npstart -- npend) which is the wildcarded portion.  all
5130Sstevel@tonic-gate 	 * children should be T_NUMs.
5140Sstevel@tonic-gate 	 */
5150Sstevel@tonic-gate 	retp = NULL;
5160Sstevel@tonic-gate 	for (npref = npstart;
5170Sstevel@tonic-gate 	    ! (npref == NULL || npref == npend);
5180Sstevel@tonic-gate 	    npref = npref->u.name.next) {
5190Sstevel@tonic-gate 		newnp = newnode(T_NAME, np->file, np->line);
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 		newnp->u.name.t = npref->u.name.t;
5220Sstevel@tonic-gate 		newnp->u.name.s = npref->u.name.s;
5230Sstevel@tonic-gate 		newnp->u.name.last = newnp;
5240Sstevel@tonic-gate 		newnp->u.name.it = npref->u.name.it;
5250Sstevel@tonic-gate 		newnp->u.name.cp = npref->u.name.cp;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 		ASSERT(npref->u.name.child != NULL);
5280Sstevel@tonic-gate 		ASSERT(npref->u.name.child->t == T_NUM);
5290Sstevel@tonic-gate 		newnp->u.name.child = newnode(T_NUM, np->file, np->line);
5300Sstevel@tonic-gate 		newnp->u.name.child->u.ull = npref->u.name.child->u.ull;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 		if (retp == NULL) {
5330Sstevel@tonic-gate 			retp = newnp;
5340Sstevel@tonic-gate 		} else {
5350Sstevel@tonic-gate 			retp->u.name.last->u.name.next = newnp;
5360Sstevel@tonic-gate 			retp->u.name.last = newnp;
5370Sstevel@tonic-gate 		}
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	ASSERT(retp != NULL);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	/* now append the nonwildcarded portion */
5430Sstevel@tonic-gate 	retp = tree_name_append(retp, eval_dup(np, ex, NULL));
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	return (retp);
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate static struct node *
5490Sstevel@tonic-gate eval_dup(struct node *np, struct lut *ex, struct node *epnames[])
5500Sstevel@tonic-gate {
5510Sstevel@tonic-gate 	struct node *newnp;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	if (np == NULL)
5540Sstevel@tonic-gate 		return (NULL);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	switch (np->t) {
5570Sstevel@tonic-gate 	case T_GLOBID:
5580Sstevel@tonic-gate 		return (tree_globid(np->u.globid.s, np->file, np->line));
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	case T_ASSIGN:
5610Sstevel@tonic-gate 	case T_CONDIF:
5620Sstevel@tonic-gate 	case T_CONDELSE:
5630Sstevel@tonic-gate 	case T_NE:
5640Sstevel@tonic-gate 	case T_EQ:
5650Sstevel@tonic-gate 	case T_LT:
5660Sstevel@tonic-gate 	case T_LE:
5670Sstevel@tonic-gate 	case T_GT:
5680Sstevel@tonic-gate 	case T_GE:
5690Sstevel@tonic-gate 	case T_BITAND:
5700Sstevel@tonic-gate 	case T_BITOR:
5710Sstevel@tonic-gate 	case T_BITXOR:
5720Sstevel@tonic-gate 	case T_BITNOT:
5730Sstevel@tonic-gate 	case T_LSHIFT:
5740Sstevel@tonic-gate 	case T_RSHIFT:
5750Sstevel@tonic-gate 	case T_LIST:
5760Sstevel@tonic-gate 	case T_AND:
5770Sstevel@tonic-gate 	case T_OR:
5780Sstevel@tonic-gate 	case T_NOT:
5790Sstevel@tonic-gate 	case T_ADD:
5800Sstevel@tonic-gate 	case T_SUB:
5810Sstevel@tonic-gate 	case T_MUL:
5820Sstevel@tonic-gate 	case T_DIV:
5830Sstevel@tonic-gate 	case T_MOD:
5840Sstevel@tonic-gate 		return (tree_expr(np->t,
5850Sstevel@tonic-gate 				    eval_dup(np->u.expr.left, ex, epnames),
5860Sstevel@tonic-gate 				    eval_dup(np->u.expr.right, ex, epnames)));
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	case T_NAME: {
5890Sstevel@tonic-gate 		struct iterinfo *iterinfop;
5900Sstevel@tonic-gate 		struct node *newchild = NULL;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 		iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
5930Sstevel@tonic-gate 		if (iterinfop != NULL) {
5940Sstevel@tonic-gate 			/* explicit iterator; not part of pathname */
5950Sstevel@tonic-gate 			newnp = newnode(T_NUM, np->file, np->line);
5960Sstevel@tonic-gate 			newnp->u.ull = iterinfop->num;
5970Sstevel@tonic-gate 			return (newnp);
5980Sstevel@tonic-gate 		}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 		/* see if np is a path with wildcard portion */
6010Sstevel@tonic-gate 		newnp = eval_wildcardedname(np, ex, epnames);
6020Sstevel@tonic-gate 		if (newnp != NULL)
6030Sstevel@tonic-gate 			return (newnp);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 		/* turn off wildcarding for child */
6060Sstevel@tonic-gate 		newchild = eval_dup(np->u.name.child, ex, NULL);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 		if (newchild != NULL) {
6090Sstevel@tonic-gate 			if (newchild->t != T_NUM) {
6100Sstevel@tonic-gate 				/*
6110Sstevel@tonic-gate 				 * not a number, eh?  we must resolve this
6120Sstevel@tonic-gate 				 * to a number.
6130Sstevel@tonic-gate 				 */
6140Sstevel@tonic-gate 				struct evalue value;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 				if (eval_expr(newchild, ex, epnames,
6170Sstevel@tonic-gate 				    NULL, NULL, NULL, 1, &value) == 0 ||
6180Sstevel@tonic-gate 				    value.t != UINT64) {
6190Sstevel@tonic-gate 					outfl(O_DIE, np->file, np->line,
6200Sstevel@tonic-gate 					    "eval_dup: could not resolve "
6210Sstevel@tonic-gate 					    "iterator of %s", np->u.name.s);
6220Sstevel@tonic-gate 				}
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 				tree_free(newchild);
6250Sstevel@tonic-gate 				newchild = newnode(T_NUM, np->file, np->line);
6260Sstevel@tonic-gate 				newchild->u.ull = value.v;
6270Sstevel@tonic-gate 			}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 			newnp = newnode(np->t, np->file, np->line);
6300Sstevel@tonic-gate 			newnp->u.name.s = np->u.name.s;
6310Sstevel@tonic-gate 			newnp->u.name.it = np->u.name.it;
6320Sstevel@tonic-gate 			newnp->u.name.cp = np->u.name.cp;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 			newnp->u.name.last = newnp;
6350Sstevel@tonic-gate 			newnp->u.name.child = newchild;
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 			if (np->u.name.next != NULL) {
6380Sstevel@tonic-gate 				/* turn off wildcarding for next */
6390Sstevel@tonic-gate 				return (tree_name_append(newnp,
6400Sstevel@tonic-gate 					eval_dup(np->u.name.next, ex, NULL)));
6410Sstevel@tonic-gate 			} else {
6420Sstevel@tonic-gate 				return (newnp);
6430Sstevel@tonic-gate 			}
6440Sstevel@tonic-gate 		} else {
6450Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
6460Sstevel@tonic-gate 			    "eval_dup: internal error: \"%s\" is neither "
6470Sstevel@tonic-gate 			    "an iterator nor a pathname", np->u.name.s);
6480Sstevel@tonic-gate 		}
6490Sstevel@tonic-gate 		/*NOTREACHED*/
6500Sstevel@tonic-gate 		break;
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 
6531414Scindi 	case T_EVENT:
6541414Scindi 		newnp = newnode(T_NAME, np->file, np->line);
6551414Scindi 
6561414Scindi 		newnp->u.name.t = np->u.event.ename->u.name.t;
6571414Scindi 		newnp->u.name.s = np->u.event.ename->u.name.s;
6581414Scindi 		newnp->u.name.it = np->u.event.ename->u.name.it;
6591414Scindi 		newnp->u.name.last = newnp;
6601414Scindi 
6611414Scindi 		return (tree_event(newnp,
6621414Scindi 		    eval_dup(np->u.event.epname, ex, epnames),
6631414Scindi 		    eval_dup(np->u.event.eexprlist, ex, epnames)));
6641414Scindi 
6650Sstevel@tonic-gate 	case T_FUNC:
6660Sstevel@tonic-gate 		return (tree_func(np->u.func.s,
6670Sstevel@tonic-gate 		    eval_dup(np->u.func.arglist, ex, epnames),
6680Sstevel@tonic-gate 		    np->file, np->line));
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	case T_QUOTE:
6710Sstevel@tonic-gate 		newnp = newnode(T_QUOTE, np->file, np->line);
6720Sstevel@tonic-gate 		newnp->u.quote.s = np->u.quote.s;
6730Sstevel@tonic-gate 		return (newnp);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	case T_NUM:
6760Sstevel@tonic-gate 		newnp = newnode(T_NUM, np->file, np->line);
6770Sstevel@tonic-gate 		newnp->u.ull = np->u.ull;
6780Sstevel@tonic-gate 		return (newnp);
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	default:
6810Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6820Sstevel@tonic-gate 		    "eval_dup: unexpected node type: %s",
6830Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 	/*NOTREACHED*/
6861717Swesolows 	return (0);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate /*
6900Sstevel@tonic-gate  * eval_potential -- see if constraint is potentially true
6910Sstevel@tonic-gate  *
6920Sstevel@tonic-gate  * this function is used at instance tree creation time to see if
6930Sstevel@tonic-gate  * any constraints are already known to be false.  if this function
6940Sstevel@tonic-gate  * returns false, then the constraint will always be false and there's
6950Sstevel@tonic-gate  * no need to include the propagation arrow in the instance tree.
6960Sstevel@tonic-gate  *
6970Sstevel@tonic-gate  * if this routine returns true, either the constraint is known to
6980Sstevel@tonic-gate  * be always true (so there's no point in attaching the constraint
6990Sstevel@tonic-gate  * to the propagation arrow in the instance tree), or the constraint
7000Sstevel@tonic-gate  * contains "deferred" expressions like global variables or poller calls
7010Sstevel@tonic-gate  * and so it must be evaluated during calls to fme_eval().  in this last
7020Sstevel@tonic-gate  * case, where a constraint needs to be attached to the propagation arrow
7030Sstevel@tonic-gate  * in the instance tree, this routine returns a newly created constraint
7040Sstevel@tonic-gate  * in *newc where all the non-deferred things have been filled in.
7050Sstevel@tonic-gate  *
7060Sstevel@tonic-gate  * so in summary:
7070Sstevel@tonic-gate  *
7080Sstevel@tonic-gate  *	return of false: constraint can never be true, *newc will be NULL.
7090Sstevel@tonic-gate  *
7100Sstevel@tonic-gate  *	return of true with *newc unchanged: constraint will always be true.
7110Sstevel@tonic-gate  *
7120Sstevel@tonic-gate  *	return of true with *newc changed: use new constraint in *newc.
7130Sstevel@tonic-gate  *
7140Sstevel@tonic-gate  * the lookup table for all explicit iterators, ex, is passed in.
7150Sstevel@tonic-gate  *
7160Sstevel@tonic-gate  * *newc can either be NULL on entry, or if can contain constraints from
7170Sstevel@tonic-gate  * previous calls to eval_potential() (i.e. for building up an instance
7180Sstevel@tonic-gate  * tree constraint from several potential constraints).  if *newc already
7190Sstevel@tonic-gate  * contains constraints, anything added to it will be joined by adding
7200Sstevel@tonic-gate  * a T_AND node at the top of *newc.
7210Sstevel@tonic-gate  */
7220Sstevel@tonic-gate int
7230Sstevel@tonic-gate eval_potential(struct node *np, struct lut *ex, struct node *epnames[],
7242318Sstephh 	    struct node **newc, struct config *croot)
7250Sstevel@tonic-gate {
7260Sstevel@tonic-gate 	struct node *newnp;
7270Sstevel@tonic-gate 	struct evalue value;
7280Sstevel@tonic-gate 
7292318Sstephh 	if (eval_expr(np, ex, epnames, NULL, croot, NULL, 1, &value) == 0) {
7300Sstevel@tonic-gate 		/*
7310Sstevel@tonic-gate 		 * couldn't eval expression because
7320Sstevel@tonic-gate 		 * it contains deferred items.  make
7330Sstevel@tonic-gate 		 * a duplicate expression with all the
7340Sstevel@tonic-gate 		 * non-deferred items expanded.
7350Sstevel@tonic-gate 		 */
7360Sstevel@tonic-gate 		newnp = eval_dup(np, ex, epnames);
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 		if (*newc == NULL) {
7390Sstevel@tonic-gate 			/*
7400Sstevel@tonic-gate 			 * constraint is potentially true if deferred
7410Sstevel@tonic-gate 			 * expression in newnp is true.  *newc was NULL
7420Sstevel@tonic-gate 			 * so new constraint is just the one in newnp.
7430Sstevel@tonic-gate 			 */
7440Sstevel@tonic-gate 			*newc = newnp;
7450Sstevel@tonic-gate 			return (1);
7460Sstevel@tonic-gate 		} else {
7470Sstevel@tonic-gate 			/*
7480Sstevel@tonic-gate 			 * constraint is potentially true if deferred
7490Sstevel@tonic-gate 			 * expression in newnp is true.  *newc already
7500Sstevel@tonic-gate 			 * contained a constraint so add an AND with the
7510Sstevel@tonic-gate 			 * constraint in newnp.
7520Sstevel@tonic-gate 			 */
7530Sstevel@tonic-gate 			*newc = tree_expr(T_AND, *newc, newnp);
7540Sstevel@tonic-gate 			return (1);
7550Sstevel@tonic-gate 		}
7560Sstevel@tonic-gate 	} else if (value.t == UNDEFINED) {
7570Sstevel@tonic-gate 		/* constraint can never be true */
7580Sstevel@tonic-gate 		return (0);
7590Sstevel@tonic-gate 	} else if (value.t == UINT64 && value.v == 0) {
7600Sstevel@tonic-gate 		/* constraint can never be true */
7610Sstevel@tonic-gate 		return (0);
7620Sstevel@tonic-gate 	} else {
7630Sstevel@tonic-gate 		/* constraint is always true (nothing deferred to eval) */
7640Sstevel@tonic-gate 		return (1);
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate static int
7690Sstevel@tonic-gate check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
7700Sstevel@tonic-gate 		struct node *np)
7710Sstevel@tonic-gate {
7721414Scindi 	/* auto-convert T_NAMES to strings */
7731717Swesolows 	if (lp->t == NODEPTR && ((struct node *)(uintptr_t)(lp->v))->t ==
7741717Swesolows 	    T_NAME) {
7751717Swesolows 		char *s = ipath2str(NULL,
7761717Swesolows 		    ipath((struct node *)(uintptr_t)lp->v));
7771414Scindi 		lp->t = STRING;
7781717Swesolows 		lp->v = (uintptr_t)stable(s);
7791414Scindi 		FREE(s);
7801414Scindi 		out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"",
7811717Swesolows 		    (char *)(uintptr_t)lp->v);
7821414Scindi 	}
7831414Scindi 	if (rp != NULL &&
7841717Swesolows 	    rp->t == NODEPTR && ((struct node *)(uintptr_t)(rp->v))->t ==
7851717Swesolows 	    T_NAME) {
7861717Swesolows 		char *s = ipath2str(NULL,
7871717Swesolows 		    ipath((struct node *)(uintptr_t)rp->v));
7881414Scindi 		rp->t = STRING;
7891717Swesolows 		rp->v = (uintptr_t)stable(s);
7901414Scindi 		FREE(s);
7911414Scindi 		out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"",
7921717Swesolows 		    (char *)(uintptr_t)rp->v);
7931414Scindi 	}
7941414Scindi 
7951414Scindi 	/* auto-convert strings to numbers */
7961414Scindi 	if (dtype == UINT64) {
7971414Scindi 		if (lp->t == STRING) {
7981414Scindi 			lp->t = UINT64;
7991717Swesolows 			lp->v = strtoull((char *)(uintptr_t)lp->v, NULL, 0);
8001414Scindi 		}
8011414Scindi 		if (rp != NULL && rp->t == STRING) {
8021414Scindi 			rp->t = UINT64;
8031717Swesolows 			rp->v = strtoull((char *)(uintptr_t)rp->v, NULL, 0);
8041414Scindi 		}
8051414Scindi 	}
8061414Scindi 
8070Sstevel@tonic-gate 	if (dtype != UNDEFINED && lp->t != dtype) {
8080Sstevel@tonic-gate 		outfl(O_OK, np->file, np->line,
8090Sstevel@tonic-gate 			"invalid datatype of argument for operation %s",
8100Sstevel@tonic-gate 			ptree_nodetype2str(np->t));
8110Sstevel@tonic-gate 		return (1);
8120Sstevel@tonic-gate 	}
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (rp != NULL && lp->t != rp->t) {
8150Sstevel@tonic-gate 		outfl(O_OK, np->file, np->line,
8160Sstevel@tonic-gate 			"mismatch in datatype of arguments for operation %s",
8170Sstevel@tonic-gate 			ptree_nodetype2str(np->t));
8180Sstevel@tonic-gate 		return (1);
8190Sstevel@tonic-gate 	}
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	return (0);
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate /*
8250Sstevel@tonic-gate  * eval_expr -- evaluate expression into *valuep
8260Sstevel@tonic-gate  *
8270Sstevel@tonic-gate  * the meaning of the return value depends on the input value of try.
8280Sstevel@tonic-gate  *
8290Sstevel@tonic-gate  * for try == 1: if any deferred items are encounted, bail out and return
8300Sstevel@tonic-gate  * false.  returns true if we made it through entire expression without
8310Sstevel@tonic-gate  * hitting any deferred items.
8320Sstevel@tonic-gate  *
8330Sstevel@tonic-gate  * for try == 0: return true if all operations were performed successfully.
8340Sstevel@tonic-gate  * return false if otherwise.  for example, any of the following conditions
8350Sstevel@tonic-gate  * will result in a false return value:
8360Sstevel@tonic-gate  *   - attempted use of an uninitialized global variable
8370Sstevel@tonic-gate  *   - failure in function evaluation
8380Sstevel@tonic-gate  *   - illegal arithmetic operation (argument out of range)
8390Sstevel@tonic-gate  */
8400Sstevel@tonic-gate int
8410Sstevel@tonic-gate eval_expr(struct node *np, struct lut *ex, struct node *epnames[],
8420Sstevel@tonic-gate 	struct lut **globals, struct config *croot, struct arrow *arrowp,
8430Sstevel@tonic-gate 	int try, struct evalue *valuep)
8440Sstevel@tonic-gate {
8450Sstevel@tonic-gate 	struct evalue *gval;
8460Sstevel@tonic-gate 	struct evalue lval;
8470Sstevel@tonic-gate 	struct evalue rval;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	if (np == NULL) {
8500Sstevel@tonic-gate 		valuep->t = UINT64;
8510Sstevel@tonic-gate 		valuep->v = 1;	/* no constraint means "true" */
8520Sstevel@tonic-gate 		return (1);
8530Sstevel@tonic-gate 	}
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	valuep->t = UNDEFINED;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	switch (np->t) {
8580Sstevel@tonic-gate 	case T_GLOBID:
8590Sstevel@tonic-gate 		if (try)
8600Sstevel@tonic-gate 			return (0);
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 		/*
8630Sstevel@tonic-gate 		 * only handle case of getting (and not setting) the value
8640Sstevel@tonic-gate 		 * of a global variable
8650Sstevel@tonic-gate 		 */
8660Sstevel@tonic-gate 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
8670Sstevel@tonic-gate 		if (gval == NULL) {
8680Sstevel@tonic-gate 			valuep->t = UNDEFINED;
8690Sstevel@tonic-gate 			return (0);
8700Sstevel@tonic-gate 		} else {
8710Sstevel@tonic-gate 			valuep->t = gval->t;
8720Sstevel@tonic-gate 			valuep->v = gval->v;
8730Sstevel@tonic-gate 			return (1);
8740Sstevel@tonic-gate 		}
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	case T_ASSIGN:
8770Sstevel@tonic-gate 		if (try)
8780Sstevel@tonic-gate 			return (0);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 		/*
8810Sstevel@tonic-gate 		 * first evaluate rhs, then try to store value in lhs which
8820Sstevel@tonic-gate 		 * should be a global variable
8830Sstevel@tonic-gate 		 */
8840Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
8850Sstevel@tonic-gate 			    arrowp, try, &rval))
8860Sstevel@tonic-gate 			return (0);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 		ASSERT(np->u.expr.left->t == T_GLOBID);
8890Sstevel@tonic-gate 		gval = lut_lookup(*globals,
8900Sstevel@tonic-gate 				(void *)np->u.expr.left->u.globid.s, NULL);
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 		if (gval == NULL) {
8930Sstevel@tonic-gate 			gval = MALLOC(sizeof (*gval));
8940Sstevel@tonic-gate 			*globals = lut_add(*globals,
8950Sstevel@tonic-gate 					(void *) np->u.expr.left->u.globid.s,
8960Sstevel@tonic-gate 					gval, NULL);
8970Sstevel@tonic-gate 		}
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 		gval->t = rval.t;
9000Sstevel@tonic-gate 		gval->v = rval.v;
9011414Scindi 
9021414Scindi 		if (gval->t == UINT64) {
9031414Scindi 			out(O_ALTFP|O_VERB2,
9041414Scindi 			    "assign $%s=%llu",
9051414Scindi 			    np->u.expr.left->u.globid.s, gval->v);
9061414Scindi 		} else {
9071414Scindi 			out(O_ALTFP|O_VERB2,
9081414Scindi 			    "assign $%s=\"%s\"",
9091717Swesolows 			    np->u.expr.left->u.globid.s,
9101717Swesolows 			    (char *)(uintptr_t)gval->v);
9111414Scindi 		}
9121414Scindi 
9131414Scindi 		/*
9141414Scindi 		 * but always return true -- an assignment should not
9151414Scindi 		 * cause a constraint to be false.
9161414Scindi 		 */
9171414Scindi 		valuep->t = UINT64;
9181414Scindi 		valuep->v = 1;
9190Sstevel@tonic-gate 		return (1);
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	case T_EQ:
9220Sstevel@tonic-gate #define	IMPLICIT_ASSIGN_IN_EQ
9230Sstevel@tonic-gate #ifdef IMPLICIT_ASSIGN_IN_EQ
9240Sstevel@tonic-gate 		/*
9250Sstevel@tonic-gate 		 * if lhs is an uninitialized global variable, perform
9260Sstevel@tonic-gate 		 * an assignment.
9270Sstevel@tonic-gate 		 *
9280Sstevel@tonic-gate 		 * one insidious side effect of implicit assignment is
9290Sstevel@tonic-gate 		 * that the "==" operator does not return a Boolean if
9300Sstevel@tonic-gate 		 * implicit assignment was performed.
9310Sstevel@tonic-gate 		 */
9320Sstevel@tonic-gate 		if (try == 0 &&
9330Sstevel@tonic-gate 		    np->u.expr.left->t == T_GLOBID &&
9340Sstevel@tonic-gate 		    (gval = lut_lookup(*globals,
9350Sstevel@tonic-gate 			(void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
9360Sstevel@tonic-gate 			if (!eval_expr(np->u.expr.right, ex, epnames, globals,
9370Sstevel@tonic-gate 					croot, arrowp, try, &rval))
9380Sstevel@tonic-gate 				return (0);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 			gval = MALLOC(sizeof (*gval));
9410Sstevel@tonic-gate 			*globals = lut_add(*globals,
9420Sstevel@tonic-gate 					(void *) np->u.expr.left->u.globid.s,
9430Sstevel@tonic-gate 					gval, NULL);
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 			gval->t = rval.t;
9460Sstevel@tonic-gate 			gval->v = rval.v;
9470Sstevel@tonic-gate 			valuep->t = rval.t;
9480Sstevel@tonic-gate 			valuep->v = rval.v;
9490Sstevel@tonic-gate 			return (1);
9500Sstevel@tonic-gate 		}
9510Sstevel@tonic-gate #endif  /* IMPLICIT_ASSIGN_IN_EQ */
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9540Sstevel@tonic-gate 				arrowp, try, &lval))
9550Sstevel@tonic-gate 			return (0);
9560Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9570Sstevel@tonic-gate 				arrowp, try, &rval))
9580Sstevel@tonic-gate 			return (0);
9590Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
9600Sstevel@tonic-gate 			return (0);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 		valuep->t = UINT64;
9630Sstevel@tonic-gate 		valuep->v = (lval.v == rval.v);
9640Sstevel@tonic-gate 		return (1);
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	case T_LT:
9670Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9680Sstevel@tonic-gate 				arrowp, try, &lval))
9690Sstevel@tonic-gate 			return (0);
9700Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9710Sstevel@tonic-gate 				arrowp, try, &rval))
9720Sstevel@tonic-gate 			return (0);
9731414Scindi 		if (check_expr_args(&lval, &rval, UINT64, np))
9740Sstevel@tonic-gate 			return (0);
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 		valuep->t = UINT64;
9770Sstevel@tonic-gate 		valuep->v = (lval.v < rval.v);
9780Sstevel@tonic-gate 		return (1);
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	case T_LE:
9810Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9820Sstevel@tonic-gate 				arrowp, try, &lval))
9830Sstevel@tonic-gate 			return (0);
9840Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9850Sstevel@tonic-gate 				arrowp, try, &rval))
9860Sstevel@tonic-gate 			return (0);
9871414Scindi 		if (check_expr_args(&lval, &rval, UINT64, np))
9880Sstevel@tonic-gate 			return (0);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 		valuep->t = UINT64;
9910Sstevel@tonic-gate 		valuep->v = (lval.v <= rval.v);
9920Sstevel@tonic-gate 		return (1);
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	case T_GT:
9950Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
9960Sstevel@tonic-gate 				arrowp, try, &lval))
9970Sstevel@tonic-gate 			return (0);
9980Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
9990Sstevel@tonic-gate 				arrowp, try, &rval))
10000Sstevel@tonic-gate 			return (0);
10011414Scindi 		if (check_expr_args(&lval, &rval, UINT64, np))
10020Sstevel@tonic-gate 			return (0);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 		valuep->t = UINT64;
10050Sstevel@tonic-gate 		valuep->v = (lval.v > rval.v);
10060Sstevel@tonic-gate 		return (1);
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	case T_GE:
10090Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
10100Sstevel@tonic-gate 				arrowp, try, &lval))
10110Sstevel@tonic-gate 			return (0);
10120Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
10130Sstevel@tonic-gate 				arrowp, try, &rval))
10140Sstevel@tonic-gate 			return (0);
10151414Scindi 		if (check_expr_args(&lval, &rval, UINT64, np))
10160Sstevel@tonic-gate 			return (0);
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 		valuep->t = UINT64;
10190Sstevel@tonic-gate 		valuep->v = (lval.v >= rval.v);
10200Sstevel@tonic-gate 		return (1);
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	case T_BITAND:
10230Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
10240Sstevel@tonic-gate 				arrowp, try, &lval))
10250Sstevel@tonic-gate 			return (0);
10260Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
10270Sstevel@tonic-gate 				arrowp, try, &rval))
10280Sstevel@tonic-gate 			return (0);
10290Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
10300Sstevel@tonic-gate 			return (0);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		valuep->t = lval.t;
10330Sstevel@tonic-gate 		valuep->v = (lval.v & rval.v);
10340Sstevel@tonic-gate 		return (1);
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	case T_BITOR:
10370Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
10380Sstevel@tonic-gate 				arrowp, try, &lval))
10390Sstevel@tonic-gate 			return (0);
10400Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
10410Sstevel@tonic-gate 				arrowp, try, &rval))
10420Sstevel@tonic-gate 			return (0);
10430Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
10440Sstevel@tonic-gate 			return (0);
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 		valuep->t = lval.t;
10470Sstevel@tonic-gate 		valuep->v = (lval.v | rval.v);
10480Sstevel@tonic-gate 		return (1);
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	case T_BITXOR:
10510Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
10520Sstevel@tonic-gate 				arrowp, try, &lval))
10530Sstevel@tonic-gate 			return (0);
10540Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
10550Sstevel@tonic-gate 				arrowp, try, &rval))
10560Sstevel@tonic-gate 			return (0);
10570Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
10580Sstevel@tonic-gate 			return (0);
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 		valuep->t = lval.t;
10610Sstevel@tonic-gate 		valuep->v = (lval.v ^ rval.v);
10620Sstevel@tonic-gate 		return (1);
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	case T_BITNOT:
10650Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
10660Sstevel@tonic-gate 				arrowp, try, &lval))
10670Sstevel@tonic-gate 			return (0);
10680Sstevel@tonic-gate 		ASSERT(np->u.expr.right == NULL);
10690Sstevel@tonic-gate 		if (check_expr_args(&lval, NULL, UINT64, np))
10700Sstevel@tonic-gate 			return (0);
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 		valuep->t = UINT64;
10730Sstevel@tonic-gate 		valuep->v = ~ lval.v;
10740Sstevel@tonic-gate 		return (1);
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	case T_LSHIFT:
10770Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
10780Sstevel@tonic-gate 				arrowp, try, &lval))
10790Sstevel@tonic-gate 			return (0);
10800Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
10810Sstevel@tonic-gate 				arrowp, try, &rval))
10820Sstevel@tonic-gate 			return (0);
10830Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
10840Sstevel@tonic-gate 			return (0);
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 		valuep->t = UINT64;
10870Sstevel@tonic-gate 		valuep->v = (lval.v << rval.v);
10880Sstevel@tonic-gate 		return (1);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	case T_RSHIFT:
10910Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
10920Sstevel@tonic-gate 				arrowp, try, &lval))
10930Sstevel@tonic-gate 			return (0);
10940Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
10950Sstevel@tonic-gate 				arrowp, try, &rval))
10960Sstevel@tonic-gate 			return (0);
10970Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
10980Sstevel@tonic-gate 			return (0);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 		valuep->t = UINT64;
11010Sstevel@tonic-gate 		valuep->v = (lval.v >> rval.v);
11020Sstevel@tonic-gate 		return (1);
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	case T_CONDIF: {
11050Sstevel@tonic-gate 		struct node *retnp;
11060Sstevel@tonic-gate 		int dotrue = 0;
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		/*
11090Sstevel@tonic-gate 		 * evaluate
11100Sstevel@tonic-gate 		 *	expression ? stmtA [ : stmtB ]
11110Sstevel@tonic-gate 		 *
11120Sstevel@tonic-gate 		 * first see if expression is true or false, then determine
11130Sstevel@tonic-gate 		 * if stmtA (or stmtB, if it exists) should be evaluated.
11140Sstevel@tonic-gate 		 *
11150Sstevel@tonic-gate 		 * "dotrue = 1" means stmtA should be evaluated.
11160Sstevel@tonic-gate 		 */
11170Sstevel@tonic-gate 		if (eval_expr(np->u.expr.left, ex, epnames, globals, croot,
11180Sstevel@tonic-gate 				arrowp, try, &lval) &&
11190Sstevel@tonic-gate 		    lval.t != UNDEFINED && lval.v != 0)
11200Sstevel@tonic-gate 			dotrue = 1;
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 		ASSERT(np->u.expr.right != NULL);
11230Sstevel@tonic-gate 		if (np->u.expr.right->t == T_CONDELSE) {
11240Sstevel@tonic-gate 			if (dotrue)
11250Sstevel@tonic-gate 				retnp = np->u.expr.right->u.expr.left;
11260Sstevel@tonic-gate 			else
11270Sstevel@tonic-gate 				retnp = np->u.expr.right->u.expr.right;
11280Sstevel@tonic-gate 		} else {
11290Sstevel@tonic-gate 			/* no ELSE clause */
11300Sstevel@tonic-gate 			if (dotrue)
11310Sstevel@tonic-gate 				retnp = np->u.expr.right;
11320Sstevel@tonic-gate 			else {
11330Sstevel@tonic-gate 				valuep->t = UINT64;
11340Sstevel@tonic-gate 				valuep->v = 0;
11350Sstevel@tonic-gate 				return (0);
11360Sstevel@tonic-gate 			}
11370Sstevel@tonic-gate 		}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 		if (!eval_expr(retnp, ex, epnames, globals, croot,
11400Sstevel@tonic-gate 			    arrowp, try, valuep))
11410Sstevel@tonic-gate 			return (0);
11420Sstevel@tonic-gate 		return (1);
11430Sstevel@tonic-gate 	}
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	case T_CONDELSE:
11460Sstevel@tonic-gate 		/*
11470Sstevel@tonic-gate 		 * shouldn't get here, since T_CONDELSE is supposed to be
11480Sstevel@tonic-gate 		 * evaluated as part of T_CONDIF
11490Sstevel@tonic-gate 		 */
11500Sstevel@tonic-gate 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
11510Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
11520Sstevel@tonic-gate 		return (0);
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 	case T_NE:
11550Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
11560Sstevel@tonic-gate 				arrowp, try, &lval))
11570Sstevel@tonic-gate 			return (0);
11580Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
11590Sstevel@tonic-gate 				arrowp, try, &rval))
11600Sstevel@tonic-gate 			return (0);
11610Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
11620Sstevel@tonic-gate 			return (0);
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 		valuep->t = UINT64;
11650Sstevel@tonic-gate 		valuep->v = (lval.v != rval.v);
11660Sstevel@tonic-gate 		return (1);
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	case T_LIST:
11690Sstevel@tonic-gate 	case T_AND:
11700Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1171*3159Sstephh 				arrowp, try, valuep)) {
1172*3159Sstephh 			/*
1173*3159Sstephh 			 * if lhs is unknown, still check rhs. If that
1174*3159Sstephh 			 * is false we can return false irrespectice of lhs
1175*3159Sstephh 			 */
1176*3159Sstephh 			if (!eval_expr(np->u.expr.right, ex, epnames, globals,
1177*3159Sstephh 			    croot, arrowp, try, valuep))
1178*3159Sstephh 				return (0);
1179*3159Sstephh 			if (valuep->v != 0)
1180*3159Sstephh 				return (0);
1181*3159Sstephh 		}
11820Sstevel@tonic-gate 		if (valuep->v == 0) {
11830Sstevel@tonic-gate 			valuep->t = UINT64;
11840Sstevel@tonic-gate 			return (1);
11850Sstevel@tonic-gate 		}
11860Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
11870Sstevel@tonic-gate 				arrowp, try, valuep))
11880Sstevel@tonic-gate 			return (0);
11890Sstevel@tonic-gate 		valuep->t = UINT64;
11900Sstevel@tonic-gate 		valuep->v = valuep->v == 0 ? 0 : 1;
11910Sstevel@tonic-gate 		return (1);
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	case T_OR:
11940Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
1195*3159Sstephh 				arrowp, try, valuep)) {
1196*3159Sstephh 			/*
1197*3159Sstephh 			 * if lhs is unknown, still check rhs. If that
1198*3159Sstephh 			 * is true we can return true irrespectice of lhs
1199*3159Sstephh 			 */
1200*3159Sstephh 			if (!eval_expr(np->u.expr.right, ex, epnames, globals,
1201*3159Sstephh 			    croot, arrowp, try, valuep))
1202*3159Sstephh 				return (0);
1203*3159Sstephh 			if (valuep->v == 0)
1204*3159Sstephh 				return (0);
1205*3159Sstephh 		}
12060Sstevel@tonic-gate 		if (valuep->v != 0) {
12070Sstevel@tonic-gate 			valuep->t = UINT64;
12080Sstevel@tonic-gate 			valuep->v = 1;
12090Sstevel@tonic-gate 			return (1);
12100Sstevel@tonic-gate 		}
12110Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
12120Sstevel@tonic-gate 				arrowp, try, valuep))
12130Sstevel@tonic-gate 			return (0);
12140Sstevel@tonic-gate 		valuep->t = UINT64;
12150Sstevel@tonic-gate 		valuep->v = valuep->v == 0 ? 0 : 1;
12160Sstevel@tonic-gate 		return (1);
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	case T_NOT:
12190Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
12200Sstevel@tonic-gate 				arrowp, try, valuep))
12210Sstevel@tonic-gate 			return (0);
12220Sstevel@tonic-gate 		valuep->t = UINT64;
12230Sstevel@tonic-gate 		valuep->v = ! valuep->v;
12240Sstevel@tonic-gate 		return (1);
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	case T_ADD:
12270Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
12280Sstevel@tonic-gate 				arrowp, try, &lval))
12290Sstevel@tonic-gate 			return (0);
12300Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
12310Sstevel@tonic-gate 				arrowp, try, &rval))
12320Sstevel@tonic-gate 			return (0);
12330Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
12340Sstevel@tonic-gate 			return (0);
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 		valuep->t = lval.t;
12370Sstevel@tonic-gate 		valuep->v = lval.v + rval.v;
12380Sstevel@tonic-gate 		return (1);
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	case T_SUB:
12410Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
12420Sstevel@tonic-gate 				arrowp, try, &lval))
12430Sstevel@tonic-gate 			return (0);
12440Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
12450Sstevel@tonic-gate 				arrowp, try, &rval))
12460Sstevel@tonic-gate 			return (0);
12470Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
12480Sstevel@tonic-gate 			return (0);
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 		/* since valuep is unsigned, return false if lval.v < rval.v */
12510Sstevel@tonic-gate 		if (lval.v < rval.v) {
12520Sstevel@tonic-gate 			out(O_ERR, "eval_expr: T_SUB result is out of range");
12530Sstevel@tonic-gate 			valuep->t = UNDEFINED;
12540Sstevel@tonic-gate 			return (0);
12550Sstevel@tonic-gate 		}
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 		valuep->t = lval.t;
12580Sstevel@tonic-gate 		valuep->v = lval.v - rval.v;
12590Sstevel@tonic-gate 		return (1);
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	case T_MUL:
12620Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
12630Sstevel@tonic-gate 				arrowp, try, &lval))
12640Sstevel@tonic-gate 			return (0);
12650Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
12660Sstevel@tonic-gate 				arrowp, try, &rval))
12670Sstevel@tonic-gate 			return (0);
12680Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
12690Sstevel@tonic-gate 			return (0);
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 		valuep->t = lval.t;
12720Sstevel@tonic-gate 		valuep->v = lval.v * rval.v;
12730Sstevel@tonic-gate 		return (1);
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	case T_DIV:
12760Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
12770Sstevel@tonic-gate 				arrowp, try, &lval))
12780Sstevel@tonic-gate 			return (0);
12790Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
12800Sstevel@tonic-gate 				arrowp, try, &rval))
12810Sstevel@tonic-gate 			return (0);
12820Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
12830Sstevel@tonic-gate 			return (0);
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 		/* return false if dividing by zero */
12860Sstevel@tonic-gate 		if (rval.v == 0) {
12870Sstevel@tonic-gate 			out(O_ERR, "eval_expr: T_DIV division by zero");
12880Sstevel@tonic-gate 			valuep->t = UNDEFINED;
12890Sstevel@tonic-gate 			return (0);
12900Sstevel@tonic-gate 		}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 		valuep->t = lval.t;
12930Sstevel@tonic-gate 		valuep->v = lval.v / rval.v;
12940Sstevel@tonic-gate 		return (1);
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	case T_MOD:
12970Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
12980Sstevel@tonic-gate 				arrowp, try, &lval))
12990Sstevel@tonic-gate 			return (0);
13000Sstevel@tonic-gate 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
13010Sstevel@tonic-gate 				arrowp, try, &rval))
13020Sstevel@tonic-gate 			return (0);
13030Sstevel@tonic-gate 		if (check_expr_args(&lval, &rval, UINT64, np))
13040Sstevel@tonic-gate 			return (0);
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 		/* return false if dividing by zero */
13070Sstevel@tonic-gate 		if (rval.v == 0) {
13080Sstevel@tonic-gate 			out(O_ERR, "eval_expr: T_MOD division by zero");
13090Sstevel@tonic-gate 			valuep->t = UNDEFINED;
13100Sstevel@tonic-gate 			return (0);
13110Sstevel@tonic-gate 		}
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 		valuep->t = lval.t;
13140Sstevel@tonic-gate 		valuep->v = lval.v % rval.v;
13150Sstevel@tonic-gate 		return (1);
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	case T_NAME:
13180Sstevel@tonic-gate 		if (try) {
13190Sstevel@tonic-gate 			struct iterinfo *iterinfop;
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 			/*
13220Sstevel@tonic-gate 			 * at itree_create() time, we can expand simple
13230Sstevel@tonic-gate 			 * iterators.  anything else we'll punt on.
13240Sstevel@tonic-gate 			 */
13250Sstevel@tonic-gate 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
13260Sstevel@tonic-gate 			if (iterinfop != NULL) {
13270Sstevel@tonic-gate 				/* explicit iterator; not part of pathname */
13280Sstevel@tonic-gate 				valuep->t = UINT64;
13290Sstevel@tonic-gate 				valuep->v = (unsigned long long)iterinfop->num;
13300Sstevel@tonic-gate 				return (1);
13310Sstevel@tonic-gate 			}
13320Sstevel@tonic-gate 			return (0);
13330Sstevel@tonic-gate 		}
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 		/* return address of struct node */
13360Sstevel@tonic-gate 		valuep->t = NODEPTR;
13371717Swesolows 		valuep->v = (uintptr_t)np;
13380Sstevel@tonic-gate 		return (1);
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	case T_QUOTE:
13410Sstevel@tonic-gate 		valuep->t = STRING;
13421717Swesolows 		valuep->v = (uintptr_t)np->u.quote.s;
13430Sstevel@tonic-gate 		return (1);
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	case T_FUNC:
13460Sstevel@tonic-gate 		return (eval_func(np, ex, epnames, np->u.func.arglist,
13470Sstevel@tonic-gate 				globals, croot, arrowp, try, valuep));
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	case T_NUM:
13500Sstevel@tonic-gate 		valuep->t = UINT64;
13510Sstevel@tonic-gate 		valuep->v = np->u.ull;
13520Sstevel@tonic-gate 		return (1);
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	default:
13550Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
13560Sstevel@tonic-gate 		    "eval_expr: unexpected node type: %s",
13570Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 	/*NOTREACHED*/
13601717Swesolows 	return (0);
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate /*
13640Sstevel@tonic-gate  * eval_fru() and eval_asru() don't do much, but are called from a number
13650Sstevel@tonic-gate  * of places.
13660Sstevel@tonic-gate  */
13670Sstevel@tonic-gate struct node *
13680Sstevel@tonic-gate eval_fru(struct node *np)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate 	ASSERT(np->t == T_NAME);
13710Sstevel@tonic-gate 	return (np);
13720Sstevel@tonic-gate }
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate struct node *
13750Sstevel@tonic-gate eval_asru(struct node *np)
13760Sstevel@tonic-gate {
13770Sstevel@tonic-gate 	ASSERT(np->t == T_NAME);
13780Sstevel@tonic-gate 	return (np);
13790Sstevel@tonic-gate }
1380