blob: c498086cd79c1c8ce585cf482aa1146db3ca64c7 [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
aPiecek02665a82022-12-14 10:38:16 +01001029trp_node_is_empty(const struct trt_node *node)
aPiecek61d062b2020-11-02 11:05:09 +01001030{
aPiecek02665a82022-12-14 10:38:16 +01001031 const ly_bool a = TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(node->iffeatures.type);
1032 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node->type);
1033 const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node->name);
1034 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
aPiecek02665a82022-12-14 10:38:16 +01001048trp_node_body_is_empty(const struct trt_node *node)
aPiecek61d062b2020-11-02 11:05:09 +01001049{
aPiecek02665a82022-12-14 10:38:16 +01001050 const ly_bool a = TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(node->iffeatures.type);
1051 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node->type);
1052 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
aPiecek02665a82022-12-14 10:38:16 +01001210trp_print_node_up_to_name(const struct trt_node *node, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001211{
aPiecek02665a82022-12-14 10:38:16 +01001212 if (node->name.type == TRD_NODE_TRIPLE_DOT) {
1213 trp_print_node_name(node->name, out);
aPiecek61d062b2020-11-02 11:05:09 +01001214 return;
1215 }
1216 /* <status>--<flags> */
aPiecek02665a82022-12-14 10:38:16 +01001217 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 */
aPiecek02665a82022-12-14 10:38:16 +01001222 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> */
aPiecek02665a82022-12-14 10:38:16 +01001227 trp_print_node_name(node->name, out);
aPiecek61d062b2020-11-02 11:05:09 +01001228}
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
aPiecek02665a82022-12-14 10:38:16 +01001237trp_print_divided_node_up_to_name(const struct trt_node *node, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001238{
aPiecek02665a82022-12-14 10:38:16 +01001239 uint32_t space = strlen(node->flags);
aPiecek61d062b2020-11-02 11:05:09 +01001240
aPiecek02665a82022-12-14 10:38:16 +01001241 if (node->name.type == TRD_NODE_CASE) {
aPiecek61d062b2020-11-02 11:05:09 +01001242 /* :(<name> */
1243 space += strlen(TRD_NODE_NAME_PREFIX_CASE);
aPiecek02665a82022-12-14 10:38:16 +01001244 } else if (node->name.type == TRD_NODE_CHOICE) {
aPiecek61d062b2020-11-02 11:05:09 +01001245 /* (<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
aPiecek02665a82022-12-14 10:38:16 +01001269trp_print_node(const struct trt_node *node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001270{
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> */
aPiecek02665a82022-12-14 10:38:16 +01001281 triple_dot = node->name.type == TRD_NODE_TRIPLE_DOT;
aPiecek61d062b2020-11-02 11:05:09 +01001282 divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED;
1283
1284 if (triple_dot) {
aPiecek02665a82022-12-14 10:38:16 +01001285 trp_print_node_name(node->name, out);
aPiecek61d062b2020-11-02 11:05:09 +01001286 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
aPiecek02665a82022-12-14 10:38:16 +01001298 trp_print_opts_keys(node->name, indent.btw_name_opts, cf_print_keys, out);
aPiecek61d062b2020-11-02 11:05:09 +01001299
1300 /* <opts>__<type> */
1301 if (indent.btw_opts_type > 0) {
1302 ly_print_(out, "%*c", indent.btw_opts_type, ' ');
1303 }
1304
1305 /* <type> */
aPiecek02665a82022-12-14 10:38:16 +01001306 trp_print_type(node->type, out);
aPiecek61d062b2020-11-02 11:05:09 +01001307
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
aPiecek02665a82022-12-14 10:38:16 +01001317 trp_print_iffeatures(node->iffeatures, cf_print_iffeatures, out);
aPiecek61d062b2020-11-02 11:05:09 +01001318}
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
aPiecek02665a82022-12-14 10:38:16 +01001469trp_print_line(const struct trt_node *node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001470{
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
aPiecek02665a82022-12-14 10:38:16 +01001483trp_print_line_up_to_node_name(const struct trt_node *node, struct trt_wrapper wr, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001484{
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
aPiecek02665a82022-12-14 10:38:16 +01001499trp_leafref_target_is_too_long(const struct trt_node *node, struct trt_wrapper wr, size_t mll, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001500{
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
aPiecek02665a82022-12-14 10:38:16 +01001504 if (node->type.type != TRD_TYPE_TARGET) {
aPiecek61d062b2020-11-02 11:05:09 +01001505 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;
aPiecek02665a82022-12-14 10:38:16 +01001518 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
aPiecek02665a82022-12-14 10:38:16 +01001530trp_default_indent_in_node(const struct trt_node *node)
aPiecek61d062b2020-11-02 11:05:09 +01001531{
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 */
aPiecek02665a82022-12-14 10:38:16 +01001538 ret.btw_name_opts = node->name.keys ? TRD_INDENT_BEFORE_KEYS : 0;
aPiecek61d062b2020-11-02 11:05:09 +01001539
1540 /* btw_opts_type */
aPiecek02665a82022-12-14 10:38:16 +01001541 if (!(TRP_TRT_TYPE_IS_EMPTY(node->type))) {
1542 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;
aPiecek03cb4872022-10-24 10:31:51 +02001545 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 */
aPiecek02665a82022-12-14 10:38:16 +01001554 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/**
aPiecek02665a82022-12-14 10:38:16 +01001594 * @brief Set the first half of the node based on the linebreak mark.
aPiecek61d062b2020-11-02 11:05:09 +01001595 *
1596 * Items in the second half of the node will be empty.
1597 *
aPiecek02665a82022-12-14 10:38:16 +01001598 * @param[in,out] innod contains information in which part of the \<node\>
1599 * the first half ends. Set first half of the node, indent is unchanged.
aPiecek61d062b2020-11-02 11:05:09 +01001600 */
aPiecek02665a82022-12-14 10:38:16 +01001601static void
1602trp_first_half_node(struct trt_pair_indent_node *innod)
aPiecek61d062b2020-11-02 11:05:09 +01001603{
aPiecek02665a82022-12-14 10:38:16 +01001604 if (innod->indent.btw_name_opts == TRD_LINEBREAK) {
1605 innod->node.type = TRP_EMPTY_TRT_TYPE;
1606 innod->node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
1607 } else if (innod->indent.btw_opts_type == TRD_LINEBREAK) {
1608 innod->node.type = TRP_EMPTY_TRT_TYPE;
1609 innod->node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
1610 } else if (innod->indent.btw_type_iffeatures == TRD_LINEBREAK) {
1611 innod->node.iffeatures = TRP_EMPTY_TRT_IFFEATURES;
aPiecek61d062b2020-11-02 11:05:09 +01001612 }
aPiecek61d062b2020-11-02 11:05:09 +01001613}
1614
1615/**
aPiecek02665a82022-12-14 10:38:16 +01001616 * @brief Set the second half of the node based on the linebreak mark.
aPiecek61d062b2020-11-02 11:05:09 +01001617 *
1618 * Items in the first half of the node will be empty.
1619 * Indentations belonging to the first node will be reset to zero.
1620 *
aPiecek02665a82022-12-14 10:38:16 +01001621 * @param[in,out] innod contains information in which part of the \<node\>
1622 * the second half starts. Set second half of the node, indent is newly set.
aPiecek61d062b2020-11-02 11:05:09 +01001623 */
aPiecek02665a82022-12-14 10:38:16 +01001624static void
1625trp_second_half_node(struct trt_pair_indent_node *innod)
aPiecek61d062b2020-11-02 11:05:09 +01001626{
aPiecek02665a82022-12-14 10:38:16 +01001627 if (innod->indent.btw_name_opts < 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001628 /* Logically, the information up to token <opts> should
1629 * be deleted, but the the trp_print_node function needs it to
1630 * create the correct indent.
aPiecek61d062b2020-11-02 11:05:09 +01001631 */
aPiecek02665a82022-12-14 10:38:16 +01001632 innod->indent.btw_name_opts = 0;
1633 innod->indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(innod->node.type) ? 0 : TRD_INDENT_BEFORE_TYPE;
1634 innod->indent.btw_type_iffeatures = innod->node.iffeatures.type == TRD_IFF_NON_PRESENT ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1635 } else if (innod->indent.btw_opts_type == TRD_LINEBREAK) {
1636 innod->indent.btw_name_opts = 0;
1637 innod->indent.btw_opts_type = 0;
1638 innod->indent.btw_type_iffeatures = innod->node.iffeatures.type == TRD_IFF_NON_PRESENT ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1639 } else if (innod->indent.btw_type_iffeatures == TRD_LINEBREAK) {
1640 innod->node.type = TRP_EMPTY_TRT_TYPE;
1641 innod->indent.btw_name_opts = 0;
1642 innod->indent.btw_opts_type = 0;
1643 innod->indent.btw_type_iffeatures = 0;
aPiecek61d062b2020-11-02 11:05:09 +01001644 }
aPiecek61d062b2020-11-02 11:05:09 +01001645}
1646
1647/**
1648 * @brief Get the correct alignment for the node.
1649 *
aPiecek874ea4d2021-04-19 12:26:36 +02001650 * This function is recursively called itself. It's like a backend
aPiecek01598c02021-04-23 14:18:24 +02001651 * function for a function ::trp_try_normal_indent_in_node().
aPiecek61d062b2020-11-02 11:05:09 +01001652 *
aPiecek61d062b2020-11-02 11:05:09 +01001653 * @param[in] pck contains speciall callback functions for printing.
aPiecek02665a82022-12-14 10:38:16 +01001654 * @param[in] wrapper contains information about '|' context.
aPiecek61d062b2020-11-02 11:05:09 +01001655 * @param[in] mll is max line length.
1656 * @param[in,out] cnt counting number of characters to print.
1657 * @param[in,out] out is output handler.
aPiecek02665a82022-12-14 10:38:16 +01001658 * @param[in,out] innod pair of node and indentation numbers of that node.
aPiecek61d062b2020-11-02 11:05:09 +01001659 */
aPiecek02665a82022-12-14 10:38:16 +01001660static void
1661trp_try_normal_indent_in_node_(struct trt_pck_print pck, struct trt_wrapper wrapper, size_t mll, size_t *cnt,
1662 struct ly_out *out, struct trt_pair_indent_node *innod)
aPiecek61d062b2020-11-02 11:05:09 +01001663{
aPiecek02665a82022-12-14 10:38:16 +01001664 trp_print_line(&innod->node, pck, TRP_INIT_PCK_INDENT(wrapper, innod->indent), out);
aPiecek61d062b2020-11-02 11:05:09 +01001665
1666 if (*cnt <= mll) {
1667 /* success */
aPiecek02665a82022-12-14 10:38:16 +01001668 return;
aPiecek61d062b2020-11-02 11:05:09 +01001669 } else {
aPiecek02665a82022-12-14 10:38:16 +01001670 innod->indent = trp_indent_in_node_place_break(innod->indent);
1671 if (innod->indent.type != TRD_INDENT_IN_NODE_FAILED) {
aPiecek61d062b2020-11-02 11:05:09 +01001672 /* erase information in node due to line break */
aPiecek02665a82022-12-14 10:38:16 +01001673 trp_first_half_node(innod);
aPiecek61d062b2020-11-02 11:05:09 +01001674 /* check if line fits, recursive call */
1675 *cnt = 0;
aPiecek02665a82022-12-14 10:38:16 +01001676 trp_try_normal_indent_in_node_(pck, wrapper, mll, cnt, out, innod);
aPiecek61d062b2020-11-02 11:05:09 +01001677 /* make sure that the result will be with the status divided
1678 * or eventually with status failed */
aPiecek02665a82022-12-14 10:38:16 +01001679 innod->indent.type = innod->indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED;
aPiecek61d062b2020-11-02 11:05:09 +01001680 }
aPiecek02665a82022-12-14 10:38:16 +01001681 return;
aPiecek61d062b2020-11-02 11:05:09 +01001682 }
1683}
1684
1685/**
1686 * @brief Get the correct alignment for the node.
1687 *
1688 * @param[in] node is \<node\> representation.
1689 * @param[in] pck contains speciall callback functions for printing.
1690 * @param[in] indent contains wrapper and indent in node numbers.
1691 * @param[in] mll is max line length.
1692 * @param[in,out] out is output handler.
aPiecek02665a82022-12-14 10:38:16 +01001693 * @param[out] innod If the node does not fit in the line, some indent variable has negative value as a line break sign
1694 * and therefore ::TRD_INDENT_IN_NODE_DIVIDED is set.
1695 * If the node fits into the line, all indent variables values has non-negative number and therefore
1696 * ::TRD_INDENT_IN_NODE_NORMAL is set.
1697 * If the node does not fit into the line, all indent variables has negative or zero values, function failed
1698 * and therefore ::TRD_INDENT_IN_NODE_FAILED is set.
aPiecek61d062b2020-11-02 11:05:09 +01001699 */
aPiecek02665a82022-12-14 10:38:16 +01001700static void
1701trp_try_normal_indent_in_node(const struct trt_node *node, struct trt_pck_print pck, struct trt_pck_indent indent,
1702 size_t mll, struct ly_out *out, struct trt_pair_indent_node *innod)
aPiecek61d062b2020-11-02 11:05:09 +01001703{
aPiecek61d062b2020-11-02 11:05:09 +01001704 struct ly_out_clb_arg *data;
1705
aPiecek02665a82022-12-14 10:38:16 +01001706 *innod = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, *node);
1707
aPiecek61d062b2020-11-02 11:05:09 +01001708 /* set ly_out to counting characters */
1709 data = out->method.clb.arg;
1710
1711 data->counter = 0;
1712 data->mode = TRD_CHAR_COUNT;
aPiecek02665a82022-12-14 10:38:16 +01001713 trp_try_normal_indent_in_node_(pck, indent.wrapper, mll, &data->counter, out, innod);
aPiecek61d062b2020-11-02 11:05:09 +01001714 data->mode = TRD_PRINT;
aPiecek61d062b2020-11-02 11:05:09 +01001715}
1716
1717/**
aPiecek01598c02021-04-23 14:18:24 +02001718 * @brief Auxiliary function for ::trp_print_entire_node()
aPiecek874ea4d2021-04-19 12:26:36 +02001719 * that prints split nodes.
aPiecek61d062b2020-11-02 11:05:09 +01001720 * @param[in] node is node representation.
1721 * @param[in] ppck contains speciall callback functions for printing.
1722 * @param[in] ipck contains wrapper and indent in node numbers.
1723 * @param[in] mll is max line length.
1724 * @param[in,out] out is output handler.
1725 */
1726static void
aPiecek02665a82022-12-14 10:38:16 +01001727trp_print_divided_node(const struct trt_node *node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001728{
1729 ly_bool entire_node_was_printed;
aPiecek02665a82022-12-14 10:38:16 +01001730 struct trt_pair_indent_node innod;
aPiecek61d062b2020-11-02 11:05:09 +01001731
aPiecek02665a82022-12-14 10:38:16 +01001732 trp_try_normal_indent_in_node(node, ppck, ipck, mll, out, &innod);
1733
1734 if (innod.indent.type == TRD_INDENT_IN_NODE_FAILED) {
aPiecek61d062b2020-11-02 11:05:09 +01001735 /* nothing can be done, continue as usual */
aPiecek02665a82022-12-14 10:38:16 +01001736 innod.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
aPiecek61d062b2020-11-02 11:05:09 +01001737 }
1738
aPiecek02665a82022-12-14 10:38:16 +01001739 trp_print_line(&innod.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, innod.indent), out);
1740 entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, innod.indent);
aPiecek61d062b2020-11-02 11:05:09 +01001741
1742 if (!entire_node_was_printed) {
1743 ly_print_(out, "\n");
1744 /* continue with second half node */
aPiecek02665a82022-12-14 10:38:16 +01001745 innod.node = *node;
1746 trp_second_half_node(&innod);
aPiecek61d062b2020-11-02 11:05:09 +01001747 /* continue with printing node */
aPiecek02665a82022-12-14 10:38:16 +01001748 trp_print_divided_node(&innod.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, innod.indent), mll, out);
aPiecek61d062b2020-11-02 11:05:09 +01001749 } else {
1750 return;
1751 }
1752}
1753
1754/**
aPiecek874ea4d2021-04-19 12:26:36 +02001755 * @brief Printing of the wrapper and the whole node,
1756 * which can be divided into several lines.
aPiecek02665a82022-12-14 10:38:16 +01001757 * @param[in] node_p is node representation.
aPiecek61d062b2020-11-02 11:05:09 +01001758 * @param[in] ppck contains speciall callback functions for printing.
1759 * @param[in] ipck contains wrapper and indent in node numbers.
1760 * @param[in] mll is max line length.
1761 * @param[in,out] out is output handler.
1762 */
1763static void
aPiecek02665a82022-12-14 10:38:16 +01001764trp_print_entire_node(const struct trt_node *node_p, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll,
1765 struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001766{
aPiecek02665a82022-12-14 10:38:16 +01001767 struct trt_pair_indent_node innod;
aPiecek61d062b2020-11-02 11:05:09 +01001768 struct trt_pck_indent tmp;
aPiecek02665a82022-12-14 10:38:16 +01001769 struct trt_node node;
aPiecek61d062b2020-11-02 11:05:09 +01001770
aPiecek02665a82022-12-14 10:38:16 +01001771 node = *node_p;
1772 if (trp_leafref_target_is_too_long(&node, ipck.wrapper, mll, out)) {
aPiecek61d062b2020-11-02 11:05:09 +01001773 node.type.type = TRD_TYPE_LEAFREF;
1774 }
1775
1776 /* check if normal indent is possible */
aPiecek02665a82022-12-14 10:38:16 +01001777 trp_try_normal_indent_in_node(&node, ppck, ipck, mll, out, &innod);
aPiecek61d062b2020-11-02 11:05:09 +01001778
aPiecek02665a82022-12-14 10:38:16 +01001779 if (innod.indent.type == TRD_INDENT_IN_NODE_NORMAL) {
aPiecek61d062b2020-11-02 11:05:09 +01001780 /* node fits to one line */
aPiecek02665a82022-12-14 10:38:16 +01001781 trp_print_line(&node, ppck, ipck, out);
1782 } else if (innod.indent.type == TRD_INDENT_IN_NODE_DIVIDED) {
aPiecek61d062b2020-11-02 11:05:09 +01001783 /* node will be divided */
1784 /* print first half */
aPiecek02665a82022-12-14 10:38:16 +01001785 tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, innod.indent);
aPiecek61d062b2020-11-02 11:05:09 +01001786 /* pretend that this is normal node */
1787 tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL;
1788
aPiecek02665a82022-12-14 10:38:16 +01001789 trp_print_line(&innod.node, ppck, tmp, out);
aPiecek61d062b2020-11-02 11:05:09 +01001790 ly_print_(out, "\n");
1791
1792 /* continue with second half on new line */
aPiecek02665a82022-12-14 10:38:16 +01001793 innod.node = node;
1794 trp_second_half_node(&innod);
1795 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), innod.indent);
aPiecek61d062b2020-11-02 11:05:09 +01001796
aPiecek02665a82022-12-14 10:38:16 +01001797 trp_print_divided_node(&innod.node, ppck, tmp, mll, out);
1798 } else if (innod.indent.type == TRD_INDENT_IN_NODE_FAILED) {
aPiecek61d062b2020-11-02 11:05:09 +01001799 /* node name is too long */
aPiecek02665a82022-12-14 10:38:16 +01001800 trp_print_line_up_to_node_name(&node, ipck.wrapper, out);
aPiecek61d062b2020-11-02 11:05:09 +01001801
aPiecek02665a82022-12-14 10:38:16 +01001802 if (trp_node_body_is_empty(&node)) {
aPiecek61d062b2020-11-02 11:05:09 +01001803 return;
1804 } else {
1805 ly_print_(out, "\n");
1806
aPiecek02665a82022-12-14 10:38:16 +01001807 innod.node = node;
1808 trp_second_half_node(&innod);
1809 innod.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1810 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), innod.indent);
aPiecek61d062b2020-11-02 11:05:09 +01001811
aPiecek02665a82022-12-14 10:38:16 +01001812 trp_print_divided_node(&innod.node, ppck, tmp, mll, out);
aPiecek61d062b2020-11-02 11:05:09 +01001813 }
aPiecek61d062b2020-11-02 11:05:09 +01001814 }
1815}
1816
aPiecek03cb4872022-10-24 10:31:51 +02001817/**
1818 * @brief Check if parent-stmt is valid for printing extensinon.
1819 *
1820 * @param[in] lysc_tree flag if ext is from compiled tree.
1821 * @param[in] ext Extension to check.
1822 * @return 1 if extension is valid.
1823 */
1824static ly_bool
1825trp_ext_parent_is_valid(ly_bool lysc_tree, void *ext)
1826{
1827 enum ly_stmt parent_stmt;
1828
1829 if (lysc_tree) {
1830 parent_stmt = ((struct lysc_ext_instance *)ext)->parent_stmt;
1831 } else {
1832 parent_stmt = ((struct lysp_ext_instance *)ext)->parent_stmt;
1833 }
1834 if ((parent_stmt & LY_STMT_OP_MASK) || (parent_stmt & LY_STMT_DATA_NODE_MASK) ||
1835 (parent_stmt & LY_STMT_SUBMODULE) || parent_stmt & LY_STMT_MODULE) {
1836 return 1;
1837 } else {
1838 return 0;
1839 }
1840}
1841
1842/**
1843 * @brief Check if printer_tree can use node extension.
1844 *
1845 * @param[in] lysc_tree Flag if @p node is compiled.
1846 * @param[in] node to check. Its type is lysc_node or lysp_node.
1847 * @return Pointer to extension instance which printer_tree can used.
1848 */
1849static void *
1850trp_ext_is_present(ly_bool lysc_tree, const void *node)
1851{
1852 const struct lysp_node *pn;
1853 const struct lysc_node *cn;
1854 LY_ARRAY_COUNT_TYPE i;
1855 void *ret = NULL;
1856
1857 if (!node) {
1858 return NULL;
1859 }
1860
1861 if (lysc_tree) {
1862 cn = (const struct lysc_node *)node;
1863 LY_ARRAY_FOR(cn->exts, i) {
1864 if (!(cn->exts && cn->exts->def->plugin && cn->exts->def->plugin->printer_ctree)) {
1865 continue;
1866 }
1867 if (!trp_ext_parent_is_valid(1, &cn->exts[i])) {
1868 continue;
1869 }
1870 ret = &cn->exts[i];
1871 break;
1872 }
1873 } else {
1874 pn = (const struct lysp_node *)node;
1875 LY_ARRAY_FOR(pn->exts, i) {
1876 if (!(pn->exts && pn->exts->record->plugin.printer_ptree)) {
1877 continue;
1878 }
1879 if (!trp_ext_parent_is_valid(0, &pn->exts[i])) {
1880 continue;
1881 }
1882 ret = &pn->exts[i];
1883 break;
1884 }
1885 }
1886
1887 return ret;
1888}
1889
1890/**
1891 * @brief Check if printer_tree can use node extension.
1892 *
1893 * @param[in] tc Context with current node.
1894 * @return 1 if some extension for printer_tree is valid.
1895 */
1896static ly_bool
1897trp_ext_is_present_in_node(struct trt_tree_ctx *tc)
1898{
1899 if (tc->lysc_tree && trp_ext_is_present(tc->lysc_tree, tc->cn)) {
1900 return 1;
1901 } else if (trp_ext_is_present(tc->lysc_tree, tc->pn)) {
1902 return 1;
1903 }
1904
1905 return 0;
1906}
1907
1908/**
1909 * @brief Release allocated memory and set pointers to NULL.
1910 *
1911 * @param[in,out] overr is override structure to release.
1912 * @param[out] filtered is flag to reset.
1913 */
1914static void
1915trp_ext_free_node_override(struct lyplg_ext_sprinter_tree_node_override *overr, ly_bool *filtered)
1916{
1917 *filtered = 0;
1918 overr->flags = NULL;
1919 overr->add_opts = NULL;
1920}
1921
1922/**
1923 * @brief Release private plugin data.
1924 *
1925 * @param[in,out] plug_ctx is plugin context.
1926 */
1927static void
1928trp_ext_free_plugin_ctx(struct lyspr_tree_ctx *plug_ctx)
1929{
1930 LY_ARRAY_FREE(plug_ctx->schemas);
1931 if (plug_ctx->free_plugin_priv) {
1932 plug_ctx->free_plugin_priv(plug_ctx->plugin_priv);
1933 }
1934}
1935
aPiecek874ea4d2021-04-19 12:26:36 +02001936/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02001937 * trop and troc getters
aPiecekef1e58e2021-04-19 13:19:44 +02001938 *********************************************************************/
1939
1940/**
1941 * @brief Get nodetype.
1942 * @param[in] node is any lysp_node.
1943 */
1944static uint16_t
1945trop_nodetype(const void *node)
1946{
1947 return ((const struct lysp_node *)node)->nodetype;
1948}
1949
1950/**
1951 * @brief Get sibling.
1952 * @param[in] node is any lysp_node.
1953 */
1954static const void *
1955trop_next(const void *node)
1956{
1957 return ((const struct lysp_node *)node)->next;
1958}
1959
1960/**
1961 * @brief Get parent.
1962 * @param[in] node is any lysp_node.
1963 */
1964static const void *
1965trop_parent(const void *node)
1966{
1967 return ((const struct lysp_node *)node)->parent;
1968}
1969
1970/**
1971 * @brief Try to get child.
1972 * @param[in] node is any lysp_node.
1973 */
1974static const void *
1975trop_child(const void *node)
1976{
1977 return lysp_node_child(node);
1978}
1979
1980/**
1981 * @brief Try to get action.
1982 * @param[in] node is any lysp_node.
1983 */
1984static const void *
1985trop_actions(const void *node)
1986{
1987 return lysp_node_actions(node);
1988}
1989
1990/**
1991 * @brief Try to get action.
1992 * @param[in] node must be of type lysp_node_action.
1993 */
1994static const void *
1995trop_action_input(const void *node)
1996{
1997 return &((const struct lysp_node_action *)node)->input;
1998}
1999
2000/**
2001 * @brief Try to get action.
2002 * @param[in] node must be of type lysp_node_action.
2003 */
2004static const void *
2005trop_action_output(const void *node)
2006{
2007 return &((const struct lysp_node_action *)node)->output;
2008}
2009
2010/**
2011 * @brief Try to get action.
2012 * @param[in] node is any lysp_node.
2013 */
2014static const void *
2015trop_notifs(const void *node)
2016{
2017 return lysp_node_notifs(node);
2018}
2019
2020/**
aPiecek01598c02021-04-23 14:18:24 +02002021 * @brief Fill struct tro_getters with @ref TRP_trop getters
aPiecekef1e58e2021-04-19 13:19:44 +02002022 * which are adapted to lysp nodes.
2023 */
2024static struct tro_getters
Michal Vasko45acb842022-11-08 09:23:17 +01002025trop_init_getters(void)
aPiecekef1e58e2021-04-19 13:19:44 +02002026{
2027 return (struct tro_getters) {
2028 .nodetype = trop_nodetype,
2029 .next = trop_next,
2030 .parent = trop_parent,
2031 .child = trop_child,
2032 .actions = trop_actions,
2033 .action_input = trop_action_input,
2034 .action_output = trop_action_output,
2035 .notifs = trop_notifs
2036 };
2037}
2038
aPiecek3f247652021-04-19 13:40:25 +02002039/**
2040 * @brief Get nodetype.
2041 * @param[in] node is any lysc_node.
2042 */
2043static uint16_t
2044troc_nodetype(const void *node)
2045{
2046 return ((const struct lysc_node *)node)->nodetype;
2047}
2048
2049/**
2050 * @brief Get sibling.
2051 * @param[in] node is any lysc_node.
2052 */
2053static const void *
2054troc_next(const void *node)
2055{
2056 return ((const struct lysc_node *)node)->next;
2057}
2058
2059/**
2060 * @brief Get parent.
2061 * @param[in] node is any lysc_node.
2062 */
2063static const void *
2064troc_parent(const void *node)
2065{
2066 return ((const struct lysc_node *)node)->parent;
2067}
2068
2069/**
2070 * @brief Try to get child.
2071 * @param[in] node is any lysc_node.
2072 */
2073static const void *
2074troc_child(const void *node)
2075{
2076 return lysc_node_child(node);
2077}
2078
2079/**
2080 * @brief Try to get action.
2081 * @param[in] node is any lysc_node.
2082 */
2083static const void *
2084troc_actions(const void *node)
2085{
2086 return lysc_node_actions(node);
2087}
2088
2089/**
2090 * @brief Try to get action.
2091 * @param[in] node must be of type lysc_node_action.
2092 */
2093static const void *
2094troc_action_input(const void *node)
2095{
2096 return &((const struct lysc_node_action *)node)->input;
2097}
2098
2099/**
2100 * @brief Try to get action.
2101 * @param[in] node must be of type lysc_node_action.
2102 */
2103static const void *
2104troc_action_output(const void *node)
2105{
2106 return &((const struct lysc_node_action *)node)->output;
2107}
2108
2109/**
2110 * @brief Try to get action.
2111 * @param[in] node is any lysc_node.
2112 */
2113static const void *
2114troc_notifs(const void *node)
2115{
2116 return lysc_node_notifs(node);
2117}
2118
2119/**
aPiecek01598c02021-04-23 14:18:24 +02002120 * @brief Fill struct tro_getters with @ref TRP_troc getters
aPiecek3f247652021-04-19 13:40:25 +02002121 * which are adapted to lysc nodes.
2122 */
2123static struct tro_getters
Michal Vasko45acb842022-11-08 09:23:17 +01002124troc_init_getters(void)
aPiecek3f247652021-04-19 13:40:25 +02002125{
2126 return (struct tro_getters) {
2127 .nodetype = troc_nodetype,
2128 .next = troc_next,
2129 .parent = troc_parent,
2130 .child = troc_child,
2131 .actions = troc_actions,
2132 .action_input = troc_action_input,
2133 .action_output = troc_action_output,
2134 .notifs = troc_notifs
2135 };
2136}
2137
aPiecekef1e58e2021-04-19 13:19:44 +02002138/**********************************************************************
2139 * tro functions
2140 *********************************************************************/
2141
2142/**
aPiecek03cb4872022-10-24 10:31:51 +02002143 * @brief Call override function for @p node.
2144 *
2145 * @param[in] lysc_tree if @p node is compiled.
2146 * @param[in] node to create override.
2147 * @param[in] erase_node_overr if override structure must be reseted.
2148 * @param[in,out] plc current plugin context.
2149 * @return pointer to override structure or NULL. Override structure in @p plc is updated too.
2150 */
2151static struct lyplg_ext_sprinter_tree_node_override *
2152tro_set_node_overr(ly_bool lysc_tree, const void *node, ly_bool erase_node_overr, struct trt_plugin_ctx *plc)
2153{
2154 LY_ERR rc = LY_SUCCESS;
2155 struct lyplg_ext_sprinter_tree_node_override *no;
2156 struct lyspr_tree_ctx *plug_ctx;
2157 struct lysc_ext_instance *ce;
2158 struct lysp_ext_instance *pe;
2159
2160 if (erase_node_overr) {
2161 trp_ext_free_node_override(&plc->node_overr, &plc->filtered);
2162 }
2163 no = &plc->node_overr;
2164 if (!plc->ctx && lysc_tree && (ce = trp_ext_is_present(lysc_tree, node))) {
2165 rc = ce->def->plugin->printer_ctree(ce, NULL, &no->flags, &no->add_opts);
2166 } else if (!plc->ctx && (pe = trp_ext_is_present(lysc_tree, node))) {
2167 rc = pe->record->plugin.printer_ptree(pe, NULL, &no->flags, &no->add_opts);
2168 } else if (plc->ctx) {
2169 if (plc->schema && plc->schema->compiled && plc->schema->cn_overr) {
2170 rc = plc->schema->cn_overr(node, plc->ctx->plugin_priv, &plc->filtered, &no->flags, &no->add_opts);
2171 } else if (plc->schema && plc->schema->pn_overr) {
2172 rc = plc->schema->pn_overr(node, plc->ctx->plugin_priv, &plc->filtered, &no->flags, &no->add_opts);
2173 } else {
2174 no = NULL;
2175 }
2176 if (trp_ext_is_present(lysc_tree, node)) {
2177 plug_ctx = plc->ctx;
2178 plc->ctx = NULL;
2179 tro_set_node_overr(lysc_tree, node, 0, plc);
2180 plc->ctx = plug_ctx;
2181 }
2182 } else {
2183 no = NULL;
2184 }
2185
2186 if (rc) {
2187 plc->last_error = rc;
2188 no = NULL;
2189 }
2190
2191 return no;
2192}
2193
2194/**
aPiecekef1e58e2021-04-19 13:19:44 +02002195 * @brief Get next sibling of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002196 *
2197 * This is a general algorithm that is able to
2198 * work with lysp_node or lysc_node.
2199 *
2200 * @param[in] node points to lysp_node or lysc_node.
aPiecek03cb4872022-10-24 10:31:51 +02002201 * @param[in] tc current tree context.
2202 * @return next sibling node.
aPiecekef1e58e2021-04-19 13:19:44 +02002203 */
2204static const void *
aPiecek03cb4872022-10-24 10:31:51 +02002205tro_next_sibling(const void *node, const struct trt_tree_ctx *tc)
aPiecekef1e58e2021-04-19 13:19:44 +02002206{
2207 struct tro_getters get;
aPiecek03cb4872022-10-24 10:31:51 +02002208 struct trt_plugin_ctx plugin_ctx;
2209 const void *tmp, *parent, *sibl;
aPiecekef1e58e2021-04-19 13:19:44 +02002210
2211 assert(node);
2212
aPiecek03cb4872022-10-24 10:31:51 +02002213 get = tc->lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002214
2215 if (get.nodetype(node) & (LYS_RPC | LYS_ACTION)) {
2216 if ((tmp = get.next(node))) {
2217 /* next action exists */
aPiecek03cb4872022-10-24 10:31:51 +02002218 sibl = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002219 } else if ((parent = get.parent(node))) {
2220 /* maybe if notif exists as sibling */
aPiecek03cb4872022-10-24 10:31:51 +02002221 sibl = get.notifs(parent);
aPiecekef1e58e2021-04-19 13:19:44 +02002222 } else {
aPiecek03cb4872022-10-24 10:31:51 +02002223 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002224 }
2225 } else if (get.nodetype(node) & LYS_INPUT) {
2226 if ((parent = get.parent(node))) {
2227 /* if output action has data */
2228 if (get.child(get.action_output(parent))) {
2229 /* then next sibling is output action */
aPiecek03cb4872022-10-24 10:31:51 +02002230 sibl = get.action_output(parent);
aPiecekef1e58e2021-04-19 13:19:44 +02002231 } else {
2232 /* input action cannot have siblings other
2233 * than output action.
2234 */
aPiecek03cb4872022-10-24 10:31:51 +02002235 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002236 }
2237 } else {
2238 /* there is no way how to get output action */
aPiecek03cb4872022-10-24 10:31:51 +02002239 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002240 }
2241 } else if (get.nodetype(node) & LYS_OUTPUT) {
2242 /* output action cannot have siblings */
aPiecek03cb4872022-10-24 10:31:51 +02002243 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002244 } else if (get.nodetype(node) & LYS_NOTIF) {
2245 /* must have as a sibling only notif */
aPiecek03cb4872022-10-24 10:31:51 +02002246 sibl = get.next(node);
aPiecekef1e58e2021-04-19 13:19:44 +02002247 } else {
2248 /* for rest of nodes */
2249 if ((tmp = get.next(node))) {
2250 /* some sibling exists */
aPiecek03cb4872022-10-24 10:31:51 +02002251 sibl = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002252 } else if ((parent = get.parent(node))) {
2253 /* Action and notif are siblings too.
2254 * They can be reached through parent.
2255 */
2256 if ((tmp = get.actions(parent))) {
2257 /* next sibling is action */
aPiecek03cb4872022-10-24 10:31:51 +02002258 sibl = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002259 } else if ((tmp = get.notifs(parent))) {
2260 /* next sibling is notif */
aPiecek03cb4872022-10-24 10:31:51 +02002261 sibl = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002262 } else {
2263 /* sibling not exists */
aPiecek03cb4872022-10-24 10:31:51 +02002264 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002265 }
2266 } else {
2267 /* sibling not exists */
aPiecek03cb4872022-10-24 10:31:51 +02002268 sibl = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002269 }
2270 }
2271
aPiecek03cb4872022-10-24 10:31:51 +02002272 plugin_ctx = tc->plugin_ctx;
2273 if (sibl && tro_set_node_overr(tc->lysc_tree, sibl, 1, &plugin_ctx) && plugin_ctx.filtered) {
2274 return tro_next_sibling(sibl, tc);
2275 }
2276
2277 return sibl;
aPiecekef1e58e2021-04-19 13:19:44 +02002278}
2279
2280/**
2281 * @brief Get child of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002282 *
2283 * This is a general algorithm that is able to
2284 * work with lysp_node or lysc_node.
2285 *
2286 * @param[in] node points to lysp_node or lysc_node.
aPiecek03cb4872022-10-24 10:31:51 +02002287 * @param[in] tc current tree context.
2288 * @return child node.
aPiecekef1e58e2021-04-19 13:19:44 +02002289 */
2290static const void *
aPiecek03cb4872022-10-24 10:31:51 +02002291tro_next_child(const void *node, const struct trt_tree_ctx *tc)
aPiecekef1e58e2021-04-19 13:19:44 +02002292{
2293 struct tro_getters get;
aPiecek03cb4872022-10-24 10:31:51 +02002294 struct trt_plugin_ctx plugin_ctx;
2295 const void *tmp, *child;
aPiecekef1e58e2021-04-19 13:19:44 +02002296
2297 assert(node);
2298
aPiecek03cb4872022-10-24 10:31:51 +02002299 get = tc->lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002300
2301 if (get.nodetype(node) & (LYS_ACTION | LYS_RPC)) {
2302 if (get.child(get.action_input(node))) {
2303 /* go to LYS_INPUT */
aPiecek03cb4872022-10-24 10:31:51 +02002304 child = get.action_input(node);
aPiecekef1e58e2021-04-19 13:19:44 +02002305 } else if (get.child(get.action_output(node))) {
2306 /* go to LYS_OUTPUT */
aPiecek03cb4872022-10-24 10:31:51 +02002307 child = get.action_output(node);
aPiecekef1e58e2021-04-19 13:19:44 +02002308 } else {
2309 /* input action and output action have no data */
aPiecek03cb4872022-10-24 10:31:51 +02002310 child = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002311 }
2312 } else {
2313 if ((tmp = get.child(node))) {
aPiecek03cb4872022-10-24 10:31:51 +02002314 child = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002315 } else {
2316 /* current node can't have children or has no children */
2317 /* but maybe has some actions or notifs */
2318 if ((tmp = get.actions(node))) {
aPiecek03cb4872022-10-24 10:31:51 +02002319 child = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002320 } else if ((tmp = get.notifs(node))) {
aPiecek03cb4872022-10-24 10:31:51 +02002321 child = tmp;
aPiecekef1e58e2021-04-19 13:19:44 +02002322 } else {
aPiecek03cb4872022-10-24 10:31:51 +02002323 child = NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002324 }
2325 }
2326 }
2327
aPiecek03cb4872022-10-24 10:31:51 +02002328 plugin_ctx = tc->plugin_ctx;
2329 if (child && tro_set_node_overr(tc->lysc_tree, child, 1, &plugin_ctx) && plugin_ctx.filtered) {
2330 return tro_next_sibling(child, tc);
2331 }
2332
2333 return child;
aPiecekef1e58e2021-04-19 13:19:44 +02002334}
2335
2336/**
aPiecek3f247652021-04-19 13:40:25 +02002337 * @brief Get new trt_parent_cache if we apply the transfer
2338 * to the child node in the tree.
2339 * @param[in] ca is parent cache for current node.
2340 * @param[in] tc contains current tree node.
2341 * @return Cache for the current node.
2342 */
2343static struct trt_parent_cache
2344tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2345{
2346 struct trt_parent_cache ret = TRP_EMPTY_PARENT_CACHE;
2347
2348 if (!tc->lysc_tree) {
2349 const struct lysp_node *pn = tc->pn;
2350
2351 ret.ancestor =
2352 pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT :
2353 pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT :
2354 pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF :
2355 ca.ancestor;
2356
2357 ret.lys_status =
2358 pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
2359 ca.lys_status;
2360
2361 ret.lys_config =
2362 ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because <flags> will be -w */
2363 ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
2364 pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
2365 ca.lys_config;
2366
2367 ret.last_list =
2368 pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
2369 ca.last_list;
2370 }
2371
2372 return ret;
2373}
2374
2375/**
aPiecekef1e58e2021-04-19 13:19:44 +02002376 * @brief Transformation of the Schema nodes flags to
2377 * Tree diagram \<status\>.
2378 * @param[in] flags is node's flags obtained from the tree.
2379 */
aPiecek41219f92022-10-26 11:24:40 +02002380static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002381tro_flags2status(uint16_t flags)
2382{
aPiecek41219f92022-10-26 11:24:40 +02002383 return flags & LYS_STATUS_OBSLT ? "o" :
2384 flags & LYS_STATUS_DEPRC ? "x" :
2385 "+";
aPiecekef1e58e2021-04-19 13:19:44 +02002386}
2387
2388/**
2389 * @brief Transformation of the Schema nodes flags to Tree diagram
2390 * \<flags\> but more specifically 'ro' or 'rw'.
2391 * @param[in] flags is node's flags obtained from the tree.
2392 */
aPiecek41219f92022-10-26 11:24:40 +02002393static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002394tro_flags2config(uint16_t flags)
2395{
2396 return flags & LYS_CONFIG_R ? TRD_FLAGS_TYPE_RO :
2397 flags & LYS_CONFIG_W ? TRD_FLAGS_TYPE_RW :
2398 TRD_FLAGS_TYPE_EMPTY;
2399}
2400
2401/**
aPiecek3f247652021-04-19 13:40:25 +02002402 * @brief Print current node's iffeatures.
2403 * @param[in] tc is tree context.
2404 * @param[in,out] out is output handler.
2405 */
2406static void
2407tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out)
2408{
2409 const struct lysp_qname *iffs;
2410
aPiecekbbc02932021-05-21 07:19:41 +02002411 if (tc->lysc_tree) {
2412 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2413 iffs = TRP_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures;
2414 } else {
2415 iffs = tc->pn->iffeatures;
2416 }
aPiecek3f247652021-04-19 13:40:25 +02002417 LY_ARRAY_COUNT_TYPE i;
2418
2419 LY_ARRAY_FOR(iffs, i) {
2420 if (i == 0) {
2421 ly_print_(out, "%s", iffs[i].str);
2422 } else {
2423 ly_print_(out, ",%s", iffs[i].str);
2424 }
2425 }
2426
2427}
2428
2429/**
2430 * @brief Print current list's keys.
2431 *
2432 * Well, actually printing keys in the lysp_tree is trivial,
2433 * because char* points to all keys. However, special functions have
2434 * been reserved for this, because in principle the list of elements
2435 * can have more implementations.
2436 *
2437 * @param[in] tc is tree context.
2438 * @param[in,out] out is output handler.
2439 */
2440static void
2441tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out)
2442{
2443 const struct lysp_node_list *list;
2444
aPiecekbbc02932021-05-21 07:19:41 +02002445 if (tc->lysc_tree) {
2446 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2447 list = (const struct lysp_node_list *)TRP_TREE_CTX_GET_LYSP_NODE(tc->cn);
2448 } else {
2449 list = (const struct lysp_node_list *)tc->pn;
2450 }
aPiecek3f247652021-04-19 13:40:25 +02002451 assert(list->nodetype & LYS_LIST);
2452
2453 if (trg_charptr_has_data(list->key)) {
2454 ly_print_(out, "%s", list->key);
2455 }
2456}
2457
2458/**
aPiecek03cb4872022-10-24 10:31:51 +02002459 * @brief Get address of the current node.
2460 * @param[in] tc contains current node.
2461 * @return Address of lysc_node or lysp_node, or NULL.
2462 */
2463static const void *
2464tro_tree_ctx_get_node(const struct trt_tree_ctx *tc)
2465{
2466 return tc->lysc_tree ?
2467 (const void *)tc->cn :
2468 (const void *)tc->pn;
2469}
2470
2471/**
2472 * @brief Get address of current node's child.
2473 * @param[in,out] tc contains current node.
2474 */
2475static const void *
2476tro_tree_ctx_get_child(const struct trt_tree_ctx *tc)
2477{
2478 if (!tro_tree_ctx_get_node(tc)) {
2479 return NULL;
2480 }
2481
2482 if (tc->lysc_tree) {
2483 return lysc_node_child(tc->cn);
2484 } else {
2485 return lysp_node_child(tc->pn);
2486 }
2487}
2488
2489/**
aPiecek3f247652021-04-19 13:40:25 +02002490 * @brief Get rpcs section if exists.
2491 * @param[in,out] tc is tree context.
2492 * @return Section representation if it exists. The @p tc is modified
2493 * and his pointer points to the first node in rpcs section.
2494 * @return Empty section representation otherwise.
2495 */
2496static struct trt_keyword_stmt
2497tro_modi_get_rpcs(struct trt_tree_ctx *tc)
2498{
aPiecek9f792e52021-04-21 08:33:56 +02002499 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002500 const void *actions;
aPiecek03cb4872022-10-24 10:31:51 +02002501 struct trt_keyword_stmt ret = {0};
aPiecek3f247652021-04-19 13:40:25 +02002502
2503 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002504 actions = tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002505 if (actions) {
2506 tc->cn = actions;
2507 }
2508 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002509 actions = tc->pmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002510 if (actions) {
2511 tc->pn = actions;
2512 tc->tpn = tc->pn;
2513 }
2514 }
2515
2516 if (actions) {
2517 tc->section = TRD_SECT_RPCS;
aPiecek03cb4872022-10-24 10:31:51 +02002518 ret.section_name = TRD_KEYWORD_RPC;
2519 ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0;
aPiecek3f247652021-04-19 13:40:25 +02002520 }
aPiecek03cb4872022-10-24 10:31:51 +02002521
2522 return ret;
aPiecek3f247652021-04-19 13:40:25 +02002523}
2524
2525/**
2526 * @brief Get notification section if exists
2527 * @param[in,out] tc is tree context.
2528 * @return Section representation if it exists.
2529 * The @p tc is modified and his pointer points to the
2530 * first node in notification section.
2531 * @return Empty section representation otherwise.
2532 */
2533static struct trt_keyword_stmt
2534tro_modi_get_notifications(struct trt_tree_ctx *tc)
2535{
aPiecek9f792e52021-04-21 08:33:56 +02002536 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002537 const void *notifs;
aPiecek03cb4872022-10-24 10:31:51 +02002538 struct trt_keyword_stmt ret = {0};
aPiecek3f247652021-04-19 13:40:25 +02002539
2540 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002541 notifs = tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002542 if (notifs) {
2543 tc->cn = notifs;
2544 }
2545 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002546 notifs = tc->pmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002547 if (notifs) {
2548 tc->pn = notifs;
2549 tc->tpn = tc->pn;
2550 }
2551 }
2552
2553 if (notifs) {
2554 tc->section = TRD_SECT_NOTIF;
aPiecek03cb4872022-10-24 10:31:51 +02002555 ret.section_name = TRD_KEYWORD_NOTIF;
2556 ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0;
aPiecek3f247652021-04-19 13:40:25 +02002557 }
aPiecek03cb4872022-10-24 10:31:51 +02002558
2559 return ret;
aPiecek3f247652021-04-19 13:40:25 +02002560}
2561
aPiecekef1e58e2021-04-19 13:19:44 +02002562static struct trt_keyword_stmt
aPiecek03cb4872022-10-24 10:31:51 +02002563tro_get_ext_section(struct trt_tree_ctx *tc, void *ext, struct lyspr_tree_ctx *plug_ctx)
aPiecekef1e58e2021-04-19 13:19:44 +02002564{
aPiecek03cb4872022-10-24 10:31:51 +02002565 struct trt_keyword_stmt ret = {0};
2566 struct lysc_ext_instance *ce = NULL;
2567 struct lysp_ext_instance *pe = NULL;
aPiecek96baa7f2021-04-23 12:32:00 +02002568
2569 if (tc->lysc_tree) {
aPiecek03cb4872022-10-24 10:31:51 +02002570 ce = ext;
2571 ret.section_name = ce->def->name;
2572 ret.argument = ce->argument;
2573 ret.has_node = plug_ctx->schemas->ctree ? 1 : 0;
aPiecek96baa7f2021-04-23 12:32:00 +02002574 } else {
aPiecek03cb4872022-10-24 10:31:51 +02002575 pe = ext;
2576 ret.section_name = pe->def->name;
2577 ret.argument = pe->argument;
2578 ret.has_node = plug_ctx->schemas->ptree ? 1 : 0;
aPiecek96baa7f2021-04-23 12:32:00 +02002579 }
2580
aPiecek03cb4872022-10-24 10:31:51 +02002581 return ret;
aPiecekef1e58e2021-04-19 13:19:44 +02002582}
2583
2584/**
2585 * @brief Get name of the module.
2586 * @param[in] tc is context of the tree.
2587 */
2588static struct trt_keyword_stmt
2589tro_read_module_name(const struct trt_tree_ctx *tc)
2590{
aPiecek9f792e52021-04-21 08:33:56 +02002591 assert(tc);
aPiecek9f792e52021-04-21 08:33:56 +02002592 struct trt_keyword_stmt ret;
2593
aPiecek03cb4872022-10-24 10:31:51 +02002594 ret.section_name = !tc->lysc_tree && tc->pmod->is_submod ?
aPiecek9f792e52021-04-21 08:33:56 +02002595 TRD_KEYWORD_SUBMODULE :
2596 TRD_KEYWORD_MODULE;
2597
aPiecek03cb4872022-10-24 10:31:51 +02002598 ret.argument = !tc->lysc_tree ?
aPiecek9f792e52021-04-21 08:33:56 +02002599 LYSP_MODULE_NAME(tc->pmod) :
2600 tc->cmod->mod->name;
2601
aPiecek03cb4872022-10-24 10:31:51 +02002602 ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0;
2603
aPiecek9f792e52021-04-21 08:33:56 +02002604 return ret;
aPiecekef1e58e2021-04-19 13:19:44 +02002605}
2606
aPiecek03cb4872022-10-24 10:31:51 +02002607static ly_bool
2608tro_read_if_sibling_exists(const struct trt_tree_ctx *tc)
2609{
2610 const void *parent;
2611
2612 if (tc->lysc_tree) {
2613 parent = troc_parent(tc->cn);
2614 } else {
2615 parent = trop_parent(tc->pn);
2616 }
2617
2618 return parent ? 1 : 0;
2619}
2620
aPiecekb8d5a0a2021-05-20 08:20:24 +02002621/**
2622 * @brief Create implicit "case" node as parent of @p node.
2623 * @param[in] node child of implicit case node.
aPiecek02665a82022-12-14 10:38:16 +01002624 * @param[out] case_node created case node.
aPiecekb8d5a0a2021-05-20 08:20:24 +02002625 */
aPiecek02665a82022-12-14 10:38:16 +01002626static void
2627tro_create_implicit_case_node(const struct trt_node *node, struct trt_node *case_node)
aPiecekb8d5a0a2021-05-20 08:20:24 +02002628{
aPiecek02665a82022-12-14 10:38:16 +01002629 case_node->status = node->status;
2630 case_node->flags = TRD_FLAGS_TYPE_EMPTY;
2631 case_node->name.type = TRD_NODE_CASE;
2632 case_node->name.keys = node->name.keys;
2633 case_node->name.module_prefix = node->name.module_prefix;
2634 case_node->name.str = node->name.str;
2635 case_node->name.opts = node->name.opts;
2636 case_node->name.add_opts = node->name.add_opts;
2637 case_node->type = TRP_EMPTY_TRT_TYPE;
2638 case_node->iffeatures = TRP_EMPTY_TRT_IFFEATURES;
2639 case_node->last_one = node->last_one;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002640}
2641
aPiecekef1e58e2021-04-19 13:19:44 +02002642/**********************************************************************
2643 * Definition of trop reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02002644 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002645
2646/**
aPiecek61d062b2020-11-02 11:05:09 +01002647 * @brief Check if list statement has keys.
2648 * @param[in] pn is pointer to the list.
2649 * @return 1 if has keys, otherwise 0.
2650 */
2651static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002652trop_list_has_keys(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002653{
aPiecekef1e58e2021-04-19 13:19:44 +02002654 return trg_charptr_has_data(((const struct lysp_node_list *)pn)->key);
aPiecek61d062b2020-11-02 11:05:09 +01002655}
2656
2657/**
2658 * @brief Check if it contains at least one feature.
aPiecek3f247652021-04-19 13:40:25 +02002659 * @param[in] pn is current node.
aPiecek61d062b2020-11-02 11:05:09 +01002660 * @return 1 if has if-features, otherwise 0.
2661 */
2662static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002663trop_node_has_iffeature(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002664{
2665 LY_ARRAY_COUNT_TYPE u;
aPiecekef1e58e2021-04-19 13:19:44 +02002666 const struct lysp_qname *iffs;
2667
aPiecek61d062b2020-11-02 11:05:09 +01002668 ly_bool ret = 0;
2669
aPiecekef1e58e2021-04-19 13:19:44 +02002670 iffs = pn->iffeatures;
aPiecek61d062b2020-11-02 11:05:09 +01002671 LY_ARRAY_FOR(iffs, u) {
2672 ret = 1;
2673 break;
2674 }
2675 return ret;
2676}
2677
2678/**
2679 * @brief Find out if leaf is also the key in last list.
2680 * @param[in] pn is pointer to leaf.
aPiecek874ea4d2021-04-19 12:26:36 +02002681 * @param[in] ca_last_list is pointer to last visited list.
2682 * Obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002683 * @return 1 if leaf is also the key, otherwise 0.
2684 */
2685static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002686trop_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
aPiecek61d062b2020-11-02 11:05:09 +01002687{
2688 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2689 const struct lysp_node_list *list = ca_last_list;
2690
2691 if (!list) {
2692 return 0;
2693 }
2694 return trg_charptr_has_data(list->key) ?
2695 trg_word_is_present(list->key, leaf->name, ' ') : 0;
2696}
2697
2698/**
2699 * @brief Check if container's type is presence.
2700 * @param[in] pn is pointer to container.
2701 * @return 1 if container has presence statement, otherwise 0.
2702 */
2703static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002704trop_container_has_presence(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002705{
2706 return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence);
2707}
2708
2709/**
2710 * @brief Get leaflist's path without lysp_node type control.
2711 * @param[in] pn is pointer to the leaflist.
2712 */
2713static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002714trop_leaflist_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002715{
2716 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2717
2718 return list->type.path ? list->type.path->expr : NULL;
2719}
2720
2721/**
2722 * @brief Get leaflist's type name without lysp_node type control.
2723 * @param[in] pn is pointer to the leaflist.
2724 */
2725static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002726trop_leaflist_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002727{
2728 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2729
2730 return list->type.name;
2731}
2732
2733/**
2734 * @brief Get leaf's path without lysp_node type control.
2735 * @param[in] pn is pointer to the leaf node.
2736 */
2737static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002738trop_leaf_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002739{
2740 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2741
2742 return leaf->type.path ? leaf->type.path->expr : NULL;
2743}
2744
2745/**
2746 * @brief Get leaf's type name without lysp_node type control.
2747 * @param[in] pn is pointer to the leaf's type name.
2748 */
2749static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002750trop_leaf_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002751{
2752 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2753
2754 return leaf->type.name;
2755}
2756
2757/**
aPiecek874ea4d2021-04-19 12:26:36 +02002758 * @brief Get pointer to data using node type specification
2759 * and getter function.
aPiecek61d062b2020-11-02 11:05:09 +01002760 *
aPiecek874ea4d2021-04-19 12:26:36 +02002761 * @param[in] flags is node type specification.
2762 * If it is the correct node, the getter function is called.
2763 * @param[in] f is getter function which provides the desired
2764 * char pointer from the structure.
aPiecek61d062b2020-11-02 11:05:09 +01002765 * @param[in] pn pointer to node.
aPiecek874ea4d2021-04-19 12:26:36 +02002766 * @return NULL if node has wrong type or getter function return
2767 * pointer to NULL.
aPiecek61d062b2020-11-02 11:05:09 +01002768 * @return Pointer to desired char pointer obtained from the node.
2769 */
2770static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002771trop_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002772{
2773 if (pn->nodetype & flags) {
2774 const char *ret = f(pn);
Michal Vasko26bbb272022-08-02 14:54:33 +02002775
aPiecek61d062b2020-11-02 11:05:09 +01002776 return trg_charptr_has_data(ret) ? ret : NULL;
2777 } else {
2778 return NULL;
2779 }
2780}
2781
2782/**
aPiecek61d062b2020-11-02 11:05:09 +01002783 * @brief Resolve \<status\> of the current node.
2784 * @param[in] nodetype is node's type obtained from the tree.
2785 * @param[in] flags is node's flags obtained from the tree.
aPiecek03cb4872022-10-24 10:31:51 +02002786 * @param[in] ca_lys_status is inherited status obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002787 * @return The status type.
2788 */
aPiecek41219f92022-10-26 11:24:40 +02002789static char *
aPiecekef1e58e2021-04-19 13:19:44 +02002790trop_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
aPiecek61d062b2020-11-02 11:05:09 +01002791{
aPiecek61d062b2020-11-02 11:05:09 +01002792 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02002793 /* LYS_INPUT and LYS_OUTPUT is special case */
aPiecekef1e58e2021-04-19 13:19:44 +02002794 return tro_flags2status(ca_lys_status);
2795 /* if ancestor's status is deprc or obslt
2796 * and also node's status is not set
2797 */
aPiecek61d062b2020-11-02 11:05:09 +01002798 } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
2799 /* get ancestor's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002800 return tro_flags2status(ca_lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002801 } else {
2802 /* else get node's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002803 return tro_flags2status(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002804 }
2805}
2806
2807/**
2808 * @brief Resolve \<flags\> of the current node.
2809 * @param[in] nodetype is node's type obtained from the tree.
2810 * @param[in] flags is node's flags obtained from the tree.
aPiecek03cb4872022-10-24 10:31:51 +02002811 * @param[in] ca_ancestor is ancestor type obtained from trt_parent_cache.
2812 * @param[in] ca_lys_config is inherited config item obtained from trt_parent_cache.
2813 * @param[in] no Override structure for flags.
aPiecek61d062b2020-11-02 11:05:09 +01002814 * @return The flags type.
2815 */
aPiecek03cb4872022-10-24 10:31:51 +02002816static const char *
2817trop_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config,
2818 struct lyplg_ext_sprinter_tree_node_override *no)
aPiecek61d062b2020-11-02 11:05:09 +01002819{
aPiecek03cb4872022-10-24 10:31:51 +02002820 if (no && no->flags) {
2821 return no->flags;
2822 } else if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) {
aPiecek61d062b2020-11-02 11:05:09 +01002823 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
2824 } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) {
2825 return TRD_FLAGS_TYPE_RO;
2826 } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) {
2827 return TRD_FLAGS_TYPE_RO;
2828 } else if (nodetype & LYS_NOTIF) {
2829 return TRD_FLAGS_TYPE_NOTIF;
2830 } else if (nodetype & LYS_USES) {
2831 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
2832 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
2833 return TRD_FLAGS_TYPE_RPC;
aPiecek61d062b2020-11-02 11:05:09 +01002834 } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002835 /* config is not set. Look at ancestor's config */
2836 return tro_flags2config(ca_lys_config);
aPiecek61d062b2020-11-02 11:05:09 +01002837 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02002838 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002839 }
2840}
2841
2842/**
2843 * @brief Resolve node type of the current node.
2844 * @param[in] pn is pointer to the current node in the tree.
aPiecek03cb4872022-10-24 10:31:51 +02002845 * @param[in] ca_last_list is pointer to the last visited list. Obtained from the trt_parent_cache.
aPiecek03cb4872022-10-24 10:31:51 +02002846 * @param[out] type Resolved type of node.
2847 * @param[out] opts Resolved opts of node.
aPiecek61d062b2020-11-02 11:05:09 +01002848 */
aPiecek41219f92022-10-26 11:24:40 +02002849static void
aPiecek03cb4872022-10-24 10:31:51 +02002850trop_resolve_node_opts(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list, trt_node_type *type,
2851 const char **opts)
aPiecek61d062b2020-11-02 11:05:09 +01002852{
2853 if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02002854 *type = TRD_NODE_ELSE;
aPiecek61d062b2020-11-02 11:05:09 +01002855 } else if (pn->nodetype & LYS_CASE) {
aPiecek41219f92022-10-26 11:24:40 +02002856 *type = TRD_NODE_CASE;
aPiecek61d062b2020-11-02 11:05:09 +01002857 } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02002858 *type = TRD_NODE_CHOICE;
2859 *opts = TRD_NODE_OPTIONAL;
aPiecek61d062b2020-11-02 11:05:09 +01002860 } else if (pn->nodetype & LYS_CHOICE) {
aPiecek41219f92022-10-26 11:24:40 +02002861 *type = TRD_NODE_CHOICE;
aPiecekef1e58e2021-04-19 13:19:44 +02002862 } else if ((pn->nodetype & LYS_CONTAINER) && (trop_container_has_presence(pn))) {
aPiecek41219f92022-10-26 11:24:40 +02002863 *opts = TRD_NODE_CONTAINER;
aPiecek61d062b2020-11-02 11:05:09 +01002864 } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
aPiecek41219f92022-10-26 11:24:40 +02002865 *opts = TRD_NODE_LISTLEAFLIST;
aPiecek61d062b2020-11-02 11:05:09 +01002866 } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02002867 *opts = TRD_NODE_OPTIONAL;
aPiecekef1e58e2021-04-19 13:19:44 +02002868 } 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 +02002869 *opts = TRD_NODE_OPTIONAL;
aPiecek61d062b2020-11-02 11:05:09 +01002870 } else {
aPiecek41219f92022-10-26 11:24:40 +02002871 *type = TRD_NODE_ELSE;
aPiecek61d062b2020-11-02 11:05:09 +01002872 }
2873}
2874
2875/**
aPiecekef1e58e2021-04-19 13:19:44 +02002876 * @brief Resolve \<type\> of the current node.
2877 * @param[in] pn is current node.
aPiecek03cb4872022-10-24 10:31:51 +02002878 * @return Resolved type.
aPiecekef1e58e2021-04-19 13:19:44 +02002879 */
2880static struct trt_type
2881trop_resolve_type(const struct lysp_node *pn)
2882{
2883 const char *tmp = NULL;
2884
aPiecek03cb4872022-10-24 10:31:51 +02002885 if (!pn) {
2886 return TRP_EMPTY_TRT_TYPE;
2887 } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_refpath, pn))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002888 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2889 } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_type_name, pn))) {
2890 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2891 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_refpath, pn))) {
2892 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2893 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_type_name, pn))) {
2894 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2895 } else if (pn->nodetype == LYS_ANYDATA) {
2896 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata");
2897 } else if (pn->nodetype & LYS_ANYXML) {
2898 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml");
2899 } else {
2900 return TRP_EMPTY_TRT_TYPE;
2901 }
2902}
2903
2904/**
aPiecek03cb4872022-10-24 10:31:51 +02002905 * @brief Resolve iffeatures.
2906 *
2907 * @param[in] pn is current parsed node.
aPiecek03cb4872022-10-24 10:31:51 +02002908 * @return Resolved iffeatures.
2909 */
2910static struct trt_iffeatures
2911trop_resolve_iffeatures(const struct lysp_node *pn)
2912{
2913 struct trt_iffeatures iff;
2914
2915 if (pn && trop_node_has_iffeature(pn)) {
2916 iff.type = TRD_IFF_PRESENT;
2917 iff.str = NULL;
2918 } else {
2919 iff.type = TRD_IFF_NON_PRESENT;
2920 iff.str = NULL;
2921 }
2922
2923 return iff;
2924}
2925
2926/**
aPiecek61d062b2020-11-02 11:05:09 +01002927 * @brief Transformation of current lysp_node to struct trt_node.
aPiecek874ea4d2021-04-19 12:26:36 +02002928 * @param[in] ca contains stored important data
2929 * when browsing the tree downwards.
aPiecek61d062b2020-11-02 11:05:09 +01002930 * @param[in] tc is context of the tree.
2931 */
2932static struct trt_node
aPiecek03cb4872022-10-24 10:31:51 +02002933trop_read_node(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002934{
aPiecekef1e58e2021-04-19 13:19:44 +02002935 const struct lysp_node *pn;
2936 struct trt_node ret;
aPiecek03cb4872022-10-24 10:31:51 +02002937 struct lyplg_ext_sprinter_tree_node_override *no;
aPiecekef1e58e2021-04-19 13:19:44 +02002938
aPiecek61d062b2020-11-02 11:05:09 +01002939 assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
aPiecekef1e58e2021-04-19 13:19:44 +02002940
aPiecek03cb4872022-10-24 10:31:51 +02002941 no = tro_set_node_overr(tc->lysc_tree, tc->pn, 1, &tc->plugin_ctx);
2942
aPiecekef1e58e2021-04-19 13:19:44 +02002943 pn = tc->pn;
2944 ret = TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01002945
2946 /* <status> */
aPiecekef1e58e2021-04-19 13:19:44 +02002947 ret.status = trop_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002948
aPiecek61d062b2020-11-02 11:05:09 +01002949 /* <flags> */
aPiecek03cb4872022-10-24 10:31:51 +02002950 ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config, no);
aPiecek61d062b2020-11-02 11:05:09 +01002951
aPiecek61d062b2020-11-02 11:05:09 +01002952 /* set type of the node */
aPiecek03cb4872022-10-24 10:31:51 +02002953 trop_resolve_node_opts(pn, ca.last_list, &ret.name.type, &ret.name.opts);
2954 ret.name.add_opts = no && no->add_opts ? no->add_opts : NULL;
aPiecekbca57772022-10-13 13:51:59 +02002955 ret.name.keys = (tc->pn->nodetype & LYS_LIST) && trop_list_has_keys(tc->pn);
aPiecek61d062b2020-11-02 11:05:09 +01002956
aPiecek34fa3772021-05-21 12:35:46 +02002957 /* The parsed tree is not compiled, so no node can be augmented
2958 * from another module. This means that nodes from the parsed tree
2959 * will never have the prefix.
2960 */
aPiecek61d062b2020-11-02 11:05:09 +01002961 ret.name.module_prefix = NULL;
2962
2963 /* set node's name */
2964 ret.name.str = pn->name;
2965
2966 /* <type> */
aPiecekef1e58e2021-04-19 13:19:44 +02002967 ret.type = trop_resolve_type(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002968
2969 /* <iffeature> */
aPiecek03cb4872022-10-24 10:31:51 +02002970 ret.iffeatures = trop_resolve_iffeatures(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002971
aPiecek03cb4872022-10-24 10:31:51 +02002972 ret.last_one = !tro_next_sibling(pn, tc);
aPiecek61d062b2020-11-02 11:05:09 +01002973
2974 return ret;
2975}
2976
aPiecekef1e58e2021-04-19 13:19:44 +02002977/**
2978 * @brief Find out if the current node has siblings.
2979 * @param[in] tc is context of the tree.
2980 * @return 1 if sibling exists otherwise 0.
2981 */
2982static ly_bool
2983trop_read_if_sibling_exists(const struct trt_tree_ctx *tc)
2984{
aPiecek03cb4872022-10-24 10:31:51 +02002985 return tro_next_sibling(tc->pn, tc) != NULL;
aPiecek96baa7f2021-04-23 12:32:00 +02002986}
2987
aPiecek874ea4d2021-04-19 12:26:36 +02002988/**********************************************************************
aPiecekef1e58e2021-04-19 13:19:44 +02002989 * Modify trop getters
aPiecek874ea4d2021-04-19 12:26:36 +02002990 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002991
2992/**
aPiecek874ea4d2021-04-19 12:26:36 +02002993 * @brief Change current node pointer to its parent
2994 * but only if parent exists.
2995 * @param[in,out] tc is tree context.
2996 * Contains pointer to the current node.
aPiecek61d062b2020-11-02 11:05:09 +01002997 * @return 1 if the node had parents and the change was successful.
aPiecek874ea4d2021-04-19 12:26:36 +02002998 * @return 0 if the node did not have parents.
2999 * The pointer to the current node did not change.
aPiecek61d062b2020-11-02 11:05:09 +01003000 */
3001static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02003002trop_modi_parent(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003003{
3004 assert(tc && tc->pn);
3005 /* If no parent exists, stay in actual node. */
aPiecek96baa7f2021-04-23 12:32:00 +02003006 if ((tc->pn != tc->tpn) && (tc->pn->parent)) {
aPiecek61d062b2020-11-02 11:05:09 +01003007 tc->pn = tc->pn->parent;
3008 return 1;
3009 } else {
3010 return 0;
3011 }
3012}
3013
3014/**
aPiecek874ea4d2021-04-19 12:26:36 +02003015 * @brief Change the current node pointer to its child
3016 * but only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01003017 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02003018 * @param[in,out] tc is context of the tree.
3019 * Contains pointer to the current node.
3020 * @return Non-empty \<node\> representation of the current
3021 * node's child. The @p tc is modified.
3022 * @return Empty \<node\> representation if child don't exists.
3023 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01003024 */
3025static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02003026trop_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003027{
aPiecekef1e58e2021-04-19 13:19:44 +02003028 const struct lysp_node *tmp;
3029
aPiecek61d062b2020-11-02 11:05:09 +01003030 assert(tc && tc->pn);
3031
aPiecek03cb4872022-10-24 10:31:51 +02003032 if ((tmp = tro_next_child(tc->pn, tc))) {
aPiecekef1e58e2021-04-19 13:19:44 +02003033 tc->pn = tmp;
aPiecek67521c22022-10-19 09:15:02 +02003034 return trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003035 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02003036 return TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01003037 }
3038}
3039
3040/**
aPiecek03cb4872022-10-24 10:31:51 +02003041 * @brief Change the pointer to the current node to its next sibling
3042 * only if exists.
3043 * @param[in] ca contains inherited data from ancestors.
3044 * @param[in,out] tc is tree context.
3045 * Contains pointer to the current node.
3046 * @return Non-empty \<node\> representation if sibling exists.
3047 * The @p tc is modified.
3048 * @return Empty \<node\> representation otherwise.
3049 * The @p tc is not modified.
3050 */
3051static struct trt_node
3052trop_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3053{
3054 const struct lysp_node *pn;
3055
3056 assert(tc && tc->pn);
3057
3058 pn = tro_next_sibling(tc->pn, tc);
3059
3060 if (pn) {
3061 if ((tc->tpn == tc->pn) && (tc->section != TRD_SECT_PLUG_DATA)) {
3062 tc->tpn = pn;
3063 }
3064 tc->pn = pn;
3065 return trop_read_node(ca, tc);
3066 } else {
3067 return TRP_EMPTY_NODE;
3068 }
3069}
3070
3071/**
aPiecek874ea4d2021-04-19 12:26:36 +02003072 * @brief Change the current node pointer to the first child of node's
3073 * parent. If current node is already first sibling/child then nothing
3074 * will change.
aPiecek03cb4872022-10-24 10:31:51 +02003075 * @param[in] ca Settings of parent.
aPiecek61d062b2020-11-02 11:05:09 +01003076 * @param[in,out] tc is tree context.
aPiecek03cb4872022-10-24 10:31:51 +02003077 * @return node for printing.
aPiecek61d062b2020-11-02 11:05:09 +01003078 */
aPiecek03cb4872022-10-24 10:31:51 +02003079static struct trt_node
3080trop_modi_first_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003081{
aPiecek03cb4872022-10-24 10:31:51 +02003082 struct trt_node node;
3083
3084 assert(tc && tc->pn);
aPiecek61d062b2020-11-02 11:05:09 +01003085
aPiecekef1e58e2021-04-19 13:19:44 +02003086 if (trop_modi_parent(tc)) {
aPiecek03cb4872022-10-24 10:31:51 +02003087 node = trop_modi_next_child(ca, tc);
3088 } else if (tc->plugin_ctx.schema) {
3089 tc->pn = tc->plugin_ctx.schema->ptree;
3090 tc->tpn = tc->pn;
3091 node = trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003092 } else {
3093 /* current node is top-node */
aPiecek61d062b2020-11-02 11:05:09 +01003094 switch (tc->section) {
3095 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02003096 tc->pn = tc->pmod->data;
aPiecek96baa7f2021-04-23 12:32:00 +02003097 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003098 break;
3099 case TRD_SECT_AUGMENT:
aPiecek9f792e52021-04-21 08:33:56 +02003100 tc->pn = (const struct lysp_node *)tc->pmod->augments;
aPiecek96baa7f2021-04-23 12:32:00 +02003101 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003102 break;
3103 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02003104 tc->pn = (const struct lysp_node *)tc->pmod->rpcs;
aPiecek96baa7f2021-04-23 12:32:00 +02003105 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003106 break;
3107 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02003108 tc->pn = (const struct lysp_node *)tc->pmod->notifs;
aPiecek96baa7f2021-04-23 12:32:00 +02003109 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003110 break;
3111 case TRD_SECT_GROUPING:
aPiecek9f792e52021-04-21 08:33:56 +02003112 tc->pn = (const struct lysp_node *)tc->pmod->groupings;
aPiecek96baa7f2021-04-23 12:32:00 +02003113 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01003114 break;
aPiecek03cb4872022-10-24 10:31:51 +02003115 case TRD_SECT_PLUG_DATA:
3116 /* Nothing to do. */
aPiecek61d062b2020-11-02 11:05:09 +01003117 break;
aPiecek96baa7f2021-04-23 12:32:00 +02003118 default:
3119 assert(0);
aPiecek61d062b2020-11-02 11:05:09 +01003120 }
aPiecek03cb4872022-10-24 10:31:51 +02003121 node = trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003122 }
aPiecek61d062b2020-11-02 11:05:09 +01003123
aPiecek03cb4872022-10-24 10:31:51 +02003124 if (tc->plugin_ctx.filtered) {
3125 node = trop_modi_next_sibling(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003126 }
aPiecek03cb4872022-10-24 10:31:51 +02003127
3128 return node;
aPiecek61d062b2020-11-02 11:05:09 +01003129}
3130
3131/**
3132 * @brief Get next (or first) augment section if exists.
aPiecek874ea4d2021-04-19 12:26:36 +02003133 * @param[in,out] tc is tree context. It is modified and his current
3134 * node is set to the lysp_node_augment.
aPiecek61d062b2020-11-02 11:05:09 +01003135 * @return Section's representation if (next augment) section exists.
aPiecek61d062b2020-11-02 11:05:09 +01003136 * @return Empty section structure otherwise.
3137 */
3138static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003139trop_modi_next_augment(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003140{
aPiecek9f792e52021-04-21 08:33:56 +02003141 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003142 const struct lysp_node_augment *augs;
aPiecek03cb4872022-10-24 10:31:51 +02003143 struct trt_keyword_stmt ret = {0};
aPiecek61d062b2020-11-02 11:05:09 +01003144
3145 /* if next_augment func was called for the first time */
3146 if (tc->section != TRD_SECT_AUGMENT) {
3147 tc->section = TRD_SECT_AUGMENT;
aPiecek9f792e52021-04-21 08:33:56 +02003148 augs = tc->pmod->augments;
aPiecek61d062b2020-11-02 11:05:09 +01003149 } else {
3150 /* get augment sibling from top-node pointer */
aPiecekdc8fd572021-04-19 10:47:23 +02003151 augs = (const struct lysp_node_augment *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003152 }
3153
aPiecekdc8fd572021-04-19 10:47:23 +02003154 if (augs) {
3155 tc->pn = &augs->node;
aPiecek61d062b2020-11-02 11:05:09 +01003156 tc->tpn = tc->pn;
aPiecek03cb4872022-10-24 10:31:51 +02003157 ret.section_name = TRD_KEYWORD_AUGMENT;
3158 ret.argument = augs->nodeid;
3159 ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0;
aPiecek61d062b2020-11-02 11:05:09 +01003160 }
aPiecek03cb4872022-10-24 10:31:51 +02003161
3162 return ret;
aPiecek61d062b2020-11-02 11:05:09 +01003163}
3164
3165/**
aPiecek61d062b2020-11-02 11:05:09 +01003166 * @brief Get next (or first) grouping section if exists
aPiecek874ea4d2021-04-19 12:26:36 +02003167 * @param[in,out] tc is tree context. It is modified and his current
3168 * node is set to the lysp_node_grp.
aPiecek61d062b2020-11-02 11:05:09 +01003169 * @return The next (or first) section representation if it exists.
aPiecek61d062b2020-11-02 11:05:09 +01003170 * @return Empty section representation otherwise.
3171 */
3172static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003173trop_modi_next_grouping(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003174{
aPiecek9f792e52021-04-21 08:33:56 +02003175 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003176 const struct lysp_node_grp *grps;
aPiecek03cb4872022-10-24 10:31:51 +02003177 struct trt_keyword_stmt ret = {0};
aPiecek61d062b2020-11-02 11:05:09 +01003178
3179 if (tc->section != TRD_SECT_GROUPING) {
3180 tc->section = TRD_SECT_GROUPING;
aPiecek9f792e52021-04-21 08:33:56 +02003181 grps = tc->pmod->groupings;
aPiecek61d062b2020-11-02 11:05:09 +01003182 } else {
aPiecekdc8fd572021-04-19 10:47:23 +02003183 grps = (const struct lysp_node_grp *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003184 }
3185
aPiecekdc8fd572021-04-19 10:47:23 +02003186 if (grps) {
3187 tc->pn = &grps->node;
aPiecek61d062b2020-11-02 11:05:09 +01003188 tc->tpn = tc->pn;
aPiecek03cb4872022-10-24 10:31:51 +02003189 ret.section_name = TRD_KEYWORD_GROUPING;
3190 ret.argument = grps->name;
3191 ret.has_node = tro_tree_ctx_get_child(tc) ? 1 : 0;
aPiecek61d062b2020-11-02 11:05:09 +01003192 }
aPiecek03cb4872022-10-24 10:31:51 +02003193
3194 return ret;
aPiecek61d062b2020-11-02 11:05:09 +01003195}
3196
aPiecek874ea4d2021-04-19 12:26:36 +02003197/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02003198 * Definition of troc reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02003199 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003200
3201/**
aPiecek3f247652021-04-19 13:40:25 +02003202 * @copydoc trop_read_if_sibling_exists
aPiecek61d062b2020-11-02 11:05:09 +01003203 */
aPiecek3f247652021-04-19 13:40:25 +02003204static ly_bool
3205troc_read_if_sibling_exists(const struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003206{
aPiecek03cb4872022-10-24 10:31:51 +02003207 return tro_next_sibling(tc->cn, tc) != NULL;
aPiecek3f247652021-04-19 13:40:25 +02003208}
aPiecek61d062b2020-11-02 11:05:09 +01003209
aPiecek3f247652021-04-19 13:40:25 +02003210/**
3211 * @brief Resolve \<flags\> of the current node.
3212 *
3213 * Use this function only if trt_tree_ctx.lysc_tree is true.
3214 *
3215 * @param[in] nodetype is current lysc_node.nodetype.
3216 * @param[in] flags is current lysc_node.flags.
aPiecek03cb4872022-10-24 10:31:51 +02003217 * @param[in] no Override structure for flags.
aPiecek3f247652021-04-19 13:40:25 +02003218 * @return The flags type.
3219 */
aPiecek03cb4872022-10-24 10:31:51 +02003220static const char *
3221troc_resolve_flags(uint16_t nodetype, uint16_t flags, struct lyplg_ext_sprinter_tree_node_override *no)
aPiecek3f247652021-04-19 13:40:25 +02003222{
aPiecek03cb4872022-10-24 10:31:51 +02003223 if (no && no->flags) {
3224 return no->flags;
3225 } else if ((nodetype & LYS_INPUT) || (flags & LYS_IS_INPUT)) {
aPiecek3f247652021-04-19 13:40:25 +02003226 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
3227 } else if ((nodetype & LYS_OUTPUT) || (flags & LYS_IS_OUTPUT)) {
3228 return TRD_FLAGS_TYPE_RO;
3229 } else if (nodetype & LYS_IS_NOTIF) {
3230 return TRD_FLAGS_TYPE_RO;
3231 } else if (nodetype & LYS_NOTIF) {
3232 return TRD_FLAGS_TYPE_NOTIF;
3233 } else if (nodetype & LYS_USES) {
3234 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
3235 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
3236 return TRD_FLAGS_TYPE_RPC;
3237 } else {
3238 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01003239 }
aPiecek61d062b2020-11-02 11:05:09 +01003240}
3241
3242/**
aPiecek3f247652021-04-19 13:40:25 +02003243 * @brief Resolve node type of the current node.
aPiecek61d062b2020-11-02 11:05:09 +01003244 *
aPiecek3f247652021-04-19 13:40:25 +02003245 * Use this function only if trt_tree_ctx.lysc_tree is true.
aPiecek61d062b2020-11-02 11:05:09 +01003246 *
aPiecek3f247652021-04-19 13:40:25 +02003247 * @param[in] nodetype is current lysc_node.nodetype.
3248 * @param[in] flags is current lysc_node.flags.
aPiecek03cb4872022-10-24 10:31:51 +02003249 * @param[out] type Resolved type of node.
3250 * @param[out] opts Resolved opts.
aPiecek3f247652021-04-19 13:40:25 +02003251 */
aPiecek41219f92022-10-26 11:24:40 +02003252static void
aPiecek03cb4872022-10-24 10:31:51 +02003253troc_resolve_node_opts(uint16_t nodetype, uint16_t flags, trt_node_type *type, const char **opts)
aPiecek3f247652021-04-19 13:40:25 +02003254{
3255 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecek41219f92022-10-26 11:24:40 +02003256 *type = TRD_NODE_ELSE;
aPiecek3f247652021-04-19 13:40:25 +02003257 } else if (nodetype & LYS_CASE) {
aPiecek41219f92022-10-26 11:24:40 +02003258 *type = TRD_NODE_CASE;
aPiecek3f247652021-04-19 13:40:25 +02003259 } else if ((nodetype & LYS_CHOICE) && !(flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02003260 *type = TRD_NODE_CHOICE;
3261 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003262 } else if (nodetype & LYS_CHOICE) {
aPiecek41219f92022-10-26 11:24:40 +02003263 *type = TRD_NODE_CHOICE;
aPiecek3f247652021-04-19 13:40:25 +02003264 } else if ((nodetype & LYS_CONTAINER) && (flags & LYS_PRESENCE)) {
aPiecek41219f92022-10-26 11:24:40 +02003265 *opts = TRD_NODE_CONTAINER;
aPiecek3f247652021-04-19 13:40:25 +02003266 } else if (nodetype & (LYS_LIST | LYS_LEAFLIST)) {
aPiecek41219f92022-10-26 11:24:40 +02003267 *opts = TRD_NODE_LISTLEAFLIST;
aPiecek3f247652021-04-19 13:40:25 +02003268 } else if ((nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(flags & LYS_MAND_TRUE)) {
aPiecek41219f92022-10-26 11:24:40 +02003269 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003270 } else if ((nodetype & LYS_LEAF) && !(flags & (LYS_MAND_TRUE | LYS_KEY))) {
aPiecek41219f92022-10-26 11:24:40 +02003271 *opts = TRD_NODE_OPTIONAL;
aPiecek3f247652021-04-19 13:40:25 +02003272 } else {
aPiecek41219f92022-10-26 11:24:40 +02003273 *type = TRD_NODE_ELSE;
aPiecek3f247652021-04-19 13:40:25 +02003274 }
3275}
3276
3277/**
aPiecek03cb4872022-10-24 10:31:51 +02003278 * @brief Resolve prefix (\<prefix\>:\<name\>) of node that has been
aPiecek34fa3772021-05-21 12:35:46 +02003279 * placed from another module via an augment statement.
3280 *
3281 * @param[in] cn is current compiled node.
3282 * @param[in] current_compiled_module is module whose nodes are
3283 * currently being printed.
3284 * @return Prefix of foreign module or NULL.
3285 */
3286static const char *
3287troc_resolve_node_prefix(const struct lysc_node *cn, const struct lysc_module *current_compiled_module)
3288{
3289 const struct lys_module *node_module;
3290 const char *ret = NULL;
3291
3292 node_module = cn->module;
aPiecek03cb4872022-10-24 10:31:51 +02003293 if (!node_module || !current_compiled_module) {
3294 return NULL;
3295 } else if (node_module->compiled != current_compiled_module) {
aPiecek34fa3772021-05-21 12:35:46 +02003296 ret = node_module->prefix;
3297 }
3298
3299 return ret;
3300}
3301
3302/**
aPiecek3f247652021-04-19 13:40:25 +02003303 * @brief Transformation of current lysc_node to struct trt_node.
3304 * @param[in] ca is not used.
3305 * @param[in] tc is context of the tree.
3306 */
3307static struct trt_node
aPiecek03cb4872022-10-24 10:31:51 +02003308troc_read_node(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek3f247652021-04-19 13:40:25 +02003309{
3310 (void) ca;
3311 const struct lysc_node *cn;
3312 struct trt_node ret;
aPiecek03cb4872022-10-24 10:31:51 +02003313 struct lyplg_ext_sprinter_tree_node_override *no;
aPiecek3f247652021-04-19 13:40:25 +02003314
aPiecek082c7dc2021-05-20 08:55:07 +02003315 assert(tc && tc->cn);
aPiecek3f247652021-04-19 13:40:25 +02003316
aPiecek03cb4872022-10-24 10:31:51 +02003317 no = tro_set_node_overr(tc->lysc_tree, tc->cn, 1, &tc->plugin_ctx);
3318
aPiecek3f247652021-04-19 13:40:25 +02003319 cn = tc->cn;
3320 ret = TRP_EMPTY_NODE;
3321
3322 /* <status> */
3323 ret.status = tro_flags2status(cn->flags);
3324
aPiecek3f247652021-04-19 13:40:25 +02003325 /* <flags> */
aPiecek03cb4872022-10-24 10:31:51 +02003326 ret.flags = troc_resolve_flags(cn->nodetype, cn->flags, no);
aPiecek3f247652021-04-19 13:40:25 +02003327
aPiecek3f247652021-04-19 13:40:25 +02003328 /* set type of the node */
aPiecek03cb4872022-10-24 10:31:51 +02003329 troc_resolve_node_opts(cn->nodetype, cn->flags, &ret.name.type, &ret.name.opts);
3330 ret.name.add_opts = no && no->add_opts ? no->add_opts : NULL;
aPiecekbca57772022-10-13 13:51:59 +02003331 ret.name.keys = (cn->nodetype & LYS_LIST) && !(cn->flags & LYS_KEYLESS);
aPiecek3f247652021-04-19 13:40:25 +02003332
aPiecek34fa3772021-05-21 12:35:46 +02003333 /* <prefix> */
3334 ret.name.module_prefix = troc_resolve_node_prefix(cn, tc->cmod);
aPiecek3f247652021-04-19 13:40:25 +02003335
3336 /* set node's name */
3337 ret.name.str = cn->name;
3338
aPiecek03cb4872022-10-24 10:31:51 +02003339 /* <type> */
3340 ret.type = trop_resolve_type(TRP_TREE_CTX_GET_LYSP_NODE(cn));
aPiecek3f247652021-04-19 13:40:25 +02003341
aPiecek03cb4872022-10-24 10:31:51 +02003342 /* <iffeature> */
3343 ret.iffeatures = trop_resolve_iffeatures(TRP_TREE_CTX_GET_LYSP_NODE(cn));
aPiecek082c7dc2021-05-20 08:55:07 +02003344
aPiecek03cb4872022-10-24 10:31:51 +02003345 ret.last_one = !tro_next_sibling(cn, tc);
aPiecek3f247652021-04-19 13:40:25 +02003346
3347 return ret;
3348}
3349
3350/**********************************************************************
3351 * Modify troc getters
3352 *********************************************************************/
3353
3354/**
aPiecek01598c02021-04-23 14:18:24 +02003355 * @copydoc ::trop_modi_parent()
aPiecek3f247652021-04-19 13:40:25 +02003356 */
3357static ly_bool
3358troc_modi_parent(struct trt_tree_ctx *tc)
3359{
3360 assert(tc && tc->cn);
3361 /* If no parent exists, stay in actual node. */
3362 if (tc->cn->parent) {
3363 tc->cn = tc->cn->parent;
3364 return 1;
3365 } else {
3366 return 0;
3367 }
3368}
3369
3370/**
aPiecek01598c02021-04-23 14:18:24 +02003371 * @copydoc ::trop_modi_next_sibling()
aPiecek3f247652021-04-19 13:40:25 +02003372 */
3373static struct trt_node
3374troc_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3375{
3376 const struct lysc_node *cn;
3377
3378 assert(tc && tc->cn);
3379
aPiecek03cb4872022-10-24 10:31:51 +02003380 cn = tro_next_sibling(tc->cn, tc);
aPiecek3f247652021-04-19 13:40:25 +02003381
3382 /* if next sibling exists */
3383 if (cn) {
3384 /* update trt_tree_ctx */
3385 tc->cn = cn;
3386 return troc_read_node(ca, tc);
3387 } else {
3388 return TRP_EMPTY_NODE;
3389 }
3390}
3391
3392/**
3393 * @copydoc trop_modi_next_child()
3394 */
3395static struct trt_node
3396troc_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3397{
3398 const struct lysc_node *tmp;
3399
3400 assert(tc && tc->cn);
3401
aPiecek03cb4872022-10-24 10:31:51 +02003402 if ((tmp = tro_next_child(tc->cn, tc))) {
aPiecek3f247652021-04-19 13:40:25 +02003403 tc->cn = tmp;
3404 return troc_read_node(ca, tc);
3405 } else {
3406 return TRP_EMPTY_NODE;
3407 }
3408}
3409
3410/**
aPiecek01598c02021-04-23 14:18:24 +02003411 * @copydoc ::trop_modi_first_sibling()
aPiecek61d062b2020-11-02 11:05:09 +01003412 */
aPiecek03cb4872022-10-24 10:31:51 +02003413static struct trt_node
3414troc_modi_first_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003415{
aPiecek03cb4872022-10-24 10:31:51 +02003416 struct trt_node node;
3417
aPiecek3f247652021-04-19 13:40:25 +02003418 assert(tc && tc->cn);
aPiecek61d062b2020-11-02 11:05:09 +01003419
aPiecek3f247652021-04-19 13:40:25 +02003420 if (troc_modi_parent(tc)) {
aPiecek03cb4872022-10-24 10:31:51 +02003421 node = troc_modi_next_child(ca, tc);
3422 } else if (tc->plugin_ctx.schema) {
3423 tc->cn = tc->plugin_ctx.schema->ctree;
3424 node = troc_read_node(ca, tc);
aPiecek3f247652021-04-19 13:40:25 +02003425 } else {
3426 /* current node is top-node */
aPiecek3f247652021-04-19 13:40:25 +02003427 switch (tc->section) {
3428 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02003429 tc->cn = tc->cmod->data;
aPiecek3f247652021-04-19 13:40:25 +02003430 break;
3431 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02003432 tc->cn = (const struct lysc_node *)tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02003433 break;
3434 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02003435 tc->cn = (const struct lysc_node *)tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02003436 break;
aPiecek03cb4872022-10-24 10:31:51 +02003437 case TRD_SECT_PLUG_DATA:
aPiecek96baa7f2021-04-23 12:32:00 +02003438 /* nothing to do */
aPiecek3f247652021-04-19 13:40:25 +02003439 break;
3440 default:
3441 assert(0);
3442 }
aPiecek03cb4872022-10-24 10:31:51 +02003443 node = troc_read_node(ca, tc);
aPiecek8f1073c2022-10-17 16:44:49 +02003444 }
3445
aPiecek03cb4872022-10-24 10:31:51 +02003446 if (tc->plugin_ctx.filtered) {
3447 node = troc_modi_next_sibling(ca, tc);
aPiecek8f1073c2022-10-17 16:44:49 +02003448 }
3449
aPiecek03cb4872022-10-24 10:31:51 +02003450 return node;
aPiecek8f1073c2022-10-17 16:44:49 +02003451}
3452
3453/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01003454 * Definition of tree browsing functions
aPiecek874ea4d2021-04-19 12:26:36 +02003455 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003456
aPiecek41219f92022-10-26 11:24:40 +02003457static uint32_t
aPiecek02665a82022-12-14 10:38:16 +01003458trb_gap_to_opts(const struct trt_node *node)
aPiecek61d062b2020-11-02 11:05:09 +01003459{
aPiecek41219f92022-10-26 11:24:40 +02003460 uint32_t len = 0;
aPiecek61d062b2020-11-02 11:05:09 +01003461
aPiecek02665a82022-12-14 10:38:16 +01003462 if (node->name.keys) {
aPiecek41219f92022-10-26 11:24:40 +02003463 return 0;
aPiecek61d062b2020-11-02 11:05:09 +01003464 }
3465
aPiecek02665a82022-12-14 10:38:16 +01003466 if (node->flags) {
3467 len += strlen(node->flags);
aPiecek41219f92022-10-26 11:24:40 +02003468 /* space between flags and name */
3469 len += 1;
3470 } else {
3471 /* space between -- and name */
3472 len += 1;
3473 }
3474
aPiecek02665a82022-12-14 10:38:16 +01003475 switch (node->name.type) {
aPiecek41219f92022-10-26 11:24:40 +02003476 case TRD_NODE_CASE:
3477 /* ':' is already counted. Plus parentheses. */
3478 len += 2;
3479 break;
3480 case TRD_NODE_CHOICE:
3481 /* Plus parentheses. */
3482 len += 2;
3483 break;
3484 default:
3485 break;
3486 }
3487
aPiecek02665a82022-12-14 10:38:16 +01003488 if (node->name.module_prefix) {
3489 len += strlen(node->name.module_prefix);
aPiecek41219f92022-10-26 11:24:40 +02003490 }
aPiecek02665a82022-12-14 10:38:16 +01003491 if (node->name.str) {
3492 len += strlen(node->name.str);
aPiecek41219f92022-10-26 11:24:40 +02003493 }
aPiecek02665a82022-12-14 10:38:16 +01003494 if (node->name.add_opts) {
3495 len += strlen(node->name.add_opts);
aPiecek03cb4872022-10-24 10:31:51 +02003496 }
aPiecek02665a82022-12-14 10:38:16 +01003497 if (node->name.opts) {
3498 len += strlen(node->name.opts);
aPiecek41219f92022-10-26 11:24:40 +02003499 }
3500
3501 return len;
3502}
3503
3504static uint32_t
aPiecek02665a82022-12-14 10:38:16 +01003505trb_gap_to_type(const struct trt_node *node)
aPiecek41219f92022-10-26 11:24:40 +02003506{
aPiecek03cb4872022-10-24 10:31:51 +02003507 uint32_t len, opts_len;
aPiecek41219f92022-10-26 11:24:40 +02003508
aPiecek02665a82022-12-14 10:38:16 +01003509 if (node->name.keys) {
aPiecek41219f92022-10-26 11:24:40 +02003510 return 0;
3511 }
3512
3513 len = trb_gap_to_opts(node);
3514 /* Gap between opts and type. */
aPiecek03cb4872022-10-24 10:31:51 +02003515 opts_len = 0;
aPiecek02665a82022-12-14 10:38:16 +01003516 opts_len += node->name.add_opts ? strlen(node->name.add_opts) : 0;
3517 opts_len += node->name.opts ? strlen(node->name.opts) : 0;
aPiecek03cb4872022-10-24 10:31:51 +02003518 if (opts_len >= TRD_INDENT_BEFORE_TYPE) {
aPiecek41219f92022-10-26 11:24:40 +02003519 /* At least one space should be there. */
3520 len += 1;
aPiecek02665a82022-12-14 10:38:16 +01003521 } else if (node->name.add_opts || node->name.opts) {
aPiecek03cb4872022-10-24 10:31:51 +02003522 len += TRD_INDENT_BEFORE_TYPE - opts_len;
aPiecek41219f92022-10-26 11:24:40 +02003523 } else {
3524 len += TRD_INDENT_BEFORE_TYPE;
3525 }
3526
3527 return len;
aPiecek61d062b2020-11-02 11:05:09 +01003528}
3529
3530/**
aPiecek874ea4d2021-04-19 12:26:36 +02003531 * @brief Calculate the trt_indent_in_node.btw_opts_type indent size
3532 * for a particular node.
aPiecek41219f92022-10-26 11:24:40 +02003533 * @param[in] node for which we get btw_opts_type.
3534 * @param[in] max_gap_before_type is the maximum value of btw_opts_type
aPiecek874ea4d2021-04-19 12:26:36 +02003535 * that it can have.
3536 * @return Indent between \<opts\> and \<type\> for node.
aPiecek61d062b2020-11-02 11:05:09 +01003537 */
3538static int16_t
aPiecek02665a82022-12-14 10:38:16 +01003539trb_calc_btw_opts_type(const struct trt_node *node, int16_t max_gap_before_type)
aPiecek61d062b2020-11-02 11:05:09 +01003540{
aPiecek41219f92022-10-26 11:24:40 +02003541 uint32_t to_opts_len;
aPiecek61d062b2020-11-02 11:05:09 +01003542
aPiecek41219f92022-10-26 11:24:40 +02003543 to_opts_len = trb_gap_to_opts(node);
3544 if (to_opts_len == 0) {
3545 return 1;
3546 } else {
3547 return max_gap_before_type - to_opts_len;
3548 }
aPiecek61d062b2020-11-02 11:05:09 +01003549}
3550
3551/**
3552 * @brief Print node.
3553 *
aPiecek01598c02021-04-23 14:18:24 +02003554 * This function is wrapper for ::trp_print_entire_node().
aPiecek874ea4d2021-04-19 12:26:36 +02003555 * But difference is that take @p max_gap_before_type which will be
3556 * used to set the unified alignment.
aPiecek61d062b2020-11-02 11:05:09 +01003557 *
aPiecek9bdd7592021-05-20 08:13:20 +02003558 * @param[in] node to print.
aPiecek61d062b2020-11-02 11:05:09 +01003559 * @param[in] max_gap_before_type is number of indent before \<type\>.
3560 * @param[in] wr is wrapper for printing indentation before node.
aPiecek61d062b2020-11-02 11:05:09 +01003561 * @param[in] pc contains mainly functions for printing.
3562 * @param[in] tc is tree context.
3563 */
3564static void
aPiecek02665a82022-12-14 10:38:16 +01003565trb_print_entire_node(const struct trt_node *node, uint32_t max_gap_before_type, struct trt_wrapper wr,
3566 struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003567{
aPiecek61d062b2020-11-02 11:05:09 +01003568 struct trt_indent_in_node ind = trp_default_indent_in_node(node);
3569
aPiecek02665a82022-12-14 10:38:16 +01003570 if ((max_gap_before_type > 0) && (node->type.type != TRD_TYPE_EMPTY)) {
aPiecek61d062b2020-11-02 11:05:09 +01003571 /* print actual node with unified indent */
aPiecek41219f92022-10-26 11:24:40 +02003572 ind.btw_opts_type = trb_calc_btw_opts_type(node, max_gap_before_type);
aPiecek61d062b2020-11-02 11:05:09 +01003573 }
3574 /* after -> print actual node with default indent */
3575 trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print),
3576 TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out);
3577}
3578
3579/**
aPiecek874ea4d2021-04-19 12:26:36 +02003580 * @brief Check if parent of the current node is the last
3581 * of his siblings.
aPiecek61d062b2020-11-02 11:05:09 +01003582 *
aPiecek874ea4d2021-04-19 12:26:36 +02003583 * To mantain stability use this function only if the current node is
3584 * the first of the siblings.
3585 * Side-effect -> current node is set to the first sibling
3586 * if node has a parent otherwise no side-effect.
aPiecek61d062b2020-11-02 11:05:09 +01003587 *
aPiecek01598c02021-04-23 14:18:24 +02003588 * @param[in] fp contains all @ref TRP_tro callback functions.
aPiecek61d062b2020-11-02 11:05:09 +01003589 * @param[in,out] tc is tree context.
3590 * @return 1 if parent is last sibling otherwise 0.
3591 */
3592static ly_bool
aPiecek02665a82022-12-14 10:38:16 +01003593trb_node_is_last_sibling(const struct trt_fp_all *fp, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003594{
aPiecek02665a82022-12-14 10:38:16 +01003595 if (fp->read.if_parent_exists(tc)) {
3596 return !fp->read.if_sibling_exists(tc);
aPiecek03cb4872022-10-24 10:31:51 +02003597 } else {
aPiecek02665a82022-12-14 10:38:16 +01003598 return !fp->read.if_sibling_exists(tc) && tc->plugin_ctx.last_schema;
aPiecek61d062b2020-11-02 11:05:09 +01003599 }
3600}
3601
3602/**
aPiecek41219f92022-10-26 11:24:40 +02003603 * @brief For all siblings find maximal space from '--' to \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01003604 *
3605 * Side-effect -> Current node is set to the first sibling.
3606 *
3607 * @param[in] ca contains inherited data from ancestors.
3608 * @param[in] pc contains mainly functions for printing.
3609 * @param[in,out] tc is tree context.
aPiecek41219f92022-10-26 11:24:40 +02003610 * @return max space.
aPiecek61d062b2020-11-02 11:05:09 +01003611 */
aPiecek41219f92022-10-26 11:24:40 +02003612static uint32_t
3613trb_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 +01003614{
aPiecek03cb4872022-10-24 10:31:51 +02003615 struct trt_node node;
aPiecek41219f92022-10-26 11:24:40 +02003616 int32_t maxlen, len;
aPiecek61d062b2020-11-02 11:05:09 +01003617
aPiecek41219f92022-10-26 11:24:40 +02003618 maxlen = 0;
aPiecek03cb4872022-10-24 10:31:51 +02003619 for (node = pc->fp.modify.first_sibling(ca, tc);
aPiecek02665a82022-12-14 10:38:16 +01003620 !trp_node_is_empty(&node);
aPiecek61d062b2020-11-02 11:05:09 +01003621 node = pc->fp.modify.next_sibling(ca, tc)) {
aPiecek02665a82022-12-14 10:38:16 +01003622 len = trb_gap_to_type(&node);
aPiecek41219f92022-10-26 11:24:40 +02003623 maxlen = maxlen < len ? len : maxlen;
aPiecek61d062b2020-11-02 11:05:09 +01003624 }
aPiecek03cb4872022-10-24 10:31:51 +02003625 pc->fp.modify.first_sibling(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003626
aPiecek41219f92022-10-26 11:24:40 +02003627 return maxlen;
aPiecek61d062b2020-11-02 11:05:09 +01003628}
3629
3630/**
aPiecek874ea4d2021-04-19 12:26:36 +02003631 * @brief Find out if it is possible to unify
3632 * the alignment before \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01003633 *
aPiecek874ea4d2021-04-19 12:26:36 +02003634 * The goal is for all node siblings to have the same alignment
3635 * for \<type\> as if they were in a column. All siblings who cannot
3636 * adapt because they do not fit on the line at all are ignored.
aPiecek61d062b2020-11-02 11:05:09 +01003637 * Side-effect -> Current node is set to the first sibling.
3638 *
3639 * @param[in] ca contains inherited data from ancestors.
3640 * @param[in] pc contains mainly functions for printing.
3641 * @param[in,out] tc is tree context.
aPiecek874ea4d2021-04-19 12:26:36 +02003642 * @return positive number indicating the maximum number of spaces
aPiecek41219f92022-10-26 11:24:40 +02003643 * before \<type\> if the length of the flags, node name and opts is 0. To calculate
aPiecek874ea4d2021-04-19 12:26:36 +02003644 * the trt_indent_in_node.btw_opts_type indent size for a particular
aPiecek01598c02021-04-23 14:18:24 +02003645 * node, use the ::trb_calc_btw_opts_type().
aPiecek61d062b2020-11-02 11:05:09 +01003646*/
3647static uint32_t
3648trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3649{
aPiecek41219f92022-10-26 11:24:40 +02003650 return trb_max_gap_to_type(ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003651}
3652
3653/**
aPiecekb8d5a0a2021-05-20 08:20:24 +02003654 * @brief Check if there is no case statement
3655 * under the choice statement.
3656 *
3657 * It can return true only if the Parsed schema tree
3658 * is used for browsing.
3659 *
3660 * @param[in] tc is tree context.
3661 * @return 1 if implicit case statement is present otherwise 0.
3662 */
3663static ly_bool
3664trb_need_implicit_node_case(struct trt_tree_ctx *tc)
3665{
3666 return !tc->lysc_tree && tc->pn->parent &&
3667 (tc->pn->parent->nodetype & LYS_CHOICE) &&
3668 (tc->pn->nodetype & (LYS_ANYDATA | LYS_CHOICE | LYS_CONTAINER |
3669 LYS_LEAF | LYS_LEAFLIST));
3670}
3671
aPiecek02665a82022-12-14 10:38:16 +01003672static void trb_print_subtree_nodes(struct trt_node *node, uint32_t max_gap_before_type,
aPiecekb8d5a0a2021-05-20 08:20:24 +02003673 struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc);
3674
3675/**
3676 * @brief Print implicit case node and his subtree.
3677 *
3678 * @param[in] node is child of implicit case.
3679 * @param[in] wr is wrapper for printing identation before node.
aPiecekb8d5a0a2021-05-20 08:20:24 +02003680 * @param[in] pc contains mainly functions for printing.
3681 * @param[in] tc is tree context. Its settings should be the same as
3682 * before the function call.
aPiecek49be5b42022-10-19 10:57:56 +02003683 * @return new indentation wrapper for @p node.
aPiecekb8d5a0a2021-05-20 08:20:24 +02003684 */
aPiecek49be5b42022-10-19 10:57:56 +02003685static struct trt_wrapper
aPiecek02665a82022-12-14 10:38:16 +01003686trb_print_implicit_node(const struct trt_node *node, struct trt_wrapper wr, struct trt_printer_ctx *pc,
aPiecek49be5b42022-10-19 10:57:56 +02003687 struct trt_tree_ctx *tc)
aPiecekb8d5a0a2021-05-20 08:20:24 +02003688{
3689 struct trt_node case_node;
3690 struct trt_wrapper wr_case_child;
3691
aPiecek02665a82022-12-14 10:38:16 +01003692 tro_create_implicit_case_node(node, &case_node);
aPiecekb8d5a0a2021-05-20 08:20:24 +02003693 ly_print_(pc->out, "\n");
aPiecek02665a82022-12-14 10:38:16 +01003694 trb_print_entire_node(&case_node, 0, wr, pc, tc);
aPiecek49be5b42022-10-19 10:57:56 +02003695 ly_print_(pc->out, "\n");
aPiecekb8d5a0a2021-05-20 08:20:24 +02003696 wr_case_child = pc->fp.read.if_sibling_exists(tc) ?
3697 trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr);
aPiecek49be5b42022-10-19 10:57:56 +02003698 return wr_case_child;
aPiecekb8d5a0a2021-05-20 08:20:24 +02003699}
3700
3701/**
aPiecek153b00f2021-04-20 13:52:57 +02003702 * @brief Calculate the wrapper about how deep in the tree the node is.
ekinzie0ab8b302022-10-10 03:03:57 -04003703 * @param[in] wr_in A wrapper to use as a starting point
aPiecek153b00f2021-04-20 13:52:57 +02003704 * @param[in] node from which to count.
3705 * @return wrapper for @p node.
3706 */
3707static struct trt_wrapper
ekinzie0ab8b302022-10-10 03:03:57 -04003708trb_count_depth(const struct trt_wrapper *wr_in, const struct lysc_node *node)
aPiecek153b00f2021-04-20 13:52:57 +02003709{
ekinzie0ab8b302022-10-10 03:03:57 -04003710 struct trt_wrapper wr = wr_in ? *wr_in : TRP_INIT_WRAPPER_TOP;
aPiecek153b00f2021-04-20 13:52:57 +02003711 const struct lysc_node *parent;
3712
3713 if (!node) {
3714 return wr;
3715 }
3716
3717 for (parent = node->parent; parent; parent = parent->parent) {
3718 wr = trp_wrapper_set_shift(wr);
3719 }
3720
3721 return wr;
3722}
3723
3724/**
3725 * @brief Print all parent nodes of @p node and the @p node itself.
3726 *
3727 * Side-effect -> trt_tree_ctx.cn will be set to @p node.
3728 *
3729 * @param[in] node on which the function is focused.
aPiecek7ed8d032022-10-10 12:32:27 +02003730 * @param[in] wr_in for printing identation before node.
aPiecek01598c02021-04-23 14:18:24 +02003731 * @param[in] pc is @ref TRP_trp settings.
aPiecek153b00f2021-04-20 13:52:57 +02003732 * @param[in,out] tc is context of tree printer.
aPiecek153b00f2021-04-20 13:52:57 +02003733 */
3734static void
ekinzie0ab8b302022-10-10 03:03:57 -04003735trb_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 +02003736{
aPiecek41219f92022-10-26 11:24:40 +02003737 uint32_t max_gap_before_type;
aPiecek153b00f2021-04-20 13:52:57 +02003738 struct trt_wrapper wr;
aPiecek9bdd7592021-05-20 08:13:20 +02003739 struct trt_node print_node;
aPiecek153b00f2021-04-20 13:52:57 +02003740
3741 assert(pc && tc && tc->section == TRD_SECT_MODULE);
3742
3743 /* stop recursion */
3744 if (!node) {
3745 return;
3746 }
ekinzie0ab8b302022-10-10 03:03:57 -04003747 trb_print_parents(node->parent, wr_in, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003748
3749 /* setup for printing */
3750 tc->cn = node;
ekinzie0ab8b302022-10-10 03:03:57 -04003751 wr = trb_count_depth(wr_in, node);
aPiecek153b00f2021-04-20 13:52:57 +02003752
3753 /* print node */
3754 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02003755 print_node = pc->fp.read.node(TRP_EMPTY_PARENT_CACHE, tc);
aPiecek41219f92022-10-26 11:24:40 +02003756 max_gap_before_type = trb_max_gap_to_type(TRP_EMPTY_PARENT_CACHE, pc, tc);
aPiecek02665a82022-12-14 10:38:16 +01003757 trb_print_entire_node(&print_node, max_gap_before_type, wr, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003758}
3759
3760/**
aPiecekdc8fd572021-04-19 10:47:23 +02003761 * @brief Set current node on its child.
3762 * @param[in,out] tc contains current node.
3763 */
3764static void
3765trb_tree_ctx_set_child(struct trt_tree_ctx *tc)
3766{
aPiecek03cb4872022-10-24 10:31:51 +02003767 const void *node = tro_tree_ctx_get_child(tc);
aPiecek3f247652021-04-19 13:40:25 +02003768
3769 if (tc->lysc_tree) {
3770 tc->cn = node;
3771 } else {
3772 tc->pn = node;
3773 }
aPiecekdc8fd572021-04-19 10:47:23 +02003774}
3775
3776/**
aPiecek03cb4872022-10-24 10:31:51 +02003777 * @brief Move extension iterator to the next position.
3778 *
3779 * @param[in] lysc_tree flag if exts is from compiled tree.
3780 * @param[in] exts is current array of extensions.
3781 * @param[in,out] i is state of iterator.
3782 * @return Pointer to the first/next extension.
3783 */
3784static void *
3785trb_ext_iter_next(ly_bool lysc_tree, void *exts, uint64_t *i)
3786{
3787 void *ext = NULL;
3788 struct lysc_ext_instance *ce;
3789 struct lysp_ext_instance *pe;
3790
3791 if (!exts) {
3792 return NULL;
3793 }
3794
3795 if (lysc_tree) {
3796 ce = exts;
3797 while (*i < LY_ARRAY_COUNT(ce)) {
3798 if (trp_ext_parent_is_valid(1, &ce[*i])) {
3799 ext = &ce[*i];
3800 break;
3801 }
3802 ++(*i);
3803 }
3804 } else {
3805 pe = exts;
3806 while (*i < LY_ARRAY_COUNT(pe)) {
3807 if (trp_ext_parent_is_valid(0, &pe[*i])) {
3808 ext = &pe[*i];
3809 break;
3810 }
3811 ++(*i);
3812 }
3813 }
3814 ++(*i);
3815
3816 return ext;
3817}
3818
3819/**
3820 * @brief Iterate over extensions in module.
3821 *
3822 * @param[in] tc contains current node.
3823 * @param[in,out] i is state of iterator.
3824 * @return First/next extension or NULL.
3825 */
3826static void *
3827trb_mod_ext_iter(const struct trt_tree_ctx *tc, uint64_t *i)
3828{
3829 if (tc->lysc_tree) {
3830 return trb_ext_iter_next(1, tc->cmod->exts, i);
3831 } else {
3832 return trb_ext_iter_next(0, tc->pmod->exts, i);
3833 }
3834}
3835
3836/**
3837 * @brief Iterate over extensions in node.
3838 *
3839 * @param[in] tc contains current node.
3840 * @param[in,out] i is state of iterator.
3841 * @return First/next extension or NULL.
3842 */
3843static void *
3844trb_ext_iter(const struct trt_tree_ctx *tc, uint64_t *i)
3845{
3846 if (tc->lysc_tree) {
3847 return trb_ext_iter_next(1, tc->cn->exts, i);
3848 } else {
3849 return trb_ext_iter_next(0, tc->pn->exts, i);
3850 }
3851}
3852
3853/**
3854 * @brief Initialize plugin context.
3855 *
3856 * @param[in] compiled if @p ext is lysc structure.
3857 * @param[in] ext current processed extension.
3858 * @param[out] plug_ctx is plugin context which will be initialized.
3859 * @return LY_ERR value.
3860 */
3861static LY_ERR
3862tro_ext_printer_tree(ly_bool compiled, void *ext, const struct lyspr_tree_ctx *plug_ctx)
3863{
3864 struct lysc_ext_instance *ext_comp;
3865 struct lysp_ext_instance *ext_pars;
3866 const char *flags = NULL, *add_opts = NULL;
3867
3868 if (compiled) {
3869 ext_comp = ext;
3870 return ext_comp->def->plugin->printer_ctree(ext, plug_ctx, &flags, &add_opts);
3871 } else {
3872 ext_pars = ext;
3873 return ext_pars->record->plugin.printer_ptree(ext, plug_ctx, &flags, &add_opts);
3874 }
3875}
3876
3877/**
3878 * @brief Reset tree context by plugin context.
3879 *
3880 * @param[in] plug_ctx is plugin context.
3881 * @param[in] i which index in schemas should be used.
3882 * @param[in] pc are printing functions.
3883 * @param[out] tc tree context which will be updated.
3884 */
3885static void
3886trm_reset_tree_ctx_by_plugin(struct lyspr_tree_ctx *plug_ctx, LY_ARRAY_COUNT_TYPE i, struct trt_printer_ctx *pc,
3887 struct trt_tree_ctx *tc)
3888{
3889 tc->plugin_ctx.ctx = plug_ctx;
3890 tc->pmod = NULL;
3891 tc->cmod = NULL;
3892 if (plug_ctx->schemas[i].compiled) {
3893 tc->lysc_tree = 1;
3894 tc->cn = plug_ctx->schemas[i].ctree;
3895 tc->plugin_ctx.schema = &plug_ctx->schemas[i];
3896 pc->fp.modify = TRP_TRT_FP_MODIFY_COMPILED;
3897 pc->fp.read = TRP_TRT_FP_READ_COMPILED;
3898 } else {
3899 tc->lysc_tree = 0;
3900 tc->pn = plug_ctx->schemas[i].ptree;
3901 tc->tpn = tc->pn;
3902 tc->plugin_ctx.schema = &plug_ctx->schemas[i];
3903 pc->fp.modify = TRP_TRT_FP_MODIFY_PARSED;
3904 pc->fp.read = TRP_TRT_FP_READ_PARSED;
3905 }
3906}
3907
3908/**
3909 * @brief Print schemas from plugin context.
3910 *
3911 * @param[in] plug_ctx is plugin context.
3912 * @param[in] last_nodes if this schemas will be the last.
3913 * @param[in] max_gap_before_type is gap before type.
3914 * @param[in] wr is indentation wrapper.
3915 * @param[in] ca containing information from parent.
3916 * @param[in] pc functions for tree traversing.
3917 * @param[in] tc current tree context.
3918 */
3919static void
3920trb_ext_print_schemas(struct lyspr_tree_ctx *plug_ctx, ly_bool last_nodes, uint32_t max_gap_before_type,
3921 struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3922{
3923 LY_ARRAY_COUNT_TYPE i;
3924 struct trt_printer_ctx pc_dupl;
3925 struct trt_tree_ctx tc_dupl;
aPiecek02665a82022-12-14 10:38:16 +01003926 struct trt_node node;
aPiecek03cb4872022-10-24 10:31:51 +02003927
3928 tc_dupl = *tc;
3929 pc_dupl = *pc;
3930
3931 LY_ARRAY_FOR(plug_ctx->schemas, i) {
3932 trm_reset_tree_ctx_by_plugin(plug_ctx, i, pc, tc);
3933 tc->plugin_ctx.last_schema = last_nodes && ((i + 1) == LY_ARRAY_COUNT(plug_ctx->schemas));
aPiecek02665a82022-12-14 10:38:16 +01003934 node = TRP_EMPTY_NODE;
3935 trb_print_subtree_nodes(&node, max_gap_before_type, wr, ca, pc, tc);
aPiecek03cb4872022-10-24 10:31:51 +02003936 *tc = tc_dupl;
3937 }
3938
3939 *pc = pc_dupl;
3940}
3941
3942/**
3943 * @brief Count unified indentation across schemas from extension instance.
3944 *
3945 * @param[in] plug_ctx is plugin context.
3946 * @param[in] ca containing parent settings.
3947 * @param[out] max_gap_before_type is result of unified indent.
3948 * @param[in] pc functions for tree traversing.
3949 * @param[in] tc is tree context.
3950 */
3951static void
3952trb_ext_try_unified_indent(struct lyspr_tree_ctx *plug_ctx, struct trt_parent_cache ca, uint32_t *max_gap_before_type,
3953 struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3954{
3955 LY_ARRAY_COUNT_TYPE i;
3956 struct trt_printer_ctx pc_dupl;
3957 struct trt_tree_ctx tc_dupl;
3958 uint32_t max;
3959
3960 tc_dupl = *tc;
3961 pc_dupl = *pc;
3962
3963 LY_ARRAY_FOR(plug_ctx->schemas, i) {
3964 trm_reset_tree_ctx_by_plugin(plug_ctx, i, pc, tc);
3965 max = trb_try_unified_indent(ca, pc, tc);
3966 *max_gap_before_type = max > *max_gap_before_type ? max : *max_gap_before_type;
3967 *tc = tc_dupl;
3968 }
3969
3970 *pc = pc_dupl;
3971}
3972
3973/**
3974 * @brief For every extension instance print all schemas.
3975 *
3976 * @param[in] wr indentation wrapper for node.
3977 * @param[in] ca parent settings.
3978 * @param[in] pc function used for tree traversing.
3979 * @param[in] tc tree context.
3980 */
3981static void
3982trb_ext_print_instances(struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc,
3983 struct trt_tree_ctx *tc)
3984{
3985 LY_ERR rc;
3986 LY_ARRAY_COUNT_TYPE i;
3987 uint64_t last_instance = UINT64_MAX;
3988 void *ext;
3989 ly_bool child_exists;
3990 uint32_t max, max_gap_before_type = 0;
3991
3992 ca = tro_parent_cache_for_child(ca, tc);
3993 /* if node is last sibling, then do not add '|' to wrapper */
aPiecek02665a82022-12-14 10:38:16 +01003994 wr = trb_node_is_last_sibling(&pc->fp, tc) ?
aPiecek03cb4872022-10-24 10:31:51 +02003995 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
3996
3997 if (tc->lysc_tree) {
3998 child_exists = tro_next_child(tc->cn, tc) ? 1 : 0;
3999 } else {
4000 child_exists = tro_next_child(tc->pn, tc) ? 1 : 0;
4001 }
4002
4003 i = 0;
4004 while ((ext = trb_ext_iter(tc, &i))) {
4005 struct lyspr_tree_ctx plug_ctx = {0};
4006
4007 rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx);
4008 LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end);
4009 trb_ext_try_unified_indent(&plug_ctx, ca, &max_gap_before_type, pc, tc);
4010 if (plug_ctx.schemas) {
4011 last_instance = i;
4012 }
4013 trp_ext_free_plugin_ctx(&plug_ctx);
4014 }
4015
4016 if (child_exists) {
4017 pc->fp.modify.next_child(ca, tc);
4018 max = trb_try_unified_indent(ca, pc, tc);
4019 max_gap_before_type = max > max_gap_before_type ? max : max_gap_before_type;
4020 pc->fp.modify.parent(tc);
4021 }
4022
4023 i = 0;
4024 while ((ext = trb_ext_iter(tc, &i))) {
4025 struct lyspr_tree_ctx plug_ctx = {0};
4026
4027 rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx);
4028 LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end);
4029 if (!child_exists && (last_instance == i)) {
4030 trb_ext_print_schemas(&plug_ctx, 1, max_gap_before_type, wr, ca, pc, tc);
4031 } else {
4032 trb_ext_print_schemas(&plug_ctx, 0, max_gap_before_type, wr, ca, pc, tc);
4033 }
4034 trp_ext_free_plugin_ctx(&plug_ctx);
4035 }
4036
4037end:
4038 return;
4039}
4040
4041/**
aPiecek61d062b2020-11-02 11:05:09 +01004042 * @brief Print subtree of nodes.
4043 *
4044 * The current node is expected to be the root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02004045 * Before root node is no linebreak printing. This must be addressed by
4046 * the caller. Root node will also be printed. Behind last printed node
4047 * is no linebreak.
aPiecek61d062b2020-11-02 11:05:09 +01004048 *
aPiecek02665a82022-12-14 10:38:16 +01004049 * @param[in,out] node current processed node used as iterator.
aPiecek874ea4d2021-04-19 12:26:36 +02004050 * @param[in] max_gap_before_type is result from
aPiecek01598c02021-04-23 14:18:24 +02004051 * ::trb_try_unified_indent() function for root node.
4052 * Set parameter to 0 if distance does not matter.
aPiecek874ea4d2021-04-19 12:26:36 +02004053 * @param[in] wr is wrapper saying how deep in the whole tree
4054 * is the root of the subtree.
4055 * @param[in] ca is parent_cache from root's parent.
4056 * If root is top-level node, insert ::TRP_EMPTY_PARENT_CACHE.
aPiecek01598c02021-04-23 14:18:24 +02004057 * @param[in] pc is @ref TRP_trp settings.
aPiecek874ea4d2021-04-19 12:26:36 +02004058 * @param[in,out] tc is context of tree printer.
aPiecek61d062b2020-11-02 11:05:09 +01004059 */
4060static void
aPiecek02665a82022-12-14 10:38:16 +01004061trb_print_subtree_nodes(struct trt_node *node, uint32_t max_gap_before_type, struct trt_wrapper wr,
aPiecek9bdd7592021-05-20 08:13:20 +02004062 struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004063{
aPiecek03cb4872022-10-24 10:31:51 +02004064 if (!trp_node_is_empty(node)) {
4065 /* Print root node. */
4066 trb_print_entire_node(node, max_gap_before_type, wr, pc, tc);
4067 if (trp_ext_is_present_in_node(tc)) {
4068 trb_ext_print_instances(wr, ca, pc, tc);
4069 }
4070 /* if node is last sibling, then do not add '|' to wrapper */
aPiecek02665a82022-12-14 10:38:16 +01004071 wr = trb_node_is_last_sibling(&pc->fp, tc) ?
aPiecek03cb4872022-10-24 10:31:51 +02004072 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
4073 /* go to the child */
4074 ca = tro_parent_cache_for_child(ca, tc);
aPiecek02665a82022-12-14 10:38:16 +01004075 *node = pc->fp.modify.next_child(ca, tc);
aPiecek03cb4872022-10-24 10:31:51 +02004076 if (trp_node_is_empty(node)) {
4077 return;
4078 }
4079 /* TODO comment browse through instances + filtered. try unified indentation for children */
4080 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
4081 } else {
4082 /* Root node is ignored, continue with child. */
aPiecek02665a82022-12-14 10:38:16 +01004083 *node = pc->fp.modify.first_sibling(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01004084 }
aPiecek67521c22022-10-19 09:15:02 +02004085
aPiecek67521c22022-10-19 09:15:02 +02004086 do {
aPiecek03cb4872022-10-24 10:31:51 +02004087 if (!tc->plugin_ctx.filtered && !trb_need_implicit_node_case(tc)) {
aPiecek67521c22022-10-19 09:15:02 +02004088 /* normal behavior */
4089 ly_print_(pc->out, "\n");
aPiecek49be5b42022-10-19 10:57:56 +02004090 trb_print_subtree_nodes(node, max_gap_before_type, wr, ca, pc, tc);
aPiecek03cb4872022-10-24 10:31:51 +02004091 } else if (!tc->plugin_ctx.filtered) {
aPiecek49be5b42022-10-19 10:57:56 +02004092 struct trt_wrapper wr_case_child;
4093
4094 wr_case_child = trb_print_implicit_node(node, wr, pc, tc);
4095 trb_print_subtree_nodes(node, max_gap_before_type, wr_case_child, ca, pc, tc);
aPiecek67521c22022-10-19 09:15:02 +02004096 }
4097 /* go to the actual node's sibling */
aPiecek02665a82022-12-14 10:38:16 +01004098 *node = pc->fp.modify.next_sibling(ca, tc);
aPiecek49be5b42022-10-19 10:57:56 +02004099 } while (!trp_node_is_empty(node));
aPiecek67521c22022-10-19 09:15:02 +02004100
4101 /* get back from child node to root node */
4102 pc->fp.modify.parent(tc);
aPiecek61d062b2020-11-02 11:05:09 +01004103}
4104
4105/**
aPiecek61d062b2020-11-02 11:05:09 +01004106 * @brief Print all parents and their children.
4107 *
aPiecek874ea4d2021-04-19 12:26:36 +02004108 * This function is suitable for printing top-level nodes that
aPiecek01598c02021-04-23 14:18:24 +02004109 * do not have ancestors. Function call ::trb_print_subtree_nodes()
aPiecek153b00f2021-04-20 13:52:57 +02004110 * for all top-level siblings. Use this function after 'module' keyword
4111 * or 'augment' and so. The nodes may not be exactly top-level in the
4112 * tree, but the function considers them that way.
aPiecek61d062b2020-11-02 11:05:09 +01004113 *
aPiecek153b00f2021-04-20 13:52:57 +02004114 * @param[in] wr is wrapper saying how deeply the top-level nodes are
4115 * immersed in the tree.
aPiecek61d062b2020-11-02 11:05:09 +01004116 * @param[pc] pc contains mainly functions for printing.
4117 * @param[in,out] tc is tree context.
4118 */
4119static void
aPiecek153b00f2021-04-20 13:52:57 +02004120trb_print_family_tree(struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004121{
aPiecek61d062b2020-11-02 11:05:09 +01004122 struct trt_parent_cache ca;
aPiecek9bdd7592021-05-20 08:13:20 +02004123 struct trt_node node;
aPiecek61d062b2020-11-02 11:05:09 +01004124 uint32_t max_gap_before_type;
4125
aPiecek03cb4872022-10-24 10:31:51 +02004126 if (!tro_tree_ctx_get_node(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004127 return;
4128 }
4129
aPiecek61d062b2020-11-02 11:05:09 +01004130 ca = TRP_EMPTY_PARENT_CACHE;
aPiecek61d062b2020-11-02 11:05:09 +01004131 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
4132
aPiecek3f247652021-04-19 13:40:25 +02004133 if (!tc->lysc_tree) {
aPiecek03cb4872022-10-24 10:31:51 +02004134 if ((tc->section == TRD_SECT_GROUPING) && (tc->tpn == tc->pn->parent)) {
aPiecek3f247652021-04-19 13:40:25 +02004135 ca.lys_config = 0x0;
4136 }
aPiecekdc8fd572021-04-19 10:47:23 +02004137 }
4138
aPiecek03cb4872022-10-24 10:31:51 +02004139 for (node = pc->fp.modify.first_sibling(ca, tc);
aPiecek02665a82022-12-14 10:38:16 +01004140 !trp_node_is_empty(&node);
aPiecek03cb4872022-10-24 10:31:51 +02004141 node = pc->fp.modify.next_sibling(ca, tc)) {
aPiecek61d062b2020-11-02 11:05:09 +01004142 ly_print_(pc->out, "\n");
aPiecek02665a82022-12-14 10:38:16 +01004143 trb_print_subtree_nodes(&node, max_gap_before_type, wr, ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01004144 }
4145}
4146
aPiecek874ea4d2021-04-19 12:26:36 +02004147/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004148 * Definition of trm main functions
aPiecek874ea4d2021-04-19 12:26:36 +02004149 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004150
4151/**
aPiecekdc8fd572021-04-19 10:47:23 +02004152 * @brief Settings if lysp_node are used for browsing through the tree.
aPiecek61d062b2020-11-02 11:05:09 +01004153 *
aPiecekdc8fd572021-04-19 10:47:23 +02004154 * @param[in] module YANG schema tree structure representing
4155 * YANG module.
aPiecek61d062b2020-11-02 11:05:09 +01004156 * @param[in] out is output handler.
aPiecekdc8fd572021-04-19 10:47:23 +02004157 * @param[in] max_line_length is the maximum line length limit
4158 * that should not be exceeded.
4159 * @param[in,out] pc will be adapted to lysp_tree.
4160 * @param[in,out] tc will be adapted to lysp_tree.
aPiecek61d062b2020-11-02 11:05:09 +01004161 */
4162static void
aPiecek03cb4872022-10-24 10:31:51 +02004163trm_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length,
4164 struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01004165{
aPiecekdc8fd572021-04-19 10:47:23 +02004166 *tc = (struct trt_tree_ctx) {
aPiecek3f247652021-04-19 13:40:25 +02004167 .lysc_tree = 0,
aPiecekdc8fd572021-04-19 10:47:23 +02004168 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02004169 .pmod = module->parsed,
4170 .cmod = NULL,
4171 .pn = module->parsed ? module->parsed->data : NULL,
4172 .tpn = module->parsed ? module->parsed->data : NULL,
aPiecek7ed8d032022-10-10 12:32:27 +02004173 .cn = NULL,
aPiecek03cb4872022-10-24 10:31:51 +02004174 .last_error = 0,
4175 .plugin_ctx.ctx = NULL,
4176 .plugin_ctx.schema = NULL,
4177 .plugin_ctx.filtered = 0,
4178 .plugin_ctx.node_overr = TRP_TREE_CTX_EMPTY_NODE_OVERR,
4179 .plugin_ctx.last_schema = 1,
4180 .plugin_ctx.last_error = 0
aPiecekdc8fd572021-04-19 10:47:23 +02004181 };
aPiecek61d062b2020-11-02 11:05:09 +01004182
aPiecekdc8fd572021-04-19 10:47:23 +02004183 pc->out = out;
4184
aPiecek03cb4872022-10-24 10:31:51 +02004185 pc->fp.modify = TRP_TRT_FP_MODIFY_PARSED;
4186 pc->fp.read = TRP_TRT_FP_READ_PARSED;
aPiecek61d062b2020-11-02 11:05:09 +01004187
aPiecekdc8fd572021-04-19 10:47:23 +02004188 pc->fp.print = (struct trt_fp_print) {
aPiecek3f247652021-04-19 13:40:25 +02004189 .print_features_names = tro_print_features_names,
4190 .print_keys = tro_print_keys
aPiecek61d062b2020-11-02 11:05:09 +01004191 };
4192
aPiecekdc8fd572021-04-19 10:47:23 +02004193 pc->max_line_length = max_line_length;
aPiecek61d062b2020-11-02 11:05:09 +01004194}
4195
4196/**
aPiecek3f247652021-04-19 13:40:25 +02004197 * @brief Settings if lysc_node are used for browsing through the tree.
4198 *
4199 * Pointers to current nodes will be set to module data.
4200 *
4201 * @param[in] module YANG schema tree structure representing
4202 * YANG module.
4203 * @param[in] out is output handler.
4204 * @param[in] max_line_length is the maximum line length limit
4205 * that should not be exceeded.
4206 * @param[in,out] pc will be adapted to lysc_tree.
4207 * @param[in,out] tc will be adapted to lysc_tree.
4208 */
4209static void
aPiecek03cb4872022-10-24 10:31:51 +02004210trm_lysc_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length,
4211 struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek3f247652021-04-19 13:40:25 +02004212{
4213 *tc = (struct trt_tree_ctx) {
4214 .lysc_tree = 1,
4215 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02004216 .pmod = module->parsed,
4217 .cmod = module->compiled,
aPiecek3f247652021-04-19 13:40:25 +02004218 .tpn = NULL,
4219 .pn = NULL,
aPiecek7ed8d032022-10-10 12:32:27 +02004220 .cn = module->compiled->data,
aPiecek03cb4872022-10-24 10:31:51 +02004221 .last_error = 0,
4222 .plugin_ctx.ctx = NULL,
4223 .plugin_ctx.schema = NULL,
4224 .plugin_ctx.filtered = 0,
4225 .plugin_ctx.node_overr = TRP_TREE_CTX_EMPTY_NODE_OVERR,
4226 .plugin_ctx.last_schema = 1,
4227 .plugin_ctx.last_error = 0
aPiecek3f247652021-04-19 13:40:25 +02004228 };
4229
4230 pc->out = out;
4231
aPiecek03cb4872022-10-24 10:31:51 +02004232 pc->fp.modify = TRP_TRT_FP_MODIFY_COMPILED;
4233 pc->fp.read = TRP_TRT_FP_READ_COMPILED;
aPiecek3f247652021-04-19 13:40:25 +02004234
4235 pc->fp.print = (struct trt_fp_print) {
4236 .print_features_names = tro_print_features_names,
4237 .print_keys = tro_print_keys
4238 };
4239
4240 pc->max_line_length = max_line_length;
4241}
4242
4243/**
4244 * @brief Reset settings to browsing through the lysc tree.
aPiecek01598c02021-04-23 14:18:24 +02004245 * @param[in,out] pc resets to @ref TRP_troc functions.
aPiecek3f247652021-04-19 13:40:25 +02004246 * @param[in,out] tc resets to lysc browsing.
4247 */
4248static void
4249trm_reset_to_lysc_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4250{
aPiecek40f22402022-10-14 10:48:08 +02004251 LY_ERR erc;
4252
4253 erc = tc->last_error;
aPiecek03cb4872022-10-24 10:31:51 +02004254 trp_ext_free_node_override(&tc->plugin_ctx.node_overr, &tc->plugin_ctx.filtered);
4255 trm_lysc_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc);
aPiecek40f22402022-10-14 10:48:08 +02004256 tc->last_error = erc;
aPiecek3f247652021-04-19 13:40:25 +02004257}
4258
4259/**
4260 * @brief Reset settings to browsing through the lysp tree.
aPiecek01598c02021-04-23 14:18:24 +02004261 * @param[in,out] pc resets to @ref TRP_trop functions.
aPiecek3f247652021-04-19 13:40:25 +02004262 * @param[in,out] tc resets to lysp browsing.
4263 */
4264static void
4265trm_reset_to_lysp_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4266{
aPiecek40f22402022-10-14 10:48:08 +02004267 LY_ERR erc;
4268
4269 erc = tc->last_error;
aPiecek03cb4872022-10-24 10:31:51 +02004270 trp_ext_free_node_override(&tc->plugin_ctx.node_overr, &tc->plugin_ctx.filtered);
4271 trm_lysp_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc);
aPiecek40f22402022-10-14 10:48:08 +02004272 tc->last_error = erc;
aPiecek3f247652021-04-19 13:40:25 +02004273}
4274
4275/**
4276 * @brief If augment's target node is located on the current module.
4277 * @param[in] pn is examined augment.
4278 * @param[in] pmod is current module.
4279 * @return 1 if nodeid refers to the local node, otherwise 0.
4280 */
4281static ly_bool
4282trm_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod)
4283{
4284 const char *id, *prefix, *name;
4285 size_t prefix_len, name_len;
4286 const struct lys_module *mod;
4287 ly_bool ret = 0;
4288
4289 if (pn == NULL) {
4290 return ret;
4291 }
4292
4293 id = pn->nodeid;
4294 if (!id) {
4295 return ret;
4296 }
4297 /* only absolute-schema-nodeid is taken into account */
4298 assert(id[0] == '/');
4299 ++id;
4300
4301 ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len);
4302 if (prefix) {
Radek Krejci8df109d2021-04-23 12:19:08 +02004303 mod = ly_resolve_prefix(pmod->mod->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, pmod);
Michal Vasko3003c9a2022-03-29 12:10:00 +02004304 ret = mod ? (mod->parsed == pmod) : 0;
aPiecek3f247652021-04-19 13:40:25 +02004305 } else {
4306 ret = 1;
4307 }
4308
4309 return ret;
4310}
4311
4312/**
aPiecek96baa7f2021-04-23 12:32:00 +02004313 * @brief Printing section module, rpcs, notifications or yang-data.
aPiecek61d062b2020-11-02 11:05:09 +01004314 *
aPiecekdc8fd572021-04-19 10:47:23 +02004315 * First node must be the first child of 'module',
aPiecek96baa7f2021-04-23 12:32:00 +02004316 * 'rpcs', 'notifications' or 'yang-data'.
aPiecek61d062b2020-11-02 11:05:09 +01004317 *
aPiecekdc8fd572021-04-19 10:47:23 +02004318 * @param[in] ks is section representation.
4319 * @param[in] pc contains mainly functions for printing.
4320 * @param[in,out] tc is the tree context.
aPiecek61d062b2020-11-02 11:05:09 +01004321 */
4322static void
aPiecekdc8fd572021-04-19 10:47:23 +02004323trm_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 +01004324{
aPiecek03cb4872022-10-24 10:31:51 +02004325 assert(ks.section_name);
aPiecekdc8fd572021-04-19 10:47:23 +02004326
aPiecek03cb4872022-10-24 10:31:51 +02004327 trp_print_keyword_stmt(ks, pc->max_line_length, pc->out);
4328 if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) || !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) {
aPiecek153b00f2021-04-20 13:52:57 +02004329 trb_print_family_tree(TRP_INIT_WRAPPER_TOP, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004330 } else {
aPiecek153b00f2021-04-20 13:52:57 +02004331 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004332 }
4333}
4334
4335/**
aPiecek96baa7f2021-04-23 12:32:00 +02004336 * @brief Printing section augment or grouping.
aPiecekdc8fd572021-04-19 10:47:23 +02004337 *
aPiecek96baa7f2021-04-23 12:32:00 +02004338 * First node is 'augment' or 'grouping' itself.
aPiecekdc8fd572021-04-19 10:47:23 +02004339 *
4340 * @param[in] ks is section representation.
4341 * @param[in] pc contains mainly functions for printing.
4342 * @param[in,out] tc is the tree context.
4343 */
4344static void
4345trm_print_section_as_subtree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4346{
aPiecek03cb4872022-10-24 10:31:51 +02004347 assert(ks.section_name);
4348 trp_print_keyword_stmt(ks, pc->max_line_length, pc->out);
aPiecekdc8fd572021-04-19 10:47:23 +02004349 trb_tree_ctx_set_child(tc);
aPiecek153b00f2021-04-20 13:52:57 +02004350 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004351}
4352
4353/**
4354 * @brief Print 'module' keyword, its name and all nodes.
4355 * @param[in] pc contains mainly functions for printing.
4356 * @param[in,out] tc is the tree context.
4357 */
4358static void
4359trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4360{
4361 trm_print_section_as_family_tree(pc->fp.read.module_name(tc), pc, tc);
4362}
4363
4364/**
4365 * @brief For all augment sections: print 'augment' keyword,
4366 * its target node and all nodes.
4367 * @param[in] pc contains mainly functions for printing.
4368 * @param[in,out] tc is the tree context.
4369 */
4370static void
4371trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4372{
4373 ly_bool once;
aPiecek3f247652021-04-19 13:40:25 +02004374 ly_bool origin_was_lysc_tree = 0;
aPiecek03cb4872022-10-24 10:31:51 +02004375 struct trt_keyword_stmt ks;
aPiecekdc8fd572021-04-19 10:47:23 +02004376
aPiecek3f247652021-04-19 13:40:25 +02004377 if (tc->lysc_tree) {
4378 origin_was_lysc_tree = 1;
4379 trm_reset_to_lysp_tree_ctx(pc, tc);
4380 }
4381
aPiecekdc8fd572021-04-19 10:47:23 +02004382 once = 1;
aPiecek03cb4872022-10-24 10:31:51 +02004383 for (ks = trop_modi_next_augment(tc); ks.section_name; ks = trop_modi_next_augment(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004384
aPiecek3f247652021-04-19 13:40:25 +02004385 if (origin_was_lysc_tree) {
4386 /* if lysc tree is used, then only augments targeting
4387 * another module are printed
4388 */
aPiecek9f792e52021-04-21 08:33:56 +02004389 if (trm_nodeid_target_is_local((const struct lysp_node_augment *)tc->tpn, tc->pmod)) {
aPiecek3f247652021-04-19 13:40:25 +02004390 continue;
4391 }
4392 }
4393
aPiecekdc8fd572021-04-19 10:47:23 +02004394 if (once) {
4395 ly_print_(pc->out, "\n");
4396 ly_print_(pc->out, "\n");
4397 once = 0;
4398 } else {
4399 ly_print_(pc->out, "\n");
4400 }
4401
4402 trm_print_section_as_subtree(ks, pc, tc);
4403 }
aPiecek3f247652021-04-19 13:40:25 +02004404
4405 if (origin_was_lysc_tree) {
4406 trm_reset_to_lysc_tree_ctx(pc, tc);
4407 }
aPiecekdc8fd572021-04-19 10:47:23 +02004408}
4409
4410/**
4411 * @brief For rpcs section: print 'rpcs' keyword and all its nodes.
4412 * @param[in] pc contains mainly functions for printing.
4413 * @param[in,out] tc is the tree context.
4414 */
4415static void
4416trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4417{
4418 struct trt_keyword_stmt rpc;
4419
aPiecek01598c02021-04-23 14:18:24 +02004420 rpc = tro_modi_get_rpcs(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004421
aPiecek03cb4872022-10-24 10:31:51 +02004422 if (rpc.section_name) {
aPiecekdc8fd572021-04-19 10:47:23 +02004423 ly_print_(pc->out, "\n");
4424 ly_print_(pc->out, "\n");
4425 trm_print_section_as_family_tree(rpc, pc, tc);
4426 }
4427}
4428
4429/**
4430 * @brief For notifications section: print 'notifications' keyword
4431 * and all its nodes.
4432 * @param[in] pc contains mainly functions for printing.
4433 * @param[in,out] tc is the tree context.
4434 */
4435static void
4436trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4437{
4438 struct trt_keyword_stmt notifs;
4439
aPiecek01598c02021-04-23 14:18:24 +02004440 notifs = tro_modi_get_notifications(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004441
aPiecek03cb4872022-10-24 10:31:51 +02004442 if (notifs.section_name) {
aPiecekdc8fd572021-04-19 10:47:23 +02004443 ly_print_(pc->out, "\n");
4444 ly_print_(pc->out, "\n");
4445 trm_print_section_as_family_tree(notifs, pc, tc);
4446 }
4447}
4448
4449/**
4450 * @brief For all grouping sections: print 'grouping' keyword, its name
4451 * and all nodes.
4452 * @param[in] pc contains mainly functions for printing.
4453 * @param[in,out] tc is the tree context.
4454 */
4455static void
4456trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4457{
4458 ly_bool once;
aPiecek03cb4872022-10-24 10:31:51 +02004459 struct trt_keyword_stmt ks;
aPiecekdc8fd572021-04-19 10:47:23 +02004460
aPiecek01598c02021-04-23 14:18:24 +02004461 if (tc->lysc_tree) {
aPiecekdc8fd572021-04-19 10:47:23 +02004462 return;
4463 }
4464
4465 once = 1;
aPiecek03cb4872022-10-24 10:31:51 +02004466 for (ks = trop_modi_next_grouping(tc); ks.section_name; ks = trop_modi_next_grouping(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004467 if (once) {
4468 ly_print_(pc->out, "\n");
4469 ly_print_(pc->out, "\n");
4470 once = 0;
4471 } else {
4472 ly_print_(pc->out, "\n");
4473 }
4474 trm_print_section_as_subtree(ks, pc, tc);
4475 }
4476}
4477
4478/**
aPiecek03cb4872022-10-24 10:31:51 +02004479 * @brief Print all sections defined in plugins.
4480 *
aPiecekdc8fd572021-04-19 10:47:23 +02004481 * @param[in] pc contains mainly functions for printing.
4482 * @param[in,out] tc is the tree context.
4483 */
4484static void
aPiecek03cb4872022-10-24 10:31:51 +02004485trm_print_plugin_ext(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecekdc8fd572021-04-19 10:47:23 +02004486{
aPiecek03cb4872022-10-24 10:31:51 +02004487 LY_ERR rc;
aPiecek96baa7f2021-04-23 12:32:00 +02004488 ly_bool once;
aPiecek03cb4872022-10-24 10:31:51 +02004489 LY_ARRAY_COUNT_TYPE i = 0, j;
4490 struct trt_keyword_stmt ks, prev_ks = {0};
4491 struct trt_printer_ctx pc_dupl;
4492 struct trt_tree_ctx tc_dupl;
aPiecek02665a82022-12-14 10:38:16 +01004493 struct trt_node node;
aPiecek03cb4872022-10-24 10:31:51 +02004494 uint32_t max_gap_before_type;
4495 void *ext;
aPiecek96baa7f2021-04-23 12:32:00 +02004496
aPiecek03cb4872022-10-24 10:31:51 +02004497 tc->section = TRD_SECT_PLUG_DATA;
4498
4499 tc_dupl = *tc;
4500 pc_dupl = *pc;
aPiecek96baa7f2021-04-23 12:32:00 +02004501
4502 once = 1;
aPiecek96baa7f2021-04-23 12:32:00 +02004503
aPiecek03cb4872022-10-24 10:31:51 +02004504 while ((ext = trb_mod_ext_iter(tc, &i))) {
4505 struct lyspr_tree_ctx plug_ctx = {0};
4506
4507 rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx);
4508 LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end);
4509 if (!plug_ctx.schemas) {
aPiecek96baa7f2021-04-23 12:32:00 +02004510 continue;
4511 }
4512
aPiecek03cb4872022-10-24 10:31:51 +02004513 ks = tro_get_ext_section(tc, ext, &plug_ctx);
4514 if (once || (prev_ks.section_name && strcmp(prev_ks.section_name, ks.section_name))) {
aPiecek96baa7f2021-04-23 12:32:00 +02004515 ly_print_(pc->out, "\n");
4516 ly_print_(pc->out, "\n");
4517 once = 0;
4518 } else {
4519 ly_print_(pc->out, "\n");
4520 }
aPiecek03cb4872022-10-24 10:31:51 +02004521 trp_print_keyword_stmt(ks, pc->max_line_length, pc->out);
aPiecek96baa7f2021-04-23 12:32:00 +02004522
aPiecek03cb4872022-10-24 10:31:51 +02004523 max_gap_before_type = 0;
4524 trb_ext_try_unified_indent(&plug_ctx, TRP_EMPTY_PARENT_CACHE, &max_gap_before_type, pc, tc);
4525 LY_ARRAY_FOR(plug_ctx.schemas, j) {
4526 trm_reset_tree_ctx_by_plugin(&plug_ctx, j, pc, tc);
aPiecek02665a82022-12-14 10:38:16 +01004527 node = TRP_EMPTY_NODE;
4528 trb_print_subtree_nodes(&node, max_gap_before_type, TRP_INIT_WRAPPER_BODY, TRP_EMPTY_PARENT_CACHE, pc, tc);
aPiecek03cb4872022-10-24 10:31:51 +02004529 }
4530
4531 *tc = tc_dupl;
4532 trp_ext_free_plugin_ctx(&plug_ctx);
4533 prev_ks = ks;
aPiecek96baa7f2021-04-23 12:32:00 +02004534 }
aPiecek03cb4872022-10-24 10:31:51 +02004535
4536end:
4537 *pc = pc_dupl;
4538 return;
aPiecekdc8fd572021-04-19 10:47:23 +02004539}
4540
4541/**
4542 * @brief Print sections module, augment, rpcs, notifications,
4543 * grouping, yang-data.
4544 * @param[in] pc contains mainly functions for printing.
4545 * @param[in,out] tc is the tree context.
4546 */
4547static void
4548trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4549{
4550 trm_print_module_section(pc, tc);
4551 trm_print_augmentations(pc, tc);
4552 trm_print_rpcs(pc, tc);
4553 trm_print_notifications(pc, tc);
4554 trm_print_groupings(pc, tc);
aPiecek03cb4872022-10-24 10:31:51 +02004555 trm_print_plugin_ext(pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004556 ly_print_(pc->out, "\n");
aPiecek61d062b2020-11-02 11:05:09 +01004557}
4558
aPiecek40f22402022-10-14 10:48:08 +02004559static LY_ERR
4560tree_print_check_error(struct ly_out_clb_arg *out, struct trt_tree_ctx *tc)
4561{
4562 if (out->last_error) {
4563 return out->last_error;
4564 } else if (tc->last_error) {
4565 return tc->last_error;
4566 } else {
4567 return LY_SUCCESS;
4568 }
4569}
4570
aPiecek874ea4d2021-04-19 12:26:36 +02004571/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004572 * Definition of module interface
aPiecek874ea4d2021-04-19 12:26:36 +02004573 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004574
4575LY_ERR
aPiecek3f247652021-04-19 13:40:25 +02004576tree_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 +01004577{
4578 struct trt_printer_ctx pc;
4579 struct trt_tree_ctx tc;
4580 struct ly_out *new_out;
4581 LY_ERR erc;
4582 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4583
aPiecekdc8fd572021-04-19 10:47:23 +02004584 LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL);
4585
aPiecek61d062b2020-11-02 11:05:09 +01004586 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4587 return erc;
4588 }
4589
4590 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek3f247652021-04-19 13:40:25 +02004591 if ((module->ctx->flags & LY_CTX_SET_PRIV_PARSED) && module->compiled) {
aPiecek03cb4872022-10-24 10:31:51 +02004592 trm_lysc_tree_ctx(module, new_out, line_length, &pc, &tc);
aPiecek3f247652021-04-19 13:40:25 +02004593 } else {
aPiecek03cb4872022-10-24 10:31:51 +02004594 trm_lysp_tree_ctx(module, new_out, line_length, &pc, &tc);
aPiecek3f247652021-04-19 13:40:25 +02004595 }
aPiecek61d062b2020-11-02 11:05:09 +01004596
4597 trm_print_sections(&pc, &tc);
aPiecek40f22402022-10-14 10:48:08 +02004598 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek61d062b2020-11-02 11:05:09 +01004599
4600 ly_out_free(new_out, NULL, 1);
4601
aPiecekdc8fd572021-04-19 10:47:23 +02004602 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004603}
4604
4605LY_ERR
aPiecek153b00f2021-04-20 13:52:57 +02004606tree_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 +01004607{
aPiecek153b00f2021-04-20 13:52:57 +02004608 struct trt_printer_ctx pc;
4609 struct trt_tree_ctx tc;
4610 struct ly_out *new_out;
4611 struct trt_wrapper wr;
4612 LY_ERR erc;
4613 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4614
4615 assert(out && node);
4616
4617 if (!(node->module->ctx->flags & LY_CTX_SET_PRIV_PARSED)) {
4618 return LY_EINVAL;
4619 }
4620
4621 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4622 return erc;
4623 }
4624
4625 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek03cb4872022-10-24 10:31:51 +02004626 trm_lysc_tree_ctx(node->module, new_out, line_length, &pc, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004627
aPiecek03cb4872022-10-24 10:31:51 +02004628 trp_print_keyword_stmt(pc.fp.read.module_name(&tc), pc.max_line_length, pc.out);
ekinzie0ab8b302022-10-10 03:03:57 -04004629 trb_print_parents(node, NULL, &pc, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004630
4631 if (!(options & LYS_PRINT_NO_SUBSTMT)) {
4632 tc.cn = lysc_node_child(node);
ekinzie0ab8b302022-10-10 03:03:57 -04004633 wr = trb_count_depth(NULL, tc.cn);
aPiecek153b00f2021-04-20 13:52:57 +02004634 trb_print_family_tree(wr, &pc, &tc);
4635 }
4636 ly_print_(out, "\n");
4637
aPiecek40f22402022-10-14 10:48:08 +02004638 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek153b00f2021-04-20 13:52:57 +02004639 ly_out_free(new_out, NULL, 1);
4640
4641 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004642}
4643
4644LY_ERR
Michal Vasko6a914fb2022-01-17 10:36:14 +01004645tree_print_parsed_submodule(struct ly_out *out, const struct lysp_submodule *submodp, uint32_t UNUSED(options),
4646 size_t line_length)
aPiecek61d062b2020-11-02 11:05:09 +01004647{
aPiecek9f792e52021-04-21 08:33:56 +02004648 struct trt_printer_ctx pc;
4649 struct trt_tree_ctx tc;
4650 struct ly_out *new_out;
4651 LY_ERR erc;
4652 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4653
4654 assert(submodp);
4655 LY_CHECK_ARG_RET(submodp->mod->ctx, out, LY_EINVAL);
4656
4657 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4658 return erc;
4659 }
4660
4661 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek03cb4872022-10-24 10:31:51 +02004662 trm_lysp_tree_ctx(submodp->mod, new_out, line_length, &pc, &tc);
aPiecek9f792e52021-04-21 08:33:56 +02004663 tc.pmod = (struct lysp_module *)submodp;
4664 tc.tpn = submodp->data;
4665 tc.pn = tc.tpn;
4666
4667 trm_print_sections(&pc, &tc);
aPiecek40f22402022-10-14 10:48:08 +02004668 erc = tree_print_check_error(&clb_arg, &tc);
aPiecek9f792e52021-04-21 08:33:56 +02004669
4670 ly_out_free(new_out, NULL, 1);
4671
4672 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004673}