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