1 /*
2  * dump-yang.c --
3  *
4  *      Operations to dump MIB modules in the YANG output format.
5  *
6  * Copyright (c) 2007 J. Schoenwaelder, Jacobs University Bremen.
7  *
8  * See the file "COPYING" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * @(#) $Id: dump-yang.c 8090 2008-04-18 12:56:29Z strauss $
12  */
13 
14 #include <config.h>
15 
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include "smi.h"
21 #include "smidump.h"
22 #include "fprint.h"
23 #include "fortopat.h"
24 
25 /*
26  * TODO:
27  * - reproduce the table comment text as a yang comment
28  * - fix the format strings to xsd pattern algorithm so that it
29  *   produces more accurate results
30  * - compute proper boundaries for binary/string length restrictions
31  * - translate notifications properly (whatever that means ;-)
32  * - handle opaque in a reasonable way (test case AGGREGATE-MIB)
33  */
34 
35 static int sflag = 0;		/* generate smi: extensions */
36 static int nflag = 0;		/* generate notifications */
37 static int INDENT = 2;		/* indent factor */
38 
39 #define  INDENTVALUE	20   /* column to start values, except multiline */
40 #define	 URNBASE	"urn:ietf:params:xml:ns:yang:smiv2:"
41 
42 
43 #define FLAG_CONFIG_FALSE 0x01
44 
45 
46 static const char *convertType[] = {
47 
48     /*
49      * Translation of the SMIng built-in types to the YANG
50      * equivalents.
51      */
52 
53     "",		  "Integer32",   NULL,	     "int32",
54     "",		  "Integer64",   NULL,	     "int64",
55     "",		  "Unsigned32",  NULL,	     "uint32",
56     "",		  "Unsigned64",  NULL,	     "uint64",
57     "",		  "OctetString", NULL,	     "binary",
58     "",		  "Enumeration", NULL,	     "enumeration",
59     "",		  "Bits",	 NULL,	     "bits",
60     "",		  "ObjectIdentifier", "yang-types", "object-identifier",
61 
62     /*
63      * We want to do these translations as well in order to retire the
64      * SNMPv2-SMI module which is not really an SMIv2 module but part
65      * of the definition of SNMPv2-SMI itself.
66      */
67 
68     "SNMPv2-SMI", "Integer32",  NULL,        "int32",
69     "SNMPv2-SMI", "Integer64",  NULL,        "int64",
70     "SNMPv2-SMI", "Unsigned32", NULL,        "uint32",
71     "SNMPv2-SMI", "Opaque",    NULL,	     "binary",
72     "SNMPv2-SMI", "Counter32", "yang-types", "counter32",
73     "SNMPv2-SMI", "Counter64", "yang-types", "counter64",
74     "SNMPv2-SMI", "Gauge32",   "yang-types", "gauge32",
75     "SNMPv2-SMI", "TimeTicks", "yang-types", "timeticks",
76     "SNMPv2-SMI", "IpAddress", "inet-types", "ipv4-address",
77 
78     /*
79      * And we like to do the same for RFC1155-SMI definitions...
80      */
81 
82     "RFC1155-SMI", "Opaque",    NULL,	     "binary",
83     "RFC1155-SMI", "Counter",   "yang-types", "counter32",
84     "RFC1155-SMI", "Gauge",     "yang-types", "gauge32",
85     "RFC1155-SMI", "TimeTicks", "yang-types", "timeticks",
86     "RFC1155-SMI", "IpAddress", "inet-types", "ipv4-address",
87 
88     /*
89      * We also translate frequently used SNMPv2-TCs that have a YANG
90      * equivalent. Note that DateAndTime is slightly different from
91      * the ISO profile used by date-and-time.
92      */
93 
94     "SNMPv2-TC",  "PhysAddress", "yang-types", "phys-address",
95     "SNMPv2-TC",  "MacAddress",  "ieee-types", "mac-address",
96     "SNMPv2-TC",  "TimeStamp",   "yang-types", "timestamp",
97 
98     NULL, NULL, NULL, NULL
99 };
100 
101 
102 static const char *convertImport[] = {
103 
104     /*
105      * Things that are not types but removed from imports...
106      */
107 
108     "SNMPv2-SMI",  "MODULE-IDENTITY",    NULL, NULL,
109     "SNMPv2-SMI",  "OBJECT-IDENTITY",    NULL, NULL,
110     "SNMPv2-SMI",  "OBJECT-TYPE",        NULL, NULL,
111     "SNMPv2-SMI",  "NOTIFICATION-TYPE",  NULL, NULL,
112     "SNMPv2-SMI",  "mib-2",              NULL, NULL,
113     "SNMPv2-TC",   "TEXTUAL-CONVENTION", NULL, NULL,
114     "SNMPv2-CONF", "OBJECT-GROUP",       NULL, NULL,
115     "SNMPv2-CONF", "NOTIFICATION-GROUP", NULL, NULL,
116     "SNMPv2-CONF", "MODULE-COMPLIANCE",  NULL, NULL,
117     "SNMPv2-CONF", "AGENT-CAPABILITIES", NULL, NULL,
118     "SNMPv2-MIB",  "snmpTraps",	         NULL, NULL,
119 
120     NULL, NULL, NULL, NULL
121 };
122 
123 /*
124  * SMIv2 modules we never like to import from...
125  */
126 
127 static const char *ignoreImports[] = {
128     "RFC1155-SMI", "SNMPv2-SMI", "SNMPv2-CONF", NULL
129 };
130 
131 
132 /*
133  * Structure used to build a list of imported types.
134  */
135 
136 typedef struct Import {
137     char          *module;
138     char	  *prefix;
139     struct Import *nextPtr;
140 } Import;
141 
142 static Import *importList = NULL;
143 
144 static int silent = 0;
145 
146 
147 static char*
getStringStatus(SmiStatus status)148 getStringStatus(SmiStatus status)
149 {
150     return
151 	(status == SMI_STATUS_CURRENT)     ? "current" :
152 	(status == SMI_STATUS_DEPRECATED)  ? "deprecated" :
153 	(status == SMI_STATUS_OBSOLETE)    ? "obsolete" :
154 	(status == SMI_STATUS_MANDATORY)   ? "current" :
155 	(status == SMI_STATUS_OPTIONAL)    ? "current" :
156 					     "<unknown>";
157 }
158 
159 
160 static char*
getStringDate(time_t t)161 getStringDate(time_t t)
162 {
163     static char   s[27];
164     struct tm	  *tm;
165 
166     tm = gmtime(&t);
167     sprintf(s, "%04d-%02d-%02d",
168 	    tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
169     return s;
170 }
171 
172 
173 
174 static char*
getValueString(SmiValue * valuePtr,SmiType * typePtr)175 getValueString(SmiValue *valuePtr, SmiType *typePtr)
176 {
177     static char    s[1024];
178     char           ss[9];
179     int		   n;
180     unsigned int   i;
181     SmiNamedNumber *nn;
182     SmiNode        *nodePtr;
183 
184     s[0] = 0;
185 
186     switch (valuePtr->basetype) {
187     case SMI_BASETYPE_UNSIGNED32:
188 	sprintf(s, "%lu", valuePtr->value.unsigned32);
189 	break;
190     case SMI_BASETYPE_INTEGER32:
191 	sprintf(s, "%ld", valuePtr->value.integer32);
192 	break;
193     case SMI_BASETYPE_UNSIGNED64:
194 	sprintf(s, UINT64_FORMAT, valuePtr->value.unsigned64);
195 	break;
196     case SMI_BASETYPE_INTEGER64:
197 	sprintf(s, INT64_FORMAT, valuePtr->value.integer64);
198 	break;
199     case SMI_BASETYPE_FLOAT32:
200     case SMI_BASETYPE_FLOAT64:
201     case SMI_BASETYPE_FLOAT128:
202 	break;
203     case SMI_BASETYPE_ENUM:
204 	for (nn = smiGetFirstNamedNumber(typePtr); nn;
205 	     nn = smiGetNextNamedNumber(nn)) {
206 	    if (nn->value.value.unsigned32 == valuePtr->value.unsigned32)
207 		break;
208 	}
209 	if (nn) {
210 	    sprintf(s, "%s", nn->name);
211 	} else {
212 	    sprintf(s, "%ld", valuePtr->value.integer32);
213 	}
214 	break;
215     case SMI_BASETYPE_OCTETSTRING:
216 	for (i = 0; i < valuePtr->len; i++) {
217 	    if (!isprint((int)valuePtr->value.ptr[i])) break;
218 	}
219 	if (i == valuePtr->len) {
220 	    sprintf(s, "\"%s\"", valuePtr->value.ptr);
221 	} else {
222             sprintf(s, "0x%*s", 2 * valuePtr->len, "");
223             for (i=0; i < valuePtr->len; i++) {
224                 sprintf(ss, "%02x", valuePtr->value.ptr[i]);
225                 strncpy(&s[2+2*i], ss, 2);
226             }
227 	}
228 	break;
229     case SMI_BASETYPE_BITS:
230 	sprintf(s, "(");
231 	for (i = 0, n = 0; i < valuePtr->len * 8; i++) {
232 	    if (valuePtr->value.ptr[i/8] & (1 << i%8)) {
233 		if (n)
234 		    sprintf(&s[strlen(s)], ", ");
235 		n++;
236 		for (nn = smiGetFirstNamedNumber(typePtr); nn;
237 		     nn = smiGetNextNamedNumber(nn)) {
238 		    if (nn->value.value.unsigned32 == i)
239 			break;
240 		}
241 		if (nn) {
242 		    sprintf(&s[strlen(s)], "%s", nn->name);
243 		} else {
244 		    sprintf(s, "%d", i);
245 		}
246 	    }
247 	}
248 	sprintf(&s[strlen(s)], ")");
249 	break;
250     case SMI_BASETYPE_UNKNOWN:
251 	break;
252     case SMI_BASETYPE_POINTER:
253 	break;
254     case SMI_BASETYPE_OBJECTIDENTIFIER:
255 	nodePtr = smiGetNodeByOID(valuePtr->len, valuePtr->value.oid);
256 	if (nodePtr) {
257 	    sprintf(s, "%s", nodePtr->name);
258 	} else {
259 	    strcpy(s, "");
260 	    for (i=0; i < valuePtr->len; i++) {
261 		if (i) strcat(s, ".");
262 		sprintf(&s[strlen(s)], "%u", valuePtr->value.oid[i]);
263 	    }
264 	}
265 	break;
266     }
267 
268     return s;
269 }
270 
271 
272 static int
isPrefixUnique(const char * prefix)273 isPrefixUnique(const char *prefix)
274 {
275     Import *import;
276 
277     for (import = importList; import; import = import->nextPtr) {
278          if (strcmp(prefix, import->prefix) == 0) {
279              return 0;
280 	 }
281     }
282 
283     return 1;
284 }
285 
286 
287 static char*
guessNicePrefix(const char * moduleName)288 guessNicePrefix(const char *moduleName)
289 {
290     char *prefix;
291     int i, d;
292 
293     char *specials[] = {
294 	"yang-smi", "smi",
295 	"yang-types", "yang",
296 	"inet-types", "inet",
297 	"ieee-types", "ieee",
298 	"SNMPv2-TC", "smiv2",
299 	NULL, NULL
300     };
301 
302     for (i = 0; specials[i]; i +=2) {
303 	if (strcmp(moduleName, specials[i]) == 0) {
304             if (isPrefixUnique(specials[i+1])) {
305                 return xstrdup(specials[i+1]);
306 	    }
307 	}
308     }
309 
310     prefix = xstrdup(moduleName);
311     for (i = 0; prefix[i]; i++) {
312         prefix[i] = tolower(prefix[i]);
313     }
314 
315     for (i = 0, d = 0; prefix[i]; i++) {
316         if (prefix[i] == '-') {
317 	    d++;
318 	    if (d > 1) {
319 		prefix[i] = 0;
320 		if (isPrefixUnique(prefix)) {
321 		    return prefix;
322 		}
323 		prefix[i] = '-';
324 	    }
325 	}
326     }
327 
328     return prefix;
329 }
330 
331 
332 static const char*
getModulePrefix(const char * moduleName)333 getModulePrefix(const char *moduleName)
334 {
335     Import *import;
336     static char *prefix = NULL;
337 
338     for (import = importList; import; import = import->nextPtr) {
339         if (strcmp(moduleName, import->module) == 0) {
340             return import->prefix;
341 	}
342     }
343 
344     if (prefix) xfree(prefix);
345     prefix = guessNicePrefix(moduleName);
346     return prefix;
347 }
348 
349 
350 
351 static Import*
addImport(char * module,char * name)352 addImport(char *module, char *name)
353 {
354     Import **import, *newImport;
355 
356     if (!module || !name) {
357 	return NULL;
358     }
359 
360     for (import = &importList; *import; import = &(*import)->nextPtr) {
361 	int c = strcmp((*import)->module, module);
362 	if (c == 0) return *import;
363 	if (c > 0) break;
364     }
365 
366     newImport = xmalloc(sizeof(Import));
367     newImport->module = module;
368     newImport->prefix = guessNicePrefix(module);
369 
370     newImport->nextPtr = *import;
371     *import = newImport;
372 
373     return *import;
374 }
375 
376 
377 
378 static void
createImportList(SmiModule * smiModule)379 createImportList(SmiModule *smiModule)
380 {
381     SmiImport   *smiImport;
382     SmiIdentifier impModule, impName;
383     SmiType	*smiType;
384     SmiNode	*smiNode;
385     int i;
386 
387     for (smiImport = smiGetFirstImport(smiModule); smiImport;
388 	 smiImport = smiGetNextImport(smiImport)) {
389 
390 	impModule = smiImport->module;
391 	impName = smiImport->name;
392 
393 	for (i = 0; convertType[i]; i += 4) {
394 	    if (strcmp(smiImport->module, convertType[i]) == 0
395 		&& strcmp(smiImport->name, convertType[i+1]) == 0) {
396 		impModule = (SmiIdentifier) convertType[i+2];
397 		impName = (SmiIdentifier) convertType[i+3];
398 		break;
399 	    }
400 	}
401 
402 	if (! impModule || ! impName) continue;
403 
404 	for (i = 0; convertImport[i]; i += 4) {
405 	    if (strcmp(smiImport->module, convertImport[i]) == 0
406 		&& strcmp(smiImport->name, convertImport[i+1]) == 0) {
407 		impModule = (SmiIdentifier) convertImport[i+2];
408 		impName = (SmiIdentifier) convertImport[i+3];
409 		break;
410 	    }
411 	}
412 
413 	if (! impModule || ! impName) continue;
414 #if 0
415 	fprintf(stderr, "%s\t%s\n", impModule, impName);
416 #endif
417 	addImport(impModule, impName);
418     }
419 
420     /*
421      * Add import for the smi:oid extension and friends.
422      */
423 
424     if (sflag) {
425 	addImport("yang-smi", "oid");
426     }
427 
428     /*
429      * Add import for yang-types that were originally ASN.1
430      * builtins...
431      */
432 
433     for (smiType = smiGetFirstType(smiModule);
434 	 smiType; smiType = smiGetNextType(smiType)) {
435 	SmiType *parentType = smiGetParentType(smiType);
436 	if (parentType && strcmp(parentType->name, "ObjectIdentifier") == 0) {
437 	    addImport("yang-types", "object-identifier");
438 	}
439     }
440 
441     for (smiNode = smiGetFirstNode(smiModule,
442 				   SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN);
443 	 smiNode;
444 	 smiNode = smiGetNextNode(smiNode,
445 				  SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN)) {
446 	smiType = smiGetNodeType(smiNode);
447 	if (! smiType->name) {
448 	    smiType = smiGetParentType(smiType);
449 	}
450 	if (smiType && strcmp(smiType->name, "ObjectIdentifier") == 0) {
451 	    addImport("yang-types", "object-identifier");
452 	}
453     }
454 }
455 
456 
457 
458 static void
freeImportList(void)459 freeImportList(void)
460 {
461     Import *import, *freeme;
462 
463     for (import = importList; import; ) {
464         xfree(import->prefix);
465 	freeme = import;
466 	import = import->nextPtr;
467 	xfree(freeme);
468     }
469     importList = NULL;
470 }
471 
472 
473 
474 static int
isGroup(SmiNode * smiNode)475 isGroup(SmiNode *smiNode)
476 {
477     SmiNode *childNode;
478 
479     for(childNode = smiGetFirstChildNode(smiNode);
480 	childNode;
481 	childNode = smiGetNextChildNode(childNode)) {
482 	if ((childNode->nodekind == SMI_NODEKIND_SCALAR
483 	     || childNode->nodekind == SMI_NODEKIND_TABLE)
484 	    && childNode->status == SMI_STATUS_CURRENT) {
485 	    return 1;
486 	}
487     }
488 
489     return 0;
490 }
491 
492 
493 static int
isIndex(SmiNode * groupNode,SmiNode * smiNode)494 isIndex(SmiNode *groupNode, SmiNode *smiNode)
495 {
496     SmiElement *smiElement;
497     int cnt = 0;
498 
499     /*
500      * We return an indication whether smiNode is part of an index. In
501      * fact, we return number of times smiNode is part of an index
502      * since we sometimes have to disambiguate names...
503      */
504 
505     for (smiElement = smiGetFirstElement(groupNode);
506 	 smiElement; smiElement = smiGetNextElement(smiElement)) {
507 	if (smiNode == smiGetElementNode(smiElement)) {
508 	    cnt++;
509 	}
510     }
511 
512     return cnt;
513 }
514 
515 
516 static void
fprintRevisions(FILE * f,int indent,SmiModule * smiModule)517 fprintRevisions(FILE *f, int indent, SmiModule *smiModule)
518 {
519     int i;
520     SmiRevision *smiRevision;
521 
522     for(i = 0, smiRevision = smiGetFirstRevision(smiModule);
523 	smiRevision; smiRevision = smiGetNextRevision(smiRevision)) {
524 	fprintSegment(f, indent, "revision ", 0);
525 	fprint(f, "\"%s\" {\n", getStringDate(smiRevision->date));
526 	fprintSegment(f, 2 * indent, "description", INDENTVALUE);
527 	fprint(f, "\n");
528 	fprintMultilineString(f, 2 * indent, smiRevision->description);
529 	fprint(f, ";\n");
530         fprintSegment(f, indent, "}\n", 0);
531 	i++;
532     }
533     if (i) {
534 	fprint(f, "\n");
535     }
536 }
537 
538 
539 static void
fprintImports(FILE * f,SmiModule * smiModule)540 fprintImports(FILE *f, SmiModule *smiModule)
541 {
542     Import *import;
543     int i, len = 4;
544 
545     for (import = importList; import; import = import->nextPtr) {
546 	for (i = 0; ignoreImports[i]; i++) {
547 	    if (strcmp(ignoreImports[i], import->module) == 0) {
548 		break;
549 	    }
550 	}
551 	if (ignoreImports[i] == NULL) {
552 	    if (strlen(import->module) > len) len = strlen(import->module);
553 	}
554     }
555 
556     for (import = importList; import; import = import->nextPtr) {
557 	for (i = 0; ignoreImports[i]; i++) {
558 	    if (strcmp(ignoreImports[i], import->module) == 0) {
559 		break;
560 	    }
561 	}
562 	if (ignoreImports[i] == NULL) {
563 	    fprintSegment(f, INDENT, "import", 0);
564 	    fprint(f, " %-*s { prefix \"%s\"; }\n", len,
565 		   import->module, import->prefix);
566 	}
567     }
568     fprint(f, "\n");
569 
570 }
571 
572 
573 
574 
575 static void
fprintSubtype(FILE * f,int indent,SmiType * smiType)576 fprintSubtype(FILE *f, int indent, SmiType *smiType)
577 {
578     SmiRange       *range;
579     SmiNamedNumber *nn;
580     char	   s[1024];
581     char	   *tkw, *lkw, *vkw;
582     int		   i = 0;
583     int		   len = 4;
584 
585     if ((smiType->basetype == SMI_BASETYPE_ENUM) ||
586 	(smiType->basetype == SMI_BASETYPE_BITS)) {
587 	for (nn = smiGetFirstNamedNumber(smiType);
588 	     nn ; nn = smiGetNextNamedNumber(nn)) {
589 	    if (strlen(nn->name) > len) len = strlen(nn->name);
590 	}
591 
592 	for(i = 0, nn = smiGetFirstNamedNumber(smiType);
593 	    nn ; i++, nn = smiGetNextNamedNumber(nn)) {
594 	    if (! i) {
595 		fprint(f, " {\n");
596 	    }
597 	    tkw = (smiType->basetype == SMI_BASETYPE_BITS) ? "bits" : "enumeration";
598 	    lkw = (smiType->basetype == SMI_BASETYPE_BITS) ? "bit" : "enum";
599 	    vkw = (smiType->basetype == SMI_BASETYPE_BITS) ? "position" : "value";
600 	    sprintf(s, "%s %-*s { %s %s; }\n",
601 		    lkw, len, nn->name,
602 		    vkw, getValueString(&nn->value, smiType));
603 	    fprintSegment(f, indent + INDENT, s, 0);
604 	}
605     } else {
606 	for(i = 0, range = smiGetFirstRange(smiType);
607 	    range ; i++, range = smiGetNextRange(range)) {
608 	    if (i) {
609 		fprint(f, " | ");
610 	    } else {
611 		fprint(f, " {\n");
612 		if (smiType->basetype == SMI_BASETYPE_OCTETSTRING) {
613 		    fprintSegment(f, indent + INDENT, "length \"", 0);
614 		} else {
615 		    fprintSegment(f, indent + INDENT, "range \"", 0);
616 		}
617 	    }
618 	    if (memcmp(&range->minValue, &range->maxValue,
619 		       sizeof(SmiValue))) {
620 		sprintf(s, "%s", getValueString(&range->minValue, smiType));
621 		sprintf(&s[strlen(s)], "..%s",
622 			getValueString(&range->maxValue, smiType));
623 	    } else {
624 		sprintf(s, "%s", getValueString(&range->minValue, smiType));
625 	    }
626 	    fprint(f, s);
627 	}
628 	if (i) {
629 	    fprint(f, "\";\n");
630 	}
631     }
632 
633     if (smiType->format
634 	&& smiType->basetype == SMI_BASETYPE_OCTETSTRING) {
635 
636 	char *pattern;
637 	pattern = smiFormatToPattern(smiType->format,
638 				     smiGetFirstRange(smiType));
639 	if (pattern) {
640 	    if (! i) {
641 		fprint(f, "{\n");
642 	    }
643 	    fprintSegment(f, indent + INDENT, "pattern \"", 0);
644 	    fprint(f, "%s\";\n", pattern);
645 	    xfree(pattern);
646 	    i++;
647 	}
648     }
649 
650     if (! i) {
651 	fprint(f, ";\n");
652     } else {
653 	fprintSegment(f, indent, "}\n", 0);
654     }
655 }
656 
657 
658 static void
fprintStatus(FILE * f,int indent,SmiStatus status)659 fprintStatus(FILE *f, int indent, SmiStatus status)
660 {
661     if ((status != SMI_STATUS_CURRENT) &&
662 	(status != SMI_STATUS_UNKNOWN) &&
663 	(status != SMI_STATUS_MANDATORY) &&
664 	(status != SMI_STATUS_OPTIONAL)) {
665 	fprintSegment(f, indent, "status", 0);
666 	fprint(f, " %s;\n", getStringStatus(status));
667     }
668 }
669 
670 
671 static void
fprintUnits(FILE * f,int indent,const char * units)672 fprintUnits(FILE *f, int indent, const char *units)
673 {
674     if (units) {
675 	fprintSegment(f, indent, "units", 0);
676 	fprint(f, " \"%s\";\n", units);
677     }
678 }
679 
680 
681 static void
fprintFormat(FILE * f,int indent,const char * format)682 fprintFormat(FILE *f, int indent, const char *format)
683 {
684     if (sflag && format) {
685 	fprintSegment(f, 2 * INDENT, "smi:display-hint", 0);
686 	fprint(f, " \"%s\";\n", format);
687     }
688 }
689 
690 
691 static void
fprintObjectIdentifier(FILE * f,int indent,SmiSubid * oid,int oidlen)692 fprintObjectIdentifier(FILE *f, int indent, SmiSubid *oid, int oidlen)
693 {
694     int i;
695 
696     if (sflag && oid && oidlen) {
697 	fprintSegment(f, indent, "smi:oid", 0);
698 	fprint(f, " \"");
699 	for (i=0; i < oidlen; i++) {
700 	    fprint(f, "%s%d", i ? "." : "", oid[i]);
701 	}
702 	fprint(f, "\";\n");
703     }
704 }
705 
706 
707 static void
fprintDescription(FILE * f,int indent,const char * description)708 fprintDescription(FILE *f, int indent, const char *description)
709 {
710     if (description) {
711 	fprintSegment(f, indent, "description", INDENTVALUE);
712 	fprint(f, "\n");
713 	fprintMultilineString(f, indent, description);
714 	fprint(f, ";\n");
715     }
716 }
717 
718 
719 static void
fprintReference(FILE * f,int indent,const char * reference)720 fprintReference(FILE *f, int indent, const char *reference)
721 {
722     if (reference) {
723 	fprintSegment(f, indent, "reference", INDENTVALUE);
724 	fprint(f, "\n");
725 	fprintMultilineString(f, indent, reference);
726 	fprint(f, ";\n");
727     }
728 }
729 
730 
731 static void
fprintConfig(FILE * f,int indent,SmiAccess access)732 fprintConfig(FILE *f, int indent, SmiAccess access)
733 {
734     if (access == SMI_ACCESS_READ_WRITE) {
735 	fprintSegment(f, indent, "config true;\n", 0);
736     } else {
737 	fprintSegment(f, indent, "config false;\n", 0);
738     }
739 }
740 
741 
742 static void
fprintDefault(FILE * f,int indent,SmiValue * value,SmiType * smiType)743 fprintDefault(FILE *f, int indent, SmiValue *value, SmiType *smiType)
744 {
745     if (sflag && value->basetype != SMI_BASETYPE_UNKNOWN) {
746 	fprintSegment(f, indent, "smi:default", 0);
747 	fprint(f, " \"%s\";\n", getValueString(value, smiType));
748     }
749 }
750 
751 
752 static int
fprintTypename(FILE * f,SmiType * smiType,int format)753 fprintTypename(FILE *f, SmiType *smiType, int format)
754 {
755     const char *typeModule = NULL, *typeName = NULL;
756     SmiModule *smiModule;
757     int i;
758 
759     if (! smiType) return 0;
760 
761     smiModule = smiGetTypeModule(smiType);
762 
763     if (smiType && ! smiType->name) {
764 	return fprintTypename(f, smiGetParentType(smiType), format);
765     }
766 
767     for (i = 0; convertType[i]; i += 4) {
768 	if (strcmp(smiModule->name, convertType[i]) == 0
769 	    && strcmp(smiType->name, convertType[i+1]) == 0) {
770 	    typeModule = convertType[i+2];
771 	    typeName = convertType[i+3];
772 	    break;
773 	}
774     }
775 
776     if (! typeName) {
777 	typeModule = smiModule->name;
778 	typeName = smiType->name;
779     }
780 
781     if (typeModule) {
782 	typeModule = getModulePrefix(typeModule);
783     }
784 
785     /*
786      * We handle a special case here. If we have a format string and
787      * the type is binary, we turn it into string.
788      */
789 
790     if (! typeModule && typeName && strcmp(typeName, "binary") == 0) {
791 	if (format) {
792 	    typeName = "string";
793 	}
794     }
795 
796     if (typeModule && typeName) {
797 	fprint(f, "%s:%s", typeModule, typeName);
798     } else {
799 	fprint(f, "%s", typeName);
800     }
801 
802     return 1;
803 }
804 
805 
806 static void
fprintTypedefs(FILE * f,SmiModule * smiModule)807 fprintTypedefs(FILE *f, SmiModule *smiModule)
808 {
809     int		 i;
810     SmiType	 *smiType, *baseType;
811 
812     for (i = 0, smiType = smiGetFirstType(smiModule);
813 	 smiType; smiType = smiGetNextType(smiType)) {
814 
815 	baseType = smiGetParentType(smiType);
816 
817 	if (!i && !silent) {
818 	    fprintSegment(f, INDENT, "/*** TYPE DEFINITIONS ***/\n\n", 0);
819 	}
820 	fprintSegment(f, INDENT, "", 0);
821 	fprint(f, "typedef %s {\n", smiType->name);
822 
823 	fprintSegment(f, 2 * INDENT, "type ", 0);
824 	fprintTypename(f, baseType, smiType->format != NULL);
825 	fprintSubtype(f, 2 * INDENT, smiType);
826 
827 	fprintUnits(f, 2 * INDENT, smiType->units);
828 	fprintStatus(f, 2 * INDENT, smiType->status);
829 	fprintDescription(f, 2 * INDENT, smiType->description);
830 	fprintReference(f, 2 * INDENT, smiType->reference);
831 	fprintFormat(f, 2 * INDENT, smiType->format);
832 	fprintDefault(f, 2 * INDENT, &smiType->value, smiType);
833 
834 	fprintSegment(f, INDENT, "}\n\n", 0);
835 	i++;
836     }
837 }
838 
839 
840 static void
fprintPath(FILE * f,SmiNode * smiNode)841 fprintPath(FILE *f, SmiNode *smiNode)
842 {
843      SmiNode *entryNode = NULL;
844      SmiNode *tableNode = NULL;
845      SmiNode *contNode = NULL;
846      SmiModule *smiModule = NULL;
847 
848      switch (smiNode->nodekind) {
849      case SMI_NODEKIND_SCALAR:
850 	     contNode = smiGetParentNode(smiNode);
851 	     break;
852      case SMI_NODEKIND_COLUMN:
853 	     entryNode = smiGetParentNode(smiNode);
854 	     tableNode = smiGetParentNode(entryNode);
855 	     contNode = smiGetParentNode(tableNode);
856 	     break;
857      case SMI_NODEKIND_ROW:
858 	     entryNode = smiNode;
859 	     tableNode = smiGetParentNode(entryNode);
860 	     contNode = smiGetParentNode(tableNode);
861 	     break;
862      case SMI_NODEKIND_TABLE:
863 	     contNode = smiGetParentNode(tableNode);
864 	     break;
865      default:
866 	     break;
867      }
868 
869      smiModule = smiGetNodeModule(contNode);
870      if (smiModule) {
871          fprint(f, "/%s:%s", getModulePrefix(smiModule->name), contNode->name);
872      }
873      if (contNode == smiNode) return;
874 
875      if (entryNode) {
876 	 smiModule = smiGetNodeModule(entryNode);
877 	 if (smiModule) {
878 	     fprint(f, "/%s:%s", getModulePrefix(smiModule->name), entryNode->name);
879 	 }
880 	 if (entryNode == smiNode) return;
881      }
882 
883      smiModule = smiGetNodeModule(smiNode);
884      if (smiModule) {
885          fprint(f, "/%s:%s", getModulePrefix(smiModule->name), smiNode->name);
886      }
887 }
888 
889 
890 static void
fprintLeaf(FILE * f,int indent,SmiNode * smiNode,int flags)891 fprintLeaf(FILE *f, int indent, SmiNode *smiNode, int flags)
892 {
893     SmiType *smiType;
894     SmiAccess config;
895 
896     smiType = smiGetNodeType(smiNode);
897 
898     fprintSegment(f, indent, "leaf ", 0);
899     fprint(f, "%s {\n", smiNode->name);
900 
901     fprintSegment(f, indent + INDENT, "type ", 0);
902     fprintTypename(f, smiType, smiNode->format != NULL);
903     if (! smiType->name) {
904 	fprintSubtype(f, indent + INDENT, smiType);
905     } else {
906 	fprint(f, ";\n");
907     }
908 
909     fprintUnits(f, indent + INDENT, smiNode->units);
910     if (flags & FLAG_CONFIG_FALSE) {
911 	config = SMI_ACCESS_READ_ONLY;
912     } else {
913 	config = smiNode->access;
914     }
915     fprintConfig(f, indent + INDENT, config);
916     fprintStatus(f, indent + INDENT, smiNode->status);
917     fprintDescription(f, indent + INDENT, smiNode->description);
918     fprintReference(f, indent + INDENT, smiNode->reference);
919     fprintFormat(f, indent + INDENT, smiNode->format);
920     fprintDefault(f, indent + INDENT, &smiNode->value, smiType);
921     fprintObjectIdentifier(f, indent + INDENT, smiNode->oid, smiNode->oidlen);
922     fprintSegment(f, indent, "}\n", 0);
923 }
924 
925 
926 static void
fprintKeyrefLeaf(FILE * f,int indent,SmiNode * smiNode,int flags)927 fprintKeyrefLeaf(FILE *f, int indent, SmiNode *smiNode, int flags)
928 {
929     SmiNode *entryNode;
930     SmiAccess config;
931 
932     entryNode = smiGetParentNode(smiNode);
933     fprintSegment(f, indent, "leaf ", 0);
934     fprint(f, "%s {\n", smiNode->name);
935     fprintSegment(f, indent + INDENT, "type keyref {\n", 0);
936     fprintSegment(f, indent + 2 * INDENT, "path \"", 0);
937     fprintPath(f, smiNode);
938     fprint(f, "\";\n");
939     fprintSegment(f, indent + INDENT, "}\n", 0);
940     if (flags & FLAG_CONFIG_FALSE) {
941 	config = SMI_ACCESS_READ_ONLY;
942     } else {
943 	config = entryNode->create
944 	    ? SMI_ACCESS_READ_WRITE : SMI_ACCESS_READ_ONLY;
945     }
946     fprintConfig(f, indent + INDENT, config);
947     fprintStatus(f, indent + INDENT, smiNode->status);
948     fprintDescription(f, indent + INDENT,
949 		      "Automagically generated keyref leaf.");
950     fprintSegment(f, indent, "}\n", 0);
951 }
952 
953 
954 static void
fprintKey(FILE * f,int indent,SmiNode * smiNode)955 fprintKey(FILE *f, int indent, SmiNode *smiNode)
956 {
957     SmiElement *smiElement;
958     int j;
959 
960     fprintSegment(f, indent, "key \"", 0);
961 
962     for (j = 0, smiElement = smiGetFirstElement(smiNode); smiElement;
963 	 j++, smiElement = smiGetNextElement(smiElement)) {
964         if (j) {
965             fprint(f, " ");
966 	}
967 	fprintWrapped(f, indent + 5,
968 		      smiGetElementNode(smiElement)->name);
969     }
970     fprint(f, "\";\n");
971 }
972 
973 
974 static void
fprintLeafs(FILE * f,int indent,SmiNode * smiNode)975 fprintLeafs(FILE *f, int indent, SmiNode *smiNode)
976 {
977     SmiNode *childNode;
978     int c;
979 
980     for (c = 0, childNode = smiGetFirstChildNode(smiNode);
981 	 childNode;
982 	 childNode = smiGetNextChildNode(childNode)) {
983 	if (childNode->nodekind == SMI_NODEKIND_COLUMN) {
984 	    fprint(f, "\n");
985 	    fprintLeaf(f, indent, childNode, 0);
986 	    c++;
987 	}
988     }
989 }
990 
991 
992 static void
fprintList(FILE * f,int indent,SmiNode * smiNode)993 fprintList(FILE *f, int indent, SmiNode *smiNode)
994 {
995     SmiNode *entryNode;
996     SmiNode *childNode;
997     SmiNode *parentNode;
998     SmiElement *smiElement;
999 
1000     entryNode = smiGetFirstChildNode(smiNode);
1001 
1002     fprint(f, "\n");
1003     fprintSegment(f, indent, "/* XXX table comments here XXX */\n", 0);
1004     fprint(f, "\n");
1005 
1006     fprintSegment(f, indent, "list", 0);
1007     fprint(f, " %s {\n\n", entryNode->name);
1008 
1009     fprintKey(f, indent + INDENT, entryNode);
1010     fprintStatus(f, indent + INDENT, entryNode->status);
1011     fprintDescription(f, indent + INDENT, entryNode->description);
1012     fprintReference(f, indent + INDENT, entryNode->reference);
1013     fprintObjectIdentifier(f, indent + INDENT,
1014 			   entryNode->oid, entryNode->oidlen);
1015     fprint(f, "\n");
1016 
1017     for (smiElement = smiGetFirstElement(entryNode); smiElement;
1018 	 smiElement = smiGetNextElement(smiElement)) {
1019 	childNode = smiGetElementNode(smiElement);
1020 	parentNode = smiGetParentNode(childNode);
1021         if (childNode->nodekind == SMI_NODEKIND_COLUMN
1022             && parentNode != entryNode) {
1023 	    fprintKeyrefLeaf(f, indent + INDENT, childNode, 0);
1024 	}
1025     }
1026 
1027     fprintLeafs(f, indent + INDENT, entryNode);
1028 
1029     fprintSegment(f, indent, "}\n", 0);
1030 }
1031 
1032 
1033 static void
fprintAugment(FILE * f,int indent,SmiNode * smiNode)1034 fprintAugment(FILE *f, int indent, SmiNode *smiNode)
1035 {
1036     SmiNode *baseEntryNode = NULL;
1037 
1038     if (smiNode) {
1039         baseEntryNode = smiGetRelatedNode(smiNode);
1040     }
1041     if (! smiNode || ! baseEntryNode) {
1042         return;
1043     }
1044 
1045     fprint(f, "\n");
1046     fprintSegment(f, indent, "/* XXX table comments here XXX */\n", 0);
1047     fprint(f, "\n");
1048 
1049     fprintSegment(f, indent, "augment", 0);
1050     fprint(f, " \"");
1051     fprintPath(f, baseEntryNode);
1052     fprint(f, "\" {\n");
1053     fprintStatus(f, indent + INDENT, smiNode->status);
1054     fprintDescription(f, indent + INDENT, smiNode->description);
1055     fprintReference(f, indent + INDENT, smiNode->reference);
1056 
1057     fprintLeafs(f, indent + INDENT, smiNode);
1058     fprintObjectIdentifier(f, indent + INDENT,
1059 			   smiNode->oid, smiNode->oidlen);
1060     fprintSegment(f, indent, "}\n\n", 0);
1061 }
1062 
1063 
1064 static void
fprintAugments(FILE * f,SmiModule * smiModule)1065 fprintAugments(FILE *f, SmiModule *smiModule)
1066 {
1067     SmiNode *smiNode;
1068 
1069     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
1070 	smiNode;
1071 	smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
1072 	if (smiNode->nodekind == SMI_NODEKIND_ROW
1073 	    && smiNode->indexkind == SMI_INDEX_AUGMENT) {
1074 	    fprintAugment(f, INDENT, smiNode);
1075 	}
1076     }
1077 
1078 }
1079 
1080 
1081 static void
fprintContainer(FILE * f,int indent,SmiNode * smiNode)1082 fprintContainer(FILE *f, int indent, SmiNode *smiNode)
1083 {
1084     SmiNode *childNode;
1085     int c;
1086 
1087     fprintSegment(f, indent, "container", 0);
1088     fprint(f, " %s {\n\n", smiNode->name);
1089 
1090     for (c = 0, childNode = smiGetFirstChildNode(smiNode);
1091 	 childNode;
1092 	 childNode = smiGetNextChildNode(childNode)) {
1093 	if (c) {
1094 	    fprint(f, "\n");
1095 	}
1096 	if (childNode->nodekind == SMI_NODEKIND_SCALAR) {
1097 	    fprintLeaf(f, indent + INDENT, childNode, 0);
1098 	    c++;
1099 	}
1100 	if (childNode->nodekind == SMI_NODEKIND_TABLE) {
1101 	    SmiNode *entryNode = smiGetFirstChildNode(childNode);
1102 	    if (entryNode) {
1103 	        switch (entryNode->indexkind) {
1104 		case SMI_INDEX_INDEX:
1105 		case SMI_INDEX_REORDER:
1106 		case SMI_INDEX_SPARSE:
1107 		case SMI_INDEX_EXPAND:
1108 			fprintList(f, indent + INDENT, childNode);
1109 			c++;
1110 			break;
1111 #if 0
1112 		case SMI_INDEX_AUGMENT:
1113 			fprintAugment(f, indent + INDENT, childNode);
1114 			c++;
1115 			break;
1116 #endif
1117 		default:
1118 			break;
1119 		}
1120 	    }
1121 	}
1122     }
1123 
1124     fprintObjectIdentifier(f, indent + INDENT,
1125 			   smiNode->oid, smiNode->oidlen);
1126 
1127     fprintSegment(f, indent, "}\n\n", 0);
1128 }
1129 
1130 
1131 static void
fprintContainers(FILE * f,SmiModule * smiModule)1132 fprintContainers(FILE *f, SmiModule *smiModule)
1133 {
1134     SmiNode *smiNode;
1135 
1136     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
1137 	smiNode;
1138 	smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
1139 	if (isGroup(smiNode)) {
1140 	    fprintContainer(f, INDENT, smiNode);
1141 	}
1142     }
1143 }
1144 
1145 
1146 static void
fprintNamespace(FILE * f,int indent,SmiModule * smiModule)1147 fprintNamespace(FILE *f, int indent, SmiModule *smiModule)
1148 {
1149      if (! silent) {
1150 	  fprintSegment(f, indent, "/*** NAMESPACE / PREFIX DEFINITION ***/\n\n", 0);
1151      }
1152 
1153      fprintSegment(f, indent, "namespace ", 0);
1154      fprint(f, "\"%s%s\";\n", URNBASE, smiModule->name);
1155      fprintSegment(f, indent, "prefix ", 0);
1156      fprint(f, "\"%s\";\n\n", getModulePrefix(smiModule->name));
1157 }
1158 
1159 
1160 static void
fprintLinkage(FILE * f,int indent,SmiModule * smiModule)1161 fprintLinkage(FILE *f, int indent, SmiModule *smiModule)
1162 {
1163      if (! silent) {
1164 	  fprintSegment(f, indent, "/*** LINKAGE (IMPORTS / INCLUDES) ***/\n\n", 0);
1165      }
1166      fprintImports(f, smiModule);
1167 }
1168 
1169 
1170 static void
fprintMeta(FILE * f,int indent,SmiModule * smiModule)1171 fprintMeta(FILE *f, int indent, SmiModule *smiModule)
1172 {
1173      if (! silent) {
1174 	  fprintSegment(f, indent, "/*** META INFORMATION ***/\n\n", 0);
1175      }
1176      fprintSegment(f, indent, "organization", INDENTVALUE);
1177      fprint(f, "\n");
1178      fprintMultilineString(f, indent, smiModule->organization);
1179      fprint(f, ";\n\n");
1180      fprintSegment(f, indent, "contact", INDENTVALUE);
1181      fprint(f, "\n");
1182      fprintMultilineString(f, indent, smiModule->contactinfo);
1183      fprint(f, ";\n\n");
1184      fprintSegment(f, indent, "description", INDENTVALUE);
1185      fprint(f, "\n");
1186      fprintMultilineString(f, indent, smiModule->description);
1187      fprint(f, ";\n\n");
1188      if (smiModule->reference) {
1189 	  fprintSegment(f, indent, "reference", INDENTVALUE);
1190 	  fprint(f, "\n");
1191 	  fprintMultilineString(f, indent, smiModule->reference);
1192 	  fprint(f, ";\n\n");
1193      }
1194 }
1195 
1196 
1197 static void
fprintNotificationIndex(FILE * f,int indent,SmiNode * entryNode,SmiNode * ignoreNode)1198 fprintNotificationIndex(FILE *f, int indent,
1199 			SmiNode *entryNode, SmiNode *ignoreNode)
1200 {
1201     SmiElement *smiElement;
1202     SmiNode *childNode;
1203     SmiNode *parentNode;
1204 
1205     for (smiElement = smiGetFirstElement(entryNode); smiElement;
1206 	 smiElement = smiGetNextElement(smiElement)) {
1207 	childNode = smiGetElementNode(smiElement);
1208 	parentNode = smiGetParentNode(childNode);
1209 	if (childNode != ignoreNode) {
1210 	    fprintKeyrefLeaf(f, indent, childNode, FLAG_CONFIG_FALSE);
1211 	}
1212     }
1213 }
1214 
1215 
1216 static int
GetPosition(SmiElement * startElement,SmiElement * thisElement)1217 GetPosition(SmiElement *startElement, SmiElement *thisElement)
1218 {
1219     SmiElement *smiElement;
1220     SmiNode *smiNode;
1221     SmiNode *thisNode = smiGetElementNode(thisElement);
1222     int cnt = 0;
1223 
1224     for (smiElement = startElement, cnt = 0;
1225 	 smiElement; smiElement = smiGetNextElement(smiElement)) {
1226 	smiNode = smiGetElementNode(smiElement);
1227 	if (smiNode == thisNode) cnt++;
1228     }
1229 
1230     if (cnt <= 1) {
1231 	return 0;
1232     }
1233 
1234     for (smiElement = startElement, cnt = 0;
1235 	 smiElement; smiElement = smiGetNextElement(smiElement)) {
1236 	smiNode = smiGetElementNode(smiElement);
1237 	if (smiNode == thisNode) cnt++;
1238 	if (smiElement == thisElement) {
1239 	    break;
1240 	}
1241     }
1242     return cnt;
1243 }
1244 
1245 
1246 static void
fprintNotification(FILE * f,SmiNode * smiNode)1247 fprintNotification(FILE *f, SmiNode *smiNode)
1248 {
1249     SmiElement *smiElement;
1250     SmiNode *vbNode, *entryNode;
1251     int c, cnt;
1252 
1253     fprintSegment(f, INDENT, "notification", 0);
1254     fprint(f, " %s {\n", smiNode->name);
1255     fprintStatus(f, INDENT + INDENT, smiNode->status);
1256     fprintDescription(f, INDENT + INDENT, smiNode->description);
1257     fprintReference(f, INDENT + INDENT, smiNode->reference);
1258     fprintObjectIdentifier(f, INDENT + INDENT, smiNode->oid, smiNode->oidlen);
1259     fprint(f, "\n");
1260 
1261     for (c = 0, smiElement = smiGetFirstElement(smiNode); smiElement;
1262 	 c++, smiElement = smiGetNextElement(smiElement)) {
1263 	vbNode = smiGetElementNode(smiElement);
1264 	if (! vbNode) continue;
1265 
1266 	cnt = GetPosition(smiGetFirstElement(smiNode), smiElement);
1267 
1268 	entryNode = (vbNode->nodekind == SMI_NODEKIND_COLUMN)
1269 	    ? smiGetParentNode(vbNode) : NULL;
1270 
1271 	fprintSegment(f, INDENT + INDENT, "container ", 0);
1272 	if (cnt) {
1273 	    fprintf(f, "%s-%s-%d {\n", smiNode->name, vbNode->name, cnt);
1274 	} else {
1275 	    fprintf(f, "%s-%s {\n", smiNode->name, vbNode->name);
1276 	}
1277 
1278 	if (entryNode) {
1279 	    switch (entryNode->indexkind) {
1280 	    case SMI_INDEX_INDEX:
1281 		fprintNotificationIndex(f, INDENT + INDENT + INDENT,
1282 					entryNode, vbNode);
1283 		break;
1284 	    case SMI_INDEX_AUGMENT:
1285 		fprintNotificationIndex(f, INDENT + INDENT + INDENT,
1286 					smiGetRelatedNode(entryNode), vbNode);
1287 		break;
1288 	    default:
1289 		break;
1290 	    }
1291 	}
1292 
1293 	if (entryNode && isIndex(entryNode, vbNode)) {
1294 	    fprintKeyrefLeaf(f, INDENT + INDENT + INDENT,
1295 			     vbNode, FLAG_CONFIG_FALSE);
1296 	} else {
1297 	    fprintLeaf(f, INDENT + INDENT + INDENT,
1298 		       vbNode, FLAG_CONFIG_FALSE);
1299 	}
1300 	fprintSegment(f, INDENT + INDENT, "}\n\n", 0);
1301     }
1302 
1303     fprintSegment(f, INDENT, "}\n", 0);
1304 }
1305 
1306 
1307 static void
fprintNotifications(FILE * f,SmiModule * smiModule)1308 fprintNotifications(FILE *f, SmiModule *smiModule)
1309 {
1310     SmiNode *smiNode;
1311     int c;
1312 
1313     for (c = 0, smiNode = smiGetFirstNode(smiModule,
1314 					  SMI_NODEKIND_NOTIFICATION);
1315 	 smiNode;
1316 	 c++, smiNode = smiGetNextNode(smiNode,
1317 				       SMI_NODEKIND_NOTIFICATION)) {
1318 	if (c) {
1319 	    fprint(f, "\n");
1320 	}
1321 	fprintNotification(f, smiNode);
1322     }
1323 }
1324 
1325 
1326 static void
dumpYang(int modc,SmiModule ** modv,int flags,char * output)1327 dumpYang(int modc, SmiModule **modv, int flags, char *output)
1328 {
1329     SmiModule   *smiModule;
1330     int		i;
1331     FILE	*f = stdout;
1332 
1333     silent = (flags & SMIDUMP_FLAG_SILENT);
1334 
1335     fprint_indent_texts = INDENT;
1336 
1337     if (output) {
1338 	f = fopen(output, "w");
1339 	if (!f) {
1340 	    fprintf(stderr, "smidump: cannot open %s for writing: ", output);
1341 	    perror(NULL);
1342 	    exit(1);
1343 	}
1344     }
1345 
1346     for (i = 0; i < modc; i++) {
1347 
1348 	smiModule = modv[i];
1349 
1350         createImportList(smiModule);
1351 
1352 	fprint(f, "/*\n");
1353 	fprint(f, " * This module has been generated by smidump "
1354 	       SMI_VERSION_STRING ":\n");
1355 	fprint(f, " *\n");
1356 	fprint(f, " *      smidump -f yang");
1357 	if (silent) {
1358 	    fprint(f, " -q");
1359 	}
1360 	if (sflag) {
1361 	    fprint(f, " --yang-smi-extensions");
1362 	}
1363 	if (nflag) {
1364 	    fprint(f, " --yang-no-notifications");
1365 	}
1366 	fprint(f, " %s\n", smiModule->name);
1367 	fprint(f, " *\n");
1368 	fprint(f, " * Do not edit. Edit the source file instead!\n");
1369 	fprint(f, " */\n\n");
1370 	fprint(f, "module %s {\n", smiModule->name);
1371 	fprint(f, "\n");
1372 
1373 	fprintNamespace(f, INDENT, smiModule);
1374 	fprintLinkage(f, INDENT, smiModule);
1375 	fprintMeta(f, INDENT, smiModule);
1376 	fprintRevisions(f, INDENT, smiModule);
1377 
1378 	fprintTypedefs(f, modv[i]);
1379 	fprintContainers(f, modv[i]);
1380 	fprintAugments(f, modv[i]);
1381 
1382 	if (! nflag) {
1383 	    fprintNotifications(f, modv[i]);
1384 	}
1385 
1386     	fprint(f, "} /* end of module %s */\n", smiModule->name);
1387 
1388         freeImportList();
1389     }
1390 
1391     if (fflush(f) || ferror(f)) {
1392 	perror("smidump: write error");
1393 	exit(1);
1394     }
1395 
1396     if (output) {
1397 	fclose(f);
1398     }
1399 }
1400 
1401 
1402 
initYang()1403 void initYang()
1404 {
1405     static SmidumpDriverOption opt[] = {
1406 	{ "smi-extensions", OPT_FLAG, &sflag, 0,
1407 	  "generate smi extensions" },
1408 	{ "no-notifications", OPT_FLAG, &nflag, 0,
1409 	  "do not generate notifications" },
1410 	{ "indent", OPT_INT, &INDENT, 0,
1411 	  "indentation (default 2)" },
1412         { 0, OPT_END, 0, 0 }
1413     };
1414 
1415     static SmidumpDriver driver = {
1416 	"yang",
1417 	dumpYang,
1418 	0,
1419 	SMIDUMP_DRIVER_CANT_UNITE,
1420 	"YANG format",
1421 	opt,
1422 	NULL
1423     };
1424 
1425     smidumpRegisterDriver(&driver);
1426 }
1427