blob: 087fc074226a7ff7f496a5c289dc2220c13025db [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
Radek Krejciefdd0ce2015-05-26 16:48:29 +02002 * @file printer/yang.c
Radek Krejcida04f4a2015-05-21 12:54:09 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Radek Krejciefdd0ce2015-05-26 16:48:29 +02004 * @brief YANG printer for libyang data model structure
Radek Krejcida04f4a2015-05-21 12:54:09 +02005 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25
Radek Krejciefdd0ce2015-05-26 16:48:29 +020026#include "../common.h"
27#include "../tree.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020028
29#define INDENT ""
30#define LEVEL (level*2)
31
32static void yang_print_mnode(FILE *f, int level, struct ly_mnode *mnode,
33 int mask);
34
35static void yang_print_text(FILE *f, int level, const char *name,
36 const char *text)
37{
38 const char *s, *t;
39
40 fprintf(f, "%*s%s\n", LEVEL, INDENT, name);
41 level++;
42
43 fprintf(f, "%*s\"", LEVEL, INDENT);
44 t = text;
45 while((s = strchr(t, '\n'))) {
46 fwrite(t, sizeof *t, s - t + 1, f);
47 t = s + 1;
48 fprintf(f, "%*s", LEVEL, INDENT);
49 }
50
51 fprintf(f, "%s\";\n\n", t);
52 level--;
53
54}
55
56/*
57 * Covers:
58 * description, reference, status
59 */
60static void yang_print_mnode_common(FILE *f, int level, struct ly_mnode *mnode)
61{
62 if (mnode->flags & LY_NODE_STATUS_CURR) {
63 fprintf(f, "%*sstatus \"current\";\n", LEVEL, INDENT);
64 } else if (mnode->flags & LY_NODE_STATUS_DEPRC) {
65 fprintf(f, "%*sstatus \"deprecated\";\n", LEVEL, INDENT);
66 } else if (mnode->flags & LY_NODE_STATUS_OBSLT) {
67 fprintf(f, "%*sstatus \"obsolete\";\n", LEVEL, INDENT);
68 }
69
70 if (mnode->dsc) {
71 yang_print_text(f, level, "description", mnode->dsc);
72 }
73 if (mnode->ref) {
74 yang_print_text(f, level, "reference", mnode->ref);
75 }
76}
77
78/*
79 * Covers:
80 * config
81 * description, reference, status
82 */
83static void yang_print_mnode_common2(FILE *f, int level, struct ly_mnode *mnode)
84{
85 if (!mnode->parent || (mnode->parent->flags & LY_NODE_CONFIG_MASK) != (mnode->flags & LY_NODE_CONFIG_MASK)) {
86 /* print config only when it differs from the parent or in root */
87 if (mnode->flags & LY_NODE_CONFIG_W) {
88 fprintf(f, "%*sconfig \"true\";\n", LEVEL, INDENT);
89 } else if (mnode->flags & LY_NODE_CONFIG_R) {
90 fprintf(f, "%*sconfig \"false\";\n", LEVEL, INDENT);
91 }
92 }
93
94 yang_print_mnode_common(f, level, mnode);
95}
96
Radek Krejci04581c62015-05-22 21:24:00 +020097static void yang_print_type(FILE *f, int level, struct ly_module *module, struct ly_type *type)
Radek Krejcida04f4a2015-05-21 12:54:09 +020098{
Radek Krejci25d782a2015-05-22 15:03:23 +020099 int i;
100
101 if (type->prefix) {
102 fprintf(f, "%*stype %s:%s {\n", LEVEL, INDENT, type->prefix, type->der->name);
103 } else {
104 fprintf(f, "%*stype %s {\n", LEVEL, INDENT, type->der->name);
105 }
106 level++;
107 switch (type->base) {
108 case LY_TYPE_ENUM:
109 for (i = 0; i < type->info.enums.count; i++) {
110 fprintf(f, "%*senum %s {\n", LEVEL, INDENT, type->info.enums.list[i].name);
111 level++;
112 yang_print_mnode_common(f, level, (struct ly_mnode *)&type->info.enums.list[i]);
113 fprintf(f, "%*svalue %d;\n", LEVEL, INDENT, type->info.enums.list[i].value);
114 level--;
115 fprintf(f, "%*s}\n", LEVEL, INDENT);
116 }
117 break;
Radek Krejci04581c62015-05-22 21:24:00 +0200118 case LY_TYPE_IDENT:
119 if (module == type->info.ident.ref->module) {
120 fprintf(f, "%*sbase %s;\n", LEVEL, INDENT, type->info.ident.ref->name);
121 } else {
122 fprintf(f, "%*sbase %s:%s;\n", LEVEL, INDENT, type->info.ident.ref->module->prefix, type->info.ident.ref->name);
123 }
124 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200125 default:
126 /* TODO other cases */
127 break;
128 }
129 level--;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200130 fprintf(f, "%*s}\n", LEVEL, INDENT);
131}
132
Radek Krejci04581c62015-05-22 21:24:00 +0200133static void yang_print_typedef(FILE *f, int level, struct ly_module *module, struct ly_tpdf *tpdf)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200134{
135 fprintf(f, "%*stypedef %s {\n", LEVEL, INDENT, tpdf->name);
136 level++;
137
138 yang_print_mnode_common(f, level, (struct ly_mnode *)tpdf);
Radek Krejci04581c62015-05-22 21:24:00 +0200139 yang_print_type(f, level, module, &tpdf->type);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200140
141 level--;
142 fprintf(f, "%*s}\n", LEVEL, INDENT);
143}
144
Radek Krejci6793db02015-05-22 17:49:54 +0200145static void yang_print_identity(FILE *f, int level, struct ly_ident *ident)
146{
147 fprintf(f, "%*sidentity %s {\n", LEVEL, INDENT, ident->name);
148 level++;
149
150 yang_print_mnode_common(f, level, (struct ly_mnode *)ident);
151 if (ident->base) {
152 if (ident->base->module == ident->module) {
153 fprintf(f, "%*sbase %s;\n", LEVEL, INDENT, ident->base->name);
154 } else {
155 fprintf(f, "%*sbase %s:%s;\n", LEVEL, INDENT, ident->base->module->prefix, ident->base->name);
156 }
157 }
158
159 level--;
160 fprintf(f, "%*s}\n", LEVEL, INDENT);
161
162}
163
Radek Krejcida04f4a2015-05-21 12:54:09 +0200164static void yang_print_container(FILE *f, int level, struct ly_mnode *mnode)
165{
166 int i;
167 struct ly_mnode *sub;
168 struct ly_mnode_container *cont = (struct ly_mnode_container *)mnode;
169
170 fprintf(f, "%*scontainer %s {\n", LEVEL, INDENT, mnode->name);
171 level++;
172 yang_print_mnode_common2(f, level, mnode);
173
174 for (i = 0; i < cont->tpdf_size; i++) {
Radek Krejci04581c62015-05-22 21:24:00 +0200175 yang_print_typedef(f, level, mnode->module, &cont->tpdf[i]);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200176 }
177
178 LY_TREE_FOR(mnode->child, sub) {
179 yang_print_mnode(f, level, sub, LY_NODE_CHOICE |LY_NODE_CONTAINER |
Radek Krejcic7c9a6c2015-05-25 16:35:06 +0200180 LY_NODE_LEAF |LY_NODE_LEAFLIST | LY_NODE_LIST |
181 LY_NODE_USES | LY_NODE_GROUPING);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200182 }
183
184 level--;
185 fprintf(f, "%*s}\n", LEVEL, INDENT);
186}
187
188static void yang_print_choice(FILE *f, int level, struct ly_mnode *mnode)
189{
190 struct ly_mnode *sub;
191
192 fprintf(f, "%*schoice %s {\n", LEVEL, INDENT, mnode->name);
193 level++;
194 yang_print_mnode_common2(f, level, mnode);
195 LY_TREE_FOR(mnode->child, sub) {
196 yang_print_mnode(f, level, sub,
197 LY_NODE_CONTAINER | LY_NODE_LEAF |
198 LY_NODE_LEAFLIST | LY_NODE_LIST);
199 }
200 level--;
201 fprintf(f, "%*s}\n", LEVEL, INDENT);
202}
203
204static void yang_print_leaf(FILE *f, int level, struct ly_mnode *mnode)
205{
206 struct ly_mnode_leaf *leaf = (struct ly_mnode_leaf *)mnode;
207
208 fprintf(f, "%*sleaf %s {\n", LEVEL, INDENT, mnode->name);
209 level++;
210 yang_print_mnode_common2(f, level, mnode);
Radek Krejci04581c62015-05-22 21:24:00 +0200211 yang_print_type(f, level, mnode->module, &leaf->type);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200212 level--;
213 fprintf(f, "%*s}\n", LEVEL, INDENT);
214}
215
216static void yang_print_leaflist(FILE *f, int level, struct ly_mnode *mnode)
217{
218 struct ly_mnode_leaflist *llist = (struct ly_mnode_leaflist *)mnode;
219
220 fprintf(f, "%*sleaf-list %s {\n", LEVEL, INDENT, mnode->name);
221 level++;
222 yang_print_mnode_common2(f, level, mnode);
Radek Krejci04581c62015-05-22 21:24:00 +0200223 yang_print_type(f, level, mnode->module, &llist->type);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200224 level--;
225 fprintf(f, "%*s}\n", LEVEL, INDENT);
226}
227
228static void yang_print_list(FILE *f, int level, struct ly_mnode *mnode)
229{
230 int i;
231 struct ly_mnode *sub;
232 struct ly_mnode_list *list = (struct ly_mnode_list *)mnode;
233
234 fprintf(f, "%*slist %s {\n", LEVEL, INDENT, mnode->name);
235 level++;
236 yang_print_mnode_common2(f, level, mnode);
237
Radek Krejcid7f0d012015-05-25 15:04:52 +0200238 if (list->keys_size) {
239 fprintf(f, "%*skey \"", LEVEL, INDENT);
240 for (i = 0; i < list->keys_size; i++) {
241 fprintf(f, "%s%s", list->keys[i]->name, i + 1 < list->keys_size ? " " : "");
242 }
243 fprintf(f, "\";\n");
244 }
245
Radek Krejcida04f4a2015-05-21 12:54:09 +0200246 for (i = 0; i < list->tpdf_size; i++) {
Radek Krejci04581c62015-05-22 21:24:00 +0200247 yang_print_typedef(f, level, list->module, &list->tpdf[i]);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200248 }
249
250 LY_TREE_FOR(mnode->child, sub) {
251 yang_print_mnode(f, level, sub, LY_NODE_CHOICE |LY_NODE_CONTAINER |
Radek Krejcic7c9a6c2015-05-25 16:35:06 +0200252 LY_NODE_LEAF |LY_NODE_LEAFLIST | LY_NODE_LIST |
253 LY_NODE_USES | LY_NODE_GROUPING);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200254 }
255 level--;
256 fprintf(f, "%*s}\n", LEVEL, INDENT);
257}
258
259static void yang_print_grouping(FILE *f, int level, struct ly_mnode *mnode)
260{
261 int i;
262 struct ly_mnode *node;
263 struct ly_mnode_grp *grp = (struct ly_mnode_grp *)mnode;
264
265 fprintf(f, "%*sgrouping %s {\n", LEVEL, INDENT, mnode->name);
266 level++;
267
268 yang_print_mnode_common(f, level, mnode);
269
270 for (i = 0; i < grp->tpdf_size; i++) {
Radek Krejci04581c62015-05-22 21:24:00 +0200271 yang_print_typedef(f, level, mnode->module, &grp->tpdf[i]);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200272 }
273
274 LY_TREE_FOR(mnode->child, node) {
275 yang_print_mnode(f, level, node, LY_NODE_CHOICE |LY_NODE_CONTAINER |
Radek Krejcic7c9a6c2015-05-25 16:35:06 +0200276 LY_NODE_LEAF |LY_NODE_LEAFLIST | LY_NODE_LIST |
277 LY_NODE_USES | LY_NODE_GROUPING);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200278 }
279
280 level--;
281 fprintf(f, "%*s}\n", LEVEL, INDENT);
282}
283
Radek Krejcic7c9a6c2015-05-25 16:35:06 +0200284static void yang_print_uses(FILE *f, int level, struct ly_mnode *mnode)
285{
286 struct ly_mnode_uses *uses = (struct ly_mnode_uses *)mnode;
287
288 fprintf(f, "%*suses %s {\n", LEVEL, INDENT, uses->name);
289 level++;
290
291 yang_print_mnode_common(f, level, mnode);
292
293 level--;
294 fprintf(f, "%*s}\n", LEVEL, INDENT);
295}
296
Radek Krejcida04f4a2015-05-21 12:54:09 +0200297static void yang_print_mnode(FILE *f, int level, struct ly_mnode *mnode,
298 int mask)
299{
300 switch(mnode->nodetype & mask) {
301 case LY_NODE_CONTAINER:
302 yang_print_container(f, level, mnode);
303 break;
304 case LY_NODE_CHOICE:
305 yang_print_choice(f, level, mnode);
306 break;
307 case LY_NODE_LEAF:
308 yang_print_leaf(f, level, mnode);
309 break;
310 case LY_NODE_LEAFLIST:
311 yang_print_leaflist(f, level, mnode);
312 break;
313 case LY_NODE_LIST:
314 yang_print_list(f, level, mnode);
315 break;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +0200316 case LY_NODE_USES:
317 yang_print_uses(f, level, mnode);
318 break;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200319 case LY_NODE_GROUPING:
320 yang_print_grouping(f, level, mnode);
321 break;
322 default: break;
323 }
324}
325
Radek Krejciefdd0ce2015-05-26 16:48:29 +0200326int yang_print_model(FILE *f, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200327{
328 int i;
329 int level = 0;
330#define LEVEL (level*2)
331
332 struct ly_mnode *mnode;
333
Radek Krejcida04f4a2015-05-21 12:54:09 +0200334 fprintf(f, "module %s {\n", module->name);
335 level++;
Radek Krejcib0594bf2015-05-21 23:51:27 +0200336
Radek Krejcida04f4a2015-05-21 12:54:09 +0200337 fprintf(f, "%*snamespace \"%s\";\n", LEVEL, INDENT, module->ns);
338 fprintf(f, "%*sprefix \"%s\";\n", LEVEL, INDENT, module->prefix);
Radek Krejcib0594bf2015-05-21 23:51:27 +0200339
340 if (module->version) {
341 fprintf(f, "%*syang-version \"%s\";\n", LEVEL, INDENT, module->version == 1 ? "1.0" : "1.1");
342 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200343
344 for (i = 0; i < module->imp_size; i++) {
345 fprintf(f, "%*simport \"%s\" {\n", LEVEL, INDENT,
346 module->imp[i].module->name);
347 level++;
348 yang_print_text(f, level, "prefix", module->imp[i].prefix);
349 if (module->imp[i].rev[0]) {
350 yang_print_text(f, level, "revision-date", module->imp[i].rev);
351 }
352 level--;
353 fprintf(f, "%*s}\n", LEVEL, INDENT);
354 }
355
356 if (module->org) {
357 yang_print_text(f, level, "organization", module->org);
358 }
359 if (module->contact) {
360 yang_print_text(f, level, "contact", module->contact);
361 }
362 if (module->dsc) {
363 yang_print_text(f, level, "description", module->dsc);
364 }
365 if (module->ref) {
366 yang_print_text(f, level, "reference", module->ref);
367 }
368 for (i = 0; i < module->rev_size; i++) {
369 if (module->rev[i].dsc || module->rev[i].ref) {
370 fprintf(f, "%*srevision \"%s\" {\n", LEVEL, INDENT,
371 module->rev[i].date);
372 level++;
373 if (module->rev[i].dsc) {
374 yang_print_text(f, level, "description", module->rev[i].dsc);
375 }
376 if (module->rev[i].ref) {
377 yang_print_text(f, level, "reference", module->rev[i].ref);
378 }
379 level--;
380 fprintf(f, "%*s}\n", LEVEL, INDENT);
381 } else {
382 yang_print_text(f, level, "revision", module->rev[i].date);
383 }
384 }
385
Radek Krejci6793db02015-05-22 17:49:54 +0200386 for (i = 0; i < module->ident_size; i++) {
387 yang_print_identity(f, level, &module->ident[i]);
388 }
389
Radek Krejcida04f4a2015-05-21 12:54:09 +0200390 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejci04581c62015-05-22 21:24:00 +0200391 yang_print_typedef(f, level, module, &module->tpdf[i]);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200392 }
393
394 LY_TREE_FOR(module->data, mnode) {
395 yang_print_mnode(f, level, mnode, LY_NODE_CHOICE |LY_NODE_CONTAINER |
Radek Krejcic7c9a6c2015-05-25 16:35:06 +0200396 LY_NODE_LEAF |LY_NODE_LEAFLIST | LY_NODE_LIST |
397 LY_NODE_USES | LY_NODE_GROUPING);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200398 }
399
400 fprintf(f, "}\n");
401
402 return EXIT_SUCCESS;
403#undef LEVEL
404}