blob: 34ee18e42fd407e6f12a798580a391a047054792 [file] [log] [blame]
Michal Vasko5ed10f12015-06-04 10:04:57 +02001/**
2 * @file printer/tree.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief TREE printer for libyang data model structure
5 *
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>
Michal Vaskob5c75d72015-06-15 12:16:52 +020025#include <assert.h>
Michal Vasko5ed10f12015-06-04 10:04:57 +020026
27#include "../common.h"
28#include "../tree.h"
29
Michal Vaskoe03bfbb2015-06-16 09:07:49 +020030/* spec_config = 0 (no special config status), 1 (read-only - rpc output, notification), 2 (write-only - rpc input) */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020031static void tree_print_mnode_choice(FILE * f, int level, char *indent, unsigned int max_name_len,
32 struct ly_mnode *mnode, int mask, int spec_config);
33static void tree_print_mnode(FILE * f, int level, char *indent, unsigned int max_name_len, struct ly_mnode *mnode,
Michal Vaskoe03bfbb2015-06-16 09:07:49 +020034 int mask, int spec_config);
Michal Vasko5ed10f12015-06-04 10:04:57 +020035
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020036static int
37sibling_is_valid_child(const struct ly_mnode *mnode)
Michal Vasko6db4fce2015-06-08 14:13:49 +020038{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020039 struct ly_mnode *cur;
Michal Vasko7ea0a312015-06-08 10:36:48 +020040
Michal Vasko07898f92015-06-15 12:17:11 +020041 if (mnode == NULL) {
42 return 0;
43 }
Michal Vasko7ea0a312015-06-08 10:36:48 +020044
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020045 /* has a following printed child */
46 LY_TREE_FOR((struct ly_mnode *)mnode->next, cur) {
47 if (cur->nodetype &
48 (LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML | LY_NODE_CHOICE |
49 LY_NODE_RPC | LY_NODE_INPUT | LY_NODE_OUTPUT | LY_NODE_NOTIF)) {
50 return 1;
51 }
52 }
Michal Vasko7ea0a312015-06-08 10:36:48 +020053
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020054 /* if in uses, the following printed child can actually be in the parent node :-/ */
Michal Vasko07898f92015-06-15 12:17:11 +020055 if (mnode->parent && mnode->parent->nodetype == LY_NODE_USES) {
56 return sibling_is_valid_child(mnode->parent);
57 }
58
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020059 return 0;
Michal Vasko7ea0a312015-06-08 10:36:48 +020060}
61
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020062static char *
63create_indent(int level, const char *old_indent, const struct ly_mnode *mnode, int shorthand)
Michal Vasko449afde2015-06-04 16:06:49 +020064{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020065 int next_is_case = 0, is_case = 0, has_next = 0, i, found;
66 char *new_indent = malloc((level * 4 + 1) * sizeof (char));
Michal Vasko14410462015-06-05 15:08:54 +020067
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020068 strcpy(new_indent, old_indent);
Michal Vasko14410462015-06-05 15:08:54 +020069
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020070 /* this is the indent of a case (standard or shorthand) */
71 if (mnode->nodetype == LY_NODE_CASE || shorthand) {
72 is_case = 1;
73 }
Michal Vasko14410462015-06-05 15:08:54 +020074
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020075 /* this is the direct child of a case */
76 if (!is_case && mnode->parent && (mnode->parent->nodetype & (LY_NODE_CASE | LY_NODE_CHOICE))) {
77 /* it is not the only child */
78 if (mnode->next && mnode->next->parent && mnode->next->parent->nodetype == LY_NODE_CHOICE) {
79 next_is_case = 1;
80 }
81 }
Michal Vasko14410462015-06-05 15:08:54 +020082
Michal Vasko07898f92015-06-15 12:17:11 +020083 /* next is a node that will actually be printed */
84 has_next = sibling_is_valid_child(mnode);
Michal Vasko14410462015-06-05 15:08:54 +020085
Michal Vasko07898f92015-06-15 12:17:11 +020086 /* there is no next, but we are in top-level of a submodule */
87 if (!has_next && mnode->module->type == 1 && !mnode->parent) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020088 struct ly_submodule *submod = (struct ly_submodule *)mnode->module;
89 struct ly_module *mod = submod->belongsto;
Michal Vasko14410462015-06-05 15:08:54 +020090
Michal Vasko07898f92015-06-15 12:17:11 +020091 /* find this submodule, check all the next ones for valid printed nodes */
92 found = 0;
93 for (i = 0; i < mod->inc_size; i++) {
94 /* we found ours, check all the following submodules and the module */
95 if (found) {
Michal Vaskof2896302015-06-16 09:30:02 +020096 if (mnode->nodetype == LY_NODE_RPC) {
97 has_next = sibling_is_valid_child(mod->inc[i].submodule->rpc);
98 } else if (mnode->nodetype == LY_NODE_NOTIF) {
99 has_next = sibling_is_valid_child(mod->inc[i].submodule->notif);
100 } else {
101 has_next = sibling_is_valid_child(mod->inc[i].submodule->data);
Michal Vasko07898f92015-06-15 12:17:11 +0200102 }
103 }
Michal Vasko7ea0a312015-06-08 10:36:48 +0200104
Michal Vasko07898f92015-06-15 12:17:11 +0200105 if (!found && !strcmp(submod->name, mod->inc[i].submodule->name)) {
106 found = 1;
107 }
108 }
Michal Vasko7ea0a312015-06-08 10:36:48 +0200109
Michal Vasko07898f92015-06-15 12:17:11 +0200110 /* there is nothing in submodules, check module */
111 if (!has_next) {
Michal Vaskof2896302015-06-16 09:30:02 +0200112 if (mnode->nodetype == LY_NODE_RPC) {
Michal Vasko0e893c92015-06-16 11:09:40 +0200113 has_next = sibling_is_valid_child(mod->rpc);
Michal Vaskof2896302015-06-16 09:30:02 +0200114 } else if (mnode->nodetype == LY_NODE_NOTIF) {
Michal Vasko0e893c92015-06-16 11:09:40 +0200115 has_next = sibling_is_valid_child(mod->notif);
Michal Vaskof2896302015-06-16 09:30:02 +0200116 } else {
Michal Vasko0e893c92015-06-16 11:09:40 +0200117 has_next = sibling_is_valid_child(mod->data);
Michal Vasko07898f92015-06-15 12:17:11 +0200118 }
119 }
120 }
121
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200122 if (has_next && !next_is_case) {
123 strcat(new_indent, "| ");
124 } else {
125 strcat(new_indent, " ");
126 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200127
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200128 return new_indent;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200129}
130
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200131static unsigned int
132get_max_name_len(struct ly_mnode *mnode)
Michal Vasko8d479bd2015-06-05 10:50:03 +0200133{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200134 struct ly_mnode *sub;
135 unsigned int max_name_len = 0, uses_max_name_len;
Michal Vasko8d479bd2015-06-05 10:50:03 +0200136
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200137 LY_TREE_FOR(mnode, sub) {
138 if (sub->nodetype == LY_NODE_USES) {
139 uses_max_name_len = get_max_name_len(sub->child);
140 if (uses_max_name_len > max_name_len) {
141 max_name_len = uses_max_name_len;
142 }
143 } else if (sub->nodetype &
144 (LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML)) {
145 if (strlen(sub->name) > max_name_len) {
146 max_name_len = strlen(sub->name);
147 }
148 }
149 }
Michal Vasko8d479bd2015-06-05 10:50:03 +0200150
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200151 return max_name_len;
Michal Vasko8d479bd2015-06-05 10:50:03 +0200152}
153
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200154static void
155tree_print_type(FILE * f, struct ly_type *type)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200156{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200157 if (type->base == LY_TYPE_LEAFREF) {
158 fprintf(f, "-> %s", type->info.lref.path);
159 } else if (type->prefix) {
160 fprintf(f, "%s:%s", type->prefix, type->der->name);
161 } else {
162 fprintf(f, "%s", type->der->name);
163 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200164}
165
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200166static void
Michal Vasko28c6b572015-06-18 12:43:31 +0200167tree_print_features(FILE *f, const struct ly_feature **features, uint8_t features_size)
168{
169 int i;
170
171 if (!features_size) {
172 return;
173 }
174
175 fprintf(f, " {");
176 for (i = 0; i < features_size; i++) {
177 if (i > 0) {
178 fprintf(f, ",");
179 }
180 fprintf(f, "%s", features[i]->name);
181 }
182 fprintf(f, "}?");
183}
184
185static void
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200186tree_print_input_output(FILE * f, int level, char *indent, struct ly_mnode *mnode, int spec_config)
Michal Vaskob5c75d72015-06-15 12:16:52 +0200187{
188 unsigned int max_child_len;
189 char *new_indent;
190 struct ly_mnode *sub;
191
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200192 assert(spec_config);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200193
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200194 fprintf(f, "%s+--%s %s\n", indent, (spec_config == 1 ? "-w" : "ro"), (spec_config == 1 ? "input" : "output"));
Michal Vaskob5c75d72015-06-15 12:16:52 +0200195
196 level++;
197 new_indent = create_indent(level, indent, mnode, 0);
198
199 max_child_len = get_max_name_len(mnode->child);
200
201 LY_TREE_FOR(mnode->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200202 tree_print_mnode(f, level, new_indent, max_child_len, sub,
203 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML | LY_NODE_USES,
204 spec_config);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200205 }
206
207 free(new_indent);
208}
209
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200210static void
211tree_print_container(FILE * f, int level, char *indent, struct ly_mnode *mnode, int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200212{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200213 unsigned int max_child_len;
214 char *new_indent;
215 struct ly_mnode_container *cont = (struct ly_mnode_container *)mnode;
216 struct ly_mnode *sub;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200217
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200218 assert(spec_config >= 0 && spec_config <= 2);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200219
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200220 fprintf(f, "%s%s--", indent,
221 (cont->flags & LY_NODE_STATUS_DEPRC ? "x" : (cont->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")));
Michal Vaskob5c75d72015-06-15 12:16:52 +0200222
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200223 if (spec_config == 0) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200224 fprintf(f, "%s ", (cont->flags & LY_NODE_CONFIG_W ? "rw" : "ro"));
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200225 } else if (spec_config == 1) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200226 fprintf(f, "-w ");
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200227 } else if (spec_config == 2) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200228 fprintf(f, "ro ");
229 }
230
Michal Vasko28c6b572015-06-18 12:43:31 +0200231 fprintf(f, "%s%s", cont->name, (cont->presence ? "!" : ""));
232
233 tree_print_features(f, (const struct ly_feature **)cont->features, cont->features_size);
234
235 fprintf(f, "\n");
Michal Vasko5ed10f12015-06-04 10:04:57 +0200236
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200237 level++;
238 new_indent = create_indent(level, indent, mnode, 0);
Michal Vasko5ed10f12015-06-04 10:04:57 +0200239
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200240 max_child_len = get_max_name_len(mnode->child);
Michal Vasko449afde2015-06-04 16:06:49 +0200241
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200242 LY_TREE_FOR(cont->child, sub) {
243 tree_print_mnode(f, level, new_indent, max_child_len, sub,
244 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML | LY_NODE_USES,
245 spec_config);
246 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200247
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200248 free(new_indent);
Michal Vasko5ed10f12015-06-04 10:04:57 +0200249}
250
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200251static void
252tree_print_choice(FILE * f, int level, char *indent, struct ly_mnode *mnode, int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200253{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200254 unsigned int max_child_len;
255 char *new_indent;
256 struct ly_mnode_choice *choice = (struct ly_mnode_choice *)mnode;
257 struct ly_mnode *sub;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200258
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200259 assert(spec_config >= 0 && spec_config <= 2);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200260
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200261 fprintf(f, "%s%s--", indent,
262 (choice->flags & LY_NODE_STATUS_DEPRC ? "x" : (choice->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")));
Michal Vaskob5c75d72015-06-15 12:16:52 +0200263
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200264 if (spec_config == 0) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200265 fprintf(f, "%s ", (choice->flags & LY_NODE_CONFIG_W ? "rw" : "ro"));
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200266 } else if (spec_config == 1) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200267 fprintf(f, "-w ");
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200268 } else if (spec_config == 2) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200269 fprintf(f, "ro ");
270 }
271
272 fprintf(f, "(%s)%s", choice->name, (choice->flags & LY_NODE_MAND_TRUE ? "" : "?"));
273
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200274 if (choice->dflt != NULL) {
275 fprintf(f, " <%s>", choice->dflt->name);
276 }
Michal Vasko28c6b572015-06-18 12:43:31 +0200277
278 tree_print_features(f, (const struct ly_feature **)choice->features, choice->features_size);
279
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200280 fprintf(f, "\n");
Michal Vasko449afde2015-06-04 16:06:49 +0200281
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200282 level++;
283 new_indent = create_indent(level, indent, mnode, 0);
Michal Vasko449afde2015-06-04 16:06:49 +0200284
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200285 max_child_len = get_max_name_len(mnode->child);
Michal Vasko449afde2015-06-04 16:06:49 +0200286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200287 LY_TREE_FOR(choice->child, sub) {
288 tree_print_mnode_choice(f, level, new_indent, max_child_len, sub,
289 LY_NODE_CASE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML,
290 spec_config);
291 }
Michal Vasko449afde2015-06-04 16:06:49 +0200292
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200293 free(new_indent);
Michal Vasko449afde2015-06-04 16:06:49 +0200294}
295
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200296static void
297tree_print_case(FILE * f, int level, char *indent, unsigned int max_name_len, struct ly_mnode *mnode, int shorthand, int spec_config)
Michal Vasko449afde2015-06-04 16:06:49 +0200298{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200299 char *new_indent;
300 struct ly_mnode_case *cas = (struct ly_mnode_case *)mnode;
301 struct ly_mnode *sub;
Radek Krejci7e97c352015-06-19 16:26:34 +0200302 int i;
303
304 /* stop if features are not enabled */
305 for (i = 0; i < cas->features_size; i++) {
306 if (!(cas->features[i]->flags & LY_NODE_FENABLED)) {
307 return;
308 }
309 }
310 /* or if the data are from augment under a not enabled feature */
311 if (cas->parent && cas->parent->nodetype == LY_NODE_AUGMENT) {
312 for (i = 0; i < cas->parent->features_size; i++) {
313 if (!(cas->parent->features[i]->flags & LY_NODE_FENABLED)) {
314 return;
315 }
316 }
317 }
Michal Vasko449afde2015-06-04 16:06:49 +0200318
Michal Vasko28c6b572015-06-18 12:43:31 +0200319 fprintf(f, "%s%s--:(%s)", indent,
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200320 (cas->flags & LY_NODE_STATUS_DEPRC ? "x" : (cas->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")), mnode->name);
Michal Vasko449afde2015-06-04 16:06:49 +0200321
Michal Vasko28c6b572015-06-18 12:43:31 +0200322 tree_print_features(f, (const struct ly_feature **)cas->features, cas->features_size);
323
324 fprintf(f, "\n");
325
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200326 level++;
327 new_indent = create_indent(level, indent, mnode, shorthand);
Michal Vasko449afde2015-06-04 16:06:49 +0200328
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200329 if (shorthand) {
330 tree_print_mnode(f, level, new_indent, max_name_len, mnode,
331 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML | LY_NODE_USES,
332 spec_config);
333 } else {
334 LY_TREE_FOR(mnode->child, sub) {
335 tree_print_mnode(f, level, new_indent, max_name_len, sub,
336 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML | LY_NODE_USES,
337 spec_config);
338 }
339 }
Michal Vasko449afde2015-06-04 16:06:49 +0200340
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200341 free(new_indent);
Michal Vasko5ed10f12015-06-04 10:04:57 +0200342}
343
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200344static void
345tree_print_anyxml(FILE * f, char *indent, unsigned int max_name_len, struct ly_mnode *mnode, int spec_config)
Michal Vasko315f70b2015-06-05 10:48:59 +0200346{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200347 struct ly_mnode_anyxml *anyxml = (struct ly_mnode_anyxml *)mnode;
Michal Vasko315f70b2015-06-05 10:48:59 +0200348
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200349 assert(spec_config >= 0 && spec_config <= 2);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200350
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200351 fprintf(f, "%s%s--", indent,
352 (anyxml->flags & LY_NODE_STATUS_DEPRC ? "x" : (anyxml->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")));
Michal Vaskob5c75d72015-06-15 12:16:52 +0200353
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200354 if (spec_config == 0) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200355 fprintf(f, "%s ", (anyxml->flags & LY_NODE_CONFIG_W ? "rw" : "ro"));
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200356 } else if (spec_config == 1) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200357 fprintf(f, "-w ");
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200358 } else if (spec_config == 2) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200359 fprintf(f, "ro ");
360 }
361
Michal Vasko28c6b572015-06-18 12:43:31 +0200362 fprintf(f, "%s%s%*sanyxml", anyxml->name, (anyxml->flags & LY_NODE_MAND_TRUE ? " " : "?"),
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200363 3 + (int)(max_name_len - strlen(anyxml->name)), " ");
Michal Vasko28c6b572015-06-18 12:43:31 +0200364
365 tree_print_features(f, (const struct ly_feature **)anyxml->features, anyxml->features_size);
366
367 fprintf(f, "\n");
Michal Vasko315f70b2015-06-05 10:48:59 +0200368}
369
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200370static void
371tree_print_leaf(FILE * f, char *indent, unsigned int max_name_len, struct ly_mnode *mnode, int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200372{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200373 struct ly_mnode_leaf *leaf = (struct ly_mnode_leaf *)mnode;
374 struct ly_mnode_list *list;
375 int i, is_key = 0;
Michal Vasko449afde2015-06-04 16:06:49 +0200376
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200377 assert(spec_config >= 0 && spec_config <= 2);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200378
Radek Krejci87e840c2015-06-19 16:44:54 +0200379 if (leaf->parent && leaf->parent->nodetype == LY_NODE_LIST) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200380 list = (struct ly_mnode_list *)leaf->parent;
381 for (i = 0; i < list->keys_size; i++) {
382 if (strcmp(list->keys[i]->name, leaf->name) == 0) {
383 is_key = 1;
384 break;
385 }
386 }
387 }
Michal Vasko449afde2015-06-04 16:06:49 +0200388
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200389 fprintf(f, "%s%s--", indent,
390 (leaf->flags & LY_NODE_STATUS_DEPRC ? "x" : (leaf->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")));
Michal Vaskob5c75d72015-06-15 12:16:52 +0200391
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200392 if (spec_config == 0) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200393 fprintf(f, "%s ", (leaf->flags & LY_NODE_CONFIG_W ? "rw" : "ro"));
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200394 } else if (spec_config == 1) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200395 fprintf(f, "-w ");
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200396 } else if (spec_config == 2) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200397 fprintf(f, "ro ");
398 }
399
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200400 fprintf(f, "%s%s%*s", leaf->name, ((leaf->flags & LY_NODE_MAND_TRUE) || is_key ? " " : "?"),
401 3 + (int)(max_name_len - strlen(leaf->name)), " ");
Michal Vaskob5c75d72015-06-15 12:16:52 +0200402
403 tree_print_type(f, &leaf->type);
404
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200405 if (leaf->dflt != NULL) {
406 fprintf(f, " <%s>", leaf->dflt);
407 }
Michal Vasko28c6b572015-06-18 12:43:31 +0200408
409 tree_print_features(f, (const struct ly_feature **)leaf->features, leaf->features_size);
410
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200411 fprintf(f, "\n");
Michal Vasko5ed10f12015-06-04 10:04:57 +0200412}
413
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200414static void
415tree_print_leaflist(FILE * f, char *indent, unsigned int max_name_len, struct ly_mnode *mnode, int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200416{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200417 struct ly_mnode_leaflist *leaflist = (struct ly_mnode_leaflist *)mnode;
Michal Vasko449afde2015-06-04 16:06:49 +0200418
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200419 assert(spec_config >= 0 && spec_config <= 2);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200420
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200421 fprintf(f, "%s%s--", indent,
422 (leaflist->flags & LY_NODE_STATUS_DEPRC ? "x" : (leaflist->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")));
Michal Vaskob5c75d72015-06-15 12:16:52 +0200423
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200424 if (spec_config == 0) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200425 fprintf(f, "%s ", (leaflist->flags & LY_NODE_CONFIG_W ? "rw" : "ro"));
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200426 } else if (spec_config == 1) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200427 fprintf(f, "-w ");
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200428 } else if (spec_config == 2) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200429 fprintf(f, "ro ");
430 }
431
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200432 fprintf(f, "%s*%*s", leaflist->name, 3 + (int)(max_name_len - strlen(leaflist->name)), " ");
Michal Vaskob5c75d72015-06-15 12:16:52 +0200433
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200434 tree_print_type(f, &leaflist->type);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200435
Michal Vasko28c6b572015-06-18 12:43:31 +0200436 tree_print_features(f, (const struct ly_feature **)leaflist->features, leaflist->features_size);
437
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200438 fprintf(f, "\n");
Michal Vasko5ed10f12015-06-04 10:04:57 +0200439}
440
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200441static void
442tree_print_list(FILE * f, int level, char *indent, struct ly_mnode *mnode, int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200443{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200444 int i;
445 unsigned int max_child_len;
446 char *new_indent;
447 struct ly_mnode *sub;
448 struct ly_mnode_list *list = (struct ly_mnode_list *)mnode;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200449
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200450 fprintf(f, "%s%s--", indent,
451 (list->flags & LY_NODE_STATUS_DEPRC ? "x" : (list->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")));
Michal Vaskob5c75d72015-06-15 12:16:52 +0200452
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200453 if (spec_config == 0) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200454 fprintf(f, "%s ", (list->flags & LY_NODE_CONFIG_W ? "rw" : "ro"));
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200455 } else if (spec_config == 1) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200456 fprintf(f, "-w ");
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200457 } else if (spec_config == 2) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200458 fprintf(f, "ro ");
459 }
460
461 fprintf(f, "%s*", list->name);
Michal Vasko5ed10f12015-06-04 10:04:57 +0200462
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200463 for (i = 0; i < list->keys_size; i++) {
464 if (i == 0) {
465 fprintf(f, " [");
466 }
467 fprintf(f, "%s%s", list->keys[i]->name, i + 1 < list->keys_size ? "," : "]");
468 }
Michal Vaskob5c75d72015-06-15 12:16:52 +0200469
Michal Vasko28c6b572015-06-18 12:43:31 +0200470 tree_print_features(f, (const struct ly_feature **)list->features, list->features_size);
471
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200472 fprintf(f, "\n");
Michal Vasko5ed10f12015-06-04 10:04:57 +0200473
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200474 level++;
475 new_indent = create_indent(level, indent, mnode, 0);
Michal Vasko5ed10f12015-06-04 10:04:57 +0200476
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200477 max_child_len = get_max_name_len(mnode->child);
Michal Vasko449afde2015-06-04 16:06:49 +0200478
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200479 LY_TREE_FOR(mnode->child, sub) {
480 tree_print_mnode(f, level, new_indent, max_child_len, sub,
481 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_USES | LY_NODE_ANYXML,
482 spec_config);
483 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200484
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200485 free(new_indent);
Michal Vasko5ed10f12015-06-04 10:04:57 +0200486}
487
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200488static void
489tree_print_uses(FILE * f, int level, char *indent, unsigned int max_name_len, struct ly_mnode *mnode, int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200490{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200491 struct ly_mnode *node;
492 struct ly_mnode_uses *uses = (struct ly_mnode_uses *)mnode;
Radek Krejci7e97c352015-06-19 16:26:34 +0200493
494 /* FIXME there are no children here */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200495 LY_TREE_FOR(uses->child, node) {
496 tree_print_mnode(f, level, indent, max_name_len, node,
497 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_USES | LY_NODE_ANYXML,
498 spec_config);
499 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200500}
501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200502static void
503tree_print_rpc(FILE * f, int level, char *indent, struct ly_mnode *mnode)
Michal Vaskob5c75d72015-06-15 12:16:52 +0200504{
505 char *new_indent;
506 struct ly_mnode *node;
507 struct ly_mnode_rpc *rpc = (struct ly_mnode_rpc *)mnode;
Radek Krejci7e97c352015-06-19 16:26:34 +0200508 int i;
509
510 /* stop if features are not enabled */
511 for (i = 0; i < rpc->features_size; i++) {
512 if (!(rpc->features[i]->flags & LY_NODE_FENABLED)) {
513 return;
514 }
515 }
Michal Vaskob5c75d72015-06-15 12:16:52 +0200516
Michal Vasko28c6b572015-06-18 12:43:31 +0200517 fprintf(f, "%s%s---x %s", indent,
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200518 (rpc->flags & LY_NODE_STATUS_DEPRC ? "x" : (rpc->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")), rpc->name);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200519
Michal Vasko28c6b572015-06-18 12:43:31 +0200520 tree_print_features(f, (const struct ly_feature **)rpc->features, rpc->features_size);
521
522 fprintf(f, "\n");
523
Michal Vaskob5c75d72015-06-15 12:16:52 +0200524 level++;
525 new_indent = create_indent(level, indent, mnode, 0);
526
527 LY_TREE_FOR(rpc->child, node) {
528 if (node->nodetype == LY_NODE_INPUT) {
529 tree_print_input_output(f, level, new_indent, node, 1);
530 } else if (node->nodetype == LY_NODE_OUTPUT) {
531 tree_print_input_output(f, level, new_indent, node, 2);
532 }
533 }
534
535 free(new_indent);
536}
537
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200538static void
539tree_print_notif(FILE * f, int level, char *indent, struct ly_mnode *mnode)
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200540{
541 unsigned int max_child_len;
542 char *new_indent;
543 struct ly_mnode *node;
544 struct ly_mnode_notif *notif = (struct ly_mnode_notif *)mnode;
Radek Krejci7e97c352015-06-19 16:26:34 +0200545 int i;
546
547 /* stop if features are not enabled */
548 for (i = 0; i < notif->features_size; i++) {
549 if (!(notif->features[i]->flags & LY_NODE_FENABLED)) {
550 return;
551 }
552 }
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200553
Michal Vasko28c6b572015-06-18 12:43:31 +0200554 fprintf(f, "%s%s---n %s", indent,
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200555 (notif->flags & LY_NODE_STATUS_DEPRC ? "x" : (notif->flags & LY_NODE_STATUS_OBSLT ? "o" : "+")),
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200556 notif->name);
557
Michal Vasko28c6b572015-06-18 12:43:31 +0200558 tree_print_features(f, (const struct ly_feature **)notif->features, notif->features_size);
559
560 fprintf(f, "\n");
561
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200562 level++;
563 new_indent = create_indent(level, indent, mnode, 0);
564
565 max_child_len = get_max_name_len(mnode->child);
566
567 LY_TREE_FOR(notif->child, node) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200568 tree_print_mnode(f, level, new_indent, max_child_len, node,
569 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML | LY_NODE_USES,
570 2);
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200571 }
572
573 free(new_indent);
574}
575
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200576static void
577tree_print_mnode_choice(FILE * f, int level, char *indent, unsigned int max_name_len, struct ly_mnode *mnode, int mask,
578 int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200579{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200580 if (mnode->nodetype & mask) {
581 if (mnode->nodetype == LY_NODE_CASE) {
582 tree_print_case(f, level, indent, max_name_len, mnode, 0, spec_config);
583 } else {
584 tree_print_case(f, level, indent, max_name_len, mnode, 1, spec_config);
585 }
586 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200587}
588
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200589static void
590tree_print_mnode(FILE * f, int level, char *indent, unsigned int max_name_len, struct ly_mnode *mnode, int mask,
591 int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200592{
Radek Krejci87e840c2015-06-19 16:44:54 +0200593 int i;
594
595 /* stop if features are not enabled */
596 for (i = 0; i < mnode->features_size; i++) {
597 if (!(mnode->features[i]->flags & LY_NODE_FENABLED)) {
598 return;
599 }
600 }
601 /* or if the data are from augment under a not enabled feature */
602 if (mnode->parent && mnode->parent->nodetype == LY_NODE_AUGMENT) {
603 for (i = 0; i < mnode->parent->features_size; i++) {
604 if (!(mnode->parent->features[i]->flags & LY_NODE_FENABLED)) {
605 return;
606 }
607 }
608 }
609
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200610 switch (mnode->nodetype & mask) {
611 case LY_NODE_CONTAINER:
612 tree_print_container(f, level, indent, mnode, spec_config);
613 break;
614 case LY_NODE_CHOICE:
615 tree_print_choice(f, level, indent, mnode, spec_config);
616 break;
617 case LY_NODE_LEAF:
618 tree_print_leaf(f, indent, max_name_len, mnode, spec_config);
619 break;
620 case LY_NODE_LEAFLIST:
621 tree_print_leaflist(f, indent, max_name_len, mnode, spec_config);
622 break;
623 case LY_NODE_LIST:
624 tree_print_list(f, level, indent, mnode, spec_config);
625 break;
626 case LY_NODE_ANYXML:
627 tree_print_anyxml(f, indent, max_name_len, mnode, spec_config);
628 break;
629 case LY_NODE_USES:
630 tree_print_uses(f, level, indent, max_name_len, mnode, spec_config);
631 break;
632 default:
633 break;
634 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200635}
636
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200637int
638tree_print_model(FILE * f, struct ly_module *module)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200639{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200640 struct ly_mnode *mnode;
641 unsigned int max_child_len;
642 int level = 1, i, have_rpcs = 0, have_notifs = 0;
643 char *indent = malloc((level * 4 + 1) * sizeof (char));
644 strcpy(indent, " ");
Michal Vasko5ed10f12015-06-04 10:04:57 +0200645
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200646 fprintf(f, "module: %s\n", module->name);
Michal Vasko5ed10f12015-06-04 10:04:57 +0200647
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200648 /* included submodules */
649 for (i = 0; i < module->inc_size; i++) {
650 max_child_len = get_max_name_len(module->inc[i].submodule->data);
Michal Vasko8d479bd2015-06-05 10:50:03 +0200651
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200652 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
653 tree_print_mnode(f, level, indent, max_child_len, mnode,
654 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML | LY_NODE_USES,
655 0);
656 }
657 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200658
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200659 /* module */
660 max_child_len = get_max_name_len(module->data);
661 level++;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200662
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200663 LY_TREE_FOR(module->data, mnode) {
664 tree_print_mnode(f, level, indent, max_child_len, mnode,
665 LY_NODE_CHOICE | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST | LY_NODE_ANYXML | LY_NODE_USES,
666 0);
667 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200668
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200669 /* rpc */
670 if (module->rpc) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200671 have_rpcs = 1;
672 } else {
673 for (i = 0; i < module->inc_size; i++) {
674 if (module->inc[i].submodule->rpc) {
675 have_rpcs = 1;
676 break;
677 }
678 }
679 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200680 if (have_rpcs) {
Michal Vaskob5c75d72015-06-15 12:16:52 +0200681 fprintf(f, "rpcs:\n");
682 for (i = 0; i < module->inc_size; i++) {
683 LY_TREE_FOR(module->inc[i].submodule->rpc, mnode) {
684 tree_print_rpc(f, level, indent, mnode);
685 }
686 }
687 LY_TREE_FOR(module->rpc, mnode) {
688 tree_print_rpc(f, level, indent, mnode);
689 }
690 }
Michal Vasko449afde2015-06-04 16:06:49 +0200691
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200692 /* notification */
693 if (module->notif) {
694 have_notifs = 1;
695 } else {
696 for (i = 0; i < module->inc_size; i++) {
697 if (module->inc[i].submodule->notif) {
698 have_notifs = 1;
699 break;
700 }
701 }
702 }
703 if (have_notifs) {
704 fprintf(f, "notifications:\n");
705 for (i = 0; i < module->inc_size; i++) {
706 LY_TREE_FOR(module->inc[i].submodule->notif, mnode) {
707 tree_print_notif(f, level, indent, mnode);
708 }
709 }
710 LY_TREE_FOR(module->notif, mnode) {
711 tree_print_notif(f, level, indent, mnode);
712 }
713 }
Michal Vasko449afde2015-06-04 16:06:49 +0200714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200715 free(indent);
716 return EXIT_SUCCESS;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200717}