blob: b7507fcfaa840c12ae0d3f9e70e3a009bd23ebb3 [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 *
74 * @subsubsection TRP_trt trt
75 * Data type marking in the printer_tree module.
76 *
77 * @subsubsection TRP_trg trg
78 * General functions.
79 *
80 * @subsection TRP_ADJUSTMENTS Adjustments
81 * It is assumed that the changes are likely to take place mainly for
aPiecek01598c02021-04-23 14:18:24 +020082 * @ref TRP_tro, @ref TRP_trop or @ref TRP_troc functions because
aPiecek3f247652021-04-19 13:40:25 +020083 * they are the only ones dependent on libyang implementation.
84 * In special cases, changes will also need to be made to the
aPiecek01598c02021-04-23 14:18:24 +020085 * @ref TRP_trp functions if a special algorithm is needed to print
aPiecek3f247652021-04-19 13:40:25 +020086 * (right now this is prepared for printing list's keys
87 * and if-features).
aPiecek61d062b2020-11-02 11:05:09 +010088 */
89
aPiecek874ea4d2021-04-19 12:26:36 +020090#include <assert.h>
91#include <string.h>
92
93#include "common.h"
94#include "compat.h"
95#include "out_internal.h"
ekinzie0ab8b302022-10-10 03:03:57 -040096#include "plugins_exts.h"
97#include "plugins_types.h"
aPiecek03cb4872022-10-24 10:31:51 +020098#include "printer_internal.h"
aPiecek704f8e92021-08-25 13:35:05 +020099#include "printer_schema.h"
aPiecek874ea4d2021-04-19 12:26:36 +0200100#include "tree_schema_internal.h"
101#include "xpath.h"
102
aPiecek61d062b2020-11-02 11:05:09 +0100103/**
104 * @brief List of available actions.
105 */
106typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200107 TRD_PRINT = 0, /**< Normal behavior. It just prints. */
108 TRD_CHAR_COUNT /**< Characters will be counted instead of printing. */
aPiecek61d062b2020-11-02 11:05:09 +0100109} trt_ly_out_clb_arg_flag;
110
111/**
aPiecek874ea4d2021-04-19 12:26:36 +0200112 * @brief Structure is passed as 'writeclb' argument
aPiecek01598c02021-04-23 14:18:24 +0200113 * to the ::ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100114 */
115struct ly_out_clb_arg {
aPiecek874ea4d2021-04-19 12:26:36 +0200116 trt_ly_out_clb_arg_flag mode; /**< flag specifying which action to take. */
117 struct ly_out *out; /**< The ly_out pointer delivered to the printer tree module via the main interface. */
118 size_t counter; /**< Counter of printed characters. */
119 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 +0100120};
121
122/**
123 * @brief Initialize struct ly_out_clb_arg with default settings.
124 */
125#define TRP_INIT_LY_OUT_CLB_ARG(MODE, OUT, COUNTER, LAST_ERROR) \
aPiecek874ea4d2021-04-19 12:26:36 +0200126 (struct ly_out_clb_arg) { \
127 .mode = MODE, .out = OUT, \
128 .counter = COUNTER, .last_error = LAST_ERROR \
129 }
aPiecek61d062b2020-11-02 11:05:09 +0100130
aPiecek874ea4d2021-04-19 12:26:36 +0200131/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100132 * Print getters
aPiecek874ea4d2021-04-19 12:26:36 +0200133 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100134
135/**
136 * @brief Callback functions that prints special cases.
137 *
138 * It just groups together tree context with trt_fp_print.
139 */
140struct trt_cf_print {
aPiecek874ea4d2021-04-19 12:26:36 +0200141 const struct trt_tree_ctx *ctx; /**< Context of libyang tree. */
Michal Vasko26bbb272022-08-02 14:54:33 +0200142
aPiecek874ea4d2021-04-19 12:26:36 +0200143 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 +0100144};
145
146/**
147 * @brief Callback functions for printing special cases.
148 *
aPiecek874ea4d2021-04-19 12:26:36 +0200149 * Functions with the suffix 'trp' can print most of the text on
150 * output, just by setting the pointer to the string. But in some
151 * cases, it's not that simple, because its entire string is fragmented
152 * in memory. For example, for printing list's keys or if-features.
aPiecek61d062b2020-11-02 11:05:09 +0100153 * However, this depends on how the libyang library is implemented.
aPiecek3f247652021-04-19 13:40:25 +0200154 * This implementation of the printer_tree module goes through
155 * a lysp tree, but if it goes through a lysc tree, these special cases
156 * would be different.
aPiecek61d062b2020-11-02 11:05:09 +0100157 * Functions must print including spaces or delimiters between names.
158 */
159struct trt_fp_print {
160 void (*print_features_names)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list of features without {}? wrapper. */
161 void (*print_keys)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list's keys without [] wrapper. */
162};
163
164/**
165 * @brief Package which only groups getter function.
166 */
167struct trt_pck_print {
168 const struct trt_tree_ctx *tree_ctx; /**< Context of libyang tree. */
169 struct trt_fp_print fps; /**< Print function. */
170};
171
172/**
173 * @brief Initialize struct trt_pck_print by parameters.
174 */
175#define TRP_INIT_PCK_PRINT(TREE_CTX, FP_PRINT) \
aPiecek874ea4d2021-04-19 12:26:36 +0200176 (struct trt_pck_print) {.tree_ctx = TREE_CTX, .fps = FP_PRINT}
aPiecek61d062b2020-11-02 11:05:09 +0100177
aPiecek874ea4d2021-04-19 12:26:36 +0200178/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100179 * Indent
aPiecek874ea4d2021-04-19 12:26:36 +0200180 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100181
182/**
aPiecek874ea4d2021-04-19 12:26:36 +0200183 * @brief Constants which are defined in the RFC or are observable
184 * from the pyang tool.
aPiecek61d062b2020-11-02 11:05:09 +0100185 */
186typedef enum {
187 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 +0100188 TRD_INDENT_LONG_LINE_BREAK = 2, /**< The new line should be indented so that it starts below \<name\> with
189 a whitespace offset of at least two characters. */
190 TRD_INDENT_LINE_BEGIN = 2, /**< Indent below the keyword (module, augment ...). */
191 TRD_INDENT_BTW_SIBLINGS = 2, /**< Indent between | and | characters. */
192 TRD_INDENT_BEFORE_KEYS = 1, /**< "..."___\<keys\>. */
193 TRD_INDENT_BEFORE_TYPE = 4, /**< "..."___\<type\>, but if mark is set then indent == 3. */
aPiecek61d062b2020-11-02 11:05:09 +0100194 TRD_INDENT_BEFORE_IFFEATURES = 1 /**< "..."___\<iffeatures\>. */
195} trt_cnf_indent;
196
197/**
198 * @brief Type of indent in node.
199 */
200typedef enum {
201 TRD_INDENT_IN_NODE_NORMAL = 0, /**< Node fits on one line. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100202 TRD_INDENT_IN_NODE_DIVIDED, /**< The node must be split into multiple rows. */
aPiecek61d062b2020-11-02 11:05:09 +0100203 TRD_INDENT_IN_NODE_FAILED /**< Cannot be crammed into one line. The condition for the maximum line length is violated. */
204} trt_indent_in_node_type;
205
206/** Constant to indicate the need to break a line. */
207#define TRD_LINEBREAK -1
208
209/**
aPiecek874ea4d2021-04-19 12:26:36 +0200210 * @brief Records the alignment between the individual
211 * elements of the node.
aPiecek61d062b2020-11-02 11:05:09 +0100212 *
aPiecek874ea4d2021-04-19 12:26:36 +0200213 * @see trp_default_indent_in_node, trp_try_normal_indent_in_node
aPiecek61d062b2020-11-02 11:05:09 +0100214 */
215struct trt_indent_in_node {
216 trt_indent_in_node_type type; /**< Type of indent in node. */
aPiecek874ea4d2021-04-19 12:26:36 +0200217 int16_t btw_name_opts; /**< Indent between node name and \<opts\>. */
218 int16_t btw_opts_type; /**< Indent between \<opts\> and \<type\>. */
aPiecek61d062b2020-11-02 11:05:09 +0100219 int16_t btw_type_iffeatures; /**< Indent between type and features. Ignored if \<type\> missing. */
220};
221
222/**
223 * @brief Type of wrappers to be printed.
224 */
225typedef enum {
226 TRD_WRAPPER_TOP = 0, /**< Related to the module. */
227 TRD_WRAPPER_BODY /**< Related to e.g. Augmentations or Groupings */
228} trd_wrapper_type;
229
230/**
231 * @brief For resolving sibling symbol ('|') placement.
232 *
233 * Bit indicates where the sibling symbol must be printed.
aPiecek874ea4d2021-04-19 12:26:36 +0200234 * This place is in multiples of ::TRD_INDENT_BTW_SIBLINGS.
aPiecek61d062b2020-11-02 11:05:09 +0100235 *
aPiecek874ea4d2021-04-19 12:26:36 +0200236 * @see TRP_INIT_WRAPPER_TOP, TRP_INIT_WRAPPER_BODY,
237 * trp_wrapper_set_mark, trp_wrapper_set_shift,
238 * trp_wrapper_if_last_sibling, trp_wrapper_eq, trp_print_wrapper
aPiecek61d062b2020-11-02 11:05:09 +0100239 */
240struct trt_wrapper {
241 trd_wrapper_type type; /**< Location of the wrapper. */
242 uint64_t bit_marks1; /**< The set bits indicate where the '|' character is to be printed.
243 It follows that the maximum immersion of the printable node is 64. */
244 uint32_t actual_pos; /**< Actual position in bit_marks. */
245};
246
247/**
248 * @brief Get wrapper related to the module section.
249 *
250 * @code
251 * module: <module-name>
252 * +--<node>
253 * |
254 * @endcode
255 */
256#define TRP_INIT_WRAPPER_TOP \
aPiecek874ea4d2021-04-19 12:26:36 +0200257 (struct trt_wrapper) { \
258 .type = TRD_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0 \
259 }
aPiecek61d062b2020-11-02 11:05:09 +0100260
261/**
aPiecek874ea4d2021-04-19 12:26:36 +0200262 * @brief Get wrapper related to subsection
263 * e.g. Augmenations or Groupings.
aPiecek61d062b2020-11-02 11:05:09 +0100264 *
265 * @code
266 * module: <module-name>
267 * +--<node>
268 *
269 * augment <target-node>:
270 * +--<node>
271 * @endcode
272 */
273#define TRP_INIT_WRAPPER_BODY \
aPiecek874ea4d2021-04-19 12:26:36 +0200274 (struct trt_wrapper) { \
275 .type = TRD_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0 \
276 }
aPiecek61d062b2020-11-02 11:05:09 +0100277
278/**
279 * @brief Package which only groups wrapper and indent in node.
280 */
281struct trt_pck_indent {
282 struct trt_wrapper wrapper; /**< Coded " | | " sequence. */
283 struct trt_indent_in_node in_node; /**< Indent in node. */
284};
285
286/**
287 * @brief Initialize struct trt_pck_indent by parameters.
288 */
289#define TRP_INIT_PCK_INDENT(WRAPPER, INDENT_IN_NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200290 (struct trt_pck_indent){ \
291 .wrapper = WRAPPER, .in_node = INDENT_IN_NODE \
292 }
aPiecek61d062b2020-11-02 11:05:09 +0100293
aPiecek874ea4d2021-04-19 12:26:36 +0200294/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100295 * flags
aPiecek874ea4d2021-04-19 12:26:36 +0200296 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100297
aPiecek41219f92022-10-26 11:24:40 +0200298#define TRD_FLAGS_TYPE_EMPTY "--"
299#define TRD_FLAGS_TYPE_RW "rw"
300#define TRD_FLAGS_TYPE_RO "ro"
301#define TRD_FLAGS_TYPE_RPC_INPUT_PARAMS "-w"
302#define TRD_FLAGS_TYPE_USES_OF_GROUPING "-u"
303#define TRD_FLAGS_TYPE_RPC "-x"
304#define TRD_FLAGS_TYPE_NOTIF "-n"
305#define TRD_FLAGS_TYPE_MOUNT_POINT "mp"
aPiecek61d062b2020-11-02 11:05:09 +0100306
aPiecek874ea4d2021-04-19 12:26:36 +0200307/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100308 * node_name and opts
aPiecek874ea4d2021-04-19 12:26:36 +0200309 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100310
311#define TRD_NODE_NAME_PREFIX_CHOICE "("
312#define TRD_NODE_NAME_PREFIX_CASE ":("
313#define TRD_NODE_NAME_TRIPLE_DOT "..."
314
315/**
316 * @brief Type of the node.
317 *
aPiecek874ea4d2021-04-19 12:26:36 +0200318 * Used mainly to complete the correct \<opts\> next to or
319 * around the \<name\>.
aPiecek61d062b2020-11-02 11:05:09 +0100320 */
321typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200322 TRD_NODE_ELSE = 0, /**< For some node which does not require special treatment. \<name\> */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100323 TRD_NODE_CASE, /**< For case node. :(\<name\>) */
324 TRD_NODE_CHOICE, /**< For choice node. (\<name\>) */
aPiecek874ea4d2021-04-19 12:26:36 +0200325 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 +0100326} trt_node_type;
327
aPiecek41219f92022-10-26 11:24:40 +0200328#define TRD_NODE_OPTIONAL "?" /**< For an optional leaf, anydata, or anyxml. \<name\>? */
329#define TRD_NODE_CONTAINER "!" /**< For a presence container. \<name\>! */
330#define TRD_NODE_LISTLEAFLIST "*" /**< For a leaf-list or list. \<name\>* */
331
aPiecek61d062b2020-11-02 11:05:09 +0100332/**
333 * @brief Type of node and his name.
334 *
aPiecek874ea4d2021-04-19 12:26:36 +0200335 * @see TRP_EMPTY_NODE_NAME, TRP_NODE_NAME_IS_EMPTY,
aPiecek61d062b2020-11-02 11:05:09 +0100336 * trp_print_node_name, trp_mark_is_used, trp_print_opts_keys
337 */
338struct trt_node_name {
339 trt_node_type type; /**< Type of the node relevant for printing. */
aPiecekbca57772022-10-13 13:51:59 +0200340 ly_bool keys; /**< Set to 1 if [\<keys\>] are to be printed. Valid for some types only. */
aPiecek34fa3772021-05-21 12:35:46 +0200341 const char *module_prefix; /**< If the node is augmented into the tree from another module,
342 so this is the prefix of that module. */
aPiecek61d062b2020-11-02 11:05:09 +0100343 const char *str; /**< Name of the node. */
aPiecek03cb4872022-10-24 10:31:51 +0200344 const char *add_opts; /**< Additional opts symbol from plugin. */
345 const char *opts; /**< The \<opts\> symbol. */
aPiecek61d062b2020-11-02 11:05:09 +0100346};
347
348/**
349 * @brief Create struct trt_node_name as empty.
350 */
351#define TRP_EMPTY_NODE_NAME \
aPiecek874ea4d2021-04-19 12:26:36 +0200352 (struct trt_node_name) { \
aPiecek03cb4872022-10-24 10:31:51 +0200353 .type = TRD_NODE_ELSE, .keys = 0, .module_prefix = NULL, .str = NULL, .opts = NULL, .add_opts = NULL \
aPiecek874ea4d2021-04-19 12:26:36 +0200354 }
aPiecek61d062b2020-11-02 11:05:09 +0100355
356/**
357 * @brief Check if struct trt_node_name is empty.
358 */
359#define TRP_NODE_NAME_IS_EMPTY(NODE_NAME) \
360 !NODE_NAME.str
361
aPiecek874ea4d2021-04-19 12:26:36 +0200362/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100363 * type
aPiecek874ea4d2021-04-19 12:26:36 +0200364 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100365
366/**
367 * @brief Type of the \<type\>
368 */
369typedef enum {
370 TRD_TYPE_NAME = 0, /**< Type is just a name that does not require special treatment. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100371 TRD_TYPE_TARGET, /**< Should have a form "-> TARGET", where TARGET is the leafref path. */
372 TRD_TYPE_LEAFREF, /**< This type is set automatically by the 'trp' algorithm.
aPiecek874ea4d2021-04-19 12:26:36 +0200373 So set type as ::TRD_TYPE_TARGET. */
aPiecek61d062b2020-11-02 11:05:09 +0100374 TRD_TYPE_EMPTY /**< Type is not used at all. */
375} trt_type_type;
376
377/**
378 * @brief \<type\> in the \<node\>.
379 *
aPiecek874ea4d2021-04-19 12:26:36 +0200380 * @see TRP_EMPTY_TRT_TYPE, TRP_TRT_TYPE_IS_EMPTY, trp_print_type
aPiecek61d062b2020-11-02 11:05:09 +0100381 */
382struct trt_type {
383 trt_type_type type; /**< Type of the \<type\>. */
384 const char *str; /**< Path or name of the type. */
385};
386
387/**
388 * @brief Create empty struct trt_type.
389 */
390#define TRP_EMPTY_TRT_TYPE \
391 (struct trt_type) {.type = TRD_TYPE_EMPTY, .str = NULL}
392
393/**
394 * @brief Check if struct trt_type is empty.
395 */
396#define TRP_TRT_TYPE_IS_EMPTY(TYPE_OF_TYPE) \
397 TYPE_OF_TYPE.type == TRD_TYPE_EMPTY
398
399/**
400 * @brief Initialize struct trt_type by parameters.
401 */
402#define TRP_INIT_TRT_TYPE(TYPE_OF_TYPE, STRING) \
403 (struct trt_type) {.type = TYPE_OF_TYPE, .str = STRING}
404
aPiecek03cb4872022-10-24 10:31:51 +0200405/**
406 * @brief If-feature type.
407 */
aPiecek41219f92022-10-26 11:24:40 +0200408typedef enum {
aPiecek03cb4872022-10-24 10:31:51 +0200409 TRD_IFF_NON_PRESENT = 0, /**< iffeatures are not present. */
410 TRD_IFF_PRESENT, /**< iffeatures are present and will be printed by
aPiecek41219f92022-10-26 11:24:40 +0200411 trt_fp_print.print_features_names callback */
aPiecek03cb4872022-10-24 10:31:51 +0200412 TRD_IFF_OVERR /**< iffeatures are override by plugin */
aPiecek41219f92022-10-26 11:24:40 +0200413} trt_iffeatures_type;
414
aPiecek03cb4872022-10-24 10:31:51 +0200415/**
416 * @brief \<if-features\>.
417 */
aPiecek41219f92022-10-26 11:24:40 +0200418struct trt_iffeatures {
aPiecek03cb4872022-10-24 10:31:51 +0200419 trt_iffeatures_type type; /**< Type of iffeature. */
420 char *str; /**< iffeatures string ready to print. Set if TRD_IFF_OVERR is set. */
aPiecek41219f92022-10-26 11:24:40 +0200421};
422
aPiecek03cb4872022-10-24 10:31:51 +0200423/**
424 * @brief Create empty iffeatures.
425 */
aPiecek41219f92022-10-26 11:24:40 +0200426#define TRP_EMPTY_TRT_IFFEATURES \
427 (struct trt_iffeatures) {.type = TRD_IFF_NON_PRESENT}
428
aPiecek03cb4872022-10-24 10:31:51 +0200429/**
430 * @brief Check if iffeatures is empty.
431 *
432 * @param[in] IFF_TYPE value from trt_iffeatures.type.
433 * @return 1 if is empty.
434 */
aPiecek41219f92022-10-26 11:24:40 +0200435#define TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(IFF_TYPE) \
436 (IFF_TYPE == TRD_IFF_NON_PRESENT)
437
aPiecek874ea4d2021-04-19 12:26:36 +0200438/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100439 * node
aPiecek874ea4d2021-04-19 12:26:36 +0200440 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100441
442/**
443 * @brief \<node\> data for printing.
444 *
aPiecek874ea4d2021-04-19 12:26:36 +0200445 * It contains RFC's:
446 * \<status\>--\<flags\> \<name\>\<opts\> \<type\> \<if-features\>.
aPiecek61d062b2020-11-02 11:05:09 +0100447 * Item \<opts\> is moved to part struct trt_node_name.
aPiecek874ea4d2021-04-19 12:26:36 +0200448 * For printing [\<keys\>] and if-features is required special
449 * functions which prints them.
aPiecek61d062b2020-11-02 11:05:09 +0100450 *
aPiecek874ea4d2021-04-19 12:26:36 +0200451 * @see TRP_EMPTY_NODE, trp_node_is_empty, trp_node_body_is_empty,
452 * trp_print_node_up_to_name, trp_print_divided_node_up_to_name,
453 * trp_print_node
aPiecek61d062b2020-11-02 11:05:09 +0100454 */
455struct trt_node {
aPiecek03cb4872022-10-24 10:31:51 +0200456 const char *status; /**< \<status\>. */
457 const char *flags; /**< \<flags\>. */
aPiecek7ed8d032022-10-10 12:32:27 +0200458 struct trt_node_name name; /**< \<node\> with \<opts\> mark or [\<keys\>]. */
459 struct trt_type type; /**< \<type\> contains the name of the type or type for leafref. */
aPiecek41219f92022-10-26 11:24:40 +0200460 struct trt_iffeatures iffeatures; /**< \<if-features\>. */
aPiecek7ed8d032022-10-10 12:32:27 +0200461 ly_bool last_one; /**< Information about whether the node is the last. */
aPiecek61d062b2020-11-02 11:05:09 +0100462};
463
464/**
465 * @brief Create struct trt_node as empty.
466 */
467#define TRP_EMPTY_NODE \
aPiecek874ea4d2021-04-19 12:26:36 +0200468 (struct trt_node) { \
aPiecek41219f92022-10-26 11:24:40 +0200469 .status = NULL, \
470 .flags = NULL, \
aPiecek874ea4d2021-04-19 12:26:36 +0200471 .name = TRP_EMPTY_NODE_NAME, \
472 .type = TRP_EMPTY_TRT_TYPE, \
aPiecek41219f92022-10-26 11:24:40 +0200473 .iffeatures = TRP_EMPTY_TRT_IFFEATURES, \
aPiecek03cb4872022-10-24 10:31:51 +0200474 .last_one = 1 \
aPiecek874ea4d2021-04-19 12:26:36 +0200475 }
aPiecek61d062b2020-11-02 11:05:09 +0100476
477/**
478 * @brief Package which only groups indent and node.
479 */
480struct trt_pair_indent_node {
481 struct trt_indent_in_node indent;
482 struct trt_node node;
483};
484
485/**
486 * @brief Initialize struct trt_pair_indent_node by parameters.
487 */
488#define TRP_INIT_PAIR_INDENT_NODE(INDENT_IN_NODE, NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200489 (struct trt_pair_indent_node) { \
490 .indent = INDENT_IN_NODE, .node = NODE \
491 }
aPiecek61d062b2020-11-02 11:05:09 +0100492
aPiecek874ea4d2021-04-19 12:26:36 +0200493/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100494 * statement
aPiecek874ea4d2021-04-19 12:26:36 +0200495 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100496
aPiecek03cb4872022-10-24 10:31:51 +0200497#define TRD_KEYWORD_MODULE "module"
498#define TRD_KEYWORD_SUBMODULE "submodule"
499#define TRD_KEYWORD_AUGMENT "augment"
500#define TRD_KEYWORD_RPC "rpcs"
501#define TRD_KEYWORD_NOTIF "notifications"
502#define TRD_KEYWORD_GROUPING "grouping"
aPiecek61d062b2020-11-02 11:05:09 +0100503
504/**
505 * @brief Main sign of the tree nodes.
506 *
aPiecek874ea4d2021-04-19 12:26:36 +0200507 * @see TRP_EMPTY_KEYWORD_STMT, TRP_KEYWORD_STMT_IS_EMPTY
aPiecek61d062b2020-11-02 11:05:09 +0100508 * trt_print_keyword_stmt_begin, trt_print_keyword_stmt_str,
509 * trt_print_keyword_stmt_end, trp_print_keyword_stmt
aPiecek61d062b2020-11-02 11:05:09 +0100510 */
511struct trt_keyword_stmt {
aPiecek03cb4872022-10-24 10:31:51 +0200512 const char *section_name; /**< String containing section name. */
513 const char *argument; /**< Name or path located begind section name. */
514 ly_bool has_node; /**< Flag if section has any nodes. */
aPiecek61d062b2020-11-02 11:05:09 +0100515};
516
517/**
518 * @brief Create struct trt_keyword_stmt as empty.
519 */
520#define TRP_EMPTY_KEYWORD_STMT \
aPiecek03cb4872022-10-24 10:31:51 +0200521 (struct trt_keyword_stmt) {.section_name = NULL, .argument = NULL, .has_node = 0}
aPiecek61d062b2020-11-02 11:05:09 +0100522
aPiecek874ea4d2021-04-19 12:26:36 +0200523/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100524 * Modify getters
aPiecek874ea4d2021-04-19 12:26:36 +0200525 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100526
527struct trt_parent_cache;
528
529/**
530 * @brief Functions that change the state of the tree_ctx structure.
531 *
aPiecek3f247652021-04-19 13:40:25 +0200532 * The 'trop' or 'troc' functions are set here, which provide data
aPiecek874ea4d2021-04-19 12:26:36 +0200533 * for the 'trp' printing functions and are also called from the
534 * 'trb' browsing functions when walking through a tree. These callback
535 * functions need to be checked or reformulated if changes to the
536 * libyang library affect the printing tree. For all, if the value
537 * cannot be returned, its empty version obtained by relevant TRP_EMPTY
538 * macro is returned.
aPiecek61d062b2020-11-02 11:05:09 +0100539 */
540struct trt_fp_modify_ctx {
541 ly_bool (*parent)(struct trt_tree_ctx *); /**< Jump to parent node. Return true if parent exists. */
aPiecek03cb4872022-10-24 10:31:51 +0200542 struct trt_node (*first_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump on the first of the siblings. */
aPiecek61d062b2020-11-02 11:05:09 +0100543 struct trt_node (*next_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to next sibling of the current node. */
544 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 +0100545};
546
aPiecek03cb4872022-10-24 10:31:51 +0200547/**
548 * @brief Create modify functions for compiled tree.
549 */
550#define TRP_TRT_FP_MODIFY_COMPILED \
551 (struct trt_fp_modify_ctx) { \
552 .parent = troc_modi_parent, \
553 .first_sibling = troc_modi_first_sibling, \
554 .next_sibling = troc_modi_next_sibling, \
555 .next_child = troc_modi_next_child, \
556 }
557
558/**
559 * @brief Create modify functions for parsed tree.
560 */
561#define TRP_TRT_FP_MODIFY_PARSED \
562 (struct trt_fp_modify_ctx) { \
563 .parent = trop_modi_parent, \
564 .first_sibling = trop_modi_first_sibling, \
565 .next_sibling = trop_modi_next_sibling, \
566 .next_child = trop_modi_next_child, \
567 }
568
aPiecek874ea4d2021-04-19 12:26:36 +0200569/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100570 * Read getters
aPiecek874ea4d2021-04-19 12:26:36 +0200571 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100572
573/**
574 * @brief Functions that do not change the state of the tree_structure.
575 *
576 * For details see trt_fp_modify_ctx.
577 */
578struct trt_fp_read {
aPiecek874ea4d2021-04-19 12:26:36 +0200579 struct trt_keyword_stmt (*module_name)(const struct trt_tree_ctx *); /**< Get name of the module. */
aPiecek03cb4872022-10-24 10:31:51 +0200580 struct trt_node (*node)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Get current node. */
aPiecek874ea4d2021-04-19 12:26:36 +0200581 ly_bool (*if_sibling_exists)(const struct trt_tree_ctx *); /**< Check if node's sibling exists. */
aPiecek03cb4872022-10-24 10:31:51 +0200582 ly_bool (*if_parent_exists)(const struct trt_tree_ctx *); /**< Check if node's parent exists. */
aPiecek61d062b2020-11-02 11:05:09 +0100583};
584
aPiecek03cb4872022-10-24 10:31:51 +0200585/**
586 * @brief Create read functions for compiled tree.
587 */
588#define TRP_TRT_FP_READ_COMPILED \
589 (struct trt_fp_read) { \
590 .module_name = tro_read_module_name, \
591 .node = troc_read_node, \
592 .if_sibling_exists = troc_read_if_sibling_exists, \
593 .if_parent_exists = tro_read_if_sibling_exists \
594 }
595
596/**
597 * @brief Create read functions for parsed tree.
598 */
599#define TRP_TRT_FP_READ_PARSED \
600 (struct trt_fp_read) { \
601 .module_name = tro_read_module_name, \
602 .node = trop_read_node, \
603 .if_sibling_exists = trop_read_if_sibling_exists, \
604 .if_parent_exists = tro_read_if_sibling_exists \
605 }
606
aPiecek874ea4d2021-04-19 12:26:36 +0200607/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100608 * All getters
aPiecek874ea4d2021-04-19 12:26:36 +0200609 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100610
611/**
aPiecek874ea4d2021-04-19 12:26:36 +0200612 * @brief A set of all necessary functions that must be provided
613 * for the printer.
aPiecek61d062b2020-11-02 11:05:09 +0100614 */
615struct trt_fp_all {
616 struct trt_fp_modify_ctx modify; /**< Function pointers which modify state of trt_tree_ctx. */
617 struct trt_fp_read read; /**< Function pointers which only reads state of trt_tree_ctx. */
618 struct trt_fp_print print; /**< Functions pointers for printing special items in node. */
619};
620
aPiecek874ea4d2021-04-19 12:26:36 +0200621/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100622 * Printer context
aPiecek874ea4d2021-04-19 12:26:36 +0200623 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100624
625/**
aPiecek01598c02021-04-23 14:18:24 +0200626 * @brief Main structure for @ref TRP_trp part.
aPiecek61d062b2020-11-02 11:05:09 +0100627 */
628struct trt_printer_ctx {
629 struct ly_out *out; /**< Handler to printing. */
aPiecek01598c02021-04-23 14:18:24 +0200630 struct trt_fp_all fp; /**< @ref TRP_tro functions callbacks. */
aPiecek61d062b2020-11-02 11:05:09 +0100631 size_t max_line_length; /**< The maximum number of characters that can be
632 printed on one line, including the last. */
633};
634
aPiecek874ea4d2021-04-19 12:26:36 +0200635/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100636 * Tro functions
aPiecek874ea4d2021-04-19 12:26:36 +0200637 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100638
639/**
640 * @brief The name of the section to which the node belongs.
641 */
642typedef enum {
643 TRD_SECT_MODULE = 0, /**< The node belongs to the "module: <module_name>:" label. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100644 TRD_SECT_AUGMENT, /**< The node belongs to some "augment <target-node>:" label. */
645 TRD_SECT_RPCS, /**< The node belongs to the "rpcs:" label. */
646 TRD_SECT_NOTIF, /**< The node belongs to the "notifications:" label. */
647 TRD_SECT_GROUPING, /**< The node belongs to some "grouping <grouping-name>:" label. */
aPiecek03cb4872022-10-24 10:31:51 +0200648 TRD_SECT_PLUG_DATA /**< The node belongs to some plugin section. */
aPiecek61d062b2020-11-02 11:05:09 +0100649} trt_actual_section;
650
651/**
652 * @brief Types of nodes that have some effect on their children.
653 */
654typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200655 TRD_ANCESTOR_ELSE = 0, /**< Everything not listed. */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100656 TRD_ANCESTOR_RPC_INPUT, /**< ::LYS_INPUT */
657 TRD_ANCESTOR_RPC_OUTPUT, /**< ::LYS_OUTPUT */
aPiecek874ea4d2021-04-19 12:26:36 +0200658 TRD_ANCESTOR_NOTIF /**< ::LYS_NOTIF */
aPiecek61d062b2020-11-02 11:05:09 +0100659} trt_ancestor_type;
660
661/**
662 * @brief Saved information when browsing the tree downwards.
663 *
aPiecek874ea4d2021-04-19 12:26:36 +0200664 * This structure helps prevent frequent retrieval of information
aPiecek01598c02021-04-23 14:18:24 +0200665 * from the tree. Functions @ref TRP_trb are designed to preserve
aPiecek874ea4d2021-04-19 12:26:36 +0200666 * this structures during their recursive calls. This functions do not
667 * interfere in any way with this data. This structure
aPiecek01598c02021-04-23 14:18:24 +0200668 * is used by @ref TRP_trop functions which, thanks to this
aPiecek874ea4d2021-04-19 12:26:36 +0200669 * structure, can return a node with the correct data. The word
670 * \b parent is in the structure name, because this data refers to
671 * the last parent and at the same time the states of its
672 * ancestors data. Only the function jumping on the child
673 * (next_child(...)) creates this structure, because the pointer
674 * to the current node moves down the tree. It's like passing
675 * the genetic code to children. Some data must be inherited and
676 * there are two approaches to this problem. Either it will always
677 * be determined which inheritance states belong to the current node
678 * (which can lead to regular travel to the root node) or
679 * the inheritance states will be stored during the recursive calls.
680 * So the problem was solved by the second option. Why does
681 * the structure contain this data? Because it walks through
aPiecek3f247652021-04-19 13:40:25 +0200682 * the lysp tree. For walks through the lysc tree is trt_parent_cache
683 * useless.
aPiecek61d062b2020-11-02 11:05:09 +0100684 *
aPiecek874ea4d2021-04-19 12:26:36 +0200685 * @see TRO_EMPTY_PARENT_CACHE, tro_parent_cache_for_child
aPiecek61d062b2020-11-02 11:05:09 +0100686 */
687struct trt_parent_cache {
aPiecek874ea4d2021-04-19 12:26:36 +0200688 trt_ancestor_type ancestor; /**< Some types of nodes have a special effect on their children. */
689 uint16_t lys_status; /**< Inherited status CURR, DEPRC, OBSLT. */
690 uint16_t lys_config; /**< Inherited config W or R. */
691 const struct lysp_node_list *last_list; /**< The last ::LYS_LIST passed. */
aPiecek61d062b2020-11-02 11:05:09 +0100692};
693
694/**
695 * @brief Return trt_parent_cache filled with default values.
696 */
697#define TRP_EMPTY_PARENT_CACHE \
aPiecek874ea4d2021-04-19 12:26:36 +0200698 (struct trt_parent_cache) { \
699 .ancestor = TRD_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \
700 .lys_config = LYS_CONFIG_W, .last_list = NULL \
701 }
aPiecek61d062b2020-11-02 11:05:09 +0100702
703/**
aPiecek03cb4872022-10-24 10:31:51 +0200704 * @brief Node override from plugin.
705 */
706struct lyplg_ext_sprinter_tree_node_override {
707 const char *flags; /**< Override for \<flags\>. */
708 const char *add_opts; /**< Additional symbols for \<opts\>. */
709};
710
711/**
712 * @brief Context for plugin extension.
713 */
714struct trt_plugin_ctx {
715 struct lyspr_tree_ctx *ctx; /**< Pointer to main context. */
716 struct lyspr_tree_schema *schema; /**< Current schema to print. */
717 ly_bool filtered; /**< Flag if current node is filtered. */
718 struct lyplg_ext_sprinter_tree_node_override node_overr; /**< Current node override. */
719 ly_bool last_schema; /**< Flag if schema is last. */
720 ly_bool last_error; /**< Last error from plugin. */
721};
722
723/**
aPiecek61d062b2020-11-02 11:05:09 +0100724 * @brief Main structure for browsing the libyang tree
725 */
726struct trt_tree_ctx {
aPiecek96baa7f2021-04-23 12:32:00 +0200727 ly_bool lysc_tree; /**< The lysc nodes are used for browsing through the tree.
728 It is assumed that once set, it does not change.
729 If it is true then trt_tree_ctx.pn and
730 trt_tree_ctx.tpn are not used.
731 If it is false then trt_tree_ctx.cn is not used. */
732 trt_actual_section section; /**< To which section pn points. */
733 const struct lysp_module *pmod; /**< Parsed YANG schema tree. */
734 const struct lysc_module *cmod; /**< Compiled YANG schema tree. */
735 const struct lysp_node *pn; /**< Actual pointer to parsed node. */
aPiecek03cb4872022-10-24 10:31:51 +0200736 const struct lysp_node *tpn; /**< Pointer to actual top-node. */
aPiecek96baa7f2021-04-23 12:32:00 +0200737 const struct lysc_node *cn; /**< Actual pointer to compiled node. */
aPiecek40f22402022-10-14 10:48:08 +0200738 LY_ERR last_error; /**< Error value during printing. */
aPiecek03cb4872022-10-24 10:31:51 +0200739
740 struct trt_plugin_ctx plugin_ctx; /**< Context for plugin. */
aPiecek61d062b2020-11-02 11:05:09 +0100741};
742
aPiecek3f247652021-04-19 13:40:25 +0200743/**
aPiecek03cb4872022-10-24 10:31:51 +0200744 * @brief Create empty node override.
745 */
746#define TRP_TREE_CTX_EMPTY_NODE_OVERR \
747 (struct lyplg_ext_sprinter_tree_node_override) { \
748 .flags = NULL, \
749 .add_opts = NULL, \
750 }
751
752/**
aPiecekbbc02932021-05-21 07:19:41 +0200753 * @brief Check if lysp node is available from
754 * the current compiled node.
755 *
756 * Use only if trt_tree_ctx.lysc_tree is set to true.
757 */
758#define TRP_TREE_CTX_LYSP_NODE_PRESENT(CN) \
759 (CN->priv)
760
761/**
aPiecek3f247652021-04-19 13:40:25 +0200762 * @brief Get lysp_node from trt_tree_ctx.cn.
aPiecekbbc02932021-05-21 07:19:41 +0200763 *
764 * Use only if :TRP_TREE_CTX_LYSP_NODE_PRESENT returns true
765 * for that node.
aPiecek3f247652021-04-19 13:40:25 +0200766 */
767#define TRP_TREE_CTX_GET_LYSP_NODE(CN) \
768 ((const struct lysp_node *)CN->priv)
769
aPiecek01598c02021-04-23 14:18:24 +0200770/** Getter function for ::trop_node_charptr(). */
aPiecek61d062b2020-11-02 11:05:09 +0100771typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
772
aPiecekef1e58e2021-04-19 13:19:44 +0200773/**
774 * @brief Simple getter functions for lysp and lysc nodes.
775 *
776 * This structure is useful if we have a general algorithm
777 * (tro function) that can be used for both lysc and lysp nodes.
778 * Thanks to this structure, we prevent code redundancy.
779 * We don't have to write basically the same algorithm twice
780 * for lysp and lysc trees.
781 */
Michal Vasko6a914fb2022-01-17 10:36:14 +0100782struct tro_getters {
aPiecekef1e58e2021-04-19 13:19:44 +0200783 uint16_t (*nodetype)(const void *); /**< Get nodetype. */
784 const void *(*next)(const void *); /**< Get sibling. */
785 const void *(*parent)(const void *); /**< Get parent. */
786 const void *(*child)(const void *); /**< Get child. */
787 const void *(*actions)(const void *); /**< Get actions. */
788 const void *(*action_input)(const void *); /**< Get input action from action node. */
789 const void *(*action_output)(const void *); /**< Get output action from action node. */
790 const void *(*notifs)(const void *); /**< Get notifs. */
791};
792
aPiecek874ea4d2021-04-19 12:26:36 +0200793/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100794 * Definition of the general Trg functions
aPiecek874ea4d2021-04-19 12:26:36 +0200795 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100796
797/**
798 * @brief Print a substring but limited to the maximum length.
799 * @param[in] str is pointer to source.
800 * @param[in] len is number of characters to be printed.
801 * @param[in,out] out is output handler.
802 * @return str parameter shifted by len.
803 */
804static const char *
805trg_print_substr(const char *str, size_t len, struct ly_out *out)
806{
807 for (size_t i = 0; i < len; i++) {
808 ly_print_(out, "%c", str[0]);
809 str++;
810 }
811 return str;
812}
813
814/**
815 * @brief Pointer is not NULL and does not point to an empty string.
816 * @param[in] str is pointer to string to be checked.
817 * @return 1 if str pointing to non empty string otherwise 0.
818 */
819static ly_bool
820trg_charptr_has_data(const char *str)
821{
822 return (str) && (str[0] != '\0');
823}
824
825/**
aPiecek874ea4d2021-04-19 12:26:36 +0200826 * @brief Check if @p word in @p src is present where words are
827 * delimited by @p delim.
828 * @param[in] src is source where words are separated by @p delim.
aPiecek61d062b2020-11-02 11:05:09 +0100829 * @param[in] word to be searched.
aPiecek874ea4d2021-04-19 12:26:36 +0200830 * @param[in] delim is delimiter between @p words in @p src.
831 * @return 1 if src contains @p word otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +0100832 */
833static ly_bool
834trg_word_is_present(const char *src, const char *word, char delim)
835{
836 const char *hit;
837
838 if ((!src) || (src[0] == '\0') || (!word)) {
839 return 0;
840 }
841
842 hit = strstr(src, word);
843
844 if (hit) {
845 /* word was founded at the begin of src
846 * OR it match somewhere after delim
847 */
848 if ((hit == src) || (hit[-1] == delim)) {
849 /* end of word was founded at the end of src
850 * OR end of word was match somewhere before delim
851 */
852 char delim_or_end = (hit + strlen(word))[0];
Michal Vasko26bbb272022-08-02 14:54:33 +0200853
aPiecek61d062b2020-11-02 11:05:09 +0100854 if ((delim_or_end == '\0') || (delim_or_end == delim)) {
855 return 1;
856 }
857 }
858 /* after -> hit is just substr and it's not the whole word */
859 /* jump to the next word */
860 for ( ; (src[0] != '\0') && (src[0] != delim); src++) {}
861 /* skip delim */
862 src = src[0] == '\0' ? src : src + 1;
863 /* continue with searching */
864 return trg_word_is_present(src, word, delim);
865 } else {
866 return 0;
867 }
868}
869
aPiecek874ea4d2021-04-19 12:26:36 +0200870/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100871 * Definition of printer functions
aPiecek874ea4d2021-04-19 12:26:36 +0200872 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100873
874/**
aPiecek01598c02021-04-23 14:18:24 +0200875 * @brief Write callback for ::ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100876 *
aPiecek874ea4d2021-04-19 12:26:36 +0200877 * @param[in] user_data is type of struct ly_out_clb_arg.
aPiecek61d062b2020-11-02 11:05:09 +0100878 * @param[in] buf contains input characters
879 * @param[in] count is number of characters in buf.
880 * @return Number of printed bytes.
881 * @return Negative value in case of error.
882 */
883static ssize_t
884trp_ly_out_clb_func(void *user_data, const void *buf, size_t count)
885{
886 LY_ERR erc = LY_SUCCESS;
887 struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data;
888
889 switch (data->mode) {
890 case TRD_PRINT:
891 erc = ly_write_(data->out, buf, count);
892 break;
893 case TRD_CHAR_COUNT:
894 data->counter = data->counter + count;
895 break;
896 default:
897 break;
898 }
899
900 if (erc != LY_SUCCESS) {
901 data->last_error = erc;
902 return -1;
903 } else {
904 return count;
905 }
906}
907
908/**
909 * @brief Check that indent in node can be considered as equivalent.
910 * @param[in] first is the first indent in node.
911 * @param[in] second is the second indent in node.
912 * @return 1 if indents are equivalent otherwise 0.
913 */
914static ly_bool
915trp_indent_in_node_are_eq(struct trt_indent_in_node first, struct trt_indent_in_node second)
916{
917 const ly_bool a = first.type == second.type;
918 const ly_bool b = first.btw_name_opts == second.btw_name_opts;
919 const ly_bool c = first.btw_opts_type == second.btw_opts_type;
920 const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures;
921
922 return a && b && c && d;
923}
924
925/**
aPiecek874ea4d2021-04-19 12:26:36 +0200926 * @brief Setting space character because node is last sibling.
927 * @param[in] wr is wrapper over which the shift operation
928 * is to be performed.
aPiecek61d062b2020-11-02 11:05:09 +0100929 * @return New shifted wrapper.
930 */
931static struct trt_wrapper
932trp_wrapper_set_shift(struct trt_wrapper wr)
933{
934 assert(wr.actual_pos < 64);
935 /* +--<node>
936 * +--<node>
937 */
938 wr.actual_pos++;
939 return wr;
940}
941
942/**
aPiecek874ea4d2021-04-19 12:26:36 +0200943 * @brief Setting '|' symbol because node is divided or
944 * it is not last sibling.
aPiecek61d062b2020-11-02 11:05:09 +0100945 * @param[in] wr is source of wrapper.
946 * @return New wrapper which is marked at actual position and shifted.
947 */
948static struct trt_wrapper
949trp_wrapper_set_mark(struct trt_wrapper wr)
950{
951 assert(wr.actual_pos < 64);
952 wr.bit_marks1 |= 1U << wr.actual_pos;
953 return trp_wrapper_set_shift(wr);
954}
955
956/**
957 * @brief Setting ' ' symbol if node is last sibling otherwise set '|'.
958 * @param[in] wr is actual wrapper.
aPiecek874ea4d2021-04-19 12:26:36 +0200959 * @param[in] last_one is flag. Value 1 saying if the node is the last
960 * and has no more siblings.
aPiecek61d062b2020-11-02 11:05:09 +0100961 * @return New wrapper for the actual node.
962 */
963static struct trt_wrapper
964trp_wrapper_if_last_sibling(struct trt_wrapper wr, ly_bool last_one)
965{
966 return last_one ? trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
967}
968
969/**
970 * @brief Test if the wrappers are equivalent.
971 * @param[in] first is the first wrapper.
972 * @param[in] second is the second wrapper.
973 * @return 1 if the wrappers are equivalent otherwise 0.
974 */
975static ly_bool
976trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second)
977{
978 const ly_bool a = first.type == second.type;
979 const ly_bool b = first.bit_marks1 == second.bit_marks1;
980 const ly_bool c = first.actual_pos == second.actual_pos;
981
982 return a && b && c;
983}
984
985/**
986 * @brief Print " | " sequence on line.
987 * @param[in] wr is wrapper to be printed.
988 * @param[in,out] out is output handler.
989 */
990static void
991trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out)
992{
993 uint32_t lb;
994
995 if (wr.type == TRD_WRAPPER_TOP) {
996 lb = TRD_INDENT_LINE_BEGIN;
997 } else if (wr.type == TRD_WRAPPER_BODY) {
998 lb = TRD_INDENT_LINE_BEGIN * 2;
999 } else {
1000 lb = TRD_INDENT_LINE_BEGIN;
1001 }
1002
1003 ly_print_(out, "%*c", lb, ' ');
1004
1005 if (trp_wrapper_eq(wr, TRP_INIT_WRAPPER_TOP)) {
1006 return;
1007 }
1008
1009 for (uint32_t i = 0; i < wr.actual_pos; i++) {
1010 /** Test if the bit on the index is set. */
1011 if ((wr.bit_marks1 >> i) & 1U) {
1012 ly_print_(out, "|");
1013 } else {
1014 ly_print_(out, " ");
1015 }
1016
1017 if (i != wr.actual_pos) {
1018 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1019 }
1020 }
1021}
1022
1023/**
1024 * @brief Check if struct trt_node is empty.
1025 * @param[in] node is item to test.
1026 * @return 1 if node is considered empty otherwise 0.
1027 */
1028static ly_bool
1029trp_node_is_empty(struct trt_node node)
1030{
aPiecek41219f92022-10-26 11:24:40 +02001031 const ly_bool a = TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(node.iffeatures.type);
aPiecek61d062b2020-11-02 11:05:09 +01001032 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
1033 const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node.name);
aPiecek41219f92022-10-26 11:24:40 +02001034 const ly_bool d = node.flags == NULL;
1035 const ly_bool e = node.status == NULL;
aPiecek61d062b2020-11-02 11:05:09 +01001036
1037 return a && b && c && d && e;
1038}
1039
1040/**
aPiecek874ea4d2021-04-19 12:26:36 +02001041 * @brief Check if [\<keys\>], \<type\> and
1042 * \<iffeatures\> are empty/not_set.
aPiecek61d062b2020-11-02 11:05:09 +01001043 * @param[in] node is item to test.
aPiecek874ea4d2021-04-19 12:26:36 +02001044 * @return 1 if node has no \<keys\> \<type\> or \<iffeatures\>
1045 * otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +01001046 */
1047static ly_bool
1048trp_node_body_is_empty(struct trt_node node)
1049{
aPiecek41219f92022-10-26 11:24:40 +02001050 const ly_bool a = TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(node.iffeatures.type);
aPiecek61d062b2020-11-02 11:05:09 +01001051 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
aPiecekbca57772022-10-13 13:51:59 +02001052 const ly_bool c = !node.name.keys;
aPiecek61d062b2020-11-02 11:05:09 +01001053
1054 return a && b && c;
1055}
1056
1057/**
aPiecek61d062b2020-11-02 11:05:09 +01001058 * @brief Print entire struct trt_node_name structure.
1059 * @param[in] node_name is item to print.
1060 * @param[in,out] out is output handler.
1061 */
1062static void
1063trp_print_node_name(struct trt_node_name node_name, struct ly_out *out)
1064{
1065 const char *mod_prefix;
1066 const char *colon;
1067 const char trd_node_name_suffix_choice[] = ")";
1068 const char trd_node_name_suffix_case[] = ")";
aPiecek61d062b2020-11-02 11:05:09 +01001069
1070 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1071 return;
1072 }
1073
1074 if (node_name.module_prefix) {
1075 mod_prefix = node_name.module_prefix;
1076 colon = ":";
1077 } else {
1078 mod_prefix = "";
1079 colon = "";
1080 }
1081
1082 switch (node_name.type) {
1083 case TRD_NODE_ELSE:
1084 ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
1085 break;
1086 case TRD_NODE_CASE:
1087 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, trd_node_name_suffix_case);
1088 break;
1089 case TRD_NODE_CHOICE:
1090 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice);
1091 break;
aPiecek61d062b2020-11-02 11:05:09 +01001092 case TRD_NODE_TRIPLE_DOT:
1093 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
1094 break;
1095 default:
1096 break;
1097 }
aPiecek41219f92022-10-26 11:24:40 +02001098
aPiecek03cb4872022-10-24 10:31:51 +02001099 if (node_name.add_opts) {
1100 ly_print_(out, "%s", node_name.add_opts);
1101 }
aPiecek41219f92022-10-26 11:24:40 +02001102 if (node_name.opts) {
1103 ly_print_(out, "%s", node_name.opts);
1104 }
aPiecek61d062b2020-11-02 11:05:09 +01001105}
1106
1107/**
aPiecek874ea4d2021-04-19 12:26:36 +02001108 * @brief Check if mark (?, !, *, /, @) is implicitly contained in
1109 * struct trt_node_name.
aPiecek61d062b2020-11-02 11:05:09 +01001110 * @param[in] node_name is structure containing the 'mark'.
1111 * @return 1 if contain otherwise 0.
1112 */
1113static ly_bool
1114trp_mark_is_used(struct trt_node_name node_name)
1115{
1116 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1117 return 0;
aPiecekbca57772022-10-13 13:51:59 +02001118 } else if (node_name.keys) {
1119 return 0;
aPiecek61d062b2020-11-02 11:05:09 +01001120 }
1121
1122 switch (node_name.type) {
1123 case TRD_NODE_ELSE:
1124 case TRD_NODE_CASE:
aPiecek61d062b2020-11-02 11:05:09 +01001125 return 0;
1126 default:
aPiecek03cb4872022-10-24 10:31:51 +02001127 if (node_name.add_opts || node_name.opts) {
aPiecek41219f92022-10-26 11:24:40 +02001128 return 1;
1129 } else {
1130 return 0;
1131 }
aPiecek61d062b2020-11-02 11:05:09 +01001132 }
1133}
1134
1135/**
1136 * @brief Print opts keys.
1137 * @param[in] node_name contains type of the node with his name.
1138 * @param[in] btw_name_opts is number of spaces between name and [keys].
aPiecek874ea4d2021-04-19 12:26:36 +02001139 * @param[in] cf is basically a pointer to the function that prints
1140 * the keys.
aPiecek61d062b2020-11-02 11:05:09 +01001141 * @param[in,out] out is output handler.
1142 */
1143static void
1144trp_print_opts_keys(struct trt_node_name node_name, int16_t btw_name_opts, struct trt_cf_print cf, struct ly_out *out)
1145{
aPiecekbca57772022-10-13 13:51:59 +02001146 if (!node_name.keys) {
aPiecek61d062b2020-11-02 11:05:09 +01001147 return;
1148 }
1149
1150 /* <name><mark>___<keys>*/
1151 if (btw_name_opts > 0) {
1152 ly_print_(out, "%*c", btw_name_opts, ' ');
1153 }
1154 ly_print_(out, "[");
1155 cf.pf(cf.ctx, out);
1156 ly_print_(out, "]");
1157}
1158
1159/**
1160 * @brief Print entire struct trt_type structure.
1161 * @param[in] type is item to print.
1162 * @param[in,out] out is output handler.
1163 */
1164static void
1165trp_print_type(struct trt_type type, struct ly_out *out)
1166{
1167 if (TRP_TRT_TYPE_IS_EMPTY(type)) {
1168 return;
1169 }
1170
1171 switch (type.type) {
1172 case TRD_TYPE_NAME:
1173 ly_print_(out, "%s", type.str);
1174 break;
1175 case TRD_TYPE_TARGET:
1176 ly_print_(out, "-> %s", type.str);
1177 break;
1178 case TRD_TYPE_LEAFREF:
1179 ly_print_(out, "leafref");
1180 default:
1181 break;
1182 }
1183}
1184
1185/**
1186 * @brief Print all iffeatures of node
1187 *
aPiecek03cb4872022-10-24 10:31:51 +02001188 * @param[in] iff is iffeatures to print.
1189 * @param[in] cf is basically a pointer to the function that prints the list of features.
aPiecek61d062b2020-11-02 11:05:09 +01001190 * @param[in,out] out is output handler.
1191 */
1192static void
aPiecek41219f92022-10-26 11:24:40 +02001193trp_print_iffeatures(struct trt_iffeatures iff, struct trt_cf_print cf, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001194{
aPiecek41219f92022-10-26 11:24:40 +02001195 if (iff.type == TRD_IFF_PRESENT) {
aPiecek61d062b2020-11-02 11:05:09 +01001196 ly_print_(out, "{");
1197 cf.pf(cf.ctx, out);
1198 ly_print_(out, "}?");
aPiecek03cb4872022-10-24 10:31:51 +02001199 } else if (iff.type == TRD_IFF_OVERR) {
1200 ly_print_(out, "%s", iff.str);
aPiecek61d062b2020-11-02 11:05:09 +01001201 }
1202}
1203
1204/**
1205 * @brief Print just \<status\>--\<flags\> \<name\> with opts mark.
1206 * @param[in] node contains items to print.
1207 * @param[in] out is output handler.
1208 */
1209static void
1210trp_print_node_up_to_name(struct trt_node node, struct ly_out *out)
1211{
1212 if (node.name.type == TRD_NODE_TRIPLE_DOT) {
1213 trp_print_node_name(node.name, out);
1214 return;
1215 }
1216 /* <status>--<flags> */
aPiecek41219f92022-10-26 11:24:40 +02001217 ly_print_(out, "%s", node.status);
aPiecek61d062b2020-11-02 11:05:09 +01001218 ly_print_(out, "--");
aPiecek874ea4d2021-04-19 12:26:36 +02001219 /* If the node is a case node, there is no space before the <name>
1220 * also case node has no flags.
1221 */
aPiecek41219f92022-10-26 11:24:40 +02001222 if (node.flags && (node.name.type != TRD_NODE_CASE)) {
1223 ly_print_(out, "%s", node.flags);
aPiecek61d062b2020-11-02 11:05:09 +01001224 ly_print_(out, " ");
1225 }
1226 /* <name> */
1227 trp_print_node_name(node.name, out);
1228}
1229
1230/**
aPiecek874ea4d2021-04-19 12:26:36 +02001231 * @brief Print alignment (spaces) instead of
1232 * \<status\>--\<flags\> \<name\> for divided node.
aPiecek61d062b2020-11-02 11:05:09 +01001233 * @param[in] node contains items to print.
1234 * @param[in] out is output handler.
1235 */
1236static void
1237trp_print_divided_node_up_to_name(struct trt_node node, struct ly_out *out)
1238{
aPiecek41219f92022-10-26 11:24:40 +02001239 uint32_t space = strlen(node.flags);
aPiecek61d062b2020-11-02 11:05:09 +01001240
1241 if (node.name.type == TRD_NODE_CASE) {
1242 /* :(<name> */
1243 space += strlen(TRD_NODE_NAME_PREFIX_CASE);
1244 } else if (node.name.type == TRD_NODE_CHOICE) {
1245 /* (<name> */
1246 space += strlen(TRD_NODE_NAME_PREFIX_CHOICE);
1247 } else {
1248 /* _<name> */
1249 space += strlen(" ");
1250 }
1251
1252 /* <name>
1253 * __
1254 */
1255 space += TRD_INDENT_LONG_LINE_BREAK;
1256
1257 ly_print_(out, "%*c", space, ' ');
1258}
1259
1260/**
1261 * @brief Print struct trt_node structure.
1262 * @param[in] node is item to print.
aPiecek874ea4d2021-04-19 12:26:36 +02001263 * @param[in] pck package of functions for
1264 * printing [\<keys\>] and \<iffeatures\>.
aPiecek61d062b2020-11-02 11:05:09 +01001265 * @param[in] indent is the indent in node.
1266 * @param[in,out] out is output handler.
1267 */
1268static void
1269trp_print_node(struct trt_node node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out)
1270{
1271 ly_bool triple_dot;
1272 ly_bool divided;
1273 struct trt_cf_print cf_print_keys;
1274 struct trt_cf_print cf_print_iffeatures;
1275
1276 if (trp_node_is_empty(node)) {
1277 return;
1278 }
1279
1280 /* <status>--<flags> <name><opts> <type> <if-features> */
1281 triple_dot = node.name.type == TRD_NODE_TRIPLE_DOT;
1282 divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED;
1283
1284 if (triple_dot) {
1285 trp_print_node_name(node.name, out);
1286 return;
1287 } else if (!divided) {
1288 trp_print_node_up_to_name(node, out);
1289 } else {
1290 trp_print_divided_node_up_to_name(node, out);
1291 }
1292
1293 /* <opts> */
1294 /* <name>___<opts>*/
1295 cf_print_keys.ctx = pck.tree_ctx;
1296 cf_print_keys.pf = pck.fps.print_keys;
1297
1298 trp_print_opts_keys(node.name, indent.btw_name_opts, cf_print_keys, out);
1299
1300 /* <opts>__<type> */
1301 if (indent.btw_opts_type > 0) {
1302 ly_print_(out, "%*c", indent.btw_opts_type, ' ');
1303 }
1304
1305 /* <type> */
1306 trp_print_type(node.type, out);
1307
1308 /* <type>__<iffeatures> */
1309 if (indent.btw_type_iffeatures > 0) {
1310 ly_print_(out, "%*c", indent.btw_type_iffeatures, ' ');
1311 }
1312
1313 /* <iffeatures> */
1314 cf_print_iffeatures.ctx = pck.tree_ctx;
1315 cf_print_iffeatures.pf = pck.fps.print_features_names;
1316
1317 trp_print_iffeatures(node.iffeatures, cf_print_iffeatures, out);
1318}
1319
1320/**
aPiecek874ea4d2021-04-19 12:26:36 +02001321 * @brief Print keyword based on trt_keyword_stmt.type.
aPiecek61d062b2020-11-02 11:05:09 +01001322 * @param[in] ks is keyword statement to print.
1323 * @param[in,out] out is output handler
1324 */
1325static void
1326trt_print_keyword_stmt_begin(struct trt_keyword_stmt ks, struct ly_out *out)
1327{
aPiecek03cb4872022-10-24 10:31:51 +02001328 if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) ||
1329 !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) {
1330 ly_print_(out, "%s: ", ks.section_name);
aPiecek61d062b2020-11-02 11:05:09 +01001331 return;
aPiecek61d062b2020-11-02 11:05:09 +01001332 }
aPiecek61d062b2020-11-02 11:05:09 +01001333
aPiecek03cb4872022-10-24 10:31:51 +02001334 ly_print_(out, "%*c", TRD_INDENT_LINE_BEGIN, ' ');
1335 if (ks.argument) {
1336 ly_print_(out, "%s ", ks.section_name);
1337 } else {
1338 ly_print_(out, "%s", ks.section_name);
aPiecek61d062b2020-11-02 11:05:09 +01001339 }
1340}
1341
1342/**
aPiecek874ea4d2021-04-19 12:26:36 +02001343 * @brief Print trt_keyword_stmt.str which is string of name or path.
aPiecek61d062b2020-11-02 11:05:09 +01001344 * @param[in] ks is keyword statement structure.
1345 * @param[in] mll is max line length.
1346 * @param[in,out] out is output handler.
1347 */
1348static void
1349trt_print_keyword_stmt_str(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
1350{
1351 uint32_t ind_initial;
1352 uint32_t ind_divided;
1353 /* flag if path must be splitted to more lines */
1354 ly_bool linebreak_was_set;
1355 /* flag if at least one subpath was printed */
1356 ly_bool subpath_printed;
1357 /* the sum of the sizes of the substrings on the current line */
1358 uint32_t how_far;
1359 /* pointer to start of the subpath */
1360 const char *sub_ptr;
1361 /* size of subpath from sub_ptr */
1362 size_t sub_len;
1363
aPiecek03cb4872022-10-24 10:31:51 +02001364 if ((!ks.argument) || (ks.argument[0] == '\0')) {
aPiecek61d062b2020-11-02 11:05:09 +01001365 return;
1366 }
1367
1368 /* module name cannot be splitted */
aPiecek03cb4872022-10-24 10:31:51 +02001369 if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) || !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) {
1370 ly_print_(out, "%s", ks.argument);
aPiecek61d062b2020-11-02 11:05:09 +01001371 return;
1372 }
1373
1374 /* after -> for trd_keyword_stmt_body do */
1375
1376 /* set begin indentation */
aPiecek03cb4872022-10-24 10:31:51 +02001377 ind_initial = TRD_INDENT_LINE_BEGIN + strlen(ks.section_name) + 1;
aPiecek61d062b2020-11-02 11:05:09 +01001378 ind_divided = ind_initial + TRD_INDENT_LONG_LINE_BREAK;
1379 linebreak_was_set = 0;
1380 subpath_printed = 0;
1381 how_far = 0;
aPiecek03cb4872022-10-24 10:31:51 +02001382 sub_ptr = ks.argument;
aPiecek61d062b2020-11-02 11:05:09 +01001383 sub_len = 0;
1384
1385 while (sub_ptr[0] != '\0') {
1386 uint32_t ind;
1387 /* skip slash */
1388 const char *tmp = sub_ptr[0] == '/' ? sub_ptr + 1 : sub_ptr;
Michal Vasko26bbb272022-08-02 14:54:33 +02001389
aPiecek61d062b2020-11-02 11:05:09 +01001390 /* get position of the end of substr */
1391 tmp = strchr(tmp, '/');
1392 /* set correct size if this is a last substring */
1393 sub_len = !tmp ? strlen(sub_ptr) : (size_t)(tmp - sub_ptr);
1394 /* actualize sum of the substring's sizes on the current line */
1395 how_far += sub_len;
1396 /* correction due to colon character if it this is last substring */
1397 how_far = *(sub_ptr + sub_len) == '\0' ? how_far + 1 : how_far;
1398 /* choose indentation which depends on
1399 * whether the string is printed on multiple lines or not
1400 */
1401 ind = linebreak_was_set ? ind_divided : ind_initial;
1402 if (ind + how_far <= mll) {
1403 /* printing before max line length */
1404 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1405 subpath_printed = 1;
1406 } else {
1407 /* printing on new line */
1408 if (subpath_printed == 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001409 /* first subpath is too long
1410 * but print it at first line anyway
1411 */
aPiecek61d062b2020-11-02 11:05:09 +01001412 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1413 subpath_printed = 1;
1414 continue;
1415 }
1416 ly_print_(out, "\n");
1417 ly_print_(out, "%*c", ind_divided, ' ');
1418 linebreak_was_set = 1;
1419 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1420 how_far = sub_len;
1421 subpath_printed = 1;
1422 }
1423 }
1424}
1425
1426/**
aPiecek874ea4d2021-04-19 12:26:36 +02001427 * @brief Print separator based on trt_keyword_stmt.type
aPiecek61d062b2020-11-02 11:05:09 +01001428 * @param[in] ks is keyword statement structure.
1429 * @param[in,out] out is output handler.
1430 */
1431static void
aPiecek03cb4872022-10-24 10:31:51 +02001432trt_print_keyword_stmt_end(struct trt_keyword_stmt ks, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001433{
aPiecek03cb4872022-10-24 10:31:51 +02001434 if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) || !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) {
1435 return;
1436 } else if (ks.has_node) {
1437 ly_print_(out, ":");
aPiecek61d062b2020-11-02 11:05:09 +01001438 }
1439}
1440
1441/**
1442 * @brief Print entire struct trt_keyword_stmt structure.
1443 * @param[in] ks is item to print.
1444 * @param[in] mll is max line length.
1445 * @param[in,out] out is output handler.
1446 */
1447static void
aPiecek03cb4872022-10-24 10:31:51 +02001448trp_print_keyword_stmt(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001449{
aPiecek03cb4872022-10-24 10:31:51 +02001450 assert(ks.section_name);
aPiecek61d062b2020-11-02 11:05:09 +01001451 trt_print_keyword_stmt_begin(ks, out);
1452 trt_print_keyword_stmt_str(ks, mll, out);
aPiecek03cb4872022-10-24 10:31:51 +02001453 trt_print_keyword_stmt_end(ks, out);
aPiecek61d062b2020-11-02 11:05:09 +01001454}
1455
aPiecek874ea4d2021-04-19 12:26:36 +02001456/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01001457 * Main trp functions
aPiecek874ea4d2021-04-19 12:26:36 +02001458 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01001459
1460/**
aPiecek874ea4d2021-04-19 12:26:36 +02001461 * @brief Printing one line including wrapper and node
1462 * which can be incomplete (divided).
aPiecek61d062b2020-11-02 11:05:09 +01001463 * @param[in] node is \<node\> representation.
1464 * @param[in] pck contains special printing functions callback.
1465 * @param[in] indent contains wrapper and indent in node numbers.
1466 * @param[in,out] out is output handler.
1467 */
1468static void
1469trp_print_line(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out)
1470{
1471 trp_print_wrapper(indent.wrapper, out);
1472 trp_print_node(node, pck, indent.in_node, out);
1473}
1474
1475/**
aPiecek874ea4d2021-04-19 12:26:36 +02001476 * @brief Printing one line including wrapper and
1477 * \<status\>--\<flags\> \<name\>\<option_mark\>.
aPiecek61d062b2020-11-02 11:05:09 +01001478 * @param[in] node is \<node\> representation.
1479 * @param[in] wr is wrapper for printing indentation before node.
1480 * @param[in] out is output handler.
1481 */
1482static void
1483trp_print_line_up_to_node_name(struct trt_node node, struct trt_wrapper wr, struct ly_out *out)
1484{
1485 trp_print_wrapper(wr, out);
1486 trp_print_node_up_to_name(node, out);
1487}
1488
1489/**
aPiecek874ea4d2021-04-19 12:26:36 +02001490 * @brief Check if leafref target must be change to string 'leafref'
1491 * because his target string is too long.
aPiecek61d062b2020-11-02 11:05:09 +01001492 * @param[in] node containing leafref target.
1493 * @param[in] wr is wrapper for printing indentation before node.
1494 * @param[in] mll is max line length.
1495 * @param[in] out is output handler.
1496 * @return true if leafref must be changed to string 'leafref'.
1497 */
1498static ly_bool
1499trp_leafref_target_is_too_long(struct trt_node node, struct trt_wrapper wr, size_t mll, struct ly_out *out)
1500{
aPiecek41219f92022-10-26 11:24:40 +02001501 size_t type_len;
aPiecek61d062b2020-11-02 11:05:09 +01001502 struct ly_out_clb_arg *data;
1503
1504 if (node.type.type != TRD_TYPE_TARGET) {
1505 return 0;
1506 }
1507
1508 /* set ly_out to counting characters */
1509 data = out->method.clb.arg;
1510
1511 data->counter = 0;
1512 data->mode = TRD_CHAR_COUNT;
1513 /* count number of printed bytes */
1514 trp_print_wrapper(wr, out);
1515 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1516 trp_print_divided_node_up_to_name(node, out);
1517 data->mode = TRD_PRINT;
aPiecek41219f92022-10-26 11:24:40 +02001518 type_len = strlen(node.type.str);
aPiecek61d062b2020-11-02 11:05:09 +01001519
aPiecek41219f92022-10-26 11:24:40 +02001520 return data->counter + type_len > mll;
aPiecek61d062b2020-11-02 11:05:09 +01001521}
1522
1523/**
1524 * @brief Get default indent in node based on node values.
1525 * @param[in] node is \<node\> representation.
aPiecek874ea4d2021-04-19 12:26:36 +02001526 * @return Default indent in node assuming that the node
1527 * will not be divided.
aPiecek61d062b2020-11-02 11:05:09 +01001528 */
1529static struct trt_indent_in_node
1530trp_default_indent_in_node(struct trt_node node)
1531{
1532 struct trt_indent_in_node ret;
aPiecek03cb4872022-10-24 10:31:51 +02001533 uint32_t opts_len = 0;
aPiecek61d062b2020-11-02 11:05:09 +01001534
1535 ret.type = TRD_INDENT_IN_NODE_NORMAL;
1536
1537 /* btw_name_opts */
aPiecekbca57772022-10-13 13:51:59 +02001538 ret.btw_name_opts = node.name.keys ? TRD_INDENT_BEFORE_KEYS : 0;
aPiecek61d062b2020-11-02 11:05:09 +01001539
1540 /* btw_opts_type */
1541 if (!(TRP_TRT_TYPE_IS_EMPTY(node.type))) {
aPiecek03cb4872022-10-24 10:31:51 +02001542 if (trp_mark_is_used(node.name)) {
1543 opts_len += node.name.add_opts ? strlen(node.name.add_opts) : 0;
1544 opts_len += node.name.opts ? strlen(node.name.opts) : 0;
1545 ret.btw_opts_type = TRD_INDENT_BEFORE_TYPE > opts_len ? 1 : TRD_INDENT_BEFORE_TYPE - opts_len;
1546 } else {
1547 ret.btw_opts_type = TRD_INDENT_BEFORE_TYPE;
1548 }
aPiecek61d062b2020-11-02 11:05:09 +01001549 } else {
1550 ret.btw_opts_type = 0;
1551 }
1552
1553 /* btw_type_iffeatures */
aPiecek41219f92022-10-26 11:24:40 +02001554 ret.btw_type_iffeatures = node.iffeatures.type == TRD_IFF_PRESENT ? TRD_INDENT_BEFORE_IFFEATURES : 0;
aPiecek61d062b2020-11-02 11:05:09 +01001555
1556 return ret;
1557}
1558
1559/**
1560 * @brief Setting linebreaks in trt_indent_in_node.
1561 *
1562 * The order where the linebreak tag can be placed is from the end.
1563 *
aPiecek874ea4d2021-04-19 12:26:36 +02001564 * @param[in] indent containing alignment lengths
1565 * or already linebreak marks.
aPiecek61d062b2020-11-02 11:05:09 +01001566 * @return indent with a newly placed linebreak tag.
aPiecek874ea4d2021-04-19 12:26:36 +02001567 * @return .type set to TRD_INDENT_IN_NODE_FAILED if it is not possible
1568 * to place a more linebreaks.
aPiecek61d062b2020-11-02 11:05:09 +01001569 */
1570static struct trt_indent_in_node
1571trp_indent_in_node_place_break(struct trt_indent_in_node indent)
1572{
1573 /* somewhere must be set a line break in node */
1574 struct trt_indent_in_node ret = indent;
1575
1576 /* gradually break the node from the end */
1577 if ((indent.btw_type_iffeatures != TRD_LINEBREAK) && (indent.btw_type_iffeatures != 0)) {
1578 ret.btw_type_iffeatures = TRD_LINEBREAK;
1579 } else if ((indent.btw_opts_type != TRD_LINEBREAK) && (indent.btw_opts_type != 0)) {
1580 ret.btw_opts_type = TRD_LINEBREAK;
1581 } else if ((indent.btw_name_opts != TRD_LINEBREAK) && (indent.btw_name_opts != 0)) {
1582 /* set line break between name and opts */
1583 ret.btw_name_opts = TRD_LINEBREAK;
1584 } else {
1585 /* it is not possible to place a more line breaks,
1586 * unfortunately the max_line_length constraint is violated
1587 */
1588 ret.type = TRD_INDENT_IN_NODE_FAILED;
1589 }
1590 return ret;
1591}
1592
1593/**
1594 * @brief Get the first half of the node based on the linebreak mark.
1595 *
1596 * Items in the second half of the node will be empty.
1597 *
1598 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001599 * @param[in] indent contains information in which part of the \<node\>
1600 * the first half ends.
aPiecek61d062b2020-11-02 11:05:09 +01001601 * @return first half of the node, indent is unchanged.
1602 */
1603static struct trt_pair_indent_node
1604trp_first_half_node(struct trt_node node, struct trt_indent_in_node indent)
1605{
1606 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1607
1608 if (indent.btw_name_opts == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001609 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001610 ret.node.type = TRP_EMPTY_TRT_TYPE;
aPiecek41219f92022-10-26 11:24:40 +02001611 ret.node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001612 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1613 ret.node.type = TRP_EMPTY_TRT_TYPE;
aPiecek41219f92022-10-26 11:24:40 +02001614 ret.node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001615 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
aPiecek41219f92022-10-26 11:24:40 +02001616 ret.node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001617 }
1618
1619 return ret;
1620}
1621
1622/**
1623 * @brief Get the second half of the node based on the linebreak mark.
1624 *
1625 * Items in the first half of the node will be empty.
1626 * Indentations belonging to the first node will be reset to zero.
1627 *
1628 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001629 * @param[in] indent contains information in which part of the \<node\>
1630 * the second half starts.
aPiecek61d062b2020-11-02 11:05:09 +01001631 * @return second half of the node, indent is newly set.
1632 */
1633static struct trt_pair_indent_node
1634trp_second_half_node(struct trt_node node, struct trt_indent_in_node indent)
1635{
1636 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1637
1638 if (indent.btw_name_opts < 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001639 /* Logically, the information up to token <opts> should
1640 * be deleted, but the the trp_print_node function needs it to
1641 * create the correct indent.
aPiecek61d062b2020-11-02 11:05:09 +01001642 */
1643 ret.indent.btw_name_opts = 0;
1644 ret.indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(node.type) ? 0 : TRD_INDENT_BEFORE_TYPE;
aPiecek41219f92022-10-26 11:24:40 +02001645 ret.indent.btw_type_iffeatures = node.iffeatures.type == TRD_IFF_NON_PRESENT ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001646 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001647 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001648 ret.indent.btw_name_opts = 0;
1649 ret.indent.btw_opts_type = 0;
aPiecek41219f92022-10-26 11:24:40 +02001650 ret.indent.btw_type_iffeatures = node.iffeatures.type == TRD_IFF_NON_PRESENT ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001651 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
aPiecekbca57772022-10-13 13:51:59 +02001652 ret.node.name.type = node.name.type;
aPiecek61d062b2020-11-02 11:05:09 +01001653 ret.node.type = TRP_EMPTY_TRT_TYPE;
1654 ret.indent.btw_name_opts = 0;
1655 ret.indent.btw_opts_type = 0;
1656 ret.indent.btw_type_iffeatures = 0;
1657 }
1658 return ret;
1659}
1660
1661/**
1662 * @brief Get the correct alignment for the node.
1663 *
aPiecek874ea4d2021-04-19 12:26:36 +02001664 * This function is recursively called itself. It's like a backend
aPiecek01598c02021-04-23 14:18:24 +02001665 * function for a function ::trp_try_normal_indent_in_node().
aPiecek61d062b2020-11-02 11:05:09 +01001666 *
1667 * @param[in] node is \<node\> representation.
1668 * @param[in] pck contains speciall callback functions for printing.
1669 * @param[in] indent contains wrapper and indent in node numbers.
1670 * @param[in] mll is max line length.
1671 * @param[in,out] cnt counting number of characters to print.
1672 * @param[in,out] out is output handler.
1673 * @return pair of node and indentation numbers of that node.
1674 */
1675static struct trt_pair_indent_node
1676trp_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)
1677{
1678 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1679
1680 trp_print_line(node, pck, indent, out);
1681
1682 if (*cnt <= mll) {
1683 /* success */
1684 return ret;
1685 } else {
1686 ret.indent = trp_indent_in_node_place_break(ret.indent);
1687 if (ret.indent.type != TRD_INDENT_IN_NODE_FAILED) {
1688 /* erase information in node due to line break */
1689 ret = trp_first_half_node(node, ret.indent);
1690 /* check if line fits, recursive call */
1691 *cnt = 0;
1692 ret = trp_try_normal_indent_in_node_(ret.node, pck, TRP_INIT_PCK_INDENT(indent.wrapper, ret.indent), mll, cnt, out);
1693 /* make sure that the result will be with the status divided
1694 * or eventually with status failed */
1695 ret.indent.type = ret.indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED;
1696 }
1697 return ret;
1698 }
1699}
1700
1701/**
1702 * @brief Get the correct alignment for the node.
1703 *
1704 * @param[in] node is \<node\> representation.
1705 * @param[in] pck contains speciall callback functions for printing.
1706 * @param[in] indent contains wrapper and indent in node numbers.
1707 * @param[in] mll is max line length.
1708 * @param[in,out] out is output handler.
aPiecek874ea4d2021-04-19 12:26:36 +02001709 * @return ::TRD_INDENT_IN_NODE_DIVIDED - the node does not fit in the
1710 * line, some indent variable has negative value as a line break sign.
1711 * @return ::TRD_INDENT_IN_NODE_NORMAL - the node fits into the line,
1712 * all indent variables values has non-negative number.
1713 * @return ::TRD_INDENT_IN_NODE_FAILED - the node does not fit into the
1714 * line, all indent variables has negative or zero values,
1715 * function failed.
aPiecek61d062b2020-11-02 11:05:09 +01001716 */
1717static struct trt_pair_indent_node
1718trp_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)
1719{
1720 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1721 struct ly_out_clb_arg *data;
1722
1723 /* set ly_out to counting characters */
1724 data = out->method.clb.arg;
1725
1726 data->counter = 0;
1727 data->mode = TRD_CHAR_COUNT;
1728 ret = trp_try_normal_indent_in_node_(node, pck, indent, mll, &data->counter, out);
1729 data->mode = TRD_PRINT;
1730
1731 return ret;
1732}
1733
1734/**
aPiecek01598c02021-04-23 14:18:24 +02001735 * @brief Auxiliary function for ::trp_print_entire_node()
aPiecek874ea4d2021-04-19 12:26:36 +02001736 * that prints split nodes.
aPiecek61d062b2020-11-02 11:05:09 +01001737 * @param[in] node is node representation.
1738 * @param[in] ppck contains speciall callback functions for printing.
1739 * @param[in] ipck contains wrapper and indent in node numbers.
1740 * @param[in] mll is max line length.
1741 * @param[in,out] out is output handler.
1742 */
1743static void
1744trp_print_divided_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1745{
1746 ly_bool entire_node_was_printed;
1747 struct trt_pair_indent_node ind_node = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1748
1749 if (ind_node.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1750 /* nothing can be done, continue as usual */
1751 ind_node.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1752 }
1753
1754 trp_print_line(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), out);
1755 entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, ind_node.indent);
1756
1757 if (!entire_node_was_printed) {
1758 ly_print_(out, "\n");
1759 /* continue with second half node */
1760 ind_node = trp_second_half_node(node, ind_node.indent);
1761 /* continue with printing node */
1762 trp_print_divided_node(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), mll, out);
1763 } else {
1764 return;
1765 }
1766}
1767
1768/**
aPiecek874ea4d2021-04-19 12:26:36 +02001769 * @brief Printing of the wrapper and the whole node,
1770 * which can be divided into several lines.
aPiecek61d062b2020-11-02 11:05:09 +01001771 * @param[in] node is node representation.
1772 * @param[in] ppck contains speciall callback functions for printing.
1773 * @param[in] ipck contains wrapper and indent in node numbers.
1774 * @param[in] mll is max line length.
1775 * @param[in,out] out is output handler.
1776 */
1777static void
1778trp_print_entire_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1779{
1780 struct trt_pair_indent_node ind_node1;
1781 struct trt_pair_indent_node ind_node2;
1782 struct trt_pck_indent tmp;
1783
1784 if (trp_leafref_target_is_too_long(node, ipck.wrapper, mll, out)) {
1785 node.type.type = TRD_TYPE_LEAFREF;
1786 }
1787
1788 /* check if normal indent is possible */
1789 ind_node1 = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1790
1791 if (ind_node1.indent.type == TRD_INDENT_IN_NODE_NORMAL) {
1792 /* node fits to one line */
1793 trp_print_line(node, ppck, ipck, out);
1794 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_DIVIDED) {
1795 /* node will be divided */
1796 /* print first half */
1797 tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node1.indent);
1798 /* pretend that this is normal node */
1799 tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL;
1800
1801 trp_print_line(ind_node1.node, ppck, tmp, out);
1802 ly_print_(out, "\n");
1803
1804 /* continue with second half on new line */
1805 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1806 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1807
1808 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1809 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1810 /* node name is too long */
1811 trp_print_line_up_to_node_name(node, ipck.wrapper, out);
1812
1813 if (trp_node_body_is_empty(node)) {
1814 return;
1815 } else {
1816 ly_print_(out, "\n");
1817
1818 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1819 ind_node2.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1820 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1821
1822 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1823 }
1824
1825 }
1826}
1827
aPiecek03cb4872022-10-24 10:31:51 +02001828/**
1829 * @brief Check if parent-stmt is valid for printing extensinon.
1830 *
1831 * @param[in] lysc_tree flag if ext is from compiled tree.
1832 * @param[in] ext Extension to check.
1833 * @return 1 if extension is valid.
1834 */
1835static ly_bool
1836trp_ext_parent_is_valid(ly_bool lysc_tree, void *ext)
1837{
1838 enum ly_stmt parent_stmt;
1839
1840 if (lysc_tree) {
1841 parent_stmt = ((struct lysc_ext_instance *)ext)->parent_stmt;
1842 } else {
1843 parent_stmt = ((struct lysp_ext_instance *)ext)->parent_stmt;
1844 }
1845 if ((parent_stmt & LY_STMT_OP_MASK) || (parent_stmt & LY_STMT_DATA_NODE_MASK) ||
1846 (parent_stmt & LY_STMT_SUBMODULE) || parent_stmt & LY_STMT_MODULE) {
1847 return 1;
1848 } else {
1849 return 0;
1850 }
1851}
1852
1853/**
1854 * @brief Check if printer_tree can use node extension.
1855 *
1856 * @param[in] lysc_tree Flag if @p node is compiled.
1857 * @param[in] node to check. Its type is lysc_node or lysp_node.
1858 * @return Pointer to extension instance which printer_tree can used.
1859 */
1860static void *
1861trp_ext_is_present(ly_bool lysc_tree, const void *node)
1862{
1863 const struct lysp_node *pn;
1864 const struct lysc_node *cn;
1865 LY_ARRAY_COUNT_TYPE i;
1866 void *ret = NULL;
1867
1868 if (!node) {
1869 return NULL;
1870 }
1871
1872 if (lysc_tree) {
1873 cn = (const struct lysc_node *)node;
1874 LY_ARRAY_FOR(cn->exts, i) {
1875 if (!(cn->exts && cn->exts->def->plugin && cn->exts->def->plugin->printer_ctree)) {
1876 continue;
1877 }
1878 if (!trp_ext_parent_is_valid(1, &cn->exts[i])) {
1879 continue;
1880 }
1881 ret = &cn->exts[i];
1882 break;
1883 }
1884 } else {
1885 pn = (const struct lysp_node *)node;
1886 LY_ARRAY_FOR(pn->exts, i) {
1887 if (!(pn->exts && pn->exts->record->plugin.printer_ptree)) {
1888 continue;
1889 }
1890 if (!trp_ext_parent_is_valid(0, &pn->exts[i])) {
1891 continue;
1892 }
1893 ret = &pn->exts[i];
1894 break;
1895 }
1896 }
1897
1898 return ret;
1899}
1900
1901/**
1902 * @brief Check if printer_tree can use node extension.
1903 *
1904 * @param[in] tc Context with current node.
1905 * @return 1 if some extension for printer_tree is valid.
1906 */
1907static ly_bool
1908trp_ext_is_present_in_node(struct trt_tree_ctx *tc)
1909{
1910 if (tc->lysc_tree && trp_ext_is_present(tc->lysc_tree, tc->cn)) {
1911 return 1;
1912 } else if (trp_ext_is_present(tc->lysc_tree, tc->pn)) {
1913 return 1;
1914 }
1915
1916 return 0;
1917}
1918
1919/**
1920 * @brief Release allocated memory and set pointers to NULL.
1921 *
1922 * @param[in,out] overr is override structure to release.
1923 * @param[out] filtered is flag to reset.
1924 */
1925static void
1926trp_ext_free_node_override(struct lyplg_ext_sprinter_tree_node_override *overr, ly_bool *filtered)
1927{
1928 *filtered = 0;
1929 overr->flags = NULL;
1930 overr->add_opts = NULL;
1931}
1932
1933/**
1934 * @brief Release private plugin data.
1935 *
1936 * @param[in,out] plug_ctx is plugin context.
1937 */
1938static void
1939trp_ext_free_plugin_ctx(struct lyspr_tree_ctx *plug_ctx)
1940{
1941 LY_ARRAY_FREE(plug_ctx->schemas);
1942 if (plug_ctx->free_plugin_priv) {
1943 plug_ctx->free_plugin_priv(plug_ctx->plugin_priv);
1944 }
1945}
1946
aPiecek874ea4d2021-04-19 12:26:36 +02001947/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02001948 * trop and troc getters
aPiecekef1e58e2021-04-19 13:19:44 +02001949 *********************************************************************/
1950
1951/**
1952 * @brief Get nodetype.
1953 * @param[in] node is any lysp_node.
1954 */
1955static uint16_t
1956trop_nodetype(const void *node)
1957{
1958 return ((const struct lysp_node *)node)->nodetype;
1959}
1960
1961/**
1962 * @brief Get sibling.
1963 * @param[in] node is any lysp_node.
1964 */
1965static const void *
1966trop_next(const void *node)
1967{
1968 return ((const struct lysp_node *)node)->next;
1969}
1970
1971/**
1972 * @brief Get parent.
1973 * @param[in] node is any lysp_node.
1974 */
1975static const void *
1976trop_parent(const void *node)
1977{
1978 return ((const struct lysp_node *)node)->parent;
1979}
1980
1981/**
1982 * @brief Try to get child.
1983 * @param[in] node is any lysp_node.
1984 */
1985static const void *
1986trop_child(const void *node)
1987{
1988 return lysp_node_child(node);
1989}
1990
1991/**
1992 * @brief Try to get action.
1993 * @param[in] node is any lysp_node.
1994 */
1995static const void *
1996trop_actions(const void *node)
1997{
1998 return lysp_node_actions(node);
1999}
2000
2001/**
2002 * @brief Try to get action.
2003 * @param[in] node must be of type lysp_node_action.
2004 */
2005static const void *
2006trop_action_input(const void *node)
2007{
2008 return &((const struct lysp_node_action *)node)->input;
2009}
2010
2011/**
2012 * @brief Try to get action.
2013 * @param[in] node must be of type lysp_node_action.
2014 */
2015static const void *
2016trop_action_output(const void *node)
2017{
2018 return &((const struct lysp_node_action *)node)->output;
2019}
2020
2021/**
2022 * @brief Try to get action.
2023 * @param[in] node is any lysp_node.
2024 */
2025static const void *
2026trop_notifs(const void *node)
2027{
2028 return lysp_node_notifs(node);
2029}
2030
2031/**
aPiecek01598c02021-04-23 14:18:24 +02002032 * @brief Fill struct tro_getters with @ref TRP_trop getters
aPiecekef1e58e2021-04-19 13:19:44 +02002033 * which are adapted to lysp nodes.
2034 */
2035static struct tro_getters
Michal Vasko45acb842022-11-08 09:23:17 +01002036trop_init_getters(void)
aPiecekef1e58e2021-04-19 13:19:44 +02002037{
2038 return (struct tro_getters) {
2039 .nodetype = trop_nodetype,
2040 .next = trop_next,
2041 .parent = trop_parent,
2042 .child = trop_child,
2043 .actions = trop_actions,
2044 .action_input = trop_action_input,
2045 .action_output = trop_action_output,
2046 .notifs = trop_notifs
2047 };
2048}
2049
aPiecek3f247652021-04-19 13:40:25 +02002050/**
2051 * @brief Get nodetype.
2052 * @param[in] node is any lysc_node.
2053 */
2054static uint16_t
2055troc_nodetype(const void *node)
2056{
2057 return ((const struct lysc_node *)node)->nodetype;
2058}
2059
2060/**
2061 * @brief Get sibling.
2062 * @param[in] node is any lysc_node.
2063 */
2064static const void *
2065troc_next(const void *node)
2066{
2067 return ((const struct lysc_node *)node)->next;
2068}
2069
2070/**
2071 * @brief Get parent.
2072 * @param[in] node is any lysc_node.
2073 */
2074static const void *
2075troc_parent(const void *node)
2076{
2077 return ((const struct lysc_node *)node)->parent;
2078}
2079
2080/**
2081 * @brief Try to get child.
2082 * @param[in] node is any lysc_node.
2083 */
2084static const void *
2085troc_child(const void *node)
2086{
2087 return lysc_node_child(node);
2088}
2089
2090/**
2091 * @brief Try to get action.
2092 * @param[in] node is any lysc_node.
2093 */
2094static const void *
2095troc_actions(const void *node)
2096{
2097 return lysc_node_actions(node);
2098}
2099
2100/**
2101 * @brief Try to get action.
2102 * @param[in] node must be of type lysc_node_action.
2103 */
2104static const void *
2105troc_action_input(const void *node)
2106{
2107 return &((const struct lysc_node_action *)node)->input;
2108}
2109
2110/**
2111 * @brief Try to get action.
2112 * @param[in] node must be of type lysc_node_action.
2113 */
2114static const void *
2115troc_action_output(const void *node)
2116{
2117 return &((const struct lysc_node_action *)node)->output;
2118}
2119
2120/**
2121 * @brief Try to get action.
2122 * @param[in] node is any lysc_node.
2123 */
2124static const void *
2125troc_notifs(const void *node)
2126{
2127 return lysc_node_notifs(node);
2128}
2129
2130/**
aPiecek01598c02021-04-23 14:18:24 +02002131 * @brief Fill struct tro_getters with @ref TRP_troc getters
aPiecek3f247652021-04-19 13:40:25 +02002132 * which are adapted to lysc nodes.
2133 */
2134static struct tro_getters
Michal Vasko45acb842022-11-08 09:23:17 +01002135troc_init_getters(void)
aPiecek3f247652021-04-19 13:40:25 +02002136{
2137 return (struct tro_getters) {
2138 .nodetype = troc_nodetype,
2139 .next = troc_next,
2140 .parent = troc_parent,
2141 .child = troc_child,
2142 .actions = troc_actions,
2143 .action_input = troc_action_input,
2144 .action_output = troc_action_output,
2145 .notifs = troc_notifs
2146 };
2147}
2148
aPiecekef1e58e2021-04-19 13:19:44 +02002149/**********************************************************************
2150 * tro functions
2151 *********************************************************************/
2152
2153/**
aPiecek03cb4872022-10-24 10:31:51 +02002154 * @brief Call override function for @p node.
2155 *
2156 * @param[in] lysc_tree if @p node is compiled.
2157 * @param[in] node to create override.
2158 * @param[in] erase_node_overr if override structure must be reseted.
2159 * @param[in,out] plc current plugin context.
2160 * @return pointer to override structure or NULL. Override structure in @p plc is updated too.
2161 */
2162static struct lyplg_ext_sprinter_tree_node_override *
2163tro_set_node_overr(ly_bool lysc_tree, const void *node, ly_bool erase_node_overr, struct trt_plugin_ctx *plc)
2164{
2165 LY_ERR rc = LY_SUCCESS;
2166 struct lyplg_ext_sprinter_tree_node_override *no;
2167 struct lyspr_tree_ctx *plug_ctx;
2168 struct lysc_ext_instance *ce;
2169 struct lysp_ext_instance *pe;
2170
2171 if (erase_node_overr) {
2172 trp_ext_free_node_override(&plc->node_overr, &plc->filtered);
2173 }
2174 no = &plc->node_overr;
2175 if (!plc->ctx && lysc_tree && (ce = trp_ext_is_present(lysc_tree, node))) {
2176 rc = ce->def->plugin->printer_ctree(ce, NULL, &no->flags, &no->add_opts);
2177 } else if (!plc->ctx && (pe = trp_ext_is_present(lysc_tree, node))) {
2178 rc = pe->record->plugin.printer_ptree(pe, NULL, &no->flags, &no->add_opts);
2179 } else if (plc->ctx) {
2180 if (plc->schema && plc->schema->compiled && plc->schema->cn_overr) {
2181 rc = plc->schema->cn_overr(node, plc->ctx->plugin_priv, &plc->filtered, &no->flags, &no->add_opts);
2182 } else if (plc->schema && plc->schema->pn_overr) {
2183 rc = plc->schema->pn_overr(node, plc->ctx->plugin_priv, &plc->filtered, &no->flags, &no->add_opts);
2184 } else {
2185 no = NULL;
2186 }
2187 if (trp_ext_is_present(lysc_tree, node)) {
2188 plug_ctx = plc->ctx;
2189 plc->ctx = NULL;
2190 tro_set_node_overr(lysc_tree, node, 0, plc);
2191 plc->ctx = plug_ctx;
2192 }
2193 } else {
2194 no = NULL;
2195 }
2196
2197 if (rc) {
2198 plc->last_error = rc;
2199 no = NULL;
2200 }
2201
2202 return no;
2203}
2204
2205/**
aPiecekef1e58e2021-04-19 13:19:44 +02002206 * @brief Get next sibling of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002207 *
2208 * This is a general algorithm that is able to
2209 * work with lysp_node or lysc_node.
2210 *
2211 * @param[in] node points to lysp_node or lysc_node.
aPiecek03cb4872022-10-24 10:31:51 +02002212 * @param[in] tc current tree context.
2213 * @return next sibling node.
aPiecekef1e58e2021-04-19 13:19:44 +02002214 */
2215static const void *
aPiecek03cb4872022-10-24 10:31:51 +02002216tro_next_sibling(const void *node, const struct trt_tree_ctx *tc)
aPiecekef1e58e2021-04-19 13:19:44 +02002217{
2218 struct tro_getters get;
aPiecek03cb4872022-10-24 10:31:51 +02002219 struct trt_plugin_ctx plugin_ctx;
2220 const void *tmp, *parent, *sibl;
aPiecekef1e58e2021-04-19 13:19:44 +02002221
2222 assert(node);
2223
aPiecek03cb4872022-10-24 10:31:51 +02002224 get = tc->lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002225
2226 if (get.nodetype(node) & (LYS_RPC | LYS_ACTION)) {
2227 if ((tmp = get.next(node))) {
2228 /* next action exists */
aPiecek03cb4872022-10-24 10:31:51 +02002229 sibl = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002230 } else if ((parent = get.parent(node))) {
2231 /* maybe if notif exists as sibling */
aPiecek03cb4872022-10-24 10:31:51 +02002232 sibl = get.notifs(parent);
aPiecekef1e58e2021-04-19 13:19:44 +02002233 } else {
aPiecek03cb4872022-10-24 10:31:51 +02002234 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002235 }
2236 } else if (get.nodetype(node) & LYS_INPUT) {
2237 if ((parent = get.parent(node))) {
2238 /* if output action has data */
2239 if (get.child(get.action_output(parent))) {
2240 /* then next sibling is output action */
aPiecek03cb4872022-10-24 10:31:51 +02002241 sibl = get.action_output(parent);
aPiecekef1e58e2021-04-19 13:19:44 +02002242 } else {
2243 /* input action cannot have siblings other
2244 * than output action.
2245 */
aPiecek03cb4872022-10-24 10:31:51 +02002246 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002247 }
2248 } else {
2249 /* there is no way how to get output action */
aPiecek03cb4872022-10-24 10:31:51 +02002250 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002251 }
2252 } else if (get.nodetype(node) & LYS_OUTPUT) {
2253 /* output action cannot have siblings */
aPiecek03cb4872022-10-24 10:31:51 +02002254 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002255 } else if (get.nodetype(node) & LYS_NOTIF) {
2256 /* must have as a sibling only notif */
aPiecek03cb4872022-10-24 10:31:51 +02002257 sibl = get.next(node);
aPiecekef1e58e2021-04-19 13:19:44 +02002258 } else {
2259 /* for rest of nodes */
2260 if ((tmp = get.next(node))) {
2261 /* some sibling exists */
aPiecek03cb4872022-10-24 10:31:51 +02002262 sibl = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002263 } else if ((parent = get.parent(node))) {
2264 /* Action and notif are siblings too.
2265 * They can be reached through parent.
2266 */
2267 if ((tmp = get.actions(parent))) {
2268 /* next sibling is action */
aPiecek03cb4872022-10-24 10:31:51 +02002269 sibl = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002270 } else if ((tmp = get.notifs(parent))) {
2271 /* next sibling is notif */
aPiecek03cb4872022-10-24 10:31:51 +02002272 sibl = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002273 } else {
2274 /* sibling not exists */
aPiecek03cb4872022-10-24 10:31:51 +02002275 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002276 }
2277 } else {
2278 /* sibling not exists */
aPiecek03cb4872022-10-24 10:31:51 +02002279 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002280 }
2281 }
2282
aPiecek03cb4872022-10-24 10:31:51 +02002283 plugin_ctx = tc->plugin_ctx;
2284 if (sibl && tro_set_node_overr(tc->lysc_tree, sibl, 1, &plugin_ctx) && plugin_ctx.filtered) {
2285 return tro_next_sibling(sibl, tc);
2286 }
2287
2288 return sibl;
aPiecekef1e58e2021-04-19 13:19:44 +02002289}
2290
2291/**
2292 * @brief Get child of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002293 *
2294 * This is a general algorithm that is able to
2295 * work with lysp_node or lysc_node.
2296 *
2297 * @param[in] node points to lysp_node or lysc_node.
aPiecek03cb4872022-10-24 10:31:51 +02002298 * @param[in] tc current tree context.
2299 * @return child node.
aPiecekef1e58e2021-04-19 13:19:44 +02002300 */
2301static const void *
aPiecek03cb4872022-10-24 10:31:51 +02002302tro_next_child(const void *node, const struct trt_tree_ctx *tc)
aPiecekef1e58e2021-04-19 13:19:44 +02002303{
2304 struct tro_getters get;
aPiecek03cb4872022-10-24 10:31:51 +02002305 struct trt_plugin_ctx plugin_ctx;
2306 const void *tmp, *child;
aPiecekef1e58e2021-04-19 13:19:44 +02002307
2308 assert(node);
2309
aPiecek03cb4872022-10-24 10:31:51 +02002310 get = tc->lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002311
2312 if (get.nodetype(node) & (LYS_ACTION | LYS_RPC)) {
2313 if (get.child(get.action_input(node))) {
2314 /* go to LYS_INPUT */
aPiecek03cb4872022-10-24 10:31:51 +02002315 child = get.action_input(node);
aPiecekef1e58e2021-04-19 13:19:44 +02002316 } else if (get.child(get.action_output(node))) {
2317 /* go to LYS_OUTPUT */
aPiecek03cb4872022-10-24 10:31:51 +02002318 child = get.action_output(node);
aPiecekef1e58e2021-04-19 13:19:44 +02002319 } else {
2320 /* input action and output action have no data */
aPiecek03cb4872022-10-24 10:31:51 +02002321 child = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002322 }
2323 } else {
2324 if ((tmp = get.child(node))) {
aPiecek03cb4872022-10-24 10:31:51 +02002325 child = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002326 } else {
2327 /* current node can't have children or has no children */
2328 /* but maybe has some actions or notifs */
2329 if ((tmp = get.actions(node))) {
aPiecek03cb4872022-10-24 10:31:51 +02002330 child = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002331 } else if ((tmp = get.notifs(node))) {
aPiecek03cb4872022-10-24 10:31:51 +02002332 child = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002333 } else {
aPiecek03cb4872022-10-24 10:31:51 +02002334 child = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002335 }
2336 }
2337 }
2338
aPiecek03cb4872022-10-24 10:31:51 +02002339 plugin_ctx = tc->plugin_ctx;
2340 if (child && tro_set_node_overr(tc->lysc_tree, child, 1, &plugin_ctx) && plugin_ctx.filtered) {
2341 return tro_next_sibling(child, tc);
2342 }
2343
2344 return child;
aPiecekef1e58e2021-04-19 13:19:44 +02002345}
2346
2347/**
aPiecek3f247652021-04-19 13:40:25 +02002348 * @brief Get new trt_parent_cache if we apply the transfer
2349 * to the child node in the tree.
2350 * @param[in] ca is parent cache for current node.
2351 * @param[in] tc contains current tree node.
2352 * @return Cache for the current node.
2353 */
2354static struct trt_parent_cache
2355tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2356{
2357 struct trt_parent_cache ret = TRP_EMPTY_PARENT_CACHE;
2358
2359 if (!tc->lysc_tree) {
2360 const struct lysp_node *pn = tc->pn;
2361
2362 ret.ancestor =
2363 pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT :
2364 pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT :
2365 pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF :
2366 ca.ancestor;
2367
2368 ret.lys_status =
2369 pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
2370 ca.lys_status;
2371
2372 ret.lys_config =
2373 ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because <flags> will be -w */
2374 ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
2375 pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
2376 ca.lys_config;
2377
2378 ret.last_list =
2379 pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
2380 ca.last_list;
2381 }
2382
2383 return ret;
2384}
2385
2386/**
aPiecekef1e58e2021-04-19 13:19:44 +02002387 * @brief Transformation of the Schema nodes flags to
2388 * Tree diagram \<status\>.
2389 * @param[in] flags is node's flags obtained from the tree.
2390 */
aPiecek41219f92022-10-26 11:24:40 +02002391static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002392tro_flags2status(uint16_t flags)
2393{
aPiecek41219f92022-10-26 11:24:40 +02002394 return flags & LYS_STATUS_OBSLT ? "o" :
2395 flags & LYS_STATUS_DEPRC ? "x" :
2396 "+";
aPiecekef1e58e2021-04-19 13:19:44 +02002397}
2398
2399/**
2400 * @brief Transformation of the Schema nodes flags to Tree diagram
2401 * \<flags\> but more specifically 'ro' or 'rw'.
2402 * @param[in] flags is node's flags obtained from the tree.
2403 */
aPiecek41219f92022-10-26 11:24:40 +02002404static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002405tro_flags2config(uint16_t flags)
2406{
2407 return flags & LYS_CONFIG_R ? TRD_FLAGS_TYPE_RO :
2408 flags & LYS_CONFIG_W ? TRD_FLAGS_TYPE_RW :
2409 TRD_FLAGS_TYPE_EMPTY;
2410}
2411
2412/**
aPiecek3f247652021-04-19 13:40:25 +02002413 * @brief Print current node's iffeatures.
2414 * @param[in] tc is tree context.
2415 * @param[in,out] out is output handler.
2416 */
2417static void
2418tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out)
2419{
2420 const struct lysp_qname *iffs;
2421
aPiecekbbc02932021-05-21 07:19:41 +02002422 if (tc->lysc_tree) {
2423 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2424 iffs = TRP_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures;
2425 } else {
2426 iffs = tc->pn->iffeatures;
2427 }
aPiecek3f247652021-04-19 13:40:25 +02002428 LY_ARRAY_COUNT_TYPE i;
2429
2430 LY_ARRAY_FOR(iffs, i) {
2431 if (i == 0) {
2432 ly_print_(out, "%s", iffs[i].str);
2433 } else {
2434 ly_print_(out, ",%s", iffs[i].str);
2435 }
2436 }
2437
2438}
2439
2440/**
2441 * @brief Print current list's keys.
2442 *
2443 * Well, actually printing keys in the lysp_tree is trivial,
2444 * because char* points to all keys. However, special functions have
2445 * been reserved for this, because in principle the list of elements
2446 * can have more implementations.
2447 *
2448 * @param[in] tc is tree context.
2449 * @param[in,out] out is output handler.
2450 */
2451static void
2452tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out)
2453{
2454 const struct lysp_node_list *list;
2455
aPiecekbbc02932021-05-21 07:19:41 +02002456 if (tc->lysc_tree) {
2457 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2458 list = (const struct lysp_node_list *)TRP_TREE_CTX_GET_LYSP_NODE(tc->cn);
2459 } else {
2460 list = (const struct lysp_node_list *)tc->pn;
2461 }
aPiecek3f247652021-04-19 13:40:25 +02002462 assert(list->nodetype & LYS_LIST);
2463
2464 if (trg_charptr_has_data(list->key)) {
2465 ly_print_(out, "%s", list->key);
2466 }
2467}
2468
2469/**
aPiecek03cb4872022-10-24 10:31:51 +02002470 * @brief Get address of the current node.
2471 * @param[in] tc contains current node.
2472 * @return Address of lysc_node or lysp_node, or NULL.
2473 */
2474static const void *
2475tro_tree_ctx_get_node(const struct trt_tree_ctx *tc)
2476{
2477 return tc->lysc_tree ?
2478 (const void *)tc->cn :
2479 (const void *)tc->pn;
2480}
2481
2482/**
2483 * @brief Get address of current node's child.
2484 * @param[in,out] tc contains current node.
2485 */
2486static const void *
2487tro_tree_ctx_get_child(const struct trt_tree_ctx *tc)
2488{
2489 if (!tro_tree_ctx_get_node(tc)) {
2490 return NULL;
2491 }
2492
2493 if (tc->lysc_tree) {
2494 return lysc_node_child(tc->cn);
2495 } else {
2496 return lysp_node_child(tc->pn);
2497 }
2498}
2499
2500/**
aPiecek3f247652021-04-19 13:40:25 +02002501 * @brief Get rpcs section if exists.
2502 * @param[in,out] tc is tree context.
2503 * @return Section representation if it exists. The @p tc is modified
2504 * and his pointer points to the first node in rpcs section.
2505 * @return Empty section representation otherwise.
2506 */
2507static struct trt_keyword_stmt
2508tro_modi_get_rpcs(struct trt_tree_ctx *tc)
2509{
aPiecek9f792e52021-04-21 08:33:56 +02002510 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002511 const void *actions;
aPiecek03cb4872022-10-24 10:31:51 +02002512 struct trt_keyword_stmt ret = {0};
aPiecek3f247652021-04-19 13:40:25 +02002513
2514 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002515 actions = tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002516 if (actions) {
2517 tc->cn = actions;
2518 }
2519 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002520 actions = tc->pmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002521 if (actions) {
2522 tc->pn = actions;
2523 tc->tpn = tc->pn;
2524 }
2525 }
2526
2527 if (actions) {
2528 tc->section = TRD_SECT_RPCS;
aPiecek03cb4872022-10-24 10:31:51 +02002529 ret.section_name = TRD_KEYWORD_RPC;
2530 ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0;
aPiecek3f247652021-04-19 13:40:25 +02002531 }
aPiecek03cb4872022-10-24 10:31:51 +02002532
2533 return ret;
aPiecek3f247652021-04-19 13:40:25 +02002534}
2535
2536/**
2537 * @brief Get notification section if exists
2538 * @param[in,out] tc is tree context.
2539 * @return Section representation if it exists.
2540 * The @p tc is modified and his pointer points to the
2541 * first node in notification section.
2542 * @return Empty section representation otherwise.
2543 */
2544static struct trt_keyword_stmt
2545tro_modi_get_notifications(struct trt_tree_ctx *tc)
2546{
aPiecek9f792e52021-04-21 08:33:56 +02002547 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002548 const void *notifs;
aPiecek03cb4872022-10-24 10:31:51 +02002549 struct trt_keyword_stmt ret = {0};
aPiecek3f247652021-04-19 13:40:25 +02002550
2551 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002552 notifs = tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002553 if (notifs) {
2554 tc->cn = notifs;
2555 }
2556 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002557 notifs = tc->pmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002558 if (notifs) {
2559 tc->pn = notifs;
2560 tc->tpn = tc->pn;
2561 }
2562 }
2563
2564 if (notifs) {
2565 tc->section = TRD_SECT_NOTIF;
aPiecek03cb4872022-10-24 10:31:51 +02002566 ret.section_name = TRD_KEYWORD_NOTIF;
2567 ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0;
aPiecek3f247652021-04-19 13:40:25 +02002568 }
aPiecek03cb4872022-10-24 10:31:51 +02002569
2570 return ret;
aPiecek3f247652021-04-19 13:40:25 +02002571}
2572
aPiecekef1e58e2021-04-19 13:19:44 +02002573static struct trt_keyword_stmt
aPiecek03cb4872022-10-24 10:31:51 +02002574tro_get_ext_section(struct trt_tree_ctx *tc, void *ext, struct lyspr_tree_ctx *plug_ctx)
aPiecekef1e58e2021-04-19 13:19:44 +02002575{
aPiecek03cb4872022-10-24 10:31:51 +02002576 struct trt_keyword_stmt ret = {0};
2577 struct lysc_ext_instance *ce = NULL;
2578 struct lysp_ext_instance *pe = NULL;
aPiecek96baa7f2021-04-23 12:32:00 +02002579
2580 if (tc->lysc_tree) {
aPiecek03cb4872022-10-24 10:31:51 +02002581 ce = ext;
2582 ret.section_name = ce->def->name;
2583 ret.argument = ce->argument;
2584 ret.has_node = plug_ctx->schemas->ctree ? 1 : 0;
aPiecek96baa7f2021-04-23 12:32:00 +02002585 } else {
aPiecek03cb4872022-10-24 10:31:51 +02002586 pe = ext;
2587 ret.section_name = pe->def->name;
2588 ret.argument = pe->argument;
2589 ret.has_node = plug_ctx->schemas->ptree ? 1 : 0;
aPiecek96baa7f2021-04-23 12:32:00 +02002590 }
2591
aPiecek03cb4872022-10-24 10:31:51 +02002592 return ret;
aPiecekef1e58e2021-04-19 13:19:44 +02002593}
2594
2595/**
2596 * @brief Get name of the module.
2597 * @param[in] tc is context of the tree.
2598 */
2599static struct trt_keyword_stmt
2600tro_read_module_name(const struct trt_tree_ctx *tc)
2601{
aPiecek9f792e52021-04-21 08:33:56 +02002602 assert(tc);
aPiecek9f792e52021-04-21 08:33:56 +02002603 struct trt_keyword_stmt ret;
2604
aPiecek03cb4872022-10-24 10:31:51 +02002605 ret.section_name = !tc->lysc_tree && tc->pmod->is_submod ?
aPiecek9f792e52021-04-21 08:33:56 +02002606 TRD_KEYWORD_SUBMODULE :
2607 TRD_KEYWORD_MODULE;
2608
aPiecek03cb4872022-10-24 10:31:51 +02002609 ret.argument = !tc->lysc_tree ?
aPiecek9f792e52021-04-21 08:33:56 +02002610 LYSP_MODULE_NAME(tc->pmod) :
2611 tc->cmod->mod->name;
2612
aPiecek03cb4872022-10-24 10:31:51 +02002613 ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0;
2614
aPiecek9f792e52021-04-21 08:33:56 +02002615 return ret;
aPiecekef1e58e2021-04-19 13:19:44 +02002616}
2617
aPiecek03cb4872022-10-24 10:31:51 +02002618static ly_bool
2619tro_read_if_sibling_exists(const struct trt_tree_ctx *tc)
2620{
2621 const void *parent;
2622
2623 if (tc->lysc_tree) {
2624 parent = troc_parent(tc->cn);
2625 } else {
2626 parent = trop_parent(tc->pn);
2627 }
2628
2629 return parent ? 1 : 0;
2630}
2631
aPiecekb8d5a0a2021-05-20 08:20:24 +02002632/**
2633 * @brief Create implicit "case" node as parent of @p node.
2634 * @param[in] node child of implicit case node.
2635 * @return The case node ready to print.
2636 */
2637static struct trt_node
2638tro_create_implicit_case_node(struct trt_node node)
2639{
2640 struct trt_node ret;
2641
2642 ret.status = node.status;
2643 ret.flags = TRD_FLAGS_TYPE_EMPTY;
2644 ret.name.type = TRD_NODE_CASE;
aPiecekbca57772022-10-13 13:51:59 +02002645 ret.name.keys = node.name.keys;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002646 ret.name.module_prefix = node.name.module_prefix;
2647 ret.name.str = node.name.str;
aPiecek41219f92022-10-26 11:24:40 +02002648 ret.name.opts = node.name.opts;
aPiecek03cb4872022-10-24 10:31:51 +02002649 ret.name.add_opts = node.name.add_opts;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002650 ret.type = TRP_EMPTY_TRT_TYPE;
aPiecek41219f92022-10-26 11:24:40 +02002651 ret.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002652 ret.last_one = node.last_one;
2653
2654 return ret;
2655}
2656
aPiecekef1e58e2021-04-19 13:19:44 +02002657/**********************************************************************
2658 * Definition of trop reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02002659 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002660
2661/**
aPiecek61d062b2020-11-02 11:05:09 +01002662 * @brief Check if list statement has keys.
2663 * @param[in] pn is pointer to the list.
2664 * @return 1 if has keys, otherwise 0.
2665 */
2666static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002667trop_list_has_keys(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002668{
aPiecekef1e58e2021-04-19 13:19:44 +02002669 return trg_charptr_has_data(((const struct lysp_node_list *)pn)->key);
aPiecek61d062b2020-11-02 11:05:09 +01002670}
2671
2672/**
2673 * @brief Check if it contains at least one feature.
aPiecek3f247652021-04-19 13:40:25 +02002674 * @param[in] pn is current node.
aPiecek61d062b2020-11-02 11:05:09 +01002675 * @return 1 if has if-features, otherwise 0.
2676 */
2677static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002678trop_node_has_iffeature(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002679{
2680 LY_ARRAY_COUNT_TYPE u;
aPiecekef1e58e2021-04-19 13:19:44 +02002681 const struct lysp_qname *iffs;
2682
aPiecek61d062b2020-11-02 11:05:09 +01002683 ly_bool ret = 0;
2684
aPiecekef1e58e2021-04-19 13:19:44 +02002685 iffs = pn->iffeatures;
aPiecek61d062b2020-11-02 11:05:09 +01002686 LY_ARRAY_FOR(iffs, u) {
2687 ret = 1;
2688 break;
2689 }
2690 return ret;
2691}
2692
2693/**
2694 * @brief Find out if leaf is also the key in last list.
2695 * @param[in] pn is pointer to leaf.
aPiecek874ea4d2021-04-19 12:26:36 +02002696 * @param[in] ca_last_list is pointer to last visited list.
2697 * Obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002698 * @return 1 if leaf is also the key, otherwise 0.
2699 */
2700static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002701trop_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
aPiecek61d062b2020-11-02 11:05:09 +01002702{
2703 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2704 const struct lysp_node_list *list = ca_last_list;
2705
2706 if (!list) {
2707 return 0;
2708 }
2709 return trg_charptr_has_data(list->key) ?
2710 trg_word_is_present(list->key, leaf->name, ' ') : 0;
2711}
2712
2713/**
2714 * @brief Check if container's type is presence.
2715 * @param[in] pn is pointer to container.
2716 * @return 1 if container has presence statement, otherwise 0.
2717 */
2718static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002719trop_container_has_presence(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002720{
2721 return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence);
2722}
2723
2724/**
2725 * @brief Get leaflist's path without lysp_node type control.
2726 * @param[in] pn is pointer to the leaflist.
2727 */
2728static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002729trop_leaflist_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002730{
2731 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2732
2733 return list->type.path ? list->type.path->expr : NULL;
2734}
2735
2736/**
2737 * @brief Get leaflist's type name without lysp_node type control.
2738 * @param[in] pn is pointer to the leaflist.
2739 */
2740static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002741trop_leaflist_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002742{
2743 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2744
2745 return list->type.name;
2746}
2747
2748/**
2749 * @brief Get leaf's path without lysp_node type control.
2750 * @param[in] pn is pointer to the leaf node.
2751 */
2752static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002753trop_leaf_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002754{
2755 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2756
2757 return leaf->type.path ? leaf->type.path->expr : NULL;
2758}
2759
2760/**
2761 * @brief Get leaf's type name without lysp_node type control.
2762 * @param[in] pn is pointer to the leaf's type name.
2763 */
2764static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002765trop_leaf_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002766{
2767 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2768
2769 return leaf->type.name;
2770}
2771
2772/**
aPiecek874ea4d2021-04-19 12:26:36 +02002773 * @brief Get pointer to data using node type specification
2774 * and getter function.
aPiecek61d062b2020-11-02 11:05:09 +01002775 *
aPiecek874ea4d2021-04-19 12:26:36 +02002776 * @param[in] flags is node type specification.
2777 * If it is the correct node, the getter function is called.
2778 * @param[in] f is getter function which provides the desired
2779 * char pointer from the structure.
aPiecek61d062b2020-11-02 11:05:09 +01002780 * @param[in] pn pointer to node.
aPiecek874ea4d2021-04-19 12:26:36 +02002781 * @return NULL if node has wrong type or getter function return
2782 * pointer to NULL.
aPiecek61d062b2020-11-02 11:05:09 +01002783 * @return Pointer to desired char pointer obtained from the node.
2784 */
2785static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002786trop_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002787{
2788 if (pn->nodetype & flags) {
2789 const char *ret = f(pn);
Michal Vasko26bbb272022-08-02 14:54:33 +02002790
aPiecek61d062b2020-11-02 11:05:09 +01002791 return trg_charptr_has_data(ret) ? ret : NULL;
2792 } else {
2793 return NULL;
2794 }
2795}
2796
2797/**
aPiecek61d062b2020-11-02 11:05:09 +01002798 * @brief Resolve \<status\> of the current node.
2799 * @param[in] nodetype is node's type obtained from the tree.
2800 * @param[in] flags is node's flags obtained from the tree.
aPiecek03cb4872022-10-24 10:31:51 +02002801 * @param[in] ca_lys_status is inherited status obtained from trt_parent_cache.
2802 * @param[in] no Override structure for status.
aPiecek61d062b2020-11-02 11:05:09 +01002803 * @return The status type.
2804 */
aPiecek41219f92022-10-26 11:24:40 +02002805static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002806trop_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
aPiecek61d062b2020-11-02 11:05:09 +01002807{
aPiecek61d062b2020-11-02 11:05:09 +01002808 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02002809 /* LYS_INPUT and LYS_OUTPUT is special case */
aPiecekef1e58e2021-04-19 13:19:44 +02002810 return tro_flags2status(ca_lys_status);
2811 /* if ancestor's status is deprc or obslt
2812 * and also node's status is not set
2813 */
aPiecek61d062b2020-11-02 11:05:09 +01002814 } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
2815 /* get ancestor's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002816 return tro_flags2status(ca_lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002817 } else {
2818 /* else get node's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002819 return tro_flags2status(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002820 }
2821}
2822
2823/**
2824 * @brief Resolve \<flags\> of the current node.
2825 * @param[in] nodetype is node's type obtained from the tree.
2826 * @param[in] flags is node's flags obtained from the tree.
aPiecek03cb4872022-10-24 10:31:51 +02002827 * @param[in] ca_ancestor is ancestor type obtained from trt_parent_cache.
2828 * @param[in] ca_lys_config is inherited config item obtained from trt_parent_cache.
2829 * @param[in] no Override structure for flags.
aPiecek61d062b2020-11-02 11:05:09 +01002830 * @return The flags type.
2831 */
aPiecek03cb4872022-10-24 10:31:51 +02002832static const char *
2833trop_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config,
2834 struct lyplg_ext_sprinter_tree_node_override *no)
aPiecek61d062b2020-11-02 11:05:09 +01002835{
aPiecek03cb4872022-10-24 10:31:51 +02002836 if (no && no->flags) {
2837 return no->flags;
2838 } else if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) {
aPiecek61d062b2020-11-02 11:05:09 +01002839 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
2840 } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) {
2841 return TRD_FLAGS_TYPE_RO;
2842 } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) {
2843 return TRD_FLAGS_TYPE_RO;
2844 } else if (nodetype & LYS_NOTIF) {
2845 return TRD_FLAGS_TYPE_NOTIF;
2846 } else if (nodetype & LYS_USES) {
2847 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
2848 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
2849 return TRD_FLAGS_TYPE_RPC;
aPiecek61d062b2020-11-02 11:05:09 +01002850 } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002851 /* config is not set. Look at ancestor's config */
2852 return tro_flags2config(ca_lys_config);
aPiecek61d062b2020-11-02 11:05:09 +01002853 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02002854 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002855 }
2856}
2857
2858/**
2859 * @brief Resolve node type of the current node.
2860 * @param[in] pn is pointer to the current node in the tree.
aPiecek03cb4872022-10-24 10:31:51 +02002861 * @param[in] ca_last_list is pointer to the last visited list. Obtained from the trt_parent_cache.
2862 * @param[in] no Override structure for opts.
2863 * @param[out] type Resolved type of node.
2864 * @param[out] opts Resolved opts of node.
aPiecek61d062b2020-11-02 11:05:09 +01002865 */
aPiecek41219f92022-10-26 11:24:40 +02002866static void
aPiecek03cb4872022-10-24 10:31:51 +02002867trop_resolve_node_opts(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list, trt_node_type *type,
2868 const char **opts)
aPiecek61d062b2020-11-02 11:05:09 +01002869{
2870 if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02002871 *type = TRD_NODE_ELSE;
aPiecek61d062b2020-11-02 11:05:09 +01002872 } else if (pn->nodetype & LYS_CASE) {
aPiecek41219f92022-10-26 11:24:40 +02002873 *type = TRD_NODE_CASE;
aPiecek61d062b2020-11-02 11:05:09 +01002874 } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02002875 *type = TRD_NODE_CHOICE;
2876 *opts = TRD_NODE_OPTIONAL;
aPiecek61d062b2020-11-02 11:05:09 +01002877 } else if (pn->nodetype & LYS_CHOICE) {
aPiecek41219f92022-10-26 11:24:40 +02002878 *type = TRD_NODE_CHOICE;
aPiecekef1e58e2021-04-19 13:19:44 +02002879 } else if ((pn->nodetype & LYS_CONTAINER) && (trop_container_has_presence(pn))) {
aPiecek41219f92022-10-26 11:24:40 +02002880 *opts = TRD_NODE_CONTAINER;
aPiecek61d062b2020-11-02 11:05:09 +01002881 } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
aPiecek41219f92022-10-26 11:24:40 +02002882 *opts = TRD_NODE_LISTLEAFLIST;
aPiecek61d062b2020-11-02 11:05:09 +01002883 } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02002884 *opts = TRD_NODE_OPTIONAL;
aPiecekef1e58e2021-04-19 13:19:44 +02002885 } else if ((pn->nodetype & LYS_LEAF) && !(pn->flags & LYS_MAND_TRUE) && (!trop_leaf_is_key(pn, ca_last_list))) {
aPiecek41219f92022-10-26 11:24:40 +02002886 *opts = TRD_NODE_OPTIONAL;
aPiecek61d062b2020-11-02 11:05:09 +01002887 } else {
aPiecek41219f92022-10-26 11:24:40 +02002888 *type = TRD_NODE_ELSE;
aPiecek61d062b2020-11-02 11:05:09 +01002889 }
2890}
2891
2892/**
aPiecekef1e58e2021-04-19 13:19:44 +02002893 * @brief Resolve \<type\> of the current node.
2894 * @param[in] pn is current node.
aPiecek03cb4872022-10-24 10:31:51 +02002895 * @param[in] no is override structure for type.
2896 * @return Resolved type.
aPiecekef1e58e2021-04-19 13:19:44 +02002897 */
2898static struct trt_type
2899trop_resolve_type(const struct lysp_node *pn)
2900{
2901 const char *tmp = NULL;
2902
aPiecek03cb4872022-10-24 10:31:51 +02002903 if (!pn) {
2904 return TRP_EMPTY_TRT_TYPE;
2905 } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_refpath, pn))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002906 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2907 } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_type_name, pn))) {
2908 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2909 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_refpath, pn))) {
2910 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2911 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_type_name, pn))) {
2912 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2913 } else if (pn->nodetype == LYS_ANYDATA) {
2914 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata");
2915 } else if (pn->nodetype & LYS_ANYXML) {
2916 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml");
2917 } else {
2918 return TRP_EMPTY_TRT_TYPE;
2919 }
2920}
2921
2922/**
aPiecek03cb4872022-10-24 10:31:51 +02002923 * @brief Resolve iffeatures.
2924 *
2925 * @param[in] pn is current parsed node.
2926 * @param[in] no is override structure for iffeatures.
2927 * @return Resolved iffeatures.
2928 */
2929static struct trt_iffeatures
2930trop_resolve_iffeatures(const struct lysp_node *pn)
2931{
2932 struct trt_iffeatures iff;
2933
2934 if (pn && trop_node_has_iffeature(pn)) {
2935 iff.type = TRD_IFF_PRESENT;
2936 iff.str = NULL;
2937 } else {
2938 iff.type = TRD_IFF_NON_PRESENT;
2939 iff.str = NULL;
2940 }
2941
2942 return iff;
2943}
2944
2945/**
aPiecek61d062b2020-11-02 11:05:09 +01002946 * @brief Transformation of current lysp_node to struct trt_node.
aPiecek874ea4d2021-04-19 12:26:36 +02002947 * @param[in] ca contains stored important data
2948 * when browsing the tree downwards.
aPiecek61d062b2020-11-02 11:05:09 +01002949 * @param[in] tc is context of the tree.
2950 */
2951static struct trt_node
aPiecek03cb4872022-10-24 10:31:51 +02002952trop_read_node(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002953{
aPiecekef1e58e2021-04-19 13:19:44 +02002954 const struct lysp_node *pn;
2955 struct trt_node ret;
aPiecek03cb4872022-10-24 10:31:51 +02002956 struct lyplg_ext_sprinter_tree_node_override *no;
aPiecekef1e58e2021-04-19 13:19:44 +02002957
aPiecek61d062b2020-11-02 11:05:09 +01002958 assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
aPiecekef1e58e2021-04-19 13:19:44 +02002959
aPiecek03cb4872022-10-24 10:31:51 +02002960 no = tro_set_node_overr(tc->lysc_tree, tc->pn, 1, &tc->plugin_ctx);
2961
aPiecekef1e58e2021-04-19 13:19:44 +02002962 pn = tc->pn;
2963 ret = TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01002964
2965 /* <status> */
aPiecekef1e58e2021-04-19 13:19:44 +02002966 ret.status = trop_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002967
aPiecek61d062b2020-11-02 11:05:09 +01002968 /* <flags> */
aPiecek03cb4872022-10-24 10:31:51 +02002969 ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config, no);
aPiecek61d062b2020-11-02 11:05:09 +01002970
aPiecek61d062b2020-11-02 11:05:09 +01002971 /* set type of the node */
aPiecek03cb4872022-10-24 10:31:51 +02002972 trop_resolve_node_opts(pn, ca.last_list, &ret.name.type, &ret.name.opts);
2973 ret.name.add_opts = no && no->add_opts ? no->add_opts : NULL;
aPiecekbca57772022-10-13 13:51:59 +02002974 ret.name.keys = (tc->pn->nodetype & LYS_LIST) && trop_list_has_keys(tc->pn);
aPiecek61d062b2020-11-02 11:05:09 +01002975
aPiecek34fa3772021-05-21 12:35:46 +02002976 /* The parsed tree is not compiled, so no node can be augmented
2977 * from another module. This means that nodes from the parsed tree
2978 * will never have the prefix.
2979 */
aPiecek61d062b2020-11-02 11:05:09 +01002980 ret.name.module_prefix = NULL;
2981
2982 /* set node's name */
2983 ret.name.str = pn->name;
2984
2985 /* <type> */
aPiecekef1e58e2021-04-19 13:19:44 +02002986 ret.type = trop_resolve_type(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002987
2988 /* <iffeature> */
aPiecek03cb4872022-10-24 10:31:51 +02002989 ret.iffeatures = trop_resolve_iffeatures(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002990
aPiecek03cb4872022-10-24 10:31:51 +02002991 ret.last_one = !tro_next_sibling(pn, tc);
aPiecek61d062b2020-11-02 11:05:09 +01002992
2993 return ret;
2994}
2995
aPiecekef1e58e2021-04-19 13:19:44 +02002996/**
2997 * @brief Find out if the current node has siblings.
2998 * @param[in] tc is context of the tree.
2999 * @return 1 if sibling exists otherwise 0.
3000 */
3001static ly_bool
3002trop_read_if_sibling_exists(const struct trt_tree_ctx *tc)
3003{
aPiecek03cb4872022-10-24 10:31:51 +02003004 return tro_next_sibling(tc->pn, tc) != NULL;
aPiecek96baa7f2021-04-23 12:32:00 +02003005}
3006
aPiecek874ea4d2021-04-19 12:26:36 +02003007/**********************************************************************
aPiecekef1e58e2021-04-19 13:19:44 +02003008 * Modify trop getters
aPiecek874ea4d2021-04-19 12:26:36 +02003009 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003010
3011/**
aPiecek874ea4d2021-04-19 12:26:36 +02003012 * @brief Change current node pointer to its parent
3013 * but only if parent exists.
3014 * @param[in,out] tc is tree context.
3015 * Contains pointer to the current node.
aPiecek61d062b2020-11-02 11:05:09 +01003016 * @return 1 if the node had parents and the change was successful.
aPiecek874ea4d2021-04-19 12:26:36 +02003017 * @return 0 if the node did not have parents.
3018 * The pointer to the current node did not change.
aPiecek61d062b2020-11-02 11:05:09 +01003019 */
3020static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02003021trop_modi_parent(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003022{
3023 assert(tc && tc->pn);
3024 /* If no parent exists, stay in actual node. */
aPiecek96baa7f2021-04-23 12:32:00 +02003025 if ((tc->pn != tc->tpn) && (tc->pn->parent)) {
aPiecek61d062b2020-11-02 11:05:09 +01003026 tc->pn = tc->pn->parent;
3027 return 1;
3028 } else {
3029 return 0;
3030 }
3031}
3032
3033/**
aPiecek874ea4d2021-04-19 12:26:36 +02003034 * @brief Change the current node pointer to its child
3035 * but only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01003036 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02003037 * @param[in,out] tc is context of the tree.
3038 * Contains pointer to the current node.
3039 * @return Non-empty \<node\> representation of the current
3040 * node's child. The @p tc is modified.
3041 * @return Empty \<node\> representation if child don't exists.
3042 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01003043 */
3044static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02003045trop_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003046{
aPiecekef1e58e2021-04-19 13:19:44 +02003047 const struct lysp_node *tmp;
3048
aPiecek61d062b2020-11-02 11:05:09 +01003049 assert(tc && tc->pn);
3050
aPiecek03cb4872022-10-24 10:31:51 +02003051 if ((tmp = tro_next_child(tc->pn, tc))) {
aPiecekef1e58e2021-04-19 13:19:44 +02003052 tc->pn = tmp;
aPiecek67521c22022-10-19 09:15:02 +02003053 return trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003054 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02003055 return TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01003056 }
3057}
3058
3059/**
aPiecek03cb4872022-10-24 10:31:51 +02003060 * @brief Change the pointer to the current node to its next sibling
3061 * only if exists.
3062 * @param[in] ca contains inherited data from ancestors.
3063 * @param[in,out] tc is tree context.
3064 * Contains pointer to the current node.
3065 * @return Non-empty \<node\> representation if sibling exists.
3066 * The @p tc is modified.
3067 * @return Empty \<node\> representation otherwise.
3068 * The @p tc is not modified.
3069 */
3070static struct trt_node
3071trop_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3072{
3073 const struct lysp_node *pn;
3074
3075 assert(tc && tc->pn);
3076
3077 pn = tro_next_sibling(tc->pn, tc);
3078
3079 if (pn) {
3080 if ((tc->tpn == tc->pn) && (tc->section != TRD_SECT_PLUG_DATA)) {
3081 tc->tpn = pn;
3082 }
3083 tc->pn = pn;
3084 return trop_read_node(ca, tc);
3085 } else {
3086 return TRP_EMPTY_NODE;
3087 }
3088}
3089
3090/**
aPiecek874ea4d2021-04-19 12:26:36 +02003091 * @brief Change the current node pointer to the first child of node's
3092 * parent. If current node is already first sibling/child then nothing
3093 * will change.
aPiecek03cb4872022-10-24 10:31:51 +02003094 * @param[in] ca Settings of parent.
aPiecek61d062b2020-11-02 11:05:09 +01003095 * @param[in,out] tc is tree context.
aPiecek03cb4872022-10-24 10:31:51 +02003096 * @return node for printing.
aPiecek61d062b2020-11-02 11:05:09 +01003097 */
aPiecek03cb4872022-10-24 10:31:51 +02003098static struct trt_node
3099trop_modi_first_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003100{
aPiecek03cb4872022-10-24 10:31:51 +02003101 struct trt_node node;
3102
3103 assert(tc && tc->pn);
aPiecek61d062b2020-11-02 11:05:09 +01003104
aPiecekef1e58e2021-04-19 13:19:44 +02003105 if (trop_modi_parent(tc)) {
aPiecek03cb4872022-10-24 10:31:51 +02003106 node = trop_modi_next_child(ca, tc);
3107 } else if (tc->plugin_ctx.schema) {
3108 tc->pn = tc->plugin_ctx.schema->ptree;
3109 tc->tpn = tc->pn;
3110 node = trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003111 } else {
3112 /* current node is top-node */
aPiecek61d062b2020-11-02 11:05:09 +01003113 switch (tc->section) {
3114 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02003115 tc->pn = tc->pmod->data;
aPiecek96baa7f2021-04-23 12:32:00 +02003116 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003117 break;
3118 case TRD_SECT_AUGMENT:
aPiecek9f792e52021-04-21 08:33:56 +02003119 tc->pn = (const struct lysp_node *)tc->pmod->augments;
aPiecek96baa7f2021-04-23 12:32:00 +02003120 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003121 break;
3122 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02003123 tc->pn = (const struct lysp_node *)tc->pmod->rpcs;
aPiecek96baa7f2021-04-23 12:32:00 +02003124 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003125 break;
3126 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02003127 tc->pn = (const struct lysp_node *)tc->pmod->notifs;
aPiecek96baa7f2021-04-23 12:32:00 +02003128 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003129 break;
3130 case TRD_SECT_GROUPING:
aPiecek9f792e52021-04-21 08:33:56 +02003131 tc->pn = (const struct lysp_node *)tc->pmod->groupings;
aPiecek96baa7f2021-04-23 12:32:00 +02003132 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003133 break;
aPiecek03cb4872022-10-24 10:31:51 +02003134 case TRD_SECT_PLUG_DATA:
3135 /* Nothing to do. */
aPiecek61d062b2020-11-02 11:05:09 +01003136 break;
aPiecek96baa7f2021-04-23 12:32:00 +02003137 default:
3138 assert(0);
aPiecek61d062b2020-11-02 11:05:09 +01003139 }
aPiecek03cb4872022-10-24 10:31:51 +02003140 node = trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003141 }
aPiecek61d062b2020-11-02 11:05:09 +01003142
aPiecek03cb4872022-10-24 10:31:51 +02003143 if (tc->plugin_ctx.filtered) {
3144 node = trop_modi_next_sibling(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003145 }
aPiecek03cb4872022-10-24 10:31:51 +02003146
3147 return node;
aPiecek61d062b2020-11-02 11:05:09 +01003148}
3149
3150/**
3151 * @brief Get next (or first) augment section if exists.
aPiecek874ea4d2021-04-19 12:26:36 +02003152 * @param[in,out] tc is tree context. It is modified and his current
3153 * node is set to the lysp_node_augment.
aPiecek61d062b2020-11-02 11:05:09 +01003154 * @return Section's representation if (next augment) section exists.
aPiecek61d062b2020-11-02 11:05:09 +01003155 * @return Empty section structure otherwise.
3156 */
3157static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003158trop_modi_next_augment(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003159{
aPiecek9f792e52021-04-21 08:33:56 +02003160 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003161 const struct lysp_node_augment *augs;
aPiecek03cb4872022-10-24 10:31:51 +02003162 struct trt_keyword_stmt ret = {0};
aPiecek61d062b2020-11-02 11:05:09 +01003163
3164 /* if next_augment func was called for the first time */
3165 if (tc->section != TRD_SECT_AUGMENT) {
3166 tc->section = TRD_SECT_AUGMENT;
aPiecek9f792e52021-04-21 08:33:56 +02003167 augs = tc->pmod->augments;
aPiecek61d062b2020-11-02 11:05:09 +01003168 } else {
3169 /* get augment sibling from top-node pointer */
aPiecekdc8fd572021-04-19 10:47:23 +02003170 augs = (const struct lysp_node_augment *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003171 }
3172
aPiecekdc8fd572021-04-19 10:47:23 +02003173 if (augs) {
3174 tc->pn = &augs->node;
aPiecek61d062b2020-11-02 11:05:09 +01003175 tc->tpn = tc->pn;
aPiecek03cb4872022-10-24 10:31:51 +02003176 ret.section_name = TRD_KEYWORD_AUGMENT;
3177 ret.argument = augs->nodeid;
3178 ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0;
aPiecek61d062b2020-11-02 11:05:09 +01003179 }
aPiecek03cb4872022-10-24 10:31:51 +02003180
3181 return ret;
aPiecek61d062b2020-11-02 11:05:09 +01003182}
3183
3184/**
aPiecek61d062b2020-11-02 11:05:09 +01003185 * @brief Get next (or first) grouping section if exists
aPiecek874ea4d2021-04-19 12:26:36 +02003186 * @param[in,out] tc is tree context. It is modified and his current
3187 * node is set to the lysp_node_grp.
aPiecek61d062b2020-11-02 11:05:09 +01003188 * @return The next (or first) section representation if it exists.
aPiecek61d062b2020-11-02 11:05:09 +01003189 * @return Empty section representation otherwise.
3190 */
3191static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003192trop_modi_next_grouping(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003193{
aPiecek9f792e52021-04-21 08:33:56 +02003194 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003195 const struct lysp_node_grp *grps;
aPiecek03cb4872022-10-24 10:31:51 +02003196 struct trt_keyword_stmt ret = {0};
aPiecek61d062b2020-11-02 11:05:09 +01003197
3198 if (tc->section != TRD_SECT_GROUPING) {
3199 tc->section = TRD_SECT_GROUPING;
aPiecek9f792e52021-04-21 08:33:56 +02003200 grps = tc->pmod->groupings;
aPiecek61d062b2020-11-02 11:05:09 +01003201 } else {
aPiecekdc8fd572021-04-19 10:47:23 +02003202 grps = (const struct lysp_node_grp *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003203 }
3204
aPiecekdc8fd572021-04-19 10:47:23 +02003205 if (grps) {
3206 tc->pn = &grps->node;
aPiecek61d062b2020-11-02 11:05:09 +01003207 tc->tpn = tc->pn;
aPiecek03cb4872022-10-24 10:31:51 +02003208 ret.section_name = TRD_KEYWORD_GROUPING;
3209 ret.argument = grps->name;
3210 ret.has_node = tro_tree_ctx_get_child(tc) ? 1 : 0;
aPiecek61d062b2020-11-02 11:05:09 +01003211 }
aPiecek03cb4872022-10-24 10:31:51 +02003212
3213 return ret;
aPiecek61d062b2020-11-02 11:05:09 +01003214}
3215
aPiecek874ea4d2021-04-19 12:26:36 +02003216/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02003217 * Definition of troc reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02003218 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003219
3220/**
aPiecek3f247652021-04-19 13:40:25 +02003221 * @copydoc trop_read_if_sibling_exists
aPiecek61d062b2020-11-02 11:05:09 +01003222 */
aPiecek3f247652021-04-19 13:40:25 +02003223static ly_bool
3224troc_read_if_sibling_exists(const struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003225{
aPiecek03cb4872022-10-24 10:31:51 +02003226 return tro_next_sibling(tc->cn, tc) != NULL;
aPiecek3f247652021-04-19 13:40:25 +02003227}
aPiecek61d062b2020-11-02 11:05:09 +01003228
aPiecek3f247652021-04-19 13:40:25 +02003229/**
3230 * @brief Resolve \<flags\> of the current node.
3231 *
3232 * Use this function only if trt_tree_ctx.lysc_tree is true.
3233 *
3234 * @param[in] nodetype is current lysc_node.nodetype.
3235 * @param[in] flags is current lysc_node.flags.
aPiecek03cb4872022-10-24 10:31:51 +02003236 * @param[in] no Override structure for flags.
aPiecek3f247652021-04-19 13:40:25 +02003237 * @return The flags type.
3238 */
aPiecek03cb4872022-10-24 10:31:51 +02003239static const char *
3240troc_resolve_flags(uint16_t nodetype, uint16_t flags, struct lyplg_ext_sprinter_tree_node_override *no)
aPiecek3f247652021-04-19 13:40:25 +02003241{
aPiecek03cb4872022-10-24 10:31:51 +02003242 if (no && no->flags) {
3243 return no->flags;
3244 } else if ((nodetype & LYS_INPUT) || (flags & LYS_IS_INPUT)) {
aPiecek3f247652021-04-19 13:40:25 +02003245 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
3246 } else if ((nodetype & LYS_OUTPUT) || (flags & LYS_IS_OUTPUT)) {
3247 return TRD_FLAGS_TYPE_RO;
3248 } else if (nodetype & LYS_IS_NOTIF) {
3249 return TRD_FLAGS_TYPE_RO;
3250 } else if (nodetype & LYS_NOTIF) {
3251 return TRD_FLAGS_TYPE_NOTIF;
3252 } else if (nodetype & LYS_USES) {
3253 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
3254 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
3255 return TRD_FLAGS_TYPE_RPC;
3256 } else {
3257 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01003258 }
aPiecek61d062b2020-11-02 11:05:09 +01003259}
3260
3261/**
aPiecek3f247652021-04-19 13:40:25 +02003262 * @brief Resolve node type of the current node.
aPiecek61d062b2020-11-02 11:05:09 +01003263 *
aPiecek3f247652021-04-19 13:40:25 +02003264 * Use this function only if trt_tree_ctx.lysc_tree is true.
aPiecek61d062b2020-11-02 11:05:09 +01003265 *
aPiecek3f247652021-04-19 13:40:25 +02003266 * @param[in] nodetype is current lysc_node.nodetype.
3267 * @param[in] flags is current lysc_node.flags.
aPiecek03cb4872022-10-24 10:31:51 +02003268 * @param[in] no Override structure for opts.
3269 * @param[out] type Resolved type of node.
3270 * @param[out] opts Resolved opts.
aPiecek3f247652021-04-19 13:40:25 +02003271 */
aPiecek41219f92022-10-26 11:24:40 +02003272static void
aPiecek03cb4872022-10-24 10:31:51 +02003273troc_resolve_node_opts(uint16_t nodetype, uint16_t flags, trt_node_type *type, const char **opts)
aPiecek3f247652021-04-19 13:40:25 +02003274{
3275 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02003276 *type = TRD_NODE_ELSE;
aPiecek3f247652021-04-19 13:40:25 +02003277 } else if (nodetype & LYS_CASE) {
aPiecek41219f92022-10-26 11:24:40 +02003278 *type = TRD_NODE_CASE;
aPiecek3f247652021-04-19 13:40:25 +02003279 } else if ((nodetype & LYS_CHOICE) && !(flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02003280 *type = TRD_NODE_CHOICE;
3281 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003282 } else if (nodetype & LYS_CHOICE) {
aPiecek41219f92022-10-26 11:24:40 +02003283 *type = TRD_NODE_CHOICE;
aPiecek3f247652021-04-19 13:40:25 +02003284 } else if ((nodetype & LYS_CONTAINER) && (flags & LYS_PRESENCE)) {
aPiecek41219f92022-10-26 11:24:40 +02003285 *opts = TRD_NODE_CONTAINER;
aPiecek3f247652021-04-19 13:40:25 +02003286 } else if (nodetype & (LYS_LIST | LYS_LEAFLIST)) {
aPiecek41219f92022-10-26 11:24:40 +02003287 *opts = TRD_NODE_LISTLEAFLIST;
aPiecek3f247652021-04-19 13:40:25 +02003288 } else if ((nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02003289 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003290 } else if ((nodetype & LYS_LEAF) && !(flags & (LYS_MAND_TRUE | LYS_KEY))) {
aPiecek41219f92022-10-26 11:24:40 +02003291 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003292 } else {
aPiecek41219f92022-10-26 11:24:40 +02003293 *type = TRD_NODE_ELSE;
aPiecek3f247652021-04-19 13:40:25 +02003294 }
3295}
3296
3297/**
aPiecek03cb4872022-10-24 10:31:51 +02003298 * @brief Resolve prefix (\<prefix\>:\<name\>) of node that has been
aPiecek34fa3772021-05-21 12:35:46 +02003299 * placed from another module via an augment statement.
3300 *
3301 * @param[in] cn is current compiled node.
3302 * @param[in] current_compiled_module is module whose nodes are
3303 * currently being printed.
3304 * @return Prefix of foreign module or NULL.
3305 */
3306static const char *
3307troc_resolve_node_prefix(const struct lysc_node *cn, const struct lysc_module *current_compiled_module)
3308{
3309 const struct lys_module *node_module;
3310 const char *ret = NULL;
3311
3312 node_module = cn->module;
aPiecek03cb4872022-10-24 10:31:51 +02003313 if (!node_module || !current_compiled_module) {
3314 return NULL;
3315 } else if (node_module->compiled != current_compiled_module) {
aPiecek34fa3772021-05-21 12:35:46 +02003316 ret = node_module->prefix;
3317 }
3318
3319 return ret;
3320}
3321
3322/**
aPiecek3f247652021-04-19 13:40:25 +02003323 * @brief Transformation of current lysc_node to struct trt_node.
3324 * @param[in] ca is not used.
3325 * @param[in] tc is context of the tree.
3326 */
3327static struct trt_node
aPiecek03cb4872022-10-24 10:31:51 +02003328troc_read_node(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek3f247652021-04-19 13:40:25 +02003329{
3330 (void) ca;
3331 const struct lysc_node *cn;
3332 struct trt_node ret;
aPiecek03cb4872022-10-24 10:31:51 +02003333 struct lyplg_ext_sprinter_tree_node_override *no;
aPiecek3f247652021-04-19 13:40:25 +02003334
aPiecek082c7dc2021-05-20 08:55:07 +02003335 assert(tc && tc->cn);
aPiecek3f247652021-04-19 13:40:25 +02003336
aPiecek03cb4872022-10-24 10:31:51 +02003337 no = tro_set_node_overr(tc->lysc_tree, tc->cn, 1, &tc->plugin_ctx);
3338
aPiecek3f247652021-04-19 13:40:25 +02003339 cn = tc->cn;
3340 ret = TRP_EMPTY_NODE;
3341
3342 /* <status> */
3343 ret.status = tro_flags2status(cn->flags);
3344
aPiecek3f247652021-04-19 13:40:25 +02003345 /* <flags> */
aPiecek03cb4872022-10-24 10:31:51 +02003346 ret.flags = troc_resolve_flags(cn->nodetype, cn->flags, no);
aPiecek3f247652021-04-19 13:40:25 +02003347
aPiecek3f247652021-04-19 13:40:25 +02003348 /* set type of the node */
aPiecek03cb4872022-10-24 10:31:51 +02003349 troc_resolve_node_opts(cn->nodetype, cn->flags, &ret.name.type, &ret.name.opts);
3350 ret.name.add_opts = no && no->add_opts ? no->add_opts : NULL;
aPiecekbca57772022-10-13 13:51:59 +02003351 ret.name.keys = (cn->nodetype & LYS_LIST) && !(cn->flags & LYS_KEYLESS);
aPiecek3f247652021-04-19 13:40:25 +02003352
aPiecek34fa3772021-05-21 12:35:46 +02003353 /* <prefix> */
3354 ret.name.module_prefix = troc_resolve_node_prefix(cn, tc->cmod);
aPiecek3f247652021-04-19 13:40:25 +02003355
3356 /* set node's name */
3357 ret.name.str = cn->name;
3358
aPiecek03cb4872022-10-24 10:31:51 +02003359 /* <type> */
3360 ret.type = trop_resolve_type(TRP_TREE_CTX_GET_LYSP_NODE(cn));
aPiecek3f247652021-04-19 13:40:25 +02003361
aPiecek03cb4872022-10-24 10:31:51 +02003362 /* <iffeature> */
3363 ret.iffeatures = trop_resolve_iffeatures(TRP_TREE_CTX_GET_LYSP_NODE(cn));
aPiecek082c7dc2021-05-20 08:55:07 +02003364
aPiecek03cb4872022-10-24 10:31:51 +02003365 ret.last_one = !tro_next_sibling(cn, tc);
aPiecek3f247652021-04-19 13:40:25 +02003366
3367 return ret;
3368}
3369
3370/**********************************************************************
3371 * Modify troc getters
3372 *********************************************************************/
3373
3374/**
aPiecek01598c02021-04-23 14:18:24 +02003375 * @copydoc ::trop_modi_parent()
aPiecek3f247652021-04-19 13:40:25 +02003376 */
3377static ly_bool
3378troc_modi_parent(struct trt_tree_ctx *tc)
3379{
3380 assert(tc && tc->cn);
3381 /* If no parent exists, stay in actual node. */
3382 if (tc->cn->parent) {
3383 tc->cn = tc->cn->parent;
3384 return 1;
3385 } else {
3386 return 0;
3387 }
3388}
3389
3390/**
aPiecek01598c02021-04-23 14:18:24 +02003391 * @copydoc ::trop_modi_next_sibling()
aPiecek3f247652021-04-19 13:40:25 +02003392 */
3393static struct trt_node
3394troc_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3395{
3396 const struct lysc_node *cn;
3397
3398 assert(tc && tc->cn);
3399
aPiecek03cb4872022-10-24 10:31:51 +02003400 cn = tro_next_sibling(tc->cn, tc);
aPiecek3f247652021-04-19 13:40:25 +02003401
3402 /* if next sibling exists */
3403 if (cn) {
3404 /* update trt_tree_ctx */
3405 tc->cn = cn;
3406 return troc_read_node(ca, tc);
3407 } else {
3408 return TRP_EMPTY_NODE;
3409 }
3410}
3411
3412/**
3413 * @copydoc trop_modi_next_child()
3414 */
3415static struct trt_node
3416troc_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3417{
3418 const struct lysc_node *tmp;
3419
3420 assert(tc && tc->cn);
3421
aPiecek03cb4872022-10-24 10:31:51 +02003422 if ((tmp = tro_next_child(tc->cn, tc))) {
aPiecek3f247652021-04-19 13:40:25 +02003423 tc->cn = tmp;
3424 return troc_read_node(ca, tc);
3425 } else {
3426 return TRP_EMPTY_NODE;
3427 }
3428}
3429
3430/**
aPiecek01598c02021-04-23 14:18:24 +02003431 * @copydoc ::trop_modi_first_sibling()
aPiecek61d062b2020-11-02 11:05:09 +01003432 */
aPiecek03cb4872022-10-24 10:31:51 +02003433static struct trt_node
3434troc_modi_first_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003435{
aPiecek03cb4872022-10-24 10:31:51 +02003436 struct trt_node node;
3437
aPiecek3f247652021-04-19 13:40:25 +02003438 assert(tc && tc->cn);
aPiecek61d062b2020-11-02 11:05:09 +01003439
aPiecek3f247652021-04-19 13:40:25 +02003440 if (troc_modi_parent(tc)) {
aPiecek03cb4872022-10-24 10:31:51 +02003441 node = troc_modi_next_child(ca, tc);
3442 } else if (tc->plugin_ctx.schema) {
3443 tc->cn = tc->plugin_ctx.schema->ctree;
3444 node = troc_read_node(ca, tc);
aPiecek3f247652021-04-19 13:40:25 +02003445 } else {
3446 /* current node is top-node */
aPiecek3f247652021-04-19 13:40:25 +02003447 switch (tc->section) {
3448 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02003449 tc->cn = tc->cmod->data;
aPiecek3f247652021-04-19 13:40:25 +02003450 break;
3451 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02003452 tc->cn = (const struct lysc_node *)tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02003453 break;
3454 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02003455 tc->cn = (const struct lysc_node *)tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02003456 break;
aPiecek03cb4872022-10-24 10:31:51 +02003457 case TRD_SECT_PLUG_DATA:
aPiecek96baa7f2021-04-23 12:32:00 +02003458 /* nothing to do */
aPiecek3f247652021-04-19 13:40:25 +02003459 break;
3460 default:
3461 assert(0);
3462 }
aPiecek03cb4872022-10-24 10:31:51 +02003463 node = troc_read_node(ca, tc);
aPiecek8f1073c2022-10-17 16:44:49 +02003464 }
3465
aPiecek03cb4872022-10-24 10:31:51 +02003466 if (tc->plugin_ctx.filtered) {
3467 node = troc_modi_next_sibling(ca, tc);
aPiecek8f1073c2022-10-17 16:44:49 +02003468 }
3469
aPiecek03cb4872022-10-24 10:31:51 +02003470 return node;
aPiecek8f1073c2022-10-17 16:44:49 +02003471}
3472
3473/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01003474 * Definition of tree browsing functions
aPiecek874ea4d2021-04-19 12:26:36 +02003475 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003476
aPiecek41219f92022-10-26 11:24:40 +02003477static uint32_t
3478trb_gap_to_opts(struct trt_node node)
aPiecek61d062b2020-11-02 11:05:09 +01003479{
aPiecek41219f92022-10-26 11:24:40 +02003480 uint32_t len = 0;
aPiecek61d062b2020-11-02 11:05:09 +01003481
aPiecek41219f92022-10-26 11:24:40 +02003482 if (node.name.keys) {
3483 return 0;
aPiecek61d062b2020-11-02 11:05:09 +01003484 }
3485
aPiecek41219f92022-10-26 11:24:40 +02003486 if (node.flags) {
3487 len += strlen(node.flags);
3488 /* space between flags and name */
3489 len += 1;
3490 } else {
3491 /* space between -- and name */
3492 len += 1;
3493 }
3494
3495 switch (node.name.type) {
3496 case TRD_NODE_CASE:
3497 /* ':' is already counted. Plus parentheses. */
3498 len += 2;
3499 break;
3500 case TRD_NODE_CHOICE:
3501 /* Plus parentheses. */
3502 len += 2;
3503 break;
3504 default:
3505 break;
3506 }
3507
3508 if (node.name.module_prefix) {
3509 len += strlen(node.name.module_prefix);
3510 }
3511 if (node.name.str) {
3512 len += strlen(node.name.str);
3513 }
aPiecek03cb4872022-10-24 10:31:51 +02003514 if (node.name.add_opts) {
3515 len += strlen(node.name.add_opts);
3516 }
aPiecek41219f92022-10-26 11:24:40 +02003517 if (node.name.opts) {
3518 len += strlen(node.name.opts);
3519 }
3520
3521 return len;
3522}
3523
3524static uint32_t
3525trb_gap_to_type(struct trt_node node)
3526{
aPiecek03cb4872022-10-24 10:31:51 +02003527 uint32_t len, opts_len;
aPiecek41219f92022-10-26 11:24:40 +02003528
3529 if (node.name.keys) {
3530 return 0;
3531 }
3532
3533 len = trb_gap_to_opts(node);
3534 /* Gap between opts and type. */
aPiecek03cb4872022-10-24 10:31:51 +02003535 opts_len = 0;
3536 opts_len += node.name.add_opts ? strlen(node.name.add_opts) : 0;
3537 opts_len += node.name.opts ? strlen(node.name.opts) : 0;
3538 if (opts_len >= TRD_INDENT_BEFORE_TYPE) {
aPiecek41219f92022-10-26 11:24:40 +02003539 /* At least one space should be there. */
3540 len += 1;
aPiecek03cb4872022-10-24 10:31:51 +02003541 } else if (node.name.add_opts || node.name.opts) {
3542 len += TRD_INDENT_BEFORE_TYPE - opts_len;
aPiecek41219f92022-10-26 11:24:40 +02003543 } else {
3544 len += TRD_INDENT_BEFORE_TYPE;
3545 }
3546
3547 return len;
aPiecek61d062b2020-11-02 11:05:09 +01003548}
3549
3550/**
aPiecek874ea4d2021-04-19 12:26:36 +02003551 * @brief Calculate the trt_indent_in_node.btw_opts_type indent size
3552 * for a particular node.
aPiecek41219f92022-10-26 11:24:40 +02003553 * @param[in] node for which we get btw_opts_type.
3554 * @param[in] max_gap_before_type is the maximum value of btw_opts_type
aPiecek874ea4d2021-04-19 12:26:36 +02003555 * that it can have.
3556 * @return Indent between \<opts\> and \<type\> for node.
aPiecek61d062b2020-11-02 11:05:09 +01003557 */
3558static int16_t
aPiecek41219f92022-10-26 11:24:40 +02003559trb_calc_btw_opts_type(struct trt_node node, int16_t max_gap_before_type)
aPiecek61d062b2020-11-02 11:05:09 +01003560{
aPiecek41219f92022-10-26 11:24:40 +02003561 uint32_t to_opts_len;
aPiecek61d062b2020-11-02 11:05:09 +01003562
aPiecek41219f92022-10-26 11:24:40 +02003563 to_opts_len = trb_gap_to_opts(node);
3564 if (to_opts_len == 0) {
3565 return 1;
3566 } else {
3567 return max_gap_before_type - to_opts_len;
3568 }
aPiecek61d062b2020-11-02 11:05:09 +01003569}
3570
3571/**
3572 * @brief Print node.
3573 *
aPiecek01598c02021-04-23 14:18:24 +02003574 * This function is wrapper for ::trp_print_entire_node().
aPiecek874ea4d2021-04-19 12:26:36 +02003575 * But difference is that take @p max_gap_before_type which will be
3576 * used to set the unified alignment.
aPiecek61d062b2020-11-02 11:05:09 +01003577 *
aPiecek9bdd7592021-05-20 08:13:20 +02003578 * @param[in] node to print.
aPiecek61d062b2020-11-02 11:05:09 +01003579 * @param[in] max_gap_before_type is number of indent before \<type\>.
3580 * @param[in] wr is wrapper for printing indentation before node.
aPiecek61d062b2020-11-02 11:05:09 +01003581 * @param[in] pc contains mainly functions for printing.
3582 * @param[in] tc is tree context.
3583 */
3584static void
aPiecek9bdd7592021-05-20 08:13:20 +02003585trb_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 +01003586{
aPiecek61d062b2020-11-02 11:05:09 +01003587 struct trt_indent_in_node ind = trp_default_indent_in_node(node);
3588
3589 if ((max_gap_before_type > 0) && (node.type.type != TRD_TYPE_EMPTY)) {
3590 /* print actual node with unified indent */
aPiecek41219f92022-10-26 11:24:40 +02003591 ind.btw_opts_type = trb_calc_btw_opts_type(node, max_gap_before_type);
aPiecek61d062b2020-11-02 11:05:09 +01003592 }
3593 /* after -> print actual node with default indent */
3594 trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print),
3595 TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out);
3596}
3597
3598/**
aPiecek874ea4d2021-04-19 12:26:36 +02003599 * @brief Check if parent of the current node is the last
3600 * of his siblings.
aPiecek61d062b2020-11-02 11:05:09 +01003601 *
aPiecek874ea4d2021-04-19 12:26:36 +02003602 * To mantain stability use this function only if the current node is
3603 * the first of the siblings.
3604 * Side-effect -> current node is set to the first sibling
3605 * if node has a parent otherwise no side-effect.
aPiecek61d062b2020-11-02 11:05:09 +01003606 *
aPiecek01598c02021-04-23 14:18:24 +02003607 * @param[in] fp contains all @ref TRP_tro callback functions.
aPiecek61d062b2020-11-02 11:05:09 +01003608 * @param[in,out] tc is tree context.
3609 * @return 1 if parent is last sibling otherwise 0.
3610 */
3611static ly_bool
aPiecek03cb4872022-10-24 10:31:51 +02003612trb_node_is_last_sibling(struct trt_fp_all fp, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003613{
aPiecek03cb4872022-10-24 10:31:51 +02003614 if (fp.read.if_parent_exists(tc)) {
aPiecek61d062b2020-11-02 11:05:09 +01003615 return !fp.read.if_sibling_exists(tc);
aPiecek03cb4872022-10-24 10:31:51 +02003616 } else {
3617 return !fp.read.if_sibling_exists(tc) && tc->plugin_ctx.last_schema;
aPiecek61d062b2020-11-02 11:05:09 +01003618 }
3619}
3620
3621/**
aPiecek41219f92022-10-26 11:24:40 +02003622 * @brief For all siblings find maximal space from '--' to \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01003623 *
3624 * Side-effect -> Current node is set to the first sibling.
3625 *
3626 * @param[in] ca contains inherited data from ancestors.
3627 * @param[in] pc contains mainly functions for printing.
3628 * @param[in,out] tc is tree context.
aPiecek41219f92022-10-26 11:24:40 +02003629 * @return max space.
aPiecek61d062b2020-11-02 11:05:09 +01003630 */
aPiecek41219f92022-10-26 11:24:40 +02003631static uint32_t
3632trb_max_gap_to_type(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003633{
aPiecek03cb4872022-10-24 10:31:51 +02003634 struct trt_node node;
aPiecek41219f92022-10-26 11:24:40 +02003635 int32_t maxlen, len;
aPiecek61d062b2020-11-02 11:05:09 +01003636
aPiecek41219f92022-10-26 11:24:40 +02003637 maxlen = 0;
aPiecek03cb4872022-10-24 10:31:51 +02003638 for (node = pc->fp.modify.first_sibling(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003639 !trp_node_is_empty(node);
3640 node = pc->fp.modify.next_sibling(ca, tc)) {
aPiecek41219f92022-10-26 11:24:40 +02003641 len = trb_gap_to_type(node);
3642 maxlen = maxlen < len ? len : maxlen;
aPiecek61d062b2020-11-02 11:05:09 +01003643 }
aPiecek03cb4872022-10-24 10:31:51 +02003644 pc->fp.modify.first_sibling(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003645
aPiecek41219f92022-10-26 11:24:40 +02003646 return maxlen;
aPiecek61d062b2020-11-02 11:05:09 +01003647}
3648
3649/**
aPiecek874ea4d2021-04-19 12:26:36 +02003650 * @brief Find out if it is possible to unify
3651 * the alignment before \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01003652 *
aPiecek874ea4d2021-04-19 12:26:36 +02003653 * The goal is for all node siblings to have the same alignment
3654 * for \<type\> as if they were in a column. All siblings who cannot
3655 * adapt because they do not fit on the line at all are ignored.
aPiecek61d062b2020-11-02 11:05:09 +01003656 * Side-effect -> Current node is set to the first sibling.
3657 *
3658 * @param[in] ca contains inherited data from ancestors.
3659 * @param[in] pc contains mainly functions for printing.
3660 * @param[in,out] tc is tree context.
aPiecek874ea4d2021-04-19 12:26:36 +02003661 * @return positive number indicating the maximum number of spaces
aPiecek41219f92022-10-26 11:24:40 +02003662 * before \<type\> if the length of the flags, node name and opts is 0. To calculate
aPiecek874ea4d2021-04-19 12:26:36 +02003663 * the trt_indent_in_node.btw_opts_type indent size for a particular
aPiecek01598c02021-04-23 14:18:24 +02003664 * node, use the ::trb_calc_btw_opts_type().
aPiecek61d062b2020-11-02 11:05:09 +01003665*/
3666static uint32_t
3667trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3668{
aPiecek41219f92022-10-26 11:24:40 +02003669 return trb_max_gap_to_type(ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003670}
3671
3672/**
aPiecekb8d5a0a2021-05-20 08:20:24 +02003673 * @brief Check if there is no case statement
3674 * under the choice statement.
3675 *
3676 * It can return true only if the Parsed schema tree
3677 * is used for browsing.
3678 *
3679 * @param[in] tc is tree context.
3680 * @return 1 if implicit case statement is present otherwise 0.
3681 */
3682static ly_bool
3683trb_need_implicit_node_case(struct trt_tree_ctx *tc)
3684{
3685 return !tc->lysc_tree && tc->pn->parent &&
3686 (tc->pn->parent->nodetype & LYS_CHOICE) &&
3687 (tc->pn->nodetype & (LYS_ANYDATA | LYS_CHOICE | LYS_CONTAINER |
3688 LYS_LEAF | LYS_LEAFLIST));
3689}
3690
3691static void trb_print_subtree_nodes(struct trt_node node, uint32_t max_gap_before_type,
3692 struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc);
3693
3694/**
3695 * @brief Print implicit case node and his subtree.
3696 *
3697 * @param[in] node is child of implicit case.
3698 * @param[in] wr is wrapper for printing identation before node.
aPiecekb8d5a0a2021-05-20 08:20:24 +02003699 * @param[in] pc contains mainly functions for printing.
3700 * @param[in] tc is tree context. Its settings should be the same as
3701 * before the function call.
aPiecek49be5b42022-10-19 10:57:56 +02003702 * @return new indentation wrapper for @p node.
aPiecekb8d5a0a2021-05-20 08:20:24 +02003703 */
aPiecek49be5b42022-10-19 10:57:56 +02003704static struct trt_wrapper
3705trb_print_implicit_node(struct trt_node node, struct trt_wrapper wr, struct trt_printer_ctx *pc,
3706 struct trt_tree_ctx *tc)
aPiecekb8d5a0a2021-05-20 08:20:24 +02003707{
3708 struct trt_node case_node;
3709 struct trt_wrapper wr_case_child;
3710
3711 case_node = tro_create_implicit_case_node(node);
3712 ly_print_(pc->out, "\n");
3713 trb_print_entire_node(case_node, 0, wr, pc, tc);
aPiecek49be5b42022-10-19 10:57:56 +02003714 ly_print_(pc->out, "\n");
aPiecekb8d5a0a2021-05-20 08:20:24 +02003715 wr_case_child = pc->fp.read.if_sibling_exists(tc) ?
3716 trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr);
aPiecek49be5b42022-10-19 10:57:56 +02003717 return wr_case_child;
aPiecekb8d5a0a2021-05-20 08:20:24 +02003718}
3719
3720/**
aPiecek153b00f2021-04-20 13:52:57 +02003721 * @brief Calculate the wrapper about how deep in the tree the node is.
ekinzie0ab8b302022-10-10 03:03:57 -04003722 * @param[in] wr_in A wrapper to use as a starting point
aPiecek153b00f2021-04-20 13:52:57 +02003723 * @param[in] node from which to count.
3724 * @return wrapper for @p node.
3725 */
3726static struct trt_wrapper
ekinzie0ab8b302022-10-10 03:03:57 -04003727trb_count_depth(const struct trt_wrapper *wr_in, const struct lysc_node *node)
aPiecek153b00f2021-04-20 13:52:57 +02003728{
ekinzie0ab8b302022-10-10 03:03:57 -04003729 struct trt_wrapper wr = wr_in ? *wr_in : TRP_INIT_WRAPPER_TOP;
aPiecek153b00f2021-04-20 13:52:57 +02003730 const struct lysc_node *parent;
3731
3732 if (!node) {
3733 return wr;
3734 }
3735
3736 for (parent = node->parent; parent; parent = parent->parent) {
3737 wr = trp_wrapper_set_shift(wr);
3738 }
3739
3740 return wr;
3741}
3742
3743/**
3744 * @brief Print all parent nodes of @p node and the @p node itself.
3745 *
3746 * Side-effect -> trt_tree_ctx.cn will be set to @p node.
3747 *
3748 * @param[in] node on which the function is focused.
aPiecek7ed8d032022-10-10 12:32:27 +02003749 * @param[in] wr_in for printing identation before node.
aPiecek01598c02021-04-23 14:18:24 +02003750 * @param[in] pc is @ref TRP_trp settings.
aPiecek153b00f2021-04-20 13:52:57 +02003751 * @param[in,out] tc is context of tree printer.
aPiecek153b00f2021-04-20 13:52:57 +02003752 */
3753static void
ekinzie0ab8b302022-10-10 03:03:57 -04003754trb_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 +02003755{
aPiecek41219f92022-10-26 11:24:40 +02003756 uint32_t max_gap_before_type;
aPiecek153b00f2021-04-20 13:52:57 +02003757 struct trt_wrapper wr;
aPiecek9bdd7592021-05-20 08:13:20 +02003758 struct trt_node print_node;
aPiecek153b00f2021-04-20 13:52:57 +02003759
3760 assert(pc && tc && tc->section == TRD_SECT_MODULE);
3761
3762 /* stop recursion */
3763 if (!node) {
3764 return;
3765 }
ekinzie0ab8b302022-10-10 03:03:57 -04003766 trb_print_parents(node->parent, wr_in, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003767
3768 /* setup for printing */
3769 tc->cn = node;
ekinzie0ab8b302022-10-10 03:03:57 -04003770 wr = trb_count_depth(wr_in, node);
aPiecek153b00f2021-04-20 13:52:57 +02003771
3772 /* print node */
3773 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02003774 print_node = pc->fp.read.node(TRP_EMPTY_PARENT_CACHE, tc);
aPiecek41219f92022-10-26 11:24:40 +02003775 max_gap_before_type = trb_max_gap_to_type(TRP_EMPTY_PARENT_CACHE, pc, tc);
3776 trb_print_entire_node(print_node, max_gap_before_type, wr, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003777}
3778
3779/**
aPiecekdc8fd572021-04-19 10:47:23 +02003780 * @brief Set current node on its child.
3781 * @param[in,out] tc contains current node.
3782 */
3783static void
3784trb_tree_ctx_set_child(struct trt_tree_ctx *tc)
3785{
aPiecek03cb4872022-10-24 10:31:51 +02003786 const void *node = tro_tree_ctx_get_child(tc);
aPiecek3f247652021-04-19 13:40:25 +02003787
3788 if (tc->lysc_tree) {
3789 tc->cn = node;
3790 } else {
3791 tc->pn = node;
3792 }
aPiecekdc8fd572021-04-19 10:47:23 +02003793}
3794
3795/**
aPiecek03cb4872022-10-24 10:31:51 +02003796 * @brief Move extension iterator to the next position.
3797 *
3798 * @param[in] lysc_tree flag if exts is from compiled tree.
3799 * @param[in] exts is current array of extensions.
3800 * @param[in,out] i is state of iterator.
3801 * @return Pointer to the first/next extension.
3802 */
3803static void *
3804trb_ext_iter_next(ly_bool lysc_tree, void *exts, uint64_t *i)
3805{
3806 void *ext = NULL;
3807 struct lysc_ext_instance *ce;
3808 struct lysp_ext_instance *pe;
3809
3810 if (!exts) {
3811 return NULL;
3812 }
3813
3814 if (lysc_tree) {
3815 ce = exts;
3816 while (*i < LY_ARRAY_COUNT(ce)) {
3817 if (trp_ext_parent_is_valid(1, &ce[*i])) {
3818 ext = &ce[*i];
3819 break;
3820 }
3821 ++(*i);
3822 }
3823 } else {
3824 pe = exts;
3825 while (*i < LY_ARRAY_COUNT(pe)) {
3826 if (trp_ext_parent_is_valid(0, &pe[*i])) {
3827 ext = &pe[*i];
3828 break;
3829 }
3830 ++(*i);
3831 }
3832 }
3833 ++(*i);
3834
3835 return ext;
3836}
3837
3838/**
3839 * @brief Iterate over extensions in module.
3840 *
3841 * @param[in] tc contains current node.
3842 * @param[in,out] i is state of iterator.
3843 * @return First/next extension or NULL.
3844 */
3845static void *
3846trb_mod_ext_iter(const struct trt_tree_ctx *tc, uint64_t *i)
3847{
3848 if (tc->lysc_tree) {
3849 return trb_ext_iter_next(1, tc->cmod->exts, i);
3850 } else {
3851 return trb_ext_iter_next(0, tc->pmod->exts, i);
3852 }
3853}
3854
3855/**
3856 * @brief Iterate over extensions in node.
3857 *
3858 * @param[in] tc contains current node.
3859 * @param[in,out] i is state of iterator.
3860 * @return First/next extension or NULL.
3861 */
3862static void *
3863trb_ext_iter(const struct trt_tree_ctx *tc, uint64_t *i)
3864{
3865 if (tc->lysc_tree) {
3866 return trb_ext_iter_next(1, tc->cn->exts, i);
3867 } else {
3868 return trb_ext_iter_next(0, tc->pn->exts, i);
3869 }
3870}
3871
3872/**
3873 * @brief Initialize plugin context.
3874 *
3875 * @param[in] compiled if @p ext is lysc structure.
3876 * @param[in] ext current processed extension.
3877 * @param[out] plug_ctx is plugin context which will be initialized.
3878 * @return LY_ERR value.
3879 */
3880static LY_ERR
3881tro_ext_printer_tree(ly_bool compiled, void *ext, const struct lyspr_tree_ctx *plug_ctx)
3882{
3883 struct lysc_ext_instance *ext_comp;
3884 struct lysp_ext_instance *ext_pars;
3885 const char *flags = NULL, *add_opts = NULL;
3886
3887 if (compiled) {
3888 ext_comp = ext;
3889 return ext_comp->def->plugin->printer_ctree(ext, plug_ctx, &flags, &add_opts);
3890 } else {
3891 ext_pars = ext;
3892 return ext_pars->record->plugin.printer_ptree(ext, plug_ctx, &flags, &add_opts);
3893 }
3894}
3895
3896/**
3897 * @brief Reset tree context by plugin context.
3898 *
3899 * @param[in] plug_ctx is plugin context.
3900 * @param[in] i which index in schemas should be used.
3901 * @param[in] pc are printing functions.
3902 * @param[out] tc tree context which will be updated.
3903 */
3904static void
3905trm_reset_tree_ctx_by_plugin(struct lyspr_tree_ctx *plug_ctx, LY_ARRAY_COUNT_TYPE i, struct trt_printer_ctx *pc,
3906 struct trt_tree_ctx *tc)
3907{
3908 tc->plugin_ctx.ctx = plug_ctx;
3909 tc->pmod = NULL;
3910 tc->cmod = NULL;
3911 if (plug_ctx->schemas[i].compiled) {
3912 tc->lysc_tree = 1;
3913 tc->cn = plug_ctx->schemas[i].ctree;
3914 tc->plugin_ctx.schema = &plug_ctx->schemas[i];
3915 pc->fp.modify = TRP_TRT_FP_MODIFY_COMPILED;
3916 pc->fp.read = TRP_TRT_FP_READ_COMPILED;
3917 } else {
3918 tc->lysc_tree = 0;
3919 tc->pn = plug_ctx->schemas[i].ptree;
3920 tc->tpn = tc->pn;
3921 tc->plugin_ctx.schema = &plug_ctx->schemas[i];
3922 pc->fp.modify = TRP_TRT_FP_MODIFY_PARSED;
3923 pc->fp.read = TRP_TRT_FP_READ_PARSED;
3924 }
3925}
3926
3927/**
3928 * @brief Print schemas from plugin context.
3929 *
3930 * @param[in] plug_ctx is plugin context.
3931 * @param[in] last_nodes if this schemas will be the last.
3932 * @param[in] max_gap_before_type is gap before type.
3933 * @param[in] wr is indentation wrapper.
3934 * @param[in] ca containing information from parent.
3935 * @param[in] pc functions for tree traversing.
3936 * @param[in] tc current tree context.
3937 */
3938static void
3939trb_ext_print_schemas(struct lyspr_tree_ctx *plug_ctx, ly_bool last_nodes, uint32_t max_gap_before_type,
3940 struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3941{
3942 LY_ARRAY_COUNT_TYPE i;
3943 struct trt_printer_ctx pc_dupl;
3944 struct trt_tree_ctx tc_dupl;
3945
3946 tc_dupl = *tc;
3947 pc_dupl = *pc;
3948
3949 LY_ARRAY_FOR(plug_ctx->schemas, i) {
3950 trm_reset_tree_ctx_by_plugin(plug_ctx, i, pc, tc);
3951 tc->plugin_ctx.last_schema = last_nodes && ((i + 1) == LY_ARRAY_COUNT(plug_ctx->schemas));
3952 trb_print_subtree_nodes(TRP_EMPTY_NODE, max_gap_before_type, wr, ca, pc, tc);
3953 *tc = tc_dupl;
3954 }
3955
3956 *pc = pc_dupl;
3957}
3958
3959/**
3960 * @brief Count unified indentation across schemas from extension instance.
3961 *
3962 * @param[in] plug_ctx is plugin context.
3963 * @param[in] ca containing parent settings.
3964 * @param[out] max_gap_before_type is result of unified indent.
3965 * @param[in] pc functions for tree traversing.
3966 * @param[in] tc is tree context.
3967 */
3968static void
3969trb_ext_try_unified_indent(struct lyspr_tree_ctx *plug_ctx, struct trt_parent_cache ca, uint32_t *max_gap_before_type,
3970 struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3971{
3972 LY_ARRAY_COUNT_TYPE i;
3973 struct trt_printer_ctx pc_dupl;
3974 struct trt_tree_ctx tc_dupl;
3975 uint32_t max;
3976
3977 tc_dupl = *tc;
3978 pc_dupl = *pc;
3979
3980 LY_ARRAY_FOR(plug_ctx->schemas, i) {
3981 trm_reset_tree_ctx_by_plugin(plug_ctx, i, pc, tc);
3982 max = trb_try_unified_indent(ca, pc, tc);
3983 *max_gap_before_type = max > *max_gap_before_type ? max : *max_gap_before_type;
3984 *tc = tc_dupl;
3985 }
3986
3987 *pc = pc_dupl;
3988}
3989
3990/**
3991 * @brief For every extension instance print all schemas.
3992 *
3993 * @param[in] wr indentation wrapper for node.
3994 * @param[in] ca parent settings.
3995 * @param[in] pc function used for tree traversing.
3996 * @param[in] tc tree context.
3997 */
3998static void
3999trb_ext_print_instances(struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc,
4000 struct trt_tree_ctx *tc)
4001{
4002 LY_ERR rc;
4003 LY_ARRAY_COUNT_TYPE i;
4004 uint64_t last_instance = UINT64_MAX;
4005 void *ext;
4006 ly_bool child_exists;
4007 uint32_t max, max_gap_before_type = 0;
4008
4009 ca = tro_parent_cache_for_child(ca, tc);
4010 /* if node is last sibling, then do not add '|' to wrapper */
4011 wr = trb_node_is_last_sibling(pc->fp, tc) ?
4012 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
4013
4014 if (tc->lysc_tree) {
4015 child_exists = tro_next_child(tc->cn, tc) ? 1 : 0;
4016 } else {
4017 child_exists = tro_next_child(tc->pn, tc) ? 1 : 0;
4018 }
4019
4020 i = 0;
4021 while ((ext = trb_ext_iter(tc, &i))) {
4022 struct lyspr_tree_ctx plug_ctx = {0};
4023
4024 rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx);
4025 LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end);
4026 trb_ext_try_unified_indent(&plug_ctx, ca, &max_gap_before_type, pc, tc);
4027 if (plug_ctx.schemas) {
4028 last_instance = i;
4029 }
4030 trp_ext_free_plugin_ctx(&plug_ctx);
4031 }
4032
4033 if (child_exists) {
4034 pc->fp.modify.next_child(ca, tc);
4035 max = trb_try_unified_indent(ca, pc, tc);
4036 max_gap_before_type = max > max_gap_before_type ? max : max_gap_before_type;
4037 pc->fp.modify.parent(tc);
4038 }
4039
4040 i = 0;
4041 while ((ext = trb_ext_iter(tc, &i))) {
4042 struct lyspr_tree_ctx plug_ctx = {0};
4043
4044 rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx);
4045 LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end);
4046 if (!child_exists && (last_instance == i)) {
4047 trb_ext_print_schemas(&plug_ctx, 1, max_gap_before_type, wr, ca, pc, tc);
4048 } else {
4049 trb_ext_print_schemas(&plug_ctx, 0, max_gap_before_type, wr, ca, pc, tc);
4050 }
4051 trp_ext_free_plugin_ctx(&plug_ctx);
4052 }
4053
4054end:
4055 return;
4056}
4057
4058/**
aPiecek61d062b2020-11-02 11:05:09 +01004059 * @brief Print subtree of nodes.
4060 *
4061 * The current node is expected to be the root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02004062 * Before root node is no linebreak printing. This must be addressed by
4063 * the caller. Root node will also be printed. Behind last printed node
4064 * is no linebreak.
aPiecek61d062b2020-11-02 11:05:09 +01004065 *
aPiecek9bdd7592021-05-20 08:13:20 +02004066 * @param[in] node is root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02004067 * @param[in] max_gap_before_type is result from
aPiecek01598c02021-04-23 14:18:24 +02004068 * ::trb_try_unified_indent() function for root node.
4069 * Set parameter to 0 if distance does not matter.
aPiecek874ea4d2021-04-19 12:26:36 +02004070 * @param[in] wr is wrapper saying how deep in the whole tree
4071 * is the root of the subtree.
4072 * @param[in] ca is parent_cache from root's parent.
4073 * If root is top-level node, insert ::TRP_EMPTY_PARENT_CACHE.
aPiecek01598c02021-04-23 14:18:24 +02004074 * @param[in] pc is @ref TRP_trp settings.
aPiecek874ea4d2021-04-19 12:26:36 +02004075 * @param[in,out] tc is context of tree printer.
aPiecek61d062b2020-11-02 11:05:09 +01004076 */
4077static void
aPiecek9bdd7592021-05-20 08:13:20 +02004078trb_print_subtree_nodes(struct trt_node node, uint32_t max_gap_before_type, struct trt_wrapper wr,
4079 struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004080{
aPiecek03cb4872022-10-24 10:31:51 +02004081 if (!trp_node_is_empty(node)) {
4082 /* Print root node. */
4083 trb_print_entire_node(node, max_gap_before_type, wr, pc, tc);
4084 if (trp_ext_is_present_in_node(tc)) {
4085 trb_ext_print_instances(wr, ca, pc, tc);
4086 }
4087 /* if node is last sibling, then do not add '|' to wrapper */
4088 wr = trb_node_is_last_sibling(pc->fp, tc) ?
4089 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
4090 /* go to the child */
4091 ca = tro_parent_cache_for_child(ca, tc);
4092 node = pc->fp.modify.next_child(ca, tc);
4093 if (trp_node_is_empty(node)) {
4094 return;
4095 }
4096 /* TODO comment browse through instances + filtered. try unified indentation for children */
4097 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
4098 } else {
4099 /* Root node is ignored, continue with child. */
4100 node = pc->fp.modify.first_sibling(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01004101 }
aPiecek67521c22022-10-19 09:15:02 +02004102
aPiecek67521c22022-10-19 09:15:02 +02004103 do {
aPiecek03cb4872022-10-24 10:31:51 +02004104 if (!tc->plugin_ctx.filtered && !trb_need_implicit_node_case(tc)) {
aPiecek67521c22022-10-19 09:15:02 +02004105 /* normal behavior */
4106 ly_print_(pc->out, "\n");
aPiecek49be5b42022-10-19 10:57:56 +02004107 trb_print_subtree_nodes(node, max_gap_before_type, wr, ca, pc, tc);
aPiecek03cb4872022-10-24 10:31:51 +02004108 } else if (!tc->plugin_ctx.filtered) {
aPiecek49be5b42022-10-19 10:57:56 +02004109 struct trt_wrapper wr_case_child;
4110
4111 wr_case_child = trb_print_implicit_node(node, wr, pc, tc);
4112 trb_print_subtree_nodes(node, max_gap_before_type, wr_case_child, ca, pc, tc);
aPiecek67521c22022-10-19 09:15:02 +02004113 }
4114 /* go to the actual node's sibling */
aPiecek49be5b42022-10-19 10:57:56 +02004115 node = pc->fp.modify.next_sibling(ca, tc);
4116 } while (!trp_node_is_empty(node));
aPiecek67521c22022-10-19 09:15:02 +02004117
4118 /* get back from child node to root node */
4119 pc->fp.modify.parent(tc);
aPiecek61d062b2020-11-02 11:05:09 +01004120}
4121
4122/**
aPiecek61d062b2020-11-02 11:05:09 +01004123 * @brief Print all parents and their children.
4124 *
aPiecek874ea4d2021-04-19 12:26:36 +02004125 * This function is suitable for printing top-level nodes that
aPiecek01598c02021-04-23 14:18:24 +02004126 * do not have ancestors. Function call ::trb_print_subtree_nodes()
aPiecek153b00f2021-04-20 13:52:57 +02004127 * for all top-level siblings. Use this function after 'module' keyword
4128 * or 'augment' and so. The nodes may not be exactly top-level in the
4129 * tree, but the function considers them that way.
aPiecek61d062b2020-11-02 11:05:09 +01004130 *
aPiecek153b00f2021-04-20 13:52:57 +02004131 * @param[in] wr is wrapper saying how deeply the top-level nodes are
4132 * immersed in the tree.
aPiecek61d062b2020-11-02 11:05:09 +01004133 * @param[pc] pc contains mainly functions for printing.
4134 * @param[in,out] tc is tree context.
4135 */
4136static void
aPiecek153b00f2021-04-20 13:52:57 +02004137trb_print_family_tree(struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004138{
aPiecek61d062b2020-11-02 11:05:09 +01004139 struct trt_parent_cache ca;
aPiecek9bdd7592021-05-20 08:13:20 +02004140 struct trt_node node;
aPiecek61d062b2020-11-02 11:05:09 +01004141 uint32_t max_gap_before_type;
4142
aPiecek03cb4872022-10-24 10:31:51 +02004143 if (!tro_tree_ctx_get_node(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004144 return;
4145 }
4146
aPiecek61d062b2020-11-02 11:05:09 +01004147 ca = TRP_EMPTY_PARENT_CACHE;
aPiecek61d062b2020-11-02 11:05:09 +01004148 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
4149
aPiecek3f247652021-04-19 13:40:25 +02004150 if (!tc->lysc_tree) {
aPiecek03cb4872022-10-24 10:31:51 +02004151 if ((tc->section == TRD_SECT_GROUPING) && (tc->tpn == tc->pn->parent)) {
aPiecek3f247652021-04-19 13:40:25 +02004152 ca.lys_config = 0x0;
4153 }
aPiecekdc8fd572021-04-19 10:47:23 +02004154 }
4155
aPiecek03cb4872022-10-24 10:31:51 +02004156 for (node = pc->fp.modify.first_sibling(ca, tc);
4157 !trp_node_is_empty(node);
4158 node = pc->fp.modify.next_sibling(ca, tc)) {
aPiecek61d062b2020-11-02 11:05:09 +01004159 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02004160 trb_print_subtree_nodes(node, max_gap_before_type, wr, ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01004161 }
4162}
4163
aPiecek874ea4d2021-04-19 12:26:36 +02004164/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004165 * Definition of trm main functions
aPiecek874ea4d2021-04-19 12:26:36 +02004166 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004167
4168/**
aPiecekdc8fd572021-04-19 10:47:23 +02004169 * @brief Settings if lysp_node are used for browsing through the tree.
aPiecek61d062b2020-11-02 11:05:09 +01004170 *
aPiecekdc8fd572021-04-19 10:47:23 +02004171 * @param[in] module YANG schema tree structure representing
4172 * YANG module.
aPiecek61d062b2020-11-02 11:05:09 +01004173 * @param[in] out is output handler.
aPiecekdc8fd572021-04-19 10:47:23 +02004174 * @param[in] max_line_length is the maximum line length limit
4175 * that should not be exceeded.
4176 * @param[in,out] pc will be adapted to lysp_tree.
4177 * @param[in,out] tc will be adapted to lysp_tree.
aPiecek61d062b2020-11-02 11:05:09 +01004178 */
4179static void
aPiecek03cb4872022-10-24 10:31:51 +02004180trm_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length,
4181 struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004182{
aPiecekdc8fd572021-04-19 10:47:23 +02004183 *tc = (struct trt_tree_ctx) {
aPiecek3f247652021-04-19 13:40:25 +02004184 .lysc_tree = 0,
aPiecekdc8fd572021-04-19 10:47:23 +02004185 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02004186 .pmod = module->parsed,
4187 .cmod = NULL,
4188 .pn = module->parsed ? module->parsed->data : NULL,
4189 .tpn = module->parsed ? module->parsed->data : NULL,
aPiecek7ed8d032022-10-10 12:32:27 +02004190 .cn = NULL,
aPiecek03cb4872022-10-24 10:31:51 +02004191 .last_error = 0,
4192 .plugin_ctx.ctx = NULL,
4193 .plugin_ctx.schema = NULL,
4194 .plugin_ctx.filtered = 0,
4195 .plugin_ctx.node_overr = TRP_TREE_CTX_EMPTY_NODE_OVERR,
4196 .plugin_ctx.last_schema = 1,
4197 .plugin_ctx.last_error = 0
aPiecekdc8fd572021-04-19 10:47:23 +02004198 };
aPiecek61d062b2020-11-02 11:05:09 +01004199
aPiecekdc8fd572021-04-19 10:47:23 +02004200 pc->out = out;
4201
aPiecek03cb4872022-10-24 10:31:51 +02004202 pc->fp.modify = TRP_TRT_FP_MODIFY_PARSED;
4203 pc->fp.read = TRP_TRT_FP_READ_PARSED;
aPiecek61d062b2020-11-02 11:05:09 +01004204
aPiecekdc8fd572021-04-19 10:47:23 +02004205 pc->fp.print = (struct trt_fp_print) {
aPiecek3f247652021-04-19 13:40:25 +02004206 .print_features_names = tro_print_features_names,
4207 .print_keys = tro_print_keys
aPiecek61d062b2020-11-02 11:05:09 +01004208 };
4209
aPiecekdc8fd572021-04-19 10:47:23 +02004210 pc->max_line_length = max_line_length;
aPiecek61d062b2020-11-02 11:05:09 +01004211}
4212
4213/**
aPiecek3f247652021-04-19 13:40:25 +02004214 * @brief Settings if lysc_node are used for browsing through the tree.
4215 *
4216 * Pointers to current nodes will be set to module data.
4217 *
4218 * @param[in] module YANG schema tree structure representing
4219 * YANG module.
4220 * @param[in] out is output handler.
4221 * @param[in] max_line_length is the maximum line length limit
4222 * that should not be exceeded.
4223 * @param[in,out] pc will be adapted to lysc_tree.
4224 * @param[in,out] tc will be adapted to lysc_tree.
4225 */
4226static void
aPiecek03cb4872022-10-24 10:31:51 +02004227trm_lysc_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length,
4228 struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek3f247652021-04-19 13:40:25 +02004229{
4230 *tc = (struct trt_tree_ctx) {
4231 .lysc_tree = 1,
4232 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02004233 .pmod = module->parsed,
4234 .cmod = module->compiled,
aPiecek3f247652021-04-19 13:40:25 +02004235 .tpn = NULL,
4236 .pn = NULL,
aPiecek7ed8d032022-10-10 12:32:27 +02004237 .cn = module->compiled->data,
aPiecek03cb4872022-10-24 10:31:51 +02004238 .last_error = 0,
4239 .plugin_ctx.ctx = NULL,
4240 .plugin_ctx.schema = NULL,
4241 .plugin_ctx.filtered = 0,
4242 .plugin_ctx.node_overr = TRP_TREE_CTX_EMPTY_NODE_OVERR,
4243 .plugin_ctx.last_schema = 1,
4244 .plugin_ctx.last_error = 0
aPiecek3f247652021-04-19 13:40:25 +02004245 };
4246
4247 pc->out = out;
4248
aPiecek03cb4872022-10-24 10:31:51 +02004249 pc->fp.modify = TRP_TRT_FP_MODIFY_COMPILED;
4250 pc->fp.read = TRP_TRT_FP_READ_COMPILED;
aPiecek3f247652021-04-19 13:40:25 +02004251
4252 pc->fp.print = (struct trt_fp_print) {
4253 .print_features_names = tro_print_features_names,
4254 .print_keys = tro_print_keys
4255 };
4256
4257 pc->max_line_length = max_line_length;
4258}
4259
4260/**
4261 * @brief Reset settings to browsing through the lysc tree.
aPiecek01598c02021-04-23 14:18:24 +02004262 * @param[in,out] pc resets to @ref TRP_troc functions.
aPiecek3f247652021-04-19 13:40:25 +02004263 * @param[in,out] tc resets to lysc browsing.
4264 */
4265static void
4266trm_reset_to_lysc_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4267{
aPiecek40f22402022-10-14 10:48:08 +02004268 LY_ERR erc;
4269
4270 erc = tc->last_error;
aPiecek03cb4872022-10-24 10:31:51 +02004271 trp_ext_free_node_override(&tc->plugin_ctx.node_overr, &tc->plugin_ctx.filtered);
4272 trm_lysc_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc);
aPiecek40f22402022-10-14 10:48:08 +02004273 tc->last_error = erc;
aPiecek3f247652021-04-19 13:40:25 +02004274}
4275
4276/**
4277 * @brief Reset settings to browsing through the lysp tree.
aPiecek01598c02021-04-23 14:18:24 +02004278 * @param[in,out] pc resets to @ref TRP_trop functions.
aPiecek3f247652021-04-19 13:40:25 +02004279 * @param[in,out] tc resets to lysp browsing.
4280 */
4281static void
4282trm_reset_to_lysp_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4283{
aPiecek40f22402022-10-14 10:48:08 +02004284 LY_ERR erc;
4285
4286 erc = tc->last_error;
aPiecek03cb4872022-10-24 10:31:51 +02004287 trp_ext_free_node_override(&tc->plugin_ctx.node_overr, &tc->plugin_ctx.filtered);
4288 trm_lysp_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc);
aPiecek40f22402022-10-14 10:48:08 +02004289 tc->last_error = erc;
aPiecek3f247652021-04-19 13:40:25 +02004290}
4291
4292/**
4293 * @brief If augment's target node is located on the current module.
4294 * @param[in] pn is examined augment.
4295 * @param[in] pmod is current module.
4296 * @return 1 if nodeid refers to the local node, otherwise 0.
4297 */
4298static ly_bool
4299trm_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod)
4300{
4301 const char *id, *prefix, *name;
4302 size_t prefix_len, name_len;
4303 const struct lys_module *mod;
4304 ly_bool ret = 0;
4305
4306 if (pn == NULL) {
4307 return ret;
4308 }
4309
4310 id = pn->nodeid;
4311 if (!id) {
4312 return ret;
4313 }
4314 /* only absolute-schema-nodeid is taken into account */
4315 assert(id[0] == '/');
4316 ++id;
4317
4318 ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len);
4319 if (prefix) {
Radek Krejci8df109d2021-04-23 12:19:08 +02004320 mod = ly_resolve_prefix(pmod->mod->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, pmod);
Michal Vasko3003c9a2022-03-29 12:10:00 +02004321 ret = mod ? (mod->parsed == pmod) : 0;
aPiecek3f247652021-04-19 13:40:25 +02004322 } else {
4323 ret = 1;
4324 }
4325
4326 return ret;
4327}
4328
4329/**
aPiecek96baa7f2021-04-23 12:32:00 +02004330 * @brief Printing section module, rpcs, notifications or yang-data.
aPiecek61d062b2020-11-02 11:05:09 +01004331 *
aPiecekdc8fd572021-04-19 10:47:23 +02004332 * First node must be the first child of 'module',
aPiecek96baa7f2021-04-23 12:32:00 +02004333 * 'rpcs', 'notifications' or 'yang-data'.
aPiecek61d062b2020-11-02 11:05:09 +01004334 *
aPiecekdc8fd572021-04-19 10:47:23 +02004335 * @param[in] ks is section representation.
4336 * @param[in] pc contains mainly functions for printing.
4337 * @param[in,out] tc is the tree context.
aPiecek61d062b2020-11-02 11:05:09 +01004338 */
4339static void
aPiecekdc8fd572021-04-19 10:47:23 +02004340trm_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 +01004341{
aPiecek03cb4872022-10-24 10:31:51 +02004342 assert(ks.section_name);
aPiecekdc8fd572021-04-19 10:47:23 +02004343
aPiecek03cb4872022-10-24 10:31:51 +02004344 trp_print_keyword_stmt(ks, pc->max_line_length, pc->out);
4345 if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) || !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) {
aPiecek153b00f2021-04-20 13:52:57 +02004346 trb_print_family_tree(TRP_INIT_WRAPPER_TOP, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004347 } else {
aPiecek153b00f2021-04-20 13:52:57 +02004348 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004349 }
4350}
4351
4352/**
aPiecek96baa7f2021-04-23 12:32:00 +02004353 * @brief Printing section augment or grouping.
aPiecekdc8fd572021-04-19 10:47:23 +02004354 *
aPiecek96baa7f2021-04-23 12:32:00 +02004355 * First node is 'augment' or 'grouping' itself.
aPiecekdc8fd572021-04-19 10:47:23 +02004356 *
4357 * @param[in] ks is section representation.
4358 * @param[in] pc contains mainly functions for printing.
4359 * @param[in,out] tc is the tree context.
4360 */
4361static void
4362trm_print_section_as_subtree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4363{
aPiecek03cb4872022-10-24 10:31:51 +02004364 assert(ks.section_name);
4365 trp_print_keyword_stmt(ks, pc->max_line_length, pc->out);
aPiecekdc8fd572021-04-19 10:47:23 +02004366 trb_tree_ctx_set_child(tc);
aPiecek153b00f2021-04-20 13:52:57 +02004367 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004368}
4369
4370/**
4371 * @brief Print 'module' keyword, its name and all nodes.
4372 * @param[in] pc contains mainly functions for printing.
4373 * @param[in,out] tc is the tree context.
4374 */
4375static void
4376trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4377{
4378 trm_print_section_as_family_tree(pc->fp.read.module_name(tc), pc, tc);
4379}
4380
4381/**
4382 * @brief For all augment sections: print 'augment' keyword,
4383 * its target node and all nodes.
4384 * @param[in] pc contains mainly functions for printing.
4385 * @param[in,out] tc is the tree context.
4386 */
4387static void
4388trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4389{
4390 ly_bool once;
aPiecek3f247652021-04-19 13:40:25 +02004391 ly_bool origin_was_lysc_tree = 0;
aPiecek03cb4872022-10-24 10:31:51 +02004392 struct trt_keyword_stmt ks;
aPiecekdc8fd572021-04-19 10:47:23 +02004393
aPiecek3f247652021-04-19 13:40:25 +02004394 if (tc->lysc_tree) {
4395 origin_was_lysc_tree = 1;
4396 trm_reset_to_lysp_tree_ctx(pc, tc);
4397 }
4398
aPiecekdc8fd572021-04-19 10:47:23 +02004399 once = 1;
aPiecek03cb4872022-10-24 10:31:51 +02004400 for (ks = trop_modi_next_augment(tc); ks.section_name; ks = trop_modi_next_augment(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004401
aPiecek3f247652021-04-19 13:40:25 +02004402 if (origin_was_lysc_tree) {
4403 /* if lysc tree is used, then only augments targeting
4404 * another module are printed
4405 */
aPiecek9f792e52021-04-21 08:33:56 +02004406 if (trm_nodeid_target_is_local((const struct lysp_node_augment *)tc->tpn, tc->pmod)) {
aPiecek3f247652021-04-19 13:40:25 +02004407 continue;
4408 }
4409 }
4410
aPiecekdc8fd572021-04-19 10:47:23 +02004411 if (once) {
4412 ly_print_(pc->out, "\n");
4413 ly_print_(pc->out, "\n");
4414 once = 0;
4415 } else {
4416 ly_print_(pc->out, "\n");
4417 }
4418
4419 trm_print_section_as_subtree(ks, pc, tc);
4420 }
aPiecek3f247652021-04-19 13:40:25 +02004421
4422 if (origin_was_lysc_tree) {
4423 trm_reset_to_lysc_tree_ctx(pc, tc);
4424 }
aPiecekdc8fd572021-04-19 10:47:23 +02004425}
4426
4427/**
4428 * @brief For rpcs section: print 'rpcs' keyword and all its nodes.
4429 * @param[in] pc contains mainly functions for printing.
4430 * @param[in,out] tc is the tree context.
4431 */
4432static void
4433trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4434{
4435 struct trt_keyword_stmt rpc;
4436
aPiecek01598c02021-04-23 14:18:24 +02004437 rpc = tro_modi_get_rpcs(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004438
aPiecek03cb4872022-10-24 10:31:51 +02004439 if (rpc.section_name) {
aPiecekdc8fd572021-04-19 10:47:23 +02004440 ly_print_(pc->out, "\n");
4441 ly_print_(pc->out, "\n");
4442 trm_print_section_as_family_tree(rpc, pc, tc);
4443 }
4444}
4445
4446/**
4447 * @brief For notifications section: print 'notifications' keyword
4448 * and all its nodes.
4449 * @param[in] pc contains mainly functions for printing.
4450 * @param[in,out] tc is the tree context.
4451 */
4452static void
4453trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4454{
4455 struct trt_keyword_stmt notifs;
4456
aPiecek01598c02021-04-23 14:18:24 +02004457 notifs = tro_modi_get_notifications(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004458
aPiecek03cb4872022-10-24 10:31:51 +02004459 if (notifs.section_name) {
aPiecekdc8fd572021-04-19 10:47:23 +02004460 ly_print_(pc->out, "\n");
4461 ly_print_(pc->out, "\n");
4462 trm_print_section_as_family_tree(notifs, pc, tc);
4463 }
4464}
4465
4466/**
4467 * @brief For all grouping sections: print 'grouping' keyword, its name
4468 * and all nodes.
4469 * @param[in] pc contains mainly functions for printing.
4470 * @param[in,out] tc is the tree context.
4471 */
4472static void
4473trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4474{
4475 ly_bool once;
aPiecek03cb4872022-10-24 10:31:51 +02004476 struct trt_keyword_stmt ks;
aPiecekdc8fd572021-04-19 10:47:23 +02004477
aPiecek01598c02021-04-23 14:18:24 +02004478 if (tc->lysc_tree) {
aPiecekdc8fd572021-04-19 10:47:23 +02004479 return;
4480 }
4481
4482 once = 1;
aPiecek03cb4872022-10-24 10:31:51 +02004483 for (ks = trop_modi_next_grouping(tc); ks.section_name; ks = trop_modi_next_grouping(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004484 if (once) {
4485 ly_print_(pc->out, "\n");
4486 ly_print_(pc->out, "\n");
4487 once = 0;
4488 } else {
4489 ly_print_(pc->out, "\n");
4490 }
4491 trm_print_section_as_subtree(ks, pc, tc);
4492 }
4493}
4494
4495/**
aPiecek03cb4872022-10-24 10:31:51 +02004496 * @brief Print all sections defined in plugins.
4497 *
aPiecekdc8fd572021-04-19 10:47:23 +02004498 * @param[in] pc contains mainly functions for printing.
4499 * @param[in,out] tc is the tree context.
4500 */
4501static void
aPiecek03cb4872022-10-24 10:31:51 +02004502trm_print_plugin_ext(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecekdc8fd572021-04-19 10:47:23 +02004503{
aPiecek03cb4872022-10-24 10:31:51 +02004504 LY_ERR rc;
aPiecek96baa7f2021-04-23 12:32:00 +02004505 ly_bool once;
aPiecek03cb4872022-10-24 10:31:51 +02004506 LY_ARRAY_COUNT_TYPE i = 0, j;
4507 struct trt_keyword_stmt ks, prev_ks = {0};
4508 struct trt_printer_ctx pc_dupl;
4509 struct trt_tree_ctx tc_dupl;
4510 uint32_t max_gap_before_type;
4511 void *ext;
aPiecek96baa7f2021-04-23 12:32:00 +02004512
aPiecek03cb4872022-10-24 10:31:51 +02004513 tc->section = TRD_SECT_PLUG_DATA;
4514
4515 tc_dupl = *tc;
4516 pc_dupl = *pc;
aPiecek96baa7f2021-04-23 12:32:00 +02004517
4518 once = 1;
aPiecek96baa7f2021-04-23 12:32:00 +02004519
aPiecek03cb4872022-10-24 10:31:51 +02004520 while ((ext = trb_mod_ext_iter(tc, &i))) {
4521 struct lyspr_tree_ctx plug_ctx = {0};
4522
4523 rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx);
4524 LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end);
4525 if (!plug_ctx.schemas) {
aPiecek96baa7f2021-04-23 12:32:00 +02004526 continue;
4527 }
4528
aPiecek03cb4872022-10-24 10:31:51 +02004529 ks = tro_get_ext_section(tc, ext, &plug_ctx);
4530 if (once || (prev_ks.section_name && strcmp(prev_ks.section_name, ks.section_name))) {
aPiecek96baa7f2021-04-23 12:32:00 +02004531 ly_print_(pc->out, "\n");
4532 ly_print_(pc->out, "\n");
4533 once = 0;
4534 } else {
4535 ly_print_(pc->out, "\n");
4536 }
aPiecek03cb4872022-10-24 10:31:51 +02004537 trp_print_keyword_stmt(ks, pc->max_line_length, pc->out);
aPiecek96baa7f2021-04-23 12:32:00 +02004538
aPiecek03cb4872022-10-24 10:31:51 +02004539 max_gap_before_type = 0;
4540 trb_ext_try_unified_indent(&plug_ctx, TRP_EMPTY_PARENT_CACHE, &max_gap_before_type, pc, tc);
4541 LY_ARRAY_FOR(plug_ctx.schemas, j) {
4542 trm_reset_tree_ctx_by_plugin(&plug_ctx, j, pc, tc);
4543 trb_print_subtree_nodes(TRP_EMPTY_NODE, max_gap_before_type, TRP_INIT_WRAPPER_BODY, TRP_EMPTY_PARENT_CACHE, pc, tc);
4544 }
4545
4546 *tc = tc_dupl;
4547 trp_ext_free_plugin_ctx(&plug_ctx);
4548 prev_ks = ks;
aPiecek96baa7f2021-04-23 12:32:00 +02004549 }
aPiecek03cb4872022-10-24 10:31:51 +02004550
4551end:
4552 *pc = pc_dupl;
4553 return;
aPiecekdc8fd572021-04-19 10:47:23 +02004554}
4555
4556/**
4557 * @brief Print sections module, augment, rpcs, notifications,
4558 * grouping, yang-data.
4559 * @param[in] pc contains mainly functions for printing.
4560 * @param[in,out] tc is the tree context.
4561 */
4562static void
4563trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4564{
4565 trm_print_module_section(pc, tc);
4566 trm_print_augmentations(pc, tc);
4567 trm_print_rpcs(pc, tc);
4568 trm_print_notifications(pc, tc);
4569 trm_print_groupings(pc, tc);
aPiecek03cb4872022-10-24 10:31:51 +02004570 trm_print_plugin_ext(pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004571 ly_print_(pc->out, "\n");
aPiecek61d062b2020-11-02 11:05:09 +01004572}
4573
aPiecek40f22402022-10-14 10:48:08 +02004574static LY_ERR
4575tree_print_check_error(struct ly_out_clb_arg *out, struct trt_tree_ctx *tc)
4576{
4577 if (out->last_error) {
4578 return out->last_error;
4579 } else if (tc->last_error) {
4580 return tc->last_error;
4581 } else {
4582 return LY_SUCCESS;
4583 }
4584}
4585
aPiecek874ea4d2021-04-19 12:26:36 +02004586/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004587 * Definition of module interface
aPiecek874ea4d2021-04-19 12:26:36 +02004588 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004589
4590LY_ERR
aPiecek3f247652021-04-19 13:40:25 +02004591tree_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 +01004592{
4593 struct trt_printer_ctx pc;
4594 struct trt_tree_ctx tc;
4595 struct ly_out *new_out;
4596 LY_ERR erc;
4597 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4598
aPiecekdc8fd572021-04-19 10:47:23 +02004599 LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL);
4600
aPiecek61d062b2020-11-02 11:05:09 +01004601 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4602 return erc;
4603 }
4604
4605 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek3f247652021-04-19 13:40:25 +02004606 if ((module->ctx->flags & LY_CTX_SET_PRIV_PARSED) && module->compiled) {
aPiecek03cb4872022-10-24 10:31:51 +02004607 trm_lysc_tree_ctx(module, new_out, line_length, &pc, &tc);
aPiecek3f247652021-04-19 13:40:25 +02004608 } else {
aPiecek03cb4872022-10-24 10:31:51 +02004609 trm_lysp_tree_ctx(module, new_out, line_length, &pc, &tc);
aPiecek3f247652021-04-19 13:40:25 +02004610 }
aPiecek61d062b2020-11-02 11:05:09 +01004611
4612 trm_print_sections(&pc, &tc);
aPiecek40f22402022-10-14 10:48:08 +02004613 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek61d062b2020-11-02 11:05:09 +01004614
4615 ly_out_free(new_out, NULL, 1);
4616
aPiecekdc8fd572021-04-19 10:47:23 +02004617 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004618}
4619
4620LY_ERR
aPiecek153b00f2021-04-20 13:52:57 +02004621tree_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 +01004622{
aPiecek153b00f2021-04-20 13:52:57 +02004623 struct trt_printer_ctx pc;
4624 struct trt_tree_ctx tc;
4625 struct ly_out *new_out;
4626 struct trt_wrapper wr;
4627 LY_ERR erc;
4628 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4629
4630 assert(out && node);
4631
4632 if (!(node->module->ctx->flags & LY_CTX_SET_PRIV_PARSED)) {
4633 return LY_EINVAL;
4634 }
4635
4636 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4637 return erc;
4638 }
4639
4640 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek03cb4872022-10-24 10:31:51 +02004641 trm_lysc_tree_ctx(node->module, new_out, line_length, &pc, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004642
aPiecek03cb4872022-10-24 10:31:51 +02004643 trp_print_keyword_stmt(pc.fp.read.module_name(&tc), pc.max_line_length, pc.out);
ekinzie0ab8b302022-10-10 03:03:57 -04004644 trb_print_parents(node, NULL, &pc, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004645
4646 if (!(options & LYS_PRINT_NO_SUBSTMT)) {
4647 tc.cn = lysc_node_child(node);
ekinzie0ab8b302022-10-10 03:03:57 -04004648 wr = trb_count_depth(NULL, tc.cn);
aPiecek153b00f2021-04-20 13:52:57 +02004649 trb_print_family_tree(wr, &pc, &tc);
4650 }
4651 ly_print_(out, "\n");
4652
aPiecek40f22402022-10-14 10:48:08 +02004653 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004654 ly_out_free(new_out, NULL, 1);
4655
4656 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004657}
4658
4659LY_ERR
Michal Vasko6a914fb2022-01-17 10:36:14 +01004660tree_print_parsed_submodule(struct ly_out *out, const struct lysp_submodule *submodp, uint32_t UNUSED(options),
4661 size_t line_length)
aPiecek61d062b2020-11-02 11:05:09 +01004662{
aPiecek9f792e52021-04-21 08:33:56 +02004663 struct trt_printer_ctx pc;
4664 struct trt_tree_ctx tc;
4665 struct ly_out *new_out;
4666 LY_ERR erc;
4667 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4668
4669 assert(submodp);
4670 LY_CHECK_ARG_RET(submodp->mod->ctx, out, LY_EINVAL);
4671
4672 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4673 return erc;
4674 }
4675
4676 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek03cb4872022-10-24 10:31:51 +02004677 trm_lysp_tree_ctx(submodp->mod, new_out, line_length, &pc, &tc);
aPiecek9f792e52021-04-21 08:33:56 +02004678 tc.pmod = (struct lysp_module *)submodp;
4679 tc.tpn = submodp->data;
4680 tc.pn = tc.tpn;
4681
4682 trm_print_sections(&pc, &tc);
aPiecek40f22402022-10-14 10:48:08 +02004683 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek9f792e52021-04-21 08:33:56 +02004684
4685 ly_out_free(new_out, NULL, 1);
4686
4687 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004688}