]>
git.ipfire.org Git - thirdparty/squid.git/blob - snmplib/parse.c
1 /******************************************************************
2 Copyright 1989, 1991, 1992 by Carnegie Mellon University
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of CMU not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
14 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21 ******************************************************************/
32 #include <sys/types.h>
41 #include <gnumalloc.h>
42 #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
50 /* A quoted string value-- too long for a general "token" */
51 char *quoted_string_buffer
;
54 * This is one element of an object identifier with either an integer
55 * subidentifier, or a textual string label, or both.
56 * The subid is -1 if not present, and label is NULL if not present.
63 /* use large token buffer in case of very long tokens: */
65 struct tc
{ /* textual conventions */
67 char descriptor
[MAXTOKEN
];
68 struct enum_list
*enums
;
75 #define SYNTAX_MASK 0x80
77 * Tokens wiht the SYNTAX_MASK bit set are syntax tokens */
83 #define OBJID (4 | SYNTAX_MASK)
84 #define OCTETSTR (5 | SYNTAX_MASK)
85 #define INTEGER (6 | SYNTAX_MASK)
86 #define NETADDR (7 | SYNTAX_MASK)
87 #define IPADDR (8 | SYNTAX_MASK)
88 #define COUNTER (9 | SYNTAX_MASK)
89 #define GAUGE (10 | SYNTAX_MASK)
90 #define TIMETICKS (11 | SYNTAX_MASK)
91 #define OPAQUE (12 | SYNTAX_MASK)
92 #define NUL (13 | SYNTAX_MASK)
94 #define OF 15 /* SEQUENCE OF */
105 /* #define RECOMMENDED 26 */
109 #define LEFTBRACKET 30
110 #define RIGHTBRACKET 31
112 #define RIGHTPAREN 33
114 #define DESCRIPTION 35
115 #define QUOTESTRING 36
118 #define DEPRECATED 39
120 #define BITSTRING (41 | SYNTAX_MASK)
121 #define NSAPADDRESS (42 | SYNTAX_MASK)
122 #define COUNTER64 (43 | SYNTAX_MASK)
126 #define COMPLIANCE 47
127 #define READCREATE 48
130 #define NUM_ENTRIES 51
131 #define MODULEIDENTITY 52
132 #define LASTUPDATED 53
133 #define ORGANIZATION 54
134 #define CONTACTINFO 55
135 #define UINTEGER32 (56 | SYNTAX_MASK)
137 #define DEFINITIONS 58
142 char *name
; /* token name */
143 int len
; /* length not counting nul */
144 int token
; /* value */
145 int hash
; /* hash of name */
146 struct tok
*next
; /* pointer to next in hash table */
150 struct tok tokens
[] =
152 {"obsolete", sizeof("obsolete") - 1, OBSOLETE
},
153 {"Opaque", sizeof("Opaque") - 1, OPAQUE
},
154 /* { "recommended", sizeof("recommended")-1, RECOMMENDED }, */
155 {"optional", sizeof("optional") - 1, OPTIONAL
},
156 {"LAST-UPDATED", sizeof("LAST-UPDATED") - 1, LASTUPDATED
},
157 {"ORGANIZATION", sizeof("ORGANIZATION") - 1, ORGANIZATION
},
158 {"CONTACT-INFO", sizeof("CONTACT-INFO") - 1, CONTACTINFO
},
159 {"MODULE-IDENTITY", sizeof("MODULE-IDENTITY") - 1, MODULEIDENTITY
},
160 {"MODULE-COMPLIANCE", sizeof("MODULE-COMPLIANCE") - 1, COMPLIANCE
},
161 {"DEFINITIONS", sizeof("DEFINITIONS") - 1, DEFINITIONS
},
162 {"END", sizeof("END") - 1, END
},
163 {";", sizeof(";") - 1, SEMI
},
164 {"AUGMENTS", sizeof("AUGMENTS") - 1, AUGMENTS
},
165 {"not-accessible", sizeof("not-accessible") - 1, NOACCESS
},
166 {"write-only", sizeof("write-only") - 1, WRITEONLY
},
167 {"NsapAddress", sizeof("NsapAddress") - 1, NSAPADDRESS
},
168 {"UNITS", sizeof("Units") - 1, UNITS
},
169 {"REFERENCE", sizeof("REFERENCE") - 1, REFERENCE
},
170 {"NUM-ENTRIES", sizeof("NUM-ENTRIES") - 1, NUM_ENTRIES
},
171 {"BITSTRING", sizeof("BitString") - 1, BITSTRING
},
172 {"BIT", sizeof("BIT") - 1, CONTINUE
},
173 {"Counter64", sizeof("Counter64") - 1, COUNTER64
},
174 {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS
},
175 {"NOTIFICATION-TYPE", sizeof("NOTIFICATION-TYPE") - 1, NOTIFTYPE
},
176 {"OBJECT-GROUP", sizeof("OBJECT-GROUP") - 1, OBJGROUP
},
177 {"OBJECTIDENTIFIER", sizeof("OBJECTIDENTIFIER") - 1, OBJID
},
179 * This CONTINUE appends the next word onto OBJECT,
180 * hopefully matching OBJECTIDENTIFIER above.
182 {"OBJECT", sizeof("OBJECT") - 1, CONTINUE
},
183 {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR
},
184 {"Gauge", sizeof("Gauge") - 1, GAUGE
},
185 {"read-write", sizeof("read-write") - 1, READWRITE
},
186 {"read-create", sizeof("read-create") - 1, READCREATE
},
187 {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR
},
188 {"OCTET", sizeof("OCTET") - 1, -1},
189 {"OF", sizeof("OF") - 1, OF
},
190 {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE
},
191 {"NULL", sizeof("NULL") - 1, NUL
},
192 {"IpAddress", sizeof("IpAddress") - 1, IPADDR
},
193 {"UInteger32", sizeof("UInteger32") - 1, UINTEGER32
},
194 {"INTEGER", sizeof("INTEGER") - 1, INTEGER
},
195 {"Counter", sizeof("Counter") - 1, COUNTER
},
196 {"read-only", sizeof("read-only") - 1, READONLY
},
197 {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION
},
198 {"INDEX", sizeof("INDEX") - 1, INDEX
},
199 {"DEFVAL", sizeof("DEFVAL") - 1, DEFVAL
},
200 {"deprecated", sizeof("deprecated") - 1, DEPRECATED
},
201 {"SIZE", sizeof("SIZE") - 1, SIZE
},
202 {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS
},
203 {"ACCESS", sizeof("ACCESS") - 1, ACCESS
},
204 {"mandatory", sizeof("mandatory") - 1, MANDATORY
},
205 {"current", sizeof("current") - 1, CURRENT
},
206 {"STATUS", sizeof("STATUS") - 1, STATUS
},
207 {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX
},
208 {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE
},
209 {"{", sizeof("{") - 1, LEFTBRACKET
},
210 {"}", sizeof("}") - 1, RIGHTBRACKET
},
211 {"::=", sizeof("::=") - 1, EQUALS
},
212 {"(", sizeof("(") - 1, LEFTPAREN
},
213 {")", sizeof(")") - 1, RIGHTPAREN
},
214 {",", sizeof(",") - 1, COMMA
},
219 #define BUCKET(x) (x & 0x01F)
221 struct tok
*buckets
[HASHSIZE
];
223 static void do_subtree();
224 static int get_token();
225 static int parseQuoteString();
226 static int tossObjectIdentifier();
236 memset(buckets
, '\0', sizeof(buckets
));
237 for (tp
= tokens
; tp
->name
; tp
++) {
238 for (h
= 0, cp
= tp
->name
; *cp
; cp
++)
243 tp
->next
= buckets
[b
]; /* BUG ??? */
248 #define NHASHSIZE 128
249 #define NBUCKET(x) (x & 0x7F)
250 struct node
*nbuckets
[NHASHSIZE
];
253 init_node_hash(nodes
)
256 struct node
*np
, *nextp
;
260 memset(nbuckets
, '\0', sizeof(nbuckets
));
261 for (np
= nodes
; np
;) {
264 for (cp
= np
->parent
; *cp
; cp
++)
266 np
->next
= nbuckets
[NBUCKET(hash
)];
267 nbuckets
[NBUCKET(hash
)] = np
;
276 /* this is to fix (what seems to be) a problem with the IBM RT C
280 return xcalloc(1, num
);
284 print_error(string
, token
, type
)
289 if (type
== ENDOFFILE
)
290 fprintf(stderr
, "%s(EOF): On or around line %d\n", string
, Line
);
292 fprintf(stderr
, "%s(%s): On or around line %d\n", string
, token
, Line
);
294 fprintf(stderr
, "%s: On or around line %d\n", string
, Line
);
298 print_subtree(tree
, count
)
305 for (i
= 0; i
< count
; i
++)
307 printf("Children of %s:\n", tree
->label
);
309 for (tp
= tree
->child_list
; tp
; tp
= tp
->next_peer
) {
310 for (i
= 0; i
< count
; i
++)
312 printf("%s\n", tp
->label
);
314 for (tp
= tree
->child_list
; tp
; tp
= tp
->next_peer
) {
315 print_subtree(tp
, count
);
320 int translation_table
[256];
323 build_translation_table()
327 for (count
= 0; count
< 256; count
++) {
330 translation_table
[count
] = TYPE_OBJID
;
333 translation_table
[count
] = TYPE_OCTETSTR
;
336 translation_table
[count
] = TYPE_INTEGER
;
339 translation_table
[count
] = TYPE_IPADDR
;
342 translation_table
[count
] = TYPE_IPADDR
;
345 translation_table
[count
] = TYPE_COUNTER
;
348 translation_table
[count
] = TYPE_GAUGE
;
351 translation_table
[count
] = TYPE_TIMETICKS
;
354 translation_table
[count
] = TYPE_OPAQUE
;
357 translation_table
[count
] = TYPE_NULL
;
360 translation_table
[count
] = TYPE_COUNTER64
;
363 translation_table
[count
] = TYPE_BITSTRING
;
366 translation_table
[count
] = TYPE_NSAPADDRESS
;
369 translation_table
[count
] = TYPE_UINTEGER
;
372 translation_table
[count
] = TYPE_OTHER
;
383 struct tree
*tp
, *lasttp
;
384 int bucket
, nodes_left
= 0;
386 build_translation_table();
387 /* grow tree from this root node */
388 init_node_hash(nodes
);
390 /* build root node */
391 tp
= (struct tree
*) Malloc(sizeof(struct tree
));
393 tp
->next_peer
= NULL
;
394 tp
->child_list
= NULL
;
396 strcpy(tp
->label
, "joint-iso-ccitt");
400 /* XXX nodes isn't needed in do_subtree() ??? */
401 do_subtree(tp
, &nodes
);
404 /* build root node */
405 tp
= (struct tree
*) Malloc(sizeof(struct tree
));
407 tp
->next_peer
= lasttp
;
408 tp
->child_list
= NULL
;
410 strcpy(tp
->label
, "ccitt");
414 /* XXX nodes isn't needed in do_subtree() ??? */
415 do_subtree(tp
, &nodes
);
418 /* build root node */
419 tp
= (struct tree
*) Malloc(sizeof(struct tree
));
421 tp
->next_peer
= lasttp
;
422 tp
->child_list
= NULL
;
424 strcpy(tp
->label
, "iso");
428 /* XXX nodes isn't needed in do_subtree() ??? */
429 do_subtree(tp
, &nodes
);
433 print_subtree(tp
, 0);
435 /* If any nodes are left, the tree is probably inconsistent */
436 for (bucket
= 0; bucket
< NHASHSIZE
; bucket
++) {
437 if (nbuckets
[bucket
]) {
443 fprintf(stderr
, "The mib description doesn't seem to be consistent.\n");
444 fprintf(stderr
, "Some nodes couldn't be linked under the \"iso\" tree.\n");
445 fprintf(stderr
, "these nodes are left:\n");
446 for (bucket
= 0; bucket
< NHASHSIZE
; bucket
++) {
447 for (np
= nbuckets
[bucket
]; np
; np
= np
->next
)
448 fprintf(stderr
, "%s ::= { %s %ld } (%d)\n", np
->label
,
449 np
->parent
, np
->subid
, np
->type
);
456 * Find all the children of root in the list of nodes. Link them into the
457 * tree and out of the nodes list.
460 do_subtree(root
, nodes
)
465 struct tree
*peer
= NULL
;
466 struct node
*np
, **headp
;
467 struct node
*oldnp
= NULL
, *child_list
= NULL
, *childp
= NULL
;
473 for (cp
= tp
->label
; *cp
; cp
++)
475 headp
= &nbuckets
[NBUCKET(hash
)];
477 * Search each of the nodes for one whose parent is root, and
478 * move each into a separate list.
480 for (np
= *headp
; np
; np
= np
->next
) {
481 if ((*tp
->label
!= *np
->parent
) || strcmp(tp
->label
, np
->parent
)) {
482 if ((*tp
->label
== *np
->label
) && !strcmp(tp
->label
, np
->label
)) {
483 /* if there is another node with the same label, assume that
484 * any children after this point in the list belong to the other node.
485 * This adds some scoping to the table and allows vendors to
486 * reuse names such as "ip".
492 if (child_list
== NULL
) {
493 child_list
= childp
= np
; /* first entry in child list */
498 /* take this node out of the node list */
500 *headp
= np
->next
; /* fix root of node list */
502 oldnp
->next
= np
->next
; /* link around this node */
507 childp
->next
= 0; /* re-terminate list */
509 * Take each element in the child list and place it into the tree.
511 for (np
= child_list
; np
; np
= np
->next
) {
512 tp
= (struct tree
*) Malloc(sizeof(struct tree
));
514 tp
->next_peer
= NULL
;
515 tp
->child_list
= NULL
;
516 strcpy(tp
->label
, np
->label
);
517 tp
->subid
= np
->subid
;
518 tp
->type
= translation_table
[np
->type
];
519 tp
->enums
= np
->enums
;
520 np
->enums
= NULL
; /* so we don't free them later */
521 tp
->description
= np
->description
; /* steals memory from np */
522 np
->description
= NULL
; /* so we don't free it later */
523 if (root
->child_list
== NULL
) {
524 root
->child_list
= tp
;
526 peer
->next_peer
= tp
;
529 /* if (tp->type == TYPE_OTHER) */
530 do_subtree(tp
, nodes
); /* recurse on this child if it isn't
533 /* free all nodes that were copied into tree */
535 for (np
= child_list
; np
; np
= np
->next
) {
546 * Takes a list of the form:
547 * { iso org(3) dod(6) 1 }
548 * and creates several nodes, one for each parent-child pair.
549 * Returns NULL on error.
552 getoid(fp
, oid
, length
)
554 struct subid
*oid
; /* an array of subids */
555 int length
; /* the length of the array */
559 char token
[MAXTOKEN
];
562 if ((type
= get_token(fp
, token
)) != LEFTBRACKET
) {
563 print_error("Expected \"{\"", token
, type
);
566 type
= get_token(fp
, token
);
567 for (count
= 0; count
< length
; count
++, oid
++) {
570 if (type
== RIGHTBRACKET
) {
572 } else if (type
!= LABEL
&& type
!= NUMBER
) {
573 print_error("Not valid for object identifier", token
, type
);
577 /* this entry has a label */
578 cp
= (char *) Malloc((unsigned) strlen(token
) + 1);
581 type
= get_token(fp
, token
);
582 if (type
== LEFTPAREN
) {
583 type
= get_token(fp
, token
);
584 if (type
== NUMBER
) {
585 oid
->subid
= atoi(token
);
586 if ((type
= get_token(fp
, token
)) != RIGHTPAREN
) {
587 print_error("Unexpected a closing parenthesis", token
, type
);
591 print_error("Expected a number", token
, type
);
598 /* this entry has just an integer sub-identifier */
599 oid
->subid
= atoi(token
);
601 type
= get_token(fp
, token
);
612 struct enum_list
*ep
, *tep
;
624 * Parse an entry of the form:
625 * label OBJECT IDENTIFIER ::= { parent 2 }
626 * The "label OBJECT IDENTIFIER" portion has already been parsed.
627 * Returns 0 on error.
630 parse_objectid(fp
, name
)
635 char token
[MAXTOKEN
];
637 struct subid
*op
, *nop
;
639 struct subid oid
[32];
640 struct node
*np
, *root
, *oldnp
= NULL
;
642 type
= get_token(fp
, token
);
643 if (type
!= EQUALS
) {
644 print_error("Bad format", token
, type
);
647 if ((length
= getoid(fp
, oid
, 32)) != 0) {
648 np
= root
= (struct node
*) Malloc(sizeof(struct node
));
649 memset(np
, '\0', sizeof(struct node
));
651 * For each parent-child subid pair in the subid array,
652 * create a node and link it into the node list.
654 for (count
= 0, op
= oid
, nop
= oid
+ 1; count
< (length
- 2); count
++,
656 /* every node must have parent's name and child's name or number */
657 if (op
->label
&& (nop
->label
|| (nop
->subid
!= -1))) {
658 strcpy(np
->parent
, op
->label
);
660 strcpy(np
->label
, nop
->label
);
661 if (nop
->subid
!= -1)
662 np
->subid
= nop
->subid
;
665 /* set up next entry */
666 np
->next
= (struct node
*) Malloc(sizeof(*np
->next
));
667 memset(np
->next
, '\0', sizeof(struct node
));
672 np
->next
= (struct node
*) NULL
;
674 * The above loop took care of all but the last pair. This pair is taken
675 * care of here. The name for this node is taken from the label for this
677 * np still points to an unused entry.
679 if (count
== (length
- 2)) {
681 strcpy(np
->parent
, op
->label
);
682 strcpy(np
->label
, name
);
683 if (nop
->subid
!= -1)
684 np
->subid
= nop
->subid
;
686 print_error("Warning: This entry is pretty silly",
696 print_error("Missing end of oid", (char *) NULL
, type
);
697 free_node(np
); /* the last node allocated wasn't used */
702 /* free the oid array */
703 for (count
= 0, op
= oid
; count
< length
; count
++, op
++) {
710 print_error("Bad object identifier", (char *) NULL
, type
);
716 get_tc(descriptor
, ep
)
718 struct enum_list
**ep
;
722 for (i
= 0; i
< MAXTC
; i
++) {
723 if (tclist
[i
].type
== 0)
725 if (!strcmp(descriptor
, tclist
[i
].descriptor
)) {
726 *ep
= tclist
[i
].enums
;
727 return tclist
[i
].type
;
734 * Parses an asn type. Structures are ignored by this parser.
735 * Returns NULL on error.
738 parse_asntype(fp
, name
, ntype
, ntoken
)
745 char token
[MAXTOKEN
];
746 struct enum_list
*ep
= 0;
750 type
= get_token(fp
, token
);
751 if (type
== SEQUENCE
) {
752 while ((type
= get_token(fp
, token
)) != ENDOFFILE
) {
753 if (type
== RIGHTBRACKET
) {
754 *ntype
= get_token(fp
, ntoken
);
758 print_error("Expected \"}\"", token
, type
);
761 if (!strcmp(token
, "TEXTUAL-CONVENTION")) {
762 while (type
!= SYNTAX
)
763 type
= get_token(fp
, token
);
764 type
= get_token(fp
, token
);
766 /* textual convention */
767 for (i
= 0; i
< MAXTC
; i
++) {
768 if (tclist
[i
].type
== 0)
772 print_error("No more textual conventions possible.", token
, type
);
776 strcpy(tcp
->descriptor
, name
);
777 if (!(type
& SYNTAX_MASK
)) {
778 print_error("Textual convention doesn't map to real type.", token
,
783 *ntype
= get_token(fp
, ntoken
);
784 if (*ntype
== LEFTPAREN
) {
786 /* don't record any constraints for now */
788 *ntype
= get_token(fp
, ntoken
);
789 if (*ntype
== LEFTPAREN
)
791 if (*ntype
== RIGHTPAREN
)
794 *ntype
= get_token(fp
, ntoken
);
795 } else if (*ntype
== LEFTBRACKET
) {
796 /* if there is an enumeration list, parse it */
797 while ((type
= get_token(fp
, token
)) != ENDOFFILE
) {
798 if (type
== RIGHTBRACKET
)
801 /* this is an enumerated label */
802 if (tcp
->enums
== 0) {
803 ep
= tcp
->enums
= (struct enum_list
*)
804 Malloc(sizeof(struct enum_list
));
806 ep
->next
= (struct enum_list
*)
807 Malloc(sizeof(struct enum_list
));
811 /* a reasonable approximation for the length */
813 (char *) Malloc((unsigned) strlen(token
) + 1);
814 strcpy(ep
->label
, token
);
815 type
= get_token(fp
, token
);
816 if (type
!= LEFTPAREN
) {
817 print_error("Expected \"(\"", token
, type
);
821 type
= get_token(fp
, token
);
822 if (type
!= NUMBER
) {
823 print_error("Expected integer", token
, type
);
827 ep
->value
= atoi(token
);
828 type
= get_token(fp
, token
);
829 if (type
!= RIGHTPAREN
) {
830 print_error("Expected \")\"", token
, type
);
836 if (type
== ENDOFFILE
) {
837 print_error("Expected \"}\"", token
, type
);
841 *ntype
= get_token(fp
, ntoken
);
849 * Parses an OBJECT TYPE macro.
850 * Returns 0 on error.
853 parse_objecttype(fp
, name
)
858 char token
[MAXTOKEN
];
860 struct subid oid
[32];
861 char syntax
[MAXTOKEN
];
862 int nexttype
, tctype
;
863 char nexttoken
[MAXTOKEN
];
865 struct enum_list
*ep
= 0;
867 type
= get_token(fp
, token
);
868 if (type
!= SYNTAX
) {
869 print_error("Bad format for OBJECT TYPE", token
, type
);
872 np
= (struct node
*) Malloc(sizeof(struct node
));
875 np
->description
= NULL
; /* default to an empty description */
876 type
= get_token(fp
, token
);
878 tctype
= get_tc(token
, &(np
->enums
));
880 if (tctype
== LABEL
) {
881 print_error("No known translation for type", token
, type
);
888 nexttype
= get_token(fp
, nexttoken
);
891 strcpy(syntax
, token
);
892 if (nexttype
== OF
) {
894 strcat(syntax
, nexttoken
);
895 nexttype
= get_token(fp
, nexttoken
);
897 strcat(syntax
, nexttoken
);
898 nexttype
= get_token(fp
, nexttoken
);
903 strcpy(syntax
, token
);
904 if (nexttype
== LEFTBRACKET
) {
905 /* if there is an enumeration list, parse it */
906 while ((type
= get_token(fp
, token
)) != ENDOFFILE
) {
907 if (type
== RIGHTBRACKET
)
910 /* this is an enumerated label */
911 if (np
->enums
== 0) {
912 ep
= np
->enums
= (struct enum_list
*)
913 Malloc(sizeof(struct enum_list
));
915 ep
->next
= (struct enum_list
*)
916 Malloc(sizeof(struct enum_list
));
920 /* a reasonable approximation for the length */
922 (char *) Malloc((unsigned) strlen(token
) + 1);
923 strcpy(ep
->label
, token
);
924 type
= get_token(fp
, token
);
925 if (type
!= LEFTPAREN
) {
926 print_error("Expected \"(\"", token
, type
);
930 type
= get_token(fp
, token
);
931 if (type
!= NUMBER
) {
932 print_error("Expected integer", token
, type
);
936 ep
->value
= atoi(token
);
937 type
= get_token(fp
, token
);
938 if (type
!= RIGHTPAREN
) {
939 print_error("Expected \")\"", token
, type
);
945 if (type
== ENDOFFILE
) {
946 print_error("Expected \"}\"", token
, type
);
950 nexttype
= get_token(fp
, nexttoken
);
951 } else if (nexttype
== LEFTPAREN
) {
952 /* ignore the "constrained integer" for now */
953 nexttype
= get_token(fp
, nexttoken
);
954 nexttype
= get_token(fp
, nexttoken
);
955 nexttype
= get_token(fp
, nexttoken
);
959 strcpy(syntax
, token
);
960 if (nexttype
== LEFTBRACKET
) {
961 /* if there is an enumeration list, parse it */
962 while ((type
= get_token(fp
, token
)) != ENDOFFILE
) {
963 if (type
== RIGHTBRACKET
)
966 /* this is an enumerated label */
967 if (np
->enums
== 0) {
968 ep
= np
->enums
= (struct enum_list
*)
969 Malloc(sizeof(struct enum_list
));
971 ep
->next
= (struct enum_list
*)
972 Malloc(sizeof(struct enum_list
));
976 /* a reasonable approximation for the length */
978 (char *) Malloc((unsigned) strlen(token
) + 1);
979 strcpy(ep
->label
, token
);
980 type
= get_token(fp
, token
);
981 if (type
!= LEFTPAREN
) {
982 print_error("Expected \"(\"", token
, type
);
986 type
= get_token(fp
, token
);
987 if (type
!= NUMBER
) {
988 print_error("Expected integer", token
, type
);
992 ep
->value
= atoi(token
);
993 type
= get_token(fp
, token
);
994 if (type
!= RIGHTPAREN
) {
995 print_error("Expected \")\"", token
, type
);
1001 if (type
== ENDOFFILE
) {
1002 print_error("Expected \"}\"", token
, type
);
1006 nexttype
= get_token(fp
, nexttoken
);
1007 } else if (nexttype
== LEFTPAREN
) {
1008 /* ignore the "constrained integer" for now */
1009 nexttype
= get_token(fp
, nexttoken
);
1010 nexttype
= get_token(fp
, nexttoken
);
1011 nexttype
= get_token(fp
, nexttoken
);
1015 strcpy(syntax
, token
);
1016 /* ignore the "constrained octet string" for now */
1017 if (nexttype
== LEFTPAREN
) {
1018 nexttype
= get_token(fp
, nexttoken
);
1019 if (nexttype
== SIZE
) {
1020 nexttype
= get_token(fp
, nexttoken
);
1021 if (nexttype
== LEFTPAREN
) {
1022 nexttype
= get_token(fp
, nexttoken
); /* 0..255 */
1023 nexttype
= get_token(fp
, nexttoken
); /* ) */
1024 nexttype
= get_token(fp
, nexttoken
); /* ) */
1025 if (nexttype
== RIGHTPAREN
) {
1026 nexttype
= get_token(fp
, nexttoken
);
1031 print_error("Bad syntax", token
, type
);
1047 strcpy(syntax
, token
);
1050 print_error("Bad syntax", token
, type
);
1054 if (nexttype
== UNITS
) {
1055 type
= get_token(fp
, token
);
1056 if (type
!= QUOTESTRING
) {
1057 print_error("Bad DESCRIPTION", token
, type
);
1061 nexttype
= get_token(fp
, nexttoken
);
1063 if (nexttype
!= ACCESS
) {
1064 print_error("Should be ACCESS", nexttoken
, nexttype
);
1068 type
= get_token(fp
, token
);
1069 if (type
!= READONLY
&& type
!= READWRITE
&& type
!= WRITEONLY
1070 && type
!= NOACCESS
&& type
!= READCREATE
) {
1071 print_error("Bad access type", nexttoken
, nexttype
);
1075 type
= get_token(fp
, token
);
1076 if (type
!= STATUS
) {
1077 print_error("Should be STATUS", token
, nexttype
);
1081 type
= get_token(fp
, token
);
1082 if (type
!= MANDATORY
&& type
!= CURRENT
&& type
!= OPTIONAL
&& type
!= OBSOLETE
&& type
!= DEPRECATED
) {
1083 print_error("Bad status", token
, type
);
1088 * Optional parts of the OBJECT-TYPE macro
1090 type
= get_token(fp
, token
);
1091 while (type
!= EQUALS
) {
1094 type
= get_token(fp
, token
);
1095 if (type
!= QUOTESTRING
) {
1096 print_error("Bad DESCRIPTION", token
, type
);
1101 printf("Description== \"%.50s\"\n", quoted_string_buffer
);
1103 np
->description
= quoted_string_buffer
;
1104 quoted_string_buffer
= xcalloc(1, MAXQUOTESTR
);
1108 type
= get_token(fp
, token
);
1109 if (type
!= QUOTESTRING
) {
1110 print_error("Bad DESCRIPTION", token
, type
);
1119 if (tossObjectIdentifier(fp
) != OBJID
) {
1120 print_error("Bad Object Identifier", token
, type
);
1127 print_error("Bad format of optional clauses", token
, type
);
1132 type
= get_token(fp
, token
);
1134 if (type
!= EQUALS
) {
1135 print_error("Bad format", token
, type
);
1139 length
= getoid(fp
, oid
, 32);
1140 if (length
> 1 && length
<= 32) {
1141 /* just take the last pair in the oid list */
1142 if (oid
[length
- 2].label
)
1143 strncpy(np
->parent
, oid
[length
- 2].label
, MAXLABEL
);
1144 strcpy(np
->label
, name
);
1145 if (oid
[length
- 1].subid
!= -1)
1146 np
->subid
= oid
[length
- 1].subid
;
1148 print_error("Warning: This entry is pretty silly", np
->label
, type
);
1150 print_error("No end to oid", (char *) NULL
, type
);
1154 /* free oid array */
1155 for (count
= 0; count
< length
; count
++) {
1156 if (oid
[count
].label
)
1157 free(oid
[count
].label
);
1158 oid
[count
].label
= 0;
1165 * Parses an OBJECT GROUP macro.
1166 * Returns 0 on error.
1168 static struct node
*
1169 parse_objectgroup(fp
, name
)
1174 char token
[MAXTOKEN
];
1176 struct subid oid
[32];
1179 np
= (struct node
*) Malloc(sizeof(struct node
));
1183 np
->description
= NULL
; /* default to an empty description */
1184 type
= get_token(fp
, token
);
1185 while (type
!= EQUALS
) {
1188 type
= get_token(fp
, token
);
1189 if (type
!= QUOTESTRING
) {
1190 print_error("Bad DESCRIPTION", token
, type
);
1195 printf("Description== \"%.50s\"\n", quoted_string_buffer
);
1197 np
->description
= quoted_string_buffer
;
1198 quoted_string_buffer
= xcalloc(1, MAXQUOTESTR
);
1205 type
= get_token(fp
, token
);
1207 length
= getoid(fp
, oid
, 32);
1208 if (length
> 1 && length
<= 32) {
1209 /* just take the last pair in the oid list */
1210 if (oid
[length
- 2].label
)
1211 strncpy(np
->parent
, oid
[length
- 2].label
, MAXLABEL
);
1212 strcpy(np
->label
, name
);
1213 if (oid
[length
- 1].subid
!= -1)
1214 np
->subid
= oid
[length
- 1].subid
;
1216 print_error("Warning: This entry is pretty silly", np
->label
, type
);
1218 print_error("No end to oid", (char *) NULL
, type
);
1222 /* free oid array */
1223 for (count
= 0; count
< length
; count
++) {
1224 if (oid
[count
].label
)
1225 free(oid
[count
].label
);
1226 oid
[count
].label
= 0;
1232 * Parses a NOTIFICATION-TYPE macro.
1233 * Returns 0 on error.
1235 static struct node
*
1236 parse_notificationDefinition(fp
, name
)
1241 char token
[MAXTOKEN
];
1243 struct subid oid
[32];
1246 np
= (struct node
*) Malloc(sizeof(struct node
));
1250 np
->description
= NULL
; /* default to an empty description */
1251 type
= get_token(fp
, token
);
1252 while (type
!= EQUALS
) {
1255 type
= get_token(fp
, token
);
1256 if (type
!= QUOTESTRING
) {
1257 print_error("Bad DESCRIPTION", token
, type
);
1262 printf("Description== \"%.50s\"\n", quoted_string_buffer
);
1264 np
->description
= quoted_string_buffer
;
1265 quoted_string_buffer
= xcalloc(1, MAXQUOTESTR
);
1272 type
= get_token(fp
, token
);
1274 length
= getoid(fp
, oid
, 32);
1275 if (length
> 1 && length
<= 32) {
1276 /* just take the last pair in the oid list */
1277 if (oid
[length
- 2].label
)
1278 strncpy(np
->parent
, oid
[length
- 2].label
, MAXLABEL
);
1279 strcpy(np
->label
, name
);
1280 if (oid
[length
- 1].subid
!= -1)
1281 np
->subid
= oid
[length
- 1].subid
;
1283 print_error("Warning: This entry is pretty silly", np
->label
, type
);
1285 print_error("No end to oid", (char *) NULL
, type
);
1289 /* free oid array */
1290 for (count
= 0; count
< length
; count
++) {
1291 if (oid
[count
].label
)
1292 free(oid
[count
].label
);
1293 oid
[count
].label
= 0;
1299 * Parses a compliance macro
1300 * Returns 0 on error.
1302 static struct node
*
1303 parse_compliance(fp
, name
)
1308 char token
[MAXTOKEN
];
1310 struct subid oid
[32];
1313 np
= (struct node
*) Malloc(sizeof(struct node
));
1317 np
->description
= NULL
; /* default to an empty description */
1318 type
= get_token(fp
, token
);
1319 while (type
!= EQUALS
) {
1320 type
= get_token(fp
, token
);
1322 length
= getoid(fp
, oid
, 32);
1323 if (length
> 1 && length
<= 32) {
1324 /* just take the last pair in the oid list */
1325 if (oid
[length
- 2].label
)
1326 strncpy(np
->parent
, oid
[length
- 2].label
, MAXLABEL
);
1327 strcpy(np
->label
, name
);
1328 if (oid
[length
- 1].subid
!= -1)
1329 np
->subid
= oid
[length
- 1].subid
;
1331 print_error("Warning: This entry is pretty silly", np
->label
, type
);
1333 print_error("No end to oid", (char *) NULL
, type
);
1337 /* free oid array */
1338 for (count
= 0; count
< length
; count
++) {
1339 if (oid
[count
].label
)
1340 free(oid
[count
].label
);
1341 oid
[count
].label
= 0;
1349 * Parses a module identity macro
1350 * Returns 0 on error.
1352 static struct node
*
1353 parse_moduleIdentity(fp
, name
)
1358 char token
[MAXTOKEN
];
1360 struct subid oid
[32];
1363 np
= (struct node
*) Malloc(sizeof(struct node
));
1367 np
->description
= NULL
; /* default to an empty description */
1368 type
= get_token(fp
, token
);
1369 while (type
!= EQUALS
) {
1370 type
= get_token(fp
, token
);
1372 length
= getoid(fp
, oid
, 32);
1373 if (length
> 1 && length
<= 32) {
1374 /* just take the last pair in the oid list */
1375 if (oid
[length
- 2].label
)
1376 strncpy(np
->parent
, oid
[length
- 2].label
, MAXLABEL
);
1377 strcpy(np
->label
, name
);
1378 if (oid
[length
- 1].subid
!= -1)
1379 np
->subid
= oid
[length
- 1].subid
;
1381 print_error("Warning: This entry is pretty silly", np
->label
, type
);
1383 print_error("No end to oid", (char *) NULL
, type
);
1387 /* free oid array */
1388 for (count
= 0; count
< length
; count
++) {
1389 if (oid
[count
].label
)
1390 free(oid
[count
].label
);
1391 oid
[count
].label
= 0;
1397 parse_mib_header(fp
, name
)
1401 int type
= DEFINITIONS
;
1402 char token
[MAXTOKEN
];
1404 /* This probably isn't good enough. If there is no
1405 * imports clause we can't go around waiting (forever) for a semicolon.
1406 * We need to check for semi following an EXPORTS clause or an IMPORTS
1407 * clause of both. Look for BEGIN; in my initial MIBs to see those
1408 * that I needed to hack to get to parse because they didn't have
1409 * an IMPORTS or and EXPORTS clause.
1411 while (type
!= SEMI
&& type
!= ENDOFFILE
) {
1412 type
= get_token(fp
, token
);
1414 return (type
== SEMI
);
1420 * Parses a mib file and returns a linked list of nodes found in the file.
1421 * Returns NULL on error.
1423 static struct node
*
1427 char token
[MAXTOKEN
];
1428 char name
[MAXTOKEN
];
1430 #define BETWEEN_MIBS 1
1432 int state
= BETWEEN_MIBS
;
1433 struct node
*np
= 0, *root
= NULL
;
1436 quoted_string_buffer
= xcalloc(1, MAXQUOTESTR
); /* free this later */
1437 memset(tclist
, '\0', 64 * sizeof(struct tc
));
1439 while (type
!= ENDOFFILE
) {
1440 type
= get_token(fp
, token
);
1443 if (state
!= IN_MIB
) {
1444 print_error("Error, end before start of MIB.", (char *) NULL
, type
);
1447 state
= BETWEEN_MIBS
;
1449 } else if (type
!= LABEL
) {
1450 if (type
== ENDOFFILE
) {
1453 print_error(token
, "is a reserved word", type
);
1456 strncpy(name
, token
, MAXTOKEN
);
1457 type
= get_token(fp
, token
);
1458 if (type
== DEFINITIONS
) {
1459 if (state
!= BETWEEN_MIBS
) {
1460 print_error("Error, nested MIBS.", (char *) NULL
, type
);
1464 if (!parse_mib_header(fp
, name
)) {
1465 print_error("Bad parse of module header", (char *) NULL
, type
);
1468 } else if (type
== OBJTYPE
) {
1470 /* first link in chain */
1471 np
= root
= parse_objecttype(fp
, name
);
1473 print_error("Bad parse of object type", (char *) NULL
,
1478 np
->next
= parse_objecttype(fp
, name
);
1479 if (np
->next
== NULL
) {
1480 print_error("Bad parse of objecttype", (char *) NULL
,
1485 /* now find end of chain */
1488 } else if (type
== OBJGROUP
) {
1490 /* first link in chain */
1491 np
= root
= parse_objectgroup(fp
, name
);
1493 print_error("Bad parse of object group", (char *) NULL
,
1498 np
->next
= parse_objectgroup(fp
, name
);
1499 if (np
->next
== NULL
) {
1500 print_error("Bad parse of objectgroup", (char *) NULL
,
1505 /* now find end of chain */
1508 } else if (type
== NOTIFTYPE
) {
1510 /* first link in chain */
1511 np
= root
= parse_notificationDefinition(fp
, name
);
1513 print_error("Bad parse of notification definition",
1514 (char *) NULL
, type
);
1518 np
->next
= parse_notificationDefinition(fp
, name
);
1519 if (np
->next
== NULL
) {
1520 print_error("Bad parse of notification definition",
1521 (char *) NULL
, type
);
1525 /* now find end of chain */
1528 } else if (type
== COMPLIANCE
) {
1530 /* first link in chain */
1531 np
= root
= parse_compliance(fp
, name
);
1533 print_error("Bad parse of module compliance", (char *) NULL
,
1538 np
->next
= parse_compliance(fp
, name
);
1539 if (np
->next
== NULL
) {
1540 print_error("Bad parse of module compliance", (char *) NULL
,
1545 /* now find end of chain */
1548 } else if (type
== MODULEIDENTITY
) {
1550 /* first link in chain */
1551 np
= root
= parse_moduleIdentity(fp
, name
);
1553 print_error("Bad parse of module identity", (char *) NULL
,
1558 np
->next
= parse_moduleIdentity(fp
, name
);
1559 if (np
->next
== NULL
) {
1560 print_error("Bad parse of module identity", (char *) NULL
,
1565 /* now find end of chain */
1568 } else if (type
== OBJID
) {
1570 /* first link in chain */
1571 np
= root
= parse_objectid(fp
, name
);
1573 print_error("Bad parse of object id", (char *) NULL
, type
);
1577 np
->next
= parse_objectid(fp
, name
);
1578 if (np
->next
== NULL
) {
1579 print_error("Bad parse of object type", (char *) NULL
,
1584 /* now find end of chain */
1587 } else if (type
== EQUALS
) {
1588 if (!parse_asntype(fp
, name
, &type
, token
)) {
1589 print_error("Bad parse of ASN type definition.", NULL
, EQUALS
);
1593 } else if (type
== ENDOFFILE
) {
1596 print_error("Bad operator", (char *) NULL
, type
);
1602 struct enum_list
*ep
;
1604 for (np
= root
; np
; np
= np
->next
) {
1605 printf("%s ::= { %s %d } (%d)\n", np
->label
, np
->parent
, np
->subid
,
1608 printf("Enums: \n");
1609 for (ep
= np
->enums
; ep
; ep
= ep
->next
) {
1610 printf("%s(%d)\n", ep
->label
, ep
->value
);
1620 * Parses a token from the file. The type of the token parsed is returned,
1621 * and the text is placed in the string pointed to by token.
1624 get_token(fp
, token
)
1628 static char last
= ' ';
1636 /* skip all white space */
1637 while (isspace(ch
) && ch
!= -1) {
1644 } else if (ch
== '"') {
1645 return parseQuoteString(fp
, token
);
1648 * Accumulate characters until end of token is found. Then attempt to
1649 * match this token as a reserved word. If a match is found, return the
1650 * type. Else it is a label.
1655 if (isspace(ch
) || ch
== '(' || ch
== ')' || ch
== '{' || ch
== '}' ||
1656 ch
== ',' || ch
== ';') {
1657 if (!isspace(ch
) && *token
== 0) {
1666 for (tp
= buckets
[BUCKET(hash
)]; tp
; tp
= tp
->next
) {
1667 if ((tp
->hash
== hash
) && (strcmp(tp
->name
, token
) == 0))
1671 if (tp
->token
== CONTINUE
)
1675 if (token
[0] == '-' && token
[1] == '-') {
1678 while ((ch
= getc(fp
)) != -1)
1687 return get_token(fp
, token
);
1689 for (cp
= token
; *cp
; cp
++)
1700 } while ((ch
= getc(fp
)) != -1);
1705 read_mib(const char *filename
)
1711 fp
= fopen(filename
, "r");
1716 fprintf(stderr
, "Mib table is bad. Exiting\n");
1719 tree
= build_tree(nodes
);
1734 fp
= fopen("mib.txt", "r");
1736 fprintf(stderr
, "open failed\n");
1740 tp
= build_tree(nodes
);
1741 print_subtree(tp
, 0);
1748 parseQuoteString(fp
, token
)
1755 *token
= '\0'; /* make the token empty */
1761 else if (ch
== '"') {
1770 * This routine parses a string like { blah blah blah } and returns OBJID if
1771 * it is well formed, and NULL if not.
1774 tossObjectIdentifier(fp
)
1780 /* ch = last; = ' '? */
1781 /* skip all white space */
1782 while (isspace(ch
) && ch
!= -1) {