xref: /illumos-gate/usr/src/cmd/fm/eversholt/common/ptree.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * ptree.c -- routines for printing the prop tree
27  *
28  * this module contains routines to print portions of the parse tree.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "out.h"
36 #include "stable.h"
37 #include "literals.h"
38 #include "lut.h"
39 #include "tree.h"
40 #include "ptree.h"
41 
42 int Pchildgen;
43 
44 #ifdef	FMAPLUGIN
45 
46 #include "itree.h"
47 #include "eval.h"
48 #include "config.h"
49 
50 static void
51 cp2num(struct config *cp, int *num)
52 {
53 	config_getcompname(cp, NULL, num);
54 }
55 
56 #else
57 
58 /*ARGSUSED*/
59 static void
60 cp2num(struct config *cp, int *num)
61 {
62 	out(O_DIE, "ptree: non-NULL cp");
63 }
64 
65 #endif	/* FMAPLUGIN */
66 
67 static int
68 is_stmt(struct node *np)
69 {
70 	switch (np->t) {
71 	case T_FAULT:
72 	case T_UPSET:
73 	case T_DEFECT:
74 	case T_ERROR:
75 	case T_EREPORT:
76 	case T_SERD:
77 	case T_STAT:
78 	case T_PROP:
79 	case T_MASK:
80 	case T_ASRU:
81 	case T_FRU:
82 	case T_CONFIG:
83 		return (1);
84 		/*NOTREACHED*/
85 		break;
86 	default:
87 		break;
88 	}
89 
90 	return (0);
91 }
92 
93 void
94 ptree(int flags, struct node *np, int no_iterators, int fileline)
95 {
96 	if (np == NULL)
97 		return;
98 
99 	switch (np->t) {
100 	case T_NOTHING:
101 		break;
102 	case T_NAME:
103 		out(flags|O_NONL, "%s", np->u.name.s);
104 		if (!no_iterators) {
105 			if (np->u.name.cp != NULL) {
106 				int num;
107 				cp2num(np->u.name.cp, &num);
108 				out(flags|O_NONL, "%d", num);
109 			} else if (np->u.name.it == IT_HORIZONTAL) {
110 				if (np->u.name.child == NULL ||
111 				    (np->u.name.childgen && !Pchildgen))
112 					out(flags|O_NONL, "<>");
113 				else {
114 					out(flags|O_NONL, "<");
115 					ptree(flags, np->u.name.child,
116 					    no_iterators, fileline);
117 					out(flags|O_NONL, ">");
118 				}
119 			} else if (np->u.name.child &&
120 			    (!np->u.name.childgen || Pchildgen)) {
121 				if (np->u.name.it != IT_NONE)
122 					out(flags|O_NONL, "[");
123 				ptree(flags, np->u.name.child, no_iterators,
124 				    fileline);
125 				if (np->u.name.it != IT_NONE)
126 					out(flags|O_NONL, "]");
127 			}
128 		}
129 		if (np->u.name.next) {
130 			ASSERT(np->u.name.next->t == T_NAME);
131 			if (np->u.name.it == IT_ENAME)
132 				out(flags|O_NONL, ".");
133 			else
134 				out(flags|O_NONL, "/");
135 			ptree(flags, np->u.name.next, no_iterators, fileline);
136 		}
137 		break;
138 	case T_TIMEVAL:
139 		ptree_timeval(flags, &np->u.ull);
140 		break;
141 	case T_NUM:
142 		out(flags|O_NONL, "%llu", np->u.ull);
143 		break;
144 	case T_QUOTE:
145 		out(flags|O_NONL, "\"%s\"", np->u.quote.s);
146 		break;
147 	case T_GLOBID:
148 		out(flags|O_NONL, "$%s", np->u.globid.s);
149 		break;
150 	case T_FUNC:
151 		out(flags|O_NONL, "%s(", np->u.func.s);
152 		ptree(flags, np->u.func.arglist, no_iterators, fileline);
153 		out(flags|O_NONL, ")");
154 		break;
155 	case T_NVPAIR:
156 		ptree(flags, np->u.expr.left, no_iterators, fileline);
157 		out(flags|O_NONL, "=");
158 		ptree(flags, np->u.expr.right, no_iterators, fileline);
159 		break;
160 	case T_EVENT:
161 		ptree(flags, np->u.event.ename, no_iterators, fileline);
162 		if (np->u.event.epname) {
163 			out(flags|O_NONL, "@");
164 			ptree(flags, np->u.event.epname,
165 			    no_iterators, fileline);
166 		}
167 		if (np->u.event.eexprlist) {
168 			out(flags|O_NONL, "{");
169 			ptree(flags, np->u.event.eexprlist,
170 			    no_iterators, fileline);
171 			out(flags|O_NONL, "}");
172 		}
173 		break;
174 	case T_ASSIGN:
175 		out(flags|O_NONL, "(");
176 		ptree(flags, np->u.expr.left, no_iterators, fileline);
177 		out(flags|O_NONL, "=");
178 		ptree(flags, np->u.expr.right, no_iterators, fileline);
179 		out(flags|O_NONL, ")");
180 		break;
181 	case T_NOT:
182 		out(flags|O_NONL, "(");
183 		out(flags|O_NONL, "!");
184 		ptree(flags, np->u.expr.left, no_iterators, fileline);
185 		out(flags|O_NONL, ")");
186 		break;
187 	case T_AND:
188 		out(flags|O_NONL, "(");
189 		ptree(flags, np->u.expr.left, no_iterators, fileline);
190 		out(flags|O_NONL, "&&");
191 		ptree(flags, np->u.expr.right, no_iterators, fileline);
192 		out(flags|O_NONL, ")");
193 		break;
194 	case T_OR:
195 		out(flags|O_NONL, "(");
196 		ptree(flags, np->u.expr.left, no_iterators, fileline);
197 		out(flags|O_NONL, "||");
198 		ptree(flags, np->u.expr.right, no_iterators, fileline);
199 		out(flags|O_NONL, ")");
200 		break;
201 	case T_EQ:
202 		out(flags|O_NONL, "(");
203 		ptree(flags, np->u.expr.left, no_iterators, fileline);
204 		out(flags|O_NONL, "==");
205 		ptree(flags, np->u.expr.right, no_iterators, fileline);
206 		out(flags|O_NONL, ")");
207 		break;
208 	case T_NE:
209 		out(flags|O_NONL, "(");
210 		ptree(flags, np->u.expr.left, no_iterators, fileline);
211 		out(flags|O_NONL, "!=");
212 		ptree(flags, np->u.expr.right, no_iterators, fileline);
213 		out(flags|O_NONL, ")");
214 		break;
215 	case T_SUB:
216 		out(flags|O_NONL, "(");
217 		ptree(flags, np->u.expr.left, no_iterators, fileline);
218 		out(flags|O_NONL, "-");
219 		ptree(flags, np->u.expr.right, no_iterators, fileline);
220 		out(flags|O_NONL, ")");
221 		break;
222 	case T_ADD:
223 		out(flags|O_NONL, "(");
224 		ptree(flags, np->u.expr.left, no_iterators, fileline);
225 		out(flags|O_NONL, "+");
226 		ptree(flags, np->u.expr.right, no_iterators, fileline);
227 		out(flags|O_NONL, ")");
228 		break;
229 	case T_MUL:
230 		out(flags|O_NONL, "(");
231 		ptree(flags, np->u.expr.left, no_iterators, fileline);
232 		out(flags|O_NONL, "*");
233 		ptree(flags, np->u.expr.right, no_iterators, fileline);
234 		out(flags|O_NONL, ")");
235 		break;
236 	case T_DIV:
237 		out(flags|O_NONL, "(");
238 		ptree(flags, np->u.expr.left, no_iterators, fileline);
239 		out(flags|O_NONL, "/");
240 		ptree(flags, np->u.expr.right, no_iterators, fileline);
241 		out(flags|O_NONL, ")");
242 		break;
243 	case T_MOD:
244 		out(flags|O_NONL, "(");
245 		ptree(flags, np->u.expr.left, no_iterators, fileline);
246 		out(flags|O_NONL, "%%");
247 		ptree(flags, np->u.expr.right, no_iterators, fileline);
248 		out(flags|O_NONL, ")");
249 		break;
250 	case T_LT:
251 		out(flags|O_NONL, "(");
252 		ptree(flags, np->u.expr.left, no_iterators, fileline);
253 		out(flags|O_NONL, "<");
254 		ptree(flags, np->u.expr.right, no_iterators, fileline);
255 		out(flags|O_NONL, ")");
256 		break;
257 	case T_LE:
258 		out(flags|O_NONL, "(");
259 		ptree(flags, np->u.expr.left, no_iterators, fileline);
260 		out(flags|O_NONL, "<=");
261 		ptree(flags, np->u.expr.right, no_iterators, fileline);
262 		out(flags|O_NONL, ")");
263 		break;
264 	case T_GT:
265 		out(flags|O_NONL, "(");
266 		ptree(flags, np->u.expr.left, no_iterators, fileline);
267 		out(flags|O_NONL, ">");
268 		ptree(flags, np->u.expr.right, no_iterators, fileline);
269 		out(flags|O_NONL, ")");
270 		break;
271 	case T_GE:
272 		out(flags|O_NONL, "(");
273 		ptree(flags, np->u.expr.left, no_iterators, fileline);
274 		out(flags|O_NONL, ">=");
275 		ptree(flags, np->u.expr.right, no_iterators, fileline);
276 		out(flags|O_NONL, ")");
277 		break;
278 	case T_BITNOT:
279 		out(flags|O_NONL, "(");
280 		out(flags|O_NONL, "~");
281 		ptree(flags, np->u.expr.left, no_iterators, fileline);
282 		out(flags|O_NONL, ")");
283 		break;
284 	case T_BITAND:
285 		out(flags|O_NONL, "(");
286 		ptree(flags, np->u.expr.left, no_iterators, fileline);
287 		out(flags|O_NONL, "&");
288 		ptree(flags, np->u.expr.right, no_iterators, fileline);
289 		out(flags|O_NONL, ")");
290 		break;
291 	case T_BITOR:
292 		out(flags|O_NONL, "(");
293 		ptree(flags, np->u.expr.left, no_iterators, fileline);
294 		out(flags|O_NONL, "|");
295 		ptree(flags, np->u.expr.right, no_iterators, fileline);
296 		out(flags|O_NONL, ")");
297 		break;
298 	case T_BITXOR:
299 		out(flags|O_NONL, "(");
300 		ptree(flags, np->u.expr.left, no_iterators, fileline);
301 		out(flags|O_NONL, "^");
302 		ptree(flags, np->u.expr.right, no_iterators, fileline);
303 		out(flags|O_NONL, ")");
304 		break;
305 	case T_LSHIFT:
306 		out(flags|O_NONL, "(");
307 		ptree(flags, np->u.expr.left, no_iterators, fileline);
308 		out(flags|O_NONL, "<<");
309 		ptree(flags, np->u.expr.right, no_iterators, fileline);
310 		out(flags|O_NONL, ")");
311 		break;
312 	case T_RSHIFT:
313 		out(flags|O_NONL, "(");
314 		ptree(flags, np->u.expr.left, no_iterators, fileline);
315 		out(flags|O_NONL, ">>");
316 		ptree(flags, np->u.expr.right, no_iterators, fileline);
317 		out(flags|O_NONL, ")");
318 		break;
319 	case T_CONDIF:
320 		out(flags|O_NONL, "(");
321 		ptree(flags, np->u.expr.left, no_iterators, fileline);
322 		out(flags|O_NONL, "?");
323 		ptree(flags, np->u.expr.right, no_iterators, fileline);
324 		out(flags|O_NONL, ")");
325 		break;
326 	case T_CONDELSE:
327 		out(flags|O_NONL, "(");
328 		ptree(flags, np->u.expr.left, no_iterators, fileline);
329 		out(flags|O_NONL, ":");
330 		ptree(flags, np->u.expr.right, no_iterators, fileline);
331 		out(flags|O_NONL, ")");
332 		break;
333 	case T_ARROW:
334 		ptree(flags, np->u.arrow.lhs, no_iterators, fileline);
335 		if (np->u.arrow.nnp) {
336 			out(flags|O_NONL, "(");
337 			ptree(flags, np->u.arrow.nnp, no_iterators, fileline);
338 			out(flags|O_NONL, ")");
339 		}
340 		out(flags|O_NONL, "->");
341 		if (np->u.arrow.knp) {
342 			out(flags|O_NONL, "(");
343 			ptree(flags, np->u.arrow.knp, no_iterators, fileline);
344 			out(flags|O_NONL, ")");
345 		}
346 		ptree(flags, np->u.arrow.rhs, no_iterators, fileline);
347 		break;
348 	case T_LIST:
349 		ptree(flags, np->u.expr.left, no_iterators, fileline);
350 		if (np->u.expr.left && np->u.expr.right &&
351 		    (np->u.expr.left->t != T_LIST ||
352 		    ! is_stmt(np->u.expr.right)))
353 			out(flags|O_NONL, ",");
354 		ptree(flags, np->u.expr.right, no_iterators, fileline);
355 		break;
356 	case T_FAULT:
357 	case T_UPSET:
358 	case T_DEFECT:
359 	case T_ERROR:
360 	case T_EREPORT:
361 		if (fileline)
362 			out(flags, "# %d \"%s\"", np->line, np->file);
363 		out(flags|O_NONL, "event ");
364 		ptree(flags, np->u.stmt.np, no_iterators, fileline);
365 		if (np->u.stmt.nvpairs) {
366 			out(flags|O_NONL, " ");
367 			ptree(flags, np->u.stmt.nvpairs, no_iterators,
368 			    fileline);
369 		}
370 		out(flags, ";");
371 		break;
372 	case T_SERD:
373 	case T_STAT:
374 		if (fileline)
375 			out(flags, "# %d \"%s\"", np->line, np->file);
376 		out(flags|O_NONL, "engine ");
377 		ptree(flags, np->u.stmt.np, no_iterators, fileline);
378 		if (np->u.stmt.nvpairs) {
379 			out(flags|O_NONL, " ");
380 			ptree(flags, np->u.stmt.nvpairs, no_iterators,
381 			    fileline);
382 		} else if (np->u.stmt.lutp) {
383 			struct plut_wlk_data pd;
384 
385 			pd.flags = flags;
386 			pd.first = 0;
387 
388 			lut_walk(np->u.stmt.lutp, ptree_plut, &pd);
389 		}
390 		out(flags, ";");
391 		break;
392 	case T_ASRU:
393 		if (fileline)
394 			out(flags, "# %d \"%s\"", np->line, np->file);
395 		out(flags|O_NONL, "asru ");
396 		ptree(flags, np->u.stmt.np, no_iterators, fileline);
397 		if (np->u.stmt.nvpairs) {
398 			out(flags|O_NONL, " ");
399 			ptree(flags, np->u.stmt.nvpairs, no_iterators,
400 			    fileline);
401 		}
402 		out(flags, ";");
403 		break;
404 	case T_FRU:
405 		if (fileline)
406 			out(flags, "# %d \"%s\"", np->line, np->file);
407 		out(flags|O_NONL, "fru ");
408 		ptree(flags, np->u.stmt.np, no_iterators, fileline);
409 		if (np->u.stmt.nvpairs) {
410 			out(flags|O_NONL, " ");
411 			ptree(flags, np->u.stmt.nvpairs, no_iterators,
412 			    fileline);
413 		}
414 		out(flags, ";");
415 		break;
416 	case T_CONFIG:
417 		if (fileline)
418 			out(flags, "# %d \"%s\"", np->line, np->file);
419 		out(flags|O_NONL, "config ");
420 		ptree(flags, np->u.stmt.np, no_iterators, fileline);
421 		if (np->u.stmt.nvpairs) {
422 			out(flags|O_NONL, " ");
423 			ptree(flags, np->u.stmt.nvpairs, no_iterators,
424 				fileline);
425 		}
426 		out(flags, ";");
427 		break;
428 	case T_PROP:
429 		if (fileline)
430 			out(flags, "# %d \"%s\"", np->line, np->file);
431 		out(flags|O_NONL, "prop ");
432 		ptree(flags, np->u.stmt.np, no_iterators, fileline);
433 		out(flags, ";");
434 		break;
435 	case T_MASK:
436 		if (fileline)
437 			out(flags, "# %d \"%s\"", np->line, np->file);
438 		out(flags|O_NONL, "mask ");
439 		ptree(flags, np->u.stmt.np, no_iterators, fileline);
440 		out(flags, ";");
441 		break;
442 	default:
443 		out(O_DIE,
444 		    "internal error: ptree unexpected nodetype: %d", np->t);
445 		/*NOTREACHED*/
446 	}
447 }
448 
449 void
450 ptree_plut(void *name, void *val, void *arg)
451 {
452 	struct plut_wlk_data *pd = (struct plut_wlk_data *)arg;
453 	int c;
454 	static int indent;
455 
456 	indent++;
457 
458 	if (pd->first == 0)
459 		out(pd->flags, ",");
460 	else
461 		pd->first = 0;
462 
463 	for (c = indent; c > 0; c--)
464 		out(pd->flags|O_NONL, "\t");
465 	out(pd->flags|O_NONL, "%s", (char *)name);
466 
467 	out(pd->flags|O_NONL, "=");
468 	ptree(pd->flags, val, 0, 0);
469 
470 	indent--;
471 }
472 
473 void
474 ptree_name(int flags, struct node *np)
475 {
476 	ptree(flags, np, 1, 0);
477 }
478 
479 void
480 ptree_name_iter(int flags, struct node *np)
481 {
482 	ptree(flags, np, 0, 0);
483 }
484 
485 const char *
486 ptree_nodetype2str(enum nodetype t)
487 {
488 	static char buf[100];
489 
490 	switch (t) {
491 	case T_NOTHING: return L_T_NOTHING;
492 	case T_NAME: return L_T_NAME;
493 	case T_GLOBID: return L_T_GLOBID;
494 	case T_EVENT: return L_T_EVENT;
495 	case T_ENGINE: return L_T_ENGINE;
496 	case T_ASRU: return L_asru;
497 	case T_FRU: return L_fru;
498 	case T_CONFIG: return L_config;
499 	case T_TIMEVAL: return L_T_TIMEVAL;
500 	case T_NUM: return L_T_NUM;
501 	case T_QUOTE: return L_T_QUOTE;
502 	case T_FUNC: return L_T_FUNC;
503 	case T_NVPAIR: return L_T_NVPAIR;
504 	case T_ASSIGN: return L_T_ASSIGN;
505 	case T_CONDIF: return L_T_CONDIF;
506 	case T_CONDELSE: return L_T_CONDELSE;
507 	case T_NOT: return L_T_NOT;
508 	case T_AND: return L_T_AND;
509 	case T_OR: return L_T_OR;
510 	case T_EQ: return L_T_EQ;
511 	case T_NE: return L_T_NE;
512 	case T_SUB: return L_T_SUB;
513 	case T_ADD: return L_T_ADD;
514 	case T_MUL: return L_T_MUL;
515 	case T_DIV: return L_T_DIV;
516 	case T_MOD: return L_T_MOD;
517 	case T_LT: return L_T_LT;
518 	case T_LE: return L_T_LE;
519 	case T_GT: return L_T_GT;
520 	case T_GE: return L_T_GE;
521 	case T_BITAND: return L_T_BITAND;
522 	case T_BITOR: return L_T_BITOR;
523 	case T_BITXOR: return L_T_BITXOR;
524 	case T_BITNOT: return L_T_BITNOT;
525 	case T_LSHIFT: return L_T_LSHIFT;
526 	case T_RSHIFT: return L_T_RSHIFT;
527 	case T_ARROW: return L_T_ARROW;
528 	case T_LIST: return L_T_LIST;
529 	case T_FAULT: return L_fault;
530 	case T_UPSET: return L_upset;
531 	case T_DEFECT: return L_defect;
532 	case T_ERROR: return L_error;
533 	case T_EREPORT: return L_ereport;
534 	case T_SERD: return L_serd;
535 	case T_STAT: return L_stat;
536 	case T_PROP: return L_prop;
537 	case T_MASK: return L_mask;
538 	default:
539 		(void) sprintf(buf, "[unexpected nodetype: %d]", t);
540 		return (buf);
541 	}
542 }
543 
544 const char *
545 ptree_nametype2str(enum nametype t)
546 {
547 	static char buf[100];
548 
549 	switch (t) {
550 	case N_UNSPEC: return L_N_UNSPEC;
551 	case N_FAULT: return L_fault;
552 	case N_DEFECT: return L_defect;
553 	case N_UPSET: return L_upset;
554 	case N_ERROR: return L_error;
555 	case N_EREPORT: return L_ereport;
556 	case N_SERD: return L_serd;
557 	case N_STAT: return L_stat;
558 	default:
559 		(void) sprintf(buf, "[unexpected nametype: %d]", t);
560 		return (buf);
561 	}
562 }
563 
564 struct printer_info {
565 	enum nodetype t;
566 	const char *pat;
567 	int flags;
568 };
569 
570 static int
571 name_pattern_match(struct node *np, const char *pat)
572 {
573 	const char *cend;	/* first character not in component in pat */
574 
575 	if (pat == NULL || *pat == '\0')
576 		return (1);	/* either no pattern or we've matched it all */
577 
578 	if (np == NULL)
579 		return (0);	/* there's more pattern and nothing to match */
580 
581 	ASSERTeq(np->t, T_NAME, ptree_nodetype2str);
582 
583 	cend = strchr(pat, '/');
584 	if (cend == NULL)
585 		cend = strchr(pat, '.');
586 	if (cend == NULL)
587 		cend = &pat[strlen(pat)];
588 
589 	while (np) {
590 		const char *s = np->u.name.s;
591 
592 		while (*s) {
593 			const char *cstart = pat;
594 
595 			while (*s && tolower(*s) == tolower(*cstart)) {
596 				cstart++;
597 				if (cstart == cend) {
598 					/* component matched */
599 					while (*cend == '/')
600 						cend++;
601 					return
602 					    name_pattern_match(np->u.name.next,
603 					    cend);
604 				}
605 				s++;
606 			}
607 			if (*s)
608 				s++;
609 		}
610 		np = np->u.name.next;
611 	}
612 	return (0);
613 }
614 
615 static int
616 name_pattern_match_in_subtree(struct node *np, const char *pat)
617 {
618 	if (pat == NULL || *pat == '\0')
619 		return (1);
620 
621 	if (np == NULL)
622 		return (0);
623 
624 	if (np->t == T_NAME)
625 		return (name_pattern_match(np, pat));
626 	else if (np->t == T_EVENT)
627 		return (name_pattern_match_in_subtree(np->u.event.ename, pat) ||
628 		    name_pattern_match_in_subtree(np->u.event.epname, pat) ||
629 		    name_pattern_match_in_subtree(np->u.event.eexprlist, pat));
630 	else if (np->t == T_ARROW)
631 		return (name_pattern_match_in_subtree(np->u.arrow.lhs, pat) ||
632 		    name_pattern_match_in_subtree(np->u.arrow.rhs, pat));
633 	else if (np->t == T_ASSIGN ||
634 			np->t == T_CONDIF ||
635 			np->t == T_CONDELSE ||
636 			np->t == T_NOT ||
637 			np->t == T_AND ||
638 			np->t == T_OR ||
639 			np->t == T_EQ ||
640 			np->t == T_NE ||
641 			np->t == T_SUB ||
642 			np->t == T_ADD ||
643 			np->t == T_MUL ||
644 			np->t == T_DIV ||
645 			np->t == T_MOD ||
646 			np->t == T_LT ||
647 			np->t == T_LE ||
648 			np->t == T_GT ||
649 			np->t == T_GE ||
650 			np->t == T_BITAND ||
651 			np->t == T_BITOR ||
652 			np->t == T_BITXOR ||
653 			np->t == T_BITNOT ||
654 			np->t == T_LSHIFT ||
655 			np->t == T_RSHIFT ||
656 			np->t == T_LIST) {
657 		return (name_pattern_match_in_subtree(np->u.expr.left, pat) ||
658 		    name_pattern_match_in_subtree(np->u.expr.right, pat));
659 	} else if (np->t == T_FUNC) {
660 		return (name_pattern_match_in_subtree(np->u.func.arglist, pat));
661 	}
662 	return (0);
663 }
664 
665 static void
666 byname_printer(struct node *lhs, struct node *rhs, void *arg)
667 {
668 	struct printer_info *infop = (struct printer_info *)arg;
669 
670 	if (infop->t != T_NOTHING && rhs->t != infop->t)
671 		return;
672 	if (!name_pattern_match(lhs, infop->pat))
673 		return;
674 	ptree(infop->flags, rhs, 0, 0);
675 }
676 
677 static void
678 ptree_type_pattern(int flags, enum nodetype t, const char *pat)
679 {
680 	struct printer_info info;
681 	struct node *np;
682 
683 	info.flags = flags;
684 	info.pat = pat;
685 	info.t = t;
686 
687 	switch (t) {
688 	case T_FAULT:
689 		lut_walk(Faults, (lut_cb)byname_printer, (void *)&info);
690 		return;
691 	case T_UPSET:
692 		lut_walk(Upsets, (lut_cb)byname_printer, (void *)&info);
693 		return;
694 	case T_DEFECT:
695 		lut_walk(Defects, (lut_cb)byname_printer, (void *)&info);
696 		return;
697 	case T_ERROR:
698 		lut_walk(Errors, (lut_cb)byname_printer, (void *)&info);
699 		return;
700 	case T_EREPORT:
701 		lut_walk(Ereports, (lut_cb)byname_printer, (void *)&info);
702 		return;
703 	case T_SERD:
704 		lut_walk(SERDs, (lut_cb)byname_printer, (void *)&info);
705 		return;
706 	case T_STAT:
707 		lut_walk(STATs, (lut_cb)byname_printer, (void *)&info);
708 		return;
709 	case T_ASRU:
710 		lut_walk(ASRUs, (lut_cb)byname_printer, (void *)&info);
711 		return;
712 	case T_FRU:
713 		lut_walk(FRUs, (lut_cb)byname_printer, (void *)&info);
714 		return;
715 	case T_CONFIG:
716 		lut_walk(Configs, (lut_cb)byname_printer, (void *)&info);
717 		return;
718 	case T_PROP:
719 		for (np = Props; np; np = np->u.stmt.next)
720 			if (name_pattern_match_in_subtree(np->u.stmt.np, pat))
721 				ptree(flags, np, 0, 0);
722 		return;
723 	case T_MASK:
724 		for (np = Masks; np; np = np->u.stmt.next)
725 			if (name_pattern_match_in_subtree(np->u.stmt.np, pat))
726 				ptree(flags, np, 0, 0);
727 		return;
728 	default:
729 		ptree(flags, tree_root(NULL), 0, 0);
730 	}
731 }
732 
733 void
734 ptree_all(int flags, const char *pat)
735 {
736 	ptree_type_pattern(flags, T_NOTHING, pat);
737 }
738 
739 void
740 ptree_fault(int flags, const char *pat)
741 {
742 	ptree_type_pattern(flags, T_FAULT, pat);
743 }
744 
745 void
746 ptree_upset(int flags, const char *pat)
747 {
748 	ptree_type_pattern(flags, T_UPSET, pat);
749 }
750 
751 void
752 ptree_defect(int flags, const char *pat)
753 {
754 	ptree_type_pattern(flags, T_DEFECT, pat);
755 }
756 
757 void
758 ptree_error(int flags, const char *pat)
759 {
760 	ptree_type_pattern(flags, T_ERROR, pat);
761 }
762 
763 void
764 ptree_ereport(int flags, const char *pat)
765 {
766 	ptree_type_pattern(flags, T_EREPORT, pat);
767 }
768 
769 void
770 ptree_serd(int flags, const char *pat)
771 {
772 	ptree_type_pattern(flags, T_SERD, pat);
773 }
774 
775 void
776 ptree_stat(int flags, const char *pat)
777 {
778 	ptree_type_pattern(flags, T_STAT, pat);
779 }
780 
781 void
782 ptree_asru(int flags, const char *pat)
783 {
784 	ptree_type_pattern(flags, T_ASRU, pat);
785 }
786 
787 void
788 ptree_fru(int flags, const char *pat)
789 {
790 	ptree_type_pattern(flags, T_FRU, pat);
791 }
792 
793 void
794 ptree_prop(int flags, const char *pat)
795 {
796 	ptree_type_pattern(flags, T_PROP, pat);
797 }
798 
799 void
800 ptree_mask(int flags, const char *pat)
801 {
802 	ptree_type_pattern(flags, T_MASK, pat);
803 }
804 
805 void
806 ptree_timeval(int flags, unsigned long long *ullp)
807 {
808 	unsigned long long val;
809 
810 #define	NOREMAINDER(den, num, val) (((val) = ((den) / (num))) * (num) == (den))
811 	if (*ullp == 0)
812 		out(flags|O_NONL, "0us");
813 	else if (*ullp >= TIMEVAL_EVENTUALLY)
814 		out(flags|O_NONL, "infinity");
815 	else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*365, val))
816 		out(flags|O_NONL, "%lluyear%s", val, (val == 1) ? "" : "s");
817 	else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*30, val))
818 		out(flags|O_NONL, "%llumonth%s", val, (val == 1) ? "" : "s");
819 	else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*7, val))
820 		out(flags|O_NONL, "%lluweek%s", val, (val == 1) ? "" : "s");
821 	else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24, val))
822 		out(flags|O_NONL, "%lluday%s", val, (val == 1) ? "" : "s");
823 	else if (NOREMAINDER(*ullp, 1000000000ULL*60*60, val))
824 		out(flags|O_NONL, "%lluhour%s", val, (val == 1) ? "" : "s");
825 	else if (NOREMAINDER(*ullp, 1000000000ULL*60, val))
826 		out(flags|O_NONL, "%lluminute%s", val, (val == 1) ? "" : "s");
827 	else if (NOREMAINDER(*ullp, 1000000000ULL, val))
828 		out(flags|O_NONL, "%llusecond%s", val, (val == 1) ? "" : "s");
829 	else if (NOREMAINDER(*ullp, 1000000ULL, val))
830 		out(flags|O_NONL, "%llums", val);
831 	else if (NOREMAINDER(*ullp, 1000ULL, val))
832 		out(flags|O_NONL, "%lluus", val);
833 	else
834 		out(flags|O_NONL, "%lluns", *ullp);
835 }
836