2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Copyright (c) 2004-2006
10 * Author: Harti Brandt <harti@freebsd.org>
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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.
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
33 * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $
35 * Generate OID table from table description.
39 * file := top | top file
41 * top := tree | typedef | include
43 * tree := head elements ')'
45 * entry := head ':' index STRING elements ')'
47 * leaf := head type STRING ACCESS ')'
49 * column := head type ACCESS ')'
51 * type := BASETYPE | BASETYPE '|' subtype | enum | bits
55 * enum := ENUM '(' value ')'
57 * bits := BITS '(' value ')'
59 * value := optminus INT STRING | optminus INT STRING value
61 * optminus := '-' | EMPTY
63 * head := '(' INT STRING
65 * elements := EMPTY | elements element
67 * element := tree | leaf | column
69 * index := type | index type
71 * typedef := 'typedef' STRING type
73 * include := 'include' filespec
75 * filespec := '"' STRING '"' | '<' STRING '>'
77 #include <sys/types.h>
78 #include <sys/param.h>
90 #include <sys/queue.h>
94 #include "snmpagent.h"
97 * Constant prefix for all OIDs
99 static const asn_subid_t prefix[] = { 1, 3, 6 };
100 #define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0]))
103 static const char *file_prefix = "";
105 /* if true generate local include paths */
106 static int localincs = 0;
108 /* if true print tokens */
111 static const char usgtxt[] = "\
112 Generate SNMP tables.\n\
113 usage: gensnmptree [-dEehlt] [-I directory] [-i infile] [-p prefix]\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\
128 * A node in the OID tree
143 TAILQ_HEAD(node_list, node);
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 */
155 struct node_list subs;
159 uint32_t index; /* index for table entry */
160 char *func; /* function for tables */
161 struct node_list subs;
165 enum snmp_syntax syntax; /* syntax for this leaf */
166 char *func; /* function name */
170 enum snmp_syntax syntax; /* syntax for this column */
177 LIST_ENTRY(func) link;
180 static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs);
185 TAILQ_ENTRY(enums) link;
190 const char *from_fname;
195 TAILQ_HEAD(, enums) enums;
196 LIST_ENTRY(type) link;
199 static LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types);
201 static void report(const char *, ...) __dead2 __printflike(1, 2);
202 static void report_node(const struct node *, const char *, ...)
203 __dead2 __printflike(2, 3);
205 /************************************************************
207 * Allocate memory and panic just in the case...
214 if ((ptr = malloc(size)) == NULL)
215 err(1, "allocing %zu bytes", size);
221 savestr(const char *s)
226 return (strcpy(xalloc(strlen(s) + 1), s));
229 /************************************************************
238 LIST_ENTRY(input) link;
240 static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
241 static struct input *input = NULL;
243 #define MAX_PATHS 100
244 static u_int npaths = 2;
245 static u_int stdpaths = 2;
246 static const char *paths[MAX_PATHS + 1] = {
247 "/usr/share/snmp/defs",
248 "/usr/local/share/snmp/defs",
252 static int pbchar = -1;
255 path_new(const char *path)
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);
266 input_new(FILE *fp, const char *path, const char *fname)
270 ip = xalloc(sizeof(*ip));
273 ip->fname = savestr(fname);
274 ip->path = savestr(path);
275 LIST_INSERT_HEAD(&inputs, ip, link);
289 LIST_REMOVE(input, link);
292 input = LIST_FIRST(&inputs);
296 tryopen(const char *path, const char *fname)
304 fn = xalloc(strlen(path) + strlen(fname) + 2);
305 sprintf(fn, "%s/%s", path, fname);
313 input_fopen(const char *fname, int loc)
319 if (fname[0] == '/') {
320 if ((fp = tryopen(NULL, fname)) != NULL) {
321 input_new(fp, NULL, fname);
332 if ((fp = tryopen(path, fname)) != NULL) {
333 input_new(fp, NULL, fname);
338 for (p = 0; paths[p] != NULL; p++)
339 if ((fp = tryopen(paths[p], fname)) != NULL) {
340 input_new(fp, paths[p], fname);
344 report("cannot open '%s'", fname);
362 if ((c = getc(input->fp)) != EOF)
378 /************************************************************
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) */
396 static const struct {
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 },
421 /* arbitrary upper limit on node names and function names */
424 u_long val; /* integer values */
425 int all_cond; /* all conditions are true */
426 int saved_token = -1;
429 * Report an error and exit.
432 report(const char *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");
449 report_node(const struct node *np, const char *fmt, ...)
454 fprintf(stderr, "line %u, node %s: ", np->lno, np->name);
455 vfprintf(stderr, fmt, ap);
456 fprintf(stderr, "\n");
462 * Return a fresh copy of the string constituting the current token.
467 return (savestr(str));
471 * Get the next token from input.
474 gettoken_internal(void)
479 if (saved_token != -1) {
487 * Skip any whitespace before the next token
489 while ((c = tgetc()) != EOF) {
498 report("unexpected character %#2x", (u_int)c);
504 while ((c = tgetc()) != EOF) {
510 report("unexpected EOF in comment");
514 * Single character tokens
516 if (strchr("():|-", c) != NULL)
519 if (c == '"' || c == '<') {
529 while ((c = tgetc()) != EOF) {
532 if (n == sizeof(str) - 1) {
534 report("filename too long '%s...'", str);
539 return (TOK_FILENAME);
548 while ((c = tgetc()) != EOF) {
553 if (n == sizeof(str) - 1) {
555 report("number too long '%s...'", str);
560 sscanf(str, "%lu", &val);
565 * So that has to be a string.
567 if (isalpha(c) || c == '_') {
570 while ((c = tgetc()) != EOF) {
571 if (!isalnum(c) && c != '_' && c != '-') {
575 if (n == sizeof(str) - 1) {
577 report("string too long '%s...'", str);
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);
592 LIST_FOREACH(t, &types, link) {
593 if (strcmp(t->name, str) == 0) {
595 return (TOK_DEFTYPE);
601 errx(1, "%u: unexpected character '%c'", input->lno, c);
603 errx(1, "%u: unexpected character 0x%02x", input->lno,
609 int tok = gettoken_internal();
615 fprintf(stderr, "EOF ");
619 fprintf(stderr, "NUM(%lu) ", val);
623 fprintf(stderr, "STR(%s) ", str);
627 fprintf(stderr, "ACCESS(%lu) ", val);
631 fprintf(stderr, "TYPE(%lu) ", val);
635 fprintf(stderr, "ENUM ");
639 fprintf(stderr, "BITS ");
643 fprintf(stderr, "TYPEDEF ");
647 fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val);
651 fprintf(stderr, "INCLUDE ");
655 fprintf(stderr, "FILENAME ");
661 fprintf(stderr, "'%c' ", tok);
662 else if (tok == '\n')
663 fprintf(stderr, "\n");
665 fprintf(stderr, "%02x ", tok);
678 pushback(enum tok tok)
681 if (saved_token != -1)
690 make_type(const char *s)
694 t = xalloc(sizeof(*t));
695 t->name = savestr(s);
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);
707 * Parse a type. We've seen the ENUM or type keyword already. Leave next
711 parse_type(enum tok *tok, struct type *t, const char *vname)
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);
725 if (gettoken() != '(')
726 report("'(' expected after ENUM");
728 if ((*tok = gettoken()) == TOK_EOF)
729 report("unexpected EOF in ENUM");
733 e = xalloc(sizeof(*e));
736 if ((*tok = gettoken()) == TOK_EOF)
737 report("unexpected EOF in ENUM");
738 e->value = -(long)val;
743 report("need value for ENUM/BITS");
744 if (gettoken() != TOK_STR)
745 report("need string in ENUM/BITS");
747 TAILQ_INSERT_TAIL(&t->enums, e, link);
748 if ((*tok = gettoken()) == TOK_EOF)
749 report("unexpected EOF in ENUM/BITS");
750 } while (*tok != ')');
753 } else if (*tok == TOK_DEFTYPE) {
757 if ((*tok = gettoken()) == '|') {
758 if (gettoken() != TOK_STR)
759 report("subtype expected after '|'");
768 * Parse the next node (complete with all subnodes)
777 node = xalloc(sizeof(struct node));
778 node->lno = input->lno;
782 report("'(' expected at begin of node");
783 if (gettoken() != TOK_NUM)
784 report("node id expected after opening '('");
786 report("subid too large '%lu'", val);
787 node->id = (asn_subid_t)val;
788 if (gettoken() != TOK_STR)
789 report("node name expected after '(' ID");
790 node->name = savetok();
792 if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
793 tok == TOK_ENUM || tok == TOK_BITS) {
795 u_int syntax = parse_type(&tok, NULL, node->name);
797 if (tok == TOK_STR) {
799 node->type = NODE_LEAF;
800 node->u.leaf.func = savetok();
801 node->u.leaf.syntax = syntax;
805 node->type = NODE_COLUMN;
806 node->u.column.syntax = syntax;
810 if (tok != TOK_ACCESS)
811 report("access keyword or ')' expected");
812 node->flags |= (u_int)val;
816 } else if (tok == ':') {
818 node->type = NODE_ENTRY;
819 TAILQ_INIT(&node->u.entry.subs);
822 node->u.entry.index = 0;
824 while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
825 tok == TOK_ENUM || tok == TOK_BITS) {
826 u_int syntax = parse_type(&tok, NULL, node->name);
827 if (index_count++ == SNMP_INDEXES_MAX)
828 report("too many table indexes");
829 node->u.entry.index |=
830 syntax << (SNMP_INDEX_SHIFT * index_count);
832 node->u.entry.index |= index_count;
833 if (index_count == 0)
834 report("need at least one index");
836 report("function name expected");
838 node->u.entry.func = savetok();
844 TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
850 node->type = NODE_TREE;
851 TAILQ_INIT(&node->u.tree.subs);
855 TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
863 * Parse a top level element. Return the tree if it was a tree, NULL
867 parse_top(enum tok tok)
874 if (tok == TOK_TYPEDEF) {
875 if (gettoken() != TOK_STR)
876 report("type name expected after typedef");
881 t->is_enum = (tok == TOK_ENUM);
882 t->is_bits = (tok == TOK_BITS);
883 t->syntax = parse_type(&tok, t, NULL);
889 if (tok == TOK_INCLUDE) {
890 if (gettoken() != TOK_FILENAME)
891 report("filename expected in include directive");
893 input_fopen(str, val);
897 report("'(' or 'typedef' expected");
901 * Generate the C-code table part for one node.
904 gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx,
911 if (oid->len == ASN_MAXOIDLEN)
912 report_node(np, "OID too long");
913 oid->subs[oid->len++] = np->id;
915 if (np->type == NODE_TREE) {
916 TAILQ_FOREACH(sub, &np->u.tree.subs, link)
917 gen_node(fp, sub, oid, 0, NULL);
921 if (np->type == NODE_ENTRY) {
922 TAILQ_FOREACH(sub, &np->u.entry.subs, link)
923 gen_node(fp, sub, oid, np->u.entry.index,
930 if ((np->flags & (FL_GET|FL_SET)) == 0) {
935 fprintf(fp, " {{ %u, {", oid->len);
936 for (n = 0; n < oid->len; n++)
937 fprintf(fp, " %u,", oid->subs[n]);
938 fprintf(fp, " }}, \"%s\", ", np->name);
940 if (np->type == NODE_COLUMN) {
941 syntax = np->u.column.syntax;
942 fprintf(fp, "SNMP_NODE_COLUMN, ");
944 syntax = np->u.leaf.syntax;
945 fprintf(fp, "SNMP_NODE_LEAF, ");
950 case SNMP_SYNTAX_NULL:
951 fprintf(fp, "SNMP_SYNTAX_NULL, ");
954 case SNMP_SYNTAX_INTEGER:
955 fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
958 case SNMP_SYNTAX_OCTETSTRING:
959 fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
962 case SNMP_SYNTAX_IPADDRESS:
963 fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
966 case SNMP_SYNTAX_OID:
967 fprintf(fp, "SNMP_SYNTAX_OID, ");
970 case SNMP_SYNTAX_TIMETICKS:
971 fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
974 case SNMP_SYNTAX_COUNTER:
975 fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
978 case SNMP_SYNTAX_GAUGE:
979 fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
982 case SNMP_SYNTAX_COUNTER64:
983 fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
986 case SNMP_SYNTAX_NOSUCHOBJECT:
987 case SNMP_SYNTAX_NOSUCHINSTANCE:
988 case SNMP_SYNTAX_ENDOFMIBVIEW:
992 if (np->type == NODE_COLUMN)
993 fprintf(fp, "%s, ", func);
995 fprintf(fp, "%s, ", np->u.leaf.func);
998 if (np->flags & FL_SET)
999 fprintf(fp, "|SNMP_NODE_CANSET");
1000 fprintf(fp, ", %#x, NULL, NULL },\n", idx);
1006 * Generate the header file with the function declarations.
1009 gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func)
1016 if (np->type == NODE_TREE) {
1017 TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1018 gen_header(fp, sub, oidlen, NULL);
1021 if (np->type == NODE_ENTRY) {
1022 TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1023 gen_header(fp, sub, oidlen, np->u.entry.func);
1027 if((np->flags & (FL_GET|FL_SET)) == 0)
1030 if (np->type == NODE_COLUMN) {
1032 errx(1, "column without function (%s) - probably "
1033 "outside of a table", np->name);
1034 sprintf(f, "%s", func);
1036 sprintf(f, "%s", np->u.leaf.func);
1038 LIST_FOREACH(ptr, &funcs, link)
1039 if (strcmp(ptr->name, f) == 0)
1043 ptr = xalloc(sizeof(*ptr));
1044 ptr->name = savestr(f);
1045 LIST_INSERT_HEAD(&funcs, ptr, link);
1047 fprintf(fp, "int %s(struct snmp_context *, "
1048 "struct snmp_value *, u_int, u_int, "
1049 "enum snmp_op);\n", f);
1052 fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
1056 * Generate the OID table.
1059 gen_table(FILE *fp, struct node *node)
1063 fprintf(fp, "#include <sys/types.h>\n");
1064 fprintf(fp, "#include <stdio.h>\n");
1065 #ifdef HAVE_STDINT_H
1066 fprintf(fp, "#include <stdint.h>\n");
1069 fprintf(fp, "#include \"asn1.h\"\n");
1070 fprintf(fp, "#include \"snmp.h\"\n");
1071 fprintf(fp, "#include \"snmpagent.h\"\n");
1073 fprintf(fp, "#include <bsnmp/asn1.h>\n");
1074 fprintf(fp, "#include <bsnmp/snmp.h>\n");
1075 fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
1077 fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
1080 fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
1082 oid.len = PREFIX_LEN;
1083 memcpy(oid.subs, prefix, sizeof(prefix));
1084 gen_node(fp, node, &oid, 0, NULL);
1086 fprintf(fp, "};\n\n");
1090 print_syntax(u_int syntax)
1094 for (i = 0; keywords[i].str != NULL; i++)
1095 if (keywords[i].tok == TOK_TYPE &&
1096 keywords[i].val == syntax) {
1097 printf(" %s", keywords[i].str);
1104 * Generate a tree definition file
1107 gen_tree(const struct node *np, int level)
1109 const struct node *sp;
1112 printf("%*s(%u %s", 2 * level, "", np->id, np->name);
1117 print_syntax(np->u.leaf.syntax);
1118 printf(" %s%s%s)\n", np->u.leaf.func,
1119 (np->flags & FL_GET) ? " GET" : "",
1120 (np->flags & FL_SET) ? " SET" : "");
1124 if (TAILQ_EMPTY(&np->u.tree.subs)) {
1128 TAILQ_FOREACH(sp, &np->u.tree.subs, link)
1129 gen_tree(sp, level + 1);
1130 printf("%*s)\n", 2 * level, "");
1137 for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++)
1138 print_syntax(SNMP_INDEX(np->u.entry.index, i));
1139 printf(" %s\n", np->u.entry.func);
1140 TAILQ_FOREACH(sp, &np->u.entry.subs, link)
1141 gen_tree(sp, level + 1);
1142 printf("%*s)\n", 2 * level, "");
1146 print_syntax(np->u.column.syntax);
1147 printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
1148 (np->flags & FL_SET) ? " SET" : "");
1154 extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
1155 const struct asn_oid *idx, const char *iname)
1160 if (oid->len == ASN_MAXOIDLEN)
1161 report_node(np, "OID too long");
1162 oid->subs[oid->len++] = np->id;
1164 if (strcmp(obj, np->name) == 0) {
1165 if (oid->len + idx->len >= ASN_MAXOIDLEN)
1166 report_node(np, "OID too long");
1167 fprintf(fp, "#define OID_%s%s\t%u\n", np->name,
1168 iname ? iname : "", np->id);
1169 fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name,
1170 iname ? iname : "", oid->len + idx->len);
1171 fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name,
1172 iname ? iname : "", oid->len + idx->len);
1173 for (n = 0; n < oid->len; n++)
1174 fprintf(fp, " %u,", oid->subs[n]);
1175 for (n = 0; n < idx->len; n++)
1176 fprintf(fp, " %u,", idx->subs[n]);
1177 fprintf(fp, " } }\n");
1181 if (np->type == NODE_TREE) {
1182 TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1183 if (!extract(fp, sub, oid, obj, idx, iname))
1185 } else if (np->type == NODE_ENTRY) {
1186 TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1187 if (!extract(fp, sub, oid, obj, idx, iname))
1195 gen_extract(FILE *fp, const struct node *root, char *object)
1199 char *s, *e, *end, *iname;
1203 /* look whether the object to extract has an index part */
1206 s = strchr(object, '.');
1208 iname = malloc(strlen(s) + 1);
1210 err(1, "cannot allocated index");
1213 for (e = iname; *e != '\0'; e++)
1220 errx(1, "bad index syntax");
1221 if ((e = strchr(s, '.')) != NULL)
1225 ul = strtoul(s, &end, 0);
1227 errx(1, "bad index syntax '%s'", end);
1229 err(1, "bad index syntax");
1231 if (idx.len == ASN_MAXOIDLEN)
1232 errx(1, "index oid too large");
1233 idx.subs[idx.len++] = ul;
1239 oid.len = PREFIX_LEN;
1240 memcpy(oid.subs, prefix, sizeof(prefix));
1241 ret = extract(fp, root, &oid, object, &idx, iname);
1250 check_sub_order(const struct node *np, const struct node_list *subs)
1253 const struct node *sub;
1254 asn_subid_t maxid = 0;
1256 /* ensure, that subids are ordered */
1258 TAILQ_FOREACH(sub, subs, link) {
1259 if (!first && sub->id <= maxid)
1260 report_node(np, "subids not ordered at %s", sub->name);
1267 * Do some sanity checks on the tree definition and do some computations.
1270 check_tree(struct node *np)
1274 if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
1275 if ((np->flags & (FL_GET|FL_SET)) != 0)
1280 if (np->type == NODE_ENTRY) {
1281 check_sub_order(np, &np->u.entry.subs);
1283 /* ensure all subnodes are columns */
1284 TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
1285 if (sub->type != NODE_COLUMN)
1286 report_node(np, "entry subnode '%s' is not "
1287 "a column", sub->name);
1291 check_sub_order(np, &np->u.tree.subs);
1293 TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1299 merge_subs(struct node_list *s1, struct node_list *s2)
1301 struct node *n1, *n2;
1303 while (!TAILQ_EMPTY(s2)) {
1304 n2 = TAILQ_FIRST(s2);
1305 TAILQ_REMOVE(s2, n2, link);
1307 TAILQ_FOREACH(n1, s1, link)
1308 if (n1->id >= n2->id)
1311 TAILQ_INSERT_TAIL(s1, n2, link);
1312 else if (n1->id > n2->id)
1313 TAILQ_INSERT_BEFORE(n1, n2, link);
1315 if (n1->type == NODE_TREE && n2->type == NODE_TREE) {
1316 if (strcmp(n1->name, n2->name) != 0)
1317 errx(1, "trees to merge must have "
1318 "same name '%s' '%s'", n1->name,
1320 merge_subs(&n1->u.tree.subs, &n2->u.tree.subs);
1322 } else if (n1->type == NODE_ENTRY &&
1323 n2->type == NODE_ENTRY) {
1324 if (strcmp(n1->name, n2->name) != 0)
1325 errx(1, "entries to merge must have "
1326 "same name '%s' '%s'", n1->name,
1328 if (n1->u.entry.index != n2->u.entry.index)
1329 errx(1, "entries to merge must have "
1330 "same index '%s'", n1->name);
1331 if (strcmp(n1->u.entry.func,
1332 n2->u.entry.func) != 0)
1333 errx(1, "entries to merge must have "
1334 "same op '%s'", n1->name);
1335 merge_subs(&n1->u.entry.subs,
1339 errx(1, "entities to merge must be both "
1340 "trees or both entries: %s, %s",
1341 n1->name, n2->name);
1347 merge(struct node **root, struct node *t)
1350 if (*root == NULL) {
1357 /* both must be trees */
1358 if ((*root)->type != NODE_TREE)
1359 errx(1, "root is not a tree");
1360 if (t->type != NODE_TREE)
1361 errx(1, "can merge only with tree");
1362 if ((*root)->id != t->id)
1363 errx(1, "trees to merge must have same id");
1365 merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs);
1369 unminus(FILE *fp, const char *s)
1372 while (*s != '\0') {
1376 fprintf(fp, "%c", *s);
1382 gen_enum(FILE *fp, const struct type *t)
1384 const struct enums *e;
1385 long min = LONG_MAX;
1388 fprintf(fp, "#ifndef %s_defined__\n", t->name);
1389 fprintf(fp, "#define %s_defined__\n", t->name);
1390 fprintf(fp, "/*\n");
1391 fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
1392 fprintf(fp, " */\n");
1393 fprintf(fp, "enum %s {\n", t->name);
1394 TAILQ_FOREACH(e, &t->enums, link) {
1395 fprintf(fp, "\t%s_", t->name);
1396 unminus(fp, e->name);
1397 fprintf(fp, " = %ld,\n", e->value);
1401 fprintf(fp, "};\n");
1402 fprintf(fp, "#define STROFF_%s %ld\n", t->name, min);
1403 fprintf(fp, "#define STRING_%s \\\n", t->name);
1404 TAILQ_FOREACH(e, &t->enums, link) {
1405 fprintf(fp, "\t[%ld] \"%s_", e->value - min, t->name);
1406 unminus(fp, e->name);
1407 fprintf(fp, "\",\\\n");
1410 fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
1416 const struct type *t;
1418 LIST_FOREACH(t, &types, link)
1419 if (t->is_enum || t->is_bits)
1424 extract_enum(FILE *fp, const char *name)
1426 const struct type *t;
1428 LIST_FOREACH(t, &types, link)
1429 if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
1437 main(int argc, char *argv[])
1444 char fname[MAXPATHLEN + 1];
1447 char *infile = NULL;
1449 while ((opt = getopt(argc, argv, "dEehI:i:lp:t")) != EOF)
1457 fprintf(stderr, "%s", usgtxt);
1481 file_prefix = optarg;
1482 if (strlen(file_prefix) + strlen("tree.c") >
1484 errx(1, "prefix too long");
1492 if (do_extract + do_tree + do_enums > 1)
1493 errx(1, "conflicting options -e/-t/-E");
1494 if (!do_extract && !do_enums && argc != optind)
1495 errx(1, "no arguments allowed");
1496 if ((do_extract || do_enums) && argc == optind)
1497 errx(1, "no objects specified");
1499 if (infile == NULL) {
1500 input_new(stdin, NULL, "<stdin>");
1502 if ((fp = fopen(infile, "r")) == NULL)
1503 err(1, "%s", infile);
1504 input_new(fp, NULL, infile);
1507 root = parse_top(gettoken());
1508 while ((tok = gettoken()) != TOK_EOF)
1509 merge(&root, parse_top(tok));
1514 while (optind < argc) {
1515 if (gen_extract(stdout, root, argv[optind]))
1516 errx(1, "object not found: %s", argv[optind]);
1522 while (optind < argc) {
1523 if (extract_enum(stdout, argv[optind]))
1524 errx(1, "enum not found: %s", argv[optind]);
1533 sprintf(fname, "%stree.h", file_prefix);
1534 if ((fp = fopen(fname, "w")) == NULL)
1535 err(1, "%s: ", fname);
1536 gen_header(fp, root, PREFIX_LEN, NULL);
1538 fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
1540 fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
1542 fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
1543 fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
1547 sprintf(fname, "%stree.c", file_prefix);
1548 if ((fp = fopen(fname, "w")) == NULL)
1549 err(1, "%s: ", fname);
1550 gen_table(fp, root);