/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ptree.c -- routines for printing the prop tree * * this module contains routines to print portions of the parse tree. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include "out.h" #include "stable.h" #include "literals.h" #include "lut.h" #include "tree.h" #include "ptree.h" int Pchildgen; #ifdef FMAPLUGIN #include "itree.h" #include "eval.h" #include "config.h" static void cp2num(struct config *cp, int *num) { config_getcompname(cp, NULL, num); } #else /*ARGSUSED*/ static void cp2num(struct config *cp, int *num) { out(O_DIE, "ptree: non-NULL cp"); } #endif /* FMAPLUGIN */ static int is_stmt(struct node *np) { switch (np->t) { case T_FAULT: case T_UPSET: case T_DEFECT: case T_ERROR: case T_EREPORT: case T_SERD: case T_STAT: case T_PROP: case T_MASK: case T_ASRU: case T_FRU: case T_CONFIG: return (1); /*NOTREACHED*/ break; default: break; } return (0); } void ptree(int flags, struct node *np, int no_iterators, int fileline) { if (np == NULL) return; switch (np->t) { case T_NOTHING: break; case T_NAME: out(flags|O_NONL, "%s", np->u.name.s); if (!no_iterators) { if (np->u.name.cp != NULL) { int num; cp2num(np->u.name.cp, &num); out(flags|O_NONL, "%d", num); } else if (np->u.name.it == IT_HORIZONTAL) { if (np->u.name.child == NULL || (np->u.name.childgen && !Pchildgen)) out(flags|O_NONL, "<>"); else { out(flags|O_NONL, "<"); ptree(flags, np->u.name.child, no_iterators, fileline); out(flags|O_NONL, ">"); } } else if (np->u.name.child && (!np->u.name.childgen || Pchildgen)) { if (np->u.name.it != IT_NONE) out(flags|O_NONL, "["); ptree(flags, np->u.name.child, no_iterators, fileline); if (np->u.name.it != IT_NONE) out(flags|O_NONL, "]"); } } if (np->u.name.next) { ASSERT(np->u.name.next->t == T_NAME); if (np->u.name.it == IT_ENAME) out(flags|O_NONL, "."); else out(flags|O_NONL, "/"); ptree(flags, np->u.name.next, no_iterators, fileline); } break; case T_TIMEVAL: ptree_timeval(flags, &np->u.ull); break; case T_NUM: out(flags|O_NONL, "%llu", np->u.ull); break; case T_QUOTE: out(flags|O_NONL, "\"%s\"", np->u.quote.s); break; case T_GLOBID: out(flags|O_NONL, "$%s", np->u.globid.s); break; case T_FUNC: out(flags|O_NONL, "%s(", np->u.func.s); ptree(flags, np->u.func.arglist, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_NVPAIR: ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "="); ptree(flags, np->u.expr.right, no_iterators, fileline); break; case T_EVENT: ptree(flags, np->u.event.ename, no_iterators, fileline); if (np->u.event.epname) { out(flags|O_NONL, "@"); ptree(flags, np->u.event.epname, no_iterators, fileline); } if (np->u.event.eexprlist) { out(flags|O_NONL, "{"); ptree(flags, np->u.event.eexprlist, no_iterators, fileline); out(flags|O_NONL, "}"); } break; case T_ASSIGN: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_NOT: out(flags|O_NONL, "("); out(flags|O_NONL, "!"); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_AND: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "&&"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_OR: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "||"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_EQ: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "=="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_NE: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "!="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_SUB: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "-"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_ADD: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "+"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_MUL: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "*"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_DIV: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "/"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_MOD: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "%%"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_LT: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "<"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_LE: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "<="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_GT: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ">"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_GE: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ">="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_BITNOT: out(flags|O_NONL, "("); out(flags|O_NONL, "~"); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_BITAND: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "&"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_BITOR: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "|"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_BITXOR: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "^"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_LSHIFT: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "<<"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_RSHIFT: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ">>"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_CONDIF: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "?"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_CONDELSE: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ":"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_ARROW: ptree(flags, np->u.arrow.lhs, no_iterators, fileline); if (np->u.arrow.nnp) { out(flags|O_NONL, "("); ptree(flags, np->u.arrow.nnp, no_iterators, fileline); out(flags|O_NONL, ")"); } out(flags|O_NONL, "->"); if (np->u.arrow.knp) { out(flags|O_NONL, "("); ptree(flags, np->u.arrow.knp, no_iterators, fileline); out(flags|O_NONL, ")"); } ptree(flags, np->u.arrow.rhs, no_iterators, fileline); break; case T_LIST: ptree(flags, np->u.expr.left, no_iterators, fileline); if (np->u.expr.left && np->u.expr.right && (np->u.expr.left->t != T_LIST || ! is_stmt(np->u.expr.right))) out(flags|O_NONL, ","); ptree(flags, np->u.expr.right, no_iterators, fileline); break; case T_FAULT: case T_UPSET: case T_DEFECT: case T_ERROR: case T_EREPORT: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "event "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } out(flags, ";"); break; case T_SERD: case T_STAT: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "engine "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } else if (np->u.stmt.lutp) { struct plut_wlk_data pd; pd.flags = flags; pd.first = 0; lut_walk(np->u.stmt.lutp, ptree_plut, &pd); } out(flags, ";"); break; case T_ASRU: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "asru "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } out(flags, ";"); break; case T_FRU: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "fru "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } out(flags, ";"); break; case T_CONFIG: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "config "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } out(flags, ";"); break; case T_PROP: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "prop "); ptree(flags, np->u.stmt.np, no_iterators, fileline); out(flags, ";"); break; case T_MASK: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "mask "); ptree(flags, np->u.stmt.np, no_iterators, fileline); out(flags, ";"); break; default: out(O_DIE, "internal error: ptree unexpected nodetype: %d", np->t); /*NOTREACHED*/ } } void ptree_plut(void *name, void *val, void *arg) { struct plut_wlk_data *pd = (struct plut_wlk_data *)arg; int c; static int indent; indent++; if (pd->first == 0) out(pd->flags, ","); else pd->first = 0; for (c = indent; c > 0; c--) out(pd->flags|O_NONL, "\t"); out(pd->flags|O_NONL, "%s", (char *)name); out(pd->flags|O_NONL, "="); ptree(pd->flags, val, 0, 0); indent--; } void ptree_name(int flags, struct node *np) { ptree(flags, np, 1, 0); } void ptree_name_iter(int flags, struct node *np) { ptree(flags, np, 0, 0); } const char * ptree_nodetype2str(enum nodetype t) { static char buf[100]; switch (t) { case T_NOTHING: return L_T_NOTHING; case T_NAME: return L_T_NAME; case T_GLOBID: return L_T_GLOBID; case T_EVENT: return L_T_EVENT; case T_ENGINE: return L_T_ENGINE; case T_ASRU: return L_asru; case T_FRU: return L_fru; case T_CONFIG: return L_config; case T_TIMEVAL: return L_T_TIMEVAL; case T_NUM: return L_T_NUM; case T_QUOTE: return L_T_QUOTE; case T_FUNC: return L_T_FUNC; case T_NVPAIR: return L_T_NVPAIR; case T_ASSIGN: return L_T_ASSIGN; case T_CONDIF: return L_T_CONDIF; case T_CONDELSE: return L_T_CONDELSE; case T_NOT: return L_T_NOT; case T_AND: return L_T_AND; case T_OR: return L_T_OR; case T_EQ: return L_T_EQ; case T_NE: return L_T_NE; case T_SUB: return L_T_SUB; case T_ADD: return L_T_ADD; case T_MUL: return L_T_MUL; case T_DIV: return L_T_DIV; case T_MOD: return L_T_MOD; case T_LT: return L_T_LT; case T_LE: return L_T_LE; case T_GT: return L_T_GT; case T_GE: return L_T_GE; case T_BITAND: return L_T_BITAND; case T_BITOR: return L_T_BITOR; case T_BITXOR: return L_T_BITXOR; case T_BITNOT: return L_T_BITNOT; case T_LSHIFT: return L_T_LSHIFT; case T_RSHIFT: return L_T_RSHIFT; case T_ARROW: return L_T_ARROW; case T_LIST: return L_T_LIST; case T_FAULT: return L_fault; case T_UPSET: return L_upset; case T_DEFECT: return L_defect; case T_ERROR: return L_error; case T_EREPORT: return L_ereport; case T_SERD: return L_serd; case T_STAT: return L_stat; case T_PROP: return L_prop; case T_MASK: return L_mask; default: (void) sprintf(buf, "[unexpected nodetype: %d]", t); return (buf); } } const char * ptree_nametype2str(enum nametype t) { static char buf[100]; switch (t) { case N_UNSPEC: return L_N_UNSPEC; case N_FAULT: return L_fault; case N_DEFECT: return L_defect; case N_UPSET: return L_upset; case N_ERROR: return L_error; case N_EREPORT: return L_ereport; case N_SERD: return L_serd; case N_STAT: return L_stat; default: (void) sprintf(buf, "[unexpected nametype: %d]", t); return (buf); } } struct printer_info { enum nodetype t; const char *pat; int flags; }; static int name_pattern_match(struct node *np, const char *pat) { const char *cend; /* first character not in component in pat */ if (pat == NULL || *pat == '\0') return (1); /* either no pattern or we've matched it all */ if (np == NULL) return (0); /* there's more pattern and nothing to match */ ASSERTeq(np->t, T_NAME, ptree_nodetype2str); cend = strchr(pat, '/'); if (cend == NULL) cend = strchr(pat, '.'); if (cend == NULL) cend = &pat[strlen(pat)]; while (np) { const char *s = np->u.name.s; while (*s) { const char *cstart = pat; while (*s && tolower(*s) == tolower(*cstart)) { cstart++; if (cstart == cend) { /* component matched */ while (*cend == '/') cend++; return name_pattern_match(np->u.name.next, cend); } s++; } if (*s) s++; } np = np->u.name.next; } return (0); } static int name_pattern_match_in_subtree(struct node *np, const char *pat) { if (pat == NULL || *pat == '\0') return (1); if (np == NULL) return (0); if (np->t == T_NAME) return (name_pattern_match(np, pat)); else if (np->t == T_EVENT) return (name_pattern_match_in_subtree(np->u.event.ename, pat) || name_pattern_match_in_subtree(np->u.event.epname, pat) || name_pattern_match_in_subtree(np->u.event.eexprlist, pat)); else if (np->t == T_ARROW) return (name_pattern_match_in_subtree(np->u.arrow.lhs, pat) || name_pattern_match_in_subtree(np->u.arrow.rhs, pat)); else if (np->t == T_ASSIGN || np->t == T_CONDIF || np->t == T_CONDELSE || np->t == T_NOT || np->t == T_AND || np->t == T_OR || np->t == T_EQ || np->t == T_NE || np->t == T_SUB || np->t == T_ADD || np->t == T_MUL || np->t == T_DIV || np->t == T_MOD || np->t == T_LT || np->t == T_LE || np->t == T_GT || np->t == T_GE || np->t == T_BITAND || np->t == T_BITOR || np->t == T_BITXOR || np->t == T_BITNOT || np->t == T_LSHIFT || np->t == T_RSHIFT || np->t == T_LIST) { return (name_pattern_match_in_subtree(np->u.expr.left, pat) || name_pattern_match_in_subtree(np->u.expr.right, pat)); } else if (np->t == T_FUNC) { return (name_pattern_match_in_subtree(np->u.func.arglist, pat)); } return (0); } static void byname_printer(struct node *lhs, struct node *rhs, void *arg) { struct printer_info *infop = (struct printer_info *)arg; if (infop->t != T_NOTHING && rhs->t != infop->t) return; if (!name_pattern_match(lhs, infop->pat)) return; ptree(infop->flags, rhs, 0, 0); } static void ptree_type_pattern(int flags, enum nodetype t, const char *pat) { struct printer_info info; struct node *np; info.flags = flags; info.pat = pat; info.t = t; switch (t) { case T_FAULT: lut_walk(Faults, (lut_cb)byname_printer, (void *)&info); return; case T_UPSET: lut_walk(Upsets, (lut_cb)byname_printer, (void *)&info); return; case T_DEFECT: lut_walk(Defects, (lut_cb)byname_printer, (void *)&info); return; case T_ERROR: lut_walk(Errors, (lut_cb)byname_printer, (void *)&info); return; case T_EREPORT: lut_walk(Ereports, (lut_cb)byname_printer, (void *)&info); return; case T_SERD: lut_walk(SERDs, (lut_cb)byname_printer, (void *)&info); return; case T_STAT: lut_walk(STATs, (lut_cb)byname_printer, (void *)&info); return; case T_ASRU: lut_walk(ASRUs, (lut_cb)byname_printer, (void *)&info); return; case T_FRU: lut_walk(FRUs, (lut_cb)byname_printer, (void *)&info); return; case T_CONFIG: lut_walk(Configs, (lut_cb)byname_printer, (void *)&info); return; case T_PROP: for (np = Props; np; np = np->u.stmt.next) if (name_pattern_match_in_subtree(np->u.stmt.np, pat)) ptree(flags, np, 0, 0); return; case T_MASK: for (np = Masks; np; np = np->u.stmt.next) if (name_pattern_match_in_subtree(np->u.stmt.np, pat)) ptree(flags, np, 0, 0); return; default: ptree(flags, tree_root(NULL), 0, 0); } } void ptree_all(int flags, const char *pat) { ptree_type_pattern(flags, T_NOTHING, pat); } void ptree_fault(int flags, const char *pat) { ptree_type_pattern(flags, T_FAULT, pat); } void ptree_upset(int flags, const char *pat) { ptree_type_pattern(flags, T_UPSET, pat); } void ptree_defect(int flags, const char *pat) { ptree_type_pattern(flags, T_DEFECT, pat); } void ptree_error(int flags, const char *pat) { ptree_type_pattern(flags, T_ERROR, pat); } void ptree_ereport(int flags, const char *pat) { ptree_type_pattern(flags, T_EREPORT, pat); } void ptree_serd(int flags, const char *pat) { ptree_type_pattern(flags, T_SERD, pat); } void ptree_stat(int flags, const char *pat) { ptree_type_pattern(flags, T_STAT, pat); } void ptree_asru(int flags, const char *pat) { ptree_type_pattern(flags, T_ASRU, pat); } void ptree_fru(int flags, const char *pat) { ptree_type_pattern(flags, T_FRU, pat); } void ptree_prop(int flags, const char *pat) { ptree_type_pattern(flags, T_PROP, pat); } void ptree_mask(int flags, const char *pat) { ptree_type_pattern(flags, T_MASK, pat); } void ptree_timeval(int flags, unsigned long long *ullp) { unsigned long long val; #define NOREMAINDER(den, num, val) (((val) = ((den) / (num))) * (num) == (den)) if (*ullp == 0) out(flags|O_NONL, "0us"); else if (*ullp >= TIMEVAL_EVENTUALLY) out(flags|O_NONL, "infinity"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*365, val)) out(flags|O_NONL, "%lluyear%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*30, val)) out(flags|O_NONL, "%llumonth%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*7, val)) out(flags|O_NONL, "%lluweek%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24, val)) out(flags|O_NONL, "%lluday%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60, val)) out(flags|O_NONL, "%lluhour%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60, val)) out(flags|O_NONL, "%lluminute%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL, val)) out(flags|O_NONL, "%llusecond%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000ULL, val)) out(flags|O_NONL, "%llums", val); else if (NOREMAINDER(*ullp, 1000ULL, val)) out(flags|O_NONL, "%lluus", val); else out(flags|O_NONL, "%lluns", *ullp); }