blob: 47a791439ee5f019e4becc54797aa4f67f87b3b9 [file] [log] [blame]
aPiecek61d062b2020-11-02 11:05:09 +01001/**
2 * @file printer_tree.c
3 * @author Adam Piecek <piecek@cesnet.cz>
4 * @brief RFC tree printer for libyang data structure
5 *
6 * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
aPiecek874ea4d2021-04-19 12:26:36 +020013 *
14 * @section TRP_DESIGN Design
15 *
16 * @code
aPiecek61d062b2020-11-02 11:05:09 +010017 * +---------+ +---------+ +---------+
18 * output | trp | | trb | | tro |
19 * <---+ Print +<---+ Browse +<-->+ Obtain |
20 * | | | | | |
21 * +---------+ +----+----+ +---------+
22 * ^
23 * |
24 * +----+----+
25 * | trm |
26 * | Manager |
27 * | |
28 * +----+----+
29 * ^
30 * | input
31 * +
aPiecek874ea4d2021-04-19 12:26:36 +020032 * @endcode
aPiecek61d062b2020-11-02 11:05:09 +010033 *
aPiecek874ea4d2021-04-19 12:26:36 +020034 * @subsection TRP_GLOSSARY Glossary
aPiecek61d062b2020-11-02 11:05:09 +010035 *
aPiecek874ea4d2021-04-19 12:26:36 +020036 * @subsubsection TRP_trm trm
37 * Manager functions are at the peak of abstraction. They are
38 * able to print individual sections of the YANG tree diagram
39 * (eg module, notifications, rpcs ...) and they call
aPiecek01598c02021-04-23 14:18:24 +020040 * Browse functions (@ref TRP_trb).
aPiecek61d062b2020-11-02 11:05:09 +010041 *
aPiecek874ea4d2021-04-19 12:26:36 +020042 * @subsubsection TRP_trb trb
43 * Browse functions contain a general algorithm (Preorder DFS)
44 * for traversing the tree. It does not matter what data type
aPiecek01598c02021-04-23 14:18:24 +020045 * the tree contains (@ref lysc_node or @ref lysp_node), because it
aPiecek874ea4d2021-04-19 12:26:36 +020046 * requires a ready-made getter functions for traversing the tree
aPiecek01598c02021-04-23 14:18:24 +020047 * (@ref trt_fp_all) and transformation function to its own node
48 * data type (@ref trt_node). These getter functions are generally
49 * referred to as @ref TRP_tro. Browse functions can repeatedly
aPiecek874ea4d2021-04-19 12:26:36 +020050 * traverse nodes in the tree, for example, to calculate the alignment
51 * gap before the nodes \<type\> in the YANG Tree Diagram.
aPiecek01598c02021-04-23 14:18:24 +020052 * The obtained @ref trt_node is passed to the @ref TRP_trp functions
aPiecek874ea4d2021-04-19 12:26:36 +020053 * to print the Tree diagram.
54 *
55 * @subsubsection TRP_tro tro
56 * Functions that provide an extra wrapper for the libyang library.
aPiecekef1e58e2021-04-19 13:19:44 +020057 * The Obtain functions are further specialized according to whether
aPiecek01598c02021-04-23 14:18:24 +020058 * they operate on lysp_tree (@ref TRP_trop) or lysc_tree
59 * (@ref TRP_troc). If they are general algorithms, then they have the
aPiecek3f247652021-04-19 13:40:25 +020060 * prefix \b tro_. The Obtain functions provide information to
aPiecek01598c02021-04-23 14:18:24 +020061 * @ref TRP_trb functions for printing the Tree diagram.
aPiecekef1e58e2021-04-19 13:19:44 +020062 *
63 * @subsubsection TRP_trop trop
64 * Functions for Obtaining information from Parsed schema tree.
aPiecek874ea4d2021-04-19 12:26:36 +020065 *
aPiecek3f247652021-04-19 13:40:25 +020066 * @subsubsection TRP_troc troc
67 * Functions for Obtaining information from Compiled schema tree.
68 *
aPiecek874ea4d2021-04-19 12:26:36 +020069 * @subsubsection TRP_trp trp
70 * Print functions take care of the printing YANG diagram. They can
71 * also split one node into multiple lines if the node does not fit
72 * on one line.
73 *
aPiecek8f1073c2022-10-17 16:44:49 +020074 * @subsubsection TRP_trocm trocm
75 * Functions for Obtaining information from mounted shared schema (RFC 8528).
76 * Parent-references can be used to specify which nodes are accessible from the mounted module.
77 * These accessible nodes are printed including their parent nodes.
78 * Functions marked as 'trocm' operate on the Compiled schema tree.
79 *
80 *
aPiecek874ea4d2021-04-19 12:26:36 +020081 * @subsubsection TRP_trt trt
82 * Data type marking in the printer_tree module.
83 *
84 * @subsubsection TRP_trg trg
85 * General functions.
86 *
87 * @subsection TRP_ADJUSTMENTS Adjustments
88 * It is assumed that the changes are likely to take place mainly for
aPiecek01598c02021-04-23 14:18:24 +020089 * @ref TRP_tro, @ref TRP_trop or @ref TRP_troc functions because
aPiecek3f247652021-04-19 13:40:25 +020090 * they are the only ones dependent on libyang implementation.
91 * In special cases, changes will also need to be made to the
aPiecek01598c02021-04-23 14:18:24 +020092 * @ref TRP_trp functions if a special algorithm is needed to print
aPiecek3f247652021-04-19 13:40:25 +020093 * (right now this is prepared for printing list's keys
94 * and if-features).
aPiecek61d062b2020-11-02 11:05:09 +010095 */
96
aPiecek874ea4d2021-04-19 12:26:36 +020097#include <assert.h>
98#include <string.h>
99
100#include "common.h"
101#include "compat.h"
102#include "out_internal.h"
ekinzie0ab8b302022-10-10 03:03:57 -0400103#include "plugins_exts.h"
104#include "plugins_types.h"
aPiecek704f8e92021-08-25 13:35:05 +0200105#include "printer_schema.h"
aPiecek874ea4d2021-04-19 12:26:36 +0200106#include "tree_schema_internal.h"
107#include "xpath.h"
108
aPiecek61d062b2020-11-02 11:05:09 +0100109/**
110 * @brief List of available actions.
111 */
112typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200113 TRD_PRINT = 0, /**< Normal behavior. It just prints. */
114 TRD_CHAR_COUNT /**< Characters will be counted instead of printing. */
aPiecek61d062b2020-11-02 11:05:09 +0100115} trt_ly_out_clb_arg_flag;
116
117/**
aPiecek874ea4d2021-04-19 12:26:36 +0200118 * @brief Structure is passed as 'writeclb' argument
aPiecek01598c02021-04-23 14:18:24 +0200119 * to the ::ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100120 */
121struct ly_out_clb_arg {
aPiecek874ea4d2021-04-19 12:26:36 +0200122 trt_ly_out_clb_arg_flag mode; /**< flag specifying which action to take. */
123 struct ly_out *out; /**< The ly_out pointer delivered to the printer tree module via the main interface. */
124 size_t counter; /**< Counter of printed characters. */
125 LY_ERR last_error; /**< The last error that occurred. If no error has occurred, it will be ::LY_SUCCESS. */
aPiecek61d062b2020-11-02 11:05:09 +0100126};
127
128/**
129 * @brief Initialize struct ly_out_clb_arg with default settings.
130 */
131#define TRP_INIT_LY_OUT_CLB_ARG(MODE, OUT, COUNTER, LAST_ERROR) \
aPiecek874ea4d2021-04-19 12:26:36 +0200132 (struct ly_out_clb_arg) { \
133 .mode = MODE, .out = OUT, \
134 .counter = COUNTER, .last_error = LAST_ERROR \
135 }
aPiecek61d062b2020-11-02 11:05:09 +0100136
aPiecek874ea4d2021-04-19 12:26:36 +0200137/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100138 * Print getters
aPiecek874ea4d2021-04-19 12:26:36 +0200139 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100140
141/**
142 * @brief Callback functions that prints special cases.
143 *
144 * It just groups together tree context with trt_fp_print.
145 */
146struct trt_cf_print {
aPiecek874ea4d2021-04-19 12:26:36 +0200147 const struct trt_tree_ctx *ctx; /**< Context of libyang tree. */
Michal Vasko26bbb272022-08-02 14:54:33 +0200148
aPiecek874ea4d2021-04-19 12:26:36 +0200149 void (*pf)(const struct trt_tree_ctx *, struct ly_out *); /**< Pointing to function which printing list's keys or features. */
aPiecek61d062b2020-11-02 11:05:09 +0100150};
151
152/**
153 * @brief Callback functions for printing special cases.
154 *
aPiecek874ea4d2021-04-19 12:26:36 +0200155 * Functions with the suffix 'trp' can print most of the text on
156 * output, just by setting the pointer to the string. But in some
157 * cases, it's not that simple, because its entire string is fragmented
158 * in memory. For example, for printing list's keys or if-features.
aPiecek61d062b2020-11-02 11:05:09 +0100159 * However, this depends on how the libyang library is implemented.
aPiecek3f247652021-04-19 13:40:25 +0200160 * This implementation of the printer_tree module goes through
161 * a lysp tree, but if it goes through a lysc tree, these special cases
162 * would be different.
aPiecek61d062b2020-11-02 11:05:09 +0100163 * Functions must print including spaces or delimiters between names.
164 */
165struct trt_fp_print {
166 void (*print_features_names)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list of features without {}? wrapper. */
167 void (*print_keys)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list's keys without [] wrapper. */
168};
169
170/**
171 * @brief Package which only groups getter function.
172 */
173struct trt_pck_print {
174 const struct trt_tree_ctx *tree_ctx; /**< Context of libyang tree. */
175 struct trt_fp_print fps; /**< Print function. */
176};
177
178/**
179 * @brief Initialize struct trt_pck_print by parameters.
180 */
181#define TRP_INIT_PCK_PRINT(TREE_CTX, FP_PRINT) \
aPiecek874ea4d2021-04-19 12:26:36 +0200182 (struct trt_pck_print) {.tree_ctx = TREE_CTX, .fps = FP_PRINT}
aPiecek61d062b2020-11-02 11:05:09 +0100183
aPiecek874ea4d2021-04-19 12:26:36 +0200184/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100185 * Indent
aPiecek874ea4d2021-04-19 12:26:36 +0200186 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100187
188/**
aPiecek874ea4d2021-04-19 12:26:36 +0200189 * @brief Constants which are defined in the RFC or are observable
190 * from the pyang tool.
aPiecek61d062b2020-11-02 11:05:09 +0100191 */
192typedef enum {
193 TRD_INDENT_EMPTY = 0, /**< If the node is a case node, there is no space before the \<name\>. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100194 TRD_INDENT_LONG_LINE_BREAK = 2, /**< The new line should be indented so that it starts below \<name\> with
195 a whitespace offset of at least two characters. */
196 TRD_INDENT_LINE_BEGIN = 2, /**< Indent below the keyword (module, augment ...). */
197 TRD_INDENT_BTW_SIBLINGS = 2, /**< Indent between | and | characters. */
198 TRD_INDENT_BEFORE_KEYS = 1, /**< "..."___\<keys\>. */
199 TRD_INDENT_BEFORE_TYPE = 4, /**< "..."___\<type\>, but if mark is set then indent == 3. */
aPiecek61d062b2020-11-02 11:05:09 +0100200 TRD_INDENT_BEFORE_IFFEATURES = 1 /**< "..."___\<iffeatures\>. */
201} trt_cnf_indent;
202
203/**
204 * @brief Type of indent in node.
205 */
206typedef enum {
207 TRD_INDENT_IN_NODE_NORMAL = 0, /**< Node fits on one line. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100208 TRD_INDENT_IN_NODE_DIVIDED, /**< The node must be split into multiple rows. */
aPiecek61d062b2020-11-02 11:05:09 +0100209 TRD_INDENT_IN_NODE_FAILED /**< Cannot be crammed into one line. The condition for the maximum line length is violated. */
210} trt_indent_in_node_type;
211
212/** Constant to indicate the need to break a line. */
213#define TRD_LINEBREAK -1
214
215/**
aPiecek874ea4d2021-04-19 12:26:36 +0200216 * @brief Records the alignment between the individual
217 * elements of the node.
aPiecek61d062b2020-11-02 11:05:09 +0100218 *
aPiecek874ea4d2021-04-19 12:26:36 +0200219 * @see trp_default_indent_in_node, trp_try_normal_indent_in_node
aPiecek61d062b2020-11-02 11:05:09 +0100220 */
221struct trt_indent_in_node {
222 trt_indent_in_node_type type; /**< Type of indent in node. */
aPiecek874ea4d2021-04-19 12:26:36 +0200223 int16_t btw_name_opts; /**< Indent between node name and \<opts\>. */
224 int16_t btw_opts_type; /**< Indent between \<opts\> and \<type\>. */
aPiecek61d062b2020-11-02 11:05:09 +0100225 int16_t btw_type_iffeatures; /**< Indent between type and features. Ignored if \<type\> missing. */
226};
227
228/**
229 * @brief Type of wrappers to be printed.
230 */
231typedef enum {
232 TRD_WRAPPER_TOP = 0, /**< Related to the module. */
233 TRD_WRAPPER_BODY /**< Related to e.g. Augmentations or Groupings */
234} trd_wrapper_type;
235
236/**
237 * @brief For resolving sibling symbol ('|') placement.
238 *
239 * Bit indicates where the sibling symbol must be printed.
aPiecek874ea4d2021-04-19 12:26:36 +0200240 * This place is in multiples of ::TRD_INDENT_BTW_SIBLINGS.
aPiecek61d062b2020-11-02 11:05:09 +0100241 *
aPiecek874ea4d2021-04-19 12:26:36 +0200242 * @see TRP_INIT_WRAPPER_TOP, TRP_INIT_WRAPPER_BODY,
243 * trp_wrapper_set_mark, trp_wrapper_set_shift,
244 * trp_wrapper_if_last_sibling, trp_wrapper_eq, trp_print_wrapper
aPiecek61d062b2020-11-02 11:05:09 +0100245 */
246struct trt_wrapper {
247 trd_wrapper_type type; /**< Location of the wrapper. */
248 uint64_t bit_marks1; /**< The set bits indicate where the '|' character is to be printed.
249 It follows that the maximum immersion of the printable node is 64. */
250 uint32_t actual_pos; /**< Actual position in bit_marks. */
251};
252
253/**
254 * @brief Get wrapper related to the module section.
255 *
256 * @code
257 * module: <module-name>
258 * +--<node>
259 * |
260 * @endcode
261 */
262#define TRP_INIT_WRAPPER_TOP \
aPiecek874ea4d2021-04-19 12:26:36 +0200263 (struct trt_wrapper) { \
264 .type = TRD_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0 \
265 }
aPiecek61d062b2020-11-02 11:05:09 +0100266
267/**
aPiecek874ea4d2021-04-19 12:26:36 +0200268 * @brief Get wrapper related to subsection
269 * e.g. Augmenations or Groupings.
aPiecek61d062b2020-11-02 11:05:09 +0100270 *
271 * @code
272 * module: <module-name>
273 * +--<node>
274 *
275 * augment <target-node>:
276 * +--<node>
277 * @endcode
278 */
279#define TRP_INIT_WRAPPER_BODY \
aPiecek874ea4d2021-04-19 12:26:36 +0200280 (struct trt_wrapper) { \
281 .type = TRD_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0 \
282 }
aPiecek61d062b2020-11-02 11:05:09 +0100283
284/**
285 * @brief Package which only groups wrapper and indent in node.
286 */
287struct trt_pck_indent {
288 struct trt_wrapper wrapper; /**< Coded " | | " sequence. */
289 struct trt_indent_in_node in_node; /**< Indent in node. */
290};
291
292/**
293 * @brief Initialize struct trt_pck_indent by parameters.
294 */
295#define TRP_INIT_PCK_INDENT(WRAPPER, INDENT_IN_NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200296 (struct trt_pck_indent){ \
297 .wrapper = WRAPPER, .in_node = INDENT_IN_NODE \
298 }
aPiecek61d062b2020-11-02 11:05:09 +0100299
aPiecek874ea4d2021-04-19 12:26:36 +0200300/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100301 * flags
aPiecek874ea4d2021-04-19 12:26:36 +0200302 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100303
aPiecek41219f92022-10-26 11:24:40 +0200304#define TRD_FLAGS_TYPE_EMPTY "--"
305#define TRD_FLAGS_TYPE_RW "rw"
306#define TRD_FLAGS_TYPE_RO "ro"
307#define TRD_FLAGS_TYPE_RPC_INPUT_PARAMS "-w"
308#define TRD_FLAGS_TYPE_USES_OF_GROUPING "-u"
309#define TRD_FLAGS_TYPE_RPC "-x"
310#define TRD_FLAGS_TYPE_NOTIF "-n"
311#define TRD_FLAGS_TYPE_MOUNT_POINT "mp"
aPiecek61d062b2020-11-02 11:05:09 +0100312
aPiecek874ea4d2021-04-19 12:26:36 +0200313/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100314 * node_name and opts
aPiecek874ea4d2021-04-19 12:26:36 +0200315 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100316
317#define TRD_NODE_NAME_PREFIX_CHOICE "("
318#define TRD_NODE_NAME_PREFIX_CASE ":("
319#define TRD_NODE_NAME_TRIPLE_DOT "..."
320
321/**
322 * @brief Type of the node.
323 *
aPiecek874ea4d2021-04-19 12:26:36 +0200324 * Used mainly to complete the correct \<opts\> next to or
325 * around the \<name\>.
aPiecek61d062b2020-11-02 11:05:09 +0100326 */
327typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200328 TRD_NODE_ELSE = 0, /**< For some node which does not require special treatment. \<name\> */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100329 TRD_NODE_CASE, /**< For case node. :(\<name\>) */
330 TRD_NODE_CHOICE, /**< For choice node. (\<name\>) */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100331 TRD_NODE_TOP_LEVEL1, /**< For a top-level data node in a mounted module. \<name\>/ */
332 TRD_NODE_TOP_LEVEL2, /**< For a top-level data node of a module identified in a mount point parent reference. \<name\>@ */
aPiecek874ea4d2021-04-19 12:26:36 +0200333 TRD_NODE_TRIPLE_DOT /**< For collapsed sibling nodes and their children. Special case which doesn't belong here very well. */
aPiecek61d062b2020-11-02 11:05:09 +0100334} trt_node_type;
335
aPiecek41219f92022-10-26 11:24:40 +0200336#define TRD_NODE_OPTIONAL "?" /**< For an optional leaf, anydata, or anyxml. \<name\>? */
337#define TRD_NODE_CONTAINER "!" /**< For a presence container. \<name\>! */
338#define TRD_NODE_LISTLEAFLIST "*" /**< For a leaf-list or list. \<name\>* */
339
aPiecek61d062b2020-11-02 11:05:09 +0100340/**
341 * @brief Type of node and his name.
342 *
aPiecek874ea4d2021-04-19 12:26:36 +0200343 * @see TRP_EMPTY_NODE_NAME, TRP_NODE_NAME_IS_EMPTY,
aPiecek61d062b2020-11-02 11:05:09 +0100344 * trp_print_node_name, trp_mark_is_used, trp_print_opts_keys
345 */
346struct trt_node_name {
347 trt_node_type type; /**< Type of the node relevant for printing. */
aPiecekbca57772022-10-13 13:51:59 +0200348 ly_bool keys; /**< Set to 1 if [\<keys\>] are to be printed. Valid for some types only. */
aPiecek34fa3772021-05-21 12:35:46 +0200349 const char *module_prefix; /**< If the node is augmented into the tree from another module,
350 so this is the prefix of that module. */
aPiecek61d062b2020-11-02 11:05:09 +0100351 const char *str; /**< Name of the node. */
aPiecek41219f92022-10-26 11:24:40 +0200352 char *opts;
aPiecek61d062b2020-11-02 11:05:09 +0100353};
354
355/**
356 * @brief Create struct trt_node_name as empty.
357 */
358#define TRP_EMPTY_NODE_NAME \
aPiecek874ea4d2021-04-19 12:26:36 +0200359 (struct trt_node_name) { \
aPiecek41219f92022-10-26 11:24:40 +0200360 .type = TRD_NODE_ELSE, .keys = 0, .module_prefix = NULL, .str = NULL, .opts = NULL \
aPiecek874ea4d2021-04-19 12:26:36 +0200361 }
aPiecek61d062b2020-11-02 11:05:09 +0100362
363/**
364 * @brief Check if struct trt_node_name is empty.
365 */
366#define TRP_NODE_NAME_IS_EMPTY(NODE_NAME) \
367 !NODE_NAME.str
368
aPiecek874ea4d2021-04-19 12:26:36 +0200369/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100370 * type
aPiecek874ea4d2021-04-19 12:26:36 +0200371 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100372
373/**
374 * @brief Type of the \<type\>
375 */
376typedef enum {
377 TRD_TYPE_NAME = 0, /**< Type is just a name that does not require special treatment. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100378 TRD_TYPE_TARGET, /**< Should have a form "-> TARGET", where TARGET is the leafref path. */
379 TRD_TYPE_LEAFREF, /**< This type is set automatically by the 'trp' algorithm.
aPiecek874ea4d2021-04-19 12:26:36 +0200380 So set type as ::TRD_TYPE_TARGET. */
aPiecek61d062b2020-11-02 11:05:09 +0100381 TRD_TYPE_EMPTY /**< Type is not used at all. */
382} trt_type_type;
383
384/**
385 * @brief \<type\> in the \<node\>.
386 *
aPiecek874ea4d2021-04-19 12:26:36 +0200387 * @see TRP_EMPTY_TRT_TYPE, TRP_TRT_TYPE_IS_EMPTY, trp_print_type
aPiecek61d062b2020-11-02 11:05:09 +0100388 */
389struct trt_type {
390 trt_type_type type; /**< Type of the \<type\>. */
391 const char *str; /**< Path or name of the type. */
392};
393
394/**
395 * @brief Create empty struct trt_type.
396 */
397#define TRP_EMPTY_TRT_TYPE \
398 (struct trt_type) {.type = TRD_TYPE_EMPTY, .str = NULL}
399
400/**
401 * @brief Check if struct trt_type is empty.
402 */
403#define TRP_TRT_TYPE_IS_EMPTY(TYPE_OF_TYPE) \
404 TYPE_OF_TYPE.type == TRD_TYPE_EMPTY
405
406/**
407 * @brief Initialize struct trt_type by parameters.
408 */
409#define TRP_INIT_TRT_TYPE(TYPE_OF_TYPE, STRING) \
410 (struct trt_type) {.type = TYPE_OF_TYPE, .str = STRING}
411
aPiecek41219f92022-10-26 11:24:40 +0200412typedef enum {
413 TRD_IFF_NON_PRESENT = 0,
414 TRD_IFF_PRESENT /**< iffeatures are present and will be printed by
415 trt_fp_print.print_features_names callback */
416} trt_iffeatures_type;
417
418struct trt_iffeatures {
419 trt_iffeatures_type type;
420};
421
422#define TRP_EMPTY_TRT_IFFEATURES \
423 (struct trt_iffeatures) {.type = TRD_IFF_NON_PRESENT}
424
425#define TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(IFF_TYPE) \
426 (IFF_TYPE == TRD_IFF_NON_PRESENT)
427
aPiecek874ea4d2021-04-19 12:26:36 +0200428/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100429 * node
aPiecek874ea4d2021-04-19 12:26:36 +0200430 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100431
432/**
433 * @brief \<node\> data for printing.
434 *
aPiecek874ea4d2021-04-19 12:26:36 +0200435 * It contains RFC's:
436 * \<status\>--\<flags\> \<name\>\<opts\> \<type\> \<if-features\>.
aPiecek61d062b2020-11-02 11:05:09 +0100437 * Item \<opts\> is moved to part struct trt_node_name.
aPiecek874ea4d2021-04-19 12:26:36 +0200438 * For printing [\<keys\>] and if-features is required special
439 * functions which prints them.
aPiecek61d062b2020-11-02 11:05:09 +0100440 *
aPiecek874ea4d2021-04-19 12:26:36 +0200441 * @see TRP_EMPTY_NODE, trp_node_is_empty, trp_node_body_is_empty,
442 * trp_print_node_up_to_name, trp_print_divided_node_up_to_name,
443 * trp_print_node
aPiecek61d062b2020-11-02 11:05:09 +0100444 */
445struct trt_node {
aPiecek41219f92022-10-26 11:24:40 +0200446 char *status; /**< \<status\>. */
447 char *flags; /**< \<flags\>. */
aPiecek7ed8d032022-10-10 12:32:27 +0200448 struct trt_node_name name; /**< \<node\> with \<opts\> mark or [\<keys\>]. */
449 struct trt_type type; /**< \<type\> contains the name of the type or type for leafref. */
aPiecek41219f92022-10-26 11:24:40 +0200450 struct trt_iffeatures iffeatures; /**< \<if-features\>. */
aPiecek7ed8d032022-10-10 12:32:27 +0200451 ly_bool last_one; /**< Information about whether the node is the last. */
452 struct lysc_ext_instance *mount; /**< Mount-point extension if flags == TRD_FLAGS_TYPE_MOUNT_POINT */
aPiecek61d062b2020-11-02 11:05:09 +0100453};
454
455/**
456 * @brief Create struct trt_node as empty.
457 */
458#define TRP_EMPTY_NODE \
aPiecek874ea4d2021-04-19 12:26:36 +0200459 (struct trt_node) { \
aPiecek41219f92022-10-26 11:24:40 +0200460 .status = NULL, \
461 .flags = NULL, \
aPiecek874ea4d2021-04-19 12:26:36 +0200462 .name = TRP_EMPTY_NODE_NAME, \
463 .type = TRP_EMPTY_TRT_TYPE, \
aPiecek41219f92022-10-26 11:24:40 +0200464 .iffeatures = TRP_EMPTY_TRT_IFFEATURES, \
ekinzie0ab8b302022-10-10 03:03:57 -0400465 .last_one = 1, \
466 .mount = NULL \
aPiecek874ea4d2021-04-19 12:26:36 +0200467 }
aPiecek61d062b2020-11-02 11:05:09 +0100468
469/**
470 * @brief Package which only groups indent and node.
471 */
472struct trt_pair_indent_node {
473 struct trt_indent_in_node indent;
474 struct trt_node node;
475};
476
477/**
478 * @brief Initialize struct trt_pair_indent_node by parameters.
479 */
480#define TRP_INIT_PAIR_INDENT_NODE(INDENT_IN_NODE, NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200481 (struct trt_pair_indent_node) { \
482 .indent = INDENT_IN_NODE, .node = NODE \
483 }
aPiecek61d062b2020-11-02 11:05:09 +0100484
aPiecek874ea4d2021-04-19 12:26:36 +0200485/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100486 * statement
aPiecek874ea4d2021-04-19 12:26:36 +0200487 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100488
489#define TRD_TOP_KEYWORD_MODULE "module"
490#define TRD_TOP_KEYWORD_SUBMODULE "submodule"
491
492#define TRD_BODY_KEYWORD_AUGMENT "augment"
493#define TRD_BODY_KEYWORD_RPC "rpcs"
494#define TRD_BODY_KEYWORD_NOTIF "notifications"
495#define TRD_BODY_KEYWORD_GROUPING "grouping"
496#define TRD_BODY_KEYWORD_YANG_DATA "yang-data"
497
498/**
499 * @brief Type of the trt_keyword.
500 */
501typedef enum {
502 TRD_KEYWORD_EMPTY = 0,
Michal Vasko6a914fb2022-01-17 10:36:14 +0100503 TRD_KEYWORD_MODULE,
504 TRD_KEYWORD_SUBMODULE,
505 TRD_KEYWORD_AUGMENT,
506 TRD_KEYWORD_RPC,
507 TRD_KEYWORD_NOTIF,
508 TRD_KEYWORD_GROUPING,
aPiecek61d062b2020-11-02 11:05:09 +0100509 TRD_KEYWORD_YANG_DATA
510} trt_keyword_type;
511
512/**
513 * @brief Main sign of the tree nodes.
514 *
aPiecek874ea4d2021-04-19 12:26:36 +0200515 * @see TRP_EMPTY_KEYWORD_STMT, TRP_KEYWORD_STMT_IS_EMPTY
aPiecek61d062b2020-11-02 11:05:09 +0100516 * trt_print_keyword_stmt_begin, trt_print_keyword_stmt_str,
517 * trt_print_keyword_stmt_end, trp_print_keyword_stmt
518 * trp_keyword_type_strlen
519 *
520 */
521struct trt_keyword_stmt {
aPiecek874ea4d2021-04-19 12:26:36 +0200522 trt_keyword_type type; /**< String containing some of the top or body keyword. */
523 const char *str; /**< Name or path, it determines the type. */
aPiecek61d062b2020-11-02 11:05:09 +0100524};
525
526/**
527 * @brief Create struct trt_keyword_stmt as empty.
528 */
529#define TRP_EMPTY_KEYWORD_STMT \
530 (struct trt_keyword_stmt) {.type = TRD_KEYWORD_EMPTY, .str = NULL}
531
532/**
533 * @brief Check if struct trt_keyword_stmt is empty.
534 */
535#define TRP_KEYWORD_STMT_IS_EMPTY(KEYWORD_TYPE) \
536 KEYWORD_TYPE.type == TRD_KEYWORD_EMPTY
537
538/**
539 * @brief Initialize struct trt_keyword_stmt by parameters.
540 */
541#define TRP_INIT_KEYWORD_STMT(KEYWORD_TYPE, STRING) \
542 (struct trt_keyword_stmt) {.type = KEYWORD_TYPE, .str = STRING}
543
aPiecek874ea4d2021-04-19 12:26:36 +0200544/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100545 * Modify getters
aPiecek874ea4d2021-04-19 12:26:36 +0200546 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100547
548struct trt_parent_cache;
549
550/**
551 * @brief Functions that change the state of the tree_ctx structure.
552 *
aPiecek3f247652021-04-19 13:40:25 +0200553 * The 'trop' or 'troc' functions are set here, which provide data
aPiecek874ea4d2021-04-19 12:26:36 +0200554 * for the 'trp' printing functions and are also called from the
555 * 'trb' browsing functions when walking through a tree. These callback
556 * functions need to be checked or reformulated if changes to the
557 * libyang library affect the printing tree. For all, if the value
558 * cannot be returned, its empty version obtained by relevant TRP_EMPTY
559 * macro is returned.
aPiecek61d062b2020-11-02 11:05:09 +0100560 */
561struct trt_fp_modify_ctx {
562 ly_bool (*parent)(struct trt_tree_ctx *); /**< Jump to parent node. Return true if parent exists. */
563 void (*first_sibling)(struct trt_tree_ctx *); /**< Jump on the first of the siblings. */
564 struct trt_node (*next_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to next sibling of the current node. */
565 struct trt_node (*next_child)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to the child of the current node. */
aPiecek61d062b2020-11-02 11:05:09 +0100566};
567
aPiecek874ea4d2021-04-19 12:26:36 +0200568/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100569 * Read getters
aPiecek874ea4d2021-04-19 12:26:36 +0200570 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100571
572/**
573 * @brief Functions that do not change the state of the tree_structure.
574 *
575 * For details see trt_fp_modify_ctx.
576 */
577struct trt_fp_read {
aPiecek874ea4d2021-04-19 12:26:36 +0200578 struct trt_keyword_stmt (*module_name)(const struct trt_tree_ctx *); /**< Get name of the module. */
579 struct trt_node (*node)(struct trt_parent_cache, const struct trt_tree_ctx *); /**< Get current node. */
580 ly_bool (*if_sibling_exists)(const struct trt_tree_ctx *); /**< Check if node's sibling exists. */
aPiecek61d062b2020-11-02 11:05:09 +0100581};
582
aPiecek874ea4d2021-04-19 12:26:36 +0200583/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100584 * All getters
aPiecek874ea4d2021-04-19 12:26:36 +0200585 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100586
587/**
aPiecek874ea4d2021-04-19 12:26:36 +0200588 * @brief A set of all necessary functions that must be provided
589 * for the printer.
aPiecek61d062b2020-11-02 11:05:09 +0100590 */
591struct trt_fp_all {
592 struct trt_fp_modify_ctx modify; /**< Function pointers which modify state of trt_tree_ctx. */
593 struct trt_fp_read read; /**< Function pointers which only reads state of trt_tree_ctx. */
594 struct trt_fp_print print; /**< Functions pointers for printing special items in node. */
595};
596
aPiecek874ea4d2021-04-19 12:26:36 +0200597/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100598 * Printer context
aPiecek874ea4d2021-04-19 12:26:36 +0200599 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100600
601/**
aPiecek01598c02021-04-23 14:18:24 +0200602 * @brief Main structure for @ref TRP_trp part.
aPiecek61d062b2020-11-02 11:05:09 +0100603 */
604struct trt_printer_ctx {
605 struct ly_out *out; /**< Handler to printing. */
aPiecek01598c02021-04-23 14:18:24 +0200606 struct trt_fp_all fp; /**< @ref TRP_tro functions callbacks. */
aPiecek61d062b2020-11-02 11:05:09 +0100607 size_t max_line_length; /**< The maximum number of characters that can be
608 printed on one line, including the last. */
609};
610
aPiecek874ea4d2021-04-19 12:26:36 +0200611/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100612 * Tro functions
aPiecek874ea4d2021-04-19 12:26:36 +0200613 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100614
615/**
616 * @brief The name of the section to which the node belongs.
617 */
618typedef enum {
619 TRD_SECT_MODULE = 0, /**< The node belongs to the "module: <module_name>:" label. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100620 TRD_SECT_AUGMENT, /**< The node belongs to some "augment <target-node>:" label. */
621 TRD_SECT_RPCS, /**< The node belongs to the "rpcs:" label. */
622 TRD_SECT_NOTIF, /**< The node belongs to the "notifications:" label. */
623 TRD_SECT_GROUPING, /**< The node belongs to some "grouping <grouping-name>:" label. */
aPiecek61d062b2020-11-02 11:05:09 +0100624 TRD_SECT_YANG_DATA /**< The node belongs to some "yang-data <yang-data-name>:" label. */
625} trt_actual_section;
626
627/**
628 * @brief Types of nodes that have some effect on their children.
629 */
630typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200631 TRD_ANCESTOR_ELSE = 0, /**< Everything not listed. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100632 TRD_ANCESTOR_RPC_INPUT, /**< ::LYS_INPUT */
633 TRD_ANCESTOR_RPC_OUTPUT, /**< ::LYS_OUTPUT */
aPiecek874ea4d2021-04-19 12:26:36 +0200634 TRD_ANCESTOR_NOTIF /**< ::LYS_NOTIF */
aPiecek61d062b2020-11-02 11:05:09 +0100635} trt_ancestor_type;
636
637/**
638 * @brief Saved information when browsing the tree downwards.
639 *
aPiecek874ea4d2021-04-19 12:26:36 +0200640 * This structure helps prevent frequent retrieval of information
aPiecek01598c02021-04-23 14:18:24 +0200641 * from the tree. Functions @ref TRP_trb are designed to preserve
aPiecek874ea4d2021-04-19 12:26:36 +0200642 * this structures during their recursive calls. This functions do not
643 * interfere in any way with this data. This structure
aPiecek01598c02021-04-23 14:18:24 +0200644 * is used by @ref TRP_trop functions which, thanks to this
aPiecek874ea4d2021-04-19 12:26:36 +0200645 * structure, can return a node with the correct data. The word
646 * \b parent is in the structure name, because this data refers to
647 * the last parent and at the same time the states of its
648 * ancestors data. Only the function jumping on the child
649 * (next_child(...)) creates this structure, because the pointer
650 * to the current node moves down the tree. It's like passing
651 * the genetic code to children. Some data must be inherited and
652 * there are two approaches to this problem. Either it will always
653 * be determined which inheritance states belong to the current node
654 * (which can lead to regular travel to the root node) or
655 * the inheritance states will be stored during the recursive calls.
656 * So the problem was solved by the second option. Why does
657 * the structure contain this data? Because it walks through
aPiecek3f247652021-04-19 13:40:25 +0200658 * the lysp tree. For walks through the lysc tree is trt_parent_cache
659 * useless.
aPiecek61d062b2020-11-02 11:05:09 +0100660 *
aPiecek874ea4d2021-04-19 12:26:36 +0200661 * @see TRO_EMPTY_PARENT_CACHE, tro_parent_cache_for_child
aPiecek61d062b2020-11-02 11:05:09 +0100662 */
663struct trt_parent_cache {
aPiecek874ea4d2021-04-19 12:26:36 +0200664 trt_ancestor_type ancestor; /**< Some types of nodes have a special effect on their children. */
665 uint16_t lys_status; /**< Inherited status CURR, DEPRC, OBSLT. */
666 uint16_t lys_config; /**< Inherited config W or R. */
667 const struct lysp_node_list *last_list; /**< The last ::LYS_LIST passed. */
aPiecek61d062b2020-11-02 11:05:09 +0100668};
669
670/**
671 * @brief Return trt_parent_cache filled with default values.
672 */
673#define TRP_EMPTY_PARENT_CACHE \
aPiecek874ea4d2021-04-19 12:26:36 +0200674 (struct trt_parent_cache) { \
675 .ancestor = TRD_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \
676 .lys_config = LYS_CONFIG_W, .last_list = NULL \
677 }
aPiecek61d062b2020-11-02 11:05:09 +0100678
679/**
680 * @brief Main structure for browsing the libyang tree
681 */
682struct trt_tree_ctx {
aPiecek96baa7f2021-04-23 12:32:00 +0200683 ly_bool lysc_tree; /**< The lysc nodes are used for browsing through the tree.
684 It is assumed that once set, it does not change.
685 If it is true then trt_tree_ctx.pn and
686 trt_tree_ctx.tpn are not used.
687 If it is false then trt_tree_ctx.cn is not used. */
ekinzie0ab8b302022-10-10 03:03:57 -0400688 ly_bool mounted; /**< This tree is a mounted schema */
aPiecek96baa7f2021-04-23 12:32:00 +0200689 trt_actual_section section; /**< To which section pn points. */
690 const struct lysp_module *pmod; /**< Parsed YANG schema tree. */
691 const struct lysc_module *cmod; /**< Compiled YANG schema tree. */
692 const struct lysp_node *pn; /**< Actual pointer to parsed node. */
Michal Vasko26bbb272022-08-02 14:54:33 +0200693
aPiecek96baa7f2021-04-23 12:32:00 +0200694 union {
695 const struct lysp_node *tpn; /**< Pointer to actual top-node. */
696 const struct lysp_ext_instance *tpn_ext; /**< Actual top-node is extension. Item trt_tree_ctx.section
697 is set to TRD_SECT_YANG_DATA. */
698 };
699 const struct lysc_node *cn; /**< Actual pointer to compiled node. */
ekinzie0ab8b302022-10-10 03:03:57 -0400700 const struct ly_set *parent_refs; /**< List of schema nodes for top-level nodes found in mount
701 point parent references */
aPiecek40f22402022-10-14 10:48:08 +0200702 LY_ERR last_error; /**< Error value during printing. */
aPiecek61d062b2020-11-02 11:05:09 +0100703};
704
aPiecek3f247652021-04-19 13:40:25 +0200705/**
aPiecekbbc02932021-05-21 07:19:41 +0200706 * @brief Check if lysp node is available from
707 * the current compiled node.
708 *
709 * Use only if trt_tree_ctx.lysc_tree is set to true.
710 */
711#define TRP_TREE_CTX_LYSP_NODE_PRESENT(CN) \
712 (CN->priv)
713
714/**
aPiecek3f247652021-04-19 13:40:25 +0200715 * @brief Get lysp_node from trt_tree_ctx.cn.
aPiecekbbc02932021-05-21 07:19:41 +0200716 *
717 * Use only if :TRP_TREE_CTX_LYSP_NODE_PRESENT returns true
718 * for that node.
aPiecek3f247652021-04-19 13:40:25 +0200719 */
720#define TRP_TREE_CTX_GET_LYSP_NODE(CN) \
721 ((const struct lysp_node *)CN->priv)
722
aPiecek01598c02021-04-23 14:18:24 +0200723/** Getter function for ::trop_node_charptr(). */
aPiecek61d062b2020-11-02 11:05:09 +0100724typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
725
aPiecekef1e58e2021-04-19 13:19:44 +0200726/**
727 * @brief Simple getter functions for lysp and lysc nodes.
728 *
729 * This structure is useful if we have a general algorithm
730 * (tro function) that can be used for both lysc and lysp nodes.
731 * Thanks to this structure, we prevent code redundancy.
732 * We don't have to write basically the same algorithm twice
733 * for lysp and lysc trees.
734 */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100735struct tro_getters {
aPiecekef1e58e2021-04-19 13:19:44 +0200736 uint16_t (*nodetype)(const void *); /**< Get nodetype. */
737 const void *(*next)(const void *); /**< Get sibling. */
738 const void *(*parent)(const void *); /**< Get parent. */
739 const void *(*child)(const void *); /**< Get child. */
740 const void *(*actions)(const void *); /**< Get actions. */
741 const void *(*action_input)(const void *); /**< Get input action from action node. */
742 const void *(*action_output)(const void *); /**< Get output action from action node. */
743 const void *(*notifs)(const void *); /**< Get notifs. */
744};
745
aPiecek874ea4d2021-04-19 12:26:36 +0200746/**********************************************************************
ekinzie0ab8b302022-10-10 03:03:57 -0400747 * Forward declarations
748 *********************************************************************/
aPiecek7ed8d032022-10-10 12:32:27 +0200749static LY_ERR trb_print_mount_point(const struct lysc_ext_instance *ext, const struct trt_wrapper wr, struct trt_printer_ctx *pc);
ekinzie0ab8b302022-10-10 03:03:57 -0400750
751/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100752 * Definition of the general Trg functions
aPiecek874ea4d2021-04-19 12:26:36 +0200753 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100754
755/**
756 * @brief Print a substring but limited to the maximum length.
757 * @param[in] str is pointer to source.
758 * @param[in] len is number of characters to be printed.
759 * @param[in,out] out is output handler.
760 * @return str parameter shifted by len.
761 */
762static const char *
763trg_print_substr(const char *str, size_t len, struct ly_out *out)
764{
765 for (size_t i = 0; i < len; i++) {
766 ly_print_(out, "%c", str[0]);
767 str++;
768 }
769 return str;
770}
771
772/**
773 * @brief Pointer is not NULL and does not point to an empty string.
774 * @param[in] str is pointer to string to be checked.
775 * @return 1 if str pointing to non empty string otherwise 0.
776 */
777static ly_bool
778trg_charptr_has_data(const char *str)
779{
780 return (str) && (str[0] != '\0');
781}
782
783/**
aPiecek874ea4d2021-04-19 12:26:36 +0200784 * @brief Check if @p word in @p src is present where words are
785 * delimited by @p delim.
786 * @param[in] src is source where words are separated by @p delim.
aPiecek61d062b2020-11-02 11:05:09 +0100787 * @param[in] word to be searched.
aPiecek874ea4d2021-04-19 12:26:36 +0200788 * @param[in] delim is delimiter between @p words in @p src.
789 * @return 1 if src contains @p word otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +0100790 */
791static ly_bool
792trg_word_is_present(const char *src, const char *word, char delim)
793{
794 const char *hit;
795
796 if ((!src) || (src[0] == '\0') || (!word)) {
797 return 0;
798 }
799
800 hit = strstr(src, word);
801
802 if (hit) {
803 /* word was founded at the begin of src
804 * OR it match somewhere after delim
805 */
806 if ((hit == src) || (hit[-1] == delim)) {
807 /* end of word was founded at the end of src
808 * OR end of word was match somewhere before delim
809 */
810 char delim_or_end = (hit + strlen(word))[0];
Michal Vasko26bbb272022-08-02 14:54:33 +0200811
aPiecek61d062b2020-11-02 11:05:09 +0100812 if ((delim_or_end == '\0') || (delim_or_end == delim)) {
813 return 1;
814 }
815 }
816 /* after -> hit is just substr and it's not the whole word */
817 /* jump to the next word */
818 for ( ; (src[0] != '\0') && (src[0] != delim); src++) {}
819 /* skip delim */
820 src = src[0] == '\0' ? src : src + 1;
821 /* continue with searching */
822 return trg_word_is_present(src, word, delim);
823 } else {
824 return 0;
825 }
826}
827
aPiecek874ea4d2021-04-19 12:26:36 +0200828/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100829 * Definition of printer functions
aPiecek874ea4d2021-04-19 12:26:36 +0200830 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100831
832/**
aPiecek01598c02021-04-23 14:18:24 +0200833 * @brief Write callback for ::ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100834 *
aPiecek874ea4d2021-04-19 12:26:36 +0200835 * @param[in] user_data is type of struct ly_out_clb_arg.
aPiecek61d062b2020-11-02 11:05:09 +0100836 * @param[in] buf contains input characters
837 * @param[in] count is number of characters in buf.
838 * @return Number of printed bytes.
839 * @return Negative value in case of error.
840 */
841static ssize_t
842trp_ly_out_clb_func(void *user_data, const void *buf, size_t count)
843{
844 LY_ERR erc = LY_SUCCESS;
845 struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data;
846
847 switch (data->mode) {
848 case TRD_PRINT:
849 erc = ly_write_(data->out, buf, count);
850 break;
851 case TRD_CHAR_COUNT:
852 data->counter = data->counter + count;
853 break;
854 default:
855 break;
856 }
857
858 if (erc != LY_SUCCESS) {
859 data->last_error = erc;
860 return -1;
861 } else {
862 return count;
863 }
864}
865
866/**
867 * @brief Check that indent in node can be considered as equivalent.
868 * @param[in] first is the first indent in node.
869 * @param[in] second is the second indent in node.
870 * @return 1 if indents are equivalent otherwise 0.
871 */
872static ly_bool
873trp_indent_in_node_are_eq(struct trt_indent_in_node first, struct trt_indent_in_node second)
874{
875 const ly_bool a = first.type == second.type;
876 const ly_bool b = first.btw_name_opts == second.btw_name_opts;
877 const ly_bool c = first.btw_opts_type == second.btw_opts_type;
878 const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures;
879
880 return a && b && c && d;
881}
882
883/**
aPiecek874ea4d2021-04-19 12:26:36 +0200884 * @brief Setting space character because node is last sibling.
885 * @param[in] wr is wrapper over which the shift operation
886 * is to be performed.
aPiecek61d062b2020-11-02 11:05:09 +0100887 * @return New shifted wrapper.
888 */
889static struct trt_wrapper
890trp_wrapper_set_shift(struct trt_wrapper wr)
891{
892 assert(wr.actual_pos < 64);
893 /* +--<node>
894 * +--<node>
895 */
896 wr.actual_pos++;
897 return wr;
898}
899
900/**
aPiecek874ea4d2021-04-19 12:26:36 +0200901 * @brief Setting '|' symbol because node is divided or
902 * it is not last sibling.
aPiecek61d062b2020-11-02 11:05:09 +0100903 * @param[in] wr is source of wrapper.
904 * @return New wrapper which is marked at actual position and shifted.
905 */
906static struct trt_wrapper
907trp_wrapper_set_mark(struct trt_wrapper wr)
908{
909 assert(wr.actual_pos < 64);
910 wr.bit_marks1 |= 1U << wr.actual_pos;
911 return trp_wrapper_set_shift(wr);
912}
913
914/**
ekinzie0ab8b302022-10-10 03:03:57 -0400915 * @brief Set '|' symbol to connect current level nodes in a module.
916 * This is only used to connect all top-level nodes in all modules under
917 * a schema mount point.
918 * @param[in] wr is the wrapper to be marked
919 * @return New wrapper which is marked at actual position.
920 */
921static struct trt_wrapper
922trp_wrapper_set_mark_top(struct trt_wrapper wr)
923{
924 wr.bit_marks1 |= 1U << wr.actual_pos;
925 return wr;
926}
927
928/**
aPiecek61d062b2020-11-02 11:05:09 +0100929 * @brief Setting ' ' symbol if node is last sibling otherwise set '|'.
930 * @param[in] wr is actual wrapper.
aPiecek874ea4d2021-04-19 12:26:36 +0200931 * @param[in] last_one is flag. Value 1 saying if the node is the last
932 * and has no more siblings.
aPiecek61d062b2020-11-02 11:05:09 +0100933 * @return New wrapper for the actual node.
934 */
935static struct trt_wrapper
936trp_wrapper_if_last_sibling(struct trt_wrapper wr, ly_bool last_one)
937{
938 return last_one ? trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
939}
940
941/**
942 * @brief Test if the wrappers are equivalent.
943 * @param[in] first is the first wrapper.
944 * @param[in] second is the second wrapper.
945 * @return 1 if the wrappers are equivalent otherwise 0.
946 */
947static ly_bool
948trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second)
949{
950 const ly_bool a = first.type == second.type;
951 const ly_bool b = first.bit_marks1 == second.bit_marks1;
952 const ly_bool c = first.actual_pos == second.actual_pos;
953
954 return a && b && c;
955}
956
957/**
958 * @brief Print " | " sequence on line.
959 * @param[in] wr is wrapper to be printed.
960 * @param[in,out] out is output handler.
961 */
962static void
963trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out)
964{
965 uint32_t lb;
966
967 if (wr.type == TRD_WRAPPER_TOP) {
968 lb = TRD_INDENT_LINE_BEGIN;
969 } else if (wr.type == TRD_WRAPPER_BODY) {
970 lb = TRD_INDENT_LINE_BEGIN * 2;
971 } else {
972 lb = TRD_INDENT_LINE_BEGIN;
973 }
974
975 ly_print_(out, "%*c", lb, ' ');
976
977 if (trp_wrapper_eq(wr, TRP_INIT_WRAPPER_TOP)) {
978 return;
979 }
980
981 for (uint32_t i = 0; i < wr.actual_pos; i++) {
982 /** Test if the bit on the index is set. */
983 if ((wr.bit_marks1 >> i) & 1U) {
984 ly_print_(out, "|");
985 } else {
986 ly_print_(out, " ");
987 }
988
989 if (i != wr.actual_pos) {
990 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
991 }
992 }
993}
994
995/**
996 * @brief Check if struct trt_node is empty.
997 * @param[in] node is item to test.
998 * @return 1 if node is considered empty otherwise 0.
999 */
1000static ly_bool
1001trp_node_is_empty(struct trt_node node)
1002{
aPiecek41219f92022-10-26 11:24:40 +02001003 const ly_bool a = TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(node.iffeatures.type);
aPiecek61d062b2020-11-02 11:05:09 +01001004 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
1005 const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node.name);
aPiecek41219f92022-10-26 11:24:40 +02001006 const ly_bool d = node.flags == NULL;
1007 const ly_bool e = node.status == NULL;
aPiecek61d062b2020-11-02 11:05:09 +01001008
1009 return a && b && c && d && e;
1010}
1011
1012/**
aPiecek874ea4d2021-04-19 12:26:36 +02001013 * @brief Check if [\<keys\>], \<type\> and
1014 * \<iffeatures\> are empty/not_set.
aPiecek61d062b2020-11-02 11:05:09 +01001015 * @param[in] node is item to test.
aPiecek874ea4d2021-04-19 12:26:36 +02001016 * @return 1 if node has no \<keys\> \<type\> or \<iffeatures\>
1017 * otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +01001018 */
1019static ly_bool
1020trp_node_body_is_empty(struct trt_node node)
1021{
aPiecek41219f92022-10-26 11:24:40 +02001022 const ly_bool a = TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(node.iffeatures.type);
aPiecek61d062b2020-11-02 11:05:09 +01001023 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
aPiecekbca57772022-10-13 13:51:59 +02001024 const ly_bool c = !node.name.keys;
aPiecek61d062b2020-11-02 11:05:09 +01001025
1026 return a && b && c;
1027}
1028
1029/**
aPiecek61d062b2020-11-02 11:05:09 +01001030 * @brief Print entire struct trt_node_name structure.
1031 * @param[in] node_name is item to print.
1032 * @param[in,out] out is output handler.
1033 */
1034static void
1035trp_print_node_name(struct trt_node_name node_name, struct ly_out *out)
1036{
1037 const char *mod_prefix;
1038 const char *colon;
1039 const char trd_node_name_suffix_choice[] = ")";
1040 const char trd_node_name_suffix_case[] = ")";
aPiecek61d062b2020-11-02 11:05:09 +01001041
1042 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1043 return;
1044 }
1045
1046 if (node_name.module_prefix) {
1047 mod_prefix = node_name.module_prefix;
1048 colon = ":";
1049 } else {
1050 mod_prefix = "";
1051 colon = "";
1052 }
1053
1054 switch (node_name.type) {
1055 case TRD_NODE_ELSE:
1056 ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
1057 break;
1058 case TRD_NODE_CASE:
1059 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, trd_node_name_suffix_case);
1060 break;
1061 case TRD_NODE_CHOICE:
1062 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice);
1063 break;
aPiecek61d062b2020-11-02 11:05:09 +01001064 case TRD_NODE_TOP_LEVEL1:
aPiecek41219f92022-10-26 11:24:40 +02001065 ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
aPiecek61d062b2020-11-02 11:05:09 +01001066 break;
1067 case TRD_NODE_TOP_LEVEL2:
aPiecek41219f92022-10-26 11:24:40 +02001068 ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
aPiecek61d062b2020-11-02 11:05:09 +01001069 break;
1070 case TRD_NODE_TRIPLE_DOT:
1071 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
1072 break;
1073 default:
1074 break;
1075 }
aPiecek41219f92022-10-26 11:24:40 +02001076
1077 if (node_name.opts) {
1078 ly_print_(out, "%s", node_name.opts);
1079 }
aPiecek61d062b2020-11-02 11:05:09 +01001080}
1081
1082/**
aPiecek874ea4d2021-04-19 12:26:36 +02001083 * @brief Check if mark (?, !, *, /, @) is implicitly contained in
1084 * struct trt_node_name.
aPiecek61d062b2020-11-02 11:05:09 +01001085 * @param[in] node_name is structure containing the 'mark'.
1086 * @return 1 if contain otherwise 0.
1087 */
1088static ly_bool
1089trp_mark_is_used(struct trt_node_name node_name)
1090{
1091 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1092 return 0;
aPiecekbca57772022-10-13 13:51:59 +02001093 } else if (node_name.keys) {
1094 return 0;
aPiecek61d062b2020-11-02 11:05:09 +01001095 }
1096
1097 switch (node_name.type) {
1098 case TRD_NODE_ELSE:
1099 case TRD_NODE_CASE:
aPiecek61d062b2020-11-02 11:05:09 +01001100 return 0;
1101 default:
aPiecek41219f92022-10-26 11:24:40 +02001102 if (node_name.opts) {
1103 return 1;
1104 } else {
1105 return 0;
1106 }
aPiecek61d062b2020-11-02 11:05:09 +01001107 }
1108}
1109
1110/**
1111 * @brief Print opts keys.
1112 * @param[in] node_name contains type of the node with his name.
1113 * @param[in] btw_name_opts is number of spaces between name and [keys].
aPiecek874ea4d2021-04-19 12:26:36 +02001114 * @param[in] cf is basically a pointer to the function that prints
1115 * the keys.
aPiecek61d062b2020-11-02 11:05:09 +01001116 * @param[in,out] out is output handler.
1117 */
1118static void
1119trp_print_opts_keys(struct trt_node_name node_name, int16_t btw_name_opts, struct trt_cf_print cf, struct ly_out *out)
1120{
aPiecekbca57772022-10-13 13:51:59 +02001121 if (!node_name.keys) {
aPiecek61d062b2020-11-02 11:05:09 +01001122 return;
1123 }
1124
1125 /* <name><mark>___<keys>*/
1126 if (btw_name_opts > 0) {
1127 ly_print_(out, "%*c", btw_name_opts, ' ');
1128 }
1129 ly_print_(out, "[");
1130 cf.pf(cf.ctx, out);
1131 ly_print_(out, "]");
1132}
1133
1134/**
1135 * @brief Print entire struct trt_type structure.
1136 * @param[in] type is item to print.
1137 * @param[in,out] out is output handler.
1138 */
1139static void
1140trp_print_type(struct trt_type type, struct ly_out *out)
1141{
1142 if (TRP_TRT_TYPE_IS_EMPTY(type)) {
1143 return;
1144 }
1145
1146 switch (type.type) {
1147 case TRD_TYPE_NAME:
1148 ly_print_(out, "%s", type.str);
1149 break;
1150 case TRD_TYPE_TARGET:
1151 ly_print_(out, "-> %s", type.str);
1152 break;
1153 case TRD_TYPE_LEAFREF:
1154 ly_print_(out, "leafref");
1155 default:
1156 break;
1157 }
1158}
1159
1160/**
1161 * @brief Print all iffeatures of node
1162 *
1163 * @param[in] iffeature_flag contains if if-features is present.
aPiecek874ea4d2021-04-19 12:26:36 +02001164 * @param[in] cf is basically a pointer to the function that prints
1165 * the list of features.
aPiecek61d062b2020-11-02 11:05:09 +01001166 * @param[in,out] out is output handler.
1167 */
1168static void
aPiecek41219f92022-10-26 11:24:40 +02001169trp_print_iffeatures(struct trt_iffeatures iff, struct trt_cf_print cf, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001170{
aPiecek41219f92022-10-26 11:24:40 +02001171 if (iff.type == TRD_IFF_PRESENT) {
aPiecek61d062b2020-11-02 11:05:09 +01001172 ly_print_(out, "{");
1173 cf.pf(cf.ctx, out);
1174 ly_print_(out, "}?");
1175 }
1176}
1177
1178/**
1179 * @brief Print just \<status\>--\<flags\> \<name\> with opts mark.
1180 * @param[in] node contains items to print.
1181 * @param[in] out is output handler.
1182 */
1183static void
1184trp_print_node_up_to_name(struct trt_node node, struct ly_out *out)
1185{
1186 if (node.name.type == TRD_NODE_TRIPLE_DOT) {
1187 trp_print_node_name(node.name, out);
1188 return;
1189 }
1190 /* <status>--<flags> */
aPiecek41219f92022-10-26 11:24:40 +02001191 ly_print_(out, "%s", node.status);
aPiecek61d062b2020-11-02 11:05:09 +01001192 ly_print_(out, "--");
aPiecek874ea4d2021-04-19 12:26:36 +02001193 /* If the node is a case node, there is no space before the <name>
1194 * also case node has no flags.
1195 */
aPiecek41219f92022-10-26 11:24:40 +02001196 if (node.flags && (node.name.type != TRD_NODE_CASE)) {
1197 ly_print_(out, "%s", node.flags);
aPiecek61d062b2020-11-02 11:05:09 +01001198 ly_print_(out, " ");
1199 }
1200 /* <name> */
1201 trp_print_node_name(node.name, out);
1202}
1203
1204/**
aPiecek874ea4d2021-04-19 12:26:36 +02001205 * @brief Print alignment (spaces) instead of
1206 * \<status\>--\<flags\> \<name\> for divided node.
aPiecek61d062b2020-11-02 11:05:09 +01001207 * @param[in] node contains items to print.
1208 * @param[in] out is output handler.
1209 */
1210static void
1211trp_print_divided_node_up_to_name(struct trt_node node, struct ly_out *out)
1212{
aPiecek41219f92022-10-26 11:24:40 +02001213 uint32_t space = strlen(node.flags);
aPiecek61d062b2020-11-02 11:05:09 +01001214
1215 if (node.name.type == TRD_NODE_CASE) {
1216 /* :(<name> */
1217 space += strlen(TRD_NODE_NAME_PREFIX_CASE);
1218 } else if (node.name.type == TRD_NODE_CHOICE) {
1219 /* (<name> */
1220 space += strlen(TRD_NODE_NAME_PREFIX_CHOICE);
1221 } else {
1222 /* _<name> */
1223 space += strlen(" ");
1224 }
1225
1226 /* <name>
1227 * __
1228 */
1229 space += TRD_INDENT_LONG_LINE_BREAK;
1230
1231 ly_print_(out, "%*c", space, ' ');
1232}
1233
1234/**
1235 * @brief Print struct trt_node structure.
1236 * @param[in] node is item to print.
aPiecek874ea4d2021-04-19 12:26:36 +02001237 * @param[in] pck package of functions for
1238 * printing [\<keys\>] and \<iffeatures\>.
aPiecek61d062b2020-11-02 11:05:09 +01001239 * @param[in] indent is the indent in node.
1240 * @param[in,out] out is output handler.
1241 */
1242static void
1243trp_print_node(struct trt_node node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out)
1244{
1245 ly_bool triple_dot;
1246 ly_bool divided;
1247 struct trt_cf_print cf_print_keys;
1248 struct trt_cf_print cf_print_iffeatures;
1249
1250 if (trp_node_is_empty(node)) {
1251 return;
1252 }
1253
1254 /* <status>--<flags> <name><opts> <type> <if-features> */
1255 triple_dot = node.name.type == TRD_NODE_TRIPLE_DOT;
1256 divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED;
1257
1258 if (triple_dot) {
1259 trp_print_node_name(node.name, out);
1260 return;
1261 } else if (!divided) {
1262 trp_print_node_up_to_name(node, out);
1263 } else {
1264 trp_print_divided_node_up_to_name(node, out);
1265 }
1266
1267 /* <opts> */
1268 /* <name>___<opts>*/
1269 cf_print_keys.ctx = pck.tree_ctx;
1270 cf_print_keys.pf = pck.fps.print_keys;
1271
1272 trp_print_opts_keys(node.name, indent.btw_name_opts, cf_print_keys, out);
1273
1274 /* <opts>__<type> */
1275 if (indent.btw_opts_type > 0) {
1276 ly_print_(out, "%*c", indent.btw_opts_type, ' ');
1277 }
1278
1279 /* <type> */
1280 trp_print_type(node.type, out);
1281
1282 /* <type>__<iffeatures> */
1283 if (indent.btw_type_iffeatures > 0) {
1284 ly_print_(out, "%*c", indent.btw_type_iffeatures, ' ');
1285 }
1286
1287 /* <iffeatures> */
1288 cf_print_iffeatures.ctx = pck.tree_ctx;
1289 cf_print_iffeatures.pf = pck.fps.print_features_names;
1290
1291 trp_print_iffeatures(node.iffeatures, cf_print_iffeatures, out);
1292}
1293
1294/**
aPiecek874ea4d2021-04-19 12:26:36 +02001295 * @brief Print keyword based on trt_keyword_stmt.type.
aPiecek61d062b2020-11-02 11:05:09 +01001296 * @param[in] ks is keyword statement to print.
1297 * @param[in,out] out is output handler
1298 */
1299static void
1300trt_print_keyword_stmt_begin(struct trt_keyword_stmt ks, struct ly_out *out)
1301{
1302 switch (ks.type) {
1303 case TRD_KEYWORD_MODULE:
1304 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_MODULE);
1305 return;
1306 case TRD_KEYWORD_SUBMODULE:
1307 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_SUBMODULE);
1308 return;
1309 default:
1310 ly_print_(out, "%*c", TRD_INDENT_LINE_BEGIN, ' ');
1311 switch (ks.type) {
1312 case TRD_KEYWORD_AUGMENT:
1313 ly_print_(out, "%s ", TRD_BODY_KEYWORD_AUGMENT);
1314 break;
1315 case TRD_KEYWORD_RPC:
1316 ly_print_(out, "%s", TRD_BODY_KEYWORD_RPC);
1317 break;
1318 case TRD_KEYWORD_NOTIF:
1319 ly_print_(out, "%s", TRD_BODY_KEYWORD_NOTIF);
1320 break;
1321 case TRD_KEYWORD_GROUPING:
1322 ly_print_(out, "%s ", TRD_BODY_KEYWORD_GROUPING);
1323 break;
1324 case TRD_KEYWORD_YANG_DATA:
1325 ly_print_(out, "%s ", TRD_BODY_KEYWORD_YANG_DATA);
1326 break;
1327 default:
1328 break;
1329 }
1330 break;
1331 }
1332}
1333
1334/**
1335 * @brief Get string length of stored keyword.
1336 * @param[in] type is type of the keyword statement.
1337 * @return length of the keyword statement name.
1338 */
1339static size_t
1340trp_keyword_type_strlen(trt_keyword_type type)
1341{
1342 switch (type) {
1343 case TRD_KEYWORD_MODULE:
1344 return sizeof(TRD_TOP_KEYWORD_MODULE) - 1;
1345 case TRD_KEYWORD_SUBMODULE:
1346 return sizeof(TRD_TOP_KEYWORD_SUBMODULE) - 1;
1347 case TRD_KEYWORD_AUGMENT:
1348 return sizeof(TRD_BODY_KEYWORD_AUGMENT) - 1;
1349 case TRD_KEYWORD_RPC:
1350 return sizeof(TRD_BODY_KEYWORD_RPC) - 1;
1351 case TRD_KEYWORD_NOTIF:
1352 return sizeof(TRD_BODY_KEYWORD_NOTIF) - 1;
1353 case TRD_KEYWORD_GROUPING:
1354 return sizeof(TRD_BODY_KEYWORD_GROUPING) - 1;
1355 case TRD_KEYWORD_YANG_DATA:
1356 return sizeof(TRD_BODY_KEYWORD_YANG_DATA) - 1;
1357 default:
1358 return 0;
1359 }
1360}
1361
1362/**
aPiecek874ea4d2021-04-19 12:26:36 +02001363 * @brief Print trt_keyword_stmt.str which is string of name or path.
aPiecek61d062b2020-11-02 11:05:09 +01001364 * @param[in] ks is keyword statement structure.
1365 * @param[in] mll is max line length.
1366 * @param[in,out] out is output handler.
1367 */
1368static void
1369trt_print_keyword_stmt_str(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
1370{
1371 uint32_t ind_initial;
1372 uint32_t ind_divided;
1373 /* flag if path must be splitted to more lines */
1374 ly_bool linebreak_was_set;
1375 /* flag if at least one subpath was printed */
1376 ly_bool subpath_printed;
1377 /* the sum of the sizes of the substrings on the current line */
1378 uint32_t how_far;
1379 /* pointer to start of the subpath */
1380 const char *sub_ptr;
1381 /* size of subpath from sub_ptr */
1382 size_t sub_len;
1383
1384 if ((!ks.str) || (ks.str[0] == '\0')) {
1385 return;
1386 }
1387
1388 /* module name cannot be splitted */
1389 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
1390 ly_print_(out, "%s", ks.str);
1391 return;
1392 }
1393
1394 /* after -> for trd_keyword_stmt_body do */
1395
1396 /* set begin indentation */
1397 ind_initial = TRD_INDENT_LINE_BEGIN + trp_keyword_type_strlen(ks.type) + 1;
1398 ind_divided = ind_initial + TRD_INDENT_LONG_LINE_BREAK;
1399 linebreak_was_set = 0;
1400 subpath_printed = 0;
1401 how_far = 0;
1402 sub_ptr = ks.str;
1403 sub_len = 0;
1404
1405 while (sub_ptr[0] != '\0') {
1406 uint32_t ind;
1407 /* skip slash */
1408 const char *tmp = sub_ptr[0] == '/' ? sub_ptr + 1 : sub_ptr;
Michal Vasko26bbb272022-08-02 14:54:33 +02001409
aPiecek61d062b2020-11-02 11:05:09 +01001410 /* get position of the end of substr */
1411 tmp = strchr(tmp, '/');
1412 /* set correct size if this is a last substring */
1413 sub_len = !tmp ? strlen(sub_ptr) : (size_t)(tmp - sub_ptr);
1414 /* actualize sum of the substring's sizes on the current line */
1415 how_far += sub_len;
1416 /* correction due to colon character if it this is last substring */
1417 how_far = *(sub_ptr + sub_len) == '\0' ? how_far + 1 : how_far;
1418 /* choose indentation which depends on
1419 * whether the string is printed on multiple lines or not
1420 */
1421 ind = linebreak_was_set ? ind_divided : ind_initial;
1422 if (ind + how_far <= mll) {
1423 /* printing before max line length */
1424 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1425 subpath_printed = 1;
1426 } else {
1427 /* printing on new line */
1428 if (subpath_printed == 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001429 /* first subpath is too long
1430 * but print it at first line anyway
1431 */
aPiecek61d062b2020-11-02 11:05:09 +01001432 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1433 subpath_printed = 1;
1434 continue;
1435 }
1436 ly_print_(out, "\n");
1437 ly_print_(out, "%*c", ind_divided, ' ');
1438 linebreak_was_set = 1;
1439 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1440 how_far = sub_len;
1441 subpath_printed = 1;
1442 }
1443 }
1444}
1445
1446/**
aPiecek874ea4d2021-04-19 12:26:36 +02001447 * @brief Print separator based on trt_keyword_stmt.type
aPiecek61d062b2020-11-02 11:05:09 +01001448 * @param[in] ks is keyword statement structure.
aPiecekdc8fd572021-04-19 10:47:23 +02001449 * @param[in] grp_has_data is flag only for grouping section.
1450 * Set to 1 if grouping section has some nodes.
1451 * Set to 0 if it doesn't have nodes or it's not grouping section.
aPiecek61d062b2020-11-02 11:05:09 +01001452 * @param[in,out] out is output handler.
1453 */
1454static void
aPiecekdc8fd572021-04-19 10:47:23 +02001455trt_print_keyword_stmt_end(struct trt_keyword_stmt ks, ly_bool grp_has_data, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001456{
1457 if ((ks.type != TRD_KEYWORD_MODULE) && (ks.type != TRD_KEYWORD_SUBMODULE)) {
aPiecekdc8fd572021-04-19 10:47:23 +02001458 if ((ks.type == TRD_KEYWORD_GROUPING) && !grp_has_data) {
1459 return;
1460 } else {
1461 ly_print_(out, ":");
1462 }
aPiecek61d062b2020-11-02 11:05:09 +01001463 }
1464}
1465
1466/**
1467 * @brief Print entire struct trt_keyword_stmt structure.
1468 * @param[in] ks is item to print.
1469 * @param[in] mll is max line length.
aPiecekdc8fd572021-04-19 10:47:23 +02001470 * @param[in] grp_has_data is flag only for grouping section.
1471 * Set to 1 if grouping section has some nodes.
1472 * Set to 0 if it doesn't have nodes or it's not grouping section.
aPiecek61d062b2020-11-02 11:05:09 +01001473 * @param[in,out] out is output handler.
1474 */
1475static void
aPiecek874ea4d2021-04-19 12:26:36 +02001476trp_print_keyword_stmt(struct trt_keyword_stmt ks, size_t mll, ly_bool grp_has_data, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001477{
1478 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
1479 return;
1480 }
1481 trt_print_keyword_stmt_begin(ks, out);
1482 trt_print_keyword_stmt_str(ks, mll, out);
aPiecekdc8fd572021-04-19 10:47:23 +02001483 trt_print_keyword_stmt_end(ks, grp_has_data, out);
aPiecek61d062b2020-11-02 11:05:09 +01001484}
1485
aPiecek874ea4d2021-04-19 12:26:36 +02001486/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01001487 * Main trp functions
aPiecek874ea4d2021-04-19 12:26:36 +02001488 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01001489
1490/**
aPiecek874ea4d2021-04-19 12:26:36 +02001491 * @brief Printing one line including wrapper and node
1492 * which can be incomplete (divided).
aPiecek61d062b2020-11-02 11:05:09 +01001493 * @param[in] node is \<node\> representation.
1494 * @param[in] pck contains special printing functions callback.
1495 * @param[in] indent contains wrapper and indent in node numbers.
1496 * @param[in,out] out is output handler.
1497 */
1498static void
1499trp_print_line(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out)
1500{
1501 trp_print_wrapper(indent.wrapper, out);
1502 trp_print_node(node, pck, indent.in_node, out);
1503}
1504
1505/**
aPiecek874ea4d2021-04-19 12:26:36 +02001506 * @brief Printing one line including wrapper and
1507 * \<status\>--\<flags\> \<name\>\<option_mark\>.
aPiecek61d062b2020-11-02 11:05:09 +01001508 * @param[in] node is \<node\> representation.
1509 * @param[in] wr is wrapper for printing indentation before node.
1510 * @param[in] out is output handler.
1511 */
1512static void
1513trp_print_line_up_to_node_name(struct trt_node node, struct trt_wrapper wr, struct ly_out *out)
1514{
1515 trp_print_wrapper(wr, out);
1516 trp_print_node_up_to_name(node, out);
1517}
1518
1519/**
aPiecek874ea4d2021-04-19 12:26:36 +02001520 * @brief Check if leafref target must be change to string 'leafref'
1521 * because his target string is too long.
aPiecek61d062b2020-11-02 11:05:09 +01001522 * @param[in] node containing leafref target.
1523 * @param[in] wr is wrapper for printing indentation before node.
1524 * @param[in] mll is max line length.
1525 * @param[in] out is output handler.
1526 * @return true if leafref must be changed to string 'leafref'.
1527 */
1528static ly_bool
1529trp_leafref_target_is_too_long(struct trt_node node, struct trt_wrapper wr, size_t mll, struct ly_out *out)
1530{
aPiecek41219f92022-10-26 11:24:40 +02001531 size_t type_len;
aPiecek61d062b2020-11-02 11:05:09 +01001532 struct ly_out_clb_arg *data;
1533
1534 if (node.type.type != TRD_TYPE_TARGET) {
1535 return 0;
1536 }
1537
1538 /* set ly_out to counting characters */
1539 data = out->method.clb.arg;
1540
1541 data->counter = 0;
1542 data->mode = TRD_CHAR_COUNT;
1543 /* count number of printed bytes */
1544 trp_print_wrapper(wr, out);
1545 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1546 trp_print_divided_node_up_to_name(node, out);
1547 data->mode = TRD_PRINT;
aPiecek41219f92022-10-26 11:24:40 +02001548 type_len = strlen(node.type.str);
aPiecek61d062b2020-11-02 11:05:09 +01001549
aPiecek41219f92022-10-26 11:24:40 +02001550 return data->counter + type_len > mll;
aPiecek61d062b2020-11-02 11:05:09 +01001551}
1552
1553/**
1554 * @brief Get default indent in node based on node values.
1555 * @param[in] node is \<node\> representation.
aPiecek874ea4d2021-04-19 12:26:36 +02001556 * @return Default indent in node assuming that the node
1557 * will not be divided.
aPiecek61d062b2020-11-02 11:05:09 +01001558 */
1559static struct trt_indent_in_node
1560trp_default_indent_in_node(struct trt_node node)
1561{
1562 struct trt_indent_in_node ret;
1563
1564 ret.type = TRD_INDENT_IN_NODE_NORMAL;
1565
1566 /* btw_name_opts */
aPiecekbca57772022-10-13 13:51:59 +02001567 ret.btw_name_opts = node.name.keys ? TRD_INDENT_BEFORE_KEYS : 0;
aPiecek61d062b2020-11-02 11:05:09 +01001568
1569 /* btw_opts_type */
1570 if (!(TRP_TRT_TYPE_IS_EMPTY(node.type))) {
1571 ret.btw_opts_type = trp_mark_is_used(node.name) ?
aPiecek41219f92022-10-26 11:24:40 +02001572 TRD_INDENT_BEFORE_TYPE - strlen(node.name.opts) :
aPiecek61d062b2020-11-02 11:05:09 +01001573 TRD_INDENT_BEFORE_TYPE;
1574 } else {
1575 ret.btw_opts_type = 0;
1576 }
1577
1578 /* btw_type_iffeatures */
aPiecek41219f92022-10-26 11:24:40 +02001579 ret.btw_type_iffeatures = node.iffeatures.type == TRD_IFF_PRESENT ? TRD_INDENT_BEFORE_IFFEATURES : 0;
aPiecek61d062b2020-11-02 11:05:09 +01001580
1581 return ret;
1582}
1583
1584/**
1585 * @brief Setting linebreaks in trt_indent_in_node.
1586 *
1587 * The order where the linebreak tag can be placed is from the end.
1588 *
aPiecek874ea4d2021-04-19 12:26:36 +02001589 * @param[in] indent containing alignment lengths
1590 * or already linebreak marks.
aPiecek61d062b2020-11-02 11:05:09 +01001591 * @return indent with a newly placed linebreak tag.
aPiecek874ea4d2021-04-19 12:26:36 +02001592 * @return .type set to TRD_INDENT_IN_NODE_FAILED if it is not possible
1593 * to place a more linebreaks.
aPiecek61d062b2020-11-02 11:05:09 +01001594 */
1595static struct trt_indent_in_node
1596trp_indent_in_node_place_break(struct trt_indent_in_node indent)
1597{
1598 /* somewhere must be set a line break in node */
1599 struct trt_indent_in_node ret = indent;
1600
1601 /* gradually break the node from the end */
1602 if ((indent.btw_type_iffeatures != TRD_LINEBREAK) && (indent.btw_type_iffeatures != 0)) {
1603 ret.btw_type_iffeatures = TRD_LINEBREAK;
1604 } else if ((indent.btw_opts_type != TRD_LINEBREAK) && (indent.btw_opts_type != 0)) {
1605 ret.btw_opts_type = TRD_LINEBREAK;
1606 } else if ((indent.btw_name_opts != TRD_LINEBREAK) && (indent.btw_name_opts != 0)) {
1607 /* set line break between name and opts */
1608 ret.btw_name_opts = TRD_LINEBREAK;
1609 } else {
1610 /* it is not possible to place a more line breaks,
1611 * unfortunately the max_line_length constraint is violated
1612 */
1613 ret.type = TRD_INDENT_IN_NODE_FAILED;
1614 }
1615 return ret;
1616}
1617
1618/**
1619 * @brief Get the first half of the node based on the linebreak mark.
1620 *
1621 * Items in the second half of the node will be empty.
1622 *
1623 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001624 * @param[in] indent contains information in which part of the \<node\>
1625 * the first half ends.
aPiecek61d062b2020-11-02 11:05:09 +01001626 * @return first half of the node, indent is unchanged.
1627 */
1628static struct trt_pair_indent_node
1629trp_first_half_node(struct trt_node node, struct trt_indent_in_node indent)
1630{
1631 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1632
1633 if (indent.btw_name_opts == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001634 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001635 ret.node.type = TRP_EMPTY_TRT_TYPE;
aPiecek41219f92022-10-26 11:24:40 +02001636 ret.node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001637 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1638 ret.node.type = TRP_EMPTY_TRT_TYPE;
aPiecek41219f92022-10-26 11:24:40 +02001639 ret.node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001640 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
aPiecek41219f92022-10-26 11:24:40 +02001641 ret.node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001642 }
1643
1644 return ret;
1645}
1646
1647/**
1648 * @brief Get the second half of the node based on the linebreak mark.
1649 *
1650 * Items in the first half of the node will be empty.
1651 * Indentations belonging to the first node will be reset to zero.
1652 *
1653 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001654 * @param[in] indent contains information in which part of the \<node\>
1655 * the second half starts.
aPiecek61d062b2020-11-02 11:05:09 +01001656 * @return second half of the node, indent is newly set.
1657 */
1658static struct trt_pair_indent_node
1659trp_second_half_node(struct trt_node node, struct trt_indent_in_node indent)
1660{
1661 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1662
1663 if (indent.btw_name_opts < 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001664 /* Logically, the information up to token <opts> should
1665 * be deleted, but the the trp_print_node function needs it to
1666 * create the correct indent.
aPiecek61d062b2020-11-02 11:05:09 +01001667 */
1668 ret.indent.btw_name_opts = 0;
1669 ret.indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(node.type) ? 0 : TRD_INDENT_BEFORE_TYPE;
aPiecek41219f92022-10-26 11:24:40 +02001670 ret.indent.btw_type_iffeatures = node.iffeatures.type == TRD_IFF_NON_PRESENT ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001671 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001672 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001673 ret.indent.btw_name_opts = 0;
1674 ret.indent.btw_opts_type = 0;
aPiecek41219f92022-10-26 11:24:40 +02001675 ret.indent.btw_type_iffeatures = node.iffeatures.type == TRD_IFF_NON_PRESENT ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001676 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001677 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001678 ret.node.type = TRP_EMPTY_TRT_TYPE;
1679 ret.indent.btw_name_opts = 0;
1680 ret.indent.btw_opts_type = 0;
1681 ret.indent.btw_type_iffeatures = 0;
1682 }
1683 return ret;
1684}
1685
1686/**
1687 * @brief Get the correct alignment for the node.
1688 *
aPiecek874ea4d2021-04-19 12:26:36 +02001689 * This function is recursively called itself. It's like a backend
aPiecek01598c02021-04-23 14:18:24 +02001690 * function for a function ::trp_try_normal_indent_in_node().
aPiecek61d062b2020-11-02 11:05:09 +01001691 *
1692 * @param[in] node is \<node\> representation.
1693 * @param[in] pck contains speciall callback functions for printing.
1694 * @param[in] indent contains wrapper and indent in node numbers.
1695 * @param[in] mll is max line length.
1696 * @param[in,out] cnt counting number of characters to print.
1697 * @param[in,out] out is output handler.
1698 * @return pair of node and indentation numbers of that node.
1699 */
1700static struct trt_pair_indent_node
1701trp_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)
1702{
1703 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1704
1705 trp_print_line(node, pck, indent, out);
1706
1707 if (*cnt <= mll) {
1708 /* success */
1709 return ret;
1710 } else {
1711 ret.indent = trp_indent_in_node_place_break(ret.indent);
1712 if (ret.indent.type != TRD_INDENT_IN_NODE_FAILED) {
1713 /* erase information in node due to line break */
1714 ret = trp_first_half_node(node, ret.indent);
1715 /* check if line fits, recursive call */
1716 *cnt = 0;
1717 ret = trp_try_normal_indent_in_node_(ret.node, pck, TRP_INIT_PCK_INDENT(indent.wrapper, ret.indent), mll, cnt, out);
1718 /* make sure that the result will be with the status divided
1719 * or eventually with status failed */
1720 ret.indent.type = ret.indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED;
1721 }
1722 return ret;
1723 }
1724}
1725
1726/**
1727 * @brief Get the correct alignment for the node.
1728 *
1729 * @param[in] node is \<node\> representation.
1730 * @param[in] pck contains speciall callback functions for printing.
1731 * @param[in] indent contains wrapper and indent in node numbers.
1732 * @param[in] mll is max line length.
1733 * @param[in,out] out is output handler.
aPiecek874ea4d2021-04-19 12:26:36 +02001734 * @return ::TRD_INDENT_IN_NODE_DIVIDED - the node does not fit in the
1735 * line, some indent variable has negative value as a line break sign.
1736 * @return ::TRD_INDENT_IN_NODE_NORMAL - the node fits into the line,
1737 * all indent variables values has non-negative number.
1738 * @return ::TRD_INDENT_IN_NODE_FAILED - the node does not fit into the
1739 * line, all indent variables has negative or zero values,
1740 * function failed.
aPiecek61d062b2020-11-02 11:05:09 +01001741 */
1742static struct trt_pair_indent_node
1743trp_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)
1744{
1745 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1746 struct ly_out_clb_arg *data;
1747
1748 /* set ly_out to counting characters */
1749 data = out->method.clb.arg;
1750
1751 data->counter = 0;
1752 data->mode = TRD_CHAR_COUNT;
1753 ret = trp_try_normal_indent_in_node_(node, pck, indent, mll, &data->counter, out);
1754 data->mode = TRD_PRINT;
1755
1756 return ret;
1757}
1758
1759/**
aPiecek01598c02021-04-23 14:18:24 +02001760 * @brief Auxiliary function for ::trp_print_entire_node()
aPiecek874ea4d2021-04-19 12:26:36 +02001761 * that prints split nodes.
aPiecek61d062b2020-11-02 11:05:09 +01001762 * @param[in] node is node representation.
1763 * @param[in] ppck contains speciall callback functions for printing.
1764 * @param[in] ipck contains wrapper and indent in node numbers.
1765 * @param[in] mll is max line length.
1766 * @param[in,out] out is output handler.
1767 */
1768static void
1769trp_print_divided_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1770{
1771 ly_bool entire_node_was_printed;
1772 struct trt_pair_indent_node ind_node = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1773
1774 if (ind_node.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1775 /* nothing can be done, continue as usual */
1776 ind_node.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1777 }
1778
1779 trp_print_line(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), out);
1780 entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, ind_node.indent);
1781
1782 if (!entire_node_was_printed) {
1783 ly_print_(out, "\n");
1784 /* continue with second half node */
1785 ind_node = trp_second_half_node(node, ind_node.indent);
1786 /* continue with printing node */
1787 trp_print_divided_node(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), mll, out);
1788 } else {
1789 return;
1790 }
1791}
1792
1793/**
aPiecek874ea4d2021-04-19 12:26:36 +02001794 * @brief Printing of the wrapper and the whole node,
1795 * which can be divided into several lines.
aPiecek61d062b2020-11-02 11:05:09 +01001796 * @param[in] node is node representation.
1797 * @param[in] ppck contains speciall callback functions for printing.
1798 * @param[in] ipck contains wrapper and indent in node numbers.
1799 * @param[in] mll is max line length.
1800 * @param[in,out] out is output handler.
1801 */
1802static void
1803trp_print_entire_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1804{
1805 struct trt_pair_indent_node ind_node1;
1806 struct trt_pair_indent_node ind_node2;
1807 struct trt_pck_indent tmp;
1808
1809 if (trp_leafref_target_is_too_long(node, ipck.wrapper, mll, out)) {
1810 node.type.type = TRD_TYPE_LEAFREF;
1811 }
1812
1813 /* check if normal indent is possible */
1814 ind_node1 = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1815
1816 if (ind_node1.indent.type == TRD_INDENT_IN_NODE_NORMAL) {
1817 /* node fits to one line */
1818 trp_print_line(node, ppck, ipck, out);
1819 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_DIVIDED) {
1820 /* node will be divided */
1821 /* print first half */
1822 tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node1.indent);
1823 /* pretend that this is normal node */
1824 tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL;
1825
1826 trp_print_line(ind_node1.node, ppck, tmp, out);
1827 ly_print_(out, "\n");
1828
1829 /* continue with second half on new line */
1830 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1831 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1832
1833 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1834 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1835 /* node name is too long */
1836 trp_print_line_up_to_node_name(node, ipck.wrapper, out);
1837
1838 if (trp_node_body_is_empty(node)) {
1839 return;
1840 } else {
1841 ly_print_(out, "\n");
1842
1843 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1844 ind_node2.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1845 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1846
1847 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1848 }
1849
1850 }
1851}
1852
aPiecek874ea4d2021-04-19 12:26:36 +02001853/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02001854 * trop and troc getters
aPiecekef1e58e2021-04-19 13:19:44 +02001855 *********************************************************************/
1856
1857/**
1858 * @brief Get nodetype.
1859 * @param[in] node is any lysp_node.
1860 */
1861static uint16_t
1862trop_nodetype(const void *node)
1863{
1864 return ((const struct lysp_node *)node)->nodetype;
1865}
1866
1867/**
1868 * @brief Get sibling.
1869 * @param[in] node is any lysp_node.
1870 */
1871static const void *
1872trop_next(const void *node)
1873{
1874 return ((const struct lysp_node *)node)->next;
1875}
1876
1877/**
1878 * @brief Get parent.
1879 * @param[in] node is any lysp_node.
1880 */
1881static const void *
1882trop_parent(const void *node)
1883{
1884 return ((const struct lysp_node *)node)->parent;
1885}
1886
1887/**
1888 * @brief Try to get child.
1889 * @param[in] node is any lysp_node.
1890 */
1891static const void *
1892trop_child(const void *node)
1893{
1894 return lysp_node_child(node);
1895}
1896
1897/**
1898 * @brief Try to get action.
1899 * @param[in] node is any lysp_node.
1900 */
1901static const void *
1902trop_actions(const void *node)
1903{
1904 return lysp_node_actions(node);
1905}
1906
1907/**
1908 * @brief Try to get action.
1909 * @param[in] node must be of type lysp_node_action.
1910 */
1911static const void *
1912trop_action_input(const void *node)
1913{
1914 return &((const struct lysp_node_action *)node)->input;
1915}
1916
1917/**
1918 * @brief Try to get action.
1919 * @param[in] node must be of type lysp_node_action.
1920 */
1921static const void *
1922trop_action_output(const void *node)
1923{
1924 return &((const struct lysp_node_action *)node)->output;
1925}
1926
1927/**
1928 * @brief Try to get action.
1929 * @param[in] node is any lysp_node.
1930 */
1931static const void *
1932trop_notifs(const void *node)
1933{
1934 return lysp_node_notifs(node);
1935}
1936
1937/**
aPiecek01598c02021-04-23 14:18:24 +02001938 * @brief Fill struct tro_getters with @ref TRP_trop getters
aPiecekef1e58e2021-04-19 13:19:44 +02001939 * which are adapted to lysp nodes.
1940 */
1941static struct tro_getters
1942trop_init_getters()
1943{
1944 return (struct tro_getters) {
1945 .nodetype = trop_nodetype,
1946 .next = trop_next,
1947 .parent = trop_parent,
1948 .child = trop_child,
1949 .actions = trop_actions,
1950 .action_input = trop_action_input,
1951 .action_output = trop_action_output,
1952 .notifs = trop_notifs
1953 };
1954}
1955
aPiecek3f247652021-04-19 13:40:25 +02001956/**
1957 * @brief Get nodetype.
1958 * @param[in] node is any lysc_node.
1959 */
1960static uint16_t
1961troc_nodetype(const void *node)
1962{
1963 return ((const struct lysc_node *)node)->nodetype;
1964}
1965
1966/**
1967 * @brief Get sibling.
1968 * @param[in] node is any lysc_node.
1969 */
1970static const void *
1971troc_next(const void *node)
1972{
1973 return ((const struct lysc_node *)node)->next;
1974}
1975
1976/**
1977 * @brief Get parent.
1978 * @param[in] node is any lysc_node.
1979 */
1980static const void *
1981troc_parent(const void *node)
1982{
1983 return ((const struct lysc_node *)node)->parent;
1984}
1985
1986/**
1987 * @brief Try to get child.
1988 * @param[in] node is any lysc_node.
1989 */
1990static const void *
1991troc_child(const void *node)
1992{
1993 return lysc_node_child(node);
1994}
1995
1996/**
1997 * @brief Try to get action.
1998 * @param[in] node is any lysc_node.
1999 */
2000static const void *
2001troc_actions(const void *node)
2002{
2003 return lysc_node_actions(node);
2004}
2005
2006/**
2007 * @brief Try to get action.
2008 * @param[in] node must be of type lysc_node_action.
2009 */
2010static const void *
2011troc_action_input(const void *node)
2012{
2013 return &((const struct lysc_node_action *)node)->input;
2014}
2015
2016/**
2017 * @brief Try to get action.
2018 * @param[in] node must be of type lysc_node_action.
2019 */
2020static const void *
2021troc_action_output(const void *node)
2022{
2023 return &((const struct lysc_node_action *)node)->output;
2024}
2025
2026/**
2027 * @brief Try to get action.
2028 * @param[in] node is any lysc_node.
2029 */
2030static const void *
2031troc_notifs(const void *node)
2032{
2033 return lysc_node_notifs(node);
2034}
2035
2036/**
aPiecek01598c02021-04-23 14:18:24 +02002037 * @brief Fill struct tro_getters with @ref TRP_troc getters
aPiecek3f247652021-04-19 13:40:25 +02002038 * which are adapted to lysc nodes.
2039 */
2040static struct tro_getters
2041troc_init_getters()
2042{
2043 return (struct tro_getters) {
2044 .nodetype = troc_nodetype,
2045 .next = troc_next,
2046 .parent = troc_parent,
2047 .child = troc_child,
2048 .actions = troc_actions,
2049 .action_input = troc_action_input,
2050 .action_output = troc_action_output,
2051 .notifs = troc_notifs
2052 };
2053}
2054
aPiecekef1e58e2021-04-19 13:19:44 +02002055/**********************************************************************
2056 * tro functions
2057 *********************************************************************/
2058
2059/**
2060 * @brief Get next sibling of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002061 *
2062 * This is a general algorithm that is able to
2063 * work with lysp_node or lysc_node.
2064 *
2065 * @param[in] node points to lysp_node or lysc_node.
2066 * @param[in] lysc_tree flag to determine what type the @p node is.
2067 * If set to true, then @p points to lysc_node otherwise lysp_node.
2068 * This flag should be the same as trt_tree_ctx.lysc_tree.
aPiecekef1e58e2021-04-19 13:19:44 +02002069 */
2070static const void *
aPiecek3f247652021-04-19 13:40:25 +02002071tro_next_sibling(const void *node, ly_bool lysc_tree)
aPiecekef1e58e2021-04-19 13:19:44 +02002072{
2073 struct tro_getters get;
2074 const void *tmp, *parent;
2075 const void *ret;
2076
2077 assert(node);
2078
aPiecek3f247652021-04-19 13:40:25 +02002079 get = lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002080
2081 if (get.nodetype(node) & (LYS_RPC | LYS_ACTION)) {
2082 if ((tmp = get.next(node))) {
2083 /* next action exists */
2084 ret = tmp;
2085 } else if ((parent = get.parent(node))) {
2086 /* maybe if notif exists as sibling */
2087 ret = get.notifs(parent);
2088 } else {
2089 ret = NULL;
2090 }
2091 } else if (get.nodetype(node) & LYS_INPUT) {
2092 if ((parent = get.parent(node))) {
2093 /* if output action has data */
2094 if (get.child(get.action_output(parent))) {
2095 /* then next sibling is output action */
2096 ret = get.action_output(parent);
2097 } else {
2098 /* input action cannot have siblings other
2099 * than output action.
2100 */
2101 ret = NULL;
2102 }
2103 } else {
2104 /* there is no way how to get output action */
2105 ret = NULL;
2106 }
2107 } else if (get.nodetype(node) & LYS_OUTPUT) {
2108 /* output action cannot have siblings */
2109 ret = NULL;
2110 } else if (get.nodetype(node) & LYS_NOTIF) {
2111 /* must have as a sibling only notif */
2112 ret = get.next(node);
2113 } else {
2114 /* for rest of nodes */
2115 if ((tmp = get.next(node))) {
2116 /* some sibling exists */
2117 ret = tmp;
2118 } else if ((parent = get.parent(node))) {
2119 /* Action and notif are siblings too.
2120 * They can be reached through parent.
2121 */
2122 if ((tmp = get.actions(parent))) {
2123 /* next sibling is action */
2124 ret = tmp;
2125 } else if ((tmp = get.notifs(parent))) {
2126 /* next sibling is notif */
2127 ret = tmp;
2128 } else {
2129 /* sibling not exists */
2130 ret = NULL;
2131 }
2132 } else {
2133 /* sibling not exists */
2134 ret = NULL;
2135 }
2136 }
2137
2138 return ret;
2139}
2140
2141/**
2142 * @brief Get child of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002143 *
2144 * This is a general algorithm that is able to
2145 * work with lysp_node or lysc_node.
2146 *
2147 * @param[in] node points to lysp_node or lysc_node.
2148 * @param[in] lysc_tree flag to determine what type the @p node is.
2149 * If set to true, then @p points to lysc_node otherwise lysp_node.
2150 * This flag should be the same as trt_tree_ctx.lysc_tree.
aPiecekef1e58e2021-04-19 13:19:44 +02002151 */
2152static const void *
aPiecek3f247652021-04-19 13:40:25 +02002153tro_next_child(const void *node, ly_bool lysc_tree)
aPiecekef1e58e2021-04-19 13:19:44 +02002154{
2155 struct tro_getters get;
2156 const void *tmp;
2157 const void *ret;
2158
2159 assert(node);
2160
aPiecek3f247652021-04-19 13:40:25 +02002161 get = lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002162
2163 if (get.nodetype(node) & (LYS_ACTION | LYS_RPC)) {
2164 if (get.child(get.action_input(node))) {
2165 /* go to LYS_INPUT */
2166 ret = get.action_input(node);
2167 } else if (get.child(get.action_output(node))) {
2168 /* go to LYS_OUTPUT */
2169 ret = get.action_output(node);
2170 } else {
2171 /* input action and output action have no data */
2172 ret = NULL;
2173 }
2174 } else {
2175 if ((tmp = get.child(node))) {
2176 ret = tmp;
2177 } else {
2178 /* current node can't have children or has no children */
2179 /* but maybe has some actions or notifs */
2180 if ((tmp = get.actions(node))) {
2181 ret = tmp;
2182 } else if ((tmp = get.notifs(node))) {
2183 ret = tmp;
2184 } else {
2185 ret = NULL;
2186 }
2187 }
2188 }
2189
2190 return ret;
2191}
2192
2193/**
aPiecek3f247652021-04-19 13:40:25 +02002194 * @brief Get new trt_parent_cache if we apply the transfer
2195 * to the child node in the tree.
2196 * @param[in] ca is parent cache for current node.
2197 * @param[in] tc contains current tree node.
2198 * @return Cache for the current node.
2199 */
2200static struct trt_parent_cache
2201tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2202{
2203 struct trt_parent_cache ret = TRP_EMPTY_PARENT_CACHE;
2204
2205 if (!tc->lysc_tree) {
2206 const struct lysp_node *pn = tc->pn;
2207
2208 ret.ancestor =
2209 pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT :
2210 pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT :
2211 pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF :
2212 ca.ancestor;
2213
2214 ret.lys_status =
2215 pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
2216 ca.lys_status;
2217
2218 ret.lys_config =
2219 ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because <flags> will be -w */
2220 ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
2221 pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
2222 ca.lys_config;
2223
2224 ret.last_list =
2225 pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
2226 ca.last_list;
2227 }
2228
2229 return ret;
2230}
2231
2232/**
aPiecekef1e58e2021-04-19 13:19:44 +02002233 * @brief Transformation of the Schema nodes flags to
2234 * Tree diagram \<status\>.
2235 * @param[in] flags is node's flags obtained from the tree.
2236 */
aPiecek41219f92022-10-26 11:24:40 +02002237static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002238tro_flags2status(uint16_t flags)
2239{
aPiecek41219f92022-10-26 11:24:40 +02002240 return flags & LYS_STATUS_OBSLT ? "o" :
2241 flags & LYS_STATUS_DEPRC ? "x" :
2242 "+";
aPiecekef1e58e2021-04-19 13:19:44 +02002243}
2244
2245/**
2246 * @brief Transformation of the Schema nodes flags to Tree diagram
2247 * \<flags\> but more specifically 'ro' or 'rw'.
2248 * @param[in] flags is node's flags obtained from the tree.
2249 */
aPiecek41219f92022-10-26 11:24:40 +02002250static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002251tro_flags2config(uint16_t flags)
2252{
2253 return flags & LYS_CONFIG_R ? TRD_FLAGS_TYPE_RO :
2254 flags & LYS_CONFIG_W ? TRD_FLAGS_TYPE_RW :
2255 TRD_FLAGS_TYPE_EMPTY;
2256}
2257
2258/**
aPiecek3f247652021-04-19 13:40:25 +02002259 * @brief Print current node's iffeatures.
2260 * @param[in] tc is tree context.
2261 * @param[in,out] out is output handler.
2262 */
2263static void
2264tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out)
2265{
2266 const struct lysp_qname *iffs;
2267
aPiecekbbc02932021-05-21 07:19:41 +02002268 if (tc->lysc_tree) {
2269 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2270 iffs = TRP_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures;
2271 } else {
2272 iffs = tc->pn->iffeatures;
2273 }
aPiecek3f247652021-04-19 13:40:25 +02002274 LY_ARRAY_COUNT_TYPE i;
2275
2276 LY_ARRAY_FOR(iffs, i) {
2277 if (i == 0) {
2278 ly_print_(out, "%s", iffs[i].str);
2279 } else {
2280 ly_print_(out, ",%s", iffs[i].str);
2281 }
2282 }
2283
2284}
2285
2286/**
2287 * @brief Print current list's keys.
2288 *
2289 * Well, actually printing keys in the lysp_tree is trivial,
2290 * because char* points to all keys. However, special functions have
2291 * been reserved for this, because in principle the list of elements
2292 * can have more implementations.
2293 *
2294 * @param[in] tc is tree context.
2295 * @param[in,out] out is output handler.
2296 */
2297static void
2298tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out)
2299{
2300 const struct lysp_node_list *list;
2301
aPiecekbbc02932021-05-21 07:19:41 +02002302 if (tc->lysc_tree) {
2303 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2304 list = (const struct lysp_node_list *)TRP_TREE_CTX_GET_LYSP_NODE(tc->cn);
2305 } else {
2306 list = (const struct lysp_node_list *)tc->pn;
2307 }
aPiecek3f247652021-04-19 13:40:25 +02002308 assert(list->nodetype & LYS_LIST);
2309
2310 if (trg_charptr_has_data(list->key)) {
2311 ly_print_(out, "%s", list->key);
2312 }
2313}
2314
2315/**
2316 * @brief Get rpcs section if exists.
2317 * @param[in,out] tc is tree context.
2318 * @return Section representation if it exists. The @p tc is modified
2319 * and his pointer points to the first node in rpcs section.
2320 * @return Empty section representation otherwise.
2321 */
2322static struct trt_keyword_stmt
2323tro_modi_get_rpcs(struct trt_tree_ctx *tc)
2324{
aPiecek9f792e52021-04-21 08:33:56 +02002325 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002326 const void *actions;
2327
2328 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002329 actions = tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002330 if (actions) {
2331 tc->cn = actions;
2332 }
2333 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002334 actions = tc->pmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002335 if (actions) {
2336 tc->pn = actions;
2337 tc->tpn = tc->pn;
2338 }
2339 }
2340
2341 if (actions) {
2342 tc->section = TRD_SECT_RPCS;
2343 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_RPC, NULL);
2344 } else {
2345 return TRP_EMPTY_KEYWORD_STMT;
2346 }
2347}
2348
2349/**
2350 * @brief Get notification section if exists
2351 * @param[in,out] tc is tree context.
2352 * @return Section representation if it exists.
2353 * The @p tc is modified and his pointer points to the
2354 * first node in notification section.
2355 * @return Empty section representation otherwise.
2356 */
2357static struct trt_keyword_stmt
2358tro_modi_get_notifications(struct trt_tree_ctx *tc)
2359{
aPiecek9f792e52021-04-21 08:33:56 +02002360 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002361 const void *notifs;
2362
2363 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002364 notifs = tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002365 if (notifs) {
2366 tc->cn = notifs;
2367 }
2368 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002369 notifs = tc->pmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002370 if (notifs) {
2371 tc->pn = notifs;
2372 tc->tpn = tc->pn;
2373 }
2374 }
2375
2376 if (notifs) {
2377 tc->section = TRD_SECT_NOTIF;
2378 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_NOTIF, NULL);
2379 } else {
2380 return TRP_EMPTY_KEYWORD_STMT;
2381 }
2382}
2383
2384/**
aPiecek96baa7f2021-04-23 12:32:00 +02002385 * @brief Get next yang-data section if it is possible.
aPiecekef1e58e2021-04-19 13:19:44 +02002386 *
2387 * @param[in,out] tc is tree context.
aPiecek96baa7f2021-04-23 12:32:00 +02002388 * @param[in] u is index to the array of extensions (lysc_ext_instance
2389 * or struct lysp_ext_instance).
aPiecekef1e58e2021-04-19 13:19:44 +02002390 * @return Section representation if it exists.
2391 * @return Empty section representation otherwise.
2392 */
2393static struct trt_keyword_stmt
aPiecek96baa7f2021-04-23 12:32:00 +02002394tro_modi_next_yang_data(struct trt_tree_ctx *tc, LY_ARRAY_COUNT_TYPE u)
aPiecekef1e58e2021-04-19 13:19:44 +02002395{
aPiecek96baa7f2021-04-23 12:32:00 +02002396 assert(tc);
2397 const void *node;
2398 const char *yang_data_name;
2399
2400 if (tc->lysc_tree) {
2401 struct lysc_ext_instance *exts;
2402 struct lysc_ext_substmt *substmts;
2403
2404 exts = tc->cmod->exts;
2405 substmts = exts[u].substmts;
2406 if (!substmts) {
2407 return TRP_EMPTY_KEYWORD_STMT;
2408 }
2409 node = *(const struct lysc_node **)substmts->storage;
2410 yang_data_name = exts[u].argument;
2411 } else {
2412 struct lysp_ext_instance *exts;
2413
2414 exts = tc->pmod->exts;
2415 node = exts[u].parsed;
2416 yang_data_name = exts[u].argument;
2417 }
2418
2419 if (tc->lysc_tree) {
2420 tc->cn = node;
2421 } else {
2422 tc->tpn_ext = &tc->pmod->exts[u];
2423 tc->pn = node;
2424 }
2425
2426 if (node) {
2427 tc->section = TRD_SECT_YANG_DATA;
2428 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_YANG_DATA, yang_data_name);
2429 } else {
2430 return TRP_EMPTY_KEYWORD_STMT;
2431 }
aPiecekef1e58e2021-04-19 13:19:44 +02002432}
2433
2434/**
2435 * @brief Get name of the module.
2436 * @param[in] tc is context of the tree.
2437 */
2438static struct trt_keyword_stmt
2439tro_read_module_name(const struct trt_tree_ctx *tc)
2440{
aPiecek9f792e52021-04-21 08:33:56 +02002441 assert(tc);
2442
2443 struct trt_keyword_stmt ret;
2444
2445 ret.type = !tc->lysc_tree && tc->pmod->is_submod ?
2446 TRD_KEYWORD_SUBMODULE :
2447 TRD_KEYWORD_MODULE;
2448
2449 ret.str = !tc->lysc_tree ?
2450 LYSP_MODULE_NAME(tc->pmod) :
2451 tc->cmod->mod->name;
2452
2453 return ret;
aPiecekef1e58e2021-04-19 13:19:44 +02002454}
2455
aPiecekb8d5a0a2021-05-20 08:20:24 +02002456/**
2457 * @brief Create implicit "case" node as parent of @p node.
2458 * @param[in] node child of implicit case node.
2459 * @return The case node ready to print.
2460 */
2461static struct trt_node
2462tro_create_implicit_case_node(struct trt_node node)
2463{
2464 struct trt_node ret;
2465
2466 ret.status = node.status;
2467 ret.flags = TRD_FLAGS_TYPE_EMPTY;
2468 ret.name.type = TRD_NODE_CASE;
aPiecekbca57772022-10-13 13:51:59 +02002469 ret.name.keys = node.name.keys;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002470 ret.name.module_prefix = node.name.module_prefix;
2471 ret.name.str = node.name.str;
aPiecek41219f92022-10-26 11:24:40 +02002472 ret.name.opts = node.name.opts;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002473 ret.type = TRP_EMPTY_TRT_TYPE;
aPiecek41219f92022-10-26 11:24:40 +02002474 ret.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002475 ret.last_one = node.last_one;
aPiecek50b64e42022-10-10 10:00:12 +02002476 ret.mount = NULL;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002477
2478 return ret;
2479}
2480
aPiecekef1e58e2021-04-19 13:19:44 +02002481/**********************************************************************
2482 * Definition of trop reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02002483 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002484
2485/**
aPiecek61d062b2020-11-02 11:05:09 +01002486 * @brief Check if list statement has keys.
2487 * @param[in] pn is pointer to the list.
2488 * @return 1 if has keys, otherwise 0.
2489 */
2490static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002491trop_list_has_keys(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002492{
aPiecekef1e58e2021-04-19 13:19:44 +02002493 return trg_charptr_has_data(((const struct lysp_node_list *)pn)->key);
aPiecek61d062b2020-11-02 11:05:09 +01002494}
2495
2496/**
2497 * @brief Check if it contains at least one feature.
aPiecek3f247652021-04-19 13:40:25 +02002498 * @param[in] pn is current node.
aPiecek61d062b2020-11-02 11:05:09 +01002499 * @return 1 if has if-features, otherwise 0.
2500 */
2501static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002502trop_node_has_iffeature(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002503{
2504 LY_ARRAY_COUNT_TYPE u;
aPiecekef1e58e2021-04-19 13:19:44 +02002505 const struct lysp_qname *iffs;
2506
aPiecek61d062b2020-11-02 11:05:09 +01002507 ly_bool ret = 0;
2508
aPiecekef1e58e2021-04-19 13:19:44 +02002509 iffs = pn->iffeatures;
aPiecek61d062b2020-11-02 11:05:09 +01002510 LY_ARRAY_FOR(iffs, u) {
2511 ret = 1;
2512 break;
2513 }
2514 return ret;
2515}
2516
2517/**
2518 * @brief Find out if leaf is also the key in last list.
2519 * @param[in] pn is pointer to leaf.
aPiecek874ea4d2021-04-19 12:26:36 +02002520 * @param[in] ca_last_list is pointer to last visited list.
2521 * Obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002522 * @return 1 if leaf is also the key, otherwise 0.
2523 */
2524static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002525trop_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
aPiecek61d062b2020-11-02 11:05:09 +01002526{
2527 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2528 const struct lysp_node_list *list = ca_last_list;
2529
2530 if (!list) {
2531 return 0;
2532 }
2533 return trg_charptr_has_data(list->key) ?
2534 trg_word_is_present(list->key, leaf->name, ' ') : 0;
2535}
2536
2537/**
2538 * @brief Check if container's type is presence.
2539 * @param[in] pn is pointer to container.
2540 * @return 1 if container has presence statement, otherwise 0.
2541 */
2542static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002543trop_container_has_presence(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002544{
2545 return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence);
2546}
2547
2548/**
aPiecek7ed8d032022-10-10 12:32:27 +02002549 * @brief Check if container has mount-point extension.
ekinzie0ab8b302022-10-10 03:03:57 -04002550 * @param[in] cn is pointer to container or list.
2551 * @param[out] mount is assigned a pointer to the extension instance, if found
aPiecek7ed8d032022-10-10 12:32:27 +02002552 * @return 1 if node has mount-point.
ekinzie0ab8b302022-10-10 03:03:57 -04002553 */
2554static ly_bool
2555troc_node_has_mount(const struct lysc_node *cn, struct lysc_ext_instance **mount)
2556{
2557 struct lysc_ext_instance *ext;
2558 uint64_t u;
2559
2560 /* The schema-mount extension plugin has already made sure that
2561 * there is only one mount-point here.
2562 */
2563 LY_ARRAY_FOR(cn->exts, u) {
2564 ext = &cn->exts[u];
2565 if (strcmp(ext->def->module->name, "ietf-yang-schema-mount") ||
2566 strcmp(ext->def->name, "mount-point")) {
2567 continue;
2568 }
2569 *mount = ext;
2570 return 1;
2571 }
2572 return 0;
2573}
2574
aPiecek7ed8d032022-10-10 12:32:27 +02002575/**
2576 * @brief Check if node has mount-point extension.
2577 *
2578 * @param[in] pn is pointer to container or list.
2579 * @return 1 if node has mount-point.
2580 */
ekinzie0ab8b302022-10-10 03:03:57 -04002581static ly_bool
2582trop_node_has_mount(const struct lysp_node *pn)
2583{
2584 struct lysp_ext_instance *ext;
2585 uint64_t u;
2586
2587 LY_ARRAY_FOR(pn->exts, u) {
2588 ext = &pn->exts[u];
2589 if (strcmp(ext->name, "yangmnt:mount-point")) {
2590 continue;
2591 }
2592 return 1;
2593 }
2594 return 0;
2595}
2596
2597/**
aPiecek61d062b2020-11-02 11:05:09 +01002598 * @brief Get leaflist's path without lysp_node type control.
2599 * @param[in] pn is pointer to the leaflist.
2600 */
2601static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002602trop_leaflist_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002603{
2604 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2605
2606 return list->type.path ? list->type.path->expr : NULL;
2607}
2608
2609/**
2610 * @brief Get leaflist's type name without lysp_node type control.
2611 * @param[in] pn is pointer to the leaflist.
2612 */
2613static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002614trop_leaflist_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002615{
2616 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2617
2618 return list->type.name;
2619}
2620
2621/**
2622 * @brief Get leaf's path without lysp_node type control.
2623 * @param[in] pn is pointer to the leaf node.
2624 */
2625static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002626trop_leaf_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002627{
2628 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2629
2630 return leaf->type.path ? leaf->type.path->expr : NULL;
2631}
2632
2633/**
2634 * @brief Get leaf's type name without lysp_node type control.
2635 * @param[in] pn is pointer to the leaf's type name.
2636 */
2637static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002638trop_leaf_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002639{
2640 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2641
2642 return leaf->type.name;
2643}
2644
2645/**
aPiecek874ea4d2021-04-19 12:26:36 +02002646 * @brief Get pointer to data using node type specification
2647 * and getter function.
aPiecek61d062b2020-11-02 11:05:09 +01002648 *
aPiecek874ea4d2021-04-19 12:26:36 +02002649 * @param[in] flags is node type specification.
2650 * If it is the correct node, the getter function is called.
2651 * @param[in] f is getter function which provides the desired
2652 * char pointer from the structure.
aPiecek61d062b2020-11-02 11:05:09 +01002653 * @param[in] pn pointer to node.
aPiecek874ea4d2021-04-19 12:26:36 +02002654 * @return NULL if node has wrong type or getter function return
2655 * pointer to NULL.
aPiecek61d062b2020-11-02 11:05:09 +01002656 * @return Pointer to desired char pointer obtained from the node.
2657 */
2658static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002659trop_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002660{
2661 if (pn->nodetype & flags) {
2662 const char *ret = f(pn);
Michal Vasko26bbb272022-08-02 14:54:33 +02002663
aPiecek61d062b2020-11-02 11:05:09 +01002664 return trg_charptr_has_data(ret) ? ret : NULL;
2665 } else {
2666 return NULL;
2667 }
2668}
2669
2670/**
aPiecek61d062b2020-11-02 11:05:09 +01002671 * @brief Resolve \<status\> of the current node.
2672 * @param[in] nodetype is node's type obtained from the tree.
2673 * @param[in] flags is node's flags obtained from the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002674 * @param[in] ca_lys_status is inherited status
2675 * obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002676 * @return The status type.
2677 */
aPiecek41219f92022-10-26 11:24:40 +02002678static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002679trop_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
aPiecek61d062b2020-11-02 11:05:09 +01002680{
aPiecek61d062b2020-11-02 11:05:09 +01002681 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02002682 /* LYS_INPUT and LYS_OUTPUT is special case */
aPiecekef1e58e2021-04-19 13:19:44 +02002683 return tro_flags2status(ca_lys_status);
2684 /* if ancestor's status is deprc or obslt
2685 * and also node's status is not set
2686 */
aPiecek61d062b2020-11-02 11:05:09 +01002687 } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
2688 /* get ancestor's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002689 return tro_flags2status(ca_lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002690 } else {
2691 /* else get node's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002692 return tro_flags2status(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002693 }
2694}
2695
2696/**
2697 * @brief Resolve \<flags\> of the current node.
2698 * @param[in] nodetype is node's type obtained from the tree.
2699 * @param[in] flags is node's flags obtained from the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002700 * @param[in] ca_ancestor is ancestor type obtained
2701 * from trt_parent_cache.
2702 * @param[in] ca_lys_config is inherited config item
2703 * obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002704 * @return The flags type.
2705 */
aPiecek41219f92022-10-26 11:24:40 +02002706static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002707trop_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config)
aPiecek61d062b2020-11-02 11:05:09 +01002708{
2709 if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) {
2710 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
2711 } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) {
2712 return TRD_FLAGS_TYPE_RO;
2713 } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) {
2714 return TRD_FLAGS_TYPE_RO;
2715 } else if (nodetype & LYS_NOTIF) {
2716 return TRD_FLAGS_TYPE_NOTIF;
2717 } else if (nodetype & LYS_USES) {
2718 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
2719 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
2720 return TRD_FLAGS_TYPE_RPC;
aPiecek61d062b2020-11-02 11:05:09 +01002721 } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002722 /* config is not set. Look at ancestor's config */
2723 return tro_flags2config(ca_lys_config);
aPiecek61d062b2020-11-02 11:05:09 +01002724 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02002725 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002726 }
2727}
2728
2729/**
2730 * @brief Resolve node type of the current node.
2731 * @param[in] pn is pointer to the current node in the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002732 * @param[in] ca_last_list is pointer to the last visited list.
2733 * Obtained from the trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002734 */
aPiecek41219f92022-10-26 11:24:40 +02002735static void
2736trop_resolve_node_opts(const struct trt_tree_ctx *tc, const struct lysp_node_list *ca_last_list, trt_node_type *type,
2737 char **opts)
aPiecek61d062b2020-11-02 11:05:09 +01002738{
ekinzie0ab8b302022-10-10 03:03:57 -04002739 const struct lysp_node *pn = tc->pn;
2740
aPiecek61d062b2020-11-02 11:05:09 +01002741 if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02002742 *type = TRD_NODE_ELSE;
aPiecek61d062b2020-11-02 11:05:09 +01002743 } else if (pn->nodetype & LYS_CASE) {
aPiecek41219f92022-10-26 11:24:40 +02002744 *type = TRD_NODE_CASE;
aPiecek61d062b2020-11-02 11:05:09 +01002745 } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02002746 *type = TRD_NODE_CHOICE;
2747 *opts = TRD_NODE_OPTIONAL;
aPiecek61d062b2020-11-02 11:05:09 +01002748 } else if (pn->nodetype & LYS_CHOICE) {
aPiecek41219f92022-10-26 11:24:40 +02002749 *type = TRD_NODE_CHOICE;
ekinzie0ab8b302022-10-10 03:03:57 -04002750 } else if (tc->mounted && (tc->pn->parent == NULL)) {
2751 if (tc->parent_refs) {
2752 for (uint32_t v = 0; v < tc->parent_refs->count; v++) {
2753 if (!strcmp(tc->pmod->mod->ns, tc->parent_refs->snodes[v]->module->ns)) {
aPiecek41219f92022-10-26 11:24:40 +02002754 *opts = "@";
2755 *type = TRD_NODE_TOP_LEVEL2;
2756 return;
ekinzie0ab8b302022-10-10 03:03:57 -04002757 }
2758 }
2759 }
aPiecek41219f92022-10-26 11:24:40 +02002760 *opts = "/";
2761 *type = TRD_NODE_TOP_LEVEL1;
aPiecekef1e58e2021-04-19 13:19:44 +02002762 } else if ((pn->nodetype & LYS_CONTAINER) && (trop_container_has_presence(pn))) {
aPiecek41219f92022-10-26 11:24:40 +02002763 *opts = TRD_NODE_CONTAINER;
aPiecek61d062b2020-11-02 11:05:09 +01002764 } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
aPiecek41219f92022-10-26 11:24:40 +02002765 *opts = TRD_NODE_LISTLEAFLIST;
aPiecek61d062b2020-11-02 11:05:09 +01002766 } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02002767 *opts = TRD_NODE_OPTIONAL;
aPiecekef1e58e2021-04-19 13:19:44 +02002768 } else if ((pn->nodetype & LYS_LEAF) && !(pn->flags & LYS_MAND_TRUE) && (!trop_leaf_is_key(pn, ca_last_list))) {
aPiecek41219f92022-10-26 11:24:40 +02002769 *opts = TRD_NODE_OPTIONAL;
aPiecek61d062b2020-11-02 11:05:09 +01002770 } else {
aPiecek41219f92022-10-26 11:24:40 +02002771 *type = TRD_NODE_ELSE;
aPiecek61d062b2020-11-02 11:05:09 +01002772 }
2773}
2774
2775/**
aPiecekef1e58e2021-04-19 13:19:44 +02002776 * @brief Resolve \<type\> of the current node.
2777 * @param[in] pn is current node.
2778 */
2779static struct trt_type
2780trop_resolve_type(const struct lysp_node *pn)
2781{
2782 const char *tmp = NULL;
2783
2784 if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_refpath, pn))) {
2785 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2786 } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_type_name, pn))) {
2787 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2788 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_refpath, pn))) {
2789 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2790 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_type_name, pn))) {
2791 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2792 } else if (pn->nodetype == LYS_ANYDATA) {
2793 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata");
2794 } else if (pn->nodetype & LYS_ANYXML) {
2795 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml");
2796 } else {
2797 return TRP_EMPTY_TRT_TYPE;
2798 }
2799}
2800
2801/**
aPiecek61d062b2020-11-02 11:05:09 +01002802 * @brief Transformation of current lysp_node to struct trt_node.
aPiecek874ea4d2021-04-19 12:26:36 +02002803 * @param[in] ca contains stored important data
2804 * when browsing the tree downwards.
aPiecek61d062b2020-11-02 11:05:09 +01002805 * @param[in] tc is context of the tree.
2806 */
2807static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02002808trop_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002809{
aPiecekef1e58e2021-04-19 13:19:44 +02002810 const struct lysp_node *pn;
2811 struct trt_node ret;
2812
aPiecek61d062b2020-11-02 11:05:09 +01002813 assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
aPiecekef1e58e2021-04-19 13:19:44 +02002814
2815 pn = tc->pn;
2816 ret = TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01002817
2818 /* <status> */
aPiecekef1e58e2021-04-19 13:19:44 +02002819 ret.status = trop_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002820
aPiecek61d062b2020-11-02 11:05:09 +01002821 /* <flags> */
ekinzie0ab8b302022-10-10 03:03:57 -04002822 if (trop_node_has_mount(pn)) {
2823 ret.flags = TRD_FLAGS_TYPE_MOUNT_POINT;
2824 } else {
2825 ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config);
2826 }
aPiecek61d062b2020-11-02 11:05:09 +01002827
aPiecek61d062b2020-11-02 11:05:09 +01002828 /* set type of the node */
aPiecek41219f92022-10-26 11:24:40 +02002829 trop_resolve_node_opts(tc, ca.last_list, &ret.name.type, &ret.name.opts);
aPiecekbca57772022-10-13 13:51:59 +02002830 ret.name.keys = (tc->pn->nodetype & LYS_LIST) && trop_list_has_keys(tc->pn);
aPiecek61d062b2020-11-02 11:05:09 +01002831
aPiecek34fa3772021-05-21 12:35:46 +02002832 /* The parsed tree is not compiled, so no node can be augmented
2833 * from another module. This means that nodes from the parsed tree
2834 * will never have the prefix.
2835 */
aPiecek61d062b2020-11-02 11:05:09 +01002836 ret.name.module_prefix = NULL;
2837
2838 /* set node's name */
2839 ret.name.str = pn->name;
2840
2841 /* <type> */
aPiecekef1e58e2021-04-19 13:19:44 +02002842 ret.type = trop_resolve_type(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002843
2844 /* <iffeature> */
aPiecek41219f92022-10-26 11:24:40 +02002845 ret.iffeatures.type = trop_node_has_iffeature(pn) ? TRD_IFF_PRESENT : TRD_IFF_NON_PRESENT;
aPiecek61d062b2020-11-02 11:05:09 +01002846
aPiecek3f247652021-04-19 13:40:25 +02002847 ret.last_one = !tro_next_sibling(pn, tc->lysc_tree);
aPiecek61d062b2020-11-02 11:05:09 +01002848
2849 return ret;
2850}
2851
aPiecekef1e58e2021-04-19 13:19:44 +02002852/**
2853 * @brief Find out if the current node has siblings.
2854 * @param[in] tc is context of the tree.
2855 * @return 1 if sibling exists otherwise 0.
2856 */
2857static ly_bool
2858trop_read_if_sibling_exists(const struct trt_tree_ctx *tc)
2859{
aPiecek3f247652021-04-19 13:40:25 +02002860 return tro_next_sibling(tc->pn, tc->lysc_tree) != NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002861}
2862
aPiecek96baa7f2021-04-23 12:32:00 +02002863/**
2864 * @brief Print all yang-data sections and print three dots instead
2865 * of nodes.
2866 * @param[in] exts is array of YANG extension instances from parsed
2867 * module (@ref sizedarrays).
2868 * @param[in] mll is maximum number of characters that can be printed
2869 * on one line.
2870 * @param[in,out] out is output handler.
2871 */
2872static void
2873trop_yang_data_sections(const struct lysp_ext_instance *exts, size_t mll, struct ly_out *out)
2874{
2875 struct trt_keyword_stmt ks;
2876 LY_ARRAY_COUNT_TYPE u;
2877 struct trt_wrapper wr;
2878
2879 if (!exts) {
2880 return;
2881 }
2882
2883 ly_print_(out, "\n");
2884 ks.type = TRD_KEYWORD_YANG_DATA;
2885 wr = TRP_INIT_WRAPPER_BODY;
2886
2887 LY_ARRAY_FOR(exts, u) {
2888 ly_print_(out, "\n");
2889
2890 /* yang-data <yang-data-name>: */
2891 ks.str = exts[u].argument;
2892 trp_print_keyword_stmt(ks, mll, 0, out);
2893 ly_print_(out, "\n");
2894
2895 /* ... */
2896 trp_print_wrapper(wr, out);
2897 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
2898 }
2899}
2900
aPiecek874ea4d2021-04-19 12:26:36 +02002901/**********************************************************************
aPiecekef1e58e2021-04-19 13:19:44 +02002902 * Modify trop getters
aPiecek874ea4d2021-04-19 12:26:36 +02002903 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002904
2905/**
aPiecek874ea4d2021-04-19 12:26:36 +02002906 * @brief Change current node pointer to its parent
2907 * but only if parent exists.
2908 * @param[in,out] tc is tree context.
2909 * Contains pointer to the current node.
aPiecek61d062b2020-11-02 11:05:09 +01002910 * @return 1 if the node had parents and the change was successful.
aPiecek874ea4d2021-04-19 12:26:36 +02002911 * @return 0 if the node did not have parents.
2912 * The pointer to the current node did not change.
aPiecek61d062b2020-11-02 11:05:09 +01002913 */
2914static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002915trop_modi_parent(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002916{
2917 assert(tc && tc->pn);
2918 /* If no parent exists, stay in actual node. */
aPiecek96baa7f2021-04-23 12:32:00 +02002919 if ((tc->pn != tc->tpn) && (tc->pn->parent)) {
aPiecek61d062b2020-11-02 11:05:09 +01002920 tc->pn = tc->pn->parent;
2921 return 1;
2922 } else {
2923 return 0;
2924 }
2925}
2926
2927/**
aPiecek874ea4d2021-04-19 12:26:36 +02002928 * @brief Change the current node pointer to its child
2929 * but only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01002930 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02002931 * @param[in,out] tc is context of the tree.
2932 * Contains pointer to the current node.
2933 * @return Non-empty \<node\> representation of the current
2934 * node's child. The @p tc is modified.
2935 * @return Empty \<node\> representation if child don't exists.
2936 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01002937 */
2938static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02002939trop_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002940{
aPiecekef1e58e2021-04-19 13:19:44 +02002941 const struct lysp_node *tmp;
2942
aPiecek61d062b2020-11-02 11:05:09 +01002943 assert(tc && tc->pn);
2944
aPiecek3f247652021-04-19 13:40:25 +02002945 if ((tmp = tro_next_child(tc->pn, tc->lysc_tree))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002946 tc->pn = tmp;
aPiecek67521c22022-10-19 09:15:02 +02002947 return trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01002948 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02002949 return TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01002950 }
2951}
2952
2953/**
aPiecek874ea4d2021-04-19 12:26:36 +02002954 * @brief Change the current node pointer to the first child of node's
2955 * parent. If current node is already first sibling/child then nothing
2956 * will change.
aPiecek61d062b2020-11-02 11:05:09 +01002957 * @param[in,out] tc is tree context.
2958 */
2959static void
aPiecekef1e58e2021-04-19 13:19:44 +02002960trop_modi_first_sibling(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002961{
aPiecek9f792e52021-04-21 08:33:56 +02002962 assert(tc && tc->pn && tc->pmod);
aPiecek61d062b2020-11-02 11:05:09 +01002963
aPiecekef1e58e2021-04-19 13:19:44 +02002964 if (trop_modi_parent(tc)) {
2965 trop_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
aPiecek61d062b2020-11-02 11:05:09 +01002966 } else {
2967 /* current node is top-node */
aPiecek61d062b2020-11-02 11:05:09 +01002968 switch (tc->section) {
2969 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02002970 tc->pn = tc->pmod->data;
aPiecek96baa7f2021-04-23 12:32:00 +02002971 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002972 break;
2973 case TRD_SECT_AUGMENT:
aPiecek9f792e52021-04-21 08:33:56 +02002974 tc->pn = (const struct lysp_node *)tc->pmod->augments;
aPiecek96baa7f2021-04-23 12:32:00 +02002975 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002976 break;
2977 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02002978 tc->pn = (const struct lysp_node *)tc->pmod->rpcs;
aPiecek96baa7f2021-04-23 12:32:00 +02002979 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002980 break;
2981 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02002982 tc->pn = (const struct lysp_node *)tc->pmod->notifs;
aPiecek96baa7f2021-04-23 12:32:00 +02002983 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002984 break;
2985 case TRD_SECT_GROUPING:
aPiecek9f792e52021-04-21 08:33:56 +02002986 tc->pn = (const struct lysp_node *)tc->pmod->groupings;
aPiecek96baa7f2021-04-23 12:32:00 +02002987 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002988 break;
2989 case TRD_SECT_YANG_DATA:
aPiecek96baa7f2021-04-23 12:32:00 +02002990 /* tpn in this case is of type lysp_ext_instance */
2991 tc->pn = tc->tpn_ext->parsed;
aPiecek61d062b2020-11-02 11:05:09 +01002992 break;
aPiecek96baa7f2021-04-23 12:32:00 +02002993 default:
2994 assert(0);
aPiecek61d062b2020-11-02 11:05:09 +01002995 }
aPiecek61d062b2020-11-02 11:05:09 +01002996 }
2997}
2998
2999/**
aPiecek874ea4d2021-04-19 12:26:36 +02003000 * @brief Change the pointer to the current node to its next sibling
3001 * only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01003002 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02003003 * @param[in,out] tc is tree context.
3004 * Contains pointer to the current node.
3005 * @return Non-empty \<node\> representation if sibling exists.
3006 * The @p tc is modified.
3007 * @return Empty \<node\> representation otherwise.
3008 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01003009 */
3010static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02003011trop_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003012{
aPiecekef1e58e2021-04-19 13:19:44 +02003013 const struct lysp_node *pn;
aPiecekef1e58e2021-04-19 13:19:44 +02003014
3015 assert(tc && tc->pn);
3016
aPiecek3f247652021-04-19 13:40:25 +02003017 pn = tro_next_sibling(tc->pn, tc->lysc_tree);
aPiecek61d062b2020-11-02 11:05:09 +01003018
aPiecekef1e58e2021-04-19 13:19:44 +02003019 if (pn) {
aPiecek96baa7f2021-04-23 12:32:00 +02003020 if ((tc->tpn == tc->pn) && (tc->section != TRD_SECT_YANG_DATA)) {
3021 tc->tpn = pn;
3022 }
aPiecekef1e58e2021-04-19 13:19:44 +02003023 tc->pn = pn;
aPiecekef1e58e2021-04-19 13:19:44 +02003024 return trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003025 } else {
3026 return TRP_EMPTY_NODE;
3027 }
3028}
3029
3030/**
3031 * @brief Get next (or first) augment section if exists.
aPiecek874ea4d2021-04-19 12:26:36 +02003032 * @param[in,out] tc is tree context. It is modified and his current
3033 * node is set to the lysp_node_augment.
aPiecek61d062b2020-11-02 11:05:09 +01003034 * @return Section's representation if (next augment) section exists.
aPiecek61d062b2020-11-02 11:05:09 +01003035 * @return Empty section structure otherwise.
3036 */
3037static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003038trop_modi_next_augment(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003039{
aPiecek9f792e52021-04-21 08:33:56 +02003040 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003041 const struct lysp_node_augment *augs;
3042
3043 /* if next_augment func was called for the first time */
3044 if (tc->section != TRD_SECT_AUGMENT) {
3045 tc->section = TRD_SECT_AUGMENT;
aPiecek9f792e52021-04-21 08:33:56 +02003046 augs = tc->pmod->augments;
aPiecek61d062b2020-11-02 11:05:09 +01003047 } else {
3048 /* get augment sibling from top-node pointer */
aPiecekdc8fd572021-04-19 10:47:23 +02003049 augs = (const struct lysp_node_augment *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003050 }
3051
aPiecekdc8fd572021-04-19 10:47:23 +02003052 if (augs) {
3053 tc->pn = &augs->node;
aPiecek61d062b2020-11-02 11:05:09 +01003054 tc->tpn = tc->pn;
3055 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_AUGMENT, augs->nodeid);
3056 } else {
3057 return TRP_EMPTY_KEYWORD_STMT;
3058 }
3059}
3060
3061/**
aPiecek61d062b2020-11-02 11:05:09 +01003062 * @brief Get next (or first) grouping section if exists
aPiecek874ea4d2021-04-19 12:26:36 +02003063 * @param[in,out] tc is tree context. It is modified and his current
3064 * node is set to the lysp_node_grp.
aPiecek61d062b2020-11-02 11:05:09 +01003065 * @return The next (or first) section representation if it exists.
aPiecek61d062b2020-11-02 11:05:09 +01003066 * @return Empty section representation otherwise.
3067 */
3068static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003069trop_modi_next_grouping(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003070{
aPiecek9f792e52021-04-21 08:33:56 +02003071 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003072 const struct lysp_node_grp *grps;
3073
3074 if (tc->section != TRD_SECT_GROUPING) {
3075 tc->section = TRD_SECT_GROUPING;
aPiecek9f792e52021-04-21 08:33:56 +02003076 grps = tc->pmod->groupings;
aPiecek61d062b2020-11-02 11:05:09 +01003077 } else {
aPiecekdc8fd572021-04-19 10:47:23 +02003078 grps = (const struct lysp_node_grp *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003079 }
3080
aPiecekdc8fd572021-04-19 10:47:23 +02003081 if (grps) {
3082 tc->pn = &grps->node;
aPiecek61d062b2020-11-02 11:05:09 +01003083 tc->tpn = tc->pn;
3084 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_GROUPING, grps->name);
3085 } else {
3086 return TRP_EMPTY_KEYWORD_STMT;
3087 }
3088}
3089
aPiecek874ea4d2021-04-19 12:26:36 +02003090/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02003091 * Definition of troc reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02003092 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003093
3094/**
aPiecek3f247652021-04-19 13:40:25 +02003095 * @copydoc trop_read_if_sibling_exists
aPiecek61d062b2020-11-02 11:05:09 +01003096 */
aPiecek3f247652021-04-19 13:40:25 +02003097static ly_bool
3098troc_read_if_sibling_exists(const struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003099{
aPiecek3f247652021-04-19 13:40:25 +02003100 return tro_next_sibling(tc->cn, tc->lysc_tree) != NULL;
3101}
aPiecek61d062b2020-11-02 11:05:09 +01003102
aPiecek3f247652021-04-19 13:40:25 +02003103/**
3104 * @brief Resolve \<flags\> of the current node.
3105 *
3106 * Use this function only if trt_tree_ctx.lysc_tree is true.
3107 *
3108 * @param[in] nodetype is current lysc_node.nodetype.
3109 * @param[in] flags is current lysc_node.flags.
3110 * @return The flags type.
3111 */
aPiecek41219f92022-10-26 11:24:40 +02003112static char *
aPiecek3f247652021-04-19 13:40:25 +02003113troc_resolve_flags(uint16_t nodetype, uint16_t flags)
3114{
3115 if ((nodetype & LYS_INPUT) || (flags & LYS_IS_INPUT)) {
3116 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
3117 } else if ((nodetype & LYS_OUTPUT) || (flags & LYS_IS_OUTPUT)) {
3118 return TRD_FLAGS_TYPE_RO;
3119 } else if (nodetype & LYS_IS_NOTIF) {
3120 return TRD_FLAGS_TYPE_RO;
3121 } else if (nodetype & LYS_NOTIF) {
3122 return TRD_FLAGS_TYPE_NOTIF;
3123 } else if (nodetype & LYS_USES) {
3124 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
3125 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
3126 return TRD_FLAGS_TYPE_RPC;
3127 } else {
3128 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01003129 }
aPiecek61d062b2020-11-02 11:05:09 +01003130}
3131
3132/**
aPiecek3f247652021-04-19 13:40:25 +02003133 * @brief Resolve node type of the current node.
aPiecek61d062b2020-11-02 11:05:09 +01003134 *
aPiecek3f247652021-04-19 13:40:25 +02003135 * Use this function only if trt_tree_ctx.lysc_tree is true.
aPiecek61d062b2020-11-02 11:05:09 +01003136 *
aPiecek3f247652021-04-19 13:40:25 +02003137 * @param[in] nodetype is current lysc_node.nodetype.
3138 * @param[in] flags is current lysc_node.flags.
3139 */
aPiecek41219f92022-10-26 11:24:40 +02003140static void
3141troc_resolve_node_opts(uint16_t nodetype, uint16_t flags, const struct trt_tree_ctx *tc, trt_node_type *type, char **opts)
aPiecek3f247652021-04-19 13:40:25 +02003142{
3143 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02003144 *type = TRD_NODE_ELSE;
aPiecek3f247652021-04-19 13:40:25 +02003145 } else if (nodetype & LYS_CASE) {
aPiecek41219f92022-10-26 11:24:40 +02003146 *type = TRD_NODE_CASE;
aPiecek3f247652021-04-19 13:40:25 +02003147 } else if ((nodetype & LYS_CHOICE) && !(flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02003148 *type = TRD_NODE_CHOICE;
3149 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003150 } else if (nodetype & LYS_CHOICE) {
aPiecek41219f92022-10-26 11:24:40 +02003151 *type = TRD_NODE_CHOICE;
ekinzie0ab8b302022-10-10 03:03:57 -04003152 } else if (tc->mounted && (tc->cn->parent == NULL)) {
3153 if (tc->parent_refs) {
3154 for (uint32_t v = 0; v < tc->parent_refs->count; v++) {
3155 if (!strcmp(tc->cn->module->ns, tc->parent_refs->snodes[v]->module->ns)) {
aPiecek41219f92022-10-26 11:24:40 +02003156 *opts = "@";
3157 *type = TRD_NODE_TOP_LEVEL2;
3158 return;
ekinzie0ab8b302022-10-10 03:03:57 -04003159 }
3160 }
3161 }
aPiecek41219f92022-10-26 11:24:40 +02003162 *opts = "/";
3163 *type = TRD_NODE_TOP_LEVEL1;
aPiecek3f247652021-04-19 13:40:25 +02003164 } else if ((nodetype & LYS_CONTAINER) && (flags & LYS_PRESENCE)) {
aPiecek41219f92022-10-26 11:24:40 +02003165 *opts = TRD_NODE_CONTAINER;
aPiecek3f247652021-04-19 13:40:25 +02003166 } else if (nodetype & (LYS_LIST | LYS_LEAFLIST)) {
aPiecek41219f92022-10-26 11:24:40 +02003167 *opts = TRD_NODE_LISTLEAFLIST;
aPiecek3f247652021-04-19 13:40:25 +02003168 } else if ((nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02003169 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003170 } else if ((nodetype & LYS_LEAF) && !(flags & (LYS_MAND_TRUE | LYS_KEY))) {
aPiecek41219f92022-10-26 11:24:40 +02003171 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003172 } else {
aPiecek41219f92022-10-26 11:24:40 +02003173 *type = TRD_NODE_ELSE;
aPiecek3f247652021-04-19 13:40:25 +02003174 }
3175}
3176
3177/**
aPiecek34fa3772021-05-21 12:35:46 +02003178 * @brief Resolve prefix (<prefix>:<name>) of node that has been
3179 * placed from another module via an augment statement.
3180 *
3181 * @param[in] cn is current compiled node.
3182 * @param[in] current_compiled_module is module whose nodes are
3183 * currently being printed.
3184 * @return Prefix of foreign module or NULL.
3185 */
3186static const char *
3187troc_resolve_node_prefix(const struct lysc_node *cn, const struct lysc_module *current_compiled_module)
3188{
3189 const struct lys_module *node_module;
3190 const char *ret = NULL;
3191
3192 node_module = cn->module;
3193 if (node_module->compiled != current_compiled_module) {
3194 ret = node_module->prefix;
3195 }
3196
3197 return ret;
3198}
3199
3200/**
aPiecek3f247652021-04-19 13:40:25 +02003201 * @brief Transformation of current lysc_node to struct trt_node.
3202 * @param[in] ca is not used.
3203 * @param[in] tc is context of the tree.
3204 */
3205static struct trt_node
3206troc_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
3207{
3208 (void) ca;
3209 const struct lysc_node *cn;
3210 struct trt_node ret;
3211
aPiecek082c7dc2021-05-20 08:55:07 +02003212 assert(tc && tc->cn);
aPiecek3f247652021-04-19 13:40:25 +02003213
3214 cn = tc->cn;
3215 ret = TRP_EMPTY_NODE;
3216
3217 /* <status> */
3218 ret.status = tro_flags2status(cn->flags);
3219
aPiecek3f247652021-04-19 13:40:25 +02003220 /* <flags> */
ekinzie0ab8b302022-10-10 03:03:57 -04003221 if (troc_node_has_mount(cn, &ret.mount)) {
3222 ret.flags = TRD_FLAGS_TYPE_MOUNT_POINT;
3223 } else {
3224 ret.flags = troc_resolve_flags(cn->nodetype, cn->flags);
3225 }
aPiecek3f247652021-04-19 13:40:25 +02003226
aPiecek3f247652021-04-19 13:40:25 +02003227 /* set type of the node */
aPiecek41219f92022-10-26 11:24:40 +02003228 troc_resolve_node_opts(cn->nodetype, cn->flags, tc, &ret.name.type, &ret.name.opts);
aPiecekbca57772022-10-13 13:51:59 +02003229 ret.name.keys = (cn->nodetype & LYS_LIST) && !(cn->flags & LYS_KEYLESS);
aPiecek3f247652021-04-19 13:40:25 +02003230
aPiecek34fa3772021-05-21 12:35:46 +02003231 /* <prefix> */
3232 ret.name.module_prefix = troc_resolve_node_prefix(cn, tc->cmod);
aPiecek3f247652021-04-19 13:40:25 +02003233
3234 /* set node's name */
3235 ret.name.str = cn->name;
3236
aPiecekbbc02932021-05-21 07:19:41 +02003237 if (TRP_TREE_CTX_LYSP_NODE_PRESENT(cn)) {
aPiecek082c7dc2021-05-20 08:55:07 +02003238 /* <type> */
3239 ret.type = trop_resolve_type(TRP_TREE_CTX_GET_LYSP_NODE(cn));
aPiecek3f247652021-04-19 13:40:25 +02003240
aPiecek082c7dc2021-05-20 08:55:07 +02003241 /* <iffeature> */
aPiecek41219f92022-10-26 11:24:40 +02003242 ret.iffeatures.type = trop_node_has_iffeature(TRP_TREE_CTX_GET_LYSP_NODE(cn)) ? TRD_IFF_PRESENT : TRD_IFF_NON_PRESENT;
aPiecek082c7dc2021-05-20 08:55:07 +02003243 } else {
aPiecekbbc02932021-05-21 07:19:41 +02003244 /* only the implicit case node doesn't have access to lysp node */
aPiecek082c7dc2021-05-20 08:55:07 +02003245 assert(tc->cn->nodetype & LYS_CASE);
3246
3247 /* <type> */
3248 ret.type = TRP_EMPTY_TRT_TYPE;
3249
aPiecek7a28e2f2021-05-21 07:27:03 +02003250 /* <iffeature> */
aPiecek41219f92022-10-26 11:24:40 +02003251 ret.iffeatures.type = TRD_IFF_NON_PRESENT;
aPiecek082c7dc2021-05-20 08:55:07 +02003252 }
aPiecek3f247652021-04-19 13:40:25 +02003253
3254 ret.last_one = !tro_next_sibling(cn, tc->lysc_tree);
3255
3256 return ret;
3257}
3258
3259/**********************************************************************
3260 * Modify troc getters
3261 *********************************************************************/
3262
3263/**
aPiecek01598c02021-04-23 14:18:24 +02003264 * @copydoc ::trop_modi_parent()
aPiecek3f247652021-04-19 13:40:25 +02003265 */
3266static ly_bool
3267troc_modi_parent(struct trt_tree_ctx *tc)
3268{
3269 assert(tc && tc->cn);
3270 /* If no parent exists, stay in actual node. */
3271 if (tc->cn->parent) {
3272 tc->cn = tc->cn->parent;
3273 return 1;
3274 } else {
3275 return 0;
3276 }
3277}
3278
3279/**
aPiecek01598c02021-04-23 14:18:24 +02003280 * @copydoc ::trop_modi_next_sibling()
aPiecek3f247652021-04-19 13:40:25 +02003281 */
3282static struct trt_node
3283troc_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3284{
3285 const struct lysc_node *cn;
3286
3287 assert(tc && tc->cn);
3288
3289 cn = tro_next_sibling(tc->cn, tc->lysc_tree);
3290
3291 /* if next sibling exists */
3292 if (cn) {
3293 /* update trt_tree_ctx */
3294 tc->cn = cn;
3295 return troc_read_node(ca, tc);
3296 } else {
3297 return TRP_EMPTY_NODE;
3298 }
3299}
3300
3301/**
3302 * @copydoc trop_modi_next_child()
3303 */
3304static struct trt_node
3305troc_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3306{
3307 const struct lysc_node *tmp;
3308
3309 assert(tc && tc->cn);
3310
3311 if ((tmp = tro_next_child(tc->cn, tc->lysc_tree))) {
3312 tc->cn = tmp;
3313 return troc_read_node(ca, tc);
3314 } else {
3315 return TRP_EMPTY_NODE;
3316 }
3317}
3318
3319/**
aPiecek01598c02021-04-23 14:18:24 +02003320 * @copydoc ::trop_modi_first_sibling()
aPiecek61d062b2020-11-02 11:05:09 +01003321 */
3322static void
aPiecek3f247652021-04-19 13:40:25 +02003323troc_modi_first_sibling(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003324{
aPiecek3f247652021-04-19 13:40:25 +02003325 assert(tc && tc->cn);
aPiecek61d062b2020-11-02 11:05:09 +01003326
aPiecek3f247652021-04-19 13:40:25 +02003327 if (troc_modi_parent(tc)) {
3328 troc_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
3329 } else {
3330 /* current node is top-node */
aPiecek3f247652021-04-19 13:40:25 +02003331 switch (tc->section) {
3332 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02003333 tc->cn = tc->cmod->data;
aPiecek3f247652021-04-19 13:40:25 +02003334 break;
3335 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02003336 tc->cn = (const struct lysc_node *)tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02003337 break;
3338 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02003339 tc->cn = (const struct lysc_node *)tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02003340 break;
3341 case TRD_SECT_YANG_DATA:
aPiecek96baa7f2021-04-23 12:32:00 +02003342 /* nothing to do */
aPiecek3f247652021-04-19 13:40:25 +02003343 break;
3344 default:
3345 assert(0);
3346 }
aPiecek61d062b2020-11-02 11:05:09 +01003347 }
3348}
3349
aPiecek874ea4d2021-04-19 12:26:36 +02003350/**********************************************************************
aPiecek8f1073c2022-10-17 16:44:49 +02003351 * Definition of trocm reading functions
3352 *********************************************************************/
3353
3354/**
3355 * @brief Get child node from current @p node.
3356 * @param[in] node from which it tries to get a child.
3357 * If set to NULL, then the top-level node of the @p parent_ref is returned.
3358 * @param[in] parent_ref is one of the referenced nodes.
3359 * @return Child of @p node, top-level node of @p parent_ref or NULL.
3360 */
3361static const struct lysc_node *
3362trocm_node_child(const struct lysc_node *node, const struct lysc_node *parent_ref)
3363{
3364 const struct lysc_node *child, *parent;
3365
3366 assert(node != parent_ref);
3367
3368 child = parent_ref;
3369 for (parent = parent_ref->parent; parent; parent = parent->parent) {
3370 if (parent == node) {
3371 return child;
3372 }
3373 child = parent;
3374 }
3375
3376 if (!node) {
3377 return child;
3378 } else {
3379 return NULL;
3380 }
3381}
3382
3383/**
3384 * @brief Get first parent-referenced node from @p cmod.
3385 * @param[in] parent_refs is the set of all parent-referenced nodes.
3386 * @param[in] cmod is compiled module from which to get the first parent-ref node.
3387 * @param[out] first_parent_ref is index to @p parent_refs where first parent-ref node is located.
3388 * @return LY_ERR value.
3389 */
3390static LY_ERR
3391trocm_first_parent_ref(const struct ly_set *parent_refs, const struct lysc_module *cmod, uint32_t *first_parent_ref)
3392{
3393 uint32_t i;
3394 const struct lysc_node *ref;
3395
3396 for (i = 0; i < parent_refs->count; i++) {
3397 ref = parent_refs->snodes[i];
3398 if (ref->module->compiled == cmod) {
3399 *first_parent_ref = i;
3400 return LY_SUCCESS;
3401 }
3402 }
3403
3404 return LY_ENOTFOUND;
3405}
3406
3407/**
3408 * @brief Get next parent-referenced node from @p cmod.
3409 * @param[in] parent_refs is the set of all parent-referenced nodes.
3410 * @param[in] cmod is compiled module from which to get the next parent-ref node.
3411 * @param[in,out] parent_ref is index to @p parent_refs where the next parent-ref node is located.
3412 * @return LY_ERR value.
3413 */
3414static LY_ERR
3415trocm_next_parent_ref(const struct ly_set *parent_refs, const struct lysc_module *cmod, uint32_t *parent_ref)
3416{
3417 (*parent_ref)++;
3418 if (*parent_ref >= parent_refs->count) {
3419 return LY_ENOT;
3420 } else if (parent_refs->snodes[*parent_ref]->module->compiled != cmod) {
3421 return LY_ENOT;
3422 } else {
3423 return LY_SUCCESS;
3424 }
3425}
3426
3427/**
3428 * @brief Get next sibling of current node @p cn.
3429 * @param[in] cn is current compiled node.
3430 * @param[in] parent_refs is the set of all parent-referenced nodes.
3431 * @return Next sibling or NULL.
3432 */
3433static const struct lysc_node *
3434trocm_next_sibling(const struct lysc_node *cn, const struct ly_set *parent_refs)
3435{
3436 LY_ERR ret;
3437 uint32_t i;
3438 const struct lysc_node *sibl, *ref, *child;
3439 const struct lysc_module *cmod;
3440
3441 cmod = cn->module->compiled;
3442 for (sibl = cn->next; sibl; sibl = sibl->next) {
3443 for (ret = trocm_first_parent_ref(parent_refs, cmod, &i);
3444 ret == LY_SUCCESS;
3445 ret = trocm_next_parent_ref(parent_refs, cmod, &i)) {
3446 ref = parent_refs->snodes[i];
3447 if (ref == sibl) {
3448 /* Sibling is in the parent-refs. */
3449 return sibl;
3450 }
3451 child = trocm_node_child(sibl, parent_refs->snodes[i]);
3452 if (child) {
3453 /* Return parent of parent-ref node. */
3454 return sibl;
3455 }
3456 }
3457 }
3458
3459 return NULL;
3460}
3461
3462/**
3463 * @copydoc trop_read_if_sibling_exists
3464 */
3465static ly_bool
3466trocm_read_if_sibling_exists(const struct trt_tree_ctx *tc)
3467{
3468 if (trocm_next_sibling(tc->cn, tc->parent_refs)) {
3469 return 1;
3470 } else {
3471 return 0;
3472 }
3473}
3474
3475/**********************************************************************
3476 * Modify trocm getters
3477 *********************************************************************/
3478
3479/**
3480 * @copydoc trop_modi_next_child()
3481 */
3482static struct trt_node
3483trocm_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3484{
3485 LY_ERR ret;
3486 uint32_t i;
3487 const struct lysc_node *child, *ref;
3488
3489 child = NULL;
3490 for (ret = trocm_first_parent_ref(tc->parent_refs, tc->cmod, &i);
3491 ret == LY_SUCCESS;
3492 ret = trocm_next_parent_ref(tc->parent_refs, tc->cmod, &i)) {
3493 ref = tc->parent_refs->snodes[i];
3494 if (ref == tc->cn) {
3495 continue;
3496 }
3497 if ((child = trocm_node_child(tc->cn, ref))) {
3498 tc->cn = child;
3499 return troc_read_node(ca, tc);
3500 }
3501 }
3502
3503 return TRP_EMPTY_NODE;
3504}
3505
3506/**
3507 * @copydoc ::trop_modi_first_sibling()
3508 */
3509static void
3510trocm_modi_first_sibling(struct trt_tree_ctx *tc)
3511{
3512 uint32_t i;
3513
3514 if (troc_modi_parent(tc)) {
3515 trocm_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
3516 } else {
3517 trocm_first_parent_ref(tc->parent_refs, tc->cmod, &i);
3518 tc->cn = trocm_node_child(NULL, tc->parent_refs->snodes[i]);
3519 }
3520}
3521
3522/**
3523 * @copydoc ::trop_modi_next_sibling()
3524 */
3525static struct trt_node
3526trocm_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3527{
3528 const struct lysc_node *sibl;
3529
3530 if ((sibl = trocm_next_sibling(tc->cn, tc->parent_refs))) {
3531 tc->cn = sibl;
3532 return troc_read_node(ca, tc);
3533 } else {
3534 return TRP_EMPTY_NODE;
3535 }
3536}
3537
3538/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01003539 * Definition of tree browsing functions
aPiecek874ea4d2021-04-19 12:26:36 +02003540 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003541
aPiecek41219f92022-10-26 11:24:40 +02003542static uint32_t
3543trb_gap_to_opts(struct trt_node node)
aPiecek61d062b2020-11-02 11:05:09 +01003544{
aPiecek41219f92022-10-26 11:24:40 +02003545 uint32_t len = 0;
aPiecek61d062b2020-11-02 11:05:09 +01003546
aPiecek41219f92022-10-26 11:24:40 +02003547 if (node.name.keys) {
3548 return 0;
aPiecek61d062b2020-11-02 11:05:09 +01003549 }
3550
aPiecek41219f92022-10-26 11:24:40 +02003551 if (node.flags) {
3552 len += strlen(node.flags);
3553 /* space between flags and name */
3554 len += 1;
3555 } else {
3556 /* space between -- and name */
3557 len += 1;
3558 }
3559
3560 switch (node.name.type) {
3561 case TRD_NODE_CASE:
3562 /* ':' is already counted. Plus parentheses. */
3563 len += 2;
3564 break;
3565 case TRD_NODE_CHOICE:
3566 /* Plus parentheses. */
3567 len += 2;
3568 break;
3569 default:
3570 break;
3571 }
3572
3573 if (node.name.module_prefix) {
3574 len += strlen(node.name.module_prefix);
3575 }
3576 if (node.name.str) {
3577 len += strlen(node.name.str);
3578 }
3579 if (node.name.opts) {
3580 len += strlen(node.name.opts);
3581 }
3582
3583 return len;
3584}
3585
3586static uint32_t
3587trb_gap_to_type(struct trt_node node)
3588{
3589 uint32_t len;
3590
3591 if (node.name.keys) {
3592 return 0;
3593 }
3594
3595 len = trb_gap_to_opts(node);
3596 /* Gap between opts and type. */
3597 if (node.name.opts && (strlen(node.name.opts) >= TRD_INDENT_BEFORE_TYPE)) {
3598 /* At least one space should be there. */
3599 len += 1;
3600 } else if (node.name.opts) {
3601 len += TRD_INDENT_BEFORE_TYPE - strlen(node.name.opts);
3602 } else {
3603 len += TRD_INDENT_BEFORE_TYPE;
3604 }
3605
3606 return len;
aPiecek61d062b2020-11-02 11:05:09 +01003607}
3608
3609/**
aPiecek874ea4d2021-04-19 12:26:36 +02003610 * @brief Calculate the trt_indent_in_node.btw_opts_type indent size
3611 * for a particular node.
aPiecek41219f92022-10-26 11:24:40 +02003612 * @param[in] node for which we get btw_opts_type.
3613 * @param[in] max_gap_before_type is the maximum value of btw_opts_type
aPiecek874ea4d2021-04-19 12:26:36 +02003614 * that it can have.
3615 * @return Indent between \<opts\> and \<type\> for node.
aPiecek61d062b2020-11-02 11:05:09 +01003616 */
3617static int16_t
aPiecek41219f92022-10-26 11:24:40 +02003618trb_calc_btw_opts_type(struct trt_node node, int16_t max_gap_before_type)
aPiecek61d062b2020-11-02 11:05:09 +01003619{
aPiecek41219f92022-10-26 11:24:40 +02003620 uint32_t to_opts_len;
aPiecek61d062b2020-11-02 11:05:09 +01003621
aPiecek41219f92022-10-26 11:24:40 +02003622 to_opts_len = trb_gap_to_opts(node);
3623 if (to_opts_len == 0) {
3624 return 1;
3625 } else {
3626 return max_gap_before_type - to_opts_len;
3627 }
aPiecek61d062b2020-11-02 11:05:09 +01003628}
3629
3630/**
3631 * @brief Print node.
3632 *
aPiecek01598c02021-04-23 14:18:24 +02003633 * This function is wrapper for ::trp_print_entire_node().
aPiecek874ea4d2021-04-19 12:26:36 +02003634 * But difference is that take @p max_gap_before_type which will be
3635 * used to set the unified alignment.
aPiecek61d062b2020-11-02 11:05:09 +01003636 *
aPiecek9bdd7592021-05-20 08:13:20 +02003637 * @param[in] node to print.
aPiecek61d062b2020-11-02 11:05:09 +01003638 * @param[in] max_gap_before_type is number of indent before \<type\>.
3639 * @param[in] wr is wrapper for printing indentation before node.
aPiecek61d062b2020-11-02 11:05:09 +01003640 * @param[in] pc contains mainly functions for printing.
3641 * @param[in] tc is tree context.
3642 */
3643static void
aPiecek9bdd7592021-05-20 08:13:20 +02003644trb_print_entire_node(struct trt_node node, uint32_t max_gap_before_type, struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003645{
aPiecek61d062b2020-11-02 11:05:09 +01003646 struct trt_indent_in_node ind = trp_default_indent_in_node(node);
3647
3648 if ((max_gap_before_type > 0) && (node.type.type != TRD_TYPE_EMPTY)) {
3649 /* print actual node with unified indent */
aPiecek41219f92022-10-26 11:24:40 +02003650 ind.btw_opts_type = trb_calc_btw_opts_type(node, max_gap_before_type);
aPiecek61d062b2020-11-02 11:05:09 +01003651 }
3652 /* after -> print actual node with default indent */
3653 trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print),
3654 TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out);
aPiecek41219f92022-10-26 11:24:40 +02003655 if (!strcmp(node.flags, TRD_FLAGS_TYPE_MOUNT_POINT) && node.mount) {
ekinzie0ab8b302022-10-10 03:03:57 -04003656 struct trt_wrapper wr_mount;
3657 struct tro_getters get;
3658
3659 wr_mount = pc->fp.read.if_sibling_exists(tc) ?
3660 trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr);
3661
3662 get = tc->lysc_tree ? troc_init_getters() : trop_init_getters();
3663 if (get.child(tc->lysc_tree ? (void *)tc->cn : (void *)tc->pn)) {
3664 /* If this node has a child, we need to draw a vertical line
3665 * from the last mounted module to the first child
3666 */
3667 wr_mount = trp_wrapper_set_mark_top(wr_mount);
3668 }
3669
aPiecek40f22402022-10-14 10:48:08 +02003670 tc->last_error = trb_print_mount_point(node.mount, wr_mount, pc);
ekinzie0ab8b302022-10-10 03:03:57 -04003671 }
aPiecek61d062b2020-11-02 11:05:09 +01003672}
3673
3674/**
aPiecek874ea4d2021-04-19 12:26:36 +02003675 * @brief Check if parent of the current node is the last
3676 * of his siblings.
aPiecek61d062b2020-11-02 11:05:09 +01003677 *
aPiecek874ea4d2021-04-19 12:26:36 +02003678 * To mantain stability use this function only if the current node is
3679 * the first of the siblings.
3680 * Side-effect -> current node is set to the first sibling
3681 * if node has a parent otherwise no side-effect.
aPiecek61d062b2020-11-02 11:05:09 +01003682 *
aPiecek01598c02021-04-23 14:18:24 +02003683 * @param[in] fp contains all @ref TRP_tro callback functions.
aPiecek61d062b2020-11-02 11:05:09 +01003684 * @param[in,out] tc is tree context.
3685 * @return 1 if parent is last sibling otherwise 0.
3686 */
3687static ly_bool
3688trb_parent_is_last_sibling(struct trt_fp_all fp, struct trt_tree_ctx *tc)
3689{
3690 if (fp.modify.parent(tc)) {
3691 ly_bool ret = fp.read.if_sibling_exists(tc);
Michal Vasko26bbb272022-08-02 14:54:33 +02003692
aPiecek61d062b2020-11-02 11:05:09 +01003693 fp.modify.next_child(TRP_EMPTY_PARENT_CACHE, tc);
3694 return !ret;
3695 } else {
3696 return !fp.read.if_sibling_exists(tc);
3697 }
3698}
3699
3700/**
aPiecek41219f92022-10-26 11:24:40 +02003701 * @brief For all siblings find maximal space from '--' to \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01003702 *
3703 * Side-effect -> Current node is set to the first sibling.
3704 *
3705 * @param[in] ca contains inherited data from ancestors.
3706 * @param[in] pc contains mainly functions for printing.
3707 * @param[in,out] tc is tree context.
aPiecek41219f92022-10-26 11:24:40 +02003708 * @return max space.
aPiecek61d062b2020-11-02 11:05:09 +01003709 */
aPiecek41219f92022-10-26 11:24:40 +02003710static uint32_t
3711trb_max_gap_to_type(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003712{
aPiecek41219f92022-10-26 11:24:40 +02003713 int32_t maxlen, len;
aPiecek61d062b2020-11-02 11:05:09 +01003714
3715 pc->fp.modify.first_sibling(tc);
3716
aPiecek41219f92022-10-26 11:24:40 +02003717 maxlen = 0;
aPiecek61d062b2020-11-02 11:05:09 +01003718 for (struct trt_node node = pc->fp.read.node(ca, tc);
3719 !trp_node_is_empty(node);
3720 node = pc->fp.modify.next_sibling(ca, tc)) {
aPiecek41219f92022-10-26 11:24:40 +02003721 len = trb_gap_to_type(node);
3722 maxlen = maxlen < len ? len : maxlen;
aPiecek61d062b2020-11-02 11:05:09 +01003723 }
3724 pc->fp.modify.first_sibling(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003725
aPiecek41219f92022-10-26 11:24:40 +02003726 return maxlen;
aPiecek61d062b2020-11-02 11:05:09 +01003727}
3728
3729/**
aPiecek874ea4d2021-04-19 12:26:36 +02003730 * @brief Find out if it is possible to unify
3731 * the alignment before \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01003732 *
aPiecek874ea4d2021-04-19 12:26:36 +02003733 * The goal is for all node siblings to have the same alignment
3734 * for \<type\> as if they were in a column. All siblings who cannot
3735 * adapt because they do not fit on the line at all are ignored.
aPiecek61d062b2020-11-02 11:05:09 +01003736 * Side-effect -> Current node is set to the first sibling.
3737 *
3738 * @param[in] ca contains inherited data from ancestors.
3739 * @param[in] pc contains mainly functions for printing.
3740 * @param[in,out] tc is tree context.
aPiecek874ea4d2021-04-19 12:26:36 +02003741 * @return positive number indicating the maximum number of spaces
aPiecek41219f92022-10-26 11:24:40 +02003742 * before \<type\> if the length of the flags, node name and opts is 0. To calculate
aPiecek874ea4d2021-04-19 12:26:36 +02003743 * the trt_indent_in_node.btw_opts_type indent size for a particular
aPiecek01598c02021-04-23 14:18:24 +02003744 * node, use the ::trb_calc_btw_opts_type().
aPiecek61d062b2020-11-02 11:05:09 +01003745*/
3746static uint32_t
3747trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3748{
aPiecek41219f92022-10-26 11:24:40 +02003749 return trb_max_gap_to_type(ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003750}
3751
3752/**
aPiecekb8d5a0a2021-05-20 08:20:24 +02003753 * @brief Check if there is no case statement
3754 * under the choice statement.
3755 *
3756 * It can return true only if the Parsed schema tree
3757 * is used for browsing.
3758 *
3759 * @param[in] tc is tree context.
3760 * @return 1 if implicit case statement is present otherwise 0.
3761 */
3762static ly_bool
3763trb_need_implicit_node_case(struct trt_tree_ctx *tc)
3764{
3765 return !tc->lysc_tree && tc->pn->parent &&
3766 (tc->pn->parent->nodetype & LYS_CHOICE) &&
3767 (tc->pn->nodetype & (LYS_ANYDATA | LYS_CHOICE | LYS_CONTAINER |
3768 LYS_LEAF | LYS_LEAFLIST));
3769}
3770
3771static void trb_print_subtree_nodes(struct trt_node node, uint32_t max_gap_before_type,
3772 struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc);
3773
3774/**
3775 * @brief Print implicit case node and his subtree.
3776 *
3777 * @param[in] node is child of implicit case.
3778 * @param[in] wr is wrapper for printing identation before node.
aPiecekb8d5a0a2021-05-20 08:20:24 +02003779 * @param[in] pc contains mainly functions for printing.
3780 * @param[in] tc is tree context. Its settings should be the same as
3781 * before the function call.
aPiecek49be5b42022-10-19 10:57:56 +02003782 * @return new indentation wrapper for @p node.
aPiecekb8d5a0a2021-05-20 08:20:24 +02003783 */
aPiecek49be5b42022-10-19 10:57:56 +02003784static struct trt_wrapper
3785trb_print_implicit_node(struct trt_node node, struct trt_wrapper wr, struct trt_printer_ctx *pc,
3786 struct trt_tree_ctx *tc)
aPiecekb8d5a0a2021-05-20 08:20:24 +02003787{
3788 struct trt_node case_node;
3789 struct trt_wrapper wr_case_child;
3790
3791 case_node = tro_create_implicit_case_node(node);
3792 ly_print_(pc->out, "\n");
3793 trb_print_entire_node(case_node, 0, wr, pc, tc);
aPiecek49be5b42022-10-19 10:57:56 +02003794 ly_print_(pc->out, "\n");
aPiecekb8d5a0a2021-05-20 08:20:24 +02003795 wr_case_child = pc->fp.read.if_sibling_exists(tc) ?
3796 trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr);
aPiecek49be5b42022-10-19 10:57:56 +02003797 return wr_case_child;
aPiecekb8d5a0a2021-05-20 08:20:24 +02003798}
3799
3800/**
aPiecek153b00f2021-04-20 13:52:57 +02003801 * @brief Calculate the wrapper about how deep in the tree the node is.
ekinzie0ab8b302022-10-10 03:03:57 -04003802 * @param[in] wr_in A wrapper to use as a starting point
aPiecek153b00f2021-04-20 13:52:57 +02003803 * @param[in] node from which to count.
3804 * @return wrapper for @p node.
3805 */
3806static struct trt_wrapper
ekinzie0ab8b302022-10-10 03:03:57 -04003807trb_count_depth(const struct trt_wrapper *wr_in, const struct lysc_node *node)
aPiecek153b00f2021-04-20 13:52:57 +02003808{
ekinzie0ab8b302022-10-10 03:03:57 -04003809 struct trt_wrapper wr = wr_in ? *wr_in : TRP_INIT_WRAPPER_TOP;
aPiecek153b00f2021-04-20 13:52:57 +02003810 const struct lysc_node *parent;
3811
3812 if (!node) {
3813 return wr;
3814 }
3815
3816 for (parent = node->parent; parent; parent = parent->parent) {
3817 wr = trp_wrapper_set_shift(wr);
3818 }
3819
3820 return wr;
3821}
3822
3823/**
3824 * @brief Print all parent nodes of @p node and the @p node itself.
3825 *
3826 * Side-effect -> trt_tree_ctx.cn will be set to @p node.
3827 *
3828 * @param[in] node on which the function is focused.
aPiecek7ed8d032022-10-10 12:32:27 +02003829 * @param[in] wr_in for printing identation before node.
aPiecek01598c02021-04-23 14:18:24 +02003830 * @param[in] pc is @ref TRP_trp settings.
aPiecek153b00f2021-04-20 13:52:57 +02003831 * @param[in,out] tc is context of tree printer.
3832 * @return wrapper for @p node.
3833 */
3834static void
ekinzie0ab8b302022-10-10 03:03:57 -04003835trb_print_parents(const struct lysc_node *node, struct trt_wrapper *wr_in, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek153b00f2021-04-20 13:52:57 +02003836{
aPiecek41219f92022-10-26 11:24:40 +02003837 uint32_t max_gap_before_type;
aPiecek153b00f2021-04-20 13:52:57 +02003838 struct trt_wrapper wr;
aPiecek9bdd7592021-05-20 08:13:20 +02003839 struct trt_node print_node;
aPiecek153b00f2021-04-20 13:52:57 +02003840
3841 assert(pc && tc && tc->section == TRD_SECT_MODULE);
3842
3843 /* stop recursion */
3844 if (!node) {
3845 return;
3846 }
ekinzie0ab8b302022-10-10 03:03:57 -04003847 trb_print_parents(node->parent, wr_in, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003848
3849 /* setup for printing */
3850 tc->cn = node;
ekinzie0ab8b302022-10-10 03:03:57 -04003851 wr = trb_count_depth(wr_in, node);
aPiecek153b00f2021-04-20 13:52:57 +02003852
3853 /* print node */
3854 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02003855 print_node = pc->fp.read.node(TRP_EMPTY_PARENT_CACHE, tc);
aPiecek41219f92022-10-26 11:24:40 +02003856 max_gap_before_type = trb_max_gap_to_type(TRP_EMPTY_PARENT_CACHE, pc, tc);
3857 trb_print_entire_node(print_node, max_gap_before_type, wr, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003858}
3859
3860/**
aPiecekdc8fd572021-04-19 10:47:23 +02003861 * @brief Get address of the current node.
3862 * @param[in] tc contains current node.
aPiecek3f247652021-04-19 13:40:25 +02003863 * @return Address of lysc_node or lysp_node, or NULL.
aPiecekdc8fd572021-04-19 10:47:23 +02003864 */
3865static const void *
3866trb_tree_ctx_get_node(struct trt_tree_ctx *tc)
3867{
aPiecek3f247652021-04-19 13:40:25 +02003868 return tc->lysc_tree ?
3869 (const void *)tc->cn :
3870 (const void *)tc->pn;
aPiecekdc8fd572021-04-19 10:47:23 +02003871}
3872
3873/**
3874 * @brief Get address of current node's child.
3875 * @param[in,out] tc contains current node.
3876 */
3877static const void *
3878trb_tree_ctx_get_child(struct trt_tree_ctx *tc)
3879{
3880 if (!trb_tree_ctx_get_node(tc)) {
3881 return NULL;
3882 }
3883
aPiecek3f247652021-04-19 13:40:25 +02003884 if (tc->lysc_tree) {
3885 return lysc_node_child(tc->cn);
3886 } else {
3887 return lysp_node_child(tc->pn);
3888 }
aPiecekdc8fd572021-04-19 10:47:23 +02003889}
3890
3891/**
3892 * @brief Set current node on its child.
3893 * @param[in,out] tc contains current node.
3894 */
3895static void
3896trb_tree_ctx_set_child(struct trt_tree_ctx *tc)
3897{
aPiecek3f247652021-04-19 13:40:25 +02003898 const void *node = trb_tree_ctx_get_child(tc);
3899
3900 if (tc->lysc_tree) {
3901 tc->cn = node;
3902 } else {
3903 tc->pn = node;
3904 }
aPiecekdc8fd572021-04-19 10:47:23 +02003905}
3906
3907/**
aPiecek61d062b2020-11-02 11:05:09 +01003908 * @brief Print subtree of nodes.
3909 *
3910 * The current node is expected to be the root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02003911 * Before root node is no linebreak printing. This must be addressed by
3912 * the caller. Root node will also be printed. Behind last printed node
3913 * is no linebreak.
aPiecek61d062b2020-11-02 11:05:09 +01003914 *
aPiecek9bdd7592021-05-20 08:13:20 +02003915 * @param[in] node is root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02003916 * @param[in] max_gap_before_type is result from
aPiecek01598c02021-04-23 14:18:24 +02003917 * ::trb_try_unified_indent() function for root node.
3918 * Set parameter to 0 if distance does not matter.
aPiecek874ea4d2021-04-19 12:26:36 +02003919 * @param[in] wr is wrapper saying how deep in the whole tree
3920 * is the root of the subtree.
3921 * @param[in] ca is parent_cache from root's parent.
3922 * If root is top-level node, insert ::TRP_EMPTY_PARENT_CACHE.
aPiecek01598c02021-04-23 14:18:24 +02003923 * @param[in] pc is @ref TRP_trp settings.
aPiecek874ea4d2021-04-19 12:26:36 +02003924 * @param[in,out] tc is context of tree printer.
aPiecek61d062b2020-11-02 11:05:09 +01003925 */
3926static void
aPiecek9bdd7592021-05-20 08:13:20 +02003927trb_print_subtree_nodes(struct trt_node node, uint32_t max_gap_before_type, struct trt_wrapper wr,
3928 struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003929{
aPiecek67521c22022-10-19 09:15:02 +02003930 /* print root node */
aPiecek9bdd7592021-05-20 08:13:20 +02003931 trb_print_entire_node(node, max_gap_before_type, wr, pc, tc);
ekinzie0ab8b302022-10-10 03:03:57 -04003932
aPiecek67521c22022-10-19 09:15:02 +02003933 /* go to the child */
aPiecek49be5b42022-10-19 10:57:56 +02003934 ca = tro_parent_cache_for_child(ca, tc);
3935 node = pc->fp.modify.next_child(ca, tc);
aPiecek67521c22022-10-19 09:15:02 +02003936 if (trp_node_is_empty(node)) {
3937 /* No child. */
3938 return;
aPiecek61d062b2020-11-02 11:05:09 +01003939 }
aPiecek67521c22022-10-19 09:15:02 +02003940
3941 /* if node is last sibling, then do not add '|' to wrapper */
3942 wr = trb_parent_is_last_sibling(pc->fp, tc) ?
3943 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
3944
3945 /* try unified indentation for children */
aPiecek49be5b42022-10-19 10:57:56 +02003946 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
aPiecek67521c22022-10-19 09:15:02 +02003947
3948 do {
3949 if (!trb_need_implicit_node_case(tc)) {
3950 /* normal behavior */
3951 ly_print_(pc->out, "\n");
aPiecek49be5b42022-10-19 10:57:56 +02003952 trb_print_subtree_nodes(node, max_gap_before_type, wr, ca, pc, tc);
aPiecek67521c22022-10-19 09:15:02 +02003953 } else {
aPiecek49be5b42022-10-19 10:57:56 +02003954 struct trt_wrapper wr_case_child;
3955
3956 wr_case_child = trb_print_implicit_node(node, wr, pc, tc);
3957 trb_print_subtree_nodes(node, max_gap_before_type, wr_case_child, ca, pc, tc);
aPiecek67521c22022-10-19 09:15:02 +02003958 }
3959 /* go to the actual node's sibling */
aPiecek49be5b42022-10-19 10:57:56 +02003960 node = pc->fp.modify.next_sibling(ca, tc);
3961 } while (!trp_node_is_empty(node));
aPiecek67521c22022-10-19 09:15:02 +02003962
3963 /* get back from child node to root node */
3964 pc->fp.modify.parent(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003965}
3966
3967/**
3968 * @brief Get number of siblings.
3969 *
3970 * Side-effect -> current node is set to the first sibling.
3971 *
3972 * @param[in] fp contains callback functions which modify tree context
3973 * @param[in,out] tc is the tree context.
3974 * @return Number of siblings of the current node.
3975 */
3976static uint32_t
3977trb_get_number_of_siblings(struct trt_fp_modify_ctx fp, struct trt_tree_ctx *tc)
3978{
3979 uint32_t ret = 1;
3980 struct trt_node node = TRP_EMPTY_NODE;
3981
3982 /* including actual node */
3983 fp.first_sibling(tc);
3984 while (!trp_node_is_empty(node = fp.next_sibling(TRP_EMPTY_PARENT_CACHE, tc))) {
3985 ret++;
3986 }
3987 fp.first_sibling(tc);
3988 return ret;
3989}
3990
3991/**
3992 * @brief Print all parents and their children.
3993 *
aPiecek874ea4d2021-04-19 12:26:36 +02003994 * This function is suitable for printing top-level nodes that
aPiecek01598c02021-04-23 14:18:24 +02003995 * do not have ancestors. Function call ::trb_print_subtree_nodes()
aPiecek153b00f2021-04-20 13:52:57 +02003996 * for all top-level siblings. Use this function after 'module' keyword
3997 * or 'augment' and so. The nodes may not be exactly top-level in the
3998 * tree, but the function considers them that way.
aPiecek61d062b2020-11-02 11:05:09 +01003999 *
aPiecek153b00f2021-04-20 13:52:57 +02004000 * @param[in] wr is wrapper saying how deeply the top-level nodes are
4001 * immersed in the tree.
aPiecek61d062b2020-11-02 11:05:09 +01004002 * @param[pc] pc contains mainly functions for printing.
4003 * @param[in,out] tc is tree context.
4004 */
4005static void
aPiecek153b00f2021-04-20 13:52:57 +02004006trb_print_family_tree(struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004007{
aPiecek61d062b2020-11-02 11:05:09 +01004008 struct trt_parent_cache ca;
aPiecek9bdd7592021-05-20 08:13:20 +02004009 struct trt_node node;
aPiecek61d062b2020-11-02 11:05:09 +01004010 uint32_t total_parents;
4011 uint32_t max_gap_before_type;
4012
aPiecekdc8fd572021-04-19 10:47:23 +02004013 if (!trb_tree_ctx_get_node(tc)) {
4014 return;
4015 }
4016
aPiecek61d062b2020-11-02 11:05:09 +01004017 ca = TRP_EMPTY_PARENT_CACHE;
4018 total_parents = trb_get_number_of_siblings(pc->fp.modify, tc);
4019 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
4020
aPiecek3f247652021-04-19 13:40:25 +02004021 if (!tc->lysc_tree) {
aPiecek96baa7f2021-04-23 12:32:00 +02004022 if (((tc->section == TRD_SECT_GROUPING) && (tc->tpn == tc->pn->parent)) ||
4023 (tc->section == TRD_SECT_YANG_DATA)) {
aPiecek3f247652021-04-19 13:40:25 +02004024 ca.lys_config = 0x0;
4025 }
aPiecekdc8fd572021-04-19 10:47:23 +02004026 }
4027
aPiecek61d062b2020-11-02 11:05:09 +01004028 for (uint32_t i = 0; i < total_parents; i++) {
4029 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02004030 node = pc->fp.read.node(ca, tc);
4031 trb_print_subtree_nodes(node, max_gap_before_type, wr, ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01004032 pc->fp.modify.next_sibling(ca, tc);
4033 }
4034}
4035
aPiecek7ed8d032022-10-10 12:32:27 +02004036/**
4037 * @brief Mounted module iterator.
4038 *
4039 * Omit internal modules, modules with no nodes (e.g., iana-if-types)
4040 * and modules that were loaded as the result of a parent-reference.
4041 *
4042 * @param[in] ext_ctx is special context of mount-point extension.
4043 * @param[in] parent_refs is set of parent-references. Can be NULL for case of 'inline' schema-ref.
4044 * @param[in,out] state of the iterator. Set the value to zero for initialization.
4045 * @return First/next mounted module or NULL.
4046 */
4047static const struct lys_module *
4048trb_mounted_module_iter(struct ly_ctx *ext_ctx, struct ly_set *parent_refs, uint32_t *state)
4049{
4050 const struct lys_module *mod = NULL;
4051 ly_bool from_parent_ref;
4052 uint32_t j;
4053
4054 if (!(*state)) {
4055 /* Get first non-internal module. */
4056 *state = ly_ctx_internal_modules_count(ext_ctx);
4057 }
4058
4059 while ((mod = ly_ctx_get_module_iter(ext_ctx, state))) {
4060 if (mod->compiled && !mod->compiled->data) {
4061 /* Compiled module with no data-nodes. */
4062 continue;
4063 } else if (mod->parsed && !mod->parsed->data) {
4064 /* Parsed module with no data-nodes. */
4065 continue;
4066 } else if (!parent_refs) {
4067 /* Mounting in 'inline' mode. Success. */
4068 break;
4069 }
4070
4071 /* Check if the module is not in parent-reference. */
4072 from_parent_ref = 0;
4073 for (j = 0; j < parent_refs->count; j++) {
4074 if (!strcmp(mod->ns, parent_refs->snodes[j]->module->ns)) {
4075 from_parent_ref = 1;
4076 break;
4077 }
4078 }
4079 if (!from_parent_ref) {
4080 /* Success. */
4081 break;
4082 }
4083 }
4084
4085 return mod;
4086}
4087
aPiecek874ea4d2021-04-19 12:26:36 +02004088/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004089 * Definition of trm main functions
aPiecek874ea4d2021-04-19 12:26:36 +02004090 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004091
4092/**
aPiecekdc8fd572021-04-19 10:47:23 +02004093 * @brief Settings if lysp_node are used for browsing through the tree.
aPiecek61d062b2020-11-02 11:05:09 +01004094 *
aPiecekdc8fd572021-04-19 10:47:23 +02004095 * @param[in] module YANG schema tree structure representing
4096 * YANG module.
aPiecek61d062b2020-11-02 11:05:09 +01004097 * @param[in] out is output handler.
aPiecekdc8fd572021-04-19 10:47:23 +02004098 * @param[in] max_line_length is the maximum line length limit
4099 * that should not be exceeded.
aPiecek7ed8d032022-10-10 12:32:27 +02004100 * @param[in] mounted context is used for printing the YANG Schema mount.
4101 * @param[in] parent_refs context is used for printing the YANG Schema mount and its parent-reference is set.
aPiecekdc8fd572021-04-19 10:47:23 +02004102 * @param[in,out] pc will be adapted to lysp_tree.
4103 * @param[in,out] tc will be adapted to lysp_tree.
aPiecek61d062b2020-11-02 11:05:09 +01004104 */
4105static void
aPiecek7ed8d032022-10-10 12:32:27 +02004106trm_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, ly_bool mounted,
4107 const struct ly_set *parent_refs, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004108{
aPiecekdc8fd572021-04-19 10:47:23 +02004109 *tc = (struct trt_tree_ctx) {
aPiecek3f247652021-04-19 13:40:25 +02004110 .lysc_tree = 0,
aPiecek7ed8d032022-10-10 12:32:27 +02004111 .mounted = mounted || parent_refs,
aPiecekdc8fd572021-04-19 10:47:23 +02004112 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02004113 .pmod = module->parsed,
4114 .cmod = NULL,
4115 .pn = module->parsed ? module->parsed->data : NULL,
4116 .tpn = module->parsed ? module->parsed->data : NULL,
aPiecek7ed8d032022-10-10 12:32:27 +02004117 .cn = NULL,
aPiecek40f22402022-10-14 10:48:08 +02004118 .parent_refs = parent_refs,
4119 .last_error = 0
aPiecekdc8fd572021-04-19 10:47:23 +02004120 };
aPiecek61d062b2020-11-02 11:05:09 +01004121
aPiecekdc8fd572021-04-19 10:47:23 +02004122 pc->out = out;
4123
4124 pc->fp.modify = (struct trt_fp_modify_ctx) {
aPiecekef1e58e2021-04-19 13:19:44 +02004125 .parent = trop_modi_parent,
4126 .first_sibling = trop_modi_first_sibling,
4127 .next_sibling = trop_modi_next_sibling,
4128 .next_child = trop_modi_next_child,
aPiecek61d062b2020-11-02 11:05:09 +01004129 };
4130
aPiecekdc8fd572021-04-19 10:47:23 +02004131 pc->fp.read = (struct trt_fp_read) {
aPiecek61d062b2020-11-02 11:05:09 +01004132 .module_name = tro_read_module_name,
aPiecekef1e58e2021-04-19 13:19:44 +02004133 .node = trop_read_node,
4134 .if_sibling_exists = trop_read_if_sibling_exists
aPiecek61d062b2020-11-02 11:05:09 +01004135 };
4136
aPiecekdc8fd572021-04-19 10:47:23 +02004137 pc->fp.print = (struct trt_fp_print) {
aPiecek3f247652021-04-19 13:40:25 +02004138 .print_features_names = tro_print_features_names,
4139 .print_keys = tro_print_keys
aPiecek61d062b2020-11-02 11:05:09 +01004140 };
4141
aPiecekdc8fd572021-04-19 10:47:23 +02004142 pc->max_line_length = max_line_length;
aPiecek61d062b2020-11-02 11:05:09 +01004143}
4144
4145/**
aPiecek3f247652021-04-19 13:40:25 +02004146 * @brief Settings if lysc_node are used for browsing through the tree.
4147 *
4148 * Pointers to current nodes will be set to module data.
4149 *
4150 * @param[in] module YANG schema tree structure representing
4151 * YANG module.
4152 * @param[in] out is output handler.
4153 * @param[in] max_line_length is the maximum line length limit
4154 * that should not be exceeded.
aPiecek7ed8d032022-10-10 12:32:27 +02004155 * @param[in] mounted context is used for printing the YANG Schema mount.
4156 * @param[in] parent_refs context is used for printing the YANG Schema mount and its parent-reference is set.
aPiecek3f247652021-04-19 13:40:25 +02004157 * @param[in,out] pc will be adapted to lysc_tree.
4158 * @param[in,out] tc will be adapted to lysc_tree.
4159 */
4160static void
aPiecek7ed8d032022-10-10 12:32:27 +02004161trm_lysc_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, ly_bool mounted,
4162 const struct ly_set *parent_refs, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek3f247652021-04-19 13:40:25 +02004163{
4164 *tc = (struct trt_tree_ctx) {
4165 .lysc_tree = 1,
aPiecek7ed8d032022-10-10 12:32:27 +02004166 .mounted = mounted || parent_refs,
aPiecek3f247652021-04-19 13:40:25 +02004167 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02004168 .pmod = module->parsed,
4169 .cmod = module->compiled,
aPiecek3f247652021-04-19 13:40:25 +02004170 .tpn = NULL,
4171 .pn = NULL,
aPiecek7ed8d032022-10-10 12:32:27 +02004172 .cn = module->compiled->data,
aPiecek40f22402022-10-14 10:48:08 +02004173 .parent_refs = parent_refs,
4174 .last_error = 0
aPiecek3f247652021-04-19 13:40:25 +02004175 };
4176
4177 pc->out = out;
4178
4179 pc->fp.modify = (struct trt_fp_modify_ctx) {
4180 .parent = troc_modi_parent,
4181 .first_sibling = troc_modi_first_sibling,
4182 .next_sibling = troc_modi_next_sibling,
4183 .next_child = troc_modi_next_child,
aPiecek3f247652021-04-19 13:40:25 +02004184 };
4185
4186 pc->fp.read = (struct trt_fp_read) {
4187 .module_name = tro_read_module_name,
4188 .node = troc_read_node,
4189 .if_sibling_exists = troc_read_if_sibling_exists
4190 };
4191
4192 pc->fp.print = (struct trt_fp_print) {
4193 .print_features_names = tro_print_features_names,
4194 .print_keys = tro_print_keys
4195 };
4196
4197 pc->max_line_length = max_line_length;
4198}
4199
4200/**
4201 * @brief Reset settings to browsing through the lysc tree.
aPiecek01598c02021-04-23 14:18:24 +02004202 * @param[in,out] pc resets to @ref TRP_troc functions.
aPiecek3f247652021-04-19 13:40:25 +02004203 * @param[in,out] tc resets to lysc browsing.
4204 */
4205static void
4206trm_reset_to_lysc_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4207{
aPiecek40f22402022-10-14 10:48:08 +02004208 LY_ERR erc;
4209
4210 erc = tc->last_error;
aPiecek7ed8d032022-10-10 12:32:27 +02004211 trm_lysc_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, tc->mounted, tc->parent_refs, pc, tc);
aPiecek40f22402022-10-14 10:48:08 +02004212 tc->last_error = erc;
aPiecek3f247652021-04-19 13:40:25 +02004213}
4214
4215/**
4216 * @brief Reset settings to browsing through the lysp tree.
aPiecek01598c02021-04-23 14:18:24 +02004217 * @param[in,out] pc resets to @ref TRP_trop functions.
aPiecek3f247652021-04-19 13:40:25 +02004218 * @param[in,out] tc resets to lysp browsing.
4219 */
4220static void
4221trm_reset_to_lysp_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4222{
aPiecek40f22402022-10-14 10:48:08 +02004223 LY_ERR erc;
4224
4225 erc = tc->last_error;
aPiecek7ed8d032022-10-10 12:32:27 +02004226 trm_lysp_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, tc->mounted, tc->parent_refs, pc, tc);
aPiecek40f22402022-10-14 10:48:08 +02004227 tc->last_error = erc;
aPiecek3f247652021-04-19 13:40:25 +02004228}
4229
4230/**
4231 * @brief If augment's target node is located on the current module.
4232 * @param[in] pn is examined augment.
4233 * @param[in] pmod is current module.
4234 * @return 1 if nodeid refers to the local node, otherwise 0.
4235 */
4236static ly_bool
4237trm_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod)
4238{
4239 const char *id, *prefix, *name;
4240 size_t prefix_len, name_len;
4241 const struct lys_module *mod;
4242 ly_bool ret = 0;
4243
4244 if (pn == NULL) {
4245 return ret;
4246 }
4247
4248 id = pn->nodeid;
4249 if (!id) {
4250 return ret;
4251 }
4252 /* only absolute-schema-nodeid is taken into account */
4253 assert(id[0] == '/');
4254 ++id;
4255
4256 ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len);
4257 if (prefix) {
Radek Krejci8df109d2021-04-23 12:19:08 +02004258 mod = ly_resolve_prefix(pmod->mod->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, pmod);
Michal Vasko3003c9a2022-03-29 12:10:00 +02004259 ret = mod ? (mod->parsed == pmod) : 0;
aPiecek3f247652021-04-19 13:40:25 +02004260 } else {
4261 ret = 1;
4262 }
4263
4264 return ret;
4265}
4266
4267/**
aPiecek96baa7f2021-04-23 12:32:00 +02004268 * @brief Printing section module, rpcs, notifications or yang-data.
aPiecek61d062b2020-11-02 11:05:09 +01004269 *
aPiecekdc8fd572021-04-19 10:47:23 +02004270 * First node must be the first child of 'module',
aPiecek96baa7f2021-04-23 12:32:00 +02004271 * 'rpcs', 'notifications' or 'yang-data'.
aPiecek61d062b2020-11-02 11:05:09 +01004272 *
aPiecekdc8fd572021-04-19 10:47:23 +02004273 * @param[in] ks is section representation.
4274 * @param[in] pc contains mainly functions for printing.
4275 * @param[in,out] tc is the tree context.
aPiecek61d062b2020-11-02 11:05:09 +01004276 */
4277static void
aPiecekdc8fd572021-04-19 10:47:23 +02004278trm_print_section_as_family_tree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004279{
aPiecekdc8fd572021-04-19 10:47:23 +02004280 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4281 return;
4282 }
4283
4284 trp_print_keyword_stmt(ks, pc->max_line_length, 0, pc->out);
4285 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
aPiecek153b00f2021-04-20 13:52:57 +02004286 trb_print_family_tree(TRP_INIT_WRAPPER_TOP, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004287 } else {
aPiecek153b00f2021-04-20 13:52:57 +02004288 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004289 }
4290}
4291
4292/**
aPiecek96baa7f2021-04-23 12:32:00 +02004293 * @brief Printing section augment or grouping.
aPiecekdc8fd572021-04-19 10:47:23 +02004294 *
aPiecek96baa7f2021-04-23 12:32:00 +02004295 * First node is 'augment' or 'grouping' itself.
aPiecekdc8fd572021-04-19 10:47:23 +02004296 *
4297 * @param[in] ks is section representation.
4298 * @param[in] pc contains mainly functions for printing.
4299 * @param[in,out] tc is the tree context.
4300 */
4301static void
4302trm_print_section_as_subtree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4303{
4304 ly_bool grp_has_data = 0;
4305
4306 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4307 return;
4308 }
4309
4310 if (ks.type == TRD_KEYWORD_GROUPING) {
4311 grp_has_data = trb_tree_ctx_get_child(tc) ? 1 : 0;
4312 }
4313
4314 trp_print_keyword_stmt(ks, pc->max_line_length, grp_has_data, pc->out);
4315 trb_tree_ctx_set_child(tc);
aPiecek153b00f2021-04-20 13:52:57 +02004316 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004317}
4318
4319/**
4320 * @brief Print 'module' keyword, its name and all nodes.
4321 * @param[in] pc contains mainly functions for printing.
4322 * @param[in,out] tc is the tree context.
4323 */
4324static void
4325trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4326{
4327 trm_print_section_as_family_tree(pc->fp.read.module_name(tc), pc, tc);
4328}
4329
4330/**
4331 * @brief For all augment sections: print 'augment' keyword,
4332 * its target node and all nodes.
4333 * @param[in] pc contains mainly functions for printing.
4334 * @param[in,out] tc is the tree context.
4335 */
4336static void
4337trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4338{
4339 ly_bool once;
aPiecek3f247652021-04-19 13:40:25 +02004340 ly_bool origin_was_lysc_tree = 0;
aPiecekdc8fd572021-04-19 10:47:23 +02004341
aPiecek3f247652021-04-19 13:40:25 +02004342 if (tc->lysc_tree) {
4343 origin_was_lysc_tree = 1;
4344 trm_reset_to_lysp_tree_ctx(pc, tc);
4345 }
4346
aPiecekdc8fd572021-04-19 10:47:23 +02004347 once = 1;
aPiecek01598c02021-04-23 14:18:24 +02004348 for (struct trt_keyword_stmt ks = trop_modi_next_augment(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004349 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
aPiecek01598c02021-04-23 14:18:24 +02004350 ks = trop_modi_next_augment(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004351
aPiecek3f247652021-04-19 13:40:25 +02004352 if (origin_was_lysc_tree) {
4353 /* if lysc tree is used, then only augments targeting
4354 * another module are printed
4355 */
aPiecek9f792e52021-04-21 08:33:56 +02004356 if (trm_nodeid_target_is_local((const struct lysp_node_augment *)tc->tpn, tc->pmod)) {
aPiecek3f247652021-04-19 13:40:25 +02004357 continue;
4358 }
4359 }
4360
aPiecekdc8fd572021-04-19 10:47:23 +02004361 if (once) {
4362 ly_print_(pc->out, "\n");
4363 ly_print_(pc->out, "\n");
4364 once = 0;
4365 } else {
4366 ly_print_(pc->out, "\n");
4367 }
4368
4369 trm_print_section_as_subtree(ks, pc, tc);
4370 }
aPiecek3f247652021-04-19 13:40:25 +02004371
4372 if (origin_was_lysc_tree) {
4373 trm_reset_to_lysc_tree_ctx(pc, tc);
4374 }
aPiecekdc8fd572021-04-19 10:47:23 +02004375}
4376
4377/**
4378 * @brief For rpcs section: print 'rpcs' keyword and all its nodes.
4379 * @param[in] pc contains mainly functions for printing.
4380 * @param[in,out] tc is the tree context.
4381 */
4382static void
4383trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4384{
4385 struct trt_keyword_stmt rpc;
4386
aPiecek01598c02021-04-23 14:18:24 +02004387 rpc = tro_modi_get_rpcs(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004388
4389 if (!(TRP_KEYWORD_STMT_IS_EMPTY(rpc))) {
4390 ly_print_(pc->out, "\n");
4391 ly_print_(pc->out, "\n");
4392 trm_print_section_as_family_tree(rpc, pc, tc);
4393 }
4394}
4395
4396/**
4397 * @brief For notifications section: print 'notifications' keyword
4398 * and all its nodes.
4399 * @param[in] pc contains mainly functions for printing.
4400 * @param[in,out] tc is the tree context.
4401 */
4402static void
4403trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4404{
4405 struct trt_keyword_stmt notifs;
4406
aPiecek01598c02021-04-23 14:18:24 +02004407 notifs = tro_modi_get_notifications(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004408
4409 if (!(TRP_KEYWORD_STMT_IS_EMPTY(notifs))) {
4410 ly_print_(pc->out, "\n");
4411 ly_print_(pc->out, "\n");
4412 trm_print_section_as_family_tree(notifs, pc, tc);
4413 }
4414}
4415
4416/**
4417 * @brief For all grouping sections: print 'grouping' keyword, its name
4418 * and all nodes.
4419 * @param[in] pc contains mainly functions for printing.
4420 * @param[in,out] tc is the tree context.
4421 */
4422static void
4423trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4424{
4425 ly_bool once;
4426
aPiecek01598c02021-04-23 14:18:24 +02004427 if (tc->lysc_tree) {
aPiecekdc8fd572021-04-19 10:47:23 +02004428 return;
4429 }
4430
4431 once = 1;
aPiecek01598c02021-04-23 14:18:24 +02004432 for (struct trt_keyword_stmt ks = trop_modi_next_grouping(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004433 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
aPiecek01598c02021-04-23 14:18:24 +02004434 ks = trop_modi_next_grouping(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004435 if (once) {
4436 ly_print_(pc->out, "\n");
4437 ly_print_(pc->out, "\n");
4438 once = 0;
4439 } else {
4440 ly_print_(pc->out, "\n");
4441 }
4442 trm_print_section_as_subtree(ks, pc, tc);
4443 }
4444}
4445
4446/**
4447 * @brief For all yang-data sections: print 'yang-data' keyword
4448 * and all its nodes.
4449 * @param[in] pc contains mainly functions for printing.
4450 * @param[in,out] tc is the tree context.
4451 */
4452static void
aPiecek96baa7f2021-04-23 12:32:00 +02004453trm_print_yang_data(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecekdc8fd572021-04-19 10:47:23 +02004454{
aPiecek96baa7f2021-04-23 12:32:00 +02004455 ly_bool once;
4456 LY_ARRAY_COUNT_TYPE count;
4457
4458 count = LY_ARRAY_COUNT(tc->pmod->exts);
4459 if (count == 0) {
4460 return;
4461 }
4462
4463 once = 1;
4464 for (LY_ARRAY_COUNT_TYPE u = 0; u < count; ++u) {
4465 struct trt_keyword_stmt ks;
4466
aPiecek01598c02021-04-23 14:18:24 +02004467 /* Only ::lys_compile_extension_instance() can set item
aPiecek96baa7f2021-04-23 12:32:00 +02004468 * ::lysp_ext_instance.parsed.
4469 */
4470 if (!tc->pmod->exts[u].parsed) {
4471 /* print at least the yang-data names */
4472 trop_yang_data_sections(tc->pmod->exts, pc->max_line_length, pc->out);
4473 continue;
4474 }
4475
4476 ks = tro_modi_next_yang_data(tc, u);
4477 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4478 break;
4479 }
4480
4481 if (once) {
4482 ly_print_(pc->out, "\n");
4483 ly_print_(pc->out, "\n");
4484 once = 0;
4485 } else {
4486 ly_print_(pc->out, "\n");
4487 }
4488
4489 trm_print_section_as_family_tree(ks, pc, tc);
4490 }
aPiecekdc8fd572021-04-19 10:47:23 +02004491}
4492
4493/**
4494 * @brief Print sections module, augment, rpcs, notifications,
4495 * grouping, yang-data.
4496 * @param[in] pc contains mainly functions for printing.
4497 * @param[in,out] tc is the tree context.
4498 */
4499static void
4500trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4501{
4502 trm_print_module_section(pc, tc);
4503 trm_print_augmentations(pc, tc);
4504 trm_print_rpcs(pc, tc);
4505 trm_print_notifications(pc, tc);
4506 trm_print_groupings(pc, tc);
4507 trm_print_yang_data(pc, tc);
4508 ly_print_(pc->out, "\n");
aPiecek61d062b2020-11-02 11:05:09 +01004509}
4510
aPiecek40f22402022-10-14 10:48:08 +02004511static LY_ERR
4512tree_print_check_error(struct ly_out_clb_arg *out, struct trt_tree_ctx *tc)
4513{
4514 if (out->last_error) {
4515 return out->last_error;
4516 } else if (tc->last_error) {
4517 return tc->last_error;
4518 } else {
4519 return LY_SUCCESS;
4520 }
4521}
4522
aPiecek874ea4d2021-04-19 12:26:36 +02004523/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004524 * Definition of module interface
aPiecek874ea4d2021-04-19 12:26:36 +02004525 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004526
4527LY_ERR
aPiecek3f247652021-04-19 13:40:25 +02004528tree_print_module(struct ly_out *out, const struct lys_module *module, uint32_t UNUSED(options), size_t line_length)
aPiecek61d062b2020-11-02 11:05:09 +01004529{
4530 struct trt_printer_ctx pc;
4531 struct trt_tree_ctx tc;
4532 struct ly_out *new_out;
4533 LY_ERR erc;
4534 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4535
aPiecekdc8fd572021-04-19 10:47:23 +02004536 LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL);
4537
aPiecek61d062b2020-11-02 11:05:09 +01004538 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4539 return erc;
4540 }
4541
4542 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek3f247652021-04-19 13:40:25 +02004543 if ((module->ctx->flags & LY_CTX_SET_PRIV_PARSED) && module->compiled) {
aPiecek7ed8d032022-10-10 12:32:27 +02004544 trm_lysc_tree_ctx(module, new_out, line_length, 0, NULL, &pc, &tc);
aPiecek3f247652021-04-19 13:40:25 +02004545 } else {
aPiecek7ed8d032022-10-10 12:32:27 +02004546 trm_lysp_tree_ctx(module, new_out, line_length, 0, NULL, &pc, &tc);
aPiecek3f247652021-04-19 13:40:25 +02004547 }
aPiecek61d062b2020-11-02 11:05:09 +01004548
4549 trm_print_sections(&pc, &tc);
aPiecek40f22402022-10-14 10:48:08 +02004550 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek61d062b2020-11-02 11:05:09 +01004551
4552 ly_out_free(new_out, NULL, 1);
4553
aPiecekdc8fd572021-04-19 10:47:23 +02004554 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004555}
4556
4557LY_ERR
aPiecek153b00f2021-04-20 13:52:57 +02004558tree_print_compiled_node(struct ly_out *out, const struct lysc_node *node, uint32_t options, size_t line_length)
aPiecek61d062b2020-11-02 11:05:09 +01004559{
aPiecek153b00f2021-04-20 13:52:57 +02004560 struct trt_printer_ctx pc;
4561 struct trt_tree_ctx tc;
4562 struct ly_out *new_out;
4563 struct trt_wrapper wr;
4564 LY_ERR erc;
4565 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4566
4567 assert(out && node);
4568
4569 if (!(node->module->ctx->flags & LY_CTX_SET_PRIV_PARSED)) {
4570 return LY_EINVAL;
4571 }
4572
4573 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4574 return erc;
4575 }
4576
4577 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek7ed8d032022-10-10 12:32:27 +02004578 trm_lysc_tree_ctx(node->module, new_out, line_length, 0, NULL, &pc, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004579
4580 trp_print_keyword_stmt(pc.fp.read.module_name(&tc), pc.max_line_length, 0, pc.out);
ekinzie0ab8b302022-10-10 03:03:57 -04004581 trb_print_parents(node, NULL, &pc, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004582
4583 if (!(options & LYS_PRINT_NO_SUBSTMT)) {
4584 tc.cn = lysc_node_child(node);
ekinzie0ab8b302022-10-10 03:03:57 -04004585 wr = trb_count_depth(NULL, tc.cn);
aPiecek153b00f2021-04-20 13:52:57 +02004586 trb_print_family_tree(wr, &pc, &tc);
4587 }
4588 ly_print_(out, "\n");
4589
aPiecek40f22402022-10-14 10:48:08 +02004590 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004591 ly_out_free(new_out, NULL, 1);
4592
4593 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004594}
4595
4596LY_ERR
Michal Vasko6a914fb2022-01-17 10:36:14 +01004597tree_print_parsed_submodule(struct ly_out *out, const struct lysp_submodule *submodp, uint32_t UNUSED(options),
4598 size_t line_length)
aPiecek61d062b2020-11-02 11:05:09 +01004599{
aPiecek9f792e52021-04-21 08:33:56 +02004600 struct trt_printer_ctx pc;
4601 struct trt_tree_ctx tc;
4602 struct ly_out *new_out;
4603 LY_ERR erc;
4604 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4605
4606 assert(submodp);
4607 LY_CHECK_ARG_RET(submodp->mod->ctx, out, LY_EINVAL);
4608
4609 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4610 return erc;
4611 }
4612
4613 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek7ed8d032022-10-10 12:32:27 +02004614 trm_lysp_tree_ctx(submodp->mod, new_out, line_length, 0, NULL, &pc, &tc);
aPiecek9f792e52021-04-21 08:33:56 +02004615 tc.pmod = (struct lysp_module *)submodp;
4616 tc.tpn = submodp->data;
4617 tc.pn = tc.tpn;
4618
4619 trm_print_sections(&pc, &tc);
aPiecek40f22402022-10-14 10:48:08 +02004620 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek9f792e52021-04-21 08:33:56 +02004621
4622 ly_out_free(new_out, NULL, 1);
4623
4624 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004625}
ekinzie0ab8b302022-10-10 03:03:57 -04004626
aPiecek8f1073c2022-10-17 16:44:49 +02004627/**********************************************************************
4628 * Functions for YANG Schema mount.
4629 *********************************************************************/
4630
4631/**
4632 * @brief Callback data for lysc_module_dfs_full.
4633 */
4634struct sort_parent_refs_state{
4635 struct ly_set *refs; /**< Set of parent-references pointers to sort. */
4636 uint64_t glob; /**< Current index in sort_parent_refs_state.refs. */
4637 uint64_t loc; /**< Current index of parent-ref node which belongs to the same module. */
4638 uint64_t total; /**< Total number of parent-ref nodes which belongs to the same module. */
4639};
4640
4641/**
4642 * @brief Callback for lysc_module_dfs_full() which sorts parent-references.
4643 * @param[in] node is current compiled node to check.
4644 * @param[in,out] data are expected to be of type struct sort_parent_refs_state.
4645 * @param[in] dfs_continue is not used.
4646 * @return LY_ERR value.
4647 */
4648static LY_ERR
4649troc_dfs_clb(struct lysc_node *node, void *data, ly_bool *UNUSED(dfs_continue))
4650{
4651 struct sort_parent_refs_state *dfs_data;
4652 struct lysc_node **snodes, *tmp;
4653 uint64_t i;
4654
4655 dfs_data = data;
4656 snodes = dfs_data->refs->snodes;
4657 for (i = dfs_data->glob; i < dfs_data->refs->count; i++) {
4658 if (snodes[i] == node) {
4659 /* swap */
4660 tmp = snodes[dfs_data->glob];
4661 snodes[dfs_data->glob] = snodes[i];
4662 snodes[i] = tmp;
4663 /* increment counters */
4664 dfs_data->glob++;
4665 dfs_data->loc++;
4666 break;
4667 }
4668 }
4669
4670 if (dfs_data->loc == dfs_data->total) {
4671 /* Stop searching in the current module. */
4672 return LY_ENOT;
4673 } else {
4674 return LY_SUCCESS;
4675 }
4676}
4677
4678/**
4679 * @brief Sort parent-references so that the order matches deep-search-first.
4680 * @param[in,out] refs is set of parent-references to sort.
4681 */
4682static void
4683troc_sort_parent_refs(struct ly_set *refs)
4684{
4685 uint64_t i, j, same_mod;
4686 const struct lys_module *mod;
4687 struct sort_parent_refs_state dfs_data;
4688
4689 if (!refs || (refs->count == 0) || (refs->count == 1)) {
4690 return;
4691 }
4692
4693 dfs_data.refs = refs;
4694 for (i = 0; i < refs->count; i++) {
4695 mod = refs->snodes[i]->module;
4696 /* Count total number of parent-references which refers to the same module. */
4697 same_mod = 1;
4698 for (j = i + 1; j < refs->count; j++) {
4699 if (mod == refs->snodes[j]->module) {
4700 ++same_mod;
4701 }
4702 }
4703 if (same_mod == 1) {
4704 continue;
4705 }
4706
4707 /* Sort all parent-references in the current module. */
4708 dfs_data.glob = i;
4709 dfs_data.loc = 1;
4710 dfs_data.total = same_mod;
4711 lysc_module_dfs_full(mod, troc_dfs_clb, &dfs_data);
4712 i = same_mod - 1;
4713 }
4714}
4715
4716/**
4717 * @brief For next module get the first parent-reference.
4718 * @param[in] parent_refs is set of parent-referenced nodes.
4719 * @param[in,out] parent_ref is the index in @p parent_refs, which is set to next parent-reference.
4720 * @return LY_ERR value.
4721 */
4722static LY_ERR
4723trocm_next_first_parent_ref(const struct ly_set *parent_refs, uint32_t *parent_ref)
4724{
4725 uint64_t i;
4726 const struct lysc_module *cmod;
4727
4728 cmod = parent_refs->snodes[*parent_ref]->module->compiled;
4729 for (i = (*parent_ref + 1); i < parent_refs->count; i++) {
4730 if (cmod != parent_refs->snodes[i]->module->compiled) {
4731 *parent_ref = i;
4732 return LY_SUCCESS;
4733 }
4734 }
4735
4736 return LY_ENOT;
4737}
4738
aPiecek7ed8d032022-10-10 12:32:27 +02004739/**
4740 * @brief Print all mounted nodes ('/') and parent-referenced nodes ('@').
4741 *
4742 * @param[in] ext is mount-point extension.
4743 * @param[in] wr is wrapper to be printed.
4744 * @param[in] pc contains mainly functions for printing.
4745 * @return LY_ERR value.
4746 */
ekinzie0ab8b302022-10-10 03:03:57 -04004747static LY_ERR
aPiecek7ed8d032022-10-10 12:32:27 +02004748trb_print_mount_point(const struct lysc_ext_instance *ext, const struct trt_wrapper wr, struct trt_printer_ctx *pc)
ekinzie0ab8b302022-10-10 03:03:57 -04004749{
aPiecek8f1073c2022-10-17 16:44:49 +02004750 LY_ERR ret = LY_SUCCESS, rc;
ekinzie0ab8b302022-10-10 03:03:57 -04004751 struct ly_ctx *ext_ctx = NULL;
aPiecek7ed8d032022-10-10 12:32:27 +02004752 const struct lys_module *mod, *last_mod;
ekinzie0ab8b302022-10-10 03:03:57 -04004753 struct trt_tree_ctx tmptc;
4754 struct trt_wrapper tmpwr;
4755 struct trt_printer_ctx tmppc;
ekinzie0ab8b302022-10-10 03:03:57 -04004756 struct ly_set *refs = NULL;
aPiecek7ed8d032022-10-10 12:32:27 +02004757 uint32_t i, iter_state;
aPiecek36f82232022-10-14 10:08:38 +02004758 ly_bool notif, rpc;
ekinzie0ab8b302022-10-10 03:03:57 -04004759
aPiecek7ed8d032022-10-10 12:32:27 +02004760 if (lyplg_ext_schema_mount_create_context(ext, &ext_ctx)) {
ekinzie0ab8b302022-10-10 03:03:57 -04004761 /* Void mount point */
4762 return LY_SUCCESS;
4763 }
4764
aPiecek40f22402022-10-14 10:48:08 +02004765 ret = lyplg_ext_schema_mount_get_parent_ref(ext, &refs);
4766 LY_CHECK_GOTO(ret, cleanup);
aPiecek7ed8d032022-10-10 12:32:27 +02004767
4768 /* Get the last mounted module which will be printed. */
4769 iter_state = 0;
4770 while ((mod = trb_mounted_module_iter(ext_ctx, refs, &iter_state))) {
4771 last_mod = mod;
ekinzie0ab8b302022-10-10 03:03:57 -04004772 }
4773
ekinzie0ab8b302022-10-10 03:03:57 -04004774 tmppc = *pc;
aPiecek7ed8d032022-10-10 12:32:27 +02004775 iter_state = 0;
4776 while ((mod = trb_mounted_module_iter(ext_ctx, refs, &iter_state))) {
4777 /* Prepare printer tree context. */
ekinzie0ab8b302022-10-10 03:03:57 -04004778 if ((ext_ctx->flags & LY_CTX_SET_PRIV_PARSED) && mod->compiled) {
aPiecek7ed8d032022-10-10 12:32:27 +02004779 trm_lysc_tree_ctx(mod, pc->out, pc->max_line_length, 1, refs, &tmppc, &tmptc);
aPiecek36f82232022-10-14 10:08:38 +02004780 notif = tmptc.cmod->notifs ? 1 : 0;
4781 rpc = tmptc.cmod->rpcs ? 1 : 0;
ekinzie0ab8b302022-10-10 03:03:57 -04004782 } else {
aPiecek7ed8d032022-10-10 12:32:27 +02004783 trm_lysp_tree_ctx(mod, pc->out, pc->max_line_length, 1, refs, &tmppc, &tmptc);
aPiecek36f82232022-10-14 10:08:38 +02004784 notif = tmptc.pmod->notifs ? 1 : 0;
4785 rpc = tmptc.pmod->rpcs ? 1 : 0;
ekinzie0ab8b302022-10-10 03:03:57 -04004786 }
aPiecek36f82232022-10-14 10:08:38 +02004787
aPiecek7ed8d032022-10-10 12:32:27 +02004788 /* Decide whether to print the symbol '|'. */
aPiecek36f82232022-10-14 10:08:38 +02004789 tmpwr = (mod == last_mod) && !rpc && !notif && !refs ? wr : trp_wrapper_set_mark_top(wr);
aPiecek7ed8d032022-10-10 12:32:27 +02004790 /* Print top-level nodes of mounted module which are denoted by the symbol '/'. */
4791 trb_print_family_tree(tmpwr, &tmppc, &tmptc);
aPiecek36f82232022-10-14 10:08:38 +02004792
4793 /* Print top-level rpc nodes. */
4794 if (rpc) {
4795 tro_modi_get_rpcs(&tmptc);
4796 tmpwr = (mod == last_mod) && !notif && !refs ? wr : trp_wrapper_set_mark_top(wr);
4797 trb_print_family_tree(tmpwr, &tmppc, &tmptc);
4798 }
4799
4800 /* Print top-level notification nodes. */
4801 if (notif) {
4802 tro_modi_get_notifications(&tmptc);
4803 tmpwr = (mod == last_mod) && !refs ? wr : trp_wrapper_set_mark_top(wr);
4804 trb_print_family_tree(tmpwr, &tmppc, &tmptc);
4805 }
ekinzie0ab8b302022-10-10 03:03:57 -04004806 }
4807
aPiecek7ed8d032022-10-10 12:32:27 +02004808 /* Print parent-referenced nodes which are denoted by the symbol '@'. */
aPiecek8f1073c2022-10-17 16:44:49 +02004809 if (!refs || (refs->count == 0)) {
4810 goto cleanup;
4811 }
4812 troc_sort_parent_refs(refs);
4813 rc = LY_SUCCESS;
4814 /* Iterate over all modules which are in refs. */
4815 for (i = 0; rc == LY_SUCCESS; rc = trocm_next_first_parent_ref(refs, &i)) {
aPiecek7ed8d032022-10-10 12:32:27 +02004816 trm_lysc_tree_ctx(refs->snodes[i]->module, pc->out, pc->max_line_length, 1, refs, &tmppc, &tmptc);
aPiecek8f1073c2022-10-17 16:44:49 +02004817 tmptc.cn = trocm_node_child(NULL, refs->snodes[i]);
4818 tmppc.fp.modify.first_sibling = trocm_modi_first_sibling;
4819 tmppc.fp.modify.next_sibling = trocm_modi_next_sibling;
4820 tmppc.fp.modify.next_child = trocm_modi_next_child;
4821 tmppc.fp.read.if_sibling_exists = trocm_read_if_sibling_exists;
4822 iter_state = i;
4823 tmpwr = trocm_next_first_parent_ref(refs, &i) ? wr : trp_wrapper_set_mark_top(wr);
4824 i = iter_state;
4825 trb_print_family_tree(tmpwr, &tmppc, &tmptc);
ekinzie0ab8b302022-10-10 03:03:57 -04004826 }
4827
aPiecek40f22402022-10-14 10:48:08 +02004828cleanup:
ekinzie0ab8b302022-10-10 03:03:57 -04004829 ly_set_free(refs, NULL);
ekinzie0ab8b302022-10-10 03:03:57 -04004830 ly_ctx_destroy(ext_ctx);
aPiecek7ed8d032022-10-10 12:32:27 +02004831
4832 return ret;
ekinzie0ab8b302022-10-10 03:03:57 -04004833}