4 * Operations to dump SMI module information as XML schema definitions.
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.
11 * See the file "COPYING" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * @(#) $Id: dump-xsd.c 8090 2008-04-18 12:56:29Z strauss $
34 #define INDENT 2 /* indent factor */
39 #define MIN(a,b) ((a)) < ((b)) ? ((a)) : ((b))
40 #endif /* #ifndef MIN */
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;
48 typedef struct XmlEscape {
53 static XmlEscape xmlEscapes [] = {
60 typedef struct TypePrefix {
63 struct TypePrefix *next;
66 static TypePrefix *typePrefixes = NULL;
70 /* some forward declarations */
71 static void fprintElement( FILE *f, SmiNode *smiNode, SmiNode *parentNode );
72 static char* getTypePrefix( char *typeName );
74 static char *getStringBasetype(SmiBasetype basetype)
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" :
92 static char* getStringStatus(SmiStatus status)
97 case SMI_STATUS_CURRENT:
100 case SMI_STATUS_DEPRECATED:
101 statStr = "deprecated";
103 case SMI_STATUS_OBSOLETE:
104 statStr = "obsolete";
106 case SMI_STATUS_MANDATORY:
107 statStr = "mandatory";
109 case SMI_STATUS_OPTIONAL:
110 statStr = "optional";
112 case SMI_STATUS_UNKNOWN:
120 static char* getStringAccess( SmiAccess smiAccess )
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";
134 *getStringValue(SmiValue *valuePtr, SmiType *typePtr)
145 switch (valuePtr->basetype) {
146 case SMI_BASETYPE_UNSIGNED32:
147 sprintf(s, "%lu", valuePtr->value.unsigned32);
149 case SMI_BASETYPE_INTEGER32:
150 sprintf(s, "%ld", valuePtr->value.integer32);
152 case SMI_BASETYPE_UNSIGNED64:
153 sprintf(s, UINT64_FORMAT, valuePtr->value.unsigned64);
155 case SMI_BASETYPE_INTEGER64:
156 sprintf(s, INT64_FORMAT, valuePtr->value.integer64);
158 case SMI_BASETYPE_FLOAT32:
159 case SMI_BASETYPE_FLOAT64:
160 case SMI_BASETYPE_FLOAT128:
162 case SMI_BASETYPE_ENUM:
163 for (nn = smiGetFirstNamedNumber(typePtr); nn;
164 nn = smiGetNextNamedNumber(nn)) {
165 if (nn->value.value.unsigned32 == valuePtr->value.unsigned32)
169 sprintf(s, "%s", nn->name);
171 sprintf(s, "%ld", valuePtr->value.integer32);
174 case SMI_BASETYPE_OCTETSTRING:
175 for (i = 0; i < valuePtr->len; i++) {
176 if (!isprint((int)valuePtr->value.ptr[i])) break;
178 if (i == valuePtr->len) {
179 sprintf(s, "\"%s\"", valuePtr->value.ptr);
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);
188 case SMI_BASETYPE_BITS:
190 for (i = 0, n = 0; i < valuePtr->len * 8; i++) {
191 if (valuePtr->value.ptr[i/8] & (1 << (7-(i%8)))) {
193 sprintf(&s[strlen(s)], ", ");
195 for (nn = smiGetFirstNamedNumber(typePtr); nn;
196 nn = smiGetNextNamedNumber(nn)) {
197 if (nn->value.value.unsigned32 == i)
201 sprintf(&s[strlen(s)], "%s", nn->name);
207 sprintf(&s[strlen(s)], ")");
209 case SMI_BASETYPE_UNKNOWN:
211 case SMI_BASETYPE_OBJECTIDENTIFIER:
212 nodePtr = smiGetNodeByOID(valuePtr->len, valuePtr->value.oid);
214 sprintf(s, "%s", nodePtr->name);
217 for (i=0; i < valuePtr->len; i++) {
218 if (i) strcat(s, ".");
219 sprintf(&s[strlen(s)], "%u", valuePtr->value.oid[i]);
229 static int smiPow( int base, unsigned int exponent )
234 if( exponent == 0 ) {
238 for( i = 0; i < exponent; i++ ) {
244 static void fprintSegment(FILE *f, int relindent, char *fmt, ...)
250 if ((ind == 0) || (ind + relindent == 0)) {
253 if (relindent < 0) ind += relindent;
254 fprintf(f, "%*c", ind * INDENT, ' ');
255 if (relindent > 0) ind += relindent;
257 vfprintf(f, fmt, ap);
264 static void fprintMultilineString(FILE *f, const char *s)
268 fprintSegment(f, 0, "");
271 for (i=0; i < len; i++) {
272 for (j = 0; xmlEscapes[j].character; j++) {
273 if (xmlEscapes[j].character == s[i]) break;
275 if (xmlEscapes[j].character) {
276 fputs(xmlEscapes[j].escape, f);
281 fprintSegment(f, 0, "");
289 static void fprintDocumentation(FILE *f, const char *description)
292 fprintSegment(f, 1, "<xsd:documentation>\n");
293 fprintMultilineString(f, description);
295 fprintSegment(f, -1, "</xsd:documentation>\n");
299 static void fprintNamedNumber( FILE *f, SmiNamedNumber *nn )
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");
312 static void fprintStdRestHead( FILE *f, SmiType *smiType )
314 char *baseTypeName = getStringBasetype(smiType->basetype);
315 char *prefix = getTypePrefix( baseTypeName );
318 fprintSegment(f, 1, "<xsd:restriction base=\"%s:%s\">\n",
319 prefix, baseTypeName );
322 fprintSegment(f, 1, "<xsd:restriction base=\"%s\">\n", baseTypeName );
327 static void fprintHexOrAsciiType( FILE *f, SmiType *parent,
328 SmiInteger32 minLength,
329 SmiInteger32 maxLength,
330 char *name, int hex )
332 char *prefix = parent ? getTypePrefix( parent->name ) : NULL;
333 char *typeFlag = hex ? "Hex" : "Ascii";
336 fprintSegment( f, 1, "<xsd:simpleType name=\"%s%s\">\n",
339 fprintSegment( f, 1, "<xsd:simpleType>\n");
342 fprintSegment( f, 1, "<xsd:restriction base=\"%s:%s%s\">\n",
343 prefix, parent->name, typeFlag );
346 fprintSegment( f, 1, "<xsd:restriction base=\"%s%s\">\n",
347 parent->name, typeFlag );
350 if( minLength > 0 ) {
351 fprintSegment( f, 0, "<xsd:minLength value=\"%d\"/>\n",
354 if( maxLength > -1 ) {
355 fprintSegment( f, 0, "<xsd:maxLength value=\"%d\"/>\n",
359 fprintSegment( f, -1, "</xsd:restriction>\n");
360 fprintSegment( f, -1, "</xsd:simpleType>\n");
364 static int dhInParent( SmiType *smiType )
366 SmiType *parent = smiGetParentType( smiType );
368 if( smiType->format && parent->format ) {
369 return ! strcmp( smiType->format, parent->format );
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
380 /* parse a (integer) display hint and specify the offset, if used */
381 static int getIntDHType( char *hint, int *offset )
383 switch( hint[ 0 ] ) {
388 *offset = atoi( &hint[2] );
389 return MD_DH_INT_DECIMAL;
391 return MD_DH_INT_NORMAL;
395 return MD_DH_INT_BIN;
398 return MD_DH_INT_OCT;
401 return MD_DH_INT_HEX;
403 /* should not occur */
409 static void fprintRestriction(FILE *f, SmiType *smiType)
413 /* print ranges etc. */
414 switch( smiType->basetype ) {
416 case SMI_BASETYPE_INTEGER32:
418 SmiInteger32 min = SMI_BASETYPE_INTEGER32_MIN;
419 SmiInteger32 max = SMI_BASETYPE_INTEGER32_MAX;
420 int offset = 0, useDecPoint = 0;
422 if( smiType->format ) {
423 /* we have a display hint here, so check if we have to use
426 getIntDHType( smiType->format, &offset ) == MD_DH_INT_DECIMAL;
427 /* xxx: other display hint types (binary, oct, hex) */
431 fprintSegment( f, 1, "<xsd:restriction base=\"xsd:decimal\">\n");
432 fprintSegment( f, 0, "<xsd:fractionDigits value=\"%d\"/>\n", offset );
435 fprintStdRestHead( f, smiType );
438 smiRange = smiGetFirstRange( smiType );
440 if( min == SMI_BASETYPE_INTEGER32_MIN ||
441 smiRange->minValue.value.integer32 < min ) {
442 min = smiRange->minValue.value.integer32;
444 if( max == SMI_BASETYPE_INTEGER32_MAX ||
445 smiRange->maxValue.value.integer32 > max ) {
446 max = smiRange->maxValue.value.integer32;
448 smiRange = smiGetNextRange( smiRange );
451 /* print minimu value */
453 fprintSegment( f, 0, "<xsd:minInclusive value=\"%d.%d\"/>\n",
454 (int)min / smiPow( 10, offset ),
455 abs( (int)min % smiPow( 10, offset ) ) );
457 fprintSegment( f, 0, "<xsd:minInclusive value=\"%d\"/>\n",
461 /* print maximum value */
463 fprintSegment( f, 0, "<xsd:maxInclusive value=\"%d.%d\"/>\n",
464 (int)max / smiPow( 10, offset ),
465 abs( (int)max % smiPow( 10, offset ) ) );
467 fprintSegment( f, 0, "<xsd:maxInclusive value=\"%d\"/>\n",
471 fprintSegment(f, -1, "</xsd:restriction>\n");
475 case SMI_BASETYPE_OCTETSTRING:
477 SmiInteger32 minLength, maxLength;
478 unsigned int numSubRanges = 0;
483 /* get range details */
484 for( smiRange = smiGetFirstRange( smiType );
486 smiRange = smiGetNextRange( smiRange ) ) {
487 if( minLength == 0 ||
488 smiRange->minValue.value.integer32 < minLength ) {
489 minLength = smiRange->minValue.value.integer32;
491 if( smiRange->maxValue.value.integer32 > maxLength ) {
492 maxLength = smiRange->maxValue.value.integer32;
499 if( smiType->format &&
500 ( smiType->decl == SMI_DECL_IMPLICIT_TYPE ||
501 smiType->decl == SMI_DECL_TEXTUALCONVENTION ) &&
502 ! dhInParent( smiType ) ) {
504 fprintStringUnion( f, indent, smiType,
505 minLength, maxLength, 0, NULL );
509 fprintSegment( f, 1, "<xsd:restriction base=\"xsd:string\">\n" );
512 pattern = smiFormatToPattern(smiType->format,
513 smiGetFirstRange(smiType));
515 fprintSegment( f, 0, "<xsd:pattern value=\"%s\"/>\n", pattern);
519 fprintf( f, "<!-- Warning: repeat in display hint. "
520 "This feature is not supported. -->\n" );
522 fprintSegment( f, -1, "</xsd:restriction>\n");
525 SmiType *parent = smiGetParentType( smiType );
527 fprintStringUnion( f, indent, smiType,
528 minLength, maxLength, secondTime,
532 if( parent->format ) {
535 pattern = smiFormatToPattern(parent->format,
536 smiGetFirstRange(smiType));
538 fprintSegment( f, 1, "<xsd:restriction base=\"xsd:string\">\n" );
539 fprintSegment(f, 0, "<xsd:pattern value=\"%s\"/>\n",
541 fprintSegment( f, -1, "</xsd:restriction>\n");
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");
563 char *prefix = getTypePrefix( parent->name );
566 fprintSegment( f, 1, "<xsd:restriction base=\"%s:%s\">\n",
567 prefix, parent->name );
569 fprintSegment( f, 1, "<xsd:restriction base=\"%s\">\n",
573 /* print length restriction */
575 fprintSegment( f, 0, "<xsd:minLength value=\"%d\"/>\n",
578 fprintSegment( f, 0, "<xsd:maxLength value=\"%d\"/>\n",
580 fprintSegment( f, -1, "</xsd:restriction>\n");
589 case SMI_BASETYPE_FLOAT128:
591 /* SmiFloat128 min, max; */
592 fprintStdRestHead( f, smiType );
594 /* xxx, only SMIng */
598 case SMI_BASETYPE_FLOAT64:
600 /* SmiFloat64 min,max;*/
601 fprintStdRestHead( f, smiType );
603 /* xxx, only SMIng */
607 case SMI_BASETYPE_FLOAT32:
609 /* SmiFloat32 min,max;*/
610 fprintStdRestHead( f, smiType );
612 /* xxx, only SMIng */
616 case SMI_BASETYPE_INTEGER64:
618 /* SmiInteger64 min,max;*/
619 fprintStdRestHead( f, smiType );
621 /* xxx, only SMIng */
625 case SMI_BASETYPE_UNSIGNED64:
627 SmiUnsigned64 min, max;
629 min = SMI_BASETYPE_UNSIGNED64_MIN;
630 max = SMI_BASETYPE_UNSIGNED64_MAX;
632 fprintStdRestHead( f, smiType );
634 smiRange = smiGetFirstRange( smiType );
636 if( smiRange->minValue.value.unsigned64 < min ) {
637 min = smiRange->minValue.value.unsigned64;
639 if( smiRange->maxValue.value.unsigned64 > max ) {
640 max = smiRange->maxValue.value.unsigned64;
642 smiRange = smiGetNextRange( smiRange );
644 fprintSegment( f, 0, "<xsd:minInclusive value=\"%lu\"/>\n",
645 (unsigned long)min );
647 fprintSegment( f, 0, "<xsd:maxInclusive value=\"%lu\"/>\n",
648 (unsigned long)max );
650 fprintSegment(f, -1, "</xsd:restriction>\n");
655 case SMI_BASETYPE_UNSIGNED32:
657 SmiUnsigned32 min, max;
662 fprintStdRestHead( f, smiType );
664 smiRange = smiGetFirstRange( smiType );
666 if( smiRange->minValue.value.unsigned32 < min ) {
667 min = smiRange->minValue.value.unsigned32;
669 if( smiRange->maxValue.value.unsigned32 > max ) {
670 max = smiRange->maxValue.value.unsigned32;
672 smiRange = smiGetNextRange( smiRange );
674 fprintSegment( f, 0, "<xsd:minInclusive value=\"%u\"/>\n",
677 fprintSegment( f, 0, "<xsd:maxInclusive value=\"%u\"/>\n",
680 fprintSegment(f, -1, "</xsd:restriction>\n");
684 case SMI_BASETYPE_ENUM:
685 case SMI_BASETYPE_BITS:
689 fprintSegment(f, 1, "<xsd:restriction base=\"xsd:NMTOKEN\">\n");
691 /* iterate named numbers */
692 for( nn = smiGetFirstNamedNumber( smiType );
694 nn = smiGetNextNamedNumber( nn ) ) {
695 fprintNamedNumber( f, nn );
697 fprintSegment(f, -1, "</xsd:restriction>\n");
701 case SMI_BASETYPE_OBJECTIDENTIFIER:
703 "<xsd:restriction base=\"smi:ObjectIdentifier\"/>\n");
705 case SMI_BASETYPE_UNKNOWN:
706 /* should not occur */
708 case SMI_BASETYPE_POINTER:
715 static unsigned int getNamedNumberCount( SmiType *smiType )
718 unsigned int ret = 0;
720 for( nn = smiGetFirstNamedNumber( smiType );
722 nn = smiGetNextNamedNumber( nn ) ) {
730 static void fprintBitList( FILE *f, SmiType *smiType )
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");
744 static int getNumSubRanges( SmiType *smiType )
749 for( smiRange = smiGetFirstRange( smiType );
751 smiRange = smiGetNextRange( smiRange ) ) {
759 static void fprintSubRangeType( FILE *f,
760 SmiRange *smiRange, SmiType *smiType )
763 switch( smiType->basetype ) {
765 case SMI_BASETYPE_UNSIGNED32: {
766 SmiUnsigned32 min, max;
771 if( smiRange->minValue.value.unsigned32 < min ) {
772 min = smiRange->minValue.value.unsigned32;
774 if( smiRange->maxValue.value.unsigned32 > max ) {
775 max = smiRange->maxValue.value.unsigned32;
778 fprintSegment( f, 1, "<xsd:simpleType>\n");
779 fprintStdRestHead( f, smiType );
781 fprintSegment( f, 0, "<xsd:minInclusive value=\"%u\"/>\n",
784 fprintSegment( f, 0, "<xsd:maxInclusive value=\"%u\"/>\n",
787 fprintSegment(f, -1, "</xsd:restriction>\n");
788 fprintSegment(f, -1, "</xsd:simpleType>\n");
792 case SMI_BASETYPE_INTEGER32: {
793 SmiInteger32 min, max;
795 min = SMI_BASETYPE_INTEGER32_MIN;
796 max = SMI_BASETYPE_INTEGER32_MAX;
798 if( min == SMI_BASETYPE_INTEGER32_MIN ||
799 smiRange->minValue.value.integer32 < min ) {
800 min = smiRange->minValue.value.integer32;
802 if( max == SMI_BASETYPE_INTEGER32_MAX ||
803 smiRange->maxValue.value.integer32 > max ) {
804 max = smiRange->maxValue.value.integer32;
807 fprintSegment( f, 1, "<xsd:simpleType>\n");
808 fprintStdRestHead( f, smiType );
810 fprintSegment( f, 0, "<xsd:minInclusive value=\"%d\"/>\n", (int)min );
812 fprintSegment( f, 0, "<xsd:maxInclusive value=\"%d\"/>\n", (int)max );
814 fprintSegment(f, -1, "</xsd:restriction>\n");
815 fprintSegment(f, -1, "</xsd:simpleType>\n");
820 case SMI_BASETYPE_OCTETSTRING: {
821 SmiInteger32 minLength, maxLength;
826 if( smiRange->minValue.value.integer32 < minLength ) {
827 minLength = smiRange->minValue.value.integer32;
829 if( smiRange->maxValue.value.integer32 > maxLength ) {
830 maxLength = smiRange->maxValue.value.integer32;
832 fprintHexOrAsciiType( f, smiType,
833 minLength, maxLength, NULL, 1 );
837 case SMI_BASETYPE_FLOAT128:
839 /* SmiFloat128 min, max;
844 case SMI_BASETYPE_FLOAT64:
846 /* SmiFloat64 min,max;
851 case SMI_BASETYPE_FLOAT32:
853 /* SmiFloat32 min,max;
858 case SMI_BASETYPE_INTEGER64:
860 /* SmiInteger64 min,max;
865 case SMI_BASETYPE_UNSIGNED64:
867 SmiUnsigned64 min, max;
869 min = SMI_BASETYPE_UNSIGNED64_MIN;
870 max = SMI_BASETYPE_UNSIGNED64_MAX;
872 if( smiRange->minValue.value.unsigned64 < min ) {
873 min = smiRange->minValue.value.unsigned64;
875 if( smiRange->maxValue.value.unsigned32 > max ) {
876 max = smiRange->maxValue.value.unsigned64;
879 fprintSegment( f, 1, "<xsd:simpleType>\n");
880 fprintStdRestHead( f, smiType );
882 fprintSegment( f, 0, "<xsd:minInclusive value=\"%lu\"/>\n",
883 (unsigned long)min );
885 fprintSegment( f, 0, "<xsd:maxInclusive value=\"%lu\"/>\n",
886 (unsigned long)max );
888 fprintSegment(f, -1, "</xsd:restriction>\n");
889 fprintSegment(f, -1, "</xsd:simpleType>\n");
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 */
904 static void fprintDisplayHint( FILE *f, char *format )
906 fprintSegment( f, 0, "<displayHint>%s</displayHint>\n", format );
909 static void fprintLengths(FILE *f, SmiType *smiType)
911 SmiRange *smiRange = smiGetFirstRange(smiType);
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);
924 fprintSegment( f, -1, "</lengths>\n");
928 static void fprintTypedef(FILE *f, SmiType *smiType, const char *name)
931 unsigned int numSubRanges = getNumSubRanges( smiType );
934 fprintSegment(f, 1, "<xsd:simpleType name=\"%s\">\n", name);
938 /* unnamed simple type */
939 fprintSegment(f, 1, "<xsd:simpleType>\n");
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 );
951 fprintSegment( f, -1, "</xsd:appinfo>\n");
953 fprintSegment( f, -1, "</xsd:annotation>\n");
956 if( ( numSubRanges > 1 ) &&
957 ( smiType->basetype != SMI_BASETYPE_OCTETSTRING ) ) {
959 fprintSegment( f, 1, "<xsd:union>\n");
961 for( smiRange = smiGetFirstRange( smiType );
963 smiRange = smiGetNextRange( smiRange ) ) {
964 fprintSubRangeType( f, smiRange, smiType );
967 fprintSegment( f, -1, "</xsd:union>\n");
969 else if( smiType->basetype == SMI_BASETYPE_BITS ) {
970 fprintBitList( f, smiType );
973 fprintRestriction(f, smiType );
975 fprintSegment(f, -1, "</xsd:simpleType>\n");
977 /* print an empty line after global types */
978 if( smiType->decl != SMI_DECL_IMPLICIT_TYPE && name ) {
984 static char* getTypePrefix( char *typeName )
992 for( iterTPr = typePrefixes; iterTPr; iterTPr = iterTPr->next ) {
993 if( ! strcmp( iterTPr->type, typeName ) ) {
994 return iterTPr->prefix;
1002 static void fprintAnnotationElem( FILE *f, SmiNode *smiNode ) {
1005 fprintSegment( f, 1, "<xsd:annotation>\n");
1006 fprintSegment( f, 1, "<xsd:appinfo>\n");
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\"" );
1014 if( smiNode->create ) {
1015 fprintf( f, " create=\"yes\"" );
1017 fprintf( f, "/>\n" );
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]);
1026 fprintf( f, "</oid>\n" );
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 );
1039 if( smiNode->format ) {
1040 fprintDisplayHint( f, smiNode->format );
1043 if( smiNode->units ) {
1044 fprintSegment( f, 0, "<units>%s</units>\n", smiNode->units );
1047 fprintSegment( f, -1, "</xsd:appinfo>\n");
1048 fprintDocumentation( f, smiNode->description );
1049 fprintSegment( f, -1, "</xsd:annotation>\n");
1053 static int hasChildren( SmiNode *smiNode, SmiNodekind nodekind )
1056 int childNodeCount = 0;
1058 for( iterNode = smiGetFirstChildNode( smiNode );
1060 iterNode = smiGetNextChildNode( iterNode ) ){
1061 if( nodekind & iterNode->nodekind ) {
1065 return childNodeCount;
1069 fprintTypeWithHint( FILE *f, SmiNode *smiNode, SmiType *smiType, char *hint )
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");
1081 pattern = smiFormatToPattern(hint, smiGetFirstRange(smiType));
1083 fprintSegment( f, 0, "<xsd:pattern value=\"%s\"/>\n", pattern);
1086 fprintSegment( f, -1, "</xsd:restriction>\n");
1087 fprintSegment( f, -1, "</xsd:simpleType>\n");
1091 static char *getParentDisplayHint( SmiType *smiType )
1095 for( iterType = smiGetParentType( smiType );
1097 iterType = smiGetParentType( iterType ) ) {
1098 if( iterType->format ) {
1099 return iterType->format;
1106 static void fprintIndexAttr( FILE *f, SmiNode *smiNode, SmiNode *augments )
1108 char *typeName, *prefix;
1111 smiType = smiGetNodeType( smiNode );
1113 /* fprint( f, "<!-- error: no type in %s -->\n", smiNode->name );*/
1117 typeName = smiType->name ?
1119 getStringBasetype( smiType->basetype );
1120 prefix = getTypePrefix( typeName );
1123 if( smiType->basetype == SMI_BASETYPE_BITS ) {
1124 fprintSegment( f, 1, "<xsd:attribute name=\"%s\" type=\"%s%s\" "
1125 "use=\"required\">\n",
1128 getStringBasetype( smiType->basetype ) );
1129 fprintAnnotationElem( f, smiNode );
1132 else if( smiType->basetype == SMI_BASETYPE_OCTETSTRING ) {
1134 if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1135 char *hint = getParentDisplayHint( smiType );
1137 fprintSegment( f, 1, "<xsd:attribute name=\"%s\" "
1138 "use=\"required\">\n", smiNode->name );
1139 fprintAnnotationElem( f, smiNode );
1141 fprintTypedef( f, smiType, NULL );
1144 fprintTypeWithHint( f, smiNode, smiType, hint );
1150 fprintSegment( f, 1, "<xsd:attribute name=\"%s\" "
1151 "type=\"%s:%s\" use=\"required\">\n",
1152 smiNode->name, prefix, typeName );
1155 fprintSegment( f, 1, "<xsd:attribute name=\"%s\" "
1156 "type=\"%s\" use=\"required\">\n",
1157 smiNode->name, typeName );
1159 fprintAnnotationElem( f, smiNode );
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",
1168 fprintAnnotationElem( f, smiNode );
1169 fprintTypedef( f, smiType, NULL );
1174 fprintSegment( f, 1,"<xsd:attribute name=\"%s\" type=\"%s:%s\" ",
1175 smiNode->name, prefix, typeName );
1176 fprintf( f, "use=\"required\">\n" );
1179 fprintSegment( f, 1, "<xsd:attribute name=\"%s\" type=\"%s\" ",
1180 smiNode->name, typeName );
1181 fprintf( f, "use=\"required\">\n" );
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");
1192 fprintAnnotationElem( f, smiNode );
1195 fprintSegment( f, -1, "</xsd:attribute>\n");
1198 static int containsIndex( SmiNode *parentNode, SmiNode *idxNode )
1200 SmiElement *iterElement;
1203 for( iterElement = smiGetFirstElement( parentNode );
1205 iterElement = smiGetNextElement( iterElement ) ) {
1206 SmiNode *iterNode = smiGetElementNode( iterElement );
1207 if( iterNode == idxNode )
1213 static void fprintIndex( FILE *f,
1214 SmiNode *smiNode, SmiNode *augments, SmiNode *parent )
1217 SmiElement *iterElem;
1219 /* iterate INDEX columns */
1220 for( iterElem = smiGetFirstElement( smiNode );
1222 iterElem = smiGetNextElement( iterElem ) ) {
1223 iterNode = smiGetElementNode( iterElem );
1224 if( ! parent || (parent && !containsIndex( parent, iterNode ) ) ) {
1225 fprintIndexAttr( f, iterNode, augments );
1229 /* print AUGMENTS-clause */
1230 iterNode = smiGetRelatedNode( smiNode );
1232 fprintIndex( f, iterNode, iterNode, NULL );
1236 /* counts index elements of a table row node */
1237 static int numIndex( SmiNode *smiNode )
1239 SmiElement *iterElem;
1242 for( iterElem = smiGetFirstElement( smiNode );
1244 iterElem = smiGetNextElement( iterElem ) ) {
1251 /* checks if the second node is a subtable of the first node */
1253 isSubTable( SmiNode *smiNode, SmiNode *subNode )
1255 SmiElement *iterElement;
1256 unsigned int numIdx = numIndex( smiNode ), numSubIdx = numIndex( subNode );
1258 /* compare number of index elements */
1259 if( numSubIdx <= numIdx ) {
1260 /* does not have more index elements --> no subtable */
1264 /* compare all index elements */
1265 for( iterElement = smiGetFirstElement( smiNode );
1267 iterElement = smiGetNextElement( iterElement ) ) {
1268 SmiElement *iterSubElement = smiGetFirstElement( subNode );
1269 SmiNode *iterSubNode;
1270 SmiNode *idxNode = smiGetElementNode( iterElement );
1272 for( iterSubElement = smiGetFirstElement( subNode );
1274 iterSubElement = smiGetNextElement( iterSubElement ) ) {
1276 iterSubNode = smiGetElementNode( iterSubElement );
1277 if( idxNode == iterSubNode ){
1286 static void fprintComplexType( FILE *f, SmiNode *smiNode, const char *name,
1293 fprintSegment( f, 1, "<xsd:complexType name=\"%sType\">\n",
1296 fprintSegment( f, 1, "<xsd:complexType>\n" );
1299 /* fprintAnnotationElem( f, smiNode ); */
1301 numChildren = hasChildren( smiNode, SMI_NODEKIND_ANY );
1303 fprintSegment( f, 1, "<xsd:sequence>\n");
1305 /* print child elements */
1306 for( iterNode = smiGetFirstChildNode( smiNode );
1308 iterNode = smiGetNextChildNode( iterNode ) ) {
1310 fprintElement( f, iterNode, NULL );
1314 /* print augmentations */
1315 if( nestAugmentedTables ) {
1316 for( iterNode = smiGetFirstNode( smiGetNodeModule( smiNode ),
1319 iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_ROW ) ) {
1320 SmiNode *augmNode = smiGetRelatedNode( iterNode );
1321 if( augmNode == smiNode ) {
1322 SmiNode *augIterNode;
1323 for( augIterNode = smiGetFirstChildNode( iterNode );
1325 augIterNode = smiGetNextChildNode( augIterNode ) ) {
1327 fprintElement( f, augIterNode, NULL );
1333 /* print subtables */
1334 if( nestSubtables ) {
1335 for( iterNode = smiGetFirstNode( smiGetNodeModule( smiNode ),
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 );*/
1347 fprintSegment( f, -1, "</xsd:sequence>\n");
1348 fprintIndex( f, smiNode, NULL, parent );
1350 fprintSegment( f, -1, "</xsd:complexType>\n");
1352 /* we are printing out a global type,
1353 so let's leave a blank line after it. */
1357 for( iterNode = smiGetFirstChildNode( smiNode );
1359 iterNode = smiGetNextChildNode( iterNode ) ) {
1360 if( iterNode->nodekind == SMI_NODEKIND_NODE ) {
1361 fprintComplexType( f, iterNode, iterNode->name, NULL );
1368 static void fprintElement( FILE *f, SmiNode *smiNode, SmiNode *parentNode )
1370 switch( smiNode->nodekind ) {
1373 case SMI_NODEKIND_NODE :
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 );
1382 iterNode = smiGetNextChildNode( iterNode ) ) {
1383 if( iterNode->nodekind == SMI_NODEKIND_SCALAR ) {
1384 fprintElement( f, iterNode, NULL );
1387 fprintSegment( f, -1, "</xsd:sequence>\n");
1388 fprintSegment( f, -1, "</xsd:complexType>\n");
1389 fprintSegment( f, -1, "</xsd:element>\n");
1393 case SMI_NODEKIND_TABLE :
1397 /* ignore tables and just include their entries */
1398 for( iterNode = smiGetFirstChildNode( smiNode );
1400 iterNode = smiGetNextChildNode( iterNode ) ) {
1401 fprintElement( f, iterNode, NULL );
1406 case SMI_NODEKIND_ROW:
1408 fprintSegment( f, 1, "<xsd:element name=\"%s\" "
1409 "minOccurs=\"0\" maxOccurs=\"unbounded\">\n",
1412 fprintAnnotationElem( f, smiNode );
1414 fprintComplexType( f, smiNode, NULL, parentNode );
1415 fprintSegment( f, -1, "</xsd:element>\n");
1418 case SMI_NODEKIND_SCALAR:
1419 case SMI_NODEKIND_COLUMN:
1421 SmiElement *iterElem;
1425 /* check if we are index column */
1426 for( iterElem = smiGetFirstElement( smiGetParentNode( smiNode ) ) ;
1428 iterElem = smiGetNextElement( iterElem ) ) {
1429 if( smiNode == smiGetElementNode( iterElem ) ) {
1430 /* we are index coulumn ==> do not print element */
1435 if( smiNode->access < SMI_ACCESS_READ_ONLY ) {
1436 /* only print accessible nodes */
1440 smiType = smiGetNodeType( smiNode );
1442 if( smiType->name ) {
1443 typeName = smiType->name;
1446 typeName = getStringBasetype( smiType->basetype );
1448 prefix = getTypePrefix( typeName );
1451 if( smiType->basetype == SMI_BASETYPE_BITS ) {
1452 fprintSegment( f, 1, "<xsd:element name=\"%s\" type=\"%s%s\" "
1453 "minOccurs=\"0\">\n",
1456 getStringBasetype( smiType->basetype ) );
1457 fprintAnnotationElem( f, smiNode );
1460 // else if( smiType->basetype == SMI_BASETYPE_OCTETSTRING ) {
1463 if( smiType->basetype == SMI_BASETYPE_OCTETSTRING ) {
1464 if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1466 char *hint = getParentDisplayHint( smiType );
1468 fprintSegment( f, 1, "<xsd:element name=\"%s\" "
1469 "minOccurs=\"0\">\n", smiNode->name );
1470 fprintAnnotationElem( f, smiNode );
1472 fprintTypedef( f, smiType, NULL );
1475 fprintTypeWithHint( f, smiNode, smiType, hint );
1481 fprintSegment( f, 1, "<xsd:element name=\"%s\" "
1482 "type=\"%s:%s\" minOccurs=\"0\">\n",
1483 smiNode->name, prefix, typeName );
1486 fprintSegment( f, 1, "<xsd:element name=\"%s\" "
1487 "type=\"%s\" minOccurs=\"0\">\n",
1488 smiNode->name, typeName );
1490 fprintAnnotationElem( f, smiNode );
1494 else if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1495 fprintSegment( f, 1, "<xsd:element name=\"%s\" minOccurs=\"0\">\n",
1497 fprintAnnotationElem( f, smiNode );
1498 fprintTypedef( f, smiType, NULL );
1503 fprintSegment( f, 1, "<xsd:element name=\"%s\" type=\"%s:%s\" "
1504 "minOccurs=\"0\">\n",
1505 smiNode->name, prefix, typeName );
1508 fprintSegment( f, 1, "<xsd:element name=\"%s\" type=\"%s\" "
1509 "minOccurs=\"0\">\n",
1510 smiNode->name, typeName );
1512 fprintAnnotationElem( f, smiNode );
1514 fprintSegment( f, -1, "</xsd:element>\n");
1518 case SMI_NODEKIND_NOTIFICATION:
1519 fprintSegment( f, 0, "<xsd:element name=\"%s\"/>\n", smiNode->name );
1523 fprintf( f, "<!-- Warning! Unhandled Element! No details available!\n");
1524 fprintf( f, " Nodekind: %#4x -->\n\n", smiNode->nodekind );
1530 static void fprintImplicitTypes( FILE *f, SmiModule *smiModule )
1535 for(iterNode = smiGetFirstNode(smiModule,
1536 SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN);
1538 iterNode = smiGetNextNode(iterNode,
1539 SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN)) {
1540 smiType = smiGetNodeType( iterNode );
1542 switch( smiType->basetype ) {
1544 case SMI_BASETYPE_BITS:
1545 if( ! getTypePrefix( smiType->name ) ) {
1546 fprintTypedef( f, smiType, iterNode->name );
1550 case SMI_BASETYPE_OCTETSTRING:
1552 if( smiType->decl == SMI_DECL_IMPLICIT_TYPE ) {
1553 fprintTypedef( f, INDENT, smiType, iterNode->name );
1566 static void fprintRows( FILE *f, SmiModule *smiModule )
1570 for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_ROW );
1572 iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_ROW ) ) {
1573 if( hasChildren( iterNode, SMI_NODEKIND_COLUMN | SMI_NODEKIND_TABLE ) ){
1574 fprintElement( f, iterNode, NULL );
1580 static void fprintImports( FILE *f, SmiModule *smiModule )
1583 char *lastModName = "";
1585 fprintSegment( f, 0, "<xsd:import namespace=\"%ssmi\" schemaLocation=\"%ssmi.xsd\"/>\n", schemaLocation, schemaLocation );
1586 for( iterImp = smiGetFirstImport( smiModule );
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 );
1596 lastModName = iterImp->module;
1604 * Check if given table io a sub table of another table.
1605 * If so, its parent table is returned (NULL otherwise).
1607 static SmiNode *isASubTable( SmiNode *smiNode, SmiModule *smiModule )
1610 int numIdxDiff = -1;
1611 SmiNode *retNode = NULL;
1613 for( iterNode = smiGetFirstNode( smiModule,
1616 iterNode = smiGetNextNode( iterNode,
1617 SMI_NODEKIND_ROW ) ) {
1619 if( isSubTable( iterNode, smiNode ) ) {
1621 if( (numIdxDiff == -1) ||
1622 ((numIndex( smiNode ) - numIndex( iterNode )) < numIdxDiff) ) {
1624 numIdxDiff = numIndex( smiNode ) - numIndex( iterNode );
1633 static void fprintGroupTypes( FILE *f, SmiModule *smiModule )
1635 SmiNode *iterNode, *iterNode2;
1638 for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_NODE );
1640 iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_NODE ) ) {
1641 if( hasChildren( iterNode, SMI_NODEKIND_SCALAR ) ) {
1642 fprintSegment(f, 1, "<xsd:complexType name=\"%sType\">\n",
1644 fprintSegment( f, 1, "<xsd:sequence>\n");
1645 for( iterNode2 = smiGetFirstChildNode( iterNode );
1647 iterNode2 = smiGetNextChildNode( iterNode2 ) ) {
1648 if( iterNode2->nodekind == SMI_NODEKIND_SCALAR ) {
1649 fprintElement( f, iterNode2, NULL );
1652 fprintSegment( f, -1, "</xsd:sequence>\n");
1653 fprintSegment(f, -1, "</xsd:complexType>\n");
1658 for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_ROW );
1660 iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_ROW ) ) {
1661 if( hasChildren( iterNode,
1662 SMI_NODEKIND_COLUMN | SMI_NODEKIND_TABLE ) ){
1664 /* skip nested subtables here */
1665 if( nestSubtables ){
1666 if( isASubTable( iterNode, smiModule ) != NULL ) {
1671 /* skip table augmentations here */
1672 if( nestAugmentedTables ) {
1673 if( iterNode->indexkind == SMI_INDEX_AUGMENT ) {
1678 fprintComplexType( f, iterNode, iterNode->name, NULL );
1686 static void fprintNotifications( FILE *f, SmiModule *smiModule )
1690 for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_NOTIFICATION );
1692 iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_NOTIFICATION ) ) {
1693 fprintElement( f, iterNode, NULL );
1699 static void fprintModuleHead(FILE *f, SmiModule *smiModule)
1701 if( smiModule->description ) {
1702 fprintSegment(f, 1, "<xsd:annotation>\n");
1703 fprintDocumentation(f, smiModule->description);
1704 fprintSegment(f, -1, "</xsd:annotation>\n\n");
1710 static void fprintKey( FILE *f, SmiNode *smiNode )
1713 SmiElement *iterElem;
1715 switch( smiNode->indexkind ) {
1717 case SMI_INDEX_INDEX:
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 );
1726 iterElem = smiGetNextElement( iterElem ) ) {
1727 SmiNode *indexNode = smiGetElementNode( iterElem );
1728 fprintSegment( f, 0, "<xsd:field ");
1729 fprintf( f, "xpath=\"@%s\"/>\n", indexNode->name );
1731 fprintSegment( f, -1, "</xsd:key>\n\n");*/
1734 case SMI_INDEX_AUGMENT:
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 );
1745 iterElem = smiGetNextElement( iterElem ) ) {
1746 SmiNode *indexNode = smiGetElementNode( iterElem );
1747 fprintSegment( f, 0, "<xsd:field ");
1748 fprintf( f, "xpath=\"@%s\"/>\n", indexNode->name );
1750 fprintSegment( f, -1, "</xsd:keyref>\n");
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 );
1759 iterElem = smiGetNextElement( iterElem ) ) {
1760 SmiNode *indexNode = smiGetElementNode( iterElem );
1761 fprintSegment( f, 0, "<xsd:field ");
1762 fprintf( f, "xpath=\"@%s\"/>\n", indexNode->name );
1764 fprintSegment( f, -1, "</xsd:unique>\n\n");
1767 case SMI_INDEX_REORDER:
1768 case SMI_INDEX_SPARSE:
1769 case SMI_INDEX_EXPAND:
1770 /* SMIng, not implemented yet */
1774 fprintf( f, "<!-- Error: Unknown index type -->\n" );
1780 static void fprintGroupElements(FILE *f, SmiModule *smiModule)
1785 for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_NODE );
1787 iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_NODE ) ) {
1788 if( hasChildren( iterNode, SMI_NODEKIND_SCALAR ) ) {
1791 fprintSegment(f, 1, "<xsd:element name=\"%s\" "
1792 "type=\"%s:%sType\" minOccurs=\"0\">\n",
1794 smiModule->name, iterNode->name);
1796 fprintSegment(f, 1, "<xsd:element name=\"%s\" "
1797 "type=\"%sType\" minOccurs=\"0\">\n",
1798 iterNode->name, iterNode->name);
1800 fprintAnnotationElem( f, iterNode );
1801 fprintSegment( f, -1, "</xsd:element>\n" );
1806 for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_ROW );
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 ) {
1817 /* skip table augmentations here */
1818 if( nestAugmentedTables ) {
1819 if( iterNode->indexkind == SMI_INDEX_AUGMENT ) {
1825 fprintSegment(f, 1, "<xsd:element name=\"%s\" "
1826 "type=\"%s:%sType\" minOccurs=\"0\" "
1827 "maxOccurs=\"unbounded\">\n",
1829 smiModule->name, iterNode->name);
1830 fprintKey( f, iterNode );
1832 fprintSegment(f, 1, "<xsd:element name=\"%s\" "
1833 "type=\"%sType\" minOccurs=\"0\" "
1834 "maxOccurs=\"unbounded\">\n",
1835 iterNode->name, iterNode->name);
1837 fprintAnnotationElem( f, iterNode );
1838 fprintSegment( f, -1, "</xsd:element>\n" );
1844 static char *getSubTableXPath( SmiNode *smiNode, SmiModule *smiModule )
1847 SmiNode *parentTable = isASubTable( smiNode, smiModule );
1850 smiAsprintf( &ret, "%s/%s",
1851 getSubTableXPath( parentTable, smiModule ),
1855 smiAsprintf( &ret, "%s", smiNode->name );
1861 static void fprintKeys( FILE *f, SmiModule *smiModule )
1866 for( iterNode = smiGetFirstNode( smiModule, SMI_NODEKIND_ROW );
1868 iterNode = smiGetNextNode( iterNode, SMI_NODEKIND_ROW ) ) {
1870 SmiElement *iterElem;
1872 /* print only keys for base tables */
1873 if( iterNode->indexkind != SMI_INDEX_INDEX ) {
1878 fprintSegment( f, 1, "<xsd:key name=\"%sKey\">\n", iterNode->name );
1879 fprintSegment( f, 0, "<xsd:selector ");
1880 fprintf( f, "xpath=\"%s\"/>\n",
1882 getSubTableXPath( iterNode, smiModule ) : iterNode->name );
1884 for( iterElem = smiGetFirstElement( iterNode );
1886 iterElem = smiGetNextElement( iterElem ) ) {
1887 SmiNode *indexNode = smiGetElementNode( iterElem );
1888 fprintSegment( f, 0, "<xsd:field ");
1889 fprintf( f, "xpath=\"@%s\"/>\n", indexNode->name );
1891 fprintSegment( f, -1, "</xsd:key>\n\n");
1898 static void fprintContextHead(FILE *f)
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");
1910 static void fprintContextFoot(FILE *f, SmiModule **modv, int modc)
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");
1926 for( i=0; i < modc; i++ ) {
1927 fprintKeys( f, modv[ i ] );
1929 fprintSegment( f, -1, "</xsd:element>\n\n");
1933 static void fprintTypedefs(FILE *f, SmiModule *smiModule)
1938 for(i = 0, smiType = smiGetFirstType(smiModule);
1940 i++, smiType = smiGetNextType(smiType)) {
1942 fprintTypedef(f, smiType, smiType->name);
1947 static void registerType( char *type, char *module )
1949 TypePrefix *oldTPr = NULL, *iterTPr = NULL;
1951 for( iterTPr = typePrefixes; iterTPr; iterTPr = iterTPr->next ) {
1955 /* type prefixes do not exist yet */
1956 typePrefixes = xmalloc( sizeof( TypePrefix ) );
1957 typePrefixes->type = type;
1958 typePrefixes->prefix = module;
1959 typePrefixes->next = NULL;
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;
1971 static void dumpXsdModules(int modc, SmiModule **modv, int flags, char *output)
1976 char *lastModName = "";
1979 f = fopen(output, "w");
1981 fprintf(stderr, "smidump: cannot open %s for writing: ", output);
1987 for (i = 0; i < modc; i++) {
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");
1993 fputs( "<!-- WARNING: files located at ", f );
1994 fprintf(f, "%s ", schemaLocation);
1995 fputs( "are subject to changes. -->\n\n", f );
1997 fprintSegment(f, 1, "<xsd:schema ");
1998 fprintf(f, "targetNamespace=\"%s%s\"\n",
1999 schemaLocation, modv[i]->name);
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);
2007 for( iterImp = smiGetFirstImport( modv[i] );
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 );
2016 lastModName = iterImp->module;
2019 fprintf(f, " xml:lang=\"en\"\n");
2020 fprintf(f, " elementFormDefault=\"qualified\"\n");
2021 fprintf(f, " attributeFormDefault=\"unqualified\">\n\n");
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]);
2032 fprintSegment(f, -1, "</xsd:schema>\n");
2035 if (fflush(f) || ferror(f)) {
2036 perror("smidump: write error");
2046 static void dumpXsdContainer(int modc, SmiModule **modv, int flags,
2053 f = fopen(output, "w");
2055 fprintf(stderr, "smidump: cannot open %s for writing: ", output);
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");
2065 fputs( "<!-- WARNING: files located at ", f );
2066 fprintf(f, "%s ", schemaLocation);
2067 fputs( "are subject to changes. -->\n\n", f );
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);
2078 fprintf(f, " xml:lang=\"en\"\n");
2079 fprintf(f, " elementFormDefault=\"qualified\"\n");
2080 fprintf(f, " attributeFormDefault=\"unqualified\">\n\n");
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);
2092 fprintContextHead(f);
2093 for (i = 0; i < modc; i++) {
2094 /* per module elements */
2095 fprintGroupElements(f, modv[i]);
2097 fprintContextFoot(f, modv, modc);
2099 fprintSegment(f, -1, "</xsd:schema>\n");
2101 if (fflush(f) || ferror(f)) {
2102 perror("smidump: write error");
2112 static void dumpXsd(int modc, SmiModule **modv, int flags, char *output)
2114 /* register smi basetypes */
2115 registerType( "Integer32", "smi" );
2116 registerType( "ObjectIdentifier", "smi" );
2117 registerType( "OctetString", "smi" );
2118 registerType( "Unsigned32", "smi" );
2119 registerType( "Unsigned64", "smi" );
2121 /* make sure url ends with '/' */
2122 if( schemaLocation[ strlen( schemaLocation ) - 1 ] != '/' ) {
2123 smiAsprintf( &schemaLocation, "%s%c", schemaLocation, '/');
2127 dumpXsdContainer(modc, modv, flags, output);
2129 dumpXsdModules(modc, modv, flags, output);
2132 /* delete type-prefix-mapping */
2133 free( typePrefixes ); /* XXX: TODO: free all malloced types in a loop */
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 }
2152 static SmidumpDriver driver = {
2156 SMIDUMP_DRIVER_CANT_UNITE,
2157 "XML schema definitions",
2162 smidumpRegisterDriver(&driver);