]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - snmplib/parse.c
SourceFormat Enforcement
[thirdparty/squid.git] / snmplib / parse.c
index a126452f81f96b5410060293a997edcb4458ce2d..02fe588e7641a0a253deb0847ce83ce82decf260 100644 (file)
@@ -1,15 +1,15 @@
-/******************************************************************
-       Copyright 1989, 1991, 1992 by Carnegie Mellon University
+/***********************************************************
+       Copyright 1989 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, 
+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 
+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.  
+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
@@ -20,37 +20,74 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 SOFTWARE.
 ******************************************************************/
 
-#include "config.h"
+/*
+ * parse.c
+ */
+#include "squid.h"
+#include "asn1.h"
+#include "cache_snmp.h"
+#include "parse.h"
+#include "snmp_debug.h"
+#include "snmp_pdu.h"
+#include "snmp_vars.h"
+#include "util.h"
 
-#if HAVE_STDIO_H
 #include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
 #endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
 #endif
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
-#if HAVE_STDLIB>H
-#include <stdlib.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
+#if HAVE_CTYPE_H
+#include <ctype.h>
 #endif
 #if HAVE_GNUMALLOC_H
 #include <gnumalloc.h>
-#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#elif HAVE_MALLOC_H
 #include <malloc.h>
 #endif
-
-#include "parse.h"
-
-/* A quoted string value-- too long for a general "token" */
-char *quoted_string_buffer;
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_ASSERT_H
+#include <assert.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
 
 /*
- * This is one element of an object identifier with either an integer
- * subidentifier, or a textual string label, or both.
+ * 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 {
@@ -58,36 +95,38 @@ struct subid {
     char *label;
 };
 
-/* use large token buffer in case of very long tokens: */
-#define MAXTC  1024
-struct tc {                    /* textual conventions */
-    int type;
-    char descriptor[MAXTOKEN];
-    struct enum_list *enums;
-} tclist[MAXTC];
-
-
+/*
+ * A linked list of nodes.
+ */
+struct node {
+    struct node *next;
+    char label[64];            /* This node's (unique) textual name */
+    u_int subid;               /* This node's integer subidentifier */
+    char parent[64];           /* The parent's textual name */
+    int type;                  /* The type of object this represents */
+    struct enum_list *enums;   /* (optional) list of enumerated integers (otherwise NULL) */
+};
 
 int Line = 1;
 
-#define SYNTAX_MASK    0x80
-/* types of tokens
- * Tokens wiht the SYNTAX_MASK bit set are syntax tokens */
+/* types of 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 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)
+#undef OBJID
+#define OBJID      4
+#define OCTETSTR    5
+#undef INTEGER
+#define INTEGER            6
+#define NETADDR            7
+#define        IPADDR      8
+#define COUNTER            9
+#define GAUGE      10
+#define TIMETICKS   11
+#define SNMP_OPAQUE        12
+#define NUL        13
 #define SEQUENCE    14
 #define OF         15          /* SEQUENCE OF */
 #define OBJTYPE            16
@@ -95,12 +134,13 @@ int Line = 1;
 #define READONLY    18
 #define READWRITE   19
 #define        WRITEONLY   20
+#undef NOACCESS
 #define NOACCESS    21
-#define STATUS     22
+#define SNMP_STATUS 22
 #define MANDATORY   23
-#define OPTIONAL    24
+#define SNMP_OPTIONAL    24
 #define OBSOLETE    25
-/* #define RECOMMENDED 26 */
+#define RECOMMENDED 26
 #define PUNCT      27
 #define EQUALS     28
 #define NUMBER     29
@@ -109,99 +149,50 @@ int Line = 1;
 #define        LEFTPAREN   32
 #define RIGHTPAREN  33
 #define COMMA      34
+/* For SNMPv2 SMI pseudo-compliance */
 #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 INDEX       36
