Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / dump-xml.c
1 /*
2  * dump-xml.c --
3  *
4  *      Operations to dump SMIng module information in XML format.
5  *
6  * Copyright (c) 2000 Frank Strauss, Technical University of Braunschweig.
7  * Copyright (c) 2000 J. Schoenwaelder, Technical University of Braunschweig.
8  *
9  * See the file "COPYING" for information on usage and redistribution
10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  *
12  * @(#) $Id: dump-xml.c 8090 2008-04-18 12:56:29Z strauss $
13  */
14
15 /*
16  * TODO:
17  *
18  * - value representations (getValueString())
19  * - finish DTD and check against it
20  * - shall we nest tables like in SMIng?
21  */
22
23 #include <config.h>
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <time.h>
31
32 #include "smi.h"
33 #include "smidump.h"
34
35
36
37 #define  INDENT         2    /* indent factor */
38 #define  INDENTVALUE    20   /* column to start values, except multiline */
39 #define  INDENTTEXTS    4    /* column to start multiline texts */
40 #define  INDENTMAX      64   /* max column to fill, break lines otherwise */
41
42
43
44 static int disableschema  = 0;
45 static int disabledoctype = 0;
46
47
48
49 typedef struct XmlEscape {
50     char character;
51     char *escape;
52 } XmlEscape;
53
54 static XmlEscape xmlEscapes [] = {
55     { '<',      "&lt;" },
56     { '>',      "&gt;" },
57     { '&',      "&amp;" },
58     { 0,        NULL }
59 };
60
61
62 static int current_column = 0;
63
64
65
66 static char *getStringLanguage(SmiLanguage lang)
67 {
68     return
69         (lang == SMI_LANGUAGE_SMIV1) ? "SMIv1" :
70         (lang == SMI_LANGUAGE_SMIV2) ? "SMIv2" :
71         (lang == SMI_LANGUAGE_SMING) ? "SMIng" :
72                                         NULL;
73 }
74
75
76
77 static char *getStringStatus(SmiStatus status)
78 {
79     return
80         (status == SMI_STATUS_CURRENT)     ? "current" :
81         (status == SMI_STATUS_DEPRECATED)  ? "deprecated" :
82         (status == SMI_STATUS_OBSOLETE)    ? "obsolete" :
83         (status == SMI_STATUS_MANDATORY)   ? "mandatory" :
84         (status == SMI_STATUS_OPTIONAL)    ? "optional" :
85                                              "<unknown>";
86 }
87
88
89
90 static char *getAccessString(SmiAccess access)
91 {
92     return
93         (access == SMI_ACCESS_NOT_ACCESSIBLE) ? "noaccess" :
94         (access == SMI_ACCESS_NOTIFY)         ? "notifyonly" :
95         (access == SMI_ACCESS_READ_ONLY)      ? "readonly" :
96         (access == SMI_ACCESS_READ_WRITE)     ? "readwrite" :
97                                                 "<unknown>";
98 }
99
100
101
102 static char *getStringBasetype(SmiBasetype basetype)
103 {
104     return
105         (basetype == SMI_BASETYPE_UNKNOWN)           ? "<UNKNOWN>" :
106         (basetype == SMI_BASETYPE_OCTETSTRING)       ? "OctetString" :
107         (basetype == SMI_BASETYPE_OBJECTIDENTIFIER)  ? "ObjectIdentifier" :
108         (basetype == SMI_BASETYPE_UNSIGNED32)        ? "Unsigned32" :
109         (basetype == SMI_BASETYPE_INTEGER32)         ? "Integer32" :
110         (basetype == SMI_BASETYPE_UNSIGNED64)        ? "Unsigned64" :
111         (basetype == SMI_BASETYPE_INTEGER64)         ? "Integer64" :
112         (basetype == SMI_BASETYPE_FLOAT32)           ? "Float32" :
113         (basetype == SMI_BASETYPE_FLOAT64)           ? "Float64" :
114         (basetype == SMI_BASETYPE_FLOAT128)          ? "Float128" :
115         (basetype == SMI_BASETYPE_ENUM)              ? "Enumeration" :
116         (basetype == SMI_BASETYPE_BITS)              ? "Bits" :
117                                                    "<unknown>";
118 }
119
120
121
122 static char *getTimeString(time_t t)
123 {
124     static char   *s = NULL;
125     struct tm     *tm;
126
127     if (s) xfree(s);
128     
129     tm = gmtime(&t);
130     smiAsprintf(&s, "%04d-%02d-%02d %02d:%02d",
131                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
132                 tm->tm_hour, tm->tm_min);
133     return s;
134 }
135
136
137
138 static void fprint(FILE *f, char *fmt, ...)
139 {
140     va_list ap;
141     char    *s;
142     char    *p;
143
144     va_start(ap, fmt);
145     current_column += smiVasprintf(&s, fmt, ap);
146     va_end(ap);
147     fputs(s, f);
148     if ((p = strrchr(s, '\n'))) {
149         current_column = strlen(p) - 1;
150     }
151     free(s);
152 }
153
154
155
156 static void fprintSegment(FILE *f, int column, char *string, int length)
157 {
158     fprint(f, "%*c%s", column, ' ', string);
159     if (length) {
160         fprint(f, "%*c", length - strlen(string) - column, ' ');
161     }
162 }
163
164
165
166 static void fprintMultilineString(FILE *f, int column, const char *s)
167 {
168     int i, j, len;
169
170 #ifdef INDENTTEXTS
171     fprintSegment(f, column + INDENTTEXTS, "", 0);
172 #endif
173     if (s) {
174         len = strlen(s);
175         for (i=0; i < len; i++) {
176             for (j = 0; xmlEscapes[j].character; j++) {
177                 if (xmlEscapes[j].character == s[i]) break;
178             }
179             if (xmlEscapes[j].character) {
180                 fputs(xmlEscapes[j].escape, f);
181                 current_column += strlen(xmlEscapes[j].escape);
182             } else {
183                 putc(s[i], f);
184                 current_column++;
185             }
186             if (s[i] == '\n') {
187                 current_column = 0;
188 #ifdef INDENTTEXTS
189                 fprintSegment(f, column + INDENTTEXTS, "", 0);
190 #endif
191             }
192         }
193     }
194     current_column++;
195 }
196
197
198
199 static char *getValueString(SmiValue *valuePtr, SmiType *typePtr)
200 {
201     static char    s[1024];
202     char           ss[9];
203     int            n;
204     unsigned int   i;
205     SmiNamedNumber *nn;
206     
207     s[0] = 0;
208     
209     switch (valuePtr->basetype) {
210     case SMI_BASETYPE_UNSIGNED32:
211         sprintf(s, "%lu", valuePtr->value.unsigned32);
212         break;
213     case SMI_BASETYPE_INTEGER32:
214         sprintf(s, "%ld", valuePtr->value.integer32);
215         break;
216     case SMI_BASETYPE_UNSIGNED64:
217         sprintf(s, UINT64_FORMAT, valuePtr->value.unsigned64);
218         break;
219     case SMI_BASETYPE_INTEGER64:
220         sprintf(s, INT64_FORMAT, valuePtr->value.integer64);
221         break;
222     case SMI_BASETYPE_FLOAT32:
223     case SMI_BASETYPE_FLOAT64:
224     case SMI_BASETYPE_FLOAT128:
225         break;
226     case SMI_BASETYPE_ENUM:
227         for (nn = smiGetFirstNamedNumber(typePtr); nn;
228              nn = smiGetNextNamedNumber(nn)) {
229             if (nn->value.value.unsigned32 == valuePtr->value.unsigned32)
230                 break;
231         }
232         if (nn) {
233             sprintf(s, "%s", nn->name);
234         } else {
235             sprintf(s, "%ld", valuePtr->value.integer32);
236         }
237         break;
238     case SMI_BASETYPE_OCTETSTRING:
239         for (i = 0; i < valuePtr->len; i++) {
240             if (!isprint((int)valuePtr->value.ptr[i])) break;
241         }
242         if (i == valuePtr->len) {
243             sprintf(s, "\"%s\"", valuePtr->value.ptr);
244         } else {
245             sprintf(s, "0x%*s", 2 * valuePtr->len, "");
246             for (i=0; i < valuePtr->len; i++) {
247                 sprintf(ss, "%02x", valuePtr->value.ptr[i]);
248                 strncpy(&s[2+2*i], ss, 2);
249             }
250         }
251         break;
252     case SMI_BASETYPE_BITS:
253         sprintf(s, "(");
254         for (i = 0, n = 0; i < valuePtr->len * 8; i++) {
255             if (valuePtr->value.ptr[i/8] & (1 << (7-(i%8)))) {
256                 if (n)
257                     sprintf(&s[strlen(s)], ", ");
258                 n++;
259                 for (nn = smiGetFirstNamedNumber(typePtr); nn;
260                      nn = smiGetNextNamedNumber(nn)) {
261                     if (nn->value.value.unsigned32 == i)
262                         break;
263                 }
264                 if (nn) {
265                     sprintf(&s[strlen(s)], "%s", nn->name);
266                 } else {
267                     sprintf(s, "%d", i);
268                 }
269             }
270         }
271         sprintf(&s[strlen(s)], ")");
272         break;
273     case SMI_BASETYPE_UNKNOWN:
274         break;
275     case SMI_BASETYPE_POINTER:
276         break;
277     case SMI_BASETYPE_OBJECTIDENTIFIER:
278         for (i = 0; i < valuePtr->len; i++) {
279             sprintf(&s[strlen(s)], i ? ".%u" : "%u", valuePtr->value.oid[i]);
280         }
281         break;
282     }
283
284     return s;
285 }
286
287
288
289 static void fprintNodeStartTag(FILE *f, int indent,
290                                const char *tag, SmiNode *smiNode)
291 {
292     unsigned int i;
293     
294     fprintSegment(f, indent, "", 0);
295     fprint(f, "<%s name=\"%s\"", tag, smiNode->name);
296     fprint(f, " oid=\"");
297     for (i = 0; i < smiNode->oidlen; i++) {
298         fprint(f, i ? ".%u" : "%u", smiNode->oid[i]);
299     }
300     fprint(f, "\"");
301     if (smiNode->create) {
302         fprint(f, " create=\"true\"");
303     }
304     if (smiNode->status != SMI_STATUS_UNKNOWN) {
305         fprint(f, " status=\"%s\"", getStringStatus(smiNode->status));
306     }
307     fprint(f, ">\n");
308 }
309
310
311
312 static void fprintNodeEndTag(FILE *f, int indent, const char *tag)
313 {
314     fprintSegment(f, indent, "", 0);
315     fprint(f, "</%s>\n", tag);
316 }
317
318
319
320 static void fprintRanges(FILE *f, int indent, SmiType *smiType)
321 {
322     SmiRange       *range;
323
324     for(range = smiGetFirstRange(smiType);
325         range;
326         range = smiGetNextRange(range)) {
327         fprintSegment(f, indent, "<range", 0);
328         fprint(f, " min=\"%s\"", getValueString(&range->minValue, smiType));
329         fprint(f, " max=\"%s\"", getValueString(&range->maxValue, smiType));
330         fprint(f, "/>\n");
331     }
332 }
333
334
335
336 static void fprintNamedNumbers(FILE *f, int indent, SmiType *smiType)
337 {
338     SmiNamedNumber *nn;
339
340     if ((smiType->basetype != SMI_BASETYPE_ENUM) &&
341         (smiType->basetype != SMI_BASETYPE_BITS)) {
342         return;
343     }
344
345     for (nn = smiGetFirstNamedNumber(smiType);
346          nn;
347          nn = smiGetNextNamedNumber(nn)) {
348         fprintSegment(f, indent, "<namednumber", 0);
349         fprint(f, " name=\"%s\"", nn->name);
350         fprint(f, " number=\"%s\"", getValueString(&nn->value, smiType));
351         fprint(f, "/>\n");
352     }
353 }
354
355
356
357 static void fprintValue(FILE *f, int indent, SmiValue *smiValue,
358                         SmiType *smiType)
359 {
360     if (smiType && smiValue && smiValue->basetype != SMI_BASETYPE_UNKNOWN) {
361         fprintSegment(f, indent, "<default>", 0);
362         fprint(f, "%s", getValueString(smiValue, smiType));
363         fprint(f, "</default>\n");
364     }
365 }
366
367
368
369 static void fprintDescription(FILE *f, int indent, const char *description)
370 {
371     if (description) {
372         fprintSegment(f, indent, "<description>\n", 0);
373         fprintMultilineString(f, indent, description);
374         fprint(f, "\n");
375         fprintSegment(f, indent, "</description>\n", 0);
376     }
377 }
378
379
380
381 static void fprintReference(FILE *f, int indent, const char *reference)
382 {
383     if (reference) {
384         fprintSegment(f, indent, "<reference>\n", 0);
385         fprintMultilineString(f, indent, reference);
386         fprint(f, "\n");
387         fprintSegment(f, indent, "</reference>\n", 0);
388     }
389 }
390
391
392
393 static void fprintFormat(FILE *f, int indent, const char *format)
394 {
395     if (format) {
396         fprintSegment(f, indent, "", 0);
397         fprint(f, "<format>%s</format>\n", format);
398     }
399 }
400
401
402
403 static void fprintUnits(FILE *f, int indent, const char *units)
404 {
405     if (units) {
406         fprintSegment(f, indent, "", 0);
407         fprint(f, "<units>%s</units>\n", units);
408     }
409 }
410
411
412
413 static void fprintAccess(FILE *f, int indent, SmiAccess smiAccess)
414 {
415     if (smiAccess != SMI_ACCESS_UNKNOWN) {
416         fprintSegment(f, indent, "", 0);
417         fprint(f, "<access>%s</access>\n", getAccessString(smiAccess));
418     }
419 }
420
421
422
423 static void fprintElementList(FILE *f, int indent, const char *tag,
424                               SmiElement *smiElement)
425 {
426     SmiModule *smiModule;
427     SmiNode   *smiNode;
428
429     for (; smiElement; smiElement = smiGetNextElement(smiElement)) {
430         smiNode = smiGetElementNode(smiElement);
431         smiModule = smiGetNodeModule(smiNode);
432         fprintSegment(f, indent, "", 0);
433         fprint(f, "<%s module=\"%s\" name=\"%s\"/>\n",
434                tag, smiModule->name, smiNode->name);
435     }
436 }
437
438
439
440 static void fprintIndex(FILE *f, int indent, SmiNode *smiNode)
441 {
442     SmiNode   *relatedNode;
443     SmiModule *relatedModule = NULL;
444
445     fprintSegment(f, indent, "<linkage", 0);
446     if (smiNode->implied) {
447         fprint(f, " implied=\"true\"");
448     }
449     fprint(f, ">\n");
450
451     relatedNode = smiGetRelatedNode(smiNode);
452     if (relatedNode) {
453         relatedModule = smiGetNodeModule(relatedNode);
454     }
455     switch (smiNode->indexkind) {
456     case SMI_INDEX_INDEX:
457         fprintElementList(f, indent + INDENT, "index",
458                           smiGetFirstElement(smiNode));
459         break;
460     case SMI_INDEX_AUGMENT:
461         if (relatedNode && relatedModule) {
462             fprintSegment(f, indent + INDENT, "", 0);
463             fprint(f, "<augments module=\"%s\" name=\"%s\"/>\n",
464                    relatedModule->name, relatedNode->name);
465         } /* TODO: else print error */
466         break;
467     case SMI_INDEX_REORDER:
468         if (relatedNode && relatedModule) {
469             fprintSegment(f, indent + INDENT, "", 0);
470             fprint(f, "<reorders module=\"%s\" name=\"%s\"/>\n",
471                    relatedModule->name, relatedNode->name);
472             fprintElementList(f, indent + INDENT, "index",
473                               smiGetFirstElement(smiNode));
474         } /* TODO: else print error */
475         break;
476     case SMI_INDEX_SPARSE:
477         if (relatedNode && relatedModule) {
478             fprintSegment(f, indent + INDENT, "", 0);
479             fprint(f, "<sparse module=\"%s\" name=\"%s\"/>\n",
480                    relatedModule->name, relatedNode->name);
481         } /* TODO: else print error */
482         break;
483     case SMI_INDEX_EXPAND:
484         if (relatedNode && relatedModule) {
485             fprintSegment(f, indent + INDENT, "", 0);
486             fprint(f, "<expands module=\"%s\" name=\"%s\"/>\n",
487                    relatedModule->name, relatedNode->name);
488             fprintElementList(f, indent + INDENT, "index",
489                               smiGetFirstElement(smiNode));
490         } /* TODO: else print error */
491         break;
492     case SMI_INDEX_UNKNOWN:
493         break;
494     }
495     fprintSegment(f, indent, "</linkage>\n", 0);
496 }
497
498
499
500 static void fprintModule(FILE *f, SmiModule *smiModule)
501 {
502     SmiRevision *smiRevision;
503     SmiNode     *smiNode;
504     int         i;
505     char        *lang;
506
507     lang = getStringLanguage(smiModule->language);
508
509     fprintSegment(f, INDENT, "", 0);
510     if (lang) {
511         fprint(f, "<module name=\"%s\" language=\"%s\">\n",
512                smiModule->name, lang);
513     } else {
514         fprint(f, "<module name=\"%s\">\n", smiModule->name);
515     }
516
517     if (smiModule->organization) {
518         fprintSegment(f, 2 * INDENT, "<organization>", INDENTVALUE);
519         fprint(f, "\n");
520         fprintMultilineString(f, 2 * INDENT, smiModule->organization);
521         fprint(f, "\n");
522         fprintSegment(f, 2 * INDENT, "</organization>\n", 0);
523     }
524
525     if (smiModule->contactinfo) {
526         fprintSegment(f, 2 * INDENT, "<contact>", INDENTVALUE);
527         fprint(f, "\n");
528         fprintMultilineString(f, 2 * INDENT, smiModule->contactinfo);
529         fprint(f, "\n");
530         fprintSegment(f, 2 * INDENT, "</contact>\n", 0);
531     }
532     fprintDescription(f, 2 * INDENT, smiModule->description);
533     fprintReference(f, 2 * INDENT, smiModule->reference);
534
535     for(i = 0, smiRevision = smiGetFirstRevision(smiModule);
536         smiRevision; smiRevision = smiGetNextRevision(smiRevision)) {
537         fprintSegment(f, 2 * INDENT, "", 0);
538         fprint(f, "<revision date=\"%s\">\n",
539                getTimeString(smiRevision->date));
540         fprintDescription(f, 3 * INDENT, smiRevision->description);
541         fprintSegment(f, 2 * INDENT, "</revision>\n", 0);
542         i++;
543     }
544
545     smiNode = smiGetModuleIdentityNode(smiModule);
546     if (smiNode) {
547         fprintSegment(f, 2 * INDENT, "", 0);
548         fprint(f, "<identity node=\"%s\"/>\n", smiNode->name);
549     }
550
551     fprintSegment(f, INDENT, "</module>\n\n", 0);
552 }
553
554
555
556 static void fprintImport(FILE *f, int indent, SmiImport *smiImport)
557 {
558     fprintSegment(f, indent, "", 0);
559     fprint(f, "<import module=\"%s\" name=\"%s\"/>\n",
560            smiImport->module, smiImport->name);
561 }
562
563
564     
565 static void fprintImports(FILE *f, SmiModule *smiModule)
566 {
567     SmiImport *smiImport;
568     int        i;
569
570     for (i = 0, smiImport = smiGetFirstImport(smiModule);
571          smiImport;
572          i++, smiImport = smiGetNextImport(smiImport)) {
573         if (i == 0) {
574             fprintSegment(f, INDENT, "<imports>\n", 0);
575         }
576         fprintImport(f, 2 * INDENT, smiImport);
577     }
578
579     if (i) {
580         fprintSegment(f, INDENT, "</imports>\n\n", 0);
581     }
582 }
583
584
585
586 static void fprintTypedef(FILE *f, int indent, SmiType *smiType)
587 {
588     SmiModule *parentModule;
589     SmiType *parentType;
590     
591     fprintSegment(f, indent, "<typedef", 0);
592     if (smiType->name) {
593         fprint(f, " name=\"%s\"", smiType->name);
594     }
595     fprint(f, " basetype=\"%s\"", getStringBasetype(smiType->basetype));
596     if (smiType->name && smiType->status != SMI_STATUS_UNKNOWN) {
597         fprint(f, " status=\"%s\"", getStringStatus(smiType->status));
598     }
599     fprint(f, ">\n");
600     
601     parentType = smiGetParentType(smiType);
602     parentModule = smiGetTypeModule(parentType);
603     if (parentType && parentType->name &&
604         parentModule && strlen(parentModule->name)) {
605         fprintSegment(f, indent + INDENT, "<parent ", 0);
606         fprintf(f, "module=\"%s\" name=\"%s\"/>\n",
607                 parentModule->name, parentType->name);
608     }
609     fprintRanges(f, indent + INDENT, smiType);
610     fprintNamedNumbers(f, indent + INDENT, smiType);
611     fprintValue(f, indent + INDENT, &smiType->value, smiType);
612     fprintFormat(f, indent + INDENT, smiType->format);
613     fprintUnits(f, indent + INDENT, smiType->units);
614     fprintDescription(f, indent + INDENT, smiType->description);
615     fprintReference(f, indent + INDENT, smiType->reference);
616     
617     fprintSegment(f, indent, "</typedef>\n", 0);
618 }
619
620
621
622 static void fprintTypedefs(FILE *f, SmiModule *smiModule)
623 {
624     int          i;
625     SmiType      *smiType;
626     
627     for(i = 0, smiType = smiGetFirstType(smiModule);
628         smiType;
629         i++, smiType = smiGetNextType(smiType)) {
630
631         if (i == 0) {
632             fprintSegment(f, INDENT, "<typedefs>\n", 0);
633         }
634         fprintTypedef(f, 2 * INDENT, smiType);
635     }
636
637     if (i) {
638         fprintSegment(f, INDENT, "</typedefs>\n\n", 0);
639     }
640 }
641
642
643
644 static void fprintNode(FILE *f, int indent, SmiNode *smiNode,
645                        SmiNode *lastSmiNode)
646 {
647     SmiModule   *smiModule;
648     SmiType     *smiType;
649     char        *tag = NULL;
650     
651     if (smiNode->nodekind == SMI_NODEKIND_NODE) {
652         tag = "node";
653     } else if (smiNode->nodekind == SMI_NODEKIND_CAPABILITIES) {
654         tag = "node";
655     } else if (smiNode->nodekind == SMI_NODEKIND_TABLE) {
656         tag = "table";
657     } else if (smiNode->nodekind == SMI_NODEKIND_ROW) {
658         indent += INDENT;
659         tag = "row";
660     } else if (smiNode->nodekind == SMI_NODEKIND_COLUMN) {
661         indent += 2 * INDENT;
662         tag = "column";
663     } else if (smiNode->nodekind == SMI_NODEKIND_SCALAR) {
664         tag = "scalar";
665     }
666
667     if (lastSmiNode
668         && lastSmiNode->nodekind == SMI_NODEKIND_COLUMN
669         && smiNode->nodekind != SMI_NODEKIND_COLUMN) {
670         fprintNodeEndTag(f, indent + INDENT, "row");
671         fprintNodeEndTag(f, indent, "table");
672     }
673
674     smiType = smiGetNodeType(smiNode);
675     
676     fprintNodeStartTag(f, indent, tag, smiNode);
677     if (smiType && (smiType->basetype != SMI_BASETYPE_UNKNOWN)) {
678         fprintSegment(f, indent + INDENT, "<syntax>\n", 0);
679         smiModule = smiGetTypeModule(smiType);
680         if (smiType->name && smiModule) {
681             fprintSegment(f, indent + 2 *INDENT, "", 0);
682             fprint(f, "<type ");
683             fprintf(f, "module=\"%s\" name=\"%s\"/>\n",
684                     smiModule->name, smiType->name);
685         } else {
686             fprintTypedef(f, indent + 2 * INDENT, smiType);
687         }
688         fprintSegment(f, indent + INDENT, "</syntax>\n", 0);
689     }
690     if ((smiNode->nodekind != SMI_NODEKIND_TABLE) &&
691         (smiNode->nodekind != SMI_NODEKIND_ROW) &&
692         (smiNode->nodekind != SMI_NODEKIND_CAPABILITIES) &&
693         (smiNode->nodekind != SMI_NODEKIND_NODE)) {
694         fprintAccess(f, indent + INDENT, smiNode->access);
695     }
696     if (smiType) {
697         fprintValue(f, indent + INDENT, &smiNode->value, smiType);
698     }
699     fprintFormat(f, indent + INDENT, smiNode->format);
700     fprintUnits(f, indent + INDENT, smiNode->units);
701     if (smiNode->nodekind == SMI_NODEKIND_ROW) {
702         fprintIndex(f, indent + INDENT, smiNode);
703     }
704     fprintDescription(f, indent + INDENT, smiNode->description);
705     fprintReference(f, indent + INDENT, smiNode->reference);
706
707     if (smiNode->nodekind != SMI_NODEKIND_ROW
708         && smiNode->nodekind != SMI_NODEKIND_TABLE) {
709         fprintNodeEndTag(f, indent, tag);
710     }
711 }
712
713
714
715 static void fprintNodes(FILE *f, SmiModule *smiModule)
716 {
717     int          i;
718     SmiNode      *smiNode, *lastSmiNode;
719     SmiNodekind  nodekinds;
720
721     nodekinds =  SMI_NODEKIND_NODE | SMI_NODEKIND_TABLE |
722         SMI_NODEKIND_ROW | SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR |
723         SMI_NODEKIND_CAPABILITIES;
724     
725     for (i = 0, lastSmiNode = NULL,
726              smiNode = smiGetFirstNode(smiModule, nodekinds);
727          smiNode;
728          i++, lastSmiNode = smiNode,
729              smiNode = smiGetNextNode(smiNode, nodekinds)) {
730
731         if (i == 0) {
732             fprintSegment(f, INDENT, "<nodes>\n", 0);
733         }
734
735         fprintNode(f, 2 * INDENT, smiNode, lastSmiNode);
736     }
737     
738     if (lastSmiNode
739         && lastSmiNode->nodekind == SMI_NODEKIND_COLUMN) {
740         fprintNodeEndTag(f, 3 * INDENT, "row");
741         fprintNodeEndTag(f, 2 * INDENT, "table");
742     }
743
744     if (i) {
745         fprintSegment(f, INDENT, "</nodes>\n\n", 0);
746     }
747 }
748
749
750
751 static void fprintNotification(FILE *f, int indent, SmiNode *smiNode)
752 {
753     fprintNodeStartTag(f, indent, "notification", smiNode);
754
755     fprintSegment(f, indent + INDENT, "<objects>\n", 0);
756     fprintElementList(f, indent + 2 * INDENT, "object",
757                       smiGetFirstElement(smiNode));
758     fprintSegment(f, indent + INDENT, "</objects>\n", 0);
759     fprintDescription(f, indent + INDENT, smiNode->description);
760     fprintReference(f, indent + INDENT, smiNode->reference);
761     
762     fprintNodeEndTag(f, indent, "notification");
763 }
764
765
766
767 static void fprintNotifications(FILE *f, SmiModule *smiModule)
768 {
769     SmiNode *smiNode;
770     int      i;
771     
772     for(i = 0, smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NOTIFICATION);
773         smiNode;
774         i++, smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NOTIFICATION)) {
775
776         if (i == 0) {
777             fprintSegment(f, INDENT, "<notifications>\n", 0);
778         }
779         fprintNotification(f, 2 * INDENT, smiNode);
780     }
781
782     if (i) {
783         fprintSegment(f, INDENT, "</notifications>\n\n", 0);
784     }
785 }
786
787
788
789 static void fprintGroup(FILE *f, int indent, SmiNode *smiNode)
790 {
791     fprintNodeStartTag(f, indent, "group", smiNode);
792     
793     fprintSegment(f, indent + INDENT, "<members>\n", 0);
794     fprintElementList(f, indent + 2 * INDENT, "member",
795                       smiGetFirstElement(smiNode));
796     fprintSegment(f, indent + INDENT, "</members>\n", 0);
797     fprintDescription(f, indent + INDENT, smiNode->description);
798     fprintReference(f, indent + INDENT, smiNode->reference);
799
800     fprintNodeEndTag(f, indent, "group");
801 }
802
803
804
805 static void fprintGroups(FILE *f, SmiModule *smiModule)
806 {
807     SmiNode *smiNode;
808     int      i;
809     
810     for(i = 0, smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_GROUP);
811         smiNode;
812         i++, smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_GROUP)) {
813
814         if (i == 0) {
815             fprintSegment(f, INDENT, "<groups>\n", 0);
816         }
817         fprintGroup(f, 2 * INDENT, smiNode);
818     }
819
820     if (i) {
821         fprintSegment(f, INDENT, "</groups>\n\n", 0);
822     }
823 }
824
825
826
827 static void fprintComplGroups(FILE *f, int indent, SmiNode *smiNode)
828 {
829     SmiNode   *optSmiNode;
830     SmiModule *optSmiModule;
831     SmiOption *smiOption;
832
833     if (! smiGetFirstElement(smiNode) && !smiGetFirstOption(smiNode)) {
834         return;
835     }
836     
837     fprintSegment(f, indent, "<requires>\n", 0);
838     fprintElementList(f, indent + INDENT, "mandatory",
839                       smiGetFirstElement(smiNode));
840
841     for(smiOption = smiGetFirstOption(smiNode);
842         smiOption;
843         smiOption = smiGetNextOption(smiOption)) {
844         optSmiNode = smiGetOptionNode(smiOption);
845         optSmiModule = smiGetNodeModule(optSmiNode);
846         fprintSegment(f, indent + INDENT, "", 0);
847         fprint(f, "<option module=\"%s\" name=\"%s\">\n",
848                optSmiModule->name, optSmiNode->name);
849         fprintDescription(f, indent + 2 * INDENT, smiOption->description);
850         fprintSegment(f, indent + INDENT, "</option>\n", 0);
851     }
852     
853     fprintSegment(f, indent, "</requires>\n", 0);
854 }
855
856
857
858 static void fprintRefinement(FILE *f, int indent, SmiRefinement *smiRefinement)
859 {
860     SmiModule *smiModule;
861     SmiNode   *smiNode;
862     SmiType   *smiType;
863
864     smiNode = smiGetRefinementNode(smiRefinement);
865     smiModule = smiGetNodeModule(smiNode);
866
867     fprintSegment(f, indent, "<refinement ", 0);
868     fprintf(f, "module=\"%s\" name=\"%s\">\n", smiModule->name, smiNode->name);
869
870     smiType = smiGetRefinementType(smiRefinement);
871     if (smiType) {
872         fprintSegment(f, indent + INDENT, "<syntax>\n", 0);
873         fprintTypedef(f, indent + 2 * INDENT, smiType);
874         fprintSegment(f, indent + INDENT, "</syntax>\n", 0);
875     }
876     
877     smiType = smiGetRefinementWriteType(smiRefinement);
878     if (smiType) {
879         fprintSegment(f, indent + INDENT, "<writesyntax>\n", 0);
880         fprintTypedef(f, indent + 2 * INDENT, smiType);
881         fprintSegment(f, indent + INDENT, "</writesyntax>\n", 0);
882     }
883
884     if (smiRefinement->access != SMI_ACCESS_UNKNOWN) {
885         fprintAccess(f, indent + INDENT, smiRefinement->access);
886     }
887     fprintDescription(f, indent + INDENT, smiRefinement->description);
888     fprintSegment(f, indent, "</refinement>\n", 0);
889 }
890
891
892
893 static void fprintRefinements(FILE *f, int indent, SmiNode *smiNode)
894 {
895     SmiRefinement *smiRefinement;
896     int            i;
897
898     for(i = 0, smiRefinement = smiGetFirstRefinement(smiNode);
899         smiRefinement;
900         i++, smiRefinement = smiGetNextRefinement(smiRefinement)) {
901
902         if (!i) {
903             fprintSegment(f, indent, "<refinements>\n", 0);
904         }
905
906         fprintRefinement(f, indent + INDENT, smiRefinement);
907     }
908     
909     if (i) {
910         fprintSegment(f, indent, "</refinements>\n\n", 0);
911     }
912 }
913
914
915
916 static void fprintCompliance(FILE *f, int indent, SmiNode *smiNode)
917 {
918     fprintNodeStartTag(f, indent, "compliance", smiNode);
919
920     fprintDescription(f, indent + INDENT, smiNode->description);
921     fprintReference(f, indent + INDENT, smiNode->reference);
922     fprintComplGroups(f, indent + INDENT, smiNode);
923     fprintRefinements(f, indent + INDENT, smiNode);
924
925     fprintNodeEndTag(f, indent, "compliance");
926 }
927
928
929
930 static void fprintCompliances(FILE *f, SmiModule *smiModule)
931 {
932     SmiNode *smiNode;
933     int      i;
934
935     for(i = 0, smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_COMPLIANCE);
936         smiNode;
937         i++, smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_COMPLIANCE)) {
938         
939         if (!i) {
940             fprintSegment(f, INDENT, "<compliances>\n", 0);
941         }
942
943         fprintCompliance(f, 2 * INDENT, smiNode);
944     }
945
946     if (i) {
947         fprintSegment(f, INDENT, "</compliances>\n\n", 0);
948     }
949 }
950
951
952
953 static void dumpXml(int modc, SmiModule **modv, int flags, char *output)
954 {
955     int  i;
956     FILE *f = stdout;
957
958     if (output) {
959         f = fopen(output, "w");
960         if (!f) {
961             fprintf(stderr, "smidump: cannot open %s for writing: ", output);
962             perror(NULL);
963             exit(1);
964         }
965     }
966
967     for (i = 0; i < modc; i++) {
968         
969         fprint(f, "<?xml version=\"1.0\"?>\n");
970         if (!disabledoctype) {
971             fprint(f, "<!DOCTYPE smi SYSTEM \"http://www.ibr.cs.tu-bs.de/projects/nmrg/smi.dtd\">\n");
972         }
973         fprint(f, "\n");
974         fprint(f, "<!-- This module has been generated by smidump "
975                SMI_VERSION_STRING ". Do not edit. -->\n");
976         fprint(f, "\n");
977
978         if (!disableschema) {
979             fprint(f, "<smi xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
980             fprint(f, "     xsi:noNamespaceSchemaLocation=\"http://www.ibr.cs.tu-bs.de/projects/nmrg/smi.xsd\">\n");
981         } else {
982             fprint(f, "<smi>\n");
983         }
984         
985         fprintModule(f, modv[i]);
986         fprintImports(f, modv[i]);
987         fprintTypedefs(f, modv[i]);
988         fprintNodes(f, modv[i]);
989         fprintNotifications(f, modv[i]);
990         fprintGroups(f, modv[i]);
991         fprintCompliances(f, modv[i]);
992         
993         fprint(f, "</smi>\n");
994     }
995     
996     if (fflush(f) || ferror(f)) {
997         perror("smidump: write error");
998         exit(1);
999     }
1000
1001     if (output) {
1002         fclose(f);
1003     }
1004 }
1005
1006
1007
1008 void initXml()
1009 {
1010     
1011     static SmidumpDriverOption opt[] = {
1012         { "no-schema", OPT_FLAG, &disableschema, 0,
1013           "disable XML Schema spec in the toplevel element"},
1014         { "no-doctype", OPT_FLAG, &disabledoctype, 0,
1015           "disable DOCTYPE spec in the XML prolog"},
1016         { 0, OPT_END, 0, 0 }
1017     };
1018
1019     static SmidumpDriver driver = {
1020         "xml",
1021         dumpXml,
1022         0,
1023         SMIDUMP_DRIVER_CANT_UNITE,
1024         "intermediate SMI XML exchange format",
1025         opt,
1026         NULL
1027     };
1028     
1029     smidumpRegisterDriver(&driver);
1030 }