Home | History | Annotate | Download | only in common
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  2869    gavinm  * Common Development and Distribution License (the "License").
      6  2869    gavinm  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21     0    stevel /*
     22  5947    stephh  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23     0    stevel  * Use is subject to license terms.
     24     0    stevel  *
     25     0    stevel  * tree.c -- routines for manipulating the prop tree
     26     0    stevel  *
     27     0    stevel  * the actions in escparse.y call these routines to construct
     28     0    stevel  * the parse tree.  these routines, in turn, call the check_X()
     29     0    stevel  * routines for semantic checking.
     30     0    stevel  */
     31     0    stevel 
     32     0    stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     33     0    stevel 
     34     0    stevel #include <stdio.h>
     35     0    stevel #include <stdlib.h>
     36     0    stevel #include <ctype.h>
     37     0    stevel #include <strings.h>
     38     0    stevel #include <alloca.h>
     39     0    stevel #include "alloc.h"
     40     0    stevel #include "out.h"
     41     0    stevel #include "stats.h"
     42     0    stevel #include "stable.h"
     43     0    stevel #include "literals.h"
     44     0    stevel #include "lut.h"
     45     0    stevel #include "esclex.h"
     46     0    stevel #include "tree.h"
     47     0    stevel #include "check.h"
     48     0    stevel #include "ptree.h"
     49     0    stevel 
     50     0    stevel static struct node *Root;
     51     0    stevel 
     52     0    stevel static char *Newname;
     53     0    stevel 
     54     0    stevel static struct stats *Faultcount;
     55     0    stevel static struct stats *Upsetcount;
     56     0    stevel static struct stats *Defectcount;
     57     0    stevel static struct stats *Errorcount;
     58     0    stevel static struct stats *Ereportcount;
     59     0    stevel static struct stats *SERDcount;
     60  1414     cindi static struct stats *STATcount;
     61     0    stevel static struct stats *ASRUcount;
     62     0    stevel static struct stats *FRUcount;
     63     0    stevel static struct stats *Configcount;
     64     0    stevel static struct stats *Propcount;
     65     0    stevel static struct stats *Maskcount;
     66     0    stevel static struct stats *Nodecount;
     67     0    stevel static struct stats *Namecount;
     68     0    stevel static struct stats *Nodesize;
     69  4436    stephh 
     70  4436    stephh struct lut *Usedprops;
     71     0    stevel 
     72     0    stevel void
     73     0    stevel tree_init(void)
     74     0    stevel {
     75     0    stevel 	Faultcount = stats_new_counter("parser.fault", "fault decls", 1);
     76     0    stevel 	Upsetcount = stats_new_counter("parser.upset", "upset decls", 1);
     77     0    stevel 	Defectcount = stats_new_counter("parser.defect", "defect decls", 1);
     78     0    stevel 	Errorcount = stats_new_counter("parser.error", "error decls", 1);
     79     0    stevel 	Ereportcount = stats_new_counter("parser.ereport", "ereport decls", 1);
     80     0    stevel 	SERDcount = stats_new_counter("parser.SERD", "SERD engine decls", 1);
     81  1414     cindi 	STATcount = stats_new_counter("parser.STAT", "STAT engine decls", 1);
     82     0    stevel 	ASRUcount = stats_new_counter("parser.ASRU", "ASRU decls", 1);
     83     0    stevel 	FRUcount = stats_new_counter("parser.FRU", "FRU decls", 1);
     84     0    stevel 	Configcount = stats_new_counter("parser.config", "config stmts", 1);
     85     0    stevel 	Propcount = stats_new_counter("parser.prop", "prop stmts", 1);
     86     0    stevel 	Maskcount = stats_new_counter("parser.mask", "mask stmts", 1);
     87     0    stevel 	Nodecount = stats_new_counter("parser.node", "nodes created", 1);
     88     0    stevel 	Namecount = stats_new_counter("parser.name", "names created", 1);
     89     0    stevel 	Nodesize =
     90     0    stevel 	    stats_new_counter("parser.nodesize", "sizeof(struct node)", 1);
     91     0    stevel 	stats_counter_add(Nodesize, sizeof (struct node));
     92     0    stevel }
     93     0    stevel 
     94     0    stevel void
     95     0    stevel tree_fini(void)
     96     0    stevel {
     97     0    stevel 	stats_delete(Faultcount);
     98     0    stevel 	stats_delete(Upsetcount);
     99     0    stevel 	stats_delete(Defectcount);
    100     0    stevel 	stats_delete(Errorcount);
    101     0    stevel 	stats_delete(Ereportcount);
    102     0    stevel 	stats_delete(SERDcount);
    103  1414     cindi 	stats_delete(STATcount);
    104     0    stevel 	stats_delete(ASRUcount);
    105     0    stevel 	stats_delete(FRUcount);
    106     0    stevel 	stats_delete(Configcount);
    107     0    stevel 	stats_delete(Propcount);
    108     0    stevel 	stats_delete(Maskcount);
    109     0    stevel 	stats_delete(Nodecount);
    110     0    stevel 	stats_delete(Namecount);
    111     0    stevel 	stats_delete(Nodesize);
    112     0    stevel 
    113     0    stevel 	/* free entire parse tree */
    114     0    stevel 	tree_free(Root);
    115     0    stevel 
    116     0    stevel 	/* free up the luts we keep for decls */
    117     0    stevel 	lut_free(Faults, NULL, NULL);
    118     0    stevel 	Faults = NULL;
    119     0    stevel 	lut_free(Upsets, NULL, NULL);
    120     0    stevel 	Upsets = NULL;
    121     0    stevel 	lut_free(Defects, NULL, NULL);
    122     0    stevel 	Defects = NULL;
    123     0    stevel 	lut_free(Errors, NULL, NULL);
    124     0    stevel 	Errors = NULL;
    125     0    stevel 	lut_free(Ereports, NULL, NULL);
    126     0    stevel 	Ereports = NULL;
    127     0    stevel 	lut_free(Ereportenames, NULL, NULL);
    128     0    stevel 	Ereportenames = NULL;
    129  6640       cth 	lut_free(Ereportenames_discard, NULL, NULL);
    130  6640       cth 	Ereportenames_discard = NULL;
    131     0    stevel 	lut_free(SERDs, NULL, NULL);
    132     0    stevel 	SERDs = NULL;
    133  1414     cindi 	lut_free(STATs, NULL, NULL);
    134  1414     cindi 	STATs = NULL;
    135     0    stevel 	lut_free(ASRUs, NULL, NULL);
    136     0    stevel 	ASRUs = NULL;
    137     0    stevel 	lut_free(FRUs, NULL, NULL);
    138     0    stevel 	FRUs = NULL;
    139     0    stevel 	lut_free(Configs, NULL, NULL);
    140     0    stevel 	Configs = NULL;
    141  5947    stephh 	lut_free(Usedprops, NULL, NULL);
    142  5947    stephh 	Usedprops = NULL;
    143     0    stevel 
    144     0    stevel 	Props = Lastprops = NULL;
    145     0    stevel 	Masks = Lastmasks = NULL;
    146     0    stevel 	Problems = Lastproblems = NULL;
    147     0    stevel 
    148     0    stevel 	if (Newname != NULL) {
    149     0    stevel 		FREE(Newname);
    150     0    stevel 		Newname = NULL;
    151     0    stevel 	}
    152     0    stevel }
    153     0    stevel 
    154  4436    stephh /*ARGSUSED*/
    155  4436    stephh static int
    156  4436    stephh nodesize(enum nodetype t, struct node *ret)
    157  4436    stephh {
    158  4436    stephh 	int size = sizeof (struct node);
    159  4436    stephh 
    160  4436    stephh 	switch (t) {
    161  4436    stephh 	case T_NAME:
    162  4436    stephh 		size += sizeof (ret->u.name) - sizeof (ret->u);
    163  4436    stephh 		break;
    164  4436    stephh 
    165  4436    stephh 	case T_GLOBID:
    166  4436    stephh 		size += sizeof (ret->u.globid) - sizeof (ret->u);
    167  4436    stephh 		break;
    168  4436    stephh 
    169  4436    stephh 	case T_TIMEVAL:
    170  4436    stephh 	case T_NUM:
    171  4436    stephh 		size += sizeof (ret->u.ull) - sizeof (ret->u);
    172  4436    stephh 		break;
    173  4436    stephh 
    174  4436    stephh 	case T_QUOTE:
    175  4436    stephh 		size += sizeof (ret->u.quote) - sizeof (ret->u);
    176  4436    stephh 		break;
    177  4436    stephh 
    178  4436    stephh 	case T_FUNC:
    179  4436    stephh 		size += sizeof (ret->u.func) - sizeof (ret->u);
    180  4436    stephh 		break;
    181  4436    stephh 
    182  4436    stephh 	case T_FAULT:
    183  4436    stephh 	case T_UPSET:
    184  4436    stephh 	case T_DEFECT:
    185  4436    stephh 	case T_ERROR:
    186  4436    stephh 	case T_EREPORT:
    187  4436    stephh 	case T_ASRU:
    188  4436    stephh 	case T_FRU:
    189  4436    stephh 	case T_SERD:
    190  4436    stephh 	case T_STAT:
    191  4436    stephh 	case T_CONFIG:
    192  4436    stephh 	case T_PROP:
    193  4436    stephh 	case T_MASK:
    194  4436    stephh 		size += sizeof (ret->u.stmt) - sizeof (ret->u);
    195  4436    stephh 		break;
    196  4436    stephh 
    197  4436    stephh 	case T_EVENT:
    198  4436    stephh 		size += sizeof (ret->u.event) - sizeof (ret->u);
    199  4436    stephh 		break;
    200  4436    stephh 
    201  4436    stephh 	case T_ARROW:
    202  4436    stephh 		size += sizeof (ret->u.arrow) - sizeof (ret->u);
    203  4436    stephh 		break;
    204  4436    stephh 
    205  4436    stephh 	default:
    206  4436    stephh 		size += sizeof (ret->u.expr) - sizeof (ret->u);
    207  4436    stephh 		break;
    208  4436    stephh 	}
    209  4436    stephh 	return (size);
    210  4436    stephh }
    211  4436    stephh 
    212     0    stevel struct node *
    213     0    stevel newnode(enum nodetype t, const char *file, int line)
    214     0    stevel {
    215  4436    stephh 	struct node *ret = NULL;
    216  4436    stephh 	int size = nodesize(t, ret);
    217     0    stevel 
    218  4436    stephh 	ret = alloc_xmalloc(size);
    219     0    stevel 	stats_counter_bump(Nodecount);
    220  4436    stephh 	bzero(ret, size);
    221     0    stevel 	ret->t = t;
    222     0    stevel 	ret->file = (file == NULL) ? "<nofile>" : file;
    223     0    stevel 	ret->line = line;
    224     0    stevel 
    225     0    stevel 	return (ret);
    226     0    stevel }
    227     0    stevel 
    228     0    stevel /*ARGSUSED*/
    229     0    stevel void
    230     0    stevel tree_free(struct node *root)
    231     0    stevel {
    232     0    stevel 	if (root == NULL)
    233     0    stevel 		return;
    234     0    stevel 
    235     0    stevel 	switch (root->t) {
    236     0    stevel 	case T_NAME:
    237     0    stevel 		tree_free(root->u.name.child);
    238     0    stevel 		tree_free(root->u.name.next);
    239     0    stevel 		break;
    240     0    stevel 	case T_FUNC:
    241     0    stevel 		tree_free(root->u.func.arglist);
    242     0    stevel 		break;
    243     0    stevel 	case T_AND:
    244     0    stevel 	case T_OR:
    245     0    stevel 	case T_EQ:
    246     0    stevel 	case T_NE:
    247     0    stevel 	case T_ADD:
    248     0    stevel 	case T_DIV:
    249     0    stevel 	case T_MOD:
    250     0    stevel 	case T_MUL:
    251     0    stevel 	case T_SUB:
    252     0    stevel 	case T_LT:
    253     0    stevel 	case T_LE:
    254     0    stevel 	case T_GT:
    255     0    stevel 	case T_GE:
    256     0    stevel 	case T_BITAND:
    257     0    stevel 	case T_BITOR:
    258     0    stevel 	case T_BITXOR:
    259     0    stevel 	case T_BITNOT:
    260     0    stevel 	case T_LSHIFT:
    261     0    stevel 	case T_RSHIFT:
    262     0    stevel 	case T_NVPAIR:
    263     0    stevel 	case T_ASSIGN:
    264     0    stevel 	case T_CONDIF:
    265     0    stevel 	case T_CONDELSE:
    266     0    stevel 	case T_LIST:
    267     0    stevel 		tree_free(root->u.expr.left);
    268     0    stevel 		tree_free(root->u.expr.right);
    269     0    stevel 		break;
    270     0    stevel 	case T_EVENT:
    271     0    stevel 		tree_free(root->u.event.ename);
    272     0    stevel 		tree_free(root->u.event.epname);
    273     0    stevel 		tree_free(root->u.event.eexprlist);
    274     0    stevel 		break;
    275     0    stevel 	case T_NOT:
    276     0    stevel 		tree_free(root->u.expr.left);
    277     0    stevel 		break;
    278     0    stevel 	case T_ARROW:
    279     0    stevel 		tree_free(root->u.arrow.lhs);
    280     0    stevel 		tree_free(root->u.arrow.nnp);
    281     0    stevel 		tree_free(root->u.arrow.knp);
    282     0    stevel 		tree_free(root->u.arrow.rhs);
    283     0    stevel 		break;
    284     0    stevel 	case T_PROP:
    285     0    stevel 	case T_MASK:
    286     0    stevel 		tree_free(root->u.stmt.np);
    287     0    stevel 		break;
    288     0    stevel 	case T_FAULT:
    289     0    stevel 	case T_UPSET:
    290     0    stevel 	case T_DEFECT:
    291     0    stevel 	case T_ERROR:
    292     0    stevel 	case T_EREPORT:
    293     0    stevel 	case T_ASRU:
    294     0    stevel 	case T_FRU:
    295     0    stevel 	case T_SERD:
    296  1414     cindi 	case T_STAT:
    297     0    stevel 	case T_CONFIG:
    298     0    stevel 		tree_free(root->u.stmt.np);
    299     0    stevel 		if (root->u.stmt.nvpairs)
    300     0    stevel 			tree_free(root->u.stmt.nvpairs);
    301     0    stevel 		if (root->u.stmt.lutp)
    302     0    stevel 			lut_free(root->u.stmt.lutp, NULL, NULL);
    303     0    stevel 		break;
    304     0    stevel 	case T_TIMEVAL:
    305     0    stevel 	case T_NUM:
    306     0    stevel 	case T_QUOTE:
    307     0    stevel 	case T_GLOBID:
    308     0    stevel 	case T_NOTHING:
    309     0    stevel 		break;
    310     0    stevel 	default:
    311     0    stevel 		out(O_DIE,
    312     0    stevel 		    "internal error: tree_free unexpected nodetype: %d",
    313     0    stevel 		    root->t);
    314     0    stevel 		/*NOTREACHED*/
    315     0    stevel 	}
    316  4436    stephh 	alloc_xfree((char *)root, nodesize(root->t, root));
    317     0    stevel }
    318     0    stevel 
    319     0    stevel static int
    320     0    stevel tree_treecmp(struct node *np1, struct node *np2, enum nodetype t,
    321     0    stevel 	    lut_cmp cmp_func)
    322     0    stevel {
    323     0    stevel 	if (np1 == NULL || np2 == NULL)
    324     0    stevel 		return (0);
    325     0    stevel 
    326     0    stevel 	if (np1->t != np2->t)
    327     0    stevel 		return (1);
    328     0    stevel 
    329     0    stevel 	ASSERT(cmp_func != NULL);
    330     0    stevel 
    331     0    stevel 	if (np1->t == t)
    332     0    stevel 		return ((*cmp_func)(np1, np2));
    333     0    stevel 
    334     0    stevel 	switch (np1->t) {
    335     0    stevel 	case T_NAME:
    336     0    stevel 		if (tree_treecmp(np1->u.name.child, np2->u.name.child, t,
    337  4436    stephh 		    cmp_func))
    338     0    stevel 			return (1);
    339     0    stevel 		return (tree_treecmp(np1->u.name.next, np2->u.name.next, t,
    340  4436    stephh 		    cmp_func));
    341     0    stevel 		/*NOTREACHED*/
    342     0    stevel 		break;
    343     0    stevel 	case T_FUNC:
    344     0    stevel 		return (tree_treecmp(np1->u.func.arglist, np2->u.func.arglist,
    345  4436    stephh 		    t, cmp_func));
    346     0    stevel 		/*NOTREACHED*/
    347     0    stevel 		break;
    348     0    stevel 	case T_AND:
    349     0    stevel 	case T_OR:
    350     0    stevel 	case T_EQ:
    351     0    stevel 	case T_NE:
    352     0    stevel 	case T_ADD:
    353     0    stevel 	case T_DIV:
    354     0    stevel 	case T_MOD:
    355     0    stevel 	case T_MUL:
    356     0    stevel 	case T_SUB:
    357     0    stevel 	case T_LT:
    358     0    stevel 	case T_LE:
    359     0    stevel 	case T_GT:
    360     0    stevel 	case T_GE:
    361     0    stevel 	case T_BITAND:
    362     0    stevel 	case T_BITOR:
    363     0    stevel 	case T_BITXOR:
    364     0    stevel 	case T_BITNOT:
    365     0    stevel 	case T_LSHIFT:
    366     0    stevel 	case T_RSHIFT:
    367     0    stevel 	case T_NVPAIR:
    368     0    stevel 	case T_ASSIGN:
    369     0    stevel 	case T_CONDIF:
    370     0    stevel 	case T_CONDELSE:
    371     0    stevel 	case T_LIST:
    372     0    stevel 		if (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t,
    373  4436    stephh 		    cmp_func))
    374     0    stevel 			return (1);
    375     0    stevel 		return (tree_treecmp(np1->u.expr.right, np2->u.expr.right, t,
    376  4436    stephh 		    cmp_func));
    377     0    stevel 		/*NOTREACHED*/
    378     0    stevel 		break;
    379     0    stevel 	case T_EVENT:
    380     0    stevel 		if (tree_treecmp(np1->u.event.ename, np2->u.event.ename, t,
    381  4436    stephh 		    cmp_func))
    382     0    stevel 			return (1);
    383     0    stevel 		if (tree_treecmp(np1->u.event.epname, np2->u.event.epname, t,
    384  4436    stephh 		    cmp_func))
    385     0    stevel 			return (1);
    386     0    stevel 		return (tree_treecmp(np1->u.event.eexprlist,
    387  4436    stephh 		    np2->u.event.eexprlist, t, cmp_func));
    388     0    stevel 		/*NOTREACHED*/
    389     0    stevel 		break;
    390     0    stevel 	case T_NOT:
    391     0    stevel 		return (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t,
    392  4436    stephh 		    cmp_func));
    393     0    stevel 		/*NOTREACHED*/
    394     0    stevel 		break;
    395     0    stevel 	case T_ARROW:
    396     0    stevel 		if (tree_treecmp(np1->u.arrow.lhs, np2->u.arrow.lhs, t,
    397  4436    stephh 		    cmp_func))
    398     0    stevel 			return (1);
    399     0    stevel 		if (tree_treecmp(np1->u.arrow.nnp, np2->u.arrow.nnp, t,
    400  4436    stephh 		    cmp_func))
    401     0    stevel 			return (1);
    402     0    stevel 		if (tree_treecmp(np1->u.arrow.knp, np2->u.arrow.knp, t,
    403  4436    stephh 		    cmp_func))
    404     0    stevel 			return (1);
    405     0    stevel 		return (tree_treecmp(np1->u.arrow.rhs, np2->u.arrow.rhs, t,
    406  4436    stephh 		    cmp_func));
    407     0    stevel 		/*NOTREACHED*/
    408     0    stevel 		break;
    409     0    stevel 	case T_PROP:
    410     0    stevel 	case T_MASK:
    411     0    stevel 		return (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t,
    412  4436    stephh 		    cmp_func));
    413     0    stevel 		/*NOTREACHED*/
    414     0    stevel 		break;
    415     0    stevel 	case T_FAULT:
    416     0    stevel 	case T_UPSET:
    417     0    stevel 	case T_DEFECT:
    418     0    stevel 	case T_ERROR:
    419     0    stevel 	case T_EREPORT:
    420     0    stevel 	case T_ASRU:
    421     0    stevel 	case T_FRU:
    422     0    stevel 	case T_SERD:
    423  1414     cindi 	case T_STAT:
    424     0    stevel 		if (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t, cmp_func))
    425     0    stevel 			return (1);
    426     0    stevel 		return (tree_treecmp(np1->u.stmt.nvpairs, np2->u.stmt.nvpairs,
    427  4436    stephh 		    t, cmp_func));
    428     0    stevel 		/*NOTREACHED*/
    429     0    stevel 		break;
    430     0    stevel 	case T_TIMEVAL:
    431     0    stevel 	case T_NUM:
    432     0    stevel 	case T_QUOTE:
    433     0    stevel 	case T_GLOBID:
    434     0    stevel 	case T_NOTHING:
    435     0    stevel 		break;
    436     0    stevel 	default:
    437     0    stevel 		out(O_DIE,
    438     0    stevel 		    "internal error: tree_treecmp unexpected nodetype: %d",
    439     0    stevel 		    np1->t);
    440     0    stevel 		/*NOTREACHED*/
    441     0    stevel 		break;
    442     0    stevel 	}
    443     0    stevel 
    444     0    stevel 	return (0);
    445     0    stevel }
    446     0    stevel 
    447     0    stevel struct node *
    448     0    stevel tree_root(struct node *np)
    449     0    stevel {
    450     0    stevel 	if (np)
    451     0    stevel 		Root = np;
    452     0    stevel 	return (Root);
    453     0    stevel }
    454     0    stevel 
    455     0    stevel struct node *
    456     0    stevel tree_nothing(void)
    457     0    stevel {
    458     0    stevel 	return (newnode(T_NOTHING, L_nofile, 0));
    459     0    stevel }
    460     0    stevel 
    461     0    stevel struct node *
    462     0    stevel tree_expr(enum nodetype t, struct node *left, struct node *right)
    463     0    stevel {
    464     0    stevel 	struct node *ret;
    465     0    stevel 
    466     0    stevel 	ASSERTinfo(left != NULL || right != NULL, ptree_nodetype2str(t));
    467     0    stevel 
    468     0    stevel 	ret = newnode(t,
    469     0    stevel 	    (left) ? left->file : right->file,
    470     0    stevel 	    (left) ? left->line : right->line);
    471     0    stevel 
    472     0    stevel 	ret->u.expr.left = left;
    473     0    stevel 	ret->u.expr.right = right;
    474     0    stevel 
    475     0    stevel 	check_expr(ret);
    476     0    stevel 
    477     0    stevel 	return (ret);
    478     0    stevel }
    479     0    stevel 
    480     0    stevel /*
    481     0    stevel  * ename_compress -- convert event class name in to more space-efficient form
    482     0    stevel  *
    483     0    stevel  * this routine is called after the parser has completed an "ename", which
    484     0    stevel  * is that part of an event that contains the class name (like ereport.x.y.z).
    485     0    stevel  * after this routine gets done with the ename, two things are true:
    486     0    stevel  *   1. the ename uses only a single struct node
    487     0    stevel  *   2. ename->u.name.s contains the *complete* class name, dots and all,
    488     0    stevel  *      entered into the string table.
    489     0    stevel  *
    490     0    stevel  * so in addition to saving space by using fewer struct nodes, this routine
    491     0    stevel  * allows consumers of the fault tree to assume the ename is a single
    492     0    stevel  * string, rather than a linked list of strings.
    493     0    stevel  */
    494     0    stevel static struct node *
    495     0    stevel ename_compress(struct node *ename)
    496     0    stevel {
    497     0    stevel 	char *buf;
    498     0    stevel 	char *cp;
    499     0    stevel 	int len = 0;
    500     0    stevel 	struct node *np;
    501     0    stevel 
    502     0    stevel 	if (ename == NULL)
    503     0    stevel 		return (ename);
    504     0    stevel 
    505     0    stevel 	ASSERT(ename->t == T_NAME);
    506     0    stevel 
    507     0    stevel 	if (ename->u.name.next == NULL)
    508     0    stevel 		return (ename);	/* no compression to be applied here */
    509     0    stevel 
    510     0    stevel 	for (np = ename; np != NULL; np = np->u.name.next) {
    511     0    stevel 		ASSERT(np->t == T_NAME);
    512     0    stevel 		len++;	/* room for '.' and final '\0' */
    513     0    stevel 		len += strlen(np->u.name.s);
    514     0    stevel 	}
    515     0    stevel 	cp = buf = alloca(len);
    516     0    stevel 	for (np = ename; np != NULL; np = np->u.name.next) {
    517     0    stevel 		ASSERT(np->t == T_NAME);
    518     0    stevel 		if (np != ename)
    519     0    stevel 			*cp++ = '.';
    520     0    stevel 		(void) strcpy(cp, np->u.name.s);
    521     0    stevel 		cp += strlen(cp);
    522     0    stevel 	}
    523     0    stevel 
    524     0    stevel 	ename->u.name.s = stable(buf);
    525     0    stevel 	tree_free(ename->u.name.next);
    526     0    stevel 	ename->u.name.next = NULL;
    527     0    stevel 	ename->u.name.last = ename;
    528     0    stevel 	return (ename);
    529     0    stevel }
    530     0    stevel 
    531     0    stevel struct node *
    532     0    stevel tree_event(struct node *ename, struct node *epname, struct node *eexprlist)
    533     0    stevel {
    534     0    stevel 	struct node *ret;
    535     0    stevel 
    536     0    stevel 	ASSERT(ename != NULL);
    537     0    stevel 
    538     0    stevel 	ret = newnode(T_EVENT, ename->file, ename->line);
    539     0    stevel 
    540     0    stevel 	ret->u.event.ename = ename_compress(ename);
    541     0    stevel 	ret->u.event.epname = epname;
    542     0    stevel 	ret->u.event.eexprlist = eexprlist;
    543     0    stevel 
    544     0    stevel 	check_event(ret);
    545     0    stevel 
    546     0    stevel 	return (ret);
    547     0    stevel }
    548     0    stevel 
    549     0    stevel struct node *
    550     0    stevel tree_name(const char *s, enum itertype it, const char *file, int line)
    551     0    stevel {
    552     0    stevel 	struct node *ret = newnode(T_NAME, file, line);
    553     0    stevel 
    554     0    stevel 	ASSERT(s != NULL);
    555     0    stevel 
    556     0    stevel 	stats_counter_bump(Namecount);
    557     0    stevel 	ret->u.name.t = N_UNSPEC;
    558     0    stevel 	ret->u.name.s = stable(s);
    559     0    stevel 	ret->u.name.it = it;
    560     0    stevel 	ret->u.name.last = ret;
    561     0    stevel 
    562     0    stevel 	if (it == IT_ENAME) {
    563     0    stevel 		/* PHASE2, possible optimization: convert to table driven */
    564     0    stevel 		if (s == L_fault)
    565     0    stevel 			ret->u.name.t = N_FAULT;
    566     0    stevel 		else if (s == L_upset)
    567     0    stevel 			ret->u.name.t = N_UPSET;
    568     0    stevel 		else if (s == L_defect)
    569     0    stevel 			ret->u.name.t = N_DEFECT;
    570     0    stevel 		else if (s == L_error)
    571     0    stevel 			ret->u.name.t = N_ERROR;
    572     0    stevel 		else if (s == L_ereport)
    573     0    stevel 			ret->u.name.t = N_EREPORT;
    574     0    stevel 		else if (s == L_serd)
    575     0    stevel 			ret->u.name.t = N_SERD;
    576  1414     cindi 		else if (s == L_stat)
    577  1414     cindi 			ret->u.name.t = N_STAT;
    578     0    stevel 		else
    579     0    stevel 			outfl(O_ERR, file, line, "unknown class: %s", s);
    580     0    stevel 	}
    581     0    stevel 	return (ret);
    582     0    stevel }
    583     0    stevel 
    584     0    stevel struct node *
    585     0    stevel tree_iname(const char *s, const char *file, int line)
    586     0    stevel {
    587     0    stevel 	struct node *ret;
    588     0    stevel 	char *ss;
    589     0    stevel 	char *ptr;
    590     0    stevel 
    591     0    stevel 	ASSERT(s != NULL && *s != '\0');
    592     0    stevel 
    593     0    stevel 	ss = STRDUP(s);
    594     0    stevel 
    595     0    stevel 	ptr = &ss[strlen(ss) - 1];
    596     0    stevel 	if (!isdigit(*ptr)) {
    597     0    stevel 		outfl(O_ERR, file, line,
    598     0    stevel 		    "instanced name expected (i.e. \"x0/y1\")");
    599     0    stevel 		FREE(ss);
    600     0    stevel 		return (tree_name(s, IT_NONE, file, line));
    601     0    stevel 	}
    602     0    stevel 	while (ptr > ss && isdigit(*(ptr - 1)))
    603     0    stevel 		ptr--;
    604     0    stevel 
    605     0    stevel 	ret = newnode(T_NAME, file, line);
    606     0    stevel 	stats_counter_bump(Namecount);
    607     0    stevel 	ret->u.name.child = tree_num(ptr, file, line);
    608     0    stevel 	*ptr = '\0';
    609     0    stevel 	ret->u.name.t = N_UNSPEC;
    610     0    stevel 	ret->u.name.s = stable(ss);
    611     0    stevel 	ret->u.name.it = IT_NONE;
    612     0    stevel 	ret->u.name.last = ret;
    613     0    stevel 	FREE(ss);
    614     0    stevel 
    615     0    stevel 	return (ret);
    616     0    stevel }
    617     0    stevel 
    618     0    stevel struct node *
    619     0    stevel tree_globid(const char *s, const char *file, int line)
    620     0    stevel {
    621     0    stevel 	struct node *ret = newnode(T_GLOBID, file, line);
    622     0    stevel 
    623     0    stevel 	ASSERT(s != NULL);
    624     0    stevel 
    625     0    stevel 	ret->u.globid.s = stable(s);
    626     0    stevel 
    627     0    stevel 	return (ret);
    628     0    stevel }
    629     0    stevel 
    630     0    stevel struct node *
    631     0    stevel tree_name_append(struct node *np1, struct node *np2)
    632     0    stevel {
    633     0    stevel 	ASSERT(np1 != NULL && np2 != NULL);
    634     0    stevel 
    635     0    stevel 	if (np1->t != T_NAME)
    636     0    stevel 		outfl(O_DIE, np1->file, np1->line,
    637     0    stevel 		    "tree_name_append: internal error (np1 type %d)", np1->t);
    638     0    stevel 	if (np2->t != T_NAME)
    639     0    stevel 		outfl(O_DIE, np2->file, np2->line,
    640     0    stevel 		    "tree_name_append: internal error (np2 type %d)", np2->t);
    641     0    stevel 
    642     0    stevel 	ASSERT(np1->u.name.last != NULL);
    643     0    stevel 
    644     0    stevel 	np1->u.name.last->u.name.next = np2;
    645     0    stevel 	np1->u.name.last = np2;
    646     0    stevel 	return (np1);
    647     0    stevel }
    648     0    stevel 
    649     0    stevel /*
    650     0    stevel  * tree_name_repairdash -- repair a class name that contained a dash
    651     0    stevel  *
    652     0    stevel  * this routine is called by the parser when a dash is encountered
    653     0    stevel  * in a class name.  the event protocol allows the dashes but our
    654     0    stevel  * lexer considers them a separate token (arithmetic minus).  an extra
    655     0    stevel  * rule in the parser catches this case and calls this routine to fixup
    656     0    stevel  * the last component of the class name (so far) by constructing the
    657     0    stevel  * new stable entry for a name including the dash.
    658     0    stevel  */
    659     0    stevel struct node *
    660     0    stevel tree_name_repairdash(struct node *np, const char *s)
    661     0    stevel {
    662     0    stevel 	int len;
    663     0    stevel 	char *buf;
    664     0    stevel 
    665     0    stevel 	ASSERT(np != NULL && s != NULL);
    666     0    stevel 
    667     0    stevel 	if (np->t != T_NAME)
    668     0    stevel 		outfl(O_DIE, np->file, np->line,
    669     0    stevel 		    "tree_name_repairdash: internal error (np type %d)",
    670     0    stevel 		    np->t);
    671     0    stevel 
    672     0    stevel 	ASSERT(np->u.name.last != NULL);
    673     0    stevel 
    674     0    stevel 	len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1;
    675     0    stevel 	buf = MALLOC(len);
    676     0    stevel 	(void) snprintf(buf, len, "%s-%s", np->u.name.last->u.name.s, s);
    677  2869    gavinm 	np->u.name.last->u.name.s = stable(buf);
    678  2869    gavinm 	FREE(buf);
    679  2869    gavinm 	return (np);
    680  2869    gavinm }
    681  2869    gavinm 
    682  2869    gavinm struct node *
    683  2869    gavinm tree_name_repairdash2(const char *s, struct node *np)
    684  2869    gavinm {
    685  2869    gavinm 	int len;
    686  2869    gavinm 	char *buf;
    687  2869    gavinm 
    688  2869    gavinm 	ASSERT(np != NULL && s != NULL);
    689  2869    gavinm 
    690  2869    gavinm 	if (np->t != T_NAME)
    691  2869    gavinm 		outfl(O_DIE, np->file, np->line,
    692  2869    gavinm 		    "tree_name_repairdash: internal error (np type %d)",
    693  2869    gavinm 		    np->t);
    694  2869    gavinm 
    695  2869    gavinm 	ASSERT(np->u.name.last != NULL);
    696  2869    gavinm 
    697  2869    gavinm 	len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1;
    698  2869    gavinm 	buf = MALLOC(len);
    699  2869    gavinm 	(void) snprintf(buf, len, "%s-%s", s, np->u.name.last->u.name.s);
    700     0    stevel 	np->u.name.last->u.name.s = stable(buf);
    701     0    stevel 	FREE(buf);
    702     0    stevel 	return (np);
    703     0    stevel }
    704     0    stevel 
    705     0    stevel struct node *
    706     0    stevel tree_name_iterator(struct node *np1, struct node *np2)
    707     0    stevel {
    708     0    stevel 	ASSERT(np1 != NULL);
    709     0    stevel 	ASSERT(np2 != NULL);
    710     0    stevel 	ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t));
    711     0    stevel 
    712     0    stevel 	np1->u.name.child = np2;
    713     0    stevel 
    714     0    stevel 	check_name_iterator(np1);
    715     0    stevel 
    716     0    stevel 	return (np1);
    717     0    stevel }
    718     0    stevel 
    719     0    stevel struct node *
    720     0    stevel tree_timeval(const char *s, const char *suffix, const char *file, int line)
    721     0    stevel {
    722     0    stevel 	struct node *ret = newnode(T_TIMEVAL, file, line);
    723     0    stevel 	const unsigned long long *ullp;
    724     0    stevel 
    725     0    stevel 	ASSERT(s != NULL);
    726     0    stevel 	ASSERT(suffix != NULL);
    727     0    stevel 
    728     0    stevel 	if ((ullp = lex_s2ullp_lut_lookup(Timesuffixlut, suffix)) == NULL) {
    729     0    stevel 		outfl(O_ERR, file, line,
    730     0    stevel 		    "unrecognized number suffix: %s", suffix);
    731     0    stevel 		/* still construct a valid timeval node so parsing continues */
    732     0    stevel 		ret->u.ull = 1;
    733     0    stevel 	} else {
    734     0    stevel 		ret->u.ull = (unsigned long long)strtoul(s, NULL, 0) * *ullp;
    735     0    stevel 	}
    736     0    stevel 
    737     0    stevel 	return (ret);
    738     0    stevel }
    739     0    stevel 
    740     0    stevel struct node *
    741     0    stevel tree_num(const char *s, const char *file, int line)
    742     0    stevel {
    743     0    stevel 	struct node *ret = newnode(T_NUM, file, line);
    744     0    stevel 
    745     0    stevel 	ret->u.ull = (unsigned long long)strtoul(s, NULL, 0);
    746     0    stevel 	return (ret);
    747     0    stevel }
    748     0    stevel 
    749     0    stevel struct node *
    750     0    stevel tree_quote(const char *s, const char *file, int line)
    751     0    stevel {
    752     0    stevel 	struct node *ret = newnode(T_QUOTE, file, line);
    753     0    stevel 
    754     0    stevel 	ret->u.quote.s = stable(s);
    755     0    stevel 	return (ret);
    756     0    stevel }
    757     0    stevel 
    758     0    stevel struct node *
    759     0    stevel tree_func(const char *s, struct node *np, const char *file, int line)
    760     0    stevel {
    761     0    stevel 	struct node *ret = newnode(T_FUNC, file, line);
    762  4436    stephh 	const char *ptr;
    763     0    stevel 
    764     0    stevel 	ret->u.func.s = s;
    765     0    stevel 	ret->u.func.arglist = np;
    766     0    stevel 
    767     0    stevel 	check_func(ret);
    768  4436    stephh 
    769  4436    stephh 	/*
    770  4436    stephh 	 * keep track of the properties we're interested in so we can ignore the
    771  4436    stephh 	 * rest
    772  4436    stephh 	 */
    773  4436    stephh 	if (strcmp(s, L_confprop) == 0 || strcmp(s, L_confprop_defined) == 0) {
    774  4436    stephh 		ptr = stable(np->u.expr.right->u.quote.s);
    775  4436    stephh 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    776  4436    stephh 	} else if (strcmp(s, L_is_connected) == 0) {
    777  4436    stephh 		ptr = stable("connected");
    778  4436    stephh 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    779  4436    stephh 		ptr = stable("CONNECTED");
    780  4436    stephh 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    781  4436    stephh 	} else if (strcmp(s, L_is_type) == 0) {
    782  4436    stephh 		ptr = stable("type");
    783  4436    stephh 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    784  4436    stephh 		ptr = stable("TYPE");
    785  4436    stephh 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    786  4436    stephh 	} else if (strcmp(s, L_is_on) == 0) {
    787  4436    stephh 		ptr = stable("on");
    788  4436    stephh 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    789  4436    stephh 		ptr = stable("ON");
    790  4436    stephh 		Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    791  4436    stephh 	}
    792     0    stevel 
    793     0    stevel 	return (ret);
    794     0    stevel }
    795     0    stevel 
    796     0    stevel /*
    797     0    stevel  * given a list from a prop or mask statement or a function argument,
    798     0    stevel  * convert all iterators to explicit iterators by inventing appropriate
    799     0    stevel  * iterator names.
    800     0    stevel  */
    801     0    stevel static void
    802  1414     cindi make_explicit(struct node *np, int eventonly)
    803     0    stevel {
    804     0    stevel 	struct node *pnp;	/* component of pathname */
    805     0    stevel 	struct node *pnp2;
    806     0    stevel 	int count;
    807     0    stevel 	static size_t namesz;
    808     0    stevel 
    809     0    stevel 	if (Newname == NULL) {
    810     0    stevel 		namesz = 200;
    811     0    stevel 		Newname = MALLOC(namesz);
    812     0    stevel 	}
    813     0    stevel 
    814     0    stevel 	if (np == NULL)
    815     0    stevel 		return;		/* all done */
    816     0    stevel 
    817     0    stevel 	switch (np->t) {
    818  1414     cindi 		case T_ASSIGN:
    819  1414     cindi 		case T_CONDIF:
    820  1414     cindi 		case T_CONDELSE:
    821  1414     cindi 		case T_NE:
    822  1414     cindi 		case T_EQ:
    823  1414     cindi 		case T_LT:
    824  1414     cindi 		case T_LE:
    825  1414     cindi 		case T_GT:
    826  1414     cindi 		case T_GE:
    827  1414     cindi 		case T_BITAND:
    828  1414     cindi 		case T_BITOR:
    829  1414     cindi 		case T_BITXOR:
    830  1414     cindi 		case T_BITNOT:
    831  1414     cindi 		case T_LSHIFT:
    832  1414     cindi 		case T_RSHIFT:
    833     0    stevel 		case T_LIST:
    834  1414     cindi 		case T_AND:
    835  1414     cindi 		case T_OR:
    836  1414     cindi 		case T_NOT:
    837  1414     cindi 		case T_ADD:
    838  1414     cindi 		case T_SUB:
    839  1414     cindi 		case T_MUL:
    840  1414     cindi 		case T_DIV:
    841  1414     cindi 		case T_MOD:
    842  1414     cindi 			make_explicit(np->u.expr.left, eventonly);
    843  1414     cindi 			make_explicit(np->u.expr.right, eventonly);
    844     0    stevel 			break;
    845     0    stevel 
    846     0    stevel 		case T_EVENT:
    847  1414     cindi 			make_explicit(np->u.event.epname, 0);
    848  1414     cindi 			make_explicit(np->u.event.eexprlist, 1);
    849  1414     cindi 			break;
    850  1414     cindi 
    851  1414     cindi 		case T_FUNC:
    852  1414     cindi 			make_explicit(np->u.func.arglist, eventonly);
    853     0    stevel 			break;
    854     0    stevel 
    855     0    stevel 		case T_NAME:
    856  1414     cindi 			if (eventonly)
    857  1414     cindi 				return;
    858     0    stevel 			for (pnp = np; pnp != NULL; pnp = pnp->u.name.next)
    859     0    stevel 				if (pnp->u.name.child == NULL) {
    860     0    stevel 					/*
    861     0    stevel 					 * found implicit iterator.  convert
    862     0    stevel 					 * it to an explicit iterator by
    863     0    stevel 					 * using the name of the component
    864     0    stevel 					 * appended with '#' and the number
    865     0    stevel 					 * of times we've seen this same
    866     0    stevel 					 * component name in this path so far.
    867     0    stevel 					 */
    868     0    stevel 					count = 0;
    869     0    stevel 					for (pnp2 = np; pnp2 != NULL;
    870     0    stevel 					    pnp2 = pnp2->u.name.next)
    871     0    stevel 						if (pnp2 == pnp)
    872     0    stevel 							break;
    873     0    stevel 						else if (pnp2->u.name.s ==
    874     0    stevel 						    pnp->u.name.s)
    875     0    stevel 							count++;
    876     0    stevel 
    877     0    stevel 					if (namesz < strlen(pnp->u.name.s) +
    878     0    stevel 					    100) {
    879     0    stevel 						namesz = strlen(pnp->u.name.s) +
    880     0    stevel 						    100;
    881     0    stevel 						FREE(Newname);
    882     0    stevel 						Newname = MALLOC(namesz);
    883     0    stevel 					}
    884     0    stevel 					/*
    885     0    stevel 					 * made up interator name is:
    886     0    stevel 					 *	name#ordinal
    887     0    stevel 					 * or
    888     0    stevel 					 *	name##ordinal
    889     0    stevel 					 * the first one is used for vertical
    890     0    stevel 					 * expansion, the second for horizontal.
    891     0    stevel 					 * either way, the '#' embedded in
    892     0    stevel 					 * the name makes it impossible to
    893     0    stevel 					 * collide with an actual iterator
    894     0    stevel 					 * given to us in the eversholt file.
    895     0    stevel 					 */
    896     0    stevel 					(void) snprintf(Newname, namesz,
    897     0    stevel 					    "%s#%s%d", pnp->u.name.s,
    898     0    stevel 					    (pnp->u.name.it == IT_HORIZONTAL) ?
    899     0    stevel 					    "#" : "", count);
    900     0    stevel 
    901     0    stevel 					pnp->u.name.child = tree_name(Newname,
    902     0    stevel 					    IT_NONE, pnp->file, pnp->line);
    903     0    stevel 					pnp->u.name.childgen = 1;
    904     0    stevel 				}
    905     0    stevel 			break;
    906     0    stevel 	}
    907     0    stevel }
    908     0    stevel 
    909     0    stevel struct node *
    910     0    stevel tree_pname(struct node *np)
    911     0    stevel {
    912  1414     cindi 	make_explicit(np, 0);
    913     0    stevel 	return (np);
    914     0    stevel }
    915     0    stevel 
    916     0    stevel struct node *
    917     0    stevel tree_arrow(struct node *lhs, struct node *nnp, struct node *knp,
    918     0    stevel     struct node *rhs)
    919     0    stevel {
    920     0    stevel 	struct node *ret;
    921     0    stevel 
    922     0    stevel 	ASSERT(lhs != NULL || rhs != NULL);
    923     0    stevel 
    924     0    stevel 	ret = newnode(T_ARROW,
    925     0    stevel 	    (lhs) ? lhs->file : rhs->file,
    926     0    stevel 	    (lhs) ? lhs->line : rhs->line);
    927     0    stevel 
    928     0    stevel 	ret->u.arrow.lhs = lhs;
    929     0    stevel 	ret->u.arrow.nnp = nnp;
    930     0    stevel 	ret->u.arrow.knp = knp;
    931     0    stevel 	ret->u.arrow.rhs = rhs;
    932     0    stevel 
    933  1414     cindi 	make_explicit(lhs, 0);
    934  1414     cindi 	make_explicit(rhs, 0);
    935     0    stevel 
    936     0    stevel 	check_arrow(ret);
    937     0    stevel 
    938     0    stevel 	return (ret);
    939     0    stevel }
    940     0    stevel 
    941     0    stevel static struct lut *
    942     0    stevel nvpair2lut(struct node *np, struct lut *lutp, enum nodetype t)
    943     0    stevel {
    944     0    stevel 	if (np) {
    945     0    stevel 		if (np->t == T_NVPAIR) {
    946     0    stevel 			ASSERTeq(np->u.expr.left->t, T_NAME,
    947     0    stevel 			    ptree_nodetype2str);
    948     0    stevel 			check_stmt_allowed_properties(t, np, lutp);
    949     0    stevel 			lutp = tree_s2np_lut_add(lutp,
    950     0    stevel 			    np->u.expr.left->u.name.s, np->u.expr.right);
    951     0    stevel 		} else if (np->t == T_LIST) {
    952     0    stevel 			lutp = nvpair2lut(np->u.expr.left, lutp, t);
    953     0    stevel 			lutp = nvpair2lut(np->u.expr.right, lutp, t);
    954     0    stevel 		} else
    955     0    stevel 			outfl(O_DIE, np->file, np->line,
    956     0    stevel 			    "internal error: nvpair2lut type %s",
    957     0    stevel 			    ptree_nodetype2str(np->t));
    958     0    stevel 	}
    959     0    stevel 
    960     0    stevel 	return (lutp);
    961     0    stevel }
    962     0    stevel 
    963     0    stevel struct lut *
    964     0    stevel tree_s2np_lut_add(struct lut *root, const char *s, struct node *np)
    965     0    stevel {
    966     0    stevel 	return (lut_add(root, (void *)s, (void *)np, NULL));
    967     0    stevel }
    968     0    stevel 
    969     0    stevel struct node *
    970     0    stevel tree_s2np_lut_lookup(struct lut *root, const char *s)
    971     0    stevel {
    972     0    stevel 	return (struct node *)lut_lookup(root, (void *)s, NULL);
    973     0    stevel }
    974     0    stevel 
    975     0    stevel struct lut *
    976     0    stevel tree_name2np_lut_add(struct lut *root, struct node *namep, struct node *np)
    977     0    stevel {
    978     0    stevel 	return (lut_add(root, (void *)namep, (void *)np,
    979     0    stevel 	    (lut_cmp)tree_namecmp));
    980     0    stevel }
    981     0    stevel 
    982     0    stevel struct node *
    983     0    stevel tree_name2np_lut_lookup(struct lut *root, struct node *namep)
    984     0    stevel {
    985     0    stevel 	return (struct node *)
    986     0    stevel 	    lut_lookup(root, (void *)namep, (lut_cmp)tree_namecmp);
    987     0    stevel }
    988     0    stevel 
    989     0    stevel struct node *
    990     0    stevel tree_name2np_lut_lookup_name(struct lut *root, struct node *namep)
    991     0    stevel {
    992     0    stevel 	return (struct node *)
    993     0    stevel 	    lut_lookup_lhs(root, (void *)namep, (lut_cmp)tree_namecmp);
    994     0    stevel }
    995     0    stevel 
    996     0    stevel struct lut *
    997     0    stevel tree_event2np_lut_add(struct lut *root, struct node *enp, struct node *np)
    998     0    stevel {
    999     0    stevel 	return (lut_add(root, (void *)enp, (void *)np, (lut_cmp)tree_eventcmp));
   1000     0    stevel }
   1001     0    stevel 
   1002     0    stevel struct node *
   1003     0    stevel tree_event2np_lut_lookup(struct lut *root, struct node *enp)
   1004     0    stevel {
   1005     0    stevel 	return ((struct node *)
   1006     0    stevel 	    lut_lookup(root, (void *)enp, (lut_cmp)tree_eventcmp));
   1007     0    stevel }
   1008     0    stevel 
   1009     0    stevel struct node *
   1010     0    stevel tree_event2np_lut_lookup_event(struct lut *root, struct node *enp)
   1011     0    stevel {
   1012     0    stevel 	return ((struct node *)
   1013     0    stevel 	    lut_lookup_lhs(root, (void *)enp, (lut_cmp)tree_eventcmp));
   1014     0    stevel }
   1015     0    stevel 
   1016     0    stevel static struct node *
   1017     0    stevel dodecl(enum nodetype t, const char *file, int line,
   1018     0    stevel     struct node *np, struct node *nvpairs, struct lut **lutpp,
   1019     0    stevel     struct stats *countp, int justpath)
   1020     0    stevel {
   1021     0    stevel 	struct node *ret;
   1022     0    stevel 	struct node *decl;
   1023     0    stevel 
   1024     0    stevel 	/* allocate parse tree node */
   1025     0    stevel 	ret = newnode(t, file, line);
   1026     0    stevel 	ret->u.stmt.np = np;
   1027     0    stevel 	ret->u.stmt.nvpairs = nvpairs;
   1028     0    stevel 
   1029     0    stevel 	/*
   1030     0    stevel 	 * the global lut pointed to by lutpp (Faults, Defects, Upsets,
   1031     0    stevel 	 * Errors, Ereports, Serds, FRUs, or ASRUs) keeps the first decl.
   1032     0    stevel 	 * if this isn't the first declr, we merge the
   1033     0    stevel 	 * nvpairs into the first decl so we have a
   1034     0    stevel 	 * merged table to look up properties from.
   1035     0    stevel 	 * if this is the first time we've seen this fault,
   1036     0    stevel 	 * we add it to the global lut and start lutp
   1037     0    stevel 	 * off with any nvpairs from this declaration statement.
   1038     0    stevel 	 */
   1039     0    stevel 	if (justpath && (decl = tree_name2np_lut_lookup(*lutpp, np)) == NULL) {
   1040     0    stevel 		/* this is the first time name is declared */
   1041     0    stevel 		stats_counter_bump(countp);
   1042     0    stevel 		*lutpp = tree_name2np_lut_add(*lutpp, np, ret);
   1043     0    stevel 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t);
   1044     0    stevel 	} else if (!justpath &&
   1045     0    stevel 	    (decl = tree_event2np_lut_lookup(*lutpp, np)) == NULL) {
   1046     0    stevel 		/* this is the first time event is declared */
   1047     0    stevel 		stats_counter_bump(countp);
   1048     0    stevel 		*lutpp = tree_event2np_lut_add(*lutpp, np, ret);
   1049     0    stevel 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t);
   1050     0    stevel 	} else {
   1051     0    stevel 		/* was declared before, just add new nvpairs to its lutp */
   1052     0    stevel 		decl->u.stmt.lutp = nvpair2lut(nvpairs, decl->u.stmt.lutp, t);
   1053     0    stevel 	}
   1054     0    stevel 
   1055     0    stevel 	return (ret);
   1056     0    stevel }
   1057     0    stevel 
   1058     0    stevel /*ARGSUSED*/
   1059     0    stevel static void
   1060     0    stevel update_serd_refstmt(void *lhs, void *rhs, void *arg)
   1061     0    stevel {
   1062     0    stevel 	struct node *serd;
   1063     0    stevel 
   1064     0    stevel 	ASSERT(rhs != NULL);
   1065     0    stevel 
   1066     0    stevel 	serd = tree_s2np_lut_lookup(((struct node *)rhs)->u.stmt.lutp,
   1067  4436    stephh 	    L_engine);
   1068     0    stevel 	if (serd == NULL)
   1069     0    stevel 		return;
   1070     0    stevel 
   1071     0    stevel 	ASSERT(serd->t == T_EVENT);
   1072     0    stevel 	if (arg != NULL && tree_eventcmp(serd, (struct node *)arg) != 0)
   1073     0    stevel 		return;
   1074     0    stevel 
   1075     0    stevel 	serd = tree_event2np_lut_lookup(SERDs, serd);
   1076     0    stevel 	if (serd != NULL)
   1077     0    stevel 		serd->u.stmt.flags |= STMT_REF;
   1078     0    stevel }
   1079     0    stevel 
   1080     0    stevel struct node *
   1081     0    stevel tree_decl(enum nodetype t, struct node *np, struct node *nvpairs,
   1082     0    stevel     const char *file, int line)
   1083     0    stevel {
   1084     0    stevel 	struct node *decl;
   1085     0    stevel 	struct node *ret;
   1086     0    stevel 
   1087     0    stevel 	ASSERT(np != NULL);
   1088     0    stevel 
   1089     0    stevel 	check_type_iterator(np);
   1090     0    stevel 
   1091     0    stevel 	switch (t) {
   1092     0    stevel 	case T_EVENT:
   1093     0    stevel 		/* determine the type of event being declared */
   1094     0    stevel 		ASSERT(np->u.event.ename->t == T_NAME);
   1095     0    stevel 		switch (np->u.event.ename->u.name.t) {
   1096     0    stevel 		case N_FAULT:
   1097     0    stevel 			ret = dodecl(T_FAULT, file, line, np, nvpairs,
   1098     0    stevel 			    &Faults, Faultcount, 0);
   1099  7197    stephh 
   1100  7197    stephh 			/* increment serd statement reference */
   1101  7197    stephh 			decl = tree_event2np_lut_lookup(Faults, np);
   1102  7197    stephh 			update_serd_refstmt(NULL, decl, NULL);
   1103     0    stevel 			break;
   1104     0    stevel 
   1105     0    stevel 		case N_UPSET:
   1106     0    stevel 			ret = dodecl(T_UPSET, file, line, np, nvpairs,
   1107     0    stevel 			    &Upsets, Upsetcount, 0);
   1108     0    stevel 
   1109     0    stevel 			/* increment serd statement reference */
   1110     0    stevel 			decl = tree_event2np_lut_lookup(Upsets, np);
   1111     0    stevel 			update_serd_refstmt(NULL, decl, NULL);
   1112     0    stevel 			break;
   1113     0    stevel 
   1114     0    stevel 		case N_DEFECT:
   1115     0    stevel 			ret = dodecl(T_DEFECT, file, line, np, nvpairs,
   1116     0    stevel 			    &Defects, Defectcount, 0);
   1117  7197    stephh 
   1118  7197    stephh 			/* increment serd statement reference */
   1119  7197    stephh 			decl = tree_event2np_lut_lookup(Defects, np);
   1120  7197    stephh 			update_serd_refstmt(NULL, decl, NULL);
   1121     0    stevel 			break;
   1122     0    stevel 
   1123     0    stevel 		case N_ERROR:
   1124     0    stevel 			ret = dodecl(T_ERROR, file, line, np, nvpairs,
   1125     0    stevel 			    &Errors, Errorcount, 0);
   1126     0    stevel 			break;
   1127     0    stevel 
   1128     0    stevel 		case N_EREPORT:
   1129     0    stevel 			ret = dodecl(T_EREPORT, file, line, np, nvpairs,
   1130     0    stevel 			    &Ereports, Ereportcount, 0);
   1131     0    stevel 			/*
   1132  6640       cth 			 * Keep a lut of just the enames, so that the DE
   1133     0    stevel 			 * can subscribe to a uniqified list of event
   1134     0    stevel 			 * classes.
   1135     0    stevel 			 */
   1136     0    stevel 			Ereportenames =
   1137     0    stevel 			    tree_name2np_lut_add(Ereportenames,
   1138     0    stevel 			    np->u.event.ename, np);
   1139  6640       cth 
   1140  6640       cth 			/*
   1141  6640       cth 			 * Keep a lut of the enames (event classes) to
   1142  6640       cth 			 * silently discard if we can't find a matching
   1143  6640       cth 			 * configuration node when an ereport of of a given
   1144  6640       cth 			 * class is received.  Such events are declaired
   1145  6640       cth 			 * with 'discard_if_config_unknown=1'.
   1146  6640       cth 			 */
   1147  6640       cth 			if (tree_s2np_lut_lookup(ret->u.stmt.lutp,
   1148  6640       cth 			    L_discard_if_config_unknown)) {
   1149  6640       cth 				Ereportenames_discard = lut_add(
   1150  6640       cth 				    Ereportenames_discard,
   1151  6640       cth 				    (void *)np->u.event.ename->u.name.s,
   1152  6640       cth 				    (void *)np->u.event.ename->u.name.s, NULL);
   1153  6640       cth 			}
   1154     0    stevel 			break;
   1155     0    stevel 
   1156     0    stevel 		default:
   1157     0    stevel 			outfl(O_ERR, file, line,
   1158     0    stevel 			    "tree_decl: internal error, event name type %s",
   1159     0    stevel 			    ptree_nametype2str(np->u.event.ename->u.name.t));
   1160     0    stevel 		}
   1161     0    stevel 		break;
   1162     0    stevel 
   1163     0    stevel 	case T_ENGINE:
   1164     0    stevel 		/* determine the type of engine being declared */
   1165     0    stevel 		ASSERT(np->u.event.ename->t == T_NAME);
   1166     0    stevel 		switch (np->u.event.ename->u.name.t) {
   1167     0    stevel 		case N_SERD:
   1168     0    stevel 			ret = dodecl(T_SERD, file, line, np, nvpairs,
   1169     0    stevel 			    &SERDs, SERDcount, 0);
   1170     0    stevel 			lut_walk(Upsets, update_serd_refstmt, np);
   1171     0    stevel 			break;
   1172     0    stevel 
   1173  1414     cindi 		case N_STAT:
   1174  1414     cindi 			ret = dodecl(T_STAT, file, line, np, nvpairs,
   1175  1414     cindi 			    &STATs, STATcount, 0);
   1176  1414     cindi 			break;
   1177  1414     cindi 
   1178     0    stevel 		default:
   1179     0    stevel 			outfl(O_ERR, file, line,
   1180     0    stevel 			    "tree_decl: internal error, engine name type %s",
   1181     0    stevel 			    ptree_nametype2str(np->u.event.ename->u.name.t));
   1182     0    stevel 		}
   1183     0    stevel 		break;
   1184     0    stevel 	case T_ASRU:
   1185     0    stevel 		ret = dodecl(T_ASRU, file, line, np, nvpairs,
   1186     0    stevel 		    &ASRUs, ASRUcount, 1);
   1187     0    stevel 		break;
   1188     0    stevel 
   1189     0    stevel 	case T_FRU:
   1190     0    stevel 		ret = dodecl(T_FRU, file, line, np, nvpairs,
   1191     0    stevel 		    &FRUs, FRUcount, 1);
   1192     0    stevel 		break;
   1193     0    stevel 
   1194     0    stevel 	case T_CONFIG:
   1195     0    stevel 		/*
   1196     0    stevel 		 * config statements are different from above: they
   1197     0    stevel 		 * are not merged at all (until the configuration cache
   1198     0    stevel 		 * code does its own style of merging.  and the properties
   1199     0    stevel 		 * are a free-for-all -- we don't check for allowed or
   1200     0    stevel 		 * required config properties.
   1201     0    stevel 		 */
   1202     0    stevel 		ret = newnode(T_CONFIG, file, line);
   1203     0    stevel 		ret->u.stmt.np = np;
   1204     0    stevel 		ret->u.stmt.nvpairs = nvpairs;
   1205     0    stevel 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, T_CONFIG);
   1206     0    stevel 
   1207     0    stevel 		if (lut_lookup(Configs, np, (lut_cmp)tree_namecmp) == NULL)
   1208     0    stevel 			stats_counter_bump(Configcount);
   1209     0    stevel 
   1210     0    stevel 		Configs = lut_add(Configs, (void *)np, (void *)ret, NULL);
   1211     0    stevel 		break;
   1212     0    stevel 
   1213     0    stevel 	default:
   1214     0    stevel 		out(O_DIE, "tree_decl: internal error, type %s",
   1215     0    stevel 		    ptree_nodetype2str(t));
   1216     0    stevel 	}
   1217     0    stevel 
   1218     0    stevel 	return (ret);
   1219     0    stevel }
   1220     0    stevel 
   1221     0    stevel /* keep backpointers in arrows to the prop they belong to (used for scoping) */
   1222     0    stevel static void
   1223     0    stevel set_arrow_prop(struct node *prop, struct node *np)
   1224     0    stevel {
   1225     0    stevel 	if (np == NULL)
   1226     0    stevel 		return;
   1227     0    stevel 
   1228     0    stevel 	if (np->t == T_ARROW) {
   1229     0    stevel 		np->u.arrow.prop = prop;
   1230     0    stevel 		set_arrow_prop(prop, np->u.arrow.lhs);
   1231     0    stevel 		/*
   1232     0    stevel 		 * no need to recurse right or handle T_LIST since
   1233     0    stevel 		 * T_ARROWs always cascade left and are at the top
   1234     0    stevel 		 * of the parse tree.  (you can see this in the rule
   1235     0    stevel 		 * for "propbody" in escparse.y.)
   1236     0    stevel 		 */
   1237     0    stevel 	}
   1238     0    stevel }
   1239     0    stevel 
   1240     0    stevel struct node *
   1241     0    stevel tree_stmt(enum nodetype t, struct node *np, const char *file, int line)
   1242     0    stevel {
   1243     0    stevel 	struct node *ret = newnode(t, file, line);
   1244     0    stevel 	struct node *pp;
   1245     0    stevel 	int inlist = 0;
   1246     0    stevel 
   1247     0    stevel 	ret->u.stmt.np = np;
   1248     0    stevel 
   1249     0    stevel 	switch (t) {
   1250     0    stevel 	case T_PROP:
   1251   854  rw145199 		check_proplists(t, np);
   1252     0    stevel 		check_propnames(t, np, 0, 0);
   1253     0    stevel 		check_propscope(np);
   1254     0    stevel 		set_arrow_prop(ret, np);
   1255     0    stevel 
   1256     0    stevel 		for (pp = Props; pp; pp = pp->u.stmt.next) {
   1257     0    stevel 			if (tree_treecmp(pp, ret, T_NAME,
   1258  4436    stephh 			    (lut_cmp)tree_namecmp) == 0) {
   1259     0    stevel 				inlist = 1;
   1260     0    stevel 				break;
   1261     0    stevel 			}
   1262     0    stevel 		}
   1263     0    stevel 		if (inlist == 0)
   1264     0    stevel 			stats_counter_bump(Propcount);
   1265     0    stevel 
   1266     0    stevel 		/* "Props" is a linked list of all prop statements */
   1267     0    stevel 		if (Lastprops)
   1268     0    stevel 			Lastprops->u.stmt.next = ret;
   1269     0    stevel 		else
   1270     0    stevel 			Props = ret;
   1271     0    stevel 		Lastprops = ret;
   1272     0    stevel 		break;
   1273     0    stevel 
   1274     0    stevel 	case T_MASK:
   1275   854  rw145199 		check_proplists(t, np);
   1276     0    stevel 		check_propnames(t, np, 0, 0);
   1277     0    stevel 		check_propscope(np);
   1278     0    stevel 		set_arrow_prop(ret, np);
   1279     0    stevel 
   1280     0    stevel 		for (pp = Masks; pp; pp = pp->u.stmt.next) {
   1281     0    stevel 			if (tree_treecmp(pp, ret, T_NAME,
   1282  4436    stephh 			    (lut_cmp)tree_namecmp) == 0) {
   1283     0    stevel 				inlist = 1;
   1284     0    stevel 				break;
   1285     0    stevel 			}
   1286     0    stevel 		}
   1287     0    stevel 		if (inlist == 0)
   1288     0    stevel 			stats_counter_bump(Maskcount);
   1289     0    stevel 
   1290     0    stevel 		/* "Masks" is a linked list of all mask statements */
   1291     0    stevel 		if (Lastmasks)
   1292     0    stevel 			Lastmasks->u.stmt.next = ret;
   1293     0    stevel 		else
   1294     0    stevel 			Masks = ret;
   1295     0    stevel 		Lastmasks = ret;
   1296     0    stevel 		stats_counter_bump(Maskcount);
   1297     0    stevel 		break;
   1298     0    stevel 
   1299     0    stevel 	default:
   1300     0    stevel 		outfl(O_DIE, np->file, np->line,
   1301     0    stevel 		    "tree_stmt: internal error (t %d)", t);
   1302     0    stevel 	}
   1303     0    stevel 
   1304     0    stevel 	return (ret);
   1305     0    stevel }
   1306     0    stevel 
   1307     0    stevel void
   1308     0    stevel tree_report()
   1309     0    stevel {
   1310     0    stevel 	/*
   1311     0    stevel 	 * The only declarations with required properties
   1312     0    stevel 	 * currently are faults and serds. Make sure the
   1313     0    stevel 	 * the declarations have the required properties.
   1314     0    stevel 	 */
   1315     0    stevel 	lut_walk(Faults, (lut_cb)check_required_props, (void *)T_FAULT);
   1316     0    stevel 	lut_walk(Upsets, (lut_cb)check_required_props, (void *)T_UPSET);
   1317     0    stevel 	lut_walk(Errors, (lut_cb)check_required_props, (void *)T_ERROR);
   1318     0    stevel 	lut_walk(Ereports, (lut_cb)check_required_props, (void *)T_EREPORT);
   1319     0    stevel 	lut_walk(SERDs, (lut_cb)check_required_props, (void *)T_SERD);
   1320  1414     cindi 	lut_walk(STATs, (lut_cb)check_required_props, (void *)T_STAT);
   1321     0    stevel 
   1322     0    stevel 	/*
   1323     0    stevel 	 * we do this now rather than while building the parse
   1324     0    stevel 	 * tree because it is inconvenient for the user if we
   1325     0    stevel 	 * require SERD engines to be declared before used in
   1326     0    stevel 	 * an upset "engine" property.
   1327     0    stevel 	 */
   1328     0    stevel 	lut_walk(Faults, (lut_cb)check_refcount, (void *)T_FAULT);
   1329  7197    stephh 	lut_walk(Faults, (lut_cb)check_upset_engine, (void *)T_FAULT);
   1330  7197    stephh 	lut_walk(Defects, (lut_cb)check_upset_engine, (void *)T_DEFECT);
   1331     0    stevel 	lut_walk(Upsets, (lut_cb)check_upset_engine, (void *)T_UPSET);
   1332     0    stevel 	lut_walk(Upsets, (lut_cb)check_refcount, (void *)T_UPSET);
   1333     0    stevel 	lut_walk(Errors, (lut_cb)check_refcount, (void *)T_ERROR);
   1334     0    stevel 	lut_walk(Ereports, (lut_cb)check_refcount, (void *)T_EREPORT);
   1335     0    stevel 	lut_walk(SERDs, (lut_cb)check_refcount, (void *)T_SERD);
   1336     0    stevel 
   1337     0    stevel 	/* check for cycles */
   1338     0    stevel 	lut_walk(Errors, (lut_cb)check_cycle, (void *)0);
   1339     0    stevel }
   1340     0    stevel 
   1341     0    stevel /* compare two T_NAMES by only looking at components, not iterators */
   1342     0    stevel int
   1343     0    stevel tree_namecmp(struct node *np1, struct node *np2)
   1344     0    stevel {
   1345     0    stevel 	ASSERT(np1 != NULL);
   1346     0    stevel 	ASSERT(np2 != NULL);
   1347     0    stevel 	ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t));
   1348     0    stevel 	ASSERTinfo(np2->t == T_NAME, ptree_nodetype2str(np1->t));
   1349     0    stevel 
   1350     0    stevel 	while (np1 && np2 && np1->u.name.s == np2->u.name.s) {
   1351     0    stevel 		np1 = np1->u.name.next;
   1352     0    stevel 		np2 = np2->u.name.next;
   1353     0    stevel 	}
   1354     0    stevel 	if (np1 == NULL)
   1355     0    stevel 		if (np2 == NULL)
   1356     0    stevel 			return (0);
   1357     0    stevel 		else
   1358     0    stevel 			return (-1);
   1359     0    stevel 	else if (np2 == NULL)
   1360     0    stevel 		return (1);
   1361     0    stevel 	else
   1362     0    stevel 		return (np2->u.name.s - np1->u.name.s);
   1363     0    stevel }
   1364     0    stevel 
   1365     0    stevel int
   1366     0    stevel tree_eventcmp(struct node *np1, struct node *np2)
   1367     0    stevel {
   1368     0    stevel 	int ret;
   1369     0    stevel 
   1370     0    stevel 	ASSERT(np1 != NULL);
   1371     0    stevel 	ASSERT(np2 != NULL);
   1372     0    stevel 	ASSERTinfo(np1->t == T_EVENT, ptree_nodetype2str(np1->t));
   1373     0    stevel 	ASSERTinfo(np2->t == T_EVENT, ptree_nodetype2str(np2->t));
   1374     0    stevel 
   1375     0    stevel 	if ((ret = tree_namecmp(np1->u.event.ename,
   1376  4436    stephh 	    np2->u.event.ename)) == 0) {
   1377     0    stevel 			if (np1->u.event.epname == NULL &&
   1378  4436    stephh 			    np2->u.event.epname == NULL)
   1379     0    stevel 				return (0);
   1380     0    stevel 			else if (np1->u.event.epname == NULL)
   1381     0    stevel 				return (-1);
   1382     0    stevel 			else if (np2->u.event.epname == NULL)
   1383     0    stevel 				return (1);
   1384     0    stevel 			else
   1385     0    stevel 				return tree_namecmp(np1->u.event.epname,
   1386  4436    stephh 				    np2->u.event.epname);
   1387     0    stevel 	} else
   1388     0    stevel 	return (ret);
   1389     0    stevel }
   1390