blob: cd53a407c3613e8c4ed1d158785d97a3e3fc1938 [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 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko5ed10f12015-06-04 10:04:57 +020013 */
14
Michal Vasko03d8cd22018-02-08 14:48:28 +010015#include <stdint.h>
Michal Vasko5ed10f12015-06-04 10:04:57 +020016#include <stdlib.h>
17#include <stdio.h>
18#include <string.h>
Michal Vaskob5c75d72015-06-15 12:16:52 +020019#include <assert.h>
Michal Vasko5ed10f12015-06-04 10:04:57 +020020
Radek Krejci998a0b82015-08-17 13:14:36 +020021#include "common.h"
Radek Krejci76b07902015-10-09 09:11:25 +020022#include "printer.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020023#include "tree_schema.h"
Michal Vasko5ed10f12015-06-04 10:04:57 +020024
Michal Vasko568b1952018-01-30 15:53:30 +010025/* module: <name>
26 * <X>+--rw <node-name> */
27#define LY_TREE_MOD_DATA_INDENT 2
Michal Vasko5ed10f12015-06-04 10:04:57 +020028
Michal Vasko568b1952018-01-30 15:53:30 +010029/* <^>rpcs:
30 * <X>+---x <rpc-name> */
31#define LY_TREE_OP_DATA_INDENT 4
32
33/* +--rw leaf<X>string */
34#define LY_TREE_TYPE_INDENT 3
35
36/* +--rw leaf
37 * | <X>string */
38#define LY_TREE_WRAP_INDENT 2
39
40/* these options are mostly inherited in recursive print, non-recursive options are parameters */
41typedef struct {
42 const struct lys_module *module; /**< (sub)module we are printing from */
43 uint8_t base_indent; /**< base indent size of all the printed text */
44 uint64_t indent; /**< bit-field of sibling (1)/ no sibling(0) on corresponding depths */
45 uint16_t line_length; /**< maximum desired line length */
46 int spec_config; /**< special config flags - 0 (no special config status),
47 1 (read-only - rpc output, notification), 2 (write-only - rpc input) */
48 int options; /**< user-specified tree printer options */
49} tp_opts;
50
51static void tree_print_snode(struct lyout *out, int level, uint16_t max_name_len, const struct lys_node *node, int mask,
52 const struct lys_node *aug_parent, int subtree, tp_opts *opts);
53
54static int
55tree_print_indent(struct lyout *out, int level, tp_opts *opts)
Michal Vaskoe8441232016-09-01 15:32:45 +020056{
Michal Vasko568b1952018-01-30 15:53:30 +010057 int i, ret = 0;
Michal Vaskoe8441232016-09-01 15:32:45 +020058
Michal Vasko568b1952018-01-30 15:53:30 +010059 if (opts->base_indent) {
60 ret += ly_print(out, "%*s", opts->base_indent, " ");
61 }
62 for (i = 0; i < level; ++i) {
63 if (opts->indent & (1 << i)) {
64 ret += ly_print(out, "| ");
Michal Vaskoe8441232016-09-01 15:32:45 +020065 } else {
Michal Vasko568b1952018-01-30 15:53:30 +010066 ret += ly_print(out, " ");
Michal Vaskoe8441232016-09-01 15:32:45 +020067 }
68 }
Michal Vasko568b1952018-01-30 15:53:30 +010069
70 return ret;
Michal Vaskoe8441232016-09-01 15:32:45 +020071}
72
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020073static int
Michal Vasko568b1952018-01-30 15:53:30 +010074tree_sibling_is_valid_child(const struct lys_node *node, int including, const struct lys_module *module,
75 const struct lys_node *aug_parent, LYS_NODE nodetype)
Michal Vasko6db4fce2015-06-08 14:13:49 +020076{
Michal Vasko58416c82017-02-01 11:43:18 +010077 struct lys_node *cur, *cur2;
Michal Vasko7ea0a312015-06-08 10:36:48 +020078
Michal Vasko80630802017-02-15 13:55:57 +010079 assert(!aug_parent || (aug_parent->nodetype == LYS_AUGMENT));
80
Michal Vaskobda37192016-02-15 11:09:13 +010081 if (!node) {
Michal Vasko07898f92015-06-15 12:17:11 +020082 return 0;
83 }
Michal Vasko7ea0a312015-06-08 10:36:48 +020084
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020085 /* has a following printed child */
Radek Krejci1d82ef62015-08-07 14:44:40 +020086 LY_TREE_FOR((struct lys_node *)(including ? node : node->next), cur) {
Michal Vasko80630802017-02-15 13:55:57 +010087 if (aug_parent && (cur->parent != aug_parent)) {
88 /* we are done traversing this augment, the nodes are all direct siblings */
89 return 0;
90 }
91
Michal Vasko568b1952018-01-30 15:53:30 +010092 if (module->type && (lys_main_module(module) != lys_node_module(cur))) {
Michal Vaskobda37192016-02-15 11:09:13 +010093 continue;
94 }
95
Michal Vaskof6f18f42015-09-24 13:06:14 +020096 if (!lys_is_disabled(cur, 0)) {
Michal Vaskoe0f11be2018-03-02 14:08:22 +010097 if ((cur->nodetype == LYS_USES) || ((cur->nodetype == LYS_CASE) && (cur->flags & LYS_IMPLICIT))) {
Michal Vasko568b1952018-01-30 15:53:30 +010098 if (tree_sibling_is_valid_child(cur->child, 1, module, NULL, nodetype)) {
Michal Vaskoc1e89352017-01-25 14:57:55 +010099 return 1;
100 }
Michal Vasko32113302017-02-01 11:34:22 +0100101 } else {
102 switch (nodetype) {
103 case LYS_GROUPING:
Michal Vaskoe0f11be2018-03-02 14:08:22 +0100104 /* we are printing groupings, they are printed separately */
Michal Vasko32113302017-02-01 11:34:22 +0100105 if (cur->nodetype == LYS_GROUPING) {
Michal Vasko568b1952018-01-30 15:53:30 +0100106 return 0;
Michal Vasko32113302017-02-01 11:34:22 +0100107 }
108 break;
109 case LYS_RPC:
110 if (cur->nodetype == LYS_RPC) {
111 return 1;
112 }
113 break;
114 case LYS_NOTIF:
115 if (cur->nodetype == LYS_NOTIF) {
116 return 1;
117 }
118 break;
119 default:
120 if (cur->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_CHOICE
Michal Vasko58416c82017-02-01 11:43:18 +0100121 | LYS_CASE | LYS_ACTION)) {
Michal Vasko32113302017-02-01 11:34:22 +0100122 return 1;
123 }
124 if ((cur->nodetype & (LYS_INPUT | LYS_OUTPUT)) && cur->child) {
125 return 1;
126 }
Michal Vasko58416c82017-02-01 11:43:18 +0100127 /* only nested notifications count here (not top-level) */
128 if (cur->nodetype == LYS_NOTIF) {
129 for (cur2 = lys_parent(cur); cur2 && (cur2->nodetype == LYS_USES); cur2 = lys_parent(cur2));
130 if (cur2) {
131 return 1;
132 }
133 }
Michal Vasko32113302017-02-01 11:34:22 +0100134 break;
Michal Vaskoc1e89352017-01-25 14:57:55 +0100135 }
Michal Vaskof6f18f42015-09-24 13:06:14 +0200136 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200137 }
138 }
Michal Vasko7ea0a312015-06-08 10:36:48 +0200139
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200140 /* if in uses, the following printed child can actually be in the parent node :-/ */
Michal Vaskodcf98e62016-05-05 17:53:53 +0200141 if (lys_parent(node) && (lys_parent(node)->nodetype == LYS_USES)) {
Michal Vasko568b1952018-01-30 15:53:30 +0100142 return tree_sibling_is_valid_child(lys_parent(node), 0, module, NULL, nodetype);
Michal Vasko07898f92015-06-15 12:17:11 +0200143 }
144
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200145 return 0;
Michal Vasko7ea0a312015-06-08 10:36:48 +0200146}
147
Michal Vasko568b1952018-01-30 15:53:30 +0100148static void
149tree_next_indent(int level, const struct lys_node *node, const struct lys_node *aug_parent, tp_opts *opts)
Michal Vasko449afde2015-06-04 16:06:49 +0200150{
Michal Vaskodc300b02017-04-07 14:09:20 +0200151 int next_is_case = 0, has_next = 0;
Michal Vasko14410462015-06-05 15:08:54 +0200152
Michal Vaskoe8441232016-09-01 15:32:45 +0200153 if (level > 64) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100154 LOGINT(node->module->ctx);
Michal Vasko568b1952018-01-30 15:53:30 +0100155 return;
Michal Vasko253035f2015-12-17 16:58:13 +0100156 }
157
Michal Vasko568b1952018-01-30 15:53:30 +0100158 /* clear level indent (it may have been set for some line wrapping) */
Michal Vasko03d8cd22018-02-08 14:48:28 +0100159 opts->indent &= ~(uint64_t)(1ULL << (level - 1));
Michal Vasko14410462015-06-05 15:08:54 +0200160
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200161 /* this is the direct child of a case */
Michal Vaskodc300b02017-04-07 14:09:20 +0200162 if ((node->nodetype != LYS_CASE) && lys_parent(node) && (lys_parent(node)->nodetype & (LYS_CASE | LYS_CHOICE))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200163 /* it is not the only child */
Michal Vaskodcf98e62016-05-05 17:53:53 +0200164 if (node->next && lys_parent(node->next) && (lys_parent(node->next)->nodetype == LYS_CHOICE)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200165 next_is_case = 1;
166 }
167 }
Michal Vasko14410462015-06-05 15:08:54 +0200168
Michal Vasko07898f92015-06-15 12:17:11 +0200169 /* next is a node that will actually be printed */
Michal Vasko568b1952018-01-30 15:53:30 +0100170 has_next = tree_sibling_is_valid_child(node, 0, opts->module, aug_parent, node->nodetype);
Michal Vasko14410462015-06-05 15:08:54 +0200171
Michal Vasko568b1952018-01-30 15:53:30 +0100172 /* set level indent */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200173 if (has_next && !next_is_case) {
Michal Vasko03d8cd22018-02-08 14:48:28 +0100174 opts->indent |= (uint64_t)1ULL << (level - 1);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200175 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200176}
177
Michal Vasko568b1952018-01-30 15:53:30 +0100178static uint16_t
179tree_get_max_name_len(const struct lys_node *sibling, const struct lys_node *aug_parent, int type_mask,
180 tp_opts *opts)
Michal Vasko8d479bd2015-06-05 10:50:03 +0200181{
Michal Vasko1e62a092015-12-01 12:27:20 +0100182 const struct lys_node *sub;
Michal Vasko568b1952018-01-30 15:53:30 +0100183 struct lys_module *nodemod;
184 unsigned int max_name_len = 0, name_len;
Michal Vasko8d479bd2015-06-05 10:50:03 +0200185
Michal Vasko568b1952018-01-30 15:53:30 +0100186 LY_TREE_FOR(sibling, sub) {
187 if (opts->module->type && (sub->module != opts->module)) {
Michal Vaskobda37192016-02-15 11:09:13 +0100188 /* when printing submodule, we are only concerned with its own data (they are in the module data) */
189 continue;
190 }
Michal Vasko568b1952018-01-30 15:53:30 +0100191 if (aug_parent && (sub->parent != aug_parent)) {
192 /* when printing augment children, skip other target children */
193 continue;
194 }
195 if (!(sub->nodetype & type_mask)) {
196 /* this sibling will not be printed */
197 continue;
198 }
Michal Vaskobda37192016-02-15 11:09:13 +0100199
Michal Vasko568b1952018-01-30 15:53:30 +0100200 if ((sub->nodetype == LYS_USES) && !(opts->options & LYS_OUTOPT_TREE_USES)) {
201 name_len = tree_get_max_name_len(sub->child, NULL, type_mask, opts);
202 } else {
203 nodemod = lys_node_module(sub);
204 name_len = strlen(sub->name);
205 if (lys_main_module(opts->module) != nodemod) {
206 /* ":" */
207 ++name_len;
208 if (opts->options & LYS_OUTOPT_TREE_RFC) {
209 name_len += strlen(nodemod->prefix);
210 } else {
211 name_len += strlen(nodemod->name);
212 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200213 }
Michal Vasko568b1952018-01-30 15:53:30 +0100214
215 /* add characters for optional opts */
216 switch (sub->nodetype) {
217 case LYS_LEAF:
218 case LYS_LEAFLIST:
219 case LYS_LIST:
220 case LYS_ANYDATA:
221 case LYS_ANYXML:
222 case LYS_CONTAINER:
223 case LYS_CASE:
224 ++name_len;
225 break;
226 case LYS_CHOICE:
227 /* choice is longer :-/ */
228 name_len += 2;
229 if (!(sub->flags & LYS_MAND_TRUE)) {
230 ++name_len;
231 }
232 break;
233 default:
234 break;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200235 }
236 }
Michal Vasko568b1952018-01-30 15:53:30 +0100237
238 if (name_len > max_name_len) {
239 max_name_len = name_len;
240 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200241 }
Michal Vasko8d479bd2015-06-05 10:50:03 +0200242
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200243 return max_name_len;
Michal Vasko8d479bd2015-06-05 10:50:03 +0200244}
245
Michal Vasko568b1952018-01-30 15:53:30 +0100246static int
247tree_leaf_is_mandatory(const struct lys_node *node)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200248{
Michal Vasko568b1952018-01-30 15:53:30 +0100249 const struct lys_node *parent;
Radek Krejcib8048692015-08-05 13:36:34 +0200250 struct lys_node_list *list;
Michal Vasko568b1952018-01-30 15:53:30 +0100251 uint16_t i;
Michal Vasko449afde2015-06-04 16:06:49 +0200252
Michal Vaskodcf98e62016-05-05 17:53:53 +0200253 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci69372e22015-08-13 09:55:27 +0200254 if (parent && parent->nodetype == LYS_LIST) {
Radek Krejcib8048692015-08-05 13:36:34 +0200255 list = (struct lys_node_list *)parent;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200256 for (i = 0; i < list->keys_size; i++) {
Michal Vasko568b1952018-01-30 15:53:30 +0100257 if (list->keys[i] == (struct lys_node_leaf *)node) {
258 return 1;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200259 }
260 }
261 }
Michal Vasko449afde2015-06-04 16:06:49 +0200262
Michal Vasko568b1952018-01-30 15:53:30 +0100263 return 0;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200264}
265
Michal Vasko568b1952018-01-30 15:53:30 +0100266static int
267tree_print_wrap(struct lyout *out, int level, int line_printed, uint8_t indent, uint16_t len, tp_opts *opts)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200268{
Michal Vasko568b1952018-01-30 15:53:30 +0100269 if (opts->line_length && (line_printed + indent + len > opts->line_length)) {
270 ly_print(out, "\n");
271 line_printed = tree_print_indent(out, level, opts);
272 /* 3 for config + space */
273 line_printed += ly_print(out, "%*s", 3 + LY_TREE_WRAP_INDENT, "");
274 } else {
275 line_printed += ly_print(out, "%*s", indent, "");
276 }
Michal Vasko449afde2015-06-04 16:06:49 +0200277
Michal Vasko568b1952018-01-30 15:53:30 +0100278 return line_printed;
279}
Michal Vaskob5c75d72015-06-15 12:16:52 +0200280
Michal Vasko568b1952018-01-30 15:53:30 +0100281static int
282tree_print_prefix(struct lyout *out, const struct lys_node *node, tp_opts *opts)
283{
284 uint16_t ret = 0;
285 const struct lys_module *nodemod;
Michal Vaskob5c75d72015-06-15 12:16:52 +0200286
Michal Vaskobda37192016-02-15 11:09:13 +0100287 nodemod = lys_node_module(node);
Michal Vasko568b1952018-01-30 15:53:30 +0100288 if (lys_main_module(opts->module) != nodemod) {
289 if (opts->options & LYS_OUTOPT_TREE_RFC) {
290 ret = ly_print(out, "%s:", nodemod->prefix);
291 } else {
292 ret = ly_print(out, "%s:", nodemod->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200293 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200294 }
Michal Vaskob5c75d72015-06-15 12:16:52 +0200295
Michal Vasko568b1952018-01-30 15:53:30 +0100296 return ret;
297}
Michal Vasko28c6b572015-06-18 12:43:31 +0200298
Michal Vasko568b1952018-01-30 15:53:30 +0100299static int
300tree_print_type(struct lyout *out, const struct lys_type *type, int options, const char **out_str)
301{
302 struct lys_module *type_mod = ((struct lys_tpdf *)type->parent)->module;
303 const char *str;
304 char *tmp;
305 int printed;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200306
Michal Vasko568b1952018-01-30 15:53:30 +0100307 if ((type->base == LY_TYPE_LEAFREF) && !type->der->module) {
308 if (options & LYS_OUTOPT_TREE_NO_LEAFREF) {
309 if (out_str) {
310 printed = 7;
311 *out_str = lydict_insert(type_mod->ctx, "leafref", printed);
312 } else {
313 printed = ly_print(out, "leafref");
314 }
315 } else {
316 if (options & LYS_OUTOPT_TREE_RFC) {
317 str = transform_json2schema(type_mod, type->info.lref.path);
318 if (out_str) {
319 printed = 3 + strlen(str);
320 tmp = malloc(printed + 1);
Michal Vasko53b7da02018-02-13 15:28:42 +0100321 LY_CHECK_ERR_RETURN(!tmp, LOGMEM(type_mod->ctx), 0);
Michal Vasko568b1952018-01-30 15:53:30 +0100322 sprintf(tmp, "-> %s", str);
323 *out_str = lydict_insert_zc(type_mod->ctx, tmp);
324 } else {
325 printed = ly_print(out, "-> %s", str);
326 }
327 lydict_remove(type_mod->ctx, str);
328 } else {
329 if (out_str) {
330 printed = 3 + strlen(type->info.lref.path);
331 tmp = malloc(printed + 1);
Michal Vasko53b7da02018-02-13 15:28:42 +0100332 LY_CHECK_ERR_RETURN(!tmp, LOGMEM(type_mod->ctx), 0);
Michal Vasko568b1952018-01-30 15:53:30 +0100333 sprintf(tmp, "-> %s", type->info.lref.path);
334 *out_str = lydict_insert_zc(type_mod->ctx, tmp);
335 } else {
336 printed = ly_print(out, "-> %s", type->info.lref.path);
337 }
338 }
Michal Vasko3510f892016-02-15 14:33:52 +0100339 }
Michal Vasko568b1952018-01-30 15:53:30 +0100340 } else if (!lys_type_is_local(type)) {
341 if (options & LYS_OUTOPT_TREE_RFC) {
342 str = transform_module_name2import_prefix(type_mod, type->der->module->name);
343 if (out_str) {
344 printed = strlen(str) + 1 + strlen(type->der->name);
345 tmp = malloc(printed + 1);
Michal Vasko53b7da02018-02-13 15:28:42 +0100346 LY_CHECK_ERR_RETURN(!tmp, LOGMEM(type_mod->ctx), 0);
Michal Vasko568b1952018-01-30 15:53:30 +0100347 sprintf(tmp, "%s:%s", str, type->der->name);
348 *out_str = lydict_insert_zc(type_mod->ctx, tmp);
349 } else {
350 printed = ly_print(out, "%s:%s", str, type->der->name);
351 }
352 } else {
353 if (out_str) {
354 printed = strlen(type->der->module->name) + 1 + strlen(type->der->name);
355 tmp = malloc(printed + 1);
Michal Vasko53b7da02018-02-13 15:28:42 +0100356 LY_CHECK_ERR_RETURN(!tmp, LOGMEM(type_mod->ctx), 0);
Michal Vasko568b1952018-01-30 15:53:30 +0100357 sprintf(tmp, "%s:%s", type->der->module->name, type->der->name);
358 *out_str = lydict_insert_zc(type_mod->ctx, tmp);
359 } else {
360 printed = ly_print(out, "%s:%s", type->der->module->name, type->der->name);
361 }
362 }
363 } else {
364 if (out_str) {
365 printed = strlen(type->der->name);
366 *out_str = lydict_insert(type_mod->ctx, type->der->name, printed);
367 } else {
368 printed = ly_print(out, "%s", type->der->name);
369 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200370 }
Michal Vasko568b1952018-01-30 15:53:30 +0100371
372 return printed;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200373}
374
Michal Vasko568b1952018-01-30 15:53:30 +0100375static int
376tree_print_config(struct lyout *out, const struct lys_node *node, int spec_config)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200377{
Michal Vasko568b1952018-01-30 15:53:30 +0100378 int ret;
Radek Krejci7e97c352015-06-19 16:26:34 +0200379
Michal Vasko568b1952018-01-30 15:53:30 +0100380 switch (node->nodetype) {
381 case LYS_RPC:
382 case LYS_ACTION:
383 return ly_print(out, "-x ");
384 case LYS_NOTIF:
385 return ly_print(out, "-n ");
386 case LYS_USES:
387 return ly_print(out, "-u ");
388 case LYS_CASE:
389 return ly_print(out, ":(");
390 default:
391 break;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200392 }
Michal Vasko568b1952018-01-30 15:53:30 +0100393
Michal Vasko0fc09972018-01-30 16:24:58 +0100394 if (spec_config == 1) {
Michal Vasko568b1952018-01-30 15:53:30 +0100395 ret = ly_print(out, "-w ");
396 } else if (spec_config == 2) {
397 ret = ly_print(out, "ro ");
Michal Vasko0fc09972018-01-30 16:24:58 +0100398 } else {
399 ret = ly_print(out, "%s ", (node->flags & LYS_CONFIG_W) ? "rw" : (node->flags & LYS_CONFIG_R) ? "ro" : "--");
Michal Vasko568b1952018-01-30 15:53:30 +0100400 }
401
402 if (node->nodetype == LYS_CHOICE) {
403 ret += ly_print(out, "(");
404 }
405 return ret;
Michal Vasko5ed10f12015-06-04 10:04:57 +0200406}
407
Michal Vasko568b1952018-01-30 15:53:30 +0100408static int
409tree_print_features(struct lyout *out, struct lys_iffeature *iff1, uint8_t iff1_size, struct lys_iffeature *iff2,
410 uint8_t iff2_size, tp_opts *opts, const char **out_str)
Michal Vaskob5c75d72015-06-15 12:16:52 +0200411{
Michal Vasko568b1952018-01-30 15:53:30 +0100412 int i, printed;
413 struct lyout *o;
Radek Krejci7e97c352015-06-19 16:26:34 +0200414
Michal Vasko568b1952018-01-30 15:53:30 +0100415 if (!iff1_size && !iff2_size) {
416 return 0;
417 }
418
419 if (out_str) {
420 o = malloc(sizeof *o);
Michal Vasko53b7da02018-02-13 15:28:42 +0100421 LY_CHECK_ERR_RETURN(!o, LOGMEM(NULL), 0);
Michal Vasko568b1952018-01-30 15:53:30 +0100422 o->type = LYOUT_MEMORY;
423 o->method.mem.buf = NULL;
424 o->method.mem.len = 0;
425 o->method.mem.size = 0;
426 } else {
427 o = out;
428 }
429
430 printed = ly_print(o, "{");
431 for (i = 0; i < iff1_size; i++) {
432 if (i > 0) {
433 printed += ly_print(o, ",");
434 }
435 printed += ly_print_iffeature(o, opts->module, &iff1[i], opts->options & LYS_OUTOPT_TREE_RFC ? 2 : 1);
436 }
437 for (i = 0; i < iff2_size; i++) {
438 if (i > 0) {
439 printed += ly_print(o, ",");
440 }
441 printed += ly_print_iffeature(o, opts->module, &iff2[i], opts->options & LYS_OUTOPT_TREE_RFC ? 2 : 1);
442 }
443 printed += ly_print(o, "}?");
444
445 if (out_str) {
446 *out_str = lydict_insert_zc(opts->module->ctx, o->method.mem.buf);
447 free(o);
448 }
449
450 return printed;
451}
452
453static int
454tree_print_keys(struct lyout *out, struct lys_node_leaf **keys, uint8_t keys_size, tp_opts *opts, const char **out_str)
455{
456 int i, printed;
457 struct lyout *o;
458
459 if (!keys_size) {
460 return 0;
461 }
462
463 if (out_str) {
464 o = malloc(sizeof *o);
Michal Vasko53b7da02018-02-13 15:28:42 +0100465 LY_CHECK_ERR_RETURN(!o, LOGMEM(NULL), 0);
Michal Vasko568b1952018-01-30 15:53:30 +0100466 o->type = LYOUT_MEMORY;
467 o->method.mem.buf = NULL;
468 o->method.mem.len = 0;
469 o->method.mem.size = 0;
470 } else {
471 o = out;
472 }
473
474 printed = ly_print(o, "[");
475 for (i = 0; i < keys_size; i++) {
476 printed += ly_print(o, "%s%s", keys[i]->name, i + 1 < keys_size ? " " : "]");
477 }
478
479 if (out_str) {
480 *out_str = lydict_insert_zc(opts->module->ctx, o->method.mem.buf);
481 free(o);
482 }
483
484 return printed;
485}
486
487/**
488 * @brief Print schema node in YANG tree diagram formatting.
489 *
490 * @param[in] out libyang output.
491 * @param[in] level Current level of depth.
492 * @param[in] max_name_len Maximal name length of all the siblings (relevant only for nodes with type).
493 * @param[in] node Schema node to print.
494 * @param[in] mask Type mask of children nodes to be printed.
495 * @param[in] aug_parent Augment node parent in case we are printing its direct children.
496 * @param[in] opts Tree printer options structure.
497 */
498static void
499tree_print_snode(struct lyout *out, int level, uint16_t max_name_len, const struct lys_node *node, int mask,
500 const struct lys_node *aug_parent, int subtree, tp_opts *opts)
501{
502 struct lys_node *sub;
503 int line_len, node_len, child_mask;
504 uint8_t text_len, text_indent;
505 uint16_t max_child_len;
506 const char *text_str;
507
508 /* disabled/not printed node */
509 if (lys_is_disabled(node, (node->parent && node->parent->nodetype == LYS_AUGMENT) ? 1 : 0) || !(node->nodetype & mask)) {
Michal Vaskoefbb3192015-07-08 10:35:00 +0200510 return;
Radek Krejci7e97c352015-06-19 16:26:34 +0200511 }
Michal Vaskob5c75d72015-06-15 12:16:52 +0200512
Michal Vaskoe0f11be2018-03-02 14:08:22 +0100513 /* implicit input/output/case */
514 if (((node->nodetype & mask) & (LYS_INPUT | LYS_OUTPUT | LYS_CASE)) && (node->flags & LYS_IMPLICIT)) {
515 if ((node->nodetype != LYS_CASE) || lys_is_disabled(node->child, 0)) {
516 return;
517 }
Radek Krejci7e97c352015-06-19 16:26:34 +0200518 }
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200519
Michal Vasko568b1952018-01-30 15:53:30 +0100520 /* special uses and grouping handling */
Radek Krejci1d82ef62015-08-07 14:44:40 +0200521 switch (node->nodetype & mask) {
Michal Vasko568b1952018-01-30 15:53:30 +0100522 case LYS_USES:
523 if (opts->options & LYS_OUTOPT_TREE_USES) {
524 break;
525 }
526 /* fallthrough */
527 case LYS_GROUPING:
528 goto print_children;
529 default:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200530 break;
Michal Vasko568b1952018-01-30 15:53:30 +0100531 }
532
533 /* print indent */
534 line_len = tree_print_indent(out, level, opts);
535 /* print status */
536 line_len += ly_print(out, "%s--", (node->flags & LYS_STATUS_DEPRC ? "x" : (node->flags & LYS_STATUS_OBSLT ? "o" : "+")));
537 /* print config flags (or special opening for case, choice) */
538 line_len += tree_print_config(out, node, opts->spec_config);
539 /* print optionally prefix */
540 node_len = tree_print_prefix(out, node, opts);
541 /* print name */
542 node_len += ly_print(out, node->name);
543
544 /* print one-character opts */
545 switch (node->nodetype & mask) {
Radek Krejci76512572015-08-04 09:47:08 +0200546 case LYS_LEAF:
Michal Vasko568b1952018-01-30 15:53:30 +0100547 if (!(node->flags & LYS_MAND_TRUE) && !tree_leaf_is_mandatory(node)) {
548 node_len += ly_print(out, "?");
549 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200550 break;
Michal Vasko568b1952018-01-30 15:53:30 +0100551 case LYS_ANYDATA:
552 case LYS_ANYXML:
553 if (!(node->flags & LYS_MAND_TRUE)) {
554 node_len += ly_print(out, "?");
555 }
556 break;
557 case LYS_CONTAINER:
558 if (((struct lys_node_container *)node)->presence) {
559 node_len += ly_print(out, "!");
560 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200561 break;
Radek Krejci76512572015-08-04 09:47:08 +0200562 case LYS_LIST:
Michal Vasko568b1952018-01-30 15:53:30 +0100563 case LYS_LEAFLIST:
564 node_len += ly_print(out, "*");
Michal Vaskoca7cbc42016-07-01 11:36:53 +0200565 break;
Michal Vaskod4742e62016-02-15 15:11:55 +0100566 case LYS_CASE:
Michal Vasko568b1952018-01-30 15:53:30 +0100567 /* kinda shady, but consistent in a way */
568 node_len += ly_print(out, ")");
569 break;
570 case LYS_CHOICE:
571 node_len += ly_print(out, ")");
572 if (!(node->flags & LYS_MAND_TRUE)) {
573 node_len += ly_print(out, "?");
574 }
575 break;
576 default:
577 break;
578 }
579 line_len += node_len;
580
581 /**
582 * wrapped print
583 */
584
585 /* learn next level indent (there is never a sibling for subtree) */
586 ++level;
587 if (!subtree) {
588 tree_next_indent(level, node, aug_parent, opts);
589 }
590
591 /* print type/keys */
592 switch (node->nodetype & mask) {
593 case LYS_LEAF:
594 case LYS_LEAFLIST:
595 assert(max_name_len);
596 text_indent = LY_TREE_TYPE_INDENT + (uint8_t)(max_name_len - node_len);
597 text_len = tree_print_type(out, &((struct lys_node_leaf *)node)->type, opts->options, &text_str);
598 line_len = tree_print_wrap(out, level, line_len, text_indent, text_len, opts);
599 line_len += ly_print(out, text_str);
600 lydict_remove(opts->module->ctx, text_str);
601 break;
602 case LYS_ANYDATA:
603 assert(max_name_len);
604 text_indent = LY_TREE_TYPE_INDENT + (uint8_t)(max_name_len - node_len);
605 line_len = tree_print_wrap(out, level, line_len, text_indent, 7, opts);
606 line_len += ly_print(out, "anydata");
607 break;
608 case LYS_ANYXML:
609 assert(max_name_len);
610 text_indent = LY_TREE_TYPE_INDENT + (uint8_t)(max_name_len - node_len);
611 line_len = tree_print_wrap(out, level, line_len, text_indent, 6, opts);
612 line_len += ly_print(out, "anyxml");
613 break;
614 case LYS_LIST:
615 text_len = tree_print_keys(out, ((struct lys_node_list *)node)->keys, ((struct lys_node_list *)node)->keys_size,
616 opts, &text_str);
617 if (text_len) {
618 line_len = tree_print_wrap(out, level, line_len, 1, text_len, opts);
619 line_len += ly_print(out, text_str);
620 lydict_remove(opts->module->ctx, text_str);
621 }
622 break;
623 default:
624 break;
625 }
626
627 /* print default */
628 if (!(opts->options & LYS_OUTOPT_TREE_RFC)) {
629 switch (node->nodetype & mask) {
630 case LYS_LEAF:
631 text_str = ((struct lys_node_leaf *)node)->dflt;
632 if (text_str) {
633 line_len = tree_print_wrap(out, level, line_len, 1, 2 + strlen(text_str), opts);
634 line_len += ly_print(out, "<%s>", text_str);
635 }
636 break;
637 case LYS_CHOICE:
638 sub = ((struct lys_node_choice *)node)->dflt;
639 if (sub) {
640 line_len = tree_print_wrap(out, level, line_len, 1, 2 + strlen(sub->name), opts);
641 line_len += ly_print(out, "<%s>", sub->name);
642 }
643 break;
644 default:
645 break;
646 }
647 }
648
649 /* print if-features */
650 switch (node->nodetype & mask) {
651 case LYS_CONTAINER:
652 case LYS_LIST:
653 case LYS_CHOICE:
654 case LYS_CASE:
655 case LYS_ANYDATA:
656 case LYS_ANYXML:
657 case LYS_LEAF:
658 case LYS_LEAFLIST:
659 case LYS_RPC:
660 case LYS_ACTION:
661 case LYS_NOTIF:
662 case LYS_USES:
663 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)) {
664 /* if-features from an augment are de facto inherited */
665 text_len = tree_print_features(out, node->iffeature, node->iffeature_size,
666 node->parent->iffeature, node->parent->iffeature_size, opts, &text_str);
667 } else {
668 text_len = tree_print_features(out, node->iffeature, node->iffeature_size, NULL, 0, opts, &text_str);
669 }
670 if (text_len) {
671 line_len = tree_print_wrap(out, level, line_len, 1, text_len, opts);
672 line_len += ly_print(out, text_str);
673 lydict_remove(opts->module->ctx, text_str);
674 }
675 break;
676 default:
677 /* only grouping */
678 break;
679 }
680
681 /* this node is finished printing */
682 ly_print(out, "\n");
683
684 if ((subtree == 1) || ((node->nodetype & mask) == LYS_USES)) {
685 /* we are printing subtree parents, finish here (or uses option) */
686 return;
687 }
688
689 /* set special config flag */
690 switch (node->nodetype & mask) {
691 case LYS_INPUT:
692 opts->spec_config = 1;
693 break;
694 case LYS_OUTPUT:
695 case LYS_NOTIF:
696 opts->spec_config = 2;
697 break;
698 default:
699 break;
700 }
701
702print_children:
703 /* set child mask and learn the longest child name (needed only if a child can have type) */
704 switch (node->nodetype & mask) {
705 case LYS_LEAF:
706 case LYS_LEAFLIST:
707 case LYS_ANYDATA:
708 case LYS_ANYXML:
709 child_mask = 0;
710 max_child_len = 0;
711 break;
712 case LYS_RPC:
713 case LYS_ACTION:
714 child_mask = LYS_INPUT | LYS_OUTPUT;
715 max_child_len = 0;
716 break;
717 case LYS_CHOICE:
718 child_mask = LYS_CASE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA;
719 max_child_len = tree_get_max_name_len(node->child, NULL, child_mask, opts);
720 break;
721 case LYS_CASE:
722 case LYS_NOTIF:
723 child_mask = LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_USES;
724 max_child_len = tree_get_max_name_len(node->child, NULL, child_mask, opts);
725 break;
726 case LYS_INPUT:
727 case LYS_OUTPUT:
728 child_mask = LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_USES;
729 max_child_len = tree_get_max_name_len(node->child, NULL, child_mask, opts);
730 break;
731 case LYS_USES:
732 child_mask = LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_USES | LYS_ACTION | LYS_NOTIF;
733 /* inherit the name length from the parent, it does not change */
734 max_child_len = max_name_len;
735 break;
736 case LYS_CONTAINER:
737 case LYS_LIST:
738 case LYS_GROUPING:
739 child_mask = LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_USES | LYS_ACTION | LYS_NOTIF;
740 max_child_len = tree_get_max_name_len(node->child, NULL, child_mask, opts);
741 break;
Michal Vaskod1bf7c42018-02-15 08:38:49 +0100742 default:
743 child_mask = 0;
744 max_child_len = 0;
745 LOGINT(node->module->ctx);
746 break;
Michal Vasko568b1952018-01-30 15:53:30 +0100747 }
748
749 /* print descendants (children) */
750 if (child_mask) {
751 LY_TREE_FOR(node->child, sub) {
752 /* submodule, foreign augments */
753 if (opts->module->type && (sub->parent != node) && (sub->module != opts->module)) {
754 continue;
755 }
756 tree_print_snode(out, level, max_child_len, sub, child_mask, NULL, 0, opts);
757 }
758 }
759
760 /* reset special config flag */
761 switch (node->nodetype & mask) {
762 case LYS_INPUT:
763 case LYS_OUTPUT:
764 case LYS_NOTIF:
765 opts->spec_config = 0;
Michal Vaskod4742e62016-02-15 15:11:55 +0100766 break;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200767 default:
768 break;
769 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200770}
771
Michal Vasko568b1952018-01-30 15:53:30 +0100772static void
773tree_print_subtree(struct lyout *out, const struct lys_node *node, tp_opts *opts)
774{
775 unsigned int depth, i, j;
776 int level = 0;
777 const struct lys_node *parent;
778
779 /* learn the depth of the node */
780 depth = 0;
781 parent = node;
782 while (lys_parent(parent)) {
783 if (lys_parent(parent)->nodetype != LYS_USES) {
784 ++depth;
785 }
786 parent = lys_parent(parent);
787 }
788
789 if (parent->nodetype == LYS_RPC) {
790 ly_print(out, "\n%*srpcs:\n", LY_TREE_MOD_DATA_INDENT, "");
791 opts->base_indent = LY_TREE_OP_DATA_INDENT;
792 } else if (parent->nodetype == LYS_NOTIF) {
793 ly_print(out, "\n%*snotifications:\n", LY_TREE_MOD_DATA_INDENT, "");
794 opts->base_indent = LY_TREE_OP_DATA_INDENT;
795 }
796
797 /* print all the parents */
798 if (depth) {
799 i = depth;
800 do {
801 parent = node;
802 for (j = 0; j < i; ++j) {
803 do {
804 parent = lys_parent(parent);
805 } while (parent->nodetype == LYS_USES);
806 }
807
808 tree_print_snode(out, level, 0, parent, LYS_CONTAINER | LYS_LIST | LYS_NOTIF | LYS_RPC | LYS_ACTION
809 | LYS_INPUT | LYS_OUTPUT, NULL, 1, opts);
810
811 ++level;
812 --i;
813 } while (i);
814 }
815
816 /* print the node and its descendants */
817 tree_print_snode(out, level, 0, node, LYS_ANY, NULL, 2, opts);
818}
819
820static int
821tree_print_aug_target(struct lyout *out, int line_printed, uint8_t indent, const char *path, tp_opts *opts)
822{
823 int printed, is_last, len;
824 const char *cur, *next;
825
826 printed = line_printed;
827 cur = path;
828 do {
829 next = strchr(cur + 1, '/');
830 if (!next) {
831 len = strlen(cur) + 1;
832 is_last = 1;
833 } else {
834 len = next - cur;
835 is_last = 0;
836 }
837
838 if (opts->line_length && cur != path && (printed + len > opts->line_length)) {
839 /* line_printed is treated as the base indent */
840 printed = ly_print(out, "\n%*s", line_printed + indent, "");
841 /* minus the newline */
842 --printed;
843 }
844 printed += ly_print(out, "%.*s%s", len, cur, is_last ? ":" : "");
845
846 cur = next;
847 } while (!is_last);
848
849 return printed;
850}
851
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200852int
Michal Vasko568b1952018-01-30 15:53:30 +0100853tree_print_model(struct lyout *out, const struct lys_module *module, const char *target_schema_path,
854 int ll, int options)
Michal Vasko5ed10f12015-06-04 10:04:57 +0200855{
Michal Vaskofb446d52018-08-01 11:42:42 +0200856 struct lys_node *node = NULL, *data, *aug;
Michal Vasko568b1952018-01-30 15:53:30 +0100857 struct ly_set *set;
858 uint16_t max_child_len;
859 int have_rpcs = 0, have_notifs = 0, have_grps = 0, have_augs = 0, printed;
860 const char *str;
861 int i, mask;
862 tp_opts opts;
863
864 memset(&opts, 0, sizeof opts);
865 opts.module = module;
866 opts.line_length = ll;
867 opts.options = options;
868
869 /* we are printing only a subtree */
870 if (target_schema_path) {
871 set = lys_find_path(module, NULL, target_schema_path);
872 if (!set) {
873 return EXIT_FAILURE;
874 } else if (set->number != 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100875 LOGVAL(module->ctx, LYE_PATH_INNODE, LY_VLOG_NONE, NULL);
Michal Vasko568b1952018-01-30 15:53:30 +0100876 if (set->number == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100877 LOGVAL(module->ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Schema path \"%s\" did not match any nodes.", target_schema_path);
Michal Vasko568b1952018-01-30 15:53:30 +0100878 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +0100879 LOGVAL(module->ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Schema path \"%s\" matched more nodes.", target_schema_path);
Michal Vasko568b1952018-01-30 15:53:30 +0100880 }
881 ly_set_free(set);
882 return EXIT_FAILURE;
883 }
884
885 node = set->set.s[0];
886 ly_set_free(set);
887 }
Michal Vasko253035f2015-12-17 16:58:13 +0100888
Michal Vaskofc6ac172015-07-07 09:46:46 +0200889 if (module->type) {
Michal Vasko568b1952018-01-30 15:53:30 +0100890 ly_print(out, "submodule: %s", module->name);
Michal Vaskobda37192016-02-15 11:09:13 +0100891 data = ((struct lys_submodule *)module)->belongsto->data;
Michal Vasko568b1952018-01-30 15:53:30 +0100892 if (options & LYS_OUTOPT_TREE_RFC) {
893 ly_print(out, "\n");
894 } else {
895 ly_print(out, " (belongs-to %s)\n", ((struct lys_submodule *)module)->belongsto->name);
896 }
Michal Vaskofc6ac172015-07-07 09:46:46 +0200897 } else {
Radek Krejci76b07902015-10-09 09:11:25 +0200898 ly_print(out, "module: %s\n", module->name);
Michal Vaskobda37192016-02-15 11:09:13 +0100899 data = module->data;
Michal Vaskofc6ac172015-07-07 09:46:46 +0200900 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200901
Michal Vasko568b1952018-01-30 15:53:30 +0100902 /* only subtree */
903 if (target_schema_path) {
904 opts.base_indent = LY_TREE_MOD_DATA_INDENT;
905 tree_print_subtree(out, node, &opts);
906 return EXIT_SUCCESS;
907 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200908
Michal Vasko568b1952018-01-30 15:53:30 +0100909 /* module */
910 opts.base_indent = LY_TREE_MOD_DATA_INDENT;
911 mask = LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_USES;
912 max_child_len = tree_get_max_name_len(data, NULL, mask, &opts);
Michal Vaskobda37192016-02-15 11:09:13 +0100913 LY_TREE_FOR(data, node) {
Michal Vasko568b1952018-01-30 15:53:30 +0100914 if (opts.module->type && (node->module != opts.module)) {
Michal Vaskobda37192016-02-15 11:09:13 +0100915 /* we're printing the submodule only */
916 continue;
917 }
918
Michal Vasko568b1952018-01-30 15:53:30 +0100919 switch (node->nodetype) {
Radek Krejci92720552015-10-05 15:28:27 +0200920 case LYS_RPC:
Radek Krejciadf7a8e2015-12-10 13:11:17 +0100921 if (!lys_is_disabled(node, 0)) {
922 have_rpcs++;
923 }
Radek Krejci92720552015-10-05 15:28:27 +0200924 break;
925 case LYS_NOTIF:
Radek Krejciadf7a8e2015-12-10 13:11:17 +0100926 if (!lys_is_disabled(node, 0)) {
927 have_notifs++;
928 }
Radek Krejci92720552015-10-05 15:28:27 +0200929 break;
Radek Krejcid5bf08e2017-01-25 11:35:04 +0100930 case LYS_GROUPING:
Michal Vasko568b1952018-01-30 15:53:30 +0100931 if ((options & LYS_OUTOPT_TREE_GROUPING) && !lys_is_disabled(node, 0)) {
Radek Krejcid5bf08e2017-01-25 11:35:04 +0100932 have_grps++;
933 }
934 break;
Radek Krejci92720552015-10-05 15:28:27 +0200935 default:
Michal Vasko568b1952018-01-30 15:53:30 +0100936 tree_print_snode(out, 0, max_child_len, node, mask, NULL, 0, &opts);
Radek Krejci92720552015-10-05 15:28:27 +0200937 break;
938 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200939 }
Michal Vasko5ed10f12015-06-04 10:04:57 +0200940
Michal Vasko568b1952018-01-30 15:53:30 +0100941 /* all remaining nodes printed with operation indent */
942 opts.base_indent = LY_TREE_OP_DATA_INDENT;
943
944 /* augments */
Radek Krejcid49202f2016-02-11 12:53:39 +0100945 for (i = 0; i < module->augment_size; i++) {
Michal Vasko861ee6d2016-02-15 15:11:31 +0100946 if ((module->type && (module->augment[i].target->module == module))
Michal Vasko9089c8d2016-10-25 09:23:53 +0200947 || (!module->type && (lys_node_module(module->augment[i].target) == module))
948 || lys_is_disabled((struct lys_node *)&module->augment[i], 0)) {
Michal Vaskoe79abe82016-02-15 12:33:23 +0100949 /* submodule, target is our submodule or module, target is in our module or any submodules */
950 continue;
951 }
952
Michal Vasko568b1952018-01-30 15:53:30 +0100953 if (!have_augs) {
954 ly_print(out, "\n");
955 have_augs = 1;
956 }
957
958 printed = ly_print(out, "%*saugment ", LY_TREE_MOD_DATA_INDENT, "");
959 if (options & LYS_OUTOPT_TREE_RFC) {
960 str = transform_json2schema(module, module->augment[i].target_name);
961 tree_print_aug_target(out, printed, LY_TREE_WRAP_INDENT, str, &opts);
962 lydict_remove(module->ctx, str);
963 } else {
964 tree_print_aug_target(out, printed, LY_TREE_WRAP_INDENT, module->augment[i].target_name, &opts);
965 }
966 ly_print(out, "\n");
967
Michal Vaskofb446d52018-08-01 11:42:42 +0200968 aug = (struct lys_node *)&module->augment[i];
Michal Vasko568b1952018-01-30 15:53:30 +0100969 mask = LYS_CHOICE | LYS_CASE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_USES
970 | LYS_ACTION | LYS_NOTIF;
Michal Vaskofb446d52018-08-01 11:42:42 +0200971 max_child_len = tree_get_max_name_len(aug->child, aug, mask, &opts);
972 LY_TREE_FOR(aug->child, node) {
Michal Vaskod4742e62016-02-15 15:11:55 +0100973 /* submodule, foreign augments */
Michal Vaskofb446d52018-08-01 11:42:42 +0200974 if (node->parent != aug) {
Michal Vaskod4742e62016-02-15 15:11:55 +0100975 continue;
976 }
Michal Vaskofb446d52018-08-01 11:42:42 +0200977 tree_print_snode(out, 0, max_child_len, node, mask, aug, 0, &opts);
Radek Krejcid49202f2016-02-11 12:53:39 +0100978 }
979 }
980
Michal Vasko568b1952018-01-30 15:53:30 +0100981 /* rpcs */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200982 if (have_rpcs) {
Michal Vasko568b1952018-01-30 15:53:30 +0100983 ly_print(out, "\n%*srpcs:\n", LY_TREE_MOD_DATA_INDENT, "");
984
Michal Vaskobda37192016-02-15 11:09:13 +0100985 LY_TREE_FOR(data, node) {
Michal Vasko568b1952018-01-30 15:53:30 +0100986 tree_print_snode(out, 0, 0, node, LYS_RPC, NULL, 0, &opts);
Michal Vaskob5c75d72015-06-15 12:16:52 +0200987 }
988 }
Michal Vasko449afde2015-06-04 16:06:49 +0200989
Michal Vasko568b1952018-01-30 15:53:30 +0100990 /* notifications */
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200991 if (have_notifs) {
Michal Vasko568b1952018-01-30 15:53:30 +0100992 ly_print(out, "\n%*snotifications:\n", LY_TREE_MOD_DATA_INDENT, "");
993
Michal Vaskobda37192016-02-15 11:09:13 +0100994 LY_TREE_FOR(data, node) {
Michal Vasko568b1952018-01-30 15:53:30 +0100995 tree_print_snode(out, 0, 0, node, LYS_NOTIF, NULL, 0, &opts);
Michal Vaskoe03bfbb2015-06-16 09:07:49 +0200996 }
997 }
Radek Krejcid5bf08e2017-01-25 11:35:04 +0100998
999 /* groupings */
Michal Vasko568b1952018-01-30 15:53:30 +01001000 if ((options & LYS_OUTOPT_TREE_GROUPING) && have_grps) {
1001 ly_print(out, "\n");
Radek Krejcid5bf08e2017-01-25 11:35:04 +01001002 LY_TREE_FOR(data, node) {
1003 if (node->nodetype == LYS_GROUPING) {
Michal Vasko568b1952018-01-30 15:53:30 +01001004 ly_print(out, "%*sgrouping %s:\n", LY_TREE_MOD_DATA_INDENT, "", node->name);
1005
1006 tree_print_snode(out, 0, 0, node, LYS_GROUPING, NULL, 0, &opts);
Radek Krejcid5bf08e2017-01-25 11:35:04 +01001007 }
1008 }
1009 }
1010
Michal Vasko95068c42016-03-24 14:58:11 +01001011 ly_print_flush(out);
Michal Vasko449afde2015-06-04 16:06:49 +02001012
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001013 return EXIT_SUCCESS;
Michal Vasko5ed10f12015-06-04 10:04:57 +02001014}