net-snmp 5.7
parse.c
00001 /*
00002  * parse.c
00003  *
00004  */
00005 /* Portions of this file are subject to the following copyrights.  See
00006  * the Net-SNMP's COPYING file for more details and other copyrights
00007  * that may apply:
00008  */
00009 /******************************************************************
00010         Copyright 1989, 1991, 1992 by Carnegie Mellon University
00011 
00012                       All Rights Reserved
00013 
00014 Permission to use, copy, modify, and distribute this software and its
00015 documentation for any purpose and without fee is hereby granted,
00016 provided that the above copyright notice appear in all copies and that
00017 both that copyright notice and this permission notice appear in
00018 supporting documentation, and that the name of CMU not be
00019 used in advertising or publicity pertaining to distribution of the
00020 software without specific, written prior permission.
00021 
00022 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00023 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00024 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00025 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00026 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00027 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00028 SOFTWARE.
00029 ******************************************************************/
00030 /*
00031  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00032  * Use is subject to license terms specified in the COPYING file
00033  * distributed with the Net-SNMP package.
00034  */
00035 #include <net-snmp/net-snmp-config.h>
00036 #include <net-snmp/net-snmp-features.h>
00037 
00038 #ifndef NETSNMP_DISABLE_MIB_LOADING
00039 
00040 #if HAVE_LIMITS_H
00041 #include <limits.h>
00042 #endif
00043 #include <stdio.h>
00044 #if HAVE_STDLIB_H
00045 #include <stdlib.h>
00046 #endif
00047 #if HAVE_STRING_H
00048 #include <string.h>
00049 #else
00050 #include <strings.h>
00051 #endif
00052 #include <ctype.h>
00053 #include <sys/types.h>
00054 #if HAVE_SYS_STAT_H
00055 #include <sys/stat.h>
00056 #endif
00057 
00058 /*
00059  * Wow.  This is ugly.  -- Wes 
00060  */
00061 #if HAVE_DIRENT_H
00062 # include <dirent.h>
00063 # define NAMLEN(dirent) strlen((dirent)->d_name)
00064 #else
00065 # define dirent direct
00066 # define NAMLEN(dirent) (dirent)->d_namlen
00067 # if HAVE_SYS_NDIR_H
00068 #  include <sys/ndir.h>
00069 # endif
00070 # if HAVE_SYS_DIR_H
00071 #  include <sys/dir.h>
00072 # endif
00073 # if HAVE_NDIR_H
00074 #  include <ndir.h>
00075 # endif
00076 #endif
00077 #if TIME_WITH_SYS_TIME
00078 # include <sys/time.h>
00079 # include <time.h>
00080 #else
00081 # if HAVE_SYS_TIME_H
00082 #  include <sys/time.h>
00083 # else
00084 #  include <time.h>
00085 # endif
00086 #endif
00087 #if HAVE_NETINET_IN_H
00088 #include <netinet/in.h>
00089 #endif
00090 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
00091 #include <regex.h>
00092 #endif
00093 #if HAVE_UNISTD_H
00094 #include <unistd.h>
00095 #endif
00096 #if HAVE_DMALLOC_H
00097 #include <dmalloc.h>
00098 #endif
00099 
00100 #include <errno.h>
00101 
00102 #include <net-snmp/types.h>
00103 #include <net-snmp/output_api.h>
00104 #include <net-snmp/config_api.h>
00105 #include <net-snmp/utilities.h>
00106 
00107 #include <net-snmp/library/parse.h>
00108 #include <net-snmp/library/mib.h>
00109 #include <net-snmp/library/snmp_api.h>
00110 #include <net-snmp/library/tools.h>
00111 
00112 netsnmp_feature_child_of(find_module, mib_api)
00113 netsnmp_feature_child_of(get_tc_description, mib_api)
00114 
00115 /*
00116  * A linked list of nodes.
00117  */
00118 struct node {
00119     struct node    *next;
00120     char           *label;  /* This node's (unique) textual name */
00121     u_long          subid;  /* This node's integer subidentifier */
00122     int             modid;  /* The module containing this node */
00123     char           *parent; /* The parent's textual name */
00124     int             tc_index; /* index into tclist (-1 if NA) */
00125     int             type;   /* The type of object this represents */
00126     int             access;
00127     int             status;
00128     struct enum_list *enums; /* (optional) list of enumerated integers */
00129     struct range_list *ranges;
00130     struct index_list *indexes;
00131     char           *augments;
00132     struct varbind_list *varbinds;
00133     char           *hint;
00134     char           *units;
00135     char           *description; /* description (a quoted string) */
00136     char           *reference; /* references (a quoted string) */
00137     char           *defaultValue;
00138     char           *filename;
00139     int             lineno;
00140 };
00141 
00142 /*
00143  * This is one element of an object identifier with either an integer
00144  * subidentifier, or a textual string label, or both.
00145  * The subid is -1 if not present, and label is NULL if not present.
00146  */
00147 struct subid_s {
00148     int             subid;
00149     int             modid;
00150     char           *label;
00151 };
00152 
00153 #define MAXTC   4096
00154 struct tc {                     /* textual conventions */
00155     int             type;
00156     int             modid;
00157     char           *descriptor;
00158     char           *hint;
00159     struct enum_list *enums;
00160     struct range_list *ranges;
00161     char           *description;
00162 } tclist[MAXTC];
00163 
00164 int             mibLine = 0;
00165 const char     *File = "(none)";
00166 static int      anonymous = 0;
00167 
00168 struct objgroup {
00169     char           *name;
00170     int             line;
00171     struct objgroup *next;
00172 }              *objgroups = NULL, *objects = NULL, *notifs = NULL;
00173 
00174 #define SYNTAX_MASK     0x80
00175 /*
00176  * types of tokens
00177  * Tokens wiht the SYNTAX_MASK bit set are syntax tokens 
00178  */
00179 #define CONTINUE    -1
00180 #define ENDOFFILE   0
00181 #define LABEL       1
00182 #define SUBTREE     2
00183 #define SYNTAX      3
00184 #define OBJID       (4 | SYNTAX_MASK)
00185 #define OCTETSTR    (5 | SYNTAX_MASK)
00186 #define INTEGER     (6 | SYNTAX_MASK)
00187 #define NETADDR     (7 | SYNTAX_MASK)
00188 #define IPADDR      (8 | SYNTAX_MASK)
00189 #define COUNTER     (9 | SYNTAX_MASK)
00190 #define GAUGE       (10 | SYNTAX_MASK)
00191 #define TIMETICKS   (11 | SYNTAX_MASK)
00192 #define KW_OPAQUE   (12 | SYNTAX_MASK)
00193 #define NUL         (13 | SYNTAX_MASK)
00194 #define SEQUENCE    14
00195 #define OF          15          /* SEQUENCE OF */
00196 #define OBJTYPE     16
00197 #define ACCESS      17
00198 #define READONLY    18
00199 #define READWRITE   19
00200 #define WRITEONLY   20
00201 #ifdef NOACCESS
00202 #undef NOACCESS                 /* agent 'NOACCESS' token */
00203 #endif
00204 #define NOACCESS    21
00205 #define STATUS      22
00206 #define MANDATORY   23
00207 #define KW_OPTIONAL    24
00208 #define OBSOLETE    25
00209 /*
00210  * #define RECOMMENDED 26 
00211  */
00212 #define PUNCT       27
00213 #define EQUALS      28
00214 #define NUMBER      29
00215 #define LEFTBRACKET 30
00216 #define RIGHTBRACKET 31
00217 #define LEFTPAREN   32
00218 #define RIGHTPAREN  33
00219 #define COMMA       34
00220 #define DESCRIPTION 35
00221 #define QUOTESTRING 36
00222 #define INDEX       37
00223 #define DEFVAL      38
00224 #define DEPRECATED  39
00225 #define SIZE        40
00226 #define BITSTRING   (41 | SYNTAX_MASK)
00227 #define NSAPADDRESS (42 | SYNTAX_MASK)
00228 #define COUNTER64   (43 | SYNTAX_MASK)
00229 #define OBJGROUP    44
00230 #define NOTIFTYPE   45
00231 #define AUGMENTS    46
00232 #define COMPLIANCE  47
00233 #define READCREATE  48
00234 #define UNITS       49
00235 #define REFERENCE   50
00236 #define NUM_ENTRIES 51
00237 #define MODULEIDENTITY 52
00238 #define LASTUPDATED 53
00239 #define ORGANIZATION 54
00240 #define CONTACTINFO 55
00241 #define UINTEGER32 (56 | SYNTAX_MASK)
00242 #define CURRENT     57
00243 #define DEFINITIONS 58
00244 #define END         59
00245 #define SEMI        60
00246 #define TRAPTYPE    61
00247 #define ENTERPRISE  62
00248 /*
00249  * #define DISPLAYSTR (63 | SYNTAX_MASK) 
00250  */
00251 #define BEGIN       64
00252 #define IMPORTS     65
00253 #define EXPORTS     66
00254 #define ACCNOTIFY   67
00255 #define BAR         68
00256 #define RANGE       69
00257 #define CONVENTION  70
00258 #define DISPLAYHINT 71
00259 #define FROM        72
00260 #define AGENTCAP    73
00261 #define MACRO       74
00262 #define IMPLIED     75
00263 #define SUPPORTS    76
00264 #define INCLUDES    77
00265 #define VARIATION   78
00266 #define REVISION    79
00267 #define NOTIMPL     80
00268 #define OBJECTS     81
00269 #define NOTIFICATIONS   82
00270 #define MODULE      83
00271 #define MINACCESS   84
00272 #define PRODREL     85
00273 #define WRSYNTAX    86
00274 #define CREATEREQ   87
00275 #define NOTIFGROUP  88
00276 #define MANDATORYGROUPS 89
00277 #define GROUP       90
00278 #define OBJECT      91
00279 #define IDENTIFIER  92
00280 #define CHOICE      93
00281 #define LEFTSQBRACK     95
00282 #define RIGHTSQBRACK    96
00283 #define IMPLICIT    97
00284 #define APPSYNTAX       (98 | SYNTAX_MASK)
00285 #define OBJSYNTAX       (99 | SYNTAX_MASK)
00286 #define SIMPLESYNTAX    (100 | SYNTAX_MASK)
00287 #define OBJNAME         (101 | SYNTAX_MASK)
00288 #define NOTIFNAME       (102 | SYNTAX_MASK)
00289 #define VARIABLES       103
00290 #define UNSIGNED32      (104 | SYNTAX_MASK)
00291 #define INTEGER32       (105 | SYNTAX_MASK)
00292 #define OBJIDENTITY     106
00293 /*
00294  * Beware of reaching SYNTAX_MASK (0x80) 
00295  */
00296 
00297 struct tok {
00298     const char     *name;       /* token name */
00299     int             len;        /* length not counting nul */
00300     int             token;      /* value */
00301     int             hash;       /* hash of name */
00302     struct tok     *next;       /* pointer to next in hash table */
00303 };
00304 
00305 
00306 static struct tok tokens[] = {
00307     {"obsolete", sizeof("obsolete") - 1, OBSOLETE}
00308     ,
00309     {"Opaque", sizeof("Opaque") - 1, KW_OPAQUE}
00310     ,
00311     {"optional", sizeof("optional") - 1, KW_OPTIONAL}
00312     ,
00313     {"LAST-UPDATED", sizeof("LAST-UPDATED") - 1, LASTUPDATED}
00314     ,
00315     {"ORGANIZATION", sizeof("ORGANIZATION") - 1, ORGANIZATION}
00316     ,
00317     {"CONTACT-INFO", sizeof("CONTACT-INFO") - 1, CONTACTINFO}
00318     ,
00319     {"MODULE-IDENTITY", sizeof("MODULE-IDENTITY") - 1, MODULEIDENTITY}
00320     ,
00321     {"MODULE-COMPLIANCE", sizeof("MODULE-COMPLIANCE") - 1, COMPLIANCE}
00322     ,
00323     {"DEFINITIONS", sizeof("DEFINITIONS") - 1, DEFINITIONS}
00324     ,
00325     {"END", sizeof("END") - 1, END}
00326     ,
00327     {"AUGMENTS", sizeof("AUGMENTS") - 1, AUGMENTS}
00328     ,
00329     {"not-accessible", sizeof("not-accessible") - 1, NOACCESS}
00330     ,
00331     {"write-only", sizeof("write-only") - 1, WRITEONLY}
00332     ,
00333     {"NsapAddress", sizeof("NsapAddress") - 1, NSAPADDRESS}
00334     ,
00335     {"UNITS", sizeof("Units") - 1, UNITS}
00336     ,
00337     {"REFERENCE", sizeof("REFERENCE") - 1, REFERENCE}
00338     ,
00339     {"NUM-ENTRIES", sizeof("NUM-ENTRIES") - 1, NUM_ENTRIES}
00340     ,
00341     {"BITSTRING", sizeof("BITSTRING") - 1, BITSTRING}
00342     ,
00343     {"BIT", sizeof("BIT") - 1, CONTINUE}
00344     ,
00345     {"BITS", sizeof("BITS") - 1, BITSTRING}
00346     ,
00347     {"Counter64", sizeof("Counter64") - 1, COUNTER64}
00348     ,
00349     {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS}
00350     ,
00351     {"NOTIFICATION-TYPE", sizeof("NOTIFICATION-TYPE") - 1, NOTIFTYPE}
00352     ,
00353     {"OBJECT-GROUP", sizeof("OBJECT-GROUP") - 1, OBJGROUP}
00354     ,
00355     {"OBJECT-IDENTITY", sizeof("OBJECT-IDENTITY") - 1, OBJIDENTITY}
00356     ,
00357     {"IDENTIFIER", sizeof("IDENTIFIER") - 1, IDENTIFIER}
00358     ,
00359     {"OBJECT", sizeof("OBJECT") - 1, OBJECT}
00360     ,
00361     {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR}
00362     ,
00363     {"Gauge", sizeof("Gauge") - 1, GAUGE}
00364     ,
00365     {"Gauge32", sizeof("Gauge32") - 1, GAUGE}
00366     ,
00367     {"Unsigned32", sizeof("Unsigned32") - 1, UNSIGNED32}
00368     ,
00369     {"read-write", sizeof("read-write") - 1, READWRITE}
00370     ,
00371     {"read-create", sizeof("read-create") - 1, READCREATE}
00372     ,
00373     {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR}
00374     ,
00375     {"OCTET", sizeof("OCTET") - 1, CONTINUE}
00376     ,
00377     {"OF", sizeof("OF") - 1, OF}
00378     ,
00379     {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE}
00380     ,
00381     {"NULL", sizeof("NULL") - 1, NUL}
00382     ,
00383     {"IpAddress", sizeof("IpAddress") - 1, IPADDR}
00384     ,
00385     {"UInteger32", sizeof("UInteger32") - 1, UINTEGER32}
00386     ,
00387     {"INTEGER", sizeof("INTEGER") - 1, INTEGER}
00388     ,
00389     {"Integer32", sizeof("Integer32") - 1, INTEGER32}
00390     ,
00391     {"Counter", sizeof("Counter") - 1, COUNTER}
00392     ,
00393     {"Counter32", sizeof("Counter32") - 1, COUNTER}
00394     ,
00395     {"read-only", sizeof("read-only") - 1, READONLY}
00396     ,
00397     {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION}
00398     ,
00399     {"INDEX", sizeof("INDEX") - 1, INDEX}
00400     ,
00401     {"DEFVAL", sizeof("DEFVAL") - 1, DEFVAL}
00402     ,
00403     {"deprecated", sizeof("deprecated") - 1, DEPRECATED}
00404     ,
00405     {"SIZE", sizeof("SIZE") - 1, SIZE}
00406     ,
00407     {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS}
00408     ,
00409     {"ACCESS", sizeof("ACCESS") - 1, ACCESS}
00410     ,
00411     {"mandatory", sizeof("mandatory") - 1, MANDATORY}
00412     ,
00413     {"current", sizeof("current") - 1, CURRENT}
00414     ,
00415     {"STATUS", sizeof("STATUS") - 1, STATUS}
00416     ,
00417     {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX}
00418     ,
00419     {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE}
00420     ,
00421     {"TRAP-TYPE", sizeof("TRAP-TYPE") - 1, TRAPTYPE}
00422     ,
00423     {"ENTERPRISE", sizeof("ENTERPRISE") - 1, ENTERPRISE}
00424     ,
00425     {"BEGIN", sizeof("BEGIN") - 1, BEGIN}
00426     ,
00427     {"IMPORTS", sizeof("IMPORTS") - 1, IMPORTS}
00428     ,
00429     {"EXPORTS", sizeof("EXPORTS") - 1, EXPORTS}
00430     ,
00431     {"accessible-for-notify", sizeof("accessible-for-notify") - 1,
00432      ACCNOTIFY}
00433     ,
00434     {"TEXTUAL-CONVENTION", sizeof("TEXTUAL-CONVENTION") - 1, CONVENTION}
00435     ,
00436     {"NOTIFICATION-GROUP", sizeof("NOTIFICATION-GROUP") - 1, NOTIFGROUP}
00437     ,
00438     {"DISPLAY-HINT", sizeof("DISPLAY-HINT") - 1, DISPLAYHINT}
00439     ,
00440     {"FROM", sizeof("FROM") - 1, FROM}
00441     ,
00442     {"AGENT-CAPABILITIES", sizeof("AGENT-CAPABILITIES") - 1, AGENTCAP}
00443     ,
00444     {"MACRO", sizeof("MACRO") - 1, MACRO}
00445     ,
00446     {"IMPLIED", sizeof("IMPLIED") - 1, IMPLIED}
00447     ,
00448     {"SUPPORTS", sizeof("SUPPORTS") - 1, SUPPORTS}
00449     ,
00450     {"INCLUDES", sizeof("INCLUDES") - 1, INCLUDES}
00451     ,
00452     {"VARIATION", sizeof("VARIATION") - 1, VARIATION}
00453     ,
00454     {"REVISION", sizeof("REVISION") - 1, REVISION}
00455     ,
00456     {"not-implemented", sizeof("not-implemented") - 1, NOTIMPL}
00457     ,
00458     {"OBJECTS", sizeof("OBJECTS") - 1, OBJECTS}
00459     ,
00460     {"NOTIFICATIONS", sizeof("NOTIFICATIONS") - 1, NOTIFICATIONS}
00461     ,
00462     {"MODULE", sizeof("MODULE") - 1, MODULE}
00463     ,
00464     {"MIN-ACCESS", sizeof("MIN-ACCESS") - 1, MINACCESS}
00465     ,
00466     {"PRODUCT-RELEASE", sizeof("PRODUCT-RELEASE") - 1, PRODREL}
00467     ,
00468     {"WRITE-SYNTAX", sizeof("WRITE-SYNTAX") - 1, WRSYNTAX}
00469     ,
00470     {"CREATION-REQUIRES", sizeof("CREATION-REQUIRES") - 1, CREATEREQ}
00471     ,
00472     {"MANDATORY-GROUPS", sizeof("MANDATORY-GROUPS") - 1, MANDATORYGROUPS}
00473     ,
00474     {"GROUP", sizeof("GROUP") - 1, GROUP}
00475     ,
00476     {"CHOICE", sizeof("CHOICE") - 1, CHOICE}
00477     ,
00478     {"IMPLICIT", sizeof("IMPLICIT") - 1, IMPLICIT}
00479     ,
00480     {"ObjectSyntax", sizeof("ObjectSyntax") - 1, OBJSYNTAX}
00481     ,
00482     {"SimpleSyntax", sizeof("SimpleSyntax") - 1, SIMPLESYNTAX}
00483     ,
00484     {"ApplicationSyntax", sizeof("ApplicationSyntax") - 1, APPSYNTAX}
00485     ,
00486     {"ObjectName", sizeof("ObjectName") - 1, OBJNAME}
00487     ,
00488     {"NotificationName", sizeof("NotificationName") - 1, NOTIFNAME}
00489     ,
00490     {"VARIABLES", sizeof("VARIABLES") - 1, VARIABLES}
00491     ,
00492     {NULL}
00493 };
00494 
00495 static struct module_compatability *module_map_head;
00496 static struct module_compatability module_map[] = {
00497     {"RFC1065-SMI", "RFC1155-SMI", NULL, 0},
00498     {"RFC1066-MIB", "RFC1156-MIB", NULL, 0},
00499     /*
00500      * 'mib' -> 'mib-2' 
00501      */
00502     {"RFC1156-MIB", "RFC1158-MIB", NULL, 0},
00503     /*
00504      * 'snmpEnableAuthTraps' -> 'snmpEnableAuthenTraps' 
00505      */
00506     {"RFC1158-MIB", "RFC1213-MIB", NULL, 0},
00507     /*
00508      * 'nullOID' -> 'zeroDotZero' 
00509      */
00510     {"RFC1155-SMI", "SNMPv2-SMI", NULL, 0},
00511     {"RFC1213-MIB", "SNMPv2-SMI", "mib-2", 0},
00512     {"RFC1213-MIB", "SNMPv2-MIB", "sys", 3},
00513     {"RFC1213-MIB", "IF-MIB", "if", 2},
00514     {"RFC1213-MIB", "IP-MIB", "ip", 2},
00515     {"RFC1213-MIB", "IP-MIB", "icmp", 4},
00516     {"RFC1213-MIB", "TCP-MIB", "tcp", 3},
00517     {"RFC1213-MIB", "UDP-MIB", "udp", 3},
00518     {"RFC1213-MIB", "SNMPv2-SMI", "transmission", 0},
00519     {"RFC1213-MIB", "SNMPv2-MIB", "snmp", 4},
00520     {"RFC1231-MIB", "TOKENRING-MIB", NULL, 0},
00521     {"RFC1271-MIB", "RMON-MIB", NULL, 0},
00522     {"RFC1286-MIB", "SOURCE-ROUTING-MIB", "dot1dSr", 7},
00523     {"RFC1286-MIB", "BRIDGE-MIB", NULL, 0},
00524     {"RFC1315-MIB", "FRAME-RELAY-DTE-MIB", NULL, 0},
00525     {"RFC1316-MIB", "CHARACTER-MIB", NULL, 0},
00526     {"RFC1406-MIB", "DS1-MIB", NULL, 0},
00527     {"RFC-1213", "RFC1213-MIB", NULL, 0},
00528 };
00529 
00530 #define MODULE_NOT_FOUND        0
00531 #define MODULE_LOADED_OK        1
00532 #define MODULE_ALREADY_LOADED   2
00533 /*
00534  * #define MODULE_LOAD_FAILED   3       
00535  */
00536 #define MODULE_LOAD_FAILED      MODULE_NOT_FOUND
00537 #define MODULE_SYNTAX_ERROR     4
00538 
00539 int gMibError = 0,gLoop = 0;
00540 char *gpMibErrorString = NULL;
00541 char gMibNames[STRINGMAX];
00542 
00543 #define HASHSIZE        32
00544 #define BUCKET(x)       (x & (HASHSIZE-1))
00545 
00546 #define NHASHSIZE    128
00547 #define NBUCKET(x)   (x & (NHASHSIZE-1))
00548 
00549 static struct tok *buckets[HASHSIZE];
00550 
00551 static struct node *nbuckets[NHASHSIZE];
00552 static struct tree *tbuckets[NHASHSIZE];
00553 static struct module *module_head = NULL;
00554 
00555 static struct node *orphan_nodes = NULL;
00556 NETSNMP_IMPORT struct tree *tree_head;
00557 struct tree        *tree_head = NULL;
00558 
00559 #define NUMBER_OF_ROOT_NODES    3
00560 static struct module_import root_imports[NUMBER_OF_ROOT_NODES];
00561 
00562 static int      current_module = 0;
00563 static int      max_module = 0;
00564 static int      first_err_module = 1;
00565 static char    *last_err_module = NULL; /* no repeats on "Cannot find module..." */
00566 
00567 static void     tree_from_node(struct tree *tp, struct node *np);
00568 static void     do_subtree(struct tree *, struct node **);
00569 static void     do_linkup(struct module *, struct node *);
00570 static void     dump_module_list(void);
00571 static int      get_token(FILE *, char *, int);
00572 static int      parseQuoteString(FILE *, char *, int);
00573 static int      tossObjectIdentifier(FILE *);
00574 static int      name_hash(const char *);
00575 static void     init_node_hash(struct node *);
00576 static void     print_error(const char *, const char *, int);
00577 static void     free_tree(struct tree *);
00578 static void     free_partial_tree(struct tree *, int);
00579 static void     free_node(struct node *);
00580 static void     build_translation_table(void);
00581 static void     init_tree_roots(void);
00582 static void     merge_anon_children(struct tree *, struct tree *);
00583 static void     unlink_tbucket(struct tree *);
00584 static void     unlink_tree(struct tree *);
00585 static int      getoid(FILE *, struct subid_s *, int);
00586 static struct node *parse_objectid(FILE *, char *);
00587 static int      get_tc(const char *, int, int *, struct enum_list **,
00588                        struct range_list **, char **);
00589 static int      get_tc_index(const char *, int);
00590 static struct enum_list *parse_enumlist(FILE *, struct enum_list **);
00591 static struct range_list *parse_ranges(FILE * fp, struct range_list **);
00592 static struct node *parse_asntype(FILE *, char *, int *, char *);
00593 static struct node *parse_objecttype(FILE *, char *);
00594 static struct node *parse_objectgroup(FILE *, char *, int,
00595                                       struct objgroup **);
00596 static struct node *parse_notificationDefinition(FILE *, char *);
00597 static struct node *parse_trapDefinition(FILE *, char *);
00598 static struct node *parse_compliance(FILE *, char *);
00599 static struct node *parse_capabilities(FILE *, char *);
00600 static struct node *parse_moduleIdentity(FILE *, char *);
00601 static struct node *parse_macro(FILE *, char *);
00602 static void     parse_imports(FILE *);
00603 static struct node *parse(FILE *, struct node *);
00604 
00605 static int     read_module_internal(const char *);
00606 static int     read_module_replacements(const char *);
00607 static int     read_import_replacements(const char *,
00608                                          struct module_import *);
00609 
00610 static void     new_module(const char *, const char *);
00611 
00612 static struct node *merge_parse_objectid(struct node *, FILE *, char *);
00613 static struct index_list *getIndexes(FILE * fp, struct index_list **);
00614 static struct varbind_list *getVarbinds(FILE * fp, struct varbind_list **);
00615 static void     free_indexes(struct index_list **);
00616 static void     free_varbinds(struct varbind_list **);
00617 static void     free_ranges(struct range_list **);
00618 static void     free_enums(struct enum_list **);
00619 static struct range_list *copy_ranges(struct range_list *);
00620 static struct enum_list *copy_enums(struct enum_list *);
00621 
00622 static u_int    compute_match(const char *search_base, const char *key);
00623 
00624 void
00625 snmp_mib_toggle_options_usage(const char *lead, FILE * outf)
00626 {
00627     fprintf(outf, "%su:  %sallow the use of underlines in MIB symbols\n",
00628             lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
00629                                            NETSNMP_DS_LIB_MIB_PARSE_LABEL)) ?
00630                    "dis" : ""));
00631     fprintf(outf, "%sc:  %sallow the use of \"--\" to terminate comments\n",
00632             lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
00633                                            NETSNMP_DS_LIB_MIB_COMMENT_TERM)) ?
00634                    "" : "dis"));
00635 
00636     fprintf(outf, "%sd:  %ssave the DESCRIPTIONs of the MIB objects\n",
00637             lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
00638                                            NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) ?
00639                    "do not " : ""));
00640 
00641     fprintf(outf, "%se:  disable errors when MIB symbols conflict\n", lead);
00642 
00643     fprintf(outf, "%sw:  enable warnings when MIB symbols conflict\n", lead);
00644 
00645     fprintf(outf, "%sW:  enable detailed warnings when MIB symbols conflict\n",
00646             lead);
00647 
00648     fprintf(outf, "%sR:  replace MIB symbols from latest module\n", lead);
00649 }
00650 
00651 char           *
00652 snmp_mib_toggle_options(char *options)
00653 {
00654     if (options) {
00655         while (*options) {
00656             switch (*options) {
00657             case 'u':
00658                 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_PARSE_LABEL,
00659                                !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
00660                                                NETSNMP_DS_LIB_MIB_PARSE_LABEL));
00661                 break;
00662 
00663             case 'c':
00664                 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
00665                                           NETSNMP_DS_LIB_MIB_COMMENT_TERM);
00666                 break;
00667 
00668             case 'e':
00669                 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
00670                                           NETSNMP_DS_LIB_MIB_ERRORS);
00671                 break;
00672 
00673             case 'w':
00674                 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
00675                                    NETSNMP_DS_LIB_MIB_WARNINGS, 1);
00676                 break;
00677 
00678             case 'W':
00679                 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
00680                                    NETSNMP_DS_LIB_MIB_WARNINGS, 2);
00681                 break;
00682 
00683             case 'd':
00684                 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, 
00685                                           NETSNMP_DS_LIB_SAVE_MIB_DESCRS);
00686                 break;
00687 
00688             case 'R':
00689                 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, 
00690                                           NETSNMP_DS_LIB_MIB_REPLACE);
00691                 break;
00692 
00693             default:
00694                 /*
00695                  * return at the unknown option 
00696                  */
00697                 return options;
00698             }
00699             options++;
00700         }
00701     }
00702     return NULL;
00703 }
00704 
00705 static int
00706 name_hash(const char *name)
00707 {
00708     int             hash = 0;
00709     const char     *cp;
00710 
00711     if (!name)
00712         return 0;
00713     for (cp = name; *cp; cp++)
00714         hash += tolower((unsigned char)(*cp));
00715     return (hash);
00716 }
00717 
00718 void
00719 netsnmp_init_mib_internals(void)
00720 {
00721     register struct tok *tp;
00722     register int    b, i;
00723     int             max_modc;
00724 
00725     if (tree_head)
00726         return;
00727 
00728     /*
00729      * Set up hash list of pre-defined tokens
00730      */
00731     memset(buckets, 0, sizeof(buckets));
00732     for (tp = tokens; tp->name; tp++) {
00733         tp->hash = name_hash(tp->name);
00734         b = BUCKET(tp->hash);
00735         if (buckets[b])
00736             tp->next = buckets[b];      /* BUG ??? */
00737         buckets[b] = tp;
00738     }
00739 
00740     /*
00741      * Initialise other internal structures
00742      */
00743 
00744     max_modc = sizeof(module_map) / sizeof(module_map[0]) - 1;
00745     for (i = 0; i < max_modc; ++i)
00746         module_map[i].next = &(module_map[i + 1]);
00747     module_map[max_modc].next = NULL;
00748     module_map_head = module_map;
00749 
00750     memset(nbuckets, 0, sizeof(nbuckets));
00751     memset(tbuckets, 0, sizeof(tbuckets));
00752     memset(tclist, 0, MAXTC * sizeof(struct tc));
00753     build_translation_table();
00754     init_tree_roots();          /* Set up initial roots */
00755     /*
00756      * Relies on 'add_mibdir' having set up the modules 
00757      */
00758 }
00759 
00760 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS
00761 void
00762 init_mib_internals(void)
00763 {
00764     netsnmp_init_mib_internals();
00765 }
00766 #endif
00767 
00768 static void
00769 init_node_hash(struct node *nodes)
00770 {
00771     struct node    *np, *nextp;
00772     int             hash;
00773 
00774     memset(nbuckets, 0, sizeof(nbuckets));
00775     for (np = nodes; np;) {
00776         nextp = np->next;
00777         hash = NBUCKET(name_hash(np->parent));
00778         np->next = nbuckets[hash];
00779         nbuckets[hash] = np;
00780         np = nextp;
00781     }
00782 }
00783 
00784 static int      erroneousMibs = 0;
00785 
00786 netsnmp_feature_child_of(parse_get_error_count, netsnmp_unused)
00787 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_GET_ERROR_COUNT
00788 int
00789 get_mib_parse_error_count(void)
00790 {
00791     return erroneousMibs;
00792 }
00793 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_GET_ERROR_COUNT */
00794 
00795 
00796 static void
00797 print_error(const char *str, const char *token, int type)
00798 {
00799     erroneousMibs++;
00800     DEBUGMSGTL(("parse-mibs", "\n"));
00801     if (type == ENDOFFILE)
00802         snmp_log(LOG_ERR, "%s (EOF): At line %d in %s\n", str, mibLine,
00803                  File);
00804     else if (token && *token)
00805         snmp_log(LOG_ERR, "%s (%s): At line %d in %s\n", str, token,
00806                  mibLine, File);
00807     else
00808         snmp_log(LOG_ERR, "%s: At line %d in %s\n", str, mibLine, File);
00809 }
00810 
00811 static void
00812 print_module_not_found(const char *cp)
00813 {
00814     if (first_err_module) {
00815         snmp_log(LOG_ERR, "MIB search path: %s\n",
00816                            netsnmp_get_mib_directory());
00817         first_err_module = 0;
00818     }
00819     if (!last_err_module || strcmp(cp, last_err_module))
00820         print_error("Cannot find module", cp, CONTINUE);
00821     if (last_err_module)
00822         free(last_err_module);
00823     last_err_module = strdup(cp);
00824 }
00825 
00826 static struct node *
00827 alloc_node(int modid)
00828 {
00829     struct node    *np;
00830     np = (struct node *) calloc(1, sizeof(struct node));
00831     if (np) {
00832         np->tc_index = -1;
00833         np->modid = modid;
00834         np->filename = strdup(File);
00835         np->lineno = mibLine;
00836     }
00837     return np;
00838 }
00839 
00840 static void
00841 unlink_tbucket(struct tree *tp)
00842 {
00843     int             hash = NBUCKET(name_hash(tp->label));
00844     struct tree    *otp = NULL, *ntp = tbuckets[hash];
00845 
00846     while (ntp && ntp != tp) {
00847         otp = ntp;
00848         ntp = ntp->next;
00849     }
00850     if (!ntp)
00851         snmp_log(LOG_EMERG, "Can't find %s in tbuckets\n", tp->label);
00852     else if (otp)
00853         otp->next = ntp->next;
00854     else
00855         tbuckets[hash] = tp->next;
00856 }
00857 
00858 static void
00859 unlink_tree(struct tree *tp)
00860 {
00861     struct tree    *otp = NULL, *ntp = tp->parent;
00862 
00863     if (!ntp) {                 /* this tree has no parent */
00864         DEBUGMSGTL(("unlink_tree", "Tree node %s has no parent\n",
00865                     tp->label));
00866     } else {
00867         ntp = ntp->child_list;
00868 
00869         while (ntp && ntp != tp) {
00870             otp = ntp;
00871             ntp = ntp->next_peer;
00872         }
00873         if (!ntp)
00874             snmp_log(LOG_EMERG, "Can't find %s in %s's children\n",
00875                      tp->label, tp->parent->label);
00876         else if (otp)
00877             otp->next_peer = ntp->next_peer;
00878         else
00879             tp->parent->child_list = tp->next_peer;
00880     }
00881 
00882     if (tree_head == tp)
00883         tree_head = tp->next_peer;
00884 }
00885 
00886 static void
00887 free_partial_tree(struct tree *tp, int keep_label)
00888 {
00889     if (!tp)
00890         return;
00891 
00892     /*
00893      * remove the data from this tree node 
00894      */
00895     free_enums(&tp->enums);
00896     free_ranges(&tp->ranges);
00897     free_indexes(&tp->indexes);
00898     free_varbinds(&tp->varbinds);
00899     if (!keep_label)
00900         SNMP_FREE(tp->label);
00901     SNMP_FREE(tp->hint);
00902     SNMP_FREE(tp->units);
00903     SNMP_FREE(tp->description);
00904     SNMP_FREE(tp->reference);
00905     SNMP_FREE(tp->augments);
00906     SNMP_FREE(tp->defaultValue);
00907 }
00908 
00909 /*
00910  * free a tree node. Note: the node must already have been unlinked
00911  * from the tree when calling this routine
00912  */
00913 static void
00914 free_tree(struct tree *Tree)
00915 {
00916     if (!Tree)
00917         return;
00918 
00919     unlink_tbucket(Tree);
00920     free_partial_tree(Tree, FALSE);
00921     if (Tree->number_modules > 1)
00922         free((char *) Tree->module_list);
00923     free((char *) Tree);
00924 }
00925 
00926 static void
00927 free_node(struct node *np)
00928 {
00929     if (!np)
00930         return;
00931 
00932     free_enums(&np->enums);
00933     free_ranges(&np->ranges);
00934     free_indexes(&np->indexes);
00935     free_varbinds(&np->varbinds);
00936     if (np->label)
00937         free(np->label);
00938     if (np->hint)
00939         free(np->hint);
00940     if (np->units)
00941         free(np->units);
00942     if (np->description)
00943         free(np->description);
00944     if (np->reference)
00945         free(np->reference);
00946     if (np->defaultValue)
00947         free(np->defaultValue);
00948     if (np->parent)
00949         free(np->parent);
00950     if (np->augments)
00951         free(np->augments);
00952     if (np->filename)
00953         free(np->filename);
00954     free((char *) np);
00955 }
00956 
00957 static void
00958 print_range_value(FILE * fp, int type, struct range_list * rp)
00959 {
00960     switch (type) {
00961     case TYPE_INTEGER:
00962     case TYPE_INTEGER32:
00963         if (rp->low == rp->high)
00964             fprintf(fp, "%d", rp->low);
00965         else
00966             fprintf(fp, "%d..%d", rp->low, rp->high);
00967         break;
00968     case TYPE_UNSIGNED32:
00969     case TYPE_OCTETSTR:
00970     case TYPE_GAUGE:
00971     case TYPE_UINTEGER:
00972         if (rp->low == rp->high)
00973             fprintf(fp, "%u", (unsigned)rp->low);
00974         else
00975             fprintf(fp, "%u..%u", (unsigned)rp->low, (unsigned)rp->high);
00976         break;
00977     default:
00978         /* No other range types allowed */
00979         break;
00980     }
00981 }
00982 
00983 #ifdef TEST
00984 static void
00985 print_nodes(FILE * fp, struct node *root)
00986 {
00987     struct enum_list *ep;
00988     struct index_list *ip;
00989     struct varbind_list *vp;
00990     struct node    *np;
00991 
00992     for (np = root; np; np = np->next) {
00993         fprintf(fp, "%s ::= { %s %ld } (%d)\n", np->label, np->parent,
00994                 np->subid, np->type);
00995         if (np->tc_index >= 0)
00996             fprintf(fp, "  TC = %s\n", tclist[np->tc_index].descriptor);
00997         if (np->enums) {
00998             fprintf(fp, "  Enums: \n");
00999             for (ep = np->enums; ep; ep = ep->next) {
01000                 fprintf(fp, "    %s(%d)\n", ep->label, ep->value);
01001             }
01002         }
01003         if (np->ranges) {
01004             struct range_list *rp;
01005             fprintf(fp, "  Ranges: ");
01006             for (rp = np->ranges; rp; rp = rp->next) {
01007                 fprintf(fp, "\n    ");
01008                 print_range_value(fp, np->type, rp);
01009             }
01010             fprintf(fp, "\n");
01011         }
01012         if (np->indexes) {
01013             fprintf(fp, "  Indexes: \n");
01014             for (ip = np->indexes; ip; ip = ip->next) {
01015                 fprintf(fp, "    %s\n", ip->ilabel);
01016             }
01017         }
01018         if (np->augments)
01019             fprintf(fp, "  Augments: %s\n", np->augments);
01020         if (np->varbinds) {
01021             fprintf(fp, "  Varbinds: \n");
01022             for (vp = np->varbinds; vp; vp = vp->next) {
01023                 fprintf(fp, "    %s\n", vp->vblabel);
01024             }
01025         }
01026         if (np->hint)
01027             fprintf(fp, "  Hint: %s\n", np->hint);
01028         if (np->units)
01029             fprintf(fp, "  Units: %s\n", np->units);
01030         if (np->defaultValue)
01031             fprintf(fp, "  DefaultValue: %s\n", np->defaultValue);
01032     }
01033 }
01034 #endif
01035 
01036 void
01037 print_subtree(FILE * f, struct tree *tree, int count)
01038 {
01039     struct tree    *tp;
01040     int             i;
01041     char            modbuf[256];
01042 
01043     for (i = 0; i < count; i++)
01044         fprintf(f, "  ");
01045     fprintf(f, "Children of %s(%ld):\n", tree->label, tree->subid);
01046     count++;
01047     for (tp = tree->child_list; tp; tp = tp->next_peer) {
01048         for (i = 0; i < count; i++)
01049             fprintf(f, "  ");
01050         fprintf(f, "%s:%s(%ld) type=%d",
01051                 module_name(tp->module_list[0], modbuf),
01052                 tp->label, tp->subid, tp->type);
01053         if (tp->tc_index != -1)
01054             fprintf(f, " tc=%d", tp->tc_index);
01055         if (tp->hint)
01056             fprintf(f, " hint=%s", tp->hint);
01057         if (tp->units)
01058             fprintf(f, " units=%s", tp->units);
01059         if (tp->number_modules > 1) {
01060             fprintf(f, " modules:");
01061             for (i = 1; i < tp->number_modules; i++)
01062                 fprintf(f, " %s", module_name(tp->module_list[i], modbuf));
01063         }
01064         fprintf(f, "\n");
01065     }
01066     for (tp = tree->child_list; tp; tp = tp->next_peer) {
01067         if (tp->child_list)
01068             print_subtree(f, tp, count);
01069     }
01070 }
01071 
01072 void
01073 print_ascii_dump_tree(FILE * f, struct tree *tree, int count)
01074 {
01075     struct tree    *tp;
01076 
01077     count++;
01078     for (tp = tree->child_list; tp; tp = tp->next_peer) {
01079         fprintf(f, "%s OBJECT IDENTIFIER ::= { %s %ld }\n", tp->label,
01080                 tree->label, tp->subid);
01081     }
01082     for (tp = tree->child_list; tp; tp = tp->next_peer) {
01083         if (tp->child_list)
01084             print_ascii_dump_tree(f, tp, count);
01085     }
01086 }
01087 
01088 static int      translation_table[256];
01089 
01090 static void
01091 build_translation_table(void)
01092 {
01093     int             count;
01094 
01095     for (count = 0; count < 256; count++) {
01096         switch (count) {
01097         case OBJID:
01098             translation_table[count] = TYPE_OBJID;
01099             break;
01100         case OCTETSTR:
01101             translation_table[count] = TYPE_OCTETSTR;
01102             break;
01103         case INTEGER:
01104             translation_table[count] = TYPE_INTEGER;
01105             break;
01106         case NETADDR:
01107             translation_table[count] = TYPE_NETADDR;
01108             break;
01109         case IPADDR:
01110             translation_table[count] = TYPE_IPADDR;
01111             break;
01112         case COUNTER:
01113             translation_table[count] = TYPE_COUNTER;
01114             break;
01115         case GAUGE:
01116             translation_table[count] = TYPE_GAUGE;
01117             break;
01118         case TIMETICKS:
01119             translation_table[count] = TYPE_TIMETICKS;
01120             break;
01121         case KW_OPAQUE:
01122             translation_table[count] = TYPE_OPAQUE;
01123             break;
01124         case NUL:
01125             translation_table[count] = TYPE_NULL;
01126             break;
01127         case COUNTER64:
01128             translation_table[count] = TYPE_COUNTER64;
01129             break;
01130         case BITSTRING:
01131             translation_table[count] = TYPE_BITSTRING;
01132             break;
01133         case NSAPADDRESS:
01134             translation_table[count] = TYPE_NSAPADDRESS;
01135             break;
01136         case INTEGER32:
01137             translation_table[count] = TYPE_INTEGER32;
01138             break;
01139         case UINTEGER32:
01140             translation_table[count] = TYPE_UINTEGER;
01141             break;
01142         case UNSIGNED32:
01143             translation_table[count] = TYPE_UNSIGNED32;
01144             break;
01145         case TRAPTYPE:
01146             translation_table[count] = TYPE_TRAPTYPE;
01147             break;
01148         case NOTIFTYPE:
01149             translation_table[count] = TYPE_NOTIFTYPE;
01150             break;
01151         case NOTIFGROUP:
01152             translation_table[count] = TYPE_NOTIFGROUP;
01153             break;
01154         case OBJGROUP:
01155             translation_table[count] = TYPE_OBJGROUP;
01156             break;
01157         case MODULEIDENTITY:
01158             translation_table[count] = TYPE_MODID;
01159             break;
01160         case OBJIDENTITY:
01161             translation_table[count] = TYPE_OBJIDENTITY;
01162             break;
01163         case AGENTCAP:
01164             translation_table[count] = TYPE_AGENTCAP;
01165             break;
01166         case COMPLIANCE:
01167             translation_table[count] = TYPE_MODCOMP;
01168             break;
01169         default:
01170             translation_table[count] = TYPE_OTHER;
01171             break;
01172         }
01173     }
01174 }
01175 
01176 static void
01177 init_tree_roots(void)
01178 {
01179     struct tree    *tp, *lasttp;
01180     int             base_modid;
01181     int             hash;
01182 
01183     base_modid = which_module("SNMPv2-SMI");
01184     if (base_modid == -1)
01185         base_modid = which_module("RFC1155-SMI");
01186     if (base_modid == -1)
01187         base_modid = which_module("RFC1213-MIB");
01188 
01189     /*
01190      * build root node 
01191      */
01192     tp = (struct tree *) calloc(1, sizeof(struct tree));
01193     if (tp == NULL)
01194         return;
01195     tp->label = strdup("joint-iso-ccitt");
01196     tp->modid = base_modid;
01197     tp->number_modules = 1;
01198     tp->module_list = &(tp->modid);
01199     tp->subid = 2;
01200     tp->tc_index = -1;
01201     set_function(tp);           /* from mib.c */
01202     hash = NBUCKET(name_hash(tp->label));
01203     tp->next = tbuckets[hash];
01204     tbuckets[hash] = tp;
01205     lasttp = tp;
01206     root_imports[0].label = strdup(tp->label);
01207     root_imports[0].modid = base_modid;
01208 
01209     /*
01210      * build root node 
01211      */
01212     tp = (struct tree *) calloc(1, sizeof(struct tree));
01213     if (tp == NULL)
01214         return;
01215     tp->next_peer = lasttp;
01216     tp->label = strdup("ccitt");
01217     tp->modid = base_modid;
01218     tp->number_modules = 1;
01219     tp->module_list = &(tp->modid);
01220     tp->subid = 0;
01221     tp->tc_index = -1;
01222     set_function(tp);           /* from mib.c */
01223     hash = NBUCKET(name_hash(tp->label));
01224     tp->next = tbuckets[hash];
01225     tbuckets[hash] = tp;
01226     lasttp = tp;
01227     root_imports[1].label = strdup(tp->label);
01228     root_imports[1].modid = base_modid;
01229 
01230     /*
01231      * build root node 
01232      */
01233     tp = (struct tree *) calloc(1, sizeof(struct tree));
01234     if (tp == NULL)
01235         return;
01236     tp->next_peer = lasttp;
01237     tp->label = strdup("iso");
01238     tp->modid = base_modid;
01239     tp->number_modules = 1;
01240     tp->module_list = &(tp->modid);
01241     tp->subid = 1;
01242     tp->tc_index = -1;
01243     set_function(tp);           /* from mib.c */
01244     hash = NBUCKET(name_hash(tp->label));
01245     tp->next = tbuckets[hash];
01246     tbuckets[hash] = tp;
01247     lasttp = tp;
01248     root_imports[2].label = strdup(tp->label);
01249     root_imports[2].modid = base_modid;
01250 
01251     tree_head = tp;
01252 }
01253 
01254 #ifdef STRICT_MIB_PARSEING
01255 #define label_compare   strcasecmp
01256 #else
01257 #define label_compare   strcmp
01258 #endif
01259 
01260 
01261 struct tree    *
01262 find_tree_node(const char *name, int modid)
01263 {
01264     struct tree    *tp, *headtp;
01265     int             count, *int_p;
01266 
01267     if (!name || !*name)
01268         return (NULL);
01269 
01270     headtp = tbuckets[NBUCKET(name_hash(name))];
01271     for (tp = headtp; tp; tp = tp->next) {
01272         if (tp->label && !label_compare(tp->label, name)) {
01273 
01274             if (modid == -1)    /* Any module */
01275                 return (tp);
01276 
01277             for (int_p = tp->module_list, count = 0;
01278                  count < tp->number_modules; ++count, ++int_p)
01279                 if (*int_p == modid)
01280                     return (tp);
01281         }
01282     }
01283 
01284     return (NULL);
01285 }
01286 
01287 /*
01288  * computes a value which represents how close name1 is to name2.
01289  * * high scores mean a worse match.
01290  * * (yes, the algorithm sucks!)
01291  */
01292 #define MAX_BAD 0xffffff
01293 
01294 static          u_int
01295 compute_match(const char *search_base, const char *key)
01296 {
01297 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
01298     int             rc;
01299     regex_t         parsetree;
01300     regmatch_t      pmatch;
01301     rc = regcomp(&parsetree, key, REG_ICASE | REG_EXTENDED);
01302     if (rc == 0)
01303         rc = regexec(&parsetree, search_base, 1, &pmatch, 0);
01304     regfree(&parsetree);
01305     if (rc == 0) {
01306         /*
01307          * found 
01308          */
01309         return pmatch.rm_so;
01310     }
01311 #else                           /* use our own wildcard matcher */
01312     /*
01313      * first find the longest matching substring (ick) 
01314      */
01315     char           *first = NULL, *result = NULL, *entry;
01316     const char     *position;
01317     char           *newkey = strdup(key);
01318     char           *st;
01319 
01320 
01321     entry = strtok_r(newkey, "*", &st);
01322     position = search_base;
01323     while (entry) {
01324         result = strcasestr(position, entry);
01325 
01326         if (result == NULL) {
01327             free(newkey);
01328             return MAX_BAD;
01329         }
01330 
01331         if (first == NULL)
01332             first = result;
01333 
01334         position = result + strlen(entry);
01335         entry = strtok_r(NULL, "*", &st);
01336     }
01337     free(newkey);
01338     if (result)
01339         return (first - search_base);
01340 #endif
01341 
01342     /*
01343      * not found 
01344      */
01345     return MAX_BAD;
01346 }
01347 
01348 /*
01349  * Find the tree node that best matches the pattern string.
01350  * Use the "reported" flag such that only one match
01351  * is attempted for every node.
01352  *
01353  * Warning! This function may recurse.
01354  *
01355  * Caller _must_ invoke clear_tree_flags before first call
01356  * to this function.  This function may be called multiple times
01357  * to ensure that the entire tree is traversed.
01358  */
01359 
01360 struct tree    *
01361 find_best_tree_node(const char *pattrn, struct tree *tree_top,
01362                     u_int * match)
01363 {
01364     struct tree    *tp, *best_so_far = NULL, *retptr;
01365     u_int           old_match = MAX_BAD, new_match = MAX_BAD;
01366 
01367     if (!pattrn || !*pattrn)
01368         return (NULL);
01369 
01370     if (!tree_top)
01371         tree_top = get_tree_head();
01372 
01373     for (tp = tree_top; tp; tp = tp->next_peer) {
01374         if (!tp->reported && tp->label)
01375             new_match = compute_match(tp->label, pattrn);
01376         tp->reported = 1;
01377 
01378         if (new_match < old_match) {
01379             best_so_far = tp;
01380             old_match = new_match;
01381         }
01382         if (new_match == 0)
01383             break;              /* this is the best result we can get */
01384         if (tp->child_list) {
01385             retptr =
01386                 find_best_tree_node(pattrn, tp->child_list, &new_match);
01387             if (new_match < old_match) {
01388                 best_so_far = retptr;
01389                 old_match = new_match;
01390             }
01391             if (new_match == 0)
01392                 break;          /* this is the best result we can get */
01393         }
01394     }
01395     if (match)
01396         *match = old_match;
01397     return (best_so_far);
01398 }
01399 
01400 
01401 static void
01402 merge_anon_children(struct tree *tp1, struct tree *tp2)
01403                 /*
01404                  * NB: tp1 is the 'anonymous' node 
01405                  */
01406 {
01407     struct tree    *child1, *child2, *previous;
01408 
01409     for (child1 = tp1->child_list; child1;) {
01410 
01411         for (child2 = tp2->child_list, previous = NULL;
01412              child2; previous = child2, child2 = child2->next_peer) {
01413 
01414             if (child1->subid == child2->subid) {
01415                 /*
01416                  * Found 'matching' children,
01417                  *  so merge them
01418                  */
01419                 if (!strncmp(child1->label, ANON, ANON_LEN)) {
01420                     merge_anon_children(child1, child2);
01421 
01422                     child1->child_list = NULL;
01423                     previous = child1;  /* Finished with 'child1' */
01424                     child1 = child1->next_peer;
01425                     free_tree(previous);
01426                     goto next;
01427                 }
01428 
01429                 else if (!strncmp(child2->label, ANON, ANON_LEN)) {
01430                     merge_anon_children(child2, child1);
01431 
01432                     if (previous)
01433                         previous->next_peer = child2->next_peer;
01434                     else
01435                         tp2->child_list = child2->next_peer;
01436                     free_tree(child2);
01437 
01438                     previous = child1;  /* Move 'child1' to 'tp2' */
01439                     child1 = child1->next_peer;
01440                     previous->next_peer = tp2->child_list;
01441                     tp2->child_list = previous;
01442                     for (previous = tp2->child_list;
01443                          previous; previous = previous->next_peer)
01444                         previous->parent = tp2;
01445                     goto next;
01446                 } else if (!label_compare(child1->label, child2->label)) {
01447                     if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
01448                                            NETSNMP_DS_LIB_MIB_WARNINGS)) {
01449                         snmp_log(LOG_WARNING,
01450                                  "Warning: %s.%ld is both %s and %s (%s)\n",
01451                                  tp2->label, child1->subid, child1->label,
01452                                  child2->label, File);
01453                     }
01454                     continue;
01455                 } else {
01456                     /*
01457                      * Two copies of the same node.
01458                      * 'child2' adopts the children of 'child1'
01459                      */
01460 
01461                     if (child2->child_list) {
01462                         for (previous = child2->child_list; previous->next_peer; previous = previous->next_peer);       /* Find the end of the list */
01463                         previous->next_peer = child1->child_list;
01464                     } else
01465                         child2->child_list = child1->child_list;
01466                     for (previous = child1->child_list;
01467                          previous; previous = previous->next_peer)
01468                         previous->parent = child2;
01469                     child1->child_list = NULL;
01470 
01471                     previous = child1;  /* Finished with 'child1' */
01472                     child1 = child1->next_peer;
01473                     free_tree(previous);
01474                     goto next;
01475                 }
01476             }
01477         }
01478         /*
01479          * If no match, move 'child1' to 'tp2' child_list
01480          */
01481         if (child1) {
01482             previous = child1;
01483             child1 = child1->next_peer;
01484             previous->parent = tp2;
01485             previous->next_peer = tp2->child_list;
01486             tp2->child_list = previous;
01487         }
01488       next:;
01489     }
01490 }
01491 
01492 
01493 /*
01494  * Find all the children of root in the list of nodes.  Link them into the
01495  * tree and out of the nodes list.
01496  */
01497 static void
01498 do_subtree(struct tree *root, struct node **nodes)
01499 {
01500     struct tree    *tp, *anon_tp = NULL;
01501     struct tree    *xroot = root;
01502     struct node    *np, **headp;
01503     struct node    *oldnp = NULL, *child_list = NULL, *childp = NULL;
01504     int             hash;
01505     int            *int_p;
01506 
01507     while (xroot->next_peer && xroot->next_peer->subid == root->subid) {
01508 #if 0
01509         printf("xroot: %s.%s => %s\n", xroot->parent->label, xroot->label,
01510                xroot->next_peer->label);
01511 #endif
01512         xroot = xroot->next_peer;
01513     }
01514 
01515     tp = root;
01516     headp = &nbuckets[NBUCKET(name_hash(tp->label))];
01517     /*
01518      * Search each of the nodes for one whose parent is root, and
01519      * move each into a separate list.
01520      */
01521     for (np = *headp; np; np = np->next) {
01522         if (!label_compare(tp->label, np->parent)) {
01523             /*
01524              * take this node out of the node list 
01525              */
01526             if (oldnp == NULL) {
01527                 *headp = np->next;      /* fix root of node list */
01528             } else {
01529                 oldnp->next = np->next; /* link around this node */
01530             }
01531             if (child_list)
01532                 childp->next = np;
01533             else
01534                 child_list = np;
01535             childp = np;
01536         } else {
01537             oldnp = np;
01538         }
01539 
01540     }
01541     if (childp)
01542         childp->next = NULL;
01543     /*
01544      * Take each element in the child list and place it into the tree.
01545      */
01546     for (np = child_list; np; np = np->next) {
01547         struct tree    *otp = NULL;
01548         struct tree    *xxroot = xroot;
01549         anon_tp = NULL;
01550         tp = xroot->child_list;
01551 
01552         if (np->subid == -1) {
01553             /*
01554              * name ::= { parent } 
01555              */
01556             np->subid = xroot->subid;
01557             tp = xroot;
01558             xxroot = xroot->parent;
01559         }
01560 
01561         while (tp) {
01562             if (tp->subid == np->subid)
01563                 break;
01564             else {
01565                 otp = tp;
01566                 tp = tp->next_peer;
01567             }
01568         }
01569         if (tp) {
01570             if (!label_compare(tp->label, np->label)) {
01571                 /*
01572                  * Update list of modules 
01573                  */
01574                 int_p =
01575                     (int *) malloc((tp->number_modules + 1) * sizeof(int));
01576                 if (int_p == NULL)
01577                     return;
01578                 memcpy(int_p, tp->module_list,
01579                        tp->number_modules * sizeof(int));
01580                 int_p[tp->number_modules] = np->modid;
01581                 if (tp->number_modules > 1)
01582                     free((char *) tp->module_list);
01583                 ++tp->number_modules;
01584                 tp->module_list = int_p;
01585 
01586                 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
01587                                            NETSNMP_DS_LIB_MIB_REPLACE)) {
01588                     /*
01589                      * Replace from node 
01590                      */
01591                     tree_from_node(tp, np);
01592                 }
01593                 /*
01594                  * Handle children 
01595                  */
01596                 do_subtree(tp, nodes);
01597                 continue;
01598             }
01599             if (!strncmp(np->label, ANON, ANON_LEN) ||
01600                 !strncmp(tp->label, ANON, ANON_LEN)) {
01601                 anon_tp = tp;   /* Need to merge these two trees later */
01602             } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
01603                                           NETSNMP_DS_LIB_MIB_WARNINGS)) {
01604                 snmp_log(LOG_WARNING,
01605                          "Warning: %s.%ld is both %s and %s (%s)\n",
01606                          root->label, np->subid, tp->label, np->label,
01607                          File);
01608             }
01609         }
01610 
01611         tp = (struct tree *) calloc(1, sizeof(struct tree));
01612         if (tp == NULL)
01613             return;
01614         tp->parent = xxroot;
01615         tp->modid = np->modid;
01616         tp->number_modules = 1;
01617         tp->module_list = &(tp->modid);
01618         tree_from_node(tp, np);
01619         tp->next_peer = otp ? otp->next_peer : xxroot->child_list;
01620         if (otp)
01621             otp->next_peer = tp;
01622         else
01623             xxroot->child_list = tp;
01624         hash = NBUCKET(name_hash(tp->label));
01625         tp->next = tbuckets[hash];
01626         tbuckets[hash] = tp;
01627         do_subtree(tp, nodes);
01628 
01629         if (anon_tp) {
01630             if (!strncmp(tp->label, ANON, ANON_LEN)) {
01631                 /*
01632                  * The new node is anonymous,
01633                  *  so merge it with the existing one.
01634                  */
01635                 merge_anon_children(tp, anon_tp);
01636 
01637                 /*
01638                  * unlink and destroy tp 
01639                  */
01640                 unlink_tree(tp);
01641                 free_tree(tp);
01642             } else if (!strncmp(anon_tp->label, ANON, ANON_LEN)) {
01643                 struct tree    *ntp;
01644                 /*
01645                  * The old node was anonymous,
01646                  *  so merge it with the existing one,
01647                  *  and fill in the full information.
01648                  */
01649                 merge_anon_children(anon_tp, tp);
01650 
01651                 /*
01652                  * unlink anon_tp from the hash 
01653                  */
01654                 unlink_tbucket(anon_tp);
01655 
01656                 /*
01657                  * get rid of old contents of anon_tp 
01658                  */
01659                 free_partial_tree(anon_tp, FALSE);
01660 
01661                 /*
01662                  * put in the current information 
01663                  */
01664                 anon_tp->label = tp->label;
01665                 anon_tp->child_list = tp->child_list;
01666                 anon_tp->modid = tp->modid;
01667                 anon_tp->tc_index = tp->tc_index;
01668                 anon_tp->type = tp->type;
01669                 anon_tp->enums = tp->enums;
01670                 anon_tp->indexes = tp->indexes;
01671                 anon_tp->augments = tp->augments;
01672                 anon_tp->varbinds = tp->varbinds;
01673                 anon_tp->ranges = tp->ranges;
01674                 anon_tp->hint = tp->hint;
01675                 anon_tp->units = tp->units;
01676                 anon_tp->description = tp->description;
01677                 anon_tp->reference = tp->reference;
01678                 anon_tp->defaultValue = tp->defaultValue;
01679                 anon_tp->parent = tp->parent;
01680 
01681                 set_function(anon_tp);
01682 
01683                 /*
01684                  * update parent pointer in moved children 
01685                  */
01686                 ntp = anon_tp->child_list;
01687                 while (ntp) {
01688                     ntp->parent = anon_tp;
01689                     ntp = ntp->next_peer;
01690                 }
01691 
01692                 /*
01693                  * hash in anon_tp in its new place 
01694                  */
01695                 hash = NBUCKET(name_hash(anon_tp->label));
01696                 anon_tp->next = tbuckets[hash];
01697                 tbuckets[hash] = anon_tp;
01698 
01699                 /*
01700                  * unlink and destroy tp 
01701                  */
01702                 unlink_tbucket(tp);
01703                 unlink_tree(tp);
01704                 free(tp);
01705             } else {
01706                 /*
01707                  * Uh?  One of these two should have been anonymous! 
01708                  */
01709                 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
01710                                        NETSNMP_DS_LIB_MIB_WARNINGS)) {
01711                     snmp_log(LOG_WARNING,
01712                              "Warning: expected anonymous node (either %s or %s) in %s\n",
01713                              tp->label, anon_tp->label, File);
01714                 }
01715             }
01716             anon_tp = NULL;
01717         }
01718     }
01719     /*
01720      * free all nodes that were copied into tree 
01721      */
01722     oldnp = NULL;
01723     for (np = child_list; np; np = np->next) {
01724         if (oldnp)
01725             free_node(oldnp);
01726         oldnp = np;
01727     }
01728     if (oldnp)
01729         free_node(oldnp);
01730 }
01731 
01732 static void
01733 do_linkup(struct module *mp, struct node *np)
01734 {
01735     struct module_import *mip;
01736     struct node    *onp, *oldp, *newp;
01737     struct tree    *tp;
01738     int             i, more;
01739     /*
01740      * All modules implicitly import
01741      *   the roots of the tree
01742      */
01743     if (snmp_get_do_debugging() > 1)
01744         dump_module_list();
01745     DEBUGMSGTL(("parse-mibs", "Processing IMPORTS for module %d %s\n",
01746                 mp->modid, mp->name));
01747     if (mp->no_imports == 0) {
01748         mp->no_imports = NUMBER_OF_ROOT_NODES;
01749         mp->imports = root_imports;
01750     }
01751 
01752     /*
01753      * Build the tree
01754      */
01755     init_node_hash(np);
01756     for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) {
01757         char            modbuf[256];
01758         DEBUGMSGTL(("parse-mibs", "  Processing import: %s\n",
01759                     mip->label));
01760         if (get_tc_index(mip->label, mip->modid) != -1)
01761             continue;
01762         tp = find_tree_node(mip->label, mip->modid);
01763         if (!tp) {
01764                 snmp_log(LOG_WARNING,
01765                          "Did not find '%s' in module %s (%s)\n",
01766                          mip->label, module_name(mip->modid, modbuf),
01767                          File);
01768             continue;
01769         }
01770         do_subtree(tp, &np);
01771     }
01772 
01773     /*
01774      * If any nodes left over,
01775      *   check that they're not the result of a "fully qualified"
01776      *   name, and then add them to the list of orphans
01777      */
01778 
01779     if (!np)
01780         return;
01781     for (tp = tree_head; tp; tp = tp->next_peer)
01782         do_subtree(tp, &np);
01783     if (!np)
01784         return;
01785 
01786     /*
01787      * quietly move all internal references to the orphan list 
01788      */
01789     oldp = orphan_nodes;
01790     do {
01791         for (i = 0; i < NHASHSIZE; i++)
01792             for (onp = nbuckets[i]; onp; onp = onp->next) {
01793                 struct node    *op = NULL;
01794                 int             hash = NBUCKET(name_hash(onp->label));
01795                 np = nbuckets[hash];
01796                 while (np) {
01797                     if (label_compare(onp->label, np->parent)) {
01798                         op = np;
01799                         np = np->next;
01800                     } else {
01801                         if (op)
01802                             op->next = np->next;
01803                         else
01804                             nbuckets[hash] = np->next;
01805                         np->next = orphan_nodes;
01806                         orphan_nodes = np;
01807                         op = NULL;
01808                         np = nbuckets[hash];
01809                     }
01810                 }
01811             }
01812         newp = orphan_nodes;
01813         more = 0;
01814         for (onp = orphan_nodes; onp != oldp; onp = onp->next) {
01815             struct node    *op = NULL;
01816             int             hash = NBUCKET(name_hash(onp->label));
01817             np = nbuckets[hash];
01818             while (np) {
01819                 if (label_compare(onp->label, np->parent)) {
01820                     op = np;
01821                     np = np->next;
01822                 } else {
01823                     if (op)
01824                         op->next = np->next;
01825                     else
01826                         nbuckets[hash] = np->next;
01827                     np->next = orphan_nodes;
01828                     orphan_nodes = np;
01829                     op = NULL;
01830                     np = nbuckets[hash];
01831                     more = 1;
01832                 }
01833             }
01834         }
01835         oldp = newp;
01836     } while (more);
01837 
01838     /*
01839      * complain about left over nodes 
01840      */
01841     for (np = orphan_nodes; np && np->next; np = np->next);     /* find the end of the orphan list */
01842     for (i = 0; i < NHASHSIZE; i++)
01843         if (nbuckets[i]) {
01844             if (orphan_nodes)
01845                 onp = np->next = nbuckets[i];
01846             else
01847                 onp = orphan_nodes = nbuckets[i];
01848             nbuckets[i] = NULL;
01849             while (onp) {
01850                 snmp_log(LOG_WARNING,
01851                          "Unlinked OID in %s: %s ::= { %s %ld }\n",
01852                          (mp->name ? mp->name : "<no module>"),
01853                          (onp->label ? onp->label : "<no label>"),
01854                          (onp->parent ? onp->parent : "<no parent>"),
01855                          onp->subid);
01856                  snmp_log(LOG_WARNING,
01857                           "Undefined identifier: %s near line %d of %s\n",
01858                           (onp->parent ? onp->parent : "<no parent>"),
01859                           onp->lineno, onp->filename);
01860                 np = onp;
01861                 onp = onp->next;
01862             }
01863         }
01864     return;
01865 }
01866 
01867 
01868 /*
01869  * Takes a list of the form:
01870  * { iso org(3) dod(6) 1 }
01871  * and creates several nodes, one for each parent-child pair.
01872  * Returns 0 on error.
01873  */
01874 static int
01875 getoid(FILE * fp, struct subid_s *id,   /* an array of subids */
01876        int length)
01877 {                               /* the length of the array */
01878     register int    count;
01879     int             type;
01880     char            token[MAXTOKEN];
01881 
01882     if ((type = get_token(fp, token, MAXTOKEN)) != LEFTBRACKET) {
01883         print_error("Expected \"{\"", token, type);
01884         return 0;
01885     }
01886     type = get_token(fp, token, MAXTOKEN);
01887     for (count = 0; count < length; count++, id++) {
01888         id->label = NULL;
01889         id->modid = current_module;
01890         id->subid = -1;
01891         if (type == RIGHTBRACKET)
01892             return count;
01893         if (type == LABEL) {
01894             /*
01895              * this entry has a label 
01896              */
01897             id->label = strdup(token);
01898             type = get_token(fp, token, MAXTOKEN);
01899             if (type == LEFTPAREN) {
01900                 type = get_token(fp, token, MAXTOKEN);
01901                 if (type == NUMBER) {
01902                     id->subid = strtoul(token, NULL, 10);
01903                     if ((type =
01904                          get_token(fp, token, MAXTOKEN)) != RIGHTPAREN) {
01905                         print_error("Expected a closing parenthesis",
01906                                     token, type);
01907                         return 0;
01908                     }
01909                 } else {
01910                     print_error("Expected a number", token, type);
01911                     return 0;
01912                 }
01913             } else {
01914                 continue;
01915             }
01916         } else if (type == NUMBER) {
01917             /*
01918              * this entry  has just an integer sub-identifier 
01919              */
01920             id->subid = strtoul(token, NULL, 10);
01921         } else {
01922             print_error("Expected label or number", token, type);
01923             return 0;
01924         }
01925         type = get_token(fp, token, MAXTOKEN);
01926     }
01927     print_error("Too long OID", token, type);
01928     return 0;
01929 }
01930 
01931 /*
01932  * Parse a sequence of object subidentifiers for the given name.
01933  * The "label OBJECT IDENTIFIER ::=" portion has already been parsed.
01934  *
01935  * The majority of cases take this form :
01936  * label OBJECT IDENTIFIER ::= { parent 2 }
01937  * where a parent label and a child subidentifier number are specified.
01938  *
01939  * Variations on the theme include cases where a number appears with
01940  * the parent, or intermediate subidentifiers are specified by label,
01941  * by number, or both.
01942  *
01943  * Here are some representative samples :
01944  * internet        OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
01945  * mgmt            OBJECT IDENTIFIER ::= { internet 2 }
01946  * rptrInfoHealth  OBJECT IDENTIFIER ::= { snmpDot3RptrMgt 0 4 }
01947  *
01948  * Here is a very rare form :
01949  * iso             OBJECT IDENTIFIER ::= { 1 }
01950  *
01951  * Returns NULL on error.  When this happens, memory may be leaked.
01952  */
01953 static struct node *
01954 parse_objectid(FILE * fp, char *name)
01955 {
01956     register int    count;
01957     register struct subid_s *op, *nop;
01958     int             length;
01959     struct subid_s  loid[32];
01960     struct node    *np, *root = NULL, *oldnp = NULL;
01961     struct tree    *tp;
01962 
01963     if ((length = getoid(fp, loid, 32)) == 0) {
01964         print_error("Bad object identifier", NULL, CONTINUE);
01965         return NULL;
01966     }
01967 
01968     /*
01969      * Handle numeric-only object identifiers,
01970      *  by labelling the first sub-identifier
01971      */
01972     op = loid;
01973     if (!op->label) {
01974         if (length == 1) {
01975             print_error("Attempt to define a root oid", name, OBJECT);
01976             return NULL;
01977         }
01978         for (tp = tree_head; tp; tp = tp->next_peer)
01979             if ((int) tp->subid == op->subid) {
01980                 op->label = strdup(tp->label);
01981                 break;
01982             }
01983     }
01984 
01985     /*
01986      * Handle  "label OBJECT-IDENTIFIER ::= { subid }"
01987      */
01988     if (length == 1) {
01989         op = loid;
01990         np = alloc_node(op->modid);
01991         if (np == NULL)
01992             return (NULL);
01993         np->subid = op->subid;
01994         np->label = strdup(name);
01995         np->parent = op->label;
01996         return np;
01997     }
01998 
01999     /*
02000      * For each parent-child subid pair in the subid array,
02001      * create a node and link it into the node list.
02002      */
02003     for (count = 0, op = loid, nop = loid + 1; count < (length - 1);
02004          count++, op++, nop++) {
02005         /*
02006          * every node must have parent's name and child's name or number 
02007          */
02008         /*
02009          * XX the next statement is always true -- does it matter ?? 
02010          */
02011         if (op->label && (nop->label || (nop->subid != -1))) {
02012             np = alloc_node(nop->modid);
02013             if (np == NULL)
02014                 return (NULL);
02015             if (root == NULL)
02016                 root = np;
02017 
02018             np->parent = strdup(op->label);
02019             if (count == (length - 2)) {
02020                 /*
02021                  * The name for this node is the label for this entry 
02022                  */
02023                 np->label = strdup(name);
02024             } else {
02025                 if (!nop->label) {
02026                     nop->label = (char *) malloc(20 + ANON_LEN);
02027                     if (nop->label == NULL)
02028                         return (NULL);
02029                     sprintf(nop->label, "%s%d", ANON, anonymous++);
02030                 }
02031                 np->label = strdup(nop->label);
02032             }
02033             if (nop->subid != -1)
02034                 np->subid = nop->subid;
02035             else
02036                 print_error("Warning: This entry is pretty silly",
02037                             np->label, CONTINUE);
02038 
02039             /*
02040              * set up next entry 
02041              */
02042             if (oldnp)
02043                 oldnp->next = np;
02044             oldnp = np;
02045         }                       /* end if(op->label... */
02046     }
02047 
02048     /*
02049      * free the loid array 
02050      */
02051     for (count = 0, op = loid; count < length; count++, op++) {
02052         if (op->label)
02053             free(op->label);
02054     }
02055 
02056     return root;
02057 }
02058 
02059 static int
02060 get_tc(const char *descriptor,
02061        int modid,
02062        int *tc_index,
02063        struct enum_list **ep, struct range_list **rp, char **hint)
02064 {
02065     int             i;
02066     struct tc      *tcp;
02067 
02068     i = get_tc_index(descriptor, modid);
02069     if (tc_index)
02070         *tc_index = i;
02071     if (i != -1) {
02072         tcp = &tclist[i];
02073         if (ep) {
02074             free_enums(ep);
02075             *ep = copy_enums(tcp->enums);
02076         }
02077         if (rp) {
02078             free_ranges(rp);
02079             *rp = copy_ranges(tcp->ranges);
02080         }
02081         if (hint) {
02082             if (*hint)
02083                 free(*hint);
02084             *hint = (tcp->hint ? strdup(tcp->hint) : NULL);
02085         }
02086         return tcp->type;
02087     }
02088     return LABEL;
02089 }
02090 
02091 /*
02092  * return index into tclist of given TC descriptor
02093  * return -1 if not found
02094  */
02095 static int
02096 get_tc_index(const char *descriptor, int modid)
02097 {
02098     int             i;
02099     struct tc      *tcp;
02100     struct module  *mp;
02101     struct module_import *mip;
02102 
02103     /*
02104      * Check that the descriptor isn't imported
02105      *  by searching the import list
02106      */
02107 
02108     for (mp = module_head; mp; mp = mp->next)
02109         if (mp->modid == modid)
02110             break;
02111     if (mp)
02112         for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) {
02113             if (!label_compare(mip->label, descriptor)) {
02114                 /*
02115                  * Found it - so amend the module ID 
02116                  */
02117                 modid = mip->modid;
02118                 break;
02119             }
02120         }
02121 
02122 
02123     for (i = 0, tcp = tclist; i < MAXTC; i++, tcp++) {
02124         if (tcp->type == 0)
02125             break;
02126         if (!label_compare(descriptor, tcp->descriptor) &&
02127             ((modid == tcp->modid) || (modid == -1))) {
02128             return i;
02129         }
02130     }
02131     return -1;
02132 }
02133 
02134 /*
02135  * translate integer tc_index to string identifier from tclist
02136  * *
02137  * * Returns pointer to string in table (should not be modified) or NULL
02138  */
02139 const char     *
02140 get_tc_descriptor(int tc_index)
02141 {
02142     if (tc_index < 0 || tc_index >= MAXTC)
02143         return NULL;
02144     return (tclist[tc_index].descriptor);
02145 }
02146 
02147 #ifndef NETSNMP_FEATURE_REMOVE_GET_TC_DESCRIPTION
02148 /* used in the perl module */
02149 const char     *
02150 get_tc_description(int tc_index)
02151 {
02152     if (tc_index < 0 || tc_index >= MAXTC)
02153         return NULL;
02154     return (tclist[tc_index].description);
02155 }
02156 #endif /* NETSNMP_FEATURE_REMOVE_GET_TC_DESCRIPTION */
02157 
02158 
02159 /*
02160  * Parses an enumeration list of the form:
02161  *        { label(value) label(value) ... }
02162  * The initial { has already been parsed.
02163  * Returns NULL on error.
02164  */
02165 
02166 static struct enum_list *
02167 parse_enumlist(FILE * fp, struct enum_list **retp)
02168 {
02169     register int    type;
02170     char            token[MAXTOKEN];
02171     struct enum_list *ep = NULL, **epp = &ep;
02172 
02173     free_enums(retp);
02174 
02175     while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) {
02176         if (type == RIGHTBRACKET)
02177             break;
02178         /* some enums use "deprecated" to indicate a no longer value label */
02179         /* (EG: IP-MIB's IpAddressStatusTC) */
02180         if (type == LABEL || type == DEPRECATED) {
02181             /*
02182              * this is an enumerated label 
02183              */
02184             *epp =
02185                 (struct enum_list *) calloc(1, sizeof(struct enum_list));
02186             if (*epp == NULL)
02187                 return (NULL);
02188             /*
02189              * a reasonable approximation for the length 
02190              */
02191             (*epp)->label = strdup(token);
02192             type = get_token(fp, token, MAXTOKEN);
02193             if (type != LEFTPAREN) {
02194                 print_error("Expected \"(\"", token, type);
02195                 return NULL;
02196             }
02197             type = get_token(fp, token, MAXTOKEN);
02198             if (type != NUMBER) {
02199                 print_error("Expected integer", token, type);
02200                 return NULL;
02201             }
02202             (*epp)->value = strtol(token, NULL, 10);
02203             type = get_token(fp, token, MAXTOKEN);
02204             if (type != RIGHTPAREN) {
02205                 print_error("Expected \")\"", token, type);
02206                 return NULL;
02207             }
02208             epp = &(*epp)->next;
02209         }
02210     }
02211     if (type == ENDOFFILE) {
02212         print_error("Expected \"}\"", token, type);
02213         return NULL;
02214     }
02215     *retp = ep;
02216     return ep;
02217 }
02218 
02219 static struct range_list *
02220 parse_ranges(FILE * fp, struct range_list **retp)
02221 {
02222     int             low, high;
02223     char            nexttoken[MAXTOKEN];
02224     int             nexttype;
02225     struct range_list *rp = NULL, **rpp = &rp;
02226     int             size = 0, taken = 1;
02227 
02228     free_ranges(retp);
02229 
02230     nexttype = get_token(fp, nexttoken, MAXTOKEN);
02231     if (nexttype == SIZE) {
02232         size = 1;
02233         taken = 0;
02234         nexttype = get_token(fp, nexttoken, MAXTOKEN);
02235         if (nexttype != LEFTPAREN)
02236             print_error("Expected \"(\" after SIZE", nexttoken, nexttype);
02237     }
02238 
02239     do {
02240         if (!taken)
02241             nexttype = get_token(fp, nexttoken, MAXTOKEN);
02242         else
02243             taken = 0;
02244         high = low = strtoul(nexttoken, NULL, 10);
02245         nexttype = get_token(fp, nexttoken, MAXTOKEN);
02246         if (nexttype == RANGE) {
02247             nexttype = get_token(fp, nexttoken, MAXTOKEN);
02248             errno = 0;
02249             high = strtoul(nexttoken, NULL, 10);
02250             if ( errno == ERANGE ) {
02251                 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
02252                                        NETSNMP_DS_LIB_MIB_WARNINGS))
02253                     snmp_log(LOG_WARNING,
02254                              "Warning: Upper bound not handled correctly (%s != %d): At line %d in %s\n",
02255                                  nexttoken, high, mibLine, File);
02256             }
02257             nexttype = get_token(fp, nexttoken, MAXTOKEN);
02258         }
02259         *rpp = (struct range_list *) calloc(1, sizeof(struct range_list));
02260         if (*rpp == NULL)
02261             break;
02262         (*rpp)->low = low;
02263         (*rpp)->high = high;
02264         rpp = &(*rpp)->next;
02265 
02266     } while (nexttype == BAR);
02267     if (size) {
02268         if (nexttype != RIGHTPAREN)
02269             print_error("Expected \")\" after SIZE", nexttoken, nexttype);
02270         nexttype = get_token(fp, nexttoken, nexttype);
02271     }
02272     if (nexttype != RIGHTPAREN)
02273         print_error("Expected \")\"", nexttoken, nexttype);
02274 
02275     *retp = rp;
02276     return rp;
02277 }
02278 
02279 /*
02280  * Parses an asn type.  Structures are ignored by this parser.
02281  * Returns NULL on error.
02282  */
02283 static struct node *
02284 parse_asntype(FILE * fp, char *name, int *ntype, char *ntoken)
02285 {
02286     int             type, i;
02287     char            token[MAXTOKEN];
02288     char            quoted_string_buffer[MAXQUOTESTR];
02289     char           *hint = NULL;
02290     char           *descr = NULL;
02291     struct tc      *tcp;
02292     int             level;
02293 
02294     type = get_token(fp, token, MAXTOKEN);
02295     if (type == SEQUENCE || type == CHOICE) {
02296         level = 0;
02297         while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) {
02298             if (type == LEFTBRACKET) {
02299                 level++;
02300             } else if (type == RIGHTBRACKET && --level == 0) {
02301                 *ntype = get_token(fp, ntoken, MAXTOKEN);
02302                 return NULL;
02303             }
02304         }
02305         print_error("Expected \"}\"", token, type);
02306         return NULL;
02307     } else if (type == LEFTBRACKET) {
02308         struct node    *np;
02309         int             ch_next = '{';
02310         ungetc(ch_next, fp);
02311         np = parse_objectid(fp, name);
02312         if (np != NULL) {
02313             *ntype = get_token(fp, ntoken, MAXTOKEN);
02314             return np;
02315         }
02316         return NULL;
02317     } else if (type == LEFTSQBRACK) {
02318         int             size = 0;
02319         do {
02320             type = get_token(fp, token, MAXTOKEN);
02321         } while (type != ENDOFFILE && type != RIGHTSQBRACK);
02322         if (type != RIGHTSQBRACK) {
02323             print_error("Expected \"]\"", token, type);
02324             return NULL;
02325         }
02326         type = get_token(fp, token, MAXTOKEN);
02327         if (type == IMPLICIT)
02328             type = get_token(fp, token, MAXTOKEN);
02329         *ntype = get_token(fp, ntoken, MAXTOKEN);
02330         if (*ntype == LEFTPAREN) {
02331             switch (type) {
02332             case OCTETSTR:
02333                 *ntype = get_token(fp, ntoken, MAXTOKEN);
02334                 if (*ntype != SIZE) {
02335                     print_error("Expected SIZE", ntoken, *ntype);
02336                     return NULL;
02337                 }
02338                 size = 1;
02339                 *ntype = get_token(fp, ntoken, MAXTOKEN);
02340                 if (*ntype != LEFTPAREN) {
02341                     print_error("Expected \"(\" after SIZE", ntoken,
02342                                 *ntype);
02343                     return NULL;
02344                 }
02345                 /*
02346                  * fall through 
02347                  */
02348             case INTEGER:
02349                 *ntype = get_token(fp, ntoken, MAXTOKEN);
02350                 do {
02351                     if (*ntype != NUMBER)
02352                         print_error("Expected NUMBER", ntoken, *ntype);
02353                     *ntype = get_token(fp, ntoken, MAXTOKEN);
02354                     if (*ntype == RANGE) {
02355                         *ntype = get_token(fp, ntoken, MAXTOKEN);
02356                         if (*ntype != NUMBER)
02357                             print_error("Expected NUMBER", ntoken, *ntype);
02358                         *ntype = get_token(fp, ntoken, MAXTOKEN);
02359                     }
02360                 } while (*ntype == BAR);
02361                 if (*ntype != RIGHTPAREN) {
02362                     print_error("Expected \")\"", ntoken, *ntype);
02363                     return NULL;
02364                 }
02365                 *ntype = get_token(fp, ntoken, MAXTOKEN);
02366                 if (size) {
02367                     if (*ntype != RIGHTPAREN) {
02368                         print_error("Expected \")\" to terminate SIZE",
02369                                     ntoken, *ntype);
02370                         return NULL;
02371                     }
02372                     *ntype = get_token(fp, ntoken, MAXTOKEN);
02373                 }
02374             }
02375         }
02376         return NULL;
02377     } else {
02378         if (type == CONVENTION) {
02379             while (type != SYNTAX && type != ENDOFFILE) {
02380                 if (type == DISPLAYHINT) {
02381                     type = get_token(fp, token, MAXTOKEN);
02382                     if (type != QUOTESTRING)
02383                         print_error("DISPLAY-HINT must be string", token,
02384                                     type);
02385                     else
02386                         hint = strdup(token);
02387                 } else if (type == DESCRIPTION &&
02388                            netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
02389                                                   NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
02390                     type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02391                     if (type != QUOTESTRING)
02392                         print_error("DESCRIPTION must be string", token,
02393                                     type);
02394                     else
02395                         descr = strdup(quoted_string_buffer);
02396                 } else
02397                     type =
02398                         get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02399             }
02400             type = get_token(fp, token, MAXTOKEN);
02401             if (type == OBJECT) {
02402                 type = get_token(fp, token, MAXTOKEN);
02403                 if (type != IDENTIFIER) {
02404                     print_error("Expected IDENTIFIER", token, type);
02405                     SNMP_FREE(hint);
02406                     return NULL;
02407                 }
02408                 type = OBJID;
02409             }
02410         } else if (type == OBJECT) {
02411             type = get_token(fp, token, MAXTOKEN);
02412             if (type != IDENTIFIER) {
02413                 print_error("Expected IDENTIFIER", token, type);
02414                 return NULL;
02415             }
02416             type = OBJID;
02417         }
02418 
02419         if (type == LABEL) {
02420             type = get_tc(token, current_module, NULL, NULL, NULL, NULL);
02421         }
02422 
02423         /*
02424          * textual convention 
02425          */
02426         for (i = 0; i < MAXTC; i++) {
02427             if (tclist[i].type == 0)
02428                 break;
02429         }
02430 
02431         if (i == MAXTC) {
02432             print_error("Too many textual conventions", token, type);
02433             SNMP_FREE(hint);
02434             return NULL;
02435         }
02436         if (!(type & SYNTAX_MASK)) {
02437             print_error("Textual convention doesn't map to real type",
02438                         token, type);
02439             SNMP_FREE(hint);
02440             return NULL;
02441         }
02442         tcp = &tclist[i];
02443         tcp->modid = current_module;
02444         tcp->descriptor = strdup(name);
02445         tcp->hint = hint;
02446         tcp->description = descr;
02447         tcp->type = type;
02448         *ntype = get_token(fp, ntoken, MAXTOKEN);
02449         if (*ntype == LEFTPAREN) {
02450             tcp->ranges = parse_ranges(fp, &tcp->ranges);
02451             *ntype = get_token(fp, ntoken, MAXTOKEN);
02452         } else if (*ntype == LEFTBRACKET) {
02453             /*
02454              * if there is an enumeration list, parse it 
02455              */
02456             tcp->enums = parse_enumlist(fp, &tcp->enums);
02457             *ntype = get_token(fp, ntoken, MAXTOKEN);
02458         }
02459         return NULL;
02460     }
02461 }
02462 
02463 
02464 /*
02465  * Parses an OBJECT TYPE macro.
02466  * Returns 0 on error.
02467  */
02468 static struct node *
02469 parse_objecttype(FILE * fp, char *name)
02470 {
02471     register int    type;
02472     char            token[MAXTOKEN];
02473     char            nexttoken[MAXTOKEN];
02474     char            quoted_string_buffer[MAXQUOTESTR];
02475     int             nexttype, tctype;
02476     register struct node *np;
02477 
02478     type = get_token(fp, token, MAXTOKEN);
02479     if (type != SYNTAX) {
02480         print_error("Bad format for OBJECT-TYPE", token, type);
02481         return NULL;
02482     }
02483     np = alloc_node(current_module);
02484     if (np == NULL)
02485         return (NULL);
02486     type = get_token(fp, token, MAXTOKEN);
02487     if (type == OBJECT) {
02488         type = get_token(fp, token, MAXTOKEN);
02489         if (type != IDENTIFIER) {
02490             print_error("Expected IDENTIFIER", token, type);
02491             free_node(np);
02492             return NULL;
02493         }
02494         type = OBJID;
02495     }
02496     if (type == LABEL) {
02497         int             tmp_index;
02498         tctype = get_tc(token, current_module, &tmp_index,
02499                         &np->enums, &np->ranges, &np->hint);
02500         if (tctype == LABEL &&
02501             netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
02502                                NETSNMP_DS_LIB_MIB_WARNINGS) > 1) {
02503             print_error("Warning: No known translation for type", token,
02504                         type);
02505         }
02506         type = tctype;
02507         np->tc_index = tmp_index;       /* store TC for later reference */
02508     }
02509     np->type = type;
02510     nexttype = get_token(fp, nexttoken, MAXTOKEN);
02511     switch (type) {
02512     case SEQUENCE:
02513         if (nexttype == OF) {
02514             nexttype = get_token(fp, nexttoken, MAXTOKEN);
02515             nexttype = get_token(fp, nexttoken, MAXTOKEN);
02516 
02517         }
02518         break;
02519     case INTEGER:
02520     case INTEGER32:
02521     case UINTEGER32:
02522     case UNSIGNED32:
02523     case COUNTER:
02524     case GAUGE:
02525     case BITSTRING:
02526     case LABEL:
02527         if (nexttype == LEFTBRACKET) {
02528             /*
02529              * if there is an enumeration list, parse it 
02530              */
02531             np->enums = parse_enumlist(fp, &np->enums);
02532             nexttype = get_token(fp, nexttoken, MAXTOKEN);
02533         } else if (nexttype == LEFTPAREN) {
02534             /*
02535              * if there is a range list, parse it 
02536              */
02537             np->ranges = parse_ranges(fp, &np->ranges);
02538             nexttype = get_token(fp, nexttoken, MAXTOKEN);
02539         }
02540         break;
02541     case OCTETSTR:
02542     case KW_OPAQUE:
02543         /*
02544          * parse any SIZE specification 
02545          */
02546         if (nexttype == LEFTPAREN) {
02547             nexttype = get_token(fp, nexttoken, MAXTOKEN);
02548             if (nexttype == SIZE) {
02549                 nexttype = get_token(fp, nexttoken, MAXTOKEN);
02550                 if (nexttype == LEFTPAREN) {
02551                     np->ranges = parse_ranges(fp, &np->ranges);
02552                     nexttype = get_token(fp, nexttoken, MAXTOKEN);      /* ) */
02553                     if (nexttype == RIGHTPAREN) {
02554                         nexttype = get_token(fp, nexttoken, MAXTOKEN);
02555                         break;
02556                     }
02557                 }
02558             }
02559             print_error("Bad SIZE syntax", token, type);
02560             free_node(np);
02561             return NULL;
02562         }
02563         break;
02564     case OBJID:
02565     case NETADDR:
02566     case IPADDR:
02567     case TIMETICKS:
02568     case NUL:
02569     case NSAPADDRESS:
02570     case COUNTER64:
02571         break;
02572     default:
02573         print_error("Bad syntax", token, type);
02574         free_node(np);
02575         return NULL;
02576     }
02577     if (nexttype == UNITS) {
02578         type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02579         if (type != QUOTESTRING) {
02580             print_error("Bad UNITS", quoted_string_buffer, type);
02581             free_node(np);
02582             return NULL;
02583         }
02584         np->units = strdup(quoted_string_buffer);
02585         nexttype = get_token(fp, nexttoken, MAXTOKEN);
02586     }
02587     if (nexttype != ACCESS) {
02588         print_error("Should be ACCESS", nexttoken, nexttype);
02589         free_node(np);
02590         return NULL;
02591     }
02592     type = get_token(fp, token, MAXTOKEN);
02593     if (type != READONLY && type != READWRITE && type != WRITEONLY
02594         && type != NOACCESS && type != READCREATE && type != ACCNOTIFY) {
02595         print_error("Bad ACCESS type", token, type);
02596         free_node(np);
02597         return NULL;
02598     }
02599     np->access = type;
02600     type = get_token(fp, token, MAXTOKEN);
02601     if (type != STATUS) {
02602         print_error("Should be STATUS", token, type);
02603         free_node(np);
02604         return NULL;
02605     }
02606     type = get_token(fp, token, MAXTOKEN);
02607     if (type != MANDATORY && type != CURRENT && type != KW_OPTIONAL &&
02608         type != OBSOLETE && type != DEPRECATED) {
02609         print_error("Bad STATUS", token, type);
02610         free_node(np);
02611         return NULL;
02612     }
02613     np->status = type;
02614     /*
02615      * Optional parts of the OBJECT-TYPE macro
02616      */
02617     type = get_token(fp, token, MAXTOKEN);
02618     while (type != EQUALS && type != ENDOFFILE) {
02619         switch (type) {
02620         case DESCRIPTION:
02621             type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02622 
02623             if (type != QUOTESTRING) {
02624                 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
02625                 free_node(np);
02626                 return NULL;
02627             }
02628             if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
02629                                        NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
02630                 np->description = strdup(quoted_string_buffer);
02631             }
02632             break;
02633 
02634         case REFERENCE:
02635             type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02636             if (type != QUOTESTRING) {
02637                 print_error("Bad REFERENCE", quoted_string_buffer, type);
02638                 free_node(np);
02639                 return NULL;
02640             }
02641             np->reference = strdup(quoted_string_buffer);
02642             break;
02643         case INDEX:
02644             if (np->augments) {
02645                 print_error("Cannot have both INDEX and AUGMENTS", token,
02646                             type);
02647                 free_node(np);
02648                 return NULL;
02649             }
02650             np->indexes = getIndexes(fp, &np->indexes);
02651             if (np->indexes == NULL) {
02652                 print_error("Bad INDEX list", token, type);
02653                 free_node(np);
02654                 return NULL;
02655             }
02656             break;
02657         case AUGMENTS:
02658             if (np->indexes) {
02659                 print_error("Cannot have both INDEX and AUGMENTS", token,
02660                             type);
02661                 free_node(np);
02662                 return NULL;
02663             }
02664             np->indexes = getIndexes(fp, &np->indexes);
02665             if (np->indexes == NULL) {
02666                 print_error("Bad AUGMENTS list", token, type);
02667                 free_node(np);
02668                 return NULL;
02669             }
02670             np->augments = strdup(np->indexes->ilabel);
02671             free_indexes(&np->indexes);
02672             break;
02673         case DEFVAL:
02674             /*
02675              * Mark's defVal section 
02676              */
02677             type = get_token(fp, quoted_string_buffer, MAXTOKEN);
02678             if (type != LEFTBRACKET) {
02679                 print_error("Bad DEFAULTVALUE", quoted_string_buffer,
02680                             type);
02681                 free_node(np);
02682                 return NULL;
02683             }
02684 
02685             {
02686                 int             level = 1;
02687                 char            defbuf[512];
02688 
02689                 defbuf[0] = 0;
02690                 while (1) {
02691                     type = get_token(fp, quoted_string_buffer, MAXTOKEN);
02692                     if ((type == RIGHTBRACKET && --level == 0)
02693                         || type == ENDOFFILE)
02694                         break;
02695                     else if (type == LEFTBRACKET)
02696                         level++;
02697                     if (type == QUOTESTRING) {
02698                         if (strlen(defbuf)+2 < sizeof(defbuf)) {
02699                             defbuf[ strlen(defbuf)+2 ] = 0;
02700                             defbuf[ strlen(defbuf)+1 ] = '"';
02701                             defbuf[ strlen(defbuf)   ] = '\\';
02702                         }
02703                         defbuf[ sizeof(defbuf)-1 ] = 0;
02704                     }
02705                     strncat(defbuf, quoted_string_buffer,
02706                             sizeof(defbuf)-strlen(defbuf)-1);
02707                     defbuf[ sizeof(defbuf)-1 ] = 0;
02708                     if (type == QUOTESTRING) {
02709                         if (strlen(defbuf)+2 < sizeof(defbuf)) {
02710                             defbuf[ strlen(defbuf)+2 ] = 0;
02711                             defbuf[ strlen(defbuf)+1 ] = '"';
02712                             defbuf[ strlen(defbuf)   ] = '\\';
02713                         }
02714                         defbuf[ sizeof(defbuf)-1 ] = 0;
02715                     }
02716                     if (strlen(defbuf)+1 < sizeof(defbuf)) {
02717                         defbuf[ strlen(defbuf)+1 ] = 0;
02718                         defbuf[ strlen(defbuf)   ] = ' ';
02719                     }
02720                 }
02721 
02722                 if (type != RIGHTBRACKET) {
02723                     print_error("Bad DEFAULTVALUE", quoted_string_buffer,
02724                                 type);
02725                     free_node(np);
02726                     return NULL;
02727                 }
02728 
02729                 defbuf[strlen(defbuf) - 1] = 0;
02730                 np->defaultValue = strdup(defbuf);
02731             }
02732 
02733             break;
02734 
02735         case NUM_ENTRIES:
02736             if (tossObjectIdentifier(fp) != OBJID) {
02737                 print_error("Bad Object Identifier", token, type);
02738                 free_node(np);
02739                 return NULL;
02740             }
02741             break;
02742 
02743         default:
02744             print_error("Bad format of optional clauses", token, type);
02745             free_node(np);
02746             return NULL;
02747 
02748         }
02749         type = get_token(fp, token, MAXTOKEN);
02750     }
02751     if (type != EQUALS) {
02752         print_error("Bad format", token, type);
02753         free_node(np);
02754         return NULL;
02755     }
02756     return merge_parse_objectid(np, fp, name);
02757 }
02758 
02759 /*
02760  * Parses an OBJECT GROUP macro.
02761  * Returns 0 on error.
02762  *
02763  * Also parses object-identity, since they are similar (ignore STATUS).
02764  *   - WJH 10/96
02765  */
02766 static struct node *
02767 parse_objectgroup(FILE * fp, char *name, int what, struct objgroup **ol)
02768 {
02769     int             type;
02770     char            token[MAXTOKEN];
02771     char            quoted_string_buffer[MAXQUOTESTR];
02772     struct node    *np;
02773 
02774     np = alloc_node(current_module);
02775     if (np == NULL)
02776         return (NULL);
02777     type = get_token(fp, token, MAXTOKEN);
02778     if (type == what) {
02779         type = get_token(fp, token, MAXTOKEN);
02780         if (type != LEFTBRACKET) {
02781             print_error("Expected \"{\"", token, type);
02782             goto skip;
02783         }
02784         do {
02785             struct objgroup *o;
02786             type = get_token(fp, token, MAXTOKEN);
02787             if (type != LABEL) {
02788                 print_error("Bad identifier", token, type);
02789                 goto skip;
02790             }
02791             o = (struct objgroup *) malloc(sizeof(struct objgroup));
02792             if (!o) {
02793                 print_error("Resource failure", token, type);
02794                 goto skip;
02795             }
02796             o->line = mibLine;
02797             o->name = strdup(token);
02798             o->next = *ol;
02799             *ol = o;
02800             type = get_token(fp, token, MAXTOKEN);
02801         } while (type == COMMA);
02802         if (type != RIGHTBRACKET) {
02803             print_error("Expected \"}\" after list", token, type);
02804             goto skip;
02805         }
02806         type = get_token(fp, token, type);
02807     }
02808     if (type != STATUS) {
02809         print_error("Expected STATUS", token, type);
02810         goto skip;
02811     }
02812     type = get_token(fp, token, MAXTOKEN);
02813     if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) {
02814         print_error("Bad STATUS value", token, type);
02815         goto skip;
02816     }
02817     type = get_token(fp, token, MAXTOKEN);
02818     if (type != DESCRIPTION) {
02819         print_error("Expected DESCRIPTION", token, type);
02820         goto skip;
02821     }
02822     type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02823     if (type != QUOTESTRING) {
02824         print_error("Bad DESCRIPTION", quoted_string_buffer, type);
02825         free_node(np);
02826         return NULL;
02827     }
02828     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
02829                                NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
02830         np->description = strdup(quoted_string_buffer);
02831     }
02832     type = get_token(fp, token, MAXTOKEN);
02833     if (type == REFERENCE) {
02834         type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02835         if (type != QUOTESTRING) {
02836             print_error("Bad REFERENCE", quoted_string_buffer, type);
02837             free_node(np);
02838             return NULL;
02839         }
02840         np->reference = strdup(quoted_string_buffer);
02841         type = get_token(fp, token, MAXTOKEN);
02842     }
02843     if (type != EQUALS)
02844         print_error("Expected \"::=\"", token, type);
02845   skip:
02846     while (type != EQUALS && type != ENDOFFILE)
02847         type = get_token(fp, token, MAXTOKEN);
02848 
02849     return merge_parse_objectid(np, fp, name);
02850 }
02851 
02852 /*
02853  * Parses a NOTIFICATION-TYPE macro.
02854  * Returns 0 on error.
02855  */
02856 static struct node *
02857 parse_notificationDefinition(FILE * fp, char *name)
02858 {
02859     register int    type;
02860     char            token[MAXTOKEN];
02861     char            quoted_string_buffer[MAXQUOTESTR];
02862     register struct node *np;
02863 
02864     np = alloc_node(current_module);
02865     if (np == NULL)
02866         return (NULL);
02867     type = get_token(fp, token, MAXTOKEN);
02868     while (type != EQUALS && type != ENDOFFILE) {
02869         switch (type) {
02870         case DESCRIPTION:
02871             type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02872             if (type != QUOTESTRING) {
02873                 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
02874                 free_node(np);
02875                 return NULL;
02876             }
02877             if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
02878                                        NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
02879                 np->description = strdup(quoted_string_buffer);
02880             }
02881             break;
02882         case REFERENCE:
02883             type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02884             if (type != QUOTESTRING) {
02885                 print_error("Bad REFERENCE", quoted_string_buffer, type);
02886                 free_node(np);
02887                 return NULL;
02888             }
02889             np->reference = strdup(quoted_string_buffer);
02890             break;
02891         case OBJECTS:
02892             np->varbinds = getVarbinds(fp, &np->varbinds);
02893             if (!np->varbinds) {
02894                 print_error("Bad OBJECTS list", token, type);
02895                 free_node(np);
02896                 return NULL;
02897             }
02898             break;
02899         default:
02900             /*
02901              * NOTHING 
02902              */
02903             break;
02904         }
02905         type = get_token(fp, token, MAXTOKEN);
02906     }
02907     return merge_parse_objectid(np, fp, name);
02908 }
02909 
02910 /*
02911  * Parses a TRAP-TYPE macro.
02912  * Returns 0 on error.
02913  */
02914 static struct node *
02915 parse_trapDefinition(FILE * fp, char *name)
02916 {
02917     register int    type;
02918     char            token[MAXTOKEN];
02919     char            quoted_string_buffer[MAXQUOTESTR];
02920     register struct node *np;
02921 
02922     np = alloc_node(current_module);
02923     if (np == NULL)
02924         return (NULL);
02925     type = get_token(fp, token, MAXTOKEN);
02926     while (type != EQUALS && type != ENDOFFILE) {
02927         switch (type) {
02928         case DESCRIPTION:
02929             type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02930             if (type != QUOTESTRING) {
02931                 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
02932                 free_node(np);
02933                 return NULL;
02934             }
02935             if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
02936                                        NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
02937                 np->description = strdup(quoted_string_buffer);
02938             }
02939             break;
02940         case REFERENCE:
02941             /* I'm not sure REFERENCEs are legal in smiv1 traps??? */
02942             type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
02943             if (type != QUOTESTRING) {
02944                 print_error("Bad REFERENCE", quoted_string_buffer, type);
02945                 free_node(np);
02946                 return NULL;
02947             }
02948             np->reference = strdup(quoted_string_buffer);
02949             break;
02950         case ENTERPRISE:
02951             type = get_token(fp, token, MAXTOKEN);
02952             if (type == LEFTBRACKET) {
02953                 type = get_token(fp, token, MAXTOKEN);
02954                 if (type != LABEL) {
02955                     print_error("Bad Trap Format", token, type);
02956                     free_node(np);
02957                     return NULL;
02958                 }
02959                 np->parent = strdup(token);
02960                 /*
02961                  * Get right bracket 
02962                  */
02963                 type = get_token(fp, token, MAXTOKEN);
02964             } else if (type == LABEL) {
02965                 np->parent = strdup(token);
02966             } else {
02967                 free_node(np);
02968                 return NULL;
02969             }
02970             break;
02971         case VARIABLES:
02972             np->varbinds = getVarbinds(fp, &np->varbinds);
02973             if (!np->varbinds) {
02974                 print_error("Bad VARIABLES list", token, type);
02975                 free_node(np);
02976                 return NULL;
02977             }
02978             break;
02979         default:
02980             /*
02981              * NOTHING 
02982              */
02983             break;
02984         }
02985         type = get_token(fp, token, MAXTOKEN);
02986     }
02987     type = get_token(fp, token, MAXTOKEN);
02988 
02989     np->label = strdup(name);
02990 
02991     if (type != NUMBER) {
02992         print_error("Expected a Number", token, type);
02993         free_node(np);
02994         return NULL;
02995     }
02996     np->subid = strtoul(token, NULL, 10);
02997     np->next = alloc_node(current_module);
02998     if (np->next == NULL) {
02999         free_node(np);
03000         return (NULL);
03001     }
03002 
03003     /* Catch the syntax error */
03004     if (np->parent == NULL) {
03005         free_node(np->next);
03006         free_node(np);
03007         gMibError = MODULE_SYNTAX_ERROR;
03008         return (NULL);
03009     }
03010 
03011     np->next->parent = np->parent;
03012     np->parent = (char *) malloc(strlen(np->parent) + 2);
03013     if (np->parent == NULL) {
03014         free_node(np->next);
03015         free_node(np);
03016         return (NULL);
03017     }
03018     strcpy(np->parent, np->next->parent);
03019     strcat(np->parent, "#");
03020     np->next->label = strdup(np->parent);
03021     return np;
03022 }
03023 
03024 
03025 /*
03026  * Parses a compliance macro
03027  * Returns 0 on error.
03028  */
03029 static int
03030 eat_syntax(FILE * fp, char *token, int maxtoken)
03031 {
03032     int             type, nexttype;
03033     struct node    *np = alloc_node(current_module);
03034     char            nexttoken[MAXTOKEN];
03035 
03036     if (!np)
03037         return 0;
03038 
03039     type = get_token(fp, token, maxtoken);
03040     nexttype = get_token(fp, nexttoken, MAXTOKEN);
03041     switch (type) {
03042     case INTEGER:
03043     case INTEGER32:
03044     case UINTEGER32:
03045     case UNSIGNED32:
03046     case COUNTER:
03047     case GAUGE:
03048     case BITSTRING:
03049     case LABEL:
03050         if (nexttype == LEFTBRACKET) {
03051             /*
03052              * if there is an enumeration list, parse it 
03053              */
03054             np->enums = parse_enumlist(fp, &np->enums);
03055             nexttype = get_token(fp, nexttoken, MAXTOKEN);
03056         } else if (nexttype == LEFTPAREN) {
03057             /*
03058              * if there is a range list, parse it 
03059              */
03060             np->ranges = parse_ranges(fp, &np->ranges);
03061             nexttype = get_token(fp, nexttoken, MAXTOKEN);
03062         }
03063         break;
03064     case OCTETSTR:
03065     case KW_OPAQUE:
03066         /*
03067          * parse any SIZE specification 
03068          */
03069         if (nexttype == LEFTPAREN) {
03070             nexttype = get_token(fp, nexttoken, MAXTOKEN);
03071             if (nexttype == SIZE) {
03072                 nexttype = get_token(fp, nexttoken, MAXTOKEN);
03073                 if (nexttype == LEFTPAREN) {
03074                     np->ranges = parse_ranges(fp, &np->ranges);
03075                     nexttype = get_token(fp, nexttoken, MAXTOKEN);      /* ) */
03076                     if (nexttype == RIGHTPAREN) {
03077                         nexttype = get_token(fp, nexttoken, MAXTOKEN);
03078                         break;
03079                     }
03080                 }
03081             }
03082             print_error("Bad SIZE syntax", token, type);
03083             free_node(np);
03084             return nexttype;
03085         }
03086         break;
03087     case OBJID:
03088     case NETADDR:
03089     case IPADDR:
03090     case TIMETICKS:
03091     case NUL:
03092     case NSAPADDRESS:
03093     case COUNTER64:
03094         break;
03095     default:
03096         print_error("Bad syntax", token, type);
03097         free_node(np);
03098         return nexttype;
03099     }
03100     free_node(np);
03101     return nexttype;
03102 }
03103 
03104 static int
03105 compliance_lookup(const char *name, int modid)
03106 {
03107     if (modid == -1) {
03108         struct objgroup *op =
03109             (struct objgroup *) malloc(sizeof(struct objgroup));
03110         if (!op)
03111             return 0;
03112         op->next = objgroups;
03113         op->name = strdup(name);
03114         op->line = mibLine;
03115         objgroups = op;
03116         return 1;
03117     } else
03118         return find_tree_node(name, modid) != NULL;
03119 }
03120 
03121 static struct node *
03122 parse_compliance(FILE * fp, char *name)
03123 {
03124     int             type;
03125     char            token[MAXTOKEN];
03126     char            quoted_string_buffer[MAXQUOTESTR];
03127     struct node    *np;
03128 
03129     np = alloc_node(current_module);
03130     if (np == NULL)
03131         return (NULL);
03132     type = get_token(fp, token, MAXTOKEN);
03133     if (type != STATUS) {
03134         print_error("Expected STATUS", token, type);
03135         goto skip;
03136     }
03137     type = get_token(fp, token, MAXTOKEN);
03138     if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) {
03139         print_error("Bad STATUS", token, type);
03140         goto skip;
03141     }
03142     type = get_token(fp, token, MAXTOKEN);
03143     if (type != DESCRIPTION) {
03144         print_error("Expected DESCRIPTION", token, type);
03145         goto skip;
03146     }
03147     type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
03148     if (type != QUOTESTRING) {
03149         print_error("Bad DESCRIPTION", quoted_string_buffer, type);
03150         goto skip;
03151     }
03152     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
03153                                NETSNMP_DS_LIB_SAVE_MIB_DESCRS))
03154         np->description = strdup(quoted_string_buffer);
03155     type = get_token(fp, token, MAXTOKEN);
03156     if (type == REFERENCE) {
03157         type = get_token(fp, quoted_string_buffer, MAXTOKEN);
03158         if (type != QUOTESTRING) {
03159             print_error("Bad REFERENCE", quoted_string_buffer, type);
03160             goto skip;
03161         }
03162         np->reference = strdup(quoted_string_buffer);
03163         type = get_token(fp, token, MAXTOKEN);
03164     }
03165     if (type != MODULE) {
03166         print_error("Expected MODULE", token, type);
03167         goto skip;
03168     }
03169     while (type == MODULE) {
03170         int             modid = -1;
03171         char            modname[MAXTOKEN];
03172         type = get_token(fp, token, MAXTOKEN);
03173         if (type == LABEL
03174             && strcmp(token, module_name(current_module, modname))) {
03175             modid = read_module_internal(token);
03176             if (modid != MODULE_LOADED_OK
03177                 && modid != MODULE_ALREADY_LOADED) {
03178                 print_error("Unknown module", token, type);
03179                 goto skip;
03180             }
03181             modid = which_module(token);
03182             type = get_token(fp, token, MAXTOKEN);
03183         }
03184         if (type == MANDATORYGROUPS) {
03185             type = get_token(fp, token, MAXTOKEN);
03186             if (type != LEFTBRACKET) {
03187                 print_error("Expected \"{\"", token, type);
03188                 goto skip;
03189             }
03190             do {
03191                 type = get_token(fp, token, MAXTOKEN);
03192                 if (type != LABEL) {
03193                     print_error("Bad group name", token, type);
03194                     goto skip;
03195                 }
03196                 if (!compliance_lookup(token, modid))
03197                     print_error("Unknown group", token, type);
03198                 type = get_token(fp, token, MAXTOKEN);
03199             } while (type == COMMA);
03200             if (type != RIGHTBRACKET) {
03201                 print_error("Expected \"}\"", token, type);
03202                 goto skip;
03203             }
03204             type = get_token(fp, token, MAXTOKEN);
03205         }
03206         while (type == GROUP || type == OBJECT) {
03207             if (type == GROUP) {
03208                 type = get_token(fp, token, MAXTOKEN);
03209                 if (type != LABEL) {
03210                     print_error("Bad group name", token, type);
03211                     goto skip;
03212                 }
03213                 if (!compliance_lookup(token, modid))
03214                     print_error("Unknown group", token, type);
03215                 type = get_token(fp, token, MAXTOKEN);
03216             } else {
03217                 type = get_token(fp, token, MAXTOKEN);
03218                 if (type != LABEL) {
03219                     print_error("Bad object name", token, type);
03220                     goto skip;
03221                 }
03222                 if (!compliance_lookup(token, modid))
03223                     print_error("Unknown group", token, type);
03224                 type = get_token(fp, token, MAXTOKEN);
03225                 if (type == SYNTAX)
03226                     type = eat_syntax(fp, token, MAXTOKEN);
03227                 if (type == WRSYNTAX)
03228                     type = eat_syntax(fp, token, MAXTOKEN);
03229                 if (type == MINACCESS) {
03230                     type = get_token(fp, token, MAXTOKEN);
03231                     if (type != NOACCESS && type != ACCNOTIFY
03232                         && type != READONLY && type != WRITEONLY
03233                         && type != READCREATE && type != READWRITE) {
03234                         print_error("Bad MIN-ACCESS spec", token, type);
03235                         goto skip;
03236                     }
03237                     type = get_token(fp, token, MAXTOKEN);
03238                 }
03239             }
03240             if (type != DESCRIPTION) {
03241                 print_error("Expected DESCRIPTION", token, type);
03242                 goto skip;
03243             }
03244             type = get_token(fp, token, MAXTOKEN);
03245             if (type != QUOTESTRING) {
03246                 print_error("Bad DESCRIPTION", token, type);
03247                 goto skip;
03248             }
03249             type = get_token(fp, token, MAXTOKEN);
03250         }
03251     }
03252   skip:
03253     while (type != EQUALS && type != ENDOFFILE)
03254         type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
03255 
03256     return merge_parse_objectid(np, fp, name);
03257 }
03258 
03259 
03260 /*
03261  * Parses a capabilities macro
03262  * Returns 0 on error.
03263  */
03264 static struct node *
03265 parse_capabilities(FILE * fp, char *name)
03266 {
03267     int             type;
03268     char            token[MAXTOKEN];
03269     char            quoted_string_buffer[MAXQUOTESTR];
03270     struct node    *np;
03271 
03272     np = alloc_node(current_module);
03273     if (np == NULL)
03274         return (NULL);
03275     type = get_token(fp, token, MAXTOKEN);
03276     if (type != PRODREL) {
03277         print_error("Expected PRODUCT-RELEASE", token, type);
03278         goto skip;
03279     }
03280     type = get_token(fp, token, MAXTOKEN);
03281     if (type != QUOTESTRING) {
03282         print_error("Expected STRING after PRODUCT-RELEASE", token, type);
03283         goto skip;
03284     }
03285     type = get_token(fp, token, MAXTOKEN);
03286     if (type != STATUS) {
03287         print_error("Expected STATUS", token, type);
03288         goto skip;
03289     }
03290     type = get_token(fp, token, MAXTOKEN);
03291     if (type != CURRENT && type != OBSOLETE) {
03292         print_error("STATUS should be current or obsolete", token, type);
03293         goto skip;
03294     }
03295     type = get_token(fp, token, MAXTOKEN);
03296     if (type != DESCRIPTION) {
03297         print_error("Expected DESCRIPTION", token, type);
03298         goto skip;
03299     }
03300     type = get_token(fp, quoted_string_buffer, MAXTOKEN);
03301     if (type != QUOTESTRING) {
03302         print_error("Bad DESCRIPTION", quoted_string_buffer, type);
03303         goto skip;
03304     }
03305     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
03306                                NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
03307         np->description = strdup(quoted_string_buffer);
03308     }
03309     type = get_token(fp, token, MAXTOKEN);
03310     if (type == REFERENCE) {
03311         type = get_token(fp, quoted_string_buffer, MAXTOKEN);
03312         if (type != QUOTESTRING) {
03313             print_error("Bad REFERENCE", quoted_string_buffer, type);
03314             goto skip;
03315         }
03316         np->reference = strdup(quoted_string_buffer);
03317         type = get_token(fp, token, type);
03318     }
03319     while (type == SUPPORTS) {
03320         int             modid;
03321         struct tree    *tp;
03322 
03323         type = get_token(fp, token, MAXTOKEN);
03324         if (type != LABEL) {
03325             print_error("Bad module name", token, type);
03326             goto skip;
03327         }
03328         modid = read_module_internal(token);
03329         if (modid != MODULE_LOADED_OK && modid != MODULE_ALREADY_LOADED) {
03330             print_error("Module not found", token, type);
03331             goto skip;
03332         }
03333         modid = which_module(token);
03334         type = get_token(fp, token, MAXTOKEN);
03335         if (type != INCLUDES) {
03336             print_error("Expected INCLUDES", token, type);
03337             goto skip;
03338         }
03339         type = get_token(fp, token, MAXTOKEN);
03340         if (type != LEFTBRACKET) {
03341             print_error("Expected \"{\"", token, type);
03342             goto skip;
03343         }
03344         do {
03345             type = get_token(fp, token, MAXTOKEN);
03346             if (type != LABEL) {
03347                 print_error("Expected group name", token, type);
03348                 goto skip;
03349             }
03350             tp = find_tree_node(token, modid);
03351             if (!tp)
03352                 print_error("Group not found in module", token, type);
03353             type = get_token(fp, token, MAXTOKEN);
03354         } while (type == COMMA);
03355         if (type != RIGHTBRACKET) {
03356             print_error("Expected \"}\" after group list", token, type);
03357             goto skip;
03358         }
03359         type = get_token(fp, token, MAXTOKEN);
03360         while (type == VARIATION) {
03361             type = get_token(fp, token, MAXTOKEN);
03362             if (type != LABEL) {
03363                 print_error("Bad object name", token, type);
03364                 goto skip;
03365             }
03366             tp = find_tree_node(token, modid);
03367             if (!tp)
03368                 print_error("Object not found in module", token, type);
03369             type = get_token(fp, token, MAXTOKEN);
03370             if (type == SYNTAX) {
03371                 type = eat_syntax(fp, token, MAXTOKEN);
03372             }
03373             if (type == WRSYNTAX) {
03374                 type = eat_syntax(fp, token, MAXTOKEN);
03375             }
03376             if (type == ACCESS) {
03377                 type = get_token(fp, token, MAXTOKEN);
03378                 if (type != ACCNOTIFY && type != READONLY
03379                     && type != READWRITE && type != READCREATE
03380                     && type != WRITEONLY && type != NOTIMPL) {
03381                     print_error("Bad ACCESS", token, type);
03382                     goto skip;
03383                 }
03384                 type = get_token(fp, token, MAXTOKEN);
03385             }
03386             if (type == CREATEREQ) {
03387                 type = get_token(fp, token, MAXTOKEN);
03388                 if (type != LEFTBRACKET) {
03389                     print_error("Expected \"{\"", token, type);
03390                     goto skip;
03391                 }
03392                 do {
03393                     type = get_token(fp, token, MAXTOKEN);
03394                     if (type != LABEL) {
03395                         print_error("Bad object name in list", token,
03396                                     type);
03397                         goto skip;
03398                     }
03399                     type = get_token(fp, token, MAXTOKEN);
03400                 } while (type == COMMA);
03401                 if (type != RIGHTBRACKET) {
03402                     print_error("Expected \"}\" after list", token, type);
03403                     goto skip;
03404                 }
03405                 type = get_token(fp, token, MAXTOKEN);
03406             }
03407             if (type == DEFVAL) {
03408                 int             level = 1;
03409                 type = get_token(fp, token, MAXTOKEN);
03410                 if (type != LEFTBRACKET) {
03411                     print_error("Expected \"{\" after DEFVAL", token,
03412                                 type);
03413                     goto skip;
03414                 }
03415                 do {
03416                     type = get_token(fp, token, MAXTOKEN);
03417                     if (type == LEFTBRACKET)
03418                         level++;
03419                     else if (type == RIGHTBRACKET)
03420                         level--;
03421                 } while (type != RIGHTBRACKET && type != ENDOFFILE
03422                          && level != 0);
03423                 if (type != RIGHTBRACKET) {
03424                     print_error("Missing \"}\" after DEFVAL", token, type);
03425                     goto skip;
03426                 }
03427                 type = get_token(fp, token, MAXTOKEN);
03428             }
03429             if (type != DESCRIPTION) {
03430                 print_error("Expected DESCRIPTION", token, type);
03431                 goto skip;
03432             }
03433             type = get_token(fp, quoted_string_buffer, MAXTOKEN);
03434             if (type != QUOTESTRING) {
03435                 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
03436                 goto skip;
03437             }
03438             type = get_token(fp, token, MAXTOKEN);
03439         }
03440     }
03441     if (type != EQUALS)
03442         print_error("Expected \"::=\"", token, type);
03443   skip:
03444     while (type != EQUALS && type != ENDOFFILE) {
03445         type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
03446     }
03447     return merge_parse_objectid(np, fp, name);
03448 }
03449 
03450 /*
03451  * Parses a module identity macro
03452  * Returns 0 on error.
03453  */
03454 static void
03455 check_utc(const char *utc)
03456 {
03457     int             len, year, month, day, hour, minute;
03458 
03459     len = strlen(utc);
03460     if (utc[len - 1] != 'Z' && utc[len - 1] != 'z') {
03461         print_error("Timestamp should end with Z", utc, QUOTESTRING);
03462         return;
03463     }
03464     if (len == 11) {
03465         len =
03466             sscanf(utc, "%2d%2d%2d%2d%2dZ", &year, &month, &day, &hour,
03467                    &minute);
03468         year += 1900;
03469     } else if (len == 13)
03470         len =
03471             sscanf(utc, "%4d%2d%2d%2d%2dZ", &year, &month, &day, &hour,
03472                    &minute);
03473     else {
03474         print_error("Bad timestamp format (11 or 13 characters)",
03475                     utc, QUOTESTRING);
03476         return;
03477     }
03478     if (len != 5) {
03479         print_error("Bad timestamp format", utc, QUOTESTRING);
03480         return;
03481     }
03482     if (month < 1 || month > 12)
03483         print_error("Bad month in timestamp", utc, QUOTESTRING);
03484     if (day < 1 || day > 31)
03485         print_error("Bad day in timestamp", utc, QUOTESTRING);
03486     if (hour < 0 || hour > 23)
03487         print_error("Bad hour in timestamp", utc, QUOTESTRING);
03488     if (minute < 0 || minute > 59)
03489         print_error("Bad minute in timestamp", utc, QUOTESTRING);
03490 }
03491 
03492 static struct node *
03493 parse_moduleIdentity(FILE * fp, char *name)
03494 {
03495     register int    type;
03496     char            token[MAXTOKEN];
03497     char            quoted_string_buffer[MAXQUOTESTR];
03498     register struct node *np;
03499 
03500     np = alloc_node(current_module);
03501     if (np == NULL)
03502         return (NULL);
03503     type = get_token(fp, token, MAXTOKEN);
03504     if (type != LASTUPDATED) {
03505         print_error("Expected LAST-UPDATED", token, type);
03506         goto skip;
03507     }
03508     type = get_token(fp, token, MAXTOKEN);
03509     if (type != QUOTESTRING) {
03510         print_error("Need STRING for LAST-UPDATED", token, type);
03511         goto skip;
03512     }
03513     check_utc(token);
03514     type = get_token(fp, token, MAXTOKEN);
03515     if (type != ORGANIZATION) {
03516         print_error("Expected ORGANIZATION", token, type);
03517         goto skip;
03518     }
03519     type = get_token(fp, token, MAXTOKEN);
03520     if (type != QUOTESTRING) {
03521         print_error("Bad ORGANIZATION", token, type);
03522         goto skip;
03523     }
03524     type = get_token(fp, token, MAXTOKEN);
03525     if (type != CONTACTINFO) {
03526         print_error("Expected CONTACT-INFO", token, type);
03527         goto skip;
03528     }
03529     type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
03530     if (type != QUOTESTRING) {
03531         print_error("Bad CONTACT-INFO", quoted_string_buffer, type);
03532         goto skip;
03533     }
03534     type = get_token(fp, token, MAXTOKEN);
03535     if (type != DESCRIPTION) {
03536         print_error("Expected DESCRIPTION", token, type);
03537         goto skip;
03538     }
03539     type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
03540     if (type != QUOTESTRING) {
03541         print_error("Bad DESCRIPTION", quoted_string_buffer, type);
03542         goto skip;
03543     }
03544     if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
03545                                NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
03546         np->description = strdup(quoted_string_buffer);
03547     }
03548     type = get_token(fp, token, MAXTOKEN);
03549     while (type == REVISION) {
03550         type = get_token(fp, token, MAXTOKEN);
03551         if (type != QUOTESTRING) {
03552             print_error("Bad REVISION", token, type);
03553             goto skip;
03554         }
03555         check_utc(token);
03556         type = get_token(fp, token, MAXTOKEN);
03557         if (type != DESCRIPTION) {
03558             print_error("Expected DESCRIPTION", token, type);
03559             goto skip;
03560         }
03561         type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
03562         if (type != QUOTESTRING) {
03563             print_error("Bad DESCRIPTION", quoted_string_buffer, type);
03564             goto skip;
03565         }
03566         type = get_token(fp, token, MAXTOKEN);
03567     }
03568     if (type != EQUALS)
03569         print_error("Expected \"::=\"", token, type);
03570   skip:
03571     while (type != EQUALS && type != ENDOFFILE) {
03572         type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
03573     }
03574     return merge_parse_objectid(np, fp, name);
03575 }
03576 
03577 
03578 /*
03579  * Parses a MACRO definition
03580  * Expect BEGIN, discard everything to end.
03581  * Returns 0 on error.
03582  */
03583 static struct node *
03584 parse_macro(FILE * fp, char *name)
03585 {
03586     register int    type;
03587     char            token[MAXTOKEN];
03588     struct node    *np;
03589     int             iLine = mibLine;
03590 
03591     np = alloc_node(current_module);
03592     if (np == NULL)
03593         return (NULL);
03594     type = get_token(fp, token, sizeof(token));
03595     while (type != EQUALS && type != ENDOFFILE) {
03596         type = get_token(fp, token, sizeof(token));
03597     }
03598     if (type != EQUALS) {
03599         if (np)
03600             free_node(np);
03601         return NULL;
03602     }
03603     while (type != BEGIN && type != ENDOFFILE) {
03604         type = get_token(fp, token, sizeof(token));
03605     }
03606     if (type != BEGIN) {
03607         if (np)
03608             free_node(np);
03609         return NULL;
03610     }
03611     while (type != END && type != ENDOFFILE) {
03612         type = get_token(fp, token, sizeof(token));
03613     }
03614     if (type != END) {
03615         if (np)
03616             free_node(np);
03617         return NULL;
03618     }
03619 
03620     if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
03621                            NETSNMP_DS_LIB_MIB_WARNINGS)) {
03622         snmp_log(LOG_WARNING,
03623                  "%s MACRO (lines %d..%d parsed and ignored).\n", name,
03624                  iLine, mibLine);
03625     }
03626 
03627     return np;
03628 }
03629 
03630 /*
03631  * Parses a module import clause
03632  *   loading any modules referenced
03633  */
03634 static void
03635 parse_imports(FILE * fp)
03636 {
03637     register int    type;
03638     char            token[MAXTOKEN];
03639     char            modbuf[256];
03640 #define MAX_IMPORTS     256
03641     struct module_import import_list[MAX_IMPORTS];
03642     int             this_module;
03643     struct module  *mp;
03644 
03645     int             import_count = 0;   /* Total number of imported descriptors */
03646     int             i = 0, old_i;       /* index of first import from each module */
03647 
03648     type = get_token(fp, token, MAXTOKEN);
03649 
03650     /*
03651      * Parse the IMPORTS clause
03652      */
03653     while (type != SEMI && type != ENDOFFILE) {
03654         if (type == LABEL) {
03655             if (import_count == MAX_IMPORTS) {
03656                 print_error("Too many imported symbols", token, type);
03657                 do {
03658                     type = get_token(fp, token, MAXTOKEN);
03659                 } while (type != SEMI && type != ENDOFFILE);
03660                 return;
03661             }
03662             import_list[import_count++].label = strdup(token);
03663         } else if (type == FROM) {
03664             type = get_token(fp, token, MAXTOKEN);
03665             if (import_count == i) {    /* All imports are handled internally */
03666                 type = get_token(fp, token, MAXTOKEN);
03667                 continue;
03668             }
03669             this_module = which_module(token);
03670 
03671             for (old_i = i; i < import_count; ++i)
03672                 import_list[i].modid = this_module;
03673 
03674             /*
03675              * Recursively read any pre-requisite modules
03676              */
03677             if (read_module_internal(token) == MODULE_NOT_FOUND) {
03678                 int found = 0;
03679                 for (; old_i < import_count; ++old_i) {
03680                     found += read_import_replacements(token, &import_list[old_i]);
03681                 }
03682                 if (!found)
03683                     print_module_not_found(token);
03684             }
03685         }
03686         type = get_token(fp, token, MAXTOKEN);
03687     }
03688 
03689     /*
03690      * Save the import information
03691      *   in the global module table
03692      */
03693     for (mp = module_head; mp; mp = mp->next)
03694         if (mp->modid == current_module) {
03695             if (import_count == 0)
03696                 return;
03697             if (mp->imports && (mp->imports != root_imports)) {
03698                 /*
03699                  * this can happen if all modules are in one source file. 
03700                  */
03701                 for (i = 0; i < mp->no_imports; ++i) {
03702                     DEBUGMSGTL(("parse-mibs",
03703                                 "#### freeing Module %d '%s' %d\n",
03704                                 mp->modid, mp->imports[i].label,
03705                                 mp->imports[i].modid));
03706                     free((char *) mp->imports[i].label);
03707                 }
03708                 free((char *) mp->imports);
03709             }
03710             mp->imports = (struct module_import *)
03711                 calloc(import_count, sizeof(struct module_import));
03712             if (mp->imports == NULL)
03713                 return;
03714             for (i = 0; i < import_count; ++i) {
03715                 mp->imports[i].label = import_list[i].label;
03716                 mp->imports[i].modid = import_list[i].modid;
03717                 DEBUGMSGTL(("parse-mibs",
03718                             "#### adding Module %d '%s' %d\n", mp->modid,
03719                             mp->imports[i].label, mp->imports[i].modid));
03720             }
03721             mp->no_imports = import_count;
03722             return;
03723         }
03724 
03725     /*
03726      * Shouldn't get this far
03727      */
03728     print_module_not_found(module_name(current_module, modbuf));
03729     return;
03730 }
03731 
03732 
03733 
03734 /*
03735  * MIB module handling routines
03736  */
03737 
03738 static void
03739 dump_module_list(void)
03740 {
03741     struct module  *mp = module_head;
03742 
03743     DEBUGMSGTL(("parse-mibs", "Module list:\n"));
03744     while (mp) {
03745         DEBUGMSGTL(("parse-mibs", "  %s %d %s %d\n", mp->name, mp->modid,
03746                     mp->file, mp->no_imports));
03747         mp = mp->next;
03748     }
03749 }
03750 
03751 int
03752 which_module(const char *name)
03753 {
03754     struct module  *mp;
03755 
03756     for (mp = module_head; mp; mp = mp->next)
03757         if (!label_compare(mp->name, name))
03758             return (mp->modid);
03759 
03760     DEBUGMSGTL(("parse-mibs", "Module %s not found\n", name));
03761     return (-1);
03762 }
03763 
03764 /*
03765  * module_name - copy module name to user buffer, return ptr to same.
03766  */
03767 char           *
03768 module_name(int modid, char *cp)
03769 {
03770     struct module  *mp;
03771 
03772     for (mp = module_head; mp; mp = mp->next)
03773         if (mp->modid == modid) {
03774             strcpy(cp, mp->name);
03775             return (cp);
03776         }
03777 
03778     if (modid != -1) DEBUGMSGTL(("parse-mibs", "Module %d not found\n", modid));
03779     sprintf(cp, "#%d", modid);
03780     return (cp);
03781 }
03782 
03783 /*
03784  *  Backwards compatability
03785  *  Read newer modules that replace the one specified:-
03786  *      either all of them (read_module_replacements),
03787  *      or those relating to a specified identifier (read_import_replacements)
03788  *      plus an interface to add new replacement requirements
03789  */
03790 netsnmp_feature_child_of(parse_add_module_replacement, netsnmp_unused)
03791 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_ADD_MODULE_REPLACEMENT
03792 void
03793 add_module_replacement(const char *old_module,
03794                        const char *new_module_name,
03795                        const char *tag, int len)
03796 {
03797     struct module_compatability *mcp;
03798 
03799     mcp = (struct module_compatability *)
03800         calloc(1, sizeof(struct module_compatability));
03801     if (mcp == NULL)
03802         return;
03803 
03804     mcp->old_module = strdup(old_module);
03805     mcp->new_module = strdup(new_module_name);
03806     if (tag)
03807         mcp->tag = strdup(tag);
03808     mcp->tag_len = len;
03809 
03810     mcp->next = module_map_head;
03811     module_map_head = mcp;
03812 }
03813 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_ADD_MODULE_REPLACEMENT */
03814 
03815 static int
03816 read_module_replacements(const char *name)
03817 {
03818     struct module_compatability *mcp;
03819 
03820     for (mcp = module_map_head; mcp; mcp = mcp->next) {
03821         if (!label_compare(mcp->old_module, name)) {
03822             if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
03823                                    NETSNMP_DS_LIB_MIB_WARNINGS)) {
03824                 snmp_log(LOG_WARNING,
03825                          "Loading replacement module %s for %s (%s)\n",
03826                          mcp->new_module, name, File);
03827             }
03828             (void) netsnmp_read_module(mcp->new_module);
03829             return 1;
03830         }
03831     }
03832     return 0;
03833 }
03834 
03835 static int
03836 read_import_replacements(const char *old_module_name,
03837                          struct module_import *identifier)
03838 {
03839     struct module_compatability *mcp;
03840 
03841     /*
03842      * Look for matches first
03843      */
03844     for (mcp = module_map_head; mcp; mcp = mcp->next) {
03845         if (!label_compare(mcp->old_module, old_module_name)) {
03846 
03847             if (                /* exact match */
03848                    (mcp->tag_len == 0 &&
03849                     (mcp->tag == NULL ||
03850                      !label_compare(mcp->tag, identifier->label))) ||
03851                    /*
03852                     * prefix match 
03853                     */
03854                    (mcp->tag_len != 0 &&
03855                     !strncmp(mcp->tag, identifier->label, mcp->tag_len))
03856                 ) {
03857 
03858                 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
03859                                        NETSNMP_DS_LIB_MIB_WARNINGS)) {
03860                     snmp_log(LOG_WARNING,
03861                              "Importing %s from replacement module %s instead of %s (%s)\n",
03862                              identifier->label, mcp->new_module,
03863                              old_module_name, File);
03864                 }
03865                 (void) netsnmp_read_module(mcp->new_module);
03866                 identifier->modid = which_module(mcp->new_module);
03867                 return 1;         /* finished! */
03868             }
03869         }
03870     }
03871 
03872     /*
03873      * If no exact match, load everything relevant
03874      */
03875     return read_module_replacements(old_module_name);
03876 }
03877 
03878 
03879 /*
03880  *  Read in the named module
03881  *      Returns the root of the whole tree
03882  *      (by analogy with 'read_mib')
03883  */
03884 static int
03885 read_module_internal(const char *name)
03886 {
03887     struct module  *mp;
03888     FILE           *fp;
03889     struct node    *np;
03890 
03891     netsnmp_init_mib_internals();
03892 
03893     for (mp = module_head; mp; mp = mp->next)
03894         if (!label_compare(mp->name, name)) {
03895             const char     *oldFile = File;
03896             int             oldLine = mibLine;
03897             int             oldModule = current_module;
03898 
03899             if (mp->no_imports != -1) {
03900                 DEBUGMSGTL(("parse-mibs", "Module %s already loaded\n",
03901                             name));
03902                 return MODULE_ALREADY_LOADED;
03903             }
03904             if ((fp = fopen(mp->file, "r")) == NULL) {
03905                 snmp_log_perror(mp->file);
03906                 return MODULE_LOAD_FAILED;
03907             }
03908             mp->no_imports = 0; /* Note that we've read the file */
03909             File = mp->file;
03910             mibLine = 1;
03911             current_module = mp->modid;
03912             /*
03913              * Parse the file
03914              */
03915             np = parse(fp, NULL);
03916             fclose(fp);
03917             File = oldFile;
03918             mibLine = oldLine;
03919             current_module = oldModule;
03920             if (np != NULL)
03921                 return MODULE_LOADED_OK;
03922             else if (gMibError == MODULE_SYNTAX_ERROR) 
03923                 return MODULE_SYNTAX_ERROR;
03924         }
03925 
03926     return MODULE_NOT_FOUND;
03927 }
03928 
03929 void
03930 adopt_orphans(void)
03931 {
03932     struct node    *np, *onp;
03933     struct tree    *tp;
03934     int             i, adopted = 1;
03935 
03936     if (!orphan_nodes)
03937         return;
03938     init_node_hash(orphan_nodes);
03939     orphan_nodes = NULL;
03940 
03941     while (adopted) {
03942         adopted = 0;
03943         for (i = 0; i < NHASHSIZE; i++)
03944             if (nbuckets[i]) {
03945                 for (np = nbuckets[i]; np != NULL; np = np->next) {
03946                     tp = find_tree_node(np->parent, -1);
03947                     if (tp) {
03948                         do_subtree(tp, &np);
03949                         adopted = 1;
03950                         /*
03951                          * if do_subtree adopted the entire bucket, stop
03952                          */
03953                         if(NULL == nbuckets[i])
03954                             break;
03955 
03956                         /*
03957                          * do_subtree may modify nbuckets, and if np
03958                          * was adopted, np->next probably isn't an orphan
03959                          * anymore. if np is still in the bucket (do_subtree
03960                          * didn't adopt it) keep on plugging. otherwise
03961                          * start over, at the top of the bucket.
03962                          */
03963                         for(onp = nbuckets[i]; onp; onp = onp->next)
03964                             if(onp == np)
03965                                 break;
03966                         if(NULL == onp) { /* not in the list */
03967                             np = nbuckets[i]; /* start over */
03968                         }
03969                     }
03970                 }
03971             }
03972     }
03973 
03974     /*
03975      * Report on outstanding orphans
03976      *    and link them back into the orphan list
03977      */
03978     for (i = 0; i < NHASHSIZE; i++)
03979         if (nbuckets[i]) {
03980             if (orphan_nodes)
03981                 onp = np->next = nbuckets[i];
03982             else
03983                 onp = orphan_nodes = nbuckets[i];
03984             nbuckets[i] = NULL;
03985             while (onp) {
03986                 char            modbuf[256];
03987                 snmp_log(LOG_WARNING,
03988                          "Cannot adopt OID in %s: %s ::= { %s %ld }\n",
03989                          module_name(onp->modid, modbuf),
03990                          (onp->label ? onp->label : "<no label>"),
03991                          (onp->parent ? onp->parent : "<no parent>"),
03992                          onp->subid);
03993 
03994                 np = onp;
03995                 onp = onp->next;
03996             }
03997         }
03998 }
03999 
04000 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS
04001 struct tree    *
04002 read_module(const char *name)
04003 {
04004     return netsnmp_read_module(name);
04005 }
04006 #endif
04007 
04008 struct tree    *
04009 netsnmp_read_module(const char *name)
04010 {
04011     int status = 0;
04012     status = read_module_internal(name);
04013 
04014     if (status == MODULE_NOT_FOUND) {
04015         if (!read_module_replacements(name))
04016             print_module_not_found(name);
04017     } else if (status == MODULE_SYNTAX_ERROR) {
04018         gMibError = 0;
04019         gLoop = 1;
04020 
04021         strncat(gMibNames, " ", sizeof(gMibNames) - strlen(gMibNames) - 1);
04022         strncat(gMibNames, name, sizeof(gMibNames) - strlen(gMibNames) - 1);
04023     }
04024 
04025     return tree_head;
04026 }
04027 
04028 /*
04029  * Prototype definition 
04030  */
04031 void            unload_module_by_ID(int modID, struct tree *tree_top);
04032 
04033 void
04034 unload_module_by_ID(int modID, struct tree *tree_top)
04035 {
04036     struct tree    *tp, *next;
04037     int             i;
04038 
04039     for (tp = tree_top; tp; tp = next) {
04040         /*
04041          * Essentially, this is equivalent to the code fragment:
04042          *      if (tp->modID == modID)
04043          *        tp->number_modules--;
04044          * but handles one tree node being part of several modules,
04045          * and possible multiple copies of the same module ID.
04046          */
04047         int             nmod = tp->number_modules;
04048         if (nmod > 0) {         /* in some module */
04049             /*
04050              * Remove all copies of this module ID
04051              */
04052             int             cnt = 0, *pi1, *pi2 = tp->module_list;
04053             for (i = 0, pi1 = pi2; i < nmod; i++, pi2++) {
04054                 if (*pi2 == modID)
04055                     continue;
04056                 cnt++;
04057                 *pi1++ = *pi2;
04058             }
04059             if (nmod != cnt) {  /* in this module */
04060                 /*
04061                  * if ( (nmod - cnt) > 1)
04062                  * printf("Dup modid %d,  %d times, '%s'\n", tp->modid, (nmod-cnt), tp->label); fflush(stdout); ?* XXDEBUG 
04063                  */
04064                 tp->number_modules = cnt;
04065                 switch (cnt) {
04066                 case 0:
04067                     tp->module_list[0] = -1;    /* Mark unused, and FALL THROUGH */
04068 
04069                 case 1:        /* save the remaining module */
04070                     if (&(tp->modid) != tp->module_list) {
04071                         tp->modid = tp->module_list[0];
04072                         free(tp->module_list);
04073                         tp->module_list = &(tp->modid);
04074                     }
04075                     break;
04076 
04077                 default:
04078                     break;
04079                 }
04080             }                   /* if tree node is in this module */
04081         }
04082         /*
04083          * if tree node is in some module 
04084          */
04085         next = tp->next_peer;
04086 
04087 
04088         /*
04089          *  OK - that's dealt with *this* node.
04090          *    Now let's look at the children.
04091          *    (Isn't recursion wonderful!)
04092          */
04093         if (tp->child_list)
04094             unload_module_by_ID(modID, tp->child_list);
04095 
04096 
04097         if (tp->number_modules == 0) {
04098             /*
04099              * This node isn't needed any more (except perhaps
04100              * for the sake of the children) 
04101              */
04102             if (tp->child_list == NULL) {
04103                 unlink_tree(tp);
04104                 free_tree(tp);
04105             } else {
04106                 free_partial_tree(tp, TRUE);
04107             }
04108         }
04109     }
04110 }
04111 
04112 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS
04113 int
04114 unload_module(const char *name)
04115 {
04116     return netsnmp_unload_module(name);
04117 }
04118 #endif
04119 
04120 int
04121 netsnmp_unload_module(const char *name)
04122 {
04123     struct module  *mp;
04124     int             modID = -1;
04125 
04126     for (mp = module_head; mp; mp = mp->next)
04127         if (!label_compare(mp->name, name)) {
04128             modID = mp->modid;
04129             break;
04130         }
04131 
04132     if (modID == -1) {
04133         DEBUGMSGTL(("unload-mib", "Module %s not found to unload\n",
04134                     name));
04135         return MODULE_NOT_FOUND;
04136     }
04137     unload_module_by_ID(modID, tree_head);
04138     mp->no_imports = -1;        /* mark as unloaded */
04139     return MODULE_LOADED_OK;    /* Well, you know what I mean! */
04140 }
04141 
04142 /*
04143  * Clear module map, tree nodes, textual convention table.
04144  */
04145 void
04146 unload_all_mibs(void)
04147 {
04148     struct module  *mp;
04149     struct module_compatability *mcp;
04150     struct tc      *ptc;
04151     unsigned int    i;
04152 
04153     for (mcp = module_map_head; mcp; mcp = module_map_head) {
04154         if (mcp == module_map)
04155             break;
04156         module_map_head = mcp->next;
04157         if (mcp->tag) free(NETSNMP_REMOVE_CONST(char *, mcp->tag));
04158         free(NETSNMP_REMOVE_CONST(char *, mcp->old_module));
04159         free(NETSNMP_REMOVE_CONST(char *, mcp->new_module));
04160         free(mcp);
04161     }
04162 
04163     for (mp = module_head; mp; mp = module_head) {
04164         struct module_import *mi = mp->imports;
04165         if (mi) {
04166             for (i = 0; i < (unsigned int)mp->no_imports; ++i) {
04167                 SNMP_FREE((mi + i)->label);
04168             }
04169             mp->no_imports = 0;
04170             if (mi == root_imports)
04171                 memset(mi, 0, sizeof(*mi));
04172             else
04173                 free(mi);
04174         }
04175 
04176         unload_module_by_ID(mp->modid, tree_head);
04177         module_head = mp->next;
04178         free(mp->name);
04179         free(mp->file);
04180         free(mp);
04181     }
04182     unload_module_by_ID(-1, tree_head);
04183     /*
04184      * tree nodes are cleared 
04185      */
04186 
04187     for (i = 0, ptc = tclist; i < MAXTC; i++, ptc++) {
04188         if (ptc->type == 0)
04189             continue;
04190         free_enums(&ptc->enums);
04191         free_ranges(&ptc->ranges);
04192         free(ptc->descriptor);
04193         if (ptc->hint)
04194             free(ptc->hint);
04195     }
04196     memset(tclist, 0, MAXTC * sizeof(struct tc));
04197 
04198     memset(buckets, 0, sizeof(buckets));
04199     memset(nbuckets, 0, sizeof(nbuckets));
04200     memset(tbuckets, 0, sizeof(tbuckets));
04201 
04202     for (i = 0; i < sizeof(root_imports) / sizeof(root_imports[0]); i++) {
04203         SNMP_FREE(root_imports[i].label);
04204     }
04205 
04206     max_module = 0;
04207     current_module = 0;
04208     module_map_head = NULL;
04209     SNMP_FREE(last_err_module);
04210 }
04211 
04212 static void
04213 new_module(const char *name, const char *file)
04214 {
04215     struct module  *mp;
04216 
04217     for (mp = module_head; mp; mp = mp->next)
04218         if (!label_compare(mp->name, name)) {
04219             DEBUGMSGTL(("parse-mibs", "  Module %s already noted\n", name));
04220             /*
04221              * Not the same file 
04222              */
04223             if (label_compare(mp->file, file)) {
04224                 DEBUGMSGTL(("parse-mibs", "    %s is now in %s\n",
04225                             name, file));
04226                 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
04227                                        NETSNMP_DS_LIB_MIB_WARNINGS)) {
04228                     snmp_log(LOG_WARNING,
04229                              "Warning: Module %s was in %s now is %s\n",
04230                              name, mp->file, file);
04231                 }
04232 
04233                 /*
04234                  * Use the new one in preference 
04235                  */
04236                 free(mp->file);
04237                 mp->file = strdup(file);
04238             }
04239             return;
04240         }
04241 
04242     /*
04243      * Add this module to the list 
04244      */
04245     DEBUGMSGTL(("parse-mibs", "  Module %d %s is in %s\n", max_module,
04246                 name, file));
04247     mp = (struct module *) calloc(1, sizeof(struct module));
04248     if (mp == NULL)
04249         return;
04250     mp->name = strdup(name);
04251     mp->file = strdup(file);
04252     mp->imports = NULL;
04253     mp->no_imports = -1;        /* Not yet loaded */
04254     mp->modid = max_module;
04255     ++max_module;
04256 
04257     mp->next = module_head;     /* Or add to the *end* of the list? */
04258     module_head = mp;
04259 }
04260 
04261 
04262 static void
04263 scan_objlist(struct node *root, struct module *mp, struct objgroup *list, const char *error)
04264 {
04265     int             oLine = mibLine;
04266 
04267     while (list) {
04268         struct objgroup *gp = list;
04269         struct node    *np;
04270         list = list->next;
04271         np = root;
04272         while (np)
04273             if (label_compare(np->label, gp->name))
04274                 np = np->next;
04275             else
04276                 break;
04277         if (!np) {
04278             int i;
04279             struct module_import *mip;
04280             /* if not local, check if it was IMPORTed */
04281             for (i = 0, mip = mp->imports; i < mp->no_imports; i++, mip++)
04282                 if (strcmp(mip->label, gp->name) == 0)
04283                     break;
04284             if (i == mp->no_imports) {
04285                 mibLine = gp->line;
04286                 print_error(error, gp->name, QUOTESTRING);
04287             }
04288         }
04289         free(gp->name);
04290         free(gp);
04291     }
04292     mibLine = oLine;
04293 }
04294 
04295 /*
04296  * Parses a mib file and returns a linked list of nodes found in the file.
04297  * Returns NULL on error.
04298  */
04299 static struct node *
04300 parse(FILE * fp, struct node *root)
04301 {
04302 #ifdef TEST
04303     extern void     xmalloc_stats(FILE *);
04304 #endif
04305     char            token[MAXTOKEN];
04306     char            name[MAXTOKEN+1];
04307     int             type = LABEL;
04308     int             lasttype = LABEL;
04309 
04310 #define BETWEEN_MIBS          1
04311 #define IN_MIB                2
04312     int             state = BETWEEN_MIBS;
04313     struct node    *np, *nnp;
04314     struct objgroup *oldgroups = NULL, *oldobjects = NULL, *oldnotifs =
04315         NULL;
04316 
04317     DEBUGMSGTL(("parse-file", "Parsing file:  %s...\n", File));
04318 
04319     if (last_err_module)
04320         free(last_err_module);
04321     last_err_module = NULL;
04322 
04323     np = root;
04324     if (np != NULL) {
04325         /*
04326          * now find end of chain 
04327          */
04328         while (np->next)
04329             np = np->next;
04330     }
04331 
04332     while (type != ENDOFFILE) {
04333         if (lasttype == CONTINUE)
04334             lasttype = type;
04335         else
04336             type = lasttype = get_token(fp, token, MAXTOKEN);
04337 
04338         switch (type) {
04339         case END:
04340             if (state != IN_MIB) {
04341                 print_error("Error, END before start of MIB", NULL, type);
04342                 return NULL;
04343             } else {
04344                 struct module  *mp;
04345 #ifdef TEST
04346                 printf("\nNodes for Module %s:\n", name);
04347                 print_nodes(stdout, root);
04348 #endif
04349                 for (mp = module_head; mp; mp = mp->next)
04350                     if (mp->modid == current_module)
04351                         break;
04352                 scan_objlist(root, mp, objgroups, "Undefined OBJECT-GROUP");
04353                 scan_objlist(root, mp, objects, "Undefined OBJECT");
04354                 scan_objlist(root, mp, notifs, "Undefined NOTIFICATION");
04355                 objgroups = oldgroups;
04356                 objects = oldobjects;
04357                 notifs = oldnotifs;
04358                 do_linkup(mp, root);
04359                 np = root = NULL;
04360             }
04361             state = BETWEEN_MIBS;
04362 #ifdef TEST
04363             if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
04364                                    NETSNMP_DS_LIB_MIB_WARNINGS)) {
04365                 /* xmalloc_stats(stderr); */
04366             }
04367 #endif
04368             continue;
04369         case IMPORTS:
04370             parse_imports(fp);
04371             continue;
04372         case EXPORTS:
04373             while (type != SEMI && type != ENDOFFILE)
04374                 type = get_token(fp, token, MAXTOKEN);
04375             continue;
04376         case LABEL:
04377         case INTEGER:
04378         case INTEGER32:
04379         case UINTEGER32:
04380         case UNSIGNED32:
04381         case COUNTER:
04382         case COUNTER64:
04383         case GAUGE:
04384         case IPADDR:
04385         case NETADDR:
04386         case NSAPADDRESS:
04387         case OBJSYNTAX:
04388         case APPSYNTAX:
04389         case SIMPLESYNTAX:
04390         case OBJNAME:
04391         case NOTIFNAME:
04392         case KW_OPAQUE:
04393         case TIMETICKS:
04394             break;
04395         case ENDOFFILE:
04396             continue;
04397         default:
04398             strncpy(name, token, sizeof(name));
04399             name[sizeof(name)-1] = '\0';
04400             type = get_token(fp, token, MAXTOKEN);
04401             nnp = NULL;
04402             if (type == MACRO) {
04403                 nnp = parse_macro(fp, name);
04404                 if (nnp == NULL) {
04405                     print_error("Bad parse of MACRO", NULL, type);
04406                     /*
04407                      * return NULL;
04408                      */
04409                 }
04410                 free_node(nnp); /* IGNORE */
04411                 nnp = NULL;
04412             } else
04413                 print_error(name, "is a reserved word", lasttype);
04414             continue;           /* see if we can parse the rest of the file */
04415         }
04416         strncpy(name, token, sizeof(name));
04417         name[sizeof(name)-1] = '\0';
04418         type = get_token(fp, token, MAXTOKEN);
04419         nnp = NULL;
04420 
04421         /*
04422          * Handle obsolete method to assign an object identifier to a
04423          * module
04424          */
04425         if (lasttype == LABEL && type == LEFTBRACKET) {
04426             while (type != RIGHTBRACKET && type != ENDOFFILE)
04427                 type = get_token(fp, token, MAXTOKEN);
04428             if (type == ENDOFFILE) {
04429                 print_error("Expected \"}\"", token, type);
04430                 return NULL;
04431             }
04432             type = get_token(fp, token, MAXTOKEN);
04433         }
04434 
04435         switch (type) {
04436         case DEFINITIONS:
04437             if (state != BETWEEN_MIBS) {
04438                 print_error("Error, nested MIBS", NULL, type);
04439                 return NULL;
04440             }
04441             state = IN_MIB;
04442             current_module = which_module(name);
04443             oldgroups = objgroups;
04444             objgroups = NULL;
04445             oldobjects = objects;
04446             objects = NULL;
04447             oldnotifs = notifs;
04448             notifs = NULL;
04449             if (current_module == -1) {
04450                 new_module(name, File);
04451                 current_module = which_module(name);
04452             }
04453             DEBUGMSGTL(("parse-mibs", "Parsing MIB: %d %s\n",
04454                         current_module, name));
04455             while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE)
04456                 if (type == BEGIN)
04457                     break;
04458             break;
04459         case OBJTYPE:
04460             nnp = parse_objecttype(fp, name);
04461             if (nnp == NULL) {
04462                 print_error("Bad parse of OBJECT-TYPE", NULL, type);
04463                 return NULL;
04464             }
04465             break;
04466         case OBJGROUP:
04467             nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
04468             if (nnp == NULL) {
04469                 print_error("Bad parse of OBJECT-GROUP", NULL, type);
04470                 return NULL;
04471             }
04472             break;
04473         case NOTIFGROUP:
04474             nnp = parse_objectgroup(fp, name, NOTIFICATIONS, &notifs);
04475             if (nnp == NULL) {
04476                 print_error("Bad parse of NOTIFICATION-GROUP", NULL, type);
04477                 return NULL;
04478             }
04479             break;
04480         case TRAPTYPE:
04481             nnp = parse_trapDefinition(fp, name);
04482             if (nnp == NULL) {
04483                 print_error("Bad parse of TRAP-TYPE", NULL, type);
04484                 return NULL;
04485             }
04486             break;
04487         case NOTIFTYPE:
04488             nnp = parse_notificationDefinition(fp, name);
04489             if (nnp == NULL) {
04490                 print_error("Bad parse of NOTIFICATION-TYPE", NULL, type);
04491                 return NULL;
04492             }
04493             break;
04494         case COMPLIANCE:
04495             nnp = parse_compliance(fp, name);
04496             if (nnp == NULL) {
04497                 print_error("Bad parse of MODULE-COMPLIANCE", NULL, type);
04498                 return NULL;
04499             }
04500             break;
04501         case AGENTCAP:
04502             nnp = parse_capabilities(fp, name);
04503             if (nnp == NULL) {
04504                 print_error("Bad parse of AGENT-CAPABILITIES", NULL, type);
04505                 return NULL;
04506             }
04507             break;
04508         case MACRO:
04509             nnp = parse_macro(fp, name);
04510             if (nnp == NULL) {
04511                 print_error("Bad parse of MACRO", NULL, type);
04512                 /*
04513                  * return NULL;
04514                  */
04515             }
04516             free_node(nnp);     /* IGNORE */
04517             nnp = NULL;
04518             break;
04519         case MODULEIDENTITY:
04520             nnp = parse_moduleIdentity(fp, name);
04521             if (nnp == NULL) {
04522                 print_error("Bad parse of MODULE-IDENTITY", NULL, type);
04523                 return NULL;
04524             }
04525             break;
04526         case OBJIDENTITY:
04527             nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
04528             if (nnp == NULL) {
04529                 print_error("Bad parse of OBJECT-IDENTITY", NULL, type);
04530                 return NULL;
04531             }
04532             break;
04533         case OBJECT:
04534             type = get_token(fp, token, MAXTOKEN);
04535             if (type != IDENTIFIER) {
04536                 print_error("Expected IDENTIFIER", token, type);
04537                 return NULL;
04538             }
04539             type = get_token(fp, token, MAXTOKEN);
04540             if (type != EQUALS) {
04541                 print_error("Expected \"::=\"", token, type);
04542                 return NULL;
04543             }
04544             nnp = parse_objectid(fp, name);
04545             if (nnp == NULL) {
04546                 print_error("Bad parse of OBJECT IDENTIFIER", NULL, type);
04547                 return NULL;
04548             }
04549             break;
04550         case EQUALS:
04551             nnp = parse_asntype(fp, name, &type, token);
04552             lasttype = CONTINUE;
04553             break;
04554         case ENDOFFILE:
04555             break;
04556         default:
04557             print_error("Bad operator", token, type);
04558             return NULL;
04559         }
04560         if (nnp) {
04561             if (np)
04562                 np->next = nnp;
04563             else
04564                 np = root = nnp;
04565             while (np->next)
04566                 np = np->next;
04567             if (np->type == TYPE_OTHER)
04568                 np->type = type;
04569         }
04570     }
04571     DEBUGMSGTL(("parse-file", "End of file (%s)\n", File));
04572     return root;
04573 }
04574 
04575 /*
04576  * return zero if character is not a label character. 
04577  */
04578 static int
04579 is_labelchar(int ich)
04580 {
04581     if ((isalnum(ich)) || (ich == '-'))
04582         return 1;
04583     if (ich == '_' && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
04584                                              NETSNMP_DS_LIB_MIB_PARSE_LABEL)) {
04585         return 1;
04586     }
04587 
04588     return 0;
04589 }
04590 
04591 /*
04592  * Parses a token from the file.  The type of the token parsed is returned,
04593  * and the text is placed in the string pointed to by token.
04594  * Warning: this method may recurse.
04595  */
04596 static int
04597 get_token(FILE * fp, char *token, int maxtlen)
04598 {
04599     register int    ch, ch_next;
04600     register char  *cp = token;
04601     register int    hash = 0;
04602     register struct tok *tp;
04603     int             too_long = 0;
04604     enum { bdigits, xdigits, other } seenSymbols;
04605 
04606     /*
04607      * skip all white space 
04608      */
04609     do {
04610         ch = getc(fp);
04611         if (ch == '\n')
04612             mibLine++;
04613     }
04614     while (isspace(ch) && ch != EOF);
04615     *cp++ = ch;
04616     *cp = '\0';
04617     switch (ch) {
04618     case EOF:
04619         return ENDOFFILE;
04620     case '"':
04621         return parseQuoteString(fp, token, maxtlen);
04622     case '\'':                 /* binary or hex constant */
04623         seenSymbols = bdigits;
04624         while ((ch = getc(fp)) != EOF && ch != '\'') {
04625             switch (seenSymbols) {
04626             case bdigits:
04627                 if (ch == '0' || ch == '1')
04628                     break;
04629                 seenSymbols = xdigits;
04630             case xdigits:
04631                 if (isxdigit(ch))
04632                     break;
04633                 seenSymbols = other;
04634             case other:
04635                 break;
04636             }
04637             if (cp - token < maxtlen - 2)
04638                 *cp++ = ch;
04639         }
04640         if (ch == '\'') {
04641             unsigned long   val = 0;
04642             char           *run = token + 1;
04643             ch = getc(fp);
04644             switch (ch) {
04645             case EOF:
04646                 return ENDOFFILE;
04647             case 'b':
04648             case 'B':
04649                 if (seenSymbols > bdigits) {
04650                     *cp++ = '\'';
04651                     *cp = 0;
04652                     return LABEL;
04653                 }
04654                 while (run != cp)
04655                     val = val * 2 + *run++ - '0';
04656                 break;
04657             case 'h':
04658             case 'H':
04659                 if (seenSymbols > xdigits) {
04660                     *cp++ = '\'';
04661                     *cp = 0;
04662                     return LABEL;
04663                 }
04664                 while (run != cp) {
04665                     ch = *run++;
04666                     if ('0' <= ch && ch <= '9')
04667                         val = val * 16 + ch - '0';
04668                     else if ('a' <= ch && ch <= 'f')
04669                         val = val * 16 + ch - 'a' + 10;
04670                     else if ('A' <= ch && ch <= 'F')
04671                         val = val * 16 + ch - 'A' + 10;
04672                 }
04673                 break;
04674             default:
04675                 *cp++ = '\'';
04676                 *cp = 0;
04677                 return LABEL;
04678             }
04679             sprintf(token, "%ld", val);
04680             return NUMBER;
04681         } else
04682             return LABEL;
04683     case '(':
04684         return LEFTPAREN;
04685     case ')':
04686         return RIGHTPAREN;
04687     case '{':
04688         return LEFTBRACKET;
04689     case '}':
04690         return RIGHTBRACKET;
04691     case '[':
04692         return LEFTSQBRACK;
04693     case ']':
04694         return RIGHTSQBRACK;
04695     case ';':
04696         return SEMI;
04697     case ',':
04698         return COMMA;
04699     case '|':
04700         return BAR;
04701     case '.':
04702         ch_next = getc(fp);
04703         if (ch_next == '.')
04704             return RANGE;
04705         ungetc(ch_next, fp);
04706         return LABEL;
04707     case ':':
04708         ch_next = getc(fp);
04709         if (ch_next != ':') {
04710             ungetc(ch_next, fp);
04711             return LABEL;
04712         }
04713         ch_next = getc(fp);
04714         if (ch_next != '=') {
04715             ungetc(ch_next, fp);
04716             return LABEL;
04717         }
04718         return EQUALS;
04719     case '-':
04720         ch_next = getc(fp);
04721         if (ch_next == '-') {
04722             if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
04723                                        NETSNMP_DS_LIB_MIB_COMMENT_TERM)) {
04724                 /*
04725                  * Treat the rest of this line as a comment. 
04726                  */
04727                 while ((ch_next != EOF) && (ch_next != '\n'))
04728                     ch_next = getc(fp);
04729             } else {
04730                 /*
04731                  * Treat the rest of the line or until another '--' as a comment 
04732                  */
04733                 /*
04734                  * (this is the "technically" correct way to parse comments) 
04735                  */
04736                 ch = ' ';
04737                 ch_next = getc(fp);
04738                 while (ch_next != EOF && ch_next != '\n' &&
04739                        (ch != '-' || ch_next != '-')) {
04740                     ch = ch_next;
04741                     ch_next = getc(fp);
04742                 }
04743             }
04744             if (ch_next == EOF)
04745                 return ENDOFFILE;
04746             if (ch_next == '\n')
04747                 mibLine++;
04748             return get_token(fp, token, maxtlen);
04749         }
04750         ungetc(ch_next, fp);
04751     default:
04752         /*
04753          * Accumulate characters until end of token is found.  Then attempt to
04754          * match this token as a reserved word.  If a match is found, return the
04755          * type.  Else it is a label.
04756          */
04757         if (!is_labelchar(ch))
04758             return LABEL;
04759         hash += tolower(ch);
04760       more:
04761         while (is_labelchar(ch_next = getc(fp))) {
04762             hash += tolower(ch_next);
04763             if (cp - token < maxtlen - 1)
04764                 *cp++ = ch_next;
04765             else
04766                 too_long = 1;
04767         }
04768         ungetc(ch_next, fp);
04769         *cp = '\0';
04770 
04771         if (too_long)
04772             print_error("Warning: token too long", token, CONTINUE);
04773         for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
04774             if ((tp->hash == hash) && (!label_compare(tp->name, token)))
04775                 break;
04776         }
04777         if (tp) {
04778             if (tp->token != CONTINUE)
04779                 return (tp->token);
04780             while (isspace((ch_next = getc(fp))))
04781                 if (ch_next == '\n')
04782                     mibLine++;
04783             if (ch_next == EOF)
04784                 return ENDOFFILE;
04785             if (isalnum(ch_next)) {
04786                 *cp++ = ch_next;
04787                 hash += tolower(ch_next);
04788                 goto more;
04789             }
04790         }
04791         if (token[0] == '-' || isdigit((unsigned char)(token[0]))) {
04792             for (cp = token + 1; *cp; cp++)
04793                 if (!isdigit((unsigned char)(*cp)))
04794                     return LABEL;
04795             return NUMBER;
04796         }
04797         return LABEL;
04798     }
04799 }
04800 
04801 netsnmp_feature_child_of(parse_get_token, netsnmp_unused)
04802 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_GET_TOKEN
04803 int
04804 snmp_get_token(FILE * fp, char *token, int maxtlen)
04805 {
04806     return get_token(fp, token, maxtlen);
04807 }
04808 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_GET_TOKEN */
04809 
04810 int
04811 add_mibfile(const char* tmpstr, const char* d_name, FILE *ip )
04812 {
04813     FILE           *fp;
04814     char            token[MAXTOKEN], token2[MAXTOKEN];
04815 
04816     /*
04817      * which module is this 
04818      */
04819     if ((fp = fopen(tmpstr, "r")) == NULL) {
04820         snmp_log_perror(tmpstr);
04821         return 1;
04822     }
04823     DEBUGMSGTL(("parse-mibs", "Checking file: %s...\n",
04824                 tmpstr));
04825     mibLine = 1;
04826     File = tmpstr;
04827     get_token(fp, token, MAXTOKEN);
04828     /*
04829      * simple test for this being a MIB 
04830      */
04831     if (get_token(fp, token2, MAXTOKEN) == DEFINITIONS) {
04832         new_module(token, tmpstr);
04833         if (ip)
04834             fprintf(ip, "%s %s\n", token, d_name);
04835         fclose(fp);
04836         return 0;
04837     } else {
04838         fclose(fp);
04839         return 1;
04840     }
04841 }
04842 
04843 /* For Win32 platforms, the directory does not maintain a last modification
04844  * date that we can compare with the modification date of the .index file.
04845  * Therefore there is no way to know whether any .index file is valid.
04846  * This is the reason for the #if !(defined(WIN32) || defined(cygwin))
04847  * in the add_mibdir function
04848  */
04849 int
04850 add_mibdir(const char *dirname)
04851 {
04852     FILE           *ip;
04853     DIR            *dir, *dir2;
04854     const char     *oldFile = File;
04855     struct dirent  *file;
04856     char            tmpstr[300];
04857     int             count = 0;
04858     int             fname_len = 0;
04859 #if !(defined(WIN32) || defined(cygwin))
04860     char           *token;
04861     char space;
04862     char newline;
04863     struct stat     dir_stat, idx_stat;
04864     char            tmpstr1[300];
04865 #endif
04866 
04867     DEBUGMSGTL(("parse-mibs", "Scanning directory %s\n", dirname));
04868 #if !(defined(WIN32) || defined(cygwin))
04869     token = netsnmp_mibindex_lookup( dirname );
04870     if (token && stat(token, &idx_stat) == 0 && stat(dirname, &dir_stat) == 0) {
04871         if (dir_stat.st_mtime < idx_stat.st_mtime) {
04872             DEBUGMSGTL(("parse-mibs", "The index is good\n"));
04873             if ((ip = fopen(token, "r")) != NULL) {
04874                 fgets(tmpstr, sizeof(tmpstr), ip); /* Skip dir line */
04875                 while (fscanf(ip, "%127s%c%299s%c", token, &space, tmpstr,
04876                     &newline) == 4) {
04877 
04878                     /*
04879                      * If an overflow of the token or tmpstr buffers has been
04880                      * found log a message and break out of the while loop,
04881                      * thus the rest of the file tokens will be ignored.
04882                      */
04883                     if (space != ' ' || newline != '\n') {
04884                         snmp_log(LOG_ERR,
04885                             "add_mibdir: strings scanned in from %s/%s " \
04886                             "are too large.  count = %d\n ", dirname,
04887                             ".index", count);
04888                             break;
04889                     }
04890                    
04891                     snprintf(tmpstr1, sizeof(tmpstr1), "%s/%s", dirname, tmpstr);
04892                     tmpstr1[ sizeof(tmpstr1)-1 ] = 0;
04893                     new_module(token, tmpstr1);
04894                     count++;
04895                 }
04896                 fclose(ip);
04897                 return count;
04898             } else
04899                 DEBUGMSGTL(("parse-mibs", "Can't read index\n"));
04900         } else
04901             DEBUGMSGTL(("parse-mibs", "Index outdated\n"));
04902     } else
04903         DEBUGMSGTL(("parse-mibs", "No index\n"));
04904 #endif
04905 
04906     if ((dir = opendir(dirname))) {
04907         ip = netsnmp_mibindex_new( dirname );
04908         while ((file = readdir(dir))) {
04909             /*
04910              * Only parse file names that don't begin with a '.' 
04911              * Also skip files ending in '~', or starting/ending
04912              * with '#' which are typically editor backup files.
04913              */
04914             if (file->d_name != NULL) {
04915               fname_len = strlen( file->d_name );
04916               if (fname_len > 0 && file->d_name[0] != '.' 
04917                                 && file->d_name[0] != '#'
04918                                 && file->d_name[fname_len-1] != '#'
04919                                 && file->d_name[fname_len-1] != '~') {
04920                 snprintf(tmpstr, sizeof(tmpstr), "%s/%s", dirname, file->d_name);
04921                 tmpstr[ sizeof(tmpstr)-1 ] = 0;
04922                 if ((dir2 = opendir(tmpstr))) {
04923                     /*
04924                      * file is a directory, don't read it 
04925                      */
04926                     closedir(dir2);
04927                 } else {
04928                     if ( !add_mibfile( tmpstr, file->d_name, ip ))
04929                         count++;
04930                 }
04931               }
04932             }
04933         }
04934         File = oldFile;
04935         closedir(dir);
04936         if (ip)
04937             fclose(ip);
04938         return (count);
04939     }
04940     else
04941         DEBUGMSGTL(("parse-mibs","cannot open MIB directory %s\n", dirname));
04942 
04943     return (-1);
04944 }
04945 
04946 
04947 /*
04948  * Returns the root of the whole tree
04949  *   (for backwards compatability)
04950  */
04951 struct tree    *
04952 read_mib(const char *filename)
04953 {
04954     FILE           *fp;
04955     char            token[MAXTOKEN];
04956 
04957     fp = fopen(filename, "r");
04958     if (fp == NULL) {
04959         snmp_log_perror(filename);
04960         return NULL;
04961     }
04962     mibLine = 1;
04963     File = filename;
04964     DEBUGMSGTL(("parse-mibs", "Parsing file: %s...\n", filename));
04965     get_token(fp, token, MAXTOKEN);
04966     fclose(fp);
04967     new_module(token, filename);
04968     (void) netsnmp_read_module(token);
04969 
04970     return tree_head;
04971 }
04972 
04973 
04974 struct tree    *
04975 read_all_mibs(void)
04976 {
04977     struct module  *mp;
04978 
04979     for (mp = module_head; mp; mp = mp->next)
04980         if (mp->no_imports == -1)
04981             netsnmp_read_module(mp->name);
04982     adopt_orphans();
04983 
04984     /* If entered the syntax error loop in "read_module()" */
04985     if (gLoop == 1) {
04986         gLoop = 0;
04987         if (gpMibErrorString != NULL) {
04988             SNMP_FREE(gpMibErrorString);
04989         }
04990         gpMibErrorString = (char *) calloc(1, MAXQUOTESTR);
04991         if (gpMibErrorString == NULL) {
04992             snmp_log(LOG_CRIT, "failed to allocated memory for gpMibErrorString\n");
04993         } else {
04994             snprintf(gpMibErrorString, sizeof(gpMibErrorString)-1, "Error in parsing MIB module(s): %s ! Unable to load corresponding MIB(s)", gMibNames);
04995         }
04996     }
04997 
04998     /* Caller's responsibility to free this memory */
04999     tree_head->parseErrorString = gpMibErrorString;
05000         
05001     return tree_head;
05002 }
05003 
05004 
05005 #ifdef TEST
05006 int main(int argc, char *argv[])
05007 {
05008     int             i;
05009     struct tree    *tp;
05010     netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_WARNINGS, 2);
05011 
05012     netsnmp_init_mib();
05013 
05014     if (argc == 1)
05015         (void) read_all_mibs();
05016     else
05017         for (i = 1; i < argc; i++)
05018             read_mib(argv[i]);
05019 
05020     for (tp = tree_head; tp; tp = tp->next_peer)
05021         print_subtree(stdout, tp, 0);
05022     free_tree(tree_head);
05023 
05024     return 0;
05025 }
05026 #endif                          /* TEST */
05027 
05028 static int
05029 parseQuoteString(FILE * fp, char *token, int maxtlen)
05030 {
05031     register int    ch;
05032     int             count = 0;
05033     int             too_long = 0;
05034     char           *token_start = token;
05035 
05036     for (ch = getc(fp); ch != EOF; ch = getc(fp)) {
05037         if (ch == '\r')
05038             continue;
05039         if (ch == '\n') {
05040             mibLine++;
05041         } else if (ch == '"') {
05042             *token = '\0';
05043             if (too_long && netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
05044                                            NETSNMP_DS_LIB_MIB_WARNINGS) > 1) {
05045                 /*
05046                  * show short form for brevity sake 
05047                  */
05048                 char            ch_save = *(token_start + 50);
05049                 *(token_start + 50) = '\0';
05050                 print_error("Warning: string too long",
05051                             token_start, QUOTESTRING);
05052                 *(token_start + 50) = ch_save;
05053             }
05054             return QUOTESTRING;
05055         }
05056         /*
05057          * maximum description length check.  If greater, keep parsing
05058          * but truncate the string 
05059          */
05060         if (++count < maxtlen)
05061             *token++ = ch;
05062         else
05063             too_long = 1;
05064     }
05065 
05066     return 0;
05067 }
05068 
05069 /*
05070  * struct index_list *
05071  * getIndexes(FILE *fp):
05072  *   This routine parses a string like  { blah blah blah } and returns a
05073  *   list of the strings enclosed within it.
05074  *
05075  */
05076 static struct index_list *
05077 getIndexes(FILE * fp, struct index_list **retp)
05078 {
05079     int             type;
05080     char            token[MAXTOKEN];
05081     char            nextIsImplied = 0;
05082 
05083     struct index_list *mylist = NULL;
05084     struct index_list **mypp = &mylist;
05085 
05086     free_indexes(retp);
05087 
05088     type = get_token(fp, token, MAXTOKEN);
05089 
05090     if (type != LEFTBRACKET) {
05091         return NULL;
05092     }
05093 
05094     type = get_token(fp, token, MAXTOKEN);
05095     while (type != RIGHTBRACKET && type != ENDOFFILE) {
05096         if ((type == LABEL) || (type & SYNTAX_MASK)) {
05097             *mypp =
05098                 (struct index_list *) calloc(1, sizeof(struct index_list));
05099             if (*mypp) {
05100                 (*mypp)->ilabel = strdup(token);
05101                 (*mypp)->isimplied = nextIsImplied;
05102                 mypp = &(*mypp)->next;
05103                 nextIsImplied = 0;
05104             }
05105         } else if (type == IMPLIED) {
05106             nextIsImplied = 1;
05107         }
05108         type = get_token(fp, token, MAXTOKEN);
05109     }
05110 
05111     *retp = mylist;
05112     return mylist;
05113 }
05114 
05115 static struct varbind_list *
05116 getVarbinds(FILE * fp, struct varbind_list **retp)
05117 {
05118     int             type;
05119     char            token[MAXTOKEN];
05120 
05121     struct varbind_list *mylist = NULL;
05122     struct varbind_list **mypp = &mylist;
05123 
05124     free_varbinds(retp);
05125 
05126     type = get_token(fp, token, MAXTOKEN);
05127 
05128     if (type != LEFTBRACKET) {
05129         return NULL;
05130     }
05131 
05132     type = get_token(fp, token, MAXTOKEN);
05133     while (type != RIGHTBRACKET && type != ENDOFFILE) {
05134         if ((type == LABEL) || (type & SYNTAX_MASK)) {
05135             *mypp =
05136                 (struct varbind_list *) calloc(1,
05137                                                sizeof(struct
05138                                                       varbind_list));
05139             if (*mypp) {
05140                 (*mypp)->vblabel = strdup(token);
05141                 mypp = &(*mypp)->next;
05142             }
05143         }
05144         type = get_token(fp, token, MAXTOKEN);
05145     }
05146 
05147     *retp = mylist;
05148     return mylist;
05149 }
05150 
05151 static void
05152 free_indexes(struct index_list **spp)
05153 {
05154     if (spp && *spp) {
05155         struct index_list *pp, *npp;
05156 
05157         pp = *spp;
05158         *spp = NULL;
05159 
05160         while (pp) {
05161             npp = pp->next;
05162             if (pp->ilabel)
05163                 free(pp->ilabel);
05164             free(pp);
05165             pp = npp;
05166         }
05167     }
05168 }
05169 
05170 static void
05171 free_varbinds(struct varbind_list **spp)
05172 {
05173     if (spp && *spp) {
05174         struct varbind_list *pp, *npp;
05175 
05176         pp = *spp;
05177         *spp = NULL;
05178 
05179         while (pp) {
05180             npp = pp->next;
05181             if (pp->vblabel)
05182                 free(pp->vblabel);
05183             free(pp);
05184             pp = npp;
05185         }
05186     }
05187 }
05188 
05189 static void
05190 free_ranges(struct range_list **spp)
05191 {
05192     if (spp && *spp) {
05193         struct range_list *pp, *npp;
05194 
05195         pp = *spp;
05196         *spp = NULL;
05197 
05198         while (pp) {
05199             npp = pp->next;
05200             free(pp);
05201             pp = npp;
05202         }
05203     }
05204 }
05205 
05206 static void
05207 free_enums(struct enum_list **spp)
05208 {
05209     if (spp && *spp) {
05210         struct enum_list *pp, *npp;
05211 
05212         pp = *spp;
05213         *spp = NULL;
05214 
05215         while (pp) {
05216             npp = pp->next;
05217             if (pp->label)
05218                 free(pp->label);
05219             free(pp);
05220             pp = npp;
05221         }
05222     }
05223 }
05224 
05225 static struct enum_list *
05226 copy_enums(struct enum_list *sp)
05227 {
05228     struct enum_list *xp = NULL, **spp = &xp;
05229 
05230     while (sp) {
05231         *spp = (struct enum_list *) calloc(1, sizeof(struct enum_list));
05232         if (!*spp)
05233             break;
05234         (*spp)->label = strdup(sp->label);
05235         (*spp)->value = sp->value;
05236         spp = &(*spp)->next;
05237         sp = sp->next;
05238     }
05239     return (xp);
05240 }
05241 
05242 static struct range_list *
05243 copy_ranges(struct range_list *sp)
05244 {
05245     struct range_list *xp = NULL, **spp = &xp;
05246 
05247     while (sp) {
05248         *spp = (struct range_list *) calloc(1, sizeof(struct range_list));
05249         if (!*spp)
05250             break;
05251         (*spp)->low = sp->low;
05252         (*spp)->high = sp->high;
05253         spp = &(*spp)->next;
05254         sp = sp->next;
05255     }
05256     return (xp);
05257 }
05258 
05259 /*
05260  * This routine parses a string like  { blah blah blah } and returns OBJID if
05261  * it is well formed, and NULL if not.
05262  */
05263 static int
05264 tossObjectIdentifier(FILE * fp)
05265 {
05266     int             type;
05267     char            token[MAXTOKEN];
05268     int             bracketcount = 1;
05269 
05270     type = get_token(fp, token, MAXTOKEN);
05271 
05272     if (type != LEFTBRACKET)
05273         return 0;
05274     while ((type != RIGHTBRACKET || bracketcount > 0) && type != ENDOFFILE) {
05275         type = get_token(fp, token, MAXTOKEN);
05276         if (type == LEFTBRACKET)
05277             bracketcount++;
05278         else if (type == RIGHTBRACKET)
05279             bracketcount--;
05280     }
05281 
05282     if (type == RIGHTBRACKET)
05283         return OBJID;
05284     else
05285         return 0;
05286 }
05287 
05288 /* Find node in any MIB module
05289    Used by Perl modules         */
05290 struct tree    *
05291 find_node(const char *name, struct tree *subtree)
05292 {                               /* Unused */
05293     return (find_tree_node(name, -1));
05294 }
05295 
05296 netsnmp_feature_child_of(parse_find_node2, netsnmp_unused)
05297 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_FIND_NODE2
05298 struct tree    *
05299 find_node2(const char *name, const char *module)
05300 {                               
05301   int modid = -1;
05302   if (module) {
05303     modid = which_module(module);
05304   }
05305   if (modid == -1)
05306   {
05307     return (NULL);
05308   }
05309   return (find_tree_node(name, modid));
05310 }
05311 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_FIND_NODE2 */
05312 
05313 #ifndef NETSNMP_FEATURE_REMOVE_FIND_MODULE
05314 /* Used in the perl module */
05315 struct module  *
05316 find_module(int mid)
05317 {
05318     struct module  *mp;
05319 
05320     for (mp = module_head; mp != NULL; mp = mp->next) {
05321         if (mp->modid == mid)
05322             break;
05323     }
05324     return mp;
05325 }
05326 #endif /* NETSNMP_FEATURE_REMOVE_FIND_MODULE */
05327 
05328 
05329 static char     leave_indent[256];
05330 static int      leave_was_simple;
05331 
05332 static void
05333 print_mib_leaves(FILE * f, struct tree *tp, int width)
05334 {
05335     struct tree    *ntp;
05336     char           *ip = leave_indent + strlen(leave_indent) - 1;
05337     char            last_ipch = *ip;
05338 
05339     *ip = '+';
05340     if (tp->type == TYPE_OTHER || tp->type > TYPE_SIMPLE_LAST) {
05341         fprintf(f, "%s--%s(%ld)\n", leave_indent, tp->label, tp->subid);
05342         if (tp->indexes) {
05343             struct index_list *xp = tp->indexes;
05344             int             first = 1, cpos = 0, len, cmax =
05345                 width - strlen(leave_indent) - 12;
05346             *ip = last_ipch;
05347             fprintf(f, "%s  |  Index: ", leave_indent);
05348             while (xp) {
05349                 if (first)
05350                     first = 0;
05351                 else
05352                     fprintf(f, ", ");
05353                 cpos += (len = strlen(xp->ilabel) + 2);
05354                 if (cpos > cmax) {
05355                     fprintf(f, "\n");
05356                     fprintf(f, "%s  |         ", leave_indent);
05357                     cpos = len;
05358                 }
05359                 fprintf(f, "%s", xp->ilabel);
05360                 xp = xp->next;
05361             }
05362             fprintf(f, "\n");
05363             *ip = '+';
05364         }
05365     } else {
05366         const char     *acc, *typ;
05367         int             size = 0;
05368         switch (tp->access) {
05369         case MIB_ACCESS_NOACCESS:
05370             acc = "----";
05371             break;
05372         case MIB_ACCESS_READONLY:
05373             acc = "-R--";
05374             break;
05375         case MIB_ACCESS_WRITEONLY:
05376             acc = "--W-";
05377             break;
05378         case MIB_ACCESS_READWRITE:
05379             acc = "-RW-";
05380             break;
05381         case MIB_ACCESS_NOTIFY:
05382             acc = "---N";
05383             break;
05384         case MIB_ACCESS_CREATE:
05385             acc = "CR--";
05386             break;
05387         default:
05388             acc = "    ";
05389             break;
05390         }
05391         switch (tp->type) {
05392         case TYPE_OBJID:
05393             typ = "ObjID    ";
05394             break;
05395         case TYPE_OCTETSTR:
05396             typ = "String   ";
05397             size = 1;
05398             break;
05399         case TYPE_INTEGER:
05400             if (tp->enums)
05401                 typ = "EnumVal  ";
05402             else
05403                 typ = "INTEGER  ";
05404             break;
05405         case TYPE_NETADDR:
05406             typ = "NetAddr  ";
05407             break;
05408         case TYPE_IPADDR:
05409             typ = "IpAddr   ";
05410             break;
05411         case TYPE_COUNTER:
05412             typ = "Counter  ";
05413             break;
05414         case TYPE_GAUGE:
05415             typ = "Gauge    ";
05416             break;
05417         case TYPE_TIMETICKS:
05418             typ = "TimeTicks";
05419             break;
05420         case TYPE_OPAQUE:
05421             typ = "Opaque   ";
05422             size = 1;
05423             break;
05424         case TYPE_NULL:
05425             typ = "Null     ";
05426             break;
05427         case TYPE_COUNTER64:
05428             typ = "Counter64";
05429             break;
05430         case TYPE_BITSTRING:
05431             typ = "BitString";
05432             break;
05433         case TYPE_NSAPADDRESS:
05434             typ = "NsapAddr ";
05435             break;
05436         case TYPE_UNSIGNED32:
05437             typ = "Unsigned ";
05438             break;
05439         case TYPE_UINTEGER:
05440             typ = "UInteger ";
05441             break;
05442         case TYPE_INTEGER32:
05443             typ = "Integer32";
05444             break;
05445         default:
05446             typ = "         ";
05447             break;
05448         }
05449         fprintf(f, "%s-- %s %s %s(%ld)\n", leave_indent, acc, typ,
05450                 tp->label, tp->subid);
05451         *ip = last_ipch;
05452         if (tp->tc_index >= 0)
05453             fprintf(f, "%s        Textual Convention: %s\n", leave_indent,
05454                     tclist[tp->tc_index].descriptor);
05455         if (tp->enums) {
05456             struct enum_list *ep = tp->enums;
05457             int             cpos = 0, cmax =
05458                 width - strlen(leave_indent) - 16;
05459             fprintf(f, "%s        Values: ", leave_indent);
05460             while (ep) {
05461                 char            buf[80];
05462                 int             bufw;
05463                 if (ep != tp->enums)
05464                     fprintf(f, ", ");
05465                 snprintf(buf, sizeof(buf), "%s(%d)", ep->label, ep->value);
05466                 buf[ sizeof(buf)-1 ] = 0;
05467                 cpos += (bufw = strlen(buf) + 2);
05468                 if (cpos >= cmax) {
05469                     fprintf(f, "\n%s                ", leave_indent);
05470                     cpos = bufw;
05471                 }
05472                 fprintf(f, "%s", buf);
05473                 ep = ep->next;
05474             }
05475             fprintf(f, "\n");
05476         }
05477         if (tp->ranges) {
05478             struct range_list *rp = tp->ranges;
05479             if (size)
05480                 fprintf(f, "%s        Size: ", leave_indent);
05481             else
05482                 fprintf(f, "%s        Range: ", leave_indent);
05483             while (rp) {
05484                 if (rp != tp->ranges)
05485                     fprintf(f, " | ");
05486                 print_range_value(f, tp->type, rp);
05487                 rp = rp->next;
05488             }
05489             fprintf(f, "\n");
05490         }
05491     }
05492     *ip = last_ipch;
05493     strcat(leave_indent, "  |");
05494     leave_was_simple = tp->type != TYPE_OTHER;
05495 
05496     {
05497         int             i, j, count = 0;
05498         struct leave {
05499             oid             id;
05500             struct tree    *tp;
05501         }              *leaves, *lp;
05502 
05503         for (ntp = tp->child_list; ntp; ntp = ntp->next_peer)
05504             count++;
05505         if (count) {
05506             leaves = (struct leave *) calloc(count, sizeof(struct leave));
05507             if (!leaves)
05508                 return;
05509             for (ntp = tp->child_list, count = 0; ntp;
05510                  ntp = ntp->next_peer) {
05511                 for (i = 0, lp = leaves; i < count; i++, lp++)
05512                     if (lp->id >= ntp->subid)
05513                         break;
05514                 for (j = count; j > i; j--)
05515                     leaves[j] = leaves[j - 1];
05516                 lp->id = ntp->subid;
05517                 lp->tp = ntp;
05518                 count++;
05519             }
05520             for (i = 1, lp = leaves; i <= count; i++, lp++) {
05521                 if (!leave_was_simple || lp->tp->type == 0)
05522                     fprintf(f, "%s\n", leave_indent);
05523                 if (i == count)
05524                     ip[3] = ' ';
05525                 print_mib_leaves(f, lp->tp, width);
05526             }
05527             free(leaves);
05528             leave_was_simple = 0;
05529         }
05530     }
05531     ip[1] = 0;
05532 }
05533 
05534 void
05535 print_mib_tree(FILE * f, struct tree *tp, int width)
05536 {
05537     leave_indent[0] = ' ';
05538     leave_indent[1] = 0;
05539     leave_was_simple = 1;
05540     print_mib_leaves(f, tp, width);
05541 }
05542 
05543 
05544 /*
05545  * Merge the parsed object identifier with the existing node.
05546  * If there is a problem with the identifier, release the existing node.
05547  */
05548 static struct node *
05549 merge_parse_objectid(struct node *np, FILE * fp, char *name)
05550 {
05551     struct node    *nnp;
05552     /*
05553      * printf("merge defval --> %s\n",np->defaultValue); 
05554      */
05555     nnp = parse_objectid(fp, name);
05556     if (nnp) {
05557 
05558         /*
05559          * apply last OID sub-identifier data to the information 
05560          */
05561         /*
05562          * already collected for this node. 
05563          */
05564         struct node    *headp, *nextp;
05565         int             ncount = 0;
05566         nextp = headp = nnp;
05567         while (nnp->next) {
05568             nextp = nnp;
05569             ncount++;
05570             nnp = nnp->next;
05571         }
05572 
05573         np->label = nnp->label;
05574         np->subid = nnp->subid;
05575         np->modid = nnp->modid;
05576         np->parent = nnp->parent;
05577         if (nnp->filename != NULL) {
05578           free(nnp->filename);
05579         }
05580         free(nnp);
05581 
05582         if (ncount) {
05583             nextp->next = np;
05584             np = headp;
05585         }
05586     } else {
05587         free_node(np);
05588         np = NULL;
05589     }
05590 
05591     return np;
05592 }
05593 
05594 /*
05595  * transfer data to tree from node
05596  *
05597  * move pointers for alloc'd data from np to tp.
05598  * this prevents them from being freed when np is released.
05599  * parent member is not moved.
05600  *
05601  * CAUTION: nodes may be repeats of existing tree nodes.
05602  * This can happen especially when resolving IMPORT clauses.
05603  *
05604  */
05605 static void
05606 tree_from_node(struct tree *tp, struct node *np)
05607 {
05608     free_partial_tree(tp, FALSE);
05609 
05610     tp->label = np->label;
05611     np->label = NULL;
05612     tp->enums = np->enums;
05613     np->enums = NULL;
05614     tp->ranges = np->ranges;
05615     np->ranges = NULL;
05616     tp->indexes = np->indexes;
05617     np->indexes = NULL;
05618     tp->augments = np->augments;
05619     np->augments = NULL;
05620     tp->varbinds = np->varbinds;
05621     np->varbinds = NULL;
05622     tp->hint = np->hint;
05623     np->hint = NULL;
05624     tp->units = np->units;
05625     np->units = NULL;
05626     tp->description = np->description;
05627     np->description = NULL;
05628     tp->reference = np->reference;
05629     np->reference = NULL;
05630     tp->defaultValue = np->defaultValue;
05631     np->defaultValue = NULL;
05632     tp->subid = np->subid;
05633     tp->tc_index = np->tc_index;
05634     tp->type = translation_table[np->type];
05635     tp->access = np->access;
05636     tp->status = np->status;
05637 
05638     set_function(tp);
05639 }
05640 
05641 #endif /* NETSNMP_DISABLE_MIB_LOADING */