xref: /freebsd/contrib/bsnmp/gensnmptree/gensnmptree.c (revision 9a696dc6bb0e8e783dfd169c8299e1f33aac2935)
1f06ca4afSHartmut Brandt /*
2f06ca4afSHartmut Brandt  * Copyright (c) 2001-2003
3f06ca4afSHartmut Brandt  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4f06ca4afSHartmut Brandt  *	All rights reserved.
5f06ca4afSHartmut Brandt  *
68e9b3e70SHartmut Brandt  * Copyright (c) 2004-2006,2018
7896052c1SHartmut Brandt  *	Hartmut Brandt.
8896052c1SHartmut Brandt  *	All rights reserved.
9896052c1SHartmut Brandt  *
10f06ca4afSHartmut Brandt  * Author: Harti Brandt <harti@freebsd.org>
11f06ca4afSHartmut Brandt  *
12896052c1SHartmut Brandt  * Redistribution and use in source and binary forms, with or without
13896052c1SHartmut Brandt  * modification, are permitted provided that the following conditions
14896052c1SHartmut Brandt  * are met:
15896052c1SHartmut Brandt  * 1. Redistributions of source code must retain the above copyright
16896052c1SHartmut Brandt  *    notice, this list of conditions and the following disclaimer.
17f06ca4afSHartmut Brandt  * 2. Redistributions in binary form must reproduce the above copyright
18f06ca4afSHartmut Brandt  *    notice, this list of conditions and the following disclaimer in the
19f06ca4afSHartmut Brandt  *    documentation and/or other materials provided with the distribution.
20f06ca4afSHartmut Brandt  *
21896052c1SHartmut Brandt  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22896052c1SHartmut Brandt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23896052c1SHartmut Brandt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24896052c1SHartmut Brandt  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
25896052c1SHartmut Brandt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26896052c1SHartmut Brandt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27896052c1SHartmut Brandt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28896052c1SHartmut Brandt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29896052c1SHartmut Brandt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30896052c1SHartmut Brandt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31896052c1SHartmut Brandt  * SUCH DAMAGE.
32f06ca4afSHartmut Brandt  *
336f557cf7SHartmut Brandt  * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $
34f06ca4afSHartmut Brandt  *
35f06ca4afSHartmut Brandt  * Generate OID table from table description.
36f06ca4afSHartmut Brandt  *
37f06ca4afSHartmut Brandt  * Syntax is:
38f06ca4afSHartmut Brandt  * ---------
396f557cf7SHartmut Brandt  * file := top | top file
406f557cf7SHartmut Brandt  *
416f557cf7SHartmut Brandt  * top := tree | typedef | include
42896052c1SHartmut Brandt  *
43f06ca4afSHartmut Brandt  * tree := head elements ')'
44f06ca4afSHartmut Brandt  *
45f06ca4afSHartmut Brandt  * entry := head ':' index STRING elements ')'
46f06ca4afSHartmut Brandt  *
476f557cf7SHartmut Brandt  * leaf := head type STRING ACCESS ')'
48f06ca4afSHartmut Brandt  *
496f557cf7SHartmut Brandt  * column := head type ACCESS ')'
506f557cf7SHartmut Brandt  *
516f557cf7SHartmut Brandt  * type := BASETYPE | BASETYPE '|' subtype | enum | bits
526f557cf7SHartmut Brandt  *
536f557cf7SHartmut Brandt  * subtype := STRING
546f557cf7SHartmut Brandt  *
556f557cf7SHartmut Brandt  * enum := ENUM '(' value ')'
566f557cf7SHartmut Brandt  *
576f557cf7SHartmut Brandt  * bits := BITS '(' value ')'
586f557cf7SHartmut Brandt  *
596f557cf7SHartmut Brandt  * value := optminus INT STRING | optminus INT STRING value
606f557cf7SHartmut Brandt  *
616f557cf7SHartmut Brandt  * optminus := '-' | EMPTY
62f06ca4afSHartmut Brandt  *
63f06ca4afSHartmut Brandt  * head := '(' INT STRING
64f06ca4afSHartmut Brandt  *
65f06ca4afSHartmut Brandt  * elements := EMPTY | elements element
66f06ca4afSHartmut Brandt  *
6794caccb3SHartmut Brandt  * element := tree | leaf | column
68f06ca4afSHartmut Brandt  *
696f557cf7SHartmut Brandt  * index := type | index type
70f06ca4afSHartmut Brandt  *
716f557cf7SHartmut Brandt  * typedef := 'typedef' STRING type
726f557cf7SHartmut Brandt  *
736f557cf7SHartmut Brandt  * include := 'include' filespec
746f557cf7SHartmut Brandt  *
756f557cf7SHartmut Brandt  * filespec := '"' STRING '"' | '<' STRING '>'
76f06ca4afSHartmut Brandt  */
77f06ca4afSHartmut Brandt #include <sys/types.h>
78f06ca4afSHartmut Brandt #include <sys/param.h>
79f06ca4afSHartmut Brandt #include <stdio.h>
80f06ca4afSHartmut Brandt #include <stdlib.h>
81f06ca4afSHartmut Brandt #include <stdarg.h>
82f06ca4afSHartmut Brandt #include <unistd.h>
83f06ca4afSHartmut Brandt #include <string.h>
84f06ca4afSHartmut Brandt #include <ctype.h>
850a9d66caSHartmut Brandt #include <inttypes.h>
86896052c1SHartmut Brandt #include <errno.h>
87896052c1SHartmut Brandt #ifdef HAVE_ERR_H
88f06ca4afSHartmut Brandt #include <err.h>
89896052c1SHartmut Brandt #endif
90f06ca4afSHartmut Brandt #include <sys/queue.h>
91896052c1SHartmut Brandt #include "support.h"
92f06ca4afSHartmut Brandt #include "asn1.h"
93f06ca4afSHartmut Brandt #include "snmp.h"
94f06ca4afSHartmut Brandt #include "snmpagent.h"
95f06ca4afSHartmut Brandt 
96f06ca4afSHartmut Brandt /*
97f06ca4afSHartmut Brandt  * Constant prefix for all OIDs
98f06ca4afSHartmut Brandt  */
99f06ca4afSHartmut Brandt static const asn_subid_t prefix[] = { 1, 3, 6 };
100f06ca4afSHartmut Brandt #define	PREFIX_LEN	(sizeof(prefix) / sizeof(prefix[0]))
101f06ca4afSHartmut Brandt 
102f06ca4afSHartmut Brandt u_int tree_size;
103f06ca4afSHartmut Brandt static const char *file_prefix = "";
104f06ca4afSHartmut Brandt 
105f06ca4afSHartmut Brandt /* if true generate local include paths */
106f06ca4afSHartmut Brandt static int localincs = 0;
107f06ca4afSHartmut Brandt 
1086f557cf7SHartmut Brandt /* if true print tokens */
1096f557cf7SHartmut Brandt static int debug;
1106f557cf7SHartmut Brandt 
111f06ca4afSHartmut Brandt static const char usgtxt[] = "\
1126f557cf7SHartmut Brandt Generate SNMP tables.\n\
1138e9b3e70SHartmut Brandt usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\
1146f557cf7SHartmut Brandt 	    [name]...\n\
115f06ca4afSHartmut Brandt options:\n\
1166f557cf7SHartmut Brandt   -d		debug mode\n\
1178e9b3e70SHartmut Brandt   -E		extract the named or all enums and bits only\n\
1186f557cf7SHartmut Brandt   -e		extract the named oids or enums\n\
1198e9b3e70SHartmut Brandt   -F		generate functions for -E into a .c file\n\
1208e9b3e70SHartmut Brandt   -f		generate functions for -E into the header\n\
121f06ca4afSHartmut Brandt   -h		print this info\n\
1226f557cf7SHartmut Brandt   -I directory	add directory to include path\n\
1236f557cf7SHartmut Brandt   -i ifile	read from the named file instead of stdin\n\
124f06ca4afSHartmut Brandt   -l		generate local include directives\n\
125f06ca4afSHartmut Brandt   -p prefix	prepend prefix to file and variable names\n\
1268e9b3e70SHartmut Brandt   -t		generate a .def file\n\
127f06ca4afSHartmut Brandt ";
128f06ca4afSHartmut Brandt 
129*04d17814SAndrey V. Elsukov /**
130*04d17814SAndrey V. Elsukov  * Program operation.
131*04d17814SAndrey V. Elsukov  */
132*04d17814SAndrey V. Elsukov enum op {
133*04d17814SAndrey V. Elsukov 	/** generate the tree */
134*04d17814SAndrey V. Elsukov 	OP_GEN,
135*04d17814SAndrey V. Elsukov 
136*04d17814SAndrey V. Elsukov 	/** extract OIDs */
137*04d17814SAndrey V. Elsukov 	OP_EXTRACT,
138*04d17814SAndrey V. Elsukov 
139*04d17814SAndrey V. Elsukov 	/** print the parsed tree */
140*04d17814SAndrey V. Elsukov 	OP_TREE,
141*04d17814SAndrey V. Elsukov 
142*04d17814SAndrey V. Elsukov 	/** extract enums */
143*04d17814SAndrey V. Elsukov 	OP_ENUMS,
144*04d17814SAndrey V. Elsukov };
145*04d17814SAndrey V. Elsukov 
146*04d17814SAndrey V. Elsukov /**
147*04d17814SAndrey V. Elsukov  * Which functions to create.
148*04d17814SAndrey V. Elsukov  */
149*04d17814SAndrey V. Elsukov enum gen_funcs {
150*04d17814SAndrey V. Elsukov 	/** none */
151*04d17814SAndrey V. Elsukov 	GEN_FUNCS_NONE,
152*04d17814SAndrey V. Elsukov 
153*04d17814SAndrey V. Elsukov 	/** functions for header files */
154*04d17814SAndrey V. Elsukov 	GEN_FUNCS_H,
155*04d17814SAndrey V. Elsukov 
156*04d17814SAndrey V. Elsukov 	/** functions for C files */
157*04d17814SAndrey V. Elsukov 	GEN_FUNCS_C,
158*04d17814SAndrey V. Elsukov };
159*04d17814SAndrey V. Elsukov 
160f06ca4afSHartmut Brandt /*
161f06ca4afSHartmut Brandt  * A node in the OID tree
162f06ca4afSHartmut Brandt  */
163f06ca4afSHartmut Brandt enum ntype {
164f06ca4afSHartmut Brandt 	NODE_LEAF = 1,
165f06ca4afSHartmut Brandt 	NODE_TREE,
166f06ca4afSHartmut Brandt 	NODE_ENTRY,
167f06ca4afSHartmut Brandt 	NODE_COLUMN
168f06ca4afSHartmut Brandt };
169f06ca4afSHartmut Brandt 
170f06ca4afSHartmut Brandt enum {
171f06ca4afSHartmut Brandt 	FL_GET	= 0x01,
172f06ca4afSHartmut Brandt 	FL_SET	= 0x02,
173f06ca4afSHartmut Brandt };
174f06ca4afSHartmut Brandt 
175f06ca4afSHartmut Brandt struct node;
176f06ca4afSHartmut Brandt TAILQ_HEAD(node_list, node);
177f06ca4afSHartmut Brandt 
178f06ca4afSHartmut Brandt struct node {
179f06ca4afSHartmut Brandt 	enum ntype	type;
180f06ca4afSHartmut Brandt 	asn_subid_t	id;	/* last element of OID */
181f06ca4afSHartmut Brandt 	char		*name;	/* name of node */
182f06ca4afSHartmut Brandt 	TAILQ_ENTRY(node) link;
183f06ca4afSHartmut Brandt 	u_int		lno;	/* starting line number */
184f06ca4afSHartmut Brandt 	u_int		flags;	/* allowed operations */
185f06ca4afSHartmut Brandt 
186f06ca4afSHartmut Brandt 	union {
187f06ca4afSHartmut Brandt 	  struct tree {
188f06ca4afSHartmut Brandt 	    struct node_list subs;
189f06ca4afSHartmut Brandt 	  }		tree;
190f06ca4afSHartmut Brandt 
191f06ca4afSHartmut Brandt 	  struct entry {
192896052c1SHartmut Brandt 	    uint32_t	index;	/* index for table entry */
193f06ca4afSHartmut Brandt 	    char	*func;	/* function for tables */
194f06ca4afSHartmut Brandt 	    struct node_list subs;
195*04d17814SAndrey V. Elsukov 	    char	*subtypes[SNMP_INDEXES_MAX];
196f06ca4afSHartmut Brandt 	  }		entry;
197f06ca4afSHartmut Brandt 
198f06ca4afSHartmut Brandt 	  struct leaf {
199f06ca4afSHartmut Brandt 	    enum snmp_syntax syntax;	/* syntax for this leaf */
200f06ca4afSHartmut Brandt 	    char	*func;		/* function name */
201*04d17814SAndrey V. Elsukov 	    char	*subtype;	/* subtype */
202f06ca4afSHartmut Brandt 	  }		leaf;
203f06ca4afSHartmut Brandt 
204f06ca4afSHartmut Brandt 	  struct column {
205f06ca4afSHartmut Brandt 	    enum snmp_syntax syntax;	/* syntax for this column */
206*04d17814SAndrey V. Elsukov 	    char	*subtype;	/* subtype */
207f06ca4afSHartmut Brandt 	  }		column;
208f06ca4afSHartmut Brandt 	}		u;
209f06ca4afSHartmut Brandt };
210f06ca4afSHartmut Brandt 
211f06ca4afSHartmut Brandt struct func {
212f06ca4afSHartmut Brandt 	const char	*name;
213f06ca4afSHartmut Brandt 	LIST_ENTRY(func) link;
214f06ca4afSHartmut Brandt };
215f06ca4afSHartmut Brandt 
216f06ca4afSHartmut Brandt static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs);
217f06ca4afSHartmut Brandt 
2186f557cf7SHartmut Brandt struct enums {
2196f557cf7SHartmut Brandt 	const char	*name;
2206f557cf7SHartmut Brandt 	long		value;
2216f557cf7SHartmut Brandt 	TAILQ_ENTRY(enums) link;
2226f557cf7SHartmut Brandt };
2236f557cf7SHartmut Brandt 
2246f557cf7SHartmut Brandt struct type {
2256f557cf7SHartmut Brandt 	const char	*name;
2266f557cf7SHartmut Brandt 	const char	*from_fname;
2276f557cf7SHartmut Brandt 	u_int		from_lno;
2286f557cf7SHartmut Brandt 	u_int		syntax;
2296f557cf7SHartmut Brandt 	int		is_enum;
2306f557cf7SHartmut Brandt 	int		is_bits;
2316f557cf7SHartmut Brandt 	TAILQ_HEAD(, enums) enums;
2326f557cf7SHartmut Brandt 	LIST_ENTRY(type) link;
2336f557cf7SHartmut Brandt };
2346f557cf7SHartmut Brandt 
2356f557cf7SHartmut Brandt static LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types);
2366f557cf7SHartmut Brandt 
2376f557cf7SHartmut Brandt static void report(const char *, ...) __dead2 __printflike(1, 2);
2386f557cf7SHartmut Brandt static void report_node(const struct node *, const char *, ...)
2396f557cf7SHartmut Brandt     __dead2 __printflike(2, 3);
2406f557cf7SHartmut Brandt 
241f06ca4afSHartmut Brandt /************************************************************
242f06ca4afSHartmut Brandt  *
243f06ca4afSHartmut Brandt  * Allocate memory and panic just in the case...
244f06ca4afSHartmut Brandt  */
245f06ca4afSHartmut Brandt static void *
xalloc(size_t size)246f06ca4afSHartmut Brandt xalloc(size_t size)
247f06ca4afSHartmut Brandt {
248f06ca4afSHartmut Brandt 	void *ptr;
249f06ca4afSHartmut Brandt 
250*04d17814SAndrey V. Elsukov 	if ((ptr = calloc(1, size)) == NULL)
251d7eb6b47SHartmut Brandt 		err(1, "allocing %zu bytes", size);
252f06ca4afSHartmut Brandt 
253f06ca4afSHartmut Brandt 	return (ptr);
254f06ca4afSHartmut Brandt }
255f06ca4afSHartmut Brandt 
2566f557cf7SHartmut Brandt static char *
savestr(const char * s)2576f557cf7SHartmut Brandt savestr(const char *s)
2586f557cf7SHartmut Brandt {
2596f557cf7SHartmut Brandt 
2606f557cf7SHartmut Brandt 	if (s == NULL)
2616f557cf7SHartmut Brandt 		return (NULL);
2626f557cf7SHartmut Brandt 	return (strcpy(xalloc(strlen(s) + 1), s));
2636f557cf7SHartmut Brandt }
2646f557cf7SHartmut Brandt 
2656f557cf7SHartmut Brandt /************************************************************
2666f557cf7SHartmut Brandt  *
2676f557cf7SHartmut Brandt  * Input stack
2686f557cf7SHartmut Brandt  */
2696f557cf7SHartmut Brandt struct input {
2706f557cf7SHartmut Brandt 	FILE		*fp;
2716f557cf7SHartmut Brandt 	u_int		lno;
2726f557cf7SHartmut Brandt 	char		*fname;
2736f557cf7SHartmut Brandt 	char		*path;
2746f557cf7SHartmut Brandt 	LIST_ENTRY(input) link;
2756f557cf7SHartmut Brandt };
2766f557cf7SHartmut Brandt static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
2776f557cf7SHartmut Brandt static struct input *input = NULL;
2786f557cf7SHartmut Brandt 
2796f557cf7SHartmut Brandt #define MAX_PATHS	100
2806f557cf7SHartmut Brandt static u_int npaths = 2;
2816f557cf7SHartmut Brandt static u_int stdpaths = 2;
2826f557cf7SHartmut Brandt static const char *paths[MAX_PATHS + 1] = {
2836f557cf7SHartmut Brandt 	"/usr/share/snmp/defs",
2846f557cf7SHartmut Brandt 	"/usr/local/share/snmp/defs",
2856f557cf7SHartmut Brandt 	NULL
2866f557cf7SHartmut Brandt };
2876f557cf7SHartmut Brandt 
2886f557cf7SHartmut Brandt static int pbchar = -1;
2896f557cf7SHartmut Brandt 
2906f557cf7SHartmut Brandt static void
path_new(const char * path)2916f557cf7SHartmut Brandt path_new(const char *path)
2926f557cf7SHartmut Brandt {
2936f557cf7SHartmut Brandt 	if (npaths >= MAX_PATHS)
2946f557cf7SHartmut Brandt 		report("too many -I directives");
2956f557cf7SHartmut Brandt 	memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths],
2966f557cf7SHartmut Brandt 	    sizeof(path[0]) * stdpaths);
2976f557cf7SHartmut Brandt 	paths[npaths - stdpaths] = savestr(path);
2986f557cf7SHartmut Brandt 	npaths++;
2996f557cf7SHartmut Brandt }
3006f557cf7SHartmut Brandt 
3016f557cf7SHartmut Brandt static void
input_new(FILE * fp,const char * path,const char * fname)3026f557cf7SHartmut Brandt input_new(FILE *fp, const char *path, const char *fname)
3036f557cf7SHartmut Brandt {
3046f557cf7SHartmut Brandt 	struct input *ip;
3056f557cf7SHartmut Brandt 
3066f557cf7SHartmut Brandt 	ip = xalloc(sizeof(*ip));
3076f557cf7SHartmut Brandt 	ip->fp = fp;
3086f557cf7SHartmut Brandt 	ip->lno = 1;
3096f557cf7SHartmut Brandt 	ip->fname = savestr(fname);
3106f557cf7SHartmut Brandt 	ip->path = savestr(path);
3116f557cf7SHartmut Brandt 	LIST_INSERT_HEAD(&inputs, ip, link);
3126f557cf7SHartmut Brandt 
3136f557cf7SHartmut Brandt 	input = ip;
3146f557cf7SHartmut Brandt }
3156f557cf7SHartmut Brandt 
3166f557cf7SHartmut Brandt static void
input_close(void)3176f557cf7SHartmut Brandt input_close(void)
3186f557cf7SHartmut Brandt {
3196f557cf7SHartmut Brandt 
3206f557cf7SHartmut Brandt 	if (input == NULL)
3216f557cf7SHartmut Brandt 		return;
3226f557cf7SHartmut Brandt 	fclose(input->fp);
3236f557cf7SHartmut Brandt 	free(input->fname);
3246f557cf7SHartmut Brandt 	free(input->path);
3256f557cf7SHartmut Brandt 	LIST_REMOVE(input, link);
3266f557cf7SHartmut Brandt 	free(input);
3276f557cf7SHartmut Brandt 
3286f557cf7SHartmut Brandt 	input = LIST_FIRST(&inputs);
3296f557cf7SHartmut Brandt }
3306f557cf7SHartmut Brandt 
3316f557cf7SHartmut Brandt static FILE *
tryopen(const char * path,const char * fname)3326f557cf7SHartmut Brandt tryopen(const char *path, const char *fname)
3336f557cf7SHartmut Brandt {
3346f557cf7SHartmut Brandt 	char *fn;
3356f557cf7SHartmut Brandt 	FILE *fp;
3366f557cf7SHartmut Brandt 
3376f557cf7SHartmut Brandt 	if (path == NULL)
3386f557cf7SHartmut Brandt 		fn = savestr(fname);
3396f557cf7SHartmut Brandt 	else {
3406f557cf7SHartmut Brandt 		fn = xalloc(strlen(path) + strlen(fname) + 2);
3416f557cf7SHartmut Brandt 		sprintf(fn, "%s/%s", path, fname);
3426f557cf7SHartmut Brandt 	}
3436f557cf7SHartmut Brandt 	fp = fopen(fn, "r");
3446f557cf7SHartmut Brandt 	free(fn);
3456f557cf7SHartmut Brandt 	return (fp);
3466f557cf7SHartmut Brandt }
3476f557cf7SHartmut Brandt 
3486f557cf7SHartmut Brandt static void
input_fopen(const char * fname,int loc)3496f557cf7SHartmut Brandt input_fopen(const char *fname, int loc)
3506f557cf7SHartmut Brandt {
3516f557cf7SHartmut Brandt 	FILE *fp;
3526f557cf7SHartmut Brandt 	char *path;
3536f557cf7SHartmut Brandt 	u_int p;
3546f557cf7SHartmut Brandt 
3556f557cf7SHartmut Brandt 	if (fname[0] == '/') {
3566f557cf7SHartmut Brandt 		if ((fp = tryopen(NULL, fname)) != NULL) {
3576f557cf7SHartmut Brandt 			input_new(fp, NULL, fname);
3586f557cf7SHartmut Brandt 			return;
3596f557cf7SHartmut Brandt 		}
3606f557cf7SHartmut Brandt 
3616f557cf7SHartmut Brandt 	} else {
3626f557cf7SHartmut Brandt 		if (loc) {
3636f557cf7SHartmut Brandt 			if (input == NULL)
3646f557cf7SHartmut Brandt 				path = NULL;
3656f557cf7SHartmut Brandt 			else
3666f557cf7SHartmut Brandt 				path = input->path;
3676f557cf7SHartmut Brandt 
3686f557cf7SHartmut Brandt 			if ((fp = tryopen(path, fname)) != NULL) {
3696f557cf7SHartmut Brandt 				input_new(fp, NULL, fname);
3706f557cf7SHartmut Brandt 				return;
3716f557cf7SHartmut Brandt 			}
3726f557cf7SHartmut Brandt 		}
3736f557cf7SHartmut Brandt 
3746f557cf7SHartmut Brandt 		for (p = 0; paths[p] != NULL; p++)
3756f557cf7SHartmut Brandt 			if ((fp = tryopen(paths[p], fname)) != NULL) {
3766f557cf7SHartmut Brandt 				input_new(fp, paths[p], fname);
3776f557cf7SHartmut Brandt 				return;
3786f557cf7SHartmut Brandt 			}
3796f557cf7SHartmut Brandt 	}
3806f557cf7SHartmut Brandt 	report("cannot open '%s'", fname);
3816f557cf7SHartmut Brandt }
3826f557cf7SHartmut Brandt 
3836f557cf7SHartmut Brandt static int
tgetc(void)3846f557cf7SHartmut Brandt tgetc(void)
3856f557cf7SHartmut Brandt {
3866f557cf7SHartmut Brandt 	int c;
3876f557cf7SHartmut Brandt 
3886f557cf7SHartmut Brandt 	if (pbchar != -1) {
3896f557cf7SHartmut Brandt 		c = pbchar;
3906f557cf7SHartmut Brandt 		pbchar = -1;
3916f557cf7SHartmut Brandt 		return (c);
3926f557cf7SHartmut Brandt 	}
3936f557cf7SHartmut Brandt 
3946f557cf7SHartmut Brandt 	for (;;) {
3956f557cf7SHartmut Brandt 		if (input == NULL)
3966f557cf7SHartmut Brandt 			return (EOF);
3976f557cf7SHartmut Brandt 
3986f557cf7SHartmut Brandt 		if ((c = getc(input->fp)) != EOF)
3996f557cf7SHartmut Brandt 			return (c);
4006f557cf7SHartmut Brandt 
4016f557cf7SHartmut Brandt 		input_close();
4026f557cf7SHartmut Brandt 	}
4036f557cf7SHartmut Brandt }
4046f557cf7SHartmut Brandt 
4056f557cf7SHartmut Brandt static void
tungetc(int c)4066f557cf7SHartmut Brandt tungetc(int c)
4076f557cf7SHartmut Brandt {
4086f557cf7SHartmut Brandt 
4096f557cf7SHartmut Brandt 	if (pbchar != -1)
4106f557cf7SHartmut Brandt 		abort();
4116f557cf7SHartmut Brandt 	pbchar = c;
4126f557cf7SHartmut Brandt }
4136f557cf7SHartmut Brandt 
414f06ca4afSHartmut Brandt /************************************************************
415f06ca4afSHartmut Brandt  *
416f06ca4afSHartmut Brandt  * Parsing input
417f06ca4afSHartmut Brandt  */
418f06ca4afSHartmut Brandt enum tok {
419f06ca4afSHartmut Brandt 	TOK_EOF = 0200,	/* end-of-file seen */
420f06ca4afSHartmut Brandt 	TOK_NUM,	/* number */
421f06ca4afSHartmut Brandt 	TOK_STR,	/* string */
422f06ca4afSHartmut Brandt 	TOK_ACCESS,	/* access operator */
423f06ca4afSHartmut Brandt 	TOK_TYPE,	/* type operator */
4246f557cf7SHartmut Brandt 	TOK_ENUM,	/* enum token (kind of a type) */
4256f557cf7SHartmut Brandt 	TOK_TYPEDEF,	/* typedef directive */
4266f557cf7SHartmut Brandt 	TOK_DEFTYPE,	/* defined type */
4276f557cf7SHartmut Brandt 	TOK_INCLUDE,	/* include directive */
4286f557cf7SHartmut Brandt 	TOK_FILENAME,	/* filename ("foo.bar" or <foo.bar>) */
4296f557cf7SHartmut Brandt 	TOK_BITS,	/* bits token (kind of a type) */
430f06ca4afSHartmut Brandt };
431f06ca4afSHartmut Brandt 
432f06ca4afSHartmut Brandt static const struct {
433f06ca4afSHartmut Brandt 	const char *str;
434f06ca4afSHartmut Brandt 	enum tok tok;
435f06ca4afSHartmut Brandt 	u_int val;
436f06ca4afSHartmut Brandt } keywords[] = {
437f06ca4afSHartmut Brandt 	{ "GET", TOK_ACCESS, FL_GET },
438f06ca4afSHartmut Brandt 	{ "SET", TOK_ACCESS, FL_SET },
439f06ca4afSHartmut Brandt 	{ "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
440f06ca4afSHartmut Brandt 	{ "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
441f06ca4afSHartmut Brandt 	{ "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
442f06ca4afSHartmut Brandt 	{ "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
443f06ca4afSHartmut Brandt 	{ "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
444f06ca4afSHartmut Brandt 	{ "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
445f06ca4afSHartmut Brandt 	{ "OID", TOK_TYPE, SNMP_SYNTAX_OID },
446f06ca4afSHartmut Brandt 	{ "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
447f06ca4afSHartmut Brandt 	{ "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
448f06ca4afSHartmut Brandt 	{ "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
449f06ca4afSHartmut Brandt 	{ "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
4506f557cf7SHartmut Brandt 	{ "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
4516f557cf7SHartmut Brandt 	{ "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
4526f557cf7SHartmut Brandt 	{ "typedef", TOK_TYPEDEF, 0 },
4536f557cf7SHartmut Brandt 	{ "include", TOK_INCLUDE, 0 },
454f06ca4afSHartmut Brandt 	{ NULL, 0, 0 }
455f06ca4afSHartmut Brandt };
456f06ca4afSHartmut Brandt 
457f06ca4afSHartmut Brandt /* arbitrary upper limit on node names and function names */
458f06ca4afSHartmut Brandt #define	MAXSTR	1000
4598e9b3e70SHartmut Brandt static char	str[MAXSTR];
4608e9b3e70SHartmut Brandt static u_long	val;		/* integer values */
4618e9b3e70SHartmut Brandt static int	saved_token = -1;
462f06ca4afSHartmut Brandt 
463f06ca4afSHartmut Brandt /*
464f06ca4afSHartmut Brandt  * Report an error and exit.
465f06ca4afSHartmut Brandt  */
466f06ca4afSHartmut Brandt static void
report(const char * fmt,...)467f06ca4afSHartmut Brandt report(const char *fmt, ...)
468f06ca4afSHartmut Brandt {
469f06ca4afSHartmut Brandt 	va_list ap;
470f06ca4afSHartmut Brandt 	int c;
471f06ca4afSHartmut Brandt 
472f06ca4afSHartmut Brandt 	va_start(ap, fmt);
4736f557cf7SHartmut Brandt 	fprintf(stderr, "line %u: ", input->lno);
474f06ca4afSHartmut Brandt 	vfprintf(stderr, fmt, ap);
475f06ca4afSHartmut Brandt 	fprintf(stderr, "\n");
476f06ca4afSHartmut Brandt 	fprintf(stderr, "context: \"");
4776f557cf7SHartmut Brandt 	while ((c = tgetc()) != EOF && c != '\n')
478f06ca4afSHartmut Brandt 		fprintf(stderr, "%c", c);
479f06ca4afSHartmut Brandt 	fprintf(stderr, "\n");
480f06ca4afSHartmut Brandt 	va_end(ap);
481f06ca4afSHartmut Brandt 	exit(1);
482f06ca4afSHartmut Brandt }
483f06ca4afSHartmut Brandt static void
report_node(const struct node * np,const char * fmt,...)484f06ca4afSHartmut Brandt report_node(const struct node *np, const char *fmt, ...)
485f06ca4afSHartmut Brandt {
486f06ca4afSHartmut Brandt 	va_list ap;
487f06ca4afSHartmut Brandt 
488f06ca4afSHartmut Brandt 	va_start(ap, fmt);
489f06ca4afSHartmut Brandt 	fprintf(stderr, "line %u, node %s: ", np->lno, np->name);
490f06ca4afSHartmut Brandt 	vfprintf(stderr, fmt, ap);
491f06ca4afSHartmut Brandt 	fprintf(stderr, "\n");
492f06ca4afSHartmut Brandt 	va_end(ap);
493f06ca4afSHartmut Brandt 	exit(1);
494f06ca4afSHartmut Brandt }
495f06ca4afSHartmut Brandt 
496f06ca4afSHartmut Brandt /*
497f06ca4afSHartmut Brandt  * Return a fresh copy of the string constituting the current token.
498f06ca4afSHartmut Brandt  */
499f06ca4afSHartmut Brandt static char *
savetok(void)500f06ca4afSHartmut Brandt savetok(void)
501f06ca4afSHartmut Brandt {
5026f557cf7SHartmut Brandt 	return (savestr(str));
503f06ca4afSHartmut Brandt }
504f06ca4afSHartmut Brandt 
505f06ca4afSHartmut Brandt /*
506f06ca4afSHartmut Brandt  * Get the next token from input.
507f06ca4afSHartmut Brandt  */
508f06ca4afSHartmut Brandt static int
gettoken_internal(void)5096f557cf7SHartmut Brandt gettoken_internal(void)
510f06ca4afSHartmut Brandt {
511f06ca4afSHartmut Brandt 	int c;
5126f557cf7SHartmut Brandt 	struct type *t;
5136f557cf7SHartmut Brandt 
5146f557cf7SHartmut Brandt 	if (saved_token != -1) {
5156f557cf7SHartmut Brandt 		c = saved_token;
5166f557cf7SHartmut Brandt 		saved_token = -1;
5176f557cf7SHartmut Brandt 		return (c);
5186f557cf7SHartmut Brandt 	}
519f06ca4afSHartmut Brandt 
520f06ca4afSHartmut Brandt   again:
521f06ca4afSHartmut Brandt 	/*
522f06ca4afSHartmut Brandt 	 * Skip any whitespace before the next token
523f06ca4afSHartmut Brandt 	 */
5246f557cf7SHartmut Brandt 	while ((c = tgetc()) != EOF) {
525f06ca4afSHartmut Brandt 		if (c == '\n')
5266f557cf7SHartmut Brandt 			input->lno++;
527f06ca4afSHartmut Brandt 		if (!isspace(c))
528f06ca4afSHartmut Brandt 			break;
529f06ca4afSHartmut Brandt 	}
530f06ca4afSHartmut Brandt 	if (c == EOF)
531f06ca4afSHartmut Brandt 		return (TOK_EOF);
532f06ca4afSHartmut Brandt 	if (!isascii(c))
533f06ca4afSHartmut Brandt 		report("unexpected character %#2x", (u_int)c);
534f06ca4afSHartmut Brandt 
535f06ca4afSHartmut Brandt 	/*
536f06ca4afSHartmut Brandt 	 * Skip comments
537f06ca4afSHartmut Brandt 	 */
538f06ca4afSHartmut Brandt 	if (c == '#') {
5396f557cf7SHartmut Brandt 		while ((c = tgetc()) != EOF) {
540f06ca4afSHartmut Brandt 			if (c == '\n') {
5416f557cf7SHartmut Brandt 				input->lno++;
542f06ca4afSHartmut Brandt 				goto again;
543f06ca4afSHartmut Brandt 			}
544f06ca4afSHartmut Brandt 		}
545f06ca4afSHartmut Brandt 		report("unexpected EOF in comment");
546f06ca4afSHartmut Brandt 	}
547f06ca4afSHartmut Brandt 
548f06ca4afSHartmut Brandt 	/*
549f06ca4afSHartmut Brandt 	 * Single character tokens
550f06ca4afSHartmut Brandt 	 */
5516f557cf7SHartmut Brandt 	if (strchr("():|-", c) != NULL)
552f06ca4afSHartmut Brandt 		return (c);
553f06ca4afSHartmut Brandt 
5546f557cf7SHartmut Brandt 	if (c == '"' || c == '<') {
5556f557cf7SHartmut Brandt 		int end = c;
5566f557cf7SHartmut Brandt 		size_t n = 0;
5576f557cf7SHartmut Brandt 
5586f557cf7SHartmut Brandt 		val = 1;
5596f557cf7SHartmut Brandt 		if (c == '<') {
5606f557cf7SHartmut Brandt 			val = 0;
5616f557cf7SHartmut Brandt 			end = '>';
5626f557cf7SHartmut Brandt 		}
5636f557cf7SHartmut Brandt 
5646f557cf7SHartmut Brandt 		while ((c = tgetc()) != EOF) {
5656f557cf7SHartmut Brandt 			if (c == end)
5666f557cf7SHartmut Brandt 				break;
5676f557cf7SHartmut Brandt 			if (n == sizeof(str) - 1) {
5686f557cf7SHartmut Brandt 				str[n++] = '\0';
5696f557cf7SHartmut Brandt 				report("filename too long '%s...'", str);
5706f557cf7SHartmut Brandt 			}
5716f557cf7SHartmut Brandt 			str[n++] = c;
5726f557cf7SHartmut Brandt 		}
5736f557cf7SHartmut Brandt 		str[n++] = '\0';
5746f557cf7SHartmut Brandt 		return (TOK_FILENAME);
5756f557cf7SHartmut Brandt 	}
5766f557cf7SHartmut Brandt 
577f06ca4afSHartmut Brandt 	/*
578f06ca4afSHartmut Brandt 	 * Sort out numbers
579f06ca4afSHartmut Brandt 	 */
580f06ca4afSHartmut Brandt 	if (isdigit(c)) {
5816f557cf7SHartmut Brandt 		size_t n = 0;
5826f557cf7SHartmut Brandt 		str[n++] = c;
5836f557cf7SHartmut Brandt 		while ((c = tgetc()) != EOF) {
5846f557cf7SHartmut Brandt 			if (!isdigit(c)) {
5856f557cf7SHartmut Brandt 				tungetc(c);
5866f557cf7SHartmut Brandt 				break;
5876f557cf7SHartmut Brandt 			}
5886f557cf7SHartmut Brandt 			if (n == sizeof(str) - 1) {
5896f557cf7SHartmut Brandt 				str[n++] = '\0';
5906f557cf7SHartmut Brandt 				report("number too long '%s...'", str);
5916f557cf7SHartmut Brandt 			}
5926f557cf7SHartmut Brandt 			str[n++] = c;
5936f557cf7SHartmut Brandt 		}
5946f557cf7SHartmut Brandt 		str[n++] = '\0';
5956f557cf7SHartmut Brandt 		sscanf(str, "%lu", &val);
596f06ca4afSHartmut Brandt 		return (TOK_NUM);
597f06ca4afSHartmut Brandt 	}
598f06ca4afSHartmut Brandt 
599f06ca4afSHartmut Brandt 	/*
600f06ca4afSHartmut Brandt 	 * So that has to be a string.
601f06ca4afSHartmut Brandt 	 */
602f06ca4afSHartmut Brandt 	if (isalpha(c) || c == '_') {
603f06ca4afSHartmut Brandt 		size_t n = 0;
604f06ca4afSHartmut Brandt 		str[n++] = c;
6056f557cf7SHartmut Brandt 		while ((c = tgetc()) != EOF) {
6066f557cf7SHartmut Brandt 			if (!isalnum(c) && c != '_' && c != '-') {
6076f557cf7SHartmut Brandt 				tungetc(c);
608f06ca4afSHartmut Brandt 				break;
609f06ca4afSHartmut Brandt 			}
610f06ca4afSHartmut Brandt 			if (n == sizeof(str) - 1) {
611f06ca4afSHartmut Brandt 				str[n++] = '\0';
612f06ca4afSHartmut Brandt 				report("string too long '%s...'", str);
613f06ca4afSHartmut Brandt 			}
614f06ca4afSHartmut Brandt 			str[n++] = c;
615f06ca4afSHartmut Brandt 		}
616f06ca4afSHartmut Brandt 		str[n++] = '\0';
617f06ca4afSHartmut Brandt 
618f06ca4afSHartmut Brandt 		/*
619f06ca4afSHartmut Brandt 		 * Keywords
620f06ca4afSHartmut Brandt 		 */
621f06ca4afSHartmut Brandt 		for (c = 0; keywords[c].str != NULL; c++)
622f06ca4afSHartmut Brandt 			if (strcmp(keywords[c].str, str) == 0) {
623f06ca4afSHartmut Brandt 				val = keywords[c].val;
624f06ca4afSHartmut Brandt 				return (keywords[c].tok);
625f06ca4afSHartmut Brandt 			}
626f06ca4afSHartmut Brandt 
6276f557cf7SHartmut Brandt 		LIST_FOREACH(t, &types, link) {
6286f557cf7SHartmut Brandt 			if (strcmp(t->name, str) == 0) {
6296f557cf7SHartmut Brandt 				val = t->syntax;
6306f557cf7SHartmut Brandt 				return (TOK_DEFTYPE);
6316f557cf7SHartmut Brandt 			}
6326f557cf7SHartmut Brandt 		}
633f06ca4afSHartmut Brandt 		return (TOK_STR);
634f06ca4afSHartmut Brandt 	}
635f06ca4afSHartmut Brandt 	if (isprint(c))
6366f557cf7SHartmut Brandt 		errx(1, "%u: unexpected character '%c'", input->lno, c);
637f06ca4afSHartmut Brandt 	else
6386f557cf7SHartmut Brandt 		errx(1, "%u: unexpected character 0x%02x", input->lno,
6396f557cf7SHartmut Brandt 		    (u_int)c);
6406f557cf7SHartmut Brandt }
6416f557cf7SHartmut Brandt static int
gettoken(void)6426f557cf7SHartmut Brandt gettoken(void)
6436f557cf7SHartmut Brandt {
6446f557cf7SHartmut Brandt 	int tok = gettoken_internal();
6456f557cf7SHartmut Brandt 
6466f557cf7SHartmut Brandt 	if (debug) {
6476f557cf7SHartmut Brandt 		switch (tok) {
6486f557cf7SHartmut Brandt 
6496f557cf7SHartmut Brandt 		  case TOK_EOF:
6506f557cf7SHartmut Brandt 			fprintf(stderr, "EOF ");
6516f557cf7SHartmut Brandt 			break;
6526f557cf7SHartmut Brandt 
6536f557cf7SHartmut Brandt 		  case TOK_NUM:
6546f557cf7SHartmut Brandt 			fprintf(stderr, "NUM(%lu) ", val);
6556f557cf7SHartmut Brandt 			break;
6566f557cf7SHartmut Brandt 
6576f557cf7SHartmut Brandt 		  case TOK_STR:
6586f557cf7SHartmut Brandt 			fprintf(stderr, "STR(%s) ", str);
6596f557cf7SHartmut Brandt 			break;
6606f557cf7SHartmut Brandt 
6616f557cf7SHartmut Brandt 		  case TOK_ACCESS:
6626f557cf7SHartmut Brandt 			fprintf(stderr, "ACCESS(%lu) ", val);
6636f557cf7SHartmut Brandt 			break;
6646f557cf7SHartmut Brandt 
6656f557cf7SHartmut Brandt 		  case TOK_TYPE:
6666f557cf7SHartmut Brandt 			fprintf(stderr, "TYPE(%lu) ", val);
6676f557cf7SHartmut Brandt 			break;
6686f557cf7SHartmut Brandt 
6696f557cf7SHartmut Brandt 		  case TOK_ENUM:
6706f557cf7SHartmut Brandt 			fprintf(stderr, "ENUM ");
6716f557cf7SHartmut Brandt 			break;
6726f557cf7SHartmut Brandt 
6736f557cf7SHartmut Brandt 		  case TOK_BITS:
6746f557cf7SHartmut Brandt 			fprintf(stderr, "BITS ");
6756f557cf7SHartmut Brandt 			break;
6766f557cf7SHartmut Brandt 
6776f557cf7SHartmut Brandt 		  case TOK_TYPEDEF:
6786f557cf7SHartmut Brandt 			fprintf(stderr, "TYPEDEF ");
6796f557cf7SHartmut Brandt 			break;
6806f557cf7SHartmut Brandt 
6816f557cf7SHartmut Brandt 		  case TOK_DEFTYPE:
6826f557cf7SHartmut Brandt 			fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val);
6836f557cf7SHartmut Brandt 			break;
6846f557cf7SHartmut Brandt 
6856f557cf7SHartmut Brandt 		  case TOK_INCLUDE:
6866f557cf7SHartmut Brandt 			fprintf(stderr, "INCLUDE ");
6876f557cf7SHartmut Brandt 			break;
6886f557cf7SHartmut Brandt 
6896f557cf7SHartmut Brandt 		  case TOK_FILENAME:
6906f557cf7SHartmut Brandt 			fprintf(stderr, "FILENAME ");
6916f557cf7SHartmut Brandt 			break;
6926f557cf7SHartmut Brandt 
6936f557cf7SHartmut Brandt 		  default:
6946f557cf7SHartmut Brandt 			if (tok < TOK_EOF) {
6956f557cf7SHartmut Brandt 				if (isprint(tok))
6966f557cf7SHartmut Brandt 					fprintf(stderr, "'%c' ", tok);
6976f557cf7SHartmut Brandt 				else if (tok == '\n')
6986f557cf7SHartmut Brandt 					fprintf(stderr, "\n");
6996f557cf7SHartmut Brandt 				else
7006f557cf7SHartmut Brandt 					fprintf(stderr, "%02x ", tok);
7016f557cf7SHartmut Brandt 			} else
7026f557cf7SHartmut Brandt 				abort();
7036f557cf7SHartmut Brandt 			break;
7046f557cf7SHartmut Brandt 		}
7056f557cf7SHartmut Brandt 	}
7066f557cf7SHartmut Brandt 	return (tok);
7076f557cf7SHartmut Brandt }
7086f557cf7SHartmut Brandt 
7096f557cf7SHartmut Brandt /**
7106f557cf7SHartmut Brandt  * Pushback a token
7116f557cf7SHartmut Brandt  */
7126f557cf7SHartmut Brandt static void
pushback(enum tok tok)7136f557cf7SHartmut Brandt pushback(enum tok tok)
7146f557cf7SHartmut Brandt {
7156f557cf7SHartmut Brandt 
7166f557cf7SHartmut Brandt 	if (saved_token != -1)
7176f557cf7SHartmut Brandt 		abort();
7186f557cf7SHartmut Brandt 	saved_token = tok;
7196f557cf7SHartmut Brandt }
7206f557cf7SHartmut Brandt 
7216f557cf7SHartmut Brandt /*
7226f557cf7SHartmut Brandt  * Create a new type
7236f557cf7SHartmut Brandt  */
7246f557cf7SHartmut Brandt static struct type *
make_type(const char * s)7256f557cf7SHartmut Brandt make_type(const char *s)
7266f557cf7SHartmut Brandt {
7276f557cf7SHartmut Brandt 	struct type *t;
7286f557cf7SHartmut Brandt 
7296f557cf7SHartmut Brandt 	t = xalloc(sizeof(*t));
7306f557cf7SHartmut Brandt 	t->name = savestr(s);
7316f557cf7SHartmut Brandt 	t->is_enum = 0;
7326f557cf7SHartmut Brandt 	t->syntax = SNMP_SYNTAX_NULL;
7336f557cf7SHartmut Brandt 	t->from_fname = savestr(input->fname);
7346f557cf7SHartmut Brandt 	t->from_lno = input->lno;
7356f557cf7SHartmut Brandt 	TAILQ_INIT(&t->enums);
7366f557cf7SHartmut Brandt 	LIST_INSERT_HEAD(&types, t, link);
7376f557cf7SHartmut Brandt 
7386f557cf7SHartmut Brandt 	return (t);
7396f557cf7SHartmut Brandt }
7406f557cf7SHartmut Brandt 
7416f557cf7SHartmut Brandt /*
7426f557cf7SHartmut Brandt  * Parse a type. We've seen the ENUM or type keyword already. Leave next
7436f557cf7SHartmut Brandt  * token.
7446f557cf7SHartmut Brandt  */
7456f557cf7SHartmut Brandt static u_int
parse_type(enum tok * tok,struct type * t,const char * vname,char ** subtype)746*04d17814SAndrey V. Elsukov parse_type(enum tok *tok, struct type *t, const char *vname, char **subtype)
7476f557cf7SHartmut Brandt {
7486f557cf7SHartmut Brandt 	u_int syntax;
7496f557cf7SHartmut Brandt 	struct enums *e;
7506f557cf7SHartmut Brandt 
7516f557cf7SHartmut Brandt 	syntax = val;
752*04d17814SAndrey V. Elsukov 	if (subtype != NULL)
753*04d17814SAndrey V. Elsukov 		*subtype = NULL;
7546f557cf7SHartmut Brandt 
7556f557cf7SHartmut Brandt 	if (*tok == TOK_ENUM || *tok == TOK_BITS) {
7566f557cf7SHartmut Brandt 		if (t == NULL && vname != NULL) {
7576f557cf7SHartmut Brandt 			t = make_type(vname);
7586f557cf7SHartmut Brandt 			t->is_enum = (*tok == TOK_ENUM);
7596f557cf7SHartmut Brandt 			t->is_bits = (*tok == TOK_BITS);
7606f557cf7SHartmut Brandt 			t->syntax = syntax;
7616f557cf7SHartmut Brandt 		}
7626f557cf7SHartmut Brandt 		if (gettoken() != '(')
7636f557cf7SHartmut Brandt 			report("'(' expected after ENUM");
7646f557cf7SHartmut Brandt 
7656f557cf7SHartmut Brandt 		if ((*tok = gettoken()) == TOK_EOF)
7666f557cf7SHartmut Brandt 			report("unexpected EOF in ENUM");
7676f557cf7SHartmut Brandt 		do {
7686f557cf7SHartmut Brandt 			e = NULL;
7696f557cf7SHartmut Brandt 			if (t != NULL) {
7706f557cf7SHartmut Brandt 				e = xalloc(sizeof(*e));
7716f557cf7SHartmut Brandt 			}
7726f557cf7SHartmut Brandt 			if (*tok == '-') {
7736f557cf7SHartmut Brandt 				if ((*tok = gettoken()) == TOK_EOF)
7746f557cf7SHartmut Brandt 					report("unexpected EOF in ENUM");
7756f557cf7SHartmut Brandt 				e->value = -(long)val;
7766f557cf7SHartmut Brandt 			} else
7776f557cf7SHartmut Brandt 				e->value = val;
7786f557cf7SHartmut Brandt 
7796f557cf7SHartmut Brandt 			if (*tok != TOK_NUM)
7806f557cf7SHartmut Brandt 				report("need value for ENUM/BITS");
7816f557cf7SHartmut Brandt 			if (gettoken() != TOK_STR)
7826f557cf7SHartmut Brandt 				report("need string in ENUM/BITS");
7836f557cf7SHartmut Brandt 			e->name = savetok();
7846f557cf7SHartmut Brandt 			TAILQ_INSERT_TAIL(&t->enums, e, link);
7856f557cf7SHartmut Brandt 			if ((*tok = gettoken()) == TOK_EOF)
7866f557cf7SHartmut Brandt 				report("unexpected EOF in ENUM/BITS");
7876f557cf7SHartmut Brandt 		} while (*tok != ')');
7886f557cf7SHartmut Brandt 		*tok = gettoken();
7896f557cf7SHartmut Brandt 
7906f557cf7SHartmut Brandt 	} else if (*tok == TOK_DEFTYPE) {
7916f557cf7SHartmut Brandt 		*tok = gettoken();
7926f557cf7SHartmut Brandt 
7936f557cf7SHartmut Brandt 	} else {
7946f557cf7SHartmut Brandt 		if ((*tok = gettoken()) == '|') {
7956f557cf7SHartmut Brandt 			if (gettoken() != TOK_STR)
7966f557cf7SHartmut Brandt 				report("subtype expected after '|'");
797*04d17814SAndrey V. Elsukov 			if (subtype != NULL)
798*04d17814SAndrey V. Elsukov 				*subtype = savetok();
7996f557cf7SHartmut Brandt 			*tok = gettoken();
8006f557cf7SHartmut Brandt 		}
8016f557cf7SHartmut Brandt 	}
8026f557cf7SHartmut Brandt 
8036f557cf7SHartmut Brandt 	return (syntax);
804f06ca4afSHartmut Brandt }
805f06ca4afSHartmut Brandt 
806f06ca4afSHartmut Brandt /*
807f06ca4afSHartmut Brandt  * Parse the next node (complete with all subnodes)
808f06ca4afSHartmut Brandt  */
809f06ca4afSHartmut Brandt static struct node *
parse(enum tok tok)810f06ca4afSHartmut Brandt parse(enum tok tok)
811f06ca4afSHartmut Brandt {
812f06ca4afSHartmut Brandt 	struct node *node;
813f06ca4afSHartmut Brandt 	struct node *sub;
814f06ca4afSHartmut Brandt 	u_int index_count;
815f06ca4afSHartmut Brandt 
816f06ca4afSHartmut Brandt 	node = xalloc(sizeof(struct node));
8176f557cf7SHartmut Brandt 	node->lno = input->lno;
8182a9284a7SHartmut Brandt 	node->flags = 0;
819f06ca4afSHartmut Brandt 
820f06ca4afSHartmut Brandt 	if (tok != '(')
821f06ca4afSHartmut Brandt 		report("'(' expected at begin of node");
822f06ca4afSHartmut Brandt 	if (gettoken() != TOK_NUM)
823f06ca4afSHartmut Brandt 		report("node id expected after opening '('");
824f06ca4afSHartmut Brandt 	if (val > ASN_MAXID)
825f06ca4afSHartmut Brandt 		report("subid too large '%lu'", val);
826f06ca4afSHartmut Brandt 	node->id = (asn_subid_t)val;
827f06ca4afSHartmut Brandt 	if (gettoken() != TOK_STR)
828f06ca4afSHartmut Brandt 		report("node name expected after '(' ID");
829f06ca4afSHartmut Brandt 	node->name = savetok();
830f06ca4afSHartmut Brandt 
8316f557cf7SHartmut Brandt 	if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
8326f557cf7SHartmut Brandt 	    tok == TOK_ENUM || tok == TOK_BITS) {
833f06ca4afSHartmut Brandt 		/* LEAF or COLUM */
834*04d17814SAndrey V. Elsukov 		char *subtype;
835*04d17814SAndrey V. Elsukov 		u_int syntax = parse_type(&tok, NULL, node->name, &subtype);
836f06ca4afSHartmut Brandt 
8376f557cf7SHartmut Brandt 		if (tok == TOK_STR) {
838f06ca4afSHartmut Brandt 			/* LEAF */
839f06ca4afSHartmut Brandt 			node->type = NODE_LEAF;
840f06ca4afSHartmut Brandt 			node->u.leaf.func = savetok();
841f06ca4afSHartmut Brandt 			node->u.leaf.syntax = syntax;
842*04d17814SAndrey V. Elsukov 			node->u.leaf.subtype = subtype;
843f06ca4afSHartmut Brandt 			tok = gettoken();
844f06ca4afSHartmut Brandt 		} else {
845f06ca4afSHartmut Brandt 			/* COLUMN */
846f06ca4afSHartmut Brandt 			node->type = NODE_COLUMN;
847f06ca4afSHartmut Brandt 			node->u.column.syntax = syntax;
848*04d17814SAndrey V. Elsukov 			node->u.column.subtype = subtype;
849f06ca4afSHartmut Brandt 		}
850f06ca4afSHartmut Brandt 
851f06ca4afSHartmut Brandt 		while (tok != ')') {
852f06ca4afSHartmut Brandt 			if (tok != TOK_ACCESS)
853f06ca4afSHartmut Brandt 				report("access keyword or ')' expected");
854f06ca4afSHartmut Brandt 			node->flags |= (u_int)val;
855f06ca4afSHartmut Brandt 			tok = gettoken();
856f06ca4afSHartmut Brandt 		}
857f06ca4afSHartmut Brandt 
858f06ca4afSHartmut Brandt 	} else if (tok == ':') {
859f06ca4afSHartmut Brandt 		/* ENTRY */
860f06ca4afSHartmut Brandt 		node->type = NODE_ENTRY;
861f06ca4afSHartmut Brandt 		TAILQ_INIT(&node->u.entry.subs);
862f06ca4afSHartmut Brandt 
863f06ca4afSHartmut Brandt 		index_count = 0;
864f06ca4afSHartmut Brandt 		node->u.entry.index = 0;
8656f557cf7SHartmut Brandt 		tok = gettoken();
8666f557cf7SHartmut Brandt 		while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
8676f557cf7SHartmut Brandt 		    tok == TOK_ENUM || tok == TOK_BITS) {
868*04d17814SAndrey V. Elsukov 			char *subtype;
869*04d17814SAndrey V. Elsukov 			u_int syntax = parse_type(&tok, NULL, node->name,
870*04d17814SAndrey V. Elsukov 			    &subtype);
871*04d17814SAndrey V. Elsukov 			if (index_count == SNMP_INDEXES_MAX)
872f06ca4afSHartmut Brandt 				report("too many table indexes");
873*04d17814SAndrey V. Elsukov 			node->u.entry.subtypes[index_count++] = subtype;
874f06ca4afSHartmut Brandt 			node->u.entry.index |=
8756f557cf7SHartmut Brandt 			    syntax << (SNMP_INDEX_SHIFT * index_count);
876f06ca4afSHartmut Brandt 		}
877f06ca4afSHartmut Brandt 		node->u.entry.index |= index_count;
878f06ca4afSHartmut Brandt 		if (index_count == 0)
879f06ca4afSHartmut Brandt 			report("need at least one index");
880f06ca4afSHartmut Brandt 		if (tok != TOK_STR)
881f06ca4afSHartmut Brandt 			report("function name expected");
882f06ca4afSHartmut Brandt 
883f06ca4afSHartmut Brandt 		node->u.entry.func = savetok();
884f06ca4afSHartmut Brandt 
885f06ca4afSHartmut Brandt 		tok = gettoken();
886f06ca4afSHartmut Brandt 
887f06ca4afSHartmut Brandt 		while (tok != ')') {
888f06ca4afSHartmut Brandt 			sub = parse(tok);
889f06ca4afSHartmut Brandt 			TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
890f06ca4afSHartmut Brandt 			tok = gettoken();
891f06ca4afSHartmut Brandt 		}
892f06ca4afSHartmut Brandt 
893f06ca4afSHartmut Brandt 	} else {
894f06ca4afSHartmut Brandt 		/* subtree */
895f06ca4afSHartmut Brandt 		node->type = NODE_TREE;
896f06ca4afSHartmut Brandt 		TAILQ_INIT(&node->u.tree.subs);
897f06ca4afSHartmut Brandt 
898f06ca4afSHartmut Brandt 		while (tok != ')') {
899f06ca4afSHartmut Brandt 			sub = parse(tok);
900f06ca4afSHartmut Brandt 			TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
901f06ca4afSHartmut Brandt 			tok = gettoken();
902f06ca4afSHartmut Brandt 		}
903f06ca4afSHartmut Brandt 	}
904f06ca4afSHartmut Brandt 	return (node);
905f06ca4afSHartmut Brandt }
906f06ca4afSHartmut Brandt 
907f06ca4afSHartmut Brandt /*
9086f557cf7SHartmut Brandt  * Parse a top level element. Return the tree if it was a tree, NULL
9096f557cf7SHartmut Brandt  * otherwise.
9106f557cf7SHartmut Brandt  */
9116f557cf7SHartmut Brandt static struct node *
parse_top(enum tok tok)9126f557cf7SHartmut Brandt parse_top(enum tok tok)
9136f557cf7SHartmut Brandt {
9146f557cf7SHartmut Brandt 	struct type *t;
9156f557cf7SHartmut Brandt 
9166f557cf7SHartmut Brandt 	if (tok == '(')
9176f557cf7SHartmut Brandt 		return (parse(tok));
9186f557cf7SHartmut Brandt 
9196f557cf7SHartmut Brandt 	if (tok == TOK_TYPEDEF) {
9206f557cf7SHartmut Brandt 		if (gettoken() != TOK_STR)
9216f557cf7SHartmut Brandt 			report("type name expected after typedef");
9226f557cf7SHartmut Brandt 
9236f557cf7SHartmut Brandt 		t = make_type(str);
9246f557cf7SHartmut Brandt 
9256f557cf7SHartmut Brandt 		tok = gettoken();
9266f557cf7SHartmut Brandt 		t->is_enum = (tok == TOK_ENUM);
9276f557cf7SHartmut Brandt 		t->is_bits = (tok == TOK_BITS);
928*04d17814SAndrey V. Elsukov 
929*04d17814SAndrey V. Elsukov 		t->syntax = parse_type(&tok, t, NULL, NULL);
9306f557cf7SHartmut Brandt 		pushback(tok);
9316f557cf7SHartmut Brandt 
9326f557cf7SHartmut Brandt 		return (NULL);
9336f557cf7SHartmut Brandt 	}
9346f557cf7SHartmut Brandt 
9356f557cf7SHartmut Brandt 	if (tok == TOK_INCLUDE) {
9366f557cf7SHartmut Brandt 		if (gettoken() != TOK_FILENAME)
9376f557cf7SHartmut Brandt 			report("filename expected in include directive");
9386f557cf7SHartmut Brandt 
9396f557cf7SHartmut Brandt 		input_fopen(str, val);
9406f557cf7SHartmut Brandt 		return (NULL);
9416f557cf7SHartmut Brandt 	}
9426f557cf7SHartmut Brandt 
9436f557cf7SHartmut Brandt 	report("'(' or 'typedef' expected");
9446f557cf7SHartmut Brandt }
9456f557cf7SHartmut Brandt 
9466f557cf7SHartmut Brandt /*
947f06ca4afSHartmut Brandt  * Generate the C-code table part for one node.
948f06ca4afSHartmut Brandt  */
949f06ca4afSHartmut Brandt static void
gen_node(FILE * fp,const struct node * np,struct asn_oid * oid,u_int idx,const char * func)950*04d17814SAndrey V. Elsukov gen_node(FILE *fp, const struct node *np, struct asn_oid *oid, u_int idx,
9516f557cf7SHartmut Brandt     const char *func)
952f06ca4afSHartmut Brandt {
953f06ca4afSHartmut Brandt 	u_int n;
954f06ca4afSHartmut Brandt 	struct node *sub;
955f06ca4afSHartmut Brandt 	u_int syntax;
956f06ca4afSHartmut Brandt 
957f06ca4afSHartmut Brandt 	if (oid->len == ASN_MAXOIDLEN)
958f06ca4afSHartmut Brandt 		report_node(np, "OID too long");
959f06ca4afSHartmut Brandt 	oid->subs[oid->len++] = np->id;
960f06ca4afSHartmut Brandt 
961f06ca4afSHartmut Brandt 	if (np->type == NODE_TREE) {
962f06ca4afSHartmut Brandt 		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
9636f557cf7SHartmut Brandt 			gen_node(fp, sub, oid, 0, NULL);
964f06ca4afSHartmut Brandt 		oid->len--;
965f06ca4afSHartmut Brandt 		return;
966f06ca4afSHartmut Brandt 	}
967f06ca4afSHartmut Brandt 	if (np->type == NODE_ENTRY) {
968f06ca4afSHartmut Brandt 		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
9696f557cf7SHartmut Brandt 			gen_node(fp, sub, oid, np->u.entry.index,
9706f557cf7SHartmut Brandt 			    np->u.entry.func);
971f06ca4afSHartmut Brandt 		oid->len--;
972f06ca4afSHartmut Brandt 		return;
973f06ca4afSHartmut Brandt 	}
974f06ca4afSHartmut Brandt 
975f06ca4afSHartmut Brandt 	/* leaf or column */
976f06ca4afSHartmut Brandt 	if ((np->flags & (FL_GET|FL_SET)) == 0) {
977f06ca4afSHartmut Brandt 		oid->len--;
978f06ca4afSHartmut Brandt 		return;
979f06ca4afSHartmut Brandt 	}
980f06ca4afSHartmut Brandt 
981f06ca4afSHartmut Brandt 	fprintf(fp, "    {{ %u, {", oid->len);
982f06ca4afSHartmut Brandt 	for (n = 0; n < oid->len; n++)
983f06ca4afSHartmut Brandt 		fprintf(fp, " %u,", oid->subs[n]);
984f06ca4afSHartmut Brandt 	fprintf(fp, " }}, \"%s\", ", np->name);
985f06ca4afSHartmut Brandt 
986f06ca4afSHartmut Brandt 	if (np->type == NODE_COLUMN) {
987f06ca4afSHartmut Brandt 		syntax = np->u.column.syntax;
988f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_NODE_COLUMN, ");
989f06ca4afSHartmut Brandt 	} else {
990f06ca4afSHartmut Brandt 		syntax = np->u.leaf.syntax;
991f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_NODE_LEAF, ");
992f06ca4afSHartmut Brandt 	}
993f06ca4afSHartmut Brandt 
994f06ca4afSHartmut Brandt 	switch (syntax) {
995f06ca4afSHartmut Brandt 
996f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NULL:
997f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_NULL, ");
998f06ca4afSHartmut Brandt 		break;
999f06ca4afSHartmut Brandt 
1000f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_INTEGER:
1001f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
1002f06ca4afSHartmut Brandt 		break;
1003f06ca4afSHartmut Brandt 
1004f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OCTETSTRING:
1005f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
1006f06ca4afSHartmut Brandt 		break;
1007f06ca4afSHartmut Brandt 
1008f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_IPADDRESS:
1009f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
1010f06ca4afSHartmut Brandt 		break;
1011f06ca4afSHartmut Brandt 
1012f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OID:
1013f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_OID, ");
1014f06ca4afSHartmut Brandt 		break;
1015f06ca4afSHartmut Brandt 
1016f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_TIMETICKS:
1017f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
1018f06ca4afSHartmut Brandt 		break;
1019f06ca4afSHartmut Brandt 
1020f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER:
1021f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
1022f06ca4afSHartmut Brandt 		break;
1023f06ca4afSHartmut Brandt 
1024f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_GAUGE:
1025f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
1026f06ca4afSHartmut Brandt 		break;
1027f06ca4afSHartmut Brandt 
1028f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER64:
1029f06ca4afSHartmut Brandt 		fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
1030f06ca4afSHartmut Brandt 		break;
1031f06ca4afSHartmut Brandt 
1032f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHOBJECT:
1033f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1034f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1035f06ca4afSHartmut Brandt 		abort();
1036f06ca4afSHartmut Brandt 	}
1037f06ca4afSHartmut Brandt 
1038f06ca4afSHartmut Brandt 	if (np->type == NODE_COLUMN)
1039f06ca4afSHartmut Brandt 		fprintf(fp, "%s, ", func);
1040f06ca4afSHartmut Brandt 	else
1041f06ca4afSHartmut Brandt 		fprintf(fp, "%s, ", np->u.leaf.func);
1042f06ca4afSHartmut Brandt 
1043f06ca4afSHartmut Brandt 	fprintf(fp, "0");
1044f06ca4afSHartmut Brandt 	if (np->flags & FL_SET)
1045f06ca4afSHartmut Brandt 		fprintf(fp, "|SNMP_NODE_CANSET");
10468eecd77aSHartmut Brandt 	fprintf(fp, ", %#x, NULL, NULL },\n", idx);
1047f06ca4afSHartmut Brandt 	oid->len--;
1048f06ca4afSHartmut Brandt 	return;
1049f06ca4afSHartmut Brandt }
1050f06ca4afSHartmut Brandt 
1051f06ca4afSHartmut Brandt /*
1052f06ca4afSHartmut Brandt  * Generate the header file with the function declarations.
1053f06ca4afSHartmut Brandt  */
1054f06ca4afSHartmut Brandt static void
gen_header(FILE * fp,const struct node * np,u_int oidlen,const char * func)1055*04d17814SAndrey V. Elsukov gen_header(FILE *fp, const struct node *np, u_int oidlen, const char *func)
1056f06ca4afSHartmut Brandt {
1057f06ca4afSHartmut Brandt 	char f[MAXSTR + 4];
1058f06ca4afSHartmut Brandt 	struct node *sub;
1059f06ca4afSHartmut Brandt 	struct func *ptr;
1060f06ca4afSHartmut Brandt 
1061f06ca4afSHartmut Brandt 	oidlen++;
1062f06ca4afSHartmut Brandt 	if (np->type == NODE_TREE) {
1063f06ca4afSHartmut Brandt 		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
10646f557cf7SHartmut Brandt 			gen_header(fp, sub, oidlen, NULL);
1065f06ca4afSHartmut Brandt 		return;
1066f06ca4afSHartmut Brandt 	}
1067f06ca4afSHartmut Brandt 	if (np->type == NODE_ENTRY) {
1068f06ca4afSHartmut Brandt 		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
10696f557cf7SHartmut Brandt 			gen_header(fp, sub, oidlen, np->u.entry.func);
1070f06ca4afSHartmut Brandt 		return;
1071f06ca4afSHartmut Brandt 	}
1072f06ca4afSHartmut Brandt 
1073f06ca4afSHartmut Brandt  	if((np->flags & (FL_GET|FL_SET)) == 0)
1074f06ca4afSHartmut Brandt 		return;
1075f06ca4afSHartmut Brandt 
107694caccb3SHartmut Brandt 	if (np->type == NODE_COLUMN) {
107794caccb3SHartmut Brandt 		if (func == NULL)
107894caccb3SHartmut Brandt 			errx(1, "column without function (%s) - probably "
107994caccb3SHartmut Brandt 			    "outside of a table", np->name);
1080f06ca4afSHartmut Brandt 		sprintf(f, "%s", func);
108194caccb3SHartmut Brandt 	} else
1082f06ca4afSHartmut Brandt 		sprintf(f, "%s", np->u.leaf.func);
1083f06ca4afSHartmut Brandt 
1084f06ca4afSHartmut Brandt 	LIST_FOREACH(ptr, &funcs, link)
1085f06ca4afSHartmut Brandt 		if (strcmp(ptr->name, f) == 0)
1086f06ca4afSHartmut Brandt 			break;
1087f06ca4afSHartmut Brandt 
1088f06ca4afSHartmut Brandt 	if (ptr == NULL) {
1089f06ca4afSHartmut Brandt 		ptr = xalloc(sizeof(*ptr));
10906f557cf7SHartmut Brandt 		ptr->name = savestr(f);
1091f06ca4afSHartmut Brandt 		LIST_INSERT_HEAD(&funcs, ptr, link);
1092f06ca4afSHartmut Brandt 
1093f06ca4afSHartmut Brandt 		fprintf(fp, "int	%s(struct snmp_context *, "
1094f06ca4afSHartmut Brandt 		    "struct snmp_value *, u_int, u_int, "
1095f06ca4afSHartmut Brandt 		    "enum snmp_op);\n", f);
1096f06ca4afSHartmut Brandt 	}
1097f06ca4afSHartmut Brandt 
1098f06ca4afSHartmut Brandt 	fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
1099f06ca4afSHartmut Brandt }
1100f06ca4afSHartmut Brandt 
1101f06ca4afSHartmut Brandt /*
1102f06ca4afSHartmut Brandt  * Generate the OID table.
1103f06ca4afSHartmut Brandt  */
1104f06ca4afSHartmut Brandt static void
gen_table(FILE * fp,const struct node * node)1105*04d17814SAndrey V. Elsukov gen_table(FILE *fp, const struct node *node)
1106f06ca4afSHartmut Brandt {
1107f06ca4afSHartmut Brandt 	struct asn_oid oid;
1108f06ca4afSHartmut Brandt 
1109f06ca4afSHartmut Brandt 	fprintf(fp, "#include <sys/types.h>\n");
1110f06ca4afSHartmut Brandt 	fprintf(fp, "#include <stdio.h>\n");
1111165c5d31SHartmut Brandt #ifdef HAVE_STDINT_H
1112896052c1SHartmut Brandt 	fprintf(fp, "#include <stdint.h>\n");
1113165c5d31SHartmut Brandt #endif
1114f06ca4afSHartmut Brandt 	if (localincs) {
1115f06ca4afSHartmut Brandt 		fprintf(fp, "#include \"asn1.h\"\n");
1116f06ca4afSHartmut Brandt 		fprintf(fp, "#include \"snmp.h\"\n");
1117f06ca4afSHartmut Brandt 		fprintf(fp, "#include \"snmpagent.h\"\n");
1118f06ca4afSHartmut Brandt 	} else {
1119f06ca4afSHartmut Brandt 		fprintf(fp, "#include <bsnmp/asn1.h>\n");
1120f06ca4afSHartmut Brandt 		fprintf(fp, "#include <bsnmp/snmp.h>\n");
1121f06ca4afSHartmut Brandt 		fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
1122f06ca4afSHartmut Brandt 	}
1123f06ca4afSHartmut Brandt 	fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
1124f06ca4afSHartmut Brandt 	fprintf(fp, "\n");
1125f06ca4afSHartmut Brandt 
1126f06ca4afSHartmut Brandt 	fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
1127f06ca4afSHartmut Brandt 
1128f06ca4afSHartmut Brandt 	oid.len = PREFIX_LEN;
1129f06ca4afSHartmut Brandt 	memcpy(oid.subs, prefix, sizeof(prefix));
11306f557cf7SHartmut Brandt 	gen_node(fp, node, &oid, 0, NULL);
1131f06ca4afSHartmut Brandt 
1132f06ca4afSHartmut Brandt 	fprintf(fp, "};\n\n");
1133f06ca4afSHartmut Brandt }
1134f06ca4afSHartmut Brandt 
1135896052c1SHartmut Brandt static void
print_syntax(u_int syntax)1136896052c1SHartmut Brandt print_syntax(u_int syntax)
1137896052c1SHartmut Brandt {
1138896052c1SHartmut Brandt 	u_int i;
1139896052c1SHartmut Brandt 
1140896052c1SHartmut Brandt 	for (i = 0; keywords[i].str != NULL; i++)
1141896052c1SHartmut Brandt 		if (keywords[i].tok == TOK_TYPE &&
1142896052c1SHartmut Brandt 		    keywords[i].val == syntax) {
1143896052c1SHartmut Brandt 			printf(" %s", keywords[i].str);
1144896052c1SHartmut Brandt 			return;
1145896052c1SHartmut Brandt 	}
1146896052c1SHartmut Brandt 	abort();
1147896052c1SHartmut Brandt }
1148896052c1SHartmut Brandt 
1149896052c1SHartmut Brandt /*
1150896052c1SHartmut Brandt  * Generate a tree definition file
1151896052c1SHartmut Brandt  */
1152896052c1SHartmut Brandt static void
gen_tree(const struct node * np,int level)1153896052c1SHartmut Brandt gen_tree(const struct node *np, int level)
1154896052c1SHartmut Brandt {
1155896052c1SHartmut Brandt 	const struct node *sp;
1156896052c1SHartmut Brandt 	u_int i;
1157896052c1SHartmut Brandt 
1158896052c1SHartmut Brandt 	printf("%*s(%u %s", 2 * level, "", np->id, np->name);
1159896052c1SHartmut Brandt 
1160896052c1SHartmut Brandt 	switch (np->type) {
1161896052c1SHartmut Brandt 
1162896052c1SHartmut Brandt 	  case NODE_LEAF:
1163896052c1SHartmut Brandt 		print_syntax(np->u.leaf.syntax);
1164*04d17814SAndrey V. Elsukov 		if (np->u.leaf.subtype != NULL)
1165*04d17814SAndrey V. Elsukov 			printf(" | %s", np->u.leaf.subtype);
1166896052c1SHartmut Brandt 		printf(" %s%s%s)\n", np->u.leaf.func,
1167896052c1SHartmut Brandt 		    (np->flags & FL_GET) ? " GET" : "",
1168896052c1SHartmut Brandt 		    (np->flags & FL_SET) ? " SET" : "");
1169896052c1SHartmut Brandt 		break;
1170896052c1SHartmut Brandt 
1171896052c1SHartmut Brandt 	  case NODE_TREE:
1172896052c1SHartmut Brandt 		if (TAILQ_EMPTY(&np->u.tree.subs)) {
1173896052c1SHartmut Brandt 			printf(")\n");
1174896052c1SHartmut Brandt 		} else {
1175896052c1SHartmut Brandt 			printf("\n");
1176896052c1SHartmut Brandt 			TAILQ_FOREACH(sp, &np->u.tree.subs, link)
1177896052c1SHartmut Brandt 				gen_tree(sp, level + 1);
1178896052c1SHartmut Brandt 			printf("%*s)\n", 2 * level, "");
1179896052c1SHartmut Brandt 		}
1180896052c1SHartmut Brandt 		break;
1181896052c1SHartmut Brandt 
1182896052c1SHartmut Brandt 	  case NODE_ENTRY:
1183896052c1SHartmut Brandt 		printf(" :");
1184896052c1SHartmut Brandt 
1185*04d17814SAndrey V. Elsukov 		for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) {
1186896052c1SHartmut Brandt 			print_syntax(SNMP_INDEX(np->u.entry.index, i));
1187*04d17814SAndrey V. Elsukov 			if (np->u.entry.subtypes[i] != NULL)
1188*04d17814SAndrey V. Elsukov 				printf(" | %s", np->u.entry.subtypes[i]);
1189*04d17814SAndrey V. Elsukov 		}
1190896052c1SHartmut Brandt 		printf(" %s\n", np->u.entry.func);
1191896052c1SHartmut Brandt 		TAILQ_FOREACH(sp, &np->u.entry.subs, link)
1192896052c1SHartmut Brandt 			gen_tree(sp, level + 1);
1193896052c1SHartmut Brandt 		printf("%*s)\n", 2 * level, "");
1194896052c1SHartmut Brandt 		break;
1195896052c1SHartmut Brandt 
1196896052c1SHartmut Brandt 	  case NODE_COLUMN:
1197896052c1SHartmut Brandt 		print_syntax(np->u.column.syntax);
1198*04d17814SAndrey V. Elsukov 		if (np->u.column.subtype != NULL)
1199*04d17814SAndrey V. Elsukov 			printf(" | %s", np->u.column.subtype);
1200896052c1SHartmut Brandt 		printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
1201896052c1SHartmut Brandt 		    (np->flags & FL_SET) ? " SET" : "");
1202896052c1SHartmut Brandt 		break;
1203896052c1SHartmut Brandt 	}
1204896052c1SHartmut Brandt }
1205896052c1SHartmut Brandt 
1206f06ca4afSHartmut Brandt static int
extract(FILE * fp,const struct node * np,struct asn_oid * oid,const char * obj,const struct asn_oid * idx,const char * iname)12076f557cf7SHartmut Brandt extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
1208896052c1SHartmut Brandt     const struct asn_oid *idx, const char *iname)
1209f06ca4afSHartmut Brandt {
1210f06ca4afSHartmut Brandt 	struct node *sub;
1211f06ca4afSHartmut Brandt 	u_long n;
1212f06ca4afSHartmut Brandt 
1213f06ca4afSHartmut Brandt 	if (oid->len == ASN_MAXOIDLEN)
1214f06ca4afSHartmut Brandt 		report_node(np, "OID too long");
1215f06ca4afSHartmut Brandt 	oid->subs[oid->len++] = np->id;
1216f06ca4afSHartmut Brandt 
1217f06ca4afSHartmut Brandt 	if (strcmp(obj, np->name) == 0) {
1218896052c1SHartmut Brandt 		if (oid->len + idx->len >= ASN_MAXOIDLEN)
1219896052c1SHartmut Brandt 			report_node(np, "OID too long");
1220896052c1SHartmut Brandt 		fprintf(fp, "#define OID_%s%s\t%u\n", np->name,
1221896052c1SHartmut Brandt 		    iname ? iname : "", np->id);
1222896052c1SHartmut Brandt 		fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name,
1223896052c1SHartmut Brandt 		    iname ? iname : "", oid->len + idx->len);
1224896052c1SHartmut Brandt 		fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name,
1225896052c1SHartmut Brandt 		    iname ? iname : "", oid->len + idx->len);
1226f06ca4afSHartmut Brandt 		for (n = 0; n < oid->len; n++)
1227f06ca4afSHartmut Brandt 			fprintf(fp, " %u,", oid->subs[n]);
1228896052c1SHartmut Brandt 		for (n = 0; n < idx->len; n++)
1229896052c1SHartmut Brandt 			fprintf(fp, " %u,", idx->subs[n]);
1230f06ca4afSHartmut Brandt 		fprintf(fp, " } }\n");
1231f06ca4afSHartmut Brandt 		return (0);
1232f06ca4afSHartmut Brandt 	}
1233f06ca4afSHartmut Brandt 
1234f06ca4afSHartmut Brandt 	if (np->type == NODE_TREE) {
1235f06ca4afSHartmut Brandt 		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
12366f557cf7SHartmut Brandt 			if (!extract(fp, sub, oid, obj, idx, iname))
1237f06ca4afSHartmut Brandt 				return (0);
1238f06ca4afSHartmut Brandt 	} else if (np->type == NODE_ENTRY) {
1239f06ca4afSHartmut Brandt 		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
12406f557cf7SHartmut Brandt 			if (!extract(fp, sub, oid, obj, idx, iname))
1241f06ca4afSHartmut Brandt 				return (0);
1242f06ca4afSHartmut Brandt 	}
1243f06ca4afSHartmut Brandt 	oid->len--;
1244f06ca4afSHartmut Brandt 	return (1);
1245f06ca4afSHartmut Brandt }
1246f06ca4afSHartmut Brandt 
1247f06ca4afSHartmut Brandt static int
gen_extract(FILE * fp,const struct node * root,char * object)12486f557cf7SHartmut Brandt gen_extract(FILE *fp, const struct node *root, char *object)
1249f06ca4afSHartmut Brandt {
1250f06ca4afSHartmut Brandt 	struct asn_oid oid;
1251896052c1SHartmut Brandt 	struct asn_oid idx;
1252896052c1SHartmut Brandt 	char *s, *e, *end, *iname;
1253896052c1SHartmut Brandt 	u_long ul;
1254896052c1SHartmut Brandt 	int ret;
1255896052c1SHartmut Brandt 
1256896052c1SHartmut Brandt 	/* look whether the object to extract has an index part */
1257896052c1SHartmut Brandt 	idx.len = 0;
1258896052c1SHartmut Brandt 	iname = NULL;
1259896052c1SHartmut Brandt 	s = strchr(object, '.');
1260896052c1SHartmut Brandt 	if (s != NULL) {
1261896052c1SHartmut Brandt 		iname = malloc(strlen(s) + 1);
1262896052c1SHartmut Brandt 		if (iname == NULL)
1263896052c1SHartmut Brandt 			err(1, "cannot allocated index");
1264896052c1SHartmut Brandt 
1265896052c1SHartmut Brandt 		strcpy(iname, s);
1266896052c1SHartmut Brandt 		for (e = iname; *e != '\0'; e++)
1267896052c1SHartmut Brandt 			if (*e == '.')
1268896052c1SHartmut Brandt 				*e = '_';
1269896052c1SHartmut Brandt 
1270896052c1SHartmut Brandt 		*s++ = '\0';
1271896052c1SHartmut Brandt 		while (s != NULL) {
1272896052c1SHartmut Brandt 			if (*s == '\0')
1273896052c1SHartmut Brandt 				errx(1, "bad index syntax");
1274896052c1SHartmut Brandt 			if ((e = strchr(s, '.')) != NULL)
1275896052c1SHartmut Brandt 				*e++ = '\0';
1276896052c1SHartmut Brandt 
1277896052c1SHartmut Brandt 			errno = 0;
1278896052c1SHartmut Brandt 			ul = strtoul(s, &end, 0);
1279896052c1SHartmut Brandt 			if (*end != '\0')
1280896052c1SHartmut Brandt 				errx(1, "bad index syntax '%s'", end);
1281896052c1SHartmut Brandt 			if (errno != 0)
1282896052c1SHartmut Brandt 				err(1, "bad index syntax");
1283896052c1SHartmut Brandt 
1284896052c1SHartmut Brandt 			if (idx.len == ASN_MAXOIDLEN)
1285896052c1SHartmut Brandt 				errx(1, "index oid too large");
1286896052c1SHartmut Brandt 			idx.subs[idx.len++] = ul;
1287896052c1SHartmut Brandt 
1288896052c1SHartmut Brandt 			s = e;
1289896052c1SHartmut Brandt 		}
1290896052c1SHartmut Brandt 	}
1291f06ca4afSHartmut Brandt 
1292f06ca4afSHartmut Brandt 	oid.len = PREFIX_LEN;
1293f06ca4afSHartmut Brandt 	memcpy(oid.subs, prefix, sizeof(prefix));
12946f557cf7SHartmut Brandt 	ret = extract(fp, root, &oid, object, &idx, iname);
1295896052c1SHartmut Brandt 	if (iname != NULL)
1296896052c1SHartmut Brandt 		free(iname);
1297896052c1SHartmut Brandt 
1298896052c1SHartmut Brandt 	return (ret);
1299f06ca4afSHartmut Brandt }
1300f06ca4afSHartmut Brandt 
1301f06ca4afSHartmut Brandt 
1302f06ca4afSHartmut Brandt static void
check_sub_order(const struct node * np,const struct node_list * subs)1303f06ca4afSHartmut Brandt check_sub_order(const struct node *np, const struct node_list *subs)
1304f06ca4afSHartmut Brandt {
1305f06ca4afSHartmut Brandt 	int first;
1306f06ca4afSHartmut Brandt 	const struct node *sub;
1307f06ca4afSHartmut Brandt 	asn_subid_t maxid = 0;
1308f06ca4afSHartmut Brandt 
1309f06ca4afSHartmut Brandt 	/* ensure, that subids are ordered */
1310f06ca4afSHartmut Brandt 	first = 1;
1311f06ca4afSHartmut Brandt 	TAILQ_FOREACH(sub, subs, link) {
1312f06ca4afSHartmut Brandt 		if (!first && sub->id <= maxid)
1313f06ca4afSHartmut Brandt 			report_node(np, "subids not ordered at %s", sub->name);
1314f06ca4afSHartmut Brandt 		maxid = sub->id;
1315f06ca4afSHartmut Brandt 		first = 0;
1316f06ca4afSHartmut Brandt 	}
1317f06ca4afSHartmut Brandt }
1318f06ca4afSHartmut Brandt 
1319f06ca4afSHartmut Brandt /*
1320f06ca4afSHartmut Brandt  * Do some sanity checks on the tree definition and do some computations.
1321f06ca4afSHartmut Brandt  */
1322f06ca4afSHartmut Brandt static void
check_tree(struct node * np)1323f06ca4afSHartmut Brandt check_tree(struct node *np)
1324f06ca4afSHartmut Brandt {
1325f06ca4afSHartmut Brandt 	struct node *sub;
1326f06ca4afSHartmut Brandt 
1327f06ca4afSHartmut Brandt 	if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
1328f06ca4afSHartmut Brandt 		if ((np->flags & (FL_GET|FL_SET)) != 0)
1329f06ca4afSHartmut Brandt 			tree_size++;
1330f06ca4afSHartmut Brandt 		return;
1331f06ca4afSHartmut Brandt 	}
1332f06ca4afSHartmut Brandt 
1333f06ca4afSHartmut Brandt 	if (np->type == NODE_ENTRY) {
1334f06ca4afSHartmut Brandt 		check_sub_order(np, &np->u.entry.subs);
1335f06ca4afSHartmut Brandt 
1336f06ca4afSHartmut Brandt 		/* ensure all subnodes are columns */
1337f06ca4afSHartmut Brandt 		TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
1338f06ca4afSHartmut Brandt 			if (sub->type != NODE_COLUMN)
1339f06ca4afSHartmut Brandt 				report_node(np, "entry subnode '%s' is not "
1340f06ca4afSHartmut Brandt 				    "a column", sub->name);
1341f06ca4afSHartmut Brandt 			check_tree(sub);
1342f06ca4afSHartmut Brandt 		}
1343f06ca4afSHartmut Brandt 	} else {
1344f06ca4afSHartmut Brandt 		check_sub_order(np, &np->u.tree.subs);
1345f06ca4afSHartmut Brandt 
1346f06ca4afSHartmut Brandt 		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1347f06ca4afSHartmut Brandt 			check_tree(sub);
1348f06ca4afSHartmut Brandt 	}
1349f06ca4afSHartmut Brandt }
1350f06ca4afSHartmut Brandt 
1351896052c1SHartmut Brandt static void
merge_subs(struct node_list * s1,struct node_list * s2)1352896052c1SHartmut Brandt merge_subs(struct node_list *s1, struct node_list *s2)
1353896052c1SHartmut Brandt {
1354896052c1SHartmut Brandt 	struct node *n1, *n2;
1355896052c1SHartmut Brandt 
1356896052c1SHartmut Brandt 	while (!TAILQ_EMPTY(s2)) {
1357896052c1SHartmut Brandt 		n2 = TAILQ_FIRST(s2);
1358896052c1SHartmut Brandt 		TAILQ_REMOVE(s2, n2, link);
1359896052c1SHartmut Brandt 
1360896052c1SHartmut Brandt 		TAILQ_FOREACH(n1, s1, link)
1361896052c1SHartmut Brandt 			if (n1->id >= n2->id)
1362896052c1SHartmut Brandt 				break;
1363896052c1SHartmut Brandt 		if (n1 == NULL)
1364896052c1SHartmut Brandt 			TAILQ_INSERT_TAIL(s1, n2, link);
1365896052c1SHartmut Brandt 		else if (n1->id > n2->id)
1366896052c1SHartmut Brandt 			TAILQ_INSERT_BEFORE(n1, n2, link);
1367896052c1SHartmut Brandt 		else {
1368896052c1SHartmut Brandt 			if (n1->type == NODE_TREE && n2->type == NODE_TREE) {
1369896052c1SHartmut Brandt 				if (strcmp(n1->name, n2->name) != 0)
1370896052c1SHartmut Brandt 					errx(1, "trees to merge must have "
1371896052c1SHartmut Brandt 					    "same name '%s' '%s'", n1->name,
1372896052c1SHartmut Brandt 					    n2->name);
1373896052c1SHartmut Brandt 				merge_subs(&n1->u.tree.subs, &n2->u.tree.subs);
1374896052c1SHartmut Brandt 				free(n2);
1375896052c1SHartmut Brandt 			} else if (n1->type == NODE_ENTRY &&
1376896052c1SHartmut Brandt 			    n2->type == NODE_ENTRY) {
1377896052c1SHartmut Brandt 				if (strcmp(n1->name, n2->name) != 0)
1378896052c1SHartmut Brandt 					errx(1, "entries to merge must have "
1379896052c1SHartmut Brandt 					    "same name '%s' '%s'", n1->name,
1380896052c1SHartmut Brandt 					    n2->name);
1381896052c1SHartmut Brandt 				if (n1->u.entry.index != n2->u.entry.index)
1382896052c1SHartmut Brandt 					errx(1, "entries to merge must have "
1383896052c1SHartmut Brandt 					    "same index '%s'", n1->name);
1384896052c1SHartmut Brandt 				if (strcmp(n1->u.entry.func,
1385896052c1SHartmut Brandt 				    n2->u.entry.func) != 0)
1386896052c1SHartmut Brandt 					errx(1, "entries to merge must have "
1387896052c1SHartmut Brandt 					    "same op '%s'", n1->name);
1388896052c1SHartmut Brandt 				merge_subs(&n1->u.entry.subs,
1389896052c1SHartmut Brandt 				    &n2->u.entry.subs);
1390896052c1SHartmut Brandt 				free(n2);
1391896052c1SHartmut Brandt 			} else
1392896052c1SHartmut Brandt 				errx(1, "entities to merge must be both "
1393896052c1SHartmut Brandt 				    "trees or both entries: %s, %s",
1394896052c1SHartmut Brandt 				    n1->name, n2->name);
1395896052c1SHartmut Brandt 		}
1396896052c1SHartmut Brandt 	}
1397896052c1SHartmut Brandt }
1398896052c1SHartmut Brandt 
1399896052c1SHartmut Brandt static void
merge(struct node ** root,struct node * t)14006f557cf7SHartmut Brandt merge(struct node **root, struct node *t)
1401896052c1SHartmut Brandt {
1402896052c1SHartmut Brandt 
14036f557cf7SHartmut Brandt 	if (*root == NULL) {
14046f557cf7SHartmut Brandt 		*root = t;
14056f557cf7SHartmut Brandt 		return;
14066f557cf7SHartmut Brandt 	}
14076f557cf7SHartmut Brandt 	if (t == NULL)
14086f557cf7SHartmut Brandt 		return;
14096f557cf7SHartmut Brandt 
1410896052c1SHartmut Brandt 	/* both must be trees */
14116f557cf7SHartmut Brandt 	if ((*root)->type != NODE_TREE)
1412896052c1SHartmut Brandt 		errx(1, "root is not a tree");
1413896052c1SHartmut Brandt 	if (t->type != NODE_TREE)
1414896052c1SHartmut Brandt 		errx(1, "can merge only with tree");
14156f557cf7SHartmut Brandt 	if ((*root)->id != t->id)
1416896052c1SHartmut Brandt 		errx(1, "trees to merge must have same id");
1417896052c1SHartmut Brandt 
14186f557cf7SHartmut Brandt 	merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs);
14196f557cf7SHartmut Brandt }
14206f557cf7SHartmut Brandt 
14216f557cf7SHartmut Brandt static void
unminus(FILE * fp,const char * s)14226f557cf7SHartmut Brandt unminus(FILE *fp, const char *s)
14236f557cf7SHartmut Brandt {
14246f557cf7SHartmut Brandt 
14256f557cf7SHartmut Brandt 	while (*s != '\0') {
14266f557cf7SHartmut Brandt 		if (*s == '-')
14276f557cf7SHartmut Brandt 			fprintf(fp, "_");
14286f557cf7SHartmut Brandt 		else
14296f557cf7SHartmut Brandt 			fprintf(fp, "%c", *s);
14306f557cf7SHartmut Brandt 		s++;
14316f557cf7SHartmut Brandt 	}
14326f557cf7SHartmut Brandt }
14336f557cf7SHartmut Brandt 
14348e9b3e70SHartmut Brandt /**
14358e9b3e70SHartmut Brandt  * Generate helper functions for an enum.
14368e9b3e70SHartmut Brandt  *
14378e9b3e70SHartmut Brandt  * We always generate a switch statement for the isok function. The compiler
14388e9b3e70SHartmut Brandt  * optimizes this into range checks if possible.
14398e9b3e70SHartmut Brandt  *
14408e9b3e70SHartmut Brandt  * \param fp		file to write to
14418e9b3e70SHartmut Brandt  * \param t		type
14428e9b3e70SHartmut Brandt  * \param ccode		generate externally visible non-inline functions
14438e9b3e70SHartmut Brandt  */
14446f557cf7SHartmut Brandt static void
gen_enum_funcs(FILE * fp,const struct type * t,int ccode)14458e9b3e70SHartmut Brandt gen_enum_funcs(FILE *fp, const struct type *t, int ccode)
14468e9b3e70SHartmut Brandt {
14478e9b3e70SHartmut Brandt 	fprintf(fp, "\n");
14488e9b3e70SHartmut Brandt 
14498e9b3e70SHartmut Brandt 	if (!ccode)
14508e9b3e70SHartmut Brandt 		fprintf(fp, "static inline ");
14518e9b3e70SHartmut Brandt 	fprintf(fp, "int\n");
14528e9b3e70SHartmut Brandt 	fprintf(fp, "isok_%s(enum %s s)\n", t->name, t->name);
14538e9b3e70SHartmut Brandt 	fprintf(fp, "{\n");
14548e9b3e70SHartmut Brandt 	fprintf(fp, "	switch (s) {\n");
14558e9b3e70SHartmut Brandt 
14568e9b3e70SHartmut Brandt 	const struct enums *e;
14578e9b3e70SHartmut Brandt 	TAILQ_FOREACH(e, &t->enums, link) {
14588e9b3e70SHartmut Brandt 		fprintf(fp, "\t  case %s_", t->name);
14598e9b3e70SHartmut Brandt 		unminus(fp, e->name);
14608e9b3e70SHartmut Brandt 		fprintf(fp, ":\n");
14618e9b3e70SHartmut Brandt 	}
14628e9b3e70SHartmut Brandt 
14638e9b3e70SHartmut Brandt 	fprintf(fp, "		return (1);\n");
14648e9b3e70SHartmut Brandt 	fprintf(fp, "	}\n");
14658e9b3e70SHartmut Brandt 	fprintf(fp, "	return (0);\n");
14668e9b3e70SHartmut Brandt 	fprintf(fp, "}\n\n");
14678e9b3e70SHartmut Brandt 
14688e9b3e70SHartmut Brandt 	if (!ccode)
14698e9b3e70SHartmut Brandt 		fprintf(fp, "static inline ");
14708e9b3e70SHartmut Brandt 	fprintf(fp, "const char *\n");
14718e9b3e70SHartmut Brandt 	fprintf(fp, "tostr_%s(enum %s s)\n", t->name, t->name);
14728e9b3e70SHartmut Brandt 	fprintf(fp, "{\n");
14738e9b3e70SHartmut Brandt 	fprintf(fp, "	static const char *vals[] = { STRING_%s };\n", t->name);
14748e9b3e70SHartmut Brandt 	fprintf(fp, "\n");
14758e9b3e70SHartmut Brandt 	fprintf(fp, "	if (isok_%s(s))\n", t->name);
14768e9b3e70SHartmut Brandt 	fprintf(fp, "		return (vals[(int)s - STROFF_%s]);\n", t->name);
14778e9b3e70SHartmut Brandt 	fprintf(fp, "	return (\"%s???\");\n", t->name);
14788e9b3e70SHartmut Brandt 	fprintf(fp, "}\n\n");
14798e9b3e70SHartmut Brandt 
14808e9b3e70SHartmut Brandt 	if (!ccode)
14818e9b3e70SHartmut Brandt 		fprintf(fp, "static inline ");
14828e9b3e70SHartmut Brandt 	fprintf(fp, "int\n");
14838e9b3e70SHartmut Brandt 	fprintf(fp, "fromstr_%s(const char *str, enum %s *s)\n",
14848e9b3e70SHartmut Brandt 	    t->name, t->name);
14858e9b3e70SHartmut Brandt 	fprintf(fp, "{\n");
14868e9b3e70SHartmut Brandt 	fprintf(fp, "	static const char *vals[] = { STRING_%s };\n", t->name);
14878e9b3e70SHartmut Brandt 	fprintf(fp, "\n");
14888e9b3e70SHartmut Brandt 	fprintf(fp, "	for (size_t i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {\n");
14898e9b3e70SHartmut Brandt 	fprintf(fp, "		if (vals[i] != NULL && strcmp(vals[i], str) == 0) {\n");
14908e9b3e70SHartmut Brandt 	fprintf(fp, "			*s = i + STROFF_%s;\n", t->name);
14918e9b3e70SHartmut Brandt 	fprintf(fp, "			return (1);\n");
14928e9b3e70SHartmut Brandt 	fprintf(fp, "		}\n");
14938e9b3e70SHartmut Brandt 	fprintf(fp, "	}\n");
14948e9b3e70SHartmut Brandt 	fprintf(fp, "	return (0);\n");
14958e9b3e70SHartmut Brandt 	fprintf(fp, "}\n");
14968e9b3e70SHartmut Brandt }
14978e9b3e70SHartmut Brandt 
14988e9b3e70SHartmut Brandt /**
1499*04d17814SAndrey V. Elsukov  * Generate a definition for the enum packed into a guard against multiple
1500*04d17814SAndrey V. Elsukov  * definitions.
1501*04d17814SAndrey V. Elsukov  *
1502*04d17814SAndrey V. Elsukov  * \param fp	file to write definition to
1503*04d17814SAndrey V. Elsukov  * \param t	type
1504*04d17814SAndrey V. Elsukov  * \param dof	generate functions too
1505*04d17814SAndrey V. Elsukov  */
1506*04d17814SAndrey V. Elsukov static void
gen_enum(FILE * fp,const struct type * t,int dof)1507*04d17814SAndrey V. Elsukov gen_enum(FILE *fp, const struct type *t, int dof)
1508*04d17814SAndrey V. Elsukov {
1509*04d17814SAndrey V. Elsukov 	const struct enums *e;
1510*04d17814SAndrey V. Elsukov 	long min = LONG_MAX;
1511*04d17814SAndrey V. Elsukov 
1512*04d17814SAndrey V. Elsukov 	fprintf(fp, "\n");
1513*04d17814SAndrey V. Elsukov 	fprintf(fp, "#ifndef %s_defined__\n", t->name);
1514*04d17814SAndrey V. Elsukov 	fprintf(fp, "#define %s_defined__\n", t->name);
1515*04d17814SAndrey V. Elsukov 	fprintf(fp, "/*\n");
1516*04d17814SAndrey V. Elsukov 	fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
1517*04d17814SAndrey V. Elsukov 	fprintf(fp, " */\n");
1518*04d17814SAndrey V. Elsukov 	fprintf(fp, "enum %s {\n", t->name);
1519*04d17814SAndrey V. Elsukov 	TAILQ_FOREACH(e, &t->enums, link) {
1520*04d17814SAndrey V. Elsukov 		fprintf(fp, "\t%s_", t->name);
1521*04d17814SAndrey V. Elsukov 		unminus(fp, e->name);
1522*04d17814SAndrey V. Elsukov 		fprintf(fp, " = %ld,\n", e->value);
1523*04d17814SAndrey V. Elsukov 		if (e->value < min)
1524*04d17814SAndrey V. Elsukov 			min = e->value;
1525*04d17814SAndrey V. Elsukov 	}
1526*04d17814SAndrey V. Elsukov 	fprintf(fp, "};\n");
1527*04d17814SAndrey V. Elsukov 	fprintf(fp, "#define	STROFF_%s %ld\n", t->name, min);
1528*04d17814SAndrey V. Elsukov 	fprintf(fp, "#define	STRING_%s \\\n", t->name);
1529*04d17814SAndrey V. Elsukov 	TAILQ_FOREACH(e, &t->enums, link) {
1530*04d17814SAndrey V. Elsukov 		fprintf(fp, "\t[%ld] = \"%s_", e->value - min, t->name);
1531*04d17814SAndrey V. Elsukov 		unminus(fp, e->name);
1532*04d17814SAndrey V. Elsukov 		fprintf(fp, "\",\\\n");
1533*04d17814SAndrey V. Elsukov 	}
1534*04d17814SAndrey V. Elsukov 	fprintf(fp, "\n");
1535*04d17814SAndrey V. Elsukov 	if (dof) {
1536*04d17814SAndrey V. Elsukov 		fprintf(fp, "#ifdef SNMPENUM_FUNCS\n");
1537*04d17814SAndrey V. Elsukov 		fprintf(fp, "\n");
1538*04d17814SAndrey V. Elsukov 		gen_enum_funcs(fp, t, 0);
1539*04d17814SAndrey V. Elsukov 		fprintf(fp, "\n");
1540*04d17814SAndrey V. Elsukov 		fprintf(fp, "#endif\n");
1541*04d17814SAndrey V. Elsukov 		fprintf(fp, "\n");
1542*04d17814SAndrey V. Elsukov 	}
1543*04d17814SAndrey V. Elsukov 	fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
1544*04d17814SAndrey V. Elsukov }
1545*04d17814SAndrey V. Elsukov 
1546*04d17814SAndrey V. Elsukov /**
15478e9b3e70SHartmut Brandt  * Generate helper functions for an enum. This generates code for a c file.
15488e9b3e70SHartmut Brandt  *
15498e9b3e70SHartmut Brandt  * \param fp		file to write to
15508e9b3e70SHartmut Brandt  * \param name		enum name
15518e9b3e70SHartmut Brandt  */
15528e9b3e70SHartmut Brandt static int
gen_enum_funcs_str(FILE * fp,const char * name)15538e9b3e70SHartmut Brandt gen_enum_funcs_str(FILE *fp, const char *name)
15548e9b3e70SHartmut Brandt {
15558e9b3e70SHartmut Brandt 	const struct type *t;
15568e9b3e70SHartmut Brandt 
15578e9b3e70SHartmut Brandt 	LIST_FOREACH(t, &types, link)
15588e9b3e70SHartmut Brandt 		if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
15598e9b3e70SHartmut Brandt 			gen_enum_funcs(fp, t, 1);
15608e9b3e70SHartmut Brandt 			return (0);
15618e9b3e70SHartmut Brandt 		}
15628e9b3e70SHartmut Brandt 
15638e9b3e70SHartmut Brandt 	return (-1);
15648e9b3e70SHartmut Brandt }
15658e9b3e70SHartmut Brandt 
15668e9b3e70SHartmut Brandt /**
15678e9b3e70SHartmut Brandt  * Generate helper functions for all enums.
15688e9b3e70SHartmut Brandt  *
15698e9b3e70SHartmut Brandt  * \param fp		file to write to
15708e9b3e70SHartmut Brandt  * \param ccode		generate externally visible non-inline functions
15718e9b3e70SHartmut Brandt  */
15728e9b3e70SHartmut Brandt static void
gen_all_enum_funcs(FILE * fp,int ccode)15738e9b3e70SHartmut Brandt gen_all_enum_funcs(FILE *fp, int ccode)
15746f557cf7SHartmut Brandt {
15756f557cf7SHartmut Brandt 	const struct type *t;
15766f557cf7SHartmut Brandt 
15776f557cf7SHartmut Brandt 	LIST_FOREACH(t, &types, link)
15786f557cf7SHartmut Brandt 		if (t->is_enum || t->is_bits)
15798e9b3e70SHartmut Brandt 			gen_enum_funcs(fp, t, ccode);
15806f557cf7SHartmut Brandt }
15816f557cf7SHartmut Brandt 
1582*04d17814SAndrey V. Elsukov static void
gen_enums(FILE * fp,int dof)1583*04d17814SAndrey V. Elsukov gen_enums(FILE *fp, int dof)
1584*04d17814SAndrey V. Elsukov {
1585*04d17814SAndrey V. Elsukov 	const struct type *t;
1586*04d17814SAndrey V. Elsukov 
1587*04d17814SAndrey V. Elsukov 	LIST_FOREACH(t, &types, link)
1588*04d17814SAndrey V. Elsukov 		if (t->is_enum || t->is_bits)
1589*04d17814SAndrey V. Elsukov 			gen_enum(fp, t, dof);
1590*04d17814SAndrey V. Elsukov }
1591*04d17814SAndrey V. Elsukov 
15928e9b3e70SHartmut Brandt /**
15938e9b3e70SHartmut Brandt  * Extract a given enum to the specified file and optionally generate static
15948e9b3e70SHartmut Brandt  * inline helper functions for them.
15958e9b3e70SHartmut Brandt  *
15968e9b3e70SHartmut Brandt  * \param fp		file to print on
15978e9b3e70SHartmut Brandt  * \param name		name of the enum
15988e9b3e70SHartmut Brandt  * \param gen_funcs	generate the functions too
15998e9b3e70SHartmut Brandt  *
16008e9b3e70SHartmut Brandt  * \return 0 if found, -1 otherwise
16018e9b3e70SHartmut Brandt  */
16026f557cf7SHartmut Brandt static int
extract_enum(FILE * fp,const char * name,int gen_funcs)16038e9b3e70SHartmut Brandt extract_enum(FILE *fp, const char *name, int gen_funcs)
16046f557cf7SHartmut Brandt {
16056f557cf7SHartmut Brandt 	const struct type *t;
16066f557cf7SHartmut Brandt 
16076f557cf7SHartmut Brandt 	LIST_FOREACH(t, &types, link)
16086f557cf7SHartmut Brandt 		if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
1609*04d17814SAndrey V. Elsukov 			gen_enum(fp, t, gen_funcs);
16106f557cf7SHartmut Brandt 			return (0);
16116f557cf7SHartmut Brandt 		}
16126f557cf7SHartmut Brandt 	return (-1);
1613896052c1SHartmut Brandt }
1614896052c1SHartmut Brandt 
16158e9b3e70SHartmut Brandt /**
16168e9b3e70SHartmut Brandt  * Extract all enums to the given file and optionally generate static inline
16178e9b3e70SHartmut Brandt  * helper functions for them.
16188e9b3e70SHartmut Brandt  *
16198e9b3e70SHartmut Brandt  * \param fp		file to print on
16208e9b3e70SHartmut Brandt  * \param gen_funcs	generate the functions too
16218e9b3e70SHartmut Brandt  */
16228e9b3e70SHartmut Brandt static void
extract_all_enums(FILE * fp,int gen_funcs)16238e9b3e70SHartmut Brandt extract_all_enums(FILE *fp, int gen_funcs)
16248e9b3e70SHartmut Brandt {
16258e9b3e70SHartmut Brandt 	const struct type *t;
16268e9b3e70SHartmut Brandt 
16278e9b3e70SHartmut Brandt 	LIST_FOREACH(t, &types, link)
1628*04d17814SAndrey V. Elsukov 		if (t->is_enum || t->is_bits)
1629*04d17814SAndrey V. Elsukov 			gen_enum(fp, t, gen_funcs);
16308e9b3e70SHartmut Brandt }
16318e9b3e70SHartmut Brandt 
16328e9b3e70SHartmut Brandt /**
16338e9b3e70SHartmut Brandt  * Extract enums and optionally generate some helper functions for them.
16348e9b3e70SHartmut Brandt  *
16358e9b3e70SHartmut Brandt  * \param argc		number of arguments
16368e9b3e70SHartmut Brandt  * \param argv		arguments (enum names)
1637*04d17814SAndrey V. Elsukov  * \param gen_funcs	which functions to generate
16388e9b3e70SHartmut Brandt  */
16398e9b3e70SHartmut Brandt static void
make_enums(int argc,char * argv[],enum gen_funcs gen_funcs)1640*04d17814SAndrey V. Elsukov make_enums(int argc, char *argv[], enum gen_funcs gen_funcs)
16418e9b3e70SHartmut Brandt {
1642*04d17814SAndrey V. Elsukov 	if (gen_funcs == GEN_FUNCS_C) {
16438e9b3e70SHartmut Brandt 		if (argc == 0)
16448e9b3e70SHartmut Brandt 			gen_all_enum_funcs(stdout, 1);
16458e9b3e70SHartmut Brandt 		else {
16468e9b3e70SHartmut Brandt 			for (int i = 0; i < argc; i++)
16478e9b3e70SHartmut Brandt 				if (gen_enum_funcs_str(stdout, argv[i]))
16488e9b3e70SHartmut Brandt 					errx(1, "enum not found: %s", argv[i]);
16498e9b3e70SHartmut Brandt 		}
16508e9b3e70SHartmut Brandt 	} else {
16518e9b3e70SHartmut Brandt 		if (argc == 0)
1652*04d17814SAndrey V. Elsukov 			extract_all_enums(stdout, gen_funcs == GEN_FUNCS_H);
16538e9b3e70SHartmut Brandt 		else {
16548e9b3e70SHartmut Brandt 			for (int i = 0; i < argc; i++)
1655*04d17814SAndrey V. Elsukov 				if (extract_enum(stdout, argv[i],
1656*04d17814SAndrey V. Elsukov 				    gen_funcs == GEN_FUNCS_H))
16578e9b3e70SHartmut Brandt 					errx(1, "enum not found: %s", argv[i]);
16588e9b3e70SHartmut Brandt 		}
16598e9b3e70SHartmut Brandt 	}
16608e9b3e70SHartmut Brandt }
16618e9b3e70SHartmut Brandt 
1662*04d17814SAndrey V. Elsukov /**
1663*04d17814SAndrey V. Elsukov  * Produce the operation tables for the daemon or a module.
1664*04d17814SAndrey V. Elsukov  *
1665*04d17814SAndrey V. Elsukov  * \param root		tree root
1666*04d17814SAndrey V. Elsukov  * \param gen_funcs	generate enum funcs
1667*04d17814SAndrey V. Elsukov  */
1668*04d17814SAndrey V. Elsukov static void
make_table(const struct node * root,int gen_funcs)1669*04d17814SAndrey V. Elsukov make_table(const struct node *root, int gen_funcs)
1670*04d17814SAndrey V. Elsukov {
1671*04d17814SAndrey V. Elsukov 	FILE *fp;
1672*04d17814SAndrey V. Elsukov 
1673*04d17814SAndrey V. Elsukov 	char fname[MAXPATHLEN + 1];
1674*04d17814SAndrey V. Elsukov 	sprintf(fname, "%stree.h", file_prefix);
1675*04d17814SAndrey V. Elsukov 	if ((fp = fopen(fname, "w")) == NULL)
1676*04d17814SAndrey V. Elsukov 		err(1, "%s: ", fname);
1677*04d17814SAndrey V. Elsukov 	gen_header(fp, root, PREFIX_LEN, NULL);
1678*04d17814SAndrey V. Elsukov 
1679*04d17814SAndrey V. Elsukov 	fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
1680*04d17814SAndrey V. Elsukov 	gen_enums(fp, gen_funcs);
1681*04d17814SAndrey V. Elsukov 	fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
1682*04d17814SAndrey V. Elsukov 
1683*04d17814SAndrey V. Elsukov 	fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
1684*04d17814SAndrey V. Elsukov 	fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
1685*04d17814SAndrey V. Elsukov 
1686*04d17814SAndrey V. Elsukov 	fclose(fp);
1687*04d17814SAndrey V. Elsukov 
1688*04d17814SAndrey V. Elsukov 	sprintf(fname, "%stree.c", file_prefix);
1689*04d17814SAndrey V. Elsukov 	if ((fp = fopen(fname, "w")) == NULL)
1690*04d17814SAndrey V. Elsukov 		err(1, "%s: ", fname);
1691*04d17814SAndrey V. Elsukov 	gen_table(fp, root);
1692*04d17814SAndrey V. Elsukov 	fclose(fp);
1693*04d17814SAndrey V. Elsukov }
1694*04d17814SAndrey V. Elsukov 
1695f06ca4afSHartmut Brandt int
main(int argc,char * argv[])1696f06ca4afSHartmut Brandt main(int argc, char *argv[])
1697f06ca4afSHartmut Brandt {
1698*04d17814SAndrey V. Elsukov 	enum op op = OP_GEN;
1699*04d17814SAndrey V. Elsukov 	enum gen_funcs gen_funcs = GEN_FUNCS_NONE;
1700*04d17814SAndrey V. Elsukov 
17016f557cf7SHartmut Brandt 	char *infile = NULL;
1702f06ca4afSHartmut Brandt 
1703*04d17814SAndrey V. Elsukov 	int opt;
17048e9b3e70SHartmut Brandt 	while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF)
1705f06ca4afSHartmut Brandt 		switch (opt) {
1706f06ca4afSHartmut Brandt 
17076f557cf7SHartmut Brandt 		  case 'd':
17086f557cf7SHartmut Brandt 			debug = 1;
17096f557cf7SHartmut Brandt 			break;
17106f557cf7SHartmut Brandt 
17116f557cf7SHartmut Brandt 		  case 'E':
1712*04d17814SAndrey V. Elsukov 			if (op != OP_GEN && op != OP_ENUMS)
1713*04d17814SAndrey V. Elsukov 				errx(1, "-E conflicts with earlier options");
1714*04d17814SAndrey V. Elsukov 			op = OP_ENUMS;
17156f557cf7SHartmut Brandt 			break;
17166f557cf7SHartmut Brandt 
1717f06ca4afSHartmut Brandt 		  case 'e':
1718*04d17814SAndrey V. Elsukov 			if (op != OP_GEN && op != OP_EXTRACT)
1719*04d17814SAndrey V. Elsukov 				errx(1, "-e conflicts with earlier options");
1720*04d17814SAndrey V. Elsukov 			op = OP_EXTRACT;
1721f06ca4afSHartmut Brandt 			break;
1722f06ca4afSHartmut Brandt 
17238e9b3e70SHartmut Brandt 		  case 'F':
1724*04d17814SAndrey V. Elsukov 			if (gen_funcs != GEN_FUNCS_NONE &&
1725*04d17814SAndrey V. Elsukov 			    gen_funcs != GEN_FUNCS_C)
1726*04d17814SAndrey V. Elsukov 				errx(1, "-F conflicts with -f");
1727*04d17814SAndrey V. Elsukov 			gen_funcs = GEN_FUNCS_C;
17288e9b3e70SHartmut Brandt 			break;
17298e9b3e70SHartmut Brandt 
17308e9b3e70SHartmut Brandt 		  case 'f':
1731*04d17814SAndrey V. Elsukov 			if (gen_funcs != GEN_FUNCS_NONE &&
1732*04d17814SAndrey V. Elsukov 			    gen_funcs != GEN_FUNCS_H)
1733*04d17814SAndrey V. Elsukov 				errx(1, "-f conflicts with -F");
1734*04d17814SAndrey V. Elsukov 			gen_funcs = GEN_FUNCS_H;
17358e9b3e70SHartmut Brandt 			break;
17368e9b3e70SHartmut Brandt 
17378e9b3e70SHartmut Brandt 		  case 'h':
17388e9b3e70SHartmut Brandt 			fprintf(stderr, "%s", usgtxt);
17398e9b3e70SHartmut Brandt 			exit(0);
17408e9b3e70SHartmut Brandt 
17416f557cf7SHartmut Brandt 		  case 'I':
17426f557cf7SHartmut Brandt 			path_new(optarg);
17436f557cf7SHartmut Brandt 			break;
17446f557cf7SHartmut Brandt 
17456f557cf7SHartmut Brandt 		  case 'i':
17466f557cf7SHartmut Brandt 			infile = optarg;
17476f557cf7SHartmut Brandt 			break;
17486f557cf7SHartmut Brandt 
1749f06ca4afSHartmut Brandt 		  case 'l':
1750f06ca4afSHartmut Brandt 			localincs = 1;
1751f06ca4afSHartmut Brandt 			break;
1752f06ca4afSHartmut Brandt 
1753f06ca4afSHartmut Brandt 		  case 'p':
1754f06ca4afSHartmut Brandt 			file_prefix = optarg;
1755f06ca4afSHartmut Brandt 			if (strlen(file_prefix) + strlen("tree.c") >
1756f06ca4afSHartmut Brandt 			    MAXPATHLEN)
1757f06ca4afSHartmut Brandt 				errx(1, "prefix too long");
1758f06ca4afSHartmut Brandt 			break;
1759896052c1SHartmut Brandt 
1760896052c1SHartmut Brandt 		  case 't':
1761*04d17814SAndrey V. Elsukov 			if (op != OP_GEN && op != OP_TREE)
1762*04d17814SAndrey V. Elsukov 				errx(1, "-t conflicts with earlier options");
1763*04d17814SAndrey V. Elsukov 			op = OP_TREE;
1764896052c1SHartmut Brandt 			break;
1765f06ca4afSHartmut Brandt 		}
1766f06ca4afSHartmut Brandt 
1767*04d17814SAndrey V. Elsukov 	argc -= optind;
1768*04d17814SAndrey V. Elsukov 	argv += optind;
1769f06ca4afSHartmut Brandt 
1770*04d17814SAndrey V. Elsukov 	/* open input */
17716f557cf7SHartmut Brandt 	if (infile == NULL) {
17726f557cf7SHartmut Brandt 		input_new(stdin, NULL, "<stdin>");
17736f557cf7SHartmut Brandt 	} else {
1774*04d17814SAndrey V. Elsukov 		FILE *fp;
17756f557cf7SHartmut Brandt 		if ((fp = fopen(infile, "r")) == NULL)
17766f557cf7SHartmut Brandt 			err(1, "%s", infile);
17776f557cf7SHartmut Brandt 		input_new(fp, NULL, infile);
17786f557cf7SHartmut Brandt 	}
17796f557cf7SHartmut Brandt 
1780*04d17814SAndrey V. Elsukov 	/* parse and check input */
1781*04d17814SAndrey V. Elsukov 	struct node *root = parse_top(gettoken());
1782*04d17814SAndrey V. Elsukov 
1783*04d17814SAndrey V. Elsukov 	int tok;
1784896052c1SHartmut Brandt 	while ((tok = gettoken()) != TOK_EOF)
17856f557cf7SHartmut Brandt 		merge(&root, parse_top(tok));
1786f06ca4afSHartmut Brandt 
17878e9b3e70SHartmut Brandt 	if (root)
1788f06ca4afSHartmut Brandt 		check_tree(root);
1789f06ca4afSHartmut Brandt 
1790*04d17814SAndrey V. Elsukov 	/* do what the user has requested */
1791*04d17814SAndrey V. Elsukov 	switch (op) {
1792*04d17814SAndrey V. Elsukov 
1793*04d17814SAndrey V. Elsukov 	  case OP_EXTRACT:
1794*04d17814SAndrey V. Elsukov 		if (argc == 0)
1795*04d17814SAndrey V. Elsukov 			errx(1, "-e requires arguments");
1796*04d17814SAndrey V. Elsukov 
1797*04d17814SAndrey V. Elsukov 		for (int i = 0; i < argc; i++)
1798*04d17814SAndrey V. Elsukov 			if (gen_extract(stdout, root, argv[i]))
1799*04d17814SAndrey V. Elsukov 				errx(1, "object not found: %s", argv[i]);
18006f557cf7SHartmut Brandt 		return (0);
1801*04d17814SAndrey V. Elsukov 
1802*04d17814SAndrey V. Elsukov 	  case OP_ENUMS:
1803*04d17814SAndrey V. Elsukov 		make_enums(argc, argv, gen_funcs);
1804f06ca4afSHartmut Brandt 		return (0);
1805*04d17814SAndrey V. Elsukov 
1806*04d17814SAndrey V. Elsukov 	  case OP_TREE:
1807*04d17814SAndrey V. Elsukov 		if (argc != 0)
1808*04d17814SAndrey V. Elsukov 			errx(1, "-t allows no arguments");
1809896052c1SHartmut Brandt 		gen_tree(root, 0);
1810896052c1SHartmut Brandt 		return (0);
18116f557cf7SHartmut Brandt 
1812*04d17814SAndrey V. Elsukov 	  case OP_GEN:
1813*04d17814SAndrey V. Elsukov 		if (argc != 0)
1814*04d17814SAndrey V. Elsukov 			errx(1, "tree generation allows no arguments");
1815*04d17814SAndrey V. Elsukov 		make_table(root, gen_funcs == GEN_FUNCS_H);
1816f06ca4afSHartmut Brandt 		return (0);
1817f06ca4afSHartmut Brandt 	}
1818*04d17814SAndrey V. Elsukov }
1819