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>
11310901Sngie *
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.
20310901Sngie *
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;
741310901Sngie
742159063Sharti			if (*tok != TOK_NUM)
743159063Sharti				report("need value for ENUM/BITS");
744159063Sharti			if (gettoken() != TOK_STR)
745159063Sharti				report("need string in ENUM/BITS");
746298450Sngie			e->name = savetok();
747298450Sngie			TAILQ_INSERT_TAIL(&t->enums, e, link);
748159063Sharti			if ((*tok = gettoken()) == TOK_EOF)
749159063Sharti				report("unexpected EOF in ENUM/BITS");
750159063Sharti		} while (*tok != ')');
751159063Sharti		*tok = gettoken();
752159063Sharti
753159063Sharti	} else if (*tok == TOK_DEFTYPE) {
754159063Sharti		*tok = gettoken();
755159063Sharti
756159063Sharti	} else {
757159063Sharti		if ((*tok = gettoken()) == '|') {
758159063Sharti			if (gettoken() != TOK_STR)
759159063Sharti				report("subtype expected after '|'");
760159063Sharti			*tok = gettoken();
761159063Sharti		}
762159063Sharti	}
763159063Sharti
764159063Sharti	return (syntax);
765159063Sharti}
766159063Sharti
767159063Sharti/*
768122394Sharti * Parse the next node (complete with all subnodes)
769122394Sharti */
770122394Shartistatic struct node *
771122394Shartiparse(enum tok tok)
772122394Sharti{
773122394Sharti	struct node *node;
774122394Sharti	struct node *sub;
775122394Sharti	u_int index_count;
776122394Sharti
777122394Sharti	node = xalloc(sizeof(struct node));
778159063Sharti	node->lno = input->lno;
779154182Sharti	node->flags = 0;
780122394Sharti
781122394Sharti	if (tok != '(')
782122394Sharti		report("'(' expected at begin of node");
783122394Sharti	if (gettoken() != TOK_NUM)
784122394Sharti		report("node id expected after opening '('");
785122394Sharti	if (val > ASN_MAXID)
786122394Sharti		report("subid too large '%lu'", val);
787122394Sharti	node->id = (asn_subid_t)val;
788122394Sharti	if (gettoken() != TOK_STR)
789122394Sharti		report("node name expected after '(' ID");
790122394Sharti	node->name = savetok();
791122394Sharti
792159063Sharti	if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
793159063Sharti	    tok == TOK_ENUM || tok == TOK_BITS) {
794122394Sharti		/* LEAF or COLUM */
795159063Sharti		u_int syntax = parse_type(&tok, NULL, node->name);
796122394Sharti
797159063Sharti		if (tok == TOK_STR) {
798122394Sharti			/* LEAF */
799122394Sharti			node->type = NODE_LEAF;
800122394Sharti			node->u.leaf.func = savetok();
801122394Sharti			node->u.leaf.syntax = syntax;
802122394Sharti			tok = gettoken();
803122394Sharti		} else {
804122394Sharti			/* COLUMN */
805122394Sharti			node->type = NODE_COLUMN;
806122394Sharti			node->u.column.syntax = syntax;
807122394Sharti		}
808122394Sharti
809122394Sharti		while (tok != ')') {
810122394Sharti			if (tok != TOK_ACCESS)
811122394Sharti				report("access keyword or ')' expected");
812122394Sharti			node->flags |= (u_int)val;
813122394Sharti			tok = gettoken();
814122394Sharti		}
815122394Sharti
816122394Sharti	} else if (tok == ':') {
817122394Sharti		/* ENTRY */
818122394Sharti		node->type = NODE_ENTRY;
819122394Sharti		TAILQ_INIT(&node->u.entry.subs);
820122394Sharti
821122394Sharti		index_count = 0;
822122394Sharti		node->u.entry.index = 0;
823159063Sharti		tok = gettoken();
824159063Sharti		while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
825159063Sharti		    tok == TOK_ENUM || tok == TOK_BITS) {
826159063Sharti			u_int syntax = parse_type(&tok, NULL, node->name);
827122394Sharti			if (index_count++ == SNMP_INDEXES_MAX)
828122394Sharti				report("too many table indexes");
829122394Sharti			node->u.entry.index |=
830159063Sharti			    syntax << (SNMP_INDEX_SHIFT * index_count);
831122394Sharti		}
832122394Sharti		node->u.entry.index |= index_count;
833122394Sharti		if (index_count == 0)
834122394Sharti			report("need at least one index");
835122394Sharti		if (tok != TOK_STR)
836122394Sharti			report("function name expected");
837122394Sharti
838122394Sharti		node->u.entry.func = savetok();
839122394Sharti
840122394Sharti		tok = gettoken();
841122394Sharti
842122394Sharti		while (tok != ')') {
843122394Sharti			sub = parse(tok);
844122394Sharti			TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
845122394Sharti			tok = gettoken();
846122394Sharti		}
847122394Sharti
848122394Sharti	} else {
849122394Sharti		/* subtree */
850122394Sharti		node->type = NODE_TREE;
851122394Sharti		TAILQ_INIT(&node->u.tree.subs);
852122394Sharti
853122394Sharti		while (tok != ')') {
854122394Sharti			sub = parse(tok);
855122394Sharti			TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
856122394Sharti			tok = gettoken();
857122394Sharti		}
858122394Sharti	}
859122394Sharti	return (node);
860122394Sharti}
861122394Sharti
862122394Sharti/*
863159063Sharti * Parse a top level element. Return the tree if it was a tree, NULL
864159063Sharti * otherwise.
865159063Sharti */
866159063Shartistatic struct node *
867159063Shartiparse_top(enum tok tok)
868159063Sharti{
869159063Sharti	struct type *t;
870159063Sharti
871159063Sharti	if (tok == '(')
872159063Sharti		return (parse(tok));
873159063Sharti
874159063Sharti	if (tok == TOK_TYPEDEF) {
875159063Sharti		if (gettoken() != TOK_STR)
876159063Sharti			report("type name expected after typedef");
877159063Sharti
878159063Sharti		t = make_type(str);
879159063Sharti
880159063Sharti		tok = gettoken();
881159063Sharti		t->is_enum = (tok == TOK_ENUM);
882159063Sharti		t->is_bits = (tok == TOK_BITS);
883159063Sharti		t->syntax = parse_type(&tok, t, NULL);
884159063Sharti		pushback(tok);
885159063Sharti
886159063Sharti		return (NULL);
887159063Sharti	}
888159063Sharti
889159063Sharti	if (tok == TOK_INCLUDE) {
890159063Sharti		if (gettoken() != TOK_FILENAME)
891159063Sharti			report("filename expected in include directive");
892159063Sharti
893159063Sharti		input_fopen(str, val);
894159063Sharti		return (NULL);
895159063Sharti	}
896159063Sharti
897159063Sharti	report("'(' or 'typedef' expected");
898159063Sharti}
899159063Sharti
900159063Sharti/*
901122394Sharti * Generate the C-code table part for one node.
902122394Sharti */
903122394Shartistatic void
904159063Shartigen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx,
905159063Sharti    const char *func)
906122394Sharti{
907122394Sharti	u_int n;
908122394Sharti	struct node *sub;
909122394Sharti	u_int syntax;
910122394Sharti
911122394Sharti	if (oid->len == ASN_MAXOIDLEN)
912122394Sharti		report_node(np, "OID too long");
913122394Sharti	oid->subs[oid->len++] = np->id;
914122394Sharti
915122394Sharti	if (np->type == NODE_TREE) {
916122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
917159063Sharti			gen_node(fp, sub, oid, 0, NULL);
918122394Sharti		oid->len--;
919122394Sharti		return;
920122394Sharti	}
921122394Sharti	if (np->type == NODE_ENTRY) {
922122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
923159063Sharti			gen_node(fp, sub, oid, np->u.entry.index,
924159063Sharti			    np->u.entry.func);
925122394Sharti		oid->len--;
926122394Sharti		return;
927122394Sharti	}
928122394Sharti
929122394Sharti	/* leaf or column */
930122394Sharti	if ((np->flags & (FL_GET|FL_SET)) == 0) {
931122394Sharti		oid->len--;
932122394Sharti		return;
933122394Sharti	}
934122394Sharti
935122394Sharti	fprintf(fp, "    {{ %u, {", oid->len);
936122394Sharti	for (n = 0; n < oid->len; n++)
937122394Sharti		fprintf(fp, " %u,", oid->subs[n]);
938122394Sharti	fprintf(fp, " }}, \"%s\", ", np->name);
939122394Sharti
940122394Sharti	if (np->type == NODE_COLUMN) {
941122394Sharti		syntax = np->u.column.syntax;
942122394Sharti		fprintf(fp, "SNMP_NODE_COLUMN, ");
943122394Sharti	} else {
944122394Sharti		syntax = np->u.leaf.syntax;
945122394Sharti		fprintf(fp, "SNMP_NODE_LEAF, ");
946122394Sharti	}
947122394Sharti
948122394Sharti	switch (syntax) {
949122394Sharti
950122394Sharti	  case SNMP_SYNTAX_NULL:
951122394Sharti		fprintf(fp, "SNMP_SYNTAX_NULL, ");
952122394Sharti		break;
953122394Sharti
954122394Sharti	  case SNMP_SYNTAX_INTEGER:
955122394Sharti		fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
956122394Sharti		break;
957122394Sharti
958122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
959122394Sharti		fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
960122394Sharti		break;
961122394Sharti
962122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
963122394Sharti		fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
964122394Sharti		break;
965122394Sharti
966122394Sharti	  case SNMP_SYNTAX_OID:
967122394Sharti		fprintf(fp, "SNMP_SYNTAX_OID, ");
968122394Sharti		break;
969122394Sharti
970122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
971122394Sharti		fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
972122394Sharti		break;
973122394Sharti
974122394Sharti	  case SNMP_SYNTAX_COUNTER:
975122394Sharti		fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
976122394Sharti		break;
977122394Sharti
978122394Sharti	  case SNMP_SYNTAX_GAUGE:
979122394Sharti		fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
980122394Sharti		break;
981122394Sharti
982122394Sharti	  case SNMP_SYNTAX_COUNTER64:
983122394Sharti		fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
984122394Sharti		break;
985122394Sharti
986122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
987122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
988122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
989122394Sharti		abort();
990122394Sharti	}
991122394Sharti
992122394Sharti	if (np->type == NODE_COLUMN)
993122394Sharti		fprintf(fp, "%s, ", func);
994122394Sharti	else
995122394Sharti		fprintf(fp, "%s, ", np->u.leaf.func);
996122394Sharti
997122394Sharti	fprintf(fp, "0");
998122394Sharti	if (np->flags & FL_SET)
999122394Sharti		fprintf(fp, "|SNMP_NODE_CANSET");
1000128237Sharti	fprintf(fp, ", %#x, NULL, NULL },\n", idx);
1001122394Sharti	oid->len--;
1002122394Sharti	return;
1003122394Sharti}
1004122394Sharti
1005122394Sharti/*
1006122394Sharti * Generate the header file with the function declarations.
1007122394Sharti */
1008122394Shartistatic void
1009159063Shartigen_header(FILE *fp, struct node *np, u_int oidlen, const char *func)
1010122394Sharti{
1011122394Sharti	char f[MAXSTR + 4];
1012122394Sharti	struct node *sub;
1013122394Sharti	struct func *ptr;
1014122394Sharti
1015122394Sharti	oidlen++;
1016122394Sharti	if (np->type == NODE_TREE) {
1017122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1018159063Sharti			gen_header(fp, sub, oidlen, NULL);
1019122394Sharti		return;
1020122394Sharti	}
1021122394Sharti	if (np->type == NODE_ENTRY) {
1022122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1023159063Sharti			gen_header(fp, sub, oidlen, np->u.entry.func);
1024122394Sharti		return;
1025122394Sharti	}
1026122394Sharti
1027122394Sharti 	if((np->flags & (FL_GET|FL_SET)) == 0)
1028122394Sharti		return;
1029122394Sharti
1030142810Sharti	if (np->type == NODE_COLUMN) {
1031142810Sharti		if (func == NULL)
1032142810Sharti			errx(1, "column without function (%s) - probably "
1033142810Sharti			    "outside of a table", np->name);
1034122394Sharti		sprintf(f, "%s", func);
1035142810Sharti	} else
1036122394Sharti		sprintf(f, "%s", np->u.leaf.func);
1037122394Sharti
1038122394Sharti	LIST_FOREACH(ptr, &funcs, link)
1039122394Sharti		if (strcmp(ptr->name, f) == 0)
1040122394Sharti			break;
1041122394Sharti
1042122394Sharti	if (ptr == NULL) {
1043122394Sharti		ptr = xalloc(sizeof(*ptr));
1044159063Sharti		ptr->name = savestr(f);
1045122394Sharti		LIST_INSERT_HEAD(&funcs, ptr, link);
1046122394Sharti
1047122394Sharti		fprintf(fp, "int	%s(struct snmp_context *, "
1048122394Sharti		    "struct snmp_value *, u_int, u_int, "
1049122394Sharti		    "enum snmp_op);\n", f);
1050122394Sharti	}
1051122394Sharti
1052122394Sharti	fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
1053122394Sharti}
1054122394Sharti
1055122394Sharti/*
1056122394Sharti * Generate the OID table.
1057122394Sharti */
1058122394Shartistatic void
1059159063Shartigen_table(FILE *fp, struct node *node)
1060122394Sharti{
1061122394Sharti	struct asn_oid oid;
1062122394Sharti
1063122394Sharti	fprintf(fp, "#include <sys/types.h>\n");
1064122394Sharti	fprintf(fp, "#include <stdio.h>\n");
1065150920Sharti#ifdef HAVE_STDINT_H
1066133211Sharti	fprintf(fp, "#include <stdint.h>\n");
1067150920Sharti#endif
1068122394Sharti	if (localincs) {
1069122394Sharti		fprintf(fp, "#include \"asn1.h\"\n");
1070122394Sharti		fprintf(fp, "#include \"snmp.h\"\n");
1071122394Sharti		fprintf(fp, "#include \"snmpagent.h\"\n");
1072122394Sharti	} else {
1073122394Sharti		fprintf(fp, "#include <bsnmp/asn1.h>\n");
1074122394Sharti		fprintf(fp, "#include <bsnmp/snmp.h>\n");
1075122394Sharti		fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
1076122394Sharti	}
1077122394Sharti	fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
1078122394Sharti	fprintf(fp, "\n");
1079122394Sharti
1080122394Sharti	fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
1081122394Sharti
1082122394Sharti	oid.len = PREFIX_LEN;
1083122394Sharti	memcpy(oid.subs, prefix, sizeof(prefix));
1084159063Sharti	gen_node(fp, node, &oid, 0, NULL);
1085122394Sharti
1086122394Sharti	fprintf(fp, "};\n\n");
1087122394Sharti}
1088122394Sharti
1089133211Shartistatic void
1090133211Shartiprint_syntax(u_int syntax)
1091133211Sharti{
1092133211Sharti	u_int i;
1093133211Sharti
1094133211Sharti	for (i = 0; keywords[i].str != NULL; i++)
1095133211Sharti		if (keywords[i].tok == TOK_TYPE &&
1096133211Sharti		    keywords[i].val == syntax) {
1097133211Sharti			printf(" %s", keywords[i].str);
1098133211Sharti			return;
1099133211Sharti	}
1100133211Sharti	abort();
1101133211Sharti}
1102133211Sharti
1103133211Sharti/*
1104133211Sharti * Generate a tree definition file
1105133211Sharti */
1106133211Shartistatic void
1107133211Shartigen_tree(const struct node *np, int level)
1108133211Sharti{
1109133211Sharti	const struct node *sp;
1110133211Sharti	u_int i;
1111133211Sharti
1112133211Sharti	printf("%*s(%u %s", 2 * level, "", np->id, np->name);
1113133211Sharti
1114133211Sharti	switch (np->type) {
1115133211Sharti
1116133211Sharti	  case NODE_LEAF:
1117133211Sharti		print_syntax(np->u.leaf.syntax);
1118133211Sharti		printf(" %s%s%s)\n", np->u.leaf.func,
1119133211Sharti		    (np->flags & FL_GET) ? " GET" : "",
1120133211Sharti		    (np->flags & FL_SET) ? " SET" : "");
1121133211Sharti		break;
1122133211Sharti
1123133211Sharti	  case NODE_TREE:
1124133211Sharti		if (TAILQ_EMPTY(&np->u.tree.subs)) {
1125133211Sharti			printf(")\n");
1126133211Sharti		} else {
1127133211Sharti			printf("\n");
1128133211Sharti			TAILQ_FOREACH(sp, &np->u.tree.subs, link)
1129133211Sharti				gen_tree(sp, level + 1);
1130133211Sharti			printf("%*s)\n", 2 * level, "");
1131133211Sharti		}
1132133211Sharti		break;
1133133211Sharti
1134133211Sharti	  case NODE_ENTRY:
1135133211Sharti		printf(" :");
1136133211Sharti
1137133211Sharti		for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++)
1138133211Sharti			print_syntax(SNMP_INDEX(np->u.entry.index, i));
1139133211Sharti		printf(" %s\n", np->u.entry.func);
1140133211Sharti		TAILQ_FOREACH(sp, &np->u.entry.subs, link)
1141133211Sharti			gen_tree(sp, level + 1);
1142133211Sharti		printf("%*s)\n", 2 * level, "");
1143133211Sharti		break;
1144133211Sharti
1145133211Sharti	  case NODE_COLUMN:
1146133211Sharti		print_syntax(np->u.column.syntax);
1147133211Sharti		printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
1148133211Sharti		    (np->flags & FL_SET) ? " SET" : "");
1149133211Sharti		break;
1150133211Sharti	}
1151133211Sharti}
1152133211Sharti
1153122394Shartistatic int
1154159063Shartiextract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
1155133211Sharti    const struct asn_oid *idx, const char *iname)
1156122394Sharti{
1157122394Sharti	struct node *sub;
1158122394Sharti	u_long n;
1159122394Sharti
1160122394Sharti	if (oid->len == ASN_MAXOIDLEN)
1161122394Sharti		report_node(np, "OID too long");
1162122394Sharti	oid->subs[oid->len++] = np->id;
1163122394Sharti
1164122394Sharti	if (strcmp(obj, np->name) == 0) {
1165133211Sharti		if (oid->len + idx->len >= ASN_MAXOIDLEN)
1166133211Sharti			report_node(np, "OID too long");
1167133211Sharti		fprintf(fp, "#define OID_%s%s\t%u\n", np->name,
1168133211Sharti		    iname ? iname : "", np->id);
1169133211Sharti		fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name,
1170133211Sharti		    iname ? iname : "", oid->len + idx->len);
1171133211Sharti		fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name,
1172133211Sharti		    iname ? iname : "", oid->len + idx->len);
1173122394Sharti		for (n = 0; n < oid->len; n++)
1174122394Sharti			fprintf(fp, " %u,", oid->subs[n]);
1175133211Sharti		for (n = 0; n < idx->len; n++)
1176133211Sharti			fprintf(fp, " %u,", idx->subs[n]);
1177122394Sharti		fprintf(fp, " } }\n");
1178122394Sharti		return (0);
1179122394Sharti	}
1180122394Sharti
1181122394Sharti	if (np->type == NODE_TREE) {
1182122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1183159063Sharti			if (!extract(fp, sub, oid, obj, idx, iname))
1184122394Sharti				return (0);
1185122394Sharti	} else if (np->type == NODE_ENTRY) {
1186122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1187159063Sharti			if (!extract(fp, sub, oid, obj, idx, iname))
1188122394Sharti				return (0);
1189122394Sharti	}
1190122394Sharti	oid->len--;
1191122394Sharti	return (1);
1192122394Sharti}
1193122394Sharti
1194122394Shartistatic int
1195159063Shartigen_extract(FILE *fp, const struct node *root, char *object)
1196122394Sharti{
1197122394Sharti	struct asn_oid oid;
1198133211Sharti	struct asn_oid idx;
1199133211Sharti	char *s, *e, *end, *iname;
1200133211Sharti	u_long ul;
1201133211Sharti	int ret;
1202122394Sharti
1203133211Sharti	/* look whether the object to extract has an index part */
1204133211Sharti	idx.len = 0;
1205133211Sharti	iname = NULL;
1206133211Sharti	s = strchr(object, '.');
1207133211Sharti	if (s != NULL) {
1208133211Sharti		iname = malloc(strlen(s) + 1);
1209133211Sharti		if (iname == NULL)
1210133211Sharti			err(1, "cannot allocated index");
1211133211Sharti
1212133211Sharti		strcpy(iname, s);
1213133211Sharti		for (e = iname; *e != '\0'; e++)
1214133211Sharti			if (*e == '.')
1215133211Sharti				*e = '_';
1216133211Sharti
1217133211Sharti		*s++ = '\0';
1218133211Sharti		while (s != NULL) {
1219133211Sharti			if (*s == '\0')
1220133211Sharti				errx(1, "bad index syntax");
1221133211Sharti			if ((e = strchr(s, '.')) != NULL)
1222133211Sharti				*e++ = '\0';
1223133211Sharti
1224133211Sharti			errno = 0;
1225133211Sharti			ul = strtoul(s, &end, 0);
1226133211Sharti			if (*end != '\0')
1227133211Sharti				errx(1, "bad index syntax '%s'", end);
1228133211Sharti			if (errno != 0)
1229133211Sharti				err(1, "bad index syntax");
1230133211Sharti
1231133211Sharti			if (idx.len == ASN_MAXOIDLEN)
1232133211Sharti				errx(1, "index oid too large");
1233133211Sharti			idx.subs[idx.len++] = ul;
1234133211Sharti
1235133211Sharti			s = e;
1236133211Sharti		}
1237133211Sharti	}
1238133211Sharti
1239122394Sharti	oid.len = PREFIX_LEN;
1240122394Sharti	memcpy(oid.subs, prefix, sizeof(prefix));
1241159063Sharti	ret = extract(fp, root, &oid, object, &idx, iname);
1242133211Sharti	if (iname != NULL)
1243133211Sharti		free(iname);
1244133211Sharti
1245133211Sharti	return (ret);
1246122394Sharti}
1247122394Sharti
1248122394Sharti
1249122394Shartistatic void
1250122394Sharticheck_sub_order(const struct node *np, const struct node_list *subs)
1251122394Sharti{
1252122394Sharti	int first;
1253122394Sharti	const struct node *sub;
1254122394Sharti	asn_subid_t maxid = 0;
1255122394Sharti
1256122394Sharti	/* ensure, that subids are ordered */
1257122394Sharti	first = 1;
1258122394Sharti	TAILQ_FOREACH(sub, subs, link) {
1259122394Sharti		if (!first && sub->id <= maxid)
1260122394Sharti			report_node(np, "subids not ordered at %s", sub->name);
1261122394Sharti		maxid = sub->id;
1262122394Sharti		first = 0;
1263122394Sharti	}
1264122394Sharti}
1265122394Sharti
1266122394Sharti/*
1267122394Sharti * Do some sanity checks on the tree definition and do some computations.
1268122394Sharti */
1269122394Shartistatic void
1270122394Sharticheck_tree(struct node *np)
1271122394Sharti{
1272122394Sharti	struct node *sub;
1273122394Sharti
1274122394Sharti	if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
1275122394Sharti		if ((np->flags & (FL_GET|FL_SET)) != 0)
1276122394Sharti			tree_size++;
1277122394Sharti		return;
1278122394Sharti	}
1279122394Sharti
1280122394Sharti	if (np->type == NODE_ENTRY) {
1281122394Sharti		check_sub_order(np, &np->u.entry.subs);
1282122394Sharti
1283122394Sharti		/* ensure all subnodes are columns */
1284122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
1285122394Sharti			if (sub->type != NODE_COLUMN)
1286122394Sharti				report_node(np, "entry subnode '%s' is not "
1287122394Sharti				    "a column", sub->name);
1288122394Sharti			check_tree(sub);
1289122394Sharti		}
1290122394Sharti	} else {
1291122394Sharti		check_sub_order(np, &np->u.tree.subs);
1292122394Sharti
1293122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1294122394Sharti			check_tree(sub);
1295122394Sharti	}
1296122394Sharti}
1297122394Sharti
1298133211Shartistatic void
1299133211Shartimerge_subs(struct node_list *s1, struct node_list *s2)
1300133211Sharti{
1301133211Sharti	struct node *n1, *n2;
1302133211Sharti
1303133211Sharti	while (!TAILQ_EMPTY(s2)) {
1304133211Sharti		n2 = TAILQ_FIRST(s2);
1305133211Sharti		TAILQ_REMOVE(s2, n2, link);
1306133211Sharti
1307133211Sharti		TAILQ_FOREACH(n1, s1, link)
1308133211Sharti			if (n1->id >= n2->id)
1309133211Sharti				break;
1310133211Sharti		if (n1 == NULL)
1311133211Sharti			TAILQ_INSERT_TAIL(s1, n2, link);
1312133211Sharti		else if (n1->id > n2->id)
1313133211Sharti			TAILQ_INSERT_BEFORE(n1, n2, link);
1314133211Sharti		else {
1315133211Sharti			if (n1->type == NODE_TREE && n2->type == NODE_TREE) {
1316133211Sharti				if (strcmp(n1->name, n2->name) != 0)
1317133211Sharti					errx(1, "trees to merge must have "
1318133211Sharti					    "same name '%s' '%s'", n1->name,
1319133211Sharti					    n2->name);
1320133211Sharti				merge_subs(&n1->u.tree.subs, &n2->u.tree.subs);
1321133211Sharti				free(n2);
1322133211Sharti			} else if (n1->type == NODE_ENTRY &&
1323133211Sharti			    n2->type == NODE_ENTRY) {
1324133211Sharti				if (strcmp(n1->name, n2->name) != 0)
1325133211Sharti					errx(1, "entries to merge must have "
1326133211Sharti					    "same name '%s' '%s'", n1->name,
1327133211Sharti					    n2->name);
1328133211Sharti				if (n1->u.entry.index != n2->u.entry.index)
1329133211Sharti					errx(1, "entries to merge must have "
1330133211Sharti					    "same index '%s'", n1->name);
1331133211Sharti				if (strcmp(n1->u.entry.func,
1332133211Sharti				    n2->u.entry.func) != 0)
1333133211Sharti					errx(1, "entries to merge must have "
1334133211Sharti					    "same op '%s'", n1->name);
1335133211Sharti				merge_subs(&n1->u.entry.subs,
1336133211Sharti				    &n2->u.entry.subs);
1337133211Sharti				free(n2);
1338133211Sharti			} else
1339133211Sharti				errx(1, "entities to merge must be both "
1340133211Sharti				    "trees or both entries: %s, %s",
1341133211Sharti				    n1->name, n2->name);
1342133211Sharti		}
1343133211Sharti	}
1344133211Sharti}
1345133211Sharti
1346133211Shartistatic void
1347159063Shartimerge(struct node **root, struct node *t)
1348133211Sharti{
1349133211Sharti
1350159063Sharti	if (*root == NULL) {
1351159063Sharti		*root = t;
1352159063Sharti		return;
1353159063Sharti	}
1354159063Sharti	if (t == NULL)
1355159063Sharti		return;
1356159063Sharti
1357133211Sharti	/* both must be trees */
1358159063Sharti	if ((*root)->type != NODE_TREE)
1359133211Sharti		errx(1, "root is not a tree");
1360133211Sharti	if (t->type != NODE_TREE)
1361133211Sharti		errx(1, "can merge only with tree");
1362159063Sharti	if ((*root)->id != t->id)
1363133211Sharti		errx(1, "trees to merge must have same id");
1364133211Sharti
1365159063Sharti	merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs);
1366133211Sharti}
1367133211Sharti
1368159063Shartistatic void
1369159063Shartiunminus(FILE *fp, const char *s)
1370159063Sharti{
1371159063Sharti
1372159063Sharti	while (*s != '\0') {
1373159063Sharti		if (*s == '-')
1374159063Sharti			fprintf(fp, "_");
1375159063Sharti		else
1376159063Sharti			fprintf(fp, "%c", *s);
1377159063Sharti		s++;
1378159063Sharti	}
1379159063Sharti}
1380159063Sharti
1381159063Shartistatic void
1382159063Shartigen_enum(FILE *fp, const struct type *t)
1383159063Sharti{
1384159063Sharti	const struct enums *e;
1385159063Sharti	long min = LONG_MAX;
1386159063Sharti
1387159063Sharti	fprintf(fp, "\n");
1388159063Sharti	fprintf(fp, "#ifndef %s_defined__\n", t->name);
1389159063Sharti	fprintf(fp, "#define %s_defined__\n", t->name);
1390159063Sharti	fprintf(fp, "/*\n");
1391159063Sharti	fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
1392159063Sharti	fprintf(fp, " */\n");
1393159063Sharti	fprintf(fp, "enum %s {\n", t->name);
1394159063Sharti	TAILQ_FOREACH(e, &t->enums, link) {
1395159063Sharti		fprintf(fp, "\t%s_", t->name);
1396159063Sharti		unminus(fp, e->name);
1397159063Sharti		fprintf(fp, " = %ld,\n", e->value);
1398159063Sharti		if (e->value < min)
1399159063Sharti			min = e->value;
1400159063Sharti	}
1401159063Sharti	fprintf(fp, "};\n");
1402159063Sharti	fprintf(fp, "#define	STROFF_%s %ld\n", t->name, min);
1403159063Sharti	fprintf(fp, "#define	STRING_%s \\\n", t->name);
1404159063Sharti	TAILQ_FOREACH(e, &t->enums, link) {
1405159063Sharti		fprintf(fp, "\t[%ld] \"%s_", e->value - min, t->name);
1406159063Sharti		unminus(fp, e->name);
1407159063Sharti		fprintf(fp, "\",\\\n");
1408159063Sharti	}
1409159063Sharti	fprintf(fp, "\n");
1410159063Sharti	fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
1411159063Sharti}
1412159063Sharti
1413159063Shartistatic void
1414159063Shartigen_enums(FILE *fp)
1415159063Sharti{
1416159063Sharti	const struct type *t;
1417159063Sharti
1418159063Sharti	LIST_FOREACH(t, &types, link)
1419159063Sharti		if (t->is_enum || t->is_bits)
1420159063Sharti			gen_enum(fp, t);
1421159063Sharti}
1422159063Sharti
1423159063Shartistatic int
1424159063Shartiextract_enum(FILE *fp, const char *name)
1425159063Sharti{
1426159063Sharti	const struct type *t;
1427159063Sharti
1428159063Sharti	LIST_FOREACH(t, &types, link)
1429159063Sharti		if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
1430159063Sharti			gen_enum(fp, t);
1431159063Sharti			return (0);
1432159063Sharti		}
1433159063Sharti	return (-1);
1434159063Sharti}
1435159063Sharti
1436122394Shartiint
1437122394Shartimain(int argc, char *argv[])
1438122394Sharti{
1439122394Sharti	int do_extract = 0;
1440133211Sharti	int do_tree = 0;
1441159063Sharti	int do_enums = 0;
1442122394Sharti	int opt;
1443122394Sharti	struct node *root;
1444122394Sharti	char fname[MAXPATHLEN + 1];
1445133211Sharti	int tok;
1446159063Sharti	FILE *fp;
1447159063Sharti	char *infile = NULL;
1448122394Sharti
1449159063Sharti	while ((opt = getopt(argc, argv, "dEehI:i:lp:t")) != EOF)
1450122394Sharti		switch (opt) {
1451122394Sharti
1452159063Sharti		  case 'd':
1453159063Sharti			debug = 1;
1454159063Sharti			break;
1455159063Sharti
1456122394Sharti		  case 'h':
1457122394Sharti			fprintf(stderr, "%s", usgtxt);
1458122394Sharti			exit(0);
1459122394Sharti
1460159063Sharti		  case 'E':
1461159063Sharti			do_enums = 1;
1462159063Sharti			break;
1463159063Sharti
1464122394Sharti		  case 'e':
1465122394Sharti			do_extract = 1;
1466122394Sharti			break;
1467122394Sharti
1468159063Sharti		  case 'I':
1469159063Sharti			path_new(optarg);
1470159063Sharti			break;
1471159063Sharti
1472159063Sharti		  case 'i':
1473159063Sharti			infile = optarg;
1474159063Sharti			break;
1475159063Sharti
1476122394Sharti		  case 'l':
1477122394Sharti			localincs = 1;
1478122394Sharti			break;
1479122394Sharti
1480122394Sharti		  case 'p':
1481122394Sharti			file_prefix = optarg;
1482122394Sharti			if (strlen(file_prefix) + strlen("tree.c") >
1483122394Sharti			    MAXPATHLEN)
1484122394Sharti				errx(1, "prefix too long");
1485122394Sharti			break;
1486133211Sharti
1487133211Sharti		  case 't':
1488133211Sharti			do_tree = 1;
1489133211Sharti			break;
1490122394Sharti		}
1491122394Sharti
1492159063Sharti	if (do_extract + do_tree + do_enums > 1)
1493159063Sharti		errx(1, "conflicting options -e/-t/-E");
1494159063Sharti	if (!do_extract && !do_enums && argc != optind)
1495122394Sharti		errx(1, "no arguments allowed");
1496159063Sharti	if ((do_extract || do_enums) && argc == optind)
1497122394Sharti		errx(1, "no objects specified");
1498122394Sharti
1499159063Sharti	if (infile == NULL) {
1500159063Sharti		input_new(stdin, NULL, "<stdin>");
1501159063Sharti	} else {
1502159063Sharti		if ((fp = fopen(infile, "r")) == NULL)
1503159063Sharti			err(1, "%s", infile);
1504159063Sharti		input_new(fp, NULL, infile);
1505159063Sharti	}
1506159063Sharti
1507159063Sharti	root = parse_top(gettoken());
1508133211Sharti	while ((tok = gettoken()) != TOK_EOF)
1509159063Sharti		merge(&root, parse_top(tok));
1510122394Sharti
1511122394Sharti	check_tree(root);
1512122394Sharti
1513122394Sharti	if (do_extract) {
1514122394Sharti		while (optind < argc) {
1515159063Sharti			if (gen_extract(stdout, root, argv[optind]))
1516122394Sharti				errx(1, "object not found: %s", argv[optind]);
1517122394Sharti			optind++;
1518122394Sharti		}
1519122394Sharti		return (0);
1520122394Sharti	}
1521159063Sharti	if (do_enums) {
1522159063Sharti		while (optind < argc) {
1523159063Sharti			if (extract_enum(stdout, argv[optind]))
1524159063Sharti				errx(1, "enum not found: %s", argv[optind]);
1525159063Sharti			optind++;
1526159063Sharti		}
1527159063Sharti		return (0);
1528159063Sharti	}
1529133211Sharti	if (do_tree) {
1530133211Sharti		gen_tree(root, 0);
1531133211Sharti		return (0);
1532133211Sharti	}
1533122394Sharti	sprintf(fname, "%stree.h", file_prefix);
1534122394Sharti	if ((fp = fopen(fname, "w")) == NULL)
1535122394Sharti		err(1, "%s: ", fname);
1536159063Sharti	gen_header(fp, root, PREFIX_LEN, NULL);
1537122394Sharti
1538159063Sharti	fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
1539159063Sharti	gen_enums(fp);
1540159063Sharti	fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
1541159063Sharti
1542122394Sharti	fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
1543122394Sharti	fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
1544122394Sharti
1545122394Sharti	fclose(fp);
1546122394Sharti
1547122394Sharti	sprintf(fname, "%stree.c", file_prefix);
1548122394Sharti	if ((fp = fopen(fname, "w")) == NULL)
1549122394Sharti		err(1, "%s: ", fname);
1550159063Sharti	gen_table(fp, root);
1551122394Sharti	fclose(fp);
1552122394Sharti
1553122394Sharti	return (0);
1554122394Sharti}
1555