Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / dump-sppi.c
1 /*
2  * dump-sppi.c --
3  *
4  *      Operations to dump SPPI module information.
5  *
6  * Copyright (c) 1999 Frank Strauss, Technical University of Braunschweig.
7  *
8  * See the file "COPYING" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  */
12
13 #include <config.h>
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <time.h>
21
22 #include "smi.h"
23 #include "smidump.h"
24
25
26 #define  INDENT         4    /* indent factor */
27 #define  INDENTVALUE    16   /* column to start values, except multiline */
28 #define  INDENTTEXTS     9   /* column to start multiline texts */
29 #define  INDENTMAX      72   /* max column to fill, break lines otherwise */
30
31 static char *convertType[] = {
32     NULL,                "INTEGER",            NULL,       "Integer32",
33     NULL,                "Bits",               NULL,       "BITS",
34     NULL,                "OctetString",        NULL,       "OCTET STRING",
35     NULL,                "ObjectIdentifier",   NULL,       "OBJECT IDENTIFIER",
36     NULL,                "IpAddress",          NULL,       "InetAddress",
37     NULL,                "Counter64",          NULL,       "Unsigned64",
38     NULL,                "Counter32",          NULL,       "Unsigned32",
39     NULL,                "Gauge32",            NULL,       "Unsigned32",
40     NULL, NULL, NULL, NULL };
41
42 static char *convertTypeMibToPib[] = {
43     NULL,                "SnmpAdminString",    NULL,       "OCTET STRING",
44     NULL, NULL, NULL, NULL };
45
46 static char *convertImport[] = {
47     "SNMPv2-SMI", "Integer32",      "COPS-PR-SPPI", "Integer32",
48     "SNMPv2-SMI", "Unsigned32",     "COPS-PR-SPPI", "Unsigned32",
49     "SNMPv2-SMI", "TimeTicks",      "COPS-PR-SPPI", "TimeTicks",
50     "SNMPv2-SMI", "IpAddress",      "INET-ADDRESS-MIB", "InetAddress",
51     "SNMPv2-SMI", "MODULE-IDENTITY","COPS-PR-SPPI", "MODULE-IDENTITY",
52     "SNMPv2-SMI", "MODULE-COMPLIANCE","COPS-PR-SPPI", "MODULE-COMPLIANCE",
53     "SNMPv2-SMI", "OBJECT-TYPE",    "COPS-PR-SPPI", "OBJECT-TYPE",
54     "SNMPv2-SMI", "OBJECT-IDENTITY","COPS-PR-SPPI", "OBJECT-IDENTITY",
55     "SNMPv2-TC",  "TEXTUAL-CONVENTION","COPS-PR-SPPI", "TEXTUAL-CONVENTION",
56     NULL, NULL, NULL, NULL };
57
58 static int current_column = 0;
59 static int silent = 0;
60 static int mibtopib = 0;
61
62
63 typedef struct Import {
64     char          *module;
65     char          *name;
66     struct Import *nextPtr;
67 } Import;
68
69 static Import *importList = NULL;
70
71
72
73 static int invalidType(SmiBasetype basetype)
74 {
75     return (basetype == SMI_BASETYPE_FLOAT32)
76         || (basetype == SMI_BASETYPE_FLOAT64)
77         || (basetype == SMI_BASETYPE_FLOAT128);
78 }
79
80
81
82 static char *getStatusString(SmiStatus status)
83 {
84     return
85         (status == SMI_STATUS_CURRENT)     ? "current" :
86         (status == SMI_STATUS_DEPRECATED)  ? "deprecated" :
87         (status == SMI_STATUS_OBSOLETE)    ? "obsolete" :
88                                              "<unknown>";
89 }
90
91
92
93 static char *getAccessString(SmiAccess access, int pibaccess)
94 {
95     return
96         (access == SMI_ACCESS_NOTIFY)         ? "notify" :
97         (access == SMI_ACCESS_INSTALL)        ? "install" :
98         (access == SMI_ACCESS_INSTALL_NOTIFY) ? "install-notify" :
99         (access == SMI_ACCESS_REPORT_ONLY)    ? "report-only" :
100         (access == SMI_ACCESS_NOT_ACCESSIBLE) ?
101              (pibaccess == 1 ? "report-only" : "not-accessible") :
102         mibtopib                              ? "notify" : 
103                                                 "<unknown>";
104 }
105
106
107 static int isSmiOnlyType(char *type)
108 {
109     return (!strcmp(type, "Counter32") ||
110             !strcmp(type, "Counter64") ||
111             !strcmp(type, "Gauge32"));
112 }
113
114
115 static char *getTimeString(time_t t)
116 {
117     static char   *s = NULL;
118     struct tm     *tm;
119
120     if (s) xfree(s);
121
122     tm = gmtime(&t);
123     smiAsprintf(&s, "%04d%02d%02d%02d%02dZ",
124                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
125                 tm->tm_hour, tm->tm_min);
126     return s;
127 }
128
129
130
131 static char *getTypeString(SmiBasetype basetype, SmiType *smiType)
132 {
133     int         i;
134     char        *typeModule, *typeName;
135
136     typeName = smiType ? smiType->name : NULL;
137     typeModule = smiType ? smiGetTypeModule(smiType)->name : NULL;
138
139     if (typeName &&
140         (basetype != SMI_BASETYPE_ENUM) &&
141         (basetype != SMI_BASETYPE_BITS)) {
142         if (mibtopib)
143             for(i=0; convertTypeMibToPib[i+1]; i += 4) {
144                 if ((!strcmp(typeName, convertTypeMibToPib[i+1])) &&
145                     ((!typeModule) || (!convertTypeMibToPib[i]) ||
146                      (!strcmp(typeModule, convertTypeMibToPib[i])))) {
147                     return convertTypeMibToPib[i+3];
148                 }
149             }
150         for(i=0; convertType[i+1]; i += 4) {
151             if ((!strcmp(typeName, convertType[i+1])) &&
152                 ((!typeModule) || (!convertType[i]) ||
153                  (!strcmp(typeModule, convertType[i])))) {
154                 return convertType[i+3];
155             }
156         }
157     }
158
159     if ((!typeModule) || (!strlen(typeModule)) || (!typeName)) {
160         if (basetype == SMI_BASETYPE_ENUM) {
161             return "INTEGER";
162         }
163         if (basetype == SMI_BASETYPE_BITS) {
164             return "BITS";
165         }
166     }
167         
168     /* TODO: fully qualified if unambigous */
169
170     return typeName;
171 }
172
173
174
175 static char *getOidString(SmiNode *smiNode, int importedParent)
176 {
177     SmiNode      *parentNode;
178     SmiModule    *smiModule;
179     static char  s[200];
180     char         append[200];
181     unsigned int i;
182
183     append[0] = 0;
184
185     parentNode = smiNode;
186     smiModule = smiGetNodeModule(smiNode);
187     
188     do {
189         
190         if (parentNode->oidlen <= 1) {
191             break;
192         }
193         
194         /* prepend the cut-off subidentifier to `append'. */
195         strcpy(s, append);
196         sprintf(append, " %u%s", parentNode->oid[parentNode->oidlen-1], s);
197
198         /* retrieve the parent SmiNode */
199         parentNode = smiGetParentNode(parentNode);
200
201         if (!parentNode) {
202             sprintf(s, "%s", append);
203             return s;
204         }
205         
206         /* found an imported or a local parent node? */
207         if ((parentNode->name && strlen(parentNode->name)) &&
208             (smiIsImported(smiModule, NULL, parentNode->name) ||
209              (!importedParent &&
210               (smiGetNodeModule(parentNode) == smiModule)) ||
211              (parentNode->oidlen == 1))) {
212             sprintf(s, "%s%s", parentNode->name, append);
213             return s;
214         }
215         
216     } while (parentNode);
217
218     s[0] = 0;
219     for (i=0; i < smiNode->oidlen; i++) {
220         if (i) strcat(s, " ");
221         sprintf(&s[strlen(s)], "%u", smiNode->oid[i]);
222     }
223     return s;
224 }
225
226
227
228 static char *getUppercaseString(char *s)
229 {
230     static char *ss;
231
232     ss = xstrdup(s);
233     ss[0] = (char)toupper((int)ss[0]);
234     return ss;
235 }
236
237
238
239 static int isObjectGroup(SmiNode *groupNode)
240 {
241     SmiNode     *smiNode;
242     SmiElement  *smiElement;
243     
244     for (smiElement = smiGetFirstElement(groupNode); smiElement;
245          smiElement = smiGetNextElement(smiElement)) {
246
247         smiNode = smiGetElementNode(smiElement);
248         
249         if (smiNode->nodekind != SMI_NODEKIND_SCALAR
250             && smiNode->nodekind != SMI_NODEKIND_COLUMN) {
251             return 0;
252         }
253     }
254
255     return 1;
256 }
257
258
259
260 static Import* addImport(char *module, char *name)
261 {
262     Import **import, *newImport;
263     int    i;
264
265     for (i = 0; convertImport[i]; i += 4) {
266         if (convertImport[i] && convertImport[i+1]
267             && !strcmp(module, convertImport[i])
268             && !strcmp(name, convertImport[i+1])) {
269             module = convertImport[i+2];
270             name = convertImport[i+3];
271             break;
272         } else if (convertImport[i] && !convertImport[i+1]
273                    && !strcmp(module, convertImport[i])) {
274             module = convertImport[i+2];
275             break;
276         }
277     }
278
279     if (!module || !name) {
280         return NULL;
281     }
282             
283     for (import = &importList; *import; import = &(*import)->nextPtr) {
284         int c = strcmp((*import)->module, module);
285         if (c < 0) continue;
286         if (c == 0) {
287             int d = strcmp((*import)->name, name);
288             if (d < 0) continue;
289             if (d == 0) return *import;
290             if (d > 0) break;
291         }
292         if (c > 0) break;
293     }
294
295     newImport = xmalloc(sizeof(Import));
296     if (! newImport) {
297         return NULL;
298     }
299     newImport->module = module;
300     newImport->name = name;
301     newImport->nextPtr = *import;
302     *import = newImport;
303         
304     return *import;
305 }
306
307
308
309 static void createImportList(SmiModule *smiModule)
310 {
311     SmiNode     *smiNode;
312     SmiType     *smiType;
313     SmiNodekind kind = SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN;
314     SmiImport   *smiImport;
315     SmiModule   *smiModule2;
316
317     if (mibtopib) {
318         addImport("TUBS-SMI", "ibrmibtopib");
319         if (smiGetFirstNode(smiModule, SMI_NODEKIND_COLUMN)) {
320             addImport("COPS-PR-SPPI", "MODULE-COMPLIANCE");
321             addImport("COPS-PR-SPPI", "OBJECT-GROUP");
322             addImport("COPS-PR-SPPI", "OBJECT-IDENTITY");
323             addImport("COPS-PR-SPPI-TC", "InstanceId");
324         }
325     }
326     
327     for(smiNode = smiGetFirstNode(smiModule, kind); smiNode;
328         smiNode = smiGetNextNode(smiNode, kind)) {
329         smiType = smiGetNodeType(smiNode);
330         if (smiType && (smiType->decl == SMI_DECL_IMPLICIT_TYPE)) {
331             smiType = smiGetParentType(smiType);
332         }
333         if (smiType) {
334             smiModule2 = smiGetTypeModule(smiType);
335             if (smiModule2 && (smiModule2 != smiModule)) {
336                 if (strlen(smiModule2->name) && smiType->name &&
337                     !isSmiOnlyType(smiType->name)) {
338                     addImport(smiModule2->name, smiType->name);
339                 }
340             }
341         }
342
343         if (smiType && smiType->basetype == SMI_BASETYPE_INTEGER32) {
344             addImport("COPS-PR-SPPI", "Integer32");
345         }
346
347         if (smiType && smiType->basetype == SMI_BASETYPE_INTEGER64) {
348             addImport("COPS-PR-SPPI", "Integer64");
349         }
350
351         if (smiType && smiType->basetype == SMI_BASETYPE_UNSIGNED32) {
352             addImport("COPS-PR-SPPI", "Unsigned32");
353         }
354
355         if (smiType && smiType->basetype == SMI_BASETYPE_UNSIGNED64) {
356             addImport("COPS-PR-SPPI", "Unsigned64");
357         }
358
359         if ((smiNode->value.basetype == SMI_BASETYPE_OBJECTIDENTIFIER) &&
360             (!strcmp(smiNode->value.value.ptr, "zeroDotZero"))) {
361             addImport("SNMPv2-SMI", "zeroDotZero");
362         }
363     }
364
365     smiNode = smiGetFirstNode(smiModule,
366                               SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN
367                               | SMI_NODEKIND_TABLE | SMI_NODEKIND_ROW);
368     if (smiNode) {
369         addImport("COPS-PR-SPPI", "OBJECT-TYPE");
370     }
371
372     smiNode = smiGetModuleIdentityNode(smiModule);
373     if (smiNode) {
374         if (strcmp("COPS-PR-SPPI", smiModule->name)) {
375             addImport("COPS-PR-SPPI", "MODULE-IDENTITY");
376         }
377     }
378     
379     for(smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NODE);
380         smiNode; smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NODE)) {
381         if (smiNode->status != SMI_STATUS_UNKNOWN &&
382             smiNode != smiGetModuleIdentityNode(smiModule)) {
383             if (strcmp("COPS-PR-SPPI", smiModule->name)) {
384                 addImport("COPS-PR-SPPI", "OBJECT-IDENTITY");
385             }
386             break;
387         }
388     }
389
390     smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_COMPLIANCE);
391     if (smiNode) {
392         if (strcmp("COPS-PR-SPPI", smiModule->name)) {
393             addImport("COPS-PR-SPPI", "MODULE-COMPLIANCE");
394         }
395     }
396
397     for(smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_GROUP);
398         smiNode;
399         smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_GROUP)) {
400         if (strcmp("COPS-PR-SPPI", smiModule->name)) {
401             addImport("COPS-PR-SPPI", "OBJECT-GROUP");
402         }
403     }
404
405     for(smiType = smiGetFirstType(smiModule);
406         smiType; smiType = smiGetNextType(smiType)) {
407         if (smiType->description) {
408             if (strcmp("COPS-PR-SPPI", smiModule->name)) {
409                 addImport("COPS-PR-SPPI", "TEXTUAL-CONVENTION");
410             }
411         }
412         if (smiType->decl == SMI_DECL_TEXTUALCONVENTION) {
413             switch (smiType->basetype) {
414             case SMI_BASETYPE_INTEGER32:
415                 addImport("COPS-PR-SPPI", "Integer32");
416                 break;
417             case SMI_BASETYPE_INTEGER64:
418                 addImport("COPS-PR-SPPI", "Integer64");
419                 break;
420             case SMI_BASETYPE_UNSIGNED32:
421                 addImport("COPS-PR-SPPI", "Unsigned32");
422                 break;
423             case SMI_BASETYPE_UNSIGNED64:
424                 addImport("COPS-PR-SPPI", "Unsigned64");
425                 break;
426             default:
427                 break;
428             }
429         }
430     }
431
432     for (smiImport = smiGetFirstImport(smiModule); smiImport;
433          smiImport = smiGetNextImport(smiImport)) {
434         if ((islower((int) smiImport->name[0]) ||
435             (smiImport->module && !strcmp(smiImport->module, "SNMPv2-SMI")) ||
436             (smiImport->module && !strcmp(smiImport->module, "SNMPv2-TC"))) &&
437             !isSmiOnlyType(smiImport->name)) {
438             addImport(smiImport->module, smiImport->name);
439         }
440     }
441 }
442
443
444
445 static void freeImportList(void)
446 {
447     Import *import, *freeme;
448
449     for (import = importList; import; ) {
450         freeme = import;
451         import = import->nextPtr;
452         xfree(freeme);
453     }
454     importList = NULL;
455 }
456
457
458
459 static void fprint(FILE *f, char *fmt, ...)
460 {
461     va_list ap;
462     char    *s;
463     char    *p;
464     
465     va_start(ap, fmt);
466     current_column += smiVasprintf(&s, fmt, ap);
467     va_end(ap);
468     fputs(s, f);
469     if ((p = strrchr(s, '\n'))) {
470         current_column = strlen(p) - 1;
471     }
472     free(s);
473 }
474
475
476
477 static void fprintSegment(FILE *f, int column, char *string,
478                           int length, int comment)
479 {
480     char *format;
481     
482     if (comment) {
483         format = "-- %*c%s";
484         /* if (column >= 3) column -= 3; */
485     } else {
486         format = "%*c%s";
487     }
488     
489     fprint(f, format, column, ' ', string);
490     if (length) {
491         fprint(f, "%*c", length - strlen(string) - column, ' ');
492     }
493 }
494
495
496
497 static void fprintWrapped(FILE *f, int column, char *string, int comment)
498 {
499     if ((current_column + strlen(string)) > INDENTMAX) {
500         putc('\n', f);
501         current_column = 0;
502         fprintSegment(f, column, "", 0, comment);
503     }
504     fprint(f, "%s", string);
505 }
506
507
508
509 static void fprintMultilineString(FILE *f, const char *s, const int comment)
510 {
511     int i, len;
512     
513     fprintSegment(f, INDENTTEXTS - 1, "\"", 0, comment);
514     if (s) {
515         len = strlen(s);
516         for (i=0; i < len; i++) {
517             putc(s[i], f);
518             current_column++;
519             if (s[i] == '\n') {
520                 current_column = 0;
521                 fprintSegment(f, INDENTTEXTS, "", 0, comment);
522             }
523         }
524     }
525     putc('\"', f);
526     current_column++;
527 }
528
529
530
531 static char *getValueString(SmiValue *valuePtr, SmiType *typePtr)
532 {
533     static char    s[1024];
534     char           ss[9];
535     int            n;
536     unsigned int   i;
537     SmiNamedNumber *nn;
538     SmiNode        *nodePtr;
539     
540     s[0] = 0;
541     
542     switch (valuePtr->basetype) {
543     case SMI_BASETYPE_UNSIGNED32:
544         sprintf(s, "%lu", valuePtr->value.unsigned32);
545         break;
546     case SMI_BASETYPE_INTEGER32:
547         sprintf(s, "%ld", valuePtr->value.integer32);
548         break;
549     case SMI_BASETYPE_UNSIGNED64:
550         sprintf(s, UINT64_FORMAT, valuePtr->value.unsigned64);
551         break;
552     case SMI_BASETYPE_INTEGER64:
553         sprintf(s, INT64_FORMAT, valuePtr->value.integer64);
554         break;
555     case SMI_BASETYPE_ENUM:
556         for (nn = smiGetFirstNamedNumber(typePtr); nn;
557              nn = smiGetNextNamedNumber(nn)) {
558             if (nn->value.value.unsigned32 == valuePtr->value.unsigned32)
559                 break;
560         }
561         if (nn) {
562             sprintf(s, "%s", nn->name);
563         } else {
564             sprintf(s, "%ld", valuePtr->value.integer32);
565         }
566         break;
567     case SMI_BASETYPE_OCTETSTRING:
568         for (i = 0; i < valuePtr->len; i++) {
569             if (!isprint((int)valuePtr->value.ptr[i])) break;
570         }
571         if (i == valuePtr->len) {
572             sprintf(s, "\"%s\"", valuePtr->value.ptr);
573         } else {
574             sprintf(s, "'%*s'H", 2 * valuePtr->len, " ");
575             for (i=0; i < valuePtr->len; i++) {
576                 sprintf(ss, "%02x", valuePtr->value.ptr[i]);
577                 strncpy(&s[1+2*i], ss, 2);
578             }
579         }
580         break;
581     case SMI_BASETYPE_BITS:
582         sprintf(s, "{");
583         for (i = 0, n = 0; i < valuePtr->len * 8; i++) {
584             if (valuePtr->value.ptr[i/8] & (1 << (7-(i%8)))) {
585                 for (nn = smiGetFirstNamedNumber(typePtr); nn;
586                      nn = smiGetNextNamedNumber(nn)) {
587                     if (nn->value.value.unsigned32 == i)
588                         break;
589                 }
590                 if (nn) {
591                     if (n)
592                         sprintf(&s[strlen(s)], ", ");
593                     n++;
594                     sprintf(&s[strlen(s)], "%s", nn->name);
595                 }
596             }
597         }
598         sprintf(&s[strlen(s)], "}");
599         break;
600     case SMI_BASETYPE_FLOAT32:
601     case SMI_BASETYPE_FLOAT64:
602     case SMI_BASETYPE_FLOAT128:
603     case SMI_BASETYPE_UNKNOWN:
604     case SMI_BASETYPE_POINTER:
605         break;
606     case SMI_BASETYPE_OBJECTIDENTIFIER:
607         nodePtr = smiGetNodeByOID(valuePtr->len, valuePtr->value.oid);
608         if (nodePtr) {
609             sprintf(s, "%s", nodePtr->name);
610         } else {
611             strcpy(s, "{");
612             for (i=0; i < valuePtr->len; i++) {
613                 if (i) strcat(s, " ");
614                 sprintf(&s[strlen(s)], "%u", valuePtr->value.oid[i]);
615             }
616             strcat(s, "}");
617         }
618         break;
619     }
620
621     return s;
622 }
623
624
625
626 static void fprintSubtype(FILE *f, SmiType *smiType, const int comment)
627 {
628     SmiRange       *range;
629     SmiNamedNumber *nn;
630     char           s[1024];
631     int            i;
632
633     if ((smiType->basetype == SMI_BASETYPE_ENUM) ||
634         (smiType->basetype == SMI_BASETYPE_BITS)) {
635         for(i = 0, nn = smiGetFirstNamedNumber(smiType);
636             nn; i++, nn = smiGetNextNamedNumber(nn)) {
637             if (i) {
638                 fprint(f, ", ");
639             } else {
640                 if (comment) {
641                     fprint(f, "\n");
642                     fprintSegment(f, INDENT, "", INDENTVALUE, comment);
643                     fprint(f, "  { ");
644                 } else {
645                     fprint(f, " { ");
646                 }
647             }
648             sprintf(s, "%s(%s)", nn->name,
649                     getValueString(&nn->value, smiType));
650             fprintWrapped(f, INDENTVALUE + INDENT, s, comment);
651         }
652         if (i) {
653             fprint(f, " }");
654         }
655     } else {
656         for(i = 0, range = smiGetFirstRange(smiType);
657             range; i++, range = smiGetNextRange(range)) {
658             if (i) {
659                 fprint(f, " | ");
660             } else {
661                 if (smiType->basetype == SMI_BASETYPE_OCTETSTRING) {
662                     fprint(f, " (SIZE(");
663                 } else {
664                     fprint(f, " (");
665                 }
666             }       
667             if (memcmp(&range->minValue, &range->maxValue,
668                        sizeof(SmiValue))) {
669                 sprintf(s, "%s", getValueString(&range->minValue, smiType));
670                 sprintf(&s[strlen(s)], "..%s", 
671                         getValueString(&range->maxValue, smiType));
672             } else {
673                 sprintf(s, "%s", getValueString(&range->minValue, smiType));
674             }
675             fprintWrapped(f, INDENTVALUE + INDENT, s, 0);
676         }
677         if (i) {
678             if (smiType->basetype == SMI_BASETYPE_OCTETSTRING) {
679                 fprint(f, ")");
680             }
681             fprint(f, ")");
682         }
683     }
684 }
685
686
687
688 static void fprintIndex(FILE *f, SmiNode *indexNode, const int comment)
689 {
690     SmiElement *smiElement;
691     int        n, j;
692
693     /* PIBs can contain both a PIB-INDEX | EXTENDS | AUGMENTS and an
694        INDEX clause. The index list's first element is the PIB-INDEX
695        (or EXTENDS/AUGMENTS) followed by the elements belonging to the
696        INDEX clause. */
697     
698     for (n = 0, smiElement = smiGetFirstElement(indexNode); smiElement;
699          n++, smiElement = smiGetNextElement(smiElement));
700     if (mibtopib) {
701         SmiNode *smiParentNode = smiGetParentNode(indexNode);
702         size_t len = strlen(smiParentNode->name);
703         char *instanceId = xmalloc(len + 11);
704
705         strcpy(instanceId, smiParentNode->name);
706         if (len > 54)
707           len = 54;
708         strcpy(&instanceId[len], "InstanceId");
709         fprintSegment(f, INDENT, "PIB-INDEX", INDENTVALUE, 0);
710         fprint(f, "{ ");
711         fprintWrapped(f, INDENTVALUE + 2, instanceId, 0);
712         fprint(f, " }\n");
713         fprintSegment(f, INDENT, "INDEX", INDENTVALUE, 0);
714         fprint(f, "{ ");
715         for (j = 0, smiElement = smiGetFirstElement(indexNode); smiElement;
716              j++, smiElement = smiGetNextElement(smiElement)) {
717              if (j)
718                  fprint(f, ", ");
719              fprintWrapped(f, INDENTVALUE + 2,
720                            smiGetElementNode(smiElement)->name, 0);
721         }
722         xfree(instanceId);
723     }
724     else
725         for (j = 0, smiElement = smiGetFirstElement(indexNode); smiElement;
726              j++, smiElement = smiGetNextElement(smiElement)) {
727             if (!j) {
728                 switch (indexNode->indexkind) {
729                     case SMI_INDEX_INDEX:
730                         fprintSegment(f, INDENT, "PIB-INDEX", INDENTVALUE,
731                                       comment);
732                         break;
733                     case SMI_INDEX_AUGMENT:
734                         fprintSegment(f, INDENT, "AUGMENTS", INDENTVALUE,
735                                       comment);
736                         break;
737                     case SMI_INDEX_SPARSE:
738                         fprintSegment(f, INDENT, "EXTENDS", INDENTVALUE,
739                                       comment);
740                         break;
741                     case SMI_INDEX_UNKNOWN:
742                     case SMI_INDEX_REORDER:
743                     case SMI_INDEX_EXPAND:
744                         fprintSegment(f, INDENT, "-- unsupported indexing --",
745                                       INDENTVALUE, comment);
746                         break;
747                 }
748                 fprint(f, "{ ");
749             } else if (j == 1) {
750                 fprint(f, " }\n");
751                 fprintSegment(f, INDENT, "INDEX", INDENTVALUE, comment);
752                 fprint(f, "{ ");
753             } else
754                 fprint(f, ", ");
755             if (indexNode->implied && ((j+1) == n)) {
756                 fprintWrapped(f, INDENTVALUE + 2, "IMPLIED ", 0);
757             }
758             fprintWrapped(f, INDENTVALUE + 2,
759                           smiGetElementNode(smiElement)->name, 0);
760             /* TODO: non-local name if non-local */
761         } /* TODO: empty? -> print error */
762     fprint(f, " }\n");
763 }
764
765
766
767 static void fprintUniqueness(FILE *f, SmiNode *indexNode, const int comment)
768 {
769     SmiElement *smiElement;
770     int        j;
771
772     smiElement = smiGetFirstUniquenessElement(indexNode);
773     if (!smiElement)
774         return;
775     fprintSegment(f, INDENT, "UNIQUENESS", INDENTVALUE, comment);
776     fprint(f, "{ ");
777     for (j = 0; smiElement; j++,
778          smiElement = smiGetNextElement(smiElement)) {
779         if (j)
780             fprint(f, ", ");
781         fprintWrapped(f, INDENTVALUE + 2,
782                       smiGetElementNode(smiElement)->name, 0);
783         /* TODO: non-local name if non-local */
784     } /* TODO: empty? -> print error */
785     fprint(f, " }\n");
786 }
787
788
789
790 static void fprintInstallErrors(FILE *f, SmiNode *indexNode, const int comment)
791 {
792     SmiElement *smiElement;
793     SmiNode    *smiNode;
794     int        j;
795     char       *id;
796
797     smiElement = smiGetFirstElement(indexNode);
798     if (!smiElement)
799         return;
800     fprintSegment(f, INDENT, "INSTALL-ERRORS", INDENTVALUE, comment);
801     fprint(f, "{ ");
802     for (j = 0; smiElement; j++,
803          smiElement = smiGetNextElement(smiElement)) {
804         smiNode = smiGetElementNode(smiElement);
805         id = xmalloc(strlen(smiNode->name) + 10);
806         sprintf(id, "%s (%ld)%s", smiNode->name,
807                 smiNode->oidlen ? (long)smiNode->oid : 0,
808                 smiGetNextElement(smiElement) ? ", " : "");
809         fprintWrapped(f, 2+INDENTVALUE, id, 0);
810         xfree(id);
811         /* TODO: non-local name if non-local */
812     } /* TODO: empty? -> print error */
813     fprint(f, " }\n");
814 }
815
816
817
818 static void fprintImports(FILE *f)
819 {
820     Import        *import;
821     char          *lastModulename = NULL;
822     char          *importedModulename, *importedDescriptor;
823     int           i;
824
825     for(import = importList; import; import = import->nextPtr) {
826         importedModulename = import->module;
827         importedDescriptor = import->name;
828
829         if (!strlen(importedModulename))
830             continue;
831         
832         for(i = 0; convertImport[i]; i += 4) {
833             if (convertImport[i] && convertImport[i+1]
834                 && !strcmp(importedModulename, convertImport[i])
835                 && !strcmp(importedDescriptor, convertImport[i+1])) {
836                 importedModulename = convertImport[i+2];
837                 importedDescriptor = convertImport[i+3];
838                 break;
839             } else if (convertImport[i] && !convertImport[i+1]
840                        && !strcmp(importedModulename, convertImport[i])) {
841                 importedModulename = convertImport[i+2];
842                 break;
843             }
844         }
845
846         if (importedModulename && importedDescriptor &&
847             strlen(importedDescriptor)) {
848             if ((!lastModulename) ||
849                 strcmp(importedModulename, lastModulename)) {
850                 if (!lastModulename) {
851                     fprint(f, "IMPORTS");
852                 } else {
853                     fprint(f, "\n");
854                     fprintSegment(f, 2 * INDENT, "", 0, 0);
855                     fprint(f, "FROM %s", lastModulename);
856                 }
857                 fprint(f, "\n");
858                 fprintSegment(f, INDENT, "", 0, 0);
859             } else {
860                 fprint(f, ", ");
861             }
862             fprintWrapped(f, INDENT, importedDescriptor, 0);
863             lastModulename = importedModulename;
864         }
865     }
866     if (lastModulename) {
867         fprint(f, "\n");
868         fprintSegment(f, 2 * INDENT, "", 0, 0);
869         fprint(f, "FROM %s;\n\n", lastModulename);
870     }
871 }
872
873
874
875 static void fprintModuleIdentity(FILE *f, SmiModule *smiModule)
876 {
877     SmiRevision  *smiRevision;
878     SmiNode      *smiNode, *smiNode2;
879     SmiElement   *smiElement;
880     char         *id;
881
882     smiNode = smiGetModuleIdentityNode(smiModule);
883     
884     if (smiNode) {
885
886         fprint(f, "%s MODULE-IDENTITY\n", smiNode->name);
887         fprintSegment(f, INDENT, "SUBJECT-CATEGORIES", INDENTVALUE, 0);
888         fprint(f, "{ ");
889         smiElement = smiGetFirstElement(smiNode);
890         if (smiElement && smiGetElementNode(smiElement))
891         {
892             for (; smiElement; smiElement = smiGetNextElement(smiElement)) {
893                 smiNode2 = smiGetElementNode(smiElement);
894                 id = xmalloc(strlen(smiNode2->name) + 10);
895                 if (smiNode2->oidlen)
896                     sprintf(id, "%s (%ld)%s", smiNode2->name, (long)smiNode2->oid,
897                             smiGetNextElement(smiElement) ? ", " : "");
898                 else
899                     sprintf(id, "%s%s", smiNode2->name,
900                             smiGetNextElement(smiElement) ? ", " : "");
901                 fprintWrapped(f, 2+INDENTVALUE, id, 0);
902                 xfree(id);
903             }
904             fprint(f, " }\n");
905         } else {
906         /* No SUBJECT-CATEGORIES entry was present, add one */
907             fprint(f, "all } -- added by smidump\n");
908         }
909         fprintSegment(f, INDENT, "LAST-UPDATED", INDENTVALUE, 0);
910         smiRevision = smiGetFirstRevision(smiModule);
911         if (smiRevision)
912             fprint(f, "\"%s\"\n", getTimeString(smiRevision->date));
913         else
914             fprint(f, "\"197001010000Z\"\n");
915         fprintSegment(f, INDENT, "ORGANIZATION", INDENTVALUE, 0);
916         fprint(f, "\n");
917         fprintMultilineString(f, smiModule->organization, 0);
918         fprint(f, "\n");
919         fprintSegment(f, INDENT, "CONTACT-INFO", INDENTVALUE, 0);
920         fprint(f, "\n");
921         fprintMultilineString(f, smiModule->contactinfo, 0);
922         fprint(f, "\n");
923         fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE, 0);
924         fprint(f, "\n");
925         if (smiModule->description) {
926             fprintMultilineString(f, smiModule->description, 0);
927         } else {
928             fprintMultilineString(f, "...", 0);
929         }
930         fprint(f, "\n");
931
932         for(; smiRevision;
933             smiRevision = smiGetNextRevision(smiRevision)) {
934             if (!smiRevision->description
935                 || strcmp(smiRevision->description,
936        "[Revision added by libsmi due to a LAST-UPDATED clause.]")) {
937                 fprintSegment(f, INDENT, "REVISION", INDENTVALUE, 0);
938                 fprint(f, "\"%s\"\n", getTimeString(smiRevision->date));
939                 fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE,
940                               0);
941                 fprint(f, "\n");
942                 if (smiRevision->description) {
943                     fprintMultilineString(f, smiRevision->description,
944                                           0);
945                 } else {
946                     fprintMultilineString(f, "...", 0);
947                 }
948                 fprint(f, "\n");
949             }
950         }
951
952         if (smiNode) {
953             fprintSegment(f, INDENT, "::= ", 0, 0);
954             if (!mibtopib)
955                 fprint(f, "{ %s }\n\n", getOidString(smiNode, 0));
956             else
957                 fprint(f, "{ ibrmibtopib %d }\n\n",
958                        smiNode->oid[smiNode->oidlen - 1]);
959         }
960         /* TODO: else error */
961
962         fprint(f, "\n");
963     }
964 }
965
966
967
968 static void fprintTypeDefinitions(FILE *f, SmiModule *smiModule)
969 {
970     SmiType      *smiType;
971     int          invalid;
972
973     for(smiType = smiGetFirstType(smiModule);
974         smiType; smiType = smiGetNextType(smiType)) {
975         if (smiType->status == SMI_STATUS_UNKNOWN) {
976             invalid = invalidType(smiType->basetype);
977             if (invalid) {
978                 fprint(f, "-- %s ::=\n", smiType->name);
979             } else {
980                 fprint(f, "%s ::=\n", smiType->name);
981             }
982             fprintSegment(f, INDENT, "", 0, invalid);
983             fprint(f, "%s", getTypeString(smiType->basetype,
984                                           smiGetParentType(smiType)));
985             fprintSubtype(f, smiType, invalid);
986             fprint(f, "\n\n");
987         }
988     }
989 }
990
991
992
993 static void fprintTextualConventions(FILE *f, SmiModule *smiModule)
994 {
995     SmiType      *smiType;
996     int          invalid;
997     
998     for(smiType = smiGetFirstType(smiModule);
999         smiType; smiType = smiGetNextType(smiType)) {
1000         if (smiType->status != SMI_STATUS_UNKNOWN) {
1001             invalid = invalidType(smiType->basetype);
1002             fprint(f, "%s ::= TEXTUAL-CONVENTION\n", smiType->name);
1003
1004             if (smiType->format) {
1005                 fprintSegment(f, INDENT, "DISPLAY-HINT", INDENTVALUE,
1006                               invalid);
1007                 fprint(f, "\"%s\"\n", smiType->format);
1008             }
1009
1010             fprintSegment(f, INDENT, "STATUS", INDENTVALUE,
1011                           invalid);
1012             fprint(f, "%s\n", getStatusString(smiType->status));
1013
1014             fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE,
1015                           invalid);
1016             fprint(f, "\n");
1017             if (smiType->description) {
1018                 fprintMultilineString(f, smiType->description,
1019                                       invalid);
1020             } else {
1021                 fprintMultilineString(f, "...", invalid);
1022             }
1023             fprint(f, "\n");
1024
1025             if (smiType->reference) {
1026                 fprintSegment(f, INDENT, "REFERENCE", INDENTVALUE,
1027                               invalid);
1028                 fprint(f, "\n");
1029                 fprintMultilineString(f, smiType->reference,
1030                                       invalid);
1031                 fprint(f, "\n");
1032             }
1033             fprintSegment(f, INDENT, "SYNTAX", INDENTVALUE,
1034                           invalid);
1035             fprint(f, "%s",
1036                    getTypeString(smiType->basetype,
1037                                  smiGetParentType(smiType)));
1038             fprintSubtype(f, smiType, invalid);
1039             fprint(f, "\n\n");
1040         }
1041     }
1042 }
1043
1044
1045
1046 static void fprintObjects(FILE *f, SmiModule *smiModule)
1047 {
1048     SmiNode      *smiNode, *rowNode, *colNode, *smiParentNode, *relatedNode;
1049     SmiType      *smiType;
1050     SmiNodekind  nodekinds;
1051     int          i, invalid, create, assignement, indentsequence, addinstanceid;
1052     
1053     nodekinds =  SMI_NODEKIND_NODE | SMI_NODEKIND_TABLE |
1054         SMI_NODEKIND_ROW | SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR;
1055             
1056     for(smiNode = smiGetFirstNode(smiModule, nodekinds);
1057         smiNode; smiNode = smiGetNextNode(smiNode, nodekinds)) {
1058
1059         smiType = smiGetNodeType(smiNode);
1060         smiParentNode = smiGetParentNode(smiNode);
1061         
1062         create = smiParentNode ? smiParentNode->create : 0;
1063         
1064         invalid = !smiType ? 0 : invalidType(smiType->basetype);
1065         assignement = 0;
1066
1067         if (invalid && silent
1068             && (smiNode->nodekind == SMI_NODEKIND_SCALAR
1069                 || smiNode->nodekind == SMI_NODEKIND_COLUMN)) {
1070             continue;
1071         }
1072
1073         if (smiNode == smiGetModuleIdentityNode(smiModule)) {
1074             continue;
1075         }
1076         
1077         if ((smiNode->nodekind == SMI_NODEKIND_NODE) &&
1078             (smiNode->status == SMI_STATUS_UNKNOWN)) {
1079             assignement = 1;
1080             fprint(f, "%s OBJECT IDENTIFIER\n", smiNode->name);
1081         } else if (smiNode->nodekind == SMI_NODEKIND_NODE) {
1082             fprint(f, "%s OBJECT-IDENTITY\n", smiNode->name);
1083         } else {
1084             if (invalid) {
1085                 fprint(f, "-- %s OBJECT-TYPE\n", smiNode->name);
1086             } else {
1087                 fprint(f, "%s OBJECT-TYPE\n", smiNode->name);
1088             }
1089         }
1090
1091         if ((smiNode->nodekind == SMI_NODEKIND_TABLE) ||
1092             (smiNode->nodekind == SMI_NODEKIND_ROW) ||
1093             (smiType)) {            fprintSegment(f, INDENT, "SYNTAX", INDENTVALUE, invalid);
1094             if (smiNode->nodekind == SMI_NODEKIND_TABLE) {
1095                 fprint(f, "SEQUENCE OF ");
1096                 rowNode = smiGetFirstChildNode(smiNode);
1097                 if (rowNode) {
1098                     smiType = smiGetNodeType(rowNode);
1099                     if (smiType) {
1100                         fprint(f, "%s\n", smiType->name);
1101                     } else {
1102                         /* guess type name is uppercase row name */
1103                         char *s = getUppercaseString(rowNode->name);
1104                         fprint(f, "%s\n", s);
1105                         xfree(s);
1106                     }
1107                     /* TODO: print non-local name qualified */
1108                 } else {
1109                     fprint(f, "<unknown>\n");
1110                 }
1111             } else if (smiNode->nodekind == SMI_NODEKIND_ROW) {
1112                 if (smiType) {
1113                     fprint(f, "%s\n", smiType->name);
1114                 } else {
1115                     char *s = getUppercaseString(smiNode->name);
1116                     /* guess type name is uppercase row name */
1117                     fprint(f, "%s\n", s);
1118                     xfree(s);
1119                 }
1120                 /* TODO: print non-local name qualified */
1121             } else if (smiType) {
1122                 if (!smiType->name) {
1123                     /*
1124                      * an implicitly restricted type.
1125                      */
1126                     fprint(f, "%s", getTypeString(smiType->basetype,
1127                                                   smiGetParentType(smiType)));
1128                     fprintSubtype(f, smiType, invalid);
1129                     fprint(f, "\n");
1130                 } else {
1131                     fprint(f, "%s\n",
1132                            getTypeString(smiType->basetype, smiType));
1133                 }
1134             }
1135         }
1136
1137         if (! assignement && smiNode->nodekind == SMI_NODEKIND_TABLE) {
1138             fprintSegment(f, INDENT, "PIB-ACCESS", INDENTVALUE, 0);
1139             fprint(f, "%s\n", getAccessString(smiNode->access, 1));
1140         }
1141
1142         if (! assignement && smiType && smiType->name &&
1143             !strcmp(smiType->name, "ReferenceId")) {
1144             relatedNode = smiGetRelatedNode(smiNode);
1145             if (relatedNode) {
1146                 fprintSegment(f, INDENT, "PIB-REFERENCES", INDENTVALUE, 0);
1147                 fprint(f, "{ %s }\n", relatedNode->name);
1148             }
1149         }
1150
1151         if (! assignement && smiType && smiType->name &&
1152             !strcmp(smiType->name, "TagReferenceId")) {
1153             relatedNode = smiGetRelatedNode(smiNode);
1154             if (relatedNode) {
1155                 fprintSegment(f, INDENT, "PIB-TAG", INDENTVALUE, 0);
1156                 fprint(f, "{ %s }\n", relatedNode->name);
1157             }
1158         }
1159
1160         if (! assignement) {
1161             fprintSegment(f, INDENT, "STATUS", INDENTVALUE, invalid);
1162             fprint(f, "%s\n", getStatusString(smiNode->status));
1163         }
1164         
1165         if (! assignement) {
1166             fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE, invalid);
1167             fprint(f, "\n");
1168             if (smiNode->description) {
1169                 fprintMultilineString(f, smiNode->description, invalid);
1170             } else {
1171                 fprintMultilineString(f, "...", invalid);
1172             }
1173             fprint(f, "\n");
1174         }
1175         
1176         if (smiNode->nodekind == SMI_NODEKIND_TABLE)
1177             fprintInstallErrors(f, smiNode, invalid);
1178             
1179         if (! assignement && smiNode->reference) {
1180             fprintSegment(f, INDENT, "REFERENCE", INDENTVALUE, invalid);
1181             fprint(f, "\n");
1182             fprintMultilineString(f, smiNode->reference, invalid);
1183             fprint(f, "\n");
1184         }
1185
1186         relatedNode = smiGetRelatedNode(smiNode);
1187         switch (smiNode->indexkind) {
1188         case SMI_INDEX_INDEX:
1189             fprintIndex(f, smiNode, invalid);
1190             break;
1191         case SMI_INDEX_AUGMENT:
1192             fprintSegment(f, INDENT, "AUGMENTS", INDENTVALUE, invalid);
1193             fprint(f, "{ %s }\n", relatedNode->name);
1194             break;
1195         case SMI_INDEX_SPARSE:
1196             fprintSegment(f, INDENT, "EXTENDS", INDENTVALUE, invalid);
1197             fprint(f, "{ %s }\n", relatedNode->name);
1198             break;
1199         case SMI_INDEX_UNKNOWN:
1200         case SMI_INDEX_REORDER:
1201         case SMI_INDEX_EXPAND:
1202             break;
1203         }
1204         
1205         if (smiNode->nodekind == SMI_NODEKIND_ROW)
1206             fprintUniqueness(f, smiNode, invalid);
1207         
1208         if (smiNode->value.basetype != SMI_BASETYPE_UNKNOWN) {
1209             fprintSegment(f, INDENT, "DEFVAL", INDENTVALUE, invalid);
1210             fprint(f, "{ %s }", getValueString(&smiNode->value, smiType));
1211             fprint(f, "\n");
1212         }
1213
1214         fprintSegment(f, INDENT, "::= ", 0, invalid);
1215         fprint(f, "{ %s }\n\n", getOidString(smiNode, 0));
1216
1217         smiType = smiGetNodeType(smiNode);
1218         addinstanceid = 0;
1219         if (smiNode->nodekind == SMI_NODEKIND_ROW) {
1220             if (mibtopib)
1221                 addinstanceid = 1;
1222             if (smiType) {
1223                 fprint(f, "%s ::= SEQUENCE {", smiType->name);
1224             } else {
1225                 /* guess type name is uppercase row name */
1226                 char *s = getUppercaseString(smiNode->name);
1227                 fprint(f, "%s ::= SEQUENCE {", s);
1228                 xfree(s);
1229             }
1230             /* Find the last valid node in this sequence. We need it
1231              * to suppress its trailing comma. Compute the longest
1232              * column name so that we can adjust the indentation of
1233              * the type names in the SEQUENCE definition. */
1234             for(indentsequence = 0, colNode = smiGetFirstChildNode(smiNode);
1235                 colNode;
1236                 colNode = smiGetNextChildNode(colNode)) {
1237                 int len = strlen(colNode->name);
1238                 if (len > indentsequence) indentsequence = len;
1239                 smiType = smiGetNodeType(colNode);
1240                 if (smiType && !invalidType(smiType->basetype)) {
1241                     relatedNode = colNode;
1242                 }
1243             }
1244             if (mibtopib) {
1245                 int len = strlen(smiParentNode->name) + 10;
1246                 if (len > 64)
1247                   len = 64;
1248                 indentsequence = len;
1249             }
1250             if (relatedNode) relatedNode = smiGetNextChildNode(relatedNode);
1251             indentsequence = (2*INDENT + indentsequence + 1) / INDENT * INDENT;
1252             /* TODO: non-local name? */
1253             for(i = 0, invalid = 0, colNode = smiGetFirstChildNode(smiNode);
1254                 colNode;
1255                 colNode = smiGetNextChildNode(colNode)) {
1256                 if (! invalid || ! silent) {
1257                     if (i && (relatedNode != colNode)) {
1258                         fprint(f, ",");
1259                     }
1260                     fprint(f, "\n");
1261                 }
1262                 
1263                 smiType = smiGetNodeType(colNode);
1264                 invalid = (smiType == NULL) || invalidType(smiType->basetype);
1265
1266                 if (! invalid || ! silent) {
1267                     fprintSegment(f, INDENT, colNode->name, indentsequence,
1268                                   invalid);
1269                     if (smiType && smiType->decl == SMI_DECL_IMPLICIT_TYPE) {
1270                         fprint(f, "%s", getTypeString(smiType->basetype,
1271                                               smiGetParentType(smiType)));
1272                     } else if (smiType) {
1273                         fprint(f, "%s", getTypeString(smiType->basetype,
1274                                               smiGetNodeType(colNode)));
1275                     } else {
1276                         fprint(f, "<unknown>");
1277                     }
1278                 }
1279                 i++;
1280             }
1281             if (mibtopib) {
1282                 size_t len = strlen(smiParentNode->name);
1283                 int maxid;
1284                 char *instanceId = xmalloc(len + 11);
1285                 strcpy(instanceId, smiParentNode->name);
1286                 if (len > 54)
1287                   len = 54;
1288                 strcpy(&instanceId[len], "InstanceId");
1289                 fprint(f, ",\n");
1290                 fprintSegment(f, INDENT, instanceId, indentsequence, 0);
1291                 fprint(f, "InstanceId\n}\n\n");
1292                 
1293                 fprint(f, "%s OBJECT-TYPE\n", instanceId);
1294                 fprintSegment(f, INDENT, "SYNTAX", INDENTVALUE, 0);
1295                 fprint(f, "InstanceId\n");
1296                 fprintSegment(f, INDENT, "STATUS", INDENTVALUE, 0);
1297                 fprint(f, "current\n");
1298                 fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE, 0);
1299                 fprint(f, "\n");
1300                 fprintMultilineString(f, "Added by smidump for automatic " \
1301                                       "MIB to PIB conversion.", 0);
1302                 fprint(f, "\n");
1303                 fprintSegment(f, INDENT, "::= ", 0, 0);
1304                 for (maxid = 0, colNode = smiGetFirstChildNode(smiNode);
1305                      colNode; colNode = smiGetNextChildNode(colNode))
1306                      if (colNode->oidlen &&
1307                          (colNode->oid[colNode->oidlen - 1] > maxid))
1308                          maxid = colNode->oid[colNode->oidlen - 1];
1309                 fprint(f, "{ %s %d }\n\n",
1310                        smiGetFirstChildNode(smiParentNode)->name, 
1311                        (maxid + 1) > 128 ? (maxid + 1) : 128);
1312                 xfree(instanceId);
1313             } else
1314                 fprint(f, "\n}\n\n");
1315         }
1316     }
1317 }
1318
1319
1320
1321 static void fprintGroups(FILE *f, SmiModule *smiModule)
1322 {
1323     SmiNode      *smiNode;
1324     SmiElement   *smiElement;
1325     int          j, objectGroup = 0;
1326     
1327     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_GROUP);
1328          smiNode; smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_GROUP)) {
1329
1330         objectGroup = isObjectGroup(smiNode);
1331
1332         if (!objectGroup) {
1333             fprint(f, "%s OBJECT IDENTIFIER\n", smiNode->name);
1334             fprintSegment(f, INDENT, "::= ", 0, 0);
1335             fprint(f, "{ %s }\n\n", getOidString(smiNode, 0));
1336         }
1337
1338         if (!objectGroup) {
1339             continue;
1340         }
1341
1342         fprint(f, "%s %s\n", smiNode->name, "OBJECT-GROUP");
1343         fprintSegment(f, INDENT, "OBJECTS", INDENTVALUE, 0);
1344         fprint(f, "{ ");
1345         for (j = 0, smiElement = smiGetFirstElement(smiNode);
1346              smiElement;
1347              j++, smiElement = smiGetNextElement(smiElement)) {
1348             if (j) {
1349                 fprint(f, ", ");
1350             }
1351             fprintWrapped(f, INDENTVALUE + 2,
1352                           smiGetElementNode(smiElement)->name, 0);
1353             /* TODO: non-local name if non-local */
1354         } /* TODO: empty? -> print error */
1355         fprint(f, " }\n");
1356
1357         fprintSegment(f, INDENT, "STATUS", INDENTVALUE, 0);
1358         fprint(f, "%s\n", getStatusString(smiNode->status));
1359
1360         fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE, 0);
1361         fprint(f, "\n");
1362         if (smiNode->description) {
1363             fprintMultilineString(f, smiNode->description, 0);
1364         } else {
1365             fprintMultilineString(f, "...", 0);
1366         }
1367         fprint(f, "\n");
1368
1369         if (smiNode->reference) {
1370             fprintSegment(f, INDENT, "REFERENCE", INDENTVALUE, 0);
1371             fprint(f, "\n");
1372             fprintMultilineString(f, smiNode->reference, 0);
1373             fprint(f, "\n");
1374         }
1375
1376         fprintSegment(f, INDENT, "::= ", 0, 0);
1377         fprint(f, "{ %s }\n\n", getOidString(smiNode, 0));
1378     }
1379 }
1380
1381
1382
1383 static void fprintModuleCompliances(FILE *f, SmiModule *smiModule)
1384 {
1385     SmiNode       *smiNode, *smiNode2;
1386     SmiModule     *smiModule2;
1387     SmiType       *smiType;
1388     SmiOption     *smiOption;
1389     SmiRefinement *smiRefinement;
1390     SmiElement    *smiElement;
1391     char          *module;
1392     char          *done = NULL; /* "+" separated list of module names */
1393     char          s[1024];
1394     int           j;
1395
1396     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_COMPLIANCE);
1397          smiNode; smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_COMPLIANCE)) {
1398         fprint(f, "%s MODULE-COMPLIANCE\n", smiNode->name);
1399
1400         fprintSegment(f, INDENT, "STATUS", INDENTVALUE, 0);
1401         fprint(f, "%s\n", getStatusString(smiNode->status));
1402
1403         fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE, 0);
1404         fprint(f, "\n");
1405         if (smiNode->description) {
1406             fprintMultilineString(f, smiNode->description, 0);
1407         } else {
1408             fprintMultilineString(f, "...", 0);
1409         }
1410         fprint(f, "\n");
1411
1412         if (smiNode->reference) {
1413             fprintSegment(f, INDENT, "REFERENCE", INDENTVALUE, 0);
1414             fprint(f, "\n");
1415             fprintMultilineString(f, smiNode->reference, 0);
1416             fprint(f, "\n");
1417         }
1418
1419         /* `this module' always first */
1420         done = xstrdup("+");
1421         for (module = smiModule->name; module; ) {
1422
1423             fprint(f, "\n");
1424             fprintSegment(f, INDENT, "MODULE", INDENTVALUE, 0);
1425             if (strlen(module) && strcmp(smiModule->name, module)) {
1426                 fprint(f, "%s\n", module);
1427             } else {
1428                 fprint(f, "-- this module\n");
1429             }
1430
1431             for (j = 0, smiElement = smiGetFirstElement(smiNode);
1432                  smiElement;
1433                  smiElement = smiGetNextElement(smiElement)) {
1434                 if (!strcmp(smiGetNodeModule(smiGetElementNode(smiElement))->name, module)) {
1435                     if (j) {
1436                         fprint(f, ", ");
1437                     } else {
1438                         fprint(f, "\n");
1439                         fprintSegment(f, 2 * INDENT, "MANDATORY-GROUPS",
1440                                       INDENTVALUE, 0);
1441                         fprint(f, "{ ");
1442                     }
1443                     j++;
1444                     fprintWrapped(f, INDENTVALUE + 2,
1445                                   smiGetElementNode(smiElement)->name,
1446                                   0);
1447                 }
1448             }
1449             if (j) {
1450                 fprint(f, " }\n");
1451             }
1452
1453             for(smiOption = smiGetFirstOption(smiNode); smiOption;
1454                 smiOption = smiGetNextOption(smiOption)) {
1455                 smiNode2 = smiGetOptionNode(smiOption);
1456                 smiModule2 = smiGetNodeModule(smiNode2);
1457                 if (!strcmp(smiModule2->name, module)) {
1458                     fprint(f, "\n");
1459                     fprintSegment(f, 2 * INDENT, "GROUP",
1460                                   INDENTVALUE, 0);
1461                     fprint(f, "%s\n", smiNode2->name);
1462                     fprintSegment(f, 2 * INDENT, "DESCRIPTION",
1463                                   INDENTVALUE, 0);
1464                     fprint(f, "\n");
1465                     if (smiOption->description) {
1466                         fprintMultilineString(f, smiOption->description,
1467                                               0);
1468                     } else {
1469                         fprintMultilineString(f, "...", 0);
1470                     }
1471                     fprint(f, "\n");
1472                 }
1473             }
1474
1475             for(smiRefinement = smiGetFirstRefinement(smiNode);
1476                 smiRefinement;
1477                 smiRefinement = smiGetNextRefinement(smiRefinement)) {
1478                 smiNode2 = smiGetRefinementNode(smiRefinement);
1479                 smiModule2 = smiGetNodeModule(smiNode2);
1480                 if (!strcmp(smiModule2->name, module)) {
1481                     fprint(f, "\n");
1482                     fprintSegment(f, 2 * INDENT, "OBJECT",
1483                                   INDENTVALUE, 0);
1484                     fprint(f, "%s\n", smiNode2->name);
1485
1486                     smiType = smiGetRefinementType(smiRefinement);
1487                     if (smiType) {
1488                         fprintSegment(f, 2 * INDENT, "SYNTAX", INDENTVALUE,
1489                                       0);
1490                         fprint(f, "%s",
1491                                getTypeString(smiType->basetype,
1492                                              smiGetParentType(smiType)));
1493                         fprintSubtype(f, smiType, 0);
1494                         fprint(f, "\n");
1495                     }
1496
1497 /*                  if ((smiRefinement->access == SMI_ACCESS_NOTIFY) ||
1498                         (smiRefinement->access >= SMI_REPORT_ONLY)) {*/
1499                     if (smiRefinement->access != SMI_ACCESS_UNKNOWN) {
1500                         fprintSegment(f, 2 * INDENT, "PIB-MIN-ACCESS",
1501                                       INDENTVALUE, 0);
1502                         fprint(f, "%s\n",
1503                                getAccessString(smiRefinement->access, 0));
1504                         /* we assume, that read-create does not appear in
1505                          * an OT refinement.
1506                          */
1507                     }
1508                     fprintSegment(f, 2 * INDENT, "DESCRIPTION",
1509                                   INDENTVALUE, 0);
1510                     fprint(f, "\n");
1511                     if (smiRefinement->description) {
1512                         fprintMultilineString(f,
1513                                               smiRefinement->description,
1514                                               0);
1515                     } else {
1516                         fprintMultilineString(f, "...", 0);
1517                     }
1518                     fprint(f, "\n");
1519                 }
1520             }
1521
1522             /*
1523              * search the next module name in the list of mandatory
1524              * groups, optional groups and refinements.
1525              */
1526             done = xrealloc(done,
1527                             strlen(done)+strlen(module)+2*sizeof(char));
1528             strcat(done, module);
1529             strcat(done, "+");
1530             module = NULL;
1531             for (smiElement = smiGetFirstElement(smiNode);
1532                  smiElement;
1533                  smiElement = smiGetNextElement(smiElement)) {
1534                 sprintf(s, "+%s+",
1535                     smiGetNodeModule(smiGetElementNode(smiElement))->name);
1536                 if ((!strstr(done, s))) {
1537                     module =
1538                      smiGetNodeModule(smiGetElementNode(smiElement))->name;
1539                     break;
1540                 }
1541             }
1542             if (!module) {
1543                 ; /* TODO: search in options list */
1544             }
1545             if (!module) {
1546                 ; /* TODO: search in refinements list */
1547             }
1548         }
1549
1550         fprint(f, "\n");
1551         fprintSegment(f, INDENT, "::= ", 0, 0);
1552         fprint(f, "{ %s }\n\n", getOidString(smiNode, 0));
1553     }
1554     xfree(done);
1555     
1556     if (mibtopib) {
1557         char *newCompliance = xmalloc(65);
1558         char *newGroup = xmalloc(65);
1559         char *newId = xmalloc(65);
1560         int len, maxid;
1561         
1562         for (maxid = 0, smiNode2 = smiGetFirstChildNode(smiNode);
1563              smiNode2; smiNode2 = smiGetNextChildNode(smiNode2))
1564              if (smiNode2->oidlen &&
1565                  (smiNode2->oid[smiNode2->oidlen - 1] > maxid))
1566                  maxid = smiNode2->oid[smiNode2->oidlen - 1];
1567         maxid++;
1568
1569         smiNode = smiGetModuleIdentityNode(smiModule);
1570         if (!smiNode || !newCompliance || !newGroup)
1571             return;
1572         len = strlen(smiNode->name);
1573         
1574         memset(newId, 0, 65);
1575         strncpy(newId, smiNode->name, 46);
1576         strcat(newId + (len > 46 ? 46 : len), "MIBtoPIBCompliance");
1577
1578         memset(newCompliance, 0, 65);
1579         strncpy(newCompliance, smiNode->name, 46);
1580         strcat(newCompliance + (len > 46 ? 46 : len), "MIBtoPIBModuleComp");
1581
1582         memset(newGroup, 0, 65);
1583         strncpy(newGroup, smiNode->name, 51);
1584         strcat(newGroup + (len > 51 ? 51 : len), "MIBtoPIBGroup");
1585
1586         fprintf(f, "-- The following three items were added in order " \
1587                 "to create a RFC compliant\n-- SPPI module. They do not " \
1588                 "provide any usable content.\n-- %s\n-- %s\n-- %s\n\n",
1589                 newId, newCompliance, newGroup);
1590         
1591         fprint(f, "%s OBJECT-IDENTITY\n", newId);
1592         fprintSegment(f, INDENT, "STATUS", INDENTVALUE, 0);
1593         fprint(f, "current\n");
1594         fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE, 0);
1595         fprint(f, "\n");
1596         fprintMultilineString(f, "Added by smidump for automatic " \
1597                               "MIB to PIB conversion.", 0);
1598         fprint(f, "\n");
1599         fprintSegment(f, INDENT, "::= ", 0, 0);
1600         fprint(f, "{ %s %d }\n\n", smiNode->name, (maxid > 128 ? maxid : 128));
1601         
1602         fprint(f, "%s MODULE-COMPLIANCE\n", newCompliance);
1603         fprintSegment(f, INDENT, "STATUS", INDENTVALUE, 0);
1604         fprint(f, "current\n");
1605         fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE, 0);
1606         fprint(f, "\n");
1607         fprintMultilineString(f, "Added by smidump for automatic " \
1608                               "MIB to PIB conversion.", 0);
1609         fprint(f, "\n");
1610         
1611         fprintSegment(f, INDENT, "MODULE", INDENTVALUE, 0);
1612         fprint(f, "-- this module\n");
1613         
1614         fprintSegment(f, 2 * INDENT, "MANDATORY-GROUPS", INDENTVALUE, 0);
1615         fprint(f, "{ ");
1616         
1617         fprintWrapped(f, INDENTVALUE + 2, newGroup, 0);
1618         fprint(f, "}\n");
1619         
1620         fprintSegment(f, INDENT, "::= ", 0, 0);
1621         fprint(f, "{ %s 1 }\n\n", newId);
1622
1623         fprint(f, "%s OBJECT-GROUP\n", newGroup);
1624         fprintSegment(f, INDENT, "OBJECTS", INDENTVALUE, 0);
1625         fprint(f, "{ ");
1626         for (len=0, smiNode2 = smiGetFirstNode(smiModule, SMI_NODEKIND_COLUMN);
1627             smiNode2; len = 1,
1628             smiNode2 = smiGetNextNode(smiNode2, SMI_NODEKIND_COLUMN)) {
1629             if (len)
1630                 fprint(f, ", ");
1631             fprintWrapped(f, INDENTVALUE + 2, smiNode2->name, 0);
1632         }
1633         for (smiNode2 = smiGetFirstNode(smiModule, SMI_NODEKIND_ROW);
1634              smiNode2; smiNode2 = smiGetNextNode(smiNode2, SMI_NODEKIND_ROW)) {
1635             SmiNode *smiParentNode = smiGetParentNode(smiNode2);
1636             size_t len = strlen(smiParentNode->name);
1637             char *instanceId = xmalloc(len + 11);
1638
1639             strcpy(instanceId, smiParentNode->name);
1640             if (len > 54)
1641               len = 54;
1642             strcpy(&instanceId[len], "InstanceId");
1643             if (len)
1644                 fprint(f, ", ");
1645             fprintWrapped(f, INDENTVALUE + 2, instanceId, 0);
1646             xfree(instanceId);
1647         }
1648
1649         fprint(f, " }\n");
1650
1651         fprintSegment(f, INDENT, "STATUS", INDENTVALUE, 0);
1652         fprint(f, "current\n");
1653
1654         fprintSegment(f, INDENT, "DESCRIPTION", INDENTVALUE, 0);
1655         fprint(f, "\n");
1656         fprintMultilineString(f, "Added by smidump for automatic" \
1657                               "MIB to PIB conversion.", 0);
1658         fprint(f, "\n");
1659
1660         fprintSegment(f, INDENT, "::= ", 0, 0);
1661         fprint(f, "{ %s 2 }\n\n", newId);
1662
1663         xfree(newCompliance);
1664         xfree(newGroup);
1665     }
1666 }
1667
1668
1669
1670 static void doDumpSppi(FILE *f, SmiModule *smiModule)
1671 {
1672     if (smiModule->language != SMI_LANGUAGE_SPPI) /* MIB to PIB conversion */
1673         mibtopib = 1;
1674     else
1675         mibtopib = 0;
1676
1677     createImportList(smiModule);
1678     
1679     fprint(f, "--\n");
1680     fprint(f, "-- This SPPI module has been generated by smidump "
1681            SMI_VERSION_STRING ". Do not edit.\n");
1682     fprint(f, "--\n\n");
1683     fprint(f, "%s%s PIB-DEFINITIONS ::= BEGIN\n\n", smiModule->name,
1684            mibtopib ? "-PIB" : "");
1685         
1686     fprintImports(f);
1687     fprintModuleIdentity(f, smiModule);
1688     fprintTypeDefinitions(f, smiModule);
1689     fprintTextualConventions(f, smiModule);
1690     fprintObjects(f, smiModule);
1691     fprintGroups(f, smiModule);
1692     fprintModuleCompliances(f, smiModule);
1693     
1694     fprint(f, "END -- end of module %s.\n", smiModule->name);
1695
1696     freeImportList();
1697 }
1698
1699
1700 static void dumpSppi(int modc, SmiModule **modv, int flags, char *output)
1701 {
1702     int  i;
1703     FILE *f = stdout;
1704
1705     silent = (flags & SMIDUMP_FLAG_SILENT);
1706
1707     if (output) {
1708         f = fopen(output, "w");
1709         if (!f) {
1710             fprintf(stderr, "smidump: cannot open %s for writing: ", output);
1711             perror(NULL);
1712             exit(1);
1713         }
1714     }
1715
1716     for (i = 0; i < modc; i++) {
1717         doDumpSppi(f, modv[i]);
1718     }
1719
1720     if (fflush(f) || ferror(f)) {
1721         perror("smidump: write error");
1722         exit(1);
1723     }
1724     
1725     if (output) {
1726         fclose(f);
1727     }
1728 }
1729
1730
1731
1732 void initSppi()
1733 {
1734     static SmidumpDriver driver = {
1735         "sppi",
1736         dumpSppi,
1737         0,
1738         SMIDUMP_DRIVER_CANT_UNITE,
1739         "SPPI (RFC 3159)",
1740         NULL,
1741         NULL
1742     };
1743     
1744     smidumpRegisterDriver(&driver);
1745 }