+#define QUOTE       37
 
 struct tok {
-    char *name;                        /* token name */
+    const 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[] =
-{
+struct tok tokens[] = {
     {"obsolete", sizeof("obsolete") - 1, OBSOLETE},
-    {"Opaque", sizeof("Opaque") - 1, OPAQUE},
-/*      { "recommended", sizeof("recommended")-1, RECOMMENDED },  */
-    {"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},
+    {"Opaque", sizeof("Opaque") - 1, SNMP_OPAQUE},
+    {"recommended", sizeof("recommended") - 1, RECOMMENDED},
+    {"optional", sizeof("optional") - 1, SNMP_OPTIONAL},
+    {"mandatory", sizeof("mandatory") - 1, MANDATORY},
+    {"current", sizeof("current") - 1, MANDATORY},
     {"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},
-    {"Counter64", sizeof("Counter64") - 1, COUNTER64},
+    {"read-write", sizeof("read-write") - 1, READWRITE},
     {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS},
-    {"NOTIFICATION-TYPE", sizeof("NOTIFICATION-TYPE") - 1, NOTIFTYPE},
-    {"OBJECT-GROUP", sizeof("OBJECT-GROUP") - 1, OBJGROUP},
     {"OBJECTIDENTIFIER", sizeof("OBJECTIDENTIFIER") - 1, OBJID},
-       /*
-        * This CONTINUE appends the next word onto OBJECT,
-        * hopefully matching OBJECTIDENTIFIER above.
-        */
+    /*
+     * This CONTINUE appends the next word onto OBJECT,
+     * hopefully matching OBJECTIDENTIFIER above.
+     */
     {"OBJECT", sizeof("OBJECT") - 1, CONTINUE},
     {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR},
     {"Gauge", sizeof("Gauge") - 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, -1},
     {"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},
     {"Counter", sizeof("Counter") - 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},
+    {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS},
+    {"STATUS", sizeof("STATUS") - 1, SNMP_STATUS},
     {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX},
     {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE},
     {"{", sizeof("{") - 1, LEFTBRACKET},
@@ -210,36 +201,37 @@ struct tok tokens[] =
     {"(", sizeof("(") - 1, LEFTPAREN},
     {")", sizeof(")") - 1, RIGHTPAREN},
     {",", sizeof(",") - 1, COMMA},
+    {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION},
+    {"INDEX", sizeof("INDEX") - 1, INDEX},
+    {"\"", sizeof("\"") - 1, QUOTE},
+    {"END", sizeof("END") - 1, ENDOFFILE},
+    /* Hacks for easier MIBFILE coercing */
+    {"read-create", sizeof("read-create") - 1, READWRITE},
     {NULL}
 };
 
 #define        HASHSIZE        32
 #define        BUCKET(x)       (x & 0x01F)
 
-struct tok *buckets[HASHSIZE];
-
-static void do_subtree();
-static int get_token();
-static int parseQuoteString();
-static int tossObjectIdentifier();
+static struct tok *buckets[HASHSIZE];
 
 static void
-hash_init()
+hash_init(void)
 {
-    struct tok *tp;
-    char *cp;
-    int h;
-    int b;
+    register struct tok *tp;
+    register const char *cp;
+    register int h;
+    register int b;
 
-    bzero((char *) buckets, sizeof(buckets));
+    memset((char *) 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;
+        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;
     }
 }
 
@@ -247,207 +239,104 @@ hash_init()
 #define NBUCKET(x)   (x & 0x7F)
 struct node *nbuckets[NHASHSIZE];
 
-void
-init_node_hash(nodes)
-     struct node *nodes;
+static void
+init_node_hash(struct node *nodes)
 {
-    struct node *np, *nextp;
-    char *cp;
-    int hash;
+    register struct node *np, *nextp;
+    register char *cp;
+    register int hash;
 
-    bzero((char *) nbuckets, sizeof(nbuckets));
+    memset((char *) 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;
+        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 char *
-Malloc(num)
-     unsigned num;
-{
-    /* this is to fix (what seems to be) a problem with the IBM RT C
-     * library malloc */
-    if (num < 16)
-       num = 16;
-    return (char *) calloc(1, num);
-}
-
 static void
-print_error(string, token, type)
-     char *string;
-     char *token;
-     int type;
+print_error(const char *string, const char *token, int type)
 {
+    assert(string != NULL);
     if (type == ENDOFFILE)
-       fprintf(stderr, "%s(EOF): On or around line %d\n", string, Line);
+        snmplib_debug(0, "%s(EOF): On or around line %d\n", string, Line);
     else if (token)
-       fprintf(stderr, "%s(%s): On or around line %d\n", string, token, Line);
+        snmplib_debug(0, "%s(%s): On or around line %d\n", string, token, Line);
     else
-       fprintf(stderr, "%s: On or around line %d\n", string, Line);
+        snmplib_debug(0, "%s: On or around line %d\n", string, Line);
 }
 
-#ifdef TEST
+#if TEST
 print_subtree(tree, count)
-     struct tree *tree;
-     int count;
+struct snmp_mib_tree *tree;
+int count;
 {
-    struct tree *tp;
+    struct snmp_mib_tree *tp;
     int i;
 
     for (i = 0; i < count; i++)
-       printf("  ");
+        printf("  ");
     printf("Children of %s:\n", tree->label);
     count++;
     for (tp = tree->child_list; tp; tp = tp->next_peer) {
-       for (i = 0; i < count; i++)
-           printf("  ");
-       printf("%s\n", tp->label);
+        for (i = 0; i < count; i++)
+            printf("  ");
+        printf("%s\n", tp->label);
     }
     for (tp = tree->child_list; tp; tp = tp->next_peer) {
-       print_subtree(tp, count);
+        print_subtree(tp, count);
     }
 }
 #endif /* TEST */
 
-int translation_table[256];
+int translation_table[40];
 
-void
-build_translation_table()
+static void
+build_translation_table(void)
 {
     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 = (struct tree *) Malloc(sizeof(struct tree));
-    tp->parent = NULL;
-    tp->next_peer = NULL;
-    tp->child_list = NULL;
-    tp->enums = NULL;
-    strcpy(tp->label, "joint-iso-ccitt");
-    tp->subid = 2;
-    tp->type = 0;
-    tp->description = 0;
-    /* XXX nodes isn't needed in do_subtree() ??? */
-    do_subtree(tp, &nodes);
-    lasttp = tp;
-
-    /* build root node */
-    tp = (struct tree *) Malloc(sizeof(struct tree));
-    tp->parent = NULL;
-    tp->next_peer = lasttp;
-    tp->child_list = NULL;
-    tp->enums = NULL;
-    strcpy(tp->label, "ccitt");
-    tp->subid = 0;
-    tp->type = 0;
-    tp->description = 0;
-    /* XXX nodes isn't needed in do_subtree() ??? */
-    do_subtree(tp, &nodes);
-    lasttp = tp;
-
-    /* build root node */
-    tp = (struct tree *) Malloc(sizeof(struct tree));
-    tp->parent = NULL;
-    tp->next_peer = lasttp;
-    tp->child_list = NULL;
-    tp->enums = NULL;
-    strcpy(tp->label, "iso");
-    tp->subid = 1;
-    tp->type = 0;
-    tp->description = 0;
-    /* XXX nodes isn't needed in do_subtree() ??? */
-    do_subtree(tp, &nodes);
-
-
-#ifdef TEST
-    print_subtree(tp, 0);
-#endif /* TEST */
-    /* If any nodes are left, the tree is probably inconsistent */
-    for (bucket = 0; bucket < NHASHSIZE; bucket++) {
-       if (nbuckets[bucket]) {
-           nodes_left = 1;
-           break;
-       }
+    for (count = 0; count < 40; 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 SNMP_OPAQUE:
+            translation_table[count] = TYPE_OPAQUE;
+            break;
+        case NUL:
+            translation_table[count] = TYPE_NULL;
+            break;
+        default:
+            translation_table[count] = TYPE_OTHER;
+            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;
 }
 
 /*
@@ -455,13 +344,11 @@ build_tree(nodes)
  * tree and out of the nodes list.
  */
 static void
-do_subtree(root, nodes)
-     struct tree *root;
-     struct node **nodes;
+do_subtree(struct snmp_mib_tree *root, struct node **nodes)
 {
-    struct tree *tp;
-    struct tree *peer = NULL;
-    struct node *np, **headp;
+    register struct snmp_mib_tree *tp;
+    struct snmp_mib_tree *peer = NULL;
+    register struct node *np = NULL, **headp = NULL;
     struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
     char *cp;
     int hash;
@@ -469,153 +356,273 @@ do_subtree(root, nodes)
     tp = root;
     hash = 0;
     for (cp = tp->label; *cp; cp++)
-       hash += *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".
-                */
-               break;
-           }
-           oldnp = np;
-       } else {
-           if (child_list == NULL) {
-               child_list = childp = np;       /* first entry in child list */
-           } else {
-               childp->next = np;
-               childp = np;
-           }
-           /* 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 ((*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".
+                 */
+                break;
+            }
+            oldnp = np;
+        } else {
+            if (child_list == NULL) {
+                child_list = childp = np;      /* first entry in child list */
+            } else {
+                childp->next = np;
+                childp = np;
+            }
+            /* 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 (childp)
-       childp->next = 0;       /* re-terminate list */
+        childp->next = 0;      /* re-terminate list */
     /*
      * Take each element in the child list and place it into the tree.
      */
     for (np = child_list; np; np = np->next) {
-       tp = (struct tree *) Malloc(sizeof(struct tree));
-       tp->parent = root;
-       tp->next_peer = NULL;
-       tp->child_list = NULL;
-       strcpy(tp->label, np->label);
-       tp->subid = np->subid;
-       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 */
-       if (root->child_list == NULL) {
-           root->child_list = tp;
-       } else {
-           peer->next_peer = tp;
-       }
-       peer = tp;
-/*      if (tp->type == TYPE_OTHER) */
-       do_subtree(tp, nodes);  /* recurse on this child if it isn't
-                                * an end node */
+        tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree));
+        tp->parent = root;
+        tp->next_peer = NULL;
+        tp->child_list = NULL;
+        strcpy(tp->label, np->label);
+        tp->subid = np->subid;
+        tp->type = translation_table[np->type];
+        tp->enums = np->enums;
+        np->enums = NULL;      /* so we don't free them later */
+        if (root->child_list == NULL) {
+            root->child_list = tp;
+        } else {
+            peer->next_peer = tp;
+        }
+        peer = 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(oldnp);
-       oldnp = np;
+        if (oldnp)
+            xfree(oldnp);
+        oldnp = np;
     }
     if (oldnp)
-       free(oldnp);
+        xfree(oldnp);
 }
 
+#if !TEST
+static
+#endif
+struct snmp_mib_tree *
+build_tree(struct node *nodes) {
+    struct node *np;
+    struct snmp_mib_tree *tp;
+    int bucket, nodes_left = 0;
+
+    /* build root node */
+    tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree));
+    tp->parent = NULL;
+    tp->next_peer = NULL;
+    tp->child_list = NULL;
+    tp->enums = NULL;
+    strcpy(tp->label, "iso");
+    tp->subid = 1;
+    tp->type = 0;
+    build_translation_table();
+    /* grow tree from this root node */
+    init_node_hash(nodes);
+    /* XXX nodes isn't needed in do_subtree() ??? */
+    do_subtree(tp, &nodes);
+#if TEST
+    print_subtree(tp, 0);
+#endif /* TEST */
+    /* 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) {
+        snmplib_debug(0, "The mib description doesn't seem to be consistent.\n");
+        snmplib_debug(0, "Some nodes couldn't be linked under the \"iso\" tree.\n");
+        snmplib_debug(0, "these nodes are left:\n");
+        for (bucket = 0; bucket < NHASHSIZE; bucket++) {
+            for (np = nbuckets[bucket]; np; np = np->next)
+                snmplib_debug(5, "%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
+                              np->type);
+        }
+    }
+    return tp;
+}
+
+/*
+ * 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 char last = ' ';
+
+static int
+get_token(register FILE *fp, register char *token)
+{
+    register int ch;
+    register char *cp = token;
+    register int hash = 0;
+    register struct tok *tp;
+
+    *cp = 0;
+    ch = (unsigned char)last;
+    /* skip all white space */
+    while (xisspace(ch) && ch != -1) {
+        ch = getc(fp);
+        if (ch == '\n')
+            Line++;
+    }
+    if (ch == -1)
+        return ENDOFFILE;
+
+    /*
+     * 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.
+     */
+    do {
+        if (ch == '\n')
+            Line++;
+        if (xisspace(ch) || ch == '(' || ch == ')' ||
+                ch == '{' || ch == '}' || ch == ',' ||
+                ch == '"') {
+            if (!xisspace(ch) && *token == 0) {
+                hash += ch;
+                *cp++ = ch;
+                last = ' ';
+            } else {
+                last = ch;
+            }
+            *cp = '\0';
+
+            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 */
+                while ((ch = getc(fp)) != -1)
+                    if (ch == '\n') {
+                        Line++;
+                        break;
+                    }
+                if (ch == -1)
+                    return ENDOFFILE;
+                last = ch;
+                return get_token(fp, token);
+            }
+            for (cp = token; *cp; cp++)
+                if (!xisdigit(*cp))
+                    return LABEL;
+            return NUMBER;
+        } else {
+            hash += ch;
+            *cp++ = ch;
+            if (ch == '\n')
+                Line++;
+        }
+
+    } while ((ch = getc(fp)) != -1);
+    return ENDOFFILE;
+}
 
 /*
  * 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.
+ *   register struct subid *SubOid;    an array of subids
+ *   int length;                       the length of the array
  */
 static int
-getoid(fp, oid, length)
-     FILE *fp;
-     struct subid *oid;                /* an array of subids */
-     int length;               /* the length of the array */
+getoid(register FILE *fp, register struct subid *SubOid, int length)
 {
-    int count;
+    register int count;
     int type;
-    char token[MAXTOKEN];
-    char *cp;
+    char token[128];
+    register char *cp;
 
     if ((type = get_token(fp, token)) != LEFTBRACKET) {
-       print_error("Expected \"{\"", token, type);
-       return 0;
+        print_error("Expected \"{\"", token, type);
+        return 0;
     }
     type = get_token(fp, token);
-    for (count = 0; count < length; count++, oid++) {
-       oid->label = 0;
-       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 */
-           cp = (char *) Malloc((unsigned) strlen(token) + 1);
-           strcpy(cp, token);
-           oid->label = cp;
-           type = get_token(fp, token);
-           if (type == LEFTPAREN) {
-               type = get_token(fp, token);
-               if (type == NUMBER) {
-                   oid->subid = atoi(token);
-                   if ((type = get_token(fp, token)) != RIGHTPAREN) {
-                       print_error("Unexpected a closing parenthesis", 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);
+    for (count = 0; count < length; count++, SubOid++) {
+        SubOid->label = 0;
+        SubOid->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 */
+            cp = (char *) xmalloc((unsigned) strlen(token) + 1);
+            strcpy(cp, token);
+            SubOid->label = cp;
+            type = get_token(fp, token);
+            if (type == LEFTPAREN) {
+                type = get_token(fp, token);
+                if (type == NUMBER) {
+                    SubOid->subid = atoi(token);
+                    if ((type = get_token(fp, token)) != RIGHTPAREN) {
+                        print_error("Unexpected a closing parenthesis", 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 */
+            SubOid->subid = atoi(token);
+        }
+        type = get_token(fp, token);
     }
     return count;
 
-
 }
 
 static void
-free_node(np)
-     struct node *np;
+free_node(struct node *np)
 {
     struct enum_list *ep, *tep;
 
     ep = np->enums;
     while (ep) {
-       tep = ep;
-       ep = ep->next;
-       free((char *) tep);
+        tep = ep;
+        ep = ep->next;
+        xfree((char *) tep);
     }
-    free((char *) np);
+    xfree((char *) np);
 }
 
 /*
@@ -625,1175 +632,461 @@ free_node(np)
  * Returns 0 on error.
  */
 static struct node *
-parse_objectid(fp, name)
-     FILE *fp;
-     char *name;
-{
+parse_objectid(FILE *fp, char *name) {
     int type;
-    char token[MAXTOKEN];
-    int count;
-    struct subid *op, *nop;
+    char token[64];
+    register int count;
+    register struct subid *op, *nop;
     int length;
-    struct subid oid[32];
+    struct subid SubOid[32];
     struct node *np, *root, *oldnp = NULL;
 
     type = get_token(fp, token);
     if (type != EQUALS) {
-       print_error("Bad format", token, type);
-       return 0;
+        print_error("Bad format", token, type);
+        return 0;
     }
-    if ((length = getoid(fp, oid, 32)) != 0) {
-       np = root = (struct node *) Malloc(sizeof(struct node));
-       bzero((char *) np, 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))) {
-               strcpy(np->parent, op->label);
-               if (nop->label)
-                   strcpy(np->label, nop->label);
-               if (nop->subid != -1)
-                   np->subid = nop->subid;
-               np->type = 0;
-               np->enums = 0;
-               /* set up next entry */
-               np->next = (struct node *) Malloc(sizeof(*np->next));
-               bzero((char *) np->next, sizeof(struct node));
-               oldnp = np;
-               np = np->next;
-           }
-       }
-       np->next = (struct node *) NULL;
-       /*
-        * 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) {
-               strcpy(np->parent, op->label);
-               strcpy(np->label, name);
-               if (nop->subid != -1)
-                   np->subid = nop->subid;
-               else
-                   print_error("Warning: This entry is pretty silly",
-                       np->label, type);
-           } else {
-               free_node(np);
-               if (oldnp)
-                   oldnp->next = NULL;
-               else
-                   return NULL;
-           }
-       } else {
-           print_error("Missing end of oid", (char *) NULL, type);
-           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);
-           op->label = 0;
-       }
-       return root;
+    if ((length = getoid(fp, SubOid, 32)) != 0) {
+        np = root = (struct node *) xmalloc(sizeof(struct node));
+        memset((char *) 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 = SubOid, nop = SubOid + 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))) {
+                strcpy(np->parent, op->label);
+                if (nop->label)
+                    strcpy(np->label, nop->label);
+                if (nop->subid != -1)
+                    np->subid = nop->subid;
+                np->type = 0;
+                np->enums = 0;
+                /* set up next entry */
+                np->next = (struct node *) xmalloc(sizeof(*np->next));
+                memset((char *) np->next, '\0', sizeof(struct node));
+                oldnp = np;
+                np = np->next;
+            }
+        }
+        np->next = (struct node *) NULL;
+        /*
+         * 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) {
+                strcpy(np->parent, op->label);
+                strcpy(np->label, name);
+                if (nop->subid != -1)
+                    np->subid = nop->subid;
+                else
+                    print_error("Warning: This entry is pretty silly", np->label, type);
+            } else {
+                free_node(np);
+                if (oldnp)
+                    oldnp->next = NULL;
+                else
+                    return NULL;
+            }
+        } else {
+            print_error("Missing end of oid", (char *) NULL, type);
+            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 = SubOid; count < length; count++, op++) {
+            if (op->label)
+                xfree(op->label);
+            op->label = 0;
+        }
+        return root;
     } else {
-       print_error("Bad object identifier", (char *) NULL, type);
-       return 0;
+        print_error("Bad object identifier", (char *) NULL, type);
+        return 0;
     }
 }
 
-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;
-}
-
 /*
- * Parses an asn type.  Structures are ignored by this parser.
+ * Parses an asn type.  This structure is ignored by this parser.
  * Returns NULL on error.
  */
 static int
-parse_asntype(fp, name, ntype, ntoken)
-     FILE *fp;
-     char *name;
-     int *ntype;
-     char *ntoken;
+parse_asntype(FILE *fp)
 {
-    int type, i;
-    char token[MAXTOKEN];
-    struct enum_list *ep = 0;
-    struct tc *tcp;
-    int level;
+    int type;
+    char token[64];
 
     type = get_token(fp, token);
-    if (type == SEQUENCE) {
-       while ((type = get_token(fp, token)) != ENDOFFILE) {
-           if (type == RIGHTBRACKET) {
-               *ntype = get_token(fp, ntoken);
-               return 1;
-           }
-       }
-       print_error("Expected \"}\"", token, type);
-       return 0;
-    } else {
-       if (!strcmp(token, "TEXTUAL-CONVENTION")) {
-           while (type != SYNTAX)
-               type = get_token(fp, token);
-           type = get_token(fp, token);
-       }
-       /* textual convention */
-       for (i = 0; i < MAXTC; i++) {
-           if (tclist[i].type == 0)
-               break;
-       }
-       if (i == MAXTC) {
-           print_error("No more textual conventions possible.", token, type);
-           return 0;
-       }
-       tcp = &tclist[i];
-       strcpy(tcp->descriptor, name);
-       if (!(type & SYNTAX_MASK)) {
-           print_error("Textual convention doesn't map to real type.", token,
-               type);
-           return 0;
-       }
-       tcp->type = type;
-       *ntype = get_token(fp, ntoken);
-       if (*ntype == LEFTPAREN) {
-           level = 1;
-           /* don't record any constraints for now */
-           while (level > 0) {
-               *ntype = get_token(fp, ntoken);
-               if (*ntype == LEFTPAREN)
-                   level++;
-               if (*ntype == RIGHTPAREN)
-                   level--;
-           }
-           *ntype = get_token(fp, ntoken);
-       } else if (*ntype == LEFTBRACKET) {
-           /* if there is an enumeration list, parse it */
-           while ((type = get_token(fp, token)) != ENDOFFILE) {
-               if (type == RIGHTBRACKET)
-                   break;
-               if (type == LABEL) {
-                   /* this is an enumerated label */
-                   if (tcp->enums == 0) {
-                       ep = tcp->enums = (struct enum_list *)
-                           Malloc(sizeof(struct enum_list));
-                   } else {
-                       ep->next = (struct enum_list *)
-                           Malloc(sizeof(struct enum_list));
-                       ep = ep->next;
-                   }
-                   ep->next = 0;
-                   /* a reasonable approximation for the length */
-                   ep->label =
-                       (char *) Malloc((unsigned) strlen(token) + 1);
-                   strcpy(ep->label, token);
-                   type = get_token(fp, token);
-                   if (type != LEFTPAREN) {
-                       print_error("Expected \"(\"", token, type);
-                       /* free_node(np); */
-                       return 0;
-                   }
-                   type = get_token(fp, token);
-                   if (type != NUMBER) {
-                       print_error("Expected integer", token, type);
-                       /* free_node(np); */
-                       return 0;
-                   }
-                   ep->value = atoi(token);
-                   type = get_token(fp, token);
-                   if (type != RIGHTPAREN) {
-                       print_error("Expected \")\"", token, type);
-                       /* free_node(np); */
-                       return 0;
-                   }
-               }
-           }
-           if (type == ENDOFFILE) {
-               print_error("Expected \"}\"", token, type);
-               /* free_node(np); */
-               return 0;
-           }
-           *ntype = get_token(fp, ntoken);
-       }
-       return 1;
+    if (type != SEQUENCE) {
+        print_error("Not a sequence", token, type);    /* should we handle this */
+        return ENDOFFILE;
     }
+    while ((type = get_token(fp, token)) != ENDOFFILE) {
+        if (type == RIGHTBRACKET)
+            return type;
+    }
+    print_error("Expected \"}\"", token, type);
+    return ENDOFFILE;
 }
 
-
 /*
  * Parses an OBJECT TYPE macro.
  * Returns 0 on error.
  */
 static struct node *
-parse_objecttype(fp, name)
-     FILE *fp;
-     char *name;
-{
-    int type;
-    char token[MAXTOKEN];
+parse_objecttype(register FILE *fp, char *name) {
+    register int type;
+    char token[64];
     int count, length;
-    struct subid oid[32];
-    char syntax[MAXTOKEN];
-    int nexttype, tctype;
-    char nexttoken[MAXTOKEN];
-    struct node *np;
-    struct enum_list *ep = 0;
+    struct subid SubOid[32];
+    char syntax[64];
+    int nexttype;
+    char nexttoken[64];
+    register struct node *np = NULL;
+    register struct enum_list *ep = NULL;
 
     type = get_token(fp, token);
     if (type != SYNTAX) {
-       print_error("Bad format for OBJECT TYPE", token, type);
-       return 0;
+        print_error("Bad format for OBJECT TYPE", token, type);
+        return 0;
     }
-    np = (struct node *) Malloc(sizeof(struct node));
+    np = (struct node *) xmalloc(sizeof(struct node));
     np->next = 0;
     np->enums = 0;
-    np->description = NULL;    /* default to an empty description */
     type = get_token(fp, token);
-    if (type == LABEL) {
-       tctype = get_tc(token, &(np->enums));
-#if 0
-       if (tctype == LABEL) {
-           print_error("No known translation for type", token, type);
-           return 0;
-       }
-#endif
-       type = tctype;
-    }
-    np->type = type;
     nexttype = get_token(fp, nexttoken);
+    np->type = type;
     switch (type) {
     case SEQUENCE:
-       strcpy(syntax, token);
-       if (nexttype == OF) {
-           strcat(syntax, " ");
-           strcat(syntax, nexttoken);
-           nexttype = get_token(fp, nexttoken);
-           strcat(syntax, " ");
-           strcat(syntax, nexttoken);
-           nexttype = get_token(fp, nexttoken);
-       }
-       break;
+        strcpy(syntax, token);
+        if (nexttype == OF) {
+            strcat(syntax, " ");
+            strcat(syntax, nexttoken);
+            nexttype = get_token(fp, nexttoken);
+            strcat(syntax, " ");
+            strcat(syntax, nexttoken);
+            nexttype = get_token(fp, nexttoken);
+        }
+        break;
     case INTEGER:
-    case UINTEGER32:
-       strcpy(syntax, token);
-       if (nexttype == LEFTBRACKET) {
-           /* if there is an enumeration list, parse it */
-           while ((type = get_token(fp, token)) != ENDOFFILE) {
-               if (type == RIGHTBRACKET)
-                   break;
-               if (type == LABEL) {
-                   /* this is an enumerated label */
-                   if (np->enums == 0) {
-                       ep = np->enums = (struct enum_list *)
-                           Malloc(sizeof(struct enum_list));
-                   } else {
-                       ep->next = (struct enum_list *)
-                           Malloc(sizeof(struct enum_list));
-                       ep = ep->next;
-                   }
-                   ep->next = 0;
-                   /* a reasonable approximation for the length */
-                   ep->label =
-                       (char *) Malloc((unsigned) strlen(token) + 1);
-                   strcpy(ep->label, token);
-                   type = get_token(fp, token);
-                   if (type != LEFTPAREN) {
-                       print_error("Expected \"(\"", token, type);
-                       free_node(np);
-                       return 0;
-                   }
-                   type = get_token(fp, token);
-                   if (type != NUMBER) {
-                       print_error("Expected integer", token, type);
-                       free_node(np);
-                       return 0;
-                   }
-                   ep->value = atoi(token);
-                   type = get_token(fp, token);
-                   if (type != RIGHTPAREN) {
-                       print_error("Expected \")\"", token, type);
-                       free_node(np);
-                       return 0;
-                   }
-               }
-           }
-           if (type == ENDOFFILE) {
-               print_error("Expected \"}\"", token, type);
-               free_node(np);
-               return 0;
-           }
-           nexttype = get_token(fp, nexttoken);
-       } else if (nexttype == LEFTPAREN) {
-           /* ignore the "constrained integer" for now */
-           nexttype = get_token(fp, nexttoken);
-           nexttype = get_token(fp, nexttoken);
-           nexttype = get_token(fp, nexttoken);
-       }
-       break;
-    case BITSTRING:
-       strcpy(syntax, token);
-       if (nexttype == LEFTBRACKET) {
-           /* if there is an enumeration list, parse it */
-           while ((type = get_token(fp, token)) != ENDOFFILE) {
-               if (type == RIGHTBRACKET)
-                   break;
-               if (type == LABEL) {
-                   /* this is an enumerated label */
-                   if (np->enums == 0) {
-                       ep = np->enums = (struct enum_list *)
-                           Malloc(sizeof(struct enum_list));
-                   } else {
-                       ep->next = (struct enum_list *)
-                           Malloc(sizeof(struct enum_list));
-                       ep = ep->next;
-                   }
-                   ep->next = 0;
-                   /* a reasonable approximation for the length */
-                   ep->label =
-                       (char *) Malloc((unsigned) strlen(token) + 1);
-                   strcpy(ep->label, token);
-                   type = get_token(fp, token);
-                   if (type != LEFTPAREN) {
-                       print_error("Expected \"(\"", token, type);
-                       free_node(np);
-                       return 0;
-                   }
-                   type = get_token(fp, token);
-                   if (type != NUMBER) {
-                       print_error("Expected integer", token, type);
-                       free_node(np);
-                       return 0;
-                   }
-                   ep->value = atoi(token);
-                   type = get_token(fp, token);
-                   if (type != RIGHTPAREN) {
-                       print_error("Expected \")\"", token, type);
-                       free_node(np);
-                       return 0;
-                   }
-               }
-           }
-           if (type == ENDOFFILE) {
-               print_error("Expected \"}\"", token, type);
-               free_node(np);
-               return 0;
-           }
-           nexttype = get_token(fp, nexttoken);
-       } else if (nexttype == LEFTPAREN) {
-           /* ignore the "constrained integer" for now */
-           nexttype = get_token(fp, nexttoken);
-           nexttype = get_token(fp, nexttoken);
-           nexttype = get_token(fp, nexttoken);
-       }
-       break;
-    case OCTETSTR:
-       strcpy(syntax, token);
-       /* ignore the "constrained octet string" for now */
-       if (nexttype == LEFTPAREN) {
-           nexttype = get_token(fp, nexttoken);
-           if (nexttype == SIZE) {
-               nexttype = get_token(fp, nexttoken);
-               if (nexttype == LEFTPAREN) {
-                   nexttype = get_token(fp, nexttoken);        /* 0..255 */
-                   nexttype = get_token(fp, nexttoken);        /* ) */
-                   nexttype = get_token(fp, nexttoken);        /* ) */
-                   if (nexttype == RIGHTPAREN) {
-                       nexttype = get_token(fp, nexttoken);
-                       break;
-                   }
-               }
-           }
-           print_error("Bad syntax", token, type);
-           free_node(np);
-           return 0;
-       }
-       break;
+        strcpy(syntax, token);
+        if (nexttype == LEFTBRACKET) {
+            /* if there is an enumeration list, parse it */
+            while ((type = get_token(fp, token)) != ENDOFFILE) {
+                if (type == RIGHTBRACKET)
+                    break;
+                if (type == LABEL) {
+                    /* this is an enumerated label */
+                    if (np->enums == 0) {
+                        ep = np->enums = (struct enum_list *)
+                                         xmalloc(sizeof(struct enum_list));
+                    } else {
+                        ep->next = (struct enum_list *)
+                                   xmalloc(sizeof(struct enum_list));
+                        ep = ep->next;
+                    }
+                    ep->next = 0;
+                    /* a reasonable approximation for the length */
+                    ep->label = (char *) xmalloc((unsigned) strlen(token) + 1);
+                    strcpy(ep->label, token);
+                    type = get_token(fp, token);
+                    if (type != LEFTPAREN) {
+                        print_error("Expected \"(\"", token, type);
+                        free_node(np);
+                        return 0;
+                    }
+                    type = get_token(fp, token);
+                    if (type != NUMBER) {
+                        print_error("Expected integer", token, type);
+                        free_node(np);
+                        return 0;
+                    }
+                    ep->value = atoi(token);
+                    type = get_token(fp, token);
+                    if (type != RIGHTPAREN) {
+                        print_error("Expected \")\"", token, type);
+                        free_node(np);
+                        return 0;
+                    }
+                }
+            }
+            if (type == ENDOFFILE) {
+                print_error("Expected \"}\"", token, type);
+                free_node(np);
+                return 0;
+            }
+            nexttype = get_token(fp, nexttoken);
+        } else if (nexttype == LEFTPAREN) {
+            /* ignore the "constrained integer" for now */
+            nexttype = get_token(fp, nexttoken);
+            nexttype = get_token(fp, nexttoken);
+            nexttype = get_token(fp, nexttoken);
+        }
+        break;
     case OBJID:
+    case OCTETSTR:
     case NETADDR:
     case IPADDR:
     case COUNTER:
     case GAUGE:
     case TIMETICKS:
-    case OPAQUE:
+    case SNMP_OPAQUE:
     case NUL:
     case LABEL:
-    case NSAPADDRESS:
-    case COUNTER64:
-       strcpy(syntax, token);
-       break;
+        strcpy(syntax, token);
+        break;
     default:
-       print_error("Bad syntax", token, type);
-       free_node(np);
-       return 0;
-    }
-    if (nexttype == UNITS) {
-       type = get_token(fp, token);
-       if (type != QUOTESTRING) {
-           print_error("Bad DESCRIPTION", token, type);
-           free_node(np);
-           return 0;
-       }
-       nexttype = get_token(fp, nexttoken);
+        print_error("Bad syntax", token, type);
+        free_node(np);
+        return 0;
     }
     if (nexttype != ACCESS) {
-       print_error("Should be ACCESS", nexttoken, nexttype);
-       free_node(np);
-       return 0;
+        print_error("Should be ACCESS", nexttoken, nexttype);
+        free_node(np);
+        return 0;
     }
     type = get_token(fp, token);
     if (type != READONLY && type != READWRITE && type != WRITEONLY
-       && type != NOACCESS && type != READCREATE) {
-       print_error("Bad access type", nexttoken, nexttype);
-       free_node(np);
-       return 0;
+            && type != NOACCESS) {
+        print_error("Bad access type", nexttoken, nexttype);
+        free_node(np);
+        return 0;
     }
     type = get_token(fp, token);
-    if (type != STATUS) {
-       print_error("Should be STATUS", token, nexttype);
-       free_node(np);
-       return 0;
+    if (type != SNMP_STATUS) {
+        print_error("Should be STATUS", token, nexttype);
+        free_node(np);
+        return 0;
     }
     type = get_token(fp, token);
-    if (type != MANDATORY && type != CURRENT && type != OPTIONAL && type != OBSOLETE && type != DEPRECATED) {
-       print_error("Bad status", token, type);
-       free_node(np);
-       return 0;
+    if (type != MANDATORY && type != SNMP_OPTIONAL && type != OBSOLETE && type != RECOMMENDED) {
+        print_error("Bad status", token, type);
+        free_node(np);
+        return 0;
     }
-    /*
-     * Optional parts of the OBJECT-TYPE macro
+    /* Fetch next token.  Either:
+     *
+     * -> EQUALS (Old MIB format)
+     * -> DESCRIPTION, INDEX (New MIB format)
      */
     type = get_token(fp, token);
-    while (type != EQUALS) {
-       switch (type) {
-       case DESCRIPTION:
-           type = get_token(fp, token);
-           if (type != QUOTESTRING) {
-               print_error("Bad DESCRIPTION", token, type);
-               free_node(np);
-               return 0;
-           }
-#ifdef TEST
-           printf("Description== \"%.50s\"\n", quoted_string_buffer);
-#endif
-           np->description = quoted_string_buffer;
-           quoted_string_buffer = (char *) calloc(1, MAXQUOTESTR);
-           break;
-
-       case REFERENCE:
-           type = get_token(fp, token);
-           if (type != QUOTESTRING) {
-               print_error("Bad DESCRIPTION", token, type);
-               free_node(np);
-               return 0;
-           }
-           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 0;
-           }
-           break;
-
-       default:
-           print_error("Bad format of optional clauses", token, type);
-           free_node(np);
-           return 0;
-
-       }
-       type = get_token(fp, token);
-    }
-    if (type != EQUALS) {
-       print_error("Bad format", token, type);
-       free_node(np);
-       return 0;
-    }
-    length = getoid(fp, oid, 32);
-    if (length > 1 && length <= 32) {
-       /* just take the last pair in the oid list */
-       if (oid[length - 2].label)
-           strncpy(np->parent, oid[length - 2].label, MAXLABEL);
-       strcpy(np->label, name);
-       if (oid[length - 1].subid != -1)
-           np->subid = oid[length - 1].subid;
-       else
-           print_error("Warning: This entry is pretty silly", np->label, type);
-    } else {
-       print_error("No end to oid", (char *) NULL, type);
-       free_node(np);
-       np = 0;
-    }
-    /* free oid array */
-    for (count = 0; count < length; count++) {
-       if (oid[count].label)
-           free(oid[count].label);
-       oid[count].label = 0;
+    if ((type != DESCRIPTION) && (type != INDEX) && (type != EQUALS)) {
+        print_error("Should be DESCRIPTION, INDEX, or EQUALS", token, nexttype);
+        free_node(np);
+        return 0;
     }
-    return np;
-}
-
-
-/*
- * Parses an OBJECT GROUP macro.
- * Returns 0 on error.
- */
-static struct node *
-parse_objectgroup(fp, name)
-     FILE *fp;
-     char *name;
-{
-    int type;
-    char token[MAXTOKEN];
-    int count, length;
-    struct subid oid[32];
-    struct node *np;
-
-    np = (struct node *) Malloc(sizeof(struct node));
-    np->type = 0;
-    np->next = 0;
-    np->enums = 0;
-    np->description = NULL;    /* default to an empty description */
-    type = get_token(fp, token);
-    while (type != EQUALS) {
-       switch (type) {
-       case DESCRIPTION:
-           type = get_token(fp, token);
-           if (type != QUOTESTRING) {
-               print_error("Bad DESCRIPTION", token, type);
-               free_node(np);
-               return 0;
-           }
-#ifdef TEST
-           printf("Description== \"%.50s\"\n", quoted_string_buffer);
-#endif
-           np->description = quoted_string_buffer;
-           quoted_string_buffer = (char *) calloc(1, MAXQUOTESTR);
-           break;
-
-       default:
-           /* NOTHING */
-           break;
-       }
-       type = get_token(fp, token);
+    if (type == DESCRIPTION) {
+
+        type = get_token(fp, token);
+        if (type != QUOTE) {
+            print_error("Should be Description open quote", token, nexttype);
+            free_node(np);
+            return 0;
+        }
+        /* Fetch description string */
+        {
+            int ReadChar;
+
+            ReadChar = last;
+            /* skip everything until closing quote */
+            while ((ReadChar != '"') && (ReadChar != -1)) {
+                ReadChar = getc(fp);
+                if (ReadChar == '\n')
+                    Line++;
+            }
+            last = ' ';
+        }
+        /* ASSERT:  Done with description. */
+        type = get_token(fp, token);
     }
-    length = getoid(fp, oid, 32);
-    if (length > 1 && length <= 32) {
-       /* just take the last pair in the oid list */
-       if (oid[length - 2].label)
-           strncpy(np->parent, oid[length - 2].label, MAXLABEL);
-       strcpy(np->label, name);
-       if (oid[length - 1].subid != -1)
-           np->subid = oid[length - 1].subid;
-       else
-           print_error("Warning: This entry is pretty silly", np->label, type);
-    } else {
-       print_error("No end to oid", (char *) NULL, type);
-       free_node(np);
-       np = 0;
+    if ((type != INDEX) && (type != EQUALS)) {
+        print_error("Should be INDEX, or EQUALS", token, nexttype);
+        free_node(np);
+        return 0;
     }
-    /* free oid array */
-    for (count = 0; count < length; count++) {
-       if (oid[count].label)
-           free(oid[count].label);
-       oid[count].label = 0;
+    if (type == INDEX) {
+
+        /* Scarf INDEX */
+
+        type = get_token(fp, token);
+        if (type != LEFTBRACKET) {
+            print_error("Should be INDEX left brace", token, type);
+            free_node(np);
+            return 0;
+        }
+        /* Fetch description string */
+        {
+            int ReadChar;
+
+            ReadChar = last;
+            /* skip everything until closing quote */
+            while ((ReadChar != '}') && (ReadChar != -1)) {
+                ReadChar = getc(fp);
+                if (ReadChar == '\n')
+                    Line++;
+            }
+            last = ' ';
+        }
+        /* ASSERT:  Done with INDEX. */
+        type = get_token(fp, token);
     }
-    return np;
-}
-
-/*
- * Parses a NOTIFICATION-TYPE macro.
- * Returns 0 on error.
- */
-static struct node *
-parse_notificationDefinition(fp, name)
-     FILE *fp;
-     char *name;
-{
-    int type;
-    char token[MAXTOKEN];
-    int count, length;
-    struct subid oid[32];
-    struct node *np;
-
-    np = (struct node *) Malloc(sizeof(struct node));
-    np->type = 0;
-    np->next = 0;
-    np->enums = 0;
-    np->description = NULL;    /* default to an empty description */
-    type = get_token(fp, token);
-    while (type != EQUALS) {
-       switch (type) {
-       case DESCRIPTION:
-           type = get_token(fp, token);
-           if (type != QUOTESTRING) {
-               print_error("Bad DESCRIPTION", token, type);
-               free_node(np);
-               return 0;
-           }
-#ifdef TEST
-           printf("Description== \"%.50s\"\n", quoted_string_buffer);
-#endif
-           np->description = quoted_string_buffer;
-           quoted_string_buffer = (char *) calloc(1, MAXQUOTESTR);
-           break;
-
-       default:
-           /* NOTHING */
-           break;
-       }
-       type = get_token(fp, token);
-    }
-    length = getoid(fp, oid, 32);
-    if (length > 1 && length <= 32) {
-       /* just take the last pair in the oid list */
-       if (oid[length - 2].label)
-           strncpy(np->parent, oid[length - 2].label, MAXLABEL);
-       strcpy(np->label, name);
-       if (oid[length - 1].subid != -1)
-           np->subid = oid[length - 1].subid;
-       else
-           print_error("Warning: This entry is pretty silly", np->label, type);
-    } else {
-       print_error("No end to oid", (char *) NULL, type);
-       free_node(np);
-       np = 0;
-    }
-    /* free oid array */
-    for (count = 0; count < length; count++) {
-       if (oid[count].label)
-           free(oid[count].label);
-       oid[count].label = 0;
-    }
-    return np;
-}
-
-/*
- * Parses a compliance macro
- * Returns 0 on error.
- */
-static struct node *
-parse_compliance(fp, name)
-     FILE *fp;
-     char *name;
-{
-    int type;
-    char token[MAXTOKEN];
-    int count, length;
-    struct subid oid[32];
-    struct node *np;
-
-    np = (struct node *) Malloc(sizeof(struct node));
-    np->type = 0;
-    np->next = 0;
-    np->enums = 0;
-    np->description = NULL;    /* default to an empty description */
-    type = get_token(fp, token);
-    while (type != EQUALS) {
-       type = get_token(fp, token);
-    }
-    length = getoid(fp, oid, 32);
-    if (length > 1 && length <= 32) {
-       /* just take the last pair in the oid list */
-       if (oid[length - 2].label)
-           strncpy(np->parent, oid[length - 2].label, MAXLABEL);
-       strcpy(np->label, name);
-       if (oid[length - 1].subid != -1)
-           np->subid = oid[length - 1].subid;
-       else
-           print_error("Warning: This entry is pretty silly", np->label, type);
-    } else {
-       print_error("No end to oid", (char *) NULL, type);
-       free_node(np);
-       np = 0;
-    }
-    /* free oid array */
-    for (count = 0; count < length; count++) {
-       if (oid[count].label)
-           free(oid[count].label);
-       oid[count].label = 0;
-    }
-    return np;
-}
-
-
-
-/*
- * Parses a module identity macro
- * Returns 0 on error.
- */
-static struct node *
-parse_moduleIdentity(fp, name)
-     FILE *fp;
-     char *name;
-{
-    int type;
-    char token[MAXTOKEN];
-    int count, length;
-    struct subid oid[32];
-    struct node *np;
-
-    np = (struct node *) Malloc(sizeof(struct node));
-    np->type = 0;
-    np->next = 0;
-    np->enums = 0;
-    np->description = NULL;    /* default to an empty description */
-    type = get_token(fp, token);
-    while (type != EQUALS) {
-       type = get_token(fp, token);
+    if (type != EQUALS) {
+        print_error("Bad format", token, type);
+        free_node(np);
+        return 0;
     }
-    length = getoid(fp, oid, 32);
+    length = getoid(fp, SubOid, 32);
     if (length > 1 && length <= 32) {
-       /* just take the last pair in the oid list */
-       if (oid[length - 2].label)
-           strncpy(np->parent, oid[length - 2].label, MAXLABEL);
-       strcpy(np->label, name);
-       if (oid[length - 1].subid != -1)
-           np->subid = oid[length - 1].subid;
-       else
-           print_error("Warning: This entry is pretty silly", np->label, type);
+        /* just take the last pair in the oid list */
+        if (SubOid[length - 2].label)
+            strncpy(np->parent, SubOid[length - 2].label, 64);
+        strcpy(np->label, name);
+        if (SubOid[length - 1].subid != -1)
+            np->subid = SubOid[length - 1].subid;
+        else
+            print_error("Warning: This entry is pretty silly", np->label, type);
     } else {
-       print_error("No end to oid", (char *) NULL, type);
-       free_node(np);
-       np = 0;
+        print_error("No end to oid", (char *) NULL, type);
+        free_node(np);
+        np = 0;
     }
     /* free oid array */
     for (count = 0; count < length; count++) {
-       if (oid[count].label)
-           free(oid[count].label);
-       oid[count].label = 0;
+        if (SubOid[count].label)
+            xfree(SubOid[count].label);
+        SubOid[count].label = 0;
     }
     return np;
 }
 
-int 
-parse_mib_header(fp, name)
-     FILE *fp;
-     char *name;
-{
-    int type = DEFINITIONS;
-    char token[MAXTOKEN];
-
-    /* This probably isn't good enough.  If there is no
-     * imports clause we can't go around waiting (forever) for a semicolon.
-     * We need to check for semi following an EXPORTS clause or an IMPORTS
-     * clause of both.  Look for BEGIN; in my initial MIBs to see those
-     * that I needed to hack to get to parse because they didn't have
-     * an IMPORTS or and EXPORTS clause.
-     */
-    while (type != SEMI && type != ENDOFFILE) {
-       type = get_token(fp, token);
-    }
-    return (type == SEMI);
-}
-
-
-
 /*
  * Parses a mib file and returns a linked list of nodes found in the file.
  * Returns NULL on error.
  */
-static struct node *
-parse(fp)
-     FILE *fp;
-{
-    char token[MAXTOKEN];
-    char name[MAXTOKEN];
+#if !TEST
+static
+#endif
+struct node *
+parse(FILE *fp) {
+    char token[64];
+    char name[64];
     int type = 1;
-#define BETWEEN_MIBS         1
-#define IN_MIB                2
-    int state = BETWEEN_MIBS;
-    struct node *np = 0, *root = NULL;
+    struct node *np = NULL, *root = NULL;
 
     hash_init();
-    quoted_string_buffer = (char *) calloc(1, MAXQUOTESTR);    /* free this later */
-    bzero(tclist, 64 * sizeof(struct tc));
 
     while (type != ENDOFFILE) {
-       type = get_token(fp, token);
-      skipget:
-       if (type == END) {
-           if (state != IN_MIB) {
-               print_error("Error, end before start of MIB.", (char *) NULL, type);
-               return NULL;
-           }
-           state = BETWEEN_MIBS;
-           continue;
-       } else if (type != LABEL) {
-           if (type == ENDOFFILE) {
-               return root;
-           }
-           print_error(token, "is a reserved word", type);
-           return NULL;
-       }
-       strncpy(name, token, MAXTOKEN);
-       type = get_token(fp, token);
-       if (type == DEFINITIONS) {
-           if (state != BETWEEN_MIBS) {
-               print_error("Error, nested MIBS.", (char *) NULL, type);
-               return NULL;
-           }
-           state = IN_MIB;
-           if (!parse_mib_header(fp, name)) {
-               print_error("Bad parse of module header", (char *) NULL, type);
-               return NULL;
-           }
-       } else if (type == OBJTYPE) {
-           if (root == NULL) {
-               /* first link in chain */
-               np = root = parse_objecttype(fp, name);
-               if (np == NULL) {
-                   print_error("Bad parse of object type", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           } else {
-               np->next = parse_objecttype(fp, name);
-               if (np->next == NULL) {
-                   print_error("Bad parse of objecttype", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           }
-           /* now find end of chain */
-           while (np->next)
-               np = np->next;
-       } else if (type == OBJGROUP) {
-           if (root == NULL) {
-               /* first link in chain */
-               np = root = parse_objectgroup(fp, name);
-               if (np == NULL) {
-                   print_error("Bad parse of object group", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           } else {
-               np->next = parse_objectgroup(fp, name);
-               if (np->next == NULL) {
-                   print_error("Bad parse of objectgroup", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           }
-           /* now find end of chain */
-           while (np->next)
-               np = np->next;
-       } else if (type == NOTIFTYPE) {
-           if (root == NULL) {
-               /* first link in chain */
-               np = root = parse_notificationDefinition(fp, name);
-               if (np == NULL) {
-                   print_error("Bad parse of notification definition",
-                       (char *) NULL, type);
-                   return NULL;
-               }
-           } else {
-               np->next = parse_notificationDefinition(fp, name);
-               if (np->next == NULL) {
-                   print_error("Bad parse of notification definition",
-                       (char *) NULL, type);
-                   return NULL;
-               }
-           }
-           /* now find end of chain */
-           while (np->next)
-               np = np->next;
-       } else if (type == COMPLIANCE) {
-           if (root == NULL) {
-               /* first link in chain */
-               np = root = parse_compliance(fp, name);
-               if (np == NULL) {
-                   print_error("Bad parse of module compliance", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           } else {
-               np->next = parse_compliance(fp, name);
-               if (np->next == NULL) {
-                   print_error("Bad parse of module compliance", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           }
-           /* now find end of chain */
-           while (np->next)
-               np = np->next;
-       } else if (type == MODULEIDENTITY) {
-           if (root == NULL) {
-               /* first link in chain */
-               np = root = parse_moduleIdentity(fp, name);
-               if (np == NULL) {
-                   print_error("Bad parse of module identity", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           } else {
-               np->next = parse_moduleIdentity(fp, name);
-               if (np->next == NULL) {
-                   print_error("Bad parse of module identity", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           }
-           /* now find end of chain */
-           while (np->next)
-               np = np->next;
-       } else if (type == OBJID) {
-           if (root == NULL) {
-               /* first link in chain */
-               np = root = parse_objectid(fp, name);
-               if (np == NULL) {
-                   print_error("Bad parse of object id", (char *) NULL, type);
-                   return NULL;
-               }
-           } else {
-               np->next = parse_objectid(fp, name);
-               if (np->next == NULL) {
-                   print_error("Bad parse of object type", (char *) NULL,
-                       type);
-                   return NULL;
-               }
-           }
-           /* now find end of chain */
-           while (np->next)
-               np = np->next;
-       } else if (type == EQUALS) {
-           if (!parse_asntype(fp, name, &type, token)) {
-               print_error("Bad parse of ASN type definition.", NULL, EQUALS);
-               return NULL;
-           }
-           goto skipget;
-       } else if (type == ENDOFFILE) {
-           break;
-       } else {
-           print_error("Bad operator", (char *) NULL, type);
-           return NULL;
-       }
+        type = get_token(fp, token);
+        if (type != LABEL) {
+            if (type == ENDOFFILE) {
+                return root;
+            }
+            print_error(token, "is a reserved word", type);
+            return NULL;
+        }
+        strncpy(name, token, 64);
+        type = get_token(fp, token);
+        if (type == OBJTYPE) {
+            if (root == NULL) {
+                /* first link in chain */
+                np = root = parse_objecttype(fp, name);
+                if (np == NULL) {
+                    print_error("Bad parse of object type", (char *) NULL, type);
+                    return NULL;
+                }
+            } else {
+                np->next = parse_objecttype(fp, name);
+                if (np->next == NULL) {
+                    print_error("Bad parse of objecttype", (char *) NULL, type);
+                    return NULL;
+                }
+            }
+            /* now find end of chain */
+            while (np->next)
+                np = np->next;
+        } else if (type == OBJID) {
+            if (root == NULL) {
+                /* first link in chain */
+                np = root = parse_objectid(fp, name);
+                if (np == NULL) {
+                    print_error("Bad parse of object id", (char *) NULL, type);
+                    return NULL;
+                }
+            } else {
+                np->next = parse_objectid(fp, name);
+                if (np->next == NULL) {
+                    print_error("Bad parse of object type", (char *) NULL, type);
+                    return NULL;
+                }
+            }
+            /* now find end of chain */
+            while (np->next)
+                np = np->next;
+        } else if (type == EQUALS) {
+            type = parse_asntype(fp);
+        } else if (type == ENDOFFILE) {
+            break;
+        } else {
+            print_error("Bad operator", (char *) NULL, type);
+            return NULL;
+        }
     }
-#ifdef TEST
+#if TEST
     {
-       struct enum_list *ep;
-
-       for (np = root; np; np = np->next) {
-           printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
-               np->type);
-           if (np->enums) {
-               printf("Enums: \n");
-               for (ep = np->enums; ep; ep = ep->next) {
-                   printf("%s(%d)\n", ep->label, ep->value);
-               }
-           }
-       }
+        struct enum_list *ep;
+
+        for (np = root; np; np = np->next) {
+            printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
+                   np->type);
+            if (np->enums) {
+                printf("Enums: \n");
+                for (ep = np->enums; ep; ep = ep->next) {
+                    printf("%s(%d)\n", ep->label, ep->value);
+                }
+            }
+        }
     }
 #endif /* TEST */
     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
-get_token(fp, token)
-     FILE *fp;
-     char *token;
-{
-    static char last = ' ';
-    int ch;
-    char *cp = token;
-    int hash = 0;
-    struct tok *tp;
-
-    *cp = 0;
-    ch = last;
-    /* skip all white space */
-    while (isspace(ch) && ch != -1) {
-       ch = getc(fp);
-       if (ch == '\n')
-           Line++;
-    }
-    if (ch == -1) {
-       return ENDOFFILE;
-    } else if (ch == '"') {
-       return parseQuoteString(fp, token);
-    }
-    /*
-     * 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.
-     */
-    do {
-       if (ch == '\n')
-           Line++;
-       if (isspace(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
-           ch == ',' || ch == ';') {
-           if (!isspace(ch) && *token == 0) {
-               hash += ch;
-               *cp++ = ch;
-               last = ' ';
-           } else {
-               last = ch;
-           }
-           *cp = '\0';
-
-           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)) != -1)
-                       if (ch == '\n') {
-                           Line++;
-                           break;
-                       }
-               }
-               if (ch == -1)
-                   return ENDOFFILE;
-               last = ch;
-               return get_token(fp, token);
-           }
-           for (cp = token; *cp; cp++)
-               if (!isdigit(*cp))
-                   return LABEL;
-           return NUMBER;
-       } else {
-           hash += ch;
-           *cp++ = ch;
-           if (ch == '\n')
-               Line++;
-       }
-
-    } while ((ch = getc(fp)) != -1);
-    return ENDOFFILE;
-}
-
-struct tree *
-read_mib(const char *filename)
-{
+struct snmp_mib_tree *
+read_mib(char *filename) {
     FILE *fp;
     struct node *nodes;
-    struct tree *tree;
+    struct snmp_mib_tree *tree;
+    char mbuf[256];
+    char *p;
 
     fp = fopen(filename, "r");
-    if (fp == NULL)
-       return NULL;
-    nodes = parse(fp);
-    if (!nodes) {
-       fprintf(stderr, "Mib table is bad.  Exiting\n");
-       exit(1);
-    }
-    tree = build_tree(nodes);
-    fclose(fp);
-    return tree;
-}
-
-
-#ifdef TEST
-main(argc, argv)
-     int argc;
-     char *argv[];
-{
-    FILE *fp;
-    struct node *nodes;
-    struct tree *tp;
-
-    fp = fopen("mib.txt", "r");
     if (fp == NULL) {
-       fprintf(stderr, "open failed\n");
-       return 1;
+        snmplib_debug(1, "init_mib: %s: %s\n", filename, xstrerror());
+        return (NULL);
     }
-    nodes = parse(fp);
-    tp = build_tree(nodes);
-    print_subtree(tp, 0);
-    fclose(fp);
-}
-
-#endif /* TEST */
-
-static int
-parseQuoteString(fp, token)
-     FILE *fp;
-     char *token;
-{
-    int ch;
-
-    ch = ' ';
-    *token = '\0';             /* make the token empty */
-
-    while (ch != -1) {
-       ch = getc(fp);
-       if (ch == '\n')
-           Line++;
-       else if (ch == '"') {
-           return QUOTESTRING;
-       }
+    mbuf[0] = '\0';
+    while ((p = fgets(mbuf, 256, fp)) && strncmp(mbuf, "DUMMY",
+            strlen("DUMMY")));
+    if (!p) {
+        snmplib_debug(0, "Bad MIB version or tag missing, install original!\n");
+        return NULL;
     }
-
-    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)
-     FILE *fp;
-{
-    int ch;
-
-    ch = getc(fp);
-/*    ch = last; = ' '? */
-    /* skip all white space */
-    while (isspace(ch) && ch != -1) {
-       ch = getc(fp);
-       if (ch == '\n')
-           Line++;
+    if (!strcmp(mbuf, "DUMMY")) {
+        snmplib_debug(0, "You need to update your MIB!\n");
+        return NULL;
     }
-    if (ch != '{')
-       return 0;
-
-    while (ch != -1) {
-       ch = getc(fp);
-
-       if (ch == '\n')
-           Line++;
-       else if (ch == '}')
-           return OBJID;
+    nodes = parse(fp);
+    if (!nodes) {
+        snmplib_debug(0, "Mib table is bad.  Exiting\n");
+        return NULL;
     }
-
-/*    last = ch; */
-    return 0;
+    tree = build_tree(nodes);
+    fclose(fp);
+    return (tree);
 }