1 /*
2 * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 #pragma ident "%Z%%M% %I% %E% SMI"
6
7 /******************************************************************
8 Copyright 1989, 1991, 1992 by Carnegie Mellon University
9
10 All Rights Reserved
11
12 Permission to use, copy, modify, and distribute this software and its
13 documentation for any purpose and without fee is hereby granted,
14 provided that the above copyright notice appear in all copies and that
15 both that copyright notice and this permission notice appear in
16 supporting documentation, and that the name of CMU not be
17 used in advertising or publicity pertaining to distribution of the
18 software without specific, written prior permission.
19
20 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26 SOFTWARE.
27 ******************************************************************/
28 /*
29 * parse.c
30 */
31
32 /* HISTORY
33 * Jerry Yeung 6-6-96
34 * Jerry Yeung 1-9-97 fix 4019317
35 */
36
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <stdlib.h>
40 #include <sys/types.h>
41 #include "parse.h"
42
43 struct trap_item *trap_list = NULL;
44
45 /* A quoted string value-- too long for a general "token" */
46 char *quoted_string_buffer;
47
48 /*
49 * This is one element of an object identifier with either an integer
50 * subidentifier, or a textual string label, or both.
51 * The subid is -1 if not present, and label is NULL if not present.
52 */
53 struct subid {
54 int subid;
55 char *label;
56 };
57
58 #define MAXTC 128
59 struct tc { /* textual conventions */
60 int type;
61 char descriptor[MAXTOKEN];
62 struct enum_list *enums;
63 } tclist[MAXTC];
64
65
66
67 int Line = 1;
68
69 #define SYNTAX_MASK 0x80
70 /* types of tokens
71 Tokens wiht the SYNTAX_MASK bit set are syntax tokens */
72 #define CONTINUE -1
73 #define ENDOFFILE 0
74 #define LABEL 1
75 #define SUBTREE 2
76 #define SYNTAX 3
77 #define PARSE_OBJID (4 | SYNTAX_MASK)
78 #define OCTETSTR (5 | SYNTAX_MASK)
79 #define PARSE_INTEGER (6 | SYNTAX_MASK)
80 #define NETADDR (7 | SYNTAX_MASK)
81 #define IPADDR (8 | SYNTAX_MASK)
82 #define PARSE_COUNTER (9 | SYNTAX_MASK)
83 #define PARSE_GUAGE (10 | SYNTAX_MASK)
84 #define PARSE_TIMETICKS (11 | SYNTAX_MASK)
85 #define PARSE_OPAQUE (12 | SYNTAX_MASK)
86 #define NUL (13 | SYNTAX_MASK)
87 #define SEQUENCE 14
88 #define OF 15 /* SEQUENCE OF */
89 #define OBJTYPE 16
90 #define ACCESS 17
91 #define READONLY 18
92 #define READWRITE 19
93 #define WRITEONLY 20
94 #define NOACCESS 21
95 #define STATUS 22
96 #define MANDATORY 23
97 #define OPTIONAL 24
98 #define OBSOLETE 25
99 /* #define RECOMMENDED 26 */
100 #define PUNCT 27
101 #define EQUALS 28
102 #define NUMBER 29
103 #define LEFTBRACKET 30
104 #define RIGHTBRACKET 31
105 #define LEFTPAREN 32
106 #define RIGHTPAREN 33
107 #define COMMA 34
108 #define DESCRIPTION 35
109 #define QUOTESTRING 36
110 #define INDEX 37
111 #define DEFVAL 38
112 #define DEPRECATED 39
113 #define SIZE 40
114 #define BITSTRING (41 | SYNTAX_MASK)
115 #define NSAPADDRESS (42 | SYNTAX_MASK)
116 #define PARSE_COUNTER64 (43 | SYNTAX_MASK)
117 #define OBJGROUP 44
118 #define NOTIFTYPE 45
119 #define AUGMENTS 46
120 #define COMPLIANCE 47
121 #define READCREATE 48
122 #define UNITS 49
123 #define REFERENCE 50
124 #define NUM_ENTRIES 51
125 #define MODULEIDENTITY 52
126 #define LASTUPDATED 53
127 #define ORGANIZATION 54
128 #define CONTACTINFO 55
129 #define UINTEGER32 (56 | SYNTAX_MASK)
130 #define CURRENT 57
131 #define DEFINITIONS 58
132 #define END 59
133 #define SEMI 60
134
135 /*
136 -- Olivier Reisacher 95/2/14
137 */
138 #define PSEUDO_TOKEN_TABLE 61
139 #define PSEUDO_TOKEN_ENTRY 62
140
141 /* Jerry Yeung 6-6-96 (trap-support) */
142 #define TRAPTYPE 63
143 #define ENTERPRISE 64
144 #define VARIABLES 65
145
146 struct tok {
147 char *name; /* token name */
148 int len; /* length not counting nul */
149 int token; /* value */
150 int hash; /* hash of name */
151 struct tok *next; /* pointer to next in hash table */
152 };
153
154
155 struct tok tokens[] = {
156 { "obsolete", sizeof ("obsolete")-1, OBSOLETE },
157 { "Opaque", sizeof ("Opaque")-1, PARSE_OPAQUE },
158 /* { "recommended", sizeof("recommended")-1, RECOMMENDED }, */
159 { "optional", sizeof ("optional")-1, OPTIONAL },
160 { "LAST-UPDATED", sizeof ("LAST-UPDATED")-1, LASTUPDATED },
161 { "ORGANIZATION", sizeof ("ORGANIZATION")-1, ORGANIZATION },
162 { "CONTACT-INFO", sizeof ("CONTACT-INFO")-1, CONTACTINFO },
163 { "MODULE-IDENTITY", sizeof ("MODULE-IDENTITY")-1, MODULEIDENTITY },
164 { "MODULE-COMPLIANCE", sizeof ("MODULE-COMPLIANCE")-1, COMPLIANCE },
165 { "DEFINITIONS", sizeof("DEFINITIONS")-1, DEFINITIONS},
166 { "END", sizeof("END")-1, END},
167 { ";", sizeof(";")-1, SEMI},
168 { "AUGMENTS", sizeof ("AUGMENTS")-1, AUGMENTS },
169 { "not-accessible", sizeof ("not-accessible")-1, NOACCESS },
170 { "write-only", sizeof ("write-only")-1, WRITEONLY },
171 { "NsapAddress", sizeof("NsapAddress")-1, NSAPADDRESS},
172 { "UNITS", sizeof("Units")-1, UNITS},
173 { "REFERENCE", sizeof("REFERENCE")-1, REFERENCE},
174 { "NUM-ENTRIES", sizeof("NUM-ENTRIES")-1, NUM_ENTRIES},
175 { "BITSTRING", sizeof("BitString")-1, BITSTRING},
176 { "BIT", sizeof("BIT")-1, CONTINUE},
177 { "Counter64", sizeof("Counter64")-1, PARSE_COUNTER64},
178 { "TimeTicks", sizeof ("TimeTicks")-1, PARSE_TIMETICKS },
179 { "NOTIFICATION-TYPE", sizeof ("NOTIFICATION-TYPE")-1, NOTIFTYPE },
180 { "OBJECT-GROUP", sizeof ("OBJECT-GROUP")-1, OBJGROUP },
181 { "OBJECTIDENTIFIER", sizeof ("OBJECTIDENTIFIER")-1, PARSE_OBJID },
182 /*
183 * This CONTINUE appends the next word onto OBJECT,
184 * hopefully matching OBJECTIDENTIFIER above.
185 */
186 { "OBJECT", sizeof ("OBJECT")-1, CONTINUE },
187 { "NetworkAddress", sizeof ("NetworkAddress")-1, NETADDR },
188 { "Gauge", sizeof ("Gauge")-1, PARSE_GUAGE },
189 { "read-write", sizeof ("read-write")-1, READWRITE },
190 { "read-create", sizeof ("read-create")-1, READCREATE },
191 { "OCTETSTRING", sizeof ("OCTETSTRING")-1, OCTETSTR },
192 { "OCTET", sizeof ("OCTET")-1, -1 },
193 { "OF", sizeof ("OF")-1, OF },
194 { "SEQUENCE", sizeof ("SEQUENCE")-1, SEQUENCE },
195 { "NULL", sizeof ("NULL")-1, NUL },
196 { "IpAddress", sizeof ("IpAddress")-1, IPADDR },
197 { "UInteger32", sizeof ("UInteger32")-1, UINTEGER32 },
198 { "INTEGER", sizeof ("INTEGER")-1, PARSE_INTEGER },
199 { "Counter", sizeof ("Counter")-1, PARSE_COUNTER },
200 { "read-only", sizeof ("read-only")-1, READONLY },
201 { "DESCRIPTION", sizeof ("DESCRIPTION")-1, DESCRIPTION },
202 { "INDEX", sizeof ("INDEX")-1, INDEX },
203 { "DEFVAL", sizeof ("DEFVAL")-1, DEFVAL },
204 { "deprecated", sizeof ("deprecated")-1, DEPRECATED },
205 { "SIZE", sizeof ("SIZE")-1, SIZE },
206 { "MAX-ACCESS", sizeof ("MAX-ACCESS")-1, ACCESS },
207 { "ACCESS", sizeof ("ACCESS")-1, ACCESS },
208 { "mandatory", sizeof ("mandatory")-1, MANDATORY },
209 { "current", sizeof ("current")-1, CURRENT },
210 { "STATUS", sizeof ("STATUS")-1, STATUS },
211 { "SYNTAX", sizeof ("SYNTAX")-1, SYNTAX },
212 { "OBJECT-TYPE", sizeof ("OBJECT-TYPE")-1, OBJTYPE },
213 { "{", sizeof ("{")-1, LEFTBRACKET },
214 { "}", sizeof ("}")-1, RIGHTBRACKET },
215 { "::=", sizeof ("::=")-1, EQUALS },
216 { "(", sizeof ("(")-1, LEFTPAREN },
217 { ")", sizeof (")")-1, RIGHTPAREN },
218 { ",", sizeof (",")-1, COMMA },
219 { "TRAP-TYPE", sizeof ("TRAP-TYPE")-1, TRAPTYPE },
220 { "ENTERPRISE", sizeof ("ENTERPRISE")-1, ENTERPRISE },
221 { "VARIABLES", sizeof ("VARIABLES")-1, VARIABLES },
222 { NULL }
223 };
224
225 #define HASHSIZE 32
226 #define BUCKET(x) (x & 0x01F)
227
228 struct tok *buckets[HASHSIZE];
229 static void
230 do_subtree(struct tree *root, struct node **nodes);
231 static int
232 get_token(register FILE *fp, register char *token);
233 static int
234 parseQuoteString(register FILE *fp, register char *token);
235 static int
236 tossObjectIdentifier(register FILE *fp);
237
238 int number_value;
239
240 static void
hash_init()241 hash_init()
242 {
243 register struct tok *tp;
244 register char *cp;
245 register int h;
246 register int b;
247
248 /*
249 -- Olivier Reisacher 95/2/14
250 bzero((char *)buckets, sizeof(buckets));
251 */
252 memset((void *) buckets, 0, sizeof(buckets));
253
254 for (tp = tokens; tp->name; tp++) {
255 for (h = 0, cp = tp->name; *cp; cp++)
256 h += *cp;
257 tp->hash = h;
258 b = BUCKET(h);
259 if (buckets[b])
260 tp->next = buckets[b]; /* BUG ??? */
261 buckets[b] = tp;
262 }
263 }
264
265 #define NHASHSIZE 128
266 #define NBUCKET(x) (x & 0x7F)
267 struct node *nbuckets[NHASHSIZE];
268
init_node_hash(nodes)269 void init_node_hash(nodes)
270 struct node *nodes;
271 {
272 register struct node *np, *nextp;
273 register char *cp;
274 register int hash;
275
276 /*
277 -- Olivier Reisacher 95/2/14
278 bzero((char *)nbuckets,sizeof(nbuckets));
279 */
280 memset((void *) nbuckets, 0, sizeof(nbuckets));
281
282 for(np = nodes; np;){
283 nextp = np->next;
284 hash = 0;
285 for(cp = np->parent; *cp; cp++)
286 hash += *cp;
287 np->next = nbuckets[NBUCKET(hash)];
288 nbuckets[NBUCKET(hash)] = np;
289 np = nextp;
290 }
291 }
292
293 static char *
Malloc(num)294 Malloc(num)
295 unsigned num;
296 {
297 char *buf;
298
299 /* this is to fix (what seems to be) a problem with the IBM RT C
300 library malloc */
301 if (num < 16)
302 num = 16;
303 buf = (char *)malloc (num);
304 if (buf == NULL) {
305 fprintf(stderr, "malloc failed. Exiting\n");
306 exit(1);
307 }
308 return (char *)buf;
309 }
310
311 static void
print_error(string,token,type)312 print_error(string, token, type)
313 char *string;
314 char *token;
315 int type;
316 {
317 if (type == ENDOFFILE)
318 fprintf(stderr, "%s(EOF): On or around line %d\n", string, Line);
319 else if (token)
320 fprintf(stderr, "%s(%s): On or around line %d\n", string, token, Line);
321 else
322 fprintf(stderr, "%s: On or around line %d\n", string, Line);
323 }
324
325 /*
326 -- Olivier Reisacher 95/2/14
327 #ifdef TEST
328 print_subtree(tree, count)
329 */
print_subtree(tree,count)330 void print_subtree(tree, count)
331 struct tree *tree;
332 int count;
333 {
334 struct tree *tp;
335 int i;
336
337 for(i = 0; i < count; i++)
338 printf(" ");
339 printf("Children of %s:\n", tree->label);
340 count++;
341 for(tp = tree->child_list; tp; tp = tp->next_peer){
342 for(i = 0; i < count; i++)
343 printf(" ");
344 printf("%s\n", tp->label);
345 }
346 for(tp = tree->child_list; tp; tp = tp->next_peer){
347 print_subtree(tp, count);
348 }
349 }
350 /*
351 -- Olivier Reisacher 95/2/14
352 #endif
353 */
354
355 int translation_table[256];
356
build_translation_table()357 void build_translation_table(){
358 int count;
359
360 for(count = 0; count < 256; count++){
361 switch(count){
362 case PARSE_OBJID:
363 translation_table[count] = TYPE_OBJID;
364 break;
365 case OCTETSTR:
366 translation_table[count] = TYPE_OCTETSTR;
367 break;
368 case PARSE_INTEGER:
369 translation_table[count] = TYPE_INTEGER;
370 break;
371 case NETADDR:
372 translation_table[count] = TYPE_IPADDR;
373 break;
374 case IPADDR:
375 translation_table[count] = TYPE_IPADDR;
376 break;
377 case PARSE_COUNTER:
378 translation_table[count] = TYPE_COUNTER;
379 break;
380 case PARSE_GUAGE:
381 translation_table[count] = TYPE_GAUGE;
382 break;
383 case PARSE_TIMETICKS:
384 translation_table[count] = TYPE_TIMETICKS;
385 break;
386 case PARSE_OPAQUE:
387 translation_table[count] = TYPE_OPAQUE;
388 break;
389 case NUL:
390 translation_table[count] = TYPE_NULL;
391 break;
392 case PARSE_COUNTER64:
393 translation_table[count] = TYPE_COUNTER64;
394 break;
395 case BITSTRING:
396 translation_table[count] = TYPE_BITSTRING;
397 break;
398 case NSAPADDRESS:
399 translation_table[count] = TYPE_NSAPADDRESS;
400 break;
401 case UINTEGER32:
402 translation_table[count] = TYPE_UINTEGER;
403 break;
404
405 /*
406 -- Olivier Reisacher 95/2/14
407 */
408 case PSEUDO_TOKEN_TABLE:
409 translation_table[count] = TYPE_TABLE;
410 break;
411 case PSEUDO_TOKEN_ENTRY:
412 translation_table[count] = TYPE_ENTRY;
413 break;
414
415 default:
416 translation_table[count] = TYPE_OTHER;
417 break;
418 }
419 }
420 }
421
422 /*
423 -- Olivier Reisacher 95/2/14
424 static struct tree *
425 */
426 struct tree *
build_tree(nodes)427 build_tree(nodes)
428 struct node *nodes;
429 {
430 struct node *np;
431 struct tree *tp;
432 int bucket, nodes_left = 0;
433
434 build_translation_table();
435 /* grow tree from this root node */
436 init_node_hash(nodes);
437
438 /*
439 -- Olivier Reisacher 95/2/14
440 build root node
441 tp = (struct tree *)Malloc(sizeof(struct tree));
442 tp->parent = NULL;
443 tp->next_peer = NULL;
444 tp->child_list = NULL;
445 tp->enums = NULL;
446 strcpy(tp->label, "joint-iso-ccitt");
447 tp->subid = 2;
448 tp->type = 0;
449 tp->description = 0;
450 XXX nodes isn't needed in do_subtree() ???
451 do_subtree(tp, &nodes);
452 lasttp = tp;
453
454 build root node
455 tp = (struct tree *)Malloc(sizeof(struct tree));
456 tp->parent = NULL;
457 tp->next_peer = lasttp;
458 tp->child_list = NULL;
459 tp->enums = NULL;
460 strcpy(tp->label, "ccitt");
461 tp->subid = 0;
462 tp->type = 0;
463 tp->description = 0;
464 XXX nodes isn't needed in do_subtree() ???
465 do_subtree(tp, &nodes);
466 lasttp = tp;
467 */
468
469 /* build root node */
470 tp = (struct tree *)Malloc(sizeof(struct tree));
471 tp->parent = NULL;
472 /*
473 -- Olivier Reisacher 95/2/14
474 tp->next_peer = lasttp;
475 */
476 tp->next_peer = NULL;
477 tp->child_list = NULL;
478 tp->enums = NULL;
479 strcpy(tp->label, "iso");
480 tp->subid = 1;
481 tp->type = 0;
482 tp->description = 0;
483 /* XXX nodes isn't needed in do_subtree() ??? */
484 do_subtree(tp, &nodes);
485 /*
486 -- Olivier Reisacher 95/2/14
487 */
488 tp->access = 0;
489 tp->indexs = NULL;
490 tp->n_indexs = 0;
491
492
493 #ifdef TEST
494 print_subtree(tp, 0);
495 #endif /* TEST */
496 /* If any nodes are left, the tree is probably inconsistent */
497 for(bucket = 0; bucket < NHASHSIZE; bucket++){
498 if (nbuckets[bucket]){
499 nodes_left = 1;
500 break;
501 }
502 }
503 if (nodes_left){
504 fprintf(stderr, "The mib description doesn't seem to be consistent.\n");
505 fprintf(stderr, "Some nodes couldn't be linked under the \"iso\" tree.\n");
506 fprintf(stderr, "these nodes are left:\n");
507 for(bucket = 0; bucket < NHASHSIZE; bucket++){
508 for(np = nbuckets[bucket]; np; np = np->next)
509 fprintf(stderr, "%s ::= { %s %d } (%d)\n", np->label,
510 np->parent, np->subid, np->type);
511 }
512 }
513 return tp;
514 }
515
516 /*
517 * Find all the children of root in the list of nodes. Link them into the
518 * tree and out of the nodes list.
519 */
520 static void
do_subtree(root,nodes)521 do_subtree(root, nodes)
522 struct tree *root;
523 struct node **nodes;
524 {
525 register struct tree *tp;
526 register struct node *np, **headp;
527 struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
528 char *cp;
529 int hash;
530
531 tp = root;
532 hash = 0;
533 for(cp = tp->label; *cp; cp++)
534 hash += *cp;
535 headp = &nbuckets[NBUCKET(hash)];
536 /*
537 * Search each of the nodes for one whose parent is root, and
538 * move each into a separate list.
539 */
540 for(np = *headp; np; np = np->next){
541 if ((*tp->label != *np->parent) || strcmp(tp->label, np->parent)){
542 if ((*tp->label == *np->label) && !strcmp(tp->label, np->label)){
543 /* if there is another node with the same label, assume that
544 * any children after this point in the list belong to the other node.
545 * This adds some scoping to the table and allows vendors to
546 * reuse names such as "ip".
547 */
548 break;
549 }
550 oldnp = np;
551 } else {
552 if (child_list == NULL){
553 child_list = childp = np; /* first entry in child list */
554 } else {
555 childp->next = np;
556 childp = np;
557 }
558 /* take this node out of the node list */
559 if (oldnp == NULL){
560 *headp = np->next; /* fix root of node list */
561 } else {
562 oldnp->next = np->next; /* link around this node */
563 }
564 }
565 }
566 if (childp)
567 childp->next = 0; /* re-terminate list */
568 /*
569 * Take each element in the child list and place it into the tree.
570 */
571 for(np = child_list; np; np = np->next){
572 tp = (struct tree *)Malloc(sizeof(struct tree));
573 tp->parent = root;
574 tp->next_peer = NULL;
575 tp->child_list = NULL;
576 strcpy(tp->label, np->label);
577 tp->subid = np->subid;
578 tp->type = translation_table[np->type];
579 tp->oct_str_len = np->oct_str_len;
580 tp->enums = np->enums;
581 np->enums = NULL; /* so we don't free them later */
582 tp->description = np->description; /* steals memory from np */
583 np->description = NULL; /* so we don't free it later */
584 /*
585 -- Olivier Reisacher 95/2/14
586 */
587 tp->access = np->access;
588 tp->indexs = np->indexs;
589 np->indexs = NULL;
590 tp->n_indexs = np->n_indexs;
591 /*
592 -- Olivier Reisacher 95/2/14
593 -- The goal of this modification is to order the
594 -- tree according to the subid
595
596 if (root->child_list == NULL){
597 root->child_list = tp;
598 } else {
599 peer->next_peer = tp;
600 }
601 peer = tp;
602 */
603 if(root->child_list == NULL)
604 {
605 root->child_list = tp;
606 }
607 else
608 {
609 struct tree *t = root->child_list;
610 struct tree *l = NULL;
611
612 while(t)
613 {
614 if(tp->subid < t->subid)
615 {
616 break;
617 }
618 l = t;
619 t = t->next_peer;
620 }
621 if(l == NULL)
622 {
623 tp->next_peer = root->child_list;
624 root->child_list = tp;
625 }
626 else
627 {
628 tp->next_peer = l->next_peer;
629 l->next_peer = tp;
630 }
631 }
632
633 /* if (tp->type == TYPE_OTHER) */
634 do_subtree(tp, nodes); /* recurse on this child if it isn't
635 an end node */
636 }
637 /* free all nodes that were copied into tree */
638 oldnp = NULL;
639 for(np = child_list; np; np = np->next){
640 if (oldnp)
641 free(oldnp);
642 oldnp = np;
643 }
644 if (oldnp)
645 free(oldnp);
646 }
647
648
649 /*
650 * Takes a list of the form:
651 * { iso org(3) dod(6) 1 }
652 * and creates several nodes, one for each parent-child pair.
653 * Returns NULL on error.
654 */
655 static int
getoid(fp,oid,length)656 getoid(fp, oid, length)
657 register FILE *fp;
658 register struct subid *oid; /* an array of subids */
659 int length; /* the length of the array */
660 {
661 register int count;
662 int type;
663 char token[MAXTOKEN];
664 register char *cp;
665
666 #ifdef TRACE_PROC
667 printf("getoid() invoked\n");
668 #endif
669
670 if ((type = get_token(fp, token)) != LEFTBRACKET){
671 print_error("Expected \"{\"", token, type);
672 return NULL;
673 }
674 type = get_token(fp, token);
675 for(count = 0; count < length; count++, oid++){
676 oid->label = 0;
677 oid->subid = -1;
678 if (type == RIGHTBRACKET){
679 return count;
680 } else if (type != LABEL && type != NUMBER){
681 print_error("Not valid for object identifier", token, type);
682 return NULL;
683 }
684 if (type == LABEL){
685 /* this entry has a label */
686 cp = (char *)Malloc((unsigned)strlen(token) + 1);
687 strcpy(cp, token);
688 oid->label = cp;
689 type = get_token(fp, token);
690 if (type == LEFTPAREN){
691 type = get_token(fp, token);
692 if (type == NUMBER){
693 oid->subid = atoi(token);
694 if ((type = get_token(fp, token)) != RIGHTPAREN){
695 print_error("Unexpected a closing parenthesis", token, type);
696 return NULL;
697 }
698 } else {
699 print_error("Expected a number", token, type);
700 return NULL;
701 }
702 } else {
703 continue;
704 }
705 } else {
706 /* this entry has just an integer sub-identifier */
707 oid->subid = atoi(token);
708 }
709 type = get_token(fp, token);
710 }
711 return count;
712
713
714 }
715
716 static void
free_node(np)717 free_node(np)
718 struct node *np;
719 {
720 struct enum_list *ep, *tep;
721 /*
722 -- Olivier Reisacher 95/2/14
723 */
724 struct index_list *ip, *tip;
725
726 ip = np->indexs;
727 while(ip)
728 {
729 tip = ip;
730 ip = ip->next;
731 free((char *)tip);
732 }
733
734
735 ep = np->enums;
736 while(ep){
737 tep = ep;
738 ep = ep->next;
739 free((char *)tep);
740 }
741 free((char *)np);
742 }
743
parse_traptype(fp,name)744 int parse_traptype(fp,name)
745 FILE *fp;
746 char *name;
747 {
748 int type;
749 char token[MAXTOKEN];
750 struct trap_item *ti;
751 struct index_list *ip;
752 static struct trap_item *last_trap_item=NULL;
753
754 #ifdef TRACE_PROC
755 printf("parse_traptype() invoked\n");
756 #endif
757
758 type = get_token(fp,token);
759 if( type == ENTERPRISE){
760 if( (type = get_token(fp,token)) == LABEL){
761 /* create a trap item */
762 ti = (struct trap_item*)calloc(1, sizeof(struct trap_item));
763 if(ti==NULL){
764 fprintf(stderr,"calloc failed\n");
765 return 0;
766 }
767 strcpy(ti->label,name);
768 strcpy(ti->enterprise_label,token);
769 ti->enterprise_subids[0] = (u_long)-1;
770
771 type = get_token(fp,token);
772 while(type != EQUALS){
773 switch(type){
774 case VARIABLES:
775 type = get_token(fp,token);
776 if(type != LEFTBRACKET){
777 print_error("{ expected in VARIABLES clause",token,type);
778 free(ti);
779 return 0;
780 }
781 type = get_token(fp,token);
782 while(type != RIGHTBRACKET)
783 {
784 if(type != LABEL)
785 {
786 print_error("LABEL expected in VARIABLES1 clause",token,type);
787 free(ti);
788 return 0;
789 }
790
791
792 (ti->n_variables)++;
793 if(ti->var_list == NULL)
794 {
795 ip = ti->var_list = (struct index_list *)
796 Malloc(sizeof(struct index_list));
797 }
798 else
799 {
800 ip->next = (struct index_list *)
801 Malloc(sizeof(struct enum_list));
802 ip = ip->next;
803 }
804 ip->next = 0;
805 ip->tp = NULL;
806
807 ip->label =
808 (char *)Malloc((unsigned)strlen(token) + 1);
809 strcpy(ip->label, token);
810
811 type = get_token(fp, token);
812
813 switch(type)
814 {
815 case COMMA:
816 type = get_token(fp, token);
817 break;
818
819 case RIGHTBRACKET:
820 break;
821
822 default:
823 print_error(", or } expected in VARIABLES clause",token,type);
824 free(ti);
825 return 0;
826
827 }
828 }
829 break;
830
831 case DESCRIPTION:
832 type = get_token(fp,token);
833 if(type != QUOTESTRING){
834 print_error("Bad DESCRIPTION",token,type);
835 free(ti);
836 return 0;
837 }
838 ti->description = quoted_string_buffer;
839 quoted_string_buffer = (char*)malloc(MAXQUOTESTR);
840 if(quoted_string_buffer==NULL){
841 fprintf(stderr,"malloc failed\n");
842 return 0;
843 }
844 break;
845 case REFERENCE:
846 type = get_token(fp,token);
847 if(type != QUOTESTRING){
848 print_error("Bad DESCRIPTION",token,type);
849 free(ti);
850 return 0;
851 }
852 break;
853 default:
854 /* NOTHING*/
855 break;
856 }
857 type = get_token(fp,token);
858 }
859 /* get the integer */
860 if( (type = get_token(fp,token)) == NUMBER){
861 ti->value = atoi(token);
862 /* attach the item to list */
863
864
865
866 }else{
867 print_error("Expected a number",token,type);
868 free(ti);
869 return 0;
870 }
871 }else{
872 print_error("Expected \"enterprise name\"",token,type);
873 return 0;
874 }
875 }else{
876 print_error("Expected \"ENTERPRISE\"",token,type);
877 return 0;
878 }
879 if(trap_list == NULL){
880 last_trap_item = trap_list = ti;
881 }else{
882 last_trap_item->next = ti;
883 last_trap_item = ti;
884 }
885 return 1;
886 }
887
888 /*
889 * Parse an entry of the form:
890 * label OBJECT IDENTIFIER ::= { parent 2 }
891 * The "label OBJECT IDENTIFIER" portion has already been parsed.
892 * Returns 0 on error.
893 */
894 static struct node *
parse_objectid(fp,name)895 parse_objectid(fp, name)
896 FILE *fp;
897 char *name;
898 {
899 int type;
900 char token[MAXTOKEN];
901 register int count;
902 register struct subid *op, *nop;
903 int length;
904 struct subid oid[32];
905 struct node *np, *root, *oldnp = NULL;
906
907 type = get_token(fp, token);
908 if (type != EQUALS){
909 print_error("Bad format", token, type);
910 return 0;
911 }
912 if ((length = getoid(fp, oid, 32)) != 0){
913 np = root = (struct node *)Malloc(sizeof(struct node));
914
915 /*
916 -- Olivier Reisacher 95/2/14
917 bzero((char *)np, sizeof(struct node));
918 */
919 memset((void *) np, 0, sizeof(struct node));
920
921 /*
922 * For each parent-child subid pair in the subid array,
923 * create a node and link it into the node list.
924 */
925 for(count = 0, op = oid, nop=oid+1; count < (length - 2); count++,
926 op++, nop++){
927 /* every node must have parent's name and child's name or number */
928 if (op->label && (nop->label || (nop->subid != -1))){
929 strcpy(np->parent, op->label);
930 if (nop->label)
931 strcpy(np->label, nop->label);
932 if (nop->subid != -1)
933 np->subid = nop->subid;
934 np->type = 0;
935 np->enums = 0;
936 /*
937 -- Olivier Reisacher 95/2/14
938 */
939 np->access = 0;
940 np->n_indexs = 0;
941 np->indexs = NULL;
942
943 /* set up next entry */
944 np->next = (struct node *)Malloc(sizeof(*np->next));
945
946 /*
947 -- Olivier Reisacher 95/2/14
948 bzero((char *)np->next, sizeof(struct node));
949 */
950 memset((void *) np->next, 0, sizeof(struct node));
951
952 oldnp = np;
953 np = np->next;
954 }
955 }
956 np->next = (struct node *)NULL;
957 /*
958 * The above loop took care of all but the last pair. This pair is taken
959 * care of here. The name for this node is taken from the label for this
960 * entry.
961 * np still points to an unused entry.
962 */
963 if (count == (length - 2)){
964 if (op->label){
965 strcpy(np->parent, op->label);
966 strcpy(np->label, name);
967 if (nop->subid != -1)
968 np->subid = nop->subid;
969 else
970 print_error("Warning: This entry is pretty silly",
971 np->label, type);
972 } else {
973 free_node(np);
974 if (oldnp)
975 oldnp->next = NULL;
976 else
977 return NULL;
978 }
979 } else {
980 print_error("Missing end of oid", (char *)NULL, type);
981 free_node(np); /* the last node allocated wasn't used */
982 if (oldnp)
983 oldnp->next = NULL;
984 return NULL;
985 }
986 /* free the oid array */
987 for(count = 0, op = oid; count < length; count++, op++){
988 if (op->label)
989 free(op->label);
990 op->label = 0;
991 }
992 return root;
993 } else {
994 print_error("Bad object identifier", (char *)NULL, type);
995 return 0;
996 }
997 }
998
999 static int
get_tc(descriptor,ep)1000 get_tc(descriptor, ep)
1001 char *descriptor;
1002 struct enum_list **ep;
1003 {
1004 int i;
1005
1006 for(i = 0; i < MAXTC; i++){
1007 if (tclist[i].type == 0)
1008 break;
1009 if (!strcmp(descriptor, tclist[i].descriptor)){
1010 *ep = tclist[i].enums;
1011 return tclist[i].type;
1012 }
1013 }
1014 return LABEL;
1015 }
1016
1017 /*
1018 * Parses an asn type. Structures are ignored by this parser.
1019 * Returns NULL on error.
1020 */
1021 static int
parse_asntype(fp,name,ntype,ntoken)1022 parse_asntype(fp, name, ntype, ntoken)
1023 FILE *fp;
1024 char *name;
1025 int *ntype;
1026 char *ntoken;
1027 {
1028 int type, i;
1029 char token[MAXTOKEN];
1030 struct enum_list *ep;
1031 struct tc *tcp;
1032 int level;
1033
1034 #ifdef TRACE_PROC
1035 printf("parse_asntype() invoked\n");
1036 #endif
1037
1038 type = get_token(fp, token);
1039 if (type == SEQUENCE){
1040 while((type = get_token(fp, token)) != ENDOFFILE){
1041 if (type == RIGHTBRACKET){
1042 *ntype = get_token(fp, ntoken);
1043 return 1;
1044 }
1045 }
1046 print_error("Expected \"}\"", token, type);
1047 return 0;
1048 } else {
1049 if (!strcmp(token, "TEXTUAL-CONVENTION")){
1050 while (type != SYNTAX)
1051 type = get_token(fp, token);
1052 type = get_token(fp, token);
1053 }
1054 /* textual convention */
1055 for(i = 0; i < MAXTC; i++){
1056 if (tclist[i].type == 0)
1057 break;
1058 }
1059 if (i == MAXTC){
1060 print_error("No more textual conventions possible.", token, type);
1061 return 0;
1062 }
1063 tcp = &tclist[i];
1064 strcpy(tcp->descriptor, name);
1065 if (!(type & SYNTAX_MASK)){
1066
1067 /*
1068 -- Olivier Reisacher 95/2/14
1069 print_error("Textual convention doesn't map to real type.", token,
1070 type);
1071 return 0;
1072 }
1073 */
1074 int w;
1075
1076 w = get_tc(token, &ep);
1077 if(!(w & SYNTAX_MASK))
1078 {
1079 print_error("Textual convention doesn't map to real type.", token, type);
1080 return 0;
1081 }
1082 type = w;
1083 }
1084
1085 tcp->type = type;
1086 *ntype = get_token(fp, ntoken);
1087 if (*ntype == LEFTPAREN){
1088 level = 1;
1089 /* don't record any constraints for now */
1090 while(level > 0){
1091 *ntype = get_token(fp, ntoken);
1092 if (*ntype == LEFTPAREN)
1093 level++;
1094 if (*ntype == RIGHTPAREN)
1095 level--;
1096 }
1097 *ntype = get_token(fp, ntoken);
1098 } else if (*ntype == LEFTBRACKET) {
1099 /* if there is an enumeration list, parse it */
1100 while((type = get_token(fp, token)) != ENDOFFILE){
1101 if (type == RIGHTBRACKET)
1102 break;
1103 if (type == LABEL){
1104 /* this is an enumerated label */
1105 if (tcp->enums == 0){
1106 ep = tcp->enums = (struct enum_list *)
1107 Malloc(sizeof(struct enum_list));
1108 } else {
1109 ep->next = (struct enum_list *)
1110 Malloc(sizeof(struct enum_list));
1111 ep = ep->next;
1112 }
1113 ep->next = 0;
1114 /* a reasonable approximation for the length */
1115 ep->label =
1116 (char *)Malloc((unsigned)strlen(token) + 1);
1117 strcpy(ep->label, token);
1118 type = get_token(fp, token);
1119 if (type != LEFTPAREN){
1120 print_error("Expected \"(\"", token, type);
1121 /* free_node(np); */
1122 return 0;
1123 }
1124 type = get_token(fp, token);
1125 if (type != NUMBER){
1126 print_error("Expected integer", token, type);
1127 /* free_node(np); */
1128 return 0;
1129 }
1130 ep->value = atoi(token);
1131 type = get_token(fp, token);
1132 if (type != RIGHTPAREN){
1133 print_error("Expected \")\"", token, type);
1134 /* free_node(np); */
1135 return 0;
1136 }
1137 }
1138 }
1139 if (type == ENDOFFILE){
1140 print_error("Expected \"}\"", token, type);
1141 /* free_node(np); */
1142 return 0;
1143 }
1144 *ntype = get_token(fp, ntoken);
1145 }
1146 return 1;
1147 }
1148 }
1149
1150
1151 /*
1152 * Parses an OBJECT TYPE macro.
1153 * Returns 0 on error.
1154 */
1155 static struct node *
parse_objecttype(fp,name)1156 parse_objecttype(fp, name)
1157 register FILE *fp;
1158 char *name;
1159 {
1160 register int type;
1161 char token[MAXTOKEN];
1162 int count, length;
1163 struct subid oid[32];
1164 char syntax[MAXTOKEN];
1165 int nexttype, tctype;
1166 char nexttoken[MAXTOKEN];
1167 register struct node *np;
1168 register struct enum_list *ep;
1169 /*
1170 -- Olivier Reisacher 95/2/14
1171 */
1172 struct index_list *ip;
1173
1174 type = get_token(fp, token);
1175 if (type != SYNTAX){
1176 print_error("Bad format for OBJECT TYPE", token, type);
1177 return 0;
1178 }
1179 np = (struct node *)Malloc(sizeof(struct node));
1180 np->next = 0;
1181 np->enums = 0;
1182 np->description = NULL; /* default to an empty description */
1183 /*
1184 -- Olivier Reisacher 95/2/14
1185 */
1186 np->access = 0;
1187 np->n_indexs = 0;
1188 np->indexs = 0;
1189
1190 type = get_token(fp, token);
1191 if (type == LABEL){
1192 tctype = get_tc(token, &(np->enums));
1193 #if 0
1194 if (tctype == LABEL){
1195 print_error("No known translation for type", token, type);
1196 return 0;
1197 }
1198 #endif
1199 type = tctype;
1200 }
1201 np->type = type;
1202 np->oct_str_len = 0;
1203 nexttype = get_token(fp, nexttoken);
1204 switch(type){
1205 case SEQUENCE:
1206 strcpy(syntax, token);
1207 if (nexttype == OF){
1208 strcat(syntax, " ");
1209 strcat(syntax, nexttoken);
1210 nexttype = get_token(fp, nexttoken);
1211 strcat(syntax, " ");
1212 strcat(syntax, nexttoken);
1213 nexttype = get_token(fp, nexttoken);
1214
1215 /*
1216 -- Olivier Reisacher 95/2/14
1217 */
1218 np->type = PSEUDO_TOKEN_TABLE;
1219 }
1220
1221 break;
1222 case PARSE_INTEGER:
1223 case UINTEGER32:
1224 strcpy(syntax, token);
1225 if (nexttype == LEFTBRACKET) {
1226 /* if there is an enumeration list, parse it */
1227 while((type = get_token(fp, token)) != ENDOFFILE){
1228 if (type == RIGHTBRACKET)
1229 break;
1230 if (type == LABEL){
1231 /* this is an enumerated label */
1232 if (np->enums == 0){
1233 ep = np->enums = (struct enum_list *)
1234 Malloc(sizeof(struct enum_list));
1235 } else {
1236 ep->next = (struct enum_list *)
1237 Malloc(sizeof(struct enum_list));
1238 ep = ep->next;
1239 }
1240 ep->next = 0;
1241 /* a reasonable approximation for the length */
1242 ep->label =
1243 (char *)Malloc((unsigned)strlen(token) + 1);
1244 strcpy(ep->label, token);
1245 type = get_token(fp, token);
1246 if (type != LEFTPAREN){
1247 print_error("Expected \"(\"", token, type);
1248 free_node(np);
1249 return 0;
1250 }
1251 type = get_token(fp, token);
1252 if (type != NUMBER){
1253 print_error("Expected integer", token, type);
1254 free_node(np);
1255 return 0;
1256 }
1257 ep->value = atoi(token);
1258 type = get_token(fp, token);
1259 if (type != RIGHTPAREN){
1260 print_error("Expected \")\"", token, type);
1261 free_node(np);
1262 return 0;
1263 }
1264 }
1265 }
1266 if (type == ENDOFFILE){
1267 print_error("Expected \"}\"", token, type);
1268 free_node(np);
1269 return 0;
1270 }
1271 nexttype = get_token(fp, nexttoken);
1272 } else if (nexttype == LEFTPAREN){
1273 /* ignore the "constrained integer" for now */
1274 nexttype = get_token(fp, nexttoken);
1275 nexttype = get_token(fp, nexttoken);
1276 nexttype = get_token(fp, nexttoken);
1277 }
1278 break;
1279 case BITSTRING:
1280 strcpy(syntax, token);
1281 if (nexttype == LEFTBRACKET) {
1282 /* if there is an enumeration list, parse it */
1283 while((type = get_token(fp, token)) != ENDOFFILE){
1284 if (type == RIGHTBRACKET)
1285 break;
1286 if (type == LABEL){
1287 /* this is an enumerated label */
1288 if (np->enums == 0){
1289 ep = np->enums = (struct enum_list *)
1290 Malloc(sizeof(struct enum_list));
1291 } else {
1292 ep->next = (struct enum_list *)
1293 Malloc(sizeof(struct enum_list));
1294 ep = ep->next;
1295 }
1296 ep->next = 0;
1297 /* a reasonable approximation for the length */
1298 ep->label =
1299 (char *)Malloc((unsigned)strlen(token) + 1);
1300 strcpy(ep->label, token);
1301 type = get_token(fp, token);
1302 if (type != LEFTPAREN){
1303 print_error("Expected \"(\"", token, type);
1304 free_node(np);
1305 return 0;
1306 }
1307 type = get_token(fp, token);
1308 if (type != NUMBER){
1309 print_error("Expected integer", token, type);
1310 free_node(np);
1311 return 0;
1312 }
1313 ep->value = atoi(token);
1314 type = get_token(fp, token);
1315 if (type != RIGHTPAREN){
1316 print_error("Expected \")\"", token, type);
1317 free_node(np);
1318 return 0;
1319 }
1320 }
1321 }
1322 if (type == ENDOFFILE){
1323 print_error("Expected \"}\"", token, type);
1324 free_node(np);
1325 return 0;
1326 }
1327 nexttype = get_token(fp, nexttoken);
1328 } else if (nexttype == LEFTPAREN){
1329 /* ignore the "constrained integer" for now */
1330 nexttype = get_token(fp, nexttoken);
1331 nexttype = get_token(fp, nexttoken);
1332 nexttype = get_token(fp, nexttoken);
1333 }
1334 break;
1335 case OCTETSTR:
1336 strcpy(syntax, token);
1337 /* ignore the "constrained octet string" for now */
1338 if (nexttype == LEFTPAREN) {
1339 nexttype = get_token(fp, nexttoken);
1340 if (nexttype == SIZE) {
1341 nexttype = get_token(fp, nexttoken);
1342 if (nexttype == LEFTPAREN) {
1343 nexttype = get_token(fp, nexttoken); /* 0..255 */
1344 np->oct_str_len = number_value;
1345 number_value = 0;
1346 nexttype = get_token(fp, nexttoken); /* ) */
1347 nexttype = get_token(fp, nexttoken); /* ) */
1348 if (nexttype == RIGHTPAREN)
1349 {
1350 nexttype = get_token(fp, nexttoken);
1351 break;
1352 }
1353 }
1354 }
1355 print_error("Bad syntax", token, type);
1356 free_node(np);
1357 return 0;
1358 }
1359 break;
1360 case PARSE_OBJID:
1361 case NETADDR:
1362 case IPADDR:
1363 case PARSE_COUNTER:
1364 case PARSE_GUAGE:
1365 case PARSE_TIMETICKS:
1366 case PARSE_OPAQUE:
1367 case NUL:
1368 case LABEL:
1369 case NSAPADDRESS:
1370 case PARSE_COUNTER64:
1371 strcpy(syntax, token);
1372 break;
1373 default:
1374 print_error("Bad syntax", token, type);
1375 free_node(np);
1376 return 0;
1377 }
1378 if (nexttype == UNITS){
1379 type = get_token(fp, token);
1380 if (type != QUOTESTRING) {
1381 print_error("Bad DESCRIPTION", token, type);
1382 free_node(np);
1383 return 0;
1384 }
1385 nexttype = get_token(fp, nexttoken);
1386 }
1387 if (nexttype != ACCESS){
1388 print_error("Should be ACCESS", nexttoken, nexttype);
1389 free_node(np);
1390 return 0;
1391 }
1392 type = get_token(fp, token);
1393 if (type != READONLY && type != READWRITE && type != WRITEONLY
1394 && type != NOACCESS && type != READCREATE){
1395 print_error("Bad access type", nexttoken, nexttype);
1396 free_node(np);
1397 return 0;
1398 }
1399
1400 /*
1401 -- Olivier Reisacher 95/2/14
1402 */
1403 switch(type)
1404 {
1405 case READONLY:
1406 np->access = READ_FLAG;
1407 break;
1408
1409 case READWRITE:
1410 np->access = READ_FLAG | WRITE_FLAG;
1411 break;
1412
1413 case WRITEONLY:
1414 np->access = WRITE_FLAG;
1415 break;
1416
1417 case NOACCESS:
1418 np->access = 0;
1419 break;
1420
1421 case READCREATE:
1422 np->access = READ_FLAG | CREATE_FLAG;
1423 break;
1424 }
1425
1426 type = get_token(fp, token);
1427 if (type != STATUS){
1428 print_error("Should be STATUS", token, nexttype);
1429 free_node(np);
1430 return 0;
1431 }
1432 type = get_token(fp, token);
1433 if (type != MANDATORY && type != CURRENT && type != OPTIONAL && type != OBSOLETE && type != DEPRECATED){
1434 print_error("Bad status", token, type);
1435 free_node(np);
1436 return 0;
1437 }
1438 /*
1439 * Optional parts of the OBJECT-TYPE macro
1440 */
1441 type = get_token(fp, token);
1442 while (type != EQUALS) {
1443 switch (type) {
1444 case DESCRIPTION:
1445 type = get_token(fp, token);
1446 if (type != QUOTESTRING) {
1447 print_error("Bad DESCRIPTION", token, type);
1448 free_node(np);
1449 return 0;
1450 }
1451 #ifdef TEST
1452 printf("Description== \"%.50s\"\n", quoted_string_buffer);
1453 #endif
1454 np->description = quoted_string_buffer;
1455 quoted_string_buffer = (char *)malloc(MAXQUOTESTR);
1456 if (!quoted_string_buffer){
1457 fprintf(stderr, "malloc failed. Exiting\n");
1458 exit(1);
1459 }
1460 break;
1461
1462 case REFERENCE:
1463 type = get_token(fp, token);
1464 if (type != QUOTESTRING) {
1465 print_error("Bad DESCRIPTION", token, type);
1466 free_node(np);
1467 return 0;
1468 }
1469 break;
1470 /*
1471 -- Olivier Reisacher 95/2/14
1472 */
1473 case INDEX:
1474 np->type = PSEUDO_TOKEN_ENTRY;
1475
1476 type = get_token(fp, token);
1477 if(type != LEFTBRACKET)
1478 {
1479 print_error("{ expected in INDEX clause",token,type);
1480 free_node(np);
1481 return 0;
1482 }
1483 type = get_token(fp, token);
1484 while(type != RIGHTBRACKET)
1485 {
1486 if(type != LABEL)
1487 {
1488 print_error("LABEL expected in INDEX clause",token,type);
1489 free_node(np);
1490 return 0;
1491 }
1492
1493
1494 (np->n_indexs)++;
1495 if(np->indexs == NULL)
1496 {
1497 ip = np->indexs = (struct index_list *)
1498 Malloc(sizeof(struct index_list));
1499 }
1500 else
1501 {
1502 ip->next = (struct index_list *)
1503 Malloc(sizeof(struct enum_list));
1504 ip = ip->next;
1505 }
1506 ip->next = 0;
1507 ip->tp = NULL;
1508
1509 ip->label =
1510 (char *)Malloc((unsigned)strlen(token) + 1);
1511 strcpy(ip->label, token);
1512
1513 type = get_token(fp, token);
1514
1515 switch(type)
1516 {
1517 case COMMA:
1518 type = get_token(fp, token);
1519 break;
1520
1521 case RIGHTBRACKET:
1522 break;
1523
1524 default:
1525 print_error(", or } expected in INDEX clause",token,type);
1526 free_node(np);
1527 return 0;
1528
1529 }
1530 }
1531 break;
1532
1533 case DEFVAL:
1534 case AUGMENTS:
1535 case NUM_ENTRIES:
1536 if (tossObjectIdentifier(fp) != PARSE_OBJID) {
1537 print_error("Bad Object Identifier", token, type);
1538 free_node(np);
1539 return 0;
1540 }
1541 break;
1542
1543 default:
1544 print_error("Bad format of optional clauses", token,type);
1545 free_node(np);
1546 return 0;
1547
1548 }
1549 type = get_token(fp, token);
1550 }
1551 if (type != EQUALS){
1552 print_error("Bad format", token, type);
1553 free_node(np);
1554 return 0;
1555 }
1556 length = getoid(fp, oid, 32);
1557 if (length > 1 && length <= 32){
1558 /* just take the last pair in the oid list */
1559 if (oid[length - 2].label)
1560 strncpy(np->parent, oid[length - 2].label, MAXLABEL);
1561 strcpy(np->label, name);
1562 if (oid[length - 1].subid != -1)
1563 np->subid = oid[length - 1].subid;
1564 else
1565 print_error("Warning: This entry is pretty silly", np->label, type);
1566 } else {
1567 print_error("No end to oid", (char *)NULL, type);
1568 free_node(np);
1569 np = 0;
1570 }
1571 /* free oid array */
1572 for(count = 0; count < length; count++){
1573 if (oid[count].label)
1574 free(oid[count].label);
1575 oid[count].label = 0;
1576 }
1577 return np;
1578 }
1579
1580
1581 /*
1582 * Parses an OBJECT GROUP macro.
1583 * Returns 0 on error.
1584 */
1585 static struct node *
parse_objectgroup(fp,name)1586 parse_objectgroup(fp, name)
1587 register FILE *fp;
1588 char *name;
1589 {
1590 register int type;
1591 char token[MAXTOKEN];
1592 int count, length;
1593 struct subid oid[32];
1594 register struct node *np;
1595
1596 np = (struct node *)Malloc(sizeof(struct node));
1597 np->type = 0;
1598 np->next = 0;
1599 np->enums = 0;
1600 np->description = NULL; /* default to an empty description */
1601
1602 /*
1603 -- Olivier Reisacher 95/2/14
1604 */
1605 np->access = 0;
1606 np->n_indexs = 0;
1607 np->indexs = 0;
1608
1609 type = get_token(fp, token);
1610 while (type != EQUALS) {
1611 switch (type) {
1612 case DESCRIPTION:
1613 type = get_token(fp, token);
1614 if (type != QUOTESTRING) {
1615 print_error("Bad DESCRIPTION", token, type);
1616 free_node(np);
1617 return 0;
1618 }
1619 #ifdef TEST
1620 printf("Description== \"%.50s\"\n", quoted_string_buffer);
1621 #endif
1622 np->description = quoted_string_buffer;
1623 quoted_string_buffer = (char *)malloc(MAXQUOTESTR);
1624 if (!quoted_string_buffer){
1625 fprintf(stderr, "malloc failed. Exiting\n");
1626 exit(1);
1627 }
1628 break;
1629
1630 default:
1631 /* NOTHING */
1632 break;
1633 }
1634 type = get_token(fp, token);
1635 }
1636 length = getoid(fp, oid, 32);
1637 if (length > 1 && length <= 32){
1638 /* just take the last pair in the oid list */
1639 if (oid[length - 2].label)
1640 strncpy(np->parent, oid[length - 2].label, MAXLABEL);
1641 strcpy(np->label, name);
1642 if (oid[length - 1].subid != -1)
1643 np->subid = oid[length - 1].subid;
1644 else
1645 print_error("Warning: This entry is pretty silly", np->label, type);
1646 } else {
1647 print_error("No end to oid", (char *)NULL, type);
1648 free_node(np);
1649 np = 0;
1650 }
1651 /* free oid array */
1652 for(count = 0; count < length; count++){
1653 if (oid[count].label)
1654 free(oid[count].label);
1655 oid[count].label = 0;
1656 }
1657 return np;
1658 }
1659
1660 /*
1661 * Parses a NOTIFICATION-TYPE macro.
1662 * Returns 0 on error.
1663 */
1664 static struct node *
parse_notificationDefinition(fp,name)1665 parse_notificationDefinition(fp, name)
1666 register FILE *fp;
1667 char *name;
1668 {
1669 register int type;
1670 char token[MAXTOKEN];
1671 int count, length;
1672 struct subid oid[32];
1673 register struct node *np;
1674
1675 np = (struct node *)Malloc(sizeof(struct node));
1676 np->type = 0;
1677 np->next = 0;
1678 np->enums = 0;
1679 np->description = NULL; /* default to an empty description */
1680 /*
1681 -- Olivier Reisacher 95/2/14
1682 */
1683 np->access = 0;
1684 np->n_indexs = 0;
1685 np->indexs = 0;
1686
1687 type = get_token(fp, token);
1688 while (type != EQUALS) {
1689 switch (type) {
1690 case DESCRIPTION:
1691 type = get_token(fp, token);
1692 if (type != QUOTESTRING) {
1693 print_error("Bad DESCRIPTION", token, type);
1694 free_node(np);
1695 return 0;
1696 }
1697 #ifdef TEST
1698 printf("Description== \"%.50s\"\n", quoted_string_buffer);
1699 #endif
1700 np->description = quoted_string_buffer;
1701 quoted_string_buffer = (char *)malloc(MAXQUOTESTR);
1702 if (!quoted_string_buffer){
1703 fprintf(stderr, "malloc failed. Exiting\n");
1704 exit(1);
1705 }
1706 break;
1707
1708 default:
1709 /* NOTHING */
1710 break;
1711 }
1712 type = get_token(fp, token);
1713 }
1714 length = getoid(fp, oid, 32);
1715 if (length > 1 && length <= 32){
1716 /* just take the last pair in the oid list */
1717 if (oid[length - 2].label)
1718 strncpy(np->parent, oid[length - 2].label, MAXLABEL);
1719 strcpy(np->label, name);
1720 if (oid[length - 1].subid != -1)
1721 np->subid = oid[length - 1].subid;
1722 else
1723 print_error("Warning: This entry is pretty silly", np->label, type);
1724 } else {
1725 print_error("No end to oid", (char *)NULL, type);
1726 free_node(np);
1727 np = 0;
1728 }
1729 /* free oid array */
1730 for(count = 0; count < length; count++){
1731 if (oid[count].label)
1732 free(oid[count].label);
1733 oid[count].label = 0;
1734 }
1735 return np;
1736 }
1737
1738 /*
1739 * Parses a compliance macro
1740 * Returns 0 on error.
1741 */
1742 static struct node *
parse_compliance(fp,name)1743 parse_compliance(fp, name)
1744 register FILE *fp;
1745 char *name;
1746 {
1747 register int type;
1748 char token[MAXTOKEN];
1749 int count, length;
1750 struct subid oid[32];
1751 register struct node *np;
1752
1753 np = (struct node *)Malloc(sizeof(struct node));
1754 np->type = 0;
1755 np->next = 0;
1756 np->enums = 0;
1757 np->description = NULL; /* default to an empty description */
1758 /*
1759 -- Olivier Reisacher 95/2/14
1760 */
1761 np->access = 0;
1762 np->n_indexs = 0;
1763 np->indexs = 0;
1764
1765 type = get_token(fp, token);
1766 while (type != EQUALS) {
1767 type = get_token(fp, token);
1768 }
1769 length = getoid(fp, oid, 32);
1770 if (length > 1 && length <= 32){
1771 /* just take the last pair in the oid list */
1772 if (oid[length - 2].label)
1773 strncpy(np->parent, oid[length - 2].label, MAXLABEL);
1774 strcpy(np->label, name);
1775 if (oid[length - 1].subid != -1)
1776 np->subid = oid[length - 1].subid;
1777 else
1778 print_error("Warning: This entry is pretty silly", np->label, type);
1779 } else {
1780 print_error("No end to oid", (char *)NULL, type);
1781 free_node(np);
1782 np = 0;
1783 }
1784 /* free oid array */
1785 for(count = 0; count < length; count++){
1786 if (oid[count].label)
1787 free(oid[count].label);
1788 oid[count].label = 0;
1789 }
1790 return np;
1791 }
1792
1793
1794
1795 /*
1796 * Parses a module identity macro
1797 * Returns 0 on error.
1798 */
1799 static struct node *
parse_moduleIdentity(fp,name)1800 parse_moduleIdentity(fp, name)
1801 register FILE *fp;
1802 char *name;
1803 {
1804 register int type;
1805 char token[MAXTOKEN];
1806 int count, length;
1807 struct subid oid[32];
1808 register struct node *np;
1809
1810 np = (struct node *)Malloc(sizeof(struct node));
1811 np->type = 0;
1812 np->next = 0;
1813 np->enums = 0;
1814 np->description = NULL; /* default to an empty description */
1815 /*
1816 -- Olivier Reisacher 95/2/14
1817 */
1818 np->n_indexs = 0;
1819 np->indexs = 0;
1820 np->access = 0;
1821
1822 type = get_token(fp, token);
1823 while (type != EQUALS) {
1824 type = get_token(fp, token);
1825 }
1826 length = getoid(fp, oid, 32);
1827 if (length > 1 && length <= 32){
1828 /* just take the last pair in the oid list */
1829 if (oid[length - 2].label)
1830 strncpy(np->parent, oid[length - 2].label, MAXLABEL);
1831 strcpy(np->label, name);
1832 if (oid[length - 1].subid != -1)
1833 np->subid = oid[length - 1].subid;
1834 else
1835 print_error("Warning: This entry is pretty silly", np->label, type);
1836 } else {
1837 print_error("No end to oid", (char *)NULL, type);
1838 free_node(np);
1839 np = 0;
1840 }
1841 /* free oid array */
1842 for(count = 0; count < length; count++){
1843 if (oid[count].label)
1844 free(oid[count].label);
1845 oid[count].label = 0;
1846 }
1847 return np;
1848 }
1849
parse_mib_header(fp,name)1850 int parse_mib_header(fp, name)
1851 register FILE *fp;
1852 char *name;
1853 {
1854 int type = DEFINITIONS;
1855 char token[MAXTOKEN];
1856
1857 #ifdef TRACE_PROC
1858 printf("parse_mib_header() invoked\n");
1859 #endif
1860
1861 /* This probably isn't good enough. If there is no
1862 imports clause we can't go around waiting (forever) for a semicolon.
1863 We need to check for semi following an EXPORTS clause or an IMPORTS
1864 clause of both. Look for BEGIN; in my initial MIBs to see those
1865 that I needed to hack to get to parse because they didn't have
1866 an IMPORTS or and EXPORTS clause.
1867 */
1868 while(type != SEMI){
1869 type = get_token(fp, token);
1870 }
1871 return 1;
1872 }
1873
1874
1875 /*
1876 -- Olivier Reisacher 95/2/14
1877 */
parse_init()1878 void parse_init()
1879 {
1880 hash_init();
1881 memset((void *) tclist, 0, 64 * sizeof(struct tc));
1882 }
1883
1884
1885 /*
1886 * Parses a mib file and returns a linked list of nodes found in the file.
1887 * Returns NULL on error.
1888 */
1889 /*
1890 -- Olivier Reisacher 95/2/14
1891 static struct node *
1892 */
1893 struct node *
parse(fp)1894 parse(fp)
1895 FILE *fp;
1896 {
1897 char token[MAXTOKEN];
1898 char name[MAXTOKEN];
1899 int type = 1;
1900 #define BETWEEN_MIBS 1
1901 #define IN_MIB 2
1902 int state = BETWEEN_MIBS;
1903 struct node *np, *root = NULL;
1904
1905 #ifdef TRACE_PROC
1906 printf("parse() invoked\n");
1907 #endif
1908
1909 /*
1910 -- Olivier Reisacher 95/2/14
1911 hash_init();
1912 */
1913 Line = 1;
1914
1915 quoted_string_buffer = (char *)malloc(MAXQUOTESTR); /* free this later */
1916 if (!quoted_string_buffer){
1917 fprintf(stderr, "malloc failed. Exiting\n");
1918 exit(1);
1919 }
1920
1921 /*
1922 -- Olivier Reisacher 95/2/14
1923 bzero(tclist, 64 * sizeof(struct tc));
1924 */
1925
1926 while(type != ENDOFFILE){
1927 type = get_token(fp, token);
1928 skipget:
1929 if (type == END){
1930 if (state != IN_MIB){
1931 print_error("Error, end before start of MIB.", (char *)NULL, type);
1932 return NULL;
1933 }
1934 state = BETWEEN_MIBS;
1935 continue;
1936 } else if (type != LABEL){
1937 if (type == ENDOFFILE){
1938 return root;
1939 }
1940 print_error(token, "is a reserved word", type);
1941 return NULL;
1942 }
1943 strncpy(name, token, MAXTOKEN);
1944 type = get_token(fp, token);
1945 if (type == DEFINITIONS){
1946 if (state != BETWEEN_MIBS){
1947 print_error("Error, nested MIBS.", (char *)NULL, type);
1948 return NULL;
1949 }
1950 state = IN_MIB;
1951 if (!parse_mib_header(fp, name)){
1952 print_error("Bad parse of module header", (char *)NULL, type);
1953 return NULL;
1954 }
1955 } else if (type == OBJTYPE){
1956 if (root == NULL){
1957 /* first link in chain */
1958 np = root = parse_objecttype(fp, name);
1959 if (np == NULL){
1960 print_error("Bad parse of object type", (char *)NULL,
1961 type);
1962 return NULL;
1963 }
1964 } else {
1965 np->next = parse_objecttype(fp, name);
1966 if (np->next == NULL){
1967 print_error("Bad parse of objecttype", (char *)NULL,
1968 type);
1969 return NULL;
1970 }
1971 }
1972 /* now find end of chain */
1973 while(np->next)
1974 np = np->next;
1975 } else if (type == OBJGROUP){
1976 if (root == NULL){
1977 /* first link in chain */
1978 np = root = parse_objectgroup(fp, name);
1979 if (np == NULL){
1980 print_error("Bad parse of object group", (char *)NULL,
1981 type);
1982 return NULL;
1983 }
1984 } else {
1985 np->next = parse_objectgroup(fp, name);
1986 if (np->next == NULL){
1987 print_error("Bad parse of objectgroup", (char *)NULL,
1988 type);
1989 return NULL;
1990 }
1991 }
1992 /* now find end of chain */
1993 while(np->next)
1994 np = np->next;
1995 } else if (type == NOTIFTYPE){
1996 if (root == NULL){
1997 /* first link in chain */
1998 np = root = parse_notificationDefinition(fp, name);
1999 if (np == NULL){
2000 print_error("Bad parse of notification definition",
2001 (char *)NULL, type);
2002 return NULL;
2003 }
2004 } else {
2005 np->next = parse_notificationDefinition(fp, name);
2006 if (np->next == NULL){
2007 print_error("Bad parse of notification definition",
2008 (char *)NULL, type);
2009 return NULL;
2010 }
2011 }
2012 /* now find end of chain */
2013 while(np->next)
2014 np = np->next;
2015 } else if (type == COMPLIANCE){
2016 if (root == NULL){
2017 /* first link in chain */
2018 np = root = parse_compliance(fp, name);
2019 if (np == NULL){
2020 print_error("Bad parse of module compliance", (char *)NULL,
2021 type);
2022 return NULL;
2023 }
2024 } else {
2025 np->next = parse_compliance(fp, name);
2026 if (np->next == NULL){
2027 print_error("Bad parse of module compliance", (char *)NULL,
2028 type);
2029 return NULL;
2030 }
2031 }
2032 /* now find end of chain */
2033 while(np->next)
2034 np = np->next;
2035 } else if (type == MODULEIDENTITY){
2036 if (root == NULL){
2037 /* first link in chain */
2038 np = root = parse_moduleIdentity(fp, name);
2039 if (np == NULL){
2040 print_error("Bad parse of module identity", (char *)NULL,
2041 type);
2042 return NULL;
2043 }
2044 } else {
2045 np->next = parse_moduleIdentity(fp, name);
2046 if (np->next == NULL){
2047 print_error("Bad parse of module identity", (char *)NULL,
2048 type);
2049 return NULL;
2050 }
2051 }
2052 /* now find end of chain */
2053 while(np->next)
2054 np = np->next;
2055 } else if (type == PARSE_OBJID){
2056 if (root == NULL){
2057 /* first link in chain */
2058 np = root = parse_objectid(fp, name);
2059 if (np == NULL){
2060 print_error("Bad parse of object id", (char *)NULL, type);
2061 return NULL;
2062 }
2063 } else {
2064 np->next = parse_objectid(fp, name);
2065 if (np->next == NULL){
2066 print_error("Bad parse of object type", (char *)NULL,
2067 type);
2068 return NULL;
2069 }
2070 }
2071 /* now find end of chain */
2072 while(np->next)
2073 np = np->next;
2074 } else if (type == EQUALS){
2075 if (!parse_asntype(fp, name, &type, token)){
2076 print_error("Bad parse of ASN type definition.", (char*)NULL, EQUALS);
2077 return NULL;
2078 }
2079 goto skipget;
2080 } else if (type == TRAPTYPE){ /* Jerry Yeung 6-6-96 */
2081 if(!parse_traptype(fp,name)){
2082 print_error("Bad parse of TRAP type",(char*)NULL,type);
2083 return NULL;
2084 }
2085 } else if (type == ENDOFFILE){
2086 break;
2087 } else {
2088 print_error("Bad operator", (char *)NULL, type);
2089 return NULL;
2090 }
2091 }
2092 #ifdef TEST
2093 {
2094 struct enum_list *ep;
2095
2096 for(np = root; np; np = np->next){
2097 printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
2098 np->type);
2099 if (np->enums){
2100 printf("Enums: \n");
2101 for(ep = np->enums; ep; ep = ep->next){
2102 printf("%s(%d)\n", ep->label, ep->value);
2103 }
2104 }
2105 }
2106 }
2107 #endif /* TEST */
2108 return root;
2109 }
2110
2111 /*
2112 * Parses a token from the file. The type of the token parsed is returned,
2113 * and the text is placed in the string pointed to by token.
2114 */
2115 static int
get_token(fp,token)2116 get_token(fp, token)
2117 register FILE *fp;
2118 register char *token;
2119 {
2120 static char last = ' ';
2121 register int ch;
2122 register char *cp = token;
2123 register int hash = 0;
2124 register struct tok *tp;
2125
2126 *cp = 0;
2127 ch = last;
2128 /* skip all white space */
2129 while(isspace(ch) && ch != -1){
2130 ch = getc(fp);
2131 if (ch == '\n')
2132 Line++;
2133 }
2134 if (ch == -1) {
2135 #ifdef TRACE_GET_TOKEN
2136 print_error("TRACE", token, ENDOFFILE);
2137 #endif
2138 return ENDOFFILE;
2139 } else if (ch == '"') {
2140 return parseQuoteString(fp, token);
2141 }
2142
2143 /*
2144 * Accumulate characters until end of token is found. Then attempt to
2145 * match this token as a reserved word. If a match is found, return the
2146 * type. Else it is a label.
2147 */
2148 do {
2149 if (ch == '\n')
2150 Line++;
2151 if (isspace(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
2152 ch == ',' || ch == ';'){
2153 if (!isspace(ch) && *token == 0){
2154 hash += ch;
2155 *cp++ = ch;
2156 last = ' ';
2157 } else {
2158 last = ch;
2159 }
2160 *cp = '\0';
2161
2162 for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
2163 if ((tp->hash == hash) && (strcmp(tp->name, token) == 0))
2164 break;
2165 }
2166 if (tp){
2167 if (tp->token == CONTINUE)
2168 continue;
2169 #ifdef TRACE_GET_TOKEN
2170 print_error("TRACE", token, tp->token);
2171 #endif
2172 return (tp->token);
2173 }
2174
2175 if (token[0] == '-' && token[1] == '-'){
2176 /* strip comment */
2177 if (ch != '\n'){
2178 while ((ch = getc(fp)) != -1)
2179 if (ch == '\n'){
2180 Line++;
2181 break;
2182 }
2183 }
2184 if (ch == -1)
2185 {
2186 #ifdef TRACE_GET_TOKEN
2187 print_error("TRACE", token, ENDOFFILE);
2188 #endif
2189 return ENDOFFILE;
2190 }
2191 last = ch;
2192 return get_token(fp, token);
2193 }
2194 for(cp = token; *cp; cp++)
2195 if (!isdigit(*cp))
2196 {
2197 #ifdef TRACE_GET_TOKEN
2198 print_error("TRACE", token, LABEL);
2199 #endif
2200 return LABEL;
2201 }
2202 #ifdef TRACE_GET_TOKEN
2203 print_error("TRACE", token, NUMBER);
2204 #endif
2205 number_value = atoi(token); /* octet string size */
2206 return NUMBER;
2207 } else {
2208 hash += ch;
2209 *cp++ = ch;
2210 if (ch == '\n')
2211 Line++;
2212 }
2213
2214 } while ((ch = getc(fp)) != -1);
2215 #ifdef TRACE_GET_TOKEN
2216 print_error("TRACE", token, ENDOFFILE);
2217 #endif
2218 return ENDOFFILE;
2219 }
2220
2221 struct tree *
read_mib(filename)2222 read_mib(filename)
2223 char *filename;
2224 {
2225 FILE *fp;
2226 struct node *nodes;
2227 struct tree *tree;
2228
2229 fp = fopen(filename, "r");
2230 if (fp == NULL)
2231 return NULL;
2232 nodes = parse(fp);
2233 if (!nodes){
2234 fprintf(stderr, "Mib table is bad. Exiting\n");
2235 exit(1);
2236 }
2237 tree = build_tree(nodes);
2238 fclose(fp);
2239 return tree;
2240 }
2241
2242
2243 #ifdef TEST
main(argc,argv)2244 main(argc, argv)
2245 int argc;
2246 char *argv[];
2247 {
2248 FILE *fp;
2249 struct node *nodes;
2250 struct tree *tp;
2251
2252 fp = fopen("mib.txt", "r");
2253 if (fp == NULL){
2254 fprintf(stderr, "open failed\n");
2255 return 1;
2256 }
2257 nodes = parse(fp);
2258 if (!nodes){
2259 fprintf(stderr, "Mib table is bad. \n");
2260 return (1);
2261 }
2262 tp = build_tree(nodes);
2263 print_subtree(tp, 0);
2264 fclose(fp);
2265 }
2266
2267 #endif /* TEST */
2268
2269 static int
parseQuoteString(fp,token)2270 parseQuoteString(fp, token)
2271 register FILE *fp;
2272 register char *token;
2273 {
2274 register int ch;
2275 register char *ptr, *ptr1;
2276 register int len = 0;
2277
2278 ch = ' ';
2279 *token = '\0'; /* make the token empty */
2280
2281 ptr = quoted_string_buffer;
2282 if (ptr)
2283 *ptr = 0;
2284
2285
2286 while(ch != -1) {
2287 ch = getc(fp);
2288 if (ch != '"') {
2289 if (ptr) {
2290 * ptr ++ = ch;
2291 len ++;
2292 if (len % MAXQUOTESTR == 0) {
2293 ptr1 = (char *) malloc (len + MAXQUOTESTR);
2294 if (!ptr1){
2295 fprintf(stderr, "malloc failed. Exiting\n");
2296 exit(1);
2297 }
2298 memcpy (ptr1, quoted_string_buffer, len);
2299 free (quoted_string_buffer);
2300 quoted_string_buffer = ptr1;
2301 ptr = ptr1 + len;
2302 }
2303 }
2304 } else {
2305 if (ptr)
2306 * ptr = 0;
2307 }
2308 if (ch == '\n')
2309 Line++;
2310 else if (ch == '"') {
2311 #ifdef TRACE_GET_TOKEN
2312 print_error("TRACE", token, QUOTESTRING);
2313 #endif
2314 return QUOTESTRING;
2315 }
2316
2317 }
2318
2319 #ifdef TRACE_GET_TOKEN
2320 print_error("TRACE", token, NULL);
2321 #endif
2322 return NULL;
2323 }
2324
2325 /*
2326 * This routine parses a string like { blah blah blah } and returns PARSE_OBJID if
2327 * it is well formed, and NULL if not.
2328 */
2329 static int
tossObjectIdentifier(fp)2330 tossObjectIdentifier(fp)
2331 register FILE *fp;
2332 {
2333 register int ch;
2334
2335 ch = getc(fp);
2336 /* ch = last; = ' '? */
2337 /* skip all white space */
2338 while(isspace(ch) && ch != -1){
2339 ch = getc(fp);
2340 if (ch == '\n')
2341 Line++;
2342 }
2343 if (ch != '{')
2344 return NULL;
2345
2346 while(ch != -1) {
2347 ch = getc(fp);
2348
2349 if (ch == '\n')
2350 Line++;
2351 else if (ch == '}')
2352 return PARSE_OBJID;
2353 }
2354
2355 /* last = ch;*/
2356 return NULL;
2357 }
2358