From f467eea07a293b5abac9d5967a6d61c11194fa8d Mon Sep 17 00:00:00 2001 From: harti Date: Tue, 30 May 2006 07:46:52 +0000 Subject: Vendor patch: add support for the BITS construct and enumerations in both gensnmpdef and gensnmptree. Add include and typedef directives to gensnmptree. Submitted by: soc-sheryana (partly) --- contrib/bsnmp/NEWS | 4 + contrib/bsnmp/gensnmpdef/gensnmpdef.1 | 31 +- contrib/bsnmp/gensnmpdef/gensnmpdef.c | 172 +++++++- contrib/bsnmp/gensnmptree/gensnmptree.1 | 103 +++-- contrib/bsnmp/gensnmptree/gensnmptree.c | 719 ++++++++++++++++++++++++++++---- 5 files changed, 915 insertions(+), 114 deletions(-) (limited to 'contrib/bsnmp') diff --git a/contrib/bsnmp/NEWS b/contrib/bsnmp/NEWS index e8f0285..6364017 100644 --- a/contrib/bsnmp/NEWS +++ b/contrib/bsnmp/NEWS @@ -1,3 +1,7 @@ +1.12a + Support for ENUM and BITS in gensnmp{tree,def}. Include directives + and typedefs. + 1.12 A couple of man page fixes from various submitters. diff --git a/contrib/bsnmp/gensnmpdef/gensnmpdef.1 b/contrib/bsnmp/gensnmpdef/gensnmpdef.1 index d8b966c..8062031 100644 --- a/contrib/bsnmp/gensnmpdef/gensnmpdef.1 +++ b/contrib/bsnmp/gensnmpdef/gensnmpdef.1 @@ -1,5 +1,5 @@ .\" -.\" Copyright (C) 2004-2005 +.\" Copyright (C) 2004-2006 .\" Hartmut Brandt. .\" All rights reserved. .\" @@ -26,9 +26,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Begemot: bsnmp/gensnmpdef/gensnmpdef.1,v 1.5 2005/10/04 08:46:46 brandt_h Exp $ +.\" $Begemot: gensnmpdef.1 383 2006-05-30 07:40:49Z brandt_h $ .\" -.Dd June 14, 2005 +.Dd May 28, 2006 .Dt GENSNMPDEF 1 .Os .Sh NAME @@ -36,7 +36,7 @@ .Nd "generate a MIB description file from MIBs" .Sh SYNOPSIS .Nm -.Op Fl h +.Op Fl hEe .Op Fl c Ar cut .Ar name Op Ar ... .Sh DESCRIPTION @@ -48,13 +48,28 @@ The description file must be edited to be actually useful for feeding it into .Xr gensnmptree 1 . .Pp -The -.Fl c -option specifies the number of initial sub-oids that should be omitted -from the tree. +The following options are available: +.Bl -tag -width indent +.It Fl c Ar cut +Specify the number of initial sub-oids that should be omitted +from the tree in the output. .Xr gensnmptree 1 automatically adds 1.3.6 in front of all OIDs so the default value of 3 is just correct in most cases. +.It Fl E +Generate typedefs for named enumerations. +These are enumerations defined via the TEXTUAL-CONVENTION macro. +The normal tree output is suppressed. +.It Fl e +Generate typedefs for unnamed enumerations. +These are enumerations defined in the SYNTAX clause of an OBJECT-TYPE macro. +The name of the enumeration is formed by appending the string +.Ql Type +to the name of the object. +The normal tree output is suppressed. +.It Fl h +Print a short help text and exit. +.El .Pp .Nm does no attempt on sorting the OID tree so in case of complex and diff --git a/contrib/bsnmp/gensnmpdef/gensnmpdef.c b/contrib/bsnmp/gensnmpdef/gensnmpdef.c index f752d3a..55c02c7 100644 --- a/contrib/bsnmp/gensnmpdef/gensnmpdef.c +++ b/contrib/bsnmp/gensnmpdef/gensnmpdef.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 + * Copyright (C) 2004-2006 * Hartmut Brandt. * All rights reserved. * @@ -26,8 +26,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Begemot: bsnmp/gensnmpdef/gensnmpdef.c,v 1.3 2004/08/06 08:46:45 brandt Exp $ + * $Begemot: gensnmpdef.c 383 2006-05-30 07:40:49Z brandt_h $ */ +#include + #include #include #include @@ -38,9 +40,13 @@ #include static const char usgtxt[] = -"Usage: gensnmpdef [-h] [-c ] MIB [MIB ...]\n" +"Usage: gensnmpdef [-hEe] [-c ] MIB [MIB ...]\n" "Options:\n" " -c specify the number of initial sub-oids to cut from the oids\n" +" -E extract named enum types. Print a typedef for all enums defined\n" +" in syntax clauses of normal objects. Suppress normal output.\n" +" -e extract unnamed enum types. Print a typedef for all enums defined\n" +" as textual conventions. Suppress normal output.\n" " -h print this help\n" "MIBs are searched according to the libsmi(3) search rules and can\n" "be specified either by path or module name\n"; @@ -48,6 +54,14 @@ static const char usgtxt[] = static SmiNode *last_node; static u_int cut = 3; +struct tdef { + char *name; + SLIST_ENTRY(tdef) link; +}; + +static SLIST_HEAD(, tdef) tdefs = SLIST_HEAD_INITIALIZER(tdef); +static int do_typedef = 0; + static void print_node(SmiNode *n, u_int level); static void @@ -135,7 +149,7 @@ static const char *const type_names[] = { [SMI_BASETYPE_FLOAT32] = "FLOAT32", [SMI_BASETYPE_FLOAT64] = "FLOAT64", [SMI_BASETYPE_FLOAT128] = "FLOAT128", - [SMI_BASETYPE_ENUM] = "INTEGER", + [SMI_BASETYPE_ENUM] = "ENUM", [SMI_BASETYPE_BITS] = "BITS", }; @@ -152,6 +166,18 @@ static const char *const type_map[] = { }; static void +print_enum(SmiType *t) +{ + SmiNamedNumber *nnum; + + printf(" ("); + for (nnum = smiGetFirstNamedNumber(t); nnum != NULL; + nnum = smiGetNextNamedNumber(nnum)) + printf(" %ld %s", nnum->value.value.integer32, nnum->name); + printf(" )"); +} + +static void print_type(SmiNode *n) { SmiType *type; @@ -168,6 +194,14 @@ print_type(SmiNode *n) } } printf("%s", type_names[type->basetype]); + + if (type->basetype == SMI_BASETYPE_ENUM || + type->basetype == SMI_BASETYPE_BITS) + print_enum(type); + + else if (type->basetype == SMI_BASETYPE_OCTETSTRING && + type->name != NULL) + printf(" | %s", type->name); } static void @@ -359,6 +393,111 @@ print_node(SmiNode *n, u_int level) printf(")\n"); } +static void +save_typdef(char *name) +{ + struct tdef *t; + t = malloc(sizeof(struct tdef)); + + if (t == NULL) + err(1, NULL); + + memset(t, 0 , sizeof(struct tdef)); + t->name = name; + SLIST_INSERT_HEAD(&tdefs, t, link); +} + +static void +tdefs_cleanup(void) +{ + struct tdef *t; + + while ((t = SLIST_FIRST(&tdefs)) != NULL) { + SLIST_REMOVE_HEAD(&tdefs, link); + free(t); + } +} + +static void +print_enum_typedef(SmiType *t) +{ + SmiNamedNumber *nnum; + + for (nnum = smiGetFirstNamedNumber(t); nnum != NULL; + nnum = smiGetNextNamedNumber(nnum)) { + printf("\t%ld %s\n" , nnum->value.value.integer32, nnum->name); + } +} + +static void +print_stype(SmiNode *n) +{ + SmiType *type; + struct tdef *t = NULL; + + type = smiGetNodeType(n); + assert(type != NULL); + + if (type->basetype == SMI_BASETYPE_ENUM) { + if (do_typedef == 'e' && type->name != NULL) { + SLIST_FOREACH(t, &tdefs, link) { + if (strcmp(t->name, type->name) == 0) + return; + } + save_typdef(type->name); + printf("typedef %s ENUM (\n", type->name); + } else if (do_typedef == 'E' && type->name == NULL) + printf("typedef %sType ENUM (\n", n->name); + else + return; + + print_enum_typedef(type); + printf(")\n\n"); + + } else if (type->basetype == SMI_BASETYPE_BITS) { + if (do_typedef == 'e' && type->name != NULL) { + SLIST_FOREACH(t, &tdefs, link) { + if (strcmp(t->name, type->name) == 0) + return; + } + save_typdef(type->name); + printf("typedef %s BITS (\n", type->name); + } else if (do_typedef == 'E' && type->name == NULL) + printf("typedef %sType BITS (\n", n->name); + else + return; + + print_enum_typedef(type); + printf(")\n\n"); + } +} + +static void +print_typdefs(SmiNode *n) +{ + SmiNode *p; + + p = n; + n = smiGetFirstChildNode(n); + while (n != NULL) { + switch (n->nodekind) { + case SMI_NODEKIND_SCALAR: + case SMI_NODEKIND_COLUMN: + print_stype(n); + break; + case SMI_NODEKIND_COMPLIANCE: + case SMI_NODEKIND_GROUP: + save_node(n); + return; + default: + break; + } + n = smiGetNextChildNode(n); + } + + save_node(p); +} + int main(int argc, char *argv[]) { @@ -373,7 +512,7 @@ main(int argc, char *argv[]) smiInit(NULL); - while ((opt = getopt(argc, argv, "c:h")) != -1) + while ((opt = getopt(argc, argv, "c:Eeh")) != -1) switch (opt) { case 'c': @@ -388,6 +527,14 @@ main(int argc, char *argv[]) cut = (u_int)u; break; + case 'E': + do_typedef = 'E'; + break; + + case 'e': + do_typedef = 'e'; + break; + case 'h': fprintf(stderr, usgtxt); exit(0); @@ -414,9 +561,12 @@ main(int argc, char *argv[]) for (opt = 0; opt < argc; opt++) { n = smiGetFirstNode(mods[opt], SMI_NODEKIND_ANY); for (;;) { - level = open_node(n, level, &last); - print_it(n, level); - last = n; + if (do_typedef == 0) { + level = open_node(n, level, &last); + print_it(n, level); + last = n; + } else + print_typdefs(n); if (last_node == NULL || (n = smiGetNextNode(last_node, SMI_NODEKIND_ANY)) @@ -424,6 +574,10 @@ main(int argc, char *argv[]) break; } } - level = close_node(last->oidlen - 1, level - 1); + if (last != NULL && do_typedef == 0) + level = close_node(last->oidlen - 1, level - 1); + else if (do_typedef != 0) + tdefs_cleanup(); + return (0); } diff --git a/contrib/bsnmp/gensnmptree/gensnmptree.1 b/contrib/bsnmp/gensnmptree/gensnmptree.1 index 593c67a..930f426 100644 --- a/contrib/bsnmp/gensnmptree/gensnmptree.1 +++ b/contrib/bsnmp/gensnmptree/gensnmptree.1 @@ -2,6 +2,9 @@ .\" Copyright (c) 2001-2005 .\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). .\" All rights reserved. +.\" Copyright (c) 2006 +.\" Hartmut Brandt +.\" All rights reserved. .\" .\" Author: Harti Brandt .\" @@ -26,9 +29,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Begemot: bsnmp/gensnmptree/gensnmptree.1,v 1.7 2006/02/27 09:52:08 brandt_h Exp $ +.\" $Begemot: gensnmptree.1 383 2006-05-30 07:40:49Z brandt_h $ .\" -.Dd February 27, 2006 +.Dd May 26, 2006 .Dt GENSNMPTREE 1 .Os .Sh NAME @@ -36,7 +39,9 @@ .Nd "generate C and header files from a MIB description file" .Sh SYNOPSIS .Nm -.Op Fl helt +.Op Fl dEehlt +.Op Fl I Ar directory +.Op Fl i Ar infile .Op Fl p Ar prefix .Op Ar name Ar ... .Sh DESCRIPTION @@ -49,9 +54,12 @@ The first form is used only for maintaining the daemon or for module writers. The second form may be used by SNMP client program writers. .Pp -If the -.Fl e -option is not used +If none of the options +.Fl e , +.Fl E +or +.FL t +are used .Nm reads a MIB description from its standard input and creates two files: a C-file @@ -61,12 +69,20 @@ containing a table used by during PDU processing and a header file .Ar prefix Ns tree.h -containing appropriate declarations of the callback functions used in this table -and the table itself. +containing appropriate declarations of the callback functions used in this +table, the table itself and definitions for all enums. .Pp -If the -.Fl e -option is specified +The following options are available: +.Bl -tag -width ".Fl E" +.It Fl d +Switch on debugging. +.It Fl E +Extract enumerations and bit constructs. +In this mode the tool emits +a header file that contains for each type given on the command line a +C-enum definition and a preprocessor define that may be used to map +values to strings. +.It Fl e .Nm expects MIB variable names (only the last component) on its command line. It reads a MIB specification from standard input and for each MIB variable @@ -83,13 +99,13 @@ is the length of the OID. .It Va OID_ Ns Ar name is the last component of the OID. .El -.Pp -The options are as follows: -.Bl -tag -width ".Fl d Ar argument" .It Fl h Print a short help page. -.It Fl e -Enter extract mode. +.It Fl I Ar directory +Add the named directory to the include path just before the standard include +directories. +.It Fl i Ar infile +Read from the named file instead of standard input. .It Fl l Generate local preprocessor includes. This is used for bootstrapping @@ -103,26 +119,44 @@ Prefix the file names and the table name with .Sh MIBS The syntax of the MIB description file can formally be specified as follows: .Bd -unfilled -offset indent -file := tree | tree file + file := top | top file + + top := tree | typedef | include + + tree := head elements ')' + + entry := head ':' index STRING elements ')' + + leaf := head type STRING ACCESS ')' + + column := head type ACCESS ')' + + type := BASETYPE | BASETYPE '|' subtype | enum | bits -tree := head elements ')' + subtype := STRING -entry := head ':' index STRING elements ')' + enum := ENUM '(' value ')' -leaf := head TYPE STRING ACCESS ')' + bits := BITS '(' value ')' -column := head TYPE ACCESS ')' + value := INT STRING | INT STRING value -head := '(' INT STRING + head := '(' INT STRING -elements := EMPTY | elements element + elements := EMPTY | elements element -element := tree | leaf + element := tree | leaf | column -index := TYPE | index TYPE + index := type | index type + + typedef := 'typedef' STRING type + + include := 'include' filespec + + filespec := '"' STRING '"' | '<' STRING '>' .Ed .Pp -.Ar TYPE +.Ar BASETYPE specifies a SNMP data type and may be one of .Bl -bullet -offset indent -compact .It @@ -163,10 +197,25 @@ SET is a decimal integer and .Ar STRING is any string starting with a letter or underscore and consisting of -letters, digits and underscores, that is not one of the keywords. +letters, digits, underscores and minuses, that is not one of the keywords. +.Pp +The +.Ar typedef +directive associates a type with a single name. +.Pp +The +.Ar include +directive is replaced by the contents of the named file. .Sh EXAMPLES The following MIB description describes the system group: .Bd -literal -offset indent +include "tc.def" + +typedef AdminStatus ENUM ( + 1 up + 2 down +) + (1 internet (2 mgmt (1 mibII diff --git a/contrib/bsnmp/gensnmptree/gensnmptree.c b/contrib/bsnmp/gensnmptree/gensnmptree.c index 990844a..b69d739 100644 --- a/contrib/bsnmp/gensnmptree/gensnmptree.c +++ b/contrib/bsnmp/gensnmptree/gensnmptree.c @@ -3,7 +3,7 @@ * Fraunhofer Institute for Open Communication Systems (FhG Fokus). * All rights reserved. * - * Copyright (c) 2004 + * Copyright (c) 2004-2006 * Hartmut Brandt. * All rights reserved. * @@ -30,21 +30,35 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Begemot: bsnmp/gensnmptree/gensnmptree.c,v 1.44 2006/02/14 09:04:17 brandt_h Exp $ + * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $ * * Generate OID table from table description. * * Syntax is: * --------- - * file := tree | tree file + * file := top | top file + * + * top := tree | typedef | include * * tree := head elements ')' * * entry := head ':' index STRING elements ')' * - * leaf := head TYPE STRING ACCESS ')' + * leaf := head type STRING ACCESS ')' + * + * column := head type ACCESS ')' + * + * type := BASETYPE | BASETYPE '|' subtype | enum | bits + * + * subtype := STRING * - * column := head TYPE ACCESS ')' + * enum := ENUM '(' value ')' + * + * bits := BITS '(' value ')' + * + * value := optminus INT STRING | optminus INT STRING value + * + * optminus := '-' | EMPTY * * head := '(' INT STRING * @@ -52,8 +66,13 @@ * * element := tree | leaf | column * - * index := TYPE | index TYPE + * index := type | index type + * + * typedef := 'typedef' STRING type * + * include := 'include' filespec + * + * filespec := '"' STRING '"' | '<' STRING '>' */ #include #include @@ -82,20 +101,27 @@ static const asn_subid_t prefix[] = { 1, 3, 6 }; u_int tree_size; static const char *file_prefix = ""; -static FILE *fp; /* if true generate local include paths */ static int localincs = 0; +/* if true print tokens */ +static int debug; + static const char usgtxt[] = "\ -Generate SNMP tables. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ -Open Communication Systems (FhG Fokus). All rights reserved.\n\ -usage: gensnmptree [-hel] [-p prefix] [name]...\n\ +Generate SNMP tables.\n\ +usage: gensnmptree [-dEehlt] [-I directory] [-i infile] [-p prefix]\n\ + [name]...\n\ options:\n\ + -d debug mode\n\ + -E extract the named enums and bits only\n\ + -e extract the named oids or enums\n\ -h print this info\n\ - -e extrace the named oids\n\ + -I directory add directory to include path\n\ + -i ifile read from the named file instead of stdin\n\ -l generate local include directives\n\ -p prefix prepend prefix to file and variable names\n\ + -t generated a .def file\n\ "; /* @@ -153,6 +179,29 @@ struct func { static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs); +struct enums { + const char *name; + long value; + TAILQ_ENTRY(enums) link; +}; + +struct type { + const char *name; + const char *from_fname; + u_int from_lno; + u_int syntax; + int is_enum; + int is_bits; + TAILQ_HEAD(, enums) enums; + LIST_ENTRY(type) link; +}; + +static LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types); + +static void report(const char *, ...) __dead2 __printflike(1, 2); +static void report_node(const struct node *, const char *, ...) + __dead2 __printflike(2, 3); + /************************************************************ * * Allocate memory and panic just in the case... @@ -168,6 +217,164 @@ xalloc(size_t size) return (ptr); } +static char * +savestr(const char *s) +{ + + if (s == NULL) + return (NULL); + return (strcpy(xalloc(strlen(s) + 1), s)); +} + +/************************************************************ + * + * Input stack + */ +struct input { + FILE *fp; + u_int lno; + char *fname; + char *path; + LIST_ENTRY(input) link; +}; +static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs); +static struct input *input = NULL; + +#define MAX_PATHS 100 +static u_int npaths = 2; +static u_int stdpaths = 2; +static const char *paths[MAX_PATHS + 1] = { + "/usr/share/snmp/defs", + "/usr/local/share/snmp/defs", + NULL +}; + +static int pbchar = -1; + +static void +path_new(const char *path) +{ + if (npaths >= MAX_PATHS) + report("too many -I directives"); + memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths], + sizeof(path[0]) * stdpaths); + paths[npaths - stdpaths] = savestr(path); + npaths++; +} + +static void +input_new(FILE *fp, const char *path, const char *fname) +{ + struct input *ip; + + ip = xalloc(sizeof(*ip)); + ip->fp = fp; + ip->lno = 1; + ip->fname = savestr(fname); + ip->path = savestr(path); + LIST_INSERT_HEAD(&inputs, ip, link); + + input = ip; +} + +static void +input_close(void) +{ + + if (input == NULL) + return; + fclose(input->fp); + free(input->fname); + free(input->path); + LIST_REMOVE(input, link); + free(input); + + input = LIST_FIRST(&inputs); +} + +static FILE * +tryopen(const char *path, const char *fname) +{ + char *fn; + FILE *fp; + + if (path == NULL) + fn = savestr(fname); + else { + fn = xalloc(strlen(path) + strlen(fname) + 2); + sprintf(fn, "%s/%s", path, fname); + } + fp = fopen(fn, "r"); + free(fn); + return (fp); +} + +static void +input_fopen(const char *fname, int loc) +{ + FILE *fp; + char *path; + u_int p; + + if (fname[0] == '/') { + if ((fp = tryopen(NULL, fname)) != NULL) { + input_new(fp, NULL, fname); + return; + } + + } else { + if (loc) { + if (input == NULL) + path = NULL; + else + path = input->path; + + if ((fp = tryopen(path, fname)) != NULL) { + input_new(fp, NULL, fname); + return; + } + } + + for (p = 0; paths[p] != NULL; p++) + if ((fp = tryopen(paths[p], fname)) != NULL) { + input_new(fp, paths[p], fname); + return; + } + } + report("cannot open '%s'", fname); +} + +static int +tgetc(void) +{ + int c; + + if (pbchar != -1) { + c = pbchar; + pbchar = -1; + return (c); + } + + for (;;) { + if (input == NULL) + return (EOF); + + if ((c = getc(input->fp)) != EOF) + return (c); + + input_close(); + } +} + +static void +tungetc(int c) +{ + + if (pbchar != -1) + abort(); + pbchar = c; +} + /************************************************************ * * Parsing input @@ -178,6 +385,12 @@ enum tok { TOK_STR, /* string */ TOK_ACCESS, /* access operator */ TOK_TYPE, /* type operator */ + TOK_ENUM, /* enum token (kind of a type) */ + TOK_TYPEDEF, /* typedef directive */ + TOK_DEFTYPE, /* defined type */ + TOK_INCLUDE, /* include directive */ + TOK_FILENAME, /* filename ("foo.bar" or ) */ + TOK_BITS, /* bits token (kind of a type) */ }; static const struct { @@ -198,6 +411,10 @@ static const struct { { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, + { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER }, + { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING }, + { "typedef", TOK_TYPEDEF, 0 }, + { "include", TOK_INCLUDE, 0 }, { NULL, 0, 0 } }; @@ -205,12 +422,8 @@ static const struct { #define MAXSTR 1000 char str[MAXSTR]; u_long val; /* integer values */ -u_int lno = 1; /* current line number */ int all_cond; /* all conditions are true */ - -static void report(const char *, ...) __dead2 __printflike(1, 2); -static void report_node(const struct node *, const char *, ...) - __dead2 __printflike(2, 3); +int saved_token = -1; /* * Report an error and exit. @@ -222,11 +435,11 @@ report(const char *fmt, ...) int c; va_start(ap, fmt); - fprintf(stderr, "line %u: ", lno); + fprintf(stderr, "line %u: ", input->lno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); fprintf(stderr, "context: \""); - while ((c = getchar()) != EOF && c != '\n') + while ((c = tgetc()) != EOF && c != '\n') fprintf(stderr, "%c", c); fprintf(stderr, "\n"); va_end(ap); @@ -251,24 +464,31 @@ report_node(const struct node *np, const char *fmt, ...) static char * savetok(void) { - return (strcpy(xalloc(strlen(str)+1), str)); + return (savestr(str)); } /* * Get the next token from input. */ static int -gettoken(void) +gettoken_internal(void) { int c; + struct type *t; + + if (saved_token != -1) { + c = saved_token; + saved_token = -1; + return (c); + } again: /* * Skip any whitespace before the next token */ - while ((c = getchar()) != EOF) { + while ((c = tgetc()) != EOF) { if (c == '\n') - lno++; + input->lno++; if (!isspace(c)) break; } @@ -281,9 +501,9 @@ gettoken(void) * Skip comments */ if (c == '#') { - while ((c = getchar()) != EOF) { + while ((c = tgetc()) != EOF) { if (c == '\n') { - lno++; + input->lno++; goto again; } } @@ -293,15 +513,51 @@ gettoken(void) /* * Single character tokens */ - if (c == ')' || c == '(' || c == ':') + if (strchr("():|-", c) != NULL) return (c); + if (c == '"' || c == '<') { + int end = c; + size_t n = 0; + + val = 1; + if (c == '<') { + val = 0; + end = '>'; + } + + while ((c = tgetc()) != EOF) { + if (c == end) + break; + if (n == sizeof(str) - 1) { + str[n++] = '\0'; + report("filename too long '%s...'", str); + } + str[n++] = c; + } + str[n++] = '\0'; + return (TOK_FILENAME); + } + /* * Sort out numbers */ if (isdigit(c)) { - ungetc(c, stdin); - scanf("%lu", &val); + size_t n = 0; + str[n++] = c; + while ((c = tgetc()) != EOF) { + if (!isdigit(c)) { + tungetc(c); + break; + } + if (n == sizeof(str) - 1) { + str[n++] = '\0'; + report("number too long '%s...'", str); + } + str[n++] = c; + } + str[n++] = '\0'; + sscanf(str, "%lu", &val); return (TOK_NUM); } @@ -311,9 +567,9 @@ gettoken(void) if (isalpha(c) || c == '_') { size_t n = 0; str[n++] = c; - while ((c = getchar()) != EOF) { - if (!isalnum(c) && c != '_') { - ungetc(c, stdin); + while ((c = tgetc()) != EOF) { + if (!isalnum(c) && c != '_' && c != '-') { + tungetc(c); break; } if (n == sizeof(str) - 1) { @@ -333,12 +589,181 @@ gettoken(void) return (keywords[c].tok); } + LIST_FOREACH(t, &types, link) { + if (strcmp(t->name, str) == 0) { + val = t->syntax; + return (TOK_DEFTYPE); + } + } return (TOK_STR); } if (isprint(c)) - errx(1, "%u: unexpected character '%c'", lno, c); + errx(1, "%u: unexpected character '%c'", input->lno, c); else - errx(1, "%u: unexpected character 0x%02x", lno, (u_int)c); + errx(1, "%u: unexpected character 0x%02x", input->lno, + (u_int)c); +} +static int +gettoken(void) +{ + int tok = gettoken_internal(); + + if (debug) { + switch (tok) { + + case TOK_EOF: + fprintf(stderr, "EOF "); + break; + + case TOK_NUM: + fprintf(stderr, "NUM(%lu) ", val); + break; + + case TOK_STR: + fprintf(stderr, "STR(%s) ", str); + break; + + case TOK_ACCESS: + fprintf(stderr, "ACCESS(%lu) ", val); + break; + + case TOK_TYPE: + fprintf(stderr, "TYPE(%lu) ", val); + break; + + case TOK_ENUM: + fprintf(stderr, "ENUM "); + break; + + case TOK_BITS: + fprintf(stderr, "BITS "); + break; + + case TOK_TYPEDEF: + fprintf(stderr, "TYPEDEF "); + break; + + case TOK_DEFTYPE: + fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val); + break; + + case TOK_INCLUDE: + fprintf(stderr, "INCLUDE "); + break; + + case TOK_FILENAME: + fprintf(stderr, "FILENAME "); + break; + + default: + if (tok < TOK_EOF) { + if (isprint(tok)) + fprintf(stderr, "'%c' ", tok); + else if (tok == '\n') + fprintf(stderr, "\n"); + else + fprintf(stderr, "%02x ", tok); + } else + abort(); + break; + } + } + return (tok); +} + +/** + * Pushback a token + */ +static void +pushback(enum tok tok) +{ + + if (saved_token != -1) + abort(); + saved_token = tok; +} + +/* + * Create a new type + */ +static struct type * +make_type(const char *s) +{ + struct type *t; + + t = xalloc(sizeof(*t)); + t->name = savestr(s); + t->is_enum = 0; + t->syntax = SNMP_SYNTAX_NULL; + t->from_fname = savestr(input->fname); + t->from_lno = input->lno; + TAILQ_INIT(&t->enums); + LIST_INSERT_HEAD(&types, t, link); + + return (t); +} + +/* + * Parse a type. We've seen the ENUM or type keyword already. Leave next + * token. + */ +static u_int +parse_type(enum tok *tok, struct type *t, const char *vname) +{ + u_int syntax; + struct enums *e; + + syntax = val; + + if (*tok == TOK_ENUM || *tok == TOK_BITS) { + if (t == NULL && vname != NULL) { + t = make_type(vname); + t->is_enum = (*tok == TOK_ENUM); + t->is_bits = (*tok == TOK_BITS); + t->syntax = syntax; + } + if (gettoken() != '(') + report("'(' expected after ENUM"); + + if ((*tok = gettoken()) == TOK_EOF) + report("unexpected EOF in ENUM"); + do { + e = NULL; + if (t != NULL) { + e = xalloc(sizeof(*e)); + } + if (*tok == '-') { + if ((*tok = gettoken()) == TOK_EOF) + report("unexpected EOF in ENUM"); + e->value = -(long)val; + } else + e->value = val; + + if (*tok != TOK_NUM) + report("need value for ENUM/BITS"); + if (gettoken() != TOK_STR) + report("need string in ENUM/BITS"); + if (e != NULL) { + e->name = savetok(); + TAILQ_INSERT_TAIL(&t->enums, e, link); + } + if ((*tok = gettoken()) == TOK_EOF) + report("unexpected EOF in ENUM/BITS"); + } while (*tok != ')'); + *tok = gettoken(); + + } else if (*tok == TOK_DEFTYPE) { + *tok = gettoken(); + + } else { + if ((*tok = gettoken()) == '|') { + if (gettoken() != TOK_STR) + report("subtype expected after '|'"); + *tok = gettoken(); + } + } + + return (syntax); } /* @@ -352,7 +777,7 @@ parse(enum tok tok) u_int index_count; node = xalloc(sizeof(struct node)); - node->lno = lno; + node->lno = input->lno; node->flags = 0; if (tok != '(') @@ -366,11 +791,12 @@ parse(enum tok tok) report("node name expected after '(' ID"); node->name = savetok(); - if ((tok = gettoken()) == TOK_TYPE) { + if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || + tok == TOK_ENUM || tok == TOK_BITS) { /* LEAF or COLUM */ - u_int syntax = val; + u_int syntax = parse_type(&tok, NULL, node->name); - if ((tok = gettoken()) == TOK_STR) { + if (tok == TOK_STR) { /* LEAF */ node->type = NODE_LEAF; node->u.leaf.func = savetok(); @@ -396,16 +822,18 @@ parse(enum tok tok) index_count = 0; node->u.entry.index = 0; - while ((tok = gettoken()) == TOK_TYPE) { + tok = gettoken(); + while (tok == TOK_TYPE || tok == TOK_DEFTYPE || + tok == TOK_ENUM || tok == TOK_BITS) { + u_int syntax = parse_type(&tok, NULL, node->name); if (index_count++ == SNMP_INDEXES_MAX) report("too many table indexes"); node->u.entry.index |= - val << (SNMP_INDEX_SHIFT * index_count); + syntax << (SNMP_INDEX_SHIFT * index_count); } node->u.entry.index |= index_count; if (index_count == 0) report("need at least one index"); - if (tok != TOK_STR) report("function name expected"); @@ -434,10 +862,49 @@ parse(enum tok tok) } /* + * Parse a top level element. Return the tree if it was a tree, NULL + * otherwise. + */ +static struct node * +parse_top(enum tok tok) +{ + struct type *t; + + if (tok == '(') + return (parse(tok)); + + if (tok == TOK_TYPEDEF) { + if (gettoken() != TOK_STR) + report("type name expected after typedef"); + + t = make_type(str); + + tok = gettoken(); + t->is_enum = (tok == TOK_ENUM); + t->is_bits = (tok == TOK_BITS); + t->syntax = parse_type(&tok, t, NULL); + pushback(tok); + + return (NULL); + } + + if (tok == TOK_INCLUDE) { + if (gettoken() != TOK_FILENAME) + report("filename expected in include directive"); + + input_fopen(str, val); + return (NULL); + } + + report("'(' or 'typedef' expected"); +} + +/* * Generate the C-code table part for one node. */ static void -gen_node(struct node *np, struct asn_oid *oid, u_int idx, const char *func) +gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx, + const char *func) { u_int n; struct node *sub; @@ -449,13 +916,14 @@ gen_node(struct node *np, struct asn_oid *oid, u_int idx, const char *func) if (np->type == NODE_TREE) { TAILQ_FOREACH(sub, &np->u.tree.subs, link) - gen_node(sub, oid, 0, NULL); + gen_node(fp, sub, oid, 0, NULL); oid->len--; return; } if (np->type == NODE_ENTRY) { TAILQ_FOREACH(sub, &np->u.entry.subs, link) - gen_node(sub, oid, np->u.entry.index, np->u.entry.func); + gen_node(fp, sub, oid, np->u.entry.index, + np->u.entry.func); oid->len--; return; } @@ -540,7 +1008,7 @@ gen_node(struct node *np, struct asn_oid *oid, u_int idx, const char *func) * Generate the header file with the function declarations. */ static void -gen_header(struct node *np, u_int oidlen, const char *func) +gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func) { char f[MAXSTR + 4]; struct node *sub; @@ -549,12 +1017,12 @@ gen_header(struct node *np, u_int oidlen, const char *func) oidlen++; if (np->type == NODE_TREE) { TAILQ_FOREACH(sub, &np->u.tree.subs, link) - gen_header(sub, oidlen, NULL); + gen_header(fp, sub, oidlen, NULL); return; } if (np->type == NODE_ENTRY) { TAILQ_FOREACH(sub, &np->u.entry.subs, link) - gen_header(sub, oidlen, np->u.entry.func); + gen_header(fp, sub, oidlen, np->u.entry.func); return; } @@ -575,7 +1043,7 @@ gen_header(struct node *np, u_int oidlen, const char *func) if (ptr == NULL) { ptr = xalloc(sizeof(*ptr)); - ptr->name = strcpy(xalloc(strlen(f)+1), f); + ptr->name = savestr(f); LIST_INSERT_HEAD(&funcs, ptr, link); fprintf(fp, "int %s(struct snmp_context *, " @@ -590,7 +1058,7 @@ gen_header(struct node *np, u_int oidlen, const char *func) * Generate the OID table. */ static void -gen_table(struct node *node) +gen_table(FILE *fp, struct node *node) { struct asn_oid oid; @@ -615,7 +1083,7 @@ gen_table(struct node *node) oid.len = PREFIX_LEN; memcpy(oid.subs, prefix, sizeof(prefix)); - gen_node(node, &oid, 0, NULL); + gen_node(fp, node, &oid, 0, NULL); fprintf(fp, "};\n\n"); } @@ -681,12 +1149,11 @@ gen_tree(const struct node *np, int level) printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", (np->flags & FL_SET) ? " SET" : ""); break; - } } static int -extract(const struct node *np, struct asn_oid *oid, const char *obj, +extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj, const struct asn_oid *idx, const char *iname) { struct node *sub; @@ -715,11 +1182,11 @@ extract(const struct node *np, struct asn_oid *oid, const char *obj, if (np->type == NODE_TREE) { TAILQ_FOREACH(sub, &np->u.tree.subs, link) - if (!extract(sub, oid, obj, idx, iname)) + if (!extract(fp, sub, oid, obj, idx, iname)) return (0); } else if (np->type == NODE_ENTRY) { TAILQ_FOREACH(sub, &np->u.entry.subs, link) - if (!extract(sub, oid, obj, idx, iname)) + if (!extract(fp, sub, oid, obj, idx, iname)) return (0); } oid->len--; @@ -727,7 +1194,7 @@ extract(const struct node *np, struct asn_oid *oid, const char *obj, } static int -gen_extract(const struct node *root, char *object) +gen_extract(FILE *fp, const struct node *root, char *object) { struct asn_oid oid; struct asn_oid idx; @@ -773,7 +1240,7 @@ gen_extract(const struct node *root, char *object) oid.len = PREFIX_LEN; memcpy(oid.subs, prefix, sizeof(prefix)); - ret = extract(root, &oid, object, &idx, iname); + ret = extract(fp, root, &oid, object, &idx, iname); if (iname != NULL) free(iname); @@ -879,18 +1346,93 @@ merge_subs(struct node_list *s1, struct node_list *s2) } static void -merge(struct node *root, struct node *t) +merge(struct node **root, struct node *t) { + if (*root == NULL) { + *root = t; + return; + } + if (t == NULL) + return; + /* both must be trees */ - if (root->type != NODE_TREE) + if ((*root)->type != NODE_TREE) errx(1, "root is not a tree"); if (t->type != NODE_TREE) errx(1, "can merge only with tree"); - if (root->id != t->id) + if ((*root)->id != t->id) errx(1, "trees to merge must have same id"); - merge_subs(&root->u.tree.subs, &t->u.tree.subs); + merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs); +} + +static void +unminus(FILE *fp, const char *s) +{ + + while (*s != '\0') { + if (*s == '-') + fprintf(fp, "_"); + else + fprintf(fp, "%c", *s); + s++; + } +} + +static void +gen_enum(FILE *fp, const struct type *t) +{ + const struct enums *e; + long min = LONG_MAX; + + fprintf(fp, "\n"); + fprintf(fp, "#ifndef %s_defined__\n", t->name); + fprintf(fp, "#define %s_defined__\n", t->name); + fprintf(fp, "/*\n"); + fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno); + fprintf(fp, " */\n"); + fprintf(fp, "enum %s {\n", t->name); + TAILQ_FOREACH(e, &t->enums, link) { + fprintf(fp, "\t%s_", t->name); + unminus(fp, e->name); + fprintf(fp, " = %ld,\n", e->value); + if (e->value < min) + min = e->value; + } + fprintf(fp, "};\n"); + fprintf(fp, "#define STROFF_%s %ld\n", t->name, min); + fprintf(fp, "#define STRING_%s \\\n", t->name); + TAILQ_FOREACH(e, &t->enums, link) { + fprintf(fp, "\t[%ld] \"%s_", e->value - min, t->name); + unminus(fp, e->name); + fprintf(fp, "\",\\\n"); + } + fprintf(fp, "\n"); + fprintf(fp, "#endif /* %s_defined__ */\n", t->name); +} + +static void +gen_enums(FILE *fp) +{ + const struct type *t; + + LIST_FOREACH(t, &types, link) + if (t->is_enum || t->is_bits) + gen_enum(fp, t); +} + +static int +extract_enum(FILE *fp, const char *name) +{ + const struct type *t; + + LIST_FOREACH(t, &types, link) + if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { + gen_enum(fp, t); + return (0); + } + return (-1); } int @@ -898,22 +1440,41 @@ main(int argc, char *argv[]) { int do_extract = 0; int do_tree = 0; + int do_enums = 0; int opt; struct node *root; char fname[MAXPATHLEN + 1]; int tok; + FILE *fp; + char *infile = NULL; - while ((opt = getopt(argc, argv, "help:t")) != EOF) + while ((opt = getopt(argc, argv, "dEehI:i:lp:t")) != EOF) switch (opt) { + case 'd': + debug = 1; + break; + case 'h': fprintf(stderr, "%s", usgtxt); exit(0); + case 'E': + do_enums = 1; + break; + case 'e': do_extract = 1; break; + case 'I': + path_new(optarg); + break; + + case 'i': + infile = optarg; + break; + case 'l': localincs = 1; break; @@ -930,27 +1491,41 @@ main(int argc, char *argv[]) break; } - if (do_extract && do_tree) - errx(1, "conflicting options -e and -t"); - if (!do_extract && argc != optind) + if (do_extract + do_tree + do_enums > 1) + errx(1, "conflicting options -e/-t/-E"); + if (!do_extract && !do_enums && argc != optind) errx(1, "no arguments allowed"); - if (do_extract && argc == optind) + if ((do_extract || do_enums) && argc == optind) errx(1, "no objects specified"); - root = parse(gettoken()); + if (infile == NULL) { + input_new(stdin, NULL, ""); + } else { + if ((fp = fopen(infile, "r")) == NULL) + err(1, "%s", infile); + input_new(fp, NULL, infile); + } + + root = parse_top(gettoken()); while ((tok = gettoken()) != TOK_EOF) - merge(root, parse(tok)); + merge(&root, parse_top(tok)); check_tree(root); if (do_extract) { - fp = stdout; while (optind < argc) { - if (gen_extract(root, argv[optind])) + if (gen_extract(stdout, root, argv[optind])) errx(1, "object not found: %s", argv[optind]); optind++; } - + return (0); + } + if (do_enums) { + while (optind < argc) { + if (extract_enum(stdout, argv[optind])) + errx(1, "enum not found: %s", argv[optind]); + optind++; + } return (0); } if (do_tree) { @@ -960,7 +1535,11 @@ main(int argc, char *argv[]) sprintf(fname, "%stree.h", file_prefix); if ((fp = fopen(fname, "w")) == NULL) err(1, "%s: ", fname); - gen_header(root, PREFIX_LEN, NULL); + gen_header(fp, root, PREFIX_LEN, NULL); + + fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); + gen_enums(fp); + fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n"); fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); @@ -970,7 +1549,7 @@ main(int argc, char *argv[]) sprintf(fname, "%stree.c", file_prefix); if ((fp = fopen(fname, "w")) == NULL) err(1, "%s: ", fname); - gen_table(root); + gen_table(fp, root); fclose(fp); return (0); -- cgit v1.1