Changeset View
Changeset View
Standalone View
Standalone View
head/contrib/bsnmp/gensnmptree/gensnmptree.c
Show First 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | |||||
/* if true generate local include paths */ | /* if true generate local include paths */ | ||||
static int localincs = 0; | static int localincs = 0; | ||||
/* if true print tokens */ | /* if true print tokens */ | ||||
static int debug; | static int debug; | ||||
static const char usgtxt[] = "\ | static const char usgtxt[] = "\ | ||||
Generate SNMP tables.\n\ | Generate SNMP tables.\n\ | ||||
$Id$\n\ | |||||
usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\ | usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\ | ||||
[name]...\n\ | [name]...\n\ | ||||
options:\n\ | options:\n\ | ||||
-d debug mode\n\ | -d debug mode\n\ | ||||
-E extract the named or all enums and bits only\n\ | -E extract the named or all enums and bits only\n\ | ||||
-e extract the named oids or enums\n\ | -e extract the named oids or enums\n\ | ||||
-F generate functions for -E into a .c file\n\ | -F generate functions for -E into a .c file\n\ | ||||
-f generate functions for -E into the header\n\ | -f generate functions for -E into the header\n\ | ||||
-h print this info\n\ | -h print this info\n\ | ||||
-I directory add directory to include path\n\ | -I directory add directory to include path\n\ | ||||
-i ifile read from the named file instead of stdin\n\ | -i ifile read from the named file instead of stdin\n\ | ||||
-l generate local include directives\n\ | -l generate local include directives\n\ | ||||
-p prefix prepend prefix to file and variable names\n\ | -p prefix prepend prefix to file and variable names\n\ | ||||
-t generate a .def file\n\ | -t generate a .def file\n\ | ||||
"; | "; | ||||
/** | |||||
* Program operation. | |||||
*/ | |||||
enum op { | |||||
/** generate the tree */ | |||||
OP_GEN, | |||||
/** extract OIDs */ | |||||
OP_EXTRACT, | |||||
/** print the parsed tree */ | |||||
OP_TREE, | |||||
/** extract enums */ | |||||
OP_ENUMS, | |||||
}; | |||||
/** | |||||
* Which functions to create. | |||||
*/ | |||||
enum gen_funcs { | |||||
/** none */ | |||||
GEN_FUNCS_NONE, | |||||
/** functions for header files */ | |||||
GEN_FUNCS_H, | |||||
/** functions for C files */ | |||||
GEN_FUNCS_C, | |||||
}; | |||||
/* | /* | ||||
* A node in the OID tree | * A node in the OID tree | ||||
*/ | */ | ||||
enum ntype { | enum ntype { | ||||
NODE_LEAF = 1, | NODE_LEAF = 1, | ||||
NODE_TREE, | NODE_TREE, | ||||
NODE_ENTRY, | NODE_ENTRY, | ||||
NODE_COLUMN | NODE_COLUMN | ||||
Show All 19 Lines | union { | ||||
struct tree { | struct tree { | ||||
struct node_list subs; | struct node_list subs; | ||||
} tree; | } tree; | ||||
struct entry { | struct entry { | ||||
uint32_t index; /* index for table entry */ | uint32_t index; /* index for table entry */ | ||||
char *func; /* function for tables */ | char *func; /* function for tables */ | ||||
struct node_list subs; | struct node_list subs; | ||||
char *subtypes[SNMP_INDEXES_MAX]; | |||||
} entry; | } entry; | ||||
struct leaf { | struct leaf { | ||||
enum snmp_syntax syntax; /* syntax for this leaf */ | enum snmp_syntax syntax; /* syntax for this leaf */ | ||||
char *func; /* function name */ | char *func; /* function name */ | ||||
char *subtype; /* subtype */ | |||||
} leaf; | } leaf; | ||||
struct column { | struct column { | ||||
enum snmp_syntax syntax; /* syntax for this column */ | enum snmp_syntax syntax; /* syntax for this column */ | ||||
char *subtype; /* subtype */ | |||||
} column; | } column; | ||||
} u; | } u; | ||||
}; | }; | ||||
struct func { | struct func { | ||||
const char *name; | const char *name; | ||||
LIST_ENTRY(func) link; | LIST_ENTRY(func) link; | ||||
}; | }; | ||||
Show All 27 Lines | |||||
* | * | ||||
* Allocate memory and panic just in the case... | * Allocate memory and panic just in the case... | ||||
*/ | */ | ||||
static void * | static void * | ||||
xalloc(size_t size) | xalloc(size_t size) | ||||
{ | { | ||||
void *ptr; | void *ptr; | ||||
if ((ptr = malloc(size)) == NULL) | if ((ptr = calloc(1, size)) == NULL) | ||||
err(1, "allocing %zu bytes", size); | err(1, "allocing %zu bytes", size); | ||||
return (ptr); | return (ptr); | ||||
} | } | ||||
static char * | static char * | ||||
savestr(const char *s) | savestr(const char *s) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 479 Lines • ▼ Show 20 Lines | make_type(const char *s) | ||||
return (t); | return (t); | ||||
} | } | ||||
/* | /* | ||||
* Parse a type. We've seen the ENUM or type keyword already. Leave next | * Parse a type. We've seen the ENUM or type keyword already. Leave next | ||||
* token. | * token. | ||||
*/ | */ | ||||
static u_int | static u_int | ||||
parse_type(enum tok *tok, struct type *t, const char *vname) | parse_type(enum tok *tok, struct type *t, const char *vname, char **subtype) | ||||
{ | { | ||||
u_int syntax; | u_int syntax; | ||||
struct enums *e; | struct enums *e; | ||||
syntax = val; | syntax = val; | ||||
if (subtype != NULL) | |||||
*subtype = NULL; | |||||
if (*tok == TOK_ENUM || *tok == TOK_BITS) { | if (*tok == TOK_ENUM || *tok == TOK_BITS) { | ||||
if (t == NULL && vname != NULL) { | if (t == NULL && vname != NULL) { | ||||
t = make_type(vname); | t = make_type(vname); | ||||
t->is_enum = (*tok == TOK_ENUM); | t->is_enum = (*tok == TOK_ENUM); | ||||
t->is_bits = (*tok == TOK_BITS); | t->is_bits = (*tok == TOK_BITS); | ||||
t->syntax = syntax; | t->syntax = syntax; | ||||
} | } | ||||
Show All 27 Lines | parse_type(enum tok *tok, struct type *t, const char *vname, char **subtype) | ||||
} else if (*tok == TOK_DEFTYPE) { | } else if (*tok == TOK_DEFTYPE) { | ||||
*tok = gettoken(); | *tok = gettoken(); | ||||
} else { | } else { | ||||
if ((*tok = gettoken()) == '|') { | if ((*tok = gettoken()) == '|') { | ||||
if (gettoken() != TOK_STR) | if (gettoken() != TOK_STR) | ||||
report("subtype expected after '|'"); | report("subtype expected after '|'"); | ||||
if (subtype != NULL) | |||||
*subtype = savetok(); | |||||
*tok = gettoken(); | *tok = gettoken(); | ||||
} | } | ||||
} | } | ||||
return (syntax); | return (syntax); | ||||
} | } | ||||
/* | /* | ||||
Show All 19 Lines | parse(enum tok tok) | ||||
node->id = (asn_subid_t)val; | node->id = (asn_subid_t)val; | ||||
if (gettoken() != TOK_STR) | if (gettoken() != TOK_STR) | ||||
report("node name expected after '(' ID"); | report("node name expected after '(' ID"); | ||||
node->name = savetok(); | node->name = savetok(); | ||||
if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || | if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || | ||||
tok == TOK_ENUM || tok == TOK_BITS) { | tok == TOK_ENUM || tok == TOK_BITS) { | ||||
/* LEAF or COLUM */ | /* LEAF or COLUM */ | ||||
u_int syntax = parse_type(&tok, NULL, node->name); | char *subtype; | ||||
u_int syntax = parse_type(&tok, NULL, node->name, &subtype); | |||||
if (tok == TOK_STR) { | if (tok == TOK_STR) { | ||||
/* LEAF */ | /* LEAF */ | ||||
node->type = NODE_LEAF; | node->type = NODE_LEAF; | ||||
node->u.leaf.func = savetok(); | node->u.leaf.func = savetok(); | ||||
node->u.leaf.syntax = syntax; | node->u.leaf.syntax = syntax; | ||||
node->u.leaf.subtype = subtype; | |||||
tok = gettoken(); | tok = gettoken(); | ||||
} else { | } else { | ||||
/* COLUMN */ | /* COLUMN */ | ||||
node->type = NODE_COLUMN; | node->type = NODE_COLUMN; | ||||
node->u.column.syntax = syntax; | node->u.column.syntax = syntax; | ||||
node->u.column.subtype = subtype; | |||||
} | } | ||||
while (tok != ')') { | while (tok != ')') { | ||||
if (tok != TOK_ACCESS) | if (tok != TOK_ACCESS) | ||||
report("access keyword or ')' expected"); | report("access keyword or ')' expected"); | ||||
node->flags |= (u_int)val; | node->flags |= (u_int)val; | ||||
tok = gettoken(); | tok = gettoken(); | ||||
} | } | ||||
} else if (tok == ':') { | } else if (tok == ':') { | ||||
/* ENTRY */ | /* ENTRY */ | ||||
node->type = NODE_ENTRY; | node->type = NODE_ENTRY; | ||||
TAILQ_INIT(&node->u.entry.subs); | TAILQ_INIT(&node->u.entry.subs); | ||||
index_count = 0; | index_count = 0; | ||||
node->u.entry.index = 0; | node->u.entry.index = 0; | ||||
tok = gettoken(); | tok = gettoken(); | ||||
while (tok == TOK_TYPE || tok == TOK_DEFTYPE || | while (tok == TOK_TYPE || tok == TOK_DEFTYPE || | ||||
tok == TOK_ENUM || tok == TOK_BITS) { | tok == TOK_ENUM || tok == TOK_BITS) { | ||||
u_int syntax = parse_type(&tok, NULL, node->name); | char *subtype; | ||||
if (index_count++ == SNMP_INDEXES_MAX) | u_int syntax = parse_type(&tok, NULL, node->name, | ||||
&subtype); | |||||
if (index_count == SNMP_INDEXES_MAX) | |||||
report("too many table indexes"); | report("too many table indexes"); | ||||
node->u.entry.subtypes[index_count++] = subtype; | |||||
node->u.entry.index |= | node->u.entry.index |= | ||||
syntax << (SNMP_INDEX_SHIFT * index_count); | syntax << (SNMP_INDEX_SHIFT * index_count); | ||||
} | } | ||||
node->u.entry.index |= index_count; | node->u.entry.index |= index_count; | ||||
if (index_count == 0) | if (index_count == 0) | ||||
report("need at least one index"); | report("need at least one index"); | ||||
if (tok != TOK_STR) | if (tok != TOK_STR) | ||||
report("function name expected"); | report("function name expected"); | ||||
Show All 38 Lines | if (tok == TOK_TYPEDEF) { | ||||
if (gettoken() != TOK_STR) | if (gettoken() != TOK_STR) | ||||
report("type name expected after typedef"); | report("type name expected after typedef"); | ||||
t = make_type(str); | t = make_type(str); | ||||
tok = gettoken(); | tok = gettoken(); | ||||
t->is_enum = (tok == TOK_ENUM); | t->is_enum = (tok == TOK_ENUM); | ||||
t->is_bits = (tok == TOK_BITS); | t->is_bits = (tok == TOK_BITS); | ||||
t->syntax = parse_type(&tok, t, NULL); | |||||
t->syntax = parse_type(&tok, t, NULL, NULL); | |||||
pushback(tok); | pushback(tok); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if (tok == TOK_INCLUDE) { | if (tok == TOK_INCLUDE) { | ||||
if (gettoken() != TOK_FILENAME) | if (gettoken() != TOK_FILENAME) | ||||
report("filename expected in include directive"); | report("filename expected in include directive"); | ||||
input_fopen(str, val); | input_fopen(str, val); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
report("'(' or 'typedef' expected"); | report("'(' or 'typedef' expected"); | ||||
} | } | ||||
/* | /* | ||||
* Generate the C-code table part for one node. | * Generate the C-code table part for one node. | ||||
*/ | */ | ||||
static void | static void | ||||
gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx, | gen_node(FILE *fp, const struct node *np, struct asn_oid *oid, u_int idx, | ||||
const char *func) | const char *func) | ||||
{ | { | ||||
u_int n; | u_int n; | ||||
struct node *sub; | struct node *sub; | ||||
u_int syntax; | u_int syntax; | ||||
if (oid->len == ASN_MAXOIDLEN) | if (oid->len == ASN_MAXOIDLEN) | ||||
report_node(np, "OID too long"); | report_node(np, "OID too long"); | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | gen_node(FILE *fp, const struct node *np, struct asn_oid *oid, u_int idx, | ||||
oid->len--; | oid->len--; | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Generate the header file with the function declarations. | * Generate the header file with the function declarations. | ||||
*/ | */ | ||||
static void | static void | ||||
gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func) | gen_header(FILE *fp, const struct node *np, u_int oidlen, const char *func) | ||||
{ | { | ||||
char f[MAXSTR + 4]; | char f[MAXSTR + 4]; | ||||
struct node *sub; | struct node *sub; | ||||
struct func *ptr; | struct func *ptr; | ||||
oidlen++; | oidlen++; | ||||
if (np->type == NODE_TREE) { | if (np->type == NODE_TREE) { | ||||
TAILQ_FOREACH(sub, &np->u.tree.subs, link) | TAILQ_FOREACH(sub, &np->u.tree.subs, link) | ||||
Show All 33 Lines | gen_header(FILE *fp, const struct node *np, u_int oidlen, const char *func) | ||||
fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); | fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); | ||||
} | } | ||||
/* | /* | ||||
* Generate the OID table. | * Generate the OID table. | ||||
*/ | */ | ||||
static void | static void | ||||
gen_table(FILE *fp, struct node *node) | gen_table(FILE *fp, const struct node *node) | ||||
{ | { | ||||
struct asn_oid oid; | struct asn_oid oid; | ||||
fprintf(fp, "#include <sys/types.h>\n"); | fprintf(fp, "#include <sys/types.h>\n"); | ||||
fprintf(fp, "#include <stdio.h>\n"); | fprintf(fp, "#include <stdio.h>\n"); | ||||
#ifdef HAVE_STDINT_H | #ifdef HAVE_STDINT_H | ||||
fprintf(fp, "#include <stdint.h>\n"); | fprintf(fp, "#include <stdint.h>\n"); | ||||
#endif | #endif | ||||
fprintf(fp, "#include <string.h>\n"); | |||||
if (localincs) { | if (localincs) { | ||||
fprintf(fp, "#include \"asn1.h\"\n"); | fprintf(fp, "#include \"asn1.h\"\n"); | ||||
fprintf(fp, "#include \"snmp.h\"\n"); | fprintf(fp, "#include \"snmp.h\"\n"); | ||||
fprintf(fp, "#include \"snmpagent.h\"\n"); | fprintf(fp, "#include \"snmpagent.h\"\n"); | ||||
} else { | } else { | ||||
fprintf(fp, "#include <bsnmp/asn1.h>\n"); | fprintf(fp, "#include <bsnmp/asn1.h>\n"); | ||||
fprintf(fp, "#include <bsnmp/snmp.h>\n"); | fprintf(fp, "#include <bsnmp/snmp.h>\n"); | ||||
fprintf(fp, "#include <bsnmp/snmpagent.h>\n"); | fprintf(fp, "#include <bsnmp/snmpagent.h>\n"); | ||||
Show All 34 Lines | gen_tree(const struct node *np, int level) | ||||
u_int i; | u_int i; | ||||
printf("%*s(%u %s", 2 * level, "", np->id, np->name); | printf("%*s(%u %s", 2 * level, "", np->id, np->name); | ||||
switch (np->type) { | switch (np->type) { | ||||
case NODE_LEAF: | case NODE_LEAF: | ||||
print_syntax(np->u.leaf.syntax); | print_syntax(np->u.leaf.syntax); | ||||
if (np->u.leaf.subtype != NULL) | |||||
printf(" | %s", np->u.leaf.subtype); | |||||
printf(" %s%s%s)\n", np->u.leaf.func, | printf(" %s%s%s)\n", np->u.leaf.func, | ||||
(np->flags & FL_GET) ? " GET" : "", | (np->flags & FL_GET) ? " GET" : "", | ||||
(np->flags & FL_SET) ? " SET" : ""); | (np->flags & FL_SET) ? " SET" : ""); | ||||
break; | break; | ||||
case NODE_TREE: | case NODE_TREE: | ||||
if (TAILQ_EMPTY(&np->u.tree.subs)) { | if (TAILQ_EMPTY(&np->u.tree.subs)) { | ||||
printf(")\n"); | printf(")\n"); | ||||
} else { | } else { | ||||
printf("\n"); | printf("\n"); | ||||
TAILQ_FOREACH(sp, &np->u.tree.subs, link) | TAILQ_FOREACH(sp, &np->u.tree.subs, link) | ||||
gen_tree(sp, level + 1); | gen_tree(sp, level + 1); | ||||
printf("%*s)\n", 2 * level, ""); | printf("%*s)\n", 2 * level, ""); | ||||
} | } | ||||
break; | break; | ||||
case NODE_ENTRY: | case NODE_ENTRY: | ||||
printf(" :"); | printf(" :"); | ||||
for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) | for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) { | ||||
print_syntax(SNMP_INDEX(np->u.entry.index, i)); | print_syntax(SNMP_INDEX(np->u.entry.index, i)); | ||||
if (np->u.entry.subtypes[i] != NULL) | |||||
printf(" | %s", np->u.entry.subtypes[i]); | |||||
} | |||||
printf(" %s\n", np->u.entry.func); | printf(" %s\n", np->u.entry.func); | ||||
TAILQ_FOREACH(sp, &np->u.entry.subs, link) | TAILQ_FOREACH(sp, &np->u.entry.subs, link) | ||||
gen_tree(sp, level + 1); | gen_tree(sp, level + 1); | ||||
printf("%*s)\n", 2 * level, ""); | printf("%*s)\n", 2 * level, ""); | ||||
break; | break; | ||||
case NODE_COLUMN: | case NODE_COLUMN: | ||||
print_syntax(np->u.column.syntax); | print_syntax(np->u.column.syntax); | ||||
if (np->u.column.subtype != NULL) | |||||
printf(" | %s", np->u.column.subtype); | |||||
printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", | printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", | ||||
(np->flags & FL_SET) ? " SET" : ""); | (np->flags & FL_SET) ? " SET" : ""); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
extract(FILE *fp, 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, | ||||
Show All 31 Lines | if (np->type == NODE_TREE) { | ||||
TAILQ_FOREACH(sub, &np->u.entry.subs, link) | TAILQ_FOREACH(sub, &np->u.entry.subs, link) | ||||
if (!extract(fp, sub, oid, obj, idx, iname)) | if (!extract(fp, sub, oid, obj, idx, iname)) | ||||
return (0); | return (0); | ||||
} | } | ||||
oid->len--; | oid->len--; | ||||
return (1); | return (1); | ||||
} | } | ||||
/** | |||||
* Extract the named OID. | |||||
* | |||||
* \param fp file to extract to | |||||
* \param root root of the tree | |||||
* \param object name of the object to extract | |||||
* | |||||
* \return 0 on success, -1 if the object was not found | |||||
*/ | |||||
static int | static int | ||||
gen_extract(FILE *fp, const struct node *root, char *object) | gen_extract(FILE *fp, const struct node *root, char *object) | ||||
{ | { | ||||
struct asn_oid oid; | struct asn_oid oid; | ||||
struct asn_oid idx; | struct asn_oid idx; | ||||
char *s, *e, *end, *iname; | char *s, *e, *end, *iname; | ||||
u_long ul; | u_long ul; | ||||
int ret; | int ret; | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | if (*s == '-') | ||||
fprintf(fp, "_"); | fprintf(fp, "_"); | ||||
else | else | ||||
fprintf(fp, "%c", *s); | fprintf(fp, "%c", *s); | ||||
s++; | s++; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Generate a definition for the enum packed into a guard against multiple | |||||
* definitions. | |||||
* | |||||
* \param fp file to write definition to | |||||
* \param t type | |||||
*/ | |||||
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); | |||||
} | |||||
/** | |||||
* Generate helper functions for an enum. | * Generate helper functions for an enum. | ||||
* | * | ||||
* We always generate a switch statement for the isok function. The compiler | * We always generate a switch statement for the isok function. The compiler | ||||
* optimizes this into range checks if possible. | * optimizes this into range checks if possible. | ||||
* | * | ||||
* \param fp file to write to | * \param fp file to write to | ||||
* \param t type | * \param t type | ||||
* \param ccode generate externally visible non-inline functions | * \param ccode generate externally visible non-inline functions | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | gen_enum_funcs(FILE *fp, const struct type *t, int ccode) | ||||
fprintf(fp, " return (1);\n"); | fprintf(fp, " return (1);\n"); | ||||
fprintf(fp, " }\n"); | fprintf(fp, " }\n"); | ||||
fprintf(fp, " }\n"); | fprintf(fp, " }\n"); | ||||
fprintf(fp, " return (0);\n"); | fprintf(fp, " return (0);\n"); | ||||
fprintf(fp, "}\n"); | fprintf(fp, "}\n"); | ||||
} | } | ||||
/** | /** | ||||
* Generate a definition for the enum packed into a guard against multiple | |||||
* definitions. | |||||
* | |||||
* \param fp file to write definition to | |||||
* \param t type | |||||
* \param dof generate functions too | |||||
*/ | |||||
static void | |||||
gen_enum(FILE *fp, const struct type *t, int dof) | |||||
{ | |||||
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"); | |||||
if (dof) { | |||||
fprintf(fp, "#ifdef SNMPENUM_FUNCS\n"); | |||||
fprintf(fp, "\n"); | |||||
gen_enum_funcs(fp, t, 0); | |||||
fprintf(fp, "\n"); | |||||
fprintf(fp, "#endif\n"); | |||||
fprintf(fp, "\n"); | |||||
} | |||||
fprintf(fp, "#endif /* %s_defined__ */\n", t->name); | |||||
} | |||||
/** | |||||
* Generate helper functions for an enum. This generates code for a c file. | * Generate helper functions for an enum. This generates code for a c file. | ||||
* | * | ||||
* \param fp file to write to | * \param fp file to write to | ||||
* \param name enum name | * \param name enum name | ||||
*/ | */ | ||||
static int | static int | ||||
gen_enum_funcs_str(FILE *fp, const char *name) | gen_enum_funcs_str(FILE *fp, const char *name) | ||||
{ | { | ||||
Show All 19 Lines | |||||
{ | { | ||||
const struct type *t; | const struct type *t; | ||||
LIST_FOREACH(t, &types, link) | LIST_FOREACH(t, &types, link) | ||||
if (t->is_enum || t->is_bits) | if (t->is_enum || t->is_bits) | ||||
gen_enum_funcs(fp, t, ccode); | gen_enum_funcs(fp, t, ccode); | ||||
} | } | ||||
static void | |||||
gen_enums(FILE *fp, int dof) | |||||
{ | |||||
const struct type *t; | |||||
LIST_FOREACH(t, &types, link) | |||||
if (t->is_enum || t->is_bits) | |||||
gen_enum(fp, t, dof); | |||||
} | |||||
/** | /** | ||||
* Extract a given enum to the specified file and optionally generate static | * Extract a given enum to the specified file and optionally generate static | ||||
* inline helper functions for them. | * inline helper functions for them. | ||||
* | * | ||||
* \param fp file to print on | * \param fp file to print on | ||||
* \param name name of the enum | * \param name name of the enum | ||||
* \param gen_funcs generate the functions too | * \param gen_funcs generate the functions too | ||||
* | * | ||||
* \return 0 if found, -1 otherwise | * \return 0 if found, -1 otherwise | ||||
*/ | */ | ||||
static int | static int | ||||
extract_enum(FILE *fp, const char *name, int gen_funcs) | extract_enum(FILE *fp, const char *name, int gen_funcs) | ||||
{ | { | ||||
const struct type *t; | const struct type *t; | ||||
LIST_FOREACH(t, &types, link) | LIST_FOREACH(t, &types, link) | ||||
if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { | if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { | ||||
gen_enum(fp, t); | gen_enum(fp, t, gen_funcs); | ||||
if (gen_funcs) | |||||
gen_enum_funcs(fp, t, 0); | |||||
return (0); | return (0); | ||||
} | } | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/** | /** | ||||
* Extract all enums to the given file and optionally generate static inline | * Extract all enums to the given file and optionally generate static inline | ||||
* helper functions for them. | * helper functions for them. | ||||
* | * | ||||
* \param fp file to print on | * \param fp file to print on | ||||
* \param gen_funcs generate the functions too | * \param gen_funcs generate the functions too | ||||
*/ | */ | ||||
static void | static void | ||||
extract_all_enums(FILE *fp, int gen_funcs) | extract_all_enums(FILE *fp, int gen_funcs) | ||||
{ | { | ||||
const struct type *t; | const struct type *t; | ||||
LIST_FOREACH(t, &types, link) | LIST_FOREACH(t, &types, link) | ||||
if (t->is_enum || t->is_bits) { | if (t->is_enum || t->is_bits) | ||||
gen_enum(fp, t); | gen_enum(fp, t, gen_funcs); | ||||
if (gen_funcs) | |||||
gen_enum_funcs(fp, t, 0); | |||||
} | } | ||||
} | |||||
/** | /** | ||||
* Extract enums and optionally generate some helper functions for them. | * Extract enums and optionally generate some helper functions for them. | ||||
* | * | ||||
* \param argc number of arguments | * \param argc number of arguments | ||||
* \param argv arguments (enum names) | * \param argv arguments (enum names) | ||||
* \param gen_funcs_h generate functions into the header file | * \param gen_funcs which functions to generate | ||||
* \param gen_funcs_c generate a .c file with functions | |||||
*/ | */ | ||||
static void | static void | ||||
make_enums(int argc, char *argv[], int gen_funcs_h, int gen_funcs_c) | make_enums(int argc, char *argv[], enum gen_funcs gen_funcs) | ||||
{ | { | ||||
if (gen_funcs_c) { | if (gen_funcs == GEN_FUNCS_C) { | ||||
if (argc == 0) | if (argc == 0) | ||||
gen_all_enum_funcs(stdout, 1); | gen_all_enum_funcs(stdout, 1); | ||||
else { | else { | ||||
for (int i = 0; i < argc; i++) | for (int i = 0; i < argc; i++) | ||||
if (gen_enum_funcs_str(stdout, argv[i])) | if (gen_enum_funcs_str(stdout, argv[i])) | ||||
errx(1, "enum not found: %s", argv[i]); | errx(1, "enum not found: %s", argv[i]); | ||||
} | } | ||||
} else { | } else { | ||||
if (argc == 0) | if (argc == 0) | ||||
extract_all_enums(stdout, gen_funcs_h); | extract_all_enums(stdout, gen_funcs == GEN_FUNCS_H); | ||||
else { | else { | ||||
for (int i = 0; i < argc; i++) | for (int i = 0; i < argc; i++) | ||||
if (extract_enum(stdout, argv[i], gen_funcs_h)) | if (extract_enum(stdout, argv[i], | ||||
gen_funcs == GEN_FUNCS_H)) | |||||
errx(1, "enum not found: %s", argv[i]); | errx(1, "enum not found: %s", argv[i]); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Produce the operation tables for the daemon or a module. | |||||
* | |||||
* \param root tree root | |||||
* \param gen_funcs generate enum funcs | |||||
*/ | |||||
static void | |||||
make_table(const struct node *root, int gen_funcs) | |||||
{ | |||||
FILE *fp; | |||||
char fname[MAXPATHLEN + 1]; | |||||
sprintf(fname, "%stree.h", file_prefix); | |||||
if ((fp = fopen(fname, "w")) == NULL) | |||||
err(1, "%s: ", fname); | |||||
gen_header(fp, root, PREFIX_LEN, NULL); | |||||
fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); | |||||
gen_enums(fp, gen_funcs); | |||||
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); | |||||
fclose(fp); | |||||
sprintf(fname, "%stree.c", file_prefix); | |||||
if ((fp = fopen(fname, "w")) == NULL) | |||||
err(1, "%s: ", fname); | |||||
gen_table(fp, root); | |||||
fclose(fp); | |||||
} | |||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
int do_extract = 0; | enum op op = OP_GEN; | ||||
int do_tree = 0; | enum gen_funcs gen_funcs = GEN_FUNCS_NONE; | ||||
int do_enums = 0; | |||||
int gen_funcs_h = 0; | |||||
int gen_funcs_c = 0; | |||||
int opt; | |||||
struct node *root; | |||||
char fname[MAXPATHLEN + 1]; | |||||
int tok; | |||||
FILE *fp; | |||||
char *infile = NULL; | char *infile = NULL; | ||||
int opt; | |||||
while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF) | while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF) | ||||
switch (opt) { | switch (opt) { | ||||
case 'd': | case 'd': | ||||
debug = 1; | debug = 1; | ||||
break; | break; | ||||
case 'E': | case 'E': | ||||
do_enums = 1; | if (op != OP_GEN && op != OP_ENUMS) | ||||
errx(1, "-E conflicts with earlier options"); | |||||
op = OP_ENUMS; | |||||
break; | break; | ||||
case 'e': | case 'e': | ||||
do_extract = 1; | if (op != OP_GEN && op != OP_EXTRACT) | ||||
errx(1, "-e conflicts with earlier options"); | |||||
op = OP_EXTRACT; | |||||
break; | break; | ||||
case 'F': | case 'F': | ||||
gen_funcs_c = 1; | if (gen_funcs != GEN_FUNCS_NONE && | ||||
gen_funcs != GEN_FUNCS_C) | |||||
errx(1, "-F conflicts with -f"); | |||||
gen_funcs = GEN_FUNCS_C; | |||||
break; | break; | ||||
case 'f': | case 'f': | ||||
gen_funcs_h = 1; | if (gen_funcs != GEN_FUNCS_NONE && | ||||
gen_funcs != GEN_FUNCS_H) | |||||
errx(1, "-f conflicts with -F"); | |||||
gen_funcs = GEN_FUNCS_H; | |||||
break; | break; | ||||
case 'h': | case 'h': | ||||
fprintf(stderr, "%s", usgtxt); | fprintf(stderr, "%s", usgtxt); | ||||
exit(0); | exit(0); | ||||
case 'I': | case 'I': | ||||
path_new(optarg); | path_new(optarg); | ||||
Show All 10 Lines | switch (opt) { | ||||
case 'p': | case 'p': | ||||
file_prefix = optarg; | file_prefix = optarg; | ||||
if (strlen(file_prefix) + strlen("tree.c") > | if (strlen(file_prefix) + strlen("tree.c") > | ||||
MAXPATHLEN) | MAXPATHLEN) | ||||
errx(1, "prefix too long"); | errx(1, "prefix too long"); | ||||
break; | break; | ||||
case 't': | case 't': | ||||
do_tree = 1; | if (op != OP_GEN && op != OP_TREE) | ||||
errx(1, "-t conflicts with earlier options"); | |||||
op = OP_TREE; | |||||
break; | break; | ||||
} | } | ||||
if (do_extract + do_tree + do_enums > 1) | argc -= optind; | ||||
errx(1, "conflicting options -e/-t/-E"); | argv += optind; | ||||
if (!do_extract && !do_enums && argc != optind) | |||||
errx(1, "no arguments allowed"); | |||||
if (do_extract && argc == optind) | |||||
errx(1, "no objects specified"); | |||||
if ((gen_funcs_h || gen_funcs_c) && (do_extract || do_tree)) | /* open input */ | ||||
errx(1, "-f and -F not allowed with -e or -t"); | |||||
if (gen_funcs_c && !do_enums) | |||||
errx(1, "-F requires -E"); | |||||
if (gen_funcs_h && gen_funcs_c) | |||||
errx(1, "-f and -F are mutually exclusive"); | |||||
if (infile == NULL) { | if (infile == NULL) { | ||||
input_new(stdin, NULL, "<stdin>"); | input_new(stdin, NULL, "<stdin>"); | ||||
} else { | } else { | ||||
FILE *fp; | |||||
if ((fp = fopen(infile, "r")) == NULL) | if ((fp = fopen(infile, "r")) == NULL) | ||||
err(1, "%s", infile); | err(1, "%s", infile); | ||||
input_new(fp, NULL, infile); | input_new(fp, NULL, infile); | ||||
} | } | ||||
root = parse_top(gettoken()); | /* parse and check input */ | ||||
struct node *root = parse_top(gettoken()); | |||||
int tok; | |||||
while ((tok = gettoken()) != TOK_EOF) | while ((tok = gettoken()) != TOK_EOF) | ||||
merge(&root, parse_top(tok)); | merge(&root, parse_top(tok)); | ||||
if (root) | if (root) | ||||
check_tree(root); | check_tree(root); | ||||
if (do_extract) { | /* do what the user has requested */ | ||||
while (optind < argc) { | switch (op) { | ||||
if (gen_extract(stdout, root, argv[optind])) | |||||
errx(1, "object not found: %s", argv[optind]); | case OP_EXTRACT: | ||||
optind++; | if (argc == 0) | ||||
} | errx(1, "-e requires arguments"); | ||||
for (int i = 0; i < argc; i++) | |||||
if (gen_extract(stdout, root, argv[i])) | |||||
errx(1, "object not found: %s", argv[i]); | |||||
return (0); | return (0); | ||||
} | |||||
if (do_enums) { | case OP_ENUMS: | ||||
make_enums(argc - optind, argv + optind, | make_enums(argc, argv, gen_funcs); | ||||
gen_funcs_h, gen_funcs_c); | |||||
return (0); | return (0); | ||||
} | |||||
if (do_tree) { | case OP_TREE: | ||||
if (argc != 0) | |||||
errx(1, "-t allows no arguments"); | |||||
gen_tree(root, 0); | gen_tree(root, 0); | ||||
return (0); | return (0); | ||||
} | |||||
sprintf(fname, "%stree.h", file_prefix); | |||||
if ((fp = fopen(fname, "w")) == NULL) | |||||
err(1, "%s: ", fname); | |||||
gen_header(fp, root, PREFIX_LEN, NULL); | |||||
fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); | case OP_GEN: | ||||
extract_all_enums(fp, gen_funcs_h); | if (argc != 0) | ||||
fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n"); | errx(1, "tree generation allows no arguments"); | ||||
make_table(root, gen_funcs == GEN_FUNCS_H); | |||||
fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); | |||||
fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); | |||||
fclose(fp); | |||||
sprintf(fname, "%stree.c", file_prefix); | |||||
if ((fp = fopen(fname, "w")) == NULL) | |||||
err(1, "%s: ", fname); | |||||
gen_table(fp, root); | |||||
fclose(fp); | |||||
return (0); | return (0); | ||||
} | |||||
} | } |