| /****************************************************************** |
| Copyright 1989, 1991, 1992 by Carnegie Mellon University |
| |
| All Rights Reserved |
| |
| Permission to use, copy, modify, and distribute this software and its |
| documentation for any purpose and without fee is hereby granted, |
| provided that the above copyright notice appear in all copies and that |
| both that copyright notice and this permission notice appear in |
| supporting documentation, and that the name of CMU not be |
| used in advertising or publicity pertaining to distribution of the |
| software without specific, written prior permission. |
| |
| CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
| ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
| CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
| ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
| WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
| ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
| SOFTWARE. |
| ******************************************************************/ |
| /* |
| * parse.c |
| */ |
| #include <config.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <sys/types.h> |
| |
| /* Wow. This is ugly. -- Wes */ |
| #if HAVE_DIRENT_H |
| # include <dirent.h> |
| # define NAMLEN(dirent) strlen((dirent)->d_name) |
| #else |
| # define dirent direct |
| # define NAMLEN(dirent) (dirent)->d_namlen |
| # if HAVE_SYS_NDIR_H |
| # include <sys/ndir.h> |
| # endif |
| # if HAVE_SYS_DIR_H |
| # include <sys/dir.h> |
| # endif |
| # if HAVE_NDIR_H |
| # include <ndir.h> |
| # endif |
| #endif |
| |
| #include "parse.h" |
| |
| /* A quoted string value-- too long for a general "token" */ |
| char *quoted_string_buffer; |
| |
| /* |
| * This is one element of an object identifier with either an integer |
| * subidentifier, or a textual string label, or both. |
| * The subid is -1 if not present, and label is NULL if not present. |
| */ |
| struct subid { |
| int subid; |
| char *label; |
| }; |
| |
| #define MAXTC 256 |
| struct tc { /* textual conventions */ |
| int type; |
| char descriptor[MAXTOKEN]; |
| struct enum_list *enums; |
| } tclist[MAXTC]; |
| |
| |
| |
| int Line = 1; |
| char File[300]; |
| int save_mib_descriptions = 0; |
| int mib_warnings = 0; |
| |
| #define SYNTAX_MASK 0x80 |
| /* types of tokens |
| Tokens wiht the SYNTAX_MASK bit set are syntax tokens */ |
| #define CONTINUE -1 |
| #define ENDOFFILE 0 |
| #define LABEL 1 |
| #define SUBTREE 2 |
| #define SYNTAX 3 |
| #define OBJID (4 | SYNTAX_MASK) |
| #define OCTETSTR (5 | SYNTAX_MASK) |
| #define INTEGER (6 | SYNTAX_MASK) |
| #define INTEGER32 INTEGER |
| #define NETADDR (7 | SYNTAX_MASK) |
| #define IPADDR (8 | SYNTAX_MASK) |
| #define COUNTER (9 | SYNTAX_MASK) |
| #define GAUGE (10 | SYNTAX_MASK) |
| #define TIMETICKS (11 | SYNTAX_MASK) |
| #define OPAQUE (12 | SYNTAX_MASK) |
| #define NUL (13 | SYNTAX_MASK) |
| #define SEQUENCE 14 |
| #define OF 15 /* SEQUENCE OF */ |
| #define OBJTYPE 16 |
| #define ACCESS 17 |
| #define READONLY 18 |
| #define READWRITE 19 |
| #define WRITEONLY 20 |
| #define NOACCESS 21 |
| #define STATUS 22 |
| #define MANDATORY 23 |
| #define OPTIONAL 24 |
| #define OBSOLETE 25 |
| /* #define RECOMMENDED 26 */ |
| #define PUNCT 27 |
| #define EQUALS 28 |
| #define NUMBER 29 |
| #define LEFTBRACKET 30 |
| #define RIGHTBRACKET 31 |
| #define LEFTPAREN 32 |
| #define RIGHTPAREN 33 |
| #define COMMA 34 |
| #define DESCRIPTION 35 |
| #define QUOTESTRING 36 |
| #define INDEX 37 |
| #define DEFVAL 38 |
| #define DEPRECATED 39 |
| #define SIZE 40 |
| #define BITSTRING (41 | SYNTAX_MASK) |
| #define NSAPADDRESS (42 | SYNTAX_MASK) |
| #define COUNTER64 (43 | SYNTAX_MASK) |
| #define OBJGROUP 44 |
| #define NOTIFTYPE 45 |
| #define AUGMENTS 46 |
| #define COMPLIANCE 47 |
| #define READCREATE 48 |
| #define UNITS 49 |
| #define REFERENCE 50 |
| #define NUM_ENTRIES 51 |
| #define MODULEIDENTITY 52 |
| #define LASTUPDATED 53 |
| #define ORGANIZATION 54 |
| #define CONTACTINFO 55 |
| #define UINTEGER32 (56 | SYNTAX_MASK) |
| #define CURRENT 57 |
| #define DEFINITIONS 58 |
| #define END 59 |
| #define SEMI 60 |
| #define TRAPTYPE 61 |
| #define ENTERPRISE 62 |
| /* #define DISPLAYSTR (63 | SYNTAX_MASK) */ |
| #define BEGIN 64 |
| #define IMPORTS 65 |
| #define EXPORTS 66 |
| #define ACCNOTIFY 67 |
| #define BAR 68 |
| #define RANGE 69 |
| #define CONVENTION 70 |
| |
| struct tok { |
| char *name; /* token name */ |
| int len; /* length not counting nul */ |
| int token; /* value */ |
| int hash; /* hash of name */ |
| struct tok *next; /* pointer to next in hash table */ |
| }; |
| |
| |
| struct tok tokens[] = { |
| { "obsolete", sizeof ("obsolete")-1, OBSOLETE }, |
| { "Opaque", sizeof ("Opaque")-1, OPAQUE }, |
| { "optional", sizeof ("optional")-1, OPTIONAL }, |
| { "LAST-UPDATED", sizeof ("LAST-UPDATED")-1, LASTUPDATED }, |
| { "ORGANIZATION", sizeof ("ORGANIZATION")-1, ORGANIZATION }, |
| { "CONTACT-INFO", sizeof ("CONTACT-INFO")-1, CONTACTINFO }, |
| { "MODULE-IDENTITY", sizeof ("MODULE-IDENTITY")-1, MODULEIDENTITY }, |
| { "MODULE-COMPLIANCE", sizeof ("MODULE-COMPLIANCE")-1, COMPLIANCE }, |
| { "DEFINITIONS", sizeof("DEFINITIONS")-1, DEFINITIONS}, |
| { "END", sizeof("END")-1, END}, |
| { ";", sizeof(";")-1, SEMI}, |
| { "AUGMENTS", sizeof ("AUGMENTS")-1, AUGMENTS }, |
| { "not-accessible", sizeof ("not-accessible")-1, NOACCESS }, |
| { "write-only", sizeof ("write-only")-1, WRITEONLY }, |
| { "NsapAddress", sizeof("NsapAddress")-1, NSAPADDRESS}, |
| { "UNITS", sizeof("Units")-1, UNITS}, |
| { "REFERENCE", sizeof("REFERENCE")-1, REFERENCE}, |
| { "NUM-ENTRIES", sizeof("NUM-ENTRIES")-1, NUM_ENTRIES}, |
| { "BITSTRING", sizeof("BITSTRING")-1, BITSTRING}, |
| { "BIT", sizeof("BIT")-1, CONTINUE}, |
| { "BITS", sizeof("BITS")-1, CONTINUE}, |
| { "Counter64", sizeof("Counter64")-1, COUNTER64}, |
| { "TimeTicks", sizeof ("TimeTicks")-1, TIMETICKS }, |
| { "NOTIFICATION-TYPE", sizeof ("NOTIFICATION-TYPE")-1, NOTIFTYPE }, |
| { "OBJECT-GROUP", sizeof ("OBJECT-GROUP")-1, OBJGROUP }, |
| { "OBJECT-IDENTITY", sizeof ("OBJECT-IDENTITY")-1, OBJGROUP }, |
| { "OBJECTIDENTIFIER", sizeof ("OBJECTIDENTIFIER")-1, OBJID }, |
| { "OBJECT", sizeof ("OBJECT")-1, CONTINUE }, |
| { "NetworkAddress", sizeof ("NetworkAddress")-1, NETADDR }, |
| { "Gauge", sizeof ("Gauge")-1, GAUGE }, |
| { "Gauge32", sizeof ("Gauge32")-1, GAUGE }, |
| { "Unsigned32", sizeof ("Unsigned32")-1, GAUGE }, |
| { "read-write", sizeof ("read-write")-1, READWRITE }, |
| { "read-create", sizeof ("read-create")-1, READCREATE }, |
| { "OCTETSTRING", sizeof ("OCTETSTRING")-1, OCTETSTR }, |
| { "OCTET", sizeof ("OCTET")-1, CONTINUE }, |
| { "OF", sizeof ("OF")-1, OF }, |
| { "SEQUENCE", sizeof ("SEQUENCE")-1, SEQUENCE }, |
| { "NULL", sizeof ("NULL")-1, NUL }, |
| { "IpAddress", sizeof ("IpAddress")-1, IPADDR }, |
| { "UInteger32", sizeof ("UInteger32")-1, UINTEGER32 }, |
| { "INTEGER", sizeof ("INTEGER")-1, INTEGER }, |
| { "Integer32", sizeof ("Integer32")-1, INTEGER32 }, |
| { "Counter", sizeof ("Counter")-1, COUNTER }, |
| { "Counter32", sizeof ("Counter32")-1, COUNTER }, |
| { "read-only", sizeof ("read-only")-1, READONLY }, |
| { "DESCRIPTION", sizeof ("DESCRIPTION")-1, DESCRIPTION }, |
| { "INDEX", sizeof ("INDEX")-1, INDEX }, |
| { "DEFVAL", sizeof ("DEFVAL")-1, DEFVAL }, |
| { "deprecated", sizeof ("deprecated")-1, DEPRECATED }, |
| { "SIZE", sizeof ("SIZE")-1, SIZE }, |
| { "MAX-ACCESS", sizeof ("MAX-ACCESS")-1, ACCESS }, |
| { "ACCESS", sizeof ("ACCESS")-1, ACCESS }, |
| { "mandatory", sizeof ("mandatory")-1, MANDATORY }, |
| { "current", sizeof ("current")-1, CURRENT }, |
| { "STATUS", sizeof ("STATUS")-1, STATUS }, |
| { "SYNTAX", sizeof ("SYNTAX")-1, SYNTAX }, |
| { "OBJECT-TYPE", sizeof ("OBJECT-TYPE")-1, OBJTYPE }, |
| { "{", sizeof ("{")-1, LEFTBRACKET }, |
| { "}", sizeof ("}")-1, RIGHTBRACKET }, |
| { "::=", sizeof ("::=")-1, EQUALS }, |
| { "(", sizeof ("(")-1, LEFTPAREN }, |
| { ")", sizeof (")")-1, RIGHTPAREN }, |
| { ",", sizeof (",")-1, COMMA }, |
| { "TRAP-TYPE", sizeof ("TRAP-TYPE")-1, TRAPTYPE }, |
| { "ENTERPRISE", sizeof ("ENTERPRISE")-1, ENTERPRISE }, |
| { "BEGIN", sizeof ("BEGIN")-1, BEGIN }, |
| { "IMPORTS", sizeof ("IMPORTS")-1, IMPORTS }, |
| { "EXPORTS", sizeof ("EXPORTS")-1, IMPORTS }, |
| { "accessible-for-notify", sizeof ("accessible-for-notify")-1, ACCNOTIFY }, |
| { "|", sizeof ("|")-1, BAR }, |
| { "..", sizeof ("..")-1, RANGE }, |
| { "TEXTUAL-CONVENTION", sizeof ("TEXTUAL-CONVENTION")-1, CONVENTION }, |
| { "NOTIFICATION-GROUP", sizeof ("NOTIFICATION-GROUP")-1, NOTIFTYPE }, |
| { NULL } |
| }; |
| |
| #define HASHSIZE 32 |
| #define BUCKET(x) (x & 0x01F) |
| |
| struct tok *buckets[HASHSIZE]; |
| |
| static void do_subtree(); |
| static int get_token(); |
| static void unget_token(); |
| static int parseQuoteString(); |
| static int tossObjectIdentifier(); |
| |
| static void |
| hash_init() |
| { |
| register struct tok *tp; |
| register char *cp; |
| register int h; |
| register int b; |
| |
| memset(buckets, 0, sizeof(buckets)); |
| for (tp = tokens; tp->name; tp++) { |
| for (h = 0, cp = tp->name; *cp; cp++) |
| h += *cp; |
| tp->hash = h; |
| b = BUCKET(h); |
| if (buckets[b]) |
| tp->next = buckets[b]; /* BUG ??? */ |
| buckets[b] = tp; |
| } |
| } |
| |
| #define NHASHSIZE 128 |
| #define NBUCKET(x) (x & 0x7F) |
| struct node *nbuckets[NHASHSIZE]; |
| |
| static void |
| init_node_hash(nodes) |
| struct node *nodes; |
| { |
| register struct node *np, *nextp; |
| register char *cp; |
| register int hash; |
| |
| memset(nbuckets, 0, sizeof(nbuckets)); |
| for(np = nodes; np;){ |
| nextp = np->next; |
| hash = 0; |
| for(cp = np->parent; *cp; cp++) |
| hash += *cp; |
| np->next = nbuckets[NBUCKET(hash)]; |
| nbuckets[NBUCKET(hash)] = np; |
| np = nextp; |
| } |
| } |
| |
| static void |
| print_error(string, token, type) |
| char *string; |
| char *token; |
| int type; |
| { |
| DEBUGP("\n"); |
| if (type == ENDOFFILE) |
| fprintf(stderr, "%s(EOF): At line %d in %s\n", string, Line, |
| File); |
| else if (token) |
| fprintf(stderr, "%s(%s): At line %d in %s\n", string, token, |
| Line, File); |
| else |
| fprintf(stderr, "%s: At line %d in %s\n", string, Line, File); |
| } |
| |
| static long Malloc_calls = 0; |
| static long Malloc_bytes = 0; |
| |
| static void * |
| Malloc(num) |
| unsigned num; |
| { |
| void *p; |
| /* this is to fix (what seems to be) a problem with the IBM RT C |
| library malloc */ |
| #if 0 |
| if (num < 16) |
| num = 16; |
| #endif |
| p = malloc(num); |
| if (!p) { |
| print_error("Out of memory", NULL, CONTINUE); |
| exit (1); |
| } |
| memset (p, 0, num); |
| Malloc_calls++; |
| Malloc_bytes += num; |
| return p; |
| } |
| |
| static char *Strdup (s) |
| char *s; |
| { |
| char *ss = Malloc (strlen (s)+1); |
| return strcpy (ss, s); |
| } |
| |
| static void Malloc_stats(fp) |
| FILE *fp; |
| { |
| fprintf (fp, "Malloc: %ld calls, %ld bytes\n", Malloc_calls, Malloc_bytes); |
| } |
| |
| static void |
| free_tree(Tree) |
| struct tree *Tree; |
| { |
| if (Tree == NULL) |
| { |
| return; |
| } |
| |
| if (Tree->enums) |
| { |
| struct enum_list *ep, *tep; |
| |
| ep = Tree->enums; |
| while(ep) |
| { |
| tep = ep; |
| ep = ep->next; |
| if (tep->label) |
| free(tep->label); |
| |
| free(tep); |
| } |
| } |
| |
| if (Tree->description) |
| free(Tree->description); |
| if (Tree->label) |
| free(Tree->label); |
| |
| free_tree(Tree->child_list); |
| free (Tree); |
| } |
| |
| static void |
| free_node(np) |
| struct node *np; |
| { |
| struct enum_list *ep, *tep; |
| |
| if (np->tc_index == -1) ep = np->enums; |
| else ep = NULL; |
| while (ep) { |
| tep = ep; |
| ep = ep->next; |
| if (tep->label) |
| free(tep->label); |
| free(tep); |
| } |
| if (np->description) |
| free(np->description); |
| if (np->label) |
| free(np->label); |
| if (np->parent) |
| free(np->parent); |
| |
| free(np); |
| } |
| |
| static void |
| print_nodes(fp, root) |
| FILE *fp; |
| struct node *root; |
| { |
| struct enum_list *ep; |
| struct node *np; |
| |
| for(np = root; np; np = np->next){ |
| fprintf(fp, "%s ::= { %s %ld } (%d)\n", np->label, np->parent, |
| np->subid, np->type); |
| if (np->tc_index >= 0) |
| fprintf(fp, " TC = %s\n",tclist[np->tc_index].descriptor); |
| if (np->enums){ |
| fprintf(fp, " Enums: \n"); |
| for(ep = np->enums; ep; ep = ep->next){ |
| fprintf(fp, " %s(%d)\n", ep->label, ep->value); |
| } |
| } |
| } |
| } |
| |
| void |
| print_subtree(f, tree, count) |
| FILE *f; |
| struct tree *tree; |
| int count; |
| { |
| struct tree *tp; |
| int i; |
| |
| for(i = 0; i < count; i++) |
| fprintf(f, " "); |
| fprintf(f, "Children of %s(%ld):\n", tree->label, tree->subid); |
| count++; |
| for(tp = tree->child_list; tp; tp = tp->next_peer){ |
| for(i = 0; i < count; i++) |
| fprintf(f, " "); |
| fprintf(f, "%s(%ld) type=%d tc=%d\n", |
| tp->label, tp->subid, tp->type, tp->tc_index); |
| } |
| for(tp = tree->child_list; tp; tp = tp->next_peer){ |
| if (tp->child_list) |
| print_subtree(f, tp, count); |
| } |
| } |
| |
| int translation_table[256]; |
| |
| static void |
| build_translation_table(){ |
| int count; |
| |
| for(count = 0; count < 256; count++){ |
| switch(count){ |
| case OBJID: |
| translation_table[count] = TYPE_OBJID; |
| break; |
| case OCTETSTR: |
| translation_table[count] = TYPE_OCTETSTR; |
| break; |
| case INTEGER: |
| translation_table[count] = TYPE_INTEGER; |
| break; |
| case NETADDR: |
| translation_table[count] = TYPE_IPADDR; |
| break; |
| case IPADDR: |
| translation_table[count] = TYPE_IPADDR; |
| break; |
| case COUNTER: |
| translation_table[count] = TYPE_COUNTER; |
| break; |
| case GAUGE: |
| translation_table[count] = TYPE_GAUGE; |
| break; |
| case TIMETICKS: |
| translation_table[count] = TYPE_TIMETICKS; |
| break; |
| case OPAQUE: |
| translation_table[count] = TYPE_OPAQUE; |
| break; |
| case NUL: |
| translation_table[count] = TYPE_NULL; |
| break; |
| case COUNTER64: |
| translation_table[count] = TYPE_COUNTER64; |
| break; |
| case BITSTRING: |
| translation_table[count] = TYPE_BITSTRING; |
| break; |
| case NSAPADDRESS: |
| translation_table[count] = TYPE_NSAPADDRESS; |
| break; |
| case UINTEGER32: |
| translation_table[count] = TYPE_UINTEGER; |
| break; |
| default: |
| translation_table[count] = TYPE_OTHER; |
| break; |
| } |
| } |
| } |
| |
| static struct tree * |
| build_tree(nodes) |
| struct node *nodes; |
| { |
| struct node *np; |
| struct tree *tp, *lasttp; |
| int bucket, nodes_left = 0; |
| |
| build_translation_table(); |
| /* grow tree from this root node */ |
| init_node_hash(nodes); |
| |
| /* build root node */ |
| tp = Malloc(sizeof(struct tree)); |
| tp->parent = NULL; |
| tp->next_peer = NULL; |
| tp->child_list = NULL; |
| tp->enums = NULL; |
| tp->label = Strdup("joint-iso-ccitt"); |
| tp->subid = 2; |
| tp->tc_index = -1; |
| tp->type = 0; |
| tp->description = NULL; |
| /* XXX nodes isn't needed in do_subtree() ??? */ |
| do_subtree(tp, &nodes); |
| lasttp = tp; |
| |
| /* build root node */ |
| tp = Malloc(sizeof(struct tree)); |
| tp->parent = NULL; |
| tp->next_peer = lasttp; |
| tp->child_list = NULL; |
| tp->enums = NULL; |
| tp->label = Strdup("ccitt"); |
| tp->subid = 0; |
| tp->tc_index = -1; |
| tp->type = 0; |
| tp->description = NULL; |
| /* XXX nodes isn't needed in do_subtree() ??? */ |
| do_subtree(tp, &nodes); |
| lasttp = tp; |
| |
| /* build root node */ |
| tp = Malloc(sizeof(struct tree)); |
| tp->parent = NULL; |
| tp->next_peer = lasttp; |
| tp->child_list = NULL; |
| tp->enums = NULL; |
| tp->label = Strdup("iso"); |
| tp->subid = 1; |
| tp->tc_index = -1; |
| tp->type = 0; |
| tp->description = NULL; |
| /* XXX nodes isn't needed in do_subtree() ??? */ |
| do_subtree(tp, &nodes); |
| |
| if (mib_warnings) Malloc_stats (stderr); |
| |
| /* If any nodes are left, the tree is probably inconsistent */ |
| for(bucket = 0; bucket < NHASHSIZE; bucket++){ |
| if (nbuckets[bucket]){ |
| nodes_left = 1; |
| break; |
| } |
| } |
| if (nodes_left){ |
| fprintf(stderr, "The mib description doesn't seem to be consistent.\n"); |
| fprintf(stderr, "Some nodes couldn't be linked under the \"iso\" tree.\n"); |
| fprintf(stderr, "these nodes are left:\n"); |
| for(bucket = 0; bucket < NHASHSIZE; bucket++){ |
| for(np = nbuckets[bucket]; np; np = np->next) |
| fprintf(stderr, "%s ::= { %s %ld } (%d)\n", np->label, |
| np->parent, np->subid, np->type); |
| } |
| } |
| return tp; |
| } |
| |
| /* |
| * Find all the children of root in the list of nodes. Link them into the |
| * tree and out of the nodes list. |
| */ |
| static void |
| do_subtree(root, nodes) |
| struct tree *root; |
| struct node **nodes; |
| { |
| register struct tree *tp; |
| register struct node *np, **headp; |
| struct node *oldnp = NULL, *child_list = NULL, *childp = NULL; |
| char *cp; |
| int hash; |
| |
| tp = root; |
| hash = 0; |
| for(cp = tp->label; *cp; cp++) |
| hash += *cp; |
| headp = &nbuckets[NBUCKET(hash)]; |
| /* |
| * Search each of the nodes for one whose parent is root, and |
| * move each into a separate list. |
| */ |
| for(np = *headp; np; np = np->next){ |
| if ((*tp->label != *np->parent) || strcmp(tp->label, np->parent)){ |
| if ((*tp->label == *np->label) && !strcmp(tp->label, np->label)){ |
| /* if there is another node with the same label, assume that |
| * any children after this point in the list belong to the other node. |
| * This adds some scoping to the table and allows vendors to |
| * reuse names such as "ip". |
| */ |
| if (mib_warnings) |
| fprintf(stderr, "Warning: duplicate label: %s.%s¹n", |
| np->parent, np->label); |
| break; |
| } |
| oldnp = np; |
| } else { |
| /* take this node out of the node list */ |
| if (oldnp == NULL){ |
| *headp = np->next; /* fix root of node list */ |
| } else { |
| oldnp->next = np->next; /* link around this node */ |
| } |
| if (child_list) childp->next = np; |
| else child_list = np; |
| childp = np; |
| } |
| } |
| if (childp) childp->next = NULL; |
| /* |
| * Take each element in the child list and place it into the tree. |
| */ |
| for(np = child_list; np; np = np->next){ |
| tp = root->child_list; |
| while (tp) |
| if (tp->subid == np->subid) break; |
| else tp = tp->next_peer; |
| if (tp) { |
| if (strcmp (tp->label, np->label) == 0) |
| continue; |
| if (mib_warnings) |
| fprintf (stderr, "Warning: %s.%ld is both %s and %s\n", |
| root->label, np->subid, tp->label, np->label); |
| } |
| tp = Malloc(sizeof(struct tree)); |
| tp->parent = root; |
| tp->child_list = NULL; |
| tp->label = np->label; |
| np->label = NULL; |
| tp->subid = np->subid; |
| tp->tc_index = np->tc_index; |
| tp->type = translation_table[np->type]; |
| tp->enums = np->enums; |
| np->enums = NULL; /* so we don't free them later */ |
| tp->description = np->description; /* steals memory from np */ |
| np->description = NULL; /* so we don't free it later */ |
| tp->next_peer = root->child_list; |
| root->child_list = tp; |
| /* if (tp->type == TYPE_OTHER) */ |
| do_subtree(tp, nodes); /* recurse on this child if it isn't |
| an end node */ |
| } |
| /* free all nodes that were copied into tree */ |
| oldnp = NULL; |
| for(np = child_list; np; np = np->next){ |
| if (oldnp) |
| free_node(oldnp); |
| oldnp = np; |
| } |
| if (oldnp) |
| free_node(oldnp); |
| } |
| |
| |
| /* |
| * Takes a list of the form: |
| * { iso org(3) dod(6) 1 } |
| * and creates several nodes, one for each parent-child pair. |
| * Returns NULL on error. |
| */ |
| static int |
| getoid(fp, oid, length) |
| register FILE *fp; |
| register struct subid *oid; /* an array of subids */ |
| int length; /* the length of the array */ |
| { |
| register int count; |
| int type; |
| char token[MAXTOKEN]; |
| |
| if ((type = get_token(fp, token,MAXTOKEN)) != LEFTBRACKET){ |
| print_error("Expected \"{\"", token, type); |
| return 0; |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| for(count = 0; count < length; count++, oid++){ |
| oid->label = NULL; |
| oid->subid = -1; |
| if (type == RIGHTBRACKET){ |
| return count; |
| } else if (type != LABEL && type != NUMBER){ |
| print_error("Not valid for object identifier", token, type); |
| return 0; |
| } |
| if (type == LABEL){ |
| /* this entry has a label */ |
| oid->label = Strdup(token); |
| type = get_token(fp, token,MAXTOKEN); |
| if (type == LEFTPAREN){ |
| type = get_token(fp, token,MAXTOKEN); |
| if (type == NUMBER){ |
| oid->subid = atoi(token); |
| if ((type = get_token(fp, token,MAXTOKEN)) != RIGHTPAREN){ |
| print_error("Expected a closing bracket", token, type); |
| return 0; |
| } |
| } else { |
| print_error("Expected a number", token, type); |
| return 0; |
| } |
| } else { |
| continue; |
| } |
| } else { |
| /* this entry has just an integer sub-identifier */ |
| oid->subid = atoi(token); |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| } |
| print_error ("Too long OID", token, type); |
| return count; |
| |
| |
| } |
| |
| /* |
| * Parse an entry of the form: |
| * label OBJECT IDENTIFIER ::= { parent 2 } |
| * The "label OBJECT IDENTIFIER ::=" portion has already been parsed. |
| * Returns 0 on error. |
| */ |
| static struct node * |
| parse_objectid(fp, name) |
| FILE *fp; |
| char *name; |
| { |
| register int count; |
| register struct subid *op, *nop; |
| int length; |
| struct subid oid[32]; |
| struct node *np, *root, *oldnp = NULL; |
| |
| if ((length = getoid(fp, oid, 32)) != 0){ |
| np = root = Malloc(sizeof(struct node)); |
| memset(np, 0, sizeof(struct node)); |
| /* |
| * For each parent-child subid pair in the subid array, |
| * create a node and link it into the node list. |
| */ |
| for(count = 0, op = oid, nop=oid+1; count < (length - 2); count++, |
| op++, nop++){ |
| /* every node must have parent's name and child's name or number */ |
| if (op->label && (nop->label || (nop->subid != -1))){ |
| np->parent = Strdup (op->label); |
| if (nop->label) |
| np->label = Strdup (nop->label); |
| if (nop->subid != -1) |
| np->subid = nop->subid; |
| np->tc_index = -1; |
| np->type = 0; |
| np->enums = NULL; |
| /* set up next entry */ |
| np->next = Malloc(sizeof(*np->next)); |
| memset(np->next, 0, sizeof(struct node)); |
| oldnp = np; |
| np = np->next; |
| } |
| } |
| np->next = NULL; |
| np->tc_index = -1; |
| /* |
| * The above loop took care of all but the last pair. This pair is taken |
| * care of here. The name for this node is taken from the label for this |
| * entry. |
| * np still points to an unused entry. |
| */ |
| if (count == (length - 2)){ |
| if (op->label){ |
| np->parent = Strdup (op->label); |
| np->label = Strdup (name); |
| if (nop->subid != -1) |
| np->subid = nop->subid; |
| else |
| print_error("Warning: This entry is pretty silly", |
| np->label, CONTINUE); |
| } else { |
| free_node(np); |
| if (oldnp) |
| oldnp->next = NULL; |
| else |
| return NULL; |
| } |
| } else { |
| print_error("Missing end of OID", NULL, CONTINUE); |
| free_node(np); /* the last node allocated wasn't used */ |
| if (oldnp) |
| oldnp->next = NULL; |
| return NULL; |
| } |
| /* free the oid array */ |
| for(count = 0, op = oid; count < length; count++, op++){ |
| if (op->label) |
| free(op->label); |
| } |
| return root; |
| } else { |
| print_error("Bad object identifier", NULL, CONTINUE); |
| return NULL; |
| } |
| } |
| |
| static int |
| get_tc(descriptor, ep) |
| char *descriptor; |
| struct enum_list **ep; |
| { |
| int i; |
| |
| for(i = 0; i < MAXTC; i++){ |
| if (tclist[i].type == 0) |
| break; |
| if (!strcmp(descriptor, tclist[i].descriptor)){ |
| *ep = tclist[i].enums; |
| return tclist[i].type; |
| } |
| } |
| return LABEL; |
| } |
| |
| /* return index into tclist of given TC descriptor |
| return -1 if not found |
| */ |
| static int |
| get_tc_index(descriptor) |
| char *descriptor; |
| { |
| int i; |
| |
| for(i = 0; i < MAXTC; i++){ |
| if (tclist[i].type == 0) |
| break; |
| if (!strcmp(descriptor, tclist[i].descriptor)){ |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| |
| /* |
| * Parses an enumeration list of the form: |
| * { label(value) label(value) ... } |
| * The initial { has already been parsed. |
| * Returns NULL on error. |
| */ |
| |
| static struct enum_list * |
| parse_enumlist(fp) |
| register FILE *fp; |
| { |
| register int type; |
| char token [MAXTOKEN]; |
| struct enum_list *ep = NULL, *rep; |
| |
| while((type = get_token(fp, token,MAXTOKEN)) != ENDOFFILE){ |
| if (type == RIGHTBRACKET) |
| break; |
| if (type == LABEL){ |
| /* this is an enumerated label */ |
| rep = Malloc(sizeof(struct enum_list)); |
| rep->next = ep; |
| ep = rep; |
| /* a reasonable approximation for the length */ |
| ep->label = Strdup(token); |
| type = get_token(fp, token,MAXTOKEN); |
| if (type != LEFTPAREN) { |
| print_error("Expected \"(\"", token, type); |
| return NULL; |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| if (type != NUMBER) { |
| print_error("Expected integer", token, type); |
| return NULL; |
| } |
| ep->value = atoi(token); |
| type = get_token(fp, token,MAXTOKEN); |
| if (type != RIGHTPAREN) { |
| print_error("Expected \")\"", token, type); |
| return NULL; |
| } |
| } |
| } |
| if (type == ENDOFFILE){ |
| print_error("Expected \"}\"", token, type); |
| return NULL; |
| } |
| return ep; |
| } |
| |
| /* |
| * Parses an asn type. Structures are ignored by this parser. |
| * Returns NULL on error. |
| */ |
| static struct node * |
| parse_asntype(fp, name, ntype, ntoken) |
| FILE *fp; |
| char *name; |
| int *ntype; |
| char *ntoken; |
| { |
| int type, i; |
| char token[MAXTOKEN]; |
| struct enum_list *ep; |
| struct tc *tcp; |
| int level; |
| |
| type = get_token(fp, token,MAXTOKEN); |
| if (type == SEQUENCE){ |
| while((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE){ |
| if (type == RIGHTBRACKET){ |
| *ntype = get_token(fp, ntoken,MAXTOKEN); |
| return NULL; |
| } |
| } |
| print_error("Expected \"}\"", token, type); |
| return NULL; |
| } else if (type == LEFTBRACKET) { |
| struct node *np; |
| unget_token (type); |
| np = parse_objectid (fp, name); |
| if (np != NULL) { |
| *ntype = get_token(fp, ntoken, MAXTOKEN); |
| return np; |
| } |
| return NULL; |
| } else { |
| if (type == CONVENTION) { |
| while (type != SYNTAX && type != ENDOFFILE) |
| type = get_token(fp, token, MAXTOKEN); |
| type = get_token(fp, token, MAXTOKEN); |
| } |
| |
| if (type == LABEL) |
| { |
| type = get_tc(token, &ep); |
| } |
| |
| |
| /* textual convention */ |
| for(i = 0; i < MAXTC; i++){ |
| if (tclist[i].type == 0) |
| break; |
| } |
| |
| if (i == MAXTC){ |
| print_error("Too many textual conventions", token, type); |
| return NULL; |
| } |
| tcp = &tclist[i]; |
| strncpy(tcp->descriptor, name, MAXTOKEN); |
| if (!(type & SYNTAX_MASK)){ |
| print_error("Textual convention doesn't map to real type", token, |
| type); |
| return NULL; |
| } |
| tcp->type = type; |
| *ntype = get_token(fp, ntoken,MAXTOKEN); |
| if (*ntype == LEFTPAREN){ |
| level = 1; |
| /* don't record any constraints for now */ |
| while(level > 0){ |
| *ntype = get_token(fp, ntoken,MAXTOKEN); |
| if (*ntype == LEFTPAREN) |
| level++; |
| else if (*ntype == RIGHTPAREN) |
| level--; |
| else if (*ntype == ENDOFFILE) |
| break; |
| } |
| *ntype = get_token(fp, ntoken,MAXTOKEN); |
| } else if (*ntype == LEFTBRACKET) { |
| /* if there is an enumeration list, parse it */ |
| tcp->enums = parse_enumlist(fp); |
| *ntype = get_token(fp, ntoken,MAXTOKEN); |
| } |
| return NULL; |
| } |
| } |
| |
| |
| /* |
| * Parses an OBJECT TYPE macro. |
| * Returns 0 on error. |
| */ |
| static struct node * |
| parse_objecttype(fp, name) |
| register FILE *fp; |
| char *name; |
| { |
| register int type; |
| char token[MAXTOKEN]; |
| int nexttype, tctype; |
| char nexttoken[MAXTOKEN]; |
| register struct node *np, *nnp; |
| |
| type = get_token(fp, token,MAXTOKEN); |
| if (type != SYNTAX){ |
| print_error("Bad format for OBJECT-TYPE", token, type); |
| return NULL; |
| } |
| np = Malloc(sizeof(struct node)); |
| np->next = NULL; |
| np->tc_index = -1; |
| np->enums = NULL; |
| np->description = NULL; /* default to an empty description */ |
| type = get_token(fp, token, MAXTOKEN); |
| if (type == LABEL){ |
| tctype = get_tc(token, &(np->enums)); |
| if (tctype == LABEL && mib_warnings > 1){ |
| print_error("Warning: No known translation for type", token, type); |
| } |
| type = tctype; |
| np->tc_index = get_tc_index(token); /* store TC for later reference */ |
| } |
| np->type = type; |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); |
| switch(type){ |
| case SEQUENCE: |
| if (nexttype == OF){ |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); |
| } |
| break; |
| case INTEGER: |
| case UINTEGER32: |
| case COUNTER: |
| case GAUGE: |
| if (nexttype == LEFTBRACKET) { |
| /* if there is an enumeration list, parse it */ |
| np->enums = parse_enumlist(fp); |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); |
| } else if (nexttype == LEFTPAREN){ |
| do { |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| if (nexttype == RANGE) { |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| } |
| } while (nexttype == BAR); |
| if (nexttype != RIGHTPAREN) |
| print_error ("Expected \")\"", nexttoken, nexttype); |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| } |
| break; |
| case BITSTRING: |
| if (nexttype == LEFTBRACKET) { |
| /* if there is an enumeration list, parse it */ |
| np->enums = parse_enumlist(fp); |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| } else if (nexttype == LEFTPAREN){ |
| /* ignore the "constrained integer" for now */ |
| do { |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| if (nexttype == RANGE) { |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| } |
| } while (nexttype == BAR); |
| if (nexttype != RIGHTPAREN) |
| print_error ("Expected \")\"", nexttoken, nexttype); |
| nexttype = get_token (fp, nexttoken, MAXTOKEN); |
| } |
| break; |
| case OCTETSTR: |
| /* ignore the "constrained octet string" for now */ |
| if (nexttype == LEFTPAREN) { |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); |
| if (nexttype == SIZE) { |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); |
| if (nexttype == LEFTPAREN) { |
| do { |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| if (nexttype == RANGE) { |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| nexttype = get_token(fp, nexttoken, MAXTOKEN); |
| } |
| } while (nexttype == BAR); |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); /* ) */ |
| if (nexttype == RIGHTPAREN) |
| { |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); |
| break; |
| } |
| } |
| } |
| print_error("Bad syntax", token, type); |
| free_node(np); |
| return NULL; |
| } |
| break; |
| case OBJID: |
| case NETADDR: |
| case IPADDR: |
| case TIMETICKS: |
| case OPAQUE: |
| case NUL: |
| case LABEL: |
| case NSAPADDRESS: |
| case COUNTER64: |
| break; |
| default: |
| print_error("Bad syntax", token, type); |
| free_node(np); |
| return NULL; |
| } |
| if (nexttype == UNITS){ |
| type = get_token(fp, quoted_string_buffer,MAXQUOTESTR); |
| if (type != QUOTESTRING) { |
| print_error("Bad UNITS", quoted_string_buffer, type); |
| free_node(np); |
| return NULL; |
| } |
| nexttype = get_token(fp, nexttoken,MAXTOKEN); |
| } |
| if (nexttype != ACCESS){ |
| print_error("Should be ACCESS", nexttoken, nexttype); |
| free_node(np); |
| return NULL; |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| if (type != READONLY && type != READWRITE && type != WRITEONLY |
| && type != NOACCESS && type != READCREATE && type != ACCNOTIFY){ |
| print_error("Bad ACCESS type", token, type); |
| free_node(np); |
| return NULL; |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| if (type != STATUS){ |
| print_error("Should be STATUS", token, type); |
| free_node(np); |
| return NULL; |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| if (type != MANDATORY && type != CURRENT && type != OPTIONAL && |
| type != OBSOLETE && type != DEPRECATED){ |
| print_error("Bad STATUS", token, type); |
| free_node(np); |
| return NULL; |
| } |
| /* |
| * Optional parts of the OBJECT-TYPE macro |
| */ |
| type = get_token(fp, token,MAXTOKEN); |
| while (type != EQUALS && type != ENDOFFILE) { |
| switch (type) { |
| case DESCRIPTION: |
| type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); |
| if (type != QUOTESTRING) { |
| print_error("Bad DESCRIPTION", quoted_string_buffer, type); |
| free_node(np); |
| return NULL; |
| } |
| if (save_mib_descriptions) { |
| np->description = Strdup (quoted_string_buffer); |
| } |
| break; |
| |
| case REFERENCE: |
| type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); |
| if (type != QUOTESTRING) { |
| print_error("Bad REFERENCE", quoted_string_buffer, type); |
| free_node(np); |
| return NULL; |
| } |
| break; |
| case INDEX: |
| case DEFVAL: |
| case AUGMENTS: |
| case NUM_ENTRIES: |
| if (tossObjectIdentifier(fp) != OBJID) { |
| print_error("Bad Object Identifier", token, type); |
| free_node(np); |
| return NULL; |
| } |
| break; |
| |
| default: |
| print_error("Bad format of optional clauses", token,type); |
| free_node(np); |
| return NULL; |
| |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| } |
| if (type != EQUALS){ |
| print_error("Bad format", token, type); |
| free_node(np); |
| return NULL; |
| } |
| nnp = parse_objectid (fp, name); |
| if (nnp) { |
| np->label = nnp->label; |
| np->parent = nnp->parent; |
| np->next = nnp->next; |
| np->subid = nnp->subid; |
| free(nnp); |
| } |
| else np = NULL; |
| return np; |
| } |
| |
| |
| /* |
| * Parses an OBJECT GROUP macro. |
| * Returns 0 on error. |
| * |
| * Also parses object-identy, since they are similar (ignore STATUS). |
| * - WJH 10/96 |
| */ |
| static struct node * |
| parse_objectgroup(fp, name) |
| register FILE *fp; |
| char *name; |
| { |
| register int type; |
| char token[MAXTOKEN]; |
| register struct node *np, *nnp; |
| |
| np = Malloc(sizeof(struct node)); |
| np->tc_index = -1; |
| np->type = 0; |
| np->next = NULL; |
| np->enums = NULL; |
| np->description = NULL; /* default to an empty description */ |
| type = get_token(fp, token,MAXTOKEN); |
| while (type != EQUALS && type != ENDOFFILE) { |
| switch (type) { |
| case DESCRIPTION: |
| type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); |
| if (type != QUOTESTRING) { |
| print_error("Bad DESCRIPTION", quoted_string_buffer, type); |
| free_node(np); |
| return NULL; |
| } |
| #ifdef TEST2 |
| printf("Description== \"%.50s\"\n", quoted_string_buffer); |
| #endif |
| if (save_mib_descriptions) { |
| np->description = Strdup (quoted_string_buffer); |
| } |
| break; |
| |
| default: |
| /* NOTHING */ |
| break; |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| } |
| nnp = parse_objectid (fp, name); |
| np->parent = nnp->parent; |
| np->label = nnp->label; |
| np->next = nnp->next; |
| np->subid = nnp->subid; |
| free(nnp); |
| return np; |
| } |
| |
| /* |
| * Parses a NOTIFICATION-TYPE macro. |
| * Returns 0 on error. |
| */ |
| static struct node * |
| parse_notificationDefinition(fp, name) |
| register FILE *fp; |
| char *name; |
| { |
| register int type; |
| char token[MAXTOKEN]; |
| register struct node *np, *nnp; |
| |
| np = Malloc(sizeof(struct node)); |
| np->tc_index = -1; |
| np->type = 0; |
| np->next = NULL; |
| np->enums = NULL; |
| np->description = NULL; /* default to an empty description */ |
| type = get_token(fp, token,MAXTOKEN); |
| while (type != EQUALS && type != ENDOFFILE) { |
| switch (type) { |
| case DESCRIPTION: |
| type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); |
| if (type != QUOTESTRING) { |
| print_error("Bad DESCRIPTION", quoted_string_buffer, type); |
| free_node(np); |
| return NULL; |
| } |
| #ifdef TEST2 |
| printf("Description== \"%.50s\"\n", quoted_string_buffer); |
| #endif |
| if (save_mib_descriptions) { |
| np->description = Strdup (quoted_string_buffer); |
| } |
| break; |
| |
| default: |
| /* NOTHING */ |
| break; |
| } |
| type = get_token(fp, token,MAXTOKEN); |
| } |
| nnp = parse_objectid (fp, name); |
| np->parent = nnp->parent; |
| np->label = nnp->label; |
| np->next = nnp->next; |
| np->subid = nnp->subid; |
| free(nnp); |
| return np; |
| } |
| |
| /* |
| * Parses a TRAP-TYPE macro. |
| * Returns 0 on error. |
| */ |
| static struct node * |
| parse_trapDefinition(fp, name) |
| register FILE *fp; |
| char *name; |
| { |
| register int type; |
| char token[MAXTOKEN]; |
| register struct node *np; |
| |
| np = Malloc(sizeof(struct node)); |
| np->tc_index = -1; |
| np->type = 0; |
| np->next = NULL; |
| np->enums = NULL; |
| np->description = NULL; /* default to an empty description */ |
| type = get_token(fp, token, MAXTOKEN); |
| while (type != EQUALS && type != ENDOFFILE) { |
| switch (type) { |
| case DESCRIPTION: |
| type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); |
| if (type != QUOTESTRING) { |
| print_error("Bad DESCRIPTION", quoted_string_buffer, type); |
| free_node(np); |
| return NULL; |
| } |
| |
| #ifdef TEST2 |
| printf("Description== \"%.50s\"\n", quoted_string_buffer); |
| #endif |
| if (save_mib_descriptions) { |
| np->description = Strdup (quoted_string_buffer); |
| } |
| break; |
| case ENTERPRISE: |
| type = get_token(fp, token, MAXTOKEN); |
| if (type == LEFTBRACKET) { |
| type = get_token(fp, token, MAXTOKEN); |
| if (type != LABEL) { |
| print_error("Bad Trap Format", token, type); |
| free_node(np); |
| return NULL; |
| } |
| np->parent = Strdup(token); |
| /* Get right bracket */ |
| type = get_token(fp, token, MAXTOKEN); |
| } |
| else if (type == LABEL) |
| np->parent = Strdup(token); |
| break; |
| default: |
| /* NOTHING */ |
| break; |
| } |
| type = get_token(fp, token, MAXTOKEN); |
| } |
| type = get_token(fp, token, MAXTOKEN); |
| |
| np->label = Strdup(name); |
| |
| if (type != NUMBER) { |
| print_error("Expected a Number", token, type); |
| free_node(np); |
| return NULL; |
| } |
| np->subid = atoi(token); |
| return np; |
| } |
| |
| |
| /* |
| * Parses a compliance macro |
| * Returns 0 on error. |
| */ |
| static struct node * |
| parse_compliance(fp, name) |
| register FILE *fp; |
| char *name; |
| { |
| register int type; |
| char token[MAXTOKEN]; |
| register struct node *np, *nnp; |
| |
| np = Malloc(sizeof(struct node)); |
| np->tc_index = -1; |
| np->type = 0; |
| np->next = NULL; |
| np->enums = NULL; |
| np->description = NULL; /* default to an empty description */ |
| type = get_token(fp, token,MAXTOKEN); |
| while (type != EQUALS && type != ENDOFFILE) |
| type = get_token(fp, quoted_string_buffer,MAXQUOTESTR); |
| nnp = parse_objectid (fp, name); |
| np->parent = nnp->parent; |
| np->label = nnp->label; |
| np->next = nnp->next; |
| np->subid = nnp->subid; |
| free(nnp); |
| return np; |
| } |
| |
| |
| |
| /* |
| * Parses a module identity macro |
| * Returns 0 on error. |
| */ |
| static struct node * |
| parse_moduleIdentity(fp, name) |
| register FILE *fp; |
| char *name; |
| { |
| register int type; |
| char token[MAXTOKEN]; |
| register struct node *np, *nnp; |
| |
| np = Malloc (sizeof (struct node)); |
| np->tc_index = -1; |
| np->type = 0; |
| np->next = NULL; |
| np->enums = NULL; |
| np->description = NULL; /* default to an empty description */ |
| type = get_token(fp, token, MAXTOKEN); |
| while (type != EQUALS && type != ENDOFFILE) { |
| type = get_token(fp, token, MAXTOKEN); |
| } |
| nnp = parse_objectid(fp, name); |
| np->parent = nnp->parent; |
| np->label = nnp->label; |
| np->subid = nnp->subid; |
| np->next = nnp->next; |
| free (nnp); |
| return np; |
| } |
| |
| |
| /* |
| * Parses a mib file and returns a linked list of nodes found in the file. |
| * Returns NULL on error. |
| */ |
| static struct node * |
| parse(fp, root) |
| FILE *fp; |
| struct node *root; |
| { |
| char token[MAXTOKEN]; |
| char name[MAXTOKEN]; |
| int type = LABEL; |
| int lasttype = LABEL; |
| |
| #define BETWEEN_MIBS 1 |
| #define IN_MIB 2 |
| int state = BETWEEN_MIBS; |
| struct node *np, *nnp; |
| |
| if (mib_warnings) fprintf (stderr, "Parsing mib file: %s...\n", File); |
| |
| np = root; |
| if (np != NULL) { |
| /* now find end of chain */ |
| while(np->next) |
| np = np->next; |
| } else { |
| hash_init(); |
| memset(tclist, 0, MAXTC * sizeof(struct tc)); |
| } |
| quoted_string_buffer = Malloc(MAXQUOTESTR); /* free this later */ |
| if (quoted_string_buffer == NULL) { |
| print_error ("Out of memory", NULL, CONTINUE); |
| return NULL; |
| } |
| |
| while (type != ENDOFFILE){ |
| if (lasttype == CONTINUE) lasttype = type; |
| else type = lasttype = get_token(fp, token,MAXTOKEN); |
| |
| switch (type) { |
| case END: |
| if (state != IN_MIB){ |
| print_error("Error, END before start of MIB", NULL, type); |
| return NULL; |
| } |
| state = BETWEEN_MIBS; |
| if (mib_warnings) Malloc_stats (stderr); |
| continue; |
| case IMPORTS: |
| while (type != SEMI && type != ENDOFFILE) |
| type = get_token(fp, token, MAXTOKEN); |
| continue; |
| case EXPORTS: |
| while (type != SEMI && type != ENDOFFILE) |
| type = get_token(fp, token, MAXTOKEN); |
| continue; |
| case LABEL: |
| break; |
| case ENDOFFILE: |
| continue; |
| default: |
| print_error(token, "is a reserved word", type); |
| return NULL; |
| } |
| strcpy(name, token); |
| type = get_token(fp, token, MAXTOKEN); |
| nnp = NULL; |
| |
| /* Handle obsolete method to assign an object identifier to a |
| module*/ |
| if (lasttype == LABEL && type == LEFTBRACKET) { |
| while (type != RIGHTBRACKET && type != ENDOFFILE) |
| type = get_token(fp, token, MAXTOKEN); |
| if (type == ENDOFFILE){ |
| print_error("Expected \"}\"", token, type); |
| return NULL; |
| } |
| type = get_token(fp, token, MAXTOKEN); |
| } |
| |
| switch (type) { |
| case DEFINITIONS: |
| if (state != BETWEEN_MIBS){ |
| print_error("Error, nested MIBS", NULL, type); |
| return NULL; |
| } |
| state = IN_MIB; |
| if (mib_warnings) fprintf (stderr, "Parsing MIB: %s\n", name); |
| while ((type = get_token (fp, token, MAXTOKEN)) != ENDOFFILE) |
| if (type == BEGIN) break; |
| break; |
| case OBJTYPE: |
| nnp = parse_objecttype(fp, name); |
| if (nnp == NULL){ |
| print_error("Bad parse of OBJECT-TYPE", NULL, type); |
| return NULL; |
| } |
| break; |
| case OBJGROUP: |
| nnp = parse_objectgroup(fp, name); |
| if (nnp == NULL){ |
| print_error("Bad parse of OBJECT-GROUP", NULL, type); |
| return NULL; |
| } |
| break; |
| case TRAPTYPE: |
| nnp = parse_trapDefinition(fp, name); |
| if (nnp == NULL){ |
| print_error("Bad parse of TRAP-TYPE", NULL, type); |
| return NULL; |
| } |
| break; |
| case NOTIFTYPE: |
| nnp = parse_notificationDefinition(fp, name); |
| if (nnp == NULL){ |
| print_error("Bad parse of NOTIFICATION-TYPE", NULL, type); |
| return NULL; |
| } |
| break; |
| case COMPLIANCE: |
| nnp = parse_compliance(fp, name); |
| if (nnp == NULL){ |
| print_error("Bad parse of MODULE-COMPLIANCE", NULL, type); |
| return NULL; |
| } |
| break; |
| case MODULEIDENTITY: |
| nnp = parse_moduleIdentity(fp, name); |
| if (nnp == NULL){ |
| print_error("Bad parse of NODULE-IDENTITY", NULL, type); |
| return NULL; |
| } |
| break; |
| case OBJID: |
| type = get_token(fp, token, MAXTOKEN); |
| if (type != EQUALS){ |
| print_error("Expected \"::=\"", token, type); |
| return NULL; |
| } |
| nnp = parse_objectid(fp, name); |
| if (nnp == NULL){ |
| print_error("Bad parse of OBJECT IDENTIFIER", NULL, type); |
| return NULL; |
| } |
| break; |
| case EQUALS: |
| nnp = parse_asntype(fp, name, &type, token); |
| lasttype = CONTINUE; |
| break; |
| case ENDOFFILE: |
| break; |
| default: |
| print_error("Bad operator", token, type); |
| return NULL; |
| } |
| if (nnp) { |
| if (np) np->next = nnp; |
| else np = root = nnp; |
| while (np->next) np = np->next; |
| } |
| } |
| free (quoted_string_buffer); |
| quoted_string_buffer = NULL; |
| return root; |
| } |
| |
| /* |
| * Parses a token from the file. The type of the token parsed is returned, |
| * and the text is placed in the string pointed to by token. |
| */ |
| |
| static int ungotten_token = CONTINUE; |
| |
| static void unget_token (token) |
| { |
| if (ungotten_token != CONTINUE) { |
| fprintf (stderr, "Double unget\n"); |
| exit (1); |
| } |
| ungotten_token = token; |
| } |
| |
| static int |
| get_token(fp, token,maxtlen) |
| register FILE *fp; |
| register char *token; |
| int maxtlen; |
| { |
| static char last = ' '; |
| register int ch, ch_next; |
| register char *cp = token; |
| register int hash = 0; |
| register struct tok *tp; |
| int too_long = 0; |
| |
| if (ungotten_token != CONTINUE) { |
| int tok = ungotten_token; |
| ungotten_token = CONTINUE; |
| return tok; |
| } |
| |
| *cp = 0; |
| ch = last; |
| /* skip all white space */ |
| while(isspace(ch) && ch != EOF){ |
| ch = getc(fp); |
| if (ch == '\n') |
| Line++; |
| } |
| if (ch == EOF) { |
| return ENDOFFILE; |
| } else if (ch == '"') { |
| return parseQuoteString(fp, token, maxtlen); |
| } |
| |
| /* |
| * Accumulate characters until end of token is found. Then attempt to |
| * match this token as a reserved word. If a match is found, return the |
| * type. Else it is a label. Handle the RANGE token correctly. |
| */ |
| do { |
| if (ch == '\n') |
| Line++; |
| ch_next = getc(fp); |
| if (isspace(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' || |
| ch == ',' || ch == ';' || ch == '|' || (ch == '.' && ch_next == '.')){ |
| if (ch == '.' && ch_next == '.' && *token == 0) { |
| hash += ch + ch_next; |
| if (cp-token < maxtlen-1) |
| *cp++ = ch; |
| else too_long = 1; |
| if (cp-token < maxtlen-1) |
| *cp++ = ch_next; |
| else too_long = 1; |
| last = ' '; |
| } |
| else if (!isspace(ch) && *token == 0){ |
| ungetc (ch_next, fp); |
| hash += ch; |
| if (cp-token < maxtlen-1) |
| *cp++ = ch; |
| else too_long = 1; |
| last = ' '; |
| } else { |
| ungetc (ch_next, fp); |
| last = ch; |
| } |
| *cp = '\0'; |
| |
| if (too_long) |
| print_error("Warning: token too long", token, CONTINUE); |
| for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) { |
| if ((tp->hash == hash) && (strcmp(tp->name, token) == 0)) |
| break; |
| } |
| if (tp){ |
| if (tp->token == CONTINUE) |
| continue; |
| return (tp->token); |
| } |
| |
| if (token[0] == '-' && token[1] == '-'){ |
| /* strip comment */ |
| if (ch != '\n'){ |
| while ((ch = getc(fp)) != EOF) |
| if (ch == '\n'){ |
| Line++; |
| break; |
| } |
| } |
| if (ch == EOF) |
| return ENDOFFILE; |
| last = ch; |
| return get_token(fp, token,maxtlen); |
| } |
| for(cp = token; *cp; cp++) |
| if (!isdigit(*cp)) |
| return LABEL; |
| return NUMBER; |
| } |
| else { |
| ungetc (ch_next, fp); |
| hash += ch; |
| if (cp-token < maxtlen-1) |
| *cp++ = ch; |
| else too_long = 1; |
| if (ch == '\n') |
| Line++; |
| } |
| |
| } while ((ch = getc(fp)) != EOF); |
| return ENDOFFILE; |
| } |
| |
| #ifndef TEST |
| struct tree * |
| read_mib(filename) |
| char *filename; |
| { |
| FILE *fp; |
| struct node *nodes = NULL; |
| struct tree *tree; |
| DIR *dir, *dir2; |
| struct dirent *file; |
| char tmpstr[300]; |
| char *libpath; |
| |
| fp = fopen(filename, "r"); |
| if (fp == NULL) |
| return NULL; |
| strcpy(File,filename); |
| DEBUGP1("Parsing %s...",filename); |
| nodes = parse(fp, nodes); |
| if (!nodes){ |
| fprintf(stderr, "Mib table is bad. Exiting\n"); |
| exit(1); |
| } |
| fclose(fp); |
| DEBUGP("Done\n"); |
| |
| libpath = getenv("SNMPLIBPATH"); |
| if (!libpath) libpath = SNMPLIBPATH; |
| sprintf(tmpstr,"%s/mibs", libpath); |
| if ((dir = opendir(tmpstr))) { |
| while ((file = readdir(dir))) { |
| /* Only parse file names not beginning with a '.' */ |
| if (file->d_name != NULL && file->d_name[0] != '.') { |
| sprintf(tmpstr, "%s/mibs/%s", libpath, file->d_name); |
| if ((dir2 = opendir(tmpstr))) { |
| /* file is a directory, don't read it */ |
| closedir(dir2); |
| } else { |
| /* parse it */ |
| if ((fp = fopen(tmpstr, "r")) == NULL) { |
| perror(tmpstr); |
| continue; |
| } |
| DEBUGP1("Parsing %s...",tmpstr); |
| Line = 1; |
| strcpy(File,tmpstr); |
| nodes = parse(fp, nodes); |
| if (nodes == NULL) { |
| fprintf(stderr, "Mib table is bad. Exiting\n"); |
| exit(1); |
| } |
| DEBUGP("done\n"); |
| fclose (fp); |
| } |
| } |
| } |
| closedir(dir); |
| } |
| tree = build_tree(nodes); |
| return tree; |
| } |
| #endif |
| |
| |
| #ifdef TEST |
| main(argc, argv) |
| int argc; |
| char *argv[]; |
| { |
| FILE *fp; |
| struct node *nodes; |
| struct tree *tp = NULL; |
| |
| if (argc == 2) strcpy (File, argv [1]); |
| else strcpy (File, "mib.txt"); |
| |
| fp = fopen(File, "r"); |
| if (fp == NULL){ |
| perror(File); |
| return 1; |
| } |
| nodes = parse(fp, NULL); |
| |
| if (nodes != NULL) |
| { |
| print_nodes(stdout, nodes); |
| tp = build_tree(nodes); |
| print_subtree(stdout, tp, 0); |
| } |
| |
| free_tree(tp); |
| |
| fclose(fp); |
| |
| return 0; |
| } |
| |
| #endif /* TEST */ |
| |
| static int |
| parseQuoteString(fp, token,maxtlen) |
| register FILE *fp; |
| register char *token; |
| int maxtlen; |
| { |
| register int ch; |
| int count = 0; |
| int too_long = 0; |
| char *token_start = token; |
| |
| ch = getc(fp); |
| while(ch != EOF) { |
| if (ch == '\n') { |
| Line++; |
| } |
| else if (ch == '"') { |
| *token = '\0'; |
| if (too_long && mib_warnings > 1) |
| print_error ("Warning: string too long", |
| token_start, QUOTESTRING); |
| return QUOTESTRING; |
| } |
| /* maximum description length check. If greater, keep parsing |
| but truncate the string */ |
| if (++count < maxtlen) |
| *token++ = ch; |
| else too_long = 1; |
| ch = getc(fp); |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * This routine parses a string like { blah blah blah } and returns OBJID if |
| * it is well formed, and NULL if not. |
| */ |
| static int |
| tossObjectIdentifier(fp) |
| register FILE *fp; |
| { |
| int type; |
| char token[MAXTOKEN]; |
| int bracketcount = 1; |
| |
| type = get_token(fp, token, MAXTOKEN); |
| |
| if (type != LEFTBRACKET) |
| return 0; |
| while ((type != RIGHTBRACKET || bracketcount > 0) && type != ENDOFFILE ) |
| { |
| type = get_token(fp, token, MAXTOKEN); |
| if (type == LEFTBRACKET) |
| bracketcount++; |
| else if (type == RIGHTBRACKET) |
| bracketcount--; |
| } |
| |
| if (type == RIGHTBRACKET) |
| return OBJID; |
| else |
| return 0; |
| } |