]> git.ipfire.org Git - thirdparty/squid.git/blob - snmplib/parse.c
gindent
[thirdparty/squid.git] / snmplib / parse.c
1 /******************************************************************
2 Copyright 1989, 1991, 1992 by Carnegie Mellon University
3
4 All Rights Reserved
5
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.
13
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
20 SOFTWARE.
21 ******************************************************************/
22
23 #include "config.h"
24
25 #if HAVE_STDIO_H
26 #include <stdio.h>
27 #endif
28 #if HAVE_CTYPE_H
29 #include <ctype.h>
30 #endif
31 #if HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34 #if HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #if HAVE_STRING_H
38 #include <string.h>
39 #endif
40 #if HAVE_GNUMALLOC_H
41 #include <gnumalloc.h>
42 #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
43 #include <malloc.h>
44 #endif
45
46 #include "parse.h"
47
48 #include "util.h"
49
50 /* A quoted string value-- too long for a general "token" */
51 char *quoted_string_buffer;
52
53 /*
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.
57 */
58 struct subid {
59 int subid;
60 char *label;
61 };
62
63 /* use large token buffer in case of very long tokens: */
64 #define MAXTC 1024
65 struct tc { /* textual conventions */
66 int type;
67 char descriptor[MAXTOKEN];
68 struct enum_list *enums;
69 } tclist[MAXTC];
70
71
72
73 int Line = 1;
74
75 #define SYNTAX_MASK 0x80
76 /* types of tokens
77 * Tokens wiht the SYNTAX_MASK bit set are syntax tokens */
78 #define CONTINUE -1
79 #define ENDOFFILE 0
80 #define LABEL 1
81 #define SUBTREE 2
82 #define SYNTAX 3
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)
93 #define SEQUENCE 14
94 #define OF 15 /* SEQUENCE OF */
95 #define OBJTYPE 16
96 #define ACCESS 17
97 #define READONLY 18
98 #define READWRITE 19
99 #define WRITEONLY 20
100 #define NOACCESS 21
101 #define STATUS 22
102 #define MANDATORY 23
103 #define OPTIONAL 24
104 #define OBSOLETE 25
105 /* #define RECOMMENDED 26 */
106 #define PUNCT 27
107 #define EQUALS 28
108 #define NUMBER 29
109 #define LEFTBRACKET 30
110 #define RIGHTBRACKET 31
111 #define LEFTPAREN 32
112 #define RIGHTPAREN 33
113 #define COMMA 34
114 #define DESCRIPTION 35
115 #define QUOTESTRING 36
116 #define INDEX 37
117 #define DEFVAL 38
118 #define DEPRECATED 39
119 #define SIZE 40
120 #define BITSTRING (41 | SYNTAX_MASK)
121 #define NSAPADDRESS (42 | SYNTAX_MASK)
122 #define COUNTER64 (43 | SYNTAX_MASK)
123 #define OBJGROUP 44
124 #define NOTIFTYPE 45
125 #define AUGMENTS 46
126 #define COMPLIANCE 47
127 #define READCREATE 48
128 #define UNITS 49
129 #define REFERENCE 50
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)
136 #define CURRENT 57
137 #define DEFINITIONS 58
138 #define END 59
139 #define SEMI 60
140
141 struct tok {
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 */
147 };
148
149
150 struct tok tokens[] =
151 {
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},
178 /*
179 * This CONTINUE appends the next word onto OBJECT,
180 * hopefully matching OBJECTIDENTIFIER above.
181 */
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},
215 {NULL}
216 };
217
218 #define HASHSIZE 32
219 #define BUCKET(x) (x & 0x01F)
220
221 struct tok *buckets[HASHSIZE];
222
223 static void do_subtree();
224 static int get_token();
225 static int parseQuoteString();
226 static int tossObjectIdentifier();
227
228 static void
229 hash_init()
230 {
231 struct tok *tp;
232 char *cp;
233 int h;
234 int b;
235
236 memset(buckets, '\0', sizeof(buckets));
237 for (tp = tokens; tp->name; tp++) {
238 for (h = 0, cp = tp->name; *cp; cp++)
239 h += *cp;
240 tp->hash = h;
241 b = BUCKET(h);
242 if (buckets[b])
243 tp->next = buckets[b]; /* BUG ??? */
244 buckets[b] = tp;
245 }
246 }
247
248 #define NHASHSIZE 128
249 #define NBUCKET(x) (x & 0x7F)
250 struct node *nbuckets[NHASHSIZE];
251
252 void
253 init_node_hash(nodes)
254 struct node *nodes;
255 {
256 struct node *np, *nextp;
257 char *cp;
258 int hash;
259
260 memset(nbuckets, '\0', sizeof(nbuckets));
261 for (np = nodes; np;) {
262 nextp = np->next;
263 hash = 0;
264 for (cp = np->parent; *cp; cp++)
265 hash += *cp;
266 np->next = nbuckets[NBUCKET(hash)];
267 nbuckets[NBUCKET(hash)] = np;
268 np = nextp;
269 }
270 }
271
272 static char *
273 Malloc(num)
274 unsigned num;
275 {
276 /* this is to fix (what seems to be) a problem with the IBM RT C
277 * library malloc */
278 if (num < 16)
279 num = 16;
280 return xcalloc(1, num);
281 }
282
283 static void
284 print_error(string, token, type)
285 char *string;
286 char *token;
287 int type;
288 {
289 if (type == ENDOFFILE)
290 fprintf(stderr, "%s(EOF): On or around line %d\n", string, Line);
291 else if (token)
292 fprintf(stderr, "%s(%s): On or around line %d\n", string, token, Line);
293 else
294 fprintf(stderr, "%s: On or around line %d\n", string, Line);
295 }
296
297 #ifdef TEST
298 print_subtree(tree, count)
299 struct tree *tree;
300 int count;
301 {
302 struct tree *tp;
303 int i;
304
305 for (i = 0; i < count; i++)
306 printf(" ");
307 printf("Children of %s:\n", tree->label);
308 count++;
309 for (tp = tree->child_list; tp; tp = tp->next_peer) {
310 for (i = 0; i < count; i++)
311 printf(" ");
312 printf("%s\n", tp->label);
313 }
314 for (tp = tree->child_list; tp; tp = tp->next_peer) {
315 print_subtree(tp, count);
316 }
317 }
318 #endif /* TEST */
319
320 int translation_table[256];
321
322 void
323 build_translation_table()
324 {
325 int count;
326
327 for (count = 0; count < 256; count++) {
328 switch (count) {
329 case OBJID:
330 translation_table[count] = TYPE_OBJID;
331 break;
332 case OCTETSTR:
333 translation_table[count] = TYPE_OCTETSTR;
334 break;
335 case INTEGER:
336 translation_table[count] = TYPE_INTEGER;
337 break;
338 case NETADDR:
339 translation_table[count] = TYPE_IPADDR;
340 break;
341 case IPADDR:
342 translation_table[count] = TYPE_IPADDR;
343 break;
344 case COUNTER:
345 translation_table[count] = TYPE_COUNTER;
346 break;
347 case GAUGE:
348 translation_table[count] = TYPE_GAUGE;
349 break;
350 case TIMETICKS:
351 translation_table[count] = TYPE_TIMETICKS;
352 break;
353 case OPAQUE:
354 translation_table[count] = TYPE_OPAQUE;
355 break;
356 case NUL:
357 translation_table[count] = TYPE_NULL;
358 break;
359 case COUNTER64:
360 translation_table[count] = TYPE_COUNTER64;
361 break;
362 case BITSTRING:
363 translation_table[count] = TYPE_BITSTRING;
364 break;
365 case NSAPADDRESS:
366 translation_table[count] = TYPE_NSAPADDRESS;
367 break;
368 case UINTEGER32:
369 translation_table[count] = TYPE_UINTEGER;
370 break;
371 default:
372 translation_table[count] = TYPE_OTHER;
373 break;
374 }
375 }
376 }
377
378 static struct tree *
379 build_tree(nodes)
380 struct node *nodes;
381 {
382 struct node *np;
383 struct tree *tp, *lasttp;
384 int bucket, nodes_left = 0;
385
386 build_translation_table();
387 /* grow tree from this root node */
388 init_node_hash(nodes);
389
390 /* build root node */
391 tp = (struct tree *) Malloc(sizeof(struct tree));
392 tp->parent = NULL;
393 tp->next_peer = NULL;
394 tp->child_list = NULL;
395 tp->enums = NULL;
396 strcpy(tp->label, "joint-iso-ccitt");
397 tp->subid = 2;
398 tp->type = 0;
399 tp->description = 0;
400 /* XXX nodes isn't needed in do_subtree() ??? */
401 do_subtree(tp, &nodes);
402 lasttp = tp;
403
404 /* build root node */
405 tp = (struct tree *) Malloc(sizeof(struct tree));
406 tp->parent = NULL;
407 tp->next_peer = lasttp;
408 tp->child_list = NULL;
409 tp->enums = NULL;
410 strcpy(tp->label, "ccitt");
411 tp->subid = 0;
412 tp->type = 0;
413 tp->description = 0;
414 /* XXX nodes isn't needed in do_subtree() ??? */
415 do_subtree(tp, &nodes);
416 lasttp = tp;
417
418 /* build root node */
419 tp = (struct tree *) Malloc(sizeof(struct tree));
420 tp->parent = NULL;
421 tp->next_peer = lasttp;
422 tp->child_list = NULL;
423 tp->enums = NULL;
424 strcpy(tp->label, "iso");
425 tp->subid = 1;
426 tp->type = 0;
427 tp->description = 0;
428 /* XXX nodes isn't needed in do_subtree() ??? */
429 do_subtree(tp, &nodes);
430
431
432 #ifdef TEST
433 print_subtree(tp, 0);
434 #endif /* TEST */
435 /* If any nodes are left, the tree is probably inconsistent */
436 for (bucket = 0; bucket < NHASHSIZE; bucket++) {
437 if (nbuckets[bucket]) {
438 nodes_left = 1;
439 break;
440 }
441 }
442 if (nodes_left) {
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);
450 }
451 }
452 return tp;
453 }
454
455 /*
456 * Find all the children of root in the list of nodes. Link them into the
457 * tree and out of the nodes list.
458 */
459 static void
460 do_subtree(root, nodes)
461 struct tree *root;
462 struct node **nodes;
463 {
464 struct tree *tp;
465 struct tree *peer = NULL;
466 struct node *np, **headp;
467 struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
468 char *cp;
469 int hash;
470
471 tp = root;
472 hash = 0;
473 for (cp = tp->label; *cp; cp++)
474 hash += *cp;
475 headp = &nbuckets[NBUCKET(hash)];
476 /*
477 * Search each of the nodes for one whose parent is root, and
478 * move each into a separate list.
479 */
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".
487 */
488 break;
489 }
490 oldnp = np;
491 } else {
492 if (child_list == NULL) {
493 child_list = childp = np; /* first entry in child list */
494 } else {
495 childp->next = np;
496 childp = np;
497 }
498 /* take this node out of the node list */
499 if (oldnp == NULL) {
500 *headp = np->next; /* fix root of node list */
501 } else {
502 oldnp->next = np->next; /* link around this node */
503 }
504 }
505 }
506 if (childp)
507 childp->next = 0; /* re-terminate list */
508 /*
509 * Take each element in the child list and place it into the tree.
510 */
511 for (np = child_list; np; np = np->next) {
512 tp = (struct tree *) Malloc(sizeof(struct tree));
513 tp->parent = root;
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;
525 } else {
526 peer->next_peer = tp;
527 }
528 peer = tp;
529 /* if (tp->type == TYPE_OTHER) */
530 do_subtree(tp, nodes); /* recurse on this child if it isn't
531 * an end node */
532 }
533 /* free all nodes that were copied into tree */
534 oldnp = NULL;
535 for (np = child_list; np; np = np->next) {
536 if (oldnp)
537 free(oldnp);
538 oldnp = np;
539 }
540 if (oldnp)
541 free(oldnp);
542 }
543
544
545 /*
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.
550 */
551 static int
552 getoid(fp, oid, length)
553 FILE *fp;
554 struct subid *oid; /* an array of subids */
555 int length; /* the length of the array */
556 {
557 int count;
558 int type;
559 char token[MAXTOKEN];
560 char *cp;
561
562 if ((type = get_token(fp, token)) != LEFTBRACKET) {
563 print_error("Expected \"{\"", token, type);
564 return 0;
565 }
566 type = get_token(fp, token);
567 for (count = 0; count < length; count++, oid++) {
568 oid->label = 0;
569 oid->subid = -1;
570 if (type == RIGHTBRACKET) {
571 return count;
572 } else if (type != LABEL && type != NUMBER) {
573 print_error("Not valid for object identifier", token, type);
574 return 0;
575 }
576 if (type == LABEL) {
577 /* this entry has a label */
578 cp = (char *) Malloc((unsigned) strlen(token) + 1);
579 strcpy(cp, token);
580 oid->label = cp;
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);
588 return 0;
589 }
590 } else {
591 print_error("Expected a number", token, type);
592 return 0;
593 }
594 } else {
595 continue;
596 }
597 } else {
598 /* this entry has just an integer sub-identifier */
599 oid->subid = atoi(token);
600 }
601 type = get_token(fp, token);
602 }
603 return count;
604
605
606 }
607
608 static void
609 free_node(np)
610 struct node *np;
611 {
612 struct enum_list *ep, *tep;
613
614 ep = np->enums;
615 while (ep) {
616 tep = ep;
617 ep = ep->next;
618 free((char *) tep);
619 }
620 free((char *) np);
621 }
622
623 /*
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.
628 */
629 static struct node *
630 parse_objectid(fp, name)
631 FILE *fp;
632 char *name;
633 {
634 int type;
635 char token[MAXTOKEN];
636 int count;
637 struct subid *op, *nop;
638 int length;
639 struct subid oid[32];
640 struct node *np, *root, *oldnp = NULL;
641
642 type = get_token(fp, token);
643 if (type != EQUALS) {
644 print_error("Bad format", token, type);
645 return 0;
646 }
647 if ((length = getoid(fp, oid, 32)) != 0) {
648 np = root = (struct node *) Malloc(sizeof(struct node));
649 memset(np, '\0', sizeof(struct node));
650 /*
651 * For each parent-child subid pair in the subid array,
652 * create a node and link it into the node list.
653 */
654 for (count = 0, op = oid, nop = oid + 1; count < (length - 2); count++,
655 op++, nop++) {
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);
659 if (nop->label)
660 strcpy(np->label, nop->label);
661 if (nop->subid != -1)
662 np->subid = nop->subid;
663 np->type = 0;
664 np->enums = 0;
665 /* set up next entry */
666 np->next = (struct node *) Malloc(sizeof(*np->next));
667 memset(np->next, '\0', sizeof(struct node));
668 oldnp = np;
669 np = np->next;
670 }
671 }
672 np->next = (struct node *) NULL;
673 /*
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
676 * entry.
677 * np still points to an unused entry.
678 */
679 if (count == (length - 2)) {
680 if (op->label) {
681 strcpy(np->parent, op->label);
682 strcpy(np->label, name);
683 if (nop->subid != -1)
684 np->subid = nop->subid;
685 else
686 print_error("Warning: This entry is pretty silly",
687 np->label, type);
688 } else {
689 free_node(np);
690 if (oldnp)
691 oldnp->next = NULL;
692 else
693 return NULL;
694 }
695 } else {
696 print_error("Missing end of oid", (char *) NULL, type);
697 free_node(np); /* the last node allocated wasn't used */
698 if (oldnp)
699 oldnp->next = NULL;
700 return NULL;
701 }
702 /* free the oid array */
703 for (count = 0, op = oid; count < length; count++, op++) {
704 if (op->label)
705 free(op->label);
706 op->label = 0;
707 }
708 return root;
709 } else {
710 print_error("Bad object identifier", (char *) NULL, type);
711 return 0;
712 }
713 }
714
715 static int
716 get_tc(descriptor, ep)
717 char *descriptor;
718 struct enum_list **ep;
719 {
720 int i;
721
722 for (i = 0; i < MAXTC; i++) {
723 if (tclist[i].type == 0)
724 break;
725 if (!strcmp(descriptor, tclist[i].descriptor)) {
726 *ep = tclist[i].enums;
727 return tclist[i].type;
728 }
729 }
730 return LABEL;
731 }
732
733 /*
734 * Parses an asn type. Structures are ignored by this parser.
735 * Returns NULL on error.
736 */
737 static int
738 parse_asntype(fp, name, ntype, ntoken)
739 FILE *fp;
740 char *name;
741 int *ntype;
742 char *ntoken;
743 {
744 int type, i;
745 char token[MAXTOKEN];
746 struct enum_list *ep = 0;
747 struct tc *tcp;
748 int level;
749
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);
755 return 1;
756 }
757 }
758 print_error("Expected \"}\"", token, type);
759 return 0;
760 } else {
761 if (!strcmp(token, "TEXTUAL-CONVENTION")) {
762 while (type != SYNTAX)
763 type = get_token(fp, token);
764 type = get_token(fp, token);
765 }
766 /* textual convention */
767 for (i = 0; i < MAXTC; i++) {
768 if (tclist[i].type == 0)
769 break;
770 }
771 if (i == MAXTC) {
772 print_error("No more textual conventions possible.", token, type);
773 return 0;
774 }
775 tcp = &tclist[i];
776 strcpy(tcp->descriptor, name);
777 if (!(type & SYNTAX_MASK)) {
778 print_error("Textual convention doesn't map to real type.", token,
779 type);
780 return 0;
781 }
782 tcp->type = type;
783 *ntype = get_token(fp, ntoken);
784 if (*ntype == LEFTPAREN) {
785 level = 1;
786 /* don't record any constraints for now */
787 while (level > 0) {
788 *ntype = get_token(fp, ntoken);
789 if (*ntype == LEFTPAREN)
790 level++;
791 if (*ntype == RIGHTPAREN)
792 level--;
793 }
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)
799 break;
800 if (type == LABEL) {
801 /* this is an enumerated label */
802 if (tcp->enums == 0) {
803 ep = tcp->enums = (struct enum_list *)
804 Malloc(sizeof(struct enum_list));
805 } else {
806 ep->next = (struct enum_list *)
807 Malloc(sizeof(struct enum_list));
808 ep = ep->next;
809 }
810 ep->next = 0;
811 /* a reasonable approximation for the length */
812 ep->label =
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);
818 /* free_node(np); */
819 return 0;
820 }
821 type = get_token(fp, token);
822 if (type != NUMBER) {
823 print_error("Expected integer", token, type);
824 /* free_node(np); */
825 return 0;
826 }
827 ep->value = atoi(token);
828 type = get_token(fp, token);
829 if (type != RIGHTPAREN) {
830 print_error("Expected \")\"", token, type);
831 /* free_node(np); */
832 return 0;
833 }
834 }
835 }
836 if (type == ENDOFFILE) {
837 print_error("Expected \"}\"", token, type);
838 /* free_node(np); */
839 return 0;
840 }
841 *ntype = get_token(fp, ntoken);
842 }
843 return 1;
844 }
845 }
846
847
848 /*
849 * Parses an OBJECT TYPE macro.
850 * Returns 0 on error.
851 */
852 static struct node *
853 parse_objecttype(fp, name)
854 FILE *fp;
855 char *name;
856 {
857 int type;
858 char token[MAXTOKEN];
859 int count, length;
860 struct subid oid[32];
861 char syntax[MAXTOKEN];
862 int nexttype, tctype;
863 char nexttoken[MAXTOKEN];
864 struct node *np;
865 struct enum_list *ep = 0;
866
867 type = get_token(fp, token);
868 if (type != SYNTAX) {
869 print_error("Bad format for OBJECT TYPE", token, type);
870 return 0;
871 }
872 np = (struct node *) Malloc(sizeof(struct node));
873 np->next = 0;
874 np->enums = 0;
875 np->description = NULL; /* default to an empty description */
876 type = get_token(fp, token);
877 if (type == LABEL) {
878 tctype = get_tc(token, &(np->enums));
879 #if 0
880 if (tctype == LABEL) {
881 print_error("No known translation for type", token, type);
882 return 0;
883 }
884 #endif
885 type = tctype;
886 }
887 np->type = type;
888 nexttype = get_token(fp, nexttoken);
889 switch (type) {
890 case SEQUENCE:
891 strcpy(syntax, token);
892 if (nexttype == OF) {
893 strcat(syntax, " ");
894 strcat(syntax, nexttoken);
895 nexttype = get_token(fp, nexttoken);
896 strcat(syntax, " ");
897 strcat(syntax, nexttoken);
898 nexttype = get_token(fp, nexttoken);
899 }
900 break;
901 case INTEGER:
902 case UINTEGER32:
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)
908 break;
909 if (type == LABEL) {
910 /* this is an enumerated label */
911 if (np->enums == 0) {
912 ep = np->enums = (struct enum_list *)
913 Malloc(sizeof(struct enum_list));
914 } else {
915 ep->next = (struct enum_list *)
916 Malloc(sizeof(struct enum_list));
917 ep = ep->next;
918 }
919 ep->next = 0;
920 /* a reasonable approximation for the length */
921 ep->label =
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);
927 free_node(np);
928 return 0;
929 }
930 type = get_token(fp, token);
931 if (type != NUMBER) {
932 print_error("Expected integer", token, type);
933 free_node(np);
934 return 0;
935 }
936 ep->value = atoi(token);
937 type = get_token(fp, token);
938 if (type != RIGHTPAREN) {
939 print_error("Expected \")\"", token, type);
940 free_node(np);
941 return 0;
942 }
943 }
944 }
945 if (type == ENDOFFILE) {
946 print_error("Expected \"}\"", token, type);
947 free_node(np);
948 return 0;
949 }
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);
956 }
957 break;
958 case BITSTRING:
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)
964 break;
965 if (type == LABEL) {
966 /* this is an enumerated label */
967 if (np->enums == 0) {
968 ep = np->enums = (struct enum_list *)
969 Malloc(sizeof(struct enum_list));
970 } else {
971 ep->next = (struct enum_list *)
972 Malloc(sizeof(struct enum_list));
973 ep = ep->next;
974 }
975 ep->next = 0;
976 /* a reasonable approximation for the length */
977 ep->label =
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);
983 free_node(np);
984 return 0;
985 }
986 type = get_token(fp, token);
987 if (type != NUMBER) {
988 print_error("Expected integer", token, type);
989 free_node(np);
990 return 0;
991 }
992 ep->value = atoi(token);
993 type = get_token(fp, token);
994 if (type != RIGHTPAREN) {
995 print_error("Expected \")\"", token, type);
996 free_node(np);
997 return 0;
998 }
999 }
1000 }
1001 if (type == ENDOFFILE) {
1002 print_error("Expected \"}\"", token, type);
1003 free_node(np);
1004 return 0;
1005 }
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);
1012 }
1013 break;
1014 case OCTETSTR:
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);
1027 break;
1028 }
1029 }
1030 }
1031 print_error("Bad syntax", token, type);
1032 free_node(np);
1033 return 0;
1034 }
1035 break;
1036 case OBJID:
1037 case NETADDR:
1038 case IPADDR:
1039 case COUNTER:
1040 case GAUGE:
1041 case TIMETICKS:
1042 case OPAQUE:
1043 case NUL:
1044 case LABEL:
1045 case NSAPADDRESS:
1046 case COUNTER64:
1047 strcpy(syntax, token);
1048 break;
1049 default:
1050 print_error("Bad syntax", token, type);
1051 free_node(np);
1052 return 0;
1053 }
1054 if (nexttype == UNITS) {
1055 type = get_token(fp, token);
1056 if (type != QUOTESTRING) {
1057 print_error("Bad DESCRIPTION", token, type);
1058 free_node(np);
1059 return 0;
1060 }
1061 nexttype = get_token(fp, nexttoken);
1062 }
1063 if (nexttype != ACCESS) {
1064 print_error("Should be ACCESS", nexttoken, nexttype);
1065 free_node(np);
1066 return 0;
1067 }
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);
1072 free_node(np);
1073 return 0;
1074 }
1075 type = get_token(fp, token);
1076 if (type != STATUS) {
1077 print_error("Should be STATUS", token, nexttype);
1078 free_node(np);
1079 return 0;
1080 }
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);
1084 free_node(np);
1085 return 0;
1086 }
1087 /*
1088 * Optional parts of the OBJECT-TYPE macro
1089 */
1090 type = get_token(fp, token);
1091 while (type != EQUALS) {
1092 switch (type) {
1093 case DESCRIPTION:
1094 type = get_token(fp, token);
1095 if (type != QUOTESTRING) {
1096 print_error("Bad DESCRIPTION", token, type);
1097 free_node(np);
1098 return 0;
1099 }
1100 #ifdef TEST
1101 printf("Description== \"%.50s\"\n", quoted_string_buffer);
1102 #endif
1103 np->description = quoted_string_buffer;
1104 quoted_string_buffer = xcalloc(1, MAXQUOTESTR);
1105 break;
1106
1107 case REFERENCE:
1108 type = get_token(fp, token);
1109 if (type != QUOTESTRING) {
1110 print_error("Bad DESCRIPTION", token, type);
1111 free_node(np);
1112 return 0;
1113 }
1114 break;
1115 case INDEX:
1116 case DEFVAL:
1117 case AUGMENTS:
1118 case NUM_ENTRIES:
1119 if (tossObjectIdentifier(fp) != OBJID) {
1120 print_error("Bad Object Identifier", token, type);
1121 free_node(np);
1122 return 0;
1123 }
1124 break;
1125
1126 default:
1127 print_error("Bad format of optional clauses", token, type);
1128 free_node(np);
1129 return 0;
1130
1131 }
1132 type = get_token(fp, token);
1133 }
1134 if (type != EQUALS) {
1135 print_error("Bad format", token, type);
1136 free_node(np);
1137 return 0;
1138 }
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;
1147 else
1148 print_error("Warning: This entry is pretty silly", np->label, type);
1149 } else {
1150 print_error("No end to oid", (char *) NULL, type);
1151 free_node(np);
1152 np = 0;
1153 }
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;
1159 }
1160 return np;
1161 }
1162
1163
1164 /*
1165 * Parses an OBJECT GROUP macro.
1166 * Returns 0 on error.
1167 */
1168 static struct node *
1169 parse_objectgroup(fp, name)
1170 FILE *fp;
1171 char *name;
1172 {
1173 int type;
1174 char token[MAXTOKEN];
1175 int count, length;
1176 struct subid oid[32];
1177 struct node *np;
1178
1179 np = (struct node *) Malloc(sizeof(struct node));
1180 np->type = 0;
1181 np->next = 0;
1182 np->enums = 0;
1183 np->description = NULL; /* default to an empty description */
1184 type = get_token(fp, token);
1185 while (type != EQUALS) {
1186 switch (type) {
1187 case DESCRIPTION:
1188 type = get_token(fp, token);
1189 if (type != QUOTESTRING) {
1190 print_error("Bad DESCRIPTION", token, type);
1191 free_node(np);
1192 return 0;
1193 }
1194 #ifdef TEST
1195 printf("Description== \"%.50s\"\n", quoted_string_buffer);
1196 #endif
1197 np->description = quoted_string_buffer;
1198 quoted_string_buffer = xcalloc(1, MAXQUOTESTR);
1199 break;
1200
1201 default:
1202 /* NOTHING */
1203 break;
1204 }
1205 type = get_token(fp, token);
1206 }
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;
1215 else
1216 print_error("Warning: This entry is pretty silly", np->label, type);
1217 } else {
1218 print_error("No end to oid", (char *) NULL, type);
1219 free_node(np);
1220 np = 0;
1221 }
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;
1227 }
1228 return np;
1229 }
1230
1231 /*
1232 * Parses a NOTIFICATION-TYPE macro.
1233 * Returns 0 on error.
1234 */
1235 static struct node *
1236 parse_notificationDefinition(fp, name)
1237 FILE *fp;
1238 char *name;
1239 {
1240 int type;
1241 char token[MAXTOKEN];
1242 int count, length;
1243 struct subid oid[32];
1244 struct node *np;
1245
1246 np = (struct node *) Malloc(sizeof(struct node));
1247 np->type = 0;
1248 np->next = 0;
1249 np->enums = 0;
1250 np->description = NULL; /* default to an empty description */
1251 type = get_token(fp, token);
1252 while (type != EQUALS) {
1253 switch (type) {
1254 case DESCRIPTION:
1255 type = get_token(fp, token);
1256 if (type != QUOTESTRING) {
1257 print_error("Bad DESCRIPTION", token, type);
1258 free_node(np);
1259 return 0;
1260 }
1261 #ifdef TEST
1262 printf("Description== \"%.50s\"\n", quoted_string_buffer);
1263 #endif
1264 np->description = quoted_string_buffer;
1265 quoted_string_buffer = xcalloc(1, MAXQUOTESTR);
1266 break;
1267
1268 default:
1269 /* NOTHING */
1270 break;
1271 }
1272 type = get_token(fp, token);
1273 }
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;
1282 else
1283 print_error("Warning: This entry is pretty silly", np->label, type);
1284 } else {
1285 print_error("No end to oid", (char *) NULL, type);
1286 free_node(np);
1287 np = 0;
1288 }
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;
1294 }
1295 return np;
1296 }
1297
1298 /*
1299 * Parses a compliance macro
1300 * Returns 0 on error.
1301 */
1302 static struct node *
1303 parse_compliance(fp, name)
1304 FILE *fp;
1305 char *name;
1306 {
1307 int type;
1308 char token[MAXTOKEN];
1309 int count, length;
1310 struct subid oid[32];
1311 struct node *np;
1312
1313 np = (struct node *) Malloc(sizeof(struct node));
1314 np->type = 0;
1315 np->next = 0;
1316 np->enums = 0;
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);
1321 }
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;
1330 else
1331 print_error("Warning: This entry is pretty silly", np->label, type);
1332 } else {
1333 print_error("No end to oid", (char *) NULL, type);
1334 free_node(np);
1335 np = 0;
1336 }
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;
1342 }
1343 return np;
1344 }
1345
1346
1347
1348 /*
1349 * Parses a module identity macro
1350 * Returns 0 on error.
1351 */
1352 static struct node *
1353 parse_moduleIdentity(fp, name)
1354 FILE *fp;
1355 char *name;
1356 {
1357 int type;
1358 char token[MAXTOKEN];
1359 int count, length;
1360 struct subid oid[32];
1361 struct node *np;
1362
1363 np = (struct node *) Malloc(sizeof(struct node));
1364 np->type = 0;
1365 np->next = 0;
1366 np->enums = 0;
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);
1371 }
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;
1380 else
1381 print_error("Warning: This entry is pretty silly", np->label, type);
1382 } else {
1383 print_error("No end to oid", (char *) NULL, type);
1384 free_node(np);
1385 np = 0;
1386 }
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;
1392 }
1393 return np;
1394 }
1395
1396 int
1397 parse_mib_header(fp, name)
1398 FILE *fp;
1399 char *name;
1400 {
1401 int type = DEFINITIONS;
1402 char token[MAXTOKEN];
1403
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.
1410 */
1411 while (type != SEMI && type != ENDOFFILE) {
1412 type = get_token(fp, token);
1413 }
1414 return (type == SEMI);
1415 }
1416
1417
1418
1419 /*
1420 * Parses a mib file and returns a linked list of nodes found in the file.
1421 * Returns NULL on error.
1422 */
1423 static struct node *
1424 parse(fp)
1425 FILE *fp;
1426 {
1427 char token[MAXTOKEN];
1428 char name[MAXTOKEN];
1429 int type = 1;
1430 #define BETWEEN_MIBS 1
1431 #define IN_MIB 2
1432 int state = BETWEEN_MIBS;
1433 struct node *np = 0, *root = NULL;
1434
1435 hash_init();
1436 quoted_string_buffer = xcalloc(1, MAXQUOTESTR); /* free this later */
1437 memset(tclist, '\0', 64 * sizeof(struct tc));
1438
1439 while (type != ENDOFFILE) {
1440 type = get_token(fp, token);
1441 skipget:
1442 if (type == END) {
1443 if (state != IN_MIB) {
1444 print_error("Error, end before start of MIB.", (char *) NULL, type);
1445 return NULL;
1446 }
1447 state = BETWEEN_MIBS;
1448 continue;
1449 } else if (type != LABEL) {
1450 if (type == ENDOFFILE) {
1451 return root;
1452 }
1453 print_error(token, "is a reserved word", type);
1454 return NULL;
1455 }
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);
1461 return NULL;
1462 }
1463 state = IN_MIB;
1464 if (!parse_mib_header(fp, name)) {
1465 print_error("Bad parse of module header", (char *) NULL, type);
1466 return NULL;
1467 }
1468 } else if (type == OBJTYPE) {
1469 if (root == NULL) {
1470 /* first link in chain */
1471 np = root = parse_objecttype(fp, name);
1472 if (np == NULL) {
1473 print_error("Bad parse of object type", (char *) NULL,
1474 type);
1475 return NULL;
1476 }
1477 } else {
1478 np->next = parse_objecttype(fp, name);
1479 if (np->next == NULL) {
1480 print_error("Bad parse of objecttype", (char *) NULL,
1481 type);
1482 return NULL;
1483 }
1484 }
1485 /* now find end of chain */
1486 while (np->next)
1487 np = np->next;
1488 } else if (type == OBJGROUP) {
1489 if (root == NULL) {
1490 /* first link in chain */
1491 np = root = parse_objectgroup(fp, name);
1492 if (np == NULL) {
1493 print_error("Bad parse of object group", (char *) NULL,
1494 type);
1495 return NULL;
1496 }
1497 } else {
1498 np->next = parse_objectgroup(fp, name);
1499 if (np->next == NULL) {
1500 print_error("Bad parse of objectgroup", (char *) NULL,
1501 type);
1502 return NULL;
1503 }
1504 }
1505 /* now find end of chain */
1506 while (np->next)
1507 np = np->next;
1508 } else if (type == NOTIFTYPE) {
1509 if (root == NULL) {
1510 /* first link in chain */
1511 np = root = parse_notificationDefinition(fp, name);
1512 if (np == NULL) {
1513 print_error("Bad parse of notification definition",
1514 (char *) NULL, type);
1515 return NULL;
1516 }
1517 } else {
1518 np->next = parse_notificationDefinition(fp, name);
1519 if (np->next == NULL) {
1520 print_error("Bad parse of notification definition",
1521 (char *) NULL, type);
1522 return NULL;
1523 }
1524 }
1525 /* now find end of chain */
1526 while (np->next)
1527 np = np->next;
1528 } else if (type == COMPLIANCE) {
1529 if (root == NULL) {
1530 /* first link in chain */
1531 np = root = parse_compliance(fp, name);
1532 if (np == NULL) {
1533 print_error("Bad parse of module compliance", (char *) NULL,
1534 type);
1535 return NULL;
1536 }
1537 } else {
1538 np->next = parse_compliance(fp, name);
1539 if (np->next == NULL) {
1540 print_error("Bad parse of module compliance", (char *) NULL,
1541 type);
1542 return NULL;
1543 }
1544 }
1545 /* now find end of chain */
1546 while (np->next)
1547 np = np->next;
1548 } else if (type == MODULEIDENTITY) {
1549 if (root == NULL) {
1550 /* first link in chain */
1551 np = root = parse_moduleIdentity(fp, name);
1552 if (np == NULL) {
1553 print_error("Bad parse of module identity", (char *) NULL,
1554 type);
1555 return NULL;
1556 }
1557 } else {
1558 np->next = parse_moduleIdentity(fp, name);
1559 if (np->next == NULL) {
1560 print_error("Bad parse of module identity", (char *) NULL,
1561 type);
1562 return NULL;
1563 }
1564 }
1565 /* now find end of chain */
1566 while (np->next)
1567 np = np->next;
1568 } else if (type == OBJID) {
1569 if (root == NULL) {
1570 /* first link in chain */
1571 np = root = parse_objectid(fp, name);
1572 if (np == NULL) {
1573 print_error("Bad parse of object id", (char *) NULL, type);
1574 return NULL;
1575 }
1576 } else {
1577 np->next = parse_objectid(fp, name);
1578 if (np->next == NULL) {
1579 print_error("Bad parse of object type", (char *) NULL,
1580 type);
1581 return NULL;
1582 }
1583 }
1584 /* now find end of chain */
1585 while (np->next)
1586 np = np->next;
1587 } else if (type == EQUALS) {
1588 if (!parse_asntype(fp, name, &type, token)) {
1589 print_error("Bad parse of ASN type definition.", NULL, EQUALS);
1590 return NULL;
1591 }
1592 goto skipget;
1593 } else if (type == ENDOFFILE) {
1594 break;
1595 } else {
1596 print_error("Bad operator", (char *) NULL, type);
1597 return NULL;
1598 }
1599 }
1600 #ifdef TEST
1601 {
1602 struct enum_list *ep;
1603
1604 for (np = root; np; np = np->next) {
1605 printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
1606 np->type);
1607 if (np->enums) {
1608 printf("Enums: \n");
1609 for (ep = np->enums; ep; ep = ep->next) {
1610 printf("%s(%d)\n", ep->label, ep->value);
1611 }
1612 }
1613 }
1614 }
1615 #endif /* TEST */
1616 return root;
1617 }
1618
1619 /*
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.
1622 */
1623 static int
1624 get_token(fp, token)
1625 FILE *fp;
1626 char *token;
1627 {
1628 static char last = ' ';
1629 int ch;
1630 char *cp = token;
1631 int hash = 0;
1632 struct tok *tp;
1633
1634 *cp = 0;
1635 ch = last;
1636 /* skip all white space */
1637 while (isspace(ch) && ch != -1) {
1638 ch = getc(fp);
1639 if (ch == '\n')
1640 Line++;
1641 }
1642 if (ch == -1) {
1643 return ENDOFFILE;
1644 } else if (ch == '"') {
1645 return parseQuoteString(fp, token);
1646 }
1647 /*
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.
1651 */
1652 do {
1653 if (ch == '\n')
1654 Line++;
1655 if (isspace(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
1656 ch == ',' || ch == ';') {
1657 if (!isspace(ch) && *token == 0) {
1658 hash += ch;
1659 *cp++ = ch;
1660 last = ' ';
1661 } else {
1662 last = ch;
1663 }
1664 *cp = '\0';
1665
1666 for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
1667 if ((tp->hash == hash) && (strcmp(tp->name, token) == 0))
1668 break;
1669 }
1670 if (tp) {
1671 if (tp->token == CONTINUE)
1672 continue;
1673 return (tp->token);
1674 }
1675 if (token[0] == '-' && token[1] == '-') {
1676 /* strip comment */
1677 if (ch != '\n') {
1678 while ((ch = getc(fp)) != -1)
1679 if (ch == '\n') {
1680 Line++;
1681 break;
1682 }
1683 }
1684 if (ch == -1)
1685 return ENDOFFILE;
1686 last = ch;
1687 return get_token(fp, token);
1688 }
1689 for (cp = token; *cp; cp++)
1690 if (!isdigit(*cp))
1691 return LABEL;
1692 return NUMBER;
1693 } else {
1694 hash += ch;
1695 *cp++ = ch;
1696 if (ch == '\n')
1697 Line++;
1698 }
1699
1700 } while ((ch = getc(fp)) != -1);
1701 return ENDOFFILE;
1702 }
1703
1704 struct tree *
1705 read_mib(const char *filename)
1706 {
1707 FILE *fp;
1708 struct node *nodes;
1709 struct tree *tree;
1710
1711 fp = fopen(filename, "r");
1712 if (fp == NULL)
1713 return NULL;
1714 nodes = parse(fp);
1715 if (!nodes) {
1716 fprintf(stderr, "Mib table is bad. Exiting\n");
1717 exit(1);
1718 }
1719 tree = build_tree(nodes);
1720 fclose(fp);
1721 return tree;
1722 }
1723
1724
1725 #ifdef TEST
1726 main(argc, argv)
1727 int argc;
1728 char *argv[];
1729 {
1730 FILE *fp;
1731 struct node *nodes;
1732 struct tree *tp;
1733
1734 fp = fopen("mib.txt", "r");
1735 if (fp == NULL) {
1736 fprintf(stderr, "open failed\n");
1737 return 1;
1738 }
1739 nodes = parse(fp);
1740 tp = build_tree(nodes);
1741 print_subtree(tp, 0);
1742 fclose(fp);
1743 }
1744
1745 #endif /* TEST */
1746
1747 static int
1748 parseQuoteString(fp, token)
1749 FILE *fp;
1750 char *token;
1751 {
1752 int ch;
1753
1754 ch = ' ';
1755 *token = '\0'; /* make the token empty */
1756
1757 while (ch != -1) {
1758 ch = getc(fp);
1759 if (ch == '\n')
1760 Line++;
1761 else if (ch == '"') {
1762 return QUOTESTRING;
1763 }
1764 }
1765
1766 return 0;
1767 }
1768
1769 /*
1770 * This routine parses a string like { blah blah blah } and returns OBJID if
1771 * it is well formed, and NULL if not.
1772 */
1773 static int
1774 tossObjectIdentifier(fp)
1775 FILE *fp;
1776 {
1777 int ch;
1778
1779 ch = getc(fp);
1780 /* ch = last; = ' '? */
1781 /* skip all white space */
1782 while (isspace(ch) && ch != -1) {
1783 ch = getc(fp);
1784 if (ch == '\n')
1785 Line++;
1786 }
1787 if (ch != '{')
1788 return 0;
1789
1790 while (ch != -1) {
1791 ch = getc(fp);
1792
1793 if (ch == '\n')
1794 Line++;
1795 else if (ch == '}')
1796 return OBJID;
1797 }
1798
1799 /* last = ch; */
1800 return 0;
1801 }