blob: 84084af5104b54e52c5527e8f5065fedaa7bbacd [file] [log] [blame]
aPiecek61d062b2020-11-02 11:05:09 +01001/**
2 * @file printer_tree.c
3 * @author Adam Piecek <piecek@cesnet.cz>
4 * @brief RFC tree printer for libyang data structure
5 *
6 * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
7 *
8 * 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
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
aPiecek874ea4d2021-04-19 12:26:36 +020013 *
14 * @section TRP_DESIGN Design
15 *
16 * @code
aPiecek61d062b2020-11-02 11:05:09 +010017 * +---------+ +---------+ +---------+
18 * output | trp | | trb | | tro |
19 * <---+ Print +<---+ Browse +<-->+ Obtain |
20 * | | | | | |
21 * +---------+ +----+----+ +---------+
22 * ^
23 * |
24 * +----+----+
25 * | trm |
26 * | Manager |
27 * | |
28 * +----+----+
29 * ^
30 * | input
31 * +
aPiecek874ea4d2021-04-19 12:26:36 +020032 * @endcode
aPiecek61d062b2020-11-02 11:05:09 +010033 *
aPiecek874ea4d2021-04-19 12:26:36 +020034 * @subsection TRP_GLOSSARY Glossary
aPiecek61d062b2020-11-02 11:05:09 +010035 *
aPiecek874ea4d2021-04-19 12:26:36 +020036 * @subsubsection TRP_trm trm
37 * Manager functions are at the peak of abstraction. They are
38 * able to print individual sections of the YANG tree diagram
39 * (eg module, notifications, rpcs ...) and they call
40 * Browse functions (\ref TRP_trb).
aPiecek61d062b2020-11-02 11:05:09 +010041 *
aPiecek874ea4d2021-04-19 12:26:36 +020042 * @subsubsection TRP_trb trb
43 * Browse functions contain a general algorithm (Preorder DFS)
44 * for traversing the tree. It does not matter what data type
45 * the tree contains (\ref lysp_node), because it
46 * requires a ready-made getter functions for traversing the tree
47 * (\ref trt_fp_all) and transformation function to its own node
48 * data type (\ref trt_node). These getter functions are generally
49 * referred to as \ref TRP_tro. Browse functions can repeatedly
50 * traverse nodes in the tree, for example, to calculate the alignment
51 * gap before the nodes \<type\> in the YANG Tree Diagram.
52 * The obtained \ref trt_node is passed to the \ref TRP_trp functions
53 * to print the Tree diagram.
54 *
55 * @subsubsection TRP_tro tro
56 * Functions that provide an extra wrapper for the libyang library.
57 * The Obtain functions provide information to
58 * \ref TRP_trb functions for printing the Tree diagram.
59 *
60 * @subsubsection TRP_trp trp
61 * Print functions take care of the printing YANG diagram. They can
62 * also split one node into multiple lines if the node does not fit
63 * on one line.
64 *
65 * @subsubsection TRP_trt trt
66 * Data type marking in the printer_tree module.
67 *
68 * @subsubsection TRP_trg trg
69 * General functions.
70 *
71 * @subsection TRP_ADJUSTMENTS Adjustments
72 * It is assumed that the changes are likely to take place mainly for
73 * \ref TRP_tro functions because * they are the only ones dependent
74 * on libyang implementation. In special cases, changes will also need
75 * to be made to the \ref TRP_trp functions if a special algorithm is
76 * needed to print (right now this is prepared for printing list's keys
77 * and if-features).
aPiecek61d062b2020-11-02 11:05:09 +010078 */
79
aPiecek874ea4d2021-04-19 12:26:36 +020080#include <assert.h>
81#include <string.h>
82
83#include "common.h"
84#include "compat.h"
85#include "out_internal.h"
86#include "tree_schema_internal.h"
87#include "xpath.h"
88
aPiecek61d062b2020-11-02 11:05:09 +010089/**
90 * @brief List of available actions.
91 */
92typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +020093 TRD_PRINT = 0, /**< Normal behavior. It just prints. */
94 TRD_CHAR_COUNT /**< Characters will be counted instead of printing. */
aPiecek61d062b2020-11-02 11:05:09 +010095} trt_ly_out_clb_arg_flag;
96
97/**
aPiecek874ea4d2021-04-19 12:26:36 +020098 * @brief Structure is passed as 'writeclb' argument
99 * to the ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100100 */
101struct ly_out_clb_arg {
aPiecek874ea4d2021-04-19 12:26:36 +0200102 trt_ly_out_clb_arg_flag mode; /**< flag specifying which action to take. */
103 struct ly_out *out; /**< The ly_out pointer delivered to the printer tree module via the main interface. */
104 size_t counter; /**< Counter of printed characters. */
105 LY_ERR last_error; /**< The last error that occurred. If no error has occurred, it will be ::LY_SUCCESS. */
aPiecek61d062b2020-11-02 11:05:09 +0100106};
107
108/**
109 * @brief Initialize struct ly_out_clb_arg with default settings.
110 */
111#define TRP_INIT_LY_OUT_CLB_ARG(MODE, OUT, COUNTER, LAST_ERROR) \
aPiecek874ea4d2021-04-19 12:26:36 +0200112 (struct ly_out_clb_arg) { \
113 .mode = MODE, .out = OUT, \
114 .counter = COUNTER, .last_error = LAST_ERROR \
115 }
aPiecek61d062b2020-11-02 11:05:09 +0100116
aPiecek874ea4d2021-04-19 12:26:36 +0200117/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100118 * Print getters
aPiecek874ea4d2021-04-19 12:26:36 +0200119 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100120
121/**
122 * @brief Callback functions that prints special cases.
123 *
124 * It just groups together tree context with trt_fp_print.
125 */
126struct trt_cf_print {
aPiecek874ea4d2021-04-19 12:26:36 +0200127 const struct trt_tree_ctx *ctx; /**< Context of libyang tree. */
128 void (*pf)(const struct trt_tree_ctx *, struct ly_out *); /**< Pointing to function which printing list's keys or features. */
aPiecek61d062b2020-11-02 11:05:09 +0100129};
130
131/**
132 * @brief Callback functions for printing special cases.
133 *
aPiecek874ea4d2021-04-19 12:26:36 +0200134 * Functions with the suffix 'trp' can print most of the text on
135 * output, just by setting the pointer to the string. But in some
136 * cases, it's not that simple, because its entire string is fragmented
137 * in memory. For example, for printing list's keys or if-features.
aPiecek61d062b2020-11-02 11:05:09 +0100138 * However, this depends on how the libyang library is implemented.
aPiecek61d062b2020-11-02 11:05:09 +0100139 * Functions must print including spaces or delimiters between names.
140 */
141struct trt_fp_print {
142 void (*print_features_names)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list of features without {}? wrapper. */
143 void (*print_keys)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list's keys without [] wrapper. */
144};
145
146/**
147 * @brief Package which only groups getter function.
148 */
149struct trt_pck_print {
150 const struct trt_tree_ctx *tree_ctx; /**< Context of libyang tree. */
151 struct trt_fp_print fps; /**< Print function. */
152};
153
154/**
155 * @brief Initialize struct trt_pck_print by parameters.
156 */
157#define TRP_INIT_PCK_PRINT(TREE_CTX, FP_PRINT) \
aPiecek874ea4d2021-04-19 12:26:36 +0200158 (struct trt_pck_print) {.tree_ctx = TREE_CTX, .fps = FP_PRINT}
aPiecek61d062b2020-11-02 11:05:09 +0100159
aPiecek874ea4d2021-04-19 12:26:36 +0200160/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100161 * Indent
aPiecek874ea4d2021-04-19 12:26:36 +0200162 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100163
164/**
aPiecek874ea4d2021-04-19 12:26:36 +0200165 * @brief Constants which are defined in the RFC or are observable
166 * from the pyang tool.
aPiecek61d062b2020-11-02 11:05:09 +0100167 */
168typedef enum {
169 TRD_INDENT_EMPTY = 0, /**< If the node is a case node, there is no space before the \<name\>. */
170 TRD_INDENT_LONG_LINE_BREAK = 2, /**< The new line should be indented so that it starts below \<name\> with a whitespace offset of at least two characters. */
171 TRD_INDENT_LINE_BEGIN = 2, /**< Indent below the keyword (module, augment ...). */
172 TRD_INDENT_BTW_SIBLINGS = 2, /**< Indent between | and | characters. */
173 TRD_INDENT_BEFORE_KEYS = 1, /**< "..."___\<keys\>. */
174 TRD_INDENT_BEFORE_TYPE = 4, /**< "..."___\<type\>, but if mark is set then indent == 3. */
175 TRD_INDENT_BEFORE_IFFEATURES = 1 /**< "..."___\<iffeatures\>. */
176} trt_cnf_indent;
177
178/**
179 * @brief Type of indent in node.
180 */
181typedef enum {
182 TRD_INDENT_IN_NODE_NORMAL = 0, /**< Node fits on one line. */
183 TRD_INDENT_IN_NODE_DIVIDED, /**< The node must be split into multiple rows. */
184 TRD_INDENT_IN_NODE_FAILED /**< Cannot be crammed into one line. The condition for the maximum line length is violated. */
185} trt_indent_in_node_type;
186
187/** Constant to indicate the need to break a line. */
188#define TRD_LINEBREAK -1
189
190/**
aPiecek874ea4d2021-04-19 12:26:36 +0200191 * @brief Records the alignment between the individual
192 * elements of the node.
aPiecek61d062b2020-11-02 11:05:09 +0100193 *
aPiecek874ea4d2021-04-19 12:26:36 +0200194 * @see trp_default_indent_in_node, trp_try_normal_indent_in_node
aPiecek61d062b2020-11-02 11:05:09 +0100195 */
196struct trt_indent_in_node {
197 trt_indent_in_node_type type; /**< Type of indent in node. */
aPiecek874ea4d2021-04-19 12:26:36 +0200198 int16_t btw_name_opts; /**< Indent between node name and \<opts\>. */
199 int16_t btw_opts_type; /**< Indent between \<opts\> and \<type\>. */
aPiecek61d062b2020-11-02 11:05:09 +0100200 int16_t btw_type_iffeatures; /**< Indent between type and features. Ignored if \<type\> missing. */
201};
202
203/**
204 * @brief Type of wrappers to be printed.
205 */
206typedef enum {
207 TRD_WRAPPER_TOP = 0, /**< Related to the module. */
208 TRD_WRAPPER_BODY /**< Related to e.g. Augmentations or Groupings */
209} trd_wrapper_type;
210
211/**
212 * @brief For resolving sibling symbol ('|') placement.
213 *
214 * Bit indicates where the sibling symbol must be printed.
aPiecek874ea4d2021-04-19 12:26:36 +0200215 * This place is in multiples of ::TRD_INDENT_BTW_SIBLINGS.
aPiecek61d062b2020-11-02 11:05:09 +0100216 *
aPiecek874ea4d2021-04-19 12:26:36 +0200217 * @see TRP_INIT_WRAPPER_TOP, TRP_INIT_WRAPPER_BODY,
218 * trp_wrapper_set_mark, trp_wrapper_set_shift,
219 * trp_wrapper_if_last_sibling, trp_wrapper_eq, trp_print_wrapper
aPiecek61d062b2020-11-02 11:05:09 +0100220 */
221struct trt_wrapper {
222 trd_wrapper_type type; /**< Location of the wrapper. */
223 uint64_t bit_marks1; /**< The set bits indicate where the '|' character is to be printed.
224 It follows that the maximum immersion of the printable node is 64. */
225 uint32_t actual_pos; /**< Actual position in bit_marks. */
226};
227
228/**
229 * @brief Get wrapper related to the module section.
230 *
231 * @code
232 * module: <module-name>
233 * +--<node>
234 * |
235 * @endcode
236 */
237#define TRP_INIT_WRAPPER_TOP \
aPiecek874ea4d2021-04-19 12:26:36 +0200238 (struct trt_wrapper) { \
239 .type = TRD_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0 \
240 }
aPiecek61d062b2020-11-02 11:05:09 +0100241
242/**
aPiecek874ea4d2021-04-19 12:26:36 +0200243 * @brief Get wrapper related to subsection
244 * e.g. Augmenations or Groupings.
aPiecek61d062b2020-11-02 11:05:09 +0100245 *
246 * @code
247 * module: <module-name>
248 * +--<node>
249 *
250 * augment <target-node>:
251 * +--<node>
252 * @endcode
253 */
254#define TRP_INIT_WRAPPER_BODY \
aPiecek874ea4d2021-04-19 12:26:36 +0200255 (struct trt_wrapper) { \
256 .type = TRD_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0 \
257 }
aPiecek61d062b2020-11-02 11:05:09 +0100258
259/**
260 * @brief Package which only groups wrapper and indent in node.
261 */
262struct trt_pck_indent {
263 struct trt_wrapper wrapper; /**< Coded " | | " sequence. */
264 struct trt_indent_in_node in_node; /**< Indent in node. */
265};
266
267/**
268 * @brief Initialize struct trt_pck_indent by parameters.
269 */
270#define TRP_INIT_PCK_INDENT(WRAPPER, INDENT_IN_NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200271 (struct trt_pck_indent){ \
272 .wrapper = WRAPPER, .in_node = INDENT_IN_NODE \
273 }
aPiecek61d062b2020-11-02 11:05:09 +0100274
aPiecek874ea4d2021-04-19 12:26:36 +0200275/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100276 * status
aPiecek874ea4d2021-04-19 12:26:36 +0200277 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100278
279/**
280 * @brief Status of the node.
281 *
aPiecek874ea4d2021-04-19 12:26:36 +0200282 * @see trp_print_status
aPiecek61d062b2020-11-02 11:05:09 +0100283 */
284typedef enum {
285 TRD_STATUS_TYPE_EMPTY = 0,
aPiecek874ea4d2021-04-19 12:26:36 +0200286 TRD_STATUS_TYPE_CURRENT, /**< ::LYS_STATUS_CURR */
287 TRD_STATUS_TYPE_DEPRECATED, /**< ::LYS_STATUS_DEPRC */
288 TRD_STATUS_TYPE_OBSOLETE /**< ::LYS_STATUS_OBSLT */
aPiecek61d062b2020-11-02 11:05:09 +0100289} trt_status_type;
290
aPiecek874ea4d2021-04-19 12:26:36 +0200291/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100292 * flags
aPiecek874ea4d2021-04-19 12:26:36 +0200293 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100294
295/**
296 * @brief Flag of the node.
297 *
aPiecek874ea4d2021-04-19 12:26:36 +0200298 * @see trp_print_flags, trp_get_flags_strlen
aPiecek61d062b2020-11-02 11:05:09 +0100299 */
300typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200301 TRD_FLAGS_TYPE_EMPTY = 0, /**< -- */
aPiecek61d062b2020-11-02 11:05:09 +0100302 TRD_FLAGS_TYPE_RW, /**< rw */
303 TRD_FLAGS_TYPE_RO, /**< ro */
304 TRD_FLAGS_TYPE_RPC_INPUT_PARAMS, /**< -w */
305 TRD_FLAGS_TYPE_USES_OF_GROUPING, /**< -u */
306 TRD_FLAGS_TYPE_RPC, /**< -x */
307 TRD_FLAGS_TYPE_NOTIF, /**< -n */
308 TRD_FLAGS_TYPE_MOUNT_POINT /**< mp */
309} trt_flags_type;
310
aPiecek874ea4d2021-04-19 12:26:36 +0200311/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100312 * node_name and opts
aPiecek874ea4d2021-04-19 12:26:36 +0200313 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100314
315#define TRD_NODE_NAME_PREFIX_CHOICE "("
316#define TRD_NODE_NAME_PREFIX_CASE ":("
317#define TRD_NODE_NAME_TRIPLE_DOT "..."
318
319/**
320 * @brief Type of the node.
321 *
aPiecek874ea4d2021-04-19 12:26:36 +0200322 * Used mainly to complete the correct \<opts\> next to or
323 * around the \<name\>.
aPiecek61d062b2020-11-02 11:05:09 +0100324 */
325typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200326 TRD_NODE_ELSE = 0, /**< For some node which does not require special treatment. \<name\> */
327 TRD_NODE_CASE, /**< For case node. :(\<name\>) */
328 TRD_NODE_CHOICE, /**< For choice node. (\<name\>) */
329 TRD_NODE_OPTIONAL_CHOICE, /**< For choice node with optional mark. (\<name\>)? */
330 TRD_NODE_OPTIONAL, /**< For an optional leaf, anydata, or anyxml. \<name\>? */
331 TRD_NODE_CONTAINER, /**< For a presence container. \<name\>! */
332 TRD_NODE_LISTLEAFLIST, /**< For a leaf-list or list (without keys). \<name\>* */
333 TRD_NODE_KEYS, /**< For a list's keys. \<name\>* [\<keys\>] */
334 TRD_NODE_TOP_LEVEL1, /**< For a top-level data node in a mounted module. \<name\>/ */
335 TRD_NODE_TOP_LEVEL2, /**< For a top-level data node of a module identified in a mount point parent reference. \<name\>@ */
336 TRD_NODE_TRIPLE_DOT /**< For collapsed sibling nodes and their children. Special case which doesn't belong here very well. */
aPiecek61d062b2020-11-02 11:05:09 +0100337} trt_node_type;
338
339/**
340 * @brief Type of node and his name.
341 *
aPiecek874ea4d2021-04-19 12:26:36 +0200342 * @see TRP_EMPTY_NODE_NAME, TRP_NODE_NAME_IS_EMPTY,
aPiecek61d062b2020-11-02 11:05:09 +0100343 * trp_print_node_name, trp_mark_is_used, trp_print_opts_keys
344 */
345struct trt_node_name {
346 trt_node_type type; /**< Type of the node relevant for printing. */
347 const char *module_prefix; /**< Prefix defined in the module where the node is defined. */
348 const char *str; /**< Name of the node. */
349};
350
351/**
352 * @brief Create struct trt_node_name as empty.
353 */
354#define TRP_EMPTY_NODE_NAME \
aPiecek874ea4d2021-04-19 12:26:36 +0200355 (struct trt_node_name) { \
356 .type = TRD_NODE_ELSE, .module_prefix = NULL, .str = NULL \
357 }
aPiecek61d062b2020-11-02 11:05:09 +0100358
359/**
360 * @brief Check if struct trt_node_name is empty.
361 */
362#define TRP_NODE_NAME_IS_EMPTY(NODE_NAME) \
363 !NODE_NAME.str
364
aPiecek874ea4d2021-04-19 12:26:36 +0200365/**
366 * @brief Every \<opts\> mark except string of list's keys
367 * has a length of one.
368 */
aPiecek61d062b2020-11-02 11:05:09 +0100369#define TRD_OPTS_MARK_LENGTH 1
370
aPiecek874ea4d2021-04-19 12:26:36 +0200371/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100372 * type
aPiecek874ea4d2021-04-19 12:26:36 +0200373 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100374
375/**
376 * @brief Type of the \<type\>
377 */
378typedef enum {
379 TRD_TYPE_NAME = 0, /**< Type is just a name that does not require special treatment. */
380 TRD_TYPE_TARGET, /**< Should have a form "-> TARGET", where TARGET is the leafref path. */
aPiecek874ea4d2021-04-19 12:26:36 +0200381 TRD_TYPE_LEAFREF, /**< This type is set automatically by the 'trp' algorithm.
382 So set type as ::TRD_TYPE_TARGET. */
aPiecek61d062b2020-11-02 11:05:09 +0100383 TRD_TYPE_EMPTY /**< Type is not used at all. */
384} trt_type_type;
385
386/**
387 * @brief \<type\> in the \<node\>.
388 *
aPiecek874ea4d2021-04-19 12:26:36 +0200389 * @see TRP_EMPTY_TRT_TYPE, TRP_TRT_TYPE_IS_EMPTY, trp_print_type
aPiecek61d062b2020-11-02 11:05:09 +0100390 */
391struct trt_type {
392 trt_type_type type; /**< Type of the \<type\>. */
393 const char *str; /**< Path or name of the type. */
394};
395
396/**
397 * @brief Create empty struct trt_type.
398 */
399#define TRP_EMPTY_TRT_TYPE \
400 (struct trt_type) {.type = TRD_TYPE_EMPTY, .str = NULL}
401
402/**
403 * @brief Check if struct trt_type is empty.
404 */
405#define TRP_TRT_TYPE_IS_EMPTY(TYPE_OF_TYPE) \
406 TYPE_OF_TYPE.type == TRD_TYPE_EMPTY
407
408/**
409 * @brief Initialize struct trt_type by parameters.
410 */
411#define TRP_INIT_TRT_TYPE(TYPE_OF_TYPE, STRING) \
412 (struct trt_type) {.type = TYPE_OF_TYPE, .str = STRING}
413
aPiecek874ea4d2021-04-19 12:26:36 +0200414/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100415 * node
aPiecek874ea4d2021-04-19 12:26:36 +0200416 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100417
418/**
419 * @brief \<node\> data for printing.
420 *
aPiecek874ea4d2021-04-19 12:26:36 +0200421 * It contains RFC's:
422 * \<status\>--\<flags\> \<name\>\<opts\> \<type\> \<if-features\>.
aPiecek61d062b2020-11-02 11:05:09 +0100423 * Item \<opts\> is moved to part struct trt_node_name.
aPiecek874ea4d2021-04-19 12:26:36 +0200424 * For printing [\<keys\>] and if-features is required special
425 * functions which prints them.
aPiecek61d062b2020-11-02 11:05:09 +0100426 *
aPiecek874ea4d2021-04-19 12:26:36 +0200427 * @see TRP_EMPTY_NODE, trp_node_is_empty, trp_node_body_is_empty,
428 * trp_print_node_up_to_name, trp_print_divided_node_up_to_name,
429 * trp_print_node
aPiecek61d062b2020-11-02 11:05:09 +0100430 */
431struct trt_node {
aPiecek874ea4d2021-04-19 12:26:36 +0200432 trt_status_type status; /**< \<status\>. */
433 trt_flags_type flags; /**< \<flags\>. */
434 struct trt_node_name name; /**< \<node\> with \<opts\> mark or [\<keys\>]. */
435 struct trt_type type; /**< \<type\> contains the name of the type or type for leafref. */
436 ly_bool iffeatures; /**< \<if-features\>. Value 1 means that iffeatures are present and
437 will be printed by trt_fp_print.print_features_names callback. */
438 ly_bool last_one; /**< Information about whether the node is the last. */
aPiecek61d062b2020-11-02 11:05:09 +0100439};
440
441/**
442 * @brief Create struct trt_node as empty.
443 */
444#define TRP_EMPTY_NODE \
aPiecek874ea4d2021-04-19 12:26:36 +0200445 (struct trt_node) { \
446 .status = TRD_STATUS_TYPE_EMPTY, \
447 .flags = TRD_FLAGS_TYPE_EMPTY, \
448 .name = TRP_EMPTY_NODE_NAME, \
449 .type = TRP_EMPTY_TRT_TYPE, \
450 .iffeatures = 0, \
451 .last_one = 1 \
452 }
aPiecek61d062b2020-11-02 11:05:09 +0100453
454/**
455 * @brief Package which only groups indent and node.
456 */
457struct trt_pair_indent_node {
458 struct trt_indent_in_node indent;
459 struct trt_node node;
460};
461
462/**
463 * @brief Initialize struct trt_pair_indent_node by parameters.
464 */
465#define TRP_INIT_PAIR_INDENT_NODE(INDENT_IN_NODE, NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200466 (struct trt_pair_indent_node) { \
467 .indent = INDENT_IN_NODE, .node = NODE \
468 }
aPiecek61d062b2020-11-02 11:05:09 +0100469
aPiecek874ea4d2021-04-19 12:26:36 +0200470/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100471 * statement
aPiecek874ea4d2021-04-19 12:26:36 +0200472 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100473
474#define TRD_TOP_KEYWORD_MODULE "module"
475#define TRD_TOP_KEYWORD_SUBMODULE "submodule"
476
477#define TRD_BODY_KEYWORD_AUGMENT "augment"
478#define TRD_BODY_KEYWORD_RPC "rpcs"
479#define TRD_BODY_KEYWORD_NOTIF "notifications"
480#define TRD_BODY_KEYWORD_GROUPING "grouping"
481#define TRD_BODY_KEYWORD_YANG_DATA "yang-data"
482
483/**
484 * @brief Type of the trt_keyword.
485 */
486typedef enum {
487 TRD_KEYWORD_EMPTY = 0,
488 TRD_KEYWORD_MODULE,
489 TRD_KEYWORD_SUBMODULE,
490 TRD_KEYWORD_AUGMENT,
491 TRD_KEYWORD_RPC,
492 TRD_KEYWORD_NOTIF,
493 TRD_KEYWORD_GROUPING,
494 TRD_KEYWORD_YANG_DATA
495} trt_keyword_type;
496
497/**
498 * @brief Main sign of the tree nodes.
499 *
aPiecek874ea4d2021-04-19 12:26:36 +0200500 * @see TRP_EMPTY_KEYWORD_STMT, TRP_KEYWORD_STMT_IS_EMPTY
aPiecek61d062b2020-11-02 11:05:09 +0100501 * trt_print_keyword_stmt_begin, trt_print_keyword_stmt_str,
502 * trt_print_keyword_stmt_end, trp_print_keyword_stmt
503 * trp_keyword_type_strlen
504 *
505 */
506struct trt_keyword_stmt {
aPiecek874ea4d2021-04-19 12:26:36 +0200507 trt_keyword_type type; /**< String containing some of the top or body keyword. */
508 const char *str; /**< Name or path, it determines the type. */
aPiecek61d062b2020-11-02 11:05:09 +0100509};
510
511/**
512 * @brief Create struct trt_keyword_stmt as empty.
513 */
514#define TRP_EMPTY_KEYWORD_STMT \
515 (struct trt_keyword_stmt) {.type = TRD_KEYWORD_EMPTY, .str = NULL}
516
517/**
518 * @brief Check if struct trt_keyword_stmt is empty.
519 */
520#define TRP_KEYWORD_STMT_IS_EMPTY(KEYWORD_TYPE) \
521 KEYWORD_TYPE.type == TRD_KEYWORD_EMPTY
522
523/**
524 * @brief Initialize struct trt_keyword_stmt by parameters.
525 */
526#define TRP_INIT_KEYWORD_STMT(KEYWORD_TYPE, STRING) \
527 (struct trt_keyword_stmt) {.type = KEYWORD_TYPE, .str = STRING}
528
aPiecek874ea4d2021-04-19 12:26:36 +0200529/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100530 * Modify getters
aPiecek874ea4d2021-04-19 12:26:36 +0200531 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100532
533struct trt_parent_cache;
534
535/**
536 * @brief Functions that change the state of the tree_ctx structure.
537 *
aPiecek874ea4d2021-04-19 12:26:36 +0200538 * The tro functions are set here, which provide data
539 * for the 'trp' printing functions and are also called from the
540 * 'trb' browsing functions when walking through a tree. These callback
541 * functions need to be checked or reformulated if changes to the
542 * libyang library affect the printing tree. For all, if the value
543 * cannot be returned, its empty version obtained by relevant TRP_EMPTY
544 * macro is returned.
aPiecek61d062b2020-11-02 11:05:09 +0100545 */
546struct trt_fp_modify_ctx {
547 ly_bool (*parent)(struct trt_tree_ctx *); /**< Jump to parent node. Return true if parent exists. */
548 void (*first_sibling)(struct trt_tree_ctx *); /**< Jump on the first of the siblings. */
549 struct trt_node (*next_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to next sibling of the current node. */
550 struct trt_node (*next_child)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to the child of the current node. */
551 struct trt_keyword_stmt (*next_augment)(struct trt_tree_ctx *); /**< Jump to the augment section. */
552 struct trt_keyword_stmt (*get_rpcs)(struct trt_tree_ctx *); /**< Jump to the rpcs section. */
553 struct trt_keyword_stmt (*get_notifications)(struct trt_tree_ctx *); /**< Jump to the notifications section. */
554 struct trt_keyword_stmt (*next_grouping)(struct trt_tree_ctx *); /**< Jump to the grouping section. */
555 struct trt_keyword_stmt (*next_yang_data)(struct trt_tree_ctx *); /**< Jump to the yang-data section. */
556};
557
aPiecek874ea4d2021-04-19 12:26:36 +0200558/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100559 * Read getters
aPiecek874ea4d2021-04-19 12:26:36 +0200560 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100561
562/**
563 * @brief Functions that do not change the state of the tree_structure.
564 *
565 * For details see trt_fp_modify_ctx.
566 */
567struct trt_fp_read {
aPiecek874ea4d2021-04-19 12:26:36 +0200568 struct trt_keyword_stmt (*module_name)(const struct trt_tree_ctx *); /**< Get name of the module. */
569 struct trt_node (*node)(struct trt_parent_cache, const struct trt_tree_ctx *); /**< Get current node. */
570 ly_bool (*if_sibling_exists)(const struct trt_tree_ctx *); /**< Check if node's sibling exists. */
aPiecek61d062b2020-11-02 11:05:09 +0100571};
572
aPiecek874ea4d2021-04-19 12:26:36 +0200573/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100574 * All getters
aPiecek874ea4d2021-04-19 12:26:36 +0200575 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100576
577/**
aPiecek874ea4d2021-04-19 12:26:36 +0200578 * @brief A set of all necessary functions that must be provided
579 * for the printer.
aPiecek61d062b2020-11-02 11:05:09 +0100580 */
581struct trt_fp_all {
582 struct trt_fp_modify_ctx modify; /**< Function pointers which modify state of trt_tree_ctx. */
583 struct trt_fp_read read; /**< Function pointers which only reads state of trt_tree_ctx. */
584 struct trt_fp_print print; /**< Functions pointers for printing special items in node. */
585};
586
aPiecek874ea4d2021-04-19 12:26:36 +0200587/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100588 * Printer context
aPiecek874ea4d2021-04-19 12:26:36 +0200589 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100590
591/**
aPiecek874ea4d2021-04-19 12:26:36 +0200592 * @brief Main structure for \ref TRP_trp part.
aPiecek61d062b2020-11-02 11:05:09 +0100593 */
594struct trt_printer_ctx {
595 struct ly_out *out; /**< Handler to printing. */
aPiecek874ea4d2021-04-19 12:26:36 +0200596 struct trt_fp_all fp; /**< \ref TRP_tro functions callbacks. */
aPiecek61d062b2020-11-02 11:05:09 +0100597 size_t max_line_length; /**< The maximum number of characters that can be
598 printed on one line, including the last. */
599};
600
aPiecek874ea4d2021-04-19 12:26:36 +0200601/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100602 * Tro functions
aPiecek874ea4d2021-04-19 12:26:36 +0200603 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100604
605/**
606 * @brief The name of the section to which the node belongs.
607 */
608typedef enum {
609 TRD_SECT_MODULE = 0, /**< The node belongs to the "module: <module_name>:" label. */
610 TRD_SECT_AUGMENT, /**< The node belongs to some "augment <target-node>:" label. */
611 TRD_SECT_RPCS, /**< The node belongs to the "rpcs:" label. */
612 TRD_SECT_NOTIF, /**< The node belongs to the "notifications:" label. */
613 TRD_SECT_GROUPING, /**< The node belongs to some "grouping <grouping-name>:" label. */
614 TRD_SECT_YANG_DATA /**< The node belongs to some "yang-data <yang-data-name>:" label. */
615} trt_actual_section;
616
617/**
618 * @brief Types of nodes that have some effect on their children.
619 */
620typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200621 TRD_ANCESTOR_ELSE = 0, /**< Everything not listed. */
622 TRD_ANCESTOR_RPC_INPUT, /**< ::LYS_INPUT */
623 TRD_ANCESTOR_RPC_OUTPUT, /**< ::LYS_OUTPUT */
624 TRD_ANCESTOR_NOTIF /**< ::LYS_NOTIF */
aPiecek61d062b2020-11-02 11:05:09 +0100625} trt_ancestor_type;
626
627/**
628 * @brief Saved information when browsing the tree downwards.
629 *
aPiecek874ea4d2021-04-19 12:26:36 +0200630 * This structure helps prevent frequent retrieval of information
631 * from the tree. Functions \ref TRP_trb are designed to preserve
632 * this structures during their recursive calls. This functions do not
633 * interfere in any way with this data. This structure
634 * is used by \ref TRP_tro functions which, thanks to this
635 * structure, can return a node with the correct data. The word
636 * \b parent is in the structure name, because this data refers to
637 * the last parent and at the same time the states of its
638 * ancestors data. Only the function jumping on the child
639 * (next_child(...)) creates this structure, because the pointer
640 * to the current node moves down the tree. It's like passing
641 * the genetic code to children. Some data must be inherited and
642 * there are two approaches to this problem. Either it will always
643 * be determined which inheritance states belong to the current node
644 * (which can lead to regular travel to the root node) or
645 * the inheritance states will be stored during the recursive calls.
646 * So the problem was solved by the second option. Why does
647 * the structure contain this data? Because it walks through
648 * the lysp tree.
aPiecek61d062b2020-11-02 11:05:09 +0100649 *
aPiecek874ea4d2021-04-19 12:26:36 +0200650 * @see TRO_EMPTY_PARENT_CACHE, tro_parent_cache_for_child
aPiecek61d062b2020-11-02 11:05:09 +0100651 */
652struct trt_parent_cache {
aPiecek874ea4d2021-04-19 12:26:36 +0200653 trt_ancestor_type ancestor; /**< Some types of nodes have a special effect on their children. */
654 uint16_t lys_status; /**< Inherited status CURR, DEPRC, OBSLT. */
655 uint16_t lys_config; /**< Inherited config W or R. */
656 const struct lysp_node_list *last_list; /**< The last ::LYS_LIST passed. */
aPiecek61d062b2020-11-02 11:05:09 +0100657};
658
659/**
660 * @brief Return trt_parent_cache filled with default values.
661 */
662#define TRP_EMPTY_PARENT_CACHE \
aPiecek874ea4d2021-04-19 12:26:36 +0200663 (struct trt_parent_cache) { \
664 .ancestor = TRD_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \
665 .lys_config = LYS_CONFIG_W, .last_list = NULL \
666 }
aPiecek61d062b2020-11-02 11:05:09 +0100667
668/**
669 * @brief Main structure for browsing the libyang tree
670 */
671struct trt_tree_ctx {
672 trt_actual_section section; /**< To which section pn points. */
673 const struct lys_module *module; /**< Schema tree structures. */
674 const struct lysp_node *pn; /**< Actual pointer to parsed node. */
675 const struct lysp_node *tpn; /**< Pointer to actual top-node. */
676};
677
678/**
679 * @brief Used for updating trt_tree_ctx
680 */
681struct trt_tree_ctx_node_patch {
682 const struct lysp_node *pn; /**< Actual pointer to parsed node. */
683 const struct lysp_node *tpn; /**< Pointer to actual top-node. */
684};
685
686/**
687 * @brief Initialize struct trt_keyword_stmt by parameters.
688 */
689#define TRP_INIT_TREE_CTX_NODE_PATCH(PN, TPN) \
690 (struct trt_tree_ctx_node_patch){.pn = PN, .tpn = TPN}
691
aPiecek874ea4d2021-04-19 12:26:36 +0200692/** Getter function for tro_lysp_node_charptr(). */
aPiecek61d062b2020-11-02 11:05:09 +0100693typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
694
aPiecek874ea4d2021-04-19 12:26:36 +0200695/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100696 * Definition of the general Trg functions
aPiecek874ea4d2021-04-19 12:26:36 +0200697 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100698
699/**
700 * @brief Print a substring but limited to the maximum length.
701 * @param[in] str is pointer to source.
702 * @param[in] len is number of characters to be printed.
703 * @param[in,out] out is output handler.
704 * @return str parameter shifted by len.
705 */
706static const char *
707trg_print_substr(const char *str, size_t len, struct ly_out *out)
708{
709 for (size_t i = 0; i < len; i++) {
710 ly_print_(out, "%c", str[0]);
711 str++;
712 }
713 return str;
714}
715
716/**
717 * @brief Pointer is not NULL and does not point to an empty string.
718 * @param[in] str is pointer to string to be checked.
719 * @return 1 if str pointing to non empty string otherwise 0.
720 */
721static ly_bool
722trg_charptr_has_data(const char *str)
723{
724 return (str) && (str[0] != '\0');
725}
726
727/**
aPiecek874ea4d2021-04-19 12:26:36 +0200728 * @brief Check if @p word in @p src is present where words are
729 * delimited by @p delim.
730 * @param[in] src is source where words are separated by @p delim.
aPiecek61d062b2020-11-02 11:05:09 +0100731 * @param[in] word to be searched.
aPiecek874ea4d2021-04-19 12:26:36 +0200732 * @param[in] delim is delimiter between @p words in @p src.
733 * @return 1 if src contains @p word otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +0100734 */
735static ly_bool
736trg_word_is_present(const char *src, const char *word, char delim)
737{
738 const char *hit;
739
740 if ((!src) || (src[0] == '\0') || (!word)) {
741 return 0;
742 }
743
744 hit = strstr(src, word);
745
746 if (hit) {
747 /* word was founded at the begin of src
748 * OR it match somewhere after delim
749 */
750 if ((hit == src) || (hit[-1] == delim)) {
751 /* end of word was founded at the end of src
752 * OR end of word was match somewhere before delim
753 */
754 char delim_or_end = (hit + strlen(word))[0];
755 if ((delim_or_end == '\0') || (delim_or_end == delim)) {
756 return 1;
757 }
758 }
759 /* after -> hit is just substr and it's not the whole word */
760 /* jump to the next word */
761 for ( ; (src[0] != '\0') && (src[0] != delim); src++) {}
762 /* skip delim */
763 src = src[0] == '\0' ? src : src + 1;
764 /* continue with searching */
765 return trg_word_is_present(src, word, delim);
766 } else {
767 return 0;
768 }
769}
770
aPiecek874ea4d2021-04-19 12:26:36 +0200771/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100772 * Definition of printer functions
aPiecek874ea4d2021-04-19 12:26:36 +0200773 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100774
775/**
aPiecek874ea4d2021-04-19 12:26:36 +0200776 * @brief Write callback for ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100777 *
aPiecek874ea4d2021-04-19 12:26:36 +0200778 * @param[in] user_data is type of struct ly_out_clb_arg.
aPiecek61d062b2020-11-02 11:05:09 +0100779 * @param[in] buf contains input characters
780 * @param[in] count is number of characters in buf.
781 * @return Number of printed bytes.
782 * @return Negative value in case of error.
783 */
784static ssize_t
785trp_ly_out_clb_func(void *user_data, const void *buf, size_t count)
786{
787 LY_ERR erc = LY_SUCCESS;
788 struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data;
789
790 switch (data->mode) {
791 case TRD_PRINT:
792 erc = ly_write_(data->out, buf, count);
793 break;
794 case TRD_CHAR_COUNT:
795 data->counter = data->counter + count;
796 break;
797 default:
798 break;
799 }
800
801 if (erc != LY_SUCCESS) {
802 data->last_error = erc;
803 return -1;
804 } else {
805 return count;
806 }
807}
808
809/**
810 * @brief Check that indent in node can be considered as equivalent.
811 * @param[in] first is the first indent in node.
812 * @param[in] second is the second indent in node.
813 * @return 1 if indents are equivalent otherwise 0.
814 */
815static ly_bool
816trp_indent_in_node_are_eq(struct trt_indent_in_node first, struct trt_indent_in_node second)
817{
818 const ly_bool a = first.type == second.type;
819 const ly_bool b = first.btw_name_opts == second.btw_name_opts;
820 const ly_bool c = first.btw_opts_type == second.btw_opts_type;
821 const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures;
822
823 return a && b && c && d;
824}
825
826/**
aPiecek874ea4d2021-04-19 12:26:36 +0200827 * @brief Setting space character because node is last sibling.
828 * @param[in] wr is wrapper over which the shift operation
829 * is to be performed.
aPiecek61d062b2020-11-02 11:05:09 +0100830 * @return New shifted wrapper.
831 */
832static struct trt_wrapper
833trp_wrapper_set_shift(struct trt_wrapper wr)
834{
835 assert(wr.actual_pos < 64);
836 /* +--<node>
837 * +--<node>
838 */
839 wr.actual_pos++;
840 return wr;
841}
842
843/**
aPiecek874ea4d2021-04-19 12:26:36 +0200844 * @brief Setting '|' symbol because node is divided or
845 * it is not last sibling.
aPiecek61d062b2020-11-02 11:05:09 +0100846 * @param[in] wr is source of wrapper.
847 * @return New wrapper which is marked at actual position and shifted.
848 */
849static struct trt_wrapper
850trp_wrapper_set_mark(struct trt_wrapper wr)
851{
852 assert(wr.actual_pos < 64);
853 wr.bit_marks1 |= 1U << wr.actual_pos;
854 return trp_wrapper_set_shift(wr);
855}
856
857/**
858 * @brief Setting ' ' symbol if node is last sibling otherwise set '|'.
859 * @param[in] wr is actual wrapper.
aPiecek874ea4d2021-04-19 12:26:36 +0200860 * @param[in] last_one is flag. Value 1 saying if the node is the last
861 * and has no more siblings.
aPiecek61d062b2020-11-02 11:05:09 +0100862 * @return New wrapper for the actual node.
863 */
864static struct trt_wrapper
865trp_wrapper_if_last_sibling(struct trt_wrapper wr, ly_bool last_one)
866{
867 return last_one ? trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
868}
869
870/**
871 * @brief Test if the wrappers are equivalent.
872 * @param[in] first is the first wrapper.
873 * @param[in] second is the second wrapper.
874 * @return 1 if the wrappers are equivalent otherwise 0.
875 */
876static ly_bool
877trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second)
878{
879 const ly_bool a = first.type == second.type;
880 const ly_bool b = first.bit_marks1 == second.bit_marks1;
881 const ly_bool c = first.actual_pos == second.actual_pos;
882
883 return a && b && c;
884}
885
886/**
887 * @brief Print " | " sequence on line.
888 * @param[in] wr is wrapper to be printed.
889 * @param[in,out] out is output handler.
890 */
891static void
892trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out)
893{
894 uint32_t lb;
895
896 if (wr.type == TRD_WRAPPER_TOP) {
897 lb = TRD_INDENT_LINE_BEGIN;
898 } else if (wr.type == TRD_WRAPPER_BODY) {
899 lb = TRD_INDENT_LINE_BEGIN * 2;
900 } else {
901 lb = TRD_INDENT_LINE_BEGIN;
902 }
903
904 ly_print_(out, "%*c", lb, ' ');
905
906 if (trp_wrapper_eq(wr, TRP_INIT_WRAPPER_TOP)) {
907 return;
908 }
909
910 for (uint32_t i = 0; i < wr.actual_pos; i++) {
911 /** Test if the bit on the index is set. */
912 if ((wr.bit_marks1 >> i) & 1U) {
913 ly_print_(out, "|");
914 } else {
915 ly_print_(out, " ");
916 }
917
918 if (i != wr.actual_pos) {
919 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
920 }
921 }
922}
923
924/**
925 * @brief Check if struct trt_node is empty.
926 * @param[in] node is item to test.
927 * @return 1 if node is considered empty otherwise 0.
928 */
929static ly_bool
930trp_node_is_empty(struct trt_node node)
931{
932 const ly_bool a = !node.iffeatures;
933 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
934 const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node.name);
935 const ly_bool d = node.flags == TRD_FLAGS_TYPE_EMPTY;
936 const ly_bool e = node.status == TRD_STATUS_TYPE_EMPTY;
937
938 return a && b && c && d && e;
939}
940
941/**
aPiecek874ea4d2021-04-19 12:26:36 +0200942 * @brief Check if [\<keys\>], \<type\> and
943 * \<iffeatures\> are empty/not_set.
aPiecek61d062b2020-11-02 11:05:09 +0100944 * @param[in] node is item to test.
aPiecek874ea4d2021-04-19 12:26:36 +0200945 * @return 1 if node has no \<keys\> \<type\> or \<iffeatures\>
946 * otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +0100947 */
948static ly_bool
949trp_node_body_is_empty(struct trt_node node)
950{
951 const ly_bool a = !node.iffeatures;
952 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
953 const ly_bool c = node.name.type != TRD_NODE_KEYS;
954
955 return a && b && c;
956}
957
958/**
959 * @brief Print \<status\> of the node.
960 * @param[in] status_type is type of status.
961 * @param[in,out] out is output handler.
962 */
963static void
964trp_print_status(trt_status_type status_type, struct ly_out *out)
965{
966 switch (status_type) {
967 case TRD_STATUS_TYPE_CURRENT:
968 ly_print_(out, "%c", '+');
969 break;
970 case TRD_STATUS_TYPE_DEPRECATED:
971 ly_print_(out, "%c", 'x');
972 break;
973 case TRD_STATUS_TYPE_OBSOLETE:
974 ly_print_(out, "%c", 'o');
975 break;
976 default:
977 break;
978 }
979}
980
981/**
982 * @brief Print \<flags\>.
983 * @param[in] flags_type is type of \<flags\>.
984 * @param[in,out] out is output handler.
985 */
986static void
987trp_print_flags(trt_flags_type flags_type, struct ly_out *out)
988{
989 switch (flags_type) {
990 case TRD_FLAGS_TYPE_RW:
991 ly_print_(out, "%s", "rw");
992 break;
993 case TRD_FLAGS_TYPE_RO:
994 ly_print_(out, "%s", "ro");
995 break;
996 case TRD_FLAGS_TYPE_RPC_INPUT_PARAMS:
997 ly_print_(out, "%s", "-w");
998 break;
999 case TRD_FLAGS_TYPE_USES_OF_GROUPING:
1000 ly_print_(out, "%s", "-u");
1001 break;
1002 case TRD_FLAGS_TYPE_RPC:
1003 ly_print_(out, "%s", "-x");
1004 break;
1005 case TRD_FLAGS_TYPE_NOTIF:
1006 ly_print_(out, "%s", "-n");
1007 break;
1008 case TRD_FLAGS_TYPE_MOUNT_POINT:
1009 ly_print_(out, "%s", "mp");
1010 break;
1011 default:
aPiecekdc8fd572021-04-19 10:47:23 +02001012 ly_print_(out, "%s", "--");
aPiecek61d062b2020-11-02 11:05:09 +01001013 break;
1014 }
1015}
1016
1017/**
1018 * @brief Get size of the \<flags\>.
1019 * @param[in] flags_type is type of \<flags\>.
1020 * @return 0 if flags_type is not set otherwise 2.
1021 */
1022static size_t
1023trp_get_flags_strlen(trt_flags_type flags_type)
1024{
1025 return flags_type == TRD_FLAGS_TYPE_EMPTY ? 0 : 2;
1026}
1027
1028/**
1029 * @brief Print entire struct trt_node_name structure.
1030 * @param[in] node_name is item to print.
1031 * @param[in,out] out is output handler.
1032 */
1033static void
1034trp_print_node_name(struct trt_node_name node_name, struct ly_out *out)
1035{
1036 const char *mod_prefix;
1037 const char *colon;
1038 const char trd_node_name_suffix_choice[] = ")";
1039 const char trd_node_name_suffix_case[] = ")";
1040 const char trd_opts_optional[] = "?"; /**< For an optional leaf, choice, anydata, or anyxml. */
1041 const char trd_opts_container[] = "!"; /**< For a presence container. */
1042 const char trd_opts_list[] = "*"; /**< For a leaf-list or list. */
1043 const char trd_opts_slash[] = "/"; /**< For a top-level data node in a mounted module. */
1044 const char trd_opts_at_sign[] = "@"; /**< For a top-level data node of a module identified in a mount point parent reference. */
1045
1046 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1047 return;
1048 }
1049
1050 if (node_name.module_prefix) {
1051 mod_prefix = node_name.module_prefix;
1052 colon = ":";
1053 } else {
1054 mod_prefix = "";
1055 colon = "";
1056 }
1057
1058 switch (node_name.type) {
1059 case TRD_NODE_ELSE:
1060 ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
1061 break;
1062 case TRD_NODE_CASE:
1063 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, trd_node_name_suffix_case);
1064 break;
1065 case TRD_NODE_CHOICE:
1066 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice);
1067 break;
1068 case TRD_NODE_OPTIONAL_CHOICE:
1069 ly_print_(out, "%s%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice, trd_opts_optional);
1070 break;
1071 case TRD_NODE_OPTIONAL:
1072 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_optional);
1073 break;
1074 case TRD_NODE_CONTAINER:
1075 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_container);
1076 break;
1077 case TRD_NODE_LISTLEAFLIST:
1078 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1079 break;
1080 case TRD_NODE_KEYS:
1081 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1082 break;
1083 case TRD_NODE_TOP_LEVEL1:
1084 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_slash);
1085 break;
1086 case TRD_NODE_TOP_LEVEL2:
1087 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_at_sign);
1088 break;
1089 case TRD_NODE_TRIPLE_DOT:
1090 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
1091 break;
1092 default:
1093 break;
1094 }
1095}
1096
1097/**
aPiecek874ea4d2021-04-19 12:26:36 +02001098 * @brief Check if mark (?, !, *, /, @) is implicitly contained in
1099 * struct trt_node_name.
aPiecek61d062b2020-11-02 11:05:09 +01001100 * @param[in] node_name is structure containing the 'mark'.
1101 * @return 1 if contain otherwise 0.
1102 */
1103static ly_bool
1104trp_mark_is_used(struct trt_node_name node_name)
1105{
1106 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1107 return 0;
1108 }
1109
1110 switch (node_name.type) {
1111 case TRD_NODE_ELSE:
1112 case TRD_NODE_CASE:
1113 case TRD_NODE_KEYS:
1114 return 0;
1115 default:
1116 return 1;
1117 }
1118}
1119
1120/**
1121 * @brief Print opts keys.
1122 * @param[in] node_name contains type of the node with his name.
1123 * @param[in] btw_name_opts is number of spaces between name and [keys].
aPiecek874ea4d2021-04-19 12:26:36 +02001124 * @param[in] cf is basically a pointer to the function that prints
1125 * the keys.
aPiecek61d062b2020-11-02 11:05:09 +01001126 * @param[in,out] out is output handler.
1127 */
1128static void
1129trp_print_opts_keys(struct trt_node_name node_name, int16_t btw_name_opts, struct trt_cf_print cf, struct ly_out *out)
1130{
1131 if (node_name.type != TRD_NODE_KEYS) {
1132 return;
1133 }
1134
1135 /* <name><mark>___<keys>*/
1136 if (btw_name_opts > 0) {
1137 ly_print_(out, "%*c", btw_name_opts, ' ');
1138 }
1139 ly_print_(out, "[");
1140 cf.pf(cf.ctx, out);
1141 ly_print_(out, "]");
1142}
1143
1144/**
1145 * @brief Print entire struct trt_type structure.
1146 * @param[in] type is item to print.
1147 * @param[in,out] out is output handler.
1148 */
1149static void
1150trp_print_type(struct trt_type type, struct ly_out *out)
1151{
1152 if (TRP_TRT_TYPE_IS_EMPTY(type)) {
1153 return;
1154 }
1155
1156 switch (type.type) {
1157 case TRD_TYPE_NAME:
1158 ly_print_(out, "%s", type.str);
1159 break;
1160 case TRD_TYPE_TARGET:
1161 ly_print_(out, "-> %s", type.str);
1162 break;
1163 case TRD_TYPE_LEAFREF:
1164 ly_print_(out, "leafref");
1165 default:
1166 break;
1167 }
1168}
1169
1170/**
1171 * @brief Print all iffeatures of node
1172 *
1173 * @param[in] iffeature_flag contains if if-features is present.
aPiecek874ea4d2021-04-19 12:26:36 +02001174 * @param[in] cf is basically a pointer to the function that prints
1175 * the list of features.
aPiecek61d062b2020-11-02 11:05:09 +01001176 * @param[in,out] out is output handler.
1177 */
1178static void
1179trp_print_iffeatures(ly_bool iffeature_flag, struct trt_cf_print cf, struct ly_out *out)
1180{
1181 if (iffeature_flag) {
1182 ly_print_(out, "{");
1183 cf.pf(cf.ctx, out);
1184 ly_print_(out, "}?");
1185 }
1186}
1187
1188/**
1189 * @brief Print just \<status\>--\<flags\> \<name\> with opts mark.
1190 * @param[in] node contains items to print.
1191 * @param[in] out is output handler.
1192 */
1193static void
1194trp_print_node_up_to_name(struct trt_node node, struct ly_out *out)
1195{
1196 if (node.name.type == TRD_NODE_TRIPLE_DOT) {
1197 trp_print_node_name(node.name, out);
1198 return;
1199 }
1200 /* <status>--<flags> */
1201 trp_print_status(node.status, out);
1202 ly_print_(out, "--");
aPiecek874ea4d2021-04-19 12:26:36 +02001203 /* If the node is a case node, there is no space before the <name>
1204 * also case node has no flags.
1205 */
aPiecek61d062b2020-11-02 11:05:09 +01001206 if (node.name.type != TRD_NODE_CASE) {
1207 trp_print_flags(node.flags, out);
1208 ly_print_(out, " ");
1209 }
1210 /* <name> */
1211 trp_print_node_name(node.name, out);
1212}
1213
1214/**
aPiecek874ea4d2021-04-19 12:26:36 +02001215 * @brief Print alignment (spaces) instead of
1216 * \<status\>--\<flags\> \<name\> for divided node.
aPiecek61d062b2020-11-02 11:05:09 +01001217 * @param[in] node contains items to print.
1218 * @param[in] out is output handler.
1219 */
1220static void
1221trp_print_divided_node_up_to_name(struct trt_node node, struct ly_out *out)
1222{
1223 uint32_t space = trp_get_flags_strlen(node.flags);
1224
1225 if (node.name.type == TRD_NODE_CASE) {
1226 /* :(<name> */
1227 space += strlen(TRD_NODE_NAME_PREFIX_CASE);
1228 } else if (node.name.type == TRD_NODE_CHOICE) {
1229 /* (<name> */
1230 space += strlen(TRD_NODE_NAME_PREFIX_CHOICE);
1231 } else {
1232 /* _<name> */
1233 space += strlen(" ");
1234 }
1235
1236 /* <name>
1237 * __
1238 */
1239 space += TRD_INDENT_LONG_LINE_BREAK;
1240
1241 ly_print_(out, "%*c", space, ' ');
1242}
1243
1244/**
1245 * @brief Print struct trt_node structure.
1246 * @param[in] node is item to print.
aPiecek874ea4d2021-04-19 12:26:36 +02001247 * @param[in] pck package of functions for
1248 * printing [\<keys\>] and \<iffeatures\>.
aPiecek61d062b2020-11-02 11:05:09 +01001249 * @param[in] indent is the indent in node.
1250 * @param[in,out] out is output handler.
1251 */
1252static void
1253trp_print_node(struct trt_node node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out)
1254{
1255 ly_bool triple_dot;
1256 ly_bool divided;
1257 struct trt_cf_print cf_print_keys;
1258 struct trt_cf_print cf_print_iffeatures;
1259
1260 if (trp_node_is_empty(node)) {
1261 return;
1262 }
1263
1264 /* <status>--<flags> <name><opts> <type> <if-features> */
1265 triple_dot = node.name.type == TRD_NODE_TRIPLE_DOT;
1266 divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED;
1267
1268 if (triple_dot) {
1269 trp_print_node_name(node.name, out);
1270 return;
1271 } else if (!divided) {
1272 trp_print_node_up_to_name(node, out);
1273 } else {
1274 trp_print_divided_node_up_to_name(node, out);
1275 }
1276
1277 /* <opts> */
1278 /* <name>___<opts>*/
1279 cf_print_keys.ctx = pck.tree_ctx;
1280 cf_print_keys.pf = pck.fps.print_keys;
1281
1282 trp_print_opts_keys(node.name, indent.btw_name_opts, cf_print_keys, out);
1283
1284 /* <opts>__<type> */
1285 if (indent.btw_opts_type > 0) {
1286 ly_print_(out, "%*c", indent.btw_opts_type, ' ');
1287 }
1288
1289 /* <type> */
1290 trp_print_type(node.type, out);
1291
1292 /* <type>__<iffeatures> */
1293 if (indent.btw_type_iffeatures > 0) {
1294 ly_print_(out, "%*c", indent.btw_type_iffeatures, ' ');
1295 }
1296
1297 /* <iffeatures> */
1298 cf_print_iffeatures.ctx = pck.tree_ctx;
1299 cf_print_iffeatures.pf = pck.fps.print_features_names;
1300
1301 trp_print_iffeatures(node.iffeatures, cf_print_iffeatures, out);
1302}
1303
1304/**
aPiecek874ea4d2021-04-19 12:26:36 +02001305 * @brief Print keyword based on trt_keyword_stmt.type.
aPiecek61d062b2020-11-02 11:05:09 +01001306 * @param[in] ks is keyword statement to print.
1307 * @param[in,out] out is output handler
1308 */
1309static void
1310trt_print_keyword_stmt_begin(struct trt_keyword_stmt ks, struct ly_out *out)
1311{
1312 switch (ks.type) {
1313 case TRD_KEYWORD_MODULE:
1314 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_MODULE);
1315 return;
1316 case TRD_KEYWORD_SUBMODULE:
1317 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_SUBMODULE);
1318 return;
1319 default:
1320 ly_print_(out, "%*c", TRD_INDENT_LINE_BEGIN, ' ');
1321 switch (ks.type) {
1322 case TRD_KEYWORD_AUGMENT:
1323 ly_print_(out, "%s ", TRD_BODY_KEYWORD_AUGMENT);
1324 break;
1325 case TRD_KEYWORD_RPC:
1326 ly_print_(out, "%s", TRD_BODY_KEYWORD_RPC);
1327 break;
1328 case TRD_KEYWORD_NOTIF:
1329 ly_print_(out, "%s", TRD_BODY_KEYWORD_NOTIF);
1330 break;
1331 case TRD_KEYWORD_GROUPING:
1332 ly_print_(out, "%s ", TRD_BODY_KEYWORD_GROUPING);
1333 break;
1334 case TRD_KEYWORD_YANG_DATA:
1335 ly_print_(out, "%s ", TRD_BODY_KEYWORD_YANG_DATA);
1336 break;
1337 default:
1338 break;
1339 }
1340 break;
1341 }
1342}
1343
1344/**
1345 * @brief Get string length of stored keyword.
1346 * @param[in] type is type of the keyword statement.
1347 * @return length of the keyword statement name.
1348 */
1349static size_t
1350trp_keyword_type_strlen(trt_keyword_type type)
1351{
1352 switch (type) {
1353 case TRD_KEYWORD_MODULE:
1354 return sizeof(TRD_TOP_KEYWORD_MODULE) - 1;
1355 case TRD_KEYWORD_SUBMODULE:
1356 return sizeof(TRD_TOP_KEYWORD_SUBMODULE) - 1;
1357 case TRD_KEYWORD_AUGMENT:
1358 return sizeof(TRD_BODY_KEYWORD_AUGMENT) - 1;
1359 case TRD_KEYWORD_RPC:
1360 return sizeof(TRD_BODY_KEYWORD_RPC) - 1;
1361 case TRD_KEYWORD_NOTIF:
1362 return sizeof(TRD_BODY_KEYWORD_NOTIF) - 1;
1363 case TRD_KEYWORD_GROUPING:
1364 return sizeof(TRD_BODY_KEYWORD_GROUPING) - 1;
1365 case TRD_KEYWORD_YANG_DATA:
1366 return sizeof(TRD_BODY_KEYWORD_YANG_DATA) - 1;
1367 default:
1368 return 0;
1369 }
1370}
1371
1372/**
aPiecek874ea4d2021-04-19 12:26:36 +02001373 * @brief Print trt_keyword_stmt.str which is string of name or path.
aPiecek61d062b2020-11-02 11:05:09 +01001374 * @param[in] ks is keyword statement structure.
1375 * @param[in] mll is max line length.
1376 * @param[in,out] out is output handler.
1377 */
1378static void
1379trt_print_keyword_stmt_str(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
1380{
1381 uint32_t ind_initial;
1382 uint32_t ind_divided;
1383 /* flag if path must be splitted to more lines */
1384 ly_bool linebreak_was_set;
1385 /* flag if at least one subpath was printed */
1386 ly_bool subpath_printed;
1387 /* the sum of the sizes of the substrings on the current line */
1388 uint32_t how_far;
1389 /* pointer to start of the subpath */
1390 const char *sub_ptr;
1391 /* size of subpath from sub_ptr */
1392 size_t sub_len;
1393
1394 if ((!ks.str) || (ks.str[0] == '\0')) {
1395 return;
1396 }
1397
1398 /* module name cannot be splitted */
1399 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
1400 ly_print_(out, "%s", ks.str);
1401 return;
1402 }
1403
1404 /* after -> for trd_keyword_stmt_body do */
1405
1406 /* set begin indentation */
1407 ind_initial = TRD_INDENT_LINE_BEGIN + trp_keyword_type_strlen(ks.type) + 1;
1408 ind_divided = ind_initial + TRD_INDENT_LONG_LINE_BREAK;
1409 linebreak_was_set = 0;
1410 subpath_printed = 0;
1411 how_far = 0;
1412 sub_ptr = ks.str;
1413 sub_len = 0;
1414
1415 while (sub_ptr[0] != '\0') {
1416 uint32_t ind;
1417 /* skip slash */
1418 const char *tmp = sub_ptr[0] == '/' ? sub_ptr + 1 : sub_ptr;
1419 /* get position of the end of substr */
1420 tmp = strchr(tmp, '/');
1421 /* set correct size if this is a last substring */
1422 sub_len = !tmp ? strlen(sub_ptr) : (size_t)(tmp - sub_ptr);
1423 /* actualize sum of the substring's sizes on the current line */
1424 how_far += sub_len;
1425 /* correction due to colon character if it this is last substring */
1426 how_far = *(sub_ptr + sub_len) == '\0' ? how_far + 1 : how_far;
1427 /* choose indentation which depends on
1428 * whether the string is printed on multiple lines or not
1429 */
1430 ind = linebreak_was_set ? ind_divided : ind_initial;
1431 if (ind + how_far <= mll) {
1432 /* printing before max line length */
1433 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1434 subpath_printed = 1;
1435 } else {
1436 /* printing on new line */
1437 if (subpath_printed == 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001438 /* first subpath is too long
1439 * but print it at first line anyway
1440 */
aPiecek61d062b2020-11-02 11:05:09 +01001441 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1442 subpath_printed = 1;
1443 continue;
1444 }
1445 ly_print_(out, "\n");
1446 ly_print_(out, "%*c", ind_divided, ' ');
1447 linebreak_was_set = 1;
1448 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1449 how_far = sub_len;
1450 subpath_printed = 1;
1451 }
1452 }
1453}
1454
1455/**
aPiecek874ea4d2021-04-19 12:26:36 +02001456 * @brief Print separator based on trt_keyword_stmt.type
aPiecek61d062b2020-11-02 11:05:09 +01001457 * @param[in] ks is keyword statement structure.
aPiecekdc8fd572021-04-19 10:47:23 +02001458 * @param[in] grp_has_data is flag only for grouping section.
1459 * Set to 1 if grouping section has some nodes.
1460 * Set to 0 if it doesn't have nodes or it's not grouping section.
aPiecek61d062b2020-11-02 11:05:09 +01001461 * @param[in,out] out is output handler.
1462 */
1463static void
aPiecekdc8fd572021-04-19 10:47:23 +02001464trt_print_keyword_stmt_end(struct trt_keyword_stmt ks, ly_bool grp_has_data, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001465{
1466 if ((ks.type != TRD_KEYWORD_MODULE) && (ks.type != TRD_KEYWORD_SUBMODULE)) {
aPiecekdc8fd572021-04-19 10:47:23 +02001467 if ((ks.type == TRD_KEYWORD_GROUPING) && !grp_has_data) {
1468 return;
1469 } else {
1470 ly_print_(out, ":");
1471 }
aPiecek61d062b2020-11-02 11:05:09 +01001472 }
1473}
1474
1475/**
1476 * @brief Print entire struct trt_keyword_stmt structure.
1477 * @param[in] ks is item to print.
1478 * @param[in] mll is max line length.
aPiecekdc8fd572021-04-19 10:47:23 +02001479 * @param[in] grp_has_data is flag only for grouping section.
1480 * Set to 1 if grouping section has some nodes.
1481 * Set to 0 if it doesn't have nodes or it's not grouping section.
aPiecek61d062b2020-11-02 11:05:09 +01001482 * @param[in,out] out is output handler.
1483 */
1484static void
aPiecek874ea4d2021-04-19 12:26:36 +02001485trp_print_keyword_stmt(struct trt_keyword_stmt ks, size_t mll, ly_bool grp_has_data, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001486{
1487 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
1488 return;
1489 }
1490 trt_print_keyword_stmt_begin(ks, out);
1491 trt_print_keyword_stmt_str(ks, mll, out);
aPiecekdc8fd572021-04-19 10:47:23 +02001492 trt_print_keyword_stmt_end(ks, grp_has_data, out);
aPiecek61d062b2020-11-02 11:05:09 +01001493}
1494
aPiecek874ea4d2021-04-19 12:26:36 +02001495/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01001496 * Main trp functions
aPiecek874ea4d2021-04-19 12:26:36 +02001497 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01001498
1499/**
aPiecek874ea4d2021-04-19 12:26:36 +02001500 * @brief Printing one line including wrapper and node
1501 * which can be incomplete (divided).
aPiecek61d062b2020-11-02 11:05:09 +01001502 * @param[in] node is \<node\> representation.
1503 * @param[in] pck contains special printing functions callback.
1504 * @param[in] indent contains wrapper and indent in node numbers.
1505 * @param[in,out] out is output handler.
1506 */
1507static void
1508trp_print_line(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out)
1509{
1510 trp_print_wrapper(indent.wrapper, out);
1511 trp_print_node(node, pck, indent.in_node, out);
1512}
1513
1514/**
aPiecek874ea4d2021-04-19 12:26:36 +02001515 * @brief Printing one line including wrapper and
1516 * \<status\>--\<flags\> \<name\>\<option_mark\>.
aPiecek61d062b2020-11-02 11:05:09 +01001517 * @param[in] node is \<node\> representation.
1518 * @param[in] wr is wrapper for printing indentation before node.
1519 * @param[in] out is output handler.
1520 */
1521static void
1522trp_print_line_up_to_node_name(struct trt_node node, struct trt_wrapper wr, struct ly_out *out)
1523{
1524 trp_print_wrapper(wr, out);
1525 trp_print_node_up_to_name(node, out);
1526}
1527
1528/**
aPiecek874ea4d2021-04-19 12:26:36 +02001529 * @brief Check if leafref target must be change to string 'leafref'
1530 * because his target string is too long.
aPiecek61d062b2020-11-02 11:05:09 +01001531 * @param[in] node containing leafref target.
1532 * @param[in] wr is wrapper for printing indentation before node.
1533 * @param[in] mll is max line length.
1534 * @param[in] out is output handler.
1535 * @return true if leafref must be changed to string 'leafref'.
1536 */
1537static ly_bool
1538trp_leafref_target_is_too_long(struct trt_node node, struct trt_wrapper wr, size_t mll, struct ly_out *out)
1539{
1540 struct ly_out_clb_arg *data;
1541
1542 if (node.type.type != TRD_TYPE_TARGET) {
1543 return 0;
1544 }
1545
1546 /* set ly_out to counting characters */
1547 data = out->method.clb.arg;
1548
1549 data->counter = 0;
1550 data->mode = TRD_CHAR_COUNT;
1551 /* count number of printed bytes */
1552 trp_print_wrapper(wr, out);
1553 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1554 trp_print_divided_node_up_to_name(node, out);
1555 data->mode = TRD_PRINT;
1556
1557 return data->counter + strlen(node.type.str) > mll;
1558}
1559
1560/**
1561 * @brief Get default indent in node based on node values.
1562 * @param[in] node is \<node\> representation.
aPiecek874ea4d2021-04-19 12:26:36 +02001563 * @return Default indent in node assuming that the node
1564 * will not be divided.
aPiecek61d062b2020-11-02 11:05:09 +01001565 */
1566static struct trt_indent_in_node
1567trp_default_indent_in_node(struct trt_node node)
1568{
1569 struct trt_indent_in_node ret;
1570
1571 ret.type = TRD_INDENT_IN_NODE_NORMAL;
1572
1573 /* btw_name_opts */
1574 ret.btw_name_opts = node.name.type == TRD_NODE_KEYS ? TRD_INDENT_BEFORE_KEYS : 0;
1575
1576 /* btw_opts_type */
1577 if (!(TRP_TRT_TYPE_IS_EMPTY(node.type))) {
1578 ret.btw_opts_type = trp_mark_is_used(node.name) ?
1579 TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
1580 TRD_INDENT_BEFORE_TYPE;
1581 } else {
1582 ret.btw_opts_type = 0;
1583 }
1584
1585 /* btw_type_iffeatures */
1586 ret.btw_type_iffeatures = node.iffeatures ? TRD_INDENT_BEFORE_IFFEATURES : 0;
1587
1588 return ret;
1589}
1590
1591/**
1592 * @brief Setting linebreaks in trt_indent_in_node.
1593 *
1594 * The order where the linebreak tag can be placed is from the end.
1595 *
aPiecek874ea4d2021-04-19 12:26:36 +02001596 * @param[in] indent containing alignment lengths
1597 * or already linebreak marks.
aPiecek61d062b2020-11-02 11:05:09 +01001598 * @return indent with a newly placed linebreak tag.
aPiecek874ea4d2021-04-19 12:26:36 +02001599 * @return .type set to TRD_INDENT_IN_NODE_FAILED if it is not possible
1600 * to place a more linebreaks.
aPiecek61d062b2020-11-02 11:05:09 +01001601 */
1602static struct trt_indent_in_node
1603trp_indent_in_node_place_break(struct trt_indent_in_node indent)
1604{
1605 /* somewhere must be set a line break in node */
1606 struct trt_indent_in_node ret = indent;
1607
1608 /* gradually break the node from the end */
1609 if ((indent.btw_type_iffeatures != TRD_LINEBREAK) && (indent.btw_type_iffeatures != 0)) {
1610 ret.btw_type_iffeatures = TRD_LINEBREAK;
1611 } else if ((indent.btw_opts_type != TRD_LINEBREAK) && (indent.btw_opts_type != 0)) {
1612 ret.btw_opts_type = TRD_LINEBREAK;
1613 } else if ((indent.btw_name_opts != TRD_LINEBREAK) && (indent.btw_name_opts != 0)) {
1614 /* set line break between name and opts */
1615 ret.btw_name_opts = TRD_LINEBREAK;
1616 } else {
1617 /* it is not possible to place a more line breaks,
1618 * unfortunately the max_line_length constraint is violated
1619 */
1620 ret.type = TRD_INDENT_IN_NODE_FAILED;
1621 }
1622 return ret;
1623}
1624
1625/**
1626 * @brief Get the first half of the node based on the linebreak mark.
1627 *
1628 * Items in the second half of the node will be empty.
1629 *
1630 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001631 * @param[in] indent contains information in which part of the \<node\>
1632 * the first half ends.
aPiecek61d062b2020-11-02 11:05:09 +01001633 * @return first half of the node, indent is unchanged.
1634 */
1635static struct trt_pair_indent_node
1636trp_first_half_node(struct trt_node node, struct trt_indent_in_node indent)
1637{
1638 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1639
1640 if (indent.btw_name_opts == TRD_LINEBREAK) {
1641 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1642 ret.node.type = TRP_EMPTY_TRT_TYPE;
1643 ret.node.iffeatures = 0;
1644 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1645 ret.node.type = TRP_EMPTY_TRT_TYPE;
1646 ret.node.iffeatures = 0;
1647 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1648 ret.node.iffeatures = 0;
1649 }
1650
1651 return ret;
1652}
1653
1654/**
1655 * @brief Get the second half of the node based on the linebreak mark.
1656 *
1657 * Items in the first half of the node will be empty.
1658 * Indentations belonging to the first node will be reset to zero.
1659 *
1660 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001661 * @param[in] indent contains information in which part of the \<node\>
1662 * the second half starts.
aPiecek61d062b2020-11-02 11:05:09 +01001663 * @return second half of the node, indent is newly set.
1664 */
1665static struct trt_pair_indent_node
1666trp_second_half_node(struct trt_node node, struct trt_indent_in_node indent)
1667{
1668 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1669
1670 if (indent.btw_name_opts < 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001671 /* Logically, the information up to token <opts> should
1672 * be deleted, but the the trp_print_node function needs it to
1673 * create the correct indent.
aPiecek61d062b2020-11-02 11:05:09 +01001674 */
1675 ret.indent.btw_name_opts = 0;
1676 ret.indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(node.type) ? 0 : TRD_INDENT_BEFORE_TYPE;
1677 ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1678 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1679 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1680 ret.indent.btw_name_opts = 0;
1681 ret.indent.btw_opts_type = 0;
1682 ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1683 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1684 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1685 ret.node.type = TRP_EMPTY_TRT_TYPE;
1686 ret.indent.btw_name_opts = 0;
1687 ret.indent.btw_opts_type = 0;
1688 ret.indent.btw_type_iffeatures = 0;
1689 }
1690 return ret;
1691}
1692
1693/**
1694 * @brief Get the correct alignment for the node.
1695 *
aPiecek874ea4d2021-04-19 12:26:36 +02001696 * This function is recursively called itself. It's like a backend
1697 * function for a function trp_try_normal_indent_in_node().
aPiecek61d062b2020-11-02 11:05:09 +01001698 *
1699 * @param[in] node is \<node\> representation.
1700 * @param[in] pck contains speciall callback functions for printing.
1701 * @param[in] indent contains wrapper and indent in node numbers.
1702 * @param[in] mll is max line length.
1703 * @param[in,out] cnt counting number of characters to print.
1704 * @param[in,out] out is output handler.
1705 * @return pair of node and indentation numbers of that node.
1706 */
1707static struct trt_pair_indent_node
1708trp_try_normal_indent_in_node_(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, size_t mll, size_t *cnt, struct ly_out *out)
1709{
1710 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1711
1712 trp_print_line(node, pck, indent, out);
1713
1714 if (*cnt <= mll) {
1715 /* success */
1716 return ret;
1717 } else {
1718 ret.indent = trp_indent_in_node_place_break(ret.indent);
1719 if (ret.indent.type != TRD_INDENT_IN_NODE_FAILED) {
1720 /* erase information in node due to line break */
1721 ret = trp_first_half_node(node, ret.indent);
1722 /* check if line fits, recursive call */
1723 *cnt = 0;
1724 ret = trp_try_normal_indent_in_node_(ret.node, pck, TRP_INIT_PCK_INDENT(indent.wrapper, ret.indent), mll, cnt, out);
1725 /* make sure that the result will be with the status divided
1726 * or eventually with status failed */
1727 ret.indent.type = ret.indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED;
1728 }
1729 return ret;
1730 }
1731}
1732
1733/**
1734 * @brief Get the correct alignment for the node.
1735 *
1736 * @param[in] node is \<node\> representation.
1737 * @param[in] pck contains speciall callback functions for printing.
1738 * @param[in] indent contains wrapper and indent in node numbers.
1739 * @param[in] mll is max line length.
1740 * @param[in,out] out is output handler.
aPiecek874ea4d2021-04-19 12:26:36 +02001741 * @return ::TRD_INDENT_IN_NODE_DIVIDED - the node does not fit in the
1742 * line, some indent variable has negative value as a line break sign.
1743 * @return ::TRD_INDENT_IN_NODE_NORMAL - the node fits into the line,
1744 * all indent variables values has non-negative number.
1745 * @return ::TRD_INDENT_IN_NODE_FAILED - the node does not fit into the
1746 * line, all indent variables has negative or zero values,
1747 * function failed.
aPiecek61d062b2020-11-02 11:05:09 +01001748 */
1749static struct trt_pair_indent_node
1750trp_try_normal_indent_in_node(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, size_t mll, struct ly_out *out)
1751{
1752 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1753 struct ly_out_clb_arg *data;
1754
1755 /* set ly_out to counting characters */
1756 data = out->method.clb.arg;
1757
1758 data->counter = 0;
1759 data->mode = TRD_CHAR_COUNT;
1760 ret = trp_try_normal_indent_in_node_(node, pck, indent, mll, &data->counter, out);
1761 data->mode = TRD_PRINT;
1762
1763 return ret;
1764}
1765
1766/**
aPiecek874ea4d2021-04-19 12:26:36 +02001767 * @brief Auxiliary function for trp_print_entire_node()
1768 * that prints split nodes.
aPiecek61d062b2020-11-02 11:05:09 +01001769 * @param[in] node is node representation.
1770 * @param[in] ppck contains speciall callback functions for printing.
1771 * @param[in] ipck contains wrapper and indent in node numbers.
1772 * @param[in] mll is max line length.
1773 * @param[in,out] out is output handler.
1774 */
1775static void
1776trp_print_divided_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1777{
1778 ly_bool entire_node_was_printed;
1779 struct trt_pair_indent_node ind_node = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1780
1781 if (ind_node.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1782 /* nothing can be done, continue as usual */
1783 ind_node.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1784 }
1785
1786 trp_print_line(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), out);
1787 entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, ind_node.indent);
1788
1789 if (!entire_node_was_printed) {
1790 ly_print_(out, "\n");
1791 /* continue with second half node */
1792 ind_node = trp_second_half_node(node, ind_node.indent);
1793 /* continue with printing node */
1794 trp_print_divided_node(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), mll, out);
1795 } else {
1796 return;
1797 }
1798}
1799
1800/**
aPiecek874ea4d2021-04-19 12:26:36 +02001801 * @brief Printing of the wrapper and the whole node,
1802 * which can be divided into several lines.
aPiecek61d062b2020-11-02 11:05:09 +01001803 * @param[in] node is node representation.
1804 * @param[in] ppck contains speciall callback functions for printing.
1805 * @param[in] ipck contains wrapper and indent in node numbers.
1806 * @param[in] mll is max line length.
1807 * @param[in,out] out is output handler.
1808 */
1809static void
1810trp_print_entire_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1811{
1812 struct trt_pair_indent_node ind_node1;
1813 struct trt_pair_indent_node ind_node2;
1814 struct trt_pck_indent tmp;
1815
1816 if (trp_leafref_target_is_too_long(node, ipck.wrapper, mll, out)) {
1817 node.type.type = TRD_TYPE_LEAFREF;
1818 }
1819
1820 /* check if normal indent is possible */
1821 ind_node1 = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1822
1823 if (ind_node1.indent.type == TRD_INDENT_IN_NODE_NORMAL) {
1824 /* node fits to one line */
1825 trp_print_line(node, ppck, ipck, out);
1826 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_DIVIDED) {
1827 /* node will be divided */
1828 /* print first half */
1829 tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node1.indent);
1830 /* pretend that this is normal node */
1831 tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL;
1832
1833 trp_print_line(ind_node1.node, ppck, tmp, out);
1834 ly_print_(out, "\n");
1835
1836 /* continue with second half on new line */
1837 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1838 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1839
1840 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1841 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1842 /* node name is too long */
1843 trp_print_line_up_to_node_name(node, ipck.wrapper, out);
1844
1845 if (trp_node_body_is_empty(node)) {
1846 return;
1847 } else {
1848 ly_print_(out, "\n");
1849
1850 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1851 ind_node2.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1852 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1853
1854 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1855 }
1856
1857 }
1858}
1859
aPiecek874ea4d2021-04-19 12:26:36 +02001860/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01001861 * Definition of Tro reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02001862 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01001863
1864/**
aPiecek874ea4d2021-04-19 12:26:36 +02001865 * @brief Get new trt_parent_cache if we apply the transfer
1866 * to the child node in the tree.
aPiecek61d062b2020-11-02 11:05:09 +01001867 * @param[in] ca is parent cache for current node.
aPiecek874ea4d2021-04-19 12:26:36 +02001868 * @param[in] tc contains current tree node.
aPiecek61d062b2020-11-02 11:05:09 +01001869 * @return Cache for the current node.
1870 */
1871static struct trt_parent_cache
1872tro_parent_cache_for_child(struct trt_parent_cache ca, const struct lysp_node *pn)
1873{
1874 struct trt_parent_cache ret;
1875
1876 ret.ancestor =
1877 pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT :
1878 pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT :
1879 pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF :
1880 ca.ancestor;
1881
1882 ret.lys_status =
1883 pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
1884 ca.lys_status;
1885
1886 ret.lys_config =
1887 ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because <flags> will be -w */
1888 ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
1889 pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
1890 ca.lys_config;
1891
1892 ret.last_list =
1893 pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
1894 ca.last_list;
1895
1896 return ret;
1897}
1898
1899/**
aPiecek874ea4d2021-04-19 12:26:36 +02001900 * @brief Get next sibling of the current node.
1901 * @param[in] node points to lysp_node.
aPiecek61d062b2020-11-02 11:05:09 +01001902 */
1903static struct trt_tree_ctx_node_patch
1904tro_read_next_sibling(const struct trt_tree_ctx *origin_tc)
1905{
1906 assert(origin_tc && origin_tc->pn);
1907
1908 struct trt_tree_ctx_node_patch tc = TRP_INIT_TREE_CTX_NODE_PATCH(origin_tc->pn, origin_tc->tpn);
1909
1910 if (tc.pn->nodetype & (LYS_RPC | LYS_ACTION)) {
1911 if (tc.tpn == tc.pn) {
1912 /* just go to the top-node's sibling */
1913 tc.pn = tc.pn->next;
1914 tc.tpn = tc.pn;
1915 } else {
1916 /* try to go to the notif node as sibling */
1917 if (!tc.pn->next) {
1918 tc.pn = (const struct lysp_node *)lysp_node_notifs(tc.pn->parent);
1919 } else {
1920 tc.pn = tc.pn->next;
1921 }
1922 }
1923 } else if (tc.pn->nodetype & LYS_INPUT) {
1924 const struct lysp_node_action *parent = (struct lysp_node_action *)tc.pn->parent;
1925 /* if output action has data */
1926 if (parent->output.child) {
1927 /* then next sibling is output action */
1928 tc.pn = &parent->output.node;
1929 } else {
1930 /* else input action has no sibling */
1931 tc.pn = NULL;
1932 }
1933 /* if current node is output action */
1934 } else if (tc.pn->nodetype & LYS_OUTPUT) {
1935 /* then next sibling does not exist */
1936 tc.pn = NULL;
1937 /* if current node is notification */
1938 } else if (tc.pn->nodetype & LYS_NOTIF) {
1939 if (tc.tpn == tc.pn) {
1940 tc.pn = tc.pn->next;
1941 tc.tpn = tc.pn;
1942 } else {
1943 tc.pn = tc.pn->next;
1944 }
1945 } else {
1946 /* else actual node is some node with 'next' element */
1947 if (tc.tpn == tc.pn) {
1948 tc.tpn = tc.pn->next;
1949 }
1950 tc.pn = tc.pn->next;
1951 }
1952
1953 return tc;
1954}
1955
1956/**
1957 * @brief Find out if the current node has siblings.
1958 * @param[in] tc is context of the tree.
1959 * @return 1 if sibling exists otherwise 0.
1960 */
1961static ly_bool
1962tro_read_if_sibling_exists(const struct trt_tree_ctx *tc)
1963{
1964 return tro_read_next_sibling(tc).pn != NULL;
1965}
1966
1967/**
1968 * @brief Check if list statement has keys.
1969 * @param[in] pn is pointer to the list.
1970 * @return 1 if has keys, otherwise 0.
1971 */
1972static ly_bool
1973tro_lysp_list_has_keys(const struct lysp_node_list *pn)
1974{
1975 return trg_charptr_has_data(pn->key);
1976}
1977
1978/**
1979 * @brief Check if it contains at least one feature.
1980 * @param[in] iffs is pointer to the if-features.
1981 * @return 1 if has if-features, otherwise 0.
1982 */
1983static ly_bool
1984tro_lysp_node_to_iffeature(const struct lysp_qname *iffs)
1985{
1986 LY_ARRAY_COUNT_TYPE u;
1987 ly_bool ret = 0;
1988
1989 LY_ARRAY_FOR(iffs, u) {
1990 ret = 1;
1991 break;
1992 }
1993 return ret;
1994}
1995
1996/**
1997 * @brief Find out if leaf is also the key in last list.
1998 * @param[in] pn is pointer to leaf.
aPiecek874ea4d2021-04-19 12:26:36 +02001999 * @param[in] ca_last_list is pointer to last visited list.
2000 * Obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002001 * @return 1 if leaf is also the key, otherwise 0.
2002 */
2003static ly_bool
2004tro_lysp_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
2005{
2006 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2007 const struct lysp_node_list *list = ca_last_list;
2008
2009 if (!list) {
2010 return 0;
2011 }
2012 return trg_charptr_has_data(list->key) ?
2013 trg_word_is_present(list->key, leaf->name, ' ') : 0;
2014}
2015
2016/**
2017 * @brief Check if container's type is presence.
2018 * @param[in] pn is pointer to container.
2019 * @return 1 if container has presence statement, otherwise 0.
2020 */
2021static ly_bool
2022tro_lysp_container_has_presence(const struct lysp_node *pn)
2023{
2024 return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence);
2025}
2026
2027/**
2028 * @brief Get leaflist's path without lysp_node type control.
2029 * @param[in] pn is pointer to the leaflist.
2030 */
2031static const char *
2032tro_lysp_leaflist_refpath(const struct lysp_node *pn)
2033{
2034 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2035
2036 return list->type.path ? list->type.path->expr : NULL;
2037}
2038
2039/**
2040 * @brief Get leaflist's type name without lysp_node type control.
2041 * @param[in] pn is pointer to the leaflist.
2042 */
2043static const char *
2044tro_lysp_leaflist_type_name(const struct lysp_node *pn)
2045{
2046 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2047
2048 return list->type.name;
2049}
2050
2051/**
2052 * @brief Get leaf's path without lysp_node type control.
2053 * @param[in] pn is pointer to the leaf node.
2054 */
2055static const char *
2056tro_lysp_leaf_refpath(const struct lysp_node *pn)
2057{
2058 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2059
2060 return leaf->type.path ? leaf->type.path->expr : NULL;
2061}
2062
2063/**
2064 * @brief Get leaf's type name without lysp_node type control.
2065 * @param[in] pn is pointer to the leaf's type name.
2066 */
2067static const char *
2068tro_lysp_leaf_type_name(const struct lysp_node *pn)
2069{
2070 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2071
2072 return leaf->type.name;
2073}
2074
2075/**
aPiecek874ea4d2021-04-19 12:26:36 +02002076 * @brief Get pointer to data using node type specification
2077 * and getter function.
aPiecek61d062b2020-11-02 11:05:09 +01002078 *
aPiecek874ea4d2021-04-19 12:26:36 +02002079 * @param[in] flags is node type specification.
2080 * If it is the correct node, the getter function is called.
2081 * @param[in] f is getter function which provides the desired
2082 * char pointer from the structure.
aPiecek61d062b2020-11-02 11:05:09 +01002083 * @param[in] pn pointer to node.
aPiecek874ea4d2021-04-19 12:26:36 +02002084 * @return NULL if node has wrong type or getter function return
2085 * pointer to NULL.
aPiecek61d062b2020-11-02 11:05:09 +01002086 * @return Pointer to desired char pointer obtained from the node.
2087 */
2088static const char *
2089tro_lysp_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn)
2090{
2091 if (pn->nodetype & flags) {
2092 const char *ret = f(pn);
2093 return trg_charptr_has_data(ret) ? ret : NULL;
2094 } else {
2095 return NULL;
2096 }
2097}
2098
2099/**
aPiecek874ea4d2021-04-19 12:26:36 +02002100 * @brief Transformation of the Schema nodes flags to
2101 * Tree diagram \<status\>.
aPiecek61d062b2020-11-02 11:05:09 +01002102 * @param[in] flags is node's flags obtained from the tree.
2103 */
2104static trt_status_type
2105tro_lysp_flags2status(uint16_t flags)
2106{
2107 return flags & LYS_STATUS_OBSLT ? TRD_STATUS_TYPE_OBSOLETE :
2108 flags & LYS_STATUS_DEPRC ? TRD_STATUS_TYPE_DEPRECATED :
2109 TRD_STATUS_TYPE_CURRENT;
2110}
2111
2112/**
aPiecek874ea4d2021-04-19 12:26:36 +02002113 * @brief Transformation of the Schema nodes flags to Tree diagram
2114 * \<flags\> but more specifically 'ro' or 'rw'.
aPiecek61d062b2020-11-02 11:05:09 +01002115 * @param[in] flags is node's flags obtained from the tree.
2116 */
2117static trt_flags_type
2118tro_lysp_flags2config(uint16_t flags)
2119{
aPiecekdc8fd572021-04-19 10:47:23 +02002120 return flags & LYS_CONFIG_R ? TRD_FLAGS_TYPE_RO :
2121 flags & LYS_CONFIG_W ? TRD_FLAGS_TYPE_RW :
2122 TRD_FLAGS_TYPE_EMPTY;
aPiecek61d062b2020-11-02 11:05:09 +01002123}
2124
2125/**
2126 * @brief Get name of the module.
2127 * @param[in] tc is context of the tree.
2128 */
2129static struct trt_keyword_stmt
2130tro_read_module_name(const struct trt_tree_ctx *tc)
2131{
2132 assert(tc && tc->module && tc->module->name);
2133 return (struct trt_keyword_stmt) {
2134 .type = TRD_KEYWORD_MODULE, .str = tc->module->name
2135 };
2136}
2137
2138/**
2139 * @brief Resolve \<status\> of the current node.
2140 * @param[in] nodetype is node's type obtained from the tree.
2141 * @param[in] flags is node's flags obtained from the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002142 * @param[in] ca_lys_status is inherited status
2143 * obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002144 * @return The status type.
2145 */
2146static trt_status_type
2147tro_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
2148{
2149 /* LYS_INPUT and LYS_OUTPUT is special case */
2150 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
2151 return tro_lysp_flags2status(ca_lys_status);
2152 /* if ancestor's status is deprc or obslt and also node's status is not set */
2153 } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
2154 /* get ancestor's status */
2155 return tro_lysp_flags2status(ca_lys_status);
2156 } else {
2157 /* else get node's status */
2158 return tro_lysp_flags2status(flags);
2159 }
2160}
2161
2162/**
2163 * @brief Resolve \<flags\> of the current node.
2164 * @param[in] nodetype is node's type obtained from the tree.
2165 * @param[in] flags is node's flags obtained from the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002166 * @param[in] ca_ancestor is ancestor type obtained
2167 * from trt_parent_cache.
2168 * @param[in] ca_lys_config is inherited config item
2169 * obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002170 * @return The flags type.
2171 */
2172static trt_flags_type
2173tro_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config)
2174{
2175 if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) {
2176 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
2177 } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) {
2178 return TRD_FLAGS_TYPE_RO;
2179 } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) {
2180 return TRD_FLAGS_TYPE_RO;
2181 } else if (nodetype & LYS_NOTIF) {
2182 return TRD_FLAGS_TYPE_NOTIF;
2183 } else if (nodetype & LYS_USES) {
2184 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
2185 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
2186 return TRD_FLAGS_TYPE_RPC;
2187 /* if config is not set then look at ancestor's config and get his config */
2188 } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
2189 return tro_lysp_flags2config(ca_lys_config);
2190 } else {
2191 return tro_lysp_flags2config(flags);
2192 }
2193}
2194
2195/**
2196 * @brief Resolve node type of the current node.
2197 * @param[in] pn is pointer to the current node in the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002198 * @param[in] ca_last_list is pointer to the last visited list.
2199 * Obtained from the trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002200 */
2201static trt_node_type
2202tro_resolve_node_type(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
2203{
2204 if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
2205 return TRD_NODE_ELSE;
2206 } else if (pn->nodetype & LYS_CASE) {
2207 return TRD_NODE_CASE;
2208 } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) {
2209 return TRD_NODE_OPTIONAL_CHOICE;
2210 } else if (pn->nodetype & LYS_CHOICE) {
2211 return TRD_NODE_CHOICE;
2212 } else if ((pn->nodetype & LYS_CONTAINER) && (tro_lysp_container_has_presence(pn))) {
2213 return TRD_NODE_CONTAINER;
2214 } else if ((pn->nodetype & LYS_LIST) && (tro_lysp_list_has_keys((const struct lysp_node_list *)pn))) {
2215 return TRD_NODE_KEYS;
2216 } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
2217 return TRD_NODE_LISTLEAFLIST;
2218 } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) {
2219 return TRD_NODE_OPTIONAL;
2220 } else if ((pn->nodetype & LYS_LEAF) && !(pn->flags & LYS_MAND_TRUE) && (!tro_lysp_leaf_is_key(pn, ca_last_list))) {
2221 return TRD_NODE_OPTIONAL;
2222 } else {
2223 return TRD_NODE_ELSE;
2224 }
2225}
2226
2227/**
2228 * @brief Transformation of current lysp_node to struct trt_node.
aPiecek874ea4d2021-04-19 12:26:36 +02002229 * @param[in] ca contains stored important data
2230 * when browsing the tree downwards.
aPiecek61d062b2020-11-02 11:05:09 +01002231 * @param[in] tc is context of the tree.
2232 */
2233static struct trt_node
2234tro_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2235{
2236 assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
2237 const struct lysp_node *pn = tc->pn;
2238 struct trt_node ret = TRP_EMPTY_NODE;
2239 const char *tmp;
2240
2241 /* <status> */
2242 ret.status = tro_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
2243
2244 /* TODO: TRD_FLAGS_TYPE_MOUNT_POINT aka "mp" is not supported right now. */
2245 /* <flags> */
2246 ret.flags = tro_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config);
2247
2248 /* TODO: TRD_NODE_TOP_LEVEL1 aka '/' is not supported right now. */
2249 /* TODO: TRD_NODE_TOP_LEVEL2 aka '@' is not supported right now. */
2250 /* set type of the node */
2251 ret.name.type = tro_resolve_node_type(pn, ca.last_list);
2252
2253 /* TODO: ret.name.module_prefix is not supported right now. */
2254 ret.name.module_prefix = NULL;
2255
2256 /* set node's name */
2257 ret.name.str = pn->name;
2258
2259 /* <type> */
2260 tmp = NULL;
2261
2262 if ((tmp = tro_lysp_node_charptr(LYS_LEAFLIST, tro_lysp_leaflist_refpath, pn))) {
2263 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2264 } else if ((tmp = tro_lysp_node_charptr(LYS_LEAFLIST, tro_lysp_leaflist_type_name, pn))) {
2265 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2266 } else if ((tmp = tro_lysp_node_charptr(LYS_LEAF, tro_lysp_leaf_refpath, pn))) {
2267 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2268 } else if ((tmp = tro_lysp_node_charptr(LYS_LEAF, tro_lysp_leaf_type_name, pn))) {
2269 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2270 } else if ((pn->nodetype & LYS_ANYDATA) == LYS_ANYDATA) {
2271 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata");
2272 } else if (pn->nodetype & LYS_ANYXML) {
2273 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml");
2274 } else {
2275 ret.type = TRP_EMPTY_TRT_TYPE;
2276 }
2277
2278 /* <iffeature> */
2279 ret.iffeatures = tro_lysp_node_to_iffeature(pn->iffeatures);
2280
2281 ret.last_one = !tro_read_if_sibling_exists(tc);
2282
2283 return ret;
2284}
2285
aPiecek874ea4d2021-04-19 12:26:36 +02002286/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01002287 * Modify Tro getters
aPiecek874ea4d2021-04-19 12:26:36 +02002288 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002289
2290/**
aPiecek874ea4d2021-04-19 12:26:36 +02002291 * @brief Change current node pointer to its parent
2292 * but only if parent exists.
2293 * @param[in,out] tc is tree context.
2294 * Contains pointer to the current node.
aPiecek61d062b2020-11-02 11:05:09 +01002295 * @return 1 if the node had parents and the change was successful.
aPiecek874ea4d2021-04-19 12:26:36 +02002296 * @return 0 if the node did not have parents.
2297 * The pointer to the current node did not change.
aPiecek61d062b2020-11-02 11:05:09 +01002298 */
2299static ly_bool
2300tro_modi_parent(struct trt_tree_ctx *tc)
2301{
2302 assert(tc && tc->pn);
2303 /* If no parent exists, stay in actual node. */
2304 if (tc->pn != tc->tpn) {
2305 tc->pn = tc->pn->parent;
2306 return 1;
2307 } else {
2308 return 0;
2309 }
2310}
2311
2312/**
aPiecek874ea4d2021-04-19 12:26:36 +02002313 * @brief Change the current node pointer to its child
2314 * but only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01002315 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02002316 * @param[in,out] tc is context of the tree.
2317 * Contains pointer to the current node.
2318 * @return Non-empty \<node\> representation of the current
2319 * node's child. The @p tc is modified.
2320 * @return Empty \<node\> representation if child don't exists.
2321 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01002322 */
2323static struct trt_node
2324tro_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
2325{
2326 assert(tc && tc->pn);
2327
2328 struct trt_parent_cache new_ca = tro_parent_cache_for_child(ca, tc->pn);
2329
2330 if (tc->pn->nodetype & (LYS_ACTION | LYS_RPC)) {
2331 const struct lysp_node_action *act = (const struct lysp_node_action *)tc->pn;
2332 if (act->input.child) {
2333 /* go to LYS_INPUT */
2334 tc->pn = &act->input.node;
2335 return tro_read_node(new_ca, tc);
2336 } else if (act->output.child) {
2337 /* go to LYS_OUTPUT */
2338 tc->pn = &act->output.node;
2339 return tro_read_node(new_ca, tc);
2340 } else {
2341 /* input action and output action are not set */
2342 return TRP_EMPTY_NODE;
2343 }
2344 } else {
2345 const struct lysp_node *pn = lysp_node_child(tc->pn);
2346 if (pn) {
2347 tc->pn = pn;
2348 return tro_read_node(new_ca, tc);
2349 } else {
2350 /* current node can't have children or has no children */
2351 /* but maybe has some actions or notifs */
2352 const struct lysp_node_action *actions = lysp_node_actions(tc->pn);
2353 const struct lysp_node_notif *notifs = lysp_node_notifs(tc->pn);
2354
2355 if (actions) {
2356 tc->pn = (const struct lysp_node *)actions;
2357 return tro_read_node(new_ca, tc);
2358 } else if (notifs) {
2359 tc->pn = (const struct lysp_node *)notifs;
2360 return tro_read_node(new_ca, tc);
2361 } else {
2362 return TRP_EMPTY_NODE;
2363 }
2364 }
2365 }
2366}
2367
2368/**
aPiecek874ea4d2021-04-19 12:26:36 +02002369 * @brief Change the current node pointer to the first child of node's
2370 * parent. If current node is already first sibling/child then nothing
2371 * will change.
aPiecek61d062b2020-11-02 11:05:09 +01002372 * @param[in,out] tc is tree context.
2373 */
2374static void
2375tro_modi_first_sibling(struct trt_tree_ctx *tc)
2376{
2377 assert(tc && tc->pn && tc->module && tc->module->parsed);
2378
2379 if (tro_modi_parent(tc)) {
2380 tro_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
2381 } else {
2382 /* current node is top-node */
2383
2384 struct lysp_module *pm = tc->module->parsed;
2385
2386 switch (tc->section) {
2387 case TRD_SECT_MODULE:
2388 tc->pn = pm->data;
2389 break;
2390 case TRD_SECT_AUGMENT:
aPiecekdc8fd572021-04-19 10:47:23 +02002391 tc->pn = (const struct lysp_node *)pm->augments;
aPiecek61d062b2020-11-02 11:05:09 +01002392 break;
2393 case TRD_SECT_RPCS:
2394 tc->pn = (const struct lysp_node *)pm->rpcs;
2395 break;
2396 case TRD_SECT_NOTIF:
2397 tc->pn = (const struct lysp_node *)pm->notifs;
2398 break;
2399 case TRD_SECT_GROUPING:
aPiecekdc8fd572021-04-19 10:47:23 +02002400 tc->pn = (const struct lysp_node *)pm->groupings;
aPiecek61d062b2020-11-02 11:05:09 +01002401 break;
2402 case TRD_SECT_YANG_DATA:
2403 /*TODO: yang-data is not supported now */
2404 break;
2405 }
2406
2407 /* update pointer to top-node */
2408 tc->tpn = tc->pn;
2409 }
2410}
2411
2412/**
aPiecek874ea4d2021-04-19 12:26:36 +02002413 * @brief Change the pointer to the current node to its next sibling
2414 * only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01002415 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02002416 * @param[in,out] tc is tree context.
2417 * Contains pointer to the current node.
2418 * @return Non-empty \<node\> representation if sibling exists.
2419 * The @p tc is modified.
2420 * @return Empty \<node\> representation otherwise.
2421 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01002422 */
2423static struct trt_node
2424tro_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
2425{
2426 struct trt_tree_ctx_node_patch patch = tro_read_next_sibling(tc);
2427
2428 /* if next sibling exists */
2429 if (patch.pn) {
2430 /* update trt_tree_ctx */
2431 tc->pn = patch.pn;
2432 tc->tpn = patch.tpn;
2433 return tro_read_node(ca, tc);
2434 } else {
2435 return TRP_EMPTY_NODE;
2436 }
2437}
2438
2439/**
2440 * @brief Get next (or first) augment section if exists.
aPiecek874ea4d2021-04-19 12:26:36 +02002441 * @param[in,out] tc is tree context. It is modified and his current
2442 * node is set to the lysp_node_augment.
aPiecek61d062b2020-11-02 11:05:09 +01002443 * @return Section's representation if (next augment) section exists.
aPiecek61d062b2020-11-02 11:05:09 +01002444 * @return Empty section structure otherwise.
2445 */
2446static struct trt_keyword_stmt
2447tro_modi_next_augment(struct trt_tree_ctx *tc)
2448{
2449 assert(tc && tc->module && tc->module->parsed);
2450 const struct lysp_node_augment *augs;
2451
2452 /* if next_augment func was called for the first time */
2453 if (tc->section != TRD_SECT_AUGMENT) {
2454 tc->section = TRD_SECT_AUGMENT;
2455 augs = tc->module->parsed->augments;
2456 } else {
2457 /* get augment sibling from top-node pointer */
aPiecekdc8fd572021-04-19 10:47:23 +02002458 augs = (const struct lysp_node_augment *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01002459 }
2460
aPiecekdc8fd572021-04-19 10:47:23 +02002461 if (augs) {
2462 tc->pn = &augs->node;
aPiecek61d062b2020-11-02 11:05:09 +01002463 tc->tpn = tc->pn;
2464 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_AUGMENT, augs->nodeid);
2465 } else {
2466 return TRP_EMPTY_KEYWORD_STMT;
2467 }
2468}
2469
2470/**
2471 * @brief Get rpcs section if exists.
2472 * @param[in,out] tc is tree context.
aPiecek874ea4d2021-04-19 12:26:36 +02002473 * @return Section representation if it exists. The @p tc is modified
2474 * and his pointer points to the first node in rpcs section.
aPiecek61d062b2020-11-02 11:05:09 +01002475 * @return Empty section representation otherwise.
2476 */
2477static struct trt_keyword_stmt
2478tro_modi_get_rpcs(struct trt_tree_ctx *tc)
2479{
2480 assert(tc && tc->module && tc->module->parsed);
2481 const struct lysp_node_action *actions = tc->module->parsed->rpcs;
2482
2483 if (actions) {
2484 tc->section = TRD_SECT_RPCS;
2485 tc->pn = &actions->node;
2486 tc->tpn = tc->pn;
2487 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_RPC, NULL);
2488 } else {
2489 return TRP_EMPTY_KEYWORD_STMT;
2490 }
2491}
2492
2493/**
2494 * @brief Get notification section if exists
2495 * @param[in,out] tc is tree context.
2496 * @return Section representation if it exists.
aPiecek874ea4d2021-04-19 12:26:36 +02002497 * The @p tc is modified and his pointer points to the
2498 * first node in notification section.
aPiecek61d062b2020-11-02 11:05:09 +01002499 * @return Empty section representation otherwise.
2500 */
2501static struct trt_keyword_stmt
2502tro_modi_get_notifications(struct trt_tree_ctx *tc)
2503{
2504 assert(tc && tc->module && tc->module->parsed);
2505 const struct lysp_node_notif *notifs = tc->module->parsed->notifs;
2506
2507 if (notifs) {
2508 tc->section = TRD_SECT_NOTIF;
2509 tc->pn = &notifs->node;
2510 tc->tpn = tc->pn;
2511 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_NOTIF, NULL);
2512 } else {
2513 return TRP_EMPTY_KEYWORD_STMT;
2514 }
2515}
2516
2517/**
2518 * @brief Get next (or first) grouping section if exists
aPiecek874ea4d2021-04-19 12:26:36 +02002519 * @param[in,out] tc is tree context. It is modified and his current
2520 * node is set to the lysp_node_grp.
aPiecek61d062b2020-11-02 11:05:09 +01002521 * @return The next (or first) section representation if it exists.
aPiecek61d062b2020-11-02 11:05:09 +01002522 * @return Empty section representation otherwise.
2523 */
2524static struct trt_keyword_stmt
2525tro_modi_next_grouping(struct trt_tree_ctx *tc)
2526{
2527 assert(tc && tc->module && tc->module->parsed);
2528 const struct lysp_node_grp *grps;
2529
2530 if (tc->section != TRD_SECT_GROUPING) {
2531 tc->section = TRD_SECT_GROUPING;
2532 grps = tc->module->parsed->groupings;
2533 } else {
aPiecekdc8fd572021-04-19 10:47:23 +02002534 grps = (const struct lysp_node_grp *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01002535 }
2536
aPiecekdc8fd572021-04-19 10:47:23 +02002537 if (grps) {
2538 tc->pn = &grps->node;
aPiecek61d062b2020-11-02 11:05:09 +01002539 tc->tpn = tc->pn;
2540 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_GROUPING, grps->name);
2541 } else {
2542 return TRP_EMPTY_KEYWORD_STMT;
2543 }
2544}
2545
2546/**
2547 * @brief Get next yang-data section if exists.
2548 *
2549 * Not implemented.
2550 *
2551 * @param[in,out] tc is tree context.
2552 * @return Section representation if it exists.
2553 * @return Empty section representation otherwise.
2554 */
2555static struct trt_keyword_stmt
2556tro_modi_next_yang_data(struct trt_tree_ctx *tc)
2557{
2558 tc->section = TRD_SECT_YANG_DATA;
2559 /* TODO: yang-data is not supported */
2560 return TRP_EMPTY_KEYWORD_STMT;
2561}
2562
aPiecek874ea4d2021-04-19 12:26:36 +02002563/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01002564 * Print Tro getters
aPiecek874ea4d2021-04-19 12:26:36 +02002565 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002566
2567/**
2568 * @brief Print current node's iffeatures.
2569 * @param[in] tc is tree context.
2570 * @param[in,out] out is output handler.
2571 */
2572static void
2573tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out)
2574{
2575 const struct lysp_qname *iffs = tc->pn->iffeatures;
2576
2577 LY_ARRAY_COUNT_TYPE i;
2578
2579 LY_ARRAY_FOR(iffs, i) {
2580 if (i == 0) {
2581 ly_print_(out, "%s", iffs[i].str);
2582 } else {
2583 ly_print_(out, ",%s", iffs[i].str);
2584 }
2585 }
2586
2587}
2588
2589/**
2590 * @brief Print current list's keys.
2591 *
aPiecek874ea4d2021-04-19 12:26:36 +02002592 * Well, actually printing keys in the lysp_tree is trivial,
2593 * because char* points to all keys. However, special functions have
2594 * been reserved for this, because in principle the list of elements
2595 * can have more implementations.
aPiecek61d062b2020-11-02 11:05:09 +01002596 *
2597 * @param[in] tc is tree context.
2598 * @param[in,out] out is output handler.
2599 */
2600static void
2601tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out)
2602{
2603 const struct lysp_node *pn = tc->pn;
2604 const struct lysp_node_list *list;
2605
2606 if (pn->nodetype != LYS_LIST) {
2607 return;
2608 }
2609
2610 list = (const struct lysp_node_list *)pn;
2611
2612 if (trg_charptr_has_data(list->key)) {
2613 ly_print_(out, "%s", list->key);
2614 }
2615}
2616
aPiecek874ea4d2021-04-19 12:26:36 +02002617/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01002618 * Definition of tree browsing functions
aPiecek874ea4d2021-04-19 12:26:36 +02002619 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002620
2621/**
2622 * @brief Get size of node name.
2623 * @param[in] name contains name and mark.
2624 * @return positive value total size of the node name.
aPiecek874ea4d2021-04-19 12:26:36 +02002625 * @return negative value as an indication that option mark
2626 * is included in the total size.
aPiecek61d062b2020-11-02 11:05:09 +01002627 */
2628static int32_t
2629trb_strlen_of_name_and_mark(struct trt_node_name name)
2630{
2631 size_t name_len = strlen(name.str);
2632
2633 if ((name.type == TRD_NODE_CHOICE) || (name.type == TRD_NODE_CASE)) {
2634 /* counting also parentheses */
2635 name_len += 2;
2636 }
2637
2638 return trp_mark_is_used(name) ?
2639 ((int32_t)(name_len + TRD_OPTS_MARK_LENGTH)) * (-1) :
2640 (int32_t)name_len;
2641}
2642
2643/**
aPiecek874ea4d2021-04-19 12:26:36 +02002644 * @brief Calculate the trt_indent_in_node.btw_opts_type indent size
2645 * for a particular node.
aPiecek61d062b2020-11-02 11:05:09 +01002646 * @param[in] name is the node for which we get btw_opts_type.
aPiecek874ea4d2021-04-19 12:26:36 +02002647 * @param[in] max_len4all is the maximum value of btw_opts_type
2648 * that it can have.
2649 * @return Indent between \<opts\> and \<type\> for node.
aPiecek61d062b2020-11-02 11:05:09 +01002650 */
2651static int16_t
2652trb_calc_btw_opts_type(struct trt_node_name name, int16_t max_len4all)
2653{
2654 int32_t name_len;
2655 int16_t min_len;
2656 int16_t ret;
2657
2658 name_len = trb_strlen_of_name_and_mark(name);
2659
2660 /* negative value indicate that in name is some opt mark */
2661 min_len = name_len < 0 ?
2662 TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
2663 TRD_INDENT_BEFORE_TYPE;
2664 ret = abs(max_len4all) - abs(name_len);
2665
2666 /* correction -> negative indicate that name is too long. */
2667 return ret < 0 ? min_len : ret;
2668}
2669
2670/**
2671 * @brief Print node.
2672 *
aPiecek874ea4d2021-04-19 12:26:36 +02002673 * This function is wrapper for trp_print_entire_node().
2674 * But difference is that take @p max_gap_before_type which will be
2675 * used to set the unified alignment.
aPiecek61d062b2020-11-02 11:05:09 +01002676 *
2677 * @param[in] max_gap_before_type is number of indent before \<type\>.
2678 * @param[in] wr is wrapper for printing indentation before node.
2679 * @param[in] ca contains inherited data from ancestors.
2680 * @param[in] pc contains mainly functions for printing.
2681 * @param[in] tc is tree context.
2682 */
2683static void
2684trb_print_entire_node(uint32_t max_gap_before_type, struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2685{
2686 struct trt_node node = pc->fp.read.node(ca, tc);
2687 struct trt_indent_in_node ind = trp_default_indent_in_node(node);
2688
2689 if ((max_gap_before_type > 0) && (node.type.type != TRD_TYPE_EMPTY)) {
2690 /* print actual node with unified indent */
2691 ind.btw_opts_type = trb_calc_btw_opts_type(node.name, max_gap_before_type);
2692 }
2693 /* after -> print actual node with default indent */
2694 trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print),
2695 TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out);
2696}
2697
2698/**
aPiecek874ea4d2021-04-19 12:26:36 +02002699 * @brief Check if parent of the current node is the last
2700 * of his siblings.
aPiecek61d062b2020-11-02 11:05:09 +01002701 *
aPiecek874ea4d2021-04-19 12:26:36 +02002702 * To mantain stability use this function only if the current node is
2703 * the first of the siblings.
2704 * Side-effect -> current node is set to the first sibling
2705 * if node has a parent otherwise no side-effect.
aPiecek61d062b2020-11-02 11:05:09 +01002706 *
aPiecek874ea4d2021-04-19 12:26:36 +02002707 * @param[in] fp contains all \ref TRP_tro callback functions.
aPiecek61d062b2020-11-02 11:05:09 +01002708 * @param[in,out] tc is tree context.
2709 * @return 1 if parent is last sibling otherwise 0.
2710 */
2711static ly_bool
2712trb_parent_is_last_sibling(struct trt_fp_all fp, struct trt_tree_ctx *tc)
2713{
2714 if (fp.modify.parent(tc)) {
2715 ly_bool ret = fp.read.if_sibling_exists(tc);
2716 fp.modify.next_child(TRP_EMPTY_PARENT_CACHE, tc);
2717 return !ret;
2718 } else {
2719 return !fp.read.if_sibling_exists(tc);
2720 }
2721}
2722
2723/**
2724 * @brief Find sibling with the biggest node name and return that size.
2725 *
2726 * Side-effect -> Current node is set to the first sibling.
2727 *
2728 * @param[in] ca contains inherited data from ancestors.
2729 * @param[in] pc contains mainly functions for printing.
2730 * @param[in,out] tc is tree context.
aPiecek874ea4d2021-04-19 12:26:36 +02002731 * @return positive number as a sign that only the node name is
2732 * included in the size.
2733 * @return negative number sign that node name and his opt mark is
2734 * included in the size.
aPiecek61d062b2020-11-02 11:05:09 +01002735 */
2736static int32_t
2737trb_maxlen_node_name(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2738{
2739 int32_t ret = 0;
2740
2741 pc->fp.modify.first_sibling(tc);
2742
2743 for (struct trt_node node = pc->fp.read.node(ca, tc);
2744 !trp_node_is_empty(node);
2745 node = pc->fp.modify.next_sibling(ca, tc)) {
2746 int32_t maxlen = trb_strlen_of_name_and_mark(node.name);
2747 ret = abs(maxlen) > abs(ret) ? maxlen : ret;
2748 }
2749 pc->fp.modify.first_sibling(tc);
2750 return ret;
2751}
2752
2753/**
aPiecek874ea4d2021-04-19 12:26:36 +02002754 * @brief Find maximal indent between
2755 * \<opts\> and \<type\> for siblings.
aPiecek61d062b2020-11-02 11:05:09 +01002756 *
2757 * Side-effect -> Current node is set to the first sibling.
2758 *
2759 * @param[in] ca contains inherited data from ancestors.
2760 * @param[in] pc contains mainly functions for printing.
2761 * @param[in,out] tc is tree context.
2762 * @return max btw_opts_type value for rest of the siblings
2763 */
2764static int16_t
2765trb_max_btw_opts_type4siblings(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2766{
2767 int32_t maxlen_node_name = trb_maxlen_node_name(ca, pc, tc);
2768 int16_t ind_before_type = maxlen_node_name < 0 ?
2769 TRD_INDENT_BEFORE_TYPE - 1 : /* mark was present */
2770 TRD_INDENT_BEFORE_TYPE;
2771
2772 return abs(maxlen_node_name) + ind_before_type;
2773}
2774
2775/**
aPiecek874ea4d2021-04-19 12:26:36 +02002776 * @brief Find out if it is possible to unify
2777 * the alignment before \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01002778 *
aPiecek874ea4d2021-04-19 12:26:36 +02002779 * The goal is for all node siblings to have the same alignment
2780 * for \<type\> as if they were in a column. All siblings who cannot
2781 * adapt because they do not fit on the line at all are ignored.
aPiecek61d062b2020-11-02 11:05:09 +01002782 * Side-effect -> Current node is set to the first sibling.
2783 *
2784 * @param[in] ca contains inherited data from ancestors.
2785 * @param[in] pc contains mainly functions for printing.
2786 * @param[in,out] tc is tree context.
2787 * @return 0 if all siblings cannot fit on the line.
aPiecek874ea4d2021-04-19 12:26:36 +02002788 * @return positive number indicating the maximum number of spaces
2789 * before \<type\> if the length of the node name is 0. To calculate
2790 * the trt_indent_in_node.btw_opts_type indent size for a particular
2791 * node, use the trb_calc_btw_opts_type().
aPiecek61d062b2020-11-02 11:05:09 +01002792*/
2793static uint32_t
2794trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2795{
2796 return trb_max_btw_opts_type4siblings(ca, pc, tc);
2797}
2798
2799/**
aPiecek874ea4d2021-04-19 12:26:36 +02002800 * @brief For the current node: recursively print all of its child
2801 * nodes and all of its siblings, including their children.
aPiecek61d062b2020-11-02 11:05:09 +01002802 *
aPiecek874ea4d2021-04-19 12:26:36 +02002803 * This function is an auxiliary function for trb_print_subtree_nodes().
aPiecek61d062b2020-11-02 11:05:09 +01002804 * The parent of the current node is expected to exist.
aPiecek874ea4d2021-04-19 12:26:36 +02002805 * Nodes are printed, including unified sibling node alignment
2806 * (align \<type\> to column).
aPiecek61d062b2020-11-02 11:05:09 +01002807 * Side-effect -> current node is set to the last sibling.
2808 *
2809 * @param[in] wr is wrapper for printing identation before node.
2810 * @param[in] ca contains inherited data from ancestors.
2811 * @param[in] pc contains mainly functions for printing.
2812 * @param[in,out] tc is tree context.
2813 */
2814static void
2815trb_print_nodes(struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2816{
2817 uint32_t max_gap_before_type;
2818 ly_bool sibling_flag = 0;
2819 ly_bool child_flag = 0;
2820
2821 /* if node is last sibling, then do not add '|' to wrapper */
2822 wr = trb_parent_is_last_sibling(pc->fp, tc) ?
2823 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
2824
2825 /* try unified indentation in node */
2826 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
2827
2828 /* print all siblings */
2829 do {
2830 struct trt_parent_cache new_ca;
2831 struct trt_node node;
2832 /* print linebreak before printing actual node */
2833 ly_print_(pc->out, "\n");
2834 /* print node */
2835 trb_print_entire_node(max_gap_before_type, wr, ca, pc, tc);
2836
2837 new_ca = tro_parent_cache_for_child(ca, tc->pn);
2838 /* go to the actual node's child or stay in actual node */
2839 node = pc->fp.modify.next_child(ca, tc);
2840 child_flag = !trp_node_is_empty(node);
2841
2842 if (child_flag) {
2843 /* print all childs - recursive call */
2844 trb_print_nodes(wr, new_ca, pc, tc);
2845 /* get back from child node to actual node */
2846 pc->fp.modify.parent(tc);
2847 }
2848
2849 /* go to the actual node's sibling */
2850 node = pc->fp.modify.next_sibling(ca, tc);
2851 sibling_flag = !trp_node_is_empty(node);
2852
2853 /* go to the next sibling or stay in actual node */
2854 } while (sibling_flag);
2855}
2856
2857/**
aPiecekdc8fd572021-04-19 10:47:23 +02002858 * @brief Get address of the current node.
2859 * @param[in] tc contains current node.
2860 * @return Address of lysp_node, or NULL.
2861 */
2862static const void *
2863trb_tree_ctx_get_node(struct trt_tree_ctx *tc)
2864{
2865 return (const void *)tc->pn;
2866}
2867
2868/**
2869 * @brief Get address of current node's child.
2870 * @param[in,out] tc contains current node.
2871 */
2872static const void *
2873trb_tree_ctx_get_child(struct trt_tree_ctx *tc)
2874{
2875 if (!trb_tree_ctx_get_node(tc)) {
2876 return NULL;
2877 }
2878
2879 return lysp_node_child(tc->pn);
2880}
2881
2882/**
2883 * @brief Set current node on its child.
2884 * @param[in,out] tc contains current node.
2885 */
2886static void
2887trb_tree_ctx_set_child(struct trt_tree_ctx *tc)
2888{
2889 tc->pn = trb_tree_ctx_get_child(tc);
2890}
2891
2892/**
aPiecek61d062b2020-11-02 11:05:09 +01002893 * @brief Print subtree of nodes.
2894 *
2895 * The current node is expected to be the root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02002896 * Before root node is no linebreak printing. This must be addressed by
2897 * the caller. Root node will also be printed. Behind last printed node
2898 * is no linebreak.
aPiecek61d062b2020-11-02 11:05:09 +01002899 *
aPiecek874ea4d2021-04-19 12:26:36 +02002900 * @param[in] max_gap_before_type is result from
2901 * trb_try_unified_indent() function for root node. Set parameter to 0
2902 * if distance does not matter.
2903 * @param[in] wr is wrapper saying how deep in the whole tree
2904 * is the root of the subtree.
2905 * @param[in] ca is parent_cache from root's parent.
2906 * If root is top-level node, insert ::TRP_EMPTY_PARENT_CACHE.
2907 * @param[in] pc is \ref TRP_trp settings.
2908 * @param[in,out] tc is context of tree printer.
aPiecek61d062b2020-11-02 11:05:09 +01002909 */
2910static void
2911trb_print_subtree_nodes(uint32_t max_gap_before_type, struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2912{
2913 struct trt_parent_cache new_ca;
2914 struct trt_node node;
2915
aPiecekdc8fd572021-04-19 10:47:23 +02002916 if (!trb_tree_ctx_get_node(tc)) {
2917 return;
2918 }
2919
aPiecek61d062b2020-11-02 11:05:09 +01002920 trb_print_entire_node(max_gap_before_type, wr, ca, pc, tc);
2921 /* go to the actual node's child */
2922 new_ca = tro_parent_cache_for_child(ca, tc->pn);
2923 node = pc->fp.modify.next_child(ca, tc);
2924
2925 if (!trp_node_is_empty(node)) {
2926 /* print root's nodes */
2927 trb_print_nodes(wr, new_ca, pc, tc);
2928 /* get back from child node to actual node */
2929 pc->fp.modify.parent(tc);
2930 }
2931}
2932
2933/**
2934 * @brief Get number of siblings.
2935 *
2936 * Side-effect -> current node is set to the first sibling.
2937 *
2938 * @param[in] fp contains callback functions which modify tree context
2939 * @param[in,out] tc is the tree context.
2940 * @return Number of siblings of the current node.
2941 */
2942static uint32_t
2943trb_get_number_of_siblings(struct trt_fp_modify_ctx fp, struct trt_tree_ctx *tc)
2944{
2945 uint32_t ret = 1;
2946 struct trt_node node = TRP_EMPTY_NODE;
2947
2948 /* including actual node */
2949 fp.first_sibling(tc);
2950 while (!trp_node_is_empty(node = fp.next_sibling(TRP_EMPTY_PARENT_CACHE, tc))) {
2951 ret++;
2952 }
2953 fp.first_sibling(tc);
2954 return ret;
2955}
2956
2957/**
2958 * @brief Print all parents and their children.
2959 *
aPiecek874ea4d2021-04-19 12:26:36 +02002960 * This function is suitable for printing top-level nodes that
2961 * do not have ancestors. Function call trb_print_subtree_nodes()
2962 * for all top-level siblings. Use this function after 'module' keyword
2963 * or 'augment' and so.
aPiecek61d062b2020-11-02 11:05:09 +01002964 *
2965 * @param[in] wr_t is type of the wrapper.
2966 * @param[pc] pc contains mainly functions for printing.
2967 * @param[in,out] tc is tree context.
2968 */
2969static void
2970trb_print_family_tree(trd_wrapper_type wr_t, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2971{
2972 struct trt_wrapper wr;
2973 struct trt_parent_cache ca;
2974 uint32_t total_parents;
2975 uint32_t max_gap_before_type;
2976
aPiecekdc8fd572021-04-19 10:47:23 +02002977 if (!trb_tree_ctx_get_node(tc)) {
2978 return;
2979 }
2980
aPiecek61d062b2020-11-02 11:05:09 +01002981 wr = wr_t == TRD_WRAPPER_TOP ? TRP_INIT_WRAPPER_TOP : TRP_INIT_WRAPPER_BODY;
2982 ca = TRP_EMPTY_PARENT_CACHE;
2983 total_parents = trb_get_number_of_siblings(pc->fp.modify, tc);
2984 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
2985
aPiecekdc8fd572021-04-19 10:47:23 +02002986 if ((tc->section == TRD_SECT_GROUPING) && (tc->tpn == tc->pn->parent)) {
2987 ca.lys_config = 0x0;
2988 }
2989
aPiecek61d062b2020-11-02 11:05:09 +01002990 for (uint32_t i = 0; i < total_parents; i++) {
2991 ly_print_(pc->out, "\n");
2992 trb_print_subtree_nodes(max_gap_before_type, wr, ca, pc, tc);
2993 pc->fp.modify.next_sibling(ca, tc);
2994 }
2995}
2996
aPiecek874ea4d2021-04-19 12:26:36 +02002997/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01002998 * Definition of trm main functions
aPiecek874ea4d2021-04-19 12:26:36 +02002999 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003000
3001/**
aPiecekdc8fd572021-04-19 10:47:23 +02003002 * @brief Settings if lysp_node are used for browsing through the tree.
aPiecek61d062b2020-11-02 11:05:09 +01003003 *
aPiecekdc8fd572021-04-19 10:47:23 +02003004 * @param[in] module YANG schema tree structure representing
3005 * YANG module.
aPiecek61d062b2020-11-02 11:05:09 +01003006 * @param[in] out is output handler.
aPiecekdc8fd572021-04-19 10:47:23 +02003007 * @param[in] max_line_length is the maximum line length limit
3008 * that should not be exceeded.
3009 * @param[in,out] pc will be adapted to lysp_tree.
3010 * @param[in,out] tc will be adapted to lysp_tree.
aPiecek61d062b2020-11-02 11:05:09 +01003011 */
3012static void
aPiecekdc8fd572021-04-19 10:47:23 +02003013trm_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003014{
aPiecekdc8fd572021-04-19 10:47:23 +02003015 *tc = (struct trt_tree_ctx) {
3016 .section = TRD_SECT_MODULE,
3017 .module = module,
3018 .pn = module->parsed->data,
3019 .tpn = module->parsed->data,
3020 };
aPiecek61d062b2020-11-02 11:05:09 +01003021
aPiecekdc8fd572021-04-19 10:47:23 +02003022 pc->out = out;
3023
3024 pc->fp.modify = (struct trt_fp_modify_ctx) {
aPiecek61d062b2020-11-02 11:05:09 +01003025 .parent = tro_modi_parent,
3026 .first_sibling = tro_modi_first_sibling,
3027 .next_sibling = tro_modi_next_sibling,
3028 .next_child = tro_modi_next_child,
3029 .next_augment = tro_modi_next_augment,
3030 .get_rpcs = tro_modi_get_rpcs,
3031 .get_notifications = tro_modi_get_notifications,
3032 .next_grouping = tro_modi_next_grouping,
3033 .next_yang_data = tro_modi_next_yang_data
3034 };
3035
aPiecekdc8fd572021-04-19 10:47:23 +02003036 pc->fp.read = (struct trt_fp_read) {
aPiecek61d062b2020-11-02 11:05:09 +01003037 .module_name = tro_read_module_name,
3038 .node = tro_read_node,
3039 .if_sibling_exists = tro_read_if_sibling_exists
3040 };
3041
aPiecekdc8fd572021-04-19 10:47:23 +02003042 pc->fp.print = (struct trt_fp_print) {
aPiecek61d062b2020-11-02 11:05:09 +01003043 .print_features_names = tro_print_features_names,
3044 .print_keys = tro_print_keys
3045 };
3046
aPiecekdc8fd572021-04-19 10:47:23 +02003047 pc->max_line_length = max_line_length;
aPiecek61d062b2020-11-02 11:05:09 +01003048}
3049
3050/**
aPiecekdc8fd572021-04-19 10:47:23 +02003051 * @brief Printing section 'module', 'rpcs' or 'notifications'.
aPiecek61d062b2020-11-02 11:05:09 +01003052 *
aPiecekdc8fd572021-04-19 10:47:23 +02003053 * First node must be the first child of 'module',
3054 * 'rpcs' or 'notifications'.
aPiecek61d062b2020-11-02 11:05:09 +01003055 *
aPiecekdc8fd572021-04-19 10:47:23 +02003056 * @param[in] ks is section representation.
3057 * @param[in] pc contains mainly functions for printing.
3058 * @param[in,out] tc is the tree context.
aPiecek61d062b2020-11-02 11:05:09 +01003059 */
3060static void
aPiecekdc8fd572021-04-19 10:47:23 +02003061trm_print_section_as_family_tree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003062{
aPiecekdc8fd572021-04-19 10:47:23 +02003063 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
3064 return;
3065 }
3066
3067 trp_print_keyword_stmt(ks, pc->max_line_length, 0, pc->out);
3068 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
3069 trb_print_family_tree(TRD_WRAPPER_TOP, pc, tc);
3070 } else {
3071 trb_print_family_tree(TRD_WRAPPER_BODY, pc, tc);
3072 }
3073}
3074
3075/**
3076 * @brief Printing section 'augment', 'grouping' or 'yang-data'.
3077 *
3078 * First node is augment, grouping or yang-data itself.
3079 *
3080 * @param[in] ks is section representation.
3081 * @param[in] pc contains mainly functions for printing.
3082 * @param[in,out] tc is the tree context.
3083 */
3084static void
3085trm_print_section_as_subtree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3086{
3087 ly_bool grp_has_data = 0;
3088
3089 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
3090 return;
3091 }
3092
3093 if (ks.type == TRD_KEYWORD_GROUPING) {
3094 grp_has_data = trb_tree_ctx_get_child(tc) ? 1 : 0;
3095 }
3096
3097 trp_print_keyword_stmt(ks, pc->max_line_length, grp_has_data, pc->out);
3098 trb_tree_ctx_set_child(tc);
3099 trb_print_family_tree(TRD_WRAPPER_BODY, pc, tc);
3100}
3101
3102/**
3103 * @brief Print 'module' keyword, its name and all nodes.
3104 * @param[in] pc contains mainly functions for printing.
3105 * @param[in,out] tc is the tree context.
3106 */
3107static void
3108trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3109{
3110 trm_print_section_as_family_tree(pc->fp.read.module_name(tc), pc, tc);
3111}
3112
3113/**
3114 * @brief For all augment sections: print 'augment' keyword,
3115 * its target node and all nodes.
3116 * @param[in] pc contains mainly functions for printing.
3117 * @param[in,out] tc is the tree context.
3118 */
3119static void
3120trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3121{
3122 ly_bool once;
3123
3124 if (!pc->fp.modify.next_augment) {
3125 return;
3126 }
3127
3128 once = 1;
3129 for (struct trt_keyword_stmt ks = pc->fp.modify.next_augment(tc);
3130 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
3131 ks = pc->fp.modify.next_augment(tc)) {
3132
3133 if (once) {
3134 ly_print_(pc->out, "\n");
3135 ly_print_(pc->out, "\n");
3136 once = 0;
3137 } else {
3138 ly_print_(pc->out, "\n");
3139 }
3140
3141 trm_print_section_as_subtree(ks, pc, tc);
3142 }
3143}
3144
3145/**
3146 * @brief For rpcs section: print 'rpcs' keyword and all its nodes.
3147 * @param[in] pc contains mainly functions for printing.
3148 * @param[in,out] tc is the tree context.
3149 */
3150static void
3151trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3152{
3153 struct trt_keyword_stmt rpc;
3154
3155 assert(pc->fp.modify.get_rpcs);
3156
3157 rpc = pc->fp.modify.get_rpcs(tc);
3158
3159 if (!(TRP_KEYWORD_STMT_IS_EMPTY(rpc))) {
3160 ly_print_(pc->out, "\n");
3161 ly_print_(pc->out, "\n");
3162 trm_print_section_as_family_tree(rpc, pc, tc);
3163 }
3164}
3165
3166/**
3167 * @brief For notifications section: print 'notifications' keyword
3168 * and all its nodes.
3169 * @param[in] pc contains mainly functions for printing.
3170 * @param[in,out] tc is the tree context.
3171 */
3172static void
3173trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3174{
3175 struct trt_keyword_stmt notifs;
3176
3177 assert(pc->fp.modify.get_notifications);
3178
3179 notifs = pc->fp.modify.get_notifications(tc);
3180
3181 if (!(TRP_KEYWORD_STMT_IS_EMPTY(notifs))) {
3182 ly_print_(pc->out, "\n");
3183 ly_print_(pc->out, "\n");
3184 trm_print_section_as_family_tree(notifs, pc, tc);
3185 }
3186}
3187
3188/**
3189 * @brief For all grouping sections: print 'grouping' keyword, its name
3190 * and all nodes.
3191 * @param[in] pc contains mainly functions for printing.
3192 * @param[in,out] tc is the tree context.
3193 */
3194static void
3195trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3196{
3197 ly_bool once;
3198
3199 if (!pc->fp.modify.next_grouping) {
3200 return;
3201 }
3202
3203 once = 1;
3204 for (struct trt_keyword_stmt ks = pc->fp.modify.next_grouping(tc);
3205 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
3206 ks = pc->fp.modify.next_grouping(tc)) {
3207 if (once) {
3208 ly_print_(pc->out, "\n");
3209 ly_print_(pc->out, "\n");
3210 once = 0;
3211 } else {
3212 ly_print_(pc->out, "\n");
3213 }
3214 trm_print_section_as_subtree(ks, pc, tc);
3215 }
3216}
3217
3218/**
3219 * @brief For all yang-data sections: print 'yang-data' keyword
3220 * and all its nodes.
3221 * @param[in] pc contains mainly functions for printing.
3222 * @param[in,out] tc is the tree context.
3223 */
3224static void
3225trm_print_yang_data(struct trt_printer_ctx *UNUSED(pc), struct trt_tree_ctx *UNUSED(tc))
3226{
3227 /* TODO yang-data is not implemented */
3228 return;
3229}
3230
3231/**
3232 * @brief Print sections module, augment, rpcs, notifications,
3233 * grouping, yang-data.
3234 * @param[in] pc contains mainly functions for printing.
3235 * @param[in,out] tc is the tree context.
3236 */
3237static void
3238trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3239{
3240 trm_print_module_section(pc, tc);
3241 trm_print_augmentations(pc, tc);
3242 trm_print_rpcs(pc, tc);
3243 trm_print_notifications(pc, tc);
3244 trm_print_groupings(pc, tc);
3245 trm_print_yang_data(pc, tc);
3246 ly_print_(pc->out, "\n");
aPiecek61d062b2020-11-02 11:05:09 +01003247}
3248
aPiecek874ea4d2021-04-19 12:26:36 +02003249/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01003250 * Definition of module interface
aPiecek874ea4d2021-04-19 12:26:36 +02003251 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003252
3253LY_ERR
3254tree_print_parsed_module(struct ly_out *out, const struct lys_module *module, uint32_t UNUSED(options), size_t line_length)
3255{
3256 struct trt_printer_ctx pc;
3257 struct trt_tree_ctx tc;
3258 struct ly_out *new_out;
3259 LY_ERR erc;
3260 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
3261
aPiecekdc8fd572021-04-19 10:47:23 +02003262 LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL);
3263
aPiecek61d062b2020-11-02 11:05:09 +01003264 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
3265 return erc;
3266 }
3267
3268 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecekdc8fd572021-04-19 10:47:23 +02003269 trm_lysp_tree_ctx(module, new_out, line_length, &pc, &tc);
aPiecek61d062b2020-11-02 11:05:09 +01003270
3271 trm_print_sections(&pc, &tc);
aPiecekdc8fd572021-04-19 10:47:23 +02003272 erc = clb_arg.last_error;
aPiecek61d062b2020-11-02 11:05:09 +01003273
3274 ly_out_free(new_out, NULL, 1);
3275
aPiecekdc8fd572021-04-19 10:47:23 +02003276 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01003277}
3278
3279LY_ERR
3280tree_print_submodule(struct ly_out *UNUSED(out), const struct lys_module *UNUSED(module), const struct lysp_submodule *UNUSED(submodp), uint32_t UNUSED(options), size_t UNUSED(line_length))
3281// LY_ERR tree_print_submodule(struct ly_out *out, const struct lys_module *module, const struct lysp_submodule *submodp, uint32_t options, size_t line_length)
3282{
3283 /** Not implemented right now. */
3284 return LY_SUCCESS;
3285}
3286
3287LY_ERR
3288tree_print_compiled_node(struct ly_out *UNUSED(out), const struct lysc_node *UNUSED(node), uint32_t UNUSED(options), size_t UNUSED(line_length))
3289// LY_ERR tree_print_compiled_node(struct ly_out *out, const struct lysc_node *node, uint32_t options, size_t line_length)
3290{
3291 /** Not implemented right now. */
3292 return LY_SUCCESS;
3293}