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 
getStringBasetype(SmiBasetype basetype)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 
getStringStatus(SmiStatus status)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 
getStringAccess(SmiAccess smiAccess)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 
smiPow(int base,unsigned int exponent)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 
fprintSegment(FILE * f,int relindent,char * fmt,...)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 
fprintMultilineString(FILE * f,const char * s)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 
fprintDocumentation(FILE * f,const char * description)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 
fprintNamedNumber(FILE * f,SmiNamedNumber * nn)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 
fprintStdRestHead(FILE * f,SmiType * smiType)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 
fprintHexOrAsciiType(FILE * f,SmiType * parent,SmiInteger32 minLength,SmiInteger32 maxLength,char * name,int hex)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 
dhInParent(SmiType * smiType)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 */
getIntDHType(char * hint,int * offset)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 
fprintRestriction(FILE * f,SmiType * smiType)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 
getNamedNumberCount(SmiType * smiType)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 
fprintBitList(FILE * f,SmiType * smiType)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 }
getNumSubRanges(SmiType * smiType)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 
fprintSubRangeType(FILE * f,SmiRange * smiRange,SmiType * smiType)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 
fprintDisplayHint(FILE * f,char * format)904 static void fprintDisplayHint( FILE *f, char *format )
905 {
906     fprintSegment( f, 0, "<displayHint>%s</displayHint>\n", format );
907 }
908 
fprintLengths(FILE * f,SmiType * smiType)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 
fprintTypedef(FILE * f,SmiType * smiType,const char * name)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 
getTypePrefix(char * typeName)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 
fprintAnnotationElem(FILE * f,SmiNode * smiNode)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 
hasChildren(SmiNode * smiNode,SmiNodekind nodekind)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
fprintTypeWithHint(FILE * f,SmiNode * smiNode,SmiType * smiType,char * hint)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 
getParentDisplayHint(SmiType * smiType)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 
fprintIndexAttr(FILE * f,SmiNode * smiNode,SmiNode * augments)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 
containsIndex(SmiNode * parentNode,SmiNode * idxNode)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 
fprintIndex(FILE * f,SmiNode * smiNode,SmiNode * augments,SmiNode * parent)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 */
numIndex(SmiNode * smiNode)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
isSubTable(SmiNode * smiNode,SmiNode * subNode)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 
fprintComplexType(FILE * f,SmiNode * smiNode,const char * name,SmiNode * parent)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 
fprintElement(FILE * f,SmiNode * smiNode,SmiNode * parentNode)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 
fprintImplicitTypes(FILE * f,SmiModule * smiModule)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 
fprintImports(FILE * f,SmiModule * smiModule)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  */
isASubTable(SmiNode * smiNode,SmiModule * smiModule)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 
fprintGroupTypes(FILE * f,SmiModule * smiModule)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 
fprintModuleHead(FILE * f,SmiModule * smiModule)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 
fprintKey(FILE * f,SmiNode * smiNode)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 
fprintGroupElements(FILE * f,SmiModule * smiModule)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 
getSubTableXPath(SmiNode * smiNode,SmiModule * smiModule)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 
fprintKeys(FILE * f,SmiModule * smiModule)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 
fprintContextHead(FILE * f)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 
fprintContextFoot(FILE * f,SmiModule ** modv,int modc)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 
fprintTypedefs(FILE * f,SmiModule * smiModule)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 
registerType(char * type,char * module)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 
dumpXsdModules(int modc,SmiModule ** modv,int flags,char * output)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 
dumpXsdContainer(int modc,SmiModule ** modv,int flags,char * output)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 
dumpXsd(int modc,SmiModule ** modv,int flags,char * output)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 
initXsd()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 }
2164