blob: 7fb42b49da9d1c42a4f76448b0c9de491bd0c316 [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 * status
aPiecek874ea4d2021-04-19 12:26:36 +0200302 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100303
304/**
305 * @brief Status of the node.
306 *
aPiecek874ea4d2021-04-19 12:26:36 +0200307 * @see trp_print_status
aPiecek61d062b2020-11-02 11:05:09 +0100308 */
309typedef enum {
310 TRD_STATUS_TYPE_EMPTY = 0,
Michal Vasko6a914fb2022-01-17 10:36:14 +0100311 TRD_STATUS_TYPE_CURRENT, /**< ::LYS_STATUS_CURR */
312 TRD_STATUS_TYPE_DEPRECATED, /**< ::LYS_STATUS_DEPRC */
aPiecek874ea4d2021-04-19 12:26:36 +0200313 TRD_STATUS_TYPE_OBSOLETE /**< ::LYS_STATUS_OBSLT */
aPiecek61d062b2020-11-02 11:05:09 +0100314} trt_status_type;
315
aPiecek874ea4d2021-04-19 12:26:36 +0200316/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100317 * flags
aPiecek874ea4d2021-04-19 12:26:36 +0200318 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100319
320/**
321 * @brief Flag of the node.
322 *
aPiecek874ea4d2021-04-19 12:26:36 +0200323 * @see trp_print_flags, trp_get_flags_strlen
aPiecek61d062b2020-11-02 11:05:09 +0100324 */
325typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200326 TRD_FLAGS_TYPE_EMPTY = 0, /**< -- */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100327 TRD_FLAGS_TYPE_RW, /**< rw */
328 TRD_FLAGS_TYPE_RO, /**< ro */
329 TRD_FLAGS_TYPE_RPC_INPUT_PARAMS, /**< -w */
330 TRD_FLAGS_TYPE_USES_OF_GROUPING, /**< -u */
331 TRD_FLAGS_TYPE_RPC, /**< -x */
332 TRD_FLAGS_TYPE_NOTIF, /**< -n */
aPiecek61d062b2020-11-02 11:05:09 +0100333 TRD_FLAGS_TYPE_MOUNT_POINT /**< mp */
334} trt_flags_type;
335
aPiecek874ea4d2021-04-19 12:26:36 +0200336/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100337 * node_name and opts
aPiecek874ea4d2021-04-19 12:26:36 +0200338 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100339
340#define TRD_NODE_NAME_PREFIX_CHOICE "("
341#define TRD_NODE_NAME_PREFIX_CASE ":("
342#define TRD_NODE_NAME_TRIPLE_DOT "..."
343
344/**
345 * @brief Type of the node.
346 *
aPiecek874ea4d2021-04-19 12:26:36 +0200347 * Used mainly to complete the correct \<opts\> next to or
348 * around the \<name\>.
aPiecek61d062b2020-11-02 11:05:09 +0100349 */
350typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200351 TRD_NODE_ELSE = 0, /**< For some node which does not require special treatment. \<name\> */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100352 TRD_NODE_CASE, /**< For case node. :(\<name\>) */
353 TRD_NODE_CHOICE, /**< For choice node. (\<name\>) */
354 TRD_NODE_OPTIONAL_CHOICE, /**< For choice node with optional mark. (\<name\>)? */
355 TRD_NODE_OPTIONAL, /**< For an optional leaf, anydata, or anyxml. \<name\>? */
356 TRD_NODE_CONTAINER, /**< For a presence container. \<name\>! */
aPiecekbca57772022-10-13 13:51:59 +0200357 TRD_NODE_LISTLEAFLIST, /**< For a leaf-list or list. \<name\>* */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100358 TRD_NODE_TOP_LEVEL1, /**< For a top-level data node in a mounted module. \<name\>/ */
359 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 +0200360 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 +0100361} trt_node_type;
362
363/**
364 * @brief Type of node and his name.
365 *
aPiecek874ea4d2021-04-19 12:26:36 +0200366 * @see TRP_EMPTY_NODE_NAME, TRP_NODE_NAME_IS_EMPTY,
aPiecek61d062b2020-11-02 11:05:09 +0100367 * trp_print_node_name, trp_mark_is_used, trp_print_opts_keys
368 */
369struct trt_node_name {
370 trt_node_type type; /**< Type of the node relevant for printing. */
aPiecekbca57772022-10-13 13:51:59 +0200371 ly_bool keys; /**< Set to 1 if [\<keys\>] are to be printed. Valid for some types only. */
aPiecek34fa3772021-05-21 12:35:46 +0200372 const char *module_prefix; /**< If the node is augmented into the tree from another module,
373 so this is the prefix of that module. */
aPiecek61d062b2020-11-02 11:05:09 +0100374 const char *str; /**< Name of the node. */
375};
376
377/**
378 * @brief Create struct trt_node_name as empty.
379 */
380#define TRP_EMPTY_NODE_NAME \
aPiecek874ea4d2021-04-19 12:26:36 +0200381 (struct trt_node_name) { \
aPiecekbca57772022-10-13 13:51:59 +0200382 .type = TRD_NODE_ELSE, .keys = 0, .module_prefix = NULL, .str = NULL \
aPiecek874ea4d2021-04-19 12:26:36 +0200383 }
aPiecek61d062b2020-11-02 11:05:09 +0100384
385/**
386 * @brief Check if struct trt_node_name is empty.
387 */
388#define TRP_NODE_NAME_IS_EMPTY(NODE_NAME) \
389 !NODE_NAME.str
390
aPiecek874ea4d2021-04-19 12:26:36 +0200391/**
392 * @brief Every \<opts\> mark except string of list's keys
393 * has a length of one.
394 */
aPiecek61d062b2020-11-02 11:05:09 +0100395#define TRD_OPTS_MARK_LENGTH 1
396
aPiecek874ea4d2021-04-19 12:26:36 +0200397/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100398 * type
aPiecek874ea4d2021-04-19 12:26:36 +0200399 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100400
401/**
402 * @brief Type of the \<type\>
403 */
404typedef enum {
405 TRD_TYPE_NAME = 0, /**< Type is just a name that does not require special treatment. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100406 TRD_TYPE_TARGET, /**< Should have a form "-> TARGET", where TARGET is the leafref path. */
407 TRD_TYPE_LEAFREF, /**< This type is set automatically by the 'trp' algorithm.
aPiecek874ea4d2021-04-19 12:26:36 +0200408 So set type as ::TRD_TYPE_TARGET. */
aPiecek61d062b2020-11-02 11:05:09 +0100409 TRD_TYPE_EMPTY /**< Type is not used at all. */
410} trt_type_type;
411
412/**
413 * @brief \<type\> in the \<node\>.
414 *
aPiecek874ea4d2021-04-19 12:26:36 +0200415 * @see TRP_EMPTY_TRT_TYPE, TRP_TRT_TYPE_IS_EMPTY, trp_print_type
aPiecek61d062b2020-11-02 11:05:09 +0100416 */
417struct trt_type {
418 trt_type_type type; /**< Type of the \<type\>. */
419 const char *str; /**< Path or name of the type. */
420};
421
422/**
423 * @brief Create empty struct trt_type.
424 */
425#define TRP_EMPTY_TRT_TYPE \
426 (struct trt_type) {.type = TRD_TYPE_EMPTY, .str = NULL}
427
428/**
429 * @brief Check if struct trt_type is empty.
430 */
431#define TRP_TRT_TYPE_IS_EMPTY(TYPE_OF_TYPE) \
432 TYPE_OF_TYPE.type == TRD_TYPE_EMPTY
433
434/**
435 * @brief Initialize struct trt_type by parameters.
436 */
437#define TRP_INIT_TRT_TYPE(TYPE_OF_TYPE, STRING) \
438 (struct trt_type) {.type = TYPE_OF_TYPE, .str = STRING}
439
aPiecek874ea4d2021-04-19 12:26:36 +0200440/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100441 * node
aPiecek874ea4d2021-04-19 12:26:36 +0200442 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100443
444/**
445 * @brief \<node\> data for printing.
446 *
aPiecek874ea4d2021-04-19 12:26:36 +0200447 * It contains RFC's:
448 * \<status\>--\<flags\> \<name\>\<opts\> \<type\> \<if-features\>.
aPiecek61d062b2020-11-02 11:05:09 +0100449 * Item \<opts\> is moved to part struct trt_node_name.
aPiecek874ea4d2021-04-19 12:26:36 +0200450 * For printing [\<keys\>] and if-features is required special
451 * functions which prints them.
aPiecek61d062b2020-11-02 11:05:09 +0100452 *
aPiecek874ea4d2021-04-19 12:26:36 +0200453 * @see TRP_EMPTY_NODE, trp_node_is_empty, trp_node_body_is_empty,
454 * trp_print_node_up_to_name, trp_print_divided_node_up_to_name,
455 * trp_print_node
aPiecek61d062b2020-11-02 11:05:09 +0100456 */
457struct trt_node {
aPiecek7ed8d032022-10-10 12:32:27 +0200458 trt_status_type status; /**< \<status\>. */
459 trt_flags_type flags; /**< \<flags\>. */
460 struct trt_node_name name; /**< \<node\> with \<opts\> mark or [\<keys\>]. */
461 struct trt_type type; /**< \<type\> contains the name of the type or type for leafref. */
462 ly_bool iffeatures; /**< \<if-features\>. Value 1 means that iffeatures are present and
463 will be printed by trt_fp_print.print_features_names callback. */
464 ly_bool last_one; /**< Information about whether the node is the last. */
465 struct lysc_ext_instance *mount; /**< Mount-point extension if flags == TRD_FLAGS_TYPE_MOUNT_POINT */
aPiecek61d062b2020-11-02 11:05:09 +0100466};
467
468/**
469 * @brief Create struct trt_node as empty.
470 */
471#define TRP_EMPTY_NODE \
aPiecek874ea4d2021-04-19 12:26:36 +0200472 (struct trt_node) { \
473 .status = TRD_STATUS_TYPE_EMPTY, \
474 .flags = TRD_FLAGS_TYPE_EMPTY, \
475 .name = TRP_EMPTY_NODE_NAME, \
476 .type = TRP_EMPTY_TRT_TYPE, \
477 .iffeatures = 0, \
ekinzie0ab8b302022-10-10 03:03:57 -0400478 .last_one = 1, \
479 .mount = NULL \
aPiecek874ea4d2021-04-19 12:26:36 +0200480 }
aPiecek61d062b2020-11-02 11:05:09 +0100481
482/**
483 * @brief Package which only groups indent and node.
484 */
485struct trt_pair_indent_node {
486 struct trt_indent_in_node indent;
487 struct trt_node node;
488};
489
490/**
491 * @brief Initialize struct trt_pair_indent_node by parameters.
492 */
493#define TRP_INIT_PAIR_INDENT_NODE(INDENT_IN_NODE, NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200494 (struct trt_pair_indent_node) { \
495 .indent = INDENT_IN_NODE, .node = NODE \
496 }
aPiecek61d062b2020-11-02 11:05:09 +0100497
aPiecek874ea4d2021-04-19 12:26:36 +0200498/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100499 * statement
aPiecek874ea4d2021-04-19 12:26:36 +0200500 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100501
502#define TRD_TOP_KEYWORD_MODULE "module"
503#define TRD_TOP_KEYWORD_SUBMODULE "submodule"
504
505#define TRD_BODY_KEYWORD_AUGMENT "augment"
506#define TRD_BODY_KEYWORD_RPC "rpcs"
507#define TRD_BODY_KEYWORD_NOTIF "notifications"
508#define TRD_BODY_KEYWORD_GROUPING "grouping"
509#define TRD_BODY_KEYWORD_YANG_DATA "yang-data"
510
511/**
512 * @brief Type of the trt_keyword.
513 */
514typedef enum {
515 TRD_KEYWORD_EMPTY = 0,
Michal Vasko6a914fb2022-01-17 10:36:14 +0100516 TRD_KEYWORD_MODULE,
517 TRD_KEYWORD_SUBMODULE,
518 TRD_KEYWORD_AUGMENT,
519 TRD_KEYWORD_RPC,
520 TRD_KEYWORD_NOTIF,
521 TRD_KEYWORD_GROUPING,
aPiecek61d062b2020-11-02 11:05:09 +0100522 TRD_KEYWORD_YANG_DATA
523} trt_keyword_type;
524
525/**
526 * @brief Main sign of the tree nodes.
527 *
aPiecek874ea4d2021-04-19 12:26:36 +0200528 * @see TRP_EMPTY_KEYWORD_STMT, TRP_KEYWORD_STMT_IS_EMPTY
aPiecek61d062b2020-11-02 11:05:09 +0100529 * trt_print_keyword_stmt_begin, trt_print_keyword_stmt_str,
530 * trt_print_keyword_stmt_end, trp_print_keyword_stmt
531 * trp_keyword_type_strlen
532 *
533 */
534struct trt_keyword_stmt {
aPiecek874ea4d2021-04-19 12:26:36 +0200535 trt_keyword_type type; /**< String containing some of the top or body keyword. */
536 const char *str; /**< Name or path, it determines the type. */
aPiecek61d062b2020-11-02 11:05:09 +0100537};
538
539/**
540 * @brief Create struct trt_keyword_stmt as empty.
541 */
542#define TRP_EMPTY_KEYWORD_STMT \
543 (struct trt_keyword_stmt) {.type = TRD_KEYWORD_EMPTY, .str = NULL}
544
545/**
546 * @brief Check if struct trt_keyword_stmt is empty.
547 */
548#define TRP_KEYWORD_STMT_IS_EMPTY(KEYWORD_TYPE) \
549 KEYWORD_TYPE.type == TRD_KEYWORD_EMPTY
550
551/**
552 * @brief Initialize struct trt_keyword_stmt by parameters.
553 */
554#define TRP_INIT_KEYWORD_STMT(KEYWORD_TYPE, STRING) \
555 (struct trt_keyword_stmt) {.type = KEYWORD_TYPE, .str = STRING}
556
aPiecek874ea4d2021-04-19 12:26:36 +0200557/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100558 * Modify getters
aPiecek874ea4d2021-04-19 12:26:36 +0200559 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100560
561struct trt_parent_cache;
562
563/**
564 * @brief Functions that change the state of the tree_ctx structure.
565 *
aPiecek3f247652021-04-19 13:40:25 +0200566 * The 'trop' or 'troc' functions are set here, which provide data
aPiecek874ea4d2021-04-19 12:26:36 +0200567 * for the 'trp' printing functions and are also called from the
568 * 'trb' browsing functions when walking through a tree. These callback
569 * functions need to be checked or reformulated if changes to the
570 * libyang library affect the printing tree. For all, if the value
571 * cannot be returned, its empty version obtained by relevant TRP_EMPTY
572 * macro is returned.
aPiecek61d062b2020-11-02 11:05:09 +0100573 */
574struct trt_fp_modify_ctx {
575 ly_bool (*parent)(struct trt_tree_ctx *); /**< Jump to parent node. Return true if parent exists. */
576 void (*first_sibling)(struct trt_tree_ctx *); /**< Jump on the first of the siblings. */
577 struct trt_node (*next_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to next sibling of the current node. */
578 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 +0100579};
580
aPiecek874ea4d2021-04-19 12:26:36 +0200581/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100582 * Read getters
aPiecek874ea4d2021-04-19 12:26:36 +0200583 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100584
585/**
586 * @brief Functions that do not change the state of the tree_structure.
587 *
588 * For details see trt_fp_modify_ctx.
589 */
590struct trt_fp_read {
aPiecek874ea4d2021-04-19 12:26:36 +0200591 struct trt_keyword_stmt (*module_name)(const struct trt_tree_ctx *); /**< Get name of the module. */
592 struct trt_node (*node)(struct trt_parent_cache, const struct trt_tree_ctx *); /**< Get current node. */
593 ly_bool (*if_sibling_exists)(const struct trt_tree_ctx *); /**< Check if node's sibling exists. */
aPiecek61d062b2020-11-02 11:05:09 +0100594};
595
aPiecek874ea4d2021-04-19 12:26:36 +0200596/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100597 * All getters
aPiecek874ea4d2021-04-19 12:26:36 +0200598 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100599
600/**
aPiecek874ea4d2021-04-19 12:26:36 +0200601 * @brief A set of all necessary functions that must be provided
602 * for the printer.
aPiecek61d062b2020-11-02 11:05:09 +0100603 */
604struct trt_fp_all {
605 struct trt_fp_modify_ctx modify; /**< Function pointers which modify state of trt_tree_ctx. */
606 struct trt_fp_read read; /**< Function pointers which only reads state of trt_tree_ctx. */
607 struct trt_fp_print print; /**< Functions pointers for printing special items in node. */
608};
609
aPiecek874ea4d2021-04-19 12:26:36 +0200610/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100611 * Printer context
aPiecek874ea4d2021-04-19 12:26:36 +0200612 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100613
614/**
aPiecek01598c02021-04-23 14:18:24 +0200615 * @brief Main structure for @ref TRP_trp part.
aPiecek61d062b2020-11-02 11:05:09 +0100616 */
617struct trt_printer_ctx {
618 struct ly_out *out; /**< Handler to printing. */
aPiecek01598c02021-04-23 14:18:24 +0200619 struct trt_fp_all fp; /**< @ref TRP_tro functions callbacks. */
aPiecek61d062b2020-11-02 11:05:09 +0100620 size_t max_line_length; /**< The maximum number of characters that can be
621 printed on one line, including the last. */
622};
623
aPiecek874ea4d2021-04-19 12:26:36 +0200624/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100625 * Tro functions
aPiecek874ea4d2021-04-19 12:26:36 +0200626 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100627
628/**
629 * @brief The name of the section to which the node belongs.
630 */
631typedef enum {
632 TRD_SECT_MODULE = 0, /**< The node belongs to the "module: <module_name>:" label. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100633 TRD_SECT_AUGMENT, /**< The node belongs to some "augment <target-node>:" label. */
634 TRD_SECT_RPCS, /**< The node belongs to the "rpcs:" label. */
635 TRD_SECT_NOTIF, /**< The node belongs to the "notifications:" label. */
636 TRD_SECT_GROUPING, /**< The node belongs to some "grouping <grouping-name>:" label. */
aPiecek61d062b2020-11-02 11:05:09 +0100637 TRD_SECT_YANG_DATA /**< The node belongs to some "yang-data <yang-data-name>:" label. */
638} trt_actual_section;
639
640/**
641 * @brief Types of nodes that have some effect on their children.
642 */
643typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200644 TRD_ANCESTOR_ELSE = 0, /**< Everything not listed. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100645 TRD_ANCESTOR_RPC_INPUT, /**< ::LYS_INPUT */
646 TRD_ANCESTOR_RPC_OUTPUT, /**< ::LYS_OUTPUT */
aPiecek874ea4d2021-04-19 12:26:36 +0200647 TRD_ANCESTOR_NOTIF /**< ::LYS_NOTIF */
aPiecek61d062b2020-11-02 11:05:09 +0100648} trt_ancestor_type;
649
650/**
651 * @brief Saved information when browsing the tree downwards.
652 *
aPiecek874ea4d2021-04-19 12:26:36 +0200653 * This structure helps prevent frequent retrieval of information
aPiecek01598c02021-04-23 14:18:24 +0200654 * from the tree. Functions @ref TRP_trb are designed to preserve
aPiecek874ea4d2021-04-19 12:26:36 +0200655 * this structures during their recursive calls. This functions do not
656 * interfere in any way with this data. This structure
aPiecek01598c02021-04-23 14:18:24 +0200657 * is used by @ref TRP_trop functions which, thanks to this
aPiecek874ea4d2021-04-19 12:26:36 +0200658 * structure, can return a node with the correct data. The word
659 * \b parent is in the structure name, because this data refers to
660 * the last parent and at the same time the states of its
661 * ancestors data. Only the function jumping on the child
662 * (next_child(...)) creates this structure, because the pointer
663 * to the current node moves down the tree. It's like passing
664 * the genetic code to children. Some data must be inherited and
665 * there are two approaches to this problem. Either it will always
666 * be determined which inheritance states belong to the current node
667 * (which can lead to regular travel to the root node) or
668 * the inheritance states will be stored during the recursive calls.
669 * So the problem was solved by the second option. Why does
670 * the structure contain this data? Because it walks through
aPiecek3f247652021-04-19 13:40:25 +0200671 * the lysp tree. For walks through the lysc tree is trt_parent_cache
672 * useless.
aPiecek61d062b2020-11-02 11:05:09 +0100673 *
aPiecek874ea4d2021-04-19 12:26:36 +0200674 * @see TRO_EMPTY_PARENT_CACHE, tro_parent_cache_for_child
aPiecek61d062b2020-11-02 11:05:09 +0100675 */
676struct trt_parent_cache {
aPiecek874ea4d2021-04-19 12:26:36 +0200677 trt_ancestor_type ancestor; /**< Some types of nodes have a special effect on their children. */
678 uint16_t lys_status; /**< Inherited status CURR, DEPRC, OBSLT. */
679 uint16_t lys_config; /**< Inherited config W or R. */
680 const struct lysp_node_list *last_list; /**< The last ::LYS_LIST passed. */
aPiecek61d062b2020-11-02 11:05:09 +0100681};
682
683/**
684 * @brief Return trt_parent_cache filled with default values.
685 */
686#define TRP_EMPTY_PARENT_CACHE \
aPiecek874ea4d2021-04-19 12:26:36 +0200687 (struct trt_parent_cache) { \
688 .ancestor = TRD_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \
689 .lys_config = LYS_CONFIG_W, .last_list = NULL \
690 }
aPiecek61d062b2020-11-02 11:05:09 +0100691
692/**
693 * @brief Main structure for browsing the libyang tree
694 */
695struct trt_tree_ctx {
aPiecek96baa7f2021-04-23 12:32:00 +0200696 ly_bool lysc_tree; /**< The lysc nodes are used for browsing through the tree.
697 It is assumed that once set, it does not change.
698 If it is true then trt_tree_ctx.pn and
699 trt_tree_ctx.tpn are not used.
700 If it is false then trt_tree_ctx.cn is not used. */
ekinzie0ab8b302022-10-10 03:03:57 -0400701 ly_bool mounted; /**< This tree is a mounted schema */
aPiecek96baa7f2021-04-23 12:32:00 +0200702 trt_actual_section section; /**< To which section pn points. */
703 const struct lysp_module *pmod; /**< Parsed YANG schema tree. */
704 const struct lysc_module *cmod; /**< Compiled YANG schema tree. */
705 const struct lysp_node *pn; /**< Actual pointer to parsed node. */
Michal Vasko26bbb272022-08-02 14:54:33 +0200706
aPiecek96baa7f2021-04-23 12:32:00 +0200707 union {
708 const struct lysp_node *tpn; /**< Pointer to actual top-node. */
709 const struct lysp_ext_instance *tpn_ext; /**< Actual top-node is extension. Item trt_tree_ctx.section
710 is set to TRD_SECT_YANG_DATA. */
711 };
712 const struct lysc_node *cn; /**< Actual pointer to compiled node. */
ekinzie0ab8b302022-10-10 03:03:57 -0400713 const struct ly_set *parent_refs; /**< List of schema nodes for top-level nodes found in mount
714 point parent references */
aPiecek40f22402022-10-14 10:48:08 +0200715 LY_ERR last_error; /**< Error value during printing. */
aPiecek61d062b2020-11-02 11:05:09 +0100716};
717
aPiecek3f247652021-04-19 13:40:25 +0200718/**
aPiecekbbc02932021-05-21 07:19:41 +0200719 * @brief Check if lysp node is available from
720 * the current compiled node.
721 *
722 * Use only if trt_tree_ctx.lysc_tree is set to true.
723 */
724#define TRP_TREE_CTX_LYSP_NODE_PRESENT(CN) \
725 (CN->priv)
726
727/**
aPiecek3f247652021-04-19 13:40:25 +0200728 * @brief Get lysp_node from trt_tree_ctx.cn.
aPiecekbbc02932021-05-21 07:19:41 +0200729 *
730 * Use only if :TRP_TREE_CTX_LYSP_NODE_PRESENT returns true
731 * for that node.
aPiecek3f247652021-04-19 13:40:25 +0200732 */
733#define TRP_TREE_CTX_GET_LYSP_NODE(CN) \
734 ((const struct lysp_node *)CN->priv)
735
aPiecek01598c02021-04-23 14:18:24 +0200736/** Getter function for ::trop_node_charptr(). */
aPiecek61d062b2020-11-02 11:05:09 +0100737typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
738
aPiecekef1e58e2021-04-19 13:19:44 +0200739/**
740 * @brief Simple getter functions for lysp and lysc nodes.
741 *
742 * This structure is useful if we have a general algorithm
743 * (tro function) that can be used for both lysc and lysp nodes.
744 * Thanks to this structure, we prevent code redundancy.
745 * We don't have to write basically the same algorithm twice
746 * for lysp and lysc trees.
747 */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100748struct tro_getters {
aPiecekef1e58e2021-04-19 13:19:44 +0200749 uint16_t (*nodetype)(const void *); /**< Get nodetype. */
750 const void *(*next)(const void *); /**< Get sibling. */
751 const void *(*parent)(const void *); /**< Get parent. */
752 const void *(*child)(const void *); /**< Get child. */
753 const void *(*actions)(const void *); /**< Get actions. */
754 const void *(*action_input)(const void *); /**< Get input action from action node. */
755 const void *(*action_output)(const void *); /**< Get output action from action node. */
756 const void *(*notifs)(const void *); /**< Get notifs. */
757};
758
aPiecek874ea4d2021-04-19 12:26:36 +0200759/**********************************************************************
ekinzie0ab8b302022-10-10 03:03:57 -0400760 * Forward declarations
761 *********************************************************************/
aPiecek7ed8d032022-10-10 12:32:27 +0200762static 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 -0400763
764/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100765 * Definition of the general Trg functions
aPiecek874ea4d2021-04-19 12:26:36 +0200766 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100767
768/**
769 * @brief Print a substring but limited to the maximum length.
770 * @param[in] str is pointer to source.
771 * @param[in] len is number of characters to be printed.
772 * @param[in,out] out is output handler.
773 * @return str parameter shifted by len.
774 */
775static const char *
776trg_print_substr(const char *str, size_t len, struct ly_out *out)
777{
778 for (size_t i = 0; i < len; i++) {
779 ly_print_(out, "%c", str[0]);
780 str++;
781 }
782 return str;
783}
784
785/**
786 * @brief Pointer is not NULL and does not point to an empty string.
787 * @param[in] str is pointer to string to be checked.
788 * @return 1 if str pointing to non empty string otherwise 0.
789 */
790static ly_bool
791trg_charptr_has_data(const char *str)
792{
793 return (str) && (str[0] != '\0');
794}
795
796/**
aPiecek874ea4d2021-04-19 12:26:36 +0200797 * @brief Check if @p word in @p src is present where words are
798 * delimited by @p delim.
799 * @param[in] src is source where words are separated by @p delim.
aPiecek61d062b2020-11-02 11:05:09 +0100800 * @param[in] word to be searched.
aPiecek874ea4d2021-04-19 12:26:36 +0200801 * @param[in] delim is delimiter between @p words in @p src.
802 * @return 1 if src contains @p word otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +0100803 */
804static ly_bool
805trg_word_is_present(const char *src, const char *word, char delim)
806{
807 const char *hit;
808
809 if ((!src) || (src[0] == '\0') || (!word)) {
810 return 0;
811 }
812
813 hit = strstr(src, word);
814
815 if (hit) {
816 /* word was founded at the begin of src
817 * OR it match somewhere after delim
818 */
819 if ((hit == src) || (hit[-1] == delim)) {
820 /* end of word was founded at the end of src
821 * OR end of word was match somewhere before delim
822 */
823 char delim_or_end = (hit + strlen(word))[0];
Michal Vasko26bbb272022-08-02 14:54:33 +0200824
aPiecek61d062b2020-11-02 11:05:09 +0100825 if ((delim_or_end == '\0') || (delim_or_end == delim)) {
826 return 1;
827 }
828 }
829 /* after -> hit is just substr and it's not the whole word */
830 /* jump to the next word */
831 for ( ; (src[0] != '\0') && (src[0] != delim); src++) {}
832 /* skip delim */
833 src = src[0] == '\0' ? src : src + 1;
834 /* continue with searching */
835 return trg_word_is_present(src, word, delim);
836 } else {
837 return 0;
838 }
839}
840
aPiecek874ea4d2021-04-19 12:26:36 +0200841/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100842 * Definition of printer functions
aPiecek874ea4d2021-04-19 12:26:36 +0200843 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100844
845/**
aPiecek01598c02021-04-23 14:18:24 +0200846 * @brief Write callback for ::ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100847 *
aPiecek874ea4d2021-04-19 12:26:36 +0200848 * @param[in] user_data is type of struct ly_out_clb_arg.
aPiecek61d062b2020-11-02 11:05:09 +0100849 * @param[in] buf contains input characters
850 * @param[in] count is number of characters in buf.
851 * @return Number of printed bytes.
852 * @return Negative value in case of error.
853 */
854static ssize_t
855trp_ly_out_clb_func(void *user_data, const void *buf, size_t count)
856{
857 LY_ERR erc = LY_SUCCESS;
858 struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data;
859
860 switch (data->mode) {
861 case TRD_PRINT:
862 erc = ly_write_(data->out, buf, count);
863 break;
864 case TRD_CHAR_COUNT:
865 data->counter = data->counter + count;
866 break;
867 default:
868 break;
869 }
870
871 if (erc != LY_SUCCESS) {
872 data->last_error = erc;
873 return -1;
874 } else {
875 return count;
876 }
877}
878
879/**
880 * @brief Check that indent in node can be considered as equivalent.
881 * @param[in] first is the first indent in node.
882 * @param[in] second is the second indent in node.
883 * @return 1 if indents are equivalent otherwise 0.
884 */
885static ly_bool
886trp_indent_in_node_are_eq(struct trt_indent_in_node first, struct trt_indent_in_node second)
887{
888 const ly_bool a = first.type == second.type;
889 const ly_bool b = first.btw_name_opts == second.btw_name_opts;
890 const ly_bool c = first.btw_opts_type == second.btw_opts_type;
891 const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures;
892
893 return a && b && c && d;
894}
895
896/**
aPiecek874ea4d2021-04-19 12:26:36 +0200897 * @brief Setting space character because node is last sibling.
898 * @param[in] wr is wrapper over which the shift operation
899 * is to be performed.
aPiecek61d062b2020-11-02 11:05:09 +0100900 * @return New shifted wrapper.
901 */
902static struct trt_wrapper
903trp_wrapper_set_shift(struct trt_wrapper wr)
904{
905 assert(wr.actual_pos < 64);
906 /* +--<node>
907 * +--<node>
908 */
909 wr.actual_pos++;
910 return wr;
911}
912
913/**
aPiecek874ea4d2021-04-19 12:26:36 +0200914 * @brief Setting '|' symbol because node is divided or
915 * it is not last sibling.
aPiecek61d062b2020-11-02 11:05:09 +0100916 * @param[in] wr is source of wrapper.
917 * @return New wrapper which is marked at actual position and shifted.
918 */
919static struct trt_wrapper
920trp_wrapper_set_mark(struct trt_wrapper wr)
921{
922 assert(wr.actual_pos < 64);
923 wr.bit_marks1 |= 1U << wr.actual_pos;
924 return trp_wrapper_set_shift(wr);
925}
926
927/**
ekinzie0ab8b302022-10-10 03:03:57 -0400928 * @brief Set '|' symbol to connect current level nodes in a module.
929 * This is only used to connect all top-level nodes in all modules under
930 * a schema mount point.
931 * @param[in] wr is the wrapper to be marked
932 * @return New wrapper which is marked at actual position.
933 */
934static struct trt_wrapper
935trp_wrapper_set_mark_top(struct trt_wrapper wr)
936{
937 wr.bit_marks1 |= 1U << wr.actual_pos;
938 return wr;
939}
940
941/**
aPiecek61d062b2020-11-02 11:05:09 +0100942 * @brief Setting ' ' symbol if node is last sibling otherwise set '|'.
943 * @param[in] wr is actual wrapper.
aPiecek874ea4d2021-04-19 12:26:36 +0200944 * @param[in] last_one is flag. Value 1 saying if the node is the last
945 * and has no more siblings.
aPiecek61d062b2020-11-02 11:05:09 +0100946 * @return New wrapper for the actual node.
947 */
948static struct trt_wrapper
949trp_wrapper_if_last_sibling(struct trt_wrapper wr, ly_bool last_one)
950{
951 return last_one ? trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
952}
953
954/**
955 * @brief Test if the wrappers are equivalent.
956 * @param[in] first is the first wrapper.
957 * @param[in] second is the second wrapper.
958 * @return 1 if the wrappers are equivalent otherwise 0.
959 */
960static ly_bool
961trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second)
962{
963 const ly_bool a = first.type == second.type;
964 const ly_bool b = first.bit_marks1 == second.bit_marks1;
965 const ly_bool c = first.actual_pos == second.actual_pos;
966
967 return a && b && c;
968}
969
970/**
971 * @brief Print " | " sequence on line.
972 * @param[in] wr is wrapper to be printed.
973 * @param[in,out] out is output handler.
974 */
975static void
976trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out)
977{
978 uint32_t lb;
979
980 if (wr.type == TRD_WRAPPER_TOP) {
981 lb = TRD_INDENT_LINE_BEGIN;
982 } else if (wr.type == TRD_WRAPPER_BODY) {
983 lb = TRD_INDENT_LINE_BEGIN * 2;
984 } else {
985 lb = TRD_INDENT_LINE_BEGIN;
986 }
987
988 ly_print_(out, "%*c", lb, ' ');
989
990 if (trp_wrapper_eq(wr, TRP_INIT_WRAPPER_TOP)) {
991 return;
992 }
993
994 for (uint32_t i = 0; i < wr.actual_pos; i++) {
995 /** Test if the bit on the index is set. */
996 if ((wr.bit_marks1 >> i) & 1U) {
997 ly_print_(out, "|");
998 } else {
999 ly_print_(out, " ");
1000 }
1001
1002 if (i != wr.actual_pos) {
1003 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1004 }
1005 }
1006}
1007
1008/**
1009 * @brief Check if struct trt_node is empty.
1010 * @param[in] node is item to test.
1011 * @return 1 if node is considered empty otherwise 0.
1012 */
1013static ly_bool
1014trp_node_is_empty(struct trt_node node)
1015{
1016 const ly_bool a = !node.iffeatures;
1017 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
1018 const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node.name);
1019 const ly_bool d = node.flags == TRD_FLAGS_TYPE_EMPTY;
1020 const ly_bool e = node.status == TRD_STATUS_TYPE_EMPTY;
1021
1022 return a && b && c && d && e;
1023}
1024
1025/**
aPiecek874ea4d2021-04-19 12:26:36 +02001026 * @brief Check if [\<keys\>], \<type\> and
1027 * \<iffeatures\> are empty/not_set.
aPiecek61d062b2020-11-02 11:05:09 +01001028 * @param[in] node is item to test.
aPiecek874ea4d2021-04-19 12:26:36 +02001029 * @return 1 if node has no \<keys\> \<type\> or \<iffeatures\>
1030 * otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +01001031 */
1032static ly_bool
1033trp_node_body_is_empty(struct trt_node node)
1034{
1035 const ly_bool a = !node.iffeatures;
1036 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
aPiecekbca57772022-10-13 13:51:59 +02001037 const ly_bool c = !node.name.keys;
aPiecek61d062b2020-11-02 11:05:09 +01001038
1039 return a && b && c;
1040}
1041
1042/**
1043 * @brief Print \<status\> of the node.
1044 * @param[in] status_type is type of status.
1045 * @param[in,out] out is output handler.
1046 */
1047static void
1048trp_print_status(trt_status_type status_type, struct ly_out *out)
1049{
1050 switch (status_type) {
1051 case TRD_STATUS_TYPE_CURRENT:
1052 ly_print_(out, "%c", '+');
1053 break;
1054 case TRD_STATUS_TYPE_DEPRECATED:
1055 ly_print_(out, "%c", 'x');
1056 break;
1057 case TRD_STATUS_TYPE_OBSOLETE:
1058 ly_print_(out, "%c", 'o');
1059 break;
1060 default:
1061 break;
1062 }
1063}
1064
1065/**
1066 * @brief Print \<flags\>.
1067 * @param[in] flags_type is type of \<flags\>.
1068 * @param[in,out] out is output handler.
1069 */
1070static void
1071trp_print_flags(trt_flags_type flags_type, struct ly_out *out)
1072{
1073 switch (flags_type) {
1074 case TRD_FLAGS_TYPE_RW:
1075 ly_print_(out, "%s", "rw");
1076 break;
1077 case TRD_FLAGS_TYPE_RO:
1078 ly_print_(out, "%s", "ro");
1079 break;
1080 case TRD_FLAGS_TYPE_RPC_INPUT_PARAMS:
1081 ly_print_(out, "%s", "-w");
1082 break;
1083 case TRD_FLAGS_TYPE_USES_OF_GROUPING:
1084 ly_print_(out, "%s", "-u");
1085 break;
1086 case TRD_FLAGS_TYPE_RPC:
1087 ly_print_(out, "%s", "-x");
1088 break;
1089 case TRD_FLAGS_TYPE_NOTIF:
1090 ly_print_(out, "%s", "-n");
1091 break;
1092 case TRD_FLAGS_TYPE_MOUNT_POINT:
1093 ly_print_(out, "%s", "mp");
1094 break;
1095 default:
aPiecekdc8fd572021-04-19 10:47:23 +02001096 ly_print_(out, "%s", "--");
aPiecek61d062b2020-11-02 11:05:09 +01001097 break;
1098 }
1099}
1100
1101/**
1102 * @brief Get size of the \<flags\>.
1103 * @param[in] flags_type is type of \<flags\>.
1104 * @return 0 if flags_type is not set otherwise 2.
1105 */
1106static size_t
1107trp_get_flags_strlen(trt_flags_type flags_type)
1108{
1109 return flags_type == TRD_FLAGS_TYPE_EMPTY ? 0 : 2;
1110}
1111
1112/**
1113 * @brief Print entire struct trt_node_name structure.
1114 * @param[in] node_name is item to print.
1115 * @param[in,out] out is output handler.
1116 */
1117static void
1118trp_print_node_name(struct trt_node_name node_name, struct ly_out *out)
1119{
1120 const char *mod_prefix;
1121 const char *colon;
1122 const char trd_node_name_suffix_choice[] = ")";
1123 const char trd_node_name_suffix_case[] = ")";
1124 const char trd_opts_optional[] = "?"; /**< For an optional leaf, choice, anydata, or anyxml. */
1125 const char trd_opts_container[] = "!"; /**< For a presence container. */
1126 const char trd_opts_list[] = "*"; /**< For a leaf-list or list. */
1127 const char trd_opts_slash[] = "/"; /**< For a top-level data node in a mounted module. */
1128 const char trd_opts_at_sign[] = "@"; /**< For a top-level data node of a module identified in a mount point parent reference. */
1129
1130 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1131 return;
1132 }
1133
1134 if (node_name.module_prefix) {
1135 mod_prefix = node_name.module_prefix;
1136 colon = ":";
1137 } else {
1138 mod_prefix = "";
1139 colon = "";
1140 }
1141
1142 switch (node_name.type) {
1143 case TRD_NODE_ELSE:
1144 ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
1145 break;
1146 case TRD_NODE_CASE:
1147 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, trd_node_name_suffix_case);
1148 break;
1149 case TRD_NODE_CHOICE:
1150 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice);
1151 break;
1152 case TRD_NODE_OPTIONAL_CHOICE:
1153 ly_print_(out, "%s%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice, trd_opts_optional);
1154 break;
1155 case TRD_NODE_OPTIONAL:
1156 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_optional);
1157 break;
1158 case TRD_NODE_CONTAINER:
1159 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_container);
1160 break;
1161 case TRD_NODE_LISTLEAFLIST:
1162 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1163 break;
aPiecek61d062b2020-11-02 11:05:09 +01001164 case TRD_NODE_TOP_LEVEL1:
1165 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_slash);
1166 break;
1167 case TRD_NODE_TOP_LEVEL2:
1168 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_at_sign);
1169 break;
1170 case TRD_NODE_TRIPLE_DOT:
1171 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
1172 break;
1173 default:
1174 break;
1175 }
1176}
1177
1178/**
aPiecek874ea4d2021-04-19 12:26:36 +02001179 * @brief Check if mark (?, !, *, /, @) is implicitly contained in
1180 * struct trt_node_name.
aPiecek61d062b2020-11-02 11:05:09 +01001181 * @param[in] node_name is structure containing the 'mark'.
1182 * @return 1 if contain otherwise 0.
1183 */
1184static ly_bool
1185trp_mark_is_used(struct trt_node_name node_name)
1186{
1187 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1188 return 0;
aPiecekbca57772022-10-13 13:51:59 +02001189 } else if (node_name.keys) {
1190 return 0;
aPiecek61d062b2020-11-02 11:05:09 +01001191 }
1192
1193 switch (node_name.type) {
1194 case TRD_NODE_ELSE:
1195 case TRD_NODE_CASE:
aPiecek61d062b2020-11-02 11:05:09 +01001196 return 0;
1197 default:
1198 return 1;
1199 }
1200}
1201
1202/**
1203 * @brief Print opts keys.
1204 * @param[in] node_name contains type of the node with his name.
1205 * @param[in] btw_name_opts is number of spaces between name and [keys].
aPiecek874ea4d2021-04-19 12:26:36 +02001206 * @param[in] cf is basically a pointer to the function that prints
1207 * the keys.
aPiecek61d062b2020-11-02 11:05:09 +01001208 * @param[in,out] out is output handler.
1209 */
1210static void
1211trp_print_opts_keys(struct trt_node_name node_name, int16_t btw_name_opts, struct trt_cf_print cf, struct ly_out *out)
1212{
aPiecekbca57772022-10-13 13:51:59 +02001213 if (!node_name.keys) {
aPiecek61d062b2020-11-02 11:05:09 +01001214 return;
1215 }
1216
1217 /* <name><mark>___<keys>*/
1218 if (btw_name_opts > 0) {
1219 ly_print_(out, "%*c", btw_name_opts, ' ');
1220 }
1221 ly_print_(out, "[");
1222 cf.pf(cf.ctx, out);
1223 ly_print_(out, "]");
1224}
1225
1226/**
1227 * @brief Print entire struct trt_type structure.
1228 * @param[in] type is item to print.
1229 * @param[in,out] out is output handler.
1230 */
1231static void
1232trp_print_type(struct trt_type type, struct ly_out *out)
1233{
1234 if (TRP_TRT_TYPE_IS_EMPTY(type)) {
1235 return;
1236 }
1237
1238 switch (type.type) {
1239 case TRD_TYPE_NAME:
1240 ly_print_(out, "%s", type.str);
1241 break;
1242 case TRD_TYPE_TARGET:
1243 ly_print_(out, "-> %s", type.str);
1244 break;
1245 case TRD_TYPE_LEAFREF:
1246 ly_print_(out, "leafref");
1247 default:
1248 break;
1249 }
1250}
1251
1252/**
1253 * @brief Print all iffeatures of node
1254 *
1255 * @param[in] iffeature_flag contains if if-features is present.
aPiecek874ea4d2021-04-19 12:26:36 +02001256 * @param[in] cf is basically a pointer to the function that prints
1257 * the list of features.
aPiecek61d062b2020-11-02 11:05:09 +01001258 * @param[in,out] out is output handler.
1259 */
1260static void
1261trp_print_iffeatures(ly_bool iffeature_flag, struct trt_cf_print cf, struct ly_out *out)
1262{
1263 if (iffeature_flag) {
1264 ly_print_(out, "{");
1265 cf.pf(cf.ctx, out);
1266 ly_print_(out, "}?");
1267 }
1268}
1269
1270/**
1271 * @brief Print just \<status\>--\<flags\> \<name\> with opts mark.
1272 * @param[in] node contains items to print.
1273 * @param[in] out is output handler.
1274 */
1275static void
1276trp_print_node_up_to_name(struct trt_node node, struct ly_out *out)
1277{
1278 if (node.name.type == TRD_NODE_TRIPLE_DOT) {
1279 trp_print_node_name(node.name, out);
1280 return;
1281 }
1282 /* <status>--<flags> */
1283 trp_print_status(node.status, out);
1284 ly_print_(out, "--");
aPiecek874ea4d2021-04-19 12:26:36 +02001285 /* If the node is a case node, there is no space before the <name>
1286 * also case node has no flags.
1287 */
aPiecek61d062b2020-11-02 11:05:09 +01001288 if (node.name.type != TRD_NODE_CASE) {
1289 trp_print_flags(node.flags, out);
1290 ly_print_(out, " ");
1291 }
1292 /* <name> */
1293 trp_print_node_name(node.name, out);
1294}
1295
1296/**
aPiecek874ea4d2021-04-19 12:26:36 +02001297 * @brief Print alignment (spaces) instead of
1298 * \<status\>--\<flags\> \<name\> for divided node.
aPiecek61d062b2020-11-02 11:05:09 +01001299 * @param[in] node contains items to print.
1300 * @param[in] out is output handler.
1301 */
1302static void
1303trp_print_divided_node_up_to_name(struct trt_node node, struct ly_out *out)
1304{
1305 uint32_t space = trp_get_flags_strlen(node.flags);
1306
1307 if (node.name.type == TRD_NODE_CASE) {
1308 /* :(<name> */
1309 space += strlen(TRD_NODE_NAME_PREFIX_CASE);
1310 } else if (node.name.type == TRD_NODE_CHOICE) {
1311 /* (<name> */
1312 space += strlen(TRD_NODE_NAME_PREFIX_CHOICE);
1313 } else {
1314 /* _<name> */
1315 space += strlen(" ");
1316 }
1317
1318 /* <name>
1319 * __
1320 */
1321 space += TRD_INDENT_LONG_LINE_BREAK;
1322
1323 ly_print_(out, "%*c", space, ' ');
1324}
1325
1326/**
1327 * @brief Print struct trt_node structure.
1328 * @param[in] node is item to print.
aPiecek874ea4d2021-04-19 12:26:36 +02001329 * @param[in] pck package of functions for
1330 * printing [\<keys\>] and \<iffeatures\>.
aPiecek61d062b2020-11-02 11:05:09 +01001331 * @param[in] indent is the indent in node.
1332 * @param[in,out] out is output handler.
1333 */
1334static void
1335trp_print_node(struct trt_node node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out)
1336{
1337 ly_bool triple_dot;
1338 ly_bool divided;
1339 struct trt_cf_print cf_print_keys;
1340 struct trt_cf_print cf_print_iffeatures;
1341
1342 if (trp_node_is_empty(node)) {
1343 return;
1344 }
1345
1346 /* <status>--<flags> <name><opts> <type> <if-features> */
1347 triple_dot = node.name.type == TRD_NODE_TRIPLE_DOT;
1348 divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED;
1349
1350 if (triple_dot) {
1351 trp_print_node_name(node.name, out);
1352 return;
1353 } else if (!divided) {
1354 trp_print_node_up_to_name(node, out);
1355 } else {
1356 trp_print_divided_node_up_to_name(node, out);
1357 }
1358
1359 /* <opts> */
1360 /* <name>___<opts>*/
1361 cf_print_keys.ctx = pck.tree_ctx;
1362 cf_print_keys.pf = pck.fps.print_keys;
1363
1364 trp_print_opts_keys(node.name, indent.btw_name_opts, cf_print_keys, out);
1365
1366 /* <opts>__<type> */
1367 if (indent.btw_opts_type > 0) {
1368 ly_print_(out, "%*c", indent.btw_opts_type, ' ');
1369 }
1370
1371 /* <type> */
1372 trp_print_type(node.type, out);
1373
1374 /* <type>__<iffeatures> */
1375 if (indent.btw_type_iffeatures > 0) {
1376 ly_print_(out, "%*c", indent.btw_type_iffeatures, ' ');
1377 }
1378
1379 /* <iffeatures> */
1380 cf_print_iffeatures.ctx = pck.tree_ctx;
1381 cf_print_iffeatures.pf = pck.fps.print_features_names;
1382
1383 trp_print_iffeatures(node.iffeatures, cf_print_iffeatures, out);
1384}
1385
1386/**
aPiecek874ea4d2021-04-19 12:26:36 +02001387 * @brief Print keyword based on trt_keyword_stmt.type.
aPiecek61d062b2020-11-02 11:05:09 +01001388 * @param[in] ks is keyword statement to print.
1389 * @param[in,out] out is output handler
1390 */
1391static void
1392trt_print_keyword_stmt_begin(struct trt_keyword_stmt ks, struct ly_out *out)
1393{
1394 switch (ks.type) {
1395 case TRD_KEYWORD_MODULE:
1396 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_MODULE);
1397 return;
1398 case TRD_KEYWORD_SUBMODULE:
1399 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_SUBMODULE);
1400 return;
1401 default:
1402 ly_print_(out, "%*c", TRD_INDENT_LINE_BEGIN, ' ');
1403 switch (ks.type) {
1404 case TRD_KEYWORD_AUGMENT:
1405 ly_print_(out, "%s ", TRD_BODY_KEYWORD_AUGMENT);
1406 break;
1407 case TRD_KEYWORD_RPC:
1408 ly_print_(out, "%s", TRD_BODY_KEYWORD_RPC);
1409 break;
1410 case TRD_KEYWORD_NOTIF:
1411 ly_print_(out, "%s", TRD_BODY_KEYWORD_NOTIF);
1412 break;
1413 case TRD_KEYWORD_GROUPING:
1414 ly_print_(out, "%s ", TRD_BODY_KEYWORD_GROUPING);
1415 break;
1416 case TRD_KEYWORD_YANG_DATA:
1417 ly_print_(out, "%s ", TRD_BODY_KEYWORD_YANG_DATA);
1418 break;
1419 default:
1420 break;
1421 }
1422 break;
1423 }
1424}
1425
1426/**
1427 * @brief Get string length of stored keyword.
1428 * @param[in] type is type of the keyword statement.
1429 * @return length of the keyword statement name.
1430 */
1431static size_t
1432trp_keyword_type_strlen(trt_keyword_type type)
1433{
1434 switch (type) {
1435 case TRD_KEYWORD_MODULE:
1436 return sizeof(TRD_TOP_KEYWORD_MODULE) - 1;
1437 case TRD_KEYWORD_SUBMODULE:
1438 return sizeof(TRD_TOP_KEYWORD_SUBMODULE) - 1;
1439 case TRD_KEYWORD_AUGMENT:
1440 return sizeof(TRD_BODY_KEYWORD_AUGMENT) - 1;
1441 case TRD_KEYWORD_RPC:
1442 return sizeof(TRD_BODY_KEYWORD_RPC) - 1;
1443 case TRD_KEYWORD_NOTIF:
1444 return sizeof(TRD_BODY_KEYWORD_NOTIF) - 1;
1445 case TRD_KEYWORD_GROUPING:
1446 return sizeof(TRD_BODY_KEYWORD_GROUPING) - 1;
1447 case TRD_KEYWORD_YANG_DATA:
1448 return sizeof(TRD_BODY_KEYWORD_YANG_DATA) - 1;
1449 default:
1450 return 0;
1451 }
1452}
1453
1454/**
aPiecek874ea4d2021-04-19 12:26:36 +02001455 * @brief Print trt_keyword_stmt.str which is string of name or path.
aPiecek61d062b2020-11-02 11:05:09 +01001456 * @param[in] ks is keyword statement structure.
1457 * @param[in] mll is max line length.
1458 * @param[in,out] out is output handler.
1459 */
1460static void
1461trt_print_keyword_stmt_str(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
1462{
1463 uint32_t ind_initial;
1464 uint32_t ind_divided;
1465 /* flag if path must be splitted to more lines */
1466 ly_bool linebreak_was_set;
1467 /* flag if at least one subpath was printed */
1468 ly_bool subpath_printed;
1469 /* the sum of the sizes of the substrings on the current line */
1470 uint32_t how_far;
1471 /* pointer to start of the subpath */
1472 const char *sub_ptr;
1473 /* size of subpath from sub_ptr */
1474 size_t sub_len;
1475
1476 if ((!ks.str) || (ks.str[0] == '\0')) {
1477 return;
1478 }
1479
1480 /* module name cannot be splitted */
1481 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
1482 ly_print_(out, "%s", ks.str);
1483 return;
1484 }
1485
1486 /* after -> for trd_keyword_stmt_body do */
1487
1488 /* set begin indentation */
1489 ind_initial = TRD_INDENT_LINE_BEGIN + trp_keyword_type_strlen(ks.type) + 1;
1490 ind_divided = ind_initial + TRD_INDENT_LONG_LINE_BREAK;
1491 linebreak_was_set = 0;
1492 subpath_printed = 0;
1493 how_far = 0;
1494 sub_ptr = ks.str;
1495 sub_len = 0;
1496
1497 while (sub_ptr[0] != '\0') {
1498 uint32_t ind;
1499 /* skip slash */
1500 const char *tmp = sub_ptr[0] == '/' ? sub_ptr + 1 : sub_ptr;
Michal Vasko26bbb272022-08-02 14:54:33 +02001501
aPiecek61d062b2020-11-02 11:05:09 +01001502 /* get position of the end of substr */
1503 tmp = strchr(tmp, '/');
1504 /* set correct size if this is a last substring */
1505 sub_len = !tmp ? strlen(sub_ptr) : (size_t)(tmp - sub_ptr);
1506 /* actualize sum of the substring's sizes on the current line */
1507 how_far += sub_len;
1508 /* correction due to colon character if it this is last substring */
1509 how_far = *(sub_ptr + sub_len) == '\0' ? how_far + 1 : how_far;
1510 /* choose indentation which depends on
1511 * whether the string is printed on multiple lines or not
1512 */
1513 ind = linebreak_was_set ? ind_divided : ind_initial;
1514 if (ind + how_far <= mll) {
1515 /* printing before max line length */
1516 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1517 subpath_printed = 1;
1518 } else {
1519 /* printing on new line */
1520 if (subpath_printed == 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001521 /* first subpath is too long
1522 * but print it at first line anyway
1523 */
aPiecek61d062b2020-11-02 11:05:09 +01001524 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1525 subpath_printed = 1;
1526 continue;
1527 }
1528 ly_print_(out, "\n");
1529 ly_print_(out, "%*c", ind_divided, ' ');
1530 linebreak_was_set = 1;
1531 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1532 how_far = sub_len;
1533 subpath_printed = 1;
1534 }
1535 }
1536}
1537
1538/**
aPiecek874ea4d2021-04-19 12:26:36 +02001539 * @brief Print separator based on trt_keyword_stmt.type
aPiecek61d062b2020-11-02 11:05:09 +01001540 * @param[in] ks is keyword statement structure.
aPiecekdc8fd572021-04-19 10:47:23 +02001541 * @param[in] grp_has_data is flag only for grouping section.
1542 * Set to 1 if grouping section has some nodes.
1543 * Set to 0 if it doesn't have nodes or it's not grouping section.
aPiecek61d062b2020-11-02 11:05:09 +01001544 * @param[in,out] out is output handler.
1545 */
1546static void
aPiecekdc8fd572021-04-19 10:47:23 +02001547trt_print_keyword_stmt_end(struct trt_keyword_stmt ks, ly_bool grp_has_data, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001548{
1549 if ((ks.type != TRD_KEYWORD_MODULE) && (ks.type != TRD_KEYWORD_SUBMODULE)) {
aPiecekdc8fd572021-04-19 10:47:23 +02001550 if ((ks.type == TRD_KEYWORD_GROUPING) && !grp_has_data) {
1551 return;
1552 } else {
1553 ly_print_(out, ":");
1554 }
aPiecek61d062b2020-11-02 11:05:09 +01001555 }
1556}
1557
1558/**
1559 * @brief Print entire struct trt_keyword_stmt structure.
1560 * @param[in] ks is item to print.
1561 * @param[in] mll is max line length.
aPiecekdc8fd572021-04-19 10:47:23 +02001562 * @param[in] grp_has_data is flag only for grouping section.
1563 * Set to 1 if grouping section has some nodes.
1564 * Set to 0 if it doesn't have nodes or it's not grouping section.
aPiecek61d062b2020-11-02 11:05:09 +01001565 * @param[in,out] out is output handler.
1566 */
1567static void
aPiecek874ea4d2021-04-19 12:26:36 +02001568trp_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 +01001569{
1570 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
1571 return;
1572 }
1573 trt_print_keyword_stmt_begin(ks, out);
1574 trt_print_keyword_stmt_str(ks, mll, out);
aPiecekdc8fd572021-04-19 10:47:23 +02001575 trt_print_keyword_stmt_end(ks, grp_has_data, out);
aPiecek61d062b2020-11-02 11:05:09 +01001576}
1577
aPiecek874ea4d2021-04-19 12:26:36 +02001578/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01001579 * Main trp functions
aPiecek874ea4d2021-04-19 12:26:36 +02001580 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01001581
1582/**
aPiecek874ea4d2021-04-19 12:26:36 +02001583 * @brief Printing one line including wrapper and node
1584 * which can be incomplete (divided).
aPiecek61d062b2020-11-02 11:05:09 +01001585 * @param[in] node is \<node\> representation.
1586 * @param[in] pck contains special printing functions callback.
1587 * @param[in] indent contains wrapper and indent in node numbers.
1588 * @param[in,out] out is output handler.
1589 */
1590static void
1591trp_print_line(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out)
1592{
1593 trp_print_wrapper(indent.wrapper, out);
1594 trp_print_node(node, pck, indent.in_node, out);
1595}
1596
1597/**
aPiecek874ea4d2021-04-19 12:26:36 +02001598 * @brief Printing one line including wrapper and
1599 * \<status\>--\<flags\> \<name\>\<option_mark\>.
aPiecek61d062b2020-11-02 11:05:09 +01001600 * @param[in] node is \<node\> representation.
1601 * @param[in] wr is wrapper for printing indentation before node.
1602 * @param[in] out is output handler.
1603 */
1604static void
1605trp_print_line_up_to_node_name(struct trt_node node, struct trt_wrapper wr, struct ly_out *out)
1606{
1607 trp_print_wrapper(wr, out);
1608 trp_print_node_up_to_name(node, out);
1609}
1610
1611/**
aPiecek874ea4d2021-04-19 12:26:36 +02001612 * @brief Check if leafref target must be change to string 'leafref'
1613 * because his target string is too long.
aPiecek61d062b2020-11-02 11:05:09 +01001614 * @param[in] node containing leafref target.
1615 * @param[in] wr is wrapper for printing indentation before node.
1616 * @param[in] mll is max line length.
1617 * @param[in] out is output handler.
1618 * @return true if leafref must be changed to string 'leafref'.
1619 */
1620static ly_bool
1621trp_leafref_target_is_too_long(struct trt_node node, struct trt_wrapper wr, size_t mll, struct ly_out *out)
1622{
1623 struct ly_out_clb_arg *data;
1624
1625 if (node.type.type != TRD_TYPE_TARGET) {
1626 return 0;
1627 }
1628
1629 /* set ly_out to counting characters */
1630 data = out->method.clb.arg;
1631
1632 data->counter = 0;
1633 data->mode = TRD_CHAR_COUNT;
1634 /* count number of printed bytes */
1635 trp_print_wrapper(wr, out);
1636 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1637 trp_print_divided_node_up_to_name(node, out);
1638 data->mode = TRD_PRINT;
1639
1640 return data->counter + strlen(node.type.str) > mll;
1641}
1642
1643/**
1644 * @brief Get default indent in node based on node values.
1645 * @param[in] node is \<node\> representation.
aPiecek874ea4d2021-04-19 12:26:36 +02001646 * @return Default indent in node assuming that the node
1647 * will not be divided.
aPiecek61d062b2020-11-02 11:05:09 +01001648 */
1649static struct trt_indent_in_node
1650trp_default_indent_in_node(struct trt_node node)
1651{
1652 struct trt_indent_in_node ret;
1653
1654 ret.type = TRD_INDENT_IN_NODE_NORMAL;
1655
1656 /* btw_name_opts */
aPiecekbca57772022-10-13 13:51:59 +02001657 ret.btw_name_opts = node.name.keys ? TRD_INDENT_BEFORE_KEYS : 0;
aPiecek61d062b2020-11-02 11:05:09 +01001658
1659 /* btw_opts_type */
1660 if (!(TRP_TRT_TYPE_IS_EMPTY(node.type))) {
1661 ret.btw_opts_type = trp_mark_is_used(node.name) ?
1662 TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
1663 TRD_INDENT_BEFORE_TYPE;
1664 } else {
1665 ret.btw_opts_type = 0;
1666 }
1667
1668 /* btw_type_iffeatures */
1669 ret.btw_type_iffeatures = node.iffeatures ? TRD_INDENT_BEFORE_IFFEATURES : 0;
1670
1671 return ret;
1672}
1673
1674/**
1675 * @brief Setting linebreaks in trt_indent_in_node.
1676 *
1677 * The order where the linebreak tag can be placed is from the end.
1678 *
aPiecek874ea4d2021-04-19 12:26:36 +02001679 * @param[in] indent containing alignment lengths
1680 * or already linebreak marks.
aPiecek61d062b2020-11-02 11:05:09 +01001681 * @return indent with a newly placed linebreak tag.
aPiecek874ea4d2021-04-19 12:26:36 +02001682 * @return .type set to TRD_INDENT_IN_NODE_FAILED if it is not possible
1683 * to place a more linebreaks.
aPiecek61d062b2020-11-02 11:05:09 +01001684 */
1685static struct trt_indent_in_node
1686trp_indent_in_node_place_break(struct trt_indent_in_node indent)
1687{
1688 /* somewhere must be set a line break in node */
1689 struct trt_indent_in_node ret = indent;
1690
1691 /* gradually break the node from the end */
1692 if ((indent.btw_type_iffeatures != TRD_LINEBREAK) && (indent.btw_type_iffeatures != 0)) {
1693 ret.btw_type_iffeatures = TRD_LINEBREAK;
1694 } else if ((indent.btw_opts_type != TRD_LINEBREAK) && (indent.btw_opts_type != 0)) {
1695 ret.btw_opts_type = TRD_LINEBREAK;
1696 } else if ((indent.btw_name_opts != TRD_LINEBREAK) && (indent.btw_name_opts != 0)) {
1697 /* set line break between name and opts */
1698 ret.btw_name_opts = TRD_LINEBREAK;
1699 } else {
1700 /* it is not possible to place a more line breaks,
1701 * unfortunately the max_line_length constraint is violated
1702 */
1703 ret.type = TRD_INDENT_IN_NODE_FAILED;
1704 }
1705 return ret;
1706}
1707
1708/**
1709 * @brief Get the first half of the node based on the linebreak mark.
1710 *
1711 * Items in the second half of the node will be empty.
1712 *
1713 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001714 * @param[in] indent contains information in which part of the \<node\>
1715 * the first half ends.
aPiecek61d062b2020-11-02 11:05:09 +01001716 * @return first half of the node, indent is unchanged.
1717 */
1718static struct trt_pair_indent_node
1719trp_first_half_node(struct trt_node node, struct trt_indent_in_node indent)
1720{
1721 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1722
1723 if (indent.btw_name_opts == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001724 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001725 ret.node.type = TRP_EMPTY_TRT_TYPE;
1726 ret.node.iffeatures = 0;
1727 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1728 ret.node.type = TRP_EMPTY_TRT_TYPE;
1729 ret.node.iffeatures = 0;
1730 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1731 ret.node.iffeatures = 0;
1732 }
1733
1734 return ret;
1735}
1736
1737/**
1738 * @brief Get the second half of the node based on the linebreak mark.
1739 *
1740 * Items in the first half of the node will be empty.
1741 * Indentations belonging to the first node will be reset to zero.
1742 *
1743 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001744 * @param[in] indent contains information in which part of the \<node\>
1745 * the second half starts.
aPiecek61d062b2020-11-02 11:05:09 +01001746 * @return second half of the node, indent is newly set.
1747 */
1748static struct trt_pair_indent_node
1749trp_second_half_node(struct trt_node node, struct trt_indent_in_node indent)
1750{
1751 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1752
1753 if (indent.btw_name_opts < 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001754 /* Logically, the information up to token <opts> should
1755 * be deleted, but the the trp_print_node function needs it to
1756 * create the correct indent.
aPiecek61d062b2020-11-02 11:05:09 +01001757 */
1758 ret.indent.btw_name_opts = 0;
1759 ret.indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(node.type) ? 0 : TRD_INDENT_BEFORE_TYPE;
1760 ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1761 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001762 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001763 ret.indent.btw_name_opts = 0;
1764 ret.indent.btw_opts_type = 0;
1765 ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1766 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001767 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001768 ret.node.type = TRP_EMPTY_TRT_TYPE;
1769 ret.indent.btw_name_opts = 0;
1770 ret.indent.btw_opts_type = 0;
1771 ret.indent.btw_type_iffeatures = 0;
1772 }
1773 return ret;
1774}
1775
1776/**
1777 * @brief Get the correct alignment for the node.
1778 *
aPiecek874ea4d2021-04-19 12:26:36 +02001779 * This function is recursively called itself. It's like a backend
aPiecek01598c02021-04-23 14:18:24 +02001780 * function for a function ::trp_try_normal_indent_in_node().
aPiecek61d062b2020-11-02 11:05:09 +01001781 *
1782 * @param[in] node is \<node\> representation.
1783 * @param[in] pck contains speciall callback functions for printing.
1784 * @param[in] indent contains wrapper and indent in node numbers.
1785 * @param[in] mll is max line length.
1786 * @param[in,out] cnt counting number of characters to print.
1787 * @param[in,out] out is output handler.
1788 * @return pair of node and indentation numbers of that node.
1789 */
1790static struct trt_pair_indent_node
1791trp_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)
1792{
1793 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1794
1795 trp_print_line(node, pck, indent, out);
1796
1797 if (*cnt <= mll) {
1798 /* success */
1799 return ret;
1800 } else {
1801 ret.indent = trp_indent_in_node_place_break(ret.indent);
1802 if (ret.indent.type != TRD_INDENT_IN_NODE_FAILED) {
1803 /* erase information in node due to line break */
1804 ret = trp_first_half_node(node, ret.indent);
1805 /* check if line fits, recursive call */
1806 *cnt = 0;
1807 ret = trp_try_normal_indent_in_node_(ret.node, pck, TRP_INIT_PCK_INDENT(indent.wrapper, ret.indent), mll, cnt, out);
1808 /* make sure that the result will be with the status divided
1809 * or eventually with status failed */
1810 ret.indent.type = ret.indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED;
1811 }
1812 return ret;
1813 }
1814}
1815
1816/**
1817 * @brief Get the correct alignment for the node.
1818 *
1819 * @param[in] node is \<node\> representation.
1820 * @param[in] pck contains speciall callback functions for printing.
1821 * @param[in] indent contains wrapper and indent in node numbers.
1822 * @param[in] mll is max line length.
1823 * @param[in,out] out is output handler.
aPiecek874ea4d2021-04-19 12:26:36 +02001824 * @return ::TRD_INDENT_IN_NODE_DIVIDED - the node does not fit in the
1825 * line, some indent variable has negative value as a line break sign.
1826 * @return ::TRD_INDENT_IN_NODE_NORMAL - the node fits into the line,
1827 * all indent variables values has non-negative number.
1828 * @return ::TRD_INDENT_IN_NODE_FAILED - the node does not fit into the
1829 * line, all indent variables has negative or zero values,
1830 * function failed.
aPiecek61d062b2020-11-02 11:05:09 +01001831 */
1832static struct trt_pair_indent_node
1833trp_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)
1834{
1835 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1836 struct ly_out_clb_arg *data;
1837
1838 /* set ly_out to counting characters */
1839 data = out->method.clb.arg;
1840
1841 data->counter = 0;
1842 data->mode = TRD_CHAR_COUNT;
1843 ret = trp_try_normal_indent_in_node_(node, pck, indent, mll, &data->counter, out);
1844 data->mode = TRD_PRINT;
1845
1846 return ret;
1847}
1848
1849/**
aPiecek01598c02021-04-23 14:18:24 +02001850 * @brief Auxiliary function for ::trp_print_entire_node()
aPiecek874ea4d2021-04-19 12:26:36 +02001851 * that prints split nodes.
aPiecek61d062b2020-11-02 11:05:09 +01001852 * @param[in] node is node representation.
1853 * @param[in] ppck contains speciall callback functions for printing.
1854 * @param[in] ipck contains wrapper and indent in node numbers.
1855 * @param[in] mll is max line length.
1856 * @param[in,out] out is output handler.
1857 */
1858static void
1859trp_print_divided_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1860{
1861 ly_bool entire_node_was_printed;
1862 struct trt_pair_indent_node ind_node = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1863
1864 if (ind_node.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1865 /* nothing can be done, continue as usual */
1866 ind_node.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1867 }
1868
1869 trp_print_line(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), out);
1870 entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, ind_node.indent);
1871
1872 if (!entire_node_was_printed) {
1873 ly_print_(out, "\n");
1874 /* continue with second half node */
1875 ind_node = trp_second_half_node(node, ind_node.indent);
1876 /* continue with printing node */
1877 trp_print_divided_node(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), mll, out);
1878 } else {
1879 return;
1880 }
1881}
1882
1883/**
aPiecek874ea4d2021-04-19 12:26:36 +02001884 * @brief Printing of the wrapper and the whole node,
1885 * which can be divided into several lines.
aPiecek61d062b2020-11-02 11:05:09 +01001886 * @param[in] node is node representation.
1887 * @param[in] ppck contains speciall callback functions for printing.
1888 * @param[in] ipck contains wrapper and indent in node numbers.
1889 * @param[in] mll is max line length.
1890 * @param[in,out] out is output handler.
1891 */
1892static void
1893trp_print_entire_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1894{
1895 struct trt_pair_indent_node ind_node1;
1896 struct trt_pair_indent_node ind_node2;
1897 struct trt_pck_indent tmp;
1898
1899 if (trp_leafref_target_is_too_long(node, ipck.wrapper, mll, out)) {
1900 node.type.type = TRD_TYPE_LEAFREF;
1901 }
1902
1903 /* check if normal indent is possible */
1904 ind_node1 = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1905
1906 if (ind_node1.indent.type == TRD_INDENT_IN_NODE_NORMAL) {
1907 /* node fits to one line */
1908 trp_print_line(node, ppck, ipck, out);
1909 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_DIVIDED) {
1910 /* node will be divided */
1911 /* print first half */
1912 tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node1.indent);
1913 /* pretend that this is normal node */
1914 tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL;
1915
1916 trp_print_line(ind_node1.node, ppck, tmp, out);
1917 ly_print_(out, "\n");
1918
1919 /* continue with second half on new line */
1920 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1921 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1922
1923 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1924 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1925 /* node name is too long */
1926 trp_print_line_up_to_node_name(node, ipck.wrapper, out);
1927
1928 if (trp_node_body_is_empty(node)) {
1929 return;
1930 } else {
1931 ly_print_(out, "\n");
1932
1933 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1934 ind_node2.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1935 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1936
1937 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1938 }
1939
1940 }
1941}
1942
aPiecek874ea4d2021-04-19 12:26:36 +02001943/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02001944 * trop and troc getters
aPiecekef1e58e2021-04-19 13:19:44 +02001945 *********************************************************************/
1946
1947/**
1948 * @brief Get nodetype.
1949 * @param[in] node is any lysp_node.
1950 */
1951static uint16_t
1952trop_nodetype(const void *node)
1953{
1954 return ((const struct lysp_node *)node)->nodetype;
1955}
1956
1957/**
1958 * @brief Get sibling.
1959 * @param[in] node is any lysp_node.
1960 */
1961static const void *
1962trop_next(const void *node)
1963{
1964 return ((const struct lysp_node *)node)->next;
1965}
1966
1967/**
1968 * @brief Get parent.
1969 * @param[in] node is any lysp_node.
1970 */
1971static const void *
1972trop_parent(const void *node)
1973{
1974 return ((const struct lysp_node *)node)->parent;
1975}
1976
1977/**
1978 * @brief Try to get child.
1979 * @param[in] node is any lysp_node.
1980 */
1981static const void *
1982trop_child(const void *node)
1983{
1984 return lysp_node_child(node);
1985}
1986
1987/**
1988 * @brief Try to get action.
1989 * @param[in] node is any lysp_node.
1990 */
1991static const void *
1992trop_actions(const void *node)
1993{
1994 return lysp_node_actions(node);
1995}
1996
1997/**
1998 * @brief Try to get action.
1999 * @param[in] node must be of type lysp_node_action.
2000 */
2001static const void *
2002trop_action_input(const void *node)
2003{
2004 return &((const struct lysp_node_action *)node)->input;
2005}
2006
2007/**
2008 * @brief Try to get action.
2009 * @param[in] node must be of type lysp_node_action.
2010 */
2011static const void *
2012trop_action_output(const void *node)
2013{
2014 return &((const struct lysp_node_action *)node)->output;
2015}
2016
2017/**
2018 * @brief Try to get action.
2019 * @param[in] node is any lysp_node.
2020 */
2021static const void *
2022trop_notifs(const void *node)
2023{
2024 return lysp_node_notifs(node);
2025}
2026
2027/**
aPiecek01598c02021-04-23 14:18:24 +02002028 * @brief Fill struct tro_getters with @ref TRP_trop getters
aPiecekef1e58e2021-04-19 13:19:44 +02002029 * which are adapted to lysp nodes.
2030 */
2031static struct tro_getters
2032trop_init_getters()
2033{
2034 return (struct tro_getters) {
2035 .nodetype = trop_nodetype,
2036 .next = trop_next,
2037 .parent = trop_parent,
2038 .child = trop_child,
2039 .actions = trop_actions,
2040 .action_input = trop_action_input,
2041 .action_output = trop_action_output,
2042 .notifs = trop_notifs
2043 };
2044}
2045
aPiecek3f247652021-04-19 13:40:25 +02002046/**
2047 * @brief Get nodetype.
2048 * @param[in] node is any lysc_node.
2049 */
2050static uint16_t
2051troc_nodetype(const void *node)
2052{
2053 return ((const struct lysc_node *)node)->nodetype;
2054}
2055
2056/**
2057 * @brief Get sibling.
2058 * @param[in] node is any lysc_node.
2059 */
2060static const void *
2061troc_next(const void *node)
2062{
2063 return ((const struct lysc_node *)node)->next;
2064}
2065
2066/**
2067 * @brief Get parent.
2068 * @param[in] node is any lysc_node.
2069 */
2070static const void *
2071troc_parent(const void *node)
2072{
2073 return ((const struct lysc_node *)node)->parent;
2074}
2075
2076/**
2077 * @brief Try to get child.
2078 * @param[in] node is any lysc_node.
2079 */
2080static const void *
2081troc_child(const void *node)
2082{
2083 return lysc_node_child(node);
2084}
2085
2086/**
2087 * @brief Try to get action.
2088 * @param[in] node is any lysc_node.
2089 */
2090static const void *
2091troc_actions(const void *node)
2092{
2093 return lysc_node_actions(node);
2094}
2095
2096/**
2097 * @brief Try to get action.
2098 * @param[in] node must be of type lysc_node_action.
2099 */
2100static const void *
2101troc_action_input(const void *node)
2102{
2103 return &((const struct lysc_node_action *)node)->input;
2104}
2105
2106/**
2107 * @brief Try to get action.
2108 * @param[in] node must be of type lysc_node_action.
2109 */
2110static const void *
2111troc_action_output(const void *node)
2112{
2113 return &((const struct lysc_node_action *)node)->output;
2114}
2115
2116/**
2117 * @brief Try to get action.
2118 * @param[in] node is any lysc_node.
2119 */
2120static const void *
2121troc_notifs(const void *node)
2122{
2123 return lysc_node_notifs(node);
2124}
2125
2126/**
aPiecek01598c02021-04-23 14:18:24 +02002127 * @brief Fill struct tro_getters with @ref TRP_troc getters
aPiecek3f247652021-04-19 13:40:25 +02002128 * which are adapted to lysc nodes.
2129 */
2130static struct tro_getters
2131troc_init_getters()
2132{
2133 return (struct tro_getters) {
2134 .nodetype = troc_nodetype,
2135 .next = troc_next,
2136 .parent = troc_parent,
2137 .child = troc_child,
2138 .actions = troc_actions,
2139 .action_input = troc_action_input,
2140 .action_output = troc_action_output,
2141 .notifs = troc_notifs
2142 };
2143}
2144
aPiecekef1e58e2021-04-19 13:19:44 +02002145/**********************************************************************
2146 * tro functions
2147 *********************************************************************/
2148
2149/**
2150 * @brief Get next sibling of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002151 *
2152 * This is a general algorithm that is able to
2153 * work with lysp_node or lysc_node.
2154 *
2155 * @param[in] node points to lysp_node or lysc_node.
2156 * @param[in] lysc_tree flag to determine what type the @p node is.
2157 * If set to true, then @p points to lysc_node otherwise lysp_node.
2158 * This flag should be the same as trt_tree_ctx.lysc_tree.
aPiecekef1e58e2021-04-19 13:19:44 +02002159 */
2160static const void *
aPiecek3f247652021-04-19 13:40:25 +02002161tro_next_sibling(const void *node, ly_bool lysc_tree)
aPiecekef1e58e2021-04-19 13:19:44 +02002162{
2163 struct tro_getters get;
2164 const void *tmp, *parent;
2165 const void *ret;
2166
2167 assert(node);
2168
aPiecek3f247652021-04-19 13:40:25 +02002169 get = lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002170
2171 if (get.nodetype(node) & (LYS_RPC | LYS_ACTION)) {
2172 if ((tmp = get.next(node))) {
2173 /* next action exists */
2174 ret = tmp;
2175 } else if ((parent = get.parent(node))) {
2176 /* maybe if notif exists as sibling */
2177 ret = get.notifs(parent);
2178 } else {
2179 ret = NULL;
2180 }
2181 } else if (get.nodetype(node) & LYS_INPUT) {
2182 if ((parent = get.parent(node))) {
2183 /* if output action has data */
2184 if (get.child(get.action_output(parent))) {
2185 /* then next sibling is output action */
2186 ret = get.action_output(parent);
2187 } else {
2188 /* input action cannot have siblings other
2189 * than output action.
2190 */
2191 ret = NULL;
2192 }
2193 } else {
2194 /* there is no way how to get output action */
2195 ret = NULL;
2196 }
2197 } else if (get.nodetype(node) & LYS_OUTPUT) {
2198 /* output action cannot have siblings */
2199 ret = NULL;
2200 } else if (get.nodetype(node) & LYS_NOTIF) {
2201 /* must have as a sibling only notif */
2202 ret = get.next(node);
2203 } else {
2204 /* for rest of nodes */
2205 if ((tmp = get.next(node))) {
2206 /* some sibling exists */
2207 ret = tmp;
2208 } else if ((parent = get.parent(node))) {
2209 /* Action and notif are siblings too.
2210 * They can be reached through parent.
2211 */
2212 if ((tmp = get.actions(parent))) {
2213 /* next sibling is action */
2214 ret = tmp;
2215 } else if ((tmp = get.notifs(parent))) {
2216 /* next sibling is notif */
2217 ret = tmp;
2218 } else {
2219 /* sibling not exists */
2220 ret = NULL;
2221 }
2222 } else {
2223 /* sibling not exists */
2224 ret = NULL;
2225 }
2226 }
2227
2228 return ret;
2229}
2230
2231/**
2232 * @brief Get child of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002233 *
2234 * This is a general algorithm that is able to
2235 * work with lysp_node or lysc_node.
2236 *
2237 * @param[in] node points to lysp_node or lysc_node.
2238 * @param[in] lysc_tree flag to determine what type the @p node is.
2239 * If set to true, then @p points to lysc_node otherwise lysp_node.
2240 * This flag should be the same as trt_tree_ctx.lysc_tree.
aPiecekef1e58e2021-04-19 13:19:44 +02002241 */
2242static const void *
aPiecek3f247652021-04-19 13:40:25 +02002243tro_next_child(const void *node, ly_bool lysc_tree)
aPiecekef1e58e2021-04-19 13:19:44 +02002244{
2245 struct tro_getters get;
2246 const void *tmp;
2247 const void *ret;
2248
2249 assert(node);
2250
aPiecek3f247652021-04-19 13:40:25 +02002251 get = lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002252
2253 if (get.nodetype(node) & (LYS_ACTION | LYS_RPC)) {
2254 if (get.child(get.action_input(node))) {
2255 /* go to LYS_INPUT */
2256 ret = get.action_input(node);
2257 } else if (get.child(get.action_output(node))) {
2258 /* go to LYS_OUTPUT */
2259 ret = get.action_output(node);
2260 } else {
2261 /* input action and output action have no data */
2262 ret = NULL;
2263 }
2264 } else {
2265 if ((tmp = get.child(node))) {
2266 ret = tmp;
2267 } else {
2268 /* current node can't have children or has no children */
2269 /* but maybe has some actions or notifs */
2270 if ((tmp = get.actions(node))) {
2271 ret = tmp;
2272 } else if ((tmp = get.notifs(node))) {
2273 ret = tmp;
2274 } else {
2275 ret = NULL;
2276 }
2277 }
2278 }
2279
2280 return ret;
2281}
2282
2283/**
aPiecek3f247652021-04-19 13:40:25 +02002284 * @brief Get new trt_parent_cache if we apply the transfer
2285 * to the child node in the tree.
2286 * @param[in] ca is parent cache for current node.
2287 * @param[in] tc contains current tree node.
2288 * @return Cache for the current node.
2289 */
2290static struct trt_parent_cache
2291tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2292{
2293 struct trt_parent_cache ret = TRP_EMPTY_PARENT_CACHE;
2294
2295 if (!tc->lysc_tree) {
2296 const struct lysp_node *pn = tc->pn;
2297
2298 ret.ancestor =
2299 pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT :
2300 pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT :
2301 pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF :
2302 ca.ancestor;
2303
2304 ret.lys_status =
2305 pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
2306 ca.lys_status;
2307
2308 ret.lys_config =
2309 ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because <flags> will be -w */
2310 ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
2311 pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
2312 ca.lys_config;
2313
2314 ret.last_list =
2315 pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
2316 ca.last_list;
2317 }
2318
2319 return ret;
2320}
2321
2322/**
aPiecekef1e58e2021-04-19 13:19:44 +02002323 * @brief Transformation of the Schema nodes flags to
2324 * Tree diagram \<status\>.
2325 * @param[in] flags is node's flags obtained from the tree.
2326 */
2327static trt_status_type
2328tro_flags2status(uint16_t flags)
2329{
2330 return flags & LYS_STATUS_OBSLT ? TRD_STATUS_TYPE_OBSOLETE :
2331 flags & LYS_STATUS_DEPRC ? TRD_STATUS_TYPE_DEPRECATED :
2332 TRD_STATUS_TYPE_CURRENT;
2333}
2334
2335/**
2336 * @brief Transformation of the Schema nodes flags to Tree diagram
2337 * \<flags\> but more specifically 'ro' or 'rw'.
2338 * @param[in] flags is node's flags obtained from the tree.
2339 */
2340static trt_flags_type
2341tro_flags2config(uint16_t flags)
2342{
2343 return flags & LYS_CONFIG_R ? TRD_FLAGS_TYPE_RO :
2344 flags & LYS_CONFIG_W ? TRD_FLAGS_TYPE_RW :
2345 TRD_FLAGS_TYPE_EMPTY;
2346}
2347
2348/**
aPiecek3f247652021-04-19 13:40:25 +02002349 * @brief Print current node's iffeatures.
2350 * @param[in] tc is tree context.
2351 * @param[in,out] out is output handler.
2352 */
2353static void
2354tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out)
2355{
2356 const struct lysp_qname *iffs;
2357
aPiecekbbc02932021-05-21 07:19:41 +02002358 if (tc->lysc_tree) {
2359 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2360 iffs = TRP_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures;
2361 } else {
2362 iffs = tc->pn->iffeatures;
2363 }
aPiecek3f247652021-04-19 13:40:25 +02002364 LY_ARRAY_COUNT_TYPE i;
2365
2366 LY_ARRAY_FOR(iffs, i) {
2367 if (i == 0) {
2368 ly_print_(out, "%s", iffs[i].str);
2369 } else {
2370 ly_print_(out, ",%s", iffs[i].str);
2371 }
2372 }
2373
2374}
2375
2376/**
2377 * @brief Print current list's keys.
2378 *
2379 * Well, actually printing keys in the lysp_tree is trivial,
2380 * because char* points to all keys. However, special functions have
2381 * been reserved for this, because in principle the list of elements
2382 * can have more implementations.
2383 *
2384 * @param[in] tc is tree context.
2385 * @param[in,out] out is output handler.
2386 */
2387static void
2388tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out)
2389{
2390 const struct lysp_node_list *list;
2391
aPiecekbbc02932021-05-21 07:19:41 +02002392 if (tc->lysc_tree) {
2393 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2394 list = (const struct lysp_node_list *)TRP_TREE_CTX_GET_LYSP_NODE(tc->cn);
2395 } else {
2396 list = (const struct lysp_node_list *)tc->pn;
2397 }
aPiecek3f247652021-04-19 13:40:25 +02002398 assert(list->nodetype & LYS_LIST);
2399
2400 if (trg_charptr_has_data(list->key)) {
2401 ly_print_(out, "%s", list->key);
2402 }
2403}
2404
2405/**
2406 * @brief Get rpcs section if exists.
2407 * @param[in,out] tc is tree context.
2408 * @return Section representation if it exists. The @p tc is modified
2409 * and his pointer points to the first node in rpcs section.
2410 * @return Empty section representation otherwise.
2411 */
2412static struct trt_keyword_stmt
2413tro_modi_get_rpcs(struct trt_tree_ctx *tc)
2414{
aPiecek9f792e52021-04-21 08:33:56 +02002415 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002416 const void *actions;
2417
2418 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002419 actions = tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002420 if (actions) {
2421 tc->cn = actions;
2422 }
2423 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002424 actions = tc->pmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002425 if (actions) {
2426 tc->pn = actions;
2427 tc->tpn = tc->pn;
2428 }
2429 }
2430
2431 if (actions) {
2432 tc->section = TRD_SECT_RPCS;
2433 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_RPC, NULL);
2434 } else {
2435 return TRP_EMPTY_KEYWORD_STMT;
2436 }
2437}
2438
2439/**
2440 * @brief Get notification section if exists
2441 * @param[in,out] tc is tree context.
2442 * @return Section representation if it exists.
2443 * The @p tc is modified and his pointer points to the
2444 * first node in notification section.
2445 * @return Empty section representation otherwise.
2446 */
2447static struct trt_keyword_stmt
2448tro_modi_get_notifications(struct trt_tree_ctx *tc)
2449{
aPiecek9f792e52021-04-21 08:33:56 +02002450 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002451 const void *notifs;
2452
2453 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002454 notifs = tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002455 if (notifs) {
2456 tc->cn = notifs;
2457 }
2458 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002459 notifs = tc->pmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002460 if (notifs) {
2461 tc->pn = notifs;
2462 tc->tpn = tc->pn;
2463 }
2464 }
2465
2466 if (notifs) {
2467 tc->section = TRD_SECT_NOTIF;
2468 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_NOTIF, NULL);
2469 } else {
2470 return TRP_EMPTY_KEYWORD_STMT;
2471 }
2472}
2473
2474/**
aPiecek96baa7f2021-04-23 12:32:00 +02002475 * @brief Get next yang-data section if it is possible.
aPiecekef1e58e2021-04-19 13:19:44 +02002476 *
2477 * @param[in,out] tc is tree context.
aPiecek96baa7f2021-04-23 12:32:00 +02002478 * @param[in] u is index to the array of extensions (lysc_ext_instance
2479 * or struct lysp_ext_instance).
aPiecekef1e58e2021-04-19 13:19:44 +02002480 * @return Section representation if it exists.
2481 * @return Empty section representation otherwise.
2482 */
2483static struct trt_keyword_stmt
aPiecek96baa7f2021-04-23 12:32:00 +02002484tro_modi_next_yang_data(struct trt_tree_ctx *tc, LY_ARRAY_COUNT_TYPE u)
aPiecekef1e58e2021-04-19 13:19:44 +02002485{
aPiecek96baa7f2021-04-23 12:32:00 +02002486 assert(tc);
2487 const void *node;
2488 const char *yang_data_name;
2489
2490 if (tc->lysc_tree) {
2491 struct lysc_ext_instance *exts;
2492 struct lysc_ext_substmt *substmts;
2493
2494 exts = tc->cmod->exts;
2495 substmts = exts[u].substmts;
2496 if (!substmts) {
2497 return TRP_EMPTY_KEYWORD_STMT;
2498 }
2499 node = *(const struct lysc_node **)substmts->storage;
2500 yang_data_name = exts[u].argument;
2501 } else {
2502 struct lysp_ext_instance *exts;
2503
2504 exts = tc->pmod->exts;
2505 node = exts[u].parsed;
2506 yang_data_name = exts[u].argument;
2507 }
2508
2509 if (tc->lysc_tree) {
2510 tc->cn = node;
2511 } else {
2512 tc->tpn_ext = &tc->pmod->exts[u];
2513 tc->pn = node;
2514 }
2515
2516 if (node) {
2517 tc->section = TRD_SECT_YANG_DATA;
2518 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_YANG_DATA, yang_data_name);
2519 } else {
2520 return TRP_EMPTY_KEYWORD_STMT;
2521 }
aPiecekef1e58e2021-04-19 13:19:44 +02002522}
2523
2524/**
2525 * @brief Get name of the module.
2526 * @param[in] tc is context of the tree.
2527 */
2528static struct trt_keyword_stmt
2529tro_read_module_name(const struct trt_tree_ctx *tc)
2530{
aPiecek9f792e52021-04-21 08:33:56 +02002531 assert(tc);
2532
2533 struct trt_keyword_stmt ret;
2534
2535 ret.type = !tc->lysc_tree && tc->pmod->is_submod ?
2536 TRD_KEYWORD_SUBMODULE :
2537 TRD_KEYWORD_MODULE;
2538
2539 ret.str = !tc->lysc_tree ?
2540 LYSP_MODULE_NAME(tc->pmod) :
2541 tc->cmod->mod->name;
2542
2543 return ret;
aPiecekef1e58e2021-04-19 13:19:44 +02002544}
2545
aPiecekb8d5a0a2021-05-20 08:20:24 +02002546/**
2547 * @brief Create implicit "case" node as parent of @p node.
2548 * @param[in] node child of implicit case node.
2549 * @return The case node ready to print.
2550 */
2551static struct trt_node
2552tro_create_implicit_case_node(struct trt_node node)
2553{
2554 struct trt_node ret;
2555
2556 ret.status = node.status;
2557 ret.flags = TRD_FLAGS_TYPE_EMPTY;
2558 ret.name.type = TRD_NODE_CASE;
aPiecekbca57772022-10-13 13:51:59 +02002559 ret.name.keys = node.name.keys;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002560 ret.name.module_prefix = node.name.module_prefix;
2561 ret.name.str = node.name.str;
2562 ret.type = TRP_EMPTY_TRT_TYPE;
aPiecek7a28e2f2021-05-21 07:27:03 +02002563 ret.iffeatures = 0;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002564 ret.last_one = node.last_one;
aPiecek50b64e42022-10-10 10:00:12 +02002565 ret.mount = NULL;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002566
2567 return ret;
2568}
2569
aPiecekef1e58e2021-04-19 13:19:44 +02002570/**********************************************************************
2571 * Definition of trop reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02002572 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002573
2574/**
aPiecek61d062b2020-11-02 11:05:09 +01002575 * @brief Check if list statement has keys.
2576 * @param[in] pn is pointer to the list.
2577 * @return 1 if has keys, otherwise 0.
2578 */
2579static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002580trop_list_has_keys(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002581{
aPiecekef1e58e2021-04-19 13:19:44 +02002582 return trg_charptr_has_data(((const struct lysp_node_list *)pn)->key);
aPiecek61d062b2020-11-02 11:05:09 +01002583}
2584
2585/**
2586 * @brief Check if it contains at least one feature.
aPiecek3f247652021-04-19 13:40:25 +02002587 * @param[in] pn is current node.
aPiecek61d062b2020-11-02 11:05:09 +01002588 * @return 1 if has if-features, otherwise 0.
2589 */
2590static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002591trop_node_has_iffeature(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002592{
2593 LY_ARRAY_COUNT_TYPE u;
aPiecekef1e58e2021-04-19 13:19:44 +02002594 const struct lysp_qname *iffs;
2595
aPiecek61d062b2020-11-02 11:05:09 +01002596 ly_bool ret = 0;
2597
aPiecekef1e58e2021-04-19 13:19:44 +02002598 iffs = pn->iffeatures;
aPiecek61d062b2020-11-02 11:05:09 +01002599 LY_ARRAY_FOR(iffs, u) {
2600 ret = 1;
2601 break;
2602 }
2603 return ret;
2604}
2605
2606/**
2607 * @brief Find out if leaf is also the key in last list.
2608 * @param[in] pn is pointer to leaf.
aPiecek874ea4d2021-04-19 12:26:36 +02002609 * @param[in] ca_last_list is pointer to last visited list.
2610 * Obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002611 * @return 1 if leaf is also the key, otherwise 0.
2612 */
2613static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002614trop_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
aPiecek61d062b2020-11-02 11:05:09 +01002615{
2616 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2617 const struct lysp_node_list *list = ca_last_list;
2618
2619 if (!list) {
2620 return 0;
2621 }
2622 return trg_charptr_has_data(list->key) ?
2623 trg_word_is_present(list->key, leaf->name, ' ') : 0;
2624}
2625
2626/**
2627 * @brief Check if container's type is presence.
2628 * @param[in] pn is pointer to container.
2629 * @return 1 if container has presence statement, otherwise 0.
2630 */
2631static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002632trop_container_has_presence(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002633{
2634 return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence);
2635}
2636
2637/**
aPiecek7ed8d032022-10-10 12:32:27 +02002638 * @brief Check if container has mount-point extension.
ekinzie0ab8b302022-10-10 03:03:57 -04002639 * @param[in] cn is pointer to container or list.
2640 * @param[out] mount is assigned a pointer to the extension instance, if found
aPiecek7ed8d032022-10-10 12:32:27 +02002641 * @return 1 if node has mount-point.
ekinzie0ab8b302022-10-10 03:03:57 -04002642 */
2643static ly_bool
2644troc_node_has_mount(const struct lysc_node *cn, struct lysc_ext_instance **mount)
2645{
2646 struct lysc_ext_instance *ext;
2647 uint64_t u;
2648
2649 /* The schema-mount extension plugin has already made sure that
2650 * there is only one mount-point here.
2651 */
2652 LY_ARRAY_FOR(cn->exts, u) {
2653 ext = &cn->exts[u];
2654 if (strcmp(ext->def->module->name, "ietf-yang-schema-mount") ||
2655 strcmp(ext->def->name, "mount-point")) {
2656 continue;
2657 }
2658 *mount = ext;
2659 return 1;
2660 }
2661 return 0;
2662}
2663
aPiecek7ed8d032022-10-10 12:32:27 +02002664/**
2665 * @brief Check if node has mount-point extension.
2666 *
2667 * @param[in] pn is pointer to container or list.
2668 * @return 1 if node has mount-point.
2669 */
ekinzie0ab8b302022-10-10 03:03:57 -04002670static ly_bool
2671trop_node_has_mount(const struct lysp_node *pn)
2672{
2673 struct lysp_ext_instance *ext;
2674 uint64_t u;
2675
2676 LY_ARRAY_FOR(pn->exts, u) {
2677 ext = &pn->exts[u];
2678 if (strcmp(ext->name, "yangmnt:mount-point")) {
2679 continue;
2680 }
2681 return 1;
2682 }
2683 return 0;
2684}
2685
2686/**
aPiecek61d062b2020-11-02 11:05:09 +01002687 * @brief Get leaflist's path without lysp_node type control.
2688 * @param[in] pn is pointer to the leaflist.
2689 */
2690static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002691trop_leaflist_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002692{
2693 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2694
2695 return list->type.path ? list->type.path->expr : NULL;
2696}
2697
2698/**
2699 * @brief Get leaflist's type name without lysp_node type control.
2700 * @param[in] pn is pointer to the leaflist.
2701 */
2702static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002703trop_leaflist_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002704{
2705 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2706
2707 return list->type.name;
2708}
2709
2710/**
2711 * @brief Get leaf's path without lysp_node type control.
2712 * @param[in] pn is pointer to the leaf node.
2713 */
2714static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002715trop_leaf_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002716{
2717 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2718
2719 return leaf->type.path ? leaf->type.path->expr : NULL;
2720}
2721
2722/**
2723 * @brief Get leaf's type name without lysp_node type control.
2724 * @param[in] pn is pointer to the leaf's type name.
2725 */
2726static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002727trop_leaf_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002728{
2729 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2730
2731 return leaf->type.name;
2732}
2733
2734/**
aPiecek874ea4d2021-04-19 12:26:36 +02002735 * @brief Get pointer to data using node type specification
2736 * and getter function.
aPiecek61d062b2020-11-02 11:05:09 +01002737 *
aPiecek874ea4d2021-04-19 12:26:36 +02002738 * @param[in] flags is node type specification.
2739 * If it is the correct node, the getter function is called.
2740 * @param[in] f is getter function which provides the desired
2741 * char pointer from the structure.
aPiecek61d062b2020-11-02 11:05:09 +01002742 * @param[in] pn pointer to node.
aPiecek874ea4d2021-04-19 12:26:36 +02002743 * @return NULL if node has wrong type or getter function return
2744 * pointer to NULL.
aPiecek61d062b2020-11-02 11:05:09 +01002745 * @return Pointer to desired char pointer obtained from the node.
2746 */
2747static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002748trop_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002749{
2750 if (pn->nodetype & flags) {
2751 const char *ret = f(pn);
Michal Vasko26bbb272022-08-02 14:54:33 +02002752
aPiecek61d062b2020-11-02 11:05:09 +01002753 return trg_charptr_has_data(ret) ? ret : NULL;
2754 } else {
2755 return NULL;
2756 }
2757}
2758
2759/**
aPiecek61d062b2020-11-02 11:05:09 +01002760 * @brief Resolve \<status\> of the current node.
2761 * @param[in] nodetype is node's type obtained from the tree.
2762 * @param[in] flags is node's flags obtained from the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002763 * @param[in] ca_lys_status is inherited status
2764 * obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002765 * @return The status type.
2766 */
2767static trt_status_type
aPiecekef1e58e2021-04-19 13:19:44 +02002768trop_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
aPiecek61d062b2020-11-02 11:05:09 +01002769{
2770 /* LYS_INPUT and LYS_OUTPUT is special case */
2771 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecekef1e58e2021-04-19 13:19:44 +02002772 return tro_flags2status(ca_lys_status);
2773 /* if ancestor's status is deprc or obslt
2774 * and also node's status is not set
2775 */
aPiecek61d062b2020-11-02 11:05:09 +01002776 } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
2777 /* get ancestor's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002778 return tro_flags2status(ca_lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002779 } else {
2780 /* else get node's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002781 return tro_flags2status(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002782 }
2783}
2784
2785/**
2786 * @brief Resolve \<flags\> of the current node.
2787 * @param[in] nodetype is node's type obtained from the tree.
2788 * @param[in] flags is node's flags obtained from the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002789 * @param[in] ca_ancestor is ancestor type obtained
2790 * from trt_parent_cache.
2791 * @param[in] ca_lys_config is inherited config item
2792 * obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002793 * @return The flags type.
2794 */
2795static trt_flags_type
aPiecekef1e58e2021-04-19 13:19:44 +02002796trop_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config)
aPiecek61d062b2020-11-02 11:05:09 +01002797{
2798 if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) {
2799 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
2800 } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) {
2801 return TRD_FLAGS_TYPE_RO;
2802 } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) {
2803 return TRD_FLAGS_TYPE_RO;
2804 } else if (nodetype & LYS_NOTIF) {
2805 return TRD_FLAGS_TYPE_NOTIF;
2806 } else if (nodetype & LYS_USES) {
2807 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
2808 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
2809 return TRD_FLAGS_TYPE_RPC;
aPiecek61d062b2020-11-02 11:05:09 +01002810 } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002811 /* config is not set. Look at ancestor's config */
2812 return tro_flags2config(ca_lys_config);
aPiecek61d062b2020-11-02 11:05:09 +01002813 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02002814 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002815 }
2816}
2817
2818/**
2819 * @brief Resolve node type of the current node.
2820 * @param[in] pn is pointer to the current node in the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002821 * @param[in] ca_last_list is pointer to the last visited list.
2822 * Obtained from the trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002823 */
2824static trt_node_type
ekinzie0ab8b302022-10-10 03:03:57 -04002825trop_resolve_node_type(const struct trt_tree_ctx *tc, const struct lysp_node_list *ca_last_list)
aPiecek61d062b2020-11-02 11:05:09 +01002826{
ekinzie0ab8b302022-10-10 03:03:57 -04002827 const struct lysp_node *pn = tc->pn;
2828
aPiecek61d062b2020-11-02 11:05:09 +01002829 if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
2830 return TRD_NODE_ELSE;
2831 } else if (pn->nodetype & LYS_CASE) {
2832 return TRD_NODE_CASE;
2833 } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) {
2834 return TRD_NODE_OPTIONAL_CHOICE;
2835 } else if (pn->nodetype & LYS_CHOICE) {
2836 return TRD_NODE_CHOICE;
ekinzie0ab8b302022-10-10 03:03:57 -04002837 } else if (tc->mounted && (tc->pn->parent == NULL)) {
2838 if (tc->parent_refs) {
2839 for (uint32_t v = 0; v < tc->parent_refs->count; v++) {
2840 if (!strcmp(tc->pmod->mod->ns, tc->parent_refs->snodes[v]->module->ns)) {
2841 return TRD_NODE_TOP_LEVEL2;
2842 }
2843 }
2844 }
2845 return TRD_NODE_TOP_LEVEL1;
aPiecekef1e58e2021-04-19 13:19:44 +02002846 } else if ((pn->nodetype & LYS_CONTAINER) && (trop_container_has_presence(pn))) {
aPiecek61d062b2020-11-02 11:05:09 +01002847 return TRD_NODE_CONTAINER;
aPiecek61d062b2020-11-02 11:05:09 +01002848 } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
2849 return TRD_NODE_LISTLEAFLIST;
2850 } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) {
2851 return TRD_NODE_OPTIONAL;
aPiecekef1e58e2021-04-19 13:19:44 +02002852 } else if ((pn->nodetype & LYS_LEAF) && !(pn->flags & LYS_MAND_TRUE) && (!trop_leaf_is_key(pn, ca_last_list))) {
aPiecek61d062b2020-11-02 11:05:09 +01002853 return TRD_NODE_OPTIONAL;
2854 } else {
2855 return TRD_NODE_ELSE;
2856 }
2857}
2858
2859/**
aPiecekef1e58e2021-04-19 13:19:44 +02002860 * @brief Resolve \<type\> of the current node.
2861 * @param[in] pn is current node.
2862 */
2863static struct trt_type
2864trop_resolve_type(const struct lysp_node *pn)
2865{
2866 const char *tmp = NULL;
2867
2868 if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_refpath, pn))) {
2869 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2870 } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_type_name, pn))) {
2871 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2872 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_refpath, pn))) {
2873 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2874 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_type_name, pn))) {
2875 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2876 } else if (pn->nodetype == LYS_ANYDATA) {
2877 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata");
2878 } else if (pn->nodetype & LYS_ANYXML) {
2879 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml");
2880 } else {
2881 return TRP_EMPTY_TRT_TYPE;
2882 }
2883}
2884
2885/**
aPiecek61d062b2020-11-02 11:05:09 +01002886 * @brief Transformation of current lysp_node to struct trt_node.
aPiecek874ea4d2021-04-19 12:26:36 +02002887 * @param[in] ca contains stored important data
2888 * when browsing the tree downwards.
aPiecek61d062b2020-11-02 11:05:09 +01002889 * @param[in] tc is context of the tree.
2890 */
2891static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02002892trop_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002893{
aPiecekef1e58e2021-04-19 13:19:44 +02002894 const struct lysp_node *pn;
2895 struct trt_node ret;
2896
aPiecek61d062b2020-11-02 11:05:09 +01002897 assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
aPiecekef1e58e2021-04-19 13:19:44 +02002898
2899 pn = tc->pn;
2900 ret = TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01002901
2902 /* <status> */
aPiecekef1e58e2021-04-19 13:19:44 +02002903 ret.status = trop_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002904
aPiecek61d062b2020-11-02 11:05:09 +01002905 /* <flags> */
ekinzie0ab8b302022-10-10 03:03:57 -04002906 if (trop_node_has_mount(pn)) {
2907 ret.flags = TRD_FLAGS_TYPE_MOUNT_POINT;
2908 } else {
2909 ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config);
2910 }
aPiecek61d062b2020-11-02 11:05:09 +01002911
aPiecek61d062b2020-11-02 11:05:09 +01002912 /* set type of the node */
ekinzie0ab8b302022-10-10 03:03:57 -04002913 ret.name.type = trop_resolve_node_type(tc, ca.last_list);
aPiecekbca57772022-10-13 13:51:59 +02002914 ret.name.keys = (tc->pn->nodetype & LYS_LIST) && trop_list_has_keys(tc->pn);
aPiecek61d062b2020-11-02 11:05:09 +01002915
aPiecek34fa3772021-05-21 12:35:46 +02002916 /* The parsed tree is not compiled, so no node can be augmented
2917 * from another module. This means that nodes from the parsed tree
2918 * will never have the prefix.
2919 */
aPiecek61d062b2020-11-02 11:05:09 +01002920 ret.name.module_prefix = NULL;
2921
2922 /* set node's name */
2923 ret.name.str = pn->name;
2924
2925 /* <type> */
aPiecekef1e58e2021-04-19 13:19:44 +02002926 ret.type = trop_resolve_type(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002927
2928 /* <iffeature> */
aPiecekef1e58e2021-04-19 13:19:44 +02002929 ret.iffeatures = trop_node_has_iffeature(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002930
aPiecek3f247652021-04-19 13:40:25 +02002931 ret.last_one = !tro_next_sibling(pn, tc->lysc_tree);
aPiecek61d062b2020-11-02 11:05:09 +01002932
2933 return ret;
2934}
2935
aPiecekef1e58e2021-04-19 13:19:44 +02002936/**
2937 * @brief Find out if the current node has siblings.
2938 * @param[in] tc is context of the tree.
2939 * @return 1 if sibling exists otherwise 0.
2940 */
2941static ly_bool
2942trop_read_if_sibling_exists(const struct trt_tree_ctx *tc)
2943{
aPiecek3f247652021-04-19 13:40:25 +02002944 return tro_next_sibling(tc->pn, tc->lysc_tree) != NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002945}
2946
aPiecek96baa7f2021-04-23 12:32:00 +02002947/**
2948 * @brief Print all yang-data sections and print three dots instead
2949 * of nodes.
2950 * @param[in] exts is array of YANG extension instances from parsed
2951 * module (@ref sizedarrays).
2952 * @param[in] mll is maximum number of characters that can be printed
2953 * on one line.
2954 * @param[in,out] out is output handler.
2955 */
2956static void
2957trop_yang_data_sections(const struct lysp_ext_instance *exts, size_t mll, struct ly_out *out)
2958{
2959 struct trt_keyword_stmt ks;
2960 LY_ARRAY_COUNT_TYPE u;
2961 struct trt_wrapper wr;
2962
2963 if (!exts) {
2964 return;
2965 }
2966
2967 ly_print_(out, "\n");
2968 ks.type = TRD_KEYWORD_YANG_DATA;
2969 wr = TRP_INIT_WRAPPER_BODY;
2970
2971 LY_ARRAY_FOR(exts, u) {
2972 ly_print_(out, "\n");
2973
2974 /* yang-data <yang-data-name>: */
2975 ks.str = exts[u].argument;
2976 trp_print_keyword_stmt(ks, mll, 0, out);
2977 ly_print_(out, "\n");
2978
2979 /* ... */
2980 trp_print_wrapper(wr, out);
2981 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
2982 }
2983}
2984
aPiecek874ea4d2021-04-19 12:26:36 +02002985/**********************************************************************
aPiecekef1e58e2021-04-19 13:19:44 +02002986 * Modify trop getters
aPiecek874ea4d2021-04-19 12:26:36 +02002987 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002988
2989/**
aPiecek874ea4d2021-04-19 12:26:36 +02002990 * @brief Change current node pointer to its parent
2991 * but only if parent exists.
2992 * @param[in,out] tc is tree context.
2993 * Contains pointer to the current node.
aPiecek61d062b2020-11-02 11:05:09 +01002994 * @return 1 if the node had parents and the change was successful.
aPiecek874ea4d2021-04-19 12:26:36 +02002995 * @return 0 if the node did not have parents.
2996 * The pointer to the current node did not change.
aPiecek61d062b2020-11-02 11:05:09 +01002997 */
2998static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002999trop_modi_parent(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003000{
3001 assert(tc && tc->pn);
3002 /* If no parent exists, stay in actual node. */
aPiecek96baa7f2021-04-23 12:32:00 +02003003 if ((tc->pn != tc->tpn) && (tc->pn->parent)) {
aPiecek61d062b2020-11-02 11:05:09 +01003004 tc->pn = tc->pn->parent;
3005 return 1;
3006 } else {
3007 return 0;
3008 }
3009}
3010
3011/**
aPiecek874ea4d2021-04-19 12:26:36 +02003012 * @brief Change the current node pointer to its child
3013 * but only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01003014 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02003015 * @param[in,out] tc is context of the tree.
3016 * Contains pointer to the current node.
3017 * @return Non-empty \<node\> representation of the current
3018 * node's child. The @p tc is modified.
3019 * @return Empty \<node\> representation if child don't exists.
3020 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01003021 */
3022static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02003023trop_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003024{
aPiecekef1e58e2021-04-19 13:19:44 +02003025 const struct lysp_node *tmp;
3026
aPiecek61d062b2020-11-02 11:05:09 +01003027 assert(tc && tc->pn);
3028
aPiecek3f247652021-04-19 13:40:25 +02003029 if ((tmp = tro_next_child(tc->pn, tc->lysc_tree))) {
aPiecekef1e58e2021-04-19 13:19:44 +02003030 tc->pn = tmp;
aPiecek3f247652021-04-19 13:40:25 +02003031 return trop_read_node(tro_parent_cache_for_child(ca, tc), tc);
aPiecek61d062b2020-11-02 11:05:09 +01003032 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02003033 return TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01003034 }
3035}
3036
3037/**
aPiecek874ea4d2021-04-19 12:26:36 +02003038 * @brief Change the current node pointer to the first child of node's
3039 * parent. If current node is already first sibling/child then nothing
3040 * will change.
aPiecek61d062b2020-11-02 11:05:09 +01003041 * @param[in,out] tc is tree context.
3042 */
3043static void
aPiecekef1e58e2021-04-19 13:19:44 +02003044trop_modi_first_sibling(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003045{
aPiecek9f792e52021-04-21 08:33:56 +02003046 assert(tc && tc->pn && tc->pmod);
aPiecek61d062b2020-11-02 11:05:09 +01003047
aPiecekef1e58e2021-04-19 13:19:44 +02003048 if (trop_modi_parent(tc)) {
3049 trop_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003050 } else {
3051 /* current node is top-node */
aPiecek61d062b2020-11-02 11:05:09 +01003052 switch (tc->section) {
3053 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02003054 tc->pn = tc->pmod->data;
aPiecek96baa7f2021-04-23 12:32:00 +02003055 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003056 break;
3057 case TRD_SECT_AUGMENT:
aPiecek9f792e52021-04-21 08:33:56 +02003058 tc->pn = (const struct lysp_node *)tc->pmod->augments;
aPiecek96baa7f2021-04-23 12:32:00 +02003059 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003060 break;
3061 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02003062 tc->pn = (const struct lysp_node *)tc->pmod->rpcs;
aPiecek96baa7f2021-04-23 12:32:00 +02003063 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003064 break;
3065 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02003066 tc->pn = (const struct lysp_node *)tc->pmod->notifs;
aPiecek96baa7f2021-04-23 12:32:00 +02003067 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003068 break;
3069 case TRD_SECT_GROUPING:
aPiecek9f792e52021-04-21 08:33:56 +02003070 tc->pn = (const struct lysp_node *)tc->pmod->groupings;
aPiecek96baa7f2021-04-23 12:32:00 +02003071 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003072 break;
3073 case TRD_SECT_YANG_DATA:
aPiecek96baa7f2021-04-23 12:32:00 +02003074 /* tpn in this case is of type lysp_ext_instance */
3075 tc->pn = tc->tpn_ext->parsed;
aPiecek61d062b2020-11-02 11:05:09 +01003076 break;
aPiecek96baa7f2021-04-23 12:32:00 +02003077 default:
3078 assert(0);
aPiecek61d062b2020-11-02 11:05:09 +01003079 }
aPiecek61d062b2020-11-02 11:05:09 +01003080 }
3081}
3082
3083/**
aPiecek874ea4d2021-04-19 12:26:36 +02003084 * @brief Change the pointer to the current node to its next sibling
3085 * only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01003086 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02003087 * @param[in,out] tc is tree context.
3088 * Contains pointer to the current node.
3089 * @return Non-empty \<node\> representation if sibling exists.
3090 * The @p tc is modified.
3091 * @return Empty \<node\> representation otherwise.
3092 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01003093 */
3094static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02003095trop_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003096{
aPiecekef1e58e2021-04-19 13:19:44 +02003097 const struct lysp_node *pn;
aPiecekef1e58e2021-04-19 13:19:44 +02003098
3099 assert(tc && tc->pn);
3100
aPiecek3f247652021-04-19 13:40:25 +02003101 pn = tro_next_sibling(tc->pn, tc->lysc_tree);
aPiecek61d062b2020-11-02 11:05:09 +01003102
aPiecekef1e58e2021-04-19 13:19:44 +02003103 if (pn) {
aPiecek96baa7f2021-04-23 12:32:00 +02003104 if ((tc->tpn == tc->pn) && (tc->section != TRD_SECT_YANG_DATA)) {
3105 tc->tpn = pn;
3106 }
aPiecekef1e58e2021-04-19 13:19:44 +02003107 tc->pn = pn;
aPiecekef1e58e2021-04-19 13:19:44 +02003108 return trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003109 } else {
3110 return TRP_EMPTY_NODE;
3111 }
3112}
3113
3114/**
3115 * @brief Get next (or first) augment section if exists.
aPiecek874ea4d2021-04-19 12:26:36 +02003116 * @param[in,out] tc is tree context. It is modified and his current
3117 * node is set to the lysp_node_augment.
aPiecek61d062b2020-11-02 11:05:09 +01003118 * @return Section's representation if (next augment) section exists.
aPiecek61d062b2020-11-02 11:05:09 +01003119 * @return Empty section structure otherwise.
3120 */
3121static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003122trop_modi_next_augment(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003123{
aPiecek9f792e52021-04-21 08:33:56 +02003124 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003125 const struct lysp_node_augment *augs;
3126
3127 /* if next_augment func was called for the first time */
3128 if (tc->section != TRD_SECT_AUGMENT) {
3129 tc->section = TRD_SECT_AUGMENT;
aPiecek9f792e52021-04-21 08:33:56 +02003130 augs = tc->pmod->augments;
aPiecek61d062b2020-11-02 11:05:09 +01003131 } else {
3132 /* get augment sibling from top-node pointer */
aPiecekdc8fd572021-04-19 10:47:23 +02003133 augs = (const struct lysp_node_augment *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003134 }
3135
aPiecekdc8fd572021-04-19 10:47:23 +02003136 if (augs) {
3137 tc->pn = &augs->node;
aPiecek61d062b2020-11-02 11:05:09 +01003138 tc->tpn = tc->pn;
3139 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_AUGMENT, augs->nodeid);
3140 } else {
3141 return TRP_EMPTY_KEYWORD_STMT;
3142 }
3143}
3144
3145/**
aPiecek61d062b2020-11-02 11:05:09 +01003146 * @brief Get next (or first) grouping section if exists
aPiecek874ea4d2021-04-19 12:26:36 +02003147 * @param[in,out] tc is tree context. It is modified and his current
3148 * node is set to the lysp_node_grp.
aPiecek61d062b2020-11-02 11:05:09 +01003149 * @return The next (or first) section representation if it exists.
aPiecek61d062b2020-11-02 11:05:09 +01003150 * @return Empty section representation otherwise.
3151 */
3152static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003153trop_modi_next_grouping(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003154{
aPiecek9f792e52021-04-21 08:33:56 +02003155 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003156 const struct lysp_node_grp *grps;
3157
3158 if (tc->section != TRD_SECT_GROUPING) {
3159 tc->section = TRD_SECT_GROUPING;
aPiecek9f792e52021-04-21 08:33:56 +02003160 grps = tc->pmod->groupings;
aPiecek61d062b2020-11-02 11:05:09 +01003161 } else {
aPiecekdc8fd572021-04-19 10:47:23 +02003162 grps = (const struct lysp_node_grp *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003163 }
3164
aPiecekdc8fd572021-04-19 10:47:23 +02003165 if (grps) {
3166 tc->pn = &grps->node;
aPiecek61d062b2020-11-02 11:05:09 +01003167 tc->tpn = tc->pn;
3168 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_GROUPING, grps->name);
3169 } else {
3170 return TRP_EMPTY_KEYWORD_STMT;
3171 }
3172}
3173
aPiecek874ea4d2021-04-19 12:26:36 +02003174/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02003175 * Definition of troc reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02003176 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003177
3178/**
aPiecek3f247652021-04-19 13:40:25 +02003179 * @copydoc trop_read_if_sibling_exists
aPiecek61d062b2020-11-02 11:05:09 +01003180 */
aPiecek3f247652021-04-19 13:40:25 +02003181static ly_bool
3182troc_read_if_sibling_exists(const struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003183{
aPiecek3f247652021-04-19 13:40:25 +02003184 return tro_next_sibling(tc->cn, tc->lysc_tree) != NULL;
3185}
aPiecek61d062b2020-11-02 11:05:09 +01003186
aPiecek3f247652021-04-19 13:40:25 +02003187/**
3188 * @brief Resolve \<flags\> of the current node.
3189 *
3190 * Use this function only if trt_tree_ctx.lysc_tree is true.
3191 *
3192 * @param[in] nodetype is current lysc_node.nodetype.
3193 * @param[in] flags is current lysc_node.flags.
3194 * @return The flags type.
3195 */
3196static trt_flags_type
3197troc_resolve_flags(uint16_t nodetype, uint16_t flags)
3198{
3199 if ((nodetype & LYS_INPUT) || (flags & LYS_IS_INPUT)) {
3200 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
3201 } else if ((nodetype & LYS_OUTPUT) || (flags & LYS_IS_OUTPUT)) {
3202 return TRD_FLAGS_TYPE_RO;
3203 } else if (nodetype & LYS_IS_NOTIF) {
3204 return TRD_FLAGS_TYPE_RO;
3205 } else if (nodetype & LYS_NOTIF) {
3206 return TRD_FLAGS_TYPE_NOTIF;
3207 } else if (nodetype & LYS_USES) {
3208 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
3209 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
3210 return TRD_FLAGS_TYPE_RPC;
3211 } else {
3212 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01003213 }
aPiecek61d062b2020-11-02 11:05:09 +01003214}
3215
3216/**
aPiecek3f247652021-04-19 13:40:25 +02003217 * @brief Resolve node type of the current node.
aPiecek61d062b2020-11-02 11:05:09 +01003218 *
aPiecek3f247652021-04-19 13:40:25 +02003219 * Use this function only if trt_tree_ctx.lysc_tree is true.
aPiecek61d062b2020-11-02 11:05:09 +01003220 *
aPiecek3f247652021-04-19 13:40:25 +02003221 * @param[in] nodetype is current lysc_node.nodetype.
3222 * @param[in] flags is current lysc_node.flags.
3223 */
3224static trt_node_type
ekinzie0ab8b302022-10-10 03:03:57 -04003225troc_resolve_node_type(const struct trt_tree_ctx *tc, uint16_t nodetype, uint16_t flags)
aPiecek3f247652021-04-19 13:40:25 +02003226{
3227 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
3228 return TRD_NODE_ELSE;
3229 } else if (nodetype & LYS_CASE) {
3230 return TRD_NODE_CASE;
3231 } else if ((nodetype & LYS_CHOICE) && !(flags & LYS_MAND_TRUE)) {
3232 return TRD_NODE_OPTIONAL_CHOICE;
3233 } else if (nodetype & LYS_CHOICE) {
3234 return TRD_NODE_CHOICE;
ekinzie0ab8b302022-10-10 03:03:57 -04003235 } else if (tc->mounted && (tc->cn->parent == NULL)) {
3236 if (tc->parent_refs) {
3237 for (uint32_t v = 0; v < tc->parent_refs->count; v++) {
3238 if (!strcmp(tc->cn->module->ns, tc->parent_refs->snodes[v]->module->ns)) {
3239 return TRD_NODE_TOP_LEVEL2;
3240 }
3241 }
3242 }
3243 return TRD_NODE_TOP_LEVEL1;
aPiecek3f247652021-04-19 13:40:25 +02003244 } else if ((nodetype & LYS_CONTAINER) && (flags & LYS_PRESENCE)) {
3245 return TRD_NODE_CONTAINER;
aPiecek3f247652021-04-19 13:40:25 +02003246 } else if (nodetype & (LYS_LIST | LYS_LEAFLIST)) {
3247 return TRD_NODE_LISTLEAFLIST;
3248 } else if ((nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(flags & LYS_MAND_TRUE)) {
3249 return TRD_NODE_OPTIONAL;
3250 } else if ((nodetype & LYS_LEAF) && !(flags & (LYS_MAND_TRUE | LYS_KEY))) {
3251 return TRD_NODE_OPTIONAL;
3252 } else {
3253 return TRD_NODE_ELSE;
3254 }
3255}
3256
3257/**
aPiecek34fa3772021-05-21 12:35:46 +02003258 * @brief Resolve prefix (<prefix>:<name>) of node that has been
3259 * placed from another module via an augment statement.
3260 *
3261 * @param[in] cn is current compiled node.
3262 * @param[in] current_compiled_module is module whose nodes are
3263 * currently being printed.
3264 * @return Prefix of foreign module or NULL.
3265 */
3266static const char *
3267troc_resolve_node_prefix(const struct lysc_node *cn, const struct lysc_module *current_compiled_module)
3268{
3269 const struct lys_module *node_module;
3270 const char *ret = NULL;
3271
3272 node_module = cn->module;
3273 if (node_module->compiled != current_compiled_module) {
3274 ret = node_module->prefix;
3275 }
3276
3277 return ret;
3278}
3279
3280/**
aPiecek3f247652021-04-19 13:40:25 +02003281 * @brief Transformation of current lysc_node to struct trt_node.
3282 * @param[in] ca is not used.
3283 * @param[in] tc is context of the tree.
3284 */
3285static struct trt_node
3286troc_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
3287{
3288 (void) ca;
3289 const struct lysc_node *cn;
3290 struct trt_node ret;
3291
aPiecek082c7dc2021-05-20 08:55:07 +02003292 assert(tc && tc->cn);
aPiecek3f247652021-04-19 13:40:25 +02003293
3294 cn = tc->cn;
3295 ret = TRP_EMPTY_NODE;
3296
3297 /* <status> */
3298 ret.status = tro_flags2status(cn->flags);
3299
aPiecek3f247652021-04-19 13:40:25 +02003300 /* <flags> */
ekinzie0ab8b302022-10-10 03:03:57 -04003301 if (troc_node_has_mount(cn, &ret.mount)) {
3302 ret.flags = TRD_FLAGS_TYPE_MOUNT_POINT;
3303 } else {
3304 ret.flags = troc_resolve_flags(cn->nodetype, cn->flags);
3305 }
aPiecek3f247652021-04-19 13:40:25 +02003306
aPiecek3f247652021-04-19 13:40:25 +02003307 /* set type of the node */
ekinzie0ab8b302022-10-10 03:03:57 -04003308 ret.name.type = troc_resolve_node_type(tc, cn->nodetype, cn->flags);
aPiecekbca57772022-10-13 13:51:59 +02003309 ret.name.keys = (cn->nodetype & LYS_LIST) && !(cn->flags & LYS_KEYLESS);
aPiecek3f247652021-04-19 13:40:25 +02003310
aPiecek34fa3772021-05-21 12:35:46 +02003311 /* <prefix> */
3312 ret.name.module_prefix = troc_resolve_node_prefix(cn, tc->cmod);
aPiecek3f247652021-04-19 13:40:25 +02003313
3314 /* set node's name */
3315 ret.name.str = cn->name;
3316
aPiecekbbc02932021-05-21 07:19:41 +02003317 if (TRP_TREE_CTX_LYSP_NODE_PRESENT(cn)) {
aPiecek082c7dc2021-05-20 08:55:07 +02003318 /* <type> */
3319 ret.type = trop_resolve_type(TRP_TREE_CTX_GET_LYSP_NODE(cn));
aPiecek3f247652021-04-19 13:40:25 +02003320
aPiecek082c7dc2021-05-20 08:55:07 +02003321 /* <iffeature> */
3322 ret.iffeatures = trop_node_has_iffeature(TRP_TREE_CTX_GET_LYSP_NODE(cn));
3323 } else {
aPiecekbbc02932021-05-21 07:19:41 +02003324 /* only the implicit case node doesn't have access to lysp node */
aPiecek082c7dc2021-05-20 08:55:07 +02003325 assert(tc->cn->nodetype & LYS_CASE);
3326
3327 /* <type> */
3328 ret.type = TRP_EMPTY_TRT_TYPE;
3329
aPiecek7a28e2f2021-05-21 07:27:03 +02003330 /* <iffeature> */
3331 ret.iffeatures = 0;
aPiecek082c7dc2021-05-20 08:55:07 +02003332 }
aPiecek3f247652021-04-19 13:40:25 +02003333
3334 ret.last_one = !tro_next_sibling(cn, tc->lysc_tree);
3335
3336 return ret;
3337}
3338
3339/**********************************************************************
3340 * Modify troc getters
3341 *********************************************************************/
3342
3343/**
aPiecek01598c02021-04-23 14:18:24 +02003344 * @copydoc ::trop_modi_parent()
aPiecek3f247652021-04-19 13:40:25 +02003345 */
3346static ly_bool
3347troc_modi_parent(struct trt_tree_ctx *tc)
3348{
3349 assert(tc && tc->cn);
3350 /* If no parent exists, stay in actual node. */
3351 if (tc->cn->parent) {
3352 tc->cn = tc->cn->parent;
3353 return 1;
3354 } else {
3355 return 0;
3356 }
3357}
3358
3359/**
aPiecek01598c02021-04-23 14:18:24 +02003360 * @copydoc ::trop_modi_next_sibling()
aPiecek3f247652021-04-19 13:40:25 +02003361 */
3362static struct trt_node
3363troc_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3364{
3365 const struct lysc_node *cn;
3366
3367 assert(tc && tc->cn);
3368
3369 cn = tro_next_sibling(tc->cn, tc->lysc_tree);
3370
3371 /* if next sibling exists */
3372 if (cn) {
3373 /* update trt_tree_ctx */
3374 tc->cn = cn;
3375 return troc_read_node(ca, tc);
3376 } else {
3377 return TRP_EMPTY_NODE;
3378 }
3379}
3380
3381/**
3382 * @copydoc trop_modi_next_child()
3383 */
3384static struct trt_node
3385troc_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3386{
3387 const struct lysc_node *tmp;
3388
3389 assert(tc && tc->cn);
3390
3391 if ((tmp = tro_next_child(tc->cn, tc->lysc_tree))) {
3392 tc->cn = tmp;
3393 return troc_read_node(ca, tc);
3394 } else {
3395 return TRP_EMPTY_NODE;
3396 }
3397}
3398
3399/**
aPiecek01598c02021-04-23 14:18:24 +02003400 * @copydoc ::trop_modi_first_sibling()
aPiecek61d062b2020-11-02 11:05:09 +01003401 */
3402static void
aPiecek3f247652021-04-19 13:40:25 +02003403troc_modi_first_sibling(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003404{
aPiecek3f247652021-04-19 13:40:25 +02003405 assert(tc && tc->cn);
aPiecek61d062b2020-11-02 11:05:09 +01003406
aPiecek3f247652021-04-19 13:40:25 +02003407 if (troc_modi_parent(tc)) {
3408 troc_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
3409 } else {
3410 /* current node is top-node */
aPiecek3f247652021-04-19 13:40:25 +02003411 switch (tc->section) {
3412 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02003413 tc->cn = tc->cmod->data;
aPiecek3f247652021-04-19 13:40:25 +02003414 break;
3415 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02003416 tc->cn = (const struct lysc_node *)tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02003417 break;
3418 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02003419 tc->cn = (const struct lysc_node *)tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02003420 break;
3421 case TRD_SECT_YANG_DATA:
aPiecek96baa7f2021-04-23 12:32:00 +02003422 /* nothing to do */
aPiecek3f247652021-04-19 13:40:25 +02003423 break;
3424 default:
3425 assert(0);
3426 }
aPiecek61d062b2020-11-02 11:05:09 +01003427 }
3428}
3429
aPiecek874ea4d2021-04-19 12:26:36 +02003430/**********************************************************************
aPiecek8f1073c2022-10-17 16:44:49 +02003431 * Definition of trocm reading functions
3432 *********************************************************************/
3433
3434/**
3435 * @brief Get child node from current @p node.
3436 * @param[in] node from which it tries to get a child.
3437 * If set to NULL, then the top-level node of the @p parent_ref is returned.
3438 * @param[in] parent_ref is one of the referenced nodes.
3439 * @return Child of @p node, top-level node of @p parent_ref or NULL.
3440 */
3441static const struct lysc_node *
3442trocm_node_child(const struct lysc_node *node, const struct lysc_node *parent_ref)
3443{
3444 const struct lysc_node *child, *parent;
3445
3446 assert(node != parent_ref);
3447
3448 child = parent_ref;
3449 for (parent = parent_ref->parent; parent; parent = parent->parent) {
3450 if (parent == node) {
3451 return child;
3452 }
3453 child = parent;
3454 }
3455
3456 if (!node) {
3457 return child;
3458 } else {
3459 return NULL;
3460 }
3461}
3462
3463/**
3464 * @brief Get first parent-referenced node from @p cmod.
3465 * @param[in] parent_refs is the set of all parent-referenced nodes.
3466 * @param[in] cmod is compiled module from which to get the first parent-ref node.
3467 * @param[out] first_parent_ref is index to @p parent_refs where first parent-ref node is located.
3468 * @return LY_ERR value.
3469 */
3470static LY_ERR
3471trocm_first_parent_ref(const struct ly_set *parent_refs, const struct lysc_module *cmod, uint32_t *first_parent_ref)
3472{
3473 uint32_t i;
3474 const struct lysc_node *ref;
3475
3476 for (i = 0; i < parent_refs->count; i++) {
3477 ref = parent_refs->snodes[i];
3478 if (ref->module->compiled == cmod) {
3479 *first_parent_ref = i;
3480 return LY_SUCCESS;
3481 }
3482 }
3483
3484 return LY_ENOTFOUND;
3485}
3486
3487/**
3488 * @brief Get next parent-referenced node from @p cmod.
3489 * @param[in] parent_refs is the set of all parent-referenced nodes.
3490 * @param[in] cmod is compiled module from which to get the next parent-ref node.
3491 * @param[in,out] parent_ref is index to @p parent_refs where the next parent-ref node is located.
3492 * @return LY_ERR value.
3493 */
3494static LY_ERR
3495trocm_next_parent_ref(const struct ly_set *parent_refs, const struct lysc_module *cmod, uint32_t *parent_ref)
3496{
3497 (*parent_ref)++;
3498 if (*parent_ref >= parent_refs->count) {
3499 return LY_ENOT;
3500 } else if (parent_refs->snodes[*parent_ref]->module->compiled != cmod) {
3501 return LY_ENOT;
3502 } else {
3503 return LY_SUCCESS;
3504 }
3505}
3506
3507/**
3508 * @brief Get next sibling of current node @p cn.
3509 * @param[in] cn is current compiled node.
3510 * @param[in] parent_refs is the set of all parent-referenced nodes.
3511 * @return Next sibling or NULL.
3512 */
3513static const struct lysc_node *
3514trocm_next_sibling(const struct lysc_node *cn, const struct ly_set *parent_refs)
3515{
3516 LY_ERR ret;
3517 uint32_t i;
3518 const struct lysc_node *sibl, *ref, *child;
3519 const struct lysc_module *cmod;
3520
3521 cmod = cn->module->compiled;
3522 for (sibl = cn->next; sibl; sibl = sibl->next) {
3523 for (ret = trocm_first_parent_ref(parent_refs, cmod, &i);
3524 ret == LY_SUCCESS;
3525 ret = trocm_next_parent_ref(parent_refs, cmod, &i)) {
3526 ref = parent_refs->snodes[i];
3527 if (ref == sibl) {
3528 /* Sibling is in the parent-refs. */
3529 return sibl;
3530 }
3531 child = trocm_node_child(sibl, parent_refs->snodes[i]);
3532 if (child) {
3533 /* Return parent of parent-ref node. */
3534 return sibl;
3535 }
3536 }
3537 }
3538
3539 return NULL;
3540}
3541
3542/**
3543 * @copydoc trop_read_if_sibling_exists
3544 */
3545static ly_bool
3546trocm_read_if_sibling_exists(const struct trt_tree_ctx *tc)
3547{
3548 if (trocm_next_sibling(tc->cn, tc->parent_refs)) {
3549 return 1;
3550 } else {
3551 return 0;
3552 }
3553}
3554
3555/**********************************************************************
3556 * Modify trocm getters
3557 *********************************************************************/
3558
3559/**
3560 * @copydoc trop_modi_next_child()
3561 */
3562static struct trt_node
3563trocm_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3564{
3565 LY_ERR ret;
3566 uint32_t i;
3567 const struct lysc_node *child, *ref;
3568
3569 child = NULL;
3570 for (ret = trocm_first_parent_ref(tc->parent_refs, tc->cmod, &i);
3571 ret == LY_SUCCESS;
3572 ret = trocm_next_parent_ref(tc->parent_refs, tc->cmod, &i)) {
3573 ref = tc->parent_refs->snodes[i];
3574 if (ref == tc->cn) {
3575 continue;
3576 }
3577 if ((child = trocm_node_child(tc->cn, ref))) {
3578 tc->cn = child;
3579 return troc_read_node(ca, tc);
3580 }
3581 }
3582
3583 return TRP_EMPTY_NODE;
3584}
3585
3586/**
3587 * @copydoc ::trop_modi_first_sibling()
3588 */
3589static void
3590trocm_modi_first_sibling(struct trt_tree_ctx *tc)
3591{
3592 uint32_t i;
3593
3594 if (troc_modi_parent(tc)) {
3595 trocm_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
3596 } else {
3597 trocm_first_parent_ref(tc->parent_refs, tc->cmod, &i);
3598 tc->cn = trocm_node_child(NULL, tc->parent_refs->snodes[i]);
3599 }
3600}
3601
3602/**
3603 * @copydoc ::trop_modi_next_sibling()
3604 */
3605static struct trt_node
3606trocm_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3607{
3608 const struct lysc_node *sibl;
3609
3610 if ((sibl = trocm_next_sibling(tc->cn, tc->parent_refs))) {
3611 tc->cn = sibl;
3612 return troc_read_node(ca, tc);
3613 } else {
3614 return TRP_EMPTY_NODE;
3615 }
3616}
3617
3618/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01003619 * Definition of tree browsing functions
aPiecek874ea4d2021-04-19 12:26:36 +02003620 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003621
3622/**
3623 * @brief Get size of node name.
3624 * @param[in] name contains name and mark.
3625 * @return positive value total size of the node name.
aPiecek874ea4d2021-04-19 12:26:36 +02003626 * @return negative value as an indication that option mark
3627 * is included in the total size.
aPiecek61d062b2020-11-02 11:05:09 +01003628 */
3629static int32_t
3630trb_strlen_of_name_and_mark(struct trt_node_name name)
3631{
3632 size_t name_len = strlen(name.str);
3633
3634 if ((name.type == TRD_NODE_CHOICE) || (name.type == TRD_NODE_CASE)) {
3635 /* counting also parentheses */
3636 name_len += 2;
3637 }
3638
3639 return trp_mark_is_used(name) ?
3640 ((int32_t)(name_len + TRD_OPTS_MARK_LENGTH)) * (-1) :
3641 (int32_t)name_len;
3642}
3643
3644/**
aPiecek874ea4d2021-04-19 12:26:36 +02003645 * @brief Calculate the trt_indent_in_node.btw_opts_type indent size
3646 * for a particular node.
aPiecek61d062b2020-11-02 11:05:09 +01003647 * @param[in] name is the node for which we get btw_opts_type.
aPiecek874ea4d2021-04-19 12:26:36 +02003648 * @param[in] max_len4all is the maximum value of btw_opts_type
3649 * that it can have.
3650 * @return Indent between \<opts\> and \<type\> for node.
aPiecek61d062b2020-11-02 11:05:09 +01003651 */
3652static int16_t
3653trb_calc_btw_opts_type(struct trt_node_name name, int16_t max_len4all)
3654{
3655 int32_t name_len;
3656 int16_t min_len;
3657 int16_t ret;
3658
3659 name_len = trb_strlen_of_name_and_mark(name);
3660
3661 /* negative value indicate that in name is some opt mark */
3662 min_len = name_len < 0 ?
3663 TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
3664 TRD_INDENT_BEFORE_TYPE;
3665 ret = abs(max_len4all) - abs(name_len);
3666
3667 /* correction -> negative indicate that name is too long. */
3668 return ret < 0 ? min_len : ret;
3669}
3670
3671/**
3672 * @brief Print node.
3673 *
aPiecek01598c02021-04-23 14:18:24 +02003674 * This function is wrapper for ::trp_print_entire_node().
aPiecek874ea4d2021-04-19 12:26:36 +02003675 * But difference is that take @p max_gap_before_type which will be
3676 * used to set the unified alignment.
aPiecek61d062b2020-11-02 11:05:09 +01003677 *
aPiecek9bdd7592021-05-20 08:13:20 +02003678 * @param[in] node to print.
aPiecek61d062b2020-11-02 11:05:09 +01003679 * @param[in] max_gap_before_type is number of indent before \<type\>.
3680 * @param[in] wr is wrapper for printing indentation before node.
aPiecek61d062b2020-11-02 11:05:09 +01003681 * @param[in] pc contains mainly functions for printing.
3682 * @param[in] tc is tree context.
3683 */
3684static void
aPiecek9bdd7592021-05-20 08:13:20 +02003685trb_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 +01003686{
aPiecek61d062b2020-11-02 11:05:09 +01003687 struct trt_indent_in_node ind = trp_default_indent_in_node(node);
3688
3689 if ((max_gap_before_type > 0) && (node.type.type != TRD_TYPE_EMPTY)) {
3690 /* print actual node with unified indent */
3691 ind.btw_opts_type = trb_calc_btw_opts_type(node.name, max_gap_before_type);
3692 }
3693 /* after -> print actual node with default indent */
3694 trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print),
3695 TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out);
aPiecek7ed8d032022-10-10 12:32:27 +02003696 if ((node.flags == TRD_FLAGS_TYPE_MOUNT_POINT) && node.mount) {
ekinzie0ab8b302022-10-10 03:03:57 -04003697 struct trt_wrapper wr_mount;
3698 struct tro_getters get;
3699
3700 wr_mount = pc->fp.read.if_sibling_exists(tc) ?
3701 trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr);
3702
3703 get = tc->lysc_tree ? troc_init_getters() : trop_init_getters();
3704 if (get.child(tc->lysc_tree ? (void *)tc->cn : (void *)tc->pn)) {
3705 /* If this node has a child, we need to draw a vertical line
3706 * from the last mounted module to the first child
3707 */
3708 wr_mount = trp_wrapper_set_mark_top(wr_mount);
3709 }
3710
aPiecek40f22402022-10-14 10:48:08 +02003711 tc->last_error = trb_print_mount_point(node.mount, wr_mount, pc);
ekinzie0ab8b302022-10-10 03:03:57 -04003712 }
aPiecek61d062b2020-11-02 11:05:09 +01003713}
3714
3715/**
aPiecek874ea4d2021-04-19 12:26:36 +02003716 * @brief Check if parent of the current node is the last
3717 * of his siblings.
aPiecek61d062b2020-11-02 11:05:09 +01003718 *
aPiecek874ea4d2021-04-19 12:26:36 +02003719 * To mantain stability use this function only if the current node is
3720 * the first of the siblings.
3721 * Side-effect -> current node is set to the first sibling
3722 * if node has a parent otherwise no side-effect.
aPiecek61d062b2020-11-02 11:05:09 +01003723 *
aPiecek01598c02021-04-23 14:18:24 +02003724 * @param[in] fp contains all @ref TRP_tro callback functions.
aPiecek61d062b2020-11-02 11:05:09 +01003725 * @param[in,out] tc is tree context.
3726 * @return 1 if parent is last sibling otherwise 0.
3727 */
3728static ly_bool
3729trb_parent_is_last_sibling(struct trt_fp_all fp, struct trt_tree_ctx *tc)
3730{
3731 if (fp.modify.parent(tc)) {
3732 ly_bool ret = fp.read.if_sibling_exists(tc);
Michal Vasko26bbb272022-08-02 14:54:33 +02003733
aPiecek61d062b2020-11-02 11:05:09 +01003734 fp.modify.next_child(TRP_EMPTY_PARENT_CACHE, tc);
3735 return !ret;
3736 } else {
3737 return !fp.read.if_sibling_exists(tc);
3738 }
3739}
3740
3741/**
3742 * @brief Find sibling with the biggest node name and return that size.
3743 *
3744 * Side-effect -> Current node is set to the first sibling.
3745 *
3746 * @param[in] ca contains inherited data from ancestors.
3747 * @param[in] pc contains mainly functions for printing.
3748 * @param[in,out] tc is tree context.
aPiecek874ea4d2021-04-19 12:26:36 +02003749 * @return positive number as a sign that only the node name is
3750 * included in the size.
3751 * @return negative number sign that node name and his opt mark is
3752 * included in the size.
aPiecek61d062b2020-11-02 11:05:09 +01003753 */
3754static int32_t
3755trb_maxlen_node_name(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3756{
3757 int32_t ret = 0;
3758
3759 pc->fp.modify.first_sibling(tc);
3760
3761 for (struct trt_node node = pc->fp.read.node(ca, tc);
3762 !trp_node_is_empty(node);
3763 node = pc->fp.modify.next_sibling(ca, tc)) {
3764 int32_t maxlen = trb_strlen_of_name_and_mark(node.name);
Michal Vasko26bbb272022-08-02 14:54:33 +02003765
aPiecek61d062b2020-11-02 11:05:09 +01003766 ret = abs(maxlen) > abs(ret) ? maxlen : ret;
3767 }
3768 pc->fp.modify.first_sibling(tc);
3769 return ret;
3770}
3771
3772/**
aPiecek874ea4d2021-04-19 12:26:36 +02003773 * @brief Find maximal indent between
3774 * \<opts\> and \<type\> for siblings.
aPiecek61d062b2020-11-02 11:05:09 +01003775 *
3776 * Side-effect -> Current node is set to the first sibling.
3777 *
3778 * @param[in] ca contains inherited data from ancestors.
3779 * @param[in] pc contains mainly functions for printing.
3780 * @param[in,out] tc is tree context.
3781 * @return max btw_opts_type value for rest of the siblings
3782 */
3783static int16_t
3784trb_max_btw_opts_type4siblings(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3785{
3786 int32_t maxlen_node_name = trb_maxlen_node_name(ca, pc, tc);
3787 int16_t ind_before_type = maxlen_node_name < 0 ?
3788 TRD_INDENT_BEFORE_TYPE - 1 : /* mark was present */
3789 TRD_INDENT_BEFORE_TYPE;
3790
3791 return abs(maxlen_node_name) + ind_before_type;
3792}
3793
3794/**
aPiecek874ea4d2021-04-19 12:26:36 +02003795 * @brief Find out if it is possible to unify
3796 * the alignment before \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01003797 *
aPiecek874ea4d2021-04-19 12:26:36 +02003798 * The goal is for all node siblings to have the same alignment
3799 * for \<type\> as if they were in a column. All siblings who cannot
3800 * adapt because they do not fit on the line at all are ignored.
aPiecek61d062b2020-11-02 11:05:09 +01003801 * Side-effect -> Current node is set to the first sibling.
3802 *
3803 * @param[in] ca contains inherited data from ancestors.
3804 * @param[in] pc contains mainly functions for printing.
3805 * @param[in,out] tc is tree context.
3806 * @return 0 if all siblings cannot fit on the line.
aPiecek874ea4d2021-04-19 12:26:36 +02003807 * @return positive number indicating the maximum number of spaces
3808 * before \<type\> if the length of the node name is 0. To calculate
3809 * the trt_indent_in_node.btw_opts_type indent size for a particular
aPiecek01598c02021-04-23 14:18:24 +02003810 * node, use the ::trb_calc_btw_opts_type().
aPiecek61d062b2020-11-02 11:05:09 +01003811*/
3812static uint32_t
3813trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3814{
3815 return trb_max_btw_opts_type4siblings(ca, pc, tc);
3816}
3817
3818/**
aPiecekb8d5a0a2021-05-20 08:20:24 +02003819 * @brief Check if there is no case statement
3820 * under the choice statement.
3821 *
3822 * It can return true only if the Parsed schema tree
3823 * is used for browsing.
3824 *
3825 * @param[in] tc is tree context.
3826 * @return 1 if implicit case statement is present otherwise 0.
3827 */
3828static ly_bool
3829trb_need_implicit_node_case(struct trt_tree_ctx *tc)
3830{
3831 return !tc->lysc_tree && tc->pn->parent &&
3832 (tc->pn->parent->nodetype & LYS_CHOICE) &&
3833 (tc->pn->nodetype & (LYS_ANYDATA | LYS_CHOICE | LYS_CONTAINER |
3834 LYS_LEAF | LYS_LEAFLIST));
3835}
3836
3837static void trb_print_subtree_nodes(struct trt_node node, uint32_t max_gap_before_type,
3838 struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc);
3839
3840/**
3841 * @brief Print implicit case node and his subtree.
3842 *
3843 * @param[in] node is child of implicit case.
3844 * @param[in] wr is wrapper for printing identation before node.
3845 * @param[in] ca contains inherited data from ancestors.
3846 * @param[in] pc contains mainly functions for printing.
3847 * @param[in] tc is tree context. Its settings should be the same as
3848 * before the function call.
3849 */
3850static void
3851trb_print_implicit_node_case_subtree(struct trt_node node, struct trt_wrapper wr,
3852 struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3853{
3854 struct trt_node case_node;
3855 struct trt_wrapper wr_case_child;
3856
3857 case_node = tro_create_implicit_case_node(node);
3858 ly_print_(pc->out, "\n");
3859 trb_print_entire_node(case_node, 0, wr, pc, tc);
3860 wr_case_child = pc->fp.read.if_sibling_exists(tc) ?
3861 trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr);
3862 ly_print_(pc->out, "\n");
3863 trb_print_subtree_nodes(node, 0, wr_case_child, ca, pc, tc);
3864}
3865
3866/**
aPiecek874ea4d2021-04-19 12:26:36 +02003867 * @brief For the current node: recursively print all of its child
3868 * nodes and all of its siblings, including their children.
aPiecek61d062b2020-11-02 11:05:09 +01003869 *
aPiecek01598c02021-04-23 14:18:24 +02003870 * This function is an auxiliary function for ::trb_print_subtree_nodes().
aPiecek61d062b2020-11-02 11:05:09 +01003871 * The parent of the current node is expected to exist.
aPiecek874ea4d2021-04-19 12:26:36 +02003872 * Nodes are printed, including unified sibling node alignment
3873 * (align \<type\> to column).
aPiecek61d062b2020-11-02 11:05:09 +01003874 * Side-effect -> current node is set to the last sibling.
3875 *
3876 * @param[in] wr is wrapper for printing identation before node.
3877 * @param[in] ca contains inherited data from ancestors.
3878 * @param[in] pc contains mainly functions for printing.
3879 * @param[in,out] tc is tree context.
3880 */
3881static void
3882trb_print_nodes(struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3883{
3884 uint32_t max_gap_before_type;
3885 ly_bool sibling_flag = 0;
3886 ly_bool child_flag = 0;
3887
3888 /* if node is last sibling, then do not add '|' to wrapper */
3889 wr = trb_parent_is_last_sibling(pc->fp, tc) ?
3890 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
3891
3892 /* try unified indentation in node */
3893 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
3894
3895 /* print all siblings */
3896 do {
3897 struct trt_parent_cache new_ca;
3898 struct trt_node node;
Michal Vasko26bbb272022-08-02 14:54:33 +02003899
aPiecek9bdd7592021-05-20 08:13:20 +02003900 node = pc->fp.read.node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003901
aPiecekb8d5a0a2021-05-20 08:20:24 +02003902 if (!trb_need_implicit_node_case(tc)) {
3903 /* normal behavior */
3904 ly_print_(pc->out, "\n");
3905 trb_print_entire_node(node, max_gap_before_type, wr, pc, tc);
3906 new_ca = tro_parent_cache_for_child(ca, tc);
3907 /* go to the actual node's child or stay in actual node */
3908 node = pc->fp.modify.next_child(ca, tc);
3909 child_flag = !trp_node_is_empty(node);
aPiecek61d062b2020-11-02 11:05:09 +01003910
aPiecekb8d5a0a2021-05-20 08:20:24 +02003911 if (child_flag) {
3912 /* print all childs - recursive call */
3913 trb_print_nodes(wr, new_ca, pc, tc);
3914 /* get back from child node to actual node */
3915 pc->fp.modify.parent(tc);
3916 }
3917 } else {
3918 /* The case statement is omitted (shorthand).
3919 * Print implicit case node and his subtree.
3920 */
3921 trb_print_implicit_node_case_subtree(node, wr, ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003922 }
3923
3924 /* go to the actual node's sibling */
3925 node = pc->fp.modify.next_sibling(ca, tc);
3926 sibling_flag = !trp_node_is_empty(node);
3927
3928 /* go to the next sibling or stay in actual node */
3929 } while (sibling_flag);
3930}
3931
3932/**
aPiecek153b00f2021-04-20 13:52:57 +02003933 * @brief Calculate the wrapper about how deep in the tree the node is.
ekinzie0ab8b302022-10-10 03:03:57 -04003934 * @param[in] wr_in A wrapper to use as a starting point
aPiecek153b00f2021-04-20 13:52:57 +02003935 * @param[in] node from which to count.
3936 * @return wrapper for @p node.
3937 */
3938static struct trt_wrapper
ekinzie0ab8b302022-10-10 03:03:57 -04003939trb_count_depth(const struct trt_wrapper *wr_in, const struct lysc_node *node)
aPiecek153b00f2021-04-20 13:52:57 +02003940{
ekinzie0ab8b302022-10-10 03:03:57 -04003941 struct trt_wrapper wr = wr_in ? *wr_in : TRP_INIT_WRAPPER_TOP;
aPiecek153b00f2021-04-20 13:52:57 +02003942 const struct lysc_node *parent;
3943
3944 if (!node) {
3945 return wr;
3946 }
3947
3948 for (parent = node->parent; parent; parent = parent->parent) {
3949 wr = trp_wrapper_set_shift(wr);
3950 }
3951
3952 return wr;
3953}
3954
3955/**
3956 * @brief Print all parent nodes of @p node and the @p node itself.
3957 *
3958 * Side-effect -> trt_tree_ctx.cn will be set to @p node.
3959 *
3960 * @param[in] node on which the function is focused.
aPiecek7ed8d032022-10-10 12:32:27 +02003961 * @param[in] wr_in for printing identation before node.
aPiecek01598c02021-04-23 14:18:24 +02003962 * @param[in] pc is @ref TRP_trp settings.
aPiecek153b00f2021-04-20 13:52:57 +02003963 * @param[in,out] tc is context of tree printer.
3964 * @return wrapper for @p node.
3965 */
3966static void
ekinzie0ab8b302022-10-10 03:03:57 -04003967trb_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 +02003968{
3969 struct trt_wrapper wr;
aPiecek9bdd7592021-05-20 08:13:20 +02003970 struct trt_node print_node;
aPiecek153b00f2021-04-20 13:52:57 +02003971
3972 assert(pc && tc && tc->section == TRD_SECT_MODULE);
3973
3974 /* stop recursion */
3975 if (!node) {
3976 return;
3977 }
ekinzie0ab8b302022-10-10 03:03:57 -04003978 trb_print_parents(node->parent, wr_in, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003979
3980 /* setup for printing */
3981 tc->cn = node;
ekinzie0ab8b302022-10-10 03:03:57 -04003982 wr = trb_count_depth(wr_in, node);
aPiecek153b00f2021-04-20 13:52:57 +02003983
3984 /* print node */
3985 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02003986 print_node = pc->fp.read.node(TRP_EMPTY_PARENT_CACHE, tc);
3987 trb_print_entire_node(print_node, 0, wr, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003988}
3989
3990/**
aPiecekdc8fd572021-04-19 10:47:23 +02003991 * @brief Get address of the current node.
3992 * @param[in] tc contains current node.
aPiecek3f247652021-04-19 13:40:25 +02003993 * @return Address of lysc_node or lysp_node, or NULL.
aPiecekdc8fd572021-04-19 10:47:23 +02003994 */
3995static const void *
3996trb_tree_ctx_get_node(struct trt_tree_ctx *tc)
3997{
aPiecek3f247652021-04-19 13:40:25 +02003998 return tc->lysc_tree ?
3999 (const void *)tc->cn :
4000 (const void *)tc->pn;
aPiecekdc8fd572021-04-19 10:47:23 +02004001}
4002
4003/**
4004 * @brief Get address of current node's child.
4005 * @param[in,out] tc contains current node.
4006 */
4007static const void *
4008trb_tree_ctx_get_child(struct trt_tree_ctx *tc)
4009{
4010 if (!trb_tree_ctx_get_node(tc)) {
4011 return NULL;
4012 }
4013
aPiecek3f247652021-04-19 13:40:25 +02004014 if (tc->lysc_tree) {
4015 return lysc_node_child(tc->cn);
4016 } else {
4017 return lysp_node_child(tc->pn);
4018 }
aPiecekdc8fd572021-04-19 10:47:23 +02004019}
4020
4021/**
4022 * @brief Set current node on its child.
4023 * @param[in,out] tc contains current node.
4024 */
4025static void
4026trb_tree_ctx_set_child(struct trt_tree_ctx *tc)
4027{
aPiecek3f247652021-04-19 13:40:25 +02004028 const void *node = trb_tree_ctx_get_child(tc);
4029
4030 if (tc->lysc_tree) {
4031 tc->cn = node;
4032 } else {
4033 tc->pn = node;
4034 }
aPiecekdc8fd572021-04-19 10:47:23 +02004035}
4036
4037/**
aPiecek61d062b2020-11-02 11:05:09 +01004038 * @brief Print subtree of nodes.
4039 *
4040 * The current node is expected to be the root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02004041 * Before root node is no linebreak printing. This must be addressed by
4042 * the caller. Root node will also be printed. Behind last printed node
4043 * is no linebreak.
aPiecek61d062b2020-11-02 11:05:09 +01004044 *
aPiecek9bdd7592021-05-20 08:13:20 +02004045 * @param[in] node is root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02004046 * @param[in] max_gap_before_type is result from
aPiecek01598c02021-04-23 14:18:24 +02004047 * ::trb_try_unified_indent() function for root node.
4048 * Set parameter to 0 if distance does not matter.
aPiecek874ea4d2021-04-19 12:26:36 +02004049 * @param[in] wr is wrapper saying how deep in the whole tree
4050 * is the root of the subtree.
4051 * @param[in] ca is parent_cache from root's parent.
4052 * If root is top-level node, insert ::TRP_EMPTY_PARENT_CACHE.
aPiecek01598c02021-04-23 14:18:24 +02004053 * @param[in] pc is @ref TRP_trp settings.
aPiecek874ea4d2021-04-19 12:26:36 +02004054 * @param[in,out] tc is context of tree printer.
aPiecek61d062b2020-11-02 11:05:09 +01004055 */
4056static void
aPiecek9bdd7592021-05-20 08:13:20 +02004057trb_print_subtree_nodes(struct trt_node node, uint32_t max_gap_before_type, struct trt_wrapper wr,
4058 struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004059{
4060 struct trt_parent_cache new_ca;
aPiecek61d062b2020-11-02 11:05:09 +01004061
aPiecek9bdd7592021-05-20 08:13:20 +02004062 trb_print_entire_node(node, max_gap_before_type, wr, pc, tc);
ekinzie0ab8b302022-10-10 03:03:57 -04004063
aPiecek61d062b2020-11-02 11:05:09 +01004064 /* go to the actual node's child */
aPiecek3f247652021-04-19 13:40:25 +02004065 new_ca = tro_parent_cache_for_child(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01004066 node = pc->fp.modify.next_child(ca, tc);
4067
4068 if (!trp_node_is_empty(node)) {
4069 /* print root's nodes */
4070 trb_print_nodes(wr, new_ca, pc, tc);
4071 /* get back from child node to actual node */
4072 pc->fp.modify.parent(tc);
4073 }
4074}
4075
4076/**
4077 * @brief Get number of siblings.
4078 *
4079 * Side-effect -> current node is set to the first sibling.
4080 *
4081 * @param[in] fp contains callback functions which modify tree context
4082 * @param[in,out] tc is the tree context.
4083 * @return Number of siblings of the current node.
4084 */
4085static uint32_t
4086trb_get_number_of_siblings(struct trt_fp_modify_ctx fp, struct trt_tree_ctx *tc)
4087{
4088 uint32_t ret = 1;
4089 struct trt_node node = TRP_EMPTY_NODE;
4090
4091 /* including actual node */
4092 fp.first_sibling(tc);
4093 while (!trp_node_is_empty(node = fp.next_sibling(TRP_EMPTY_PARENT_CACHE, tc))) {
4094 ret++;
4095 }
4096 fp.first_sibling(tc);
4097 return ret;
4098}
4099
4100/**
4101 * @brief Print all parents and their children.
4102 *
aPiecek874ea4d2021-04-19 12:26:36 +02004103 * This function is suitable for printing top-level nodes that
aPiecek01598c02021-04-23 14:18:24 +02004104 * do not have ancestors. Function call ::trb_print_subtree_nodes()
aPiecek153b00f2021-04-20 13:52:57 +02004105 * for all top-level siblings. Use this function after 'module' keyword
4106 * or 'augment' and so. The nodes may not be exactly top-level in the
4107 * tree, but the function considers them that way.
aPiecek61d062b2020-11-02 11:05:09 +01004108 *
aPiecek153b00f2021-04-20 13:52:57 +02004109 * @param[in] wr is wrapper saying how deeply the top-level nodes are
4110 * immersed in the tree.
aPiecek61d062b2020-11-02 11:05:09 +01004111 * @param[pc] pc contains mainly functions for printing.
4112 * @param[in,out] tc is tree context.
4113 */
4114static void
aPiecek153b00f2021-04-20 13:52:57 +02004115trb_print_family_tree(struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004116{
aPiecek61d062b2020-11-02 11:05:09 +01004117 struct trt_parent_cache ca;
aPiecek9bdd7592021-05-20 08:13:20 +02004118 struct trt_node node;
aPiecek61d062b2020-11-02 11:05:09 +01004119 uint32_t total_parents;
4120 uint32_t max_gap_before_type;
4121
aPiecekdc8fd572021-04-19 10:47:23 +02004122 if (!trb_tree_ctx_get_node(tc)) {
4123 return;
4124 }
4125
aPiecek61d062b2020-11-02 11:05:09 +01004126 ca = TRP_EMPTY_PARENT_CACHE;
4127 total_parents = trb_get_number_of_siblings(pc->fp.modify, tc);
4128 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
4129
aPiecek3f247652021-04-19 13:40:25 +02004130 if (!tc->lysc_tree) {
aPiecek96baa7f2021-04-23 12:32:00 +02004131 if (((tc->section == TRD_SECT_GROUPING) && (tc->tpn == tc->pn->parent)) ||
4132 (tc->section == TRD_SECT_YANG_DATA)) {
aPiecek3f247652021-04-19 13:40:25 +02004133 ca.lys_config = 0x0;
4134 }
aPiecekdc8fd572021-04-19 10:47:23 +02004135 }
4136
aPiecek61d062b2020-11-02 11:05:09 +01004137 for (uint32_t i = 0; i < total_parents; i++) {
4138 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02004139 node = pc->fp.read.node(ca, tc);
4140 trb_print_subtree_nodes(node, max_gap_before_type, wr, ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01004141 pc->fp.modify.next_sibling(ca, tc);
4142 }
4143}
4144
aPiecek7ed8d032022-10-10 12:32:27 +02004145/**
4146 * @brief Mounted module iterator.
4147 *
4148 * Omit internal modules, modules with no nodes (e.g., iana-if-types)
4149 * and modules that were loaded as the result of a parent-reference.
4150 *
4151 * @param[in] ext_ctx is special context of mount-point extension.
4152 * @param[in] parent_refs is set of parent-references. Can be NULL for case of 'inline' schema-ref.
4153 * @param[in,out] state of the iterator. Set the value to zero for initialization.
4154 * @return First/next mounted module or NULL.
4155 */
4156static const struct lys_module *
4157trb_mounted_module_iter(struct ly_ctx *ext_ctx, struct ly_set *parent_refs, uint32_t *state)
4158{
4159 const struct lys_module *mod = NULL;
4160 ly_bool from_parent_ref;
4161 uint32_t j;
4162
4163 if (!(*state)) {
4164 /* Get first non-internal module. */
4165 *state = ly_ctx_internal_modules_count(ext_ctx);
4166 }
4167
4168 while ((mod = ly_ctx_get_module_iter(ext_ctx, state))) {
4169 if (mod->compiled && !mod->compiled->data) {
4170 /* Compiled module with no data-nodes. */
4171 continue;
4172 } else if (mod->parsed && !mod->parsed->data) {
4173 /* Parsed module with no data-nodes. */
4174 continue;
4175 } else if (!parent_refs) {
4176 /* Mounting in 'inline' mode. Success. */
4177 break;
4178 }
4179
4180 /* Check if the module is not in parent-reference. */
4181 from_parent_ref = 0;
4182 for (j = 0; j < parent_refs->count; j++) {
4183 if (!strcmp(mod->ns, parent_refs->snodes[j]->module->ns)) {
4184 from_parent_ref = 1;
4185 break;
4186 }
4187 }
4188 if (!from_parent_ref) {
4189 /* Success. */
4190 break;
4191 }
4192 }
4193
4194 return mod;
4195}
4196
aPiecek874ea4d2021-04-19 12:26:36 +02004197/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004198 * Definition of trm main functions
aPiecek874ea4d2021-04-19 12:26:36 +02004199 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004200
4201/**
aPiecekdc8fd572021-04-19 10:47:23 +02004202 * @brief Settings if lysp_node are used for browsing through the tree.
aPiecek61d062b2020-11-02 11:05:09 +01004203 *
aPiecekdc8fd572021-04-19 10:47:23 +02004204 * @param[in] module YANG schema tree structure representing
4205 * YANG module.
aPiecek61d062b2020-11-02 11:05:09 +01004206 * @param[in] out is output handler.
aPiecekdc8fd572021-04-19 10:47:23 +02004207 * @param[in] max_line_length is the maximum line length limit
4208 * that should not be exceeded.
aPiecek7ed8d032022-10-10 12:32:27 +02004209 * @param[in] mounted context is used for printing the YANG Schema mount.
4210 * @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 +02004211 * @param[in,out] pc will be adapted to lysp_tree.
4212 * @param[in,out] tc will be adapted to lysp_tree.
aPiecek61d062b2020-11-02 11:05:09 +01004213 */
4214static void
aPiecek7ed8d032022-10-10 12:32:27 +02004215trm_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, ly_bool mounted,
4216 const struct ly_set *parent_refs, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004217{
aPiecekdc8fd572021-04-19 10:47:23 +02004218 *tc = (struct trt_tree_ctx) {
aPiecek3f247652021-04-19 13:40:25 +02004219 .lysc_tree = 0,
aPiecek7ed8d032022-10-10 12:32:27 +02004220 .mounted = mounted || parent_refs,
aPiecekdc8fd572021-04-19 10:47:23 +02004221 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02004222 .pmod = module->parsed,
4223 .cmod = NULL,
4224 .pn = module->parsed ? module->parsed->data : NULL,
4225 .tpn = module->parsed ? module->parsed->data : NULL,
aPiecek7ed8d032022-10-10 12:32:27 +02004226 .cn = NULL,
aPiecek40f22402022-10-14 10:48:08 +02004227 .parent_refs = parent_refs,
4228 .last_error = 0
aPiecekdc8fd572021-04-19 10:47:23 +02004229 };
aPiecek61d062b2020-11-02 11:05:09 +01004230
aPiecekdc8fd572021-04-19 10:47:23 +02004231 pc->out = out;
4232
4233 pc->fp.modify = (struct trt_fp_modify_ctx) {
aPiecekef1e58e2021-04-19 13:19:44 +02004234 .parent = trop_modi_parent,
4235 .first_sibling = trop_modi_first_sibling,
4236 .next_sibling = trop_modi_next_sibling,
4237 .next_child = trop_modi_next_child,
aPiecek61d062b2020-11-02 11:05:09 +01004238 };
4239
aPiecekdc8fd572021-04-19 10:47:23 +02004240 pc->fp.read = (struct trt_fp_read) {
aPiecek61d062b2020-11-02 11:05:09 +01004241 .module_name = tro_read_module_name,
aPiecekef1e58e2021-04-19 13:19:44 +02004242 .node = trop_read_node,
4243 .if_sibling_exists = trop_read_if_sibling_exists
aPiecek61d062b2020-11-02 11:05:09 +01004244 };
4245
aPiecekdc8fd572021-04-19 10:47:23 +02004246 pc->fp.print = (struct trt_fp_print) {
aPiecek3f247652021-04-19 13:40:25 +02004247 .print_features_names = tro_print_features_names,
4248 .print_keys = tro_print_keys
aPiecek61d062b2020-11-02 11:05:09 +01004249 };
4250
aPiecekdc8fd572021-04-19 10:47:23 +02004251 pc->max_line_length = max_line_length;
aPiecek61d062b2020-11-02 11:05:09 +01004252}
4253
4254/**
aPiecek3f247652021-04-19 13:40:25 +02004255 * @brief Settings if lysc_node are used for browsing through the tree.
4256 *
4257 * Pointers to current nodes will be set to module data.
4258 *
4259 * @param[in] module YANG schema tree structure representing
4260 * YANG module.
4261 * @param[in] out is output handler.
4262 * @param[in] max_line_length is the maximum line length limit
4263 * that should not be exceeded.
aPiecek7ed8d032022-10-10 12:32:27 +02004264 * @param[in] mounted context is used for printing the YANG Schema mount.
4265 * @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 +02004266 * @param[in,out] pc will be adapted to lysc_tree.
4267 * @param[in,out] tc will be adapted to lysc_tree.
4268 */
4269static void
aPiecek7ed8d032022-10-10 12:32:27 +02004270trm_lysc_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, ly_bool mounted,
4271 const struct ly_set *parent_refs, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek3f247652021-04-19 13:40:25 +02004272{
4273 *tc = (struct trt_tree_ctx) {
4274 .lysc_tree = 1,
aPiecek7ed8d032022-10-10 12:32:27 +02004275 .mounted = mounted || parent_refs,
aPiecek3f247652021-04-19 13:40:25 +02004276 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02004277 .pmod = module->parsed,
4278 .cmod = module->compiled,
aPiecek3f247652021-04-19 13:40:25 +02004279 .tpn = NULL,
4280 .pn = NULL,
aPiecek7ed8d032022-10-10 12:32:27 +02004281 .cn = module->compiled->data,
aPiecek40f22402022-10-14 10:48:08 +02004282 .parent_refs = parent_refs,
4283 .last_error = 0
aPiecek3f247652021-04-19 13:40:25 +02004284 };
4285
4286 pc->out = out;
4287
4288 pc->fp.modify = (struct trt_fp_modify_ctx) {
4289 .parent = troc_modi_parent,
4290 .first_sibling = troc_modi_first_sibling,
4291 .next_sibling = troc_modi_next_sibling,
4292 .next_child = troc_modi_next_child,
aPiecek3f247652021-04-19 13:40:25 +02004293 };
4294
4295 pc->fp.read = (struct trt_fp_read) {
4296 .module_name = tro_read_module_name,
4297 .node = troc_read_node,
4298 .if_sibling_exists = troc_read_if_sibling_exists
4299 };
4300
4301 pc->fp.print = (struct trt_fp_print) {
4302 .print_features_names = tro_print_features_names,
4303 .print_keys = tro_print_keys
4304 };
4305
4306 pc->max_line_length = max_line_length;
4307}
4308
4309/**
4310 * @brief Reset settings to browsing through the lysc tree.
aPiecek01598c02021-04-23 14:18:24 +02004311 * @param[in,out] pc resets to @ref TRP_troc functions.
aPiecek3f247652021-04-19 13:40:25 +02004312 * @param[in,out] tc resets to lysc browsing.
4313 */
4314static void
4315trm_reset_to_lysc_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4316{
aPiecek40f22402022-10-14 10:48:08 +02004317 LY_ERR erc;
4318
4319 erc = tc->last_error;
aPiecek7ed8d032022-10-10 12:32:27 +02004320 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 +02004321 tc->last_error = erc;
aPiecek3f247652021-04-19 13:40:25 +02004322}
4323
4324/**
4325 * @brief Reset settings to browsing through the lysp tree.
aPiecek01598c02021-04-23 14:18:24 +02004326 * @param[in,out] pc resets to @ref TRP_trop functions.
aPiecek3f247652021-04-19 13:40:25 +02004327 * @param[in,out] tc resets to lysp browsing.
4328 */
4329static void
4330trm_reset_to_lysp_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4331{
aPiecek40f22402022-10-14 10:48:08 +02004332 LY_ERR erc;
4333
4334 erc = tc->last_error;
aPiecek7ed8d032022-10-10 12:32:27 +02004335 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 +02004336 tc->last_error = erc;
aPiecek3f247652021-04-19 13:40:25 +02004337}
4338
4339/**
4340 * @brief If augment's target node is located on the current module.
4341 * @param[in] pn is examined augment.
4342 * @param[in] pmod is current module.
4343 * @return 1 if nodeid refers to the local node, otherwise 0.
4344 */
4345static ly_bool
4346trm_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod)
4347{
4348 const char *id, *prefix, *name;
4349 size_t prefix_len, name_len;
4350 const struct lys_module *mod;
4351 ly_bool ret = 0;
4352
4353 if (pn == NULL) {
4354 return ret;
4355 }
4356
4357 id = pn->nodeid;
4358 if (!id) {
4359 return ret;
4360 }
4361 /* only absolute-schema-nodeid is taken into account */
4362 assert(id[0] == '/');
4363 ++id;
4364
4365 ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len);
4366 if (prefix) {
Radek Krejci8df109d2021-04-23 12:19:08 +02004367 mod = ly_resolve_prefix(pmod->mod->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, pmod);
Michal Vasko3003c9a2022-03-29 12:10:00 +02004368 ret = mod ? (mod->parsed == pmod) : 0;
aPiecek3f247652021-04-19 13:40:25 +02004369 } else {
4370 ret = 1;
4371 }
4372
4373 return ret;
4374}
4375
4376/**
aPiecek96baa7f2021-04-23 12:32:00 +02004377 * @brief Printing section module, rpcs, notifications or yang-data.
aPiecek61d062b2020-11-02 11:05:09 +01004378 *
aPiecekdc8fd572021-04-19 10:47:23 +02004379 * First node must be the first child of 'module',
aPiecek96baa7f2021-04-23 12:32:00 +02004380 * 'rpcs', 'notifications' or 'yang-data'.
aPiecek61d062b2020-11-02 11:05:09 +01004381 *
aPiecekdc8fd572021-04-19 10:47:23 +02004382 * @param[in] ks is section representation.
4383 * @param[in] pc contains mainly functions for printing.
4384 * @param[in,out] tc is the tree context.
aPiecek61d062b2020-11-02 11:05:09 +01004385 */
4386static void
aPiecekdc8fd572021-04-19 10:47:23 +02004387trm_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 +01004388{
aPiecekdc8fd572021-04-19 10:47:23 +02004389 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4390 return;
4391 }
4392
4393 trp_print_keyword_stmt(ks, pc->max_line_length, 0, pc->out);
4394 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
aPiecek153b00f2021-04-20 13:52:57 +02004395 trb_print_family_tree(TRP_INIT_WRAPPER_TOP, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004396 } else {
aPiecek153b00f2021-04-20 13:52:57 +02004397 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004398 }
4399}
4400
4401/**
aPiecek96baa7f2021-04-23 12:32:00 +02004402 * @brief Printing section augment or grouping.
aPiecekdc8fd572021-04-19 10:47:23 +02004403 *
aPiecek96baa7f2021-04-23 12:32:00 +02004404 * First node is 'augment' or 'grouping' itself.
aPiecekdc8fd572021-04-19 10:47:23 +02004405 *
4406 * @param[in] ks is section representation.
4407 * @param[in] pc contains mainly functions for printing.
4408 * @param[in,out] tc is the tree context.
4409 */
4410static void
4411trm_print_section_as_subtree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4412{
4413 ly_bool grp_has_data = 0;
4414
4415 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4416 return;
4417 }
4418
4419 if (ks.type == TRD_KEYWORD_GROUPING) {
4420 grp_has_data = trb_tree_ctx_get_child(tc) ? 1 : 0;
4421 }
4422
4423 trp_print_keyword_stmt(ks, pc->max_line_length, grp_has_data, pc->out);
4424 trb_tree_ctx_set_child(tc);
aPiecek153b00f2021-04-20 13:52:57 +02004425 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004426}
4427
4428/**
4429 * @brief Print 'module' keyword, its name and all nodes.
4430 * @param[in] pc contains mainly functions for printing.
4431 * @param[in,out] tc is the tree context.
4432 */
4433static void
4434trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4435{
4436 trm_print_section_as_family_tree(pc->fp.read.module_name(tc), pc, tc);
4437}
4438
4439/**
4440 * @brief For all augment sections: print 'augment' keyword,
4441 * its target node and all nodes.
4442 * @param[in] pc contains mainly functions for printing.
4443 * @param[in,out] tc is the tree context.
4444 */
4445static void
4446trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4447{
4448 ly_bool once;
aPiecek3f247652021-04-19 13:40:25 +02004449 ly_bool origin_was_lysc_tree = 0;
aPiecekdc8fd572021-04-19 10:47:23 +02004450
aPiecek3f247652021-04-19 13:40:25 +02004451 if (tc->lysc_tree) {
4452 origin_was_lysc_tree = 1;
4453 trm_reset_to_lysp_tree_ctx(pc, tc);
4454 }
4455
aPiecekdc8fd572021-04-19 10:47:23 +02004456 once = 1;
aPiecek01598c02021-04-23 14:18:24 +02004457 for (struct trt_keyword_stmt ks = trop_modi_next_augment(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004458 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
aPiecek01598c02021-04-23 14:18:24 +02004459 ks = trop_modi_next_augment(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004460
aPiecek3f247652021-04-19 13:40:25 +02004461 if (origin_was_lysc_tree) {
4462 /* if lysc tree is used, then only augments targeting
4463 * another module are printed
4464 */
aPiecek9f792e52021-04-21 08:33:56 +02004465 if (trm_nodeid_target_is_local((const struct lysp_node_augment *)tc->tpn, tc->pmod)) {
aPiecek3f247652021-04-19 13:40:25 +02004466 continue;
4467 }
4468 }
4469
aPiecekdc8fd572021-04-19 10:47:23 +02004470 if (once) {
4471 ly_print_(pc->out, "\n");
4472 ly_print_(pc->out, "\n");
4473 once = 0;
4474 } else {
4475 ly_print_(pc->out, "\n");
4476 }
4477
4478 trm_print_section_as_subtree(ks, pc, tc);
4479 }
aPiecek3f247652021-04-19 13:40:25 +02004480
4481 if (origin_was_lysc_tree) {
4482 trm_reset_to_lysc_tree_ctx(pc, tc);
4483 }
aPiecekdc8fd572021-04-19 10:47:23 +02004484}
4485
4486/**
4487 * @brief For rpcs section: print 'rpcs' keyword and all its nodes.
4488 * @param[in] pc contains mainly functions for printing.
4489 * @param[in,out] tc is the tree context.
4490 */
4491static void
4492trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4493{
4494 struct trt_keyword_stmt rpc;
4495
aPiecek01598c02021-04-23 14:18:24 +02004496 rpc = tro_modi_get_rpcs(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004497
4498 if (!(TRP_KEYWORD_STMT_IS_EMPTY(rpc))) {
4499 ly_print_(pc->out, "\n");
4500 ly_print_(pc->out, "\n");
4501 trm_print_section_as_family_tree(rpc, pc, tc);
4502 }
4503}
4504
4505/**
4506 * @brief For notifications section: print 'notifications' keyword
4507 * and all its nodes.
4508 * @param[in] pc contains mainly functions for printing.
4509 * @param[in,out] tc is the tree context.
4510 */
4511static void
4512trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4513{
4514 struct trt_keyword_stmt notifs;
4515
aPiecek01598c02021-04-23 14:18:24 +02004516 notifs = tro_modi_get_notifications(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004517
4518 if (!(TRP_KEYWORD_STMT_IS_EMPTY(notifs))) {
4519 ly_print_(pc->out, "\n");
4520 ly_print_(pc->out, "\n");
4521 trm_print_section_as_family_tree(notifs, pc, tc);
4522 }
4523}
4524
4525/**
4526 * @brief For all grouping sections: print 'grouping' keyword, its name
4527 * and all nodes.
4528 * @param[in] pc contains mainly functions for printing.
4529 * @param[in,out] tc is the tree context.
4530 */
4531static void
4532trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4533{
4534 ly_bool once;
4535
aPiecek01598c02021-04-23 14:18:24 +02004536 if (tc->lysc_tree) {
aPiecekdc8fd572021-04-19 10:47:23 +02004537 return;
4538 }
4539
4540 once = 1;
aPiecek01598c02021-04-23 14:18:24 +02004541 for (struct trt_keyword_stmt ks = trop_modi_next_grouping(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004542 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
aPiecek01598c02021-04-23 14:18:24 +02004543 ks = trop_modi_next_grouping(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004544 if (once) {
4545 ly_print_(pc->out, "\n");
4546 ly_print_(pc->out, "\n");
4547 once = 0;
4548 } else {
4549 ly_print_(pc->out, "\n");
4550 }
4551 trm_print_section_as_subtree(ks, pc, tc);
4552 }
4553}
4554
4555/**
4556 * @brief For all yang-data sections: print 'yang-data' keyword
4557 * and all its nodes.
4558 * @param[in] pc contains mainly functions for printing.
4559 * @param[in,out] tc is the tree context.
4560 */
4561static void
aPiecek96baa7f2021-04-23 12:32:00 +02004562trm_print_yang_data(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecekdc8fd572021-04-19 10:47:23 +02004563{
aPiecek96baa7f2021-04-23 12:32:00 +02004564 ly_bool once;
4565 LY_ARRAY_COUNT_TYPE count;
4566
4567 count = LY_ARRAY_COUNT(tc->pmod->exts);
4568 if (count == 0) {
4569 return;
4570 }
4571
4572 once = 1;
4573 for (LY_ARRAY_COUNT_TYPE u = 0; u < count; ++u) {
4574 struct trt_keyword_stmt ks;
4575
aPiecek01598c02021-04-23 14:18:24 +02004576 /* Only ::lys_compile_extension_instance() can set item
aPiecek96baa7f2021-04-23 12:32:00 +02004577 * ::lysp_ext_instance.parsed.
4578 */
4579 if (!tc->pmod->exts[u].parsed) {
4580 /* print at least the yang-data names */
4581 trop_yang_data_sections(tc->pmod->exts, pc->max_line_length, pc->out);
4582 continue;
4583 }
4584
4585 ks = tro_modi_next_yang_data(tc, u);
4586 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4587 break;
4588 }
4589
4590 if (once) {
4591 ly_print_(pc->out, "\n");
4592 ly_print_(pc->out, "\n");
4593 once = 0;
4594 } else {
4595 ly_print_(pc->out, "\n");
4596 }
4597
4598 trm_print_section_as_family_tree(ks, pc, tc);
4599 }
aPiecekdc8fd572021-04-19 10:47:23 +02004600}
4601
4602/**
4603 * @brief Print sections module, augment, rpcs, notifications,
4604 * grouping, yang-data.
4605 * @param[in] pc contains mainly functions for printing.
4606 * @param[in,out] tc is the tree context.
4607 */
4608static void
4609trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4610{
4611 trm_print_module_section(pc, tc);
4612 trm_print_augmentations(pc, tc);
4613 trm_print_rpcs(pc, tc);
4614 trm_print_notifications(pc, tc);
4615 trm_print_groupings(pc, tc);
4616 trm_print_yang_data(pc, tc);
4617 ly_print_(pc->out, "\n");
aPiecek61d062b2020-11-02 11:05:09 +01004618}
4619
aPiecek40f22402022-10-14 10:48:08 +02004620static LY_ERR
4621tree_print_check_error(struct ly_out_clb_arg *out, struct trt_tree_ctx *tc)
4622{
4623 if (out->last_error) {
4624 return out->last_error;
4625 } else if (tc->last_error) {
4626 return tc->last_error;
4627 } else {
4628 return LY_SUCCESS;
4629 }
4630}
4631
aPiecek874ea4d2021-04-19 12:26:36 +02004632/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004633 * Definition of module interface
aPiecek874ea4d2021-04-19 12:26:36 +02004634 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004635
4636LY_ERR
aPiecek3f247652021-04-19 13:40:25 +02004637tree_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 +01004638{
4639 struct trt_printer_ctx pc;
4640 struct trt_tree_ctx tc;
4641 struct ly_out *new_out;
4642 LY_ERR erc;
4643 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4644
aPiecekdc8fd572021-04-19 10:47:23 +02004645 LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL);
4646
aPiecek61d062b2020-11-02 11:05:09 +01004647 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4648 return erc;
4649 }
4650
4651 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek3f247652021-04-19 13:40:25 +02004652 if ((module->ctx->flags & LY_CTX_SET_PRIV_PARSED) && module->compiled) {
aPiecek7ed8d032022-10-10 12:32:27 +02004653 trm_lysc_tree_ctx(module, new_out, line_length, 0, NULL, &pc, &tc);
aPiecek3f247652021-04-19 13:40:25 +02004654 } else {
aPiecek7ed8d032022-10-10 12:32:27 +02004655 trm_lysp_tree_ctx(module, new_out, line_length, 0, NULL, &pc, &tc);
aPiecek3f247652021-04-19 13:40:25 +02004656 }
aPiecek61d062b2020-11-02 11:05:09 +01004657
4658 trm_print_sections(&pc, &tc);
aPiecek40f22402022-10-14 10:48:08 +02004659 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek61d062b2020-11-02 11:05:09 +01004660
4661 ly_out_free(new_out, NULL, 1);
4662
aPiecekdc8fd572021-04-19 10:47:23 +02004663 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004664}
4665
4666LY_ERR
aPiecek153b00f2021-04-20 13:52:57 +02004667tree_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 +01004668{
aPiecek153b00f2021-04-20 13:52:57 +02004669 struct trt_printer_ctx pc;
4670 struct trt_tree_ctx tc;
4671 struct ly_out *new_out;
4672 struct trt_wrapper wr;
4673 LY_ERR erc;
4674 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4675
4676 assert(out && node);
4677
4678 if (!(node->module->ctx->flags & LY_CTX_SET_PRIV_PARSED)) {
4679 return LY_EINVAL;
4680 }
4681
4682 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4683 return erc;
4684 }
4685
4686 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek7ed8d032022-10-10 12:32:27 +02004687 trm_lysc_tree_ctx(node->module, new_out, line_length, 0, NULL, &pc, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004688
4689 trp_print_keyword_stmt(pc.fp.read.module_name(&tc), pc.max_line_length, 0, pc.out);
ekinzie0ab8b302022-10-10 03:03:57 -04004690 trb_print_parents(node, NULL, &pc, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004691
4692 if (!(options & LYS_PRINT_NO_SUBSTMT)) {
4693 tc.cn = lysc_node_child(node);
ekinzie0ab8b302022-10-10 03:03:57 -04004694 wr = trb_count_depth(NULL, tc.cn);
aPiecek153b00f2021-04-20 13:52:57 +02004695 trb_print_family_tree(wr, &pc, &tc);
4696 }
4697 ly_print_(out, "\n");
4698
aPiecek40f22402022-10-14 10:48:08 +02004699 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004700 ly_out_free(new_out, NULL, 1);
4701
4702 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004703}
4704
4705LY_ERR
Michal Vasko6a914fb2022-01-17 10:36:14 +01004706tree_print_parsed_submodule(struct ly_out *out, const struct lysp_submodule *submodp, uint32_t UNUSED(options),
4707 size_t line_length)
aPiecek61d062b2020-11-02 11:05:09 +01004708{
aPiecek9f792e52021-04-21 08:33:56 +02004709 struct trt_printer_ctx pc;
4710 struct trt_tree_ctx tc;
4711 struct ly_out *new_out;
4712 LY_ERR erc;
4713 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4714
4715 assert(submodp);
4716 LY_CHECK_ARG_RET(submodp->mod->ctx, out, LY_EINVAL);
4717
4718 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4719 return erc;
4720 }
4721
4722 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek7ed8d032022-10-10 12:32:27 +02004723 trm_lysp_tree_ctx(submodp->mod, new_out, line_length, 0, NULL, &pc, &tc);
aPiecek9f792e52021-04-21 08:33:56 +02004724 tc.pmod = (struct lysp_module *)submodp;
4725 tc.tpn = submodp->data;
4726 tc.pn = tc.tpn;
4727
4728 trm_print_sections(&pc, &tc);
aPiecek40f22402022-10-14 10:48:08 +02004729 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek9f792e52021-04-21 08:33:56 +02004730
4731 ly_out_free(new_out, NULL, 1);
4732
4733 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004734}
ekinzie0ab8b302022-10-10 03:03:57 -04004735
aPiecek8f1073c2022-10-17 16:44:49 +02004736/**********************************************************************
4737 * Functions for YANG Schema mount.
4738 *********************************************************************/
4739
4740/**
4741 * @brief Callback data for lysc_module_dfs_full.
4742 */
4743struct sort_parent_refs_state{
4744 struct ly_set *refs; /**< Set of parent-references pointers to sort. */
4745 uint64_t glob; /**< Current index in sort_parent_refs_state.refs. */
4746 uint64_t loc; /**< Current index of parent-ref node which belongs to the same module. */
4747 uint64_t total; /**< Total number of parent-ref nodes which belongs to the same module. */
4748};
4749
4750/**
4751 * @brief Callback for lysc_module_dfs_full() which sorts parent-references.
4752 * @param[in] node is current compiled node to check.
4753 * @param[in,out] data are expected to be of type struct sort_parent_refs_state.
4754 * @param[in] dfs_continue is not used.
4755 * @return LY_ERR value.
4756 */
4757static LY_ERR
4758troc_dfs_clb(struct lysc_node *node, void *data, ly_bool *UNUSED(dfs_continue))
4759{
4760 struct sort_parent_refs_state *dfs_data;
4761 struct lysc_node **snodes, *tmp;
4762 uint64_t i;
4763
4764 dfs_data = data;
4765 snodes = dfs_data->refs->snodes;
4766 for (i = dfs_data->glob; i < dfs_data->refs->count; i++) {
4767 if (snodes[i] == node) {
4768 /* swap */
4769 tmp = snodes[dfs_data->glob];
4770 snodes[dfs_data->glob] = snodes[i];
4771 snodes[i] = tmp;
4772 /* increment counters */
4773 dfs_data->glob++;
4774 dfs_data->loc++;
4775 break;
4776 }
4777 }
4778
4779 if (dfs_data->loc == dfs_data->total) {
4780 /* Stop searching in the current module. */
4781 return LY_ENOT;
4782 } else {
4783 return LY_SUCCESS;
4784 }
4785}
4786
4787/**
4788 * @brief Sort parent-references so that the order matches deep-search-first.
4789 * @param[in,out] refs is set of parent-references to sort.
4790 */
4791static void
4792troc_sort_parent_refs(struct ly_set *refs)
4793{
4794 uint64_t i, j, same_mod;
4795 const struct lys_module *mod;
4796 struct sort_parent_refs_state dfs_data;
4797
4798 if (!refs || (refs->count == 0) || (refs->count == 1)) {
4799 return;
4800 }
4801
4802 dfs_data.refs = refs;
4803 for (i = 0; i < refs->count; i++) {
4804 mod = refs->snodes[i]->module;
4805 /* Count total number of parent-references which refers to the same module. */
4806 same_mod = 1;
4807 for (j = i + 1; j < refs->count; j++) {
4808 if (mod == refs->snodes[j]->module) {
4809 ++same_mod;
4810 }
4811 }
4812 if (same_mod == 1) {
4813 continue;
4814 }
4815
4816 /* Sort all parent-references in the current module. */
4817 dfs_data.glob = i;
4818 dfs_data.loc = 1;
4819 dfs_data.total = same_mod;
4820 lysc_module_dfs_full(mod, troc_dfs_clb, &dfs_data);
4821 i = same_mod - 1;
4822 }
4823}
4824
4825/**
4826 * @brief For next module get the first parent-reference.
4827 * @param[in] parent_refs is set of parent-referenced nodes.
4828 * @param[in,out] parent_ref is the index in @p parent_refs, which is set to next parent-reference.
4829 * @return LY_ERR value.
4830 */
4831static LY_ERR
4832trocm_next_first_parent_ref(const struct ly_set *parent_refs, uint32_t *parent_ref)
4833{
4834 uint64_t i;
4835 const struct lysc_module *cmod;
4836
4837 cmod = parent_refs->snodes[*parent_ref]->module->compiled;
4838 for (i = (*parent_ref + 1); i < parent_refs->count; i++) {
4839 if (cmod != parent_refs->snodes[i]->module->compiled) {
4840 *parent_ref = i;
4841 return LY_SUCCESS;
4842 }
4843 }
4844
4845 return LY_ENOT;
4846}
4847
aPiecek7ed8d032022-10-10 12:32:27 +02004848/**
4849 * @brief Print all mounted nodes ('/') and parent-referenced nodes ('@').
4850 *
4851 * @param[in] ext is mount-point extension.
4852 * @param[in] wr is wrapper to be printed.
4853 * @param[in] pc contains mainly functions for printing.
4854 * @return LY_ERR value.
4855 */
ekinzie0ab8b302022-10-10 03:03:57 -04004856static LY_ERR
aPiecek7ed8d032022-10-10 12:32:27 +02004857trb_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 -04004858{
aPiecek8f1073c2022-10-17 16:44:49 +02004859 LY_ERR ret = LY_SUCCESS, rc;
ekinzie0ab8b302022-10-10 03:03:57 -04004860 struct ly_ctx *ext_ctx = NULL;
aPiecek7ed8d032022-10-10 12:32:27 +02004861 const struct lys_module *mod, *last_mod;
ekinzie0ab8b302022-10-10 03:03:57 -04004862 struct trt_tree_ctx tmptc;
4863 struct trt_wrapper tmpwr;
4864 struct trt_printer_ctx tmppc;
ekinzie0ab8b302022-10-10 03:03:57 -04004865 struct ly_set *refs = NULL;
aPiecek7ed8d032022-10-10 12:32:27 +02004866 uint32_t i, iter_state;
aPiecek36f82232022-10-14 10:08:38 +02004867 ly_bool notif, rpc;
ekinzie0ab8b302022-10-10 03:03:57 -04004868
aPiecek7ed8d032022-10-10 12:32:27 +02004869 if (lyplg_ext_schema_mount_create_context(ext, &ext_ctx)) {
ekinzie0ab8b302022-10-10 03:03:57 -04004870 /* Void mount point */
4871 return LY_SUCCESS;
4872 }
4873
aPiecek40f22402022-10-14 10:48:08 +02004874 ret = lyplg_ext_schema_mount_get_parent_ref(ext, &refs);
4875 LY_CHECK_GOTO(ret, cleanup);
aPiecek7ed8d032022-10-10 12:32:27 +02004876
4877 /* Get the last mounted module which will be printed. */
4878 iter_state = 0;
4879 while ((mod = trb_mounted_module_iter(ext_ctx, refs, &iter_state))) {
4880 last_mod = mod;
ekinzie0ab8b302022-10-10 03:03:57 -04004881 }
4882
ekinzie0ab8b302022-10-10 03:03:57 -04004883 tmppc = *pc;
aPiecek7ed8d032022-10-10 12:32:27 +02004884 iter_state = 0;
4885 while ((mod = trb_mounted_module_iter(ext_ctx, refs, &iter_state))) {
4886 /* Prepare printer tree context. */
ekinzie0ab8b302022-10-10 03:03:57 -04004887 if ((ext_ctx->flags & LY_CTX_SET_PRIV_PARSED) && mod->compiled) {
aPiecek7ed8d032022-10-10 12:32:27 +02004888 trm_lysc_tree_ctx(mod, pc->out, pc->max_line_length, 1, refs, &tmppc, &tmptc);
aPiecek36f82232022-10-14 10:08:38 +02004889 notif = tmptc.cmod->notifs ? 1 : 0;
4890 rpc = tmptc.cmod->rpcs ? 1 : 0;
ekinzie0ab8b302022-10-10 03:03:57 -04004891 } else {
aPiecek7ed8d032022-10-10 12:32:27 +02004892 trm_lysp_tree_ctx(mod, pc->out, pc->max_line_length, 1, refs, &tmppc, &tmptc);
aPiecek36f82232022-10-14 10:08:38 +02004893 notif = tmptc.pmod->notifs ? 1 : 0;
4894 rpc = tmptc.pmod->rpcs ? 1 : 0;
ekinzie0ab8b302022-10-10 03:03:57 -04004895 }
aPiecek36f82232022-10-14 10:08:38 +02004896
aPiecek7ed8d032022-10-10 12:32:27 +02004897 /* Decide whether to print the symbol '|'. */
aPiecek36f82232022-10-14 10:08:38 +02004898 tmpwr = (mod == last_mod) && !rpc && !notif && !refs ? wr : trp_wrapper_set_mark_top(wr);
aPiecek7ed8d032022-10-10 12:32:27 +02004899 /* Print top-level nodes of mounted module which are denoted by the symbol '/'. */
4900 trb_print_family_tree(tmpwr, &tmppc, &tmptc);
aPiecek36f82232022-10-14 10:08:38 +02004901
4902 /* Print top-level rpc nodes. */
4903 if (rpc) {
4904 tro_modi_get_rpcs(&tmptc);
4905 tmpwr = (mod == last_mod) && !notif && !refs ? wr : trp_wrapper_set_mark_top(wr);
4906 trb_print_family_tree(tmpwr, &tmppc, &tmptc);
4907 }
4908
4909 /* Print top-level notification nodes. */
4910 if (notif) {
4911 tro_modi_get_notifications(&tmptc);
4912 tmpwr = (mod == last_mod) && !refs ? wr : trp_wrapper_set_mark_top(wr);
4913 trb_print_family_tree(tmpwr, &tmppc, &tmptc);
4914 }
ekinzie0ab8b302022-10-10 03:03:57 -04004915 }
4916
aPiecek7ed8d032022-10-10 12:32:27 +02004917 /* Print parent-referenced nodes which are denoted by the symbol '@'. */
aPiecek8f1073c2022-10-17 16:44:49 +02004918 if (!refs || (refs->count == 0)) {
4919 goto cleanup;
4920 }
4921 troc_sort_parent_refs(refs);
4922 rc = LY_SUCCESS;
4923 /* Iterate over all modules which are in refs. */
4924 for (i = 0; rc == LY_SUCCESS; rc = trocm_next_first_parent_ref(refs, &i)) {
aPiecek7ed8d032022-10-10 12:32:27 +02004925 trm_lysc_tree_ctx(refs->snodes[i]->module, pc->out, pc->max_line_length, 1, refs, &tmppc, &tmptc);
aPiecek8f1073c2022-10-17 16:44:49 +02004926 tmptc.cn = trocm_node_child(NULL, refs->snodes[i]);
4927 tmppc.fp.modify.first_sibling = trocm_modi_first_sibling;
4928 tmppc.fp.modify.next_sibling = trocm_modi_next_sibling;
4929 tmppc.fp.modify.next_child = trocm_modi_next_child;
4930 tmppc.fp.read.if_sibling_exists = trocm_read_if_sibling_exists;
4931 iter_state = i;
4932 tmpwr = trocm_next_first_parent_ref(refs, &i) ? wr : trp_wrapper_set_mark_top(wr);
4933 i = iter_state;
4934 trb_print_family_tree(tmpwr, &tmppc, &tmptc);
ekinzie0ab8b302022-10-10 03:03:57 -04004935 }
4936
aPiecek40f22402022-10-14 10:48:08 +02004937cleanup:
ekinzie0ab8b302022-10-10 03:03:57 -04004938 ly_set_free(refs, NULL);
ekinzie0ab8b302022-10-10 03:03:57 -04004939 ly_ctx_destroy(ext_ctx);
aPiecek7ed8d032022-10-10 12:32:27 +02004940
4941 return ret;
ekinzie0ab8b302022-10-10 03:03:57 -04004942}