1122394Sharti/*
2122394Sharti * Copyright (c) 2001-2003
3122394Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122394Sharti *	All rights reserved.
5122394Sharti *
6159063Sharti * Copyright (c) 2004-2006
7133211Sharti *	Hartmut Brandt.
8133211Sharti *	All rights reserved.
9133211Sharti *
10122394Sharti * Author: Harti Brandt <harti@freebsd.org>
11133211Sharti *
12133211Sharti * Redistribution and use in source and binary forms, with or without
13133211Sharti * modification, are permitted provided that the following conditions
14133211Sharti * are met:
15133211Sharti * 1. Redistributions of source code must retain the above copyright
16133211Sharti *    notice, this list of conditions and the following disclaimer.
17122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
18122394Sharti *    notice, this list of conditions and the following disclaimer in the
19122394Sharti *    documentation and/or other materials provided with the distribution.
20133211Sharti *
21133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24133211Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
25133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31133211Sharti * SUCH DAMAGE.
32122394Sharti *
33159063Sharti * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $
34122394Sharti *
35122394Sharti * Generate OID table from table description.
36122394Sharti *
37122394Sharti * Syntax is:
38122394Sharti * ---------
39159063Sharti * file := top | top file
40133211Sharti *
41159063Sharti * top := tree | typedef | include
42159063Sharti *
43122394Sharti * tree := head elements ')'
44122394Sharti *
45122394Sharti * entry := head ':' index STRING elements ')'
46122394Sharti *
47159063Sharti * leaf := head type STRING ACCESS ')'
48122394Sharti *
49159063Sharti * column := head type ACCESS ')'
50122394Sharti *
51159063Sharti * type := BASETYPE | BASETYPE '|' subtype | enum | bits
52159063Sharti *
53159063Sharti * subtype := STRING
54159063Sharti *
55159063Sharti * enum := ENUM '(' value ')'
56159063Sharti *
57159063Sharti * bits := BITS '(' value ')'
58159063Sharti *
59159063Sharti * value := optminus INT STRING | optminus INT STRING value
60159063Sharti *
61159063Sharti * optminus := '-' | EMPTY
62159063Sharti *
63122394Sharti * head := '(' INT STRING
64122394Sharti *
65122394Sharti * elements := EMPTY | elements element
66122394Sharti *
67142810Sharti * element := tree | leaf | column
68122394Sharti *
69159063Sharti * index := type | index type
70122394Sharti *
71159063Sharti * typedef := 'typedef' STRING type
72159063Sharti *
73159063Sharti * include := 'include' filespec
74159063Sharti *
75159063Sharti * filespec := '"' STRING '"' | '<' STRING '>'
76122394Sharti */
77122394Sharti#include <sys/types.h>
78122394Sharti#include <sys/param.h>
79122394Sharti#include <stdio.h>
80122394Sharti#include <stdlib.h>
81122394Sharti#include <stdarg.h>
82122394Sharti#include <unistd.h>
83122394Sharti#include <string.h>
84122394Sharti#include <ctype.h>
85133429Sharti#include <inttypes.h>
86133211Sharti#include <errno.h>
87133211Sharti#ifdef HAVE_ERR_H
88122394Sharti#include <err.h>
89133211Sharti#endif
90122394Sharti#include <sys/queue.h>
91133211Sharti#include "support.h"
92122394Sharti#include "asn1.h"
93122394Sharti#include "snmp.h"
94122394Sharti#include "snmpagent.h"
95122394Sharti
96122394Sharti/*
97122394Sharti * Constant prefix for all OIDs
98122394Sharti */
99122394Shartistatic const asn_subid_t prefix[] = { 1, 3, 6 };
100122394Sharti#define	PREFIX_LEN	(sizeof(prefix) / sizeof(prefix[0]))
101122394Sharti
102122394Shartiu_int tree_size;
103122394Shartistatic const char *file_prefix = "";
104122394Sharti
105122394Sharti/* if true generate local include paths */
106122394Shartistatic int localincs = 0;
107122394Sharti
108159063Sharti/* if true print tokens */
109159063Shartistatic int debug;
110159063Sharti
111122394Shartistatic const char usgtxt[] = "\
112159063ShartiGenerate SNMP tables.\n\
113159063Shartiusage: gensnmptree [-dEehlt] [-I directory] [-i infile] [-p prefix]\n\
114159063Sharti	    [name]...\n\
115122394Shartioptions:\n\
116159063Sharti  -d		debug mode\n\
117159063Sharti  -E		extract the named enums and bits only\n\
118159063Sharti  -e		extract the named oids or enums\n\
119122394Sharti  -h		print this info\n\
120159063Sharti  -I directory	add directory to include path\n\
121159063Sharti  -i ifile	read from the named file instead of stdin\n\
122122394Sharti  -l		generate local include directives\n\
123122394Sharti  -p prefix	prepend prefix to file and variable names\n\
124159063Sharti  -t		generated a .def file\n\
125122394Sharti";
126122394Sharti
127122394Sharti/*
128122394Sharti * A node in the OID tree
129122394Sharti */
130122394Shartienum ntype {
131122394Sharti	NODE_LEAF = 1,
132122394Sharti	NODE_TREE,
133122394Sharti	NODE_ENTRY,
134122394Sharti	NODE_COLUMN
135122394Sharti};
136122394Sharti
137122394Shartienum {
138122394Sharti	FL_GET	= 0x01,
139122394Sharti	FL_SET	= 0x02,
140122394Sharti};
141122394Sharti
142122394Shartistruct node;
143122394ShartiTAILQ_HEAD(node_list, node);
144122394Sharti
145122394Shartistruct node {
146122394Sharti	enum ntype	type;
147122394Sharti	asn_subid_t	id;	/* last element of OID */
148122394Sharti	char		*name;	/* name of node */
149122394Sharti	TAILQ_ENTRY(node) link;
150122394Sharti	u_int		lno;	/* starting line number */
151122394Sharti	u_int		flags;	/* allowed operations */
152122394Sharti
153122394Sharti	union {
154122394Sharti	  struct tree {
155122394Sharti	    struct node_list subs;
156122394Sharti	  }		tree;
157122394Sharti
158122394Sharti	  struct entry {
159133211Sharti	    uint32_t	index;	/* index for table entry */
160122394Sharti	    char	*func;	/* function for tables */
161122394Sharti	    struct node_list subs;
162122394Sharti	  }		entry;
163122394Sharti
164122394Sharti	  struct leaf {
165122394Sharti	    enum snmp_syntax syntax;	/* syntax for this leaf */
166122394Sharti	    char	*func;		/* function name */
167122394Sharti	  }		leaf;
168122394Sharti
169122394Sharti	  struct column {
170122394Sharti	    enum snmp_syntax syntax;	/* syntax for this column */
171122394Sharti	  }		column;
172122394Sharti	}		u;
173122394Sharti};
174122394Sharti
175122394Shartistruct func {
176122394Sharti	const char	*name;
177122394Sharti	LIST_ENTRY(func) link;
178122394Sharti};
179122394Sharti
180122394Shartistatic LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs);
181122394Sharti
182159063Shartistruct enums {
183159063Sharti	const char	*name;
184159063Sharti	long		value;
185159063Sharti	TAILQ_ENTRY(enums) link;
186159063Sharti};
187159063Sharti
188159063Shartistruct type {
189159063Sharti	const char	*name;
190159063Sharti	const char	*from_fname;
191159063Sharti	u_int		from_lno;
192159063Sharti	u_int		syntax;
193159063Sharti	int		is_enum;
194159063Sharti	int		is_bits;
195159063Sharti	TAILQ_HEAD(, enums) enums;
196159063Sharti	LIST_ENTRY(type) link;
197159063Sharti};
198159063Sharti
199159063Shartistatic LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types);
200159063Sharti
201159063Shartistatic void report(const char *, ...) __dead2 __printflike(1, 2);
202159063Shartistatic void report_node(const struct node *, const char *, ...)
203159063Sharti    __dead2 __printflike(2, 3);
204159063Sharti
205122394Sharti/************************************************************
206122394Sharti *
207122394Sharti * Allocate memory and panic just in the case...
208122394Sharti */
209122394Shartistatic void *
210122394Shartixalloc(size_t size)
211122394Sharti{
212122394Sharti	void *ptr;
213122394Sharti
214122394Sharti	if ((ptr = malloc(size)) == NULL)
215145557Sharti		err(1, "allocing %zu bytes", size);
216122394Sharti
217122394Sharti	return (ptr);
218122394Sharti}
219122394Sharti
220159063Shartistatic char *
221159063Shartisavestr(const char *s)
222159063Sharti{
223159063Sharti
224159063Sharti	if (s == NULL)
225159063Sharti		return (NULL);
226159063Sharti	return (strcpy(xalloc(strlen(s) + 1), s));
227159063Sharti}
228159063Sharti
229122394Sharti/************************************************************
230122394Sharti *
231159063Sharti * Input stack
232159063Sharti */
233159063Shartistruct input {
234159063Sharti	FILE		*fp;
235159063Sharti	u_int		lno;
236159063Sharti	char		*fname;
237159063Sharti	char		*path;
238159063Sharti	LIST_ENTRY(input) link;
239159063Sharti};
240159063Shartistatic LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
241159063Shartistatic struct input *input = NULL;
242159063Sharti
243159063Sharti#define MAX_PATHS	100
244159063Shartistatic u_int npaths = 2;
245159063Shartistatic u_int stdpaths = 2;
246159063Shartistatic const char *paths[MAX_PATHS + 1] = {
247159063Sharti	"/usr/share/snmp/defs",
248159063Sharti	"/usr/local/share/snmp/defs",
249159063Sharti	NULL
250159063Sharti};
251159063Sharti
252159063Shartistatic int pbchar = -1;
253159063Sharti
254159063Shartistatic void
255159063Shartipath_new(const char *path)
256159063Sharti{
257159063Sharti	if (npaths >= MAX_PATHS)
258159063Sharti		report("too many -I directives");
259159063Sharti	memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths],
260159063Sharti	    sizeof(path[0]) * stdpaths);
261159063Sharti	paths[npaths - stdpaths] = savestr(path);
262159063Sharti	npaths++;
263159063Sharti}
264159063Sharti
265159063Shartistatic void
266159063Shartiinput_new(FILE *fp, const char *path, const char *fname)
267159063Sharti{
268159063Sharti	struct input *ip;
269159063Sharti
270159063Sharti	ip = xalloc(sizeof(*ip));
271159063Sharti	ip->fp = fp;
272159063Sharti	ip->lno = 1;
273159063Sharti	ip->fname = savestr(fname);
274159063Sharti	ip->path = savestr(path);
275159063Sharti	LIST_INSERT_HEAD(&inputs, ip, link);
276159063Sharti
277159063Sharti	input = ip;
278159063Sharti}
279159063Sharti
280159063Shartistatic void
281159063Shartiinput_close(void)
282159063Sharti{
283159063Sharti
284159063Sharti	if (input == NULL)
285159063Sharti		return;
286159063Sharti	fclose(input->fp);
287159063Sharti	free(input->fname);
288159063Sharti	free(input->path);
289159063Sharti	LIST_REMOVE(input, link);
290159063Sharti	free(input);
291159063Sharti
292159063Sharti	input = LIST_FIRST(&inputs);
293159063Sharti}
294159063Sharti
295159063Shartistatic FILE *
296159063Shartitryopen(const char *path, const char *fname)
297159063Sharti{
298159063Sharti	char *fn;
299159063Sharti	FILE *fp;
300159063Sharti
301159063Sharti	if (path == NULL)
302159063Sharti		fn = savestr(fname);
303159063Sharti	else {
304159063Sharti		fn = xalloc(strlen(path) + strlen(fname) + 2);
305159063Sharti		sprintf(fn, "%s/%s", path, fname);
306159063Sharti	}
307159063Sharti	fp = fopen(fn, "r");
308159063Sharti	free(fn);
309159063Sharti	return (fp);
310159063Sharti}
311159063Sharti
312159063Shartistatic void
313159063Shartiinput_fopen(const char *fname, int loc)
314159063Sharti{
315159063Sharti	FILE *fp;
316159063Sharti	char *path;
317159063Sharti	u_int p;
318159063Sharti
319159063Sharti	if (fname[0] == '/') {
320159063Sharti		if ((fp = tryopen(NULL, fname)) != NULL) {
321159063Sharti			input_new(fp, NULL, fname);
322159063Sharti			return;
323159063Sharti		}
324159063Sharti
325159063Sharti	} else {
326159063Sharti		if (loc) {
327159063Sharti			if (input == NULL)
328159063Sharti				path = NULL;
329159063Sharti			else
330159063Sharti				path = input->path;
331159063Sharti
332159063Sharti			if ((fp = tryopen(path, fname)) != NULL) {
333159063Sharti				input_new(fp, NULL, fname);
334159063Sharti				return;
335159063Sharti			}
336159063Sharti		}
337159063Sharti
338159063Sharti		for (p = 0; paths[p] != NULL; p++)
339159063Sharti			if ((fp = tryopen(paths[p], fname)) != NULL) {
340159063Sharti				input_new(fp, paths[p], fname);
341159063Sharti				return;
342159063Sharti			}
343159063Sharti	}
344159063Sharti	report("cannot open '%s'", fname);
345159063Sharti}
346159063Sharti
347159063Shartistatic int
348159063Shartitgetc(void)
349159063Sharti{
350159063Sharti	int c;
351159063Sharti
352159063Sharti	if (pbchar != -1) {
353159063Sharti		c = pbchar;
354159063Sharti		pbchar = -1;
355159063Sharti		return (c);
356159063Sharti	}
357159063Sharti
358159063Sharti	for (;;) {
359159063Sharti		if (input == NULL)
360159063Sharti			return (EOF);
361159063Sharti
362159063Sharti		if ((c = getc(input->fp)) != EOF)
363159063Sharti			return (c);
364159063Sharti
365159063Sharti		input_close();
366159063Sharti	}
367159063Sharti}
368159063Sharti
369159063Shartistatic void
370159063Shartitungetc(int c)
371159063Sharti{
372159063Sharti
373159063Sharti	if (pbchar != -1)
374159063Sharti		abort();
375159063Sharti	pbchar = c;
376159063Sharti}
377159063Sharti
378159063Sharti/************************************************************
379159063Sharti *
380122394Sharti * Parsing input
381122394Sharti */
382122394Shartienum tok {
383122394Sharti	TOK_EOF = 0200,	/* end-of-file seen */
384122394Sharti	TOK_NUM,	/* number */
385122394Sharti	TOK_STR,	/* string */
386122394Sharti	TOK_ACCESS,	/* access operator */
387122394Sharti	TOK_TYPE,	/* type operator */
388159063Sharti	TOK_ENUM,	/* enum token (kind of a type) */
389159063Sharti	TOK_TYPEDEF,	/* typedef directive */
390159063Sharti	TOK_DEFTYPE,	/* defined type */
391159063Sharti	TOK_INCLUDE,	/* include directive */
392159063Sharti	TOK_FILENAME,	/* filename ("foo.bar" or <foo.bar>) */
393159063Sharti	TOK_BITS,	/* bits token (kind of a type) */
394122394Sharti};
395122394Sharti
396122394Shartistatic const struct {
397122394Sharti	const char *str;
398122394Sharti	enum tok tok;
399122394Sharti	u_int val;
400122394Sharti} keywords[] = {
401122394Sharti	{ "GET", TOK_ACCESS, FL_GET },
402122394Sharti	{ "SET", TOK_ACCESS, FL_SET },
403122394Sharti	{ "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
404122394Sharti	{ "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
405122394Sharti	{ "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
406122394Sharti	{ "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
407122394Sharti	{ "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
408122394Sharti	{ "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
409122394Sharti	{ "OID", TOK_TYPE, SNMP_SYNTAX_OID },
410122394Sharti	{ "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
411122394Sharti	{ "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
412122394Sharti	{ "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
413122394Sharti	{ "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
414159063Sharti	{ "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
415159063Sharti	{ "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
416159063Sharti	{ "typedef", TOK_TYPEDEF, 0 },
417159063Sharti	{ "include", TOK_INCLUDE, 0 },
418122394Sharti	{ NULL, 0, 0 }
419122394Sharti};
420122394Sharti
421122394Sharti/* arbitrary upper limit on node names and function names */
422122394Sharti#define	MAXSTR	1000
423122394Shartichar	str[MAXSTR];
424122394Shartiu_long	val;		/* integer values */
425133211Shartiint	all_cond;	/* all conditions are true */
426159063Shartiint	saved_token = -1;
427122394Sharti
428122394Sharti/*
429122394Sharti * Report an error and exit.
430122394Sharti */
431122394Shartistatic void
432122394Shartireport(const char *fmt, ...)
433122394Sharti{
434122394Sharti	va_list ap;
435122394Sharti	int c;
436122394Sharti
437122394Sharti	va_start(ap, fmt);
438159063Sharti	fprintf(stderr, "line %u: ", input->lno);
439122394Sharti	vfprintf(stderr, fmt, ap);
440122394Sharti	fprintf(stderr, "\n");
441122394Sharti	fprintf(stderr, "context: \"");
442159063Sharti	while ((c = tgetc()) != EOF && c != '\n')
443122394Sharti		fprintf(stderr, "%c", c);
444122394Sharti	fprintf(stderr, "\n");
445122394Sharti	va_end(ap);
446122394Sharti	exit(1);
447122394Sharti}
448122394Shartistatic void
449122394Shartireport_node(const struct node *np, const char *fmt, ...)
450122394Sharti{
451122394Sharti	va_list ap;
452122394Sharti
453122394Sharti	va_start(ap, fmt);
454122394Sharti	fprintf(stderr, "line %u, node %s: ", np->lno, np->name);
455122394Sharti	vfprintf(stderr, fmt, ap);
456122394Sharti	fprintf(stderr, "\n");
457122394Sharti	va_end(ap);
458122394Sharti	exit(1);
459122394Sharti}
460122394Sharti
461122394Sharti/*
462122394Sharti * Return a fresh copy of the string constituting the current token.
463122394Sharti */
464122394Shartistatic char *
465122394Shartisavetok(void)
466122394Sharti{
467159063Sharti	return (savestr(str));
468122394Sharti}
469122394Sharti
470122394Sharti/*
471122394Sharti * Get the next token from input.
472122394Sharti */
473122394Shartistatic int
474159063Shartigettoken_internal(void)
475122394Sharti{
476122394Sharti	int c;
477159063Sharti	struct type *t;
478122394Sharti
479159063Sharti	if (saved_token != -1) {
480159063Sharti		c = saved_token;
481159063Sharti		saved_token = -1;
482159063Sharti		return (c);
483159063Sharti	}
484159063Sharti
485122394Sharti  again:
486122394Sharti	/*
487122394Sharti	 * Skip any whitespace before the next token
488122394Sharti	 */
489159063Sharti	while ((c = tgetc()) != EOF) {
490122394Sharti		if (c == '\n')
491159063Sharti			input->lno++;
492122394Sharti		if (!isspace(c))
493122394Sharti			break;
494122394Sharti	}
495122394Sharti	if (c == EOF)
496122394Sharti		return (TOK_EOF);
497122394Sharti	if (!isascii(c))
498122394Sharti		report("unexpected character %#2x", (u_int)c);
499122394Sharti
500122394Sharti	/*
501122394Sharti	 * Skip comments
502122394Sharti	 */
503122394Sharti	if (c == '#') {
504159063Sharti		while ((c = tgetc()) != EOF) {
505122394Sharti			if (c == '\n') {
506159063Sharti				input->lno++;
507122394Sharti				goto again;
508122394Sharti			}
509122394Sharti		}
510122394Sharti		report("unexpected EOF in comment");
511122394Sharti	}
512122394Sharti
513122394Sharti	/*
514122394Sharti	 * Single character tokens
515122394Sharti	 */
516159063Sharti	if (strchr("():|-", c) != NULL)
517122394Sharti		return (c);
518122394Sharti
519159063Sharti	if (c == '"' || c == '<') {
520159063Sharti		int end = c;
521159063Sharti		size_t n = 0;
522159063Sharti
523159063Sharti		val = 1;
524159063Sharti		if (c == '<') {
525159063Sharti			val = 0;
526159063Sharti			end = '>';
527159063Sharti		}
528159063Sharti
529159063Sharti		while ((c = tgetc()) != EOF) {
530159063Sharti			if (c == end)
531159063Sharti				break;
532159063Sharti			if (n == sizeof(str) - 1) {
533159063Sharti				str[n++] = '\0';
534159063Sharti				report("filename too long '%s...'", str);
535159063Sharti			}
536159063Sharti			str[n++] = c;
537159063Sharti		}
538159063Sharti		str[n++] = '\0';
539159063Sharti		return (TOK_FILENAME);
540159063Sharti	}
541159063Sharti
542122394Sharti	/*
543122394Sharti	 * Sort out numbers
544122394Sharti	 */
545122394Sharti	if (isdigit(c)) {
546159063Sharti		size_t n = 0;
547159063Sharti		str[n++] = c;
548159063Sharti		while ((c = tgetc()) != EOF) {
549159063Sharti			if (!isdigit(c)) {
550159063Sharti				tungetc(c);
551159063Sharti				break;
552159063Sharti			}
553159063Sharti			if (n == sizeof(str) - 1) {
554159063Sharti				str[n++] = '\0';
555159063Sharti				report("number too long '%s...'", str);
556159063Sharti			}
557159063Sharti			str[n++] = c;
558159063Sharti		}
559159063Sharti		str[n++] = '\0';
560159063Sharti		sscanf(str, "%lu", &val);
561122394Sharti		return (TOK_NUM);
562122394Sharti	}
563122394Sharti
564122394Sharti	/*
565122394Sharti	 * So that has to be a string.
566122394Sharti	 */
567122394Sharti	if (isalpha(c) || c == '_') {
568122394Sharti		size_t n = 0;
569122394Sharti		str[n++] = c;
570159063Sharti		while ((c = tgetc()) != EOF) {
571159063Sharti			if (!isalnum(c) && c != '_' && c != '-') {
572159063Sharti				tungetc(c);
573122394Sharti				break;
574122394Sharti			}
575122394Sharti			if (n == sizeof(str) - 1) {
576122394Sharti				str[n++] = '\0';
577122394Sharti				report("string too long '%s...'", str);
578122394Sharti			}
579122394Sharti			str[n++] = c;
580122394Sharti		}
581122394Sharti		str[n++] = '\0';
582122394Sharti
583122394Sharti		/*
584122394Sharti		 * Keywords
585122394Sharti		 */
586122394Sharti		for (c = 0; keywords[c].str != NULL; c++)
587122394Sharti			if (strcmp(keywords[c].str, str) == 0) {
588122394Sharti				val = keywords[c].val;
589122394Sharti				return (keywords[c].tok);
590122394Sharti			}
591122394Sharti
592159063Sharti		LIST_FOREACH(t, &types, link) {
593159063Sharti			if (strcmp(t->name, str) == 0) {
594159063Sharti				val = t->syntax;
595159063Sharti				return (TOK_DEFTYPE);
596159063Sharti			}
597159063Sharti		}
598122394Sharti		return (TOK_STR);
599122394Sharti	}
600122394Sharti	if (isprint(c))
601159063Sharti		errx(1, "%u: unexpected character '%c'", input->lno, c);
602122394Sharti	else
603159063Sharti		errx(1, "%u: unexpected character 0x%02x", input->lno,
604159063Sharti		    (u_int)c);
605122394Sharti}
606159063Shartistatic int
607159063Shartigettoken(void)
608159063Sharti{
609159063Sharti	int tok = gettoken_internal();
610122394Sharti
611159063Sharti	if (debug) {
612159063Sharti		switch (tok) {
613159063Sharti
614159063Sharti		  case TOK_EOF:
615159063Sharti			fprintf(stderr, "EOF ");
616159063Sharti			break;
617159063Sharti
618159063Sharti		  case TOK_NUM:
619159063Sharti			fprintf(stderr, "NUM(%lu) ", val);
620159063Sharti			break;
621159063Sharti
622159063Sharti		  case TOK_STR:
623159063Sharti			fprintf(stderr, "STR(%s) ", str);
624159063Sharti			break;
625159063Sharti
626159063Sharti		  case TOK_ACCESS:
627159063Sharti			fprintf(stderr, "ACCESS(%lu) ", val);
628159063Sharti			break;
629159063Sharti
630159063Sharti		  case TOK_TYPE:
631159063Sharti			fprintf(stderr, "TYPE(%lu) ", val);
632159063Sharti			break;
633159063Sharti
634159063Sharti		  case TOK_ENUM:
635159063Sharti			fprintf(stderr, "ENUM ");
636159063Sharti			break;
637159063Sharti
638159063Sharti		  case TOK_BITS:
639159063Sharti			fprintf(stderr, "BITS ");
640159063Sharti			break;
641159063Sharti
642159063Sharti		  case TOK_TYPEDEF:
643159063Sharti			fprintf(stderr, "TYPEDEF ");
644159063Sharti			break;
645159063Sharti
646159063Sharti		  case TOK_DEFTYPE:
647159063Sharti			fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val);
648159063Sharti			break;
649159063Sharti
650159063Sharti		  case TOK_INCLUDE:
651159063Sharti			fprintf(stderr, "INCLUDE ");
652159063Sharti			break;
653159063Sharti
654159063Sharti		  case TOK_FILENAME:
655159063Sharti			fprintf(stderr, "FILENAME ");
656159063Sharti			break;
657159063Sharti
658159063Sharti		  default:
659159063Sharti			if (tok < TOK_EOF) {
660159063Sharti				if (isprint(tok))
661159063Sharti					fprintf(stderr, "'%c' ", tok);
662159063Sharti				else if (tok == '\n')
663159063Sharti					fprintf(stderr, "\n");
664159063Sharti				else
665159063Sharti					fprintf(stderr, "%02x ", tok);
666159063Sharti			} else
667159063Sharti				abort();
668159063Sharti			break;
669159063Sharti		}
670159063Sharti	}
671159063Sharti	return (tok);
672159063Sharti}
673159063Sharti
674159063Sharti/**
675159063Sharti * Pushback a token
676159063Sharti */
677159063Shartistatic void
678159063Shartipushback(enum tok tok)
679159063Sharti{
680159063Sharti
681159063Sharti	if (saved_token != -1)
682159063Sharti		abort();
683159063Sharti	saved_token = tok;
684159063Sharti}
685159063Sharti
686122394Sharti/*
687159063Sharti * Create a new type
688159063Sharti */
689159063Shartistatic struct type *
690159063Shartimake_type(const char *s)
691159063Sharti{
692159063Sharti	struct type *t;
693159063Sharti
694159063Sharti	t = xalloc(sizeof(*t));
695159063Sharti	t->name = savestr(s);
696159063Sharti	t->is_enum = 0;
697159063Sharti	t->syntax = SNMP_SYNTAX_NULL;
698159063Sharti	t->from_fname = savestr(input->fname);
699159063Sharti	t->from_lno = input->lno;
700159063Sharti	TAILQ_INIT(&t->enums);
701159063Sharti	LIST_INSERT_HEAD(&types, t, link);
702159063Sharti
703159063Sharti	return (t);
704159063Sharti}
705159063Sharti
706159063Sharti/*
707159063Sharti * Parse a type. We've seen the ENUM or type keyword already. Leave next
708159063Sharti * token.
709159063Sharti */
710159063Shartistatic u_int
711159063Shartiparse_type(enum tok *tok, struct type *t, const char *vname)
712159063Sharti{
713159063Sharti	u_int syntax;
714159063Sharti	struct enums *e;
715159063Sharti
716159063Sharti	syntax = val;
717159063Sharti
718159063Sharti	if (*tok == TOK_ENUM || *tok == TOK_BITS) {
719159063Sharti		if (t == NULL && vname != NULL) {
720159063Sharti			t = make_type(vname);
721159063Sharti			t->is_enum = (*tok == TOK_ENUM);
722159063Sharti			t->is_bits = (*tok == TOK_BITS);
723159063Sharti			t->syntax = syntax;
724159063Sharti		}
725159063Sharti		if (gettoken() != '(')
726159063Sharti			report("'(' expected after ENUM");
727159063Sharti
728159063Sharti		if ((*tok = gettoken()) == TOK_EOF)
729159063Sharti			report("unexpected EOF in ENUM");
730159063Sharti		do {
731159063Sharti			e = NULL;
732159063Sharti			if (t != NULL) {
733159063Sharti				e = xalloc(sizeof(*e));
734159063Sharti			}
735159063Sharti			if (*tok == '-') {
736159063Sharti				if ((*tok = gettoken()) == TOK_EOF)
737159063Sharti					report("unexpected EOF in ENUM");
738159063Sharti				e->value = -(long)val;
739159063Sharti			} else
740159063Sharti				e->value = val;
741159063Sharti
742159063Sharti			if (*tok != TOK_NUM)
743159063Sharti				report("need value for ENUM/BITS");
744159063Sharti			if (gettoken() != TOK_STR)
745159063Sharti				report("need string in ENUM/BITS");
746159063Sharti			if (e != NULL) {
747159063Sharti				e->name = savetok();
748159063Sharti				TAILQ_INSERT_TAIL(&t->enums, e, link);
749159063Sharti			}
750159063Sharti			if ((*tok = gettoken()) == TOK_EOF)
751159063Sharti				report("unexpected EOF in ENUM/BITS");
752159063Sharti		} while (*tok != ')');
753159063Sharti		*tok = gettoken();
754159063Sharti
755159063Sharti	} else if (*tok == TOK_DEFTYPE) {
756159063Sharti		*tok = gettoken();
757159063Sharti
758159063Sharti	} else {
759159063Sharti		if ((*tok = gettoken()) == '|') {
760159063Sharti			if (gettoken() != TOK_STR)
761159063Sharti				report("subtype expected after '|'");
762159063Sharti			*tok = gettoken();
763159063Sharti		}
764159063Sharti	}
765159063Sharti
766159063Sharti	return (syntax);
767159063Sharti}
768159063Sharti
769159063Sharti/*
770122394Sharti * Parse the next node (complete with all subnodes)
771122394Sharti */
772122394Shartistatic struct node *
773122394Shartiparse(enum tok tok)
774122394Sharti{
775122394Sharti	struct node *node;
776122394Sharti	struct node *sub;
777122394Sharti	u_int index_count;
778122394Sharti
779122394Sharti	node = xalloc(sizeof(struct node));
780159063Sharti	node->lno = input->lno;
781154182Sharti	node->flags = 0;
782122394Sharti
783122394Sharti	if (tok != '(')
784122394Sharti		report("'(' expected at begin of node");
785122394Sharti	if (gettoken() != TOK_NUM)
786122394Sharti		report("node id expected after opening '('");
787122394Sharti	if (val > ASN_MAXID)
788122394Sharti		report("subid too large '%lu'", val);
789122394Sharti	node->id = (asn_subid_t)val;
790122394Sharti	if (gettoken() != TOK_STR)
791122394Sharti		report("node name expected after '(' ID");
792122394Sharti	node->name = savetok();
793122394Sharti
794159063Sharti	if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
795159063Sharti	    tok == TOK_ENUM || tok == TOK_BITS) {
796122394Sharti		/* LEAF or COLUM */
797159063Sharti		u_int syntax = parse_type(&tok, NULL, node->name);
798122394Sharti
799159063Sharti		if (tok == TOK_STR) {
800122394Sharti			/* LEAF */
801122394Sharti			node->type = NODE_LEAF;
802122394Sharti			node->u.leaf.func = savetok();
803122394Sharti			node->u.leaf.syntax = syntax;
804122394Sharti			tok = gettoken();
805122394Sharti		} else {
806122394Sharti			/* COLUMN */
807122394Sharti			node->type = NODE_COLUMN;
808122394Sharti			node->u.column.syntax = syntax;
809122394Sharti		}
810122394Sharti
811122394Sharti		while (tok != ')') {
812122394Sharti			if (tok != TOK_ACCESS)
813122394Sharti				report("access keyword or ')' expected");
814122394Sharti			node->flags |= (u_int)val;
815122394Sharti			tok = gettoken();
816122394Sharti		}
817122394Sharti
818122394Sharti	} else if (tok == ':') {
819122394Sharti		/* ENTRY */
820122394Sharti		node->type = NODE_ENTRY;
821122394Sharti		TAILQ_INIT(&node->u.entry.subs);
822122394Sharti
823122394Sharti		index_count = 0;
824122394Sharti		node->u.entry.index = 0;
825159063Sharti		tok = gettoken();
826159063Sharti		while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
827159063Sharti		    tok == TOK_ENUM || tok == TOK_BITS) {
828159063Sharti			u_int syntax = parse_type(&tok, NULL, node->name);
829122394Sharti			if (index_count++ == SNMP_INDEXES_MAX)
830122394Sharti				report("too many table indexes");
831122394Sharti			node->u.entry.index |=
832159063Sharti			    syntax << (SNMP_INDEX_SHIFT * index_count);
833122394Sharti		}
834122394Sharti		node->u.entry.index |= index_count;
835122394Sharti		if (index_count == 0)
836122394Sharti			report("need at least one index");
837122394Sharti		if (tok != TOK_STR)
838122394Sharti			report("function name expected");
839122394Sharti
840122394Sharti		node->u.entry.func = savetok();
841122394Sharti
842122394Sharti		tok = gettoken();
843122394Sharti
844122394Sharti		while (tok != ')') {
845122394Sharti			sub = parse(tok);
846122394Sharti			TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
847122394Sharti			tok = gettoken();
848122394Sharti		}
849122394Sharti
850122394Sharti	} else {
851122394Sharti		/* subtree */
852122394Sharti		node->type = NODE_TREE;
853122394Sharti		TAILQ_INIT(&node->u.tree.subs);
854122394Sharti
855122394Sharti		while (tok != ')') {
856122394Sharti			sub = parse(tok);
857122394Sharti			TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
858122394Sharti			tok = gettoken();
859122394Sharti		}
860122394Sharti	}
861122394Sharti	return (node);
862122394Sharti}
863122394Sharti
864122394Sharti/*
865159063Sharti * Parse a top level element. Return the tree if it was a tree, NULL
866159063Sharti * otherwise.
867159063Sharti */
868159063Shartistatic struct node *
869159063Shartiparse_top(enum tok tok)
870159063Sharti{
871159063Sharti	struct type *t;
872159063Sharti
873159063Sharti	if (tok == '(')
874159063Sharti		return (parse(tok));
875159063Sharti
876159063Sharti	if (tok == TOK_TYPEDEF) {
877159063Sharti		if (gettoken() != TOK_STR)
878159063Sharti			report("type name expected after typedef");
879159063Sharti
880159063Sharti		t = make_type(str);
881159063Sharti
882159063Sharti		tok = gettoken();
883159063Sharti		t->is_enum = (tok == TOK_ENUM);
884159063Sharti		t->is_bits = (tok == TOK_BITS);
885159063Sharti		t->syntax = parse_type(&tok, t, NULL);
886159063Sharti		pushback(tok);
887159063Sharti
888159063Sharti		return (NULL);
889159063Sharti	}
890159063Sharti
891159063Sharti	if (tok == TOK_INCLUDE) {
892159063Sharti		if (gettoken() != TOK_FILENAME)
893159063Sharti			report("filename expected in include directive");
894159063Sharti
895159063Sharti		input_fopen(str, val);
896159063Sharti		return (NULL);
897159063Sharti	}
898159063Sharti
899159063Sharti	report("'(' or 'typedef' expected");
900159063Sharti}
901159063Sharti
902159063Sharti/*
903122394Sharti * Generate the C-code table part for one node.
904122394Sharti */
905122394Shartistatic void
906159063Shartigen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx,
907159063Sharti    const char *func)
908122394Sharti{
909122394Sharti	u_int n;
910122394Sharti	struct node *sub;
911122394Sharti	u_int syntax;
912122394Sharti
913122394Sharti	if (oid->len == ASN_MAXOIDLEN)
914122394Sharti		report_node(np, "OID too long");
915122394Sharti	oid->subs[oid->len++] = np->id;
916122394Sharti
917122394Sharti	if (np->type == NODE_TREE) {
918122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
919159063Sharti			gen_node(fp, sub, oid, 0, NULL);
920122394Sharti		oid->len--;
921122394Sharti		return;
922122394Sharti	}
923122394Sharti	if (np->type == NODE_ENTRY) {
924122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
925159063Sharti			gen_node(fp, sub, oid, np->u.entry.index,
926159063Sharti			    np->u.entry.func);
927122394Sharti		oid->len--;
928122394Sharti		return;
929122394Sharti	}
930122394Sharti
931122394Sharti	/* leaf or column */
932122394Sharti	if ((np->flags & (FL_GET|FL_SET)) == 0) {
933122394Sharti		oid->len--;
934122394Sharti		return;
935122394Sharti	}
936122394Sharti
937122394Sharti	fprintf(fp, "    {{ %u, {", oid->len);
938122394Sharti	for (n = 0; n < oid->len; n++)
939122394Sharti		fprintf(fp, " %u,", oid->subs[n]);
940122394Sharti	fprintf(fp, " }}, \"%s\", ", np->name);
941122394Sharti
942122394Sharti	if (np->type == NODE_COLUMN) {
943122394Sharti		syntax = np->u.column.syntax;
944122394Sharti		fprintf(fp, "SNMP_NODE_COLUMN, ");
945122394Sharti	} else {
946122394Sharti		syntax = np->u.leaf.syntax;
947122394Sharti		fprintf(fp, "SNMP_NODE_LEAF, ");
948122394Sharti	}
949122394Sharti
950122394Sharti	switch (syntax) {
951122394Sharti
952122394Sharti	  case SNMP_SYNTAX_NULL:
953122394Sharti		fprintf(fp, "SNMP_SYNTAX_NULL, ");
954122394Sharti		break;
955122394Sharti
956122394Sharti	  case SNMP_SYNTAX_INTEGER:
957122394Sharti		fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
958122394Sharti		break;
959122394Sharti
960122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
961122394Sharti		fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
962122394Sharti		break;
963122394Sharti
964122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
965122394Sharti		fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
966122394Sharti		break;
967122394Sharti
968122394Sharti	  case SNMP_SYNTAX_OID:
969122394Sharti		fprintf(fp, "SNMP_SYNTAX_OID, ");
970122394Sharti		break;
971122394Sharti
972122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
973122394Sharti		fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
974122394Sharti		break;
975122394Sharti
976122394Sharti	  case SNMP_SYNTAX_COUNTER:
977122394Sharti		fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
978122394Sharti		break;
979122394Sharti
980122394Sharti	  case SNMP_SYNTAX_GAUGE:
981122394Sharti		fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
982122394Sharti		break;
983122394Sharti
984122394Sharti	  case SNMP_SYNTAX_COUNTER64:
985122394Sharti		fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
986122394Sharti		break;
987122394Sharti
988122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
989122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
990122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
991122394Sharti		abort();
992122394Sharti	}
993122394Sharti
994122394Sharti	if (np->type == NODE_COLUMN)
995122394Sharti		fprintf(fp, "%s, ", func);
996122394Sharti	else
997122394Sharti		fprintf(fp, "%s, ", np->u.leaf.func);
998122394Sharti
999122394Sharti	fprintf(fp, "0");
1000122394Sharti	if (np->flags & FL_SET)
1001122394Sharti		fprintf(fp, "|SNMP_NODE_CANSET");
1002128237Sharti	fprintf(fp, ", %#x, NULL, NULL },\n", idx);
1003122394Sharti	oid->len--;
1004122394Sharti	return;
1005122394Sharti}
1006122394Sharti
1007122394Sharti/*
1008122394Sharti * Generate the header file with the function declarations.
1009122394Sharti */
1010122394Shartistatic void
1011159063Shartigen_header(FILE *fp, struct node *np, u_int oidlen, const char *func)
1012122394Sharti{
1013122394Sharti	char f[MAXSTR + 4];
1014122394Sharti	struct node *sub;
1015122394Sharti	struct func *ptr;
1016122394Sharti
1017122394Sharti	oidlen++;
1018122394Sharti	if (np->type == NODE_TREE) {
1019122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1020159063Sharti			gen_header(fp, sub, oidlen, NULL);
1021122394Sharti		return;
1022122394Sharti	}
1023122394Sharti	if (np->type == NODE_ENTRY) {
1024122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1025159063Sharti			gen_header(fp, sub, oidlen, np->u.entry.func);
1026122394Sharti		return;
1027122394Sharti	}
1028122394Sharti
1029122394Sharti 	if((np->flags & (FL_GET|FL_SET)) == 0)
1030122394Sharti		return;
1031122394Sharti
1032142810Sharti	if (np->type == NODE_COLUMN) {
1033142810Sharti		if (func == NULL)
1034142810Sharti			errx(1, "column without function (%s) - probably "
1035142810Sharti			    "outside of a table", np->name);
1036122394Sharti		sprintf(f, "%s", func);
1037142810Sharti	} else
1038122394Sharti		sprintf(f, "%s", np->u.leaf.func);
1039122394Sharti
1040122394Sharti	LIST_FOREACH(ptr, &funcs, link)
1041122394Sharti		if (strcmp(ptr->name, f) == 0)
1042122394Sharti			break;
1043122394Sharti
1044122394Sharti	if (ptr == NULL) {
1045122394Sharti		ptr = xalloc(sizeof(*ptr));
1046159063Sharti		ptr->name = savestr(f);
1047122394Sharti		LIST_INSERT_HEAD(&funcs, ptr, link);
1048122394Sharti
1049122394Sharti		fprintf(fp, "int	%s(struct snmp_context *, "
1050122394Sharti		    "struct snmp_value *, u_int, u_int, "
1051122394Sharti		    "enum snmp_op);\n", f);
1052122394Sharti	}
1053122394Sharti
1054122394Sharti	fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
1055122394Sharti}
1056122394Sharti
1057122394Sharti/*
1058122394Sharti * Generate the OID table.
1059122394Sharti */
1060122394Shartistatic void
1061159063Shartigen_table(FILE *fp, struct node *node)
1062122394Sharti{
1063122394Sharti	struct asn_oid oid;
1064122394Sharti
1065122394Sharti	fprintf(fp, "#include <sys/types.h>\n");
1066122394Sharti	fprintf(fp, "#include <stdio.h>\n");
1067150920Sharti#ifdef HAVE_STDINT_H
1068133211Sharti	fprintf(fp, "#include <stdint.h>\n");
1069150920Sharti#endif
1070122394Sharti	if (localincs) {
1071122394Sharti		fprintf(fp, "#include \"asn1.h\"\n");
1072122394Sharti		fprintf(fp, "#include \"snmp.h\"\n");
1073122394Sharti		fprintf(fp, "#include \"snmpagent.h\"\n");
1074122394Sharti	} else {
1075122394Sharti		fprintf(fp, "#include <bsnmp/asn1.h>\n");
1076122394Sharti		fprintf(fp, "#include <bsnmp/snmp.h>\n");
1077122394Sharti		fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
1078122394Sharti	}
1079122394Sharti	fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
1080122394Sharti	fprintf(fp, "\n");
1081122394Sharti
1082122394Sharti	fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
1083122394Sharti
1084122394Sharti	oid.len = PREFIX_LEN;
1085122394Sharti	memcpy(oid.subs, prefix, sizeof(prefix));
1086159063Sharti	gen_node(fp, node, &oid, 0, NULL);
1087122394Sharti
1088122394Sharti	fprintf(fp, "};\n\n");
1089122394Sharti}
1090122394Sharti
1091133211Shartistatic void
1092133211Shartiprint_syntax(u_int syntax)
1093133211Sharti{
1094133211Sharti	u_int i;
1095133211Sharti
1096133211Sharti	for (i = 0; keywords[i].str != NULL; i++)
1097133211Sharti		if (keywords[i].tok == TOK_TYPE &&
1098133211Sharti		    keywords[i].val == syntax) {
1099133211Sharti			printf(" %s", keywords[i].str);
1100133211Sharti			return;
1101133211Sharti	}
1102133211Sharti	abort();
1103133211Sharti}
1104133211Sharti
1105133211Sharti/*
1106133211Sharti * Generate a tree definition file
1107133211Sharti */
1108133211Shartistatic void
1109133211Shartigen_tree(const struct node *np, int level)
1110133211Sharti{
1111133211Sharti	const struct node *sp;
1112133211Sharti	u_int i;
1113133211Sharti
1114133211Sharti	printf("%*s(%u %s", 2 * level, "", np->id, np->name);
1115133211Sharti
1116133211Sharti	switch (np->type) {
1117133211Sharti
1118133211Sharti	  case NODE_LEAF:
1119133211Sharti		print_syntax(np->u.leaf.syntax);
1120133211Sharti		printf(" %s%s%s)\n", np->u.leaf.func,
1121133211Sharti		    (np->flags & FL_GET) ? " GET" : "",
1122133211Sharti		    (np->flags & FL_SET) ? " SET" : "");
1123133211Sharti		break;
1124133211Sharti
1125133211Sharti	  case NODE_TREE:
1126133211Sharti		if (TAILQ_EMPTY(&np->u.tree.subs)) {
1127133211Sharti			printf(")\n");
1128133211Sharti		} else {
1129133211Sharti			printf("\n");
1130133211Sharti			TAILQ_FOREACH(sp, &np->u.tree.subs, link)
1131133211Sharti				gen_tree(sp, level + 1);
1132133211Sharti			printf("%*s)\n", 2 * level, "");
1133133211Sharti		}
1134133211Sharti		break;
1135133211Sharti
1136133211Sharti	  case NODE_ENTRY:
1137133211Sharti		printf(" :");
1138133211Sharti
1139133211Sharti		for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++)
1140133211Sharti			print_syntax(SNMP_INDEX(np->u.entry.index, i));
1141133211Sharti		printf(" %s\n", np->u.entry.func);
1142133211Sharti		TAILQ_FOREACH(sp, &np->u.entry.subs, link)
1143133211Sharti			gen_tree(sp, level + 1);
1144133211Sharti		printf("%*s)\n", 2 * level, "");
1145133211Sharti		break;
1146133211Sharti
1147133211Sharti	  case NODE_COLUMN:
1148133211Sharti		print_syntax(np->u.column.syntax);
1149133211Sharti		printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
1150133211Sharti		    (np->flags & FL_SET) ? " SET" : "");
1151133211Sharti		break;
1152133211Sharti	}
1153133211Sharti}
1154133211Sharti
1155122394Shartistatic int
1156159063Shartiextract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
1157133211Sharti    const struct asn_oid *idx, const char *iname)
1158122394Sharti{
1159122394Sharti	struct node *sub;
1160122394Sharti	u_long n;
1161122394Sharti
1162122394Sharti	if (oid->len == ASN_MAXOIDLEN)
1163122394Sharti		report_node(np, "OID too long");
1164122394Sharti	oid->subs[oid->len++] = np->id;
1165122394Sharti
1166122394Sharti	if (strcmp(obj, np->name) == 0) {
1167133211Sharti		if (oid->len + idx->len >= ASN_MAXOIDLEN)
1168133211Sharti			report_node(np, "OID too long");
1169133211Sharti		fprintf(fp, "#define OID_%s%s\t%u\n", np->name,
1170133211Sharti		    iname ? iname : "", np->id);
1171133211Sharti		fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name,
1172133211Sharti		    iname ? iname : "", oid->len + idx->len);
1173133211Sharti		fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name,
1174133211Sharti		    iname ? iname : "", oid->len + idx->len);
1175122394Sharti		for (n = 0; n < oid->len; n++)
1176122394Sharti			fprintf(fp, " %u,", oid->subs[n]);
1177133211Sharti		for (n = 0; n < idx->len; n++)
1178133211Sharti			fprintf(fp, " %u,", idx->subs[n]);
1179122394Sharti		fprintf(fp, " } }\n");
1180122394Sharti		return (0);
1181122394Sharti	}
1182122394Sharti
1183122394Sharti	if (np->type == NODE_TREE) {
1184122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1185159063Sharti			if (!extract(fp, sub, oid, obj, idx, iname))
1186122394Sharti				return (0);
1187122394Sharti	} else if (np->type == NODE_ENTRY) {
1188122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1189159063Sharti			if (!extract(fp, sub, oid, obj, idx, iname))
1190122394Sharti				return (0);
1191122394Sharti	}
1192122394Sharti	oid->len--;
1193122394Sharti	return (1);
1194122394Sharti}
1195122394Sharti
1196122394Shartistatic int
1197159063Shartigen_extract(FILE *fp, const struct node *root, char *object)
1198122394Sharti{
1199122394Sharti	struct asn_oid oid;
1200133211Sharti	struct asn_oid idx;
1201133211Sharti	char *s, *e, *end, *iname;
1202133211Sharti	u_long ul;
1203133211Sharti	int ret;
1204122394Sharti
1205133211Sharti	/* look whether the object to extract has an index part */
1206133211Sharti	idx.len = 0;
1207133211Sharti	iname = NULL;
1208133211Sharti	s = strchr(object, '.');
1209133211Sharti	if (s != NULL) {
1210133211Sharti		iname = malloc(strlen(s) + 1);
1211133211Sharti		if (iname == NULL)
1212133211Sharti			err(1, "cannot allocated index");
1213133211Sharti
1214133211Sharti		strcpy(iname, s);
1215133211Sharti		for (e = iname; *e != '\0'; e++)
1216133211Sharti			if (*e == '.')
1217133211Sharti				*e = '_';
1218133211Sharti
1219133211Sharti		*s++ = '\0';
1220133211Sharti		while (s != NULL) {
1221133211Sharti			if (*s == '\0')
1222133211Sharti				errx(1, "bad index syntax");
1223133211Sharti			if ((e = strchr(s, '.')) != NULL)
1224133211Sharti				*e++ = '\0';
1225133211Sharti
1226133211Sharti			errno = 0;
1227133211Sharti			ul = strtoul(s, &end, 0);
1228133211Sharti			if (*end != '\0')
1229133211Sharti				errx(1, "bad index syntax '%s'", end);
1230133211Sharti			if (errno != 0)
1231133211Sharti				err(1, "bad index syntax");
1232133211Sharti
1233133211Sharti			if (idx.len == ASN_MAXOIDLEN)
1234133211Sharti				errx(1, "index oid too large");
1235133211Sharti			idx.subs[idx.len++] = ul;
1236133211Sharti
1237133211Sharti			s = e;
1238133211Sharti		}
1239133211Sharti	}
1240133211Sharti
1241122394Sharti	oid.len = PREFIX_LEN;
1242122394Sharti	memcpy(oid.subs, prefix, sizeof(prefix));
1243159063Sharti	ret = extract(fp, root, &oid, object, &idx, iname);
1244133211Sharti	if (iname != NULL)
1245133211Sharti		free(iname);
1246133211Sharti
1247133211Sharti	return (ret);
1248122394Sharti}
1249122394Sharti
1250122394Sharti
1251122394Shartistatic void
1252122394Sharticheck_sub_order(const struct node *np, const struct node_list *subs)
1253122394Sharti{
1254122394Sharti	int first;
1255122394Sharti	const struct node *sub;
1256122394Sharti	asn_subid_t maxid = 0;
1257122394Sharti
1258122394Sharti	/* ensure, that subids are ordered */
1259122394Sharti	first = 1;
1260122394Sharti	TAILQ_FOREACH(sub, subs, link) {
1261122394Sharti		if (!first && sub->id <= maxid)
1262122394Sharti			report_node(np, "subids not ordered at %s", sub->name);
1263122394Sharti		maxid = sub->id;
1264122394Sharti		first = 0;
1265122394Sharti	}
1266122394Sharti}
1267122394Sharti
1268122394Sharti/*
1269122394Sharti * Do some sanity checks on the tree definition and do some computations.
1270122394Sharti */
1271122394Shartistatic void
1272122394Sharticheck_tree(struct node *np)
1273122394Sharti{
1274122394Sharti	struct node *sub;
1275122394Sharti
1276122394Sharti	if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
1277122394Sharti		if ((np->flags & (FL_GET|FL_SET)) != 0)
1278122394Sharti			tree_size++;
1279122394Sharti		return;
1280122394Sharti	}
1281122394Sharti
1282122394Sharti	if (np->type == NODE_ENTRY) {
1283122394Sharti		check_sub_order(np, &np->u.entry.subs);
1284122394Sharti
1285122394Sharti		/* ensure all subnodes are columns */
1286122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
1287122394Sharti			if (sub->type != NODE_COLUMN)
1288122394Sharti				report_node(np, "entry subnode '%s' is not "
1289122394Sharti				    "a column", sub->name);
1290122394Sharti			check_tree(sub);
1291122394Sharti		}
1292122394Sharti	} else {
1293122394Sharti		check_sub_order(np, &np->u.tree.subs);
1294122394Sharti
1295122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1296122394Sharti			check_tree(sub);
1297122394Sharti	}
1298122394Sharti}
1299122394Sharti
1300133211Shartistatic void
1301133211Shartimerge_subs(struct node_list *s1, struct node_list *s2)
1302133211Sharti{
1303133211Sharti	struct node *n1, *n2;
1304133211Sharti
1305133211Sharti	while (!TAILQ_EMPTY(s2)) {
1306133211Sharti		n2 = TAILQ_FIRST(s2);
1307133211Sharti		TAILQ_REMOVE(s2, n2, link);
1308133211Sharti
1309133211Sharti		TAILQ_FOREACH(n1, s1, link)
1310133211Sharti			if (n1->id >= n2->id)
1311133211Sharti				break;
1312133211Sharti		if (n1 == NULL)
1313133211Sharti			TAILQ_INSERT_TAIL(s1, n2, link);
1314133211Sharti		else if (n1->id > n2->id)
1315133211Sharti			TAILQ_INSERT_BEFORE(n1, n2, link);
1316133211Sharti		else {
1317133211Sharti			if (n1->type == NODE_TREE && n2->type == NODE_TREE) {
1318133211Sharti				if (strcmp(n1->name, n2->name) != 0)
1319133211Sharti					errx(1, "trees to merge must have "
1320133211Sharti					    "same name '%s' '%s'", n1->name,
1321133211Sharti					    n2->name);
1322133211Sharti				merge_subs(&n1->u.tree.subs, &n2->u.tree.subs);
1323133211Sharti				free(n2);
1324133211Sharti			} else if (n1->type == NODE_ENTRY &&
1325133211Sharti			    n2->type == NODE_ENTRY) {
1326133211Sharti				if (strcmp(n1->name, n2->name) != 0)
1327133211Sharti					errx(1, "entries to merge must have "
1328133211Sharti					    "same name '%s' '%s'", n1->name,
1329133211Sharti					    n2->name);
1330133211Sharti				if (n1->u.entry.index != n2->u.entry.index)
1331133211Sharti					errx(1, "entries to merge must have "
1332133211Sharti					    "same index '%s'", n1->name);
1333133211Sharti				if (strcmp(n1->u.entry.func,
1334133211Sharti				    n2->u.entry.func) != 0)
1335133211Sharti					errx(1, "entries to merge must have "
1336133211Sharti					    "same op '%s'", n1->name);
1337133211Sharti				merge_subs(&n1->u.entry.subs,
1338133211Sharti				    &n2->u.entry.subs);
1339133211Sharti				free(n2);
1340133211Sharti			} else
1341133211Sharti				errx(1, "entities to merge must be both "
1342133211Sharti				    "trees or both entries: %s, %s",
1343133211Sharti				    n1->name, n2->name);
1344133211Sharti		}
1345133211Sharti	}
1346133211Sharti}
1347133211Sharti
1348133211Shartistatic void
1349159063Shartimerge(struct node **root, struct node *t)
1350133211Sharti{
1351133211Sharti
1352159063Sharti	if (*root == NULL) {
1353159063Sharti		*root = t;
1354159063Sharti		return;
1355159063Sharti	}
1356159063Sharti	if (t == NULL)
1357159063Sharti		return;
1358159063Sharti
1359133211Sharti	/* both must be trees */
1360159063Sharti	if ((*root)->type != NODE_TREE)
1361133211Sharti		errx(1, "root is not a tree");
1362133211Sharti	if (t->type != NODE_TREE)
1363133211Sharti		errx(1, "can merge only with tree");
1364159063Sharti	if ((*root)->id != t->id)
1365133211Sharti		errx(1, "trees to merge must have same id");
1366133211Sharti
1367159063Sharti	merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs);
1368133211Sharti}
1369133211Sharti
1370159063Shartistatic void
1371159063Shartiunminus(FILE *fp, const char *s)
1372159063Sharti{
1373159063Sharti
1374159063Sharti	while (*s != '\0') {
1375159063Sharti		if (*s == '-')
1376159063Sharti			fprintf(fp, "_");
1377159063Sharti		else
1378159063Sharti			fprintf(fp, "%c", *s);
1379159063Sharti		s++;
1380159063Sharti	}
1381159063Sharti}
1382159063Sharti
1383159063Shartistatic void
1384159063Shartigen_enum(FILE *fp, const struct type *t)
1385159063Sharti{
1386159063Sharti	const struct enums *e;
1387159063Sharti	long min = LONG_MAX;
1388159063Sharti
1389159063Sharti	fprintf(fp, "\n");
1390159063Sharti	fprintf(fp, "#ifndef %s_defined__\n", t->name);
1391159063Sharti	fprintf(fp, "#define %s_defined__\n", t->name);
1392159063Sharti	fprintf(fp, "/*\n");
1393159063Sharti	fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
1394159063Sharti	fprintf(fp, " */\n");
1395159063Sharti	fprintf(fp, "enum %s {\n", t->name);
1396159063Sharti	TAILQ_FOREACH(e, &t->enums, link) {
1397159063Sharti		fprintf(fp, "\t%s_", t->name);
1398159063Sharti		unminus(fp, e->name);
1399159063Sharti		fprintf(fp, " = %ld,\n", e->value);
1400159063Sharti		if (e->value < min)
1401159063Sharti			min = e->value;
1402159063Sharti	}
1403159063Sharti	fprintf(fp, "};\n");
1404159063Sharti	fprintf(fp, "#define	STROFF_%s %ld\n", t->name, min);
1405159063Sharti	fprintf(fp, "#define	STRING_%s \\\n", t->name);
1406159063Sharti	TAILQ_FOREACH(e, &t->enums, link) {
1407159063Sharti		fprintf(fp, "\t[%ld] \"%s_", e->value - min, t->name);
1408159063Sharti		unminus(fp, e->name);
1409159063Sharti		fprintf(fp, "\",\\\n");
1410159063Sharti	}
1411159063Sharti	fprintf(fp, "\n");
1412159063Sharti	fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
1413159063Sharti}
1414159063Sharti
1415159063Shartistatic void
1416159063Shartigen_enums(FILE *fp)
1417159063Sharti{
1418159063Sharti	const struct type *t;
1419159063Sharti
1420159063Sharti	LIST_FOREACH(t, &types, link)
1421159063Sharti		if (t->is_enum || t->is_bits)
1422159063Sharti			gen_enum(fp, t);
1423159063Sharti}
1424159063Sharti
1425159063Shartistatic int
1426159063Shartiextract_enum(FILE *fp, const char *name)
1427159063Sharti{
1428159063Sharti	const struct type *t;
1429159063Sharti
1430159063Sharti	LIST_FOREACH(t, &types, link)
1431159063Sharti		if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
1432159063Sharti			gen_enum(fp, t);
1433159063Sharti			return (0);
1434159063Sharti		}
1435159063Sharti	return (-1);
1436159063Sharti}
1437159063Sharti
1438122394Shartiint
1439122394Shartimain(int argc, char *argv[])
1440122394Sharti{
1441122394Sharti	int do_extract = 0;
1442133211Sharti	int do_tree = 0;
1443159063Sharti	int do_enums = 0;
1444122394Sharti	int opt;
1445122394Sharti	struct node *root;
1446122394Sharti	char fname[MAXPATHLEN + 1];
1447133211Sharti	int tok;
1448159063Sharti	FILE *fp;
1449159063Sharti	char *infile = NULL;
1450122394Sharti
1451159063Sharti	while ((opt = getopt(argc, argv, "dEehI:i:lp:t")) != EOF)
1452122394Sharti		switch (opt) {
1453122394Sharti
1454159063Sharti		  case 'd':
1455159063Sharti			debug = 1;
1456159063Sharti			break;
1457159063Sharti
1458122394Sharti		  case 'h':
1459122394Sharti			fprintf(stderr, "%s", usgtxt);
1460122394Sharti			exit(0);
1461122394Sharti
1462159063Sharti		  case 'E':
1463159063Sharti			do_enums = 1;
1464159063Sharti			break;
1465159063Sharti
1466122394Sharti		  case 'e':
1467122394Sharti			do_extract = 1;
1468122394Sharti			break;
1469122394Sharti
1470159063Sharti		  case 'I':
1471159063Sharti			path_new(optarg);
1472159063Sharti			break;
1473159063Sharti
1474159063Sharti		  case 'i':
1475159063Sharti			infile = optarg;
1476159063Sharti			break;
1477159063Sharti
1478122394Sharti		  case 'l':
1479122394Sharti			localincs = 1;
1480122394Sharti			break;
1481122394Sharti
1482122394Sharti		  case 'p':
1483122394Sharti			file_prefix = optarg;
1484122394Sharti			if (strlen(file_prefix) + strlen("tree.c") >
1485122394Sharti			    MAXPATHLEN)
1486122394Sharti				errx(1, "prefix too long");
1487122394Sharti			break;
1488133211Sharti
1489133211Sharti		  case 't':
1490133211Sharti			do_tree = 1;
1491133211Sharti			break;
1492122394Sharti		}
1493122394Sharti
1494159063Sharti	if (do_extract + do_tree + do_enums > 1)
1495159063Sharti		errx(1, "conflicting options -e/-t/-E");
1496159063Sharti	if (!do_extract && !do_enums && argc != optind)
1497122394Sharti		errx(1, "no arguments allowed");
1498159063Sharti	if ((do_extract || do_enums) && argc == optind)
1499122394Sharti		errx(1, "no objects specified");
1500122394Sharti
1501159063Sharti	if (infile == NULL) {
1502159063Sharti		input_new(stdin, NULL, "<stdin>");
1503159063Sharti	} else {
1504159063Sharti		if ((fp = fopen(infile, "r")) == NULL)
1505159063Sharti			err(1, "%s", infile);
1506159063Sharti		input_new(fp, NULL, infile);
1507159063Sharti	}
1508159063Sharti
1509159063Sharti	root = parse_top(gettoken());
1510133211Sharti	while ((tok = gettoken()) != TOK_EOF)
1511159063Sharti		merge(&root, parse_top(tok));
1512122394Sharti
1513122394Sharti	check_tree(root);
1514122394Sharti
1515122394Sharti	if (do_extract) {
1516122394Sharti		while (optind < argc) {
1517159063Sharti			if (gen_extract(stdout, root, argv[optind]))
1518122394Sharti				errx(1, "object not found: %s", argv[optind]);
1519122394Sharti			optind++;
1520122394Sharti		}
1521122394Sharti		return (0);
1522122394Sharti	}
1523159063Sharti	if (do_enums) {
1524159063Sharti		while (optind < argc) {
1525159063Sharti			if (extract_enum(stdout, argv[optind]))
1526159063Sharti				errx(1, "enum not found: %s", argv[optind]);
1527159063Sharti			optind++;
1528159063Sharti		}
1529159063Sharti		return (0);
1530159063Sharti	}
1531133211Sharti	if (do_tree) {
1532133211Sharti		gen_tree(root, 0);
1533133211Sharti		return (0);
1534133211Sharti	}
1535122394Sharti	sprintf(fname, "%stree.h", file_prefix);
1536122394Sharti	if ((fp = fopen(fname, "w")) == NULL)
1537122394Sharti		err(1, "%s: ", fname);
1538159063Sharti	gen_header(fp, root, PREFIX_LEN, NULL);
1539122394Sharti
1540159063Sharti	fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
1541159063Sharti	gen_enums(fp);
1542159063Sharti	fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
1543159063Sharti
1544122394Sharti	fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
1545122394Sharti	fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
1546122394Sharti
1547122394Sharti	fclose(fp);
1548122394Sharti
1549122394Sharti	sprintf(fname, "%stree.c", file_prefix);
1550122394Sharti	if ((fp = fopen(fname, "w")) == NULL)
1551122394Sharti		err(1, "%s: ", fname);
1552159063Sharti	gen_table(fp, root);
1553122394Sharti	fclose(fp);
1554122394Sharti
1555122394Sharti	return (0);
1556122394Sharti}
1557