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