xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/itree.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  *
26*0Sstevel@tonic-gate  * itree.c -- instance tree creation and manipulation
27*0Sstevel@tonic-gate  *
28*0Sstevel@tonic-gate  * this module provides the instance tree
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <stdio.h>
34*0Sstevel@tonic-gate #include <ctype.h>
35*0Sstevel@tonic-gate #include <string.h>
36*0Sstevel@tonic-gate #include <strings.h>
37*0Sstevel@tonic-gate #include "alloc.h"
38*0Sstevel@tonic-gate #include "out.h"
39*0Sstevel@tonic-gate #include "stable.h"
40*0Sstevel@tonic-gate #include "literals.h"
41*0Sstevel@tonic-gate #include "lut.h"
42*0Sstevel@tonic-gate #include "tree.h"
43*0Sstevel@tonic-gate #include "ptree.h"
44*0Sstevel@tonic-gate #include "itree.h"
45*0Sstevel@tonic-gate #include "ipath.h"
46*0Sstevel@tonic-gate #include "eval.h"
47*0Sstevel@tonic-gate #include "config.h"
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate /*
50*0Sstevel@tonic-gate  * struct info contains the state we keep when expanding a prop statement
51*0Sstevel@tonic-gate  * as part of constructing the instance tree.  state kept in struct info
52*0Sstevel@tonic-gate  * is the non-recursive stuff -- the stuff that doesn't need to be on
53*0Sstevel@tonic-gate  * the stack.  the rest of the state that is passed between all the
54*0Sstevel@tonic-gate  * mutually recursive functions, is required to be on the stack since
55*0Sstevel@tonic-gate  * we need to backtrack and recurse as we do the instance tree construction.
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate struct info {
58*0Sstevel@tonic-gate 	struct lut *lut;
59*0Sstevel@tonic-gate 	struct node *anp;	/* arrow np */
60*0Sstevel@tonic-gate 	struct lut *ex;		/* dictionary of explicit iterators */
61*0Sstevel@tonic-gate 	struct config *croot;
62*0Sstevel@tonic-gate } Ninfo;
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate /*
65*0Sstevel@tonic-gate  * struct wildcardinfo is used to track wildcarded portions of paths.
66*0Sstevel@tonic-gate  *
67*0Sstevel@tonic-gate  * for example, if the epname of an event is "c/d" and the path "a/b/c/d"
68*0Sstevel@tonic-gate  * exists, the wildcard path ewname is filled in with the path "a/b".  when
69*0Sstevel@tonic-gate  * matching is done, epname is temporarily replaced with the concatenation
70*0Sstevel@tonic-gate  * of ewname and epname.  cpstart is set to the (struct config *)
71*0Sstevel@tonic-gate  * corresponding to component "c".
72*0Sstevel@tonic-gate  *
73*0Sstevel@tonic-gate  * a linked list of these structs is used to track the expansion of each
74*0Sstevel@tonic-gate  * event node as it is processed in vmatch() --> vmatch_event() calls.
75*0Sstevel@tonic-gate  */
76*0Sstevel@tonic-gate struct wildcardinfo {
77*0Sstevel@tonic-gate 	struct node *nptop;		/* event node fed to vmatch */
78*0Sstevel@tonic-gate 	struct node *oldepname;		/* epname without the wildcard part */
79*0Sstevel@tonic-gate 	enum status {
80*0Sstevel@tonic-gate 		WC_UNDEFINED,		/* struct is not yet initialized */
81*0Sstevel@tonic-gate 		WC_UNDERCONSTRUCTION,	/* wildcard path not yet done */
82*0Sstevel@tonic-gate 		WC_COMPLETE,		/* wildcard path done and is in use */
83*0Sstevel@tonic-gate 		WC_REFERENCING		/* use another node's wildcard path */
84*0Sstevel@tonic-gate 	} s;
85*0Sstevel@tonic-gate 	struct wildcardpath {
86*0Sstevel@tonic-gate 		struct node *ewname;	/* wildcard path */
87*0Sstevel@tonic-gate 		struct config *cpstart;	/* starting cp node for oldepname */
88*0Sstevel@tonic-gate 		struct config *cpforcedwc;	/* forced wildcard for this */
89*0Sstevel@tonic-gate 		int refcount;		/* number of event nodes using this */
90*0Sstevel@tonic-gate 	} *p;
91*0Sstevel@tonic-gate 	struct wildcardinfo *next;
92*0Sstevel@tonic-gate };
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate static void vmatch(struct info *infop, struct node *np,
95*0Sstevel@tonic-gate     struct node *lnp, struct node *anp, struct wildcardinfo **wcproot);
96*0Sstevel@tonic-gate static void hmatch(struct info *infop, struct node *np, struct node *nextnp);
97*0Sstevel@tonic-gate static void itree_pbubble(int flags, struct bubble *bp);
98*0Sstevel@tonic-gate static void itree_destructor(void *left, void *right, void *arg);
99*0Sstevel@tonic-gate static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
100*0Sstevel@tonic-gate     struct node *toev, struct lut *ex);
101*0Sstevel@tonic-gate static void itree_free_arrowlists(struct bubble *bubp, int arrows_too);
102*0Sstevel@tonic-gate static void arrow_add_within(struct arrow *ap, struct node *xpr);
103*0Sstevel@tonic-gate static struct arrow *itree_add_arrow(struct bubble *frombubblep,
104*0Sstevel@tonic-gate     struct bubble *tobubblep, struct node *apnode, struct node *fromevent,
105*0Sstevel@tonic-gate     struct node *toevent, struct lut *ex);
106*0Sstevel@tonic-gate static struct constraintlist *itree_add_constraint(struct arrow *arrowp,
107*0Sstevel@tonic-gate     struct node *c);
108*0Sstevel@tonic-gate static struct bubble *itree_add_bubble(struct event *eventp,
109*0Sstevel@tonic-gate     enum bubbletype btype, int nork, int gen);
110*0Sstevel@tonic-gate static void itree_free_bubble(struct bubble *freeme);
111*0Sstevel@tonic-gate static void itree_free_constraints(struct arrow *ap);
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate /*
114*0Sstevel@tonic-gate  * the following struct contains the state we build up during
115*0Sstevel@tonic-gate  * vertical and horizontal expansion so that generate()
116*0Sstevel@tonic-gate  * has everything it needs to construct the appropriate arrows.
117*0Sstevel@tonic-gate  * after setting up the state by calling:
118*0Sstevel@tonic-gate  *	generate_arrownp()
119*0Sstevel@tonic-gate  *	generate_nork()
120*0Sstevel@tonic-gate  *	generate_new()
121*0Sstevel@tonic-gate  *	generate_from()
122*0Sstevel@tonic-gate  *	generate_to()
123*0Sstevel@tonic-gate  * the actual arrow generation is done by calling:
124*0Sstevel@tonic-gate  *	generate()
125*0Sstevel@tonic-gate  */
126*0Sstevel@tonic-gate static struct {
127*0Sstevel@tonic-gate 	int generation;		/* generation number of arrow set */
128*0Sstevel@tonic-gate 	struct node *arrownp;	/* top-level parse tree for arrow */
129*0Sstevel@tonic-gate 	int n;			/* n value associated with arrow */
130*0Sstevel@tonic-gate 	int k;			/* k value associated with arrow */
131*0Sstevel@tonic-gate 	struct node *fromnp;	/* left-hand-side event in parse tree */
132*0Sstevel@tonic-gate 	struct node *tonp;	/* right-hand-side event in parse tree */
133*0Sstevel@tonic-gate 	struct event *frome;	/* left-hand-side event in instance tree */
134*0Sstevel@tonic-gate 	struct event *toe;	/* right-hand-side event in instance tree */
135*0Sstevel@tonic-gate 	struct bubble *frombp;	/* bubble arrow comes from */
136*0Sstevel@tonic-gate 	struct bubble *tobp;	/* bubble arrow goes to */
137*0Sstevel@tonic-gate } G;
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate static void
140*0Sstevel@tonic-gate generate_arrownp(struct node *arrownp)
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	G.arrownp = arrownp;
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate static void
146*0Sstevel@tonic-gate generate_nork(int n, int k)
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate 	G.n = n;
149*0Sstevel@tonic-gate 	G.k = k;
150*0Sstevel@tonic-gate }
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate static void
153*0Sstevel@tonic-gate generate_new(void)
154*0Sstevel@tonic-gate {
155*0Sstevel@tonic-gate 	G.generation++;
156*0Sstevel@tonic-gate }
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate static void
159*0Sstevel@tonic-gate generate_from(struct node *fromeventnp, struct event *fromevent)
160*0Sstevel@tonic-gate {
161*0Sstevel@tonic-gate 	G.fromnp = fromeventnp;
162*0Sstevel@tonic-gate 	G.frome = fromevent;
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "from bubble on ");
165*0Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
166*0Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, NULL);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0);
169*0Sstevel@tonic-gate }
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate static void
172*0Sstevel@tonic-gate generate_to(struct node *toeventnp, struct event *toevent)
173*0Sstevel@tonic-gate {
174*0Sstevel@tonic-gate 	G.tonp = toeventnp;
175*0Sstevel@tonic-gate 	G.toe = toevent;
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "to bubble (gen %d) on ", G.generation);
178*0Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
179*0Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, NULL);
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation);
182*0Sstevel@tonic-gate }
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate static void
185*0Sstevel@tonic-gate generate(struct lut *ex)
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	ASSERT(G.arrownp != NULL);
188*0Sstevel@tonic-gate 	ASSERT(G.fromnp != NULL);
189*0Sstevel@tonic-gate 	ASSERT(G.frome != NULL);
190*0Sstevel@tonic-gate 	ASSERT(G.frombp != NULL);
191*0Sstevel@tonic-gate 	ASSERT(G.tonp != NULL);
192*0Sstevel@tonic-gate 	ASSERT(G.toe != NULL);
193*0Sstevel@tonic-gate 	ASSERT(G.tobp != NULL);
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "        Arrow \"");
196*0Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
197*0Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL, "\" -> \"");
198*0Sstevel@tonic-gate 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	if (itree_add_arrow(G.frombp, G.tobp, G.arrownp,
201*0Sstevel@tonic-gate 	    G.fromnp, G.tonp, ex) == NULL) {
202*0Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "\" (prevented by constraints)");
203*0Sstevel@tonic-gate 	} else {
204*0Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "\"");
205*0Sstevel@tonic-gate 	}
206*0Sstevel@tonic-gate }
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate enum childnode_action {
209*0Sstevel@tonic-gate 	CN_NONE,
210*0Sstevel@tonic-gate 	CN_INSTANTIZE,
211*0Sstevel@tonic-gate 	CN_DUP
212*0Sstevel@tonic-gate };
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate static struct node *
215*0Sstevel@tonic-gate tname_dup(struct node *namep, enum childnode_action act)
216*0Sstevel@tonic-gate {
217*0Sstevel@tonic-gate 	struct node *retp = NULL;
218*0Sstevel@tonic-gate 	const char *file;
219*0Sstevel@tonic-gate 	int line;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	if (namep == NULL)
222*0Sstevel@tonic-gate 		return (NULL);
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	file = namep->file;
225*0Sstevel@tonic-gate 	line = namep->line;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	for (; namep != NULL; namep = namep->u.name.next) {
228*0Sstevel@tonic-gate 		struct node *newnp = newnode(T_NAME, file, line);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 		newnp->u.name.t = namep->u.name.t;
231*0Sstevel@tonic-gate 		newnp->u.name.s = namep->u.name.s;
232*0Sstevel@tonic-gate 		newnp->u.name.last = newnp;
233*0Sstevel@tonic-gate 		newnp->u.name.it = namep->u.name.it;
234*0Sstevel@tonic-gate 		newnp->u.name.cp = namep->u.name.cp;
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 		if (act == CN_DUP) {
237*0Sstevel@tonic-gate 			struct node *npc;
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 			npc = namep->u.name.child;
240*0Sstevel@tonic-gate 			if (npc != NULL) {
241*0Sstevel@tonic-gate 				switch (npc->t) {
242*0Sstevel@tonic-gate 				case T_NUM:
243*0Sstevel@tonic-gate 					newnp->u.name.child =
244*0Sstevel@tonic-gate 						newnode(T_NUM, file, line);
245*0Sstevel@tonic-gate 					newnp->u.name.child->u.ull =
246*0Sstevel@tonic-gate 						npc->u.ull;
247*0Sstevel@tonic-gate 					break;
248*0Sstevel@tonic-gate 				case T_NAME:
249*0Sstevel@tonic-gate 					newnp->u.name.child =
250*0Sstevel@tonic-gate 						tree_name(npc->u.name.s,
251*0Sstevel@tonic-gate 							npc->u.name.it,
252*0Sstevel@tonic-gate 							file, line);
253*0Sstevel@tonic-gate 					break;
254*0Sstevel@tonic-gate 				default:
255*0Sstevel@tonic-gate 					out(O_DIE, "tname_dup: "
256*0Sstevel@tonic-gate 					    "invalid child type %s",
257*0Sstevel@tonic-gate 					    ptree_nodetype2str(npc->t));
258*0Sstevel@tonic-gate 				}
259*0Sstevel@tonic-gate 			}
260*0Sstevel@tonic-gate 		} else if (act == CN_INSTANTIZE) {
261*0Sstevel@tonic-gate 			newnp->u.name.child = newnode(T_NUM, file, line);
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 			if (namep->u.name.child == NULL ||
264*0Sstevel@tonic-gate 			    namep->u.name.child->t != T_NUM) {
265*0Sstevel@tonic-gate 				int inum;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 				ASSERT(newnp->u.name.cp != NULL);
268*0Sstevel@tonic-gate 				config_getcompname(newnp->u.name.cp,
269*0Sstevel@tonic-gate 						    NULL, &inum);
270*0Sstevel@tonic-gate 				newnp->u.name.child->u.ull =
271*0Sstevel@tonic-gate 					(unsigned long long)inum;
272*0Sstevel@tonic-gate 			} else {
273*0Sstevel@tonic-gate 				newnp->u.name.child->u.ull =
274*0Sstevel@tonic-gate 					namep->u.name.child->u.ull;
275*0Sstevel@tonic-gate 			}
276*0Sstevel@tonic-gate 		}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 		if (retp == NULL) {
279*0Sstevel@tonic-gate 			retp = newnp;
280*0Sstevel@tonic-gate 		} else {
281*0Sstevel@tonic-gate 			retp->u.name.last->u.name.next = newnp;
282*0Sstevel@tonic-gate 			retp->u.name.last = newnp;
283*0Sstevel@tonic-gate 		}
284*0Sstevel@tonic-gate 	}
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	return (retp);
287*0Sstevel@tonic-gate }
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate struct prop_wlk_data {
290*0Sstevel@tonic-gate 	struct lut *props;
291*0Sstevel@tonic-gate 	struct node *epname;
292*0Sstevel@tonic-gate };
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate static struct lut *props2instance(struct node *, struct node *);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate /*
297*0Sstevel@tonic-gate  * let oldepname be a subset of epname.  return the subsection of epname
298*0Sstevel@tonic-gate  * that ends with oldepname.  make each component in the path explicitly
299*0Sstevel@tonic-gate  * instanced (i.e., with a T_NUM child).
300*0Sstevel@tonic-gate  */
301*0Sstevel@tonic-gate static struct node *
302*0Sstevel@tonic-gate tname_dup_to_epname(struct node *oldepname, struct node *epname)
303*0Sstevel@tonic-gate {
304*0Sstevel@tonic-gate 	struct node *npref, *npend, *np1, *np2;
305*0Sstevel@tonic-gate 	struct node *ret = NULL;
306*0Sstevel@tonic-gate 	int foundmatch = 0;
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	if (epname == NULL)
309*0Sstevel@tonic-gate 		return (NULL);
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	/*
312*0Sstevel@tonic-gate 	 * search for the longest path in epname which contains
313*0Sstevel@tonic-gate 	 * oldnode->u.event.epname.  set npend to point to just past the
314*0Sstevel@tonic-gate 	 * end of this path.
315*0Sstevel@tonic-gate 	 */
316*0Sstevel@tonic-gate 	npend = NULL;
317*0Sstevel@tonic-gate 	for (npref = epname; npref; npref = npref->u.name.next) {
318*0Sstevel@tonic-gate 		if (npref->u.name.s == oldepname->u.name.s) {
319*0Sstevel@tonic-gate 			for (np1 = npref, np2 = oldepname;
320*0Sstevel@tonic-gate 			    np1 != NULL && np2 != NULL;
321*0Sstevel@tonic-gate 			    np1 = np1->u.name.next, np2 = np2->u.name.next) {
322*0Sstevel@tonic-gate 				if (np1->u.name.s != np2->u.name.s)
323*0Sstevel@tonic-gate 					break;
324*0Sstevel@tonic-gate 			}
325*0Sstevel@tonic-gate 			if (np2 == NULL) {
326*0Sstevel@tonic-gate 				foundmatch = 1;
327*0Sstevel@tonic-gate 				npend = np1;
328*0Sstevel@tonic-gate 				if (np1 == NULL) {
329*0Sstevel@tonic-gate 					/* oldepname matched npref up to end */
330*0Sstevel@tonic-gate 					break;
331*0Sstevel@tonic-gate 				}
332*0Sstevel@tonic-gate 			}
333*0Sstevel@tonic-gate 		}
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	if (foundmatch == 0) {
337*0Sstevel@tonic-gate 		/*
338*0Sstevel@tonic-gate 		 * if oldepname could not be found in epname, return a
339*0Sstevel@tonic-gate 		 * duplicate of the former.  do not try to instantize
340*0Sstevel@tonic-gate 		 * oldepname since it might not be a path.
341*0Sstevel@tonic-gate 		 */
342*0Sstevel@tonic-gate 		return (tname_dup(oldepname, CN_DUP));
343*0Sstevel@tonic-gate 	}
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	/*
346*0Sstevel@tonic-gate 	 * dup (epname -- npend).  all children should be T_NUMs.
347*0Sstevel@tonic-gate 	 */
348*0Sstevel@tonic-gate 	for (npref = epname;
349*0Sstevel@tonic-gate 	    ! (npref == NULL || npref == npend);
350*0Sstevel@tonic-gate 	    npref = npref->u.name.next) {
351*0Sstevel@tonic-gate 		struct node *newnp = newnode(T_NAME, oldepname->file,
352*0Sstevel@tonic-gate 					    oldepname->line);
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 		newnp->u.name.t = npref->u.name.t;
355*0Sstevel@tonic-gate 		newnp->u.name.s = npref->u.name.s;
356*0Sstevel@tonic-gate 		newnp->u.name.last = newnp;
357*0Sstevel@tonic-gate 		newnp->u.name.it = npref->u.name.it;
358*0Sstevel@tonic-gate 		newnp->u.name.cp = npref->u.name.cp;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 		newnp->u.name.child = newnode(T_NUM, oldepname->file,
361*0Sstevel@tonic-gate 					    oldepname->line);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 		if (npref->u.name.child == NULL ||
364*0Sstevel@tonic-gate 		    npref->u.name.child->t != T_NUM) {
365*0Sstevel@tonic-gate 			int childnum;
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 			ASSERT(npref->u.name.cp != NULL);
368*0Sstevel@tonic-gate 			config_getcompname(npref->u.name.cp, NULL, &childnum);
369*0Sstevel@tonic-gate 			newnp->u.name.child->u.ull = childnum;
370*0Sstevel@tonic-gate 		} else {
371*0Sstevel@tonic-gate 			newnp->u.name.child->u.ull =
372*0Sstevel@tonic-gate 				npref->u.name.child->u.ull;
373*0Sstevel@tonic-gate 		}
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 		if (ret == NULL) {
376*0Sstevel@tonic-gate 			ret = newnp;
377*0Sstevel@tonic-gate 		} else {
378*0Sstevel@tonic-gate 			ret->u.name.last->u.name.next = newnp;
379*0Sstevel@tonic-gate 			ret->u.name.last = newnp;
380*0Sstevel@tonic-gate 		}
381*0Sstevel@tonic-gate 	}
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	return (ret);
384*0Sstevel@tonic-gate }
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate /*
387*0Sstevel@tonic-gate  * restriction: oldnode->u.event.epname has to be equivalent to or a subset
388*0Sstevel@tonic-gate  * of epname
389*0Sstevel@tonic-gate  */
390*0Sstevel@tonic-gate static struct node *
391*0Sstevel@tonic-gate tevent_dup_to_epname(struct node *oldnode, struct node *epname)
392*0Sstevel@tonic-gate {
393*0Sstevel@tonic-gate 	struct node *ret;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	ret = newnode(T_EVENT, oldnode->file, oldnode->line);
396*0Sstevel@tonic-gate 	ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE);
397*0Sstevel@tonic-gate 	ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname,
398*0Sstevel@tonic-gate 						    epname);
399*0Sstevel@tonic-gate 	return (ret);
400*0Sstevel@tonic-gate }
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate static void
403*0Sstevel@tonic-gate nv_instantiate(void *name, void *val, void *arg)
404*0Sstevel@tonic-gate {
405*0Sstevel@tonic-gate 	struct prop_wlk_data *pd = (struct prop_wlk_data *)arg;
406*0Sstevel@tonic-gate 	struct node *orhs = (struct node *)val;
407*0Sstevel@tonic-gate 	struct node *nrhs;
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	/* handle engines by instantizing the entire engine */
410*0Sstevel@tonic-gate 	if (name == L_engine) {
411*0Sstevel@tonic-gate 		ASSERT(orhs->t == T_EVENT);
412*0Sstevel@tonic-gate 		ASSERT(orhs->u.event.ename->u.name.t == N_SERD);
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 		/* there are only SERD engines for now */
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 		nrhs = newnode(T_SERD, orhs->file, orhs->line);
417*0Sstevel@tonic-gate 		nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname);
418*0Sstevel@tonic-gate 		nrhs->u.stmt.lutp = props2instance(orhs, pd->epname);
419*0Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
420*0Sstevel@tonic-gate 		return;
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	switch (orhs->t) {
424*0Sstevel@tonic-gate 	case T_NUM:
425*0Sstevel@tonic-gate 		nrhs = newnode(T_NUM, orhs->file, orhs->line);
426*0Sstevel@tonic-gate 		nrhs->u.ull = orhs->u.ull;
427*0Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
428*0Sstevel@tonic-gate 		break;
429*0Sstevel@tonic-gate 	case T_TIMEVAL:
430*0Sstevel@tonic-gate 		nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line);
431*0Sstevel@tonic-gate 		nrhs->u.ull = orhs->u.ull;
432*0Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
433*0Sstevel@tonic-gate 		break;
434*0Sstevel@tonic-gate 	case T_NAME:
435*0Sstevel@tonic-gate 		nrhs = tname_dup_to_epname(orhs, pd->epname);
436*0Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
437*0Sstevel@tonic-gate 		break;
438*0Sstevel@tonic-gate 	case T_EVENT:
439*0Sstevel@tonic-gate 		nrhs = tevent_dup_to_epname(orhs, pd->epname);
440*0Sstevel@tonic-gate 		pd->props = lut_add(pd->props, name, nrhs, NULL);
441*0Sstevel@tonic-gate 		break;
442*0Sstevel@tonic-gate 	default:
443*0Sstevel@tonic-gate 		out(O_DEBUG, "unexpected nvpair value type %s",
444*0Sstevel@tonic-gate 		    ptree_nodetype2str(((struct node *)val)->t));
445*0Sstevel@tonic-gate 	}
446*0Sstevel@tonic-gate }
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate static struct lut *
449*0Sstevel@tonic-gate props2instance(struct node *eventnp, struct node *epname)
450*0Sstevel@tonic-gate {
451*0Sstevel@tonic-gate 	struct prop_wlk_data pd;
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	pd.props = NULL;
454*0Sstevel@tonic-gate 	pd.epname = epname;
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	ASSERT(eventnp->u.event.declp != NULL);
457*0Sstevel@tonic-gate 	lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd);
458*0Sstevel@tonic-gate 	return (pd.props);
459*0Sstevel@tonic-gate }
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate /*ARGSUSED*/
462*0Sstevel@tonic-gate static void
463*0Sstevel@tonic-gate instances_destructor(void *left, void *right, void *arg)
464*0Sstevel@tonic-gate {
465*0Sstevel@tonic-gate 	struct node *dn = (struct node *)right;
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	if (dn->t == T_SERD) {
468*0Sstevel@tonic-gate 		/* we allocated the lut during itree_create(), so free it */
469*0Sstevel@tonic-gate 		lut_free(dn->u.stmt.lutp, instances_destructor, NULL);
470*0Sstevel@tonic-gate 		dn->u.stmt.lutp = NULL;
471*0Sstevel@tonic-gate 	}
472*0Sstevel@tonic-gate 	tree_free(dn);
473*0Sstevel@tonic-gate }
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate /*
476*0Sstevel@tonic-gate  * event_cmp -- used via lut_lookup/lut_add on instance tree lut
477*0Sstevel@tonic-gate  */
478*0Sstevel@tonic-gate static int
479*0Sstevel@tonic-gate event_cmp(struct event *ep1, struct event *ep2)
480*0Sstevel@tonic-gate {
481*0Sstevel@tonic-gate 	int diff;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	if ((diff = ep2->enode->u.event.ename->u.name.s -
484*0Sstevel@tonic-gate 	    ep1->enode->u.event.ename->u.name.s) != 0)
485*0Sstevel@tonic-gate 		return (diff);
486*0Sstevel@tonic-gate 	if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0)
487*0Sstevel@tonic-gate 		return (diff);
488*0Sstevel@tonic-gate 	return (0);
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate }
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate struct event *
493*0Sstevel@tonic-gate itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp)
494*0Sstevel@tonic-gate {
495*0Sstevel@tonic-gate 	struct event searchevent;	/* just used for searching */
496*0Sstevel@tonic-gate 	struct node searcheventnode;
497*0Sstevel@tonic-gate 	struct node searchenamenode;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	searchevent.enode = &searcheventnode;
500*0Sstevel@tonic-gate 	searcheventnode.t = T_EVENT;
501*0Sstevel@tonic-gate 	searcheventnode.u.event.ename = &searchenamenode;
502*0Sstevel@tonic-gate 	searchenamenode.t = T_NAME;
503*0Sstevel@tonic-gate 	searchenamenode.u.name.s = ename;
504*0Sstevel@tonic-gate 	searchevent.ipp = ipp;
505*0Sstevel@tonic-gate 	return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp));
506*0Sstevel@tonic-gate }
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate static struct event *
509*0Sstevel@tonic-gate find_or_add_event(struct info *infop, struct node *np)
510*0Sstevel@tonic-gate {
511*0Sstevel@tonic-gate 	struct event *ret;
512*0Sstevel@tonic-gate 	struct event searchevent;	/* just used for searching */
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	ASSERTeq(np->t, T_EVENT, ptree_nodetype2str);
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	searchevent.enode = np;
517*0Sstevel@tonic-gate 	searchevent.ipp = ipath(np->u.event.epname);
518*0Sstevel@tonic-gate 	if ((ret = lut_lookup(infop->lut, (void *)&searchevent,
519*0Sstevel@tonic-gate 	    (lut_cmp)event_cmp)) != NULL)
520*0Sstevel@tonic-gate 		return (ret);
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	/* wasn't already in tree, allocate it */
523*0Sstevel@tonic-gate 	ret = MALLOC(sizeof (*ret));
524*0Sstevel@tonic-gate 	bzero(ret, sizeof (*ret));
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 	ret->t = np->u.event.ename->u.name.t;
527*0Sstevel@tonic-gate 	ret->enode = np;
528*0Sstevel@tonic-gate 	ret->ipp = searchevent.ipp;
529*0Sstevel@tonic-gate 	ret->props = props2instance(np, np->u.event.epname);
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret,
532*0Sstevel@tonic-gate 	    (lut_cmp)event_cmp);
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	return (ret);
535*0Sstevel@tonic-gate }
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate /*
538*0Sstevel@tonic-gate  * hmatch_event -- perform any appropriate horizontal expansion on an event
539*0Sstevel@tonic-gate  *
540*0Sstevel@tonic-gate  * this routine is used to perform horizontal expansion on both the
541*0Sstevel@tonic-gate  * left-hand-side events in a prop, and the right-hand-side events.
542*0Sstevel@tonic-gate  * when called to handle a left-side event, nextnp point to the right
543*0Sstevel@tonic-gate  * side of the prop that should be passed to hmatch() for each match
544*0Sstevel@tonic-gate  * found by horizontal expansion.   when no horizontal expansion exists,
545*0Sstevel@tonic-gate  * we will still "match" one event for every event found in the list on
546*0Sstevel@tonic-gate  * the left-hand-side of the prop because vmatch() already found that
547*0Sstevel@tonic-gate  * there's at least one match during vertical expansion.
548*0Sstevel@tonic-gate  */
549*0Sstevel@tonic-gate static void
550*0Sstevel@tonic-gate hmatch_event(struct info *infop, struct node *eventnp, struct node *epname,
551*0Sstevel@tonic-gate     struct config *ncp, struct node *nextnp, int rematch)
552*0Sstevel@tonic-gate {
553*0Sstevel@tonic-gate 	if (epname == NULL) {
554*0Sstevel@tonic-gate 		/*
555*0Sstevel@tonic-gate 		 * end of pathname recursion, either we just located
556*0Sstevel@tonic-gate 		 * a left-hand-side event and we're ready to move on
557*0Sstevel@tonic-gate 		 * to the expanding the right-hand-side events, or
558*0Sstevel@tonic-gate 		 * we're further down the recursion and we just located
559*0Sstevel@tonic-gate 		 * a right-hand-side event.  the passed-in parameter
560*0Sstevel@tonic-gate 		 * "nextnp" tells us whether we're working on the left
561*0Sstevel@tonic-gate 		 * side and need to move on to nextnp, or if nextnp is
562*0Sstevel@tonic-gate 		 * NULL, we're working on the right side.
563*0Sstevel@tonic-gate 		 */
564*0Sstevel@tonic-gate 		if (nextnp) {
565*0Sstevel@tonic-gate 			/*
566*0Sstevel@tonic-gate 			 * finished a left side expansion, move on to right.
567*0Sstevel@tonic-gate 			 * tell generate() what event we just matched so
568*0Sstevel@tonic-gate 			 * it can be used at the source of any arrows
569*0Sstevel@tonic-gate 			 * we generate as we match events on the right side.
570*0Sstevel@tonic-gate 			 */
571*0Sstevel@tonic-gate 			generate_from(eventnp,
572*0Sstevel@tonic-gate 			    find_or_add_event(infop, eventnp));
573*0Sstevel@tonic-gate 			hmatch(infop, nextnp, NULL);
574*0Sstevel@tonic-gate 		} else {
575*0Sstevel@tonic-gate 			/*
576*0Sstevel@tonic-gate 			 * finished a right side expansion.  tell generate
577*0Sstevel@tonic-gate 			 * the information about the destination and let
578*0Sstevel@tonic-gate 			 * it construct the arrows as appropriate.
579*0Sstevel@tonic-gate 			 */
580*0Sstevel@tonic-gate 			generate_to(eventnp,
581*0Sstevel@tonic-gate 			    find_or_add_event(infop, eventnp));
582*0Sstevel@tonic-gate 			generate(infop->ex);
583*0Sstevel@tonic-gate 		}
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 		return;
586*0Sstevel@tonic-gate 	}
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 	ASSERTeq(epname->t, T_NAME, ptree_nodetype2str);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	/*
591*0Sstevel@tonic-gate 	 * we only get here when eventnp already has a completely
592*0Sstevel@tonic-gate 	 * instanced epname in it already.  so we first recurse
593*0Sstevel@tonic-gate 	 * down to the end of the name and as the recursion pops
594*0Sstevel@tonic-gate 	 * up, we look for opportunities to advance horizontal
595*0Sstevel@tonic-gate 	 * expansions on to the next match.  when we do advance
596*0Sstevel@tonic-gate 	 * horizontal expansions, we potentially render all cp
597*0Sstevel@tonic-gate 	 * pointers on all components to the right as invalid,
598*0Sstevel@tonic-gate 	 * so we pass in an "ncp" config handle so matching against
599*0Sstevel@tonic-gate 	 * the config can happen.
600*0Sstevel@tonic-gate 	 */
601*0Sstevel@tonic-gate 	if (rematch) {
602*0Sstevel@tonic-gate 		struct config *ocp = epname->u.name.cp;
603*0Sstevel@tonic-gate 		char *ncp_s;
604*0Sstevel@tonic-gate 		int ncp_num, num;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 		for (; ncp; ncp = config_next(ncp)) {
607*0Sstevel@tonic-gate 			config_getcompname(ncp, &ncp_s, &ncp_num);
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 			if (ncp_s == epname->u.name.s) {
610*0Sstevel@tonic-gate 				/* found a matching component name */
611*0Sstevel@tonic-gate 				config_getcompname(epname->u.name.cp,
612*0Sstevel@tonic-gate 				    NULL, &num);
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 				if (epname->u.name.it != IT_HORIZONTAL &&
615*0Sstevel@tonic-gate 				    ncp_num != num)
616*0Sstevel@tonic-gate 					continue;
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 				epname->u.name.cp = ncp;
619*0Sstevel@tonic-gate 				hmatch_event(infop, eventnp,
620*0Sstevel@tonic-gate 				    epname->u.name.next, config_child(ncp),
621*0Sstevel@tonic-gate 				    nextnp, 1);
622*0Sstevel@tonic-gate 			}
623*0Sstevel@tonic-gate 		}
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 		epname->u.name.cp = ocp;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 		return;		/* no more config to match against */
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	} else {
630*0Sstevel@tonic-gate 		hmatch_event(infop, eventnp, epname->u.name.next, ncp,
631*0Sstevel@tonic-gate 		    nextnp, 0);
632*0Sstevel@tonic-gate 	}
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	if (epname->u.name.it == IT_HORIZONTAL) {
635*0Sstevel@tonic-gate 		struct config *cp;
636*0Sstevel@tonic-gate 		struct config *ocp = epname->u.name.cp;
637*0Sstevel@tonic-gate 		char *cp_s;
638*0Sstevel@tonic-gate 		int cp_num;
639*0Sstevel@tonic-gate 		int ocp_num;
640*0Sstevel@tonic-gate 		struct iterinfo *iterinfop = NULL;
641*0Sstevel@tonic-gate 		const char *iters;
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 		config_getcompname(ocp, NULL, &ocp_num);
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 		for (cp = config_next(ocp); cp; cp = config_next(cp)) {
646*0Sstevel@tonic-gate 			config_getcompname(cp, &cp_s, &cp_num);
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 			if (cp_s == epname->u.name.s) {
649*0Sstevel@tonic-gate 				ASSERT(epname->u.name.child != NULL);
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 				iters = epname->u.name.child->u.name.s;
652*0Sstevel@tonic-gate 				if ((iterinfop = lut_lookup(infop->ex,
653*0Sstevel@tonic-gate 				    (void *)iters, NULL)) == NULL) {
654*0Sstevel@tonic-gate 					out(O_DIE,
655*0Sstevel@tonic-gate 					    "hmatch_event: internal error: "
656*0Sstevel@tonic-gate 					    "iterator \"%s\" undefined", iters);
657*0Sstevel@tonic-gate 				} else {
658*0Sstevel@tonic-gate 					/* advance dict entry to next match */
659*0Sstevel@tonic-gate 					iterinfop->num = cp_num;
660*0Sstevel@tonic-gate 				}
661*0Sstevel@tonic-gate 				epname->u.name.cp = cp;
662*0Sstevel@tonic-gate 				hmatch_event(infop, eventnp,
663*0Sstevel@tonic-gate 				    epname->u.name.next, config_child(cp),
664*0Sstevel@tonic-gate 				    nextnp, 1);
665*0Sstevel@tonic-gate 			}
666*0Sstevel@tonic-gate 		}
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 		if (iterinfop != NULL) {
669*0Sstevel@tonic-gate 			/* restore dict entry */
670*0Sstevel@tonic-gate 			iterinfop->num = ocp_num;
671*0Sstevel@tonic-gate 		}
672*0Sstevel@tonic-gate 		epname->u.name.cp = ocp;
673*0Sstevel@tonic-gate 	}
674*0Sstevel@tonic-gate }
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate /*
677*0Sstevel@tonic-gate  * hmatch -- check for horizontal expansion matches
678*0Sstevel@tonic-gate  *
679*0Sstevel@tonic-gate  * np points to the things we're matching (like a T_LIST or a T_EVENT)
680*0Sstevel@tonic-gate  * and if we're working on a left-side of a prop, nextnp points to
681*0Sstevel@tonic-gate  * the other side of the prop that we'll tackle next when this recursion
682*0Sstevel@tonic-gate  * bottoms out.  when all the events in the entire prop arrow have been
683*0Sstevel@tonic-gate  * horizontally expanded, generate() will be called to generate the
684*0Sstevel@tonic-gate  * actualy arrow.
685*0Sstevel@tonic-gate  */
686*0Sstevel@tonic-gate static void
687*0Sstevel@tonic-gate hmatch(struct info *infop, struct node *np, struct node *nextnp)
688*0Sstevel@tonic-gate {
689*0Sstevel@tonic-gate 	if (np == NULL)
690*0Sstevel@tonic-gate 		return;		/* all done */
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	/*
693*0Sstevel@tonic-gate 	 * for each item in the list of events (which could just
694*0Sstevel@tonic-gate 	 * be a single event, or it could get larger in the loop
695*0Sstevel@tonic-gate 	 * below due to horizontal expansion), call hmatch on
696*0Sstevel@tonic-gate 	 * the right side and create arrows to each element.
697*0Sstevel@tonic-gate 	 */
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	switch (np->t) {
700*0Sstevel@tonic-gate 	case T_LIST:
701*0Sstevel@tonic-gate 		/* loop through the list */
702*0Sstevel@tonic-gate 		if (np->u.expr.left)
703*0Sstevel@tonic-gate 			hmatch(infop, np->u.expr.left, nextnp);
704*0Sstevel@tonic-gate 		if (np->u.expr.right)
705*0Sstevel@tonic-gate 			hmatch(infop, np->u.expr.right, nextnp);
706*0Sstevel@tonic-gate 		break;
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	case T_EVENT:
709*0Sstevel@tonic-gate 		hmatch_event(infop, np, np->u.event.epname,
710*0Sstevel@tonic-gate 		    NULL, nextnp, 0);
711*0Sstevel@tonic-gate 		break;
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	default:
714*0Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
715*0Sstevel@tonic-gate 		    "hmatch: unexpected type: %s",
716*0Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
717*0Sstevel@tonic-gate 	}
718*0Sstevel@tonic-gate }
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate static int
721*0Sstevel@tonic-gate itree_np2nork(struct node *norknp)
722*0Sstevel@tonic-gate {
723*0Sstevel@tonic-gate 	if (norknp == NULL)
724*0Sstevel@tonic-gate 		return (1);
725*0Sstevel@tonic-gate 	else if (norknp->t == T_NAME && norknp->u.name.s == L_A)
726*0Sstevel@tonic-gate 		return (-1);	/* our internal version of "all" */
727*0Sstevel@tonic-gate 	else if (norknp->t == T_NUM)
728*0Sstevel@tonic-gate 		return ((int)norknp->u.ull);
729*0Sstevel@tonic-gate 	else
730*0Sstevel@tonic-gate 		out(O_DIE, norknp->file, norknp->line,
731*0Sstevel@tonic-gate 		    "itree_np2nork: internal error type %s",
732*0Sstevel@tonic-gate 		    ptree_nodetype2str(norknp->t));
733*0Sstevel@tonic-gate 	/*NOTREACHED*/
734*0Sstevel@tonic-gate }
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate static struct iterinfo *
737*0Sstevel@tonic-gate newiterinfo(int num, struct node *np)
738*0Sstevel@tonic-gate {
739*0Sstevel@tonic-gate 	struct iterinfo *ret = MALLOC(sizeof (*ret));
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	ret->num = num;
742*0Sstevel@tonic-gate 	ret->np = np;
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	return (ret);
745*0Sstevel@tonic-gate }
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate /*ARGSUSED*/
748*0Sstevel@tonic-gate static void
749*0Sstevel@tonic-gate iterinfo_destructor(void *left, void *right, void *arg)
750*0Sstevel@tonic-gate {
751*0Sstevel@tonic-gate 	struct iterinfo *iterinfop = (struct iterinfo *)right;
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	bzero(iterinfop, sizeof (*iterinfop));
754*0Sstevel@tonic-gate 	FREE(iterinfop);
755*0Sstevel@tonic-gate }
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate /*
758*0Sstevel@tonic-gate  * update epname to include the wildcarded portion
759*0Sstevel@tonic-gate  */
760*0Sstevel@tonic-gate static void
761*0Sstevel@tonic-gate create_wildcardedpath(struct wildcardinfo **wcproot)
762*0Sstevel@tonic-gate {
763*0Sstevel@tonic-gate 	struct wildcardinfo *wcp;
764*0Sstevel@tonic-gate 	struct node *nptop;
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 	wcp = *wcproot;
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	if (wcp->s == WC_UNDERCONSTRUCTION) {
769*0Sstevel@tonic-gate 		ASSERT(wcp->p->refcount == 1);
770*0Sstevel@tonic-gate 		wcp->s = WC_COMPLETE;
771*0Sstevel@tonic-gate 	}
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	/* path has no wildcard */
774*0Sstevel@tonic-gate 	if (wcp->p->ewname == NULL)
775*0Sstevel@tonic-gate 		return;
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	/*
778*0Sstevel@tonic-gate 	 * get to this point if a wildcard portion of the path exists.
779*0Sstevel@tonic-gate 	 *
780*0Sstevel@tonic-gate 	 * first set oldepname to the start of the existing epname for use
781*0Sstevel@tonic-gate 	 * in future comparisons, then update epname to include the
782*0Sstevel@tonic-gate 	 * wildcard portion.
783*0Sstevel@tonic-gate 	 */
784*0Sstevel@tonic-gate 	nptop = wcp->nptop;
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	ASSERT(wcp->oldepname == nptop->u.event.epname);
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 	nptop->u.event.epname =	tname_dup(wcp->p->ewname, CN_DUP);
789*0Sstevel@tonic-gate 	nptop->u.event.epname = tree_name_append(nptop->u.event.epname,
790*0Sstevel@tonic-gate 					tname_dup(wcp->oldepname, CN_DUP));
791*0Sstevel@tonic-gate }
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate /*
794*0Sstevel@tonic-gate  * restore epname to its former (nonwildcarded) state
795*0Sstevel@tonic-gate  */
796*0Sstevel@tonic-gate static void
797*0Sstevel@tonic-gate undo_wildcardedpath(struct wildcardinfo **wcproot)
798*0Sstevel@tonic-gate {
799*0Sstevel@tonic-gate 	struct wildcardinfo *wcp;
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 	wcp = *wcproot;
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	if (wcp->s == WC_COMPLETE) {
804*0Sstevel@tonic-gate 		ASSERT(wcp->p->refcount == 1);
805*0Sstevel@tonic-gate 		wcp->s = WC_UNDERCONSTRUCTION;
806*0Sstevel@tonic-gate 	}
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 	/* path has no wildcard */
809*0Sstevel@tonic-gate 	if (wcp->p->ewname == NULL)
810*0Sstevel@tonic-gate 		return;
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	ASSERT(wcp->oldepname != NULL);
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	tree_free(wcp->nptop->u.event.epname);
815*0Sstevel@tonic-gate 	wcp->nptop->u.event.epname = wcp->oldepname;
816*0Sstevel@tonic-gate }
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate static void
819*0Sstevel@tonic-gate vmatch_event(struct info *infop, struct config *cp, struct node *np,
820*0Sstevel@tonic-gate 	    struct node *lnp, struct node *anp,
821*0Sstevel@tonic-gate 	    struct wildcardinfo **wcproot, int dowildcard)
822*0Sstevel@tonic-gate {
823*0Sstevel@tonic-gate 	struct wildcardinfo *wcp;
824*0Sstevel@tonic-gate 	char *cp_s;
825*0Sstevel@tonic-gate 	int cp_num;
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 	wcp = *wcproot;
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	if ((np == NULL && wcp->oldepname != NULL) ||
830*0Sstevel@tonic-gate 	    (cp == NULL && wcp->oldepname == NULL)) {
831*0Sstevel@tonic-gate 		/*
832*0Sstevel@tonic-gate 		 * the pathname matched the config (but not necessarily a
833*0Sstevel@tonic-gate 		 * match at the end)
834*0Sstevel@tonic-gate 		 */
835*0Sstevel@tonic-gate 		create_wildcardedpath(wcproot);
836*0Sstevel@tonic-gate 		vmatch(infop, np, lnp, anp, wcproot);
837*0Sstevel@tonic-gate 		undo_wildcardedpath(wcproot);
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 		if (cp != NULL && wcp->s == WC_UNDERCONSTRUCTION) {
840*0Sstevel@tonic-gate 			/*
841*0Sstevel@tonic-gate 			 * pathname match did not occur at the end of the
842*0Sstevel@tonic-gate 			 * configuration path.  more matches may be found
843*0Sstevel@tonic-gate 			 * later in the path, so we set cpforcedwc to force
844*0Sstevel@tonic-gate 			 * wildcarding for startcp.
845*0Sstevel@tonic-gate 			 *
846*0Sstevel@tonic-gate 			 * note that cpforcedwc may already have been set
847*0Sstevel@tonic-gate 			 * in an earlier match due to vertical expansion on
848*0Sstevel@tonic-gate 			 * the nonwildcarded epname.
849*0Sstevel@tonic-gate 			 */
850*0Sstevel@tonic-gate 			if (wcp->p->cpforcedwc != wcp->p->cpstart) {
851*0Sstevel@tonic-gate 				ASSERT(wcp->p->cpforcedwc == NULL);
852*0Sstevel@tonic-gate 				wcp->p->cpforcedwc = wcp->p->cpstart;
853*0Sstevel@tonic-gate 			}
854*0Sstevel@tonic-gate 		}
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 		return;
857*0Sstevel@tonic-gate 	}
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	if (cp == NULL)
860*0Sstevel@tonic-gate 		return;	/* no more config to match against */
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 	for (; cp; cp = config_next(cp)) {
863*0Sstevel@tonic-gate 		config_getcompname(cp, &cp_s, &cp_num);
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 		if (cp_s == np->u.name.s &&
866*0Sstevel@tonic-gate 		    ! (wcp->s == WC_UNDERCONSTRUCTION &&
867*0Sstevel@tonic-gate 		    cp == wcp->p->cpstart &&
868*0Sstevel@tonic-gate 		    wcp->p->cpstart == wcp->p->cpforcedwc)) {
869*0Sstevel@tonic-gate 			/* found a matching component name */
870*0Sstevel@tonic-gate 			if (np->u.name.child &&
871*0Sstevel@tonic-gate 			    np->u.name.child->t == T_NUM) {
872*0Sstevel@tonic-gate 				/*
873*0Sstevel@tonic-gate 				 * an explicit instance number was given
874*0Sstevel@tonic-gate 				 * in the source.  so only consider this
875*0Sstevel@tonic-gate 				 * a configuration match if the number
876*0Sstevel@tonic-gate 				 * also matches.
877*0Sstevel@tonic-gate 				 */
878*0Sstevel@tonic-gate 				if (cp_num != np->u.name.child->u.ull)
879*0Sstevel@tonic-gate 					continue;
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 				np->u.name.cp = cp;
882*0Sstevel@tonic-gate 			} else {
883*0Sstevel@tonic-gate 				struct iterinfo *iterinfop;
884*0Sstevel@tonic-gate 				const char *iters;
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 				/*
887*0Sstevel@tonic-gate 				 * vertical iterator.  look it up in
888*0Sstevel@tonic-gate 				 * the appropriate lut and if we get
889*0Sstevel@tonic-gate 				 * back a value it is either one that we
890*0Sstevel@tonic-gate 				 * set earlier, in which case we record
891*0Sstevel@tonic-gate 				 * the new value for this iteration and
892*0Sstevel@tonic-gate 				 * keep matching, or it is one that was
893*0Sstevel@tonic-gate 				 * set by an earlier reference to the
894*0Sstevel@tonic-gate 				 * iterator, in which case we only consider
895*0Sstevel@tonic-gate 				 * this a configuration match if the number
896*0Sstevel@tonic-gate 				 * matches cp_num.
897*0Sstevel@tonic-gate 				 */
898*0Sstevel@tonic-gate 
899*0Sstevel@tonic-gate 				ASSERT(np->u.name.child != NULL);
900*0Sstevel@tonic-gate 				ASSERT(np->u.name.child->t == T_NAME);
901*0Sstevel@tonic-gate 				iters = np->u.name.child->u.name.s;
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 				if ((iterinfop = lut_lookup(infop->ex,
904*0Sstevel@tonic-gate 				    (void *)iters, NULL)) == NULL) {
905*0Sstevel@tonic-gate 					/* we're the first use, record our np */
906*0Sstevel@tonic-gate 					infop->ex = lut_add(infop->ex,
907*0Sstevel@tonic-gate 					    (void *)iters,
908*0Sstevel@tonic-gate 					    newiterinfo(cp_num, np), NULL);
909*0Sstevel@tonic-gate 				} else if (np == iterinfop->np) {
910*0Sstevel@tonic-gate 					/*
911*0Sstevel@tonic-gate 					 * we're the first use, back again
912*0Sstevel@tonic-gate 					 * for another iteration.  so update
913*0Sstevel@tonic-gate 					 * the num bound to this iterator in
914*0Sstevel@tonic-gate 					 * the lut.
915*0Sstevel@tonic-gate 					 */
916*0Sstevel@tonic-gate 					iterinfop->num = cp_num;
917*0Sstevel@tonic-gate 				} else if (cp_num != iterinfop->num) {
918*0Sstevel@tonic-gate 					/*
919*0Sstevel@tonic-gate 					 * an earlier reference to this
920*0Sstevel@tonic-gate 					 * iterator bound it to a different
921*0Sstevel@tonic-gate 					 * instance number, so there's no
922*0Sstevel@tonic-gate 					 * match here after all.
923*0Sstevel@tonic-gate 					 */
924*0Sstevel@tonic-gate 					continue;
925*0Sstevel@tonic-gate 				}
926*0Sstevel@tonic-gate 				np->u.name.cp = cp;
927*0Sstevel@tonic-gate 			}
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 			/*
930*0Sstevel@tonic-gate 			 * if wildcarding was done in a call earlier in the
931*0Sstevel@tonic-gate 			 * stack, record the current cp as the first
932*0Sstevel@tonic-gate 			 * matching and nonwildcarded cp.
933*0Sstevel@tonic-gate 			 */
934*0Sstevel@tonic-gate 			if (dowildcard && wcp->s == WC_UNDERCONSTRUCTION)
935*0Sstevel@tonic-gate 				wcp->p->cpstart = cp;
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 			/*
938*0Sstevel@tonic-gate 			 * if this was an IT_HORIZONTAL name,
939*0Sstevel@tonic-gate 			 * hmatch() will use the cp to expand
940*0Sstevel@tonic-gate 			 * all matches horizontally into a list.
941*0Sstevel@tonic-gate 			 * we know the list will contain at least
942*0Sstevel@tonic-gate 			 * one element (the one we just matched),
943*0Sstevel@tonic-gate 			 * so we just store cp and let hmatch_event()
944*0Sstevel@tonic-gate 			 * do the rest.
945*0Sstevel@tonic-gate 			 *
946*0Sstevel@tonic-gate 			 * recurse on to next component.  note that
947*0Sstevel@tonic-gate 			 * wildcarding is now turned off.
948*0Sstevel@tonic-gate 			 */
949*0Sstevel@tonic-gate 			vmatch_event(infop, config_child(cp), np->u.name.next,
950*0Sstevel@tonic-gate 				    lnp, anp, wcproot, 0);
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 			/*
953*0Sstevel@tonic-gate 			 * if wildcarding is being forced for this
954*0Sstevel@tonic-gate 			 * component, repeat call to vmatch_event() with
955*0Sstevel@tonic-gate 			 * the same np
956*0Sstevel@tonic-gate 			 */
957*0Sstevel@tonic-gate 			if (dowildcard &&
958*0Sstevel@tonic-gate 			    wcp->s == WC_UNDERCONSTRUCTION &&
959*0Sstevel@tonic-gate 			    cp == wcp->p->cpforcedwc) {
960*0Sstevel@tonic-gate 				vmatch_event(infop, cp, np, lnp, anp,
961*0Sstevel@tonic-gate 					    wcproot, 1);
962*0Sstevel@tonic-gate 			}
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 			if (np->u.name.it == IT_HORIZONTAL) {
965*0Sstevel@tonic-gate 				/*
966*0Sstevel@tonic-gate 				 * hmatch() finished iterating through
967*0Sstevel@tonic-gate 				 * the configuration as described above, so
968*0Sstevel@tonic-gate 				 * don't continue iterating here.
969*0Sstevel@tonic-gate 				 */
970*0Sstevel@tonic-gate 				return;
971*0Sstevel@tonic-gate 			}
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 		} else if (dowildcard && wcp->s == WC_UNDERCONSTRUCTION) {
974*0Sstevel@tonic-gate 			/*
975*0Sstevel@tonic-gate 			 * no matching cp, and we are constructing our own
976*0Sstevel@tonic-gate 			 * wildcard path.  (in other words, we are not
977*0Sstevel@tonic-gate 			 * referencing a wildcard path created for an
978*0Sstevel@tonic-gate 			 * earlier event.)
979*0Sstevel@tonic-gate 			 *
980*0Sstevel@tonic-gate 			 * add wildcard entry, then recurse on to config
981*0Sstevel@tonic-gate 			 * child
982*0Sstevel@tonic-gate 			 */
983*0Sstevel@tonic-gate 			struct node *cpnode, *prevlast;
984*0Sstevel@tonic-gate 
985*0Sstevel@tonic-gate 			if (wcp->p->cpstart == wcp->p->cpforcedwc)
986*0Sstevel@tonic-gate 				wcp->p->cpforcedwc = NULL;
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 			cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
989*0Sstevel@tonic-gate 			cpnode->u.name.child = newnode(T_NUM, NULL, 0);
990*0Sstevel@tonic-gate 			cpnode->u.name.child->u.ull = cp_num;
991*0Sstevel@tonic-gate 			cpnode->u.name.cp = cp;
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 			if (wcp->p->ewname == NULL) {
994*0Sstevel@tonic-gate 				prevlast = NULL;
995*0Sstevel@tonic-gate 				wcp->p->ewname = cpnode;
996*0Sstevel@tonic-gate 			} else {
997*0Sstevel@tonic-gate 				prevlast = wcp->p->ewname->u.name.last;
998*0Sstevel@tonic-gate 				wcp->p->ewname =
999*0Sstevel@tonic-gate 					tree_name_append(wcp->p->ewname,
1000*0Sstevel@tonic-gate 							    cpnode);
1001*0Sstevel@tonic-gate 			}
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 			vmatch_event(infop, config_child(cp), np, lnp, anp,
1004*0Sstevel@tonic-gate 				    wcproot, 1);
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate 			/*
1007*0Sstevel@tonic-gate 			 * back out last addition to ewname and continue
1008*0Sstevel@tonic-gate 			 * with loop
1009*0Sstevel@tonic-gate 			 */
1010*0Sstevel@tonic-gate 			tree_free(cpnode);
1011*0Sstevel@tonic-gate 			if (prevlast == NULL) {
1012*0Sstevel@tonic-gate 				wcp->p->ewname = NULL;
1013*0Sstevel@tonic-gate 			} else {
1014*0Sstevel@tonic-gate 				prevlast->u.name.next = NULL;
1015*0Sstevel@tonic-gate 				wcp->p->ewname->u.name.last = prevlast;
1016*0Sstevel@tonic-gate 			}
1017*0Sstevel@tonic-gate 		}
1018*0Sstevel@tonic-gate 	}
1019*0Sstevel@tonic-gate }
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate /*
1022*0Sstevel@tonic-gate  * for the event node np, which will be subjected to pathname
1023*0Sstevel@tonic-gate  * expansion/matching, create a (struct wildcardinfo) to hold wildcard
1024*0Sstevel@tonic-gate  * information.  this struct will be inserted into the first location in
1025*0Sstevel@tonic-gate  * the list that starts with *wcproot.
1026*0Sstevel@tonic-gate  *
1027*0Sstevel@tonic-gate  * cp is the starting node of the configuration; cpstart, which is output,
1028*0Sstevel@tonic-gate  * is the starting node of the nonwildcarded portion of the path.
1029*0Sstevel@tonic-gate  */
1030*0Sstevel@tonic-gate static void
1031*0Sstevel@tonic-gate add_wildcardentry(struct wildcardinfo **wcproot, struct config *cp,
1032*0Sstevel@tonic-gate 		struct node *np, struct config **cpstart)
1033*0Sstevel@tonic-gate {
1034*0Sstevel@tonic-gate 	struct wildcardinfo *wcpnew, *wcp;
1035*0Sstevel@tonic-gate 	struct node *np1, *np2;
1036*0Sstevel@tonic-gate 
1037*0Sstevel@tonic-gate 	/*
1038*0Sstevel@tonic-gate 	 * create entry for np
1039*0Sstevel@tonic-gate 	 */
1040*0Sstevel@tonic-gate 	wcpnew = MALLOC(sizeof (struct wildcardinfo));
1041*0Sstevel@tonic-gate 	bzero(wcpnew, sizeof (struct wildcardinfo));
1042*0Sstevel@tonic-gate 	wcpnew->nptop = np;
1043*0Sstevel@tonic-gate 	wcpnew->oldepname = np->u.event.epname;
1044*0Sstevel@tonic-gate 	np2 = wcpnew->oldepname;
1045*0Sstevel@tonic-gate 
1046*0Sstevel@tonic-gate 	/*
1047*0Sstevel@tonic-gate 	 * search all completed entries for an epname whose first entry
1048*0Sstevel@tonic-gate 	 * matches.  note that NULL epnames are considered valid and can be
1049*0Sstevel@tonic-gate 	 * matched.
1050*0Sstevel@tonic-gate 	 */
1051*0Sstevel@tonic-gate 	for (wcp = *wcproot; wcp; wcp = wcp->next) {
1052*0Sstevel@tonic-gate 		ASSERT(wcp->s == WC_COMPLETE || wcp->s == WC_REFERENCING);
1053*0Sstevel@tonic-gate 		if (wcp->s != WC_COMPLETE)
1054*0Sstevel@tonic-gate 			continue;
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate 		np1 = wcp->oldepname;
1057*0Sstevel@tonic-gate 		if ((np1 && np2 && np1->u.name.s == np2->u.name.s) ||
1058*0Sstevel@tonic-gate 		    (np1 == NULL && np2 == NULL)) {
1059*0Sstevel@tonic-gate 			wcpnew->p = wcp->p;
1060*0Sstevel@tonic-gate 			wcpnew->s = WC_REFERENCING;
1061*0Sstevel@tonic-gate 
1062*0Sstevel@tonic-gate 			wcp->p->refcount++;
1063*0Sstevel@tonic-gate 			break;
1064*0Sstevel@tonic-gate 		}
1065*0Sstevel@tonic-gate 	}
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	if (wcpnew->p == NULL) {
1068*0Sstevel@tonic-gate 		wcpnew->s = WC_UNDERCONSTRUCTION;
1069*0Sstevel@tonic-gate 
1070*0Sstevel@tonic-gate 		wcpnew->p = MALLOC(sizeof (struct wildcardpath));
1071*0Sstevel@tonic-gate 		bzero(wcpnew->p, sizeof (struct wildcardpath));
1072*0Sstevel@tonic-gate 		wcpnew->p->cpstart = cp;
1073*0Sstevel@tonic-gate 		wcpnew->p->refcount = 1;
1074*0Sstevel@tonic-gate 	}
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 	wcpnew->next = *wcproot;
1077*0Sstevel@tonic-gate 	*wcproot = wcpnew;
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate 	*cpstart = wcpnew->p->cpstart;
1080*0Sstevel@tonic-gate }
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate static void
1083*0Sstevel@tonic-gate delete_wildcardentry(struct wildcardinfo **wcproot)
1084*0Sstevel@tonic-gate {
1085*0Sstevel@tonic-gate 	struct wildcardinfo *wcp;
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	wcp = *wcproot;
1088*0Sstevel@tonic-gate 	*wcproot = wcp->next;
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	switch (wcp->s) {
1091*0Sstevel@tonic-gate 	case WC_UNDERCONSTRUCTION:
1092*0Sstevel@tonic-gate 	case WC_COMPLETE:
1093*0Sstevel@tonic-gate 		ASSERT(wcp->p->refcount == 1);
1094*0Sstevel@tonic-gate 		tree_free(wcp->p->ewname);
1095*0Sstevel@tonic-gate 		FREE(wcp->p);
1096*0Sstevel@tonic-gate 		break;
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	case WC_REFERENCING:
1099*0Sstevel@tonic-gate 		ASSERT(wcp->p->refcount > 1);
1100*0Sstevel@tonic-gate 		wcp->p->refcount--;
1101*0Sstevel@tonic-gate 		break;
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate 	default:
1104*0Sstevel@tonic-gate 		out(O_DIE, "deletewc: invalid status");
1105*0Sstevel@tonic-gate 		break;
1106*0Sstevel@tonic-gate 	}
1107*0Sstevel@tonic-gate 
1108*0Sstevel@tonic-gate 	FREE(wcp);
1109*0Sstevel@tonic-gate }
1110*0Sstevel@tonic-gate 
1111*0Sstevel@tonic-gate /*
1112*0Sstevel@tonic-gate  * vmatch -- find the next vertical expansion match in the config database
1113*0Sstevel@tonic-gate  *
1114*0Sstevel@tonic-gate  * this routine is called with three node pointers:
1115*0Sstevel@tonic-gate  *	 np -- the parse we're matching
1116*0Sstevel@tonic-gate  *	lnp -- the rest of the list we're currently working on
1117*0Sstevel@tonic-gate  *	anp -- the rest of the arrow we're currently working on
1118*0Sstevel@tonic-gate  *
1119*0Sstevel@tonic-gate  * the expansion matching happens via three types of recursion:
1120*0Sstevel@tonic-gate  *
1121*0Sstevel@tonic-gate  *	- when given an arrow, handle the left-side and then recursively
1122*0Sstevel@tonic-gate  *	  handle the right side (which might be another cascaded arrow).
1123*0Sstevel@tonic-gate  *
1124*0Sstevel@tonic-gate  *	- when handling one side of an arrow, recurse through the T_LIST
1125*0Sstevel@tonic-gate  *	  to get to each event (or just move on to the event if there
1126*0Sstevel@tonic-gate  *	  is a single event instead of a list)  since the arrow parse
1127*0Sstevel@tonic-gate  *	  trees recurse left, we actually start with the right-most
1128*0Sstevel@tonic-gate  *	  event list in the prop statement and work our way towards
1129*0Sstevel@tonic-gate  *	  the left-most event list.
1130*0Sstevel@tonic-gate  *
1131*0Sstevel@tonic-gate  *	- when handling an event, recurse down each component of the
1132*0Sstevel@tonic-gate  *	  pathname, matching in the config database and recording the
1133*0Sstevel@tonic-gate  *	  matches in the explicit iterator dictionary as we go.
1134*0Sstevel@tonic-gate  *
1135*0Sstevel@tonic-gate  * when the bottom of this matching recursion is met, meaning we have
1136*0Sstevel@tonic-gate  * set the "cp" pointers on all the names in the entire statement,
1137*0Sstevel@tonic-gate  * we call hmatch() which does it's own recursion to handle horizontal
1138*0Sstevel@tonic-gate  * expandsion and then call generate() to generate nodes, bubbles, and
1139*0Sstevel@tonic-gate  * arrows in the instance tree.  generate() looks at the cp pointers to
1140*0Sstevel@tonic-gate  * see what instance numbers were matched in the configuration database.
1141*0Sstevel@tonic-gate  *
1142*0Sstevel@tonic-gate  * when horizontal expansion appears, vmatch() finds only the first match
1143*0Sstevel@tonic-gate  * and hmatch() then takes the horizontal expansion through all the other
1144*0Sstevel@tonic-gate  * matches when generating the arrows in the instance tree.
1145*0Sstevel@tonic-gate  *
1146*0Sstevel@tonic-gate  * the "infop" passed down through the recursion contains a dictionary
1147*0Sstevel@tonic-gate  * of the explicit iterators (all the implicit iterators have been converted
1148*0Sstevel@tonic-gate  * to explicit iterators when the parse tree was created by tree.c), which
1149*0Sstevel@tonic-gate  * allows things like this to work correctly:
1150*0Sstevel@tonic-gate  *
1151*0Sstevel@tonic-gate  *	prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n];
1152*0Sstevel@tonic-gate  *
1153*0Sstevel@tonic-gate  * during the top level call, the explicit iterator "n" will match an
1154*0Sstevel@tonic-gate  * instance number in the config database, and the result will be recorded
1155*0Sstevel@tonic-gate  * in the explicit iterator dictionary and passed down via "infop".  so
1156*0Sstevel@tonic-gate  * when the recursive call tries to match y[n] in the config database, it
1157*0Sstevel@tonic-gate  * will only match the same instance number as x[n] did since the dictionary
1158*0Sstevel@tonic-gate  * is consulted to see if "n" took on a value already.
1159*0Sstevel@tonic-gate  *
1160*0Sstevel@tonic-gate  * at any point during the recursion, match*() can return to indicate
1161*0Sstevel@tonic-gate  * a match was not found in the config database and that the caller should
1162*0Sstevel@tonic-gate  * move on to the next potential match, if any.
1163*0Sstevel@tonic-gate  *
1164*0Sstevel@tonic-gate  * constraints are completely ignored by match(), so the statement:
1165*0Sstevel@tonic-gate  *
1166*0Sstevel@tonic-gate  *	prop error.a@x[n] -> error.b@x[n] {n != 0};
1167*0Sstevel@tonic-gate  *
1168*0Sstevel@tonic-gate  * might very well match x[0] if it appears in the config database.  it
1169*0Sstevel@tonic-gate  * is the generate() routine that takes that match and then decides what
1170*0Sstevel@tonic-gate  * arrow, if any, should be generated in the instance tree.  generate()
1171*0Sstevel@tonic-gate  * looks at the explicit iterator dictionary to get values like "n" in
1172*0Sstevel@tonic-gate  * the above example so that it can evaluate constraints.
1173*0Sstevel@tonic-gate  *
1174*0Sstevel@tonic-gate  */
1175*0Sstevel@tonic-gate static void
1176*0Sstevel@tonic-gate vmatch(struct info *infop, struct node *np, struct node *lnp,
1177*0Sstevel@tonic-gate     struct node *anp, struct wildcardinfo **wcproot)
1178*0Sstevel@tonic-gate {
1179*0Sstevel@tonic-gate 	if (np == NULL) {
1180*0Sstevel@tonic-gate 		if (lnp)
1181*0Sstevel@tonic-gate 			vmatch(infop, lnp, NULL, anp, wcproot);
1182*0Sstevel@tonic-gate 		else if (anp)
1183*0Sstevel@tonic-gate 			vmatch(infop, anp, NULL, NULL, wcproot);
1184*0Sstevel@tonic-gate 		else {
1185*0Sstevel@tonic-gate 			struct node *src;
1186*0Sstevel@tonic-gate 			struct node *dst;
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 			/* end of vertical match recursion */
1189*0Sstevel@tonic-gate 			outfl(O_ALTFP|O_VERB3|O_NONL,
1190*0Sstevel@tonic-gate 			    infop->anp->file, infop->anp->line, "vmatch: ");
1191*0Sstevel@tonic-gate 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp);
1192*0Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3, NULL);
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate 			generate_nork(
1195*0Sstevel@tonic-gate 			    itree_np2nork(infop->anp->u.arrow.nnp),
1196*0Sstevel@tonic-gate 			    itree_np2nork(infop->anp->u.arrow.knp));
1197*0Sstevel@tonic-gate 			dst = infop->anp->u.arrow.rhs;
1198*0Sstevel@tonic-gate 			src = infop->anp->u.arrow.lhs;
1199*0Sstevel@tonic-gate 			for (;;) {
1200*0Sstevel@tonic-gate 				generate_new();	/* new set of arrows */
1201*0Sstevel@tonic-gate 				if (src->t == T_ARROW) {
1202*0Sstevel@tonic-gate 					hmatch(infop, src->u.arrow.rhs, dst);
1203*0Sstevel@tonic-gate 					generate_nork(
1204*0Sstevel@tonic-gate 					    itree_np2nork(src->u.arrow.nnp),
1205*0Sstevel@tonic-gate 					    itree_np2nork(src->u.arrow.knp));
1206*0Sstevel@tonic-gate 					dst = src->u.arrow.rhs;
1207*0Sstevel@tonic-gate 					src = src->u.arrow.lhs;
1208*0Sstevel@tonic-gate 				} else {
1209*0Sstevel@tonic-gate 					hmatch(infop, src, dst);
1210*0Sstevel@tonic-gate 					break;
1211*0Sstevel@tonic-gate 				}
1212*0Sstevel@tonic-gate 			}
1213*0Sstevel@tonic-gate 		}
1214*0Sstevel@tonic-gate 		return;
1215*0Sstevel@tonic-gate 	}
1216*0Sstevel@tonic-gate 
1217*0Sstevel@tonic-gate 	switch (np->t) {
1218*0Sstevel@tonic-gate 	case T_EVENT: {
1219*0Sstevel@tonic-gate 		struct config *cpstart;
1220*0Sstevel@tonic-gate 
1221*0Sstevel@tonic-gate 		add_wildcardentry(wcproot, config_child(infop->croot),
1222*0Sstevel@tonic-gate 				np, &cpstart);
1223*0Sstevel@tonic-gate 		vmatch_event(infop, cpstart, np->u.event.epname, lnp, anp,
1224*0Sstevel@tonic-gate 			    wcproot, 1);
1225*0Sstevel@tonic-gate 		delete_wildcardentry(wcproot);
1226*0Sstevel@tonic-gate 		break;
1227*0Sstevel@tonic-gate 	}
1228*0Sstevel@tonic-gate 	case T_LIST:
1229*0Sstevel@tonic-gate 		ASSERT(lnp == NULL);
1230*0Sstevel@tonic-gate 		vmatch(infop, np->u.expr.right, np->u.expr.left, anp, wcproot);
1231*0Sstevel@tonic-gate 		break;
1232*0Sstevel@tonic-gate 
1233*0Sstevel@tonic-gate 	case T_ARROW:
1234*0Sstevel@tonic-gate 		ASSERT(lnp == NULL && anp == NULL);
1235*0Sstevel@tonic-gate 		vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.lhs, wcproot);
1236*0Sstevel@tonic-gate 		break;
1237*0Sstevel@tonic-gate 
1238*0Sstevel@tonic-gate 	default:
1239*0Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
1240*0Sstevel@tonic-gate 		    "vmatch: unexpected type: %s",
1241*0Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
1242*0Sstevel@tonic-gate 	}
1243*0Sstevel@tonic-gate }
1244*0Sstevel@tonic-gate 
1245*0Sstevel@tonic-gate static void
1246*0Sstevel@tonic-gate cp_reset(struct node *np)
1247*0Sstevel@tonic-gate {
1248*0Sstevel@tonic-gate 	if (np == NULL)
1249*0Sstevel@tonic-gate 		return;
1250*0Sstevel@tonic-gate 	switch (np->t) {
1251*0Sstevel@tonic-gate 	case T_NAME:
1252*0Sstevel@tonic-gate 		np->u.name.cp = NULL;
1253*0Sstevel@tonic-gate 		cp_reset(np->u.name.next);
1254*0Sstevel@tonic-gate 		break;
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate 	case T_LIST:
1257*0Sstevel@tonic-gate 		cp_reset(np->u.expr.left);
1258*0Sstevel@tonic-gate 		cp_reset(np->u.expr.right);
1259*0Sstevel@tonic-gate 		break;
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate 	case T_ARROW:
1262*0Sstevel@tonic-gate 		cp_reset(np->u.arrow.lhs);
1263*0Sstevel@tonic-gate 		cp_reset(np->u.arrow.rhs);
1264*0Sstevel@tonic-gate 		break;
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate 	case T_EVENT:
1267*0Sstevel@tonic-gate 		cp_reset(np->u.event.epname);
1268*0Sstevel@tonic-gate 		break;
1269*0Sstevel@tonic-gate 	}
1270*0Sstevel@tonic-gate }
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate /*
1273*0Sstevel@tonic-gate  * itree_create -- apply the current config to the current parse tree
1274*0Sstevel@tonic-gate  *
1275*0Sstevel@tonic-gate  * returns a lut mapping fully-instance-qualified names to struct events.
1276*0Sstevel@tonic-gate  *
1277*0Sstevel@tonic-gate  */
1278*0Sstevel@tonic-gate struct lut *
1279*0Sstevel@tonic-gate itree_create(struct config *croot)
1280*0Sstevel@tonic-gate {
1281*0Sstevel@tonic-gate 	struct lut *retval;
1282*0Sstevel@tonic-gate 	struct node *propnp;
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 	Ninfo.lut = NULL;
1285*0Sstevel@tonic-gate 	Ninfo.croot = croot;
1286*0Sstevel@tonic-gate 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
1287*0Sstevel@tonic-gate 		struct node *anp = propnp->u.stmt.np;
1288*0Sstevel@tonic-gate 		struct wildcardinfo *wcproot = NULL;
1289*0Sstevel@tonic-gate 
1290*0Sstevel@tonic-gate 		ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str);
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate 		Ninfo.anp = anp;
1293*0Sstevel@tonic-gate 		Ninfo.ex = NULL;
1294*0Sstevel@tonic-gate 
1295*0Sstevel@tonic-gate 		generate_arrownp(anp);
1296*0Sstevel@tonic-gate 		vmatch(&Ninfo, anp, NULL, NULL, &wcproot);
1297*0Sstevel@tonic-gate 
1298*0Sstevel@tonic-gate 		if (Ninfo.ex) {
1299*0Sstevel@tonic-gate 			lut_free(Ninfo.ex, iterinfo_destructor, NULL);
1300*0Sstevel@tonic-gate 			Ninfo.ex = NULL;
1301*0Sstevel@tonic-gate 		}
1302*0Sstevel@tonic-gate 		ASSERT(wcproot == NULL);
1303*0Sstevel@tonic-gate 		cp_reset(anp);
1304*0Sstevel@tonic-gate 	}
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate 	retval = Ninfo.lut;
1307*0Sstevel@tonic-gate 	Ninfo.lut = NULL;
1308*0Sstevel@tonic-gate 	return (retval);
1309*0Sstevel@tonic-gate }
1310*0Sstevel@tonic-gate 
1311*0Sstevel@tonic-gate void
1312*0Sstevel@tonic-gate itree_free(struct lut *lutp)
1313*0Sstevel@tonic-gate {
1314*0Sstevel@tonic-gate 	lut_free(lutp, itree_destructor, NULL);
1315*0Sstevel@tonic-gate }
1316*0Sstevel@tonic-gate 
1317*0Sstevel@tonic-gate int
1318*0Sstevel@tonic-gate itree_nameinstancecmp(struct node *np1, struct node *np2)
1319*0Sstevel@tonic-gate {
1320*0Sstevel@tonic-gate 	int np1type = (int)np1->u.name.t;
1321*0Sstevel@tonic-gate 	int np2type = (int)np2->u.name.t;
1322*0Sstevel@tonic-gate 	int num1;
1323*0Sstevel@tonic-gate 	int num2;
1324*0Sstevel@tonic-gate 
1325*0Sstevel@tonic-gate 	while (np1 && np2 && np1->u.name.s == np2->u.name.s) {
1326*0Sstevel@tonic-gate 		if (np1->u.name.next != NULL && np2->u.name.next != NULL) {
1327*0Sstevel@tonic-gate 			if (np1->u.name.cp != NULL) {
1328*0Sstevel@tonic-gate 				config_getcompname(np1->u.name.cp, NULL, &num1);
1329*0Sstevel@tonic-gate 			} else {
1330*0Sstevel@tonic-gate 				ASSERT(np1->u.name.child != NULL);
1331*0Sstevel@tonic-gate 				ASSERT(np1->u.name.child->t == T_NUM);
1332*0Sstevel@tonic-gate 				num1 = (int)np1->u.name.child->u.ull;
1333*0Sstevel@tonic-gate 			}
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 			if (np2->u.name.cp != NULL) {
1336*0Sstevel@tonic-gate 				config_getcompname(np2->u.name.cp, NULL, &num2);
1337*0Sstevel@tonic-gate 			} else {
1338*0Sstevel@tonic-gate 				ASSERT(np2->u.name.child != NULL);
1339*0Sstevel@tonic-gate 				ASSERT(np2->u.name.child->t == T_NUM);
1340*0Sstevel@tonic-gate 				num2 = (int)np2->u.name.child->u.ull;
1341*0Sstevel@tonic-gate 			}
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 			if (num1 != num2)
1344*0Sstevel@tonic-gate 				return (num1 - num2);
1345*0Sstevel@tonic-gate 		}
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 		np1 = np1->u.name.next;
1348*0Sstevel@tonic-gate 		np2 = np2->u.name.next;
1349*0Sstevel@tonic-gate 	}
1350*0Sstevel@tonic-gate 	if (np1 == NULL)
1351*0Sstevel@tonic-gate 		if (np2 == NULL)
1352*0Sstevel@tonic-gate 			return (np1type - np2type);
1353*0Sstevel@tonic-gate 		else
1354*0Sstevel@tonic-gate 			return (-1);
1355*0Sstevel@tonic-gate 	else if (np2 == NULL)
1356*0Sstevel@tonic-gate 		return (1);
1357*0Sstevel@tonic-gate 	else
1358*0Sstevel@tonic-gate 		return (strcmp(np1->u.name.s, np2->u.name.s));
1359*0Sstevel@tonic-gate }
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate void
1362*0Sstevel@tonic-gate itree_pevent_brief(int flags, struct event *ep)
1363*0Sstevel@tonic-gate {
1364*0Sstevel@tonic-gate 	ASSERT(ep != NULL);
1365*0Sstevel@tonic-gate 	ASSERT(ep->enode != NULL);
1366*0Sstevel@tonic-gate 	ASSERT(ep->ipp != NULL);
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate 	ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp);
1369*0Sstevel@tonic-gate }
1370*0Sstevel@tonic-gate 
1371*0Sstevel@tonic-gate /*ARGSUSED*/
1372*0Sstevel@tonic-gate static void
1373*0Sstevel@tonic-gate itree_pevent(struct event *lhs, struct event *ep, void *arg)
1374*0Sstevel@tonic-gate {
1375*0Sstevel@tonic-gate 	struct plut_wlk_data propd;
1376*0Sstevel@tonic-gate 	struct bubble *bp;
1377*0Sstevel@tonic-gate 	int flags = (int)arg;
1378*0Sstevel@tonic-gate 
1379*0Sstevel@tonic-gate 	itree_pevent_brief(flags, ep);
1380*0Sstevel@tonic-gate 	if (ep->t == N_EREPORT)
1381*0Sstevel@tonic-gate 		out(flags, " (count %d)", ep->count);
1382*0Sstevel@tonic-gate 	else
1383*0Sstevel@tonic-gate 		out(flags, NULL);
1384*0Sstevel@tonic-gate 
1385*0Sstevel@tonic-gate 	if (ep->props) {
1386*0Sstevel@tonic-gate 		propd.flags = flags;
1387*0Sstevel@tonic-gate 		propd.first = 1;
1388*0Sstevel@tonic-gate 		out(flags, "Properties:");
1389*0Sstevel@tonic-gate 		lut_walk(ep->props, ptree_plut, (void *)&propd);
1390*0Sstevel@tonic-gate 	}
1391*0Sstevel@tonic-gate 
1392*0Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
1393*0Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
1394*0Sstevel@tonic-gate 		/* Print only TO bubbles in this loop */
1395*0Sstevel@tonic-gate 		if (bp->t != B_TO)
1396*0Sstevel@tonic-gate 			continue;
1397*0Sstevel@tonic-gate 		itree_pbubble(flags, bp);
1398*0Sstevel@tonic-gate 	}
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
1401*0Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
1402*0Sstevel@tonic-gate 		/* Print only INHIBIT bubbles in this loop */
1403*0Sstevel@tonic-gate 		if (bp->t != B_INHIBIT)
1404*0Sstevel@tonic-gate 			continue;
1405*0Sstevel@tonic-gate 		itree_pbubble(flags, bp);
1406*0Sstevel@tonic-gate 	}
1407*0Sstevel@tonic-gate 
1408*0Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
1409*0Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
1410*0Sstevel@tonic-gate 		/* Print only FROM bubbles in this loop */
1411*0Sstevel@tonic-gate 		if (bp->t != B_FROM)
1412*0Sstevel@tonic-gate 			continue;
1413*0Sstevel@tonic-gate 		itree_pbubble(flags, bp);
1414*0Sstevel@tonic-gate 	}
1415*0Sstevel@tonic-gate }
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate static void
1418*0Sstevel@tonic-gate itree_pbubble(int flags, struct bubble *bp)
1419*0Sstevel@tonic-gate {
1420*0Sstevel@tonic-gate 	struct constraintlist *cp;
1421*0Sstevel@tonic-gate 	struct arrowlist *ap;
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 	ASSERT(bp != NULL);
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 	out(flags|O_NONL, "   ");
1426*0Sstevel@tonic-gate 	if (bp->mark)
1427*0Sstevel@tonic-gate 		out(flags|O_NONL, "*");
1428*0Sstevel@tonic-gate 	else
1429*0Sstevel@tonic-gate 		out(flags|O_NONL, " ");
1430*0Sstevel@tonic-gate 	if (bp->t == B_FROM)
1431*0Sstevel@tonic-gate 		out(flags|O_NONL, "N=%d to:", bp->nork);
1432*0Sstevel@tonic-gate 	else if (bp->t == B_TO)
1433*0Sstevel@tonic-gate 		out(flags|O_NONL, "K=%d from:", bp->nork);
1434*0Sstevel@tonic-gate 	else
1435*0Sstevel@tonic-gate 		out(flags|O_NONL, "K=%d masked from:", bp->nork);
1436*0Sstevel@tonic-gate 
1437*0Sstevel@tonic-gate 	if (bp->t == B_TO || bp->t == B_INHIBIT) {
1438*0Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
1439*0Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
1440*0Sstevel@tonic-gate 			ASSERT(ap->arrowp->head == bp);
1441*0Sstevel@tonic-gate 			ASSERT(ap->arrowp->tail != NULL);
1442*0Sstevel@tonic-gate 			ASSERT(ap->arrowp->tail->myevent != NULL);
1443*0Sstevel@tonic-gate 			out(flags|O_NONL, " ");
1444*0Sstevel@tonic-gate 			itree_pevent_brief(flags, ap->arrowp->tail->myevent);
1445*0Sstevel@tonic-gate 		}
1446*0Sstevel@tonic-gate 		out(flags, NULL);
1447*0Sstevel@tonic-gate 		return;
1448*0Sstevel@tonic-gate 	}
1449*0Sstevel@tonic-gate 
1450*0Sstevel@tonic-gate 	for (ap = itree_next_arrow(bp, NULL); ap;
1451*0Sstevel@tonic-gate 	    ap = itree_next_arrow(bp, ap)) {
1452*0Sstevel@tonic-gate 		ASSERT(ap->arrowp->tail == bp);
1453*0Sstevel@tonic-gate 		ASSERT(ap->arrowp->head != NULL);
1454*0Sstevel@tonic-gate 		ASSERT(ap->arrowp->head->myevent != NULL);
1455*0Sstevel@tonic-gate 
1456*0Sstevel@tonic-gate 		out(flags|O_NONL, " ");
1457*0Sstevel@tonic-gate 		itree_pevent_brief(flags, ap->arrowp->head->myevent);
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 		out(flags|O_NONL, " ");
1460*0Sstevel@tonic-gate 		ptree_timeval(flags, &ap->arrowp->mindelay);
1461*0Sstevel@tonic-gate 		out(flags|O_NONL, ",");
1462*0Sstevel@tonic-gate 		ptree_timeval(flags, &ap->arrowp->maxdelay);
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate 		/* Display anything from the propogation node? */
1465*0Sstevel@tonic-gate 		out(O_VERB3|O_NONL, " <%s:%d>",
1466*0Sstevel@tonic-gate 		    ap->arrowp->pnode->file, ap->arrowp->pnode->line);
1467*0Sstevel@tonic-gate 
1468*0Sstevel@tonic-gate 		if (itree_next_constraint(ap->arrowp, NULL))
1469*0Sstevel@tonic-gate 			out(flags|O_NONL, " {");
1470*0Sstevel@tonic-gate 
1471*0Sstevel@tonic-gate 		for (cp = itree_next_constraint(ap->arrowp, NULL); cp;
1472*0Sstevel@tonic-gate 		    cp = itree_next_constraint(ap->arrowp, cp)) {
1473*0Sstevel@tonic-gate 			ptree(flags, cp->cnode, 1, 0);
1474*0Sstevel@tonic-gate 			if (itree_next_constraint(ap->arrowp, cp))
1475*0Sstevel@tonic-gate 				out(flags|O_NONL, ", ");
1476*0Sstevel@tonic-gate 		}
1477*0Sstevel@tonic-gate 
1478*0Sstevel@tonic-gate 		if (itree_next_constraint(ap->arrowp, NULL))
1479*0Sstevel@tonic-gate 			out(flags|O_NONL, "}");
1480*0Sstevel@tonic-gate 	}
1481*0Sstevel@tonic-gate 	out(flags, NULL);
1482*0Sstevel@tonic-gate }
1483*0Sstevel@tonic-gate 
1484*0Sstevel@tonic-gate void
1485*0Sstevel@tonic-gate itree_ptree(int flags, struct lut *itp)
1486*0Sstevel@tonic-gate {
1487*0Sstevel@tonic-gate 	lut_walk(itp, (lut_cb)itree_pevent, (void *)flags);
1488*0Sstevel@tonic-gate }
1489*0Sstevel@tonic-gate 
1490*0Sstevel@tonic-gate /*ARGSUSED*/
1491*0Sstevel@tonic-gate static void
1492*0Sstevel@tonic-gate itree_destructor(void *left, void *right, void *arg)
1493*0Sstevel@tonic-gate {
1494*0Sstevel@tonic-gate 	struct event *ep = (struct event *)right;
1495*0Sstevel@tonic-gate 	struct bubble *nextbub, *bub;
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate 	/* Free the properties */
1498*0Sstevel@tonic-gate 	lut_free(ep->props, instances_destructor, NULL);
1499*0Sstevel@tonic-gate 
1500*0Sstevel@tonic-gate 	/* Free my bubbles */
1501*0Sstevel@tonic-gate 	for (bub = ep->bubbles; bub != NULL; ) {
1502*0Sstevel@tonic-gate 		nextbub = bub->next;
1503*0Sstevel@tonic-gate 		/*
1504*0Sstevel@tonic-gate 		 * Free arrows if they are FROM me.  Free arrowlists on
1505*0Sstevel@tonic-gate 		 * other types of bubbles (but not the attached arrows,
1506*0Sstevel@tonic-gate 		 * which will be freed when we free the originating
1507*0Sstevel@tonic-gate 		 * bubble.
1508*0Sstevel@tonic-gate 		 */
1509*0Sstevel@tonic-gate 		if (bub->t == B_FROM)
1510*0Sstevel@tonic-gate 			itree_free_arrowlists(bub, 1);
1511*0Sstevel@tonic-gate 		else
1512*0Sstevel@tonic-gate 			itree_free_arrowlists(bub, 0);
1513*0Sstevel@tonic-gate 		itree_free_bubble(bub);
1514*0Sstevel@tonic-gate 		bub = nextbub;
1515*0Sstevel@tonic-gate 	}
1516*0Sstevel@tonic-gate 
1517*0Sstevel@tonic-gate 	if (ep->nvp != NULL)
1518*0Sstevel@tonic-gate 		nvlist_free(ep->nvp);
1519*0Sstevel@tonic-gate 	bzero(ep, sizeof (*ep));
1520*0Sstevel@tonic-gate 	FREE(ep);
1521*0Sstevel@tonic-gate }
1522*0Sstevel@tonic-gate 
1523*0Sstevel@tonic-gate static void
1524*0Sstevel@tonic-gate itree_free_bubble(struct bubble *freeme)
1525*0Sstevel@tonic-gate {
1526*0Sstevel@tonic-gate 	bzero(freeme, sizeof (*freeme));
1527*0Sstevel@tonic-gate 	FREE(freeme);
1528*0Sstevel@tonic-gate }
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate static struct bubble *
1531*0Sstevel@tonic-gate itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen)
1532*0Sstevel@tonic-gate {
1533*0Sstevel@tonic-gate 	struct bubble *prev = NULL;
1534*0Sstevel@tonic-gate 	struct bubble *curr;
1535*0Sstevel@tonic-gate 	struct bubble *newb;
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate 	/* Use existing bubbles as appropriate when possible */
1538*0Sstevel@tonic-gate 	for (curr = eventp->bubbles;
1539*0Sstevel@tonic-gate 	    curr != NULL;
1540*0Sstevel@tonic-gate 	    prev = curr, curr = curr->next) {
1541*0Sstevel@tonic-gate 		if (btype == B_TO && curr->t == B_TO) {
1542*0Sstevel@tonic-gate 			/* see if an existing "to" bubble works for us */
1543*0Sstevel@tonic-gate 			if (gen == curr->gen)
1544*0Sstevel@tonic-gate 				return (curr);	/* matched gen number */
1545*0Sstevel@tonic-gate 			else if (nork == 1 && curr->nork == 1) {
1546*0Sstevel@tonic-gate 				curr->gen = gen;
1547*0Sstevel@tonic-gate 				return (curr);	/* coalesce K==1 bubbles */
1548*0Sstevel@tonic-gate 			}
1549*0Sstevel@tonic-gate 		} else if (btype == B_FROM && curr->t == B_FROM) {
1550*0Sstevel@tonic-gate 			/* see if an existing "from" bubble works for us */
1551*0Sstevel@tonic-gate 			if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) ||
1552*0Sstevel@tonic-gate 			    (nork == 0 && curr->nork == 0))
1553*0Sstevel@tonic-gate 				return (curr);
1554*0Sstevel@tonic-gate 		}
1555*0Sstevel@tonic-gate 	}
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate 	newb = MALLOC(sizeof (struct bubble));
1558*0Sstevel@tonic-gate 	newb->next = NULL;
1559*0Sstevel@tonic-gate 	newb->t = btype;
1560*0Sstevel@tonic-gate 	newb->myevent = eventp;
1561*0Sstevel@tonic-gate 	newb->nork = nork;
1562*0Sstevel@tonic-gate 	newb->mark = 0;
1563*0Sstevel@tonic-gate 	newb->gen = gen;
1564*0Sstevel@tonic-gate 	newb->arrows = NULL;
1565*0Sstevel@tonic-gate 
1566*0Sstevel@tonic-gate 	if (prev == NULL)
1567*0Sstevel@tonic-gate 		eventp->bubbles = newb;
1568*0Sstevel@tonic-gate 	else
1569*0Sstevel@tonic-gate 		prev->next = newb;
1570*0Sstevel@tonic-gate 
1571*0Sstevel@tonic-gate 	return (newb);
1572*0Sstevel@tonic-gate }
1573*0Sstevel@tonic-gate 
1574*0Sstevel@tonic-gate struct bubble *
1575*0Sstevel@tonic-gate itree_next_bubble(struct event *eventp, struct bubble *last)
1576*0Sstevel@tonic-gate {
1577*0Sstevel@tonic-gate 	struct bubble *next;
1578*0Sstevel@tonic-gate 
1579*0Sstevel@tonic-gate 	for (;;) {
1580*0Sstevel@tonic-gate 		if (last != NULL)
1581*0Sstevel@tonic-gate 			next = last->next;
1582*0Sstevel@tonic-gate 		else
1583*0Sstevel@tonic-gate 			next = eventp->bubbles;
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate 		if (next == NULL || next->arrows != NULL)
1586*0Sstevel@tonic-gate 			return (next);
1587*0Sstevel@tonic-gate 
1588*0Sstevel@tonic-gate 		/* bubble was empty, skip it */
1589*0Sstevel@tonic-gate 		last = next;
1590*0Sstevel@tonic-gate 	}
1591*0Sstevel@tonic-gate }
1592*0Sstevel@tonic-gate 
1593*0Sstevel@tonic-gate static void
1594*0Sstevel@tonic-gate add_arrow(struct bubble *bp, struct arrow *ap)
1595*0Sstevel@tonic-gate {
1596*0Sstevel@tonic-gate 	struct arrowlist *prev = NULL;
1597*0Sstevel@tonic-gate 	struct arrowlist *curr;
1598*0Sstevel@tonic-gate 	struct arrowlist *newal;
1599*0Sstevel@tonic-gate 
1600*0Sstevel@tonic-gate 	newal = MALLOC(sizeof (struct arrowlist));
1601*0Sstevel@tonic-gate 	bzero(newal, sizeof (struct arrowlist));
1602*0Sstevel@tonic-gate 	newal->arrowp = ap;
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 	curr = itree_next_arrow(bp, NULL);
1605*0Sstevel@tonic-gate 	while (curr != NULL) {
1606*0Sstevel@tonic-gate 		prev = curr;
1607*0Sstevel@tonic-gate 		curr = itree_next_arrow(bp, curr);
1608*0Sstevel@tonic-gate 	}
1609*0Sstevel@tonic-gate 
1610*0Sstevel@tonic-gate 	if (prev == NULL)
1611*0Sstevel@tonic-gate 		bp->arrows = newal;
1612*0Sstevel@tonic-gate 	else
1613*0Sstevel@tonic-gate 		prev->next = newal;
1614*0Sstevel@tonic-gate }
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate static struct arrow *
1617*0Sstevel@tonic-gate itree_add_arrow(struct bubble *frombubblep, struct bubble *tobubblep,
1618*0Sstevel@tonic-gate     struct node *apnode, struct node *fromevent, struct node *toevent,
1619*0Sstevel@tonic-gate     struct lut *ex)
1620*0Sstevel@tonic-gate {
1621*0Sstevel@tonic-gate 	struct arrow *newa;
1622*0Sstevel@tonic-gate 
1623*0Sstevel@tonic-gate 	ASSERTeq(frombubblep->t, B_FROM, itree_bubbletype2str);
1624*0Sstevel@tonic-gate 	ASSERTinfo(tobubblep->t == B_TO || tobubblep->t == B_INHIBIT,
1625*0Sstevel@tonic-gate 	    itree_bubbletype2str(tobubblep->t));
1626*0Sstevel@tonic-gate 	newa = MALLOC(sizeof (struct arrow));
1627*0Sstevel@tonic-gate 	newa->tail = frombubblep;
1628*0Sstevel@tonic-gate 	newa->head = tobubblep;
1629*0Sstevel@tonic-gate 	newa->pnode = apnode;
1630*0Sstevel@tonic-gate 	newa->constraints = NULL;
1631*0Sstevel@tonic-gate 
1632*0Sstevel@tonic-gate 	/*
1633*0Sstevel@tonic-gate 	 *  Set default delays, then try to re-set them from
1634*0Sstevel@tonic-gate 	 *  any within() constraints.
1635*0Sstevel@tonic-gate 	 */
1636*0Sstevel@tonic-gate 	newa->mindelay = newa->maxdelay = 0ULL;
1637*0Sstevel@tonic-gate 	if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) {
1638*0Sstevel@tonic-gate 		FREE(newa);
1639*0Sstevel@tonic-gate 		return (NULL);
1640*0Sstevel@tonic-gate 	}
1641*0Sstevel@tonic-gate 
1642*0Sstevel@tonic-gate 	add_arrow(frombubblep, newa);
1643*0Sstevel@tonic-gate 	add_arrow(tobubblep, newa);
1644*0Sstevel@tonic-gate 	return (newa);
1645*0Sstevel@tonic-gate }
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate /* returns false if traits show that arrow should not be added after all */
1648*0Sstevel@tonic-gate static int
1649*0Sstevel@tonic-gate itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
1650*0Sstevel@tonic-gate     struct node *toev, struct lut *ex)
1651*0Sstevel@tonic-gate {
1652*0Sstevel@tonic-gate 	struct node *epnames[] = { NULL, NULL, NULL };
1653*0Sstevel@tonic-gate 	struct node *newc = NULL;
1654*0Sstevel@tonic-gate 
1655*0Sstevel@tonic-gate 	ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str);
1656*0Sstevel@tonic-gate 	ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str);
1657*0Sstevel@tonic-gate 
1658*0Sstevel@tonic-gate 	/*
1659*0Sstevel@tonic-gate 	 * search for the within values first on the declaration of
1660*0Sstevel@tonic-gate 	 * the destination event, and then on the prop.  this allows
1661*0Sstevel@tonic-gate 	 * one to specify a "default" within by putting it on the
1662*0Sstevel@tonic-gate 	 * declaration,  but then allow overriding on the prop statement.
1663*0Sstevel@tonic-gate 	 */
1664*0Sstevel@tonic-gate 	arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist);
1665*0Sstevel@tonic-gate 	arrow_add_within(ap, toev->u.event.eexprlist);
1666*0Sstevel@tonic-gate 
1667*0Sstevel@tonic-gate 	/*
1668*0Sstevel@tonic-gate 	 * handle any global constraints inherited from the
1669*0Sstevel@tonic-gate 	 * "fromev" event's declaration
1670*0Sstevel@tonic-gate 	 */
1671*0Sstevel@tonic-gate 	ASSERT(fromev->u.event.declp != NULL);
1672*0Sstevel@tonic-gate 	ASSERT(fromev->u.event.declp->u.stmt.np != NULL);
1673*0Sstevel@tonic-gate 
1674*0Sstevel@tonic-gate #ifdef	notdef
1675*0Sstevel@tonic-gate 	/* XXX not quite ready to evaluate constraints from decls yet */
1676*0Sstevel@tonic-gate 	if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist)
1677*0Sstevel@tonic-gate 		(void) itree_add_constraint(ap,
1678*0Sstevel@tonic-gate 		    fromev->u.event.declp->u.stmt.np->u.event.eexprlist);
1679*0Sstevel@tonic-gate #endif	/* notdef */
1680*0Sstevel@tonic-gate 
1681*0Sstevel@tonic-gate 	/* handle constraints on the from event in the prop statement */
1682*0Sstevel@tonic-gate 	epnames[0] = fromev->u.event.epname;
1683*0Sstevel@tonic-gate 	epnames[1] = toev->u.event.epname;
1684*0Sstevel@tonic-gate 	if (eval_potential(fromev->u.event.eexprlist, ex, epnames, &newc) == 0)
1685*0Sstevel@tonic-gate 		return (0);		/* constraint disallows arrow */
1686*0Sstevel@tonic-gate 
1687*0Sstevel@tonic-gate 	/*
1688*0Sstevel@tonic-gate 	 * handle any global constraints inherited from the
1689*0Sstevel@tonic-gate 	 * "toev" event's declaration
1690*0Sstevel@tonic-gate 	 */
1691*0Sstevel@tonic-gate 	ASSERT(toev->u.event.declp != NULL);
1692*0Sstevel@tonic-gate 	ASSERT(toev->u.event.declp->u.stmt.np != NULL);
1693*0Sstevel@tonic-gate 
1694*0Sstevel@tonic-gate #ifdef	notdef
1695*0Sstevel@tonic-gate 	/* XXX not quite ready to evaluate constraints from decls yet */
1696*0Sstevel@tonic-gate 	if (toev->u.event.declp->u.stmt.np->u.event.eexprlist)
1697*0Sstevel@tonic-gate 		(void) itree_add_constraint(ap,
1698*0Sstevel@tonic-gate 		    toev->u.event.declp->u.stmt.np->u.event.eexprlist);
1699*0Sstevel@tonic-gate #endif	/* notdef */
1700*0Sstevel@tonic-gate 
1701*0Sstevel@tonic-gate 	/* handle constraints on the to event in the prop statement */
1702*0Sstevel@tonic-gate 	epnames[0] = toev->u.event.epname;
1703*0Sstevel@tonic-gate 	epnames[1] = fromev->u.event.epname;
1704*0Sstevel@tonic-gate 	if (eval_potential(toev->u.event.eexprlist, ex, epnames, &newc) == 0)
1705*0Sstevel@tonic-gate 		return (0);		/* constraint disallows arrow */
1706*0Sstevel@tonic-gate 
1707*0Sstevel@tonic-gate 	/* if we came up with any deferred constraints, add them to arrow */
1708*0Sstevel@tonic-gate 	if (newc != NULL)
1709*0Sstevel@tonic-gate 		(void) itree_add_constraint(ap, newc);
1710*0Sstevel@tonic-gate 
1711*0Sstevel@tonic-gate 	return (1);	/* constraints allow arrow */
1712*0Sstevel@tonic-gate }
1713*0Sstevel@tonic-gate 
1714*0Sstevel@tonic-gate /*
1715*0Sstevel@tonic-gate  * Set within() constraint.  If the constraint were set multiple times,
1716*0Sstevel@tonic-gate  * the last one would "win".
1717*0Sstevel@tonic-gate  */
1718*0Sstevel@tonic-gate static void
1719*0Sstevel@tonic-gate arrow_add_within(struct arrow *ap, struct node *xpr)
1720*0Sstevel@tonic-gate {
1721*0Sstevel@tonic-gate 	struct node *arglist;
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 	/* end of expressions list */
1724*0Sstevel@tonic-gate 	if (xpr == NULL)
1725*0Sstevel@tonic-gate 		return;
1726*0Sstevel@tonic-gate 
1727*0Sstevel@tonic-gate 	switch (xpr->t) {
1728*0Sstevel@tonic-gate 	case T_LIST:
1729*0Sstevel@tonic-gate 		arrow_add_within(ap, xpr->u.expr.left);
1730*0Sstevel@tonic-gate 		arrow_add_within(ap, xpr->u.expr.right);
1731*0Sstevel@tonic-gate 		return;
1732*0Sstevel@tonic-gate 	case T_FUNC:
1733*0Sstevel@tonic-gate 		if (xpr->u.func.s != L_within)
1734*0Sstevel@tonic-gate 			return;
1735*0Sstevel@tonic-gate 		arglist = xpr->u.func.arglist;
1736*0Sstevel@tonic-gate 		switch (arglist->t) {
1737*0Sstevel@tonic-gate 		case T_TIMEVAL:
1738*0Sstevel@tonic-gate 			ap->mindelay = 0;
1739*0Sstevel@tonic-gate 			ap->maxdelay = arglist->u.ull;
1740*0Sstevel@tonic-gate 			break;
1741*0Sstevel@tonic-gate 		case T_NAME:
1742*0Sstevel@tonic-gate 			ASSERT(arglist->u.name.s == L_infinity);
1743*0Sstevel@tonic-gate 			ap->mindelay = 0;
1744*0Sstevel@tonic-gate 			ap->maxdelay = TIMEVAL_EVENTUALLY;
1745*0Sstevel@tonic-gate 			break;
1746*0Sstevel@tonic-gate 		case T_LIST:
1747*0Sstevel@tonic-gate 			ASSERT(arglist->u.expr.left->t == T_TIMEVAL);
1748*0Sstevel@tonic-gate 			ap->mindelay = arglist->u.expr.left->u.ull;
1749*0Sstevel@tonic-gate 			switch (arglist->u.expr.right->t) {
1750*0Sstevel@tonic-gate 			case T_TIMEVAL:
1751*0Sstevel@tonic-gate 				ap->maxdelay = arglist->u.ull;
1752*0Sstevel@tonic-gate 				break;
1753*0Sstevel@tonic-gate 			case T_NAME:
1754*0Sstevel@tonic-gate 				ASSERT(arglist->u.expr.right->u.name.s ==
1755*0Sstevel@tonic-gate 				    L_infinity);
1756*0Sstevel@tonic-gate 				ap->maxdelay = TIMEVAL_EVENTUALLY;
1757*0Sstevel@tonic-gate 				break;
1758*0Sstevel@tonic-gate 			default:
1759*0Sstevel@tonic-gate 				out(O_DIE, "within: unexpected 2nd arg type");
1760*0Sstevel@tonic-gate 			}
1761*0Sstevel@tonic-gate 			break;
1762*0Sstevel@tonic-gate 		default:
1763*0Sstevel@tonic-gate 			out(O_DIE, "within: unexpected 1st arg type");
1764*0Sstevel@tonic-gate 		}
1765*0Sstevel@tonic-gate 		break;
1766*0Sstevel@tonic-gate 	default:
1767*0Sstevel@tonic-gate 		return;
1768*0Sstevel@tonic-gate 	}
1769*0Sstevel@tonic-gate }
1770*0Sstevel@tonic-gate 
1771*0Sstevel@tonic-gate static void
1772*0Sstevel@tonic-gate itree_free_arrowlists(struct bubble *bubp, int arrows_too)
1773*0Sstevel@tonic-gate {
1774*0Sstevel@tonic-gate 	struct arrowlist *al, *nal;
1775*0Sstevel@tonic-gate 
1776*0Sstevel@tonic-gate 	al = bubp->arrows;
1777*0Sstevel@tonic-gate 	while (al != NULL) {
1778*0Sstevel@tonic-gate 		nal = al->next;
1779*0Sstevel@tonic-gate 		if (arrows_too) {
1780*0Sstevel@tonic-gate 			itree_free_constraints(al->arrowp);
1781*0Sstevel@tonic-gate 			bzero(al->arrowp, sizeof (struct arrow));
1782*0Sstevel@tonic-gate 			FREE(al->arrowp);
1783*0Sstevel@tonic-gate 		}
1784*0Sstevel@tonic-gate 		bzero(al, sizeof (*al));
1785*0Sstevel@tonic-gate 		FREE(al);
1786*0Sstevel@tonic-gate 		al = nal;
1787*0Sstevel@tonic-gate 	}
1788*0Sstevel@tonic-gate }
1789*0Sstevel@tonic-gate 
1790*0Sstevel@tonic-gate struct arrowlist *
1791*0Sstevel@tonic-gate itree_next_arrow(struct bubble *bubble, struct arrowlist *last)
1792*0Sstevel@tonic-gate {
1793*0Sstevel@tonic-gate 	struct arrowlist *next;
1794*0Sstevel@tonic-gate 
1795*0Sstevel@tonic-gate 	if (last != NULL)
1796*0Sstevel@tonic-gate 		next = last->next;
1797*0Sstevel@tonic-gate 	else
1798*0Sstevel@tonic-gate 		next = bubble->arrows;
1799*0Sstevel@tonic-gate 	return (next);
1800*0Sstevel@tonic-gate }
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate static struct constraintlist *
1803*0Sstevel@tonic-gate itree_add_constraint(struct arrow *arrowp, struct node *c)
1804*0Sstevel@tonic-gate {
1805*0Sstevel@tonic-gate 	struct constraintlist *prev = NULL;
1806*0Sstevel@tonic-gate 	struct constraintlist *curr;
1807*0Sstevel@tonic-gate 	struct constraintlist *newc;
1808*0Sstevel@tonic-gate 
1809*0Sstevel@tonic-gate 	for (curr = arrowp->constraints;
1810*0Sstevel@tonic-gate 	    curr != NULL;
1811*0Sstevel@tonic-gate 	    prev = curr, curr = curr->next);
1812*0Sstevel@tonic-gate 
1813*0Sstevel@tonic-gate 	newc = MALLOC(sizeof (struct constraintlist));
1814*0Sstevel@tonic-gate 	newc->next = NULL;
1815*0Sstevel@tonic-gate 	newc->cnode = c;
1816*0Sstevel@tonic-gate 
1817*0Sstevel@tonic-gate 	if (prev == NULL)
1818*0Sstevel@tonic-gate 		arrowp->constraints = newc;
1819*0Sstevel@tonic-gate 	else
1820*0Sstevel@tonic-gate 		prev->next = newc;
1821*0Sstevel@tonic-gate 
1822*0Sstevel@tonic-gate 	return (newc);
1823*0Sstevel@tonic-gate }
1824*0Sstevel@tonic-gate 
1825*0Sstevel@tonic-gate struct constraintlist *
1826*0Sstevel@tonic-gate itree_next_constraint(struct arrow *arrowp, struct constraintlist *last)
1827*0Sstevel@tonic-gate {
1828*0Sstevel@tonic-gate 	struct constraintlist *next;
1829*0Sstevel@tonic-gate 
1830*0Sstevel@tonic-gate 	if (last != NULL)
1831*0Sstevel@tonic-gate 		next = last->next;
1832*0Sstevel@tonic-gate 	else
1833*0Sstevel@tonic-gate 		next = arrowp->constraints;
1834*0Sstevel@tonic-gate 	return (next);
1835*0Sstevel@tonic-gate }
1836*0Sstevel@tonic-gate 
1837*0Sstevel@tonic-gate static void
1838*0Sstevel@tonic-gate itree_free_constraints(struct arrow *ap)
1839*0Sstevel@tonic-gate {
1840*0Sstevel@tonic-gate 	struct constraintlist *cl, *ncl;
1841*0Sstevel@tonic-gate 
1842*0Sstevel@tonic-gate 	cl = ap->constraints;
1843*0Sstevel@tonic-gate 	while (cl != NULL) {
1844*0Sstevel@tonic-gate 		ncl = cl->next;
1845*0Sstevel@tonic-gate 		ASSERT(cl->cnode != NULL);
1846*0Sstevel@tonic-gate 		tree_free(cl->cnode);
1847*0Sstevel@tonic-gate 		bzero(cl, sizeof (*cl));
1848*0Sstevel@tonic-gate 		FREE(cl);
1849*0Sstevel@tonic-gate 		cl = ncl;
1850*0Sstevel@tonic-gate 	}
1851*0Sstevel@tonic-gate }
1852*0Sstevel@tonic-gate 
1853*0Sstevel@tonic-gate const char *
1854*0Sstevel@tonic-gate itree_bubbletype2str(enum bubbletype t)
1855*0Sstevel@tonic-gate {
1856*0Sstevel@tonic-gate 	static char buf[100];
1857*0Sstevel@tonic-gate 
1858*0Sstevel@tonic-gate 	switch (t) {
1859*0Sstevel@tonic-gate 	case B_FROM:	return L_from;
1860*0Sstevel@tonic-gate 	case B_TO:	return L_to;
1861*0Sstevel@tonic-gate 	case B_INHIBIT:	return L_inhibit;
1862*0Sstevel@tonic-gate 	default:
1863*0Sstevel@tonic-gate 		(void) sprintf(buf, "[unexpected bubbletype: %d]", t);
1864*0Sstevel@tonic-gate 		return (buf);
1865*0Sstevel@tonic-gate 	}
1866*0Sstevel@tonic-gate }
1867*0Sstevel@tonic-gate 
1868*0Sstevel@tonic-gate /*
1869*0Sstevel@tonic-gate  * itree_fini -- clean up any half-built itrees
1870*0Sstevel@tonic-gate  */
1871*0Sstevel@tonic-gate void
1872*0Sstevel@tonic-gate itree_fini(void)
1873*0Sstevel@tonic-gate {
1874*0Sstevel@tonic-gate 	if (Ninfo.lut != NULL) {
1875*0Sstevel@tonic-gate 		itree_free(Ninfo.lut);
1876*0Sstevel@tonic-gate 		Ninfo.lut = NULL;
1877*0Sstevel@tonic-gate 	}
1878*0Sstevel@tonic-gate 	if (Ninfo.ex) {
1879*0Sstevel@tonic-gate 		lut_free(Ninfo.ex, iterinfo_destructor, NULL);
1880*0Sstevel@tonic-gate 		Ninfo.ex = NULL;
1881*0Sstevel@tonic-gate 	}
1882*0Sstevel@tonic-gate }
1883