summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHartmut Brandt <harti@FreeBSD.org>2006-05-30 07:46:52 +0000
committerHartmut Brandt <harti@FreeBSD.org>2006-05-30 07:46:52 +0000
commit6f557cf7be92974e10f78ff4adbd7d5b4d718ef9 (patch)
treebe5e56b85cb4f924ef1751353bcca382349168cb
parent748b5b1ebd1b2c58c21a90cdc5abdd462eeb22b3 (diff)
downloadsrc-test2-6f557cf7be92974e10f78ff4adbd7d5b4d718ef9.tar.gz
src-test2-6f557cf7be92974e10f78ff4adbd7d5b4d718ef9.zip
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)
Notes
Notes: svn path=/vendor/bsnmp/dist/; revision=159063
-rw-r--r--contrib/bsnmp/NEWS4
-rw-r--r--contrib/bsnmp/gensnmpdef/gensnmpdef.131
-rw-r--r--contrib/bsnmp/gensnmpdef/gensnmpdef.c172
-rw-r--r--contrib/bsnmp/gensnmptree/gensnmptree.1103
-rw-r--r--contrib/bsnmp/gensnmptree/gensnmptree.c719
5 files changed, 915 insertions, 114 deletions
diff --git a/contrib/bsnmp/NEWS b/contrib/bsnmp/NEWS
index e8f02850dbfc..63640179bdf5 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 d8b966cb0ae5..806203180676 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 f752d3a5a284..55c02c7191a5 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 <sys/queue.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -38,9 +40,13 @@
#include <smi.h>
static const char usgtxt[] =
-"Usage: gensnmpdef [-h] [-c <cut>] MIB [MIB ...]\n"
+"Usage: gensnmpdef [-hEe] [-c <cut>] 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 593c67abdb19..930f4269456c 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 <harti@freebsd.org>
.\"
@@ -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 990844a0eade..b69d739a3b16 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 <sys/types.h>
#include <sys/param.h>
@@ -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 <foo.bar>) */
+ 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, "<stdin>");
+ } 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);