PageRenderTime 243ms CodeModel.GetById 137ms app.highlight 95ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/bsnmp/gensnmptree/gensnmptree.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1556 lines | 1379 code | 61 blank | 116 comment | 58 complexity | cae68a9a5ad50ce71c9b3b669f8641ee MD5 | raw file
   1/*
   2 * Copyright (c) 2001-2003
   3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
   4 *	All rights reserved.
   5 *
   6 * Copyright (c) 2004-2006
   7 *	Hartmut Brandt.
   8 *	All rights reserved.
   9 *
  10 * Author: Harti Brandt <harti@freebsd.org>
  11 * 
  12 * Redistribution and use in source and binary forms, with or without
  13 * modification, are permitted provided that the following conditions
  14 * are met:
  15 * 1. Redistributions of source code must retain the above copyright
  16 *    notice, this list of conditions and the following disclaimer.
  17 * 2. Redistributions in binary form must reproduce the above copyright
  18 *    notice, this list of conditions and the following disclaimer in the
  19 *    documentation and/or other materials provided with the distribution.
  20 * 
  21 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31 * SUCH DAMAGE.
  32 *
  33 * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $
  34 *
  35 * Generate OID table from table description.
  36 *
  37 * Syntax is:
  38 * ---------
  39 * file := top | top file
  40 *
  41 * top := tree | typedef | include
  42 *
  43 * tree := head elements ')'
  44 *
  45 * entry := head ':' index STRING elements ')'
  46 *
  47 * leaf := head type STRING ACCESS ')'
  48 *
  49 * column := head type ACCESS ')'
  50 *
  51 * type := BASETYPE | BASETYPE '|' subtype | enum | bits
  52 *
  53 * subtype := STRING
  54 *
  55 * enum := ENUM '(' value ')'
  56 *
  57 * bits := BITS '(' value ')'
  58 *
  59 * value := optminus INT STRING | optminus INT STRING value
  60 *
  61 * optminus := '-' | EMPTY
  62 *
  63 * head := '(' INT STRING
  64 *
  65 * elements := EMPTY | elements element
  66 *
  67 * element := tree | leaf | column
  68 *
  69 * index := type | index type
  70 *
  71 * typedef := 'typedef' STRING type
  72 *
  73 * include := 'include' filespec
  74 *
  75 * filespec := '"' STRING '"' | '<' STRING '>'
  76 */
  77#include <sys/types.h>
  78#include <sys/param.h>
  79#include <stdio.h>
  80#include <stdlib.h>
  81#include <stdarg.h>
  82#include <unistd.h>
  83#include <string.h>
  84#include <ctype.h>
  85#include <inttypes.h>
  86#include <errno.h>
  87#ifdef HAVE_ERR_H
  88#include <err.h>
  89#endif
  90#include <sys/queue.h>
  91#include "support.h"
  92#include "asn1.h"
  93#include "snmp.h"
  94#include "snmpagent.h"
  95
  96/*
  97 * Constant prefix for all OIDs
  98 */
  99static const asn_subid_t prefix[] = { 1, 3, 6 };
 100#define	PREFIX_LEN	(sizeof(prefix) / sizeof(prefix[0]))
 101
 102u_int tree_size;
 103static const char *file_prefix = "";
 104
 105/* if true generate local include paths */
 106static int localincs = 0;
 107
 108/* if true print tokens */
 109static int debug;
 110
 111static const char usgtxt[] = "\
 112Generate SNMP tables.\n\
 113usage: gensnmptree [-dEehlt] [-I directory] [-i infile] [-p prefix]\n\
 114	    [name]...\n\
 115options:\n\
 116  -d		debug mode\n\
 117  -E		extract the named enums and bits only\n\
 118  -e		extract the named oids or enums\n\
 119  -h		print this info\n\
 120  -I directory	add directory to include path\n\
 121  -i ifile	read from the named file instead of stdin\n\
 122  -l		generate local include directives\n\
 123  -p prefix	prepend prefix to file and variable names\n\
 124  -t		generated a .def file\n\
 125";
 126
 127/*
 128 * A node in the OID tree
 129 */
 130enum ntype {
 131	NODE_LEAF = 1,
 132	NODE_TREE,
 133	NODE_ENTRY,
 134	NODE_COLUMN
 135};
 136
 137enum {
 138	FL_GET	= 0x01,
 139	FL_SET	= 0x02,
 140};
 141
 142struct node;
 143TAILQ_HEAD(node_list, node);
 144
 145struct node {
 146	enum ntype	type;
 147	asn_subid_t	id;	/* last element of OID */
 148	char		*name;	/* name of node */
 149	TAILQ_ENTRY(node) link;
 150	u_int		lno;	/* starting line number */
 151	u_int		flags;	/* allowed operations */
 152
 153	union {
 154	  struct tree {
 155	    struct node_list subs;
 156	  }		tree;
 157
 158	  struct entry {
 159	    uint32_t	index;	/* index for table entry */
 160	    char	*func;	/* function for tables */
 161	    struct node_list subs;
 162	  }		entry;
 163
 164	  struct leaf {
 165	    enum snmp_syntax syntax;	/* syntax for this leaf */
 166	    char	*func;		/* function name */
 167	  }		leaf;
 168
 169	  struct column {
 170	    enum snmp_syntax syntax;	/* syntax for this column */
 171	  }		column;
 172	}		u;
 173};
 174
 175struct func {
 176	const char	*name;
 177	LIST_ENTRY(func) link;
 178};
 179
 180static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs);
 181
 182struct enums {
 183	const char	*name;
 184	long		value;
 185	TAILQ_ENTRY(enums) link;
 186};
 187
 188struct type {
 189	const char	*name;
 190	const char	*from_fname;
 191	u_int		from_lno;
 192	u_int		syntax;
 193	int		is_enum;
 194	int		is_bits;
 195	TAILQ_HEAD(, enums) enums;
 196	LIST_ENTRY(type) link;
 197};
 198
 199static LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types);
 200
 201static void report(const char *, ...) __dead2 __printflike(1, 2);
 202static void report_node(const struct node *, const char *, ...)
 203    __dead2 __printflike(2, 3);
 204
 205/************************************************************
 206 *
 207 * Allocate memory and panic just in the case...
 208 */
 209static void *
 210xalloc(size_t size)
 211{
 212	void *ptr;
 213
 214	if ((ptr = malloc(size)) == NULL)
 215		err(1, "allocing %zu bytes", size);
 216
 217	return (ptr);
 218}
 219
 220static char *
 221savestr(const char *s)
 222{
 223
 224	if (s == NULL)
 225		return (NULL);
 226	return (strcpy(xalloc(strlen(s) + 1), s));
 227}
 228
 229/************************************************************
 230 *
 231 * Input stack
 232 */
 233struct input {
 234	FILE		*fp;
 235	u_int		lno;
 236	char		*fname;
 237	char		*path;
 238	LIST_ENTRY(input) link;
 239};
 240static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
 241static struct input *input = NULL;
 242
 243#define MAX_PATHS	100
 244static u_int npaths = 2;
 245static u_int stdpaths = 2;
 246static const char *paths[MAX_PATHS + 1] = {
 247	"/usr/share/snmp/defs",
 248	"/usr/local/share/snmp/defs",
 249	NULL
 250};
 251
 252static int pbchar = -1;
 253
 254static void
 255path_new(const char *path)
 256{
 257	if (npaths >= MAX_PATHS)
 258		report("too many -I directives");
 259	memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths],
 260	    sizeof(path[0]) * stdpaths);
 261	paths[npaths - stdpaths] = savestr(path);
 262	npaths++;
 263}
 264
 265static void
 266input_new(FILE *fp, const char *path, const char *fname)
 267{
 268	struct input *ip;
 269
 270	ip = xalloc(sizeof(*ip));
 271	ip->fp = fp;
 272	ip->lno = 1;
 273	ip->fname = savestr(fname);
 274	ip->path = savestr(path);
 275	LIST_INSERT_HEAD(&inputs, ip, link);
 276
 277	input = ip;
 278}
 279
 280static void
 281input_close(void)
 282{
 283
 284	if (input == NULL)
 285		return;
 286	fclose(input->fp);
 287	free(input->fname);
 288	free(input->path);
 289	LIST_REMOVE(input, link);
 290	free(input);
 291
 292	input = LIST_FIRST(&inputs);
 293}
 294
 295static FILE *
 296tryopen(const char *path, const char *fname)
 297{
 298	char *fn;
 299	FILE *fp;
 300
 301	if (path == NULL)
 302		fn = savestr(fname);
 303	else {
 304		fn = xalloc(strlen(path) + strlen(fname) + 2);
 305		sprintf(fn, "%s/%s", path, fname);
 306	}
 307	fp = fopen(fn, "r");
 308	free(fn);
 309	return (fp);
 310}
 311
 312static void
 313input_fopen(const char *fname, int loc)
 314{
 315	FILE *fp;
 316	char *path;
 317	u_int p;
 318
 319	if (fname[0] == '/') {
 320		if ((fp = tryopen(NULL, fname)) != NULL) {
 321			input_new(fp, NULL, fname);
 322			return;
 323		}
 324
 325	} else {
 326		if (loc) {
 327			if (input == NULL)
 328				path = NULL;
 329			else
 330				path = input->path;
 331
 332			if ((fp = tryopen(path, fname)) != NULL) {
 333				input_new(fp, NULL, fname);
 334				return;
 335			}
 336		}
 337
 338		for (p = 0; paths[p] != NULL; p++)
 339			if ((fp = tryopen(paths[p], fname)) != NULL) {
 340				input_new(fp, paths[p], fname);
 341				return;
 342			}
 343	}
 344	report("cannot open '%s'", fname);
 345}
 346
 347static int
 348tgetc(void)
 349{
 350	int c;
 351
 352	if (pbchar != -1) {
 353		c = pbchar;
 354		pbchar = -1;
 355		return (c);
 356	}
 357
 358	for (;;) {
 359		if (input == NULL)
 360			return (EOF);
 361
 362		if ((c = getc(input->fp)) != EOF)
 363			return (c);
 364
 365		input_close();
 366	}
 367}
 368
 369static void
 370tungetc(int c)
 371{
 372
 373	if (pbchar != -1)
 374		abort();
 375	pbchar = c;
 376}
 377
 378/************************************************************
 379 *
 380 * Parsing input
 381 */
 382enum tok {
 383	TOK_EOF = 0200,	/* end-of-file seen */
 384	TOK_NUM,	/* number */
 385	TOK_STR,	/* string */
 386	TOK_ACCESS,	/* access operator */
 387	TOK_TYPE,	/* type operator */
 388	TOK_ENUM,	/* enum token (kind of a type) */
 389	TOK_TYPEDEF,	/* typedef directive */
 390	TOK_DEFTYPE,	/* defined type */
 391	TOK_INCLUDE,	/* include directive */
 392	TOK_FILENAME,	/* filename ("foo.bar" or <foo.bar>) */
 393	TOK_BITS,	/* bits token (kind of a type) */
 394};
 395
 396static const struct {
 397	const char *str;
 398	enum tok tok;
 399	u_int val;
 400} keywords[] = {
 401	{ "GET", TOK_ACCESS, FL_GET },
 402	{ "SET", TOK_ACCESS, FL_SET },
 403	{ "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
 404	{ "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
 405	{ "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
 406	{ "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
 407	{ "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
 408	{ "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
 409	{ "OID", TOK_TYPE, SNMP_SYNTAX_OID },
 410	{ "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
 411	{ "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
 412	{ "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
 413	{ "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
 414	{ "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
 415	{ "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
 416	{ "typedef", TOK_TYPEDEF, 0 },
 417	{ "include", TOK_INCLUDE, 0 },
 418	{ NULL, 0, 0 }
 419};
 420
 421/* arbitrary upper limit on node names and function names */
 422#define	MAXSTR	1000
 423char	str[MAXSTR];
 424u_long	val;		/* integer values */
 425int	all_cond;	/* all conditions are true */
 426int	saved_token = -1;
 427
 428/*
 429 * Report an error and exit.
 430 */
 431static void
 432report(const char *fmt, ...)
 433{
 434	va_list ap;
 435	int c;
 436
 437	va_start(ap, fmt);
 438	fprintf(stderr, "line %u: ", input->lno);
 439	vfprintf(stderr, fmt, ap);
 440	fprintf(stderr, "\n");
 441	fprintf(stderr, "context: \"");
 442	while ((c = tgetc()) != EOF && c != '\n')
 443		fprintf(stderr, "%c", c);
 444	fprintf(stderr, "\n");
 445	va_end(ap);
 446	exit(1);
 447}
 448static void
 449report_node(const struct node *np, const char *fmt, ...)
 450{
 451	va_list ap;
 452
 453	va_start(ap, fmt);
 454	fprintf(stderr, "line %u, node %s: ", np->lno, np->name);
 455	vfprintf(stderr, fmt, ap);
 456	fprintf(stderr, "\n");
 457	va_end(ap);
 458	exit(1);
 459}
 460
 461/*
 462 * Return a fresh copy of the string constituting the current token.
 463 */
 464static char *
 465savetok(void)
 466{
 467	return (savestr(str));
 468}
 469
 470/*
 471 * Get the next token from input.
 472 */
 473static int
 474gettoken_internal(void)
 475{
 476	int c;
 477	struct type *t;
 478
 479	if (saved_token != -1) {
 480		c = saved_token;
 481		saved_token = -1;
 482		return (c);
 483	}
 484
 485  again:
 486	/*
 487	 * Skip any whitespace before the next token
 488	 */
 489	while ((c = tgetc()) != EOF) {
 490		if (c == '\n')
 491			input->lno++;
 492		if (!isspace(c))
 493			break;
 494	}
 495	if (c == EOF)
 496		return (TOK_EOF);
 497	if (!isascii(c))
 498		report("unexpected character %#2x", (u_int)c);
 499
 500	/*
 501	 * Skip comments
 502	 */
 503	if (c == '#') {
 504		while ((c = tgetc()) != EOF) {
 505			if (c == '\n') {
 506				input->lno++;
 507				goto again;
 508			}
 509		}
 510		report("unexpected EOF in comment");
 511	}
 512
 513	/*
 514	 * Single character tokens
 515	 */
 516	if (strchr("():|-", c) != NULL)
 517		return (c);
 518
 519	if (c == '"' || c == '<') {
 520		int end = c;
 521		size_t n = 0;
 522
 523		val = 1;
 524		if (c == '<') {
 525			val = 0;
 526			end = '>';
 527		}
 528
 529		while ((c = tgetc()) != EOF) {
 530			if (c == end)
 531				break;
 532			if (n == sizeof(str) - 1) {
 533				str[n++] = '\0';
 534				report("filename too long '%s...'", str);
 535			}
 536			str[n++] = c;
 537		}
 538		str[n++] = '\0';
 539		return (TOK_FILENAME);
 540	}
 541
 542	/*
 543	 * Sort out numbers
 544	 */
 545	if (isdigit(c)) {
 546		size_t n = 0;
 547		str[n++] = c;
 548		while ((c = tgetc()) != EOF) {
 549			if (!isdigit(c)) {
 550				tungetc(c);
 551				break;
 552			}
 553			if (n == sizeof(str) - 1) {
 554				str[n++] = '\0';
 555				report("number too long '%s...'", str);
 556			}
 557			str[n++] = c;
 558		}
 559		str[n++] = '\0';
 560		sscanf(str, "%lu", &val);
 561		return (TOK_NUM);
 562	}
 563
 564	/*
 565	 * So that has to be a string.
 566	 */
 567	if (isalpha(c) || c == '_') {
 568		size_t n = 0;
 569		str[n++] = c;
 570		while ((c = tgetc()) != EOF) {
 571			if (!isalnum(c) && c != '_' && c != '-') {
 572				tungetc(c);
 573				break;
 574			}
 575			if (n == sizeof(str) - 1) {
 576				str[n++] = '\0';
 577				report("string too long '%s...'", str);
 578			}
 579			str[n++] = c;
 580		}
 581		str[n++] = '\0';
 582
 583		/*
 584		 * Keywords
 585		 */
 586		for (c = 0; keywords[c].str != NULL; c++)
 587			if (strcmp(keywords[c].str, str) == 0) {
 588				val = keywords[c].val;
 589				return (keywords[c].tok);
 590			}
 591
 592		LIST_FOREACH(t, &types, link) {
 593			if (strcmp(t->name, str) == 0) {
 594				val = t->syntax;
 595				return (TOK_DEFTYPE);
 596			}
 597		}
 598		return (TOK_STR);
 599	}
 600	if (isprint(c))
 601		errx(1, "%u: unexpected character '%c'", input->lno, c);
 602	else
 603		errx(1, "%u: unexpected character 0x%02x", input->lno,
 604		    (u_int)c);
 605}
 606static int
 607gettoken(void)
 608{
 609	int tok = gettoken_internal();
 610
 611	if (debug) {
 612		switch (tok) {
 613
 614		  case TOK_EOF:
 615			fprintf(stderr, "EOF ");
 616			break;
 617
 618		  case TOK_NUM:
 619			fprintf(stderr, "NUM(%lu) ", val);
 620			break;
 621
 622		  case TOK_STR:
 623			fprintf(stderr, "STR(%s) ", str);
 624			break;
 625
 626		  case TOK_ACCESS:
 627			fprintf(stderr, "ACCESS(%lu) ", val);
 628			break;
 629
 630		  case TOK_TYPE:
 631			fprintf(stderr, "TYPE(%lu) ", val);
 632			break;
 633
 634		  case TOK_ENUM:
 635			fprintf(stderr, "ENUM ");
 636			break;
 637
 638		  case TOK_BITS:
 639			fprintf(stderr, "BITS ");
 640			break;
 641
 642		  case TOK_TYPEDEF:
 643			fprintf(stderr, "TYPEDEF ");
 644			break;
 645
 646		  case TOK_DEFTYPE:
 647			fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val);
 648			break;
 649
 650		  case TOK_INCLUDE:
 651			fprintf(stderr, "INCLUDE ");
 652			break;
 653
 654		  case TOK_FILENAME:
 655			fprintf(stderr, "FILENAME ");
 656			break;
 657
 658		  default:
 659			if (tok < TOK_EOF) {
 660				if (isprint(tok))
 661					fprintf(stderr, "'%c' ", tok);
 662				else if (tok == '\n')
 663					fprintf(stderr, "\n");
 664				else
 665					fprintf(stderr, "%02x ", tok);
 666			} else
 667				abort();
 668			break;
 669		}
 670	}
 671	return (tok);
 672}
 673
 674/**
 675 * Pushback a token
 676 */
 677static void
 678pushback(enum tok tok)
 679{
 680
 681	if (saved_token != -1)
 682		abort();
 683	saved_token = tok;
 684}
 685
 686/*
 687 * Create a new type
 688 */
 689static struct type *
 690make_type(const char *s)
 691{
 692	struct type *t;
 693
 694	t = xalloc(sizeof(*t));
 695	t->name = savestr(s);
 696	t->is_enum = 0;
 697	t->syntax = SNMP_SYNTAX_NULL;
 698	t->from_fname = savestr(input->fname);
 699	t->from_lno = input->lno;
 700	TAILQ_INIT(&t->enums);
 701	LIST_INSERT_HEAD(&types, t, link);
 702
 703	return (t);
 704}
 705
 706/*
 707 * Parse a type. We've seen the ENUM or type keyword already. Leave next
 708 * token.
 709 */
 710static u_int
 711parse_type(enum tok *tok, struct type *t, const char *vname)
 712{
 713	u_int syntax;
 714	struct enums *e;
 715
 716	syntax = val;
 717
 718	if (*tok == TOK_ENUM || *tok == TOK_BITS) {
 719		if (t == NULL && vname != NULL) {
 720			t = make_type(vname);
 721			t->is_enum = (*tok == TOK_ENUM);
 722			t->is_bits = (*tok == TOK_BITS);
 723			t->syntax = syntax;
 724		}
 725		if (gettoken() != '(')
 726			report("'(' expected after ENUM");
 727
 728		if ((*tok = gettoken()) == TOK_EOF)
 729			report("unexpected EOF in ENUM");
 730		do {
 731			e = NULL;
 732			if (t != NULL) {
 733				e = xalloc(sizeof(*e));
 734			}
 735			if (*tok == '-') {
 736				if ((*tok = gettoken()) == TOK_EOF)
 737					report("unexpected EOF in ENUM");
 738				e->value = -(long)val;
 739			} else
 740				e->value = val;
 741			
 742			if (*tok != TOK_NUM)
 743				report("need value for ENUM/BITS");
 744			if (gettoken() != TOK_STR)
 745				report("need string in ENUM/BITS");
 746			if (e != NULL) {
 747				e->name = savetok();
 748				TAILQ_INSERT_TAIL(&t->enums, e, link);
 749			}
 750			if ((*tok = gettoken()) == TOK_EOF)
 751				report("unexpected EOF in ENUM/BITS");
 752		} while (*tok != ')');
 753		*tok = gettoken();
 754
 755	} else if (*tok == TOK_DEFTYPE) {
 756		*tok = gettoken();
 757
 758	} else {
 759		if ((*tok = gettoken()) == '|') {
 760			if (gettoken() != TOK_STR)
 761				report("subtype expected after '|'");
 762			*tok = gettoken();
 763		}
 764	}
 765
 766	return (syntax);
 767}
 768
 769/*
 770 * Parse the next node (complete with all subnodes)
 771 */
 772static struct node *
 773parse(enum tok tok)
 774{
 775	struct node *node;
 776	struct node *sub;
 777	u_int index_count;
 778
 779	node = xalloc(sizeof(struct node));
 780	node->lno = input->lno;
 781	node->flags = 0;
 782
 783	if (tok != '(')
 784		report("'(' expected at begin of node");
 785	if (gettoken() != TOK_NUM)
 786		report("node id expected after opening '('");
 787	if (val > ASN_MAXID)
 788		report("subid too large '%lu'", val);
 789	node->id = (asn_subid_t)val;
 790	if (gettoken() != TOK_STR)
 791		report("node name expected after '(' ID");
 792	node->name = savetok();
 793
 794	if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
 795	    tok == TOK_ENUM || tok == TOK_BITS) {
 796		/* LEAF or COLUM */
 797		u_int syntax = parse_type(&tok, NULL, node->name);
 798
 799		if (tok == TOK_STR) {
 800			/* LEAF */
 801			node->type = NODE_LEAF;
 802			node->u.leaf.func = savetok();
 803			node->u.leaf.syntax = syntax;
 804			tok = gettoken();
 805		} else {
 806			/* COLUMN */
 807			node->type = NODE_COLUMN;
 808			node->u.column.syntax = syntax;
 809		}
 810
 811		while (tok != ')') {
 812			if (tok != TOK_ACCESS)
 813				report("access keyword or ')' expected");
 814			node->flags |= (u_int)val;
 815			tok = gettoken();
 816		}
 817
 818	} else if (tok == ':') {
 819		/* ENTRY */
 820		node->type = NODE_ENTRY;
 821		TAILQ_INIT(&node->u.entry.subs);
 822
 823		index_count = 0;
 824		node->u.entry.index = 0;
 825		tok = gettoken();
 826		while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
 827		    tok == TOK_ENUM || tok == TOK_BITS) {
 828			u_int syntax = parse_type(&tok, NULL, node->name);
 829			if (index_count++ == SNMP_INDEXES_MAX)
 830				report("too many table indexes");
 831			node->u.entry.index |=
 832			    syntax << (SNMP_INDEX_SHIFT * index_count);
 833		}
 834		node->u.entry.index |= index_count;
 835		if (index_count == 0)
 836			report("need at least one index");
 837		if (tok != TOK_STR)
 838			report("function name expected");
 839
 840		node->u.entry.func = savetok();
 841
 842		tok = gettoken();
 843
 844		while (tok != ')') {
 845			sub = parse(tok);
 846			TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
 847			tok = gettoken();
 848		}
 849
 850	} else {
 851		/* subtree */
 852		node->type = NODE_TREE;
 853		TAILQ_INIT(&node->u.tree.subs);
 854
 855		while (tok != ')') {
 856			sub = parse(tok);
 857			TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
 858			tok = gettoken();
 859		}
 860	}
 861	return (node);
 862}
 863
 864/*
 865 * Parse a top level element. Return the tree if it was a tree, NULL
 866 * otherwise.
 867 */
 868static struct node *
 869parse_top(enum tok tok)
 870{
 871	struct type *t;
 872
 873	if (tok == '(')
 874		return (parse(tok));
 875
 876	if (tok == TOK_TYPEDEF) {
 877		if (gettoken() != TOK_STR)
 878			report("type name expected after typedef");
 879
 880		t = make_type(str);
 881
 882		tok = gettoken();
 883		t->is_enum = (tok == TOK_ENUM);
 884		t->is_bits = (tok == TOK_BITS);
 885		t->syntax = parse_type(&tok, t, NULL);
 886		pushback(tok);
 887
 888		return (NULL);
 889	}
 890
 891	if (tok == TOK_INCLUDE) {
 892		if (gettoken() != TOK_FILENAME)
 893			report("filename expected in include directive");
 894
 895		input_fopen(str, val);
 896		return (NULL);
 897	}
 898
 899	report("'(' or 'typedef' expected");
 900}
 901
 902/*
 903 * Generate the C-code table part for one node.
 904 */
 905static void
 906gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx,
 907    const char *func)
 908{
 909	u_int n;
 910	struct node *sub;
 911	u_int syntax;
 912
 913	if (oid->len == ASN_MAXOIDLEN)
 914		report_node(np, "OID too long");
 915	oid->subs[oid->len++] = np->id;
 916
 917	if (np->type == NODE_TREE) {
 918		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
 919			gen_node(fp, sub, oid, 0, NULL);
 920		oid->len--;
 921		return;
 922	}
 923	if (np->type == NODE_ENTRY) {
 924		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
 925			gen_node(fp, sub, oid, np->u.entry.index,
 926			    np->u.entry.func);
 927		oid->len--;
 928		return;
 929	}
 930
 931	/* leaf or column */
 932	if ((np->flags & (FL_GET|FL_SET)) == 0) {
 933		oid->len--;
 934		return;
 935	}
 936
 937	fprintf(fp, "    {{ %u, {", oid->len);
 938	for (n = 0; n < oid->len; n++)
 939		fprintf(fp, " %u,", oid->subs[n]);
 940	fprintf(fp, " }}, \"%s\", ", np->name);
 941
 942	if (np->type == NODE_COLUMN) {
 943		syntax = np->u.column.syntax;
 944		fprintf(fp, "SNMP_NODE_COLUMN, ");
 945	} else {
 946		syntax = np->u.leaf.syntax;
 947		fprintf(fp, "SNMP_NODE_LEAF, ");
 948	}
 949
 950	switch (syntax) {
 951
 952	  case SNMP_SYNTAX_NULL:
 953		fprintf(fp, "SNMP_SYNTAX_NULL, ");
 954		break;
 955
 956	  case SNMP_SYNTAX_INTEGER:
 957		fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
 958		break;
 959
 960	  case SNMP_SYNTAX_OCTETSTRING:
 961		fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
 962		break;
 963
 964	  case SNMP_SYNTAX_IPADDRESS:
 965		fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
 966		break;
 967
 968	  case SNMP_SYNTAX_OID:
 969		fprintf(fp, "SNMP_SYNTAX_OID, ");
 970		break;
 971
 972	  case SNMP_SYNTAX_TIMETICKS:
 973		fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
 974		break;
 975
 976	  case SNMP_SYNTAX_COUNTER:
 977		fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
 978		break;
 979
 980	  case SNMP_SYNTAX_GAUGE:
 981		fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
 982		break;
 983
 984	  case SNMP_SYNTAX_COUNTER64:
 985		fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
 986		break;
 987
 988	  case SNMP_SYNTAX_NOSUCHOBJECT:
 989	  case SNMP_SYNTAX_NOSUCHINSTANCE:
 990	  case SNMP_SYNTAX_ENDOFMIBVIEW:
 991		abort();
 992	}
 993
 994	if (np->type == NODE_COLUMN)
 995		fprintf(fp, "%s, ", func);
 996	else
 997		fprintf(fp, "%s, ", np->u.leaf.func);
 998
 999	fprintf(fp, "0");
1000	if (np->flags & FL_SET)
1001		fprintf(fp, "|SNMP_NODE_CANSET");
1002	fprintf(fp, ", %#x, NULL, NULL },\n", idx);
1003	oid->len--;
1004	return;
1005}
1006
1007/*
1008 * Generate the header file with the function declarations.
1009 */
1010static void
1011gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func)
1012{
1013	char f[MAXSTR + 4];
1014	struct node *sub;
1015	struct func *ptr;
1016
1017	oidlen++;
1018	if (np->type == NODE_TREE) {
1019		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1020			gen_header(fp, sub, oidlen, NULL);
1021		return;
1022	}
1023	if (np->type == NODE_ENTRY) {
1024		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1025			gen_header(fp, sub, oidlen, np->u.entry.func);
1026		return;
1027	}
1028
1029 	if((np->flags & (FL_GET|FL_SET)) == 0)
1030		return;
1031
1032	if (np->type == NODE_COLUMN) {
1033		if (func == NULL)
1034			errx(1, "column without function (%s) - probably "
1035			    "outside of a table", np->name);
1036		sprintf(f, "%s", func);
1037	} else
1038		sprintf(f, "%s", np->u.leaf.func);
1039
1040	LIST_FOREACH(ptr, &funcs, link)
1041		if (strcmp(ptr->name, f) == 0)
1042			break;
1043
1044	if (ptr == NULL) {
1045		ptr = xalloc(sizeof(*ptr));
1046		ptr->name = savestr(f);
1047		LIST_INSERT_HEAD(&funcs, ptr, link);
1048
1049		fprintf(fp, "int	%s(struct snmp_context *, "
1050		    "struct snmp_value *, u_int, u_int, "
1051		    "enum snmp_op);\n", f);
1052	}
1053
1054	fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
1055}
1056
1057/*
1058 * Generate the OID table.
1059 */
1060static void
1061gen_table(FILE *fp, struct node *node)
1062{
1063	struct asn_oid oid;
1064
1065	fprintf(fp, "#include <sys/types.h>\n");
1066	fprintf(fp, "#include <stdio.h>\n");
1067#ifdef HAVE_STDINT_H
1068	fprintf(fp, "#include <stdint.h>\n");
1069#endif
1070	if (localincs) {
1071		fprintf(fp, "#include \"asn1.h\"\n");
1072		fprintf(fp, "#include \"snmp.h\"\n");
1073		fprintf(fp, "#include \"snmpagent.h\"\n");
1074	} else {
1075		fprintf(fp, "#include <bsnmp/asn1.h>\n");
1076		fprintf(fp, "#include <bsnmp/snmp.h>\n");
1077		fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
1078	}
1079	fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
1080	fprintf(fp, "\n");
1081
1082	fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
1083
1084	oid.len = PREFIX_LEN;
1085	memcpy(oid.subs, prefix, sizeof(prefix));
1086	gen_node(fp, node, &oid, 0, NULL);
1087
1088	fprintf(fp, "};\n\n");
1089}
1090
1091static void
1092print_syntax(u_int syntax)
1093{
1094	u_int i;
1095
1096	for (i = 0; keywords[i].str != NULL; i++)
1097		if (keywords[i].tok == TOK_TYPE &&
1098		    keywords[i].val == syntax) {
1099			printf(" %s", keywords[i].str);
1100			return;
1101	}
1102	abort();
1103}
1104
1105/*
1106 * Generate a tree definition file
1107 */
1108static void
1109gen_tree(const struct node *np, int level)
1110{
1111	const struct node *sp;
1112	u_int i;
1113
1114	printf("%*s(%u %s", 2 * level, "", np->id, np->name);
1115
1116	switch (np->type) {
1117
1118	  case NODE_LEAF:
1119		print_syntax(np->u.leaf.syntax);
1120		printf(" %s%s%s)\n", np->u.leaf.func,
1121		    (np->flags & FL_GET) ? " GET" : "",
1122		    (np->flags & FL_SET) ? " SET" : "");
1123		break;
1124
1125	  case NODE_TREE:
1126		if (TAILQ_EMPTY(&np->u.tree.subs)) {
1127			printf(")\n");
1128		} else {
1129			printf("\n");
1130			TAILQ_FOREACH(sp, &np->u.tree.subs, link)
1131				gen_tree(sp, level + 1);
1132			printf("%*s)\n", 2 * level, "");
1133		}
1134		break;
1135
1136	  case NODE_ENTRY:
1137		printf(" :");
1138
1139		for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++)
1140			print_syntax(SNMP_INDEX(np->u.entry.index, i));
1141		printf(" %s\n", np->u.entry.func);
1142		TAILQ_FOREACH(sp, &np->u.entry.subs, link)
1143			gen_tree(sp, level + 1);
1144		printf("%*s)\n", 2 * level, "");
1145		break;
1146
1147	  case NODE_COLUMN:
1148		print_syntax(np->u.column.syntax);
1149		printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
1150		    (np->flags & FL_SET) ? " SET" : "");
1151		break;
1152	}
1153}
1154
1155static int
1156extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
1157    const struct asn_oid *idx, const char *iname)
1158{
1159	struct node *sub;
1160	u_long n;
1161
1162	if (oid->len == ASN_MAXOIDLEN)
1163		report_node(np, "OID too long");
1164	oid->subs[oid->len++] = np->id;
1165
1166	if (strcmp(obj, np->name) == 0) {
1167		if (oid->len + idx->len >= ASN_MAXOIDLEN)
1168			report_node(np, "OID too long");
1169		fprintf(fp, "#define OID_%s%s\t%u\n", np->name,
1170		    iname ? iname : "", np->id);
1171		fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name,
1172		    iname ? iname : "", oid->len + idx->len);
1173		fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name,
1174		    iname ? iname : "", oid->len + idx->len);
1175		for (n = 0; n < oid->len; n++)
1176			fprintf(fp, " %u,", oid->subs[n]);
1177		for (n = 0; n < idx->len; n++)
1178			fprintf(fp, " %u,", idx->subs[n]);
1179		fprintf(fp, " } }\n");
1180		return (0);
1181	}
1182
1183	if (np->type == NODE_TREE) {
1184		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1185			if (!extract(fp, sub, oid, obj, idx, iname))
1186				return (0);
1187	} else if (np->type == NODE_ENTRY) {
1188		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1189			if (!extract(fp, sub, oid, obj, idx, iname))
1190				return (0);
1191	}
1192	oid->len--;
1193	return (1);
1194}
1195
1196static int
1197gen_extract(FILE *fp, const struct node *root, char *object)
1198{
1199	struct asn_oid oid;
1200	struct asn_oid idx;
1201	char *s, *e, *end, *iname;
1202	u_long ul;
1203	int ret;
1204
1205	/* look whether the object to extract has an index part */
1206	idx.len = 0;
1207	iname = NULL;
1208	s = strchr(object, '.');
1209	if (s != NULL) {
1210		iname = malloc(strlen(s) + 1);
1211		if (iname == NULL)
1212			err(1, "cannot allocated index");
1213
1214		strcpy(iname, s);
1215		for (e = iname; *e != '\0'; e++)
1216			if (*e == '.')
1217				*e = '_';
1218
1219		*s++ = '\0';
1220		while (s != NULL) {
1221			if (*s == '\0')
1222				errx(1, "bad index syntax");
1223			if ((e = strchr(s, '.')) != NULL)
1224				*e++ = '\0';
1225
1226			errno = 0;
1227			ul = strtoul(s, &end, 0);
1228			if (*end != '\0')
1229				errx(1, "bad index syntax '%s'", end);
1230			if (errno != 0)
1231				err(1, "bad index syntax");
1232
1233			if (idx.len == ASN_MAXOIDLEN)
1234				errx(1, "index oid too large");
1235			idx.subs[idx.len++] = ul;
1236
1237			s = e;
1238		}
1239	}
1240
1241	oid.len = PREFIX_LEN;
1242	memcpy(oid.subs, prefix, sizeof(prefix));
1243	ret = extract(fp, root, &oid, object, &idx, iname);
1244	if (iname != NULL)
1245		free(iname);
1246
1247	return (ret);
1248}
1249
1250
1251static void
1252check_sub_order(const struct node *np, const struct node_list *subs)
1253{
1254	int first;
1255	const struct node *sub;
1256	asn_subid_t maxid = 0;
1257
1258	/* ensure, that subids are ordered */
1259	first = 1;
1260	TAILQ_FOREACH(sub, subs, link) {
1261		if (!first && sub->id <= maxid)
1262			report_node(np, "subids not ordered at %s", sub->name);
1263		maxid = sub->id;
1264		first = 0;
1265	}
1266}
1267
1268/*
1269 * Do some sanity checks on the tree definition and do some computations.
1270 */
1271static void
1272check_tree(struct node *np)
1273{
1274	struct node *sub;
1275
1276	if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
1277		if ((np->flags & (FL_GET|FL_SET)) != 0)
1278			tree_size++;
1279		return;
1280	}
1281
1282	if (np->type == NODE_ENTRY) {
1283		check_sub_order(np, &np->u.entry.subs);
1284
1285		/* ensure all subnodes are columns */
1286		TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
1287			if (sub->type != NODE_COLUMN)
1288				report_node(np, "entry subnode '%s' is not "
1289				    "a column", sub->name);
1290			check_tree(sub);
1291		}
1292	} else {
1293		check_sub_order(np, &np->u.tree.subs);
1294
1295		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1296			check_tree(sub);
1297	}
1298}
1299
1300static void
1301merge_subs(struct node_list *s1, struct node_list *s2)
1302{
1303	struct node *n1, *n2;
1304
1305	while (!TAILQ_EMPTY(s2)) {
1306		n2 = TAILQ_FIRST(s2);
1307		TAILQ_REMOVE(s2, n2, link);
1308
1309		TAILQ_FOREACH(n1, s1, link)
1310			if (n1->id >= n2->id)
1311				break;
1312		if (n1 == NULL)
1313			TAILQ_INSERT_TAIL(s1, n2, link);
1314		else if (n1->id > n2->id)
1315			TAILQ_INSERT_BEFORE(n1, n2, link);
1316		else {
1317			if (n1->type == NODE_TREE && n2->type == NODE_TREE) {
1318				if (strcmp(n1->name, n2->name) != 0)
1319					errx(1, "trees to merge must have "
1320					    "same name '%s' '%s'", n1->name,
1321					    n2->name);
1322				merge_subs(&n1->u.tree.subs, &n2->u.tree.subs);
1323				free(n2);
1324			} else if (n1->type == NODE_ENTRY &&
1325			    n2->type == NODE_ENTRY) {
1326				if (strcmp(n1->name, n2->name) != 0)
1327					errx(1, "entries to merge must have "
1328					    "same name '%s' '%s'", n1->name,
1329					    n2->name);
1330				if (n1->u.entry.index != n2->u.entry.index)
1331					errx(1, "entries to merge must have "
1332					    "same index '%s'", n1->name);
1333				if (strcmp(n1->u.entry.func,
1334				    n2->u.entry.func) != 0)
1335					errx(1, "entries to merge must have "
1336					    "same op '%s'", n1->name);
1337				merge_subs(&n1->u.entry.subs,
1338				    &n2->u.entry.subs);
1339				free(n2);
1340			} else
1341				errx(1, "entities to merge must be both "
1342				    "trees or both entries: %s, %s",
1343				    n1->name, n2->name);
1344		}
1345	}
1346}
1347
1348static void
1349merge(struct node **root, struct node *t)
1350{
1351
1352	if (*root == NULL) {
1353		*root = t;
1354		return;
1355	}
1356	if (t == NULL)
1357		return;
1358
1359	/* both must be trees */
1360	if ((*root)->type != NODE_TREE)
1361		errx(1, "root is not a tree");
1362	if (t->type != NODE_TREE)
1363		errx(1, "can merge only with tree");
1364	if ((*root)->id != t->id)
1365		errx(1, "trees to merge must have same id");
1366
1367	merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs);
1368}
1369
1370static void
1371unminus(FILE *fp, const char *s)
1372{
1373
1374	while (*s != '\0') {
1375		if (*s == '-')
1376			fprintf(fp, "_");
1377		else
1378			fprintf(fp, "%c", *s);
1379		s++;
1380	}
1381}
1382
1383static void
1384gen_enum(FILE *fp, const struct type *t)
1385{
1386	const struct enums *e;
1387	long min = LONG_MAX;
1388
1389	fprintf(fp, "\n");
1390	fprintf(fp, "#ifndef %s_defined__\n", t->name);
1391	fprintf(fp, "#define %s_defined__\n", t->name);
1392	fprintf(fp, "/*\n");
1393	fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
1394	fprintf(fp, " */\n");
1395	fprintf(fp, "enum %s {\n", t->name);
1396	TAILQ_FOREACH(e, &t->enums, link) {
1397		fprintf(fp, "\t%s_", t->name);
1398		unminus(fp, e->name);
1399		fprintf(fp, " = %ld,\n", e->value);
1400		if (e->value < min)
1401			min = e->value;
1402	}
1403	fprintf(fp, "};\n");
1404	fprintf(fp, "#define	STROFF_%s %ld\n", t->name, min);
1405	fprintf(fp, "#define	STRING_%s \\\n", t->name);
1406	TAILQ_FOREACH(e, &t->enums, link) {
1407		fprintf(fp, "\t[%ld] \"%s_", e->value - min, t->name);
1408		unminus(fp, e->name);
1409		fprintf(fp, "\",\\\n");
1410	}
1411	fprintf(fp, "\n");
1412	fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
1413}
1414
1415static void
1416gen_enums(FILE *fp)
1417{
1418	const struct type *t;
1419
1420	LIST_FOREACH(t, &types, link)
1421		if (t->is_enum || t->is_bits)
1422			gen_enum(fp, t);
1423}
1424
1425static int
1426extract_enum(FILE *fp, const char *name)
1427{
1428	const struct type *t;
1429
1430	LIST_FOREACH(t, &types, link)
1431		if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
1432			gen_enum(fp, t);
1433			return (0);
1434		}
1435	return (-1);
1436}
1437
1438int
1439main(int argc, char *argv[])
1440{
1441	int do_extract = 0;
1442	int do_tree = 0;
1443	int do_enums = 0;
1444	int opt;
1445	struct node *root;
1446	char fname[MAXPATHLEN + 1];
1447	int tok;
1448	FILE *fp;
1449	char *infile = NULL;
1450
1451	while ((opt = getopt(argc, argv, "dEehI:i:lp:t")) != EOF)
1452		switch (opt) {
1453
1454		  case 'd':
1455			debug = 1;
1456			break;
1457
1458		  case 'h':
1459			fprintf(stderr, "%s", usgtxt);
1460			exit(0);
1461
1462		  case 'E':
1463			do_enums = 1;
1464			break;
1465
1466		  case 'e':
1467			do_extract = 1;
1468			break;
1469
1470		  case 'I':
1471			path_new(optarg);
1472			break;
1473
1474		  case 'i':
1475			infile = optarg;
1476			break;
1477
1478		  case 'l':
1479			localincs = 1;
1480			break;
1481
1482		  case 'p':
1483			file_prefix = optarg;
1484			if (strlen(file_prefix) + strlen("tree.c") >
1485			    MAXPATHLEN)
1486				errx(1, "prefix too long");
1487			break;
1488
1489		  case 't':
1490			do_tree = 1;
1491			break;
1492		}
1493
1494	if (do_extract + do_tree + do_enums > 1)
1495		errx(1, "conflicting options -e/-t/-E");
1496	if (!do_extract && !do_enums && argc != optind)
1497		errx(1, "no arguments allowed");
1498	if ((do_extract || do_enums) && argc == optind)
1499		errx(1, "no objects specified");
1500
1501	if (infile == NULL) {
1502		input_new(stdin, NULL, "<stdin>");
1503	} else {
1504		if ((fp = fopen(infile, "r")) == NULL)
1505			err(1, "%s", infile);
1506		input_new(fp, NULL, infile);
1507	}
1508
1509	root = parse_top(gettoken());
1510	while ((tok = gettoken()) != TOK_EOF)
1511		merge(&root, parse_top(tok));
1512
1513	check_tree(root);
1514
1515	if (do_extract) {
1516		while (optind < argc) {
1517			if (gen_extract(stdout, root, argv[optind]))
1518				errx(1, "object not found: %s", argv[optind]);
1519			optind++;
1520		}
1521		return (0);
1522	}
1523	if (do_enums) {
1524		while (optind < argc) {
1525			if (extract_enum(stdout, argv[optind]))
1526				errx(1, "enum not found: %s", argv[optind]);
1527			optind++;
1528		}
1529		return (0);
1530	}
1531	if (do_tree) {
1532		gen_tree(root, 0);
1533		return (0);
1534	}
1535	sprintf(fname, "%stree.h", file_prefix);
1536	if ((fp = fopen(fname, "w")) == NULL)
1537		err(1, "%s: ", fname);
1538	gen_header(fp, root, PREFIX_LEN, NULL);
1539
1540	fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
1541	gen_enums(fp);
1542	fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
1543
1544	fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
1545	fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
1546
1547	fclose(fp);
1548
1549	sprintf(fname, "%stree.c", file_prefix);
1550	if ((fp = fopen(fname, "w")) == NULL)
1551		err(1, "%s: ", fname);
1552	gen_table(fp, root);
1553	fclose(fp);
1554
1555	return (0);
1556}