Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / dump-xsd.c
1 /*
2  * dump-xsd.c --
3  *
4  *      Operations to dump SMI module information as XML schema definitions.
5  *
6  * Copyright (c) 2001 J. Schoenwaelder, Technical University of Braunschweig.
7  *           (c) 2002 T. Klie, Technical University of Braunschweig.
8  *           (c) 2002 F. Strauss, Technical University of Braunschweig.
9  *           (c) 2007 T. Klie, Technical University of Braunschweig.
10  *
11  * See the file "COPYING" for information on usage and redistribution
12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13  *
14  * @(#) $Id: dump-xsd.c 8090 2008-04-18 12:56:29Z strauss $
15  */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <time.h>
25 #ifdef HAVE_WIN_H
26 #include "win.h"
27 #endif
28
29 #include "smi.h"
30 #include "smidump.h"
31 #include "fortopat.h"
32
33
34 #define  INDENT         2    /* indent factor */
35
36 static int ind = 0;
37
38 #ifndef MIN
39 #define MIN(a,b) ((a)) < ((b)) ? ((a)) : ((b))
40 #endif /* #ifndef MIN */
41
42 static char *schemaLocation = "http://www.ibr.cs.tu-bs.de/projects/libsmi/xsd/";
43 static int container = 0;
44 static char *containerBasename = "container";
45 static int *nestAugmentedTables = 0;
46 static int *nestSubtables = 0;
47
48 typedef struct XmlEscape {
49     char character;
50     char *escape;
51 } XmlEscape;
52
53 static XmlEscape xmlEscapes [] = {
54     { '<',      "&lt;" },
55     { '>',      "&gt;" },
56     { '&',      "&amp;" },
57     { 0,        NULL }
58 };
59
60 typedef struct TypePrefix {
61     char *type;
62     char *prefix;
63     struct TypePrefix *next;
64 } TypePrefix;
65
66 static TypePrefix *typePrefixes = NULL;
67
68
69
70 /* some forward declarations */
71 static void fprintElement( FILE *f, SmiNode *smiNode, SmiNode *parentNode );
72 static char* getTypePrefix( char *typeName );
73
74 static char *getStringBasetype(SmiBasetype basetype)
75 {
76     return
77         (basetype == SMI_BASETYPE_UNKNOWN)           ? "<UNKNOWN>" :
78         (basetype == SMI_BASETYPE_OCTETSTRING)       ? "OctetString" :
79         (basetype == SMI_BASETYPE_OBJECTIDENTIFIER)  ? "ObjectIdentifier" :
80         (basetype == SMI_BASETYPE_UNSIGNED32)        ? "Unsigned32" :
81         (basetype == SMI_BASETYPE_INTEGER32)         ? "Integer32" :
82         (basetype == SMI_BASETYPE_UNSIGNED64)        ? "Unsigned64" :
83         (basetype == SMI_BASETYPE_INTEGER64)         ? "Integer64" :
84         (basetype == SMI_BASETYPE_FLOAT32)           ? "Float32" :
85         (basetype == SMI_BASETYPE_FLOAT64)           ? "Float64" :
86         (basetype == SMI_BASETYPE_FLOAT128)          ? "Float128" :
87         (basetype == SMI_BASETYPE_ENUM)              ? "Enumeration" :
88         (basetype == SMI_BASETYPE_BITS)              ? "Bits" :
89                                                    "<unknown>";
90 }
91
92 static char* getStringStatus(SmiStatus status)
93 {
94     char *statStr;
95     
96     switch( status ) {
97     case SMI_STATUS_CURRENT:
98         statStr = "current";
99         break;
100     case SMI_STATUS_DEPRECATED:
101         statStr = "deprecated";
102         break;
103     case SMI_STATUS_OBSOLETE:
104         statStr = "obsolete";
105         break;
106     case SMI_STATUS_MANDATORY:
107         statStr = "mandatory";
108         break;
109     case SMI_STATUS_OPTIONAL:
110         statStr = "optional";
111         break;
112     case SMI_STATUS_UNKNOWN:
113     default:
114         statStr = "unknown";
115         break;
116     }
117     return statStr;
118 }
119
120 static char* getStringAccess( SmiAccess smiAccess )
121 {
122     switch( smiAccess ) {
123     case SMI_ACCESS_NOT_IMPLEMENTED: return "not-implemented";
124     case SMI_ACCESS_NOT_ACCESSIBLE : return "not-accessible";
125     case SMI_ACCESS_NOTIFY         : return "notify";
126     case SMI_ACCESS_READ_ONLY      : return "read-only";
127     case SMI_ACCESS_READ_WRITE     : return "read-write";
128     case SMI_ACCESS_UNKNOWN:
129     default: return "unknown";
130     }
131 }
132 #if 0
133 static char
134 *getStringValue(SmiValue *valuePtr, SmiType *typePtr)
135 {
136     static char    s[1024];
137     char           ss[9];
138     int            n;
139     unsigned int   i;
140     SmiNamedNumber *nn;
141     SmiNode        *nodePtr;
142     
143     s[0] = 0;
144     
145     switch (valuePtr->basetype) {
146     case SMI_BASETYPE_UNSIGNED32:
147         sprintf(s, "%lu", valuePtr->value.unsigned32);
148         break;
149     case SMI_BASETYPE_INTEGER32:
150         sprintf(s, "%ld", valuePtr->value.integer32);
151         break;
152     case SMI_BASETYPE_UNSIGNED64:
153         sprintf(s, UINT64_FORMAT, valuePtr->value.unsigned64);
154         break;
155     case SMI_BASETYPE_INTEGER64:
156         sprintf(s, INT64_FORMAT, valuePtr->value.integer64);
157         break;
158     case SMI_BASETYPE_FLOAT32:
159     case SMI_BASETYPE_FLOAT64:
160     case SMI_BASETYPE_FLOAT128:
161         break;
162     case SMI_BASETYPE_ENUM:
163         for (nn = smiGetFirstNamedNumber(typePtr); nn;
164              nn = smiGetNextNamedNumber(nn)) {
165             if (nn->value.value.unsigned32 == valuePtr->value.unsigned32)
166                 break;
167         }
168         if (nn) {
169             sprintf(s, "%s", nn->name);
170         } else {
171             sprintf(s, "%ld", valuePtr->value.integer32);
172         }
173         break;
174     case SMI_BASETYPE_OCTETSTRING:
175         for (i = 0; i < valuePtr->len; i++) {
176             if (!isprint((int)valuePtr->value.ptr[i])) break;
177         }
178         if (i == valuePtr->len) {
179             sprintf(s, "\"%s\"", valuePtr->value.ptr);
180         } else {
181             sprintf(s, "0x%*s", 2 * valuePtr->len, "");
182             for (i=0; i < valuePtr->len; i++) {
183                 sprintf(ss, "%02x", valuePtr->value.ptr[i]);
184                 strncpy(&s[2+2*i], ss, 2);
185             }
186         }
187         break;
188     case SMI_BASETYPE_BITS:
189         sprintf(s, "(");
190         for (i = 0, n = 0; i < valuePtr->len * 8; i++) {
191             if (valuePtr->value.ptr[i/8] & (1 << (7-(i%8)))) {
192                 if (n)
193                     sprintf(&s[strlen(s)], ", ");
194                 n++;
195                 for (nn = smiGetFirstNamedNumber(typePtr); nn;
196                      nn = smiGetNextNamedNumber(nn)) {
197                     if (nn->value.value.unsigned32 == i)
198                         break;
199                 }
200                 if (nn) {
201                     sprintf(&s[strlen(s)], "%s", nn->name);
202                 } else {
203                     sprintf(s, "%d", i);
204                 }
205             }
206         }
207         sprintf(&s[strlen(s)], ")");
208         break;
209     case SMI_BASETYPE_UNKNOWN:
210         break;
211     case SMI_BASETYPE_OBJECTIDENTIFIER:
212         nodePtr = smiGetNodeByOID(valuePtr->len, valuePtr->value.oid);
213         if (nodePtr) {
214             sprintf(s, "%s", nodePtr->name);
215         } else {
216             strcpy(s, "");
217             for (i=0; i < valuePtr->len; i++) {
218                 if (i) strcat(s, ".");
219                 sprintf(&s[strlen(s)], "%u", valuePtr->value.oid[i]);
220             }
221         }
222         break;
223     }
224
225     return s;
226 }
227 #endif /* 0 */
228
229 static int smiPow( int base, unsigned int exponent )
230 {
231   unsigned int i;
232   int ret = 1;
233   
234   if( exponent == 0 ) {
235     return 1;
236   }
237
238   for( i = 0; i < exponent; i++ ) {
239     ret *= base;
240   }
241   return ret;
242 }
243
244 static void fprintSegment(FILE *f, int relindent, char *fmt, ...)
245 {
246     va_list ap;
247
248     va_start(ap, fmt);
249      
250     if ((ind == 0) || (ind + relindent == 0)) {
251         ind += relindent;
252     } else {
253         if (relindent < 0) ind += relindent;
254         fprintf(f, "%*c", ind * INDENT, ' ');
255         if (relindent > 0) ind += relindent;
256     }
257     vfprintf(f, fmt, ap);
258
259     va_end(ap);
260 }
261
262
263
264 static void fprintMultilineString(FILE *f, const char *s)
265 {
266     int i, j, len;
267
268     fprintSegment(f, 0, "");
269     if (s) {
270         len = strlen(s);
271         for (i=0; i < len; i++) {
272             for (j = 0; xmlEscapes[j].character; j++) {
273                 if (xmlEscapes[j].character == s[i]) break;
274             }
275             if (xmlEscapes[j].character) {
276                 fputs(xmlEscapes[j].escape, f);
277             } else {
278                 putc(s[i], f);
279             }
280             if (s[i] == '\n') {
281                 fprintSegment(f, 0, "");
282             }
283         }
284     }
285 }
286
287
288
289 static void fprintDocumentation(FILE *f, const char *description)
290 {
291     if (description) {
292         fprintSegment(f, 1, "<xsd:documentation>\n");
293         fprintMultilineString(f, description);
294         fprintf(f, "\n");
295         fprintSegment(f, -1, "</xsd:documentation>\n");
296     }
297 }
298
299 static void fprintNamedNumber( FILE *f, SmiNamedNumber *nn )
300 {
301     fprintSegment( f, 1, "<xsd:enumeration value=\"%s\">\n", nn->name );
302     fprintSegment( f, 1, "<xsd:annotation>\n");
303     fprintSegment( f, 1, "<xsd:appinfo>\n");
304     fprintSegment( f, 0, "<intVal>%d</intVal>\n",
305                    (int)nn->value.value.integer32 );
306     fprintSegment( f, -1, "</xsd:appinfo>\n");
307     fprintSegment( f, -1, "</xsd:annotation>\n");
308     fprintSegment( f, -1, "</xsd:enumeration>\n");
309 }
310
311
312 static void fprintStdRestHead( FILE *f, SmiType *smiType )
313 {
314     char *baseTypeName = getStringBasetype(smiType->basetype);
315     char *prefix = getTypePrefix( baseTypeName );
316     
317     if( prefix ) {
318         fprintSegment(f, 1, "<xsd:restriction base=\"%s:%s\">\n",
319                       prefix, baseTypeName );
320     }
321     else {
322         fprintSegment(f, 1, "<xsd:restriction base=\"%s\">\n", baseTypeName );
323     }
324 }
325
326
327 static void fprintHexOrAsciiType( FILE *f, SmiType *parent,
328                                   SmiInteger32 minLength,
329                                   SmiInteger32 maxLength,
330                                   char *name, int hex )
331 {
332     char *prefix = parent ? getTypePrefix( parent->name ) : NULL;
333     char *typeFlag = hex ? "Hex" : "Ascii";
334     
335     if( name ) {
336         fprintSegment( f, 1, "<xsd:simpleType name=\"%s%s\">\n",
337                        name, typeFlag );
338     } else {
339         fprintSegment( f, 1, "<xsd:simpleType>\n");
340     }
341     if( prefix ) {
342         fprintSegment( f, 1, "<xsd:restriction base=\"%s:%s%s\">\n",
343                        prefix, parent->name, typeFlag );
344     }
345     else {
346         fprintSegment( f, 1, "<xsd:restriction base=\"%s%s\">\n",
347                        parent->name, typeFlag );
348     }
349    
350     if( minLength > 0 ) {
351         fprintSegment( f, 0, "<xsd:minLength value=\"%d\"/>\n",
352                        (int)minLength );
353     }
354     if( maxLength > -1 ) {
355         fprintSegment( f, 0, "<xsd:maxLength value=\"%d\"/>\n",
356                        (int)maxLength );
357     }
358
359     fprintSegment( f, -1, "</xsd:restriction>\n");
360     fprintSegment( f, -1, "</xsd:simpleType>\n");
361 }
362
363
364 static int dhInParent( SmiType *smiType )
365 {
366     SmiType *parent = smiGetParentType( smiType );
367
368     if( smiType->format && parent->format ) {
369         return ! strcmp( smiType->format, parent->format );
370     }
371     return 0;
372 }
373
374 #define MD_DH_INT_NORMAL   1
375 #define MD_DH_INT_DECIMAL  2
376 #define MD_DH_INT_BIN      3
377 #define MD_DH_INT_OCT      4
378 #define MD_DH_INT_HEX      5
379
380 /* parse a (integer) display hint and specify the offset, if used */
381 static int getIntDHType( char *hint, int *offset )
382 {
383     switch( hint[ 0 ] ) {
384
385     case 'd':
386         if( hint[1] ) {
387             *offset = 0;
388             *offset = atoi( &hint[2] );
389             return MD_DH_INT_DECIMAL;
390         }
391         return MD_DH_INT_NORMAL;
392
393     case 'b':
394         /* binary value */
395         return MD_DH_INT_BIN;
396     case 'o':
397         /* octet value */
398         return MD_DH_INT_OCT;
399     case 'x':
400         /* hex value */
401         return MD_DH_INT_HEX;
402     default:
403         /* should not occur */
404         return 0;
405     }
406 }
407
408
409 static void fprintRestriction(FILE *f, SmiType *smiType)
410 {
411     SmiRange *smiRange;
412     
413     /* print ranges etc. */
414     switch( smiType->basetype ) {
415
416     case SMI_BASETYPE_INTEGER32:
417     {
418         SmiInteger32 min = SMI_BASETYPE_INTEGER32_MIN;
419         SmiInteger32 max = SMI_BASETYPE_INTEGER32_MAX;
420         int offset = 0, useDecPoint = 0;
421
422         if( smiType->format ) {
423           /* we have a display hint here, so check if we have to use
424              a decimal point */
425           useDecPoint =  
426             getIntDHType( smiType->format, &offset ) == MD_DH_INT_DECIMAL; 
427           /* xxx: other display hint types (binary, oct, hex) */
428         }
429
430         if( useDecPoint ) {
431           fprintSegment( f, 1, "<xsd:restriction base=\"xsd:decimal\">\n");
432           fprintSegment( f, 0, "<xsd:fractionDigits value=\"%d\"/>\n", offset );
433         }
434         else {
435           fprintStdRestHead( f, smiType );
436         }
437
438         smiRange = smiGetFirstRange( smiType );
439         while( smiRange ) {
440             if( min == SMI_BASETYPE_INTEGER32_MIN ||
441                 smiRange->minValue.value.integer32 < min ) {
442                 min = smiRange->minValue.value.integer32;
443             }
444             if( max == SMI_BASETYPE_INTEGER32_MAX ||
445                 smiRange->maxValue.value.integer32 > max ) {
446                 max = smiRange->maxValue.value.integer32;
447             }
448             smiRange = smiGetNextRange( smiRange );
449         }
450         
451         /* print minimu value */
452         if( useDecPoint ) {
453             fprintSegment( f, 0, "<xsd:minInclusive value=\"%d.%d\"/>\n", 
454                            (int)min / smiPow( 10, offset ), 
455                            abs( (int)min % smiPow( 10, offset ) ) );
456         } else {
457             fprintSegment( f, 0, "<xsd:minInclusive value=\"%d\"/>\n",
458                            (int)min );
459         }
460
461         /* print maximum value */
462         if( useDecPoint ) {
463             fprintSegment( f, 0, "<xsd:maxInclusive value=\"%d.%d\"/>\n", 
464                            (int)max / smiPow( 10, offset ), 
465                            abs( (int)max % smiPow( 10, offset ) ) );
466         } else {
467             fprintSegment( f, 0, "<xsd:maxInclusive value=\"%d\"/>\n",
468                            (int)max );
469         }
470         
471         fprintSegment(f, -1, "</xsd:restriction>\n");
472         break;
473     }
474     
475     case SMI_BASETYPE_OCTETSTRING:
476     {
477         SmiInteger32  minLength, maxLength;
478         unsigned int numSubRanges = 0;
479         
480         minLength = 0;
481         maxLength = -1;
482
483         /* get range details */
484         for( smiRange = smiGetFirstRange( smiType );
485              smiRange;
486              smiRange = smiGetNextRange( smiRange ) ) {
487             if( minLength == 0 ||
488                 smiRange->minValue.value.integer32 < minLength ) {
489                 minLength = smiRange->minValue.value.integer32;      
490             }
491             if( smiRange->maxValue.value.integer32 > maxLength ) {
492                 maxLength = smiRange->maxValue.value.integer32;
493             }
494             numSubRanges++;
495         }
496
497         
498
499         if( smiType->format &&
500             ( smiType->decl == SMI_DECL_IMPLICIT_TYPE ||
501               smiType->decl == SMI_DECL_TEXTUALCONVENTION ) &&
502             ! dhInParent( smiType ) ) {
503             /*
504             fprintStringUnion( f, indent, smiType,
505                                minLength, maxLength, 0, NULL );
506             */
507             char *pattern;
508             
509             fprintSegment( f, 1, "<xsd:restriction base=\"xsd:string\">\n" );
510
511             /* create regexp */
512             pattern = smiFormatToPattern(smiType->format,
513                                          smiGetFirstRange(smiType));
514             if (pattern) {
515                 fprintSegment( f, 0, "<xsd:pattern value=\"%s\"/>\n", pattern);
516                 xfree(pattern);
517             }
518             else {
519                 fprintf( f, "<!-- Warning: repeat in display hint. "
520                          "This feature is not supported. -->\n" );
521             }
522             fprintSegment( f, -1, "</xsd:restriction>\n");
523         }
524         else {
525             SmiType *parent = smiGetParentType( smiType );
526             /*
527             fprintStringUnion( f, indent, smiType,
528                                minLength, maxLength, secondTime,
529                                smiType->name );
530             */
531             if( parent ) {
532                 if(  parent->format ) {
533                     char *pattern;
534
535                     pattern = smiFormatToPattern(parent->format,
536                                                  smiGetFirstRange(smiType));
537                     if (pattern) {
538                         fprintSegment( f, 1, "<xsd:restriction base=\"xsd:string\">\n" );
539                         fprintSegment(f, 0, "<xsd:pattern value=\"%s\"/>\n",
540                                       pattern);
541                         fprintSegment( f, -1, "</xsd:restriction>\n");
542                         xfree(pattern);
543                     }
544                 }
545                 
546                 
547                 else if( smiType->name &&
548                          ! strcmp( smiType->name, "IpAddress" ) ) {
549                     SmiUnsigned32 lengths[] = {4, 4};
550                     lengths[0] = 4; lengths[1] = 4;
551                     fprintSegment( f, 1, "<xsd:restriction base=\"xsd:string\">\n" );
552                     fprintSegment( f, 0, "<xsd:pattern "
553                                    "value=\"(0|[1-9](([0-9]){0,2}))."
554                                    "(0|[1-9](([0-9]){0,2}))."
555                                    "(0|[1-9](([0-9]){0,2}))."
556                                    "(0|[1-9](([0-9]){0,2}))\"/>\n" );
557                     fprintSegment( f, -1, "</xsd:restriction>\n");
558                 }
559                 
560                 else {
561                     
562                     
563                     char *prefix = getTypePrefix( parent->name );
564
565                     if( prefix ) {
566                         fprintSegment( f, 1, "<xsd:restriction base=\"%s:%s\">\n",
567                                        prefix, parent->name );
568                     } else {
569                         fprintSegment( f, 1, "<xsd:restriction base=\"%s\">\n",
570                                        parent->name );
571                     }
572
573                     /* print length restriction */
574                     if( minLength > 0 )
575                         fprintSegment( f, 0, "<xsd:minLength value=\"%d\"/>\n",
576                                        (int)minLength );
577                     if( maxLength > -1 )
578                         fprintSegment( f, 0, "<xsd:maxLength value=\"%d\"/>\n",
579                                        (int)maxLength );                    
580                     fprintSegment( f, -1, "</xsd:restriction>\n");
581                 }
582                     
583
584             }
585         }
586         break;
587     }
588
589     case SMI_BASETYPE_FLOAT128:
590     {
591 /*      SmiFloat128 min, max; */
592         fprintStdRestHead( f, smiType );
593         
594         /* xxx, only SMIng */
595         break;
596     }
597
598     case SMI_BASETYPE_FLOAT64:
599     {
600 /*      SmiFloat64 min,max;*/
601         fprintStdRestHead( f, smiType );
602
603         /* xxx, only SMIng */
604         break;
605     }
606     
607     case SMI_BASETYPE_FLOAT32:
608     {
609 /*      SmiFloat32 min,max;*/
610         fprintStdRestHead( f, smiType );
611         
612         /* xxx, only SMIng */
613         break;
614     }
615     
616     case SMI_BASETYPE_INTEGER64:
617     {
618 /*      SmiInteger64 min,max;*/
619         fprintStdRestHead( f, smiType );
620         
621         /* xxx, only SMIng */
622         break;
623     }
624
625     case SMI_BASETYPE_UNSIGNED64:
626     {
627         SmiUnsigned64 min, max;
628
629         min = SMI_BASETYPE_UNSIGNED64_MIN;
630         max = SMI_BASETYPE_UNSIGNED64_MAX;
631
632         fprintStdRestHead( f, smiType );
633         
634         smiRange = smiGetFirstRange( smiType );
635         while( smiRange ) {
636             if( smiRange->minValue.value.unsigned64 < min ) {
637                 min = smiRange->minValue.value.unsigned64;
638             }
639             if( smiRange->maxValue.value.unsigned64 > max ) {
640                 max = smiRange->maxValue.value.unsigned64;
641             }
642             smiRange = smiGetNextRange( smiRange );
643         }
644         fprintSegment( f, 0, "<xsd:minInclusive value=\"%lu\"/>\n",
645                        (unsigned long)min );
646
647         fprintSegment( f, 0, "<xsd:maxInclusive value=\"%lu\"/>\n",
648                        (unsigned long)max );
649         
650         fprintSegment(f, -1, "</xsd:restriction>\n");
651         
652         break;
653     }
654
655     case SMI_BASETYPE_UNSIGNED32:
656     {
657         SmiUnsigned32 min, max;
658
659         min = 0;
660         max = 4294967295UL;
661
662         fprintStdRestHead( f, smiType );
663         
664         smiRange = smiGetFirstRange( smiType );
665         while( smiRange ) {
666             if( smiRange->minValue.value.unsigned32 < min ) {
667                 min = smiRange->minValue.value.unsigned32;
668             }
669             if( smiRange->maxValue.value.unsigned32 > max ) {
670                 max = smiRange->maxValue.value.unsigned32;
671             }
672             smiRange = smiGetNextRange( smiRange );
673         }
674         fprintSegment( f, 0, "<xsd:minInclusive value=\"%u\"/>\n",
675                        (unsigned int)min );
676
677         fprintSegment( f, 0, "<xsd:maxInclusive value=\"%u\"/>\n",
678                        (unsigned int)max );
679         
680         fprintSegment(f, -1, "</xsd:restriction>\n");
681         break;
682     }
683
684     case SMI_BASETYPE_ENUM:
685     case SMI_BASETYPE_BITS:
686     {
687         SmiNamedNumber *nn;
688         
689         fprintSegment(f, 1, "<xsd:restriction base=\"xsd:NMTOKEN\">\n");
690
691         /* iterate named numbers */
692         for( nn = smiGetFirstNamedNumber( smiType );
693              nn;
694              nn = smiGetNextNamedNumber( nn ) ) {
695             fprintNamedNumber( f, nn );
696         }
697         fprintSegment(f, -1, "</xsd:restriction>\n");
698         break;
699     }
700
701     case SMI_BASETYPE_OBJECTIDENTIFIER:
702         fprintSegment( f, 0,
703                        "<xsd:restriction base=\"smi:ObjectIdentifier\"/>\n");
704         break;
705     case SMI_BASETYPE_UNKNOWN:
706         /* should not occur */
707         break;
708     case SMI_BASETYPE_POINTER:
709         /* TODO */
710         break;
711     }
712 }
713     
714
715 static unsigned int getNamedNumberCount( SmiType *smiType )
716 {
717     SmiNamedNumber *nn;
718     unsigned int ret = 0;
719
720     for( nn = smiGetFirstNamedNumber( smiType );
721          nn;
722          nn = smiGetNextNamedNumber( nn ) ) {
723         ret++;
724     }
725
726     return ret;
727 }
728
729
730 static void fprintBitList( FILE *f, SmiType *smiType )
731 {
732     fprintSegment( f, 1, "<xsd:restriction>\n" );
733     fprintSegment( f, 1, "<xsd:simpleType>\n" );
734     fprintSegment( f, 1, "<xsd:list>\n" );  
735     fprintSegment( f, 1, "<xsd:simpleType>\n" );
736     fprintRestriction( f, smiType );
737     fprintSegment( f, -1, "</xsd:simpleType>\n" );
738     fprintSegment( f, -1, "</xsd:list>\n" );
739     fprintSegment( f, -1, "</xsd:simpleType>\n");
740     fprintSegment( f, 0, "<xsd:maxLength value=\"%d\"/>\n",
741                    getNamedNumberCount( smiType ) );
742     fprintSegment( f, -1, "</xsd:restriction>\n");
743 }
744 static int getNumSubRanges( SmiType *smiType )
745 {
746     SmiRange *smiRange;
747     int num = 0;
748
749     for( smiRange = smiGetFirstRange( smiType );
750          smiRange;
751          smiRange = smiGetNextRange( smiRange ) ) {
752         num++;
753     }
754     
755     return num;
756 }
757
758
759 static void fprintSubRangeType( FILE *f,
760                                 SmiRange *smiRange, SmiType *smiType )
761 {
762     
763     switch( smiType->basetype ) {
764
765     case SMI_BASETYPE_UNSIGNED32: {
766         SmiUnsigned32 min, max;
767
768         min = 0;
769         max = 4294967295UL;
770
771         if( smiRange->minValue.value.unsigned32 < min ) {
772             min = smiRange->minValue.value.unsigned32;
773         }
774         if( smiRange->maxValue.value.unsigned32 > max ) {
775             max = smiRange->maxValue.value.unsigned32;
776         }
777         
778         fprintSegment( f, 1, "<xsd:simpleType>\n");
779         fprintStdRestHead( f, smiType );
780
781         fprintSegment( f, 0, "<xsd:minInclusive value=\"%u\"/>\n",
782                        (unsigned int)min );
783         
784         fprintSegment( f, 0, "<xsd:maxInclusive value=\"%u\"/>\n",
785                        (unsigned int)max );
786
787         fprintSegment(f, -1, "</xsd:restriction>\n");
788         fprintSegment(f, -1, "</xsd:simpleType>\n");
789         break;
790     }
791
792     case SMI_BASETYPE_INTEGER32: {
793         SmiInteger32 min, max;
794
795         min = SMI_BASETYPE_INTEGER32_MIN;
796         max = SMI_BASETYPE_INTEGER32_MAX;
797
798         if( min == SMI_BASETYPE_INTEGER32_MIN ||
799             smiRange->minValue.value.integer32 < min ) {
800             min = smiRange->minValue.value.integer32;
801         }
802         if( max == SMI_BASETYPE_INTEGER32_MAX ||
803             smiRange->maxValue.value.integer32 > max ) {
804             max = smiRange->maxValue.value.integer32;
805         }
806
807         fprintSegment( f, 1, "<xsd:simpleType>\n");
808         fprintStdRestHead( f, smiType );
809         
810         fprintSegment( f, 0, "<xsd:minInclusive value=\"%d\"/>\n", (int)min );
811
812         fprintSegment( f, 0, "<xsd:maxInclusive value=\"%d\"/>\n", (int)max );
813
814         fprintSegment(f, -1, "</xsd:restriction>\n");   
815         fprintSegment(f, -1, "</xsd:simpleType>\n");
816         break;
817         
818     }
819
820     case SMI_BASETYPE_OCTETSTRING: {
821         SmiInteger32  minLength, maxLength;
822         
823         minLength = 0;
824         maxLength = -1;
825         
826         if( smiRange->minValue.value.integer32 < minLength ) {
827             minLength = smiRange->minValue.value.integer32;          
828         }
829         if( smiRange->maxValue.value.integer32 > maxLength ) {
830             maxLength = smiRange->maxValue.value.integer32;
831         }
832         fprintHexOrAsciiType( f, smiType,
833                               minLength, maxLength, NULL, 1 );
834         break;
835     }
836
837     case SMI_BASETYPE_FLOAT128:
838     {
839 /*      SmiFloat128 min, max; 
840         xxx, only SMIng */
841         break;
842     }
843
844     case SMI_BASETYPE_FLOAT64:
845     {
846 /*      SmiFloat64 min,max;
847         xxx, only SMIng */
848         break;
849     }
850     
851     case SMI_BASETYPE_FLOAT32:
852     {
853 /*      SmiFloat32 min,max;
854         xxx, only SMIng */
855         break;
856     }
857
858     case SMI_BASETYPE_INTEGER64:
859     {
860 /*      SmiInteger64 min,max;
861          xxx, only SMIng */
862         break;
863     }
864
865     case SMI_BASETYPE_UNSIGNED64:
866     {
867         SmiUnsigned64 min, max;
868
869         min = SMI_BASETYPE_UNSIGNED64_MIN;
870         max = SMI_BASETYPE_UNSIGNED64_MAX;
871
872         if( smiRange->minValue.value.unsigned64 < min ) {
873             min = smiRange->minValue.value.unsigned64;
874         }
875         if( smiRange->maxValue.value.unsigned32 > max ) {
876             max = smiRange->maxValue.value.unsigned64;
877         }
878         
879         fprintSegment( f, 1, "<xsd:simpleType>\n");
880         fprintStdRestHead( f, smiType );
881
882         fprintSegment( f, 0, "<xsd:minInclusive value=\"%lu\"/>\n",
883                        (unsigned long)min );
884
885         fprintSegment( f, 0, "<xsd:maxInclusive value=\"%lu\"/>\n",
886                        (unsigned long)max );
887
888         fprintSegment(f, -1, "</xsd:restriction>\n");
889         fprintSegment(f, -1, "</xsd:simpleType>\n");
890         break;
891     }
892
893     case SMI_BASETYPE_ENUM:
894     case SMI_BASETYPE_BITS:
895     case SMI_BASETYPE_OBJECTIDENTIFIER:
896     case SMI_BASETYPE_UNKNOWN:
897     case SMI_BASETYPE_POINTER:
898         /* should not occur */
899         break;
900         
901     }
902 }
903
904 static void fprintDisplayHint( FILE *f, char *format )
905 {
906     fprintSegment( f, 0, "<displayHint>%s</displayHint>\n", format );
907 }
908
909 static void fprintLengths(FILE *f, SmiType *smiType)
910 {
911     SmiRange *smiRange = smiGetFirstRange(smiType);
912
913     if (! smiRange) {
914         return;
915     }
916     
917     fprintSegment(f, 1, "<lengths>\n");
918     for (smiRange = smiGetFirstRange(smiType);
919          smiRange; smiRange = smiGetNextRange(smiRange)) {
920         fprintSegment(f, 0, "<length min=\"%u\" max=\"%u\"/>\n",
921                       smiRange->minValue.value.unsigned32,
922                       smiRange->maxValue.value.unsigned32);
923     }
924     fprintSegment( f, -1, "</lengths>\n");
925 }
926
927
928 static void fprintTypedef(FILE *f, SmiType *smiType, const char *name)
929 {
930     SmiRange *smiRange;
931     unsigned int numSubRanges = getNumSubRanges( smiType );
932     
933     if ( name ) {
934         fprintSegment(f, 1, "<xsd:simpleType name=\"%s\">\n", name);
935     }
936
937     else {
938         /* unnamed simple type */
939         fprintSegment(f, 1, "<xsd:simpleType>\n");
940     }
941
942     if( smiType->description ) {
943         fprintSegment( f, 1, "<xsd:annotation>\n");
944         fprintDocumentation(f, smiType->description);
945         if( smiType->format ) {
946             fprintSegment( f, 1, "<xsd:appinfo>\n");
947             fprintDisplayHint( f, smiType->format );
948             if( smiType->basetype == SMI_BASETYPE_OCTETSTRING ) {
949               fprintLengths( f, smiType );
950             }
951             fprintSegment( f, -1, "</xsd:appinfo>\n");
952         }
953         fprintSegment( f, -1, "</xsd:annotation>\n");
954     }
955         
956     if( ( numSubRanges > 1 ) &&
957              ( smiType->basetype != SMI_BASETYPE_OCTETSTRING ) ) {
958         
959         fprintSegment( f, 1, "<xsd:union>\n");
960         
961         for( smiRange = smiGetFirstRange( smiType );
962              smiRange;
963              smiRange = smiGetNextRange( smiRange ) ) {
964             fprintSubRangeType( f, smiRange, smiType );
965         }
966         
967         fprintSegment( f, -1, "</xsd:union>\n");
968     }
969     else if( smiType->basetype == SMI_BASETYPE_BITS ) {
970         fprintBitList( f, smiType );
971     }
972     else {
973         fprintRestriction(f, smiType );
974     }
975     fprintSegment(f, -1, "</xsd:simpleType>\n");
976
977     /* print an empty line after global types */
978     if( smiType->decl != SMI_DECL_IMPLICIT_TYPE && name ) {
979         fprintf( f, "\n" );
980     } 
981 }
982
983
984 static char* getTypePrefix( char *typeName )
985 {
986     TypePrefix *iterTPr;
987
988     if( !typeName ) {
989         return NULL;
990     }
991
992     for( iterTPr = typePrefixes; iterTPr; iterTPr = iterTPr->next ) {
993         if( ! strcmp( iterTPr->type, typeName ) ) {
994             return iterTPr->prefix;
995         }
996     }
997
998     return NULL;
999 }
1000
1001
1002 static void fprintAnnotationElem( FILE *f, SmiNode *smiNode ) {
1003     int i;
1004     
1005     fprintSegment( f, 1, "<xsd:annotation>\n");
1006     fprintSegment( f, 1, "<xsd:appinfo>\n");
1007
1008     if( smiNode->nodekind == SMI_NODEKIND_ROW &&
1009         ( smiNode->implied || smiNode->create ) ) {
1010         fprintSegment( f, 0, "<flags" );
1011         if( smiNode->implied ) {
1012             fprintf( f, " implied=\"yes\"" );
1013         }
1014         if( smiNode->create ) {
1015             fprintf( f, " create=\"yes\"" );
1016         }
1017         fprintf( f, "/>\n" );
1018     }
1019     
1020     fprintSegment( f, 0, "<maxAccess>%s</maxAccess>\n",
1021                    getStringAccess( smiNode->access ) );
1022     fprintSegment( f, 0, "<oid>");
1023     for (i = 0; i < smiNode->oidlen; i++) {
1024         fprintf(f, i ? ".%u" : "%u", smiNode->oid[i]);
1025     }
1026     fprintf( f, "</oid>\n" );
1027
1028     fprintSegment( f, 0, "<status>%s</status>\n",
1029                    getStringStatus( smiNode->status ) );
1030     if( smiNode->value.basetype != SMI_BASETYPE_UNKNOWN ) {
1031         char *defval = smiRenderValue( &smiNode->value,
1032                                        smiGetNodeType( smiNode ),
1033                                        SMI_RENDER_FORMAT | SMI_RENDER_NAME );
1034         fprintSegment( f, 0, "<default>%s</default>\n", defval );
1035
1036     }
1037
1038
1039     if( smiNode->format ) {
1040         fprintDisplayHint( f, smiNode->format );
1041     }
1042
1043     if( smiNode->units ) {
1044         fprintSegment( f, 0, "<units>%s</units>\n", smiNode->units );
1045     }
1046   
1047     fprintSegment( f, -1, "</xsd:appinfo>\n");
1048     fprintDocumentation( f, smiNode->description );
1049     fprintSegment( f, -1, "</xsd:annotation>\n");
1050     
1051 }
1052
1053 static int hasChildren( SmiNode *smiNode, SmiNodekind nodekind )
1054 {
1055     SmiNode *iterNode;
1056     int childNodeCount = 0; 
1057
1058     for( iterNode = smiGetFirstChildNode( smiNode );
1059          iterNode;
1060          iterNode = smiGetNextChildNode( iterNode ) ){
1061         if( nodekind & iterNode->nodekind ) {
1062             childNodeCount++;
1063         }
1064     }
1065     return childNodeCount;
1066 }
1067
1068 static void
1069 fprintTypeWithHint( FILE *f, SmiNode *smiNode, SmiType *smiType, char *hint )
1070 {
1071     char *pattern;
1072     
1073     fprintSegment( f, 1, "<xsd:simpleType>\n");
1074     fprintSegment( f, 1, "<xsd:annotation>\n");
1075     fprintSegment( f, 1, "<xsd:appinfo>\n");
1076     fprintDisplayHint( f, hint );
1077     fprintSegment( f, -1, "</xsd:appinfo>\n");
1078     fprintSegment( f, -1, "</xsd:annotation>\n");
1079     fprintSegment( f, 1, "<xsd:restriction base=\"xsd:string\">\n");
1080
1081     pattern = smiFormatToPattern(hint, smiGetFirstRange(smiType));
1082     if (pattern) {
1083         fprintSegment( f, 0, "<xsd:pattern value=\"%s\"/>\n", pattern);
1084         xfree(pattern);
1085     }
1086     fprintSegment( f, -1, "</xsd:restriction>\n");
1087     fprintSegment( f, -1, "</xsd:simpleType>\n");
1088 }
1089
1090
1091 static char *getParentDisplayHint( SmiType *smiType )
1092 {
1093     SmiType *iterType;
1094
1095     for( iterType = smiGetParentType( smiType );
1096          iterType;
1097          iterType = smiGetParentType( iterType ) ) {
1098         if( iterType->format ) {
1099             return iterType->format;
1100         }       
1101     }
1102     return NULL;
1103 }
1104
1105
1106 static void fprintIndexAttr( FILE *f, SmiNode *smiNode, SmiNode *augments )
1107 {
1108     char *typeName, *prefix;
1109     SmiType *smiType;
1110
1111     smiType = smiGetNodeType( smiNode );
1112     if( !smiType ) {
1113 /*      fprint( f, "<!-- error: no type in %s -->\n", smiNode->name );*/
1114         return;
1115     }
1116
1117     typeName = smiType->name ?
1118         smiType->name :
1119         getStringBasetype( smiType->basetype );
1120     prefix = getTypePrefix( typeName );
1121     
1122
1123     if( smiType->basetype == SMI_BASETYPE_BITS ) {
1124             fprintSegment( f, 1, "<xsd:attribute name=\"%s\" type=\"%s%s\" "
1125                            "use=\"required\">\n",
1126                            smiNode->name,
1127                            smiNode->name,
1128                            getStringBasetype( smiType->basetype ) );
1129             fprintAnnotationElem( f, smiNode );
1130     }
1131
1132     else if( smiType->basetype == SMI_BASETYPE_OCTETSTRING ) {      
1133         
1134         if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1135             char *hint = getParentDisplayHint( smiType );
1136             
1137             fprintSegment( f, 1, "<xsd:attribute name=\"%s\" "
1138                            "use=\"required\">\n", smiNode->name );
1139             fprintAnnotationElem( f, smiNode );
1140             if( ! hint ) {
1141                 fprintTypedef( f, smiType, NULL );
1142             }
1143             else {
1144                 fprintTypeWithHint( f, smiNode, smiType, hint );
1145             }
1146         }
1147         
1148         else {
1149             if( prefix ) {
1150                 fprintSegment( f, 1, "<xsd:attribute name=\"%s\" "
1151                                "type=\"%s:%s\" use=\"required\">\n",
1152                                smiNode->name, prefix, typeName );
1153             }
1154             else {                  
1155                 fprintSegment( f, 1, "<xsd:attribute name=\"%s\" "
1156                                "type=\"%s\" use=\"required\">\n",
1157                                smiNode->name, typeName );
1158             }
1159             fprintAnnotationElem( f, smiNode );
1160         }
1161     }
1162     
1163     /* check for other (implicit) types */
1164     else if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1165         fprintSegment( f, 1, "<xsd:attribute name=\"%s\" "
1166                        "use=\"required\">\n",
1167                        smiNode->name );
1168         fprintAnnotationElem( f, smiNode );
1169         fprintTypedef( f, smiType, NULL );
1170     }
1171     
1172     else {      
1173         if( prefix ) {
1174             fprintSegment( f, 1,"<xsd:attribute name=\"%s\" type=\"%s:%s\" ",
1175                            smiNode->name, prefix, typeName );
1176             fprintf( f, "use=\"required\">\n" );
1177         }
1178         else {
1179             fprintSegment( f, 1, "<xsd:attribute name=\"%s\" type=\"%s\" ",
1180                            smiNode->name, typeName );
1181             fprintf( f, "use=\"required\">\n" );
1182         }
1183         
1184         if( augments ) {
1185             fprintSegment( f, 1, "<xsd:annotation>\n");
1186             fprintSegment( f, 1, "<xsd:appinfo>\n");
1187             fprintSegment( f, 0, "<augments>%s</augments>\n", augments->name );
1188             fprintSegment( f, -1, "</xsd:appinfo>\n");
1189             fprintSegment( f, -1, "</xsd:annotation>\n");
1190         }
1191         else {
1192             fprintAnnotationElem( f, smiNode );
1193             }
1194     }
1195     fprintSegment( f, -1, "</xsd:attribute>\n"); 
1196 }
1197
1198 static int containsIndex( SmiNode *parentNode, SmiNode *idxNode )
1199 {
1200     SmiElement *iterElement;
1201
1202
1203     for( iterElement = smiGetFirstElement( parentNode );
1204          iterElement;
1205          iterElement = smiGetNextElement( iterElement ) ) {
1206         SmiNode *iterNode = smiGetElementNode( iterElement );   
1207         if( iterNode == idxNode )
1208             return 1;
1209     }
1210     return 0;
1211 }
1212
1213 static void fprintIndex( FILE *f,
1214                          SmiNode *smiNode, SmiNode *augments, SmiNode *parent )
1215 {
1216     SmiNode *iterNode;
1217     SmiElement *iterElem;
1218   
1219     /* iterate INDEX columns */
1220     for( iterElem = smiGetFirstElement( smiNode );
1221          iterElem;
1222          iterElem = smiGetNextElement( iterElem ) ) {
1223         iterNode = smiGetElementNode( iterElem );
1224         if( ! parent || (parent && !containsIndex( parent, iterNode ) ) ) {
1225             fprintIndexAttr( f, iterNode, augments );
1226         }
1227     }
1228
1229     /* print AUGMENTS-clause */
1230     iterNode = smiGetRelatedNode( smiNode );
1231     if( iterNode ) {
1232         fprintIndex( f, iterNode, iterNode, NULL );
1233     }
1234 }
1235
1236 /* counts index elements of a table row node */
1237 static int numIndex( SmiNode *smiNode )
1238 {
1239     SmiElement *iterElem;
1240     int ret = 0;
1241
1242     for( iterElem = smiGetFirstElement( smiNode );
1243          iterElem;
1244          iterElem = smiGetNextElement( iterElem ) ) {
1245         ret++;
1246     }
1247     return ret;
1248 }
1249
1250
1251 /* checks if the second node is a subtable of the first node */
1252 static int
1253 isSubTable( SmiNode *smiNode, SmiNode *subNode )
1254 {
1255     SmiElement *iterElement;
1256     unsigned int numIdx = numIndex( smiNode ), numSubIdx = numIndex( subNode );
1257
1258     /* compare number of index elements */
1259     if( numSubIdx <= numIdx ) {
1260         /* does not have more index elements --> no subtable */
1261         return 0;
1262     }
1263
1264     /* compare all index elements */
1265     for( iterElement = smiGetFirstElement( smiNode );
1266          iterElement;
1267          iterElement = smiGetNextElement( iterElement ) ) {
1268         SmiElement *iterSubElement = smiGetFirstElement( subNode );
1269         SmiNode *iterSubNode;
1270         SmiNode *idxNode = smiGetElementNode( iterElement );
1271         
1272         for( iterSubElement = smiGetFirstElement( subNode );
1273              iterSubElement;
1274              iterSubElement = smiGetNextElement( iterSubElement ) ) {
1275             
1276             iterSubNode = smiGetElementNode( iterSubElement );
1277             if( idxNode == iterSubNode ){
1278                 return 1;
1279             }
1280         }
1281     }
1282     return 0;
1283 }
1284
1285
1286 static void fprintComplexType( FILE *f, SmiNode *smiNode, const char *name,
1287                                SmiNode *parent )
1288 {
1289     SmiNode *iterNode;
1290     int numChildren;
1291     
1292     if( name ) {
1293         fprintSegment( f, 1, "<xsd:complexType name=\"%sType\">\n",
1294                        smiNode->name );
1295     } else {
1296         fprintSegment( f, 1, "<xsd:complexType>\n" );
1297     }
1298
1299 /*    fprintAnnotationElem( f, smiNode ); */
1300
1301     numChildren = hasChildren( smiNode, SMI_NODEKIND_ANY );
1302
1303     fprintSegment( f, 1, "<xsd:sequence>\n");
1304
1305     /* print child elements */
1306     for( iterNode = smiGetFirstChildNode( smiNode );
1307          iterNode;
1308          iterNode = smiGetNextChildNode( iterNode ) ) {
1309         
1310         fprintElement( f, iterNode, NULL );
1311         
1312     }
1313
1314     /* print augmentations */
1315     if( nestAugmentedTables ) {
1316         for( iterNode = smiGetFirstNode( smiGetNodeModule( smiNode ),
1317                                          SMI_NODEKIND_ROW );
1318              iterNode;
1319              iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_ROW ) ) {
1320             SmiNode *augmNode = smiGetRelatedNode( iterNode );
1321             if( augmNode == smiNode ) {
1322                 SmiNode *augIterNode;
1323                 for( augIterNode = smiGetFirstChildNode( iterNode );
1324                      augIterNode;
1325                      augIterNode = smiGetNextChildNode( augIterNode ) ) {
1326                     
1327                     fprintElement( f, augIterNode, NULL );
1328                 }
1329             }
1330         }
1331     }
1332     
1333     /* print subtables */
1334     if( nestSubtables ) {
1335         for( iterNode = smiGetFirstNode( smiGetNodeModule( smiNode ),
1336                                          SMI_NODEKIND_ROW );
1337              iterNode;
1338              iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_ROW ) ) {
1339             if( isSubTable( smiNode, iterNode ) ) {
1340 /*          fputs( "<!-- Here BEGIN subtable entry -->\n", f );*/
1341                 fprintElement( f, iterNode, smiNode );
1342 /*          fputs( "<!-- Here END subtable entry -->\n", f );*/
1343             }
1344         }
1345     }
1346     
1347     fprintSegment( f, -1, "</xsd:sequence>\n");
1348     fprintIndex( f, smiNode, NULL, parent );
1349     
1350     fprintSegment( f, -1, "</xsd:complexType>\n");
1351     if( name ) {
1352         /* we are printing out a global type,
1353            so let's leave a blank line after it. */
1354         fprintf( f, "\n" );
1355     }
1356
1357     for( iterNode = smiGetFirstChildNode( smiNode );
1358          iterNode;
1359          iterNode = smiGetNextChildNode( iterNode ) ) {
1360         if( iterNode->nodekind == SMI_NODEKIND_NODE ) {
1361             fprintComplexType( f, iterNode, iterNode->name, NULL );
1362         }
1363     }
1364
1365 }    
1366
1367
1368 static void fprintElement( FILE *f, SmiNode *smiNode, SmiNode *parentNode )
1369 {
1370     switch( smiNode->nodekind ) {
1371         SmiType *smiType;
1372
1373     case SMI_NODEKIND_NODE :
1374         {
1375             SmiNode *iterNode;
1376
1377             fprintSegment( f, 1, "<xsd:element name=\"%s\">\n", smiNode->name);
1378             fprintSegment( f, 1, "<xsd:complexType>\n");
1379             fprintSegment( f, 1, "<xsd:sequence>\n");
1380             for( iterNode = smiGetFirstChildNode( smiNode );
1381                  iterNode;
1382                  iterNode = smiGetNextChildNode( iterNode ) ) {
1383                 if( iterNode->nodekind == SMI_NODEKIND_SCALAR ) {
1384                     fprintElement( f, iterNode, NULL );
1385                 }
1386             }
1387             fprintSegment( f, -1, "</xsd:sequence>\n");
1388             fprintSegment( f, -1, "</xsd:complexType>\n");
1389             fprintSegment( f, -1, "</xsd:element>\n");
1390         }
1391         break;
1392         
1393     case SMI_NODEKIND_TABLE :
1394     {
1395         SmiNode *iterNode;
1396         
1397         /* ignore tables and just include their entries */
1398         for( iterNode = smiGetFirstChildNode( smiNode );
1399              iterNode;
1400              iterNode = smiGetNextChildNode( iterNode ) ) {
1401             fprintElement( f, iterNode, NULL );
1402         }
1403         break;
1404     }
1405
1406     case SMI_NODEKIND_ROW:
1407        
1408         fprintSegment( f, 1, "<xsd:element name=\"%s\" "
1409                        "minOccurs=\"0\" maxOccurs=\"unbounded\">\n",
1410                        smiNode->name );
1411         
1412         fprintAnnotationElem( f, smiNode );
1413         
1414         fprintComplexType( f, smiNode, NULL, parentNode );
1415         fprintSegment( f, -1, "</xsd:element>\n");      
1416         break;
1417     
1418     case SMI_NODEKIND_SCALAR:
1419     case SMI_NODEKIND_COLUMN:
1420     {
1421         SmiElement *iterElem;
1422         char *prefix;
1423         char *typeName;
1424         
1425         /* check if we are index column */
1426         for( iterElem = smiGetFirstElement( smiGetParentNode( smiNode ) ) ;
1427              iterElem;
1428              iterElem = smiGetNextElement( iterElem ) ) {
1429             if( smiNode == smiGetElementNode( iterElem ) ) {
1430                 /* we are index coulumn ==> do not print element */
1431                 return;
1432             }
1433         }
1434         
1435         if( smiNode->access < SMI_ACCESS_READ_ONLY ) {
1436             /* only print accessible nodes */
1437             return;
1438         }
1439         
1440         smiType = smiGetNodeType( smiNode );
1441
1442         if( smiType->name ) {
1443             typeName = smiType->name;
1444         }
1445         else {
1446             typeName = getStringBasetype( smiType->basetype );
1447         }
1448         prefix = getTypePrefix( typeName );
1449
1450 #if 0
1451         if( smiType->basetype == SMI_BASETYPE_BITS ) {
1452             fprintSegment( f, 1, "<xsd:element name=\"%s\" type=\"%s%s\" "
1453                            "minOccurs=\"0\">\n",
1454                            smiNode->name,
1455                            smiNode->name,
1456                            getStringBasetype( smiType->basetype ) );
1457             fprintAnnotationElem( f, smiNode );
1458         }
1459         
1460 //      else if( smiType->basetype == SMI_BASETYPE_OCTETSTRING ) {
1461 #endif /* 0 */
1462
1463         if( smiType->basetype == SMI_BASETYPE_OCTETSTRING ) {
1464             if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1465
1466                 char *hint = getParentDisplayHint( smiType );
1467
1468                 fprintSegment( f, 1, "<xsd:element name=\"%s\" "
1469                                "minOccurs=\"0\">\n", smiNode->name );
1470                 fprintAnnotationElem( f, smiNode );
1471                 if( ! hint ) {
1472                     fprintTypedef( f, smiType, NULL );
1473                 }
1474                 else {
1475                     fprintTypeWithHint( f, smiNode, smiType, hint );
1476                 }
1477             }
1478
1479             else {
1480                 if( prefix ) {
1481                     fprintSegment( f, 1, "<xsd:element name=\"%s\" "
1482                                    "type=\"%s:%s\" minOccurs=\"0\">\n",
1483                                    smiNode->name, prefix, typeName );
1484                 }
1485                 else {              
1486                     fprintSegment( f, 1, "<xsd:element name=\"%s\" "
1487                                    "type=\"%s\" minOccurs=\"0\">\n",
1488                                    smiNode->name, typeName );
1489                 }
1490                 fprintAnnotationElem( f, smiNode );
1491             }              
1492         }
1493
1494         else if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1495             fprintSegment( f, 1, "<xsd:element name=\"%s\" minOccurs=\"0\">\n",
1496                            smiNode->name );
1497             fprintAnnotationElem( f, smiNode );
1498             fprintTypedef( f, smiType, NULL );
1499         }
1500         
1501         else {
1502             if( prefix ) {
1503                 fprintSegment( f, 1, "<xsd:element name=\"%s\" type=\"%s:%s\" "
1504                                "minOccurs=\"0\">\n",
1505                                smiNode->name, prefix, typeName );
1506             }
1507             else {
1508                 fprintSegment( f, 1, "<xsd:element name=\"%s\" type=\"%s\" "
1509                                "minOccurs=\"0\">\n",
1510                                smiNode->name, typeName );
1511             }
1512             fprintAnnotationElem( f, smiNode );
1513         }
1514         fprintSegment( f, -1, "</xsd:element>\n"); 
1515         break;
1516     }
1517
1518     case SMI_NODEKIND_NOTIFICATION:
1519         fprintSegment( f, 0, "<xsd:element name=\"%s\"/>\n", smiNode->name );
1520         break;
1521
1522     default:
1523         fprintf( f, "<!-- Warning! Unhandled Element! No details available!\n");
1524         fprintf( f, "      Nodekind: %#4x -->\n\n", smiNode->nodekind );
1525         
1526     }
1527 }
1528
1529
1530 static void fprintImplicitTypes( FILE *f, SmiModule *smiModule )
1531 {
1532     SmiNode *iterNode;
1533     SmiType *smiType;
1534
1535     for(iterNode = smiGetFirstNode(smiModule,
1536                                    SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN);
1537         iterNode;
1538         iterNode = smiGetNextNode(iterNode,
1539                                   SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN)) {
1540         smiType = smiGetNodeType( iterNode );
1541         if( smiType ) {
1542                 switch( smiType->basetype ) {
1543                     
1544                 case SMI_BASETYPE_BITS:
1545                     if( ! getTypePrefix( smiType->name ) ) {
1546                         fprintTypedef( f, smiType, iterNode->name );
1547                         break;
1548                     }
1549
1550                 case SMI_BASETYPE_OCTETSTRING:
1551 #if 0
1552                     if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1553                         fprintTypedef( f, INDENT, smiType, iterNode->name );
1554                     }
1555 #endif /* 0 */
1556                     break;
1557                 default:
1558                     break;
1559                 }
1560         }
1561     }
1562 }
1563
1564
1565 #if 0
1566 static void fprintRows( FILE *f, SmiModule *smiModule )
1567 {
1568     SmiNode *iterNode;
1569
1570     for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_ROW );
1571          iterNode;
1572          iterNode = smiGetNextNode( iterNode,  SMI_NODEKIND_ROW ) ) {
1573         if( hasChildren( iterNode, SMI_NODEKIND_COLUMN | SMI_NODEKIND_TABLE ) ){
1574             fprintElement( f, iterNode, NULL );
1575         }
1576     }
1577 }
1578 #endif
1579
1580 static void fprintImports( FILE *f, SmiModule *smiModule )
1581 {
1582     SmiImport *iterImp;
1583     char *lastModName = "";
1584     
1585     fprintSegment( f, 0, "<xsd:import namespace=\"%ssmi\" schemaLocation=\"%ssmi.xsd\"/>\n", schemaLocation, schemaLocation );
1586     for( iterImp = smiGetFirstImport( smiModule );
1587          iterImp;
1588          iterImp = smiGetNextImport( iterImp ) ) {
1589         /* assume imports to be ordered by module names */
1590         if( strcmp( iterImp->module, lastModName ) ) {
1591             fprintSegment( f, 0, "<xsd:import ");
1592             fprintf( f, "namespace=\"%s%s\" schemaLocation=\"%s%s.xsd\"/>\n",
1593                     schemaLocation, iterImp->module,
1594                     schemaLocation, iterImp->module );
1595         }
1596         lastModName = iterImp->module;
1597     }
1598     fprintf( f, "\n");
1599    
1600 }
1601
1602
1603 /*
1604  * Check if given table io a sub table of another table.
1605  * If so, its parent table is returned (NULL otherwise).
1606  */
1607 static SmiNode *isASubTable( SmiNode *smiNode, SmiModule *smiModule )
1608 {
1609     SmiNode *iterNode;
1610     int numIdxDiff = -1;
1611     SmiNode *retNode = NULL;
1612     
1613     for( iterNode = smiGetFirstNode( smiModule,
1614                                      SMI_NODEKIND_ROW );
1615          iterNode;
1616          iterNode = smiGetNextNode( iterNode,
1617                                     SMI_NODEKIND_ROW ) ) {
1618         
1619         if( isSubTable( iterNode, smiNode ) ) {
1620
1621             if( (numIdxDiff == -1) ||
1622                 ((numIndex( smiNode ) - numIndex( iterNode )) < numIdxDiff) ) {
1623                 retNode = iterNode;
1624                 numIdxDiff = numIndex( smiNode ) - numIndex( iterNode );
1625             }
1626             
1627         }
1628     }
1629     return retNode;
1630 }
1631
1632
1633 static void fprintGroupTypes( FILE *f, SmiModule *smiModule )
1634 {
1635     SmiNode *iterNode, *iterNode2;
1636
1637     /* scalar groups */
1638     for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_NODE );
1639          iterNode;
1640          iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_NODE ) ) {
1641         if( hasChildren( iterNode, SMI_NODEKIND_SCALAR ) ) {
1642             fprintSegment(f, 1, "<xsd:complexType name=\"%sType\">\n",
1643                           iterNode->name);
1644             fprintSegment( f, 1, "<xsd:sequence>\n");
1645             for( iterNode2 = smiGetFirstChildNode( iterNode );
1646                  iterNode2;
1647                  iterNode2 = smiGetNextChildNode( iterNode2 ) ) {
1648                 if( iterNode2->nodekind == SMI_NODEKIND_SCALAR ) {
1649                     fprintElement( f, iterNode2, NULL );
1650                 }
1651             }
1652             fprintSegment( f, -1, "</xsd:sequence>\n");
1653             fprintSegment(f, -1, "</xsd:complexType>\n");
1654         }
1655     }   
1656
1657     /* rows */
1658     for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_ROW );
1659          iterNode;
1660          iterNode = smiGetNextNode( iterNode,  SMI_NODEKIND_ROW ) ) {
1661         if( hasChildren( iterNode,
1662                          SMI_NODEKIND_COLUMN | SMI_NODEKIND_TABLE ) ){     
1663
1664             /* skip nested subtables here */
1665             if( nestSubtables ){
1666                 if( isASubTable( iterNode, smiModule ) != NULL ) {
1667                     continue;
1668                 }
1669             }
1670
1671             /* skip table augmentations here */
1672             if( nestAugmentedTables ) {
1673                 if( iterNode->indexkind == SMI_INDEX_AUGMENT ) {
1674                     continue;
1675                 }
1676             }
1677             
1678             fprintComplexType( f, iterNode, iterNode->name, NULL );
1679             
1680         }
1681     }   
1682 }
1683
1684
1685 #if 0
1686 static void fprintNotifications( FILE *f, SmiModule *smiModule )
1687 {
1688     SmiNode *iterNode;
1689     
1690     for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_NOTIFICATION );
1691          iterNode;
1692          iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_NOTIFICATION ) ) {
1693         fprintElement( f, iterNode, NULL );
1694     }
1695 }
1696 #endif
1697
1698
1699 static void fprintModuleHead(FILE *f, SmiModule *smiModule)
1700 {
1701     if( smiModule->description ) {
1702         fprintSegment(f, 1, "<xsd:annotation>\n");
1703         fprintDocumentation(f, smiModule->description);
1704         fprintSegment(f, -1, "</xsd:annotation>\n\n");
1705     }
1706     
1707 }
1708
1709
1710 static void fprintKey( FILE *f, SmiNode *smiNode )
1711 {
1712     SmiNode *relNode;
1713     SmiElement *iterElem;
1714     
1715     switch( smiNode->indexkind ) {
1716         
1717     case SMI_INDEX_INDEX:
1718         
1719         /* print key */
1720 /*      fprintSegment( f, 1, "<xsd:key " );
1721         fprintf( f, "name=\"%sKey\">\n", smiNode->name );
1722         fprintSegment( f, 0, "<xsd:selector ");
1723         fprintf( f, "xpath=\"%s\"/>\n", smiNode->name );
1724         for( iterElem = smiGetFirstElement( smiNode );
1725              iterElem;
1726              iterElem = smiGetNextElement( iterElem ) ) {
1727             SmiNode *indexNode = smiGetElementNode( iterElem );
1728             fprintSegment( f, 0, "<xsd:field ");
1729             fprintf( f, "xpath=\"@%s\"/>\n", indexNode->name );
1730         }
1731         fprintSegment( f, -1, "</xsd:key>\n\n");*/
1732         break;
1733         
1734     case SMI_INDEX_AUGMENT:
1735         
1736         /* print keyref */
1737         fprintSegment( f, 1, "<xsd:keyref " );
1738         relNode = smiGetRelatedNode( smiNode );
1739         fprintf( f, "name=\"%sKeyRef\" ", smiNode->name );
1740         fprintf( f, "refer=\"%sKey\">\n", relNode->name );
1741         fprintSegment( f, 0, "<xsd:selector ");
1742         fprintf( f, "xpath=\"%s\"/>\n", smiNode->name );
1743         for( iterElem = smiGetFirstElement( relNode );
1744              iterElem;
1745              iterElem = smiGetNextElement( iterElem ) ) {
1746             SmiNode *indexNode = smiGetElementNode( iterElem );
1747             fprintSegment( f, 0, "<xsd:field ");
1748             fprintf( f, "xpath=\"@%s\"/>\n", indexNode->name );
1749         }
1750         fprintSegment( f, -1, "</xsd:keyref>\n");
1751         
1752         /* print unique clause */
1753         fprintSegment( f, 1, "<xsd:unique " );
1754         fprintf( f, "name=\"%sKeyRefUnique\">\n", smiNode->name );
1755         fprintSegment( f, 0, "<xsd:selector ");
1756         fprintf( f, "xpath=\"%s\"/>\n", smiNode->name );
1757         for( iterElem = smiGetFirstElement( relNode );
1758              iterElem;
1759              iterElem = smiGetNextElement( iterElem ) ) {
1760             SmiNode *indexNode = smiGetElementNode( iterElem );
1761             fprintSegment( f, 0, "<xsd:field ");
1762             fprintf( f, "xpath=\"@%s\"/>\n", indexNode->name );
1763         }
1764         fprintSegment( f, -1, "</xsd:unique>\n\n");
1765         break;
1766
1767     case SMI_INDEX_REORDER:
1768     case SMI_INDEX_SPARSE:
1769     case SMI_INDEX_EXPAND:
1770         /* SMIng, not implemented yet */
1771         break;
1772         
1773     default:
1774         fprintf( f, "<!-- Error: Unknown index type -->\n" );
1775         break;
1776     }   
1777 }
1778
1779
1780 static void fprintGroupElements(FILE *f, SmiModule *smiModule)
1781 {
1782     SmiNode *iterNode;
1783
1784     /* scalar groups */
1785     for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_NODE );
1786          iterNode;
1787          iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_NODE ) ) {
1788         if( hasChildren( iterNode, SMI_NODEKIND_SCALAR ) ) {
1789             
1790             if (container) {
1791                 fprintSegment(f, 1, "<xsd:element name=\"%s\" "
1792                               "type=\"%s:%sType\" minOccurs=\"0\">\n",
1793                               iterNode->name,
1794                               smiModule->name, iterNode->name);
1795             } else {
1796                 fprintSegment(f, 1, "<xsd:element name=\"%s\" "
1797                               "type=\"%sType\" minOccurs=\"0\">\n",
1798                               iterNode->name, iterNode->name);
1799             }
1800             fprintAnnotationElem( f, iterNode );
1801             fprintSegment( f, -1, "</xsd:element>\n" );
1802         }
1803     }   
1804
1805     /* rows */
1806     for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_ROW );
1807          iterNode;
1808          iterNode = smiGetNextNode( iterNode,  SMI_NODEKIND_ROW ) ) {
1809         if( hasChildren( iterNode, SMI_NODEKIND_COLUMN | SMI_NODEKIND_TABLE ) ){
1810             /* skip nested subtables here */
1811             if( nestSubtables ){
1812                 if( isASubTable( iterNode, smiModule ) != NULL ) {
1813                     continue;
1814                 }
1815             }
1816
1817             /* skip table augmentations here */
1818             if( nestAugmentedTables ) {
1819                 if( iterNode->indexkind == SMI_INDEX_AUGMENT ) {
1820                     continue;
1821                 }
1822             }
1823
1824             if (container) {
1825                 fprintSegment(f, 1, "<xsd:element name=\"%s\" "
1826                               "type=\"%s:%sType\" minOccurs=\"0\" "
1827                               "maxOccurs=\"unbounded\">\n",
1828                               iterNode->name,
1829                               smiModule->name, iterNode->name);
1830                 fprintKey( f, iterNode );
1831             } else {
1832                 fprintSegment(f, 1, "<xsd:element name=\"%s\" "
1833                               "type=\"%sType\" minOccurs=\"0\" "
1834                               "maxOccurs=\"unbounded\">\n",
1835                               iterNode->name, iterNode->name);
1836             }
1837             fprintAnnotationElem( f, iterNode );
1838             fprintSegment( f, -1, "</xsd:element>\n" );
1839         }
1840     }   
1841 }
1842
1843
1844 static char *getSubTableXPath( SmiNode *smiNode, SmiModule *smiModule )
1845 {
1846     char *ret;
1847     SmiNode *parentTable = isASubTable( smiNode, smiModule );
1848
1849     if( parentTable ) {
1850         smiAsprintf( &ret, "%s/%s",
1851                      getSubTableXPath( parentTable, smiModule ),
1852                      smiNode->name );
1853     }
1854     else {
1855         smiAsprintf( &ret, "%s", smiNode->name );
1856     }
1857     return ret;   
1858 }
1859
1860
1861 static void fprintKeys( FILE *f, SmiModule *smiModule )
1862 {
1863
1864     SmiNode *iterNode;
1865
1866     for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_ROW );
1867          iterNode;
1868          iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_ROW ) ) {
1869
1870         SmiElement *iterElem;
1871
1872         /* print only keys for base tables */
1873         if( iterNode->indexkind != SMI_INDEX_INDEX ) {
1874             continue;
1875         }
1876         
1877         /* print key */
1878         fprintSegment( f, 1, "<xsd:key name=\"%sKey\">\n", iterNode->name );
1879         fprintSegment( f, 0, "<xsd:selector ");
1880         fprintf( f, "xpath=\"%s\"/>\n",
1881                  nestSubtables ?
1882                  getSubTableXPath( iterNode, smiModule ) : iterNode->name );
1883             
1884         for( iterElem = smiGetFirstElement( iterNode );
1885              iterElem;
1886              iterElem = smiGetNextElement( iterElem ) ) {
1887             SmiNode *indexNode = smiGetElementNode( iterElem );
1888             fprintSegment( f, 0, "<xsd:field ");
1889             fprintf( f, "xpath=\"@%s\"/>\n", indexNode->name );
1890         }
1891         fprintSegment( f, -1, "</xsd:key>\n\n");
1892     }
1893     
1894
1895 }
1896
1897
1898 static void fprintContextHead(FILE *f)
1899 {
1900     fprintSegment( f, 1, "<xsd:element name=\"snmp-data\">\n");
1901     fprintSegment( f, 1, "<xsd:complexType>\n");
1902     fprintSegment( f, 1, "<xsd:sequence>\n");
1903     fprintSegment( f, 1, "<xsd:element name=\"context\" "
1904                    "minOccurs=\"0\" maxOccurs=\"unbounded\">\n");
1905     fprintSegment( f, 1, "<xsd:complexType>\n");
1906     fprintSegment( f, 1, "<xsd:sequence>\n");
1907 }
1908
1909
1910 static void fprintContextFoot(FILE *f, SmiModule **modv, int modc)
1911 {
1912     int i;
1913     
1914     fprintSegment( f, -1, "</xsd:sequence>\n");
1915     fprintSegment( f, 0, "<xsd:attribute name=\"ipaddr\" type=\"xsd:NMTOKEN\" use=\"required\"/>\n");
1916     fprintSegment( f, 0, "<xsd:attribute name=\"hostname\" type=\"xsd:NMTOKEN\"/>\n");
1917     fprintSegment( f, 0, "<xsd:attribute name=\"port\" type=\"xsd:unsignedInt\" use=\"required\"/>\n");
1918     fprintSegment( f, 0, "<xsd:attribute name=\"community\" type=\"xsd:NMTOKEN\" use=\"required\"/>\n");
1919     fprintSegment( f, 0, "<xsd:attribute name=\"caching\" type=\"xsd:NMTOKEN\"/>\n");
1920     fprintSegment( f, 0, "<xsd:attribute name=\"time\" type=\"xsd:dateTime\" use=\"required\"/>\n");
1921     fprintSegment( f, -1, "</xsd:complexType>\n");
1922     fprintSegment( f, -1, "</xsd:element>\n");
1923     fprintSegment( f, -1, "</xsd:sequence>\n");
1924     fprintSegment( f, -1, "</xsd:complexType>\n");
1925
1926     for( i=0; i < modc; i++ ) {
1927         fprintKeys( f, modv[ i ] );
1928     }
1929     fprintSegment( f, -1, "</xsd:element>\n\n");
1930 }
1931
1932
1933 static void fprintTypedefs(FILE *f, SmiModule *smiModule)
1934 {
1935     int          i;
1936     SmiType      *smiType;
1937     
1938     for(i = 0, smiType = smiGetFirstType(smiModule);
1939         smiType;
1940         i++, smiType = smiGetNextType(smiType)) {
1941         fprintf(f, "\n");
1942         fprintTypedef(f, smiType, smiType->name);
1943     }
1944 }
1945
1946
1947 static void registerType( char *type, char *module )
1948 {
1949     TypePrefix *oldTPr = NULL, *iterTPr = NULL;
1950
1951     for( iterTPr = typePrefixes; iterTPr; iterTPr = iterTPr->next ) {
1952         oldTPr = iterTPr;
1953     }
1954     if( ! oldTPr ) {
1955         /* type prefixes do not exist yet */
1956         typePrefixes = xmalloc( sizeof( TypePrefix ) );
1957         typePrefixes->type = type;
1958         typePrefixes->prefix = module;
1959         typePrefixes->next = NULL;
1960     }
1961     else {
1962         /* create new TypePrefix */
1963         oldTPr->next = xmalloc( sizeof( TypePrefix ) );
1964         oldTPr->next->type = type;
1965         oldTPr->next->prefix = module;
1966         oldTPr->next->next = NULL;
1967     }
1968 }
1969
1970
1971 static void dumpXsdModules(int modc, SmiModule **modv, int flags, char *output)
1972 {
1973     int  i;
1974     FILE *f = stdout;
1975     SmiImport *iterImp;
1976     char *lastModName = "";
1977
1978     if (output) {
1979         f = fopen(output, "w");
1980         if (!f) {
1981             fprintf(stderr, "smidump: cannot open %s for writing: ", output);
1982             perror(NULL);
1983             exit(1);
1984         }
1985     }
1986
1987     for (i = 0; i < modc; i++) {
1988
1989         fprintf(f, "<?xml version=\"1.0\"?>\n"); 
1990         fprintf(f, "<!-- This module has been generated by smidump "
1991                SMI_VERSION_STRING ". Do not edit. -->\n");
1992         
1993         fputs( "<!-- WARNING: files located at ", f );
1994         fprintf(f, "%s ", schemaLocation);
1995         fputs( "are subject to changes. -->\n\n", f );
1996
1997         fprintSegment(f, 1, "<xsd:schema ");
1998         fprintf(f, "targetNamespace=\"%s%s\"\n",
1999                 schemaLocation, modv[i]->name);
2000     
2001         fprintf(f, "            xmlns=\"%s%s\"\n",
2002                 schemaLocation, modv[i]->name);
2003 /*      fprintf(f, "            xmlns:xmn=\"http://www.w3.org/XML/1998/namespace\"\n"); */
2004         fprintf(f, "            xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
2005         fprintf(f, "            xmlns:smi=\"%ssmi\"\n", schemaLocation);
2006     
2007         for( iterImp = smiGetFirstImport( modv[i] );
2008              iterImp;
2009              iterImp = smiGetNextImport( iterImp ) ) {
2010             registerType( iterImp->name, iterImp->module );
2011             /* assume imports to be ordered by module names */
2012             if( strcmp( iterImp->module, lastModName ) ) {
2013                 fprintf( f, "            xmlns:%s=\"%s%s\"\n",
2014                          iterImp->module, schemaLocation, iterImp->module );
2015             }
2016             lastModName = iterImp->module;
2017         }
2018   
2019         fprintf(f, "            xml:lang=\"en\"\n");
2020         fprintf(f, "            elementFormDefault=\"qualified\"\n");
2021         fprintf(f, "            attributeFormDefault=\"unqualified\">\n\n");
2022
2023         fprintModuleHead(f, modv[i]);
2024         fprintImports(f, modv[i]);
2025         fprintContextHead(f);
2026         fprintGroupElements(f, modv[i]);
2027         fprintContextFoot(f, modv, 0);
2028         fprintGroupTypes(f, modv[i]);
2029         fprintImplicitTypes(f, modv[i]);
2030         fprintTypedefs(f, modv[i]);
2031
2032         fprintSegment(f, -1, "</xsd:schema>\n");
2033     }
2034
2035     if (fflush(f) || ferror(f)) {
2036         perror("smidump: write error");
2037         exit(1);
2038     }
2039
2040     if (output) {
2041         fclose(f);
2042     }
2043 }
2044
2045
2046 static void dumpXsdContainer(int modc, SmiModule **modv, int flags,
2047                              char *output)
2048 {
2049     int  i;
2050     FILE *f = stdout;
2051
2052     if (output) {
2053         f = fopen(output, "w");
2054         if (!f) {
2055             fprintf(stderr, "smidump: cannot open %s for writing: ", output);
2056             perror(NULL);
2057             exit(1);
2058         }
2059     }
2060
2061     fprintf(f, "<?xml version=\"1.0\"?>\n"); 
2062     fprintf(f, "<!-- This module has been generated by smidump "
2063             SMI_VERSION_STRING ". Do not edit. -->\n");
2064         
2065     fputs( "<!-- WARNING: files located at ", f );
2066     fprintf(f, "%s ", schemaLocation);
2067     fputs( "are subject to changes. -->\n\n", f );
2068     
2069     fprintSegment(f, 1, "<xsd:schema ");
2070     fprintf(f, "targetNamespace=\"%s%s\"\n", schemaLocation, containerBasename);
2071     fprintf(f, "            xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
2072     fprintf(f, "            xmlns:smi=\"%ssmi\"\n", schemaLocation);
2073     for (i = 0; i < modc; i++) {
2074         fprintf(f, "            xmlns:%s=\"%s%s\"\n",
2075                 modv[i]->name, schemaLocation, modv[i]->name);
2076     }
2077     
2078     fprintf(f, "            xml:lang=\"en\"\n");
2079     fprintf(f, "            elementFormDefault=\"qualified\"\n");
2080     fprintf(f, "            attributeFormDefault=\"unqualified\">\n\n");
2081
2082     /* imports */
2083     for (i = 0; i < modc; i++) {
2084         fprintSegment( f, 0, "<xsd:import ");
2085         fprintf( f, "namespace=\"%s%s\" schemaLocation=\"%s%s.xsd\"/>\n",
2086                  schemaLocation, modv[i]->name,
2087                  schemaLocation, modv[i]->name);
2088     }
2089     fprintf( f, "\n");
2090     
2091     /* context */
2092     fprintContextHead(f);
2093     for (i = 0; i < modc; i++) {
2094         /* per module elements */
2095         fprintGroupElements(f, modv[i]);
2096     }
2097     fprintContextFoot(f, modv, modc);
2098
2099     fprintSegment(f, -1, "</xsd:schema>\n");
2100
2101     if (fflush(f) || ferror(f)) {
2102         perror("smidump: write error");
2103         exit(1);
2104     }
2105
2106     if (output) {
2107         fclose(f);
2108     }
2109 }
2110
2111
2112 static void dumpXsd(int modc, SmiModule **modv, int flags, char *output)
2113 {
2114     /* register smi basetypes */
2115     registerType( "Integer32", "smi" );
2116     registerType( "ObjectIdentifier", "smi" );
2117     registerType( "OctetString", "smi" );
2118     registerType( "Unsigned32", "smi" );
2119     registerType( "Unsigned64", "smi" );
2120
2121     /* make sure url ends with '/' */
2122     if( schemaLocation[ strlen( schemaLocation ) - 1 ] != '/' ) {
2123         smiAsprintf( &schemaLocation, "%s%c", schemaLocation, '/');
2124     }
2125         
2126     if (container) {
2127         dumpXsdContainer(modc, modv, flags, output);
2128     } else {
2129         dumpXsdModules(modc, modv, flags, output);
2130     }
2131
2132     /* delete type-prefix-mapping */
2133     free( typePrefixes ); /* XXX: TODO: free all malloced types in a loop */
2134 }
2135
2136
2137 void initXsd()
2138 {
2139
2140     static SmidumpDriverOption opt[] = {
2141         { "schema-url", OPT_STRING, &schemaLocation, 0,
2142           "URI prefix for schema definitions and namespaces" },
2143         { "container", OPT_FLAG, &container, 0,
2144           "generate a container schema" },
2145         { "nest-augments", OPT_FLAG, &nestAugmentedTables, 0,
2146           "Nest rows of augmented tables in the base tables" },
2147         { "nest-subtables", OPT_FLAG, &nestSubtables, 0,
2148           "Nest subtables in the base tables" },
2149         { 0, OPT_END, 0, 0 }
2150     };
2151     
2152     static SmidumpDriver driver = {
2153         "xsd",
2154         dumpXsd,
2155         0,
2156         SMIDUMP_DRIVER_CANT_UNITE,
2157         "XML schema definitions",
2158         opt,
2159         NULL
2160     };
2161     
2162     smidumpRegisterDriver(&driver);
2163 }