blob: 796370da5af68530e105c64eff6488b8f2880716 [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
13 */
14
15#include <assert.h>
Radek Krejci77114102021-03-10 15:21:57 +010016#include <stdint.h>
17#include <stdlib.h>
aPiecek61d062b2020-11-02 11:05:09 +010018#include <string.h>
Radek Krejci77114102021-03-10 15:21:57 +010019#include <sys/types.h>
aPiecek61d062b2020-11-02 11:05:09 +010020
21#include "compat.h"
Radek Krejci77114102021-03-10 15:21:57 +010022#include "log.h"
23#include "out.h"
aPiecek61d062b2020-11-02 11:05:09 +010024#include "out_internal.h"
25#include "printer_internal.h"
Radek Krejci77114102021-03-10 15:21:57 +010026#include "tree.h"
27#include "tree_schema.h"
aPiecek61d062b2020-11-02 11:05:09 +010028#include "xpath.h"
29
Radek Krejci77114102021-03-10 15:21:57 +010030struct trt_tree_ctx;
31
aPiecek61d062b2020-11-02 11:05:09 +010032/******************************************************************************
33 * Declarations start
34 *****************************************************************************/
35
36/*
37 * +---------+ +---------+ +---------+
38 * output | trp | | trb | | tro |
39 * <---+ Print +<---+ Browse +<-->+ Obtain |
40 * | | | | | |
41 * +---------+ +----+----+ +---------+
42 * ^
43 * |
44 * +----+----+
45 * | trm |
46 * | Manager |
47 * | |
48 * +----+----+
49 * ^
50 * | input
51 * +
52 *
53 * Glossary:
54 * trt - type
55 * trp - functions for Printing
56 * trb - functions for Browse the tree
57 * tro - functions for Obtaining information from libyang
58 * trm - Main functions, Manager
59 * trg - General functions
60 *
61 * - Manager functions (trm) are able to print individual sections of the YANG tree diagram
62 * (eg module, notifications, rpcs ...) and they call Browse functions (trb).
63 * - Browse functions contain a general algorithm (Preorder DFS) for traversing the tree.
64 * They call the Obtain functions (tro) to get information about the node
65 * or eg to get a sibling or child for the current node.
66 * This obtained information is passed on to the Print functions (trp) for printing.
67 * Gap offsets before the node type are also calculated in the Browse functions.
68 * - Print functions (trp) take care of the printing itself.
69 * They can also split one node into multiple lines if the node does not fit on one line.
70 *
71 * For future adjustments:
72 * it is assumed that the changes are likely to take place mainly for tro functions
73 * because they are the only ones dependent on libyang implementation.
74 * In special cases, changes will also need to be made to the trp functions
75 * if a special algorithm is needed to print (right now this is prepared for printing list's keys
76 * and if-features).
77 */
78
79/**
80 * @brief List of available actions.
81 */
82typedef enum {
83 TRD_PRINT = 0,
84 TRD_CHAR_COUNT
85} trt_ly_out_clb_arg_flag;
86
87/**
88 * @brief Specific argument to be passed to the ly_write_clb.
89 */
90struct ly_out_clb_arg {
91 trt_ly_out_clb_arg_flag mode; /**< flag specifying which action to take. */
92 struct ly_out *out; /**< The ly_out pointer delivered to the printer tree module via the main interface. */
93 size_t counter; /**< Counter of printed characters. */
94 LY_ERR last_error; /**< The last error that occurred. If no error has occurred, it will be LY_SUCCESS. */
95};
96
97/**
98 * @brief Initialize struct ly_out_clb_arg with default settings.
99 */
100#define TRP_INIT_LY_OUT_CLB_ARG(MODE, OUT, COUNTER, LAST_ERROR) \
101 (struct ly_out_clb_arg){.mode = MODE, .out = OUT, .counter = COUNTER, .last_error = LAST_ERROR}
102
103/******************************************************************************
104 * Print getters
105 *****************************************************************************/
106
107/**
108 * @brief Callback functions that prints special cases.
109 *
110 * It just groups together tree context with trt_fp_print.
111 */
112struct trt_cf_print {
113 const struct trt_tree_ctx *ctx; /**< Context of libyang tree. */
114 void (*pf)(const struct trt_tree_ctx *, struct ly_out *); /**< Pointing to function which printing list's keys or features. */
115};
116
117/**
118 * @brief Callback functions for printing special cases.
119 *
120 * Functions with the suffix 'trp' can print most of the text on output, just by setting the pointer to the string.
121 * But in some cases, it's not that simple, because its entire string is fragmented in memory.
122 * For example, for printing list's keys or if-features.
123 * However, this depends on how the libyang library is implemented.
124 * This implementation of the printer_tree module goes through a lysp tree, but if it goes through a lysc tree,
125 * these special cases would be different.
126 * Functions must print including spaces or delimiters between names.
127 */
128struct trt_fp_print {
129 void (*print_features_names)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list of features without {}? wrapper. */
130 void (*print_keys)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list's keys without [] wrapper. */
131};
132
133/**
134 * @brief Package which only groups getter function.
135 */
136struct trt_pck_print {
137 const struct trt_tree_ctx *tree_ctx; /**< Context of libyang tree. */
138 struct trt_fp_print fps; /**< Print function. */
139};
140
141/**
142 * @brief Initialize struct trt_pck_print by parameters.
143 */
144#define TRP_INIT_PCK_PRINT(TREE_CTX, FP_PRINT) \
145 (struct trt_pck_print){.tree_ctx = TREE_CTX, .fps = FP_PRINT}
146
147/******************************************************************************
148 * Indent
149 *****************************************************************************/
150
151/**
152 * @brief Constants which are defined in the RFC or are observable from the pyang tool.
153 */
154typedef enum {
155 TRD_INDENT_EMPTY = 0, /**< If the node is a case node, there is no space before the \<name\>. */
156 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. */
157 TRD_INDENT_LINE_BEGIN = 2, /**< Indent below the keyword (module, augment ...). */
158 TRD_INDENT_BTW_SIBLINGS = 2, /**< Indent between | and | characters. */
159 TRD_INDENT_BEFORE_KEYS = 1, /**< "..."___\<keys\>. */
160 TRD_INDENT_BEFORE_TYPE = 4, /**< "..."___\<type\>, but if mark is set then indent == 3. */
161 TRD_INDENT_BEFORE_IFFEATURES = 1 /**< "..."___\<iffeatures\>. */
162} trt_cnf_indent;
163
164/**
165 * @brief Type of indent in node.
166 */
167typedef enum {
168 TRD_INDENT_IN_NODE_NORMAL = 0, /**< Node fits on one line. */
169 TRD_INDENT_IN_NODE_DIVIDED, /**< The node must be split into multiple rows. */
170 TRD_INDENT_IN_NODE_FAILED /**< Cannot be crammed into one line. The condition for the maximum line length is violated. */
171} trt_indent_in_node_type;
172
173/** Constant to indicate the need to break a line. */
174#define TRD_LINEBREAK -1
175
176/**
177 * @brief Records the alignment between the individual elements of the node.
178 *
179 * See trp_indent_in_node_are_eq, trp_indent_in_node_place_break.
180 */
181struct trt_indent_in_node {
182 trt_indent_in_node_type type; /**< Type of indent in node. */
183 int16_t btw_name_opts; /**< Indent between node name and opts. */
184 int16_t btw_opts_type; /**< Indent between opts and type. */
185 int16_t btw_type_iffeatures; /**< Indent between type and features. Ignored if \<type\> missing. */
186};
187
188/**
189 * @brief Type of wrappers to be printed.
190 */
191typedef enum {
192 TRD_WRAPPER_TOP = 0, /**< Related to the module. */
193 TRD_WRAPPER_BODY /**< Related to e.g. Augmentations or Groupings */
194} trd_wrapper_type;
195
196/**
197 * @brief For resolving sibling symbol ('|') placement.
198 *
199 * Bit indicates where the sibling symbol must be printed.
200 * This place is in multiples of TRD_INDENT_BTW_SIBLINGS.
201 *
202 * See: TRP_INIT_WRAPPER_TOP, TRP_INIT_WRAPPER_BODY, trp_wrapper_set_mark,
203 * trp_wrapper_set_shift, trp_wrapper_if_last_sibling, trp_wrapper_eq,
204 * trp_print_wrapper
205 */
206struct trt_wrapper {
207 trd_wrapper_type type; /**< Location of the wrapper. */
208 uint64_t bit_marks1; /**< The set bits indicate where the '|' character is to be printed.
209 It follows that the maximum immersion of the printable node is 64. */
210 uint32_t actual_pos; /**< Actual position in bit_marks. */
211};
212
213/**
214 * @brief Get wrapper related to the module section.
215 *
216 * @code
217 * module: <module-name>
218 * +--<node>
219 * |
220 * @endcode
221 */
222#define TRP_INIT_WRAPPER_TOP \
223 (struct trt_wrapper) {.type = TRD_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0}
224
225/**
226 * @brief Get wrapper related to subsection e.g. Augmenations or Groupings.
227 *
228 * @code
229 * module: <module-name>
230 * +--<node>
231 *
232 * augment <target-node>:
233 * +--<node>
234 * @endcode
235 */
236#define TRP_INIT_WRAPPER_BODY \
237 (struct trt_wrapper) {.type = TRD_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0}
238
239/**
240 * @brief Package which only groups wrapper and indent in node.
241 */
242struct trt_pck_indent {
243 struct trt_wrapper wrapper; /**< Coded " | | " sequence. */
244 struct trt_indent_in_node in_node; /**< Indent in node. */
245};
246
247/**
248 * @brief Initialize struct trt_pck_indent by parameters.
249 */
250#define TRP_INIT_PCK_INDENT(WRAPPER, INDENT_IN_NODE) \
251 (struct trt_pck_indent){.wrapper = WRAPPER, .in_node = INDENT_IN_NODE}
252
253/******************************************************************************
254 * status
255 *****************************************************************************/
256
257/**
258 * @brief Status of the node.
259 *
260 * See: trp_print_status
261 */
262typedef enum {
263 TRD_STATUS_TYPE_EMPTY = 0,
264 TRD_STATUS_TYPE_CURRENT,
265 TRD_STATUS_TYPE_DEPRECATED,
266 TRD_STATUS_TYPE_OBSOLETE
267} trt_status_type;
268
269/******************************************************************************
270 * flags
271 *****************************************************************************/
272
273/**
274 * @brief Flag of the node.
275 *
276 * See: trp_print_flags, trp_get_flags_strlen
277 */
278typedef enum {
279 TRD_FLAGS_TYPE_EMPTY = 0,
280 TRD_FLAGS_TYPE_RW, /**< rw */
281 TRD_FLAGS_TYPE_RO, /**< ro */
282 TRD_FLAGS_TYPE_RPC_INPUT_PARAMS, /**< -w */
283 TRD_FLAGS_TYPE_USES_OF_GROUPING, /**< -u */
284 TRD_FLAGS_TYPE_RPC, /**< -x */
285 TRD_FLAGS_TYPE_NOTIF, /**< -n */
286 TRD_FLAGS_TYPE_MOUNT_POINT /**< mp */
287} trt_flags_type;
288
289/******************************************************************************
290 * node_name and opts
291 *****************************************************************************/
292
293#define TRD_NODE_NAME_PREFIX_CHOICE "("
294#define TRD_NODE_NAME_PREFIX_CASE ":("
295#define TRD_NODE_NAME_TRIPLE_DOT "..."
296
297/**
298 * @brief Type of the node.
299 *
300 * Used mainly to complete the correct \<opts\> next to or around the \<name\>.
301 */
302typedef enum {
303 TRD_NODE_ELSE = 0, /**< For some node which does not require special treatment. \<name\> */
304 TRD_NODE_CASE, /**< For case node. :(\<name\>) */
305 TRD_NODE_CHOICE, /**< For choice node. (\<name\>) */
306 TRD_NODE_OPTIONAL_CHOICE, /**< For choice node with optional mark. (\<name\>)? */
307 TRD_NODE_OPTIONAL, /**< For an optional leaf, anydata, or anyxml. \<name\>? */
308 TRD_NODE_CONTAINER, /**< For a presence container. \<name\>! */
309 TRD_NODE_LISTLEAFLIST, /**< For a leaf-list or list (without keys). \<name\>* */
310 TRD_NODE_KEYS, /**< For a list's keys. \<name\>* [\<keys\>] */
311 TRD_NODE_TOP_LEVEL1, /**< For a top-level data node in a mounted module. \<name\>/ */
312 TRD_NODE_TOP_LEVEL2, /**< For a top-level data node of a module identified in a mount point parent reference. \<name\>@ */
313 TRD_NODE_TRIPLE_DOT /**< For collapsed sibling nodes and their children. Special case which doesn't belong here very well. */
314} trt_node_type;
315
316/**
317 * @brief Type of node and his name.
318 *
319 * See: TRP_EMPTY_NODE_NAME, TRP_NODE_NAME_IS_EMPTY,
320 * trp_print_node_name, trp_mark_is_used, trp_print_opts_keys
321 */
322struct trt_node_name {
323 trt_node_type type; /**< Type of the node relevant for printing. */
324 const char *module_prefix; /**< Prefix defined in the module where the node is defined. */
325 const char *str; /**< Name of the node. */
326};
327
328/**
329 * @brief Create struct trt_node_name as empty.
330 */
331#define TRP_EMPTY_NODE_NAME \
332 (struct trt_node_name){.type = TRD_NODE_ELSE, .module_prefix = NULL, .str = NULL}
333
334/**
335 * @brief Check if struct trt_node_name is empty.
336 */
337#define TRP_NODE_NAME_IS_EMPTY(NODE_NAME) \
338 !NODE_NAME.str
339
340/**< Every opts mark has a length of one. */
341#define TRD_OPTS_MARK_LENGTH 1
342
343/******************************************************************************
344 * type
345 *****************************************************************************/
346
347/**
348 * @brief Type of the \<type\>
349 */
350typedef enum {
351 TRD_TYPE_NAME = 0, /**< Type is just a name that does not require special treatment. */
352 TRD_TYPE_TARGET, /**< Should have a form "-> TARGET", where TARGET is the leafref path. */
353 TRD_TYPE_LEAFREF, /**< This type is set automatically by the 'trp' algorithm. So set type as TRD_TYPE_TARGET. */
354 TRD_TYPE_EMPTY /**< Type is not used at all. */
355} trt_type_type;
356
357/**
358 * @brief \<type\> in the \<node\>.
359 *
360 * See: TRP_EMPTY_TRT_TYPE, TRP_TRT_TYPE_IS_EMPTY, trp_print_type
361 */
362struct trt_type {
363 trt_type_type type; /**< Type of the \<type\>. */
364 const char *str; /**< Path or name of the type. */
365};
366
367/**
368 * @brief Create empty struct trt_type.
369 */
370#define TRP_EMPTY_TRT_TYPE \
371 (struct trt_type) {.type = TRD_TYPE_EMPTY, .str = NULL}
372
373/**
374 * @brief Check if struct trt_type is empty.
375 */
376#define TRP_TRT_TYPE_IS_EMPTY(TYPE_OF_TYPE) \
377 TYPE_OF_TYPE.type == TRD_TYPE_EMPTY
378
379/**
380 * @brief Initialize struct trt_type by parameters.
381 */
382#define TRP_INIT_TRT_TYPE(TYPE_OF_TYPE, STRING) \
383 (struct trt_type) {.type = TYPE_OF_TYPE, .str = STRING}
384
385/******************************************************************************
386 * node
387 *****************************************************************************/
388
389/**
390 * @brief \<node\> data for printing.
391 *
392 * It contains RFC's: \<status\>--\<flags\> \<name\>\<opts\> \<type\> \<if-features\>.
393 * Item \<opts\> is moved to part struct trt_node_name.
394 * For printing [\<keys\>] and if-features is required special functions which prints them.
395 *
396 * See: TRP_EMPTY_NODE, trp_node_is_empty, trp_node_body_is_empty, trp_print_node_up_to_name,
397 * trp_print_divided_node_up_to_name, trp_print_node
398 */
399struct trt_node {
400 trt_status_type status; /**< \<status\>. */
401 trt_flags_type flags; /**< \<flags\>. */
402 struct trt_node_name name; /**< \<node\> with \<opts\> mark or [\<keys\>]. */
403 struct trt_type type; /**< \<type\> contains the name of the type or type for leafref. */
404 ly_bool iffeatures; /**< \<if-features\>. Value 1 means that iffeatures are present and will be printed by print_features_names callback. */
405 ly_bool last_one; /**< Information about whether the node is the last. */
406};
407
408/**
409 * @brief Create struct trt_node as empty.
410 */
411#define TRP_EMPTY_NODE \
412 (struct trt_node) {.status = TRD_STATUS_TYPE_EMPTY, .flags = TRD_FLAGS_TYPE_EMPTY, \
413 .name = TRP_EMPTY_NODE_NAME, .type = TRP_EMPTY_TRT_TYPE, .iffeatures = 0, .last_one = 1}
414
415/**
416 * @brief Package which only groups indent and node.
417 */
418struct trt_pair_indent_node {
419 struct trt_indent_in_node indent;
420 struct trt_node node;
421};
422
423/**
424 * @brief Initialize struct trt_pair_indent_node by parameters.
425 */
426#define TRP_INIT_PAIR_INDENT_NODE(INDENT_IN_NODE, NODE) \
427 (struct trt_pair_indent_node){.indent = INDENT_IN_NODE, .node = NODE}
428
429/******************************************************************************
430 * statement
431 *****************************************************************************/
432
433#define TRD_TOP_KEYWORD_MODULE "module"
434#define TRD_TOP_KEYWORD_SUBMODULE "submodule"
435
436#define TRD_BODY_KEYWORD_AUGMENT "augment"
437#define TRD_BODY_KEYWORD_RPC "rpcs"
438#define TRD_BODY_KEYWORD_NOTIF "notifications"
439#define TRD_BODY_KEYWORD_GROUPING "grouping"
440#define TRD_BODY_KEYWORD_YANG_DATA "yang-data"
441
442/**
443 * @brief Type of the trt_keyword.
444 */
445typedef enum {
446 TRD_KEYWORD_EMPTY = 0,
447 TRD_KEYWORD_MODULE,
448 TRD_KEYWORD_SUBMODULE,
449 TRD_KEYWORD_AUGMENT,
450 TRD_KEYWORD_RPC,
451 TRD_KEYWORD_NOTIF,
452 TRD_KEYWORD_GROUPING,
453 TRD_KEYWORD_YANG_DATA
454} trt_keyword_type;
455
456/**
457 * @brief Main sign of the tree nodes.
458 *
459 * See: TRP_EMPTY_KEYWORD_STMT, TRP_KEYWORD_STMT_IS_EMPTY
460 * trt_print_keyword_stmt_begin, trt_print_keyword_stmt_str,
461 * trt_print_keyword_stmt_end, trp_print_keyword_stmt
462 * trp_keyword_type_strlen
463 *
464 */
465struct trt_keyword_stmt {
466 trt_keyword_type type; /**< String containing some of the top or body keyword. */
467 const char *str; /**< Name or path, it determines the type. */
468};
469
470/**
471 * @brief Create struct trt_keyword_stmt as empty.
472 */
473#define TRP_EMPTY_KEYWORD_STMT \
474 (struct trt_keyword_stmt) {.type = TRD_KEYWORD_EMPTY, .str = NULL}
475
476/**
477 * @brief Check if struct trt_keyword_stmt is empty.
478 */
479#define TRP_KEYWORD_STMT_IS_EMPTY(KEYWORD_TYPE) \
480 KEYWORD_TYPE.type == TRD_KEYWORD_EMPTY
481
482/**
483 * @brief Initialize struct trt_keyword_stmt by parameters.
484 */
485#define TRP_INIT_KEYWORD_STMT(KEYWORD_TYPE, STRING) \
486 (struct trt_keyword_stmt) {.type = KEYWORD_TYPE, .str = STRING}
487
488/******************************************************************************
489 * Modify getters
490 *****************************************************************************/
491
492struct trt_parent_cache;
493
494/**
495 * @brief Functions that change the state of the tree_ctx structure.
496 *
497 * The 'tro' functions are set here, which provide data for the 'trp' printing functions
498 * and are also called from the 'trb' browsing functions when walking through a tree.
499 * These callback functions need to be checked or reformulated
500 * if changes to the libyang library affect the printing tree.
501 * For all, if the value cannot be returned,
502 * its empty version obtained by relevant TRP_EMPTY macro is returned.
503 */
504struct trt_fp_modify_ctx {
505 ly_bool (*parent)(struct trt_tree_ctx *); /**< Jump to parent node. Return true if parent exists. */
506 void (*first_sibling)(struct trt_tree_ctx *); /**< Jump on the first of the siblings. */
507 struct trt_node (*next_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to next sibling of the current node. */
508 struct trt_node (*next_child)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to the child of the current node. */
509 struct trt_keyword_stmt (*next_augment)(struct trt_tree_ctx *); /**< Jump to the augment section. */
510 struct trt_keyword_stmt (*get_rpcs)(struct trt_tree_ctx *); /**< Jump to the rpcs section. */
511 struct trt_keyword_stmt (*get_notifications)(struct trt_tree_ctx *); /**< Jump to the notifications section. */
512 struct trt_keyword_stmt (*next_grouping)(struct trt_tree_ctx *); /**< Jump to the grouping section. */
513 struct trt_keyword_stmt (*next_yang_data)(struct trt_tree_ctx *); /**< Jump to the yang-data section. */
514};
515
516/******************************************************************************
517 * Read getters
518 *****************************************************************************/
519
520/**
521 * @brief Functions that do not change the state of the tree_structure.
522 *
523 * For details see trt_fp_modify_ctx.
524 */
525struct trt_fp_read {
526 struct trt_keyword_stmt (*module_name)(const struct trt_tree_ctx *); /**< Get name of the module. */
527 struct trt_node (*node)(struct trt_parent_cache, const struct trt_tree_ctx *); /**< Get current node. */
528 ly_bool (*if_sibling_exists)(const struct trt_tree_ctx *); /**< Check if node's sibling exists. */
529};
530
531/******************************************************************************
532 * All getters
533 *****************************************************************************/
534
535/**
536 * @brief A set of all necessary functions that must be provided for the printer.
537 */
538struct trt_fp_all {
539 struct trt_fp_modify_ctx modify; /**< Function pointers which modify state of trt_tree_ctx. */
540 struct trt_fp_read read; /**< Function pointers which only reads state of trt_tree_ctx. */
541 struct trt_fp_print print; /**< Functions pointers for printing special items in node. */
542};
543
544/******************************************************************************
545 * Printer context
546 *****************************************************************************/
547
548/**
549 * @brief Main structure for trp component (printer part).
550 */
551struct trt_printer_ctx {
552 struct ly_out *out; /**< Handler to printing. */
553 struct trt_fp_all fp; /**< 'tro' functions callbacks. */
554 size_t max_line_length; /**< The maximum number of characters that can be
555 printed on one line, including the last. */
556};
557
558/******************************************************************************
559 * Tro functions
560 *****************************************************************************/
561
562/**
563 * @brief The name of the section to which the node belongs.
564 */
565typedef enum {
566 TRD_SECT_MODULE = 0, /**< The node belongs to the "module: <module_name>:" label. */
567 TRD_SECT_AUGMENT, /**< The node belongs to some "augment <target-node>:" label. */
568 TRD_SECT_RPCS, /**< The node belongs to the "rpcs:" label. */
569 TRD_SECT_NOTIF, /**< The node belongs to the "notifications:" label. */
570 TRD_SECT_GROUPING, /**< The node belongs to some "grouping <grouping-name>:" label. */
571 TRD_SECT_YANG_DATA /**< The node belongs to some "yang-data <yang-data-name>:" label. */
572} trt_actual_section;
573
574/**
575 * @brief Types of nodes that have some effect on their children.
576 */
577typedef enum {
578 TRD_ANCESTOR_ELSE = 0,
579 TRD_ANCESTOR_RPC_INPUT,
580 TRD_ANCESTOR_RPC_OUTPUT,
581 TRD_ANCESTOR_NOTIF
582} trt_ancestor_type;
583
584/**
585 * @brief Saved information when browsing the tree downwards.
586 *
587 * This structure helps prevent frequent retrieval of information from the tree.
588 * Browsing functions (trb) are designed to preserve this structures during their recursive calls.
589 * Browsing functions (trb) do not interfere in any way with this data.
590 * This structure is used by Obtaining functions (tro) which, thanks to this structure, can return a node with the correct data.
591 * The word parent is in the name, because this data refers to the last parent and at the same time the states of its ancestors data.
592 * Only the function jumping on the child (next_child(...)) creates this structure,
593 * because the pointer to the current node moves down the tree.
594 * It's like passing the genetic code to children.
595 * Some data must be inherited and there are two approaches to this problem.
596 * Either it will always be determined which inheritance states belong to the current node
597 * (which can lead to regular travel to the root node) or the inheritance states will be stored during the recursive calls.
598 * So the problem was solved by the second option.
599 * Why does the structure contain this data? Because it walks through the lysp tree.
600 * In the future, this data may change if another type of tree (such as the lysc tree) is traversed.
601 *
602 * See: TRO_EMPTY_PARENT_CACHE, tro_parent_cache_for_child
603 */
604struct trt_parent_cache {
605 trt_ancestor_type ancestor; /**< Some types of nodes have a special effect on their children. */
606 uint16_t lys_status; /**< Inherited status CURR, DEPRC, OBSLT. */
607 uint16_t lys_config; /**< Inherited config W or R. */
608 const struct lysp_node_list *last_list; /**< The last LYS_LIST passed. */
609};
610
611/**
612 * @brief Return trt_parent_cache filled with default values.
613 */
614#define TRP_EMPTY_PARENT_CACHE \
615 (struct trt_parent_cache) {.ancestor = TRD_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \
616 .lys_config = LYS_CONFIG_W, .last_list = NULL}
617
618/**
619 * @brief Main structure for browsing the libyang tree
620 */
621struct trt_tree_ctx {
622 trt_actual_section section; /**< To which section pn points. */
623 const struct lys_module *module; /**< Schema tree structures. */
624 const struct lysp_node *pn; /**< Actual pointer to parsed node. */
625 const struct lysp_node *tpn; /**< Pointer to actual top-node. */
626};
627
628/**
629 * @brief Used for updating trt_tree_ctx
630 */
631struct trt_tree_ctx_node_patch {
632 const struct lysp_node *pn; /**< Actual pointer to parsed node. */
633 const struct lysp_node *tpn; /**< Pointer to actual top-node. */
634};
635
636/**
637 * @brief Initialize struct trt_keyword_stmt by parameters.
638 */
639#define TRP_INIT_TREE_CTX_NODE_PATCH(PN, TPN) \
640 (struct trt_tree_ctx_node_patch){.pn = PN, .tpn = TPN}
641
642/** Getter function for tro_lysp_node_charptr function. */
643typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
644
645/******************************************************************************
646 * Definition of the general Trg functions
647 *****************************************************************************/
648
649/**
650 * @brief Print a substring but limited to the maximum length.
651 * @param[in] str is pointer to source.
652 * @param[in] len is number of characters to be printed.
653 * @param[in,out] out is output handler.
654 * @return str parameter shifted by len.
655 */
656static const char *
657trg_print_substr(const char *str, size_t len, struct ly_out *out)
658{
659 for (size_t i = 0; i < len; i++) {
660 ly_print_(out, "%c", str[0]);
661 str++;
662 }
663 return str;
664}
665
666/**
667 * @brief Pointer is not NULL and does not point to an empty string.
668 * @param[in] str is pointer to string to be checked.
669 * @return 1 if str pointing to non empty string otherwise 0.
670 */
671static ly_bool
672trg_charptr_has_data(const char *str)
673{
674 return (str) && (str[0] != '\0');
675}
676
677/**
678 * @brief Check if 'word' in 'src' is present where words are delimited by 'delim'.
679 * @param[in] src is source where words are separated by delim.
680 * @param[in] word to be searched.
681 * @param[in] delim is delimiter between words in src.
682 * @return 1 if src contains word otherwise 0.
683 */
684static ly_bool
685trg_word_is_present(const char *src, const char *word, char delim)
686{
687 const char *hit;
688
689 if ((!src) || (src[0] == '\0') || (!word)) {
690 return 0;
691 }
692
693 hit = strstr(src, word);
694
695 if (hit) {
696 /* word was founded at the begin of src
697 * OR it match somewhere after delim
698 */
699 if ((hit == src) || (hit[-1] == delim)) {
700 /* end of word was founded at the end of src
701 * OR end of word was match somewhere before delim
702 */
703 char delim_or_end = (hit + strlen(word))[0];
704 if ((delim_or_end == '\0') || (delim_or_end == delim)) {
705 return 1;
706 }
707 }
708 /* after -> hit is just substr and it's not the whole word */
709 /* jump to the next word */
710 for ( ; (src[0] != '\0') && (src[0] != delim); src++) {}
711 /* skip delim */
712 src = src[0] == '\0' ? src : src + 1;
713 /* continue with searching */
714 return trg_word_is_present(src, word, delim);
715 } else {
716 return 0;
717 }
718}
719
720/******************************************************************************
721 * Definition of printer functions
722 *****************************************************************************/
723
724/**
725 * @brief Write callback for ly_out_new_clb function.
726 *
727 * @param[in] user_data is type of struct ly_out_clb_arg*.
728 * @param[in] buf contains input characters
729 * @param[in] count is number of characters in buf.
730 * @return Number of printed bytes.
731 * @return Negative value in case of error.
732 */
733static ssize_t
734trp_ly_out_clb_func(void *user_data, const void *buf, size_t count)
735{
736 LY_ERR erc = LY_SUCCESS;
737 struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data;
738
739 switch (data->mode) {
740 case TRD_PRINT:
741 erc = ly_write_(data->out, buf, count);
742 break;
743 case TRD_CHAR_COUNT:
744 data->counter = data->counter + count;
745 break;
746 default:
747 break;
748 }
749
750 if (erc != LY_SUCCESS) {
751 data->last_error = erc;
752 return -1;
753 } else {
754 return count;
755 }
756}
757
758/**
759 * @brief Check that indent in node can be considered as equivalent.
760 * @param[in] first is the first indent in node.
761 * @param[in] second is the second indent in node.
762 * @return 1 if indents are equivalent otherwise 0.
763 */
764static ly_bool
765trp_indent_in_node_are_eq(struct trt_indent_in_node first, struct trt_indent_in_node second)
766{
767 const ly_bool a = first.type == second.type;
768 const ly_bool b = first.btw_name_opts == second.btw_name_opts;
769 const ly_bool c = first.btw_opts_type == second.btw_opts_type;
770 const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures;
771
772 return a && b && c && d;
773}
774
775/**
776 * @brief Setting ' ' symbol because node is last sibling.
777 * @param[in] wr is wrapper over which the shift operation is to be performed.
778 * @return New shifted wrapper.
779 */
780static struct trt_wrapper
781trp_wrapper_set_shift(struct trt_wrapper wr)
782{
783 assert(wr.actual_pos < 64);
784 /* +--<node>
785 * +--<node>
786 */
787 wr.actual_pos++;
788 return wr;
789}
790
791/**
792 * @brief Setting '|' symbol because node is divided or it is not last sibling.
793 * @param[in] wr is source of wrapper.
794 * @return New wrapper which is marked at actual position and shifted.
795 */
796static struct trt_wrapper
797trp_wrapper_set_mark(struct trt_wrapper wr)
798{
799 assert(wr.actual_pos < 64);
800 wr.bit_marks1 |= 1U << wr.actual_pos;
801 return trp_wrapper_set_shift(wr);
802}
803
804/**
805 * @brief Setting ' ' symbol if node is last sibling otherwise set '|'.
806 * @param[in] wr is actual wrapper.
807 * @param[in] last_one is flag. Value 1 saying if the node is the last and has no more siblings.
808 * @return New wrapper for the actual node.
809 */
810static struct trt_wrapper
811trp_wrapper_if_last_sibling(struct trt_wrapper wr, ly_bool last_one)
812{
813 return last_one ? trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
814}
815
816/**
817 * @brief Test if the wrappers are equivalent.
818 * @param[in] first is the first wrapper.
819 * @param[in] second is the second wrapper.
820 * @return 1 if the wrappers are equivalent otherwise 0.
821 */
822static ly_bool
823trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second)
824{
825 const ly_bool a = first.type == second.type;
826 const ly_bool b = first.bit_marks1 == second.bit_marks1;
827 const ly_bool c = first.actual_pos == second.actual_pos;
828
829 return a && b && c;
830}
831
832/**
833 * @brief Print " | " sequence on line.
834 * @param[in] wr is wrapper to be printed.
835 * @param[in,out] out is output handler.
836 */
837static void
838trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out)
839{
840 uint32_t lb;
841
842 if (wr.type == TRD_WRAPPER_TOP) {
843 lb = TRD_INDENT_LINE_BEGIN;
844 } else if (wr.type == TRD_WRAPPER_BODY) {
845 lb = TRD_INDENT_LINE_BEGIN * 2;
846 } else {
847 lb = TRD_INDENT_LINE_BEGIN;
848 }
849
850 ly_print_(out, "%*c", lb, ' ');
851
852 if (trp_wrapper_eq(wr, TRP_INIT_WRAPPER_TOP)) {
853 return;
854 }
855
856 for (uint32_t i = 0; i < wr.actual_pos; i++) {
857 /** Test if the bit on the index is set. */
858 if ((wr.bit_marks1 >> i) & 1U) {
859 ly_print_(out, "|");
860 } else {
861 ly_print_(out, " ");
862 }
863
864 if (i != wr.actual_pos) {
865 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
866 }
867 }
868}
869
870/**
871 * @brief Check if struct trt_node is empty.
872 * @param[in] node is item to test.
873 * @return 1 if node is considered empty otherwise 0.
874 */
875static ly_bool
876trp_node_is_empty(struct trt_node node)
877{
878 const ly_bool a = !node.iffeatures;
879 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
880 const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node.name);
881 const ly_bool d = node.flags == TRD_FLAGS_TYPE_EMPTY;
882 const ly_bool e = node.status == TRD_STATUS_TYPE_EMPTY;
883
884 return a && b && c && d && e;
885}
886
887/**
888 * @brief Check if [\<keys\>], \<type\> and \<iffeatures\> are empty/not_set.
889 * @param[in] node is item to test.
890 * @return 1 if node has no \<keys\> \<type\> or \<iffeatures\> otherwise 0.
891 */
892static ly_bool
893trp_node_body_is_empty(struct trt_node node)
894{
895 const ly_bool a = !node.iffeatures;
896 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
897 const ly_bool c = node.name.type != TRD_NODE_KEYS;
898
899 return a && b && c;
900}
901
902/**
903 * @brief Print \<status\> of the node.
904 * @param[in] status_type is type of status.
905 * @param[in,out] out is output handler.
906 */
907static void
908trp_print_status(trt_status_type status_type, struct ly_out *out)
909{
910 switch (status_type) {
911 case TRD_STATUS_TYPE_CURRENT:
912 ly_print_(out, "%c", '+');
913 break;
914 case TRD_STATUS_TYPE_DEPRECATED:
915 ly_print_(out, "%c", 'x');
916 break;
917 case TRD_STATUS_TYPE_OBSOLETE:
918 ly_print_(out, "%c", 'o');
919 break;
920 default:
921 break;
922 }
923}
924
925/**
926 * @brief Print \<flags\>.
927 * @param[in] flags_type is type of \<flags\>.
928 * @param[in,out] out is output handler.
929 */
930static void
931trp_print_flags(trt_flags_type flags_type, struct ly_out *out)
932{
933 switch (flags_type) {
934 case TRD_FLAGS_TYPE_RW:
935 ly_print_(out, "%s", "rw");
936 break;
937 case TRD_FLAGS_TYPE_RO:
938 ly_print_(out, "%s", "ro");
939 break;
940 case TRD_FLAGS_TYPE_RPC_INPUT_PARAMS:
941 ly_print_(out, "%s", "-w");
942 break;
943 case TRD_FLAGS_TYPE_USES_OF_GROUPING:
944 ly_print_(out, "%s", "-u");
945 break;
946 case TRD_FLAGS_TYPE_RPC:
947 ly_print_(out, "%s", "-x");
948 break;
949 case TRD_FLAGS_TYPE_NOTIF:
950 ly_print_(out, "%s", "-n");
951 break;
952 case TRD_FLAGS_TYPE_MOUNT_POINT:
953 ly_print_(out, "%s", "mp");
954 break;
955 default:
956 break;
957 }
958}
959
960/**
961 * @brief Get size of the \<flags\>.
962 * @param[in] flags_type is type of \<flags\>.
963 * @return 0 if flags_type is not set otherwise 2.
964 */
965static size_t
966trp_get_flags_strlen(trt_flags_type flags_type)
967{
968 return flags_type == TRD_FLAGS_TYPE_EMPTY ? 0 : 2;
969}
970
971/**
972 * @brief Print entire struct trt_node_name structure.
973 * @param[in] node_name is item to print.
974 * @param[in,out] out is output handler.
975 */
976static void
977trp_print_node_name(struct trt_node_name node_name, struct ly_out *out)
978{
979 const char *mod_prefix;
980 const char *colon;
981 const char trd_node_name_suffix_choice[] = ")";
982 const char trd_node_name_suffix_case[] = ")";
983 const char trd_opts_optional[] = "?"; /**< For an optional leaf, choice, anydata, or anyxml. */
984 const char trd_opts_container[] = "!"; /**< For a presence container. */
985 const char trd_opts_list[] = "*"; /**< For a leaf-list or list. */
986 const char trd_opts_slash[] = "/"; /**< For a top-level data node in a mounted module. */
987 const char trd_opts_at_sign[] = "@"; /**< For a top-level data node of a module identified in a mount point parent reference. */
988
989 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
990 return;
991 }
992
993 if (node_name.module_prefix) {
994 mod_prefix = node_name.module_prefix;
995 colon = ":";
996 } else {
997 mod_prefix = "";
998 colon = "";
999 }
1000
1001 switch (node_name.type) {
1002 case TRD_NODE_ELSE:
1003 ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
1004 break;
1005 case TRD_NODE_CASE:
1006 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, trd_node_name_suffix_case);
1007 break;
1008 case TRD_NODE_CHOICE:
1009 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice);
1010 break;
1011 case TRD_NODE_OPTIONAL_CHOICE:
1012 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);
1013 break;
1014 case TRD_NODE_OPTIONAL:
1015 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_optional);
1016 break;
1017 case TRD_NODE_CONTAINER:
1018 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_container);
1019 break;
1020 case TRD_NODE_LISTLEAFLIST:
1021 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1022 break;
1023 case TRD_NODE_KEYS:
1024 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1025 break;
1026 case TRD_NODE_TOP_LEVEL1:
1027 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_slash);
1028 break;
1029 case TRD_NODE_TOP_LEVEL2:
1030 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_at_sign);
1031 break;
1032 case TRD_NODE_TRIPLE_DOT:
1033 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
1034 break;
1035 default:
1036 break;
1037 }
1038}
1039
1040/**
1041 * @brief Check if mark (?, !, *, /, @) is implicitly contained in struct trt_node_name.
1042 * @param[in] node_name is structure containing the 'mark'.
1043 * @return 1 if contain otherwise 0.
1044 */
1045static ly_bool
1046trp_mark_is_used(struct trt_node_name node_name)
1047{
1048 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1049 return 0;
1050 }
1051
1052 switch (node_name.type) {
1053 case TRD_NODE_ELSE:
1054 case TRD_NODE_CASE:
1055 case TRD_NODE_KEYS:
1056 return 0;
1057 default:
1058 return 1;
1059 }
1060}
1061
1062/**
1063 * @brief Print opts keys.
1064 * @param[in] node_name contains type of the node with his name.
1065 * @param[in] btw_name_opts is number of spaces between name and [keys].
1066 * @param[in] cf is basically a pointer to the function that prints the keys.
1067 * @param[in,out] out is output handler.
1068 */
1069static void
1070trp_print_opts_keys(struct trt_node_name node_name, int16_t btw_name_opts, struct trt_cf_print cf, struct ly_out *out)
1071{
1072 if (node_name.type != TRD_NODE_KEYS) {
1073 return;
1074 }
1075
1076 /* <name><mark>___<keys>*/
1077 if (btw_name_opts > 0) {
1078 ly_print_(out, "%*c", btw_name_opts, ' ');
1079 }
1080 ly_print_(out, "[");
1081 cf.pf(cf.ctx, out);
1082 ly_print_(out, "]");
1083}
1084
1085/**
1086 * @brief Print entire struct trt_type structure.
1087 * @param[in] type is item to print.
1088 * @param[in,out] out is output handler.
1089 */
1090static void
1091trp_print_type(struct trt_type type, struct ly_out *out)
1092{
1093 if (TRP_TRT_TYPE_IS_EMPTY(type)) {
1094 return;
1095 }
1096
1097 switch (type.type) {
1098 case TRD_TYPE_NAME:
1099 ly_print_(out, "%s", type.str);
1100 break;
1101 case TRD_TYPE_TARGET:
1102 ly_print_(out, "-> %s", type.str);
1103 break;
1104 case TRD_TYPE_LEAFREF:
1105 ly_print_(out, "leafref");
1106 default:
1107 break;
1108 }
1109}
1110
1111/**
1112 * @brief Print all iffeatures of node
1113 *
1114 * @param[in] iffeature_flag contains if if-features is present.
1115 * @param[in] cf is basically a pointer to the function that prints the list of features.
1116 * @param[in,out] out is output handler.
1117 */
1118static void
1119trp_print_iffeatures(ly_bool iffeature_flag, struct trt_cf_print cf, struct ly_out *out)
1120{
1121 if (iffeature_flag) {
1122 ly_print_(out, "{");
1123 cf.pf(cf.ctx, out);
1124 ly_print_(out, "}?");
1125 }
1126}
1127
1128/**
1129 * @brief Print just \<status\>--\<flags\> \<name\> with opts mark.
1130 * @param[in] node contains items to print.
1131 * @param[in] out is output handler.
1132 */
1133static void
1134trp_print_node_up_to_name(struct trt_node node, struct ly_out *out)
1135{
1136 if (node.name.type == TRD_NODE_TRIPLE_DOT) {
1137 trp_print_node_name(node.name, out);
1138 return;
1139 }
1140 /* <status>--<flags> */
1141 trp_print_status(node.status, out);
1142 ly_print_(out, "--");
1143 /* If the node is a case node, there is no space before the <name> */
1144 /* also case node has no flags. */
1145 if (node.name.type != TRD_NODE_CASE) {
1146 trp_print_flags(node.flags, out);
1147 ly_print_(out, " ");
1148 }
1149 /* <name> */
1150 trp_print_node_name(node.name, out);
1151}
1152
1153/**
1154 * @brief Print alignment (spaces) instead of \<status\>--\<flags\> \<name\> for divided node.
1155 * @param[in] node contains items to print.
1156 * @param[in] out is output handler.
1157 */
1158static void
1159trp_print_divided_node_up_to_name(struct trt_node node, struct ly_out *out)
1160{
1161 uint32_t space = trp_get_flags_strlen(node.flags);
1162
1163 if (node.name.type == TRD_NODE_CASE) {
1164 /* :(<name> */
1165 space += strlen(TRD_NODE_NAME_PREFIX_CASE);
1166 } else if (node.name.type == TRD_NODE_CHOICE) {
1167 /* (<name> */
1168 space += strlen(TRD_NODE_NAME_PREFIX_CHOICE);
1169 } else {
1170 /* _<name> */
1171 space += strlen(" ");
1172 }
1173
1174 /* <name>
1175 * __
1176 */
1177 space += TRD_INDENT_LONG_LINE_BREAK;
1178
1179 ly_print_(out, "%*c", space, ' ');
1180}
1181
1182/**
1183 * @brief Print struct trt_node structure.
1184 * @param[in] node is item to print.
1185 * @param[in] pck package of functions for printing [\<keys\>] and \<iffeatures\>.
1186 * @param[in] indent is the indent in node.
1187 * @param[in,out] out is output handler.
1188 */
1189static void
1190trp_print_node(struct trt_node node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out)
1191{
1192 ly_bool triple_dot;
1193 ly_bool divided;
1194 struct trt_cf_print cf_print_keys;
1195 struct trt_cf_print cf_print_iffeatures;
1196
1197 if (trp_node_is_empty(node)) {
1198 return;
1199 }
1200
1201 /* <status>--<flags> <name><opts> <type> <if-features> */
1202 triple_dot = node.name.type == TRD_NODE_TRIPLE_DOT;
1203 divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED;
1204
1205 if (triple_dot) {
1206 trp_print_node_name(node.name, out);
1207 return;
1208 } else if (!divided) {
1209 trp_print_node_up_to_name(node, out);
1210 } else {
1211 trp_print_divided_node_up_to_name(node, out);
1212 }
1213
1214 /* <opts> */
1215 /* <name>___<opts>*/
1216 cf_print_keys.ctx = pck.tree_ctx;
1217 cf_print_keys.pf = pck.fps.print_keys;
1218
1219 trp_print_opts_keys(node.name, indent.btw_name_opts, cf_print_keys, out);
1220
1221 /* <opts>__<type> */
1222 if (indent.btw_opts_type > 0) {
1223 ly_print_(out, "%*c", indent.btw_opts_type, ' ');
1224 }
1225
1226 /* <type> */
1227 trp_print_type(node.type, out);
1228
1229 /* <type>__<iffeatures> */
1230 if (indent.btw_type_iffeatures > 0) {
1231 ly_print_(out, "%*c", indent.btw_type_iffeatures, ' ');
1232 }
1233
1234 /* <iffeatures> */
1235 cf_print_iffeatures.ctx = pck.tree_ctx;
1236 cf_print_iffeatures.pf = pck.fps.print_features_names;
1237
1238 trp_print_iffeatures(node.iffeatures, cf_print_iffeatures, out);
1239}
1240
1241/**
1242 * @brief Print .keyword based on .type.
1243 * @param[in] ks is keyword statement to print.
1244 * @param[in,out] out is output handler
1245 */
1246static void
1247trt_print_keyword_stmt_begin(struct trt_keyword_stmt ks, struct ly_out *out)
1248{
1249 switch (ks.type) {
1250 case TRD_KEYWORD_MODULE:
1251 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_MODULE);
1252 return;
1253 case TRD_KEYWORD_SUBMODULE:
1254 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_SUBMODULE);
1255 return;
1256 default:
1257 ly_print_(out, "%*c", TRD_INDENT_LINE_BEGIN, ' ');
1258 switch (ks.type) {
1259 case TRD_KEYWORD_AUGMENT:
1260 ly_print_(out, "%s ", TRD_BODY_KEYWORD_AUGMENT);
1261 break;
1262 case TRD_KEYWORD_RPC:
1263 ly_print_(out, "%s", TRD_BODY_KEYWORD_RPC);
1264 break;
1265 case TRD_KEYWORD_NOTIF:
1266 ly_print_(out, "%s", TRD_BODY_KEYWORD_NOTIF);
1267 break;
1268 case TRD_KEYWORD_GROUPING:
1269 ly_print_(out, "%s ", TRD_BODY_KEYWORD_GROUPING);
1270 break;
1271 case TRD_KEYWORD_YANG_DATA:
1272 ly_print_(out, "%s ", TRD_BODY_KEYWORD_YANG_DATA);
1273 break;
1274 default:
1275 break;
1276 }
1277 break;
1278 }
1279}
1280
1281/**
1282 * @brief Get string length of stored keyword.
1283 * @param[in] type is type of the keyword statement.
1284 * @return length of the keyword statement name.
1285 */
1286static size_t
1287trp_keyword_type_strlen(trt_keyword_type type)
1288{
1289 switch (type) {
1290 case TRD_KEYWORD_MODULE:
1291 return sizeof(TRD_TOP_KEYWORD_MODULE) - 1;
1292 case TRD_KEYWORD_SUBMODULE:
1293 return sizeof(TRD_TOP_KEYWORD_SUBMODULE) - 1;
1294 case TRD_KEYWORD_AUGMENT:
1295 return sizeof(TRD_BODY_KEYWORD_AUGMENT) - 1;
1296 case TRD_KEYWORD_RPC:
1297 return sizeof(TRD_BODY_KEYWORD_RPC) - 1;
1298 case TRD_KEYWORD_NOTIF:
1299 return sizeof(TRD_BODY_KEYWORD_NOTIF) - 1;
1300 case TRD_KEYWORD_GROUPING:
1301 return sizeof(TRD_BODY_KEYWORD_GROUPING) - 1;
1302 case TRD_KEYWORD_YANG_DATA:
1303 return sizeof(TRD_BODY_KEYWORD_YANG_DATA) - 1;
1304 default:
1305 return 0;
1306 }
1307}
1308
1309/**
1310 * @brief Print .str which is string of name or path.
1311 * @param[in] ks is keyword statement structure.
1312 * @param[in] mll is max line length.
1313 * @param[in,out] out is output handler.
1314 */
1315static void
1316trt_print_keyword_stmt_str(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
1317{
1318 uint32_t ind_initial;
1319 uint32_t ind_divided;
1320 /* flag if path must be splitted to more lines */
1321 ly_bool linebreak_was_set;
1322 /* flag if at least one subpath was printed */
1323 ly_bool subpath_printed;
1324 /* the sum of the sizes of the substrings on the current line */
1325 uint32_t how_far;
1326 /* pointer to start of the subpath */
1327 const char *sub_ptr;
1328 /* size of subpath from sub_ptr */
1329 size_t sub_len;
1330
1331 if ((!ks.str) || (ks.str[0] == '\0')) {
1332 return;
1333 }
1334
1335 /* module name cannot be splitted */
1336 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
1337 ly_print_(out, "%s", ks.str);
1338 return;
1339 }
1340
1341 /* after -> for trd_keyword_stmt_body do */
1342
1343 /* set begin indentation */
1344 ind_initial = TRD_INDENT_LINE_BEGIN + trp_keyword_type_strlen(ks.type) + 1;
1345 ind_divided = ind_initial + TRD_INDENT_LONG_LINE_BREAK;
1346 linebreak_was_set = 0;
1347 subpath_printed = 0;
1348 how_far = 0;
1349 sub_ptr = ks.str;
1350 sub_len = 0;
1351
1352 while (sub_ptr[0] != '\0') {
1353 uint32_t ind;
1354 /* skip slash */
1355 const char *tmp = sub_ptr[0] == '/' ? sub_ptr + 1 : sub_ptr;
1356 /* get position of the end of substr */
1357 tmp = strchr(tmp, '/');
1358 /* set correct size if this is a last substring */
1359 sub_len = !tmp ? strlen(sub_ptr) : (size_t)(tmp - sub_ptr);
1360 /* actualize sum of the substring's sizes on the current line */
1361 how_far += sub_len;
1362 /* correction due to colon character if it this is last substring */
1363 how_far = *(sub_ptr + sub_len) == '\0' ? how_far + 1 : how_far;
1364 /* choose indentation which depends on
1365 * whether the string is printed on multiple lines or not
1366 */
1367 ind = linebreak_was_set ? ind_divided : ind_initial;
1368 if (ind + how_far <= mll) {
1369 /* printing before max line length */
1370 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1371 subpath_printed = 1;
1372 } else {
1373 /* printing on new line */
1374 if (subpath_printed == 0) {
1375 /* first subpath is too long but print it at first line anyway */
1376 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1377 subpath_printed = 1;
1378 continue;
1379 }
1380 ly_print_(out, "\n");
1381 ly_print_(out, "%*c", ind_divided, ' ');
1382 linebreak_was_set = 1;
1383 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1384 how_far = sub_len;
1385 subpath_printed = 1;
1386 }
1387 }
1388}
1389
1390/**
1391 * @brief Print separator based on .type.
1392 * @param[in] ks is keyword statement structure.
1393 * @param[in,out] out is output handler.
1394 */
1395static void
1396trt_print_keyword_stmt_end(struct trt_keyword_stmt ks, struct ly_out *out)
1397{
1398 if ((ks.type != TRD_KEYWORD_MODULE) && (ks.type != TRD_KEYWORD_SUBMODULE)) {
1399 ly_print_(out, ":");
1400 }
1401}
1402
1403/**
1404 * @brief Print entire struct trt_keyword_stmt structure.
1405 * @param[in] ks is item to print.
1406 * @param[in] mll is max line length.
1407 * @param[in,out] out is output handler.
1408 */
1409static void
1410trp_print_keyword_stmt(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
1411{
1412 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
1413 return;
1414 }
1415 trt_print_keyword_stmt_begin(ks, out);
1416 trt_print_keyword_stmt_str(ks, mll, out);
1417 trt_print_keyword_stmt_end(ks, out);
1418}
1419
1420/******************************************************************************
1421 * Main trp functions
1422 *****************************************************************************/
1423
1424/**
1425 * @brief Printing one line including wrapper and node which can be incomplete (divided).
1426 * @param[in] node is \<node\> representation.
1427 * @param[in] pck contains special printing functions callback.
1428 * @param[in] indent contains wrapper and indent in node numbers.
1429 * @param[in,out] out is output handler.
1430 */
1431static void
1432trp_print_line(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out)
1433{
1434 trp_print_wrapper(indent.wrapper, out);
1435 trp_print_node(node, pck, indent.in_node, out);
1436}
1437
1438/**
1439 * @brief Printing one line including wrapper and \<status\>--\<flags\> \<name\>\<option_mark\>.
1440 * @param[in] node is \<node\> representation.
1441 * @param[in] wr is wrapper for printing indentation before node.
1442 * @param[in] out is output handler.
1443 */
1444static void
1445trp_print_line_up_to_node_name(struct trt_node node, struct trt_wrapper wr, struct ly_out *out)
1446{
1447 trp_print_wrapper(wr, out);
1448 trp_print_node_up_to_name(node, out);
1449}
1450
1451/**
1452 * @brief Check if leafref target must be change to string 'leafref' because his target string is too long.
1453 * @param[in] node containing leafref target.
1454 * @param[in] wr is wrapper for printing indentation before node.
1455 * @param[in] mll is max line length.
1456 * @param[in] out is output handler.
1457 * @return true if leafref must be changed to string 'leafref'.
1458 */
1459static ly_bool
1460trp_leafref_target_is_too_long(struct trt_node node, struct trt_wrapper wr, size_t mll, struct ly_out *out)
1461{
1462 struct ly_out_clb_arg *data;
1463
1464 if (node.type.type != TRD_TYPE_TARGET) {
1465 return 0;
1466 }
1467
1468 /* set ly_out to counting characters */
1469 data = out->method.clb.arg;
1470
1471 data->counter = 0;
1472 data->mode = TRD_CHAR_COUNT;
1473 /* count number of printed bytes */
1474 trp_print_wrapper(wr, out);
1475 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1476 trp_print_divided_node_up_to_name(node, out);
1477 data->mode = TRD_PRINT;
1478
1479 return data->counter + strlen(node.type.str) > mll;
1480}
1481
1482/**
1483 * @brief Get default indent in node based on node values.
1484 * @param[in] node is \<node\> representation.
1485 * @return Default indent in node assuming that the node will not be divided.
1486 */
1487static struct trt_indent_in_node
1488trp_default_indent_in_node(struct trt_node node)
1489{
1490 struct trt_indent_in_node ret;
1491
1492 ret.type = TRD_INDENT_IN_NODE_NORMAL;
1493
1494 /* btw_name_opts */
1495 ret.btw_name_opts = node.name.type == TRD_NODE_KEYS ? TRD_INDENT_BEFORE_KEYS : 0;
1496
1497 /* btw_opts_type */
1498 if (!(TRP_TRT_TYPE_IS_EMPTY(node.type))) {
1499 ret.btw_opts_type = trp_mark_is_used(node.name) ?
1500 TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
1501 TRD_INDENT_BEFORE_TYPE;
1502 } else {
1503 ret.btw_opts_type = 0;
1504 }
1505
1506 /* btw_type_iffeatures */
1507 ret.btw_type_iffeatures = node.iffeatures ? TRD_INDENT_BEFORE_IFFEATURES : 0;
1508
1509 return ret;
1510}
1511
1512/**
1513 * @brief Setting linebreaks in trt_indent_in_node.
1514 *
1515 * The order where the linebreak tag can be placed is from the end.
1516 *
1517 * @param[in] indent containing alignment lengths or already linebreak marks.
1518 * @return indent with a newly placed linebreak tag.
1519 * @return .type set to TRD_INDENT_IN_NODE_FAILED if it is not possible to place a more linebreaks.
1520 */
1521static struct trt_indent_in_node
1522trp_indent_in_node_place_break(struct trt_indent_in_node indent)
1523{
1524 /* somewhere must be set a line break in node */
1525 struct trt_indent_in_node ret = indent;
1526
1527 /* gradually break the node from the end */
1528 if ((indent.btw_type_iffeatures != TRD_LINEBREAK) && (indent.btw_type_iffeatures != 0)) {
1529 ret.btw_type_iffeatures = TRD_LINEBREAK;
1530 } else if ((indent.btw_opts_type != TRD_LINEBREAK) && (indent.btw_opts_type != 0)) {
1531 ret.btw_opts_type = TRD_LINEBREAK;
1532 } else if ((indent.btw_name_opts != TRD_LINEBREAK) && (indent.btw_name_opts != 0)) {
1533 /* set line break between name and opts */
1534 ret.btw_name_opts = TRD_LINEBREAK;
1535 } else {
1536 /* it is not possible to place a more line breaks,
1537 * unfortunately the max_line_length constraint is violated
1538 */
1539 ret.type = TRD_INDENT_IN_NODE_FAILED;
1540 }
1541 return ret;
1542}
1543
1544/**
1545 * @brief Get the first half of the node based on the linebreak mark.
1546 *
1547 * Items in the second half of the node will be empty.
1548 *
1549 * @param[in] node the whole \<node\> to be split.
1550 * @param[in] indent contains information in which part of the \<node\> the first half ends.
1551 * @return first half of the node, indent is unchanged.
1552 */
1553static struct trt_pair_indent_node
1554trp_first_half_node(struct trt_node node, struct trt_indent_in_node indent)
1555{
1556 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1557
1558 if (indent.btw_name_opts == TRD_LINEBREAK) {
1559 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1560 ret.node.type = TRP_EMPTY_TRT_TYPE;
1561 ret.node.iffeatures = 0;
1562 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1563 ret.node.type = TRP_EMPTY_TRT_TYPE;
1564 ret.node.iffeatures = 0;
1565 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1566 ret.node.iffeatures = 0;
1567 }
1568
1569 return ret;
1570}
1571
1572/**
1573 * @brief Get the second half of the node based on the linebreak mark.
1574 *
1575 * Items in the first half of the node will be empty.
1576 * Indentations belonging to the first node will be reset to zero.
1577 *
1578 * @param[in] node the whole \<node\> to be split.
1579 * @param[in] indent contains information in which part of the \<node\> the second half starts.
1580 * @return second half of the node, indent is newly set.
1581 */
1582static struct trt_pair_indent_node
1583trp_second_half_node(struct trt_node node, struct trt_indent_in_node indent)
1584{
1585 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1586
1587 if (indent.btw_name_opts < 0) {
1588 /* Logically, the information up to token <opts> should be deleted,
1589 * but the the trp_print_node function needs it to create
1590 * the correct indent.
1591 */
1592 ret.indent.btw_name_opts = 0;
1593 ret.indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(node.type) ? 0 : TRD_INDENT_BEFORE_TYPE;
1594 ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1595 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1596 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1597 ret.indent.btw_name_opts = 0;
1598 ret.indent.btw_opts_type = 0;
1599 ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1600 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1601 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1602 ret.node.type = TRP_EMPTY_TRT_TYPE;
1603 ret.indent.btw_name_opts = 0;
1604 ret.indent.btw_opts_type = 0;
1605 ret.indent.btw_type_iffeatures = 0;
1606 }
1607 return ret;
1608}
1609
1610/**
1611 * @brief Get the correct alignment for the node.
1612 *
1613 * This function is recursively called itself.
1614 * It's like a backend function for a function trp_try_normal_indent_in_node.
1615 *
1616 * @param[in] node is \<node\> representation.
1617 * @param[in] pck contains speciall callback functions for printing.
1618 * @param[in] indent contains wrapper and indent in node numbers.
1619 * @param[in] mll is max line length.
1620 * @param[in,out] cnt counting number of characters to print.
1621 * @param[in,out] out is output handler.
1622 * @return pair of node and indentation numbers of that node.
1623 */
1624static struct trt_pair_indent_node
1625trp_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)
1626{
1627 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1628
1629 trp_print_line(node, pck, indent, out);
1630
1631 if (*cnt <= mll) {
1632 /* success */
1633 return ret;
1634 } else {
1635 ret.indent = trp_indent_in_node_place_break(ret.indent);
1636 if (ret.indent.type != TRD_INDENT_IN_NODE_FAILED) {
1637 /* erase information in node due to line break */
1638 ret = trp_first_half_node(node, ret.indent);
1639 /* check if line fits, recursive call */
1640 *cnt = 0;
1641 ret = trp_try_normal_indent_in_node_(ret.node, pck, TRP_INIT_PCK_INDENT(indent.wrapper, ret.indent), mll, cnt, out);
1642 /* make sure that the result will be with the status divided
1643 * or eventually with status failed */
1644 ret.indent.type = ret.indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED;
1645 }
1646 return ret;
1647 }
1648}
1649
1650/**
1651 * @brief Get the correct alignment for the node.
1652 *
1653 * @param[in] node is \<node\> representation.
1654 * @param[in] pck contains speciall callback functions for printing.
1655 * @param[in] indent contains wrapper and indent in node numbers.
1656 * @param[in] mll is max line length.
1657 * @param[in,out] out is output handler.
1658 * @return .type == TRD_INDENT_IN_NODE_DIVIDED - the node does not fit in the line, some indent variable has negative value as a line break sign.
1659 * @return .type == TRD_INDENT_IN_NODE_NORMAL - the node fits into the line, all indent variables values has non-negative number.
1660 * @return .type == TRD_INDENT_IN_NODE_FAILED - the node does not fit into the line, all indent variables has negative or zero values, function failed.
1661 */
1662static struct trt_pair_indent_node
1663trp_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)
1664{
1665 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1666 struct ly_out_clb_arg *data;
1667
1668 /* set ly_out to counting characters */
1669 data = out->method.clb.arg;
1670
1671 data->counter = 0;
1672 data->mode = TRD_CHAR_COUNT;
1673 ret = trp_try_normal_indent_in_node_(node, pck, indent, mll, &data->counter, out);
1674 data->mode = TRD_PRINT;
1675
1676 return ret;
1677}
1678
1679/**
1680 * @brief Auxiliary function for trp_print_entire_node that prints split nodes.
1681 * @param[in] node is node representation.
1682 * @param[in] ppck contains speciall callback functions for printing.
1683 * @param[in] ipck contains wrapper and indent in node numbers.
1684 * @param[in] mll is max line length.
1685 * @param[in,out] out is output handler.
1686 */
1687static void
1688trp_print_divided_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1689{
1690 ly_bool entire_node_was_printed;
1691 struct trt_pair_indent_node ind_node = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1692
1693 if (ind_node.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1694 /* nothing can be done, continue as usual */
1695 ind_node.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1696 }
1697
1698 trp_print_line(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), out);
1699 entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, ind_node.indent);
1700
1701 if (!entire_node_was_printed) {
1702 ly_print_(out, "\n");
1703 /* continue with second half node */
1704 ind_node = trp_second_half_node(node, ind_node.indent);
1705 /* continue with printing node */
1706 trp_print_divided_node(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), mll, out);
1707 } else {
1708 return;
1709 }
1710}
1711
1712/**
1713 * @brief Printing of the wrapper and the whole node, which can be divided into several lines.
1714 * @param[in] node is node representation.
1715 * @param[in] ppck contains speciall callback functions for printing.
1716 * @param[in] ipck contains wrapper and indent in node numbers.
1717 * @param[in] mll is max line length.
1718 * @param[in,out] out is output handler.
1719 */
1720static void
1721trp_print_entire_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1722{
1723 struct trt_pair_indent_node ind_node1;
1724 struct trt_pair_indent_node ind_node2;
1725 struct trt_pck_indent tmp;
1726
1727 if (trp_leafref_target_is_too_long(node, ipck.wrapper, mll, out)) {
1728 node.type.type = TRD_TYPE_LEAFREF;
1729 }
1730
1731 /* check if normal indent is possible */
1732 ind_node1 = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1733
1734 if (ind_node1.indent.type == TRD_INDENT_IN_NODE_NORMAL) {
1735 /* node fits to one line */
1736 trp_print_line(node, ppck, ipck, out);
1737 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_DIVIDED) {
1738 /* node will be divided */
1739 /* print first half */
1740 tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node1.indent);
1741 /* pretend that this is normal node */
1742 tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL;
1743
1744 trp_print_line(ind_node1.node, ppck, tmp, out);
1745 ly_print_(out, "\n");
1746
1747 /* continue with second half on new line */
1748 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1749 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1750
1751 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1752 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1753 /* node name is too long */
1754 trp_print_line_up_to_node_name(node, ipck.wrapper, out);
1755
1756 if (trp_node_body_is_empty(node)) {
1757 return;
1758 } else {
1759 ly_print_(out, "\n");
1760
1761 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1762 ind_node2.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1763 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1764
1765 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1766 }
1767
1768 }
1769}
1770
1771/******************************************************************************
1772 * Definition of Tro reading functions
1773 *****************************************************************************/
1774
1775/**
1776 * @brief Get new trt_parent_cache if we apply the transfer to the child node in the tree.
1777 * @param[in] ca is parent cache for current node.
1778 * @param[in] pn is pointer to the current tree node.
1779 * @return Cache for the current node.
1780 */
1781static struct trt_parent_cache
1782tro_parent_cache_for_child(struct trt_parent_cache ca, const struct lysp_node *pn)
1783{
1784 struct trt_parent_cache ret;
1785
1786 ret.ancestor =
1787 pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT :
1788 pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT :
1789 pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF :
1790 ca.ancestor;
1791
1792 ret.lys_status =
1793 pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
1794 ca.lys_status;
1795
1796 ret.lys_config =
1797 ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because <flags> will be -w */
1798 ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
1799 pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
1800 ca.lys_config;
1801
1802 ret.last_list =
1803 pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
1804 ca.last_list;
1805
1806 return ret;
1807}
1808
1809/**
1810 * @brief Read next sibling of the current node.
1811 * @param[in] origin_tc is context of the tree.
1812 * @return A patch structure that has prepared pointers for updating struct trt_tree_ctx.
1813 * If sibling exists then .pn points to him, otherwise is set to NULL.
1814 * The .tpn points to its sibling if it exists and if .pn points to the same node as .tpn,
1815 * otherwise .tpn value from origin_tc is copied.
1816 */
1817static struct trt_tree_ctx_node_patch
1818tro_read_next_sibling(const struct trt_tree_ctx *origin_tc)
1819{
1820 assert(origin_tc && origin_tc->pn);
1821
1822 struct trt_tree_ctx_node_patch tc = TRP_INIT_TREE_CTX_NODE_PATCH(origin_tc->pn, origin_tc->tpn);
1823
1824 if (tc.pn->nodetype & (LYS_RPC | LYS_ACTION)) {
1825 if (tc.tpn == tc.pn) {
1826 /* just go to the top-node's sibling */
1827 tc.pn = tc.pn->next;
1828 tc.tpn = tc.pn;
1829 } else {
1830 /* try to go to the notif node as sibling */
1831 if (!tc.pn->next) {
1832 tc.pn = (const struct lysp_node *)lysp_node_notifs(tc.pn->parent);
1833 } else {
1834 tc.pn = tc.pn->next;
1835 }
1836 }
1837 } else if (tc.pn->nodetype & LYS_INPUT) {
1838 const struct lysp_node_action *parent = (struct lysp_node_action *)tc.pn->parent;
1839 /* if output action has data */
1840 if (parent->output.child) {
1841 /* then next sibling is output action */
1842 tc.pn = &parent->output.node;
1843 } else {
1844 /* else input action has no sibling */
1845 tc.pn = NULL;
1846 }
1847 /* if current node is output action */
1848 } else if (tc.pn->nodetype & LYS_OUTPUT) {
1849 /* then next sibling does not exist */
1850 tc.pn = NULL;
1851 /* if current node is notification */
1852 } else if (tc.pn->nodetype & LYS_NOTIF) {
1853 if (tc.tpn == tc.pn) {
1854 tc.pn = tc.pn->next;
1855 tc.tpn = tc.pn;
1856 } else {
1857 tc.pn = tc.pn->next;
1858 }
1859 } else {
1860 /* else actual node is some node with 'next' element */
1861 if (tc.tpn == tc.pn) {
1862 tc.tpn = tc.pn->next;
1863 }
1864 tc.pn = tc.pn->next;
1865 }
1866
1867 return tc;
1868}
1869
1870/**
1871 * @brief Find out if the current node has siblings.
1872 * @param[in] tc is context of the tree.
1873 * @return 1 if sibling exists otherwise 0.
1874 */
1875static ly_bool
1876tro_read_if_sibling_exists(const struct trt_tree_ctx *tc)
1877{
1878 return tro_read_next_sibling(tc).pn != NULL;
1879}
1880
1881/**
1882 * @brief Check if list statement has keys.
1883 * @param[in] pn is pointer to the list.
1884 * @return 1 if has keys, otherwise 0.
1885 */
1886static ly_bool
1887tro_lysp_list_has_keys(const struct lysp_node_list *pn)
1888{
1889 return trg_charptr_has_data(pn->key);
1890}
1891
1892/**
1893 * @brief Check if it contains at least one feature.
1894 * @param[in] iffs is pointer to the if-features.
1895 * @return 1 if has if-features, otherwise 0.
1896 */
1897static ly_bool
1898tro_lysp_node_to_iffeature(const struct lysp_qname *iffs)
1899{
1900 LY_ARRAY_COUNT_TYPE u;
1901 ly_bool ret = 0;
1902
1903 LY_ARRAY_FOR(iffs, u) {
1904 ret = 1;
1905 break;
1906 }
1907 return ret;
1908}
1909
1910/**
1911 * @brief Find out if leaf is also the key in last list.
1912 * @param[in] pn is pointer to leaf.
1913 * @param[in] ca_last_list is pointer to last visited list. Obtained from trt_parent_cache.
1914 * @return 1 if leaf is also the key, otherwise 0.
1915 */
1916static ly_bool
1917tro_lysp_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
1918{
1919 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
1920 const struct lysp_node_list *list = ca_last_list;
1921
1922 if (!list) {
1923 return 0;
1924 }
1925 return trg_charptr_has_data(list->key) ?
1926 trg_word_is_present(list->key, leaf->name, ' ') : 0;
1927}
1928
1929/**
1930 * @brief Check if container's type is presence.
1931 * @param[in] pn is pointer to container.
1932 * @return 1 if container has presence statement, otherwise 0.
1933 */
1934static ly_bool
1935tro_lysp_container_has_presence(const struct lysp_node *pn)
1936{
1937 return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence);
1938}
1939
1940/**
1941 * @brief Get leaflist's path without lysp_node type control.
1942 * @param[in] pn is pointer to the leaflist.
1943 */
1944static const char *
1945tro_lysp_leaflist_refpath(const struct lysp_node *pn)
1946{
1947 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
1948
1949 return list->type.path ? list->type.path->expr : NULL;
1950}
1951
1952/**
1953 * @brief Get leaflist's type name without lysp_node type control.
1954 * @param[in] pn is pointer to the leaflist.
1955 */
1956static const char *
1957tro_lysp_leaflist_type_name(const struct lysp_node *pn)
1958{
1959 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
1960
1961 return list->type.name;
1962}
1963
1964/**
1965 * @brief Get leaf's path without lysp_node type control.
1966 * @param[in] pn is pointer to the leaf node.
1967 */
1968static const char *
1969tro_lysp_leaf_refpath(const struct lysp_node *pn)
1970{
1971 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
1972
1973 return leaf->type.path ? leaf->type.path->expr : NULL;
1974}
1975
1976/**
1977 * @brief Get leaf's type name without lysp_node type control.
1978 * @param[in] pn is pointer to the leaf's type name.
1979 */
1980static const char *
1981tro_lysp_leaf_type_name(const struct lysp_node *pn)
1982{
1983 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
1984
1985 return leaf->type.name;
1986}
1987
1988/**
1989 * @brief Get pointer to data using node type specification and getter function.
1990 *
1991 * @param[in] flags is node type specification. If it is the correct node, the getter function is called.
1992 * @param[in] f is getter function which provides the desired char pointer from the structure.
1993 * @param[in] pn pointer to node.
1994 * @return NULL if node has wrong type or getter function return pointer to NULL.
1995 * @return Pointer to desired char pointer obtained from the node.
1996 */
1997static const char *
1998tro_lysp_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn)
1999{
2000 if (pn->nodetype & flags) {
2001 const char *ret = f(pn);
2002 return trg_charptr_has_data(ret) ? ret : NULL;
2003 } else {
2004 return NULL;
2005 }
2006}
2007
2008/**
2009 * @brief Transformation of the lysp flags to Yang tree \<status\>.
2010 * @param[in] flags is node's flags obtained from the tree.
2011 */
2012static trt_status_type
2013tro_lysp_flags2status(uint16_t flags)
2014{
2015 return flags & LYS_STATUS_OBSLT ? TRD_STATUS_TYPE_OBSOLETE :
2016 flags & LYS_STATUS_DEPRC ? TRD_STATUS_TYPE_DEPRECATED :
2017 TRD_STATUS_TYPE_CURRENT;
2018}
2019
2020/**
2021 * @brief Transformation of the lysp flags to Yang tree \<flags\> but more specifically 'ro' or 'rw'.
2022 * @param[in] flags is node's flags obtained from the tree.
2023 */
2024static trt_flags_type
2025tro_lysp_flags2config(uint16_t flags)
2026{
2027 return flags & LYS_CONFIG_R ?
2028 TRD_FLAGS_TYPE_RO : TRD_FLAGS_TYPE_RW;
2029}
2030
2031/**
2032 * @brief Get name of the module.
2033 * @param[in] tc is context of the tree.
2034 */
2035static struct trt_keyword_stmt
2036tro_read_module_name(const struct trt_tree_ctx *tc)
2037{
2038 assert(tc && tc->module && tc->module->name);
2039 return (struct trt_keyword_stmt) {
2040 .type = TRD_KEYWORD_MODULE, .str = tc->module->name
2041 };
2042}
2043
2044/**
2045 * @brief Resolve \<status\> of the current node.
2046 * @param[in] nodetype is node's type obtained from the tree.
2047 * @param[in] flags is node's flags obtained from the tree.
2048 * @param[in] ca_lys_status is inherited status obtained from trt_parent_cache.
2049 * @return The status type.
2050 */
2051static trt_status_type
2052tro_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
2053{
2054 /* LYS_INPUT and LYS_OUTPUT is special case */
2055 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
2056 return tro_lysp_flags2status(ca_lys_status);
2057 /* if ancestor's status is deprc or obslt and also node's status is not set */
2058 } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
2059 /* get ancestor's status */
2060 return tro_lysp_flags2status(ca_lys_status);
2061 } else {
2062 /* else get node's status */
2063 return tro_lysp_flags2status(flags);
2064 }
2065}
2066
2067/**
2068 * @brief Resolve \<flags\> of the current node.
2069 * @param[in] nodetype is node's type obtained from the tree.
2070 * @param[in] flags is node's flags obtained from the tree.
2071 * @param[in] ca_ancestor is ancestor type obtained from trt_parent_cache.
2072 * @param[in] ca_lys_config is inherited config item obtained from trt_parent_cache.
2073 * @return The flags type.
2074 */
2075static trt_flags_type
2076tro_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config)
2077{
2078 if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) {
2079 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
2080 } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) {
2081 return TRD_FLAGS_TYPE_RO;
2082 } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) {
2083 return TRD_FLAGS_TYPE_RO;
2084 } else if (nodetype & LYS_NOTIF) {
2085 return TRD_FLAGS_TYPE_NOTIF;
2086 } else if (nodetype & LYS_USES) {
2087 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
2088 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
2089 return TRD_FLAGS_TYPE_RPC;
2090 /* if config is not set then look at ancestor's config and get his config */
2091 } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
2092 return tro_lysp_flags2config(ca_lys_config);
2093 } else {
2094 return tro_lysp_flags2config(flags);
2095 }
2096}
2097
2098/**
2099 * @brief Resolve node type of the current node.
2100 * @param[in] pn is pointer to the current node in the tree.
2101 * @param[in] ca_last_list is pointer to the last visited list. Obtained from the trt_parent_cache.
2102 */
2103static trt_node_type
2104tro_resolve_node_type(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
2105{
2106 if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
2107 return TRD_NODE_ELSE;
2108 } else if (pn->nodetype & LYS_CASE) {
2109 return TRD_NODE_CASE;
2110 } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) {
2111 return TRD_NODE_OPTIONAL_CHOICE;
2112 } else if (pn->nodetype & LYS_CHOICE) {
2113 return TRD_NODE_CHOICE;
2114 } else if ((pn->nodetype & LYS_CONTAINER) && (tro_lysp_container_has_presence(pn))) {
2115 return TRD_NODE_CONTAINER;
2116 } else if ((pn->nodetype & LYS_LIST) && (tro_lysp_list_has_keys((const struct lysp_node_list *)pn))) {
2117 return TRD_NODE_KEYS;
2118 } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
2119 return TRD_NODE_LISTLEAFLIST;
2120 } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) {
2121 return TRD_NODE_OPTIONAL;
2122 } else if ((pn->nodetype & LYS_LEAF) && !(pn->flags & LYS_MAND_TRUE) && (!tro_lysp_leaf_is_key(pn, ca_last_list))) {
2123 return TRD_NODE_OPTIONAL;
2124 } else {
2125 return TRD_NODE_ELSE;
2126 }
2127}
2128
2129/**
2130 * @brief Transformation of current lysp_node to struct trt_node.
2131 * @param[in] ca contains stored important data when browsing the tree downwards.
2132 * @param[in] tc is context of the tree.
2133 */
2134static struct trt_node
2135tro_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2136{
2137 assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
2138 const struct lysp_node *pn = tc->pn;
2139 struct trt_node ret = TRP_EMPTY_NODE;
2140 const char *tmp;
2141
2142 /* <status> */
2143 ret.status = tro_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
2144
2145 /* TODO: TRD_FLAGS_TYPE_MOUNT_POINT aka "mp" is not supported right now. */
2146 /* <flags> */
2147 ret.flags = tro_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config);
2148
2149 /* TODO: TRD_NODE_TOP_LEVEL1 aka '/' is not supported right now. */
2150 /* TODO: TRD_NODE_TOP_LEVEL2 aka '@' is not supported right now. */
2151 /* set type of the node */
2152 ret.name.type = tro_resolve_node_type(pn, ca.last_list);
2153
2154 /* TODO: ret.name.module_prefix is not supported right now. */
2155 ret.name.module_prefix = NULL;
2156
2157 /* set node's name */
2158 ret.name.str = pn->name;
2159
2160 /* <type> */
2161 tmp = NULL;
2162
2163 if ((tmp = tro_lysp_node_charptr(LYS_LEAFLIST, tro_lysp_leaflist_refpath, pn))) {
2164 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2165 } else if ((tmp = tro_lysp_node_charptr(LYS_LEAFLIST, tro_lysp_leaflist_type_name, pn))) {
2166 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2167 } else if ((tmp = tro_lysp_node_charptr(LYS_LEAF, tro_lysp_leaf_refpath, pn))) {
2168 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2169 } else if ((tmp = tro_lysp_node_charptr(LYS_LEAF, tro_lysp_leaf_type_name, pn))) {
2170 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2171 } else if ((pn->nodetype & LYS_ANYDATA) == LYS_ANYDATA) {
2172 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata");
2173 } else if (pn->nodetype & LYS_ANYXML) {
2174 ret.type = TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml");
2175 } else {
2176 ret.type = TRP_EMPTY_TRT_TYPE;
2177 }
2178
2179 /* <iffeature> */
2180 ret.iffeatures = tro_lysp_node_to_iffeature(pn->iffeatures);
2181
2182 ret.last_one = !tro_read_if_sibling_exists(tc);
2183
2184 return ret;
2185}
2186
2187/******************************************************************************
2188 * Modify Tro getters
2189 *****************************************************************************/
2190
2191/**
2192 * @brief Change current node pointer to its parent but only if parent exists.
2193 * @param[in,out] tc is tree context. Contains pointer to the current node.
2194 * @return 1 if the node had parents and the change was successful.
2195 * @return 0 if the node did not have parents. The pointer to the current node did not change.
2196 */
2197static ly_bool
2198tro_modi_parent(struct trt_tree_ctx *tc)
2199{
2200 assert(tc && tc->pn);
2201 /* If no parent exists, stay in actual node. */
2202 if (tc->pn != tc->tpn) {
2203 tc->pn = tc->pn->parent;
2204 return 1;
2205 } else {
2206 return 0;
2207 }
2208}
2209
2210/**
2211 * @brief Change the current node pointer to its child but only if exists.
2212 * @param[in] ca contains inherited data from ancestors.
2213 * @param[in,out] tc is context of the tree. Contains pointer to the current node.
2214 * @return Non-empty \<node\> representation of the current node's child. The tc parameter is modified.
2215 * @return Empty \<node\> representation if child don't exists. The tc parameter is not modified.
2216 */
2217static struct trt_node
2218tro_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
2219{
2220 assert(tc && tc->pn);
2221
2222 struct trt_parent_cache new_ca = tro_parent_cache_for_child(ca, tc->pn);
2223
2224 if (tc->pn->nodetype & (LYS_ACTION | LYS_RPC)) {
2225 const struct lysp_node_action *act = (const struct lysp_node_action *)tc->pn;
2226 if (act->input.child) {
2227 /* go to LYS_INPUT */
2228 tc->pn = &act->input.node;
2229 return tro_read_node(new_ca, tc);
2230 } else if (act->output.child) {
2231 /* go to LYS_OUTPUT */
2232 tc->pn = &act->output.node;
2233 return tro_read_node(new_ca, tc);
2234 } else {
2235 /* input action and output action are not set */
2236 return TRP_EMPTY_NODE;
2237 }
2238 } else {
2239 const struct lysp_node *pn = lysp_node_child(tc->pn);
2240 if (pn) {
2241 tc->pn = pn;
2242 return tro_read_node(new_ca, tc);
2243 } else {
2244 /* current node can't have children or has no children */
2245 /* but maybe has some actions or notifs */
2246 const struct lysp_node_action *actions = lysp_node_actions(tc->pn);
2247 const struct lysp_node_notif *notifs = lysp_node_notifs(tc->pn);
2248
2249 if (actions) {
2250 tc->pn = (const struct lysp_node *)actions;
2251 return tro_read_node(new_ca, tc);
2252 } else if (notifs) {
2253 tc->pn = (const struct lysp_node *)notifs;
2254 return tro_read_node(new_ca, tc);
2255 } else {
2256 return TRP_EMPTY_NODE;
2257 }
2258 }
2259 }
2260}
2261
2262/**
2263 * @brief Change the current node pointer to the first child of node's parent.
2264 * If current node is already first sibling/child then nothing will change.
2265 * @param[in,out] tc is tree context.
2266 */
2267static void
2268tro_modi_first_sibling(struct trt_tree_ctx *tc)
2269{
2270 assert(tc && tc->pn && tc->module && tc->module->parsed);
2271
2272 if (tro_modi_parent(tc)) {
2273 tro_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
2274 } else {
2275 /* current node is top-node */
2276
2277 struct lysp_module *pm = tc->module->parsed;
2278
2279 switch (tc->section) {
2280 case TRD_SECT_MODULE:
2281 tc->pn = pm->data;
2282 break;
2283 case TRD_SECT_AUGMENT:
2284 tc->pn = ((const struct lysp_node_augment *)tc->pn->parent)->child;
2285 break;
2286 case TRD_SECT_RPCS:
2287 tc->pn = (const struct lysp_node *)pm->rpcs;
2288 break;
2289 case TRD_SECT_NOTIF:
2290 tc->pn = (const struct lysp_node *)pm->notifs;
2291 break;
2292 case TRD_SECT_GROUPING:
2293 tc->pn = ((const struct lysp_node_grp *)tc->pn->parent)->child;
2294 break;
2295 case TRD_SECT_YANG_DATA:
2296 /*TODO: yang-data is not supported now */
2297 break;
2298 }
2299
2300 /* update pointer to top-node */
2301 tc->tpn = tc->pn;
2302 }
2303}
2304
2305/**
2306 * @brief Change the pointer to the current node to its next sibling only if exists.
2307 * @param[in] ca contains inherited data from ancestors.
2308 * @param[in,out] tc is tree context. Contains pointer to the current node.
2309 * @return Non-empty \<node\> representation if sibling exists. The tc is modified.
2310 * @return Empty \<node\> representation otherwise. The tc is not modified.
2311 */
2312static struct trt_node
2313tro_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
2314{
2315 struct trt_tree_ctx_node_patch patch = tro_read_next_sibling(tc);
2316
2317 /* if next sibling exists */
2318 if (patch.pn) {
2319 /* update trt_tree_ctx */
2320 tc->pn = patch.pn;
2321 tc->tpn = patch.tpn;
2322 return tro_read_node(ca, tc);
2323 } else {
2324 return TRP_EMPTY_NODE;
2325 }
2326}
2327
2328/**
2329 * @brief Get next (or first) augment section if exists.
2330 * @param[in,out] tc is tree context.
2331 * @return Section's representation if (next augment) section exists.
2332 * The tc is modified and his pointer points to the first node in augment section.
2333 * @return Empty section structure otherwise.
2334 */
2335static struct trt_keyword_stmt
2336tro_modi_next_augment(struct trt_tree_ctx *tc)
2337{
2338 assert(tc && tc->module && tc->module->parsed);
2339 const struct lysp_node_augment *augs;
2340
2341 /* if next_augment func was called for the first time */
2342 if (tc->section != TRD_SECT_AUGMENT) {
2343 tc->section = TRD_SECT_AUGMENT;
2344 augs = tc->module->parsed->augments;
2345 } else {
2346 /* get augment sibling from top-node pointer */
2347 augs = (const struct lysp_node_augment *)tc->tpn->parent->next;
2348 }
2349
2350 if ((augs) && (augs->child)) {
2351 tc->pn = augs->child;
2352 tc->tpn = tc->pn;
2353 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_AUGMENT, augs->nodeid);
2354 } else {
2355 return TRP_EMPTY_KEYWORD_STMT;
2356 }
2357}
2358
2359/**
2360 * @brief Get rpcs section if exists.
2361 * @param[in,out] tc is tree context.
2362 * @return Section representation if it exists.
2363 * The tc is modified and his pointer points to the first node in rpcs section.
2364 * @return Empty section representation otherwise.
2365 */
2366static struct trt_keyword_stmt
2367tro_modi_get_rpcs(struct trt_tree_ctx *tc)
2368{
2369 assert(tc && tc->module && tc->module->parsed);
2370 const struct lysp_node_action *actions = tc->module->parsed->rpcs;
2371
2372 if (actions) {
2373 tc->section = TRD_SECT_RPCS;
2374 tc->pn = &actions->node;
2375 tc->tpn = tc->pn;
2376 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_RPC, NULL);
2377 } else {
2378 return TRP_EMPTY_KEYWORD_STMT;
2379 }
2380}
2381
2382/**
2383 * @brief Get notification section if exists
2384 * @param[in,out] tc is tree context.
2385 * @return Section representation if it exists.
2386 * The tc is modified and his pointer points to the first node in notification section.
2387 * @return Empty section representation otherwise.
2388 */
2389static struct trt_keyword_stmt
2390tro_modi_get_notifications(struct trt_tree_ctx *tc)
2391{
2392 assert(tc && tc->module && tc->module->parsed);
2393 const struct lysp_node_notif *notifs = tc->module->parsed->notifs;
2394
2395 if (notifs) {
2396 tc->section = TRD_SECT_NOTIF;
2397 tc->pn = &notifs->node;
2398 tc->tpn = tc->pn;
2399 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_NOTIF, NULL);
2400 } else {
2401 return TRP_EMPTY_KEYWORD_STMT;
2402 }
2403}
2404
2405/**
2406 * @brief Get next (or first) grouping section if exists
2407 * @param[in,out] tc is tree context.
2408 * @return The next (or first) section representation if it exists.
2409 * The tc is modified and his pointer points to the first node in this grouping section.
2410 * @return Empty section representation otherwise.
2411 */
2412static struct trt_keyword_stmt
2413tro_modi_next_grouping(struct trt_tree_ctx *tc)
2414{
2415 assert(tc && tc->module && tc->module->parsed);
2416 const struct lysp_node_grp *grps;
2417
2418 if (tc->section != TRD_SECT_GROUPING) {
2419 tc->section = TRD_SECT_GROUPING;
2420 grps = tc->module->parsed->groupings;
2421 } else {
2422 grps = (const struct lysp_node_grp *)tc->tpn->parent->next;
2423 }
2424
2425 if ((grps) && (grps->child)) {
2426 tc->pn = grps->child;
2427 tc->tpn = tc->pn;
2428 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_GROUPING, grps->name);
2429 } else {
2430 return TRP_EMPTY_KEYWORD_STMT;
2431 }
2432}
2433
2434/**
2435 * @brief Get next yang-data section if exists.
2436 *
2437 * Not implemented.
2438 *
2439 * @param[in,out] tc is tree context.
2440 * @return Section representation if it exists.
2441 * @return Empty section representation otherwise.
2442 */
2443static struct trt_keyword_stmt
2444tro_modi_next_yang_data(struct trt_tree_ctx *tc)
2445{
2446 tc->section = TRD_SECT_YANG_DATA;
2447 /* TODO: yang-data is not supported */
2448 return TRP_EMPTY_KEYWORD_STMT;
2449}
2450
2451/******************************************************************************
2452 * Print Tro getters
2453 *****************************************************************************/
2454
2455/**
2456 * @brief Print current node's iffeatures.
2457 * @param[in] tc is tree context.
2458 * @param[in,out] out is output handler.
2459 */
2460static void
2461tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out)
2462{
2463 const struct lysp_qname *iffs = tc->pn->iffeatures;
2464
2465 LY_ARRAY_COUNT_TYPE i;
2466
2467 LY_ARRAY_FOR(iffs, i) {
2468 if (i == 0) {
2469 ly_print_(out, "%s", iffs[i].str);
2470 } else {
2471 ly_print_(out, ",%s", iffs[i].str);
2472 }
2473 }
2474
2475}
2476
2477/**
2478 * @brief Print current list's keys.
2479 *
2480 * Well, actually printing keys in the lysp_tree is trivial, because char* points to all keys.
2481 * However, special functions have been reserved for this, because in principle
2482 * the list of elements can have more implementations.
2483 *
2484 * @param[in] tc is tree context.
2485 * @param[in,out] out is output handler.
2486 */
2487static void
2488tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out)
2489{
2490 const struct lysp_node *pn = tc->pn;
2491 const struct lysp_node_list *list;
2492
2493 if (pn->nodetype != LYS_LIST) {
2494 return;
2495 }
2496
2497 list = (const struct lysp_node_list *)pn;
2498
2499 if (trg_charptr_has_data(list->key)) {
2500 ly_print_(out, "%s", list->key);
2501 }
2502}
2503
2504/******************************************************************************
2505 * Definition of tree browsing functions
2506 *****************************************************************************/
2507
2508/**
2509 * @brief Get size of node name.
2510 * @param[in] name contains name and mark.
2511 * @return positive value total size of the node name.
2512 * @return negative value as an indication that option mark is included in the total size.
2513 */
2514static int32_t
2515trb_strlen_of_name_and_mark(struct trt_node_name name)
2516{
2517 size_t name_len = strlen(name.str);
2518
2519 if ((name.type == TRD_NODE_CHOICE) || (name.type == TRD_NODE_CASE)) {
2520 /* counting also parentheses */
2521 name_len += 2;
2522 }
2523
2524 return trp_mark_is_used(name) ?
2525 ((int32_t)(name_len + TRD_OPTS_MARK_LENGTH)) * (-1) :
2526 (int32_t)name_len;
2527}
2528
2529/**
2530 * @brief Calculate the btw_opts_type indent size for a particular node.
2531 * @param[in] name is the node for which we get btw_opts_type.
2532 * @param[in] max_len4all is the maximum value of btw_opts_type that it can have.
2533 * @return btw_opts_type for node.
2534 */
2535static int16_t
2536trb_calc_btw_opts_type(struct trt_node_name name, int16_t max_len4all)
2537{
2538 int32_t name_len;
2539 int16_t min_len;
2540 int16_t ret;
2541
2542 name_len = trb_strlen_of_name_and_mark(name);
2543
2544 /* negative value indicate that in name is some opt mark */
2545 min_len = name_len < 0 ?
2546 TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
2547 TRD_INDENT_BEFORE_TYPE;
2548 ret = abs(max_len4all) - abs(name_len);
2549
2550 /* correction -> negative indicate that name is too long. */
2551 return ret < 0 ? min_len : ret;
2552}
2553
2554/**
2555 * @brief Print node.
2556 *
2557 * This function is wrapper for trp_print_entire_node function.
2558 * But difference is that take max_gap_before_type parameter which will be used to set the unified alignment.
2559 *
2560 * @param[in] max_gap_before_type is number of indent before \<type\>.
2561 * @param[in] wr is wrapper for printing indentation before node.
2562 * @param[in] ca contains inherited data from ancestors.
2563 * @param[in] pc contains mainly functions for printing.
2564 * @param[in] tc is tree context.
2565 */
2566static void
2567trb_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)
2568{
2569 struct trt_node node = pc->fp.read.node(ca, tc);
2570 struct trt_indent_in_node ind = trp_default_indent_in_node(node);
2571
2572 if ((max_gap_before_type > 0) && (node.type.type != TRD_TYPE_EMPTY)) {
2573 /* print actual node with unified indent */
2574 ind.btw_opts_type = trb_calc_btw_opts_type(node.name, max_gap_before_type);
2575 }
2576 /* after -> print actual node with default indent */
2577 trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print),
2578 TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out);
2579}
2580
2581/**
2582 * @brief Check if parent of the current node is the last of his siblings.
2583 *
2584 * To mantain stability use this function only if the current node is the first of the siblings.
2585 * Side-effect -> current node is set to the first sibling if node has a parent otherwise no side-effect.
2586 *
2587 * @param[in] fp contains all 'tro' callback functions.
2588 * @param[in,out] tc is tree context.
2589 * @return 1 if parent is last sibling otherwise 0.
2590 */
2591static ly_bool
2592trb_parent_is_last_sibling(struct trt_fp_all fp, struct trt_tree_ctx *tc)
2593{
2594 if (fp.modify.parent(tc)) {
2595 ly_bool ret = fp.read.if_sibling_exists(tc);
2596 fp.modify.next_child(TRP_EMPTY_PARENT_CACHE, tc);
2597 return !ret;
2598 } else {
2599 return !fp.read.if_sibling_exists(tc);
2600 }
2601}
2602
2603/**
2604 * @brief Find sibling with the biggest node name and return that size.
2605 *
2606 * Side-effect -> Current node is set to the first sibling.
2607 *
2608 * @param[in] ca contains inherited data from ancestors.
2609 * @param[in] pc contains mainly functions for printing.
2610 * @param[in,out] tc is tree context.
2611 * @return positive number lesser than upper_limit as a sign that only the node name is included in the size.
2612 * @return negative number whose absolute value is less than upper_limit and sign that node name and his opt mark is included in the size.
2613 */
2614static int32_t
2615trb_maxlen_node_name(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2616{
2617 int32_t ret = 0;
2618
2619 pc->fp.modify.first_sibling(tc);
2620
2621 for (struct trt_node node = pc->fp.read.node(ca, tc);
2622 !trp_node_is_empty(node);
2623 node = pc->fp.modify.next_sibling(ca, tc)) {
2624 int32_t maxlen = trb_strlen_of_name_and_mark(node.name);
2625 ret = abs(maxlen) > abs(ret) ? maxlen : ret;
2626 }
2627 pc->fp.modify.first_sibling(tc);
2628 return ret;
2629}
2630
2631/**
2632 * @brief Find maximal indent between \<opts\> and \<type\> for siblings.
2633 *
2634 * Side-effect -> Current node is set to the first sibling.
2635 *
2636 * @param[in] ca contains inherited data from ancestors.
2637 * @param[in] pc contains mainly functions for printing.
2638 * @param[in,out] tc is tree context.
2639 * @return max btw_opts_type value for rest of the siblings
2640 */
2641static int16_t
2642trb_max_btw_opts_type4siblings(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2643{
2644 int32_t maxlen_node_name = trb_maxlen_node_name(ca, pc, tc);
2645 int16_t ind_before_type = maxlen_node_name < 0 ?
2646 TRD_INDENT_BEFORE_TYPE - 1 : /* mark was present */
2647 TRD_INDENT_BEFORE_TYPE;
2648
2649 return abs(maxlen_node_name) + ind_before_type;
2650}
2651
2652/**
2653 * @brief Find out if it is possible to unify the alignment before \<type\>.
2654 *
2655 * The goal is for all node siblings to have the same alignment for \<type\> as if they were in a column.
2656 * All siblings who cannot adapt because they do not fit on the line at all are ignored.
2657 * Side-effect -> Current node is set to the first sibling.
2658 *
2659 * @param[in] ca contains inherited data from ancestors.
2660 * @param[in] pc contains mainly functions for printing.
2661 * @param[in,out] tc is tree context.
2662 * @return 0 if all siblings cannot fit on the line.
2663 * @return positive number indicating the maximum number of spaces before \<type\> if the length of the node name is 0.
2664 * To calculate the btw_opts_type indent size for a particular node, use the trb_calc_btw_opts_type function.
2665*/
2666static uint32_t
2667trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2668{
2669 return trb_max_btw_opts_type4siblings(ca, pc, tc);
2670}
2671
2672/**
2673 * @brief For the current node: recursively print all of its child nodes and all of its siblings, including their children.
2674 *
2675 * This function is an auxiliary function for trb_print_subtree_nodes.
2676 * The parent of the current node is expected to exist.
2677 * Nodes are printed, including unified sibling node alignment (align \<type\> to column).
2678 * Side-effect -> current node is set to the last sibling.
2679 *
2680 * @param[in] wr is wrapper for printing identation before node.
2681 * @param[in] ca contains inherited data from ancestors.
2682 * @param[in] pc contains mainly functions for printing.
2683 * @param[in,out] tc is tree context.
2684 */
2685static void
2686trb_print_nodes(struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2687{
2688 uint32_t max_gap_before_type;
2689 ly_bool sibling_flag = 0;
2690 ly_bool child_flag = 0;
2691
2692 /* if node is last sibling, then do not add '|' to wrapper */
2693 wr = trb_parent_is_last_sibling(pc->fp, tc) ?
2694 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
2695
2696 /* try unified indentation in node */
2697 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
2698
2699 /* print all siblings */
2700 do {
2701 struct trt_parent_cache new_ca;
2702 struct trt_node node;
2703 /* print linebreak before printing actual node */
2704 ly_print_(pc->out, "\n");
2705 /* print node */
2706 trb_print_entire_node(max_gap_before_type, wr, ca, pc, tc);
2707
2708 new_ca = tro_parent_cache_for_child(ca, tc->pn);
2709 /* go to the actual node's child or stay in actual node */
2710 node = pc->fp.modify.next_child(ca, tc);
2711 child_flag = !trp_node_is_empty(node);
2712
2713 if (child_flag) {
2714 /* print all childs - recursive call */
2715 trb_print_nodes(wr, new_ca, pc, tc);
2716 /* get back from child node to actual node */
2717 pc->fp.modify.parent(tc);
2718 }
2719
2720 /* go to the actual node's sibling */
2721 node = pc->fp.modify.next_sibling(ca, tc);
2722 sibling_flag = !trp_node_is_empty(node);
2723
2724 /* go to the next sibling or stay in actual node */
2725 } while (sibling_flag);
2726}
2727
2728/**
2729 * @brief Print subtree of nodes.
2730 *
2731 * The current node is expected to be the root of the subtree.
2732 * Before root node is no linebreak printing. This must be addressed by the caller.
2733 * Root node will also be printed. Behind last printed node is no linebreak.
2734 *
2735 * @param[in] max_gap_before_type is result from trb_try_unified_indent function for root node. Set parameter to 0 if distance does not matter.
2736 * @param[in] wr is wrapper saying how deep in the whole tree is the root of the subtree.
2737 * @param[in] ca is parent_cache from root's parent. If root is top-level node, insert TRP_EMPTY_PARENT_CACHE.
2738 * @param[in] pc is pointer to the printer (trp) context.
2739 * @param[in,out] tc is pointer to the tree (tro) context.
2740 */
2741static void
2742trb_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)
2743{
2744 struct trt_parent_cache new_ca;
2745 struct trt_node node;
2746
2747 trb_print_entire_node(max_gap_before_type, wr, ca, pc, tc);
2748 /* go to the actual node's child */
2749 new_ca = tro_parent_cache_for_child(ca, tc->pn);
2750 node = pc->fp.modify.next_child(ca, tc);
2751
2752 if (!trp_node_is_empty(node)) {
2753 /* print root's nodes */
2754 trb_print_nodes(wr, new_ca, pc, tc);
2755 /* get back from child node to actual node */
2756 pc->fp.modify.parent(tc);
2757 }
2758}
2759
2760/**
2761 * @brief Get number of siblings.
2762 *
2763 * Side-effect -> current node is set to the first sibling.
2764 *
2765 * @param[in] fp contains callback functions which modify tree context
2766 * @param[in,out] tc is the tree context.
2767 * @return Number of siblings of the current node.
2768 */
2769static uint32_t
2770trb_get_number_of_siblings(struct trt_fp_modify_ctx fp, struct trt_tree_ctx *tc)
2771{
2772 uint32_t ret = 1;
2773 struct trt_node node = TRP_EMPTY_NODE;
2774
2775 /* including actual node */
2776 fp.first_sibling(tc);
2777 while (!trp_node_is_empty(node = fp.next_sibling(TRP_EMPTY_PARENT_CACHE, tc))) {
2778 ret++;
2779 }
2780 fp.first_sibling(tc);
2781 return ret;
2782}
2783
2784/**
2785 * @brief Print all parents and their children.
2786 *
2787 * This function is suitable for printing top-level nodes that do not have ancestors.
2788 * Function call print_subtree_nodes for all top-level siblings.
2789 * Use this function after 'module' keyword or 'augment' and so.
2790 *
2791 * @param[in] wr_t is type of the wrapper.
2792 * @param[pc] pc contains mainly functions for printing.
2793 * @param[in,out] tc is tree context.
2794 */
2795static void
2796trb_print_family_tree(trd_wrapper_type wr_t, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2797{
2798 struct trt_wrapper wr;
2799 struct trt_parent_cache ca;
2800 uint32_t total_parents;
2801 uint32_t max_gap_before_type;
2802
2803 wr = wr_t == TRD_WRAPPER_TOP ? TRP_INIT_WRAPPER_TOP : TRP_INIT_WRAPPER_BODY;
2804 ca = TRP_EMPTY_PARENT_CACHE;
2805 total_parents = trb_get_number_of_siblings(pc->fp.modify, tc);
2806 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
2807
2808 for (uint32_t i = 0; i < total_parents; i++) {
2809 ly_print_(pc->out, "\n");
2810 trb_print_subtree_nodes(max_gap_before_type, wr, ca, pc, tc);
2811 pc->fp.modify.next_sibling(ca, tc);
2812 }
2813}
2814
2815/******************************************************************************
2816 * Definition of trm main functions
2817 *****************************************************************************/
2818
2819/**
2820 * @brief General function to prevent repetitiveness code.
2821 * @param[in] ks is section representation.
2822 * @param[in] pc contains mainly functions for printing.
2823 * @param[in,out] tc is the tree context.
2824 */
2825static void
2826trm_print_body_section(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2827{
2828 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
2829 return;
2830 }
2831 trp_print_keyword_stmt(ks, pc->max_line_length, pc->out);
2832 trb_print_family_tree(TRD_WRAPPER_BODY, pc, tc);
2833}
2834
2835/**
2836 * @brief Print 'module' keyword, its name and all nodes.
2837 * @param[in] pc contains mainly functions for printing.
2838 * @param[in,out] tc is the tree context.
2839 */
2840static void
2841trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2842{
2843 trp_print_keyword_stmt(pc->fp.read.module_name(tc), pc->max_line_length, pc->out);
2844 /* check if module section contains any data */
2845 if (tc->tpn) {
2846 trb_print_family_tree(TRD_WRAPPER_TOP, pc, tc);
2847 }
2848}
2849
2850/**
2851 * @brief For all augment sections: print 'augment' keyword, its target node and all nodes.
2852 * @param[in] pc contains mainly functions for printing.
2853 * @param[in,out] tc is the tree context.
2854 */
2855static void
2856trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2857{
2858 ly_bool once = 1;
2859
2860 for (struct trt_keyword_stmt ks = pc->fp.modify.next_augment(tc);
2861 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
2862 ks = pc->fp.modify.next_augment(tc)) {
2863 if (once) {
2864 ly_print_(pc->out, "\n");
2865 ly_print_(pc->out, "\n");
2866 once = 0;
2867 } else {
2868 ly_print_(pc->out, "\n");
2869 }
2870 trm_print_body_section(ks, pc, tc);
2871 }
2872}
2873
2874/**
2875 * @brief For rpcs section: print 'rpcs' keyword and all its nodes.
2876 * @param[in] pc contains mainly functions for printing.
2877 * @param[in,out] tc is the tree context.
2878 */
2879static void
2880trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2881{
2882 struct trt_keyword_stmt rpc = pc->fp.modify.get_rpcs(tc);
2883
2884 if (!(TRP_KEYWORD_STMT_IS_EMPTY(rpc))) {
2885 ly_print_(pc->out, "\n");
2886 ly_print_(pc->out, "\n");
2887 trm_print_body_section(rpc, pc, tc);
2888 }
2889}
2890
2891/**
2892 * @brief For notifications section: print 'notifications' keyword and all its nodes.
2893 * @param[in] pc contains mainly functions for printing.
2894 * @param[in,out] tc is the tree context.
2895 */
2896static void
2897trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2898{
2899 struct trt_keyword_stmt notifs = pc->fp.modify.get_notifications(tc);
2900
2901 if (!(TRP_KEYWORD_STMT_IS_EMPTY(notifs))) {
2902 ly_print_(pc->out, "\n");
2903 ly_print_(pc->out, "\n");
2904 trm_print_body_section(notifs, pc, tc);
2905 }
2906}
2907
2908/**
2909 * @brief For all grouping sections: print 'grouping' keyword, its name and all nodes.
2910 * @param[in] pc contains mainly functions for printing.
2911 * @param[in,out] tc is the tree context.
2912 */
2913static void
2914trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2915{
2916 ly_bool once = 1;
2917
2918 for (struct trt_keyword_stmt ks = pc->fp.modify.next_grouping(tc);
2919 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
2920 ks = pc->fp.modify.next_grouping(tc)) {
2921 if (once) {
2922 ly_print_(pc->out, "\n");
2923 ly_print_(pc->out, "\n");
2924 once = 0;
2925 } else {
2926 ly_print_(pc->out, "\n");
2927 }
2928 trm_print_body_section(ks, pc, tc);
2929 }
2930}
2931
2932/**
2933 * @brief For all yang-data sections: print 'yang-data' keyword and all its nodes.
2934 * @param[in] pc contains mainly functions for printing.
2935 * @param[in,out] tc is the tree context.
2936 */
2937static void
2938trm_print_yang_data(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2939{
2940 ly_bool once = 1;
2941
2942 for (struct trt_keyword_stmt ks = pc->fp.modify.next_yang_data(tc);
2943 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
2944 ks = pc->fp.modify.next_yang_data(tc)) {
2945 if (once) {
2946 ly_print_(pc->out, "\n");
2947 ly_print_(pc->out, "\n");
2948 once = 0;
2949 } else {
2950 ly_print_(pc->out, "\n");
2951 }
2952 trm_print_body_section(ks, pc, tc);
2953 }
2954}
2955
2956/**
2957 * @brief Print sections module, augment, rpcs, notifications, grouping, yang-data.
2958 * @param[in] pc contains mainly functions for printing.
2959 * @param[in,out] tc is the tree context.
2960 */
2961static void
2962trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
2963{
2964 trm_print_module_section(pc, tc);
2965
2966 trm_print_augmentations(pc, tc);
2967
2968 trm_print_rpcs(pc, tc);
2969
2970 trm_print_notifications(pc, tc);
2971
2972 trm_print_groupings(pc, tc);
2973
2974 trm_print_yang_data(pc, tc);
2975
2976 ly_print_(pc->out, "\n");
2977}
2978
2979/**
2980 * @brief Set default settings for trt_printer_ctx.
2981 *
2982 * Fill trt_printer_ctx so that it will contain all items correctly defined
2983 * except for max_line_length which is parameters of the printer tree module.
2984 *
2985 * @param[in] out is output handler.
2986 * @param[in] max_line_length is the maximum line length limit that should not be exceeded.
2987 * @param[in,out] ctx fill structure with default values.
2988 */
2989static void
2990trm_default_printer_ctx(struct ly_out *out, size_t max_line_length, struct trt_printer_ctx *ctx)
2991{
2992 ctx->out = out;
2993
2994 ctx->fp.modify = (struct trt_fp_modify_ctx) {
2995 .parent = tro_modi_parent,
2996 .first_sibling = tro_modi_first_sibling,
2997 .next_sibling = tro_modi_next_sibling,
2998 .next_child = tro_modi_next_child,
2999 .next_augment = tro_modi_next_augment,
3000 .get_rpcs = tro_modi_get_rpcs,
3001 .get_notifications = tro_modi_get_notifications,
3002 .next_grouping = tro_modi_next_grouping,
3003 .next_yang_data = tro_modi_next_yang_data
3004 };
3005
3006 ctx->fp.read = (struct trt_fp_read) {
3007 .module_name = tro_read_module_name,
3008 .node = tro_read_node,
3009 .if_sibling_exists = tro_read_if_sibling_exists
3010 };
3011
3012 ctx->fp.print = (struct trt_fp_print) {
3013 .print_features_names = tro_print_features_names,
3014 .print_keys = tro_print_keys
3015 };
3016
3017 ctx->max_line_length = max_line_length;
3018}
3019
3020/**
3021 * @brief Set default settings for trt_tree_ctx.
3022 *
3023 * Pointers to current nodes will be set to module data.
3024 *
3025 * @param[in] module is pointer to the YANG schema tree structures representing YANG module.
3026 * @param[in,out] tc fill structure with default values.
3027 */
3028static void
3029trm_default_tree_ctx(const struct lys_module *module, struct trt_tree_ctx *tc)
3030{
3031 tc->section = TRD_SECT_MODULE;
3032 tc->module = module;
3033 tc->pn = module->parsed->data;
3034 tc->tpn = module->parsed->data;
3035}
3036
3037/******************************************************************************
3038 * Definition of module interface
3039 *****************************************************************************/
3040
3041LY_ERR
3042tree_print_parsed_module(struct ly_out *out, const struct lys_module *module, uint32_t UNUSED(options), size_t line_length)
3043{
3044 struct trt_printer_ctx pc;
3045 struct trt_tree_ctx tc;
3046 struct ly_out *new_out;
3047 LY_ERR erc;
3048 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
3049
3050 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
3051 return erc;
3052 }
3053
3054 line_length = line_length == 0 ? SIZE_MAX : line_length;
3055 trm_default_printer_ctx(new_out, line_length, &pc);
3056 trm_default_tree_ctx(module, &tc);
3057
3058 trm_print_sections(&pc, &tc);
3059
3060 ly_out_free(new_out, NULL, 1);
3061
3062 return clb_arg.last_error;
3063}
3064
3065LY_ERR
3066tree_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))
3067// 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)
3068{
3069 /** Not implemented right now. */
3070 return LY_SUCCESS;
3071}
3072
3073LY_ERR
3074tree_print_compiled_node(struct ly_out *UNUSED(out), const struct lysc_node *UNUSED(node), uint32_t UNUSED(options), size_t UNUSED(line_length))
3075// LY_ERR tree_print_compiled_node(struct ly_out *out, const struct lysc_node *node, uint32_t options, size_t line_length)
3076{
3077 /** Not implemented right now. */
3078 return LY_SUCCESS;
3079}