blob: a49b84c639af41cee0444fb2d8466aad3d9621b9 [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"
96#include "tree_schema_internal.h"
97#include "xpath.h"
98
aPiecek61d062b2020-11-02 11:05:09 +010099/**
100 * @brief List of available actions.
101 */
102typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200103 TRD_PRINT = 0, /**< Normal behavior. It just prints. */
104 TRD_CHAR_COUNT /**< Characters will be counted instead of printing. */
aPiecek61d062b2020-11-02 11:05:09 +0100105} trt_ly_out_clb_arg_flag;
106
107/**
aPiecek874ea4d2021-04-19 12:26:36 +0200108 * @brief Structure is passed as 'writeclb' argument
aPiecek01598c02021-04-23 14:18:24 +0200109 * to the ::ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100110 */
111struct ly_out_clb_arg {
aPiecek874ea4d2021-04-19 12:26:36 +0200112 trt_ly_out_clb_arg_flag mode; /**< flag specifying which action to take. */
113 struct ly_out *out; /**< The ly_out pointer delivered to the printer tree module via the main interface. */
114 size_t counter; /**< Counter of printed characters. */
115 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 +0100116};
117
118/**
119 * @brief Initialize struct ly_out_clb_arg with default settings.
120 */
121#define TRP_INIT_LY_OUT_CLB_ARG(MODE, OUT, COUNTER, LAST_ERROR) \
aPiecek874ea4d2021-04-19 12:26:36 +0200122 (struct ly_out_clb_arg) { \
123 .mode = MODE, .out = OUT, \
124 .counter = COUNTER, .last_error = LAST_ERROR \
125 }
aPiecek61d062b2020-11-02 11:05:09 +0100126
aPiecek874ea4d2021-04-19 12:26:36 +0200127/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100128 * Print getters
aPiecek874ea4d2021-04-19 12:26:36 +0200129 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100130
131/**
132 * @brief Callback functions that prints special cases.
133 *
134 * It just groups together tree context with trt_fp_print.
135 */
136struct trt_cf_print {
aPiecek874ea4d2021-04-19 12:26:36 +0200137 const struct trt_tree_ctx *ctx; /**< Context of libyang tree. */
138 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 +0100139};
140
141/**
142 * @brief Callback functions for printing special cases.
143 *
aPiecek874ea4d2021-04-19 12:26:36 +0200144 * Functions with the suffix 'trp' can print most of the text on
145 * output, just by setting the pointer to the string. But in some
146 * cases, it's not that simple, because its entire string is fragmented
147 * in memory. For example, for printing list's keys or if-features.
aPiecek61d062b2020-11-02 11:05:09 +0100148 * However, this depends on how the libyang library is implemented.
aPiecek3f247652021-04-19 13:40:25 +0200149 * This implementation of the printer_tree module goes through
150 * a lysp tree, but if it goes through a lysc tree, these special cases
151 * would be different.
aPiecek61d062b2020-11-02 11:05:09 +0100152 * Functions must print including spaces or delimiters between names.
153 */
154struct trt_fp_print {
155 void (*print_features_names)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list of features without {}? wrapper. */
156 void (*print_keys)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list's keys without [] wrapper. */
157};
158
159/**
160 * @brief Package which only groups getter function.
161 */
162struct trt_pck_print {
163 const struct trt_tree_ctx *tree_ctx; /**< Context of libyang tree. */
164 struct trt_fp_print fps; /**< Print function. */
165};
166
167/**
168 * @brief Initialize struct trt_pck_print by parameters.
169 */
170#define TRP_INIT_PCK_PRINT(TREE_CTX, FP_PRINT) \
aPiecek874ea4d2021-04-19 12:26:36 +0200171 (struct trt_pck_print) {.tree_ctx = TREE_CTX, .fps = FP_PRINT}
aPiecek61d062b2020-11-02 11:05:09 +0100172
aPiecek874ea4d2021-04-19 12:26:36 +0200173/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100174 * Indent
aPiecek874ea4d2021-04-19 12:26:36 +0200175 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100176
177/**
aPiecek874ea4d2021-04-19 12:26:36 +0200178 * @brief Constants which are defined in the RFC or are observable
179 * from the pyang tool.
aPiecek61d062b2020-11-02 11:05:09 +0100180 */
181typedef enum {
182 TRD_INDENT_EMPTY = 0, /**< If the node is a case node, there is no space before the \<name\>. */
183 TRD_INDENT_LONG_LINE_BREAK = 2, /**< The new line should be indented so that it starts below \<name\> with a whitespace offset of at least two characters. */
184 TRD_INDENT_LINE_BEGIN = 2, /**< Indent below the keyword (module, augment ...). */
185 TRD_INDENT_BTW_SIBLINGS = 2, /**< Indent between | and | characters. */
186 TRD_INDENT_BEFORE_KEYS = 1, /**< "..."___\<keys\>. */
187 TRD_INDENT_BEFORE_TYPE = 4, /**< "..."___\<type\>, but if mark is set then indent == 3. */
188 TRD_INDENT_BEFORE_IFFEATURES = 1 /**< "..."___\<iffeatures\>. */
189} trt_cnf_indent;
190
191/**
192 * @brief Type of indent in node.
193 */
194typedef enum {
195 TRD_INDENT_IN_NODE_NORMAL = 0, /**< Node fits on one line. */
196 TRD_INDENT_IN_NODE_DIVIDED, /**< The node must be split into multiple rows. */
197 TRD_INDENT_IN_NODE_FAILED /**< Cannot be crammed into one line. The condition for the maximum line length is violated. */
198} trt_indent_in_node_type;
199
200/** Constant to indicate the need to break a line. */
201#define TRD_LINEBREAK -1
202
203/**
aPiecek874ea4d2021-04-19 12:26:36 +0200204 * @brief Records the alignment between the individual
205 * elements of the node.
aPiecek61d062b2020-11-02 11:05:09 +0100206 *
aPiecek874ea4d2021-04-19 12:26:36 +0200207 * @see trp_default_indent_in_node, trp_try_normal_indent_in_node
aPiecek61d062b2020-11-02 11:05:09 +0100208 */
209struct trt_indent_in_node {
210 trt_indent_in_node_type type; /**< Type of indent in node. */
aPiecek874ea4d2021-04-19 12:26:36 +0200211 int16_t btw_name_opts; /**< Indent between node name and \<opts\>. */
212 int16_t btw_opts_type; /**< Indent between \<opts\> and \<type\>. */
aPiecek61d062b2020-11-02 11:05:09 +0100213 int16_t btw_type_iffeatures; /**< Indent between type and features. Ignored if \<type\> missing. */
214};
215
216/**
217 * @brief Type of wrappers to be printed.
218 */
219typedef enum {
220 TRD_WRAPPER_TOP = 0, /**< Related to the module. */
221 TRD_WRAPPER_BODY /**< Related to e.g. Augmentations or Groupings */
222} trd_wrapper_type;
223
224/**
225 * @brief For resolving sibling symbol ('|') placement.
226 *
227 * Bit indicates where the sibling symbol must be printed.
aPiecek874ea4d2021-04-19 12:26:36 +0200228 * This place is in multiples of ::TRD_INDENT_BTW_SIBLINGS.
aPiecek61d062b2020-11-02 11:05:09 +0100229 *
aPiecek874ea4d2021-04-19 12:26:36 +0200230 * @see TRP_INIT_WRAPPER_TOP, TRP_INIT_WRAPPER_BODY,
231 * trp_wrapper_set_mark, trp_wrapper_set_shift,
232 * trp_wrapper_if_last_sibling, trp_wrapper_eq, trp_print_wrapper
aPiecek61d062b2020-11-02 11:05:09 +0100233 */
234struct trt_wrapper {
235 trd_wrapper_type type; /**< Location of the wrapper. */
236 uint64_t bit_marks1; /**< The set bits indicate where the '|' character is to be printed.
237 It follows that the maximum immersion of the printable node is 64. */
238 uint32_t actual_pos; /**< Actual position in bit_marks. */
239};
240
241/**
242 * @brief Get wrapper related to the module section.
243 *
244 * @code
245 * module: <module-name>
246 * +--<node>
247 * |
248 * @endcode
249 */
250#define TRP_INIT_WRAPPER_TOP \
aPiecek874ea4d2021-04-19 12:26:36 +0200251 (struct trt_wrapper) { \
252 .type = TRD_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0 \
253 }
aPiecek61d062b2020-11-02 11:05:09 +0100254
255/**
aPiecek874ea4d2021-04-19 12:26:36 +0200256 * @brief Get wrapper related to subsection
257 * e.g. Augmenations or Groupings.
aPiecek61d062b2020-11-02 11:05:09 +0100258 *
259 * @code
260 * module: <module-name>
261 * +--<node>
262 *
263 * augment <target-node>:
264 * +--<node>
265 * @endcode
266 */
267#define TRP_INIT_WRAPPER_BODY \
aPiecek874ea4d2021-04-19 12:26:36 +0200268 (struct trt_wrapper) { \
269 .type = TRD_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0 \
270 }
aPiecek61d062b2020-11-02 11:05:09 +0100271
272/**
273 * @brief Package which only groups wrapper and indent in node.
274 */
275struct trt_pck_indent {
276 struct trt_wrapper wrapper; /**< Coded " | | " sequence. */
277 struct trt_indent_in_node in_node; /**< Indent in node. */
278};
279
280/**
281 * @brief Initialize struct trt_pck_indent by parameters.
282 */
283#define TRP_INIT_PCK_INDENT(WRAPPER, INDENT_IN_NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200284 (struct trt_pck_indent){ \
285 .wrapper = WRAPPER, .in_node = INDENT_IN_NODE \
286 }
aPiecek61d062b2020-11-02 11:05:09 +0100287
aPiecek874ea4d2021-04-19 12:26:36 +0200288/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100289 * status
aPiecek874ea4d2021-04-19 12:26:36 +0200290 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100291
292/**
293 * @brief Status of the node.
294 *
aPiecek874ea4d2021-04-19 12:26:36 +0200295 * @see trp_print_status
aPiecek61d062b2020-11-02 11:05:09 +0100296 */
297typedef enum {
298 TRD_STATUS_TYPE_EMPTY = 0,
aPiecek874ea4d2021-04-19 12:26:36 +0200299 TRD_STATUS_TYPE_CURRENT, /**< ::LYS_STATUS_CURR */
300 TRD_STATUS_TYPE_DEPRECATED, /**< ::LYS_STATUS_DEPRC */
301 TRD_STATUS_TYPE_OBSOLETE /**< ::LYS_STATUS_OBSLT */
aPiecek61d062b2020-11-02 11:05:09 +0100302} trt_status_type;
303
aPiecek874ea4d2021-04-19 12:26:36 +0200304/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100305 * flags
aPiecek874ea4d2021-04-19 12:26:36 +0200306 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100307
308/**
309 * @brief Flag of the node.
310 *
aPiecek874ea4d2021-04-19 12:26:36 +0200311 * @see trp_print_flags, trp_get_flags_strlen
aPiecek61d062b2020-11-02 11:05:09 +0100312 */
313typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200314 TRD_FLAGS_TYPE_EMPTY = 0, /**< -- */
aPiecek61d062b2020-11-02 11:05:09 +0100315 TRD_FLAGS_TYPE_RW, /**< rw */
316 TRD_FLAGS_TYPE_RO, /**< ro */
317 TRD_FLAGS_TYPE_RPC_INPUT_PARAMS, /**< -w */
318 TRD_FLAGS_TYPE_USES_OF_GROUPING, /**< -u */
319 TRD_FLAGS_TYPE_RPC, /**< -x */
320 TRD_FLAGS_TYPE_NOTIF, /**< -n */
321 TRD_FLAGS_TYPE_MOUNT_POINT /**< mp */
322} trt_flags_type;
323
aPiecek874ea4d2021-04-19 12:26:36 +0200324/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100325 * node_name and opts
aPiecek874ea4d2021-04-19 12:26:36 +0200326 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100327
328#define TRD_NODE_NAME_PREFIX_CHOICE "("
329#define TRD_NODE_NAME_PREFIX_CASE ":("
330#define TRD_NODE_NAME_TRIPLE_DOT "..."
331
332/**
333 * @brief Type of the node.
334 *
aPiecek874ea4d2021-04-19 12:26:36 +0200335 * Used mainly to complete the correct \<opts\> next to or
336 * around the \<name\>.
aPiecek61d062b2020-11-02 11:05:09 +0100337 */
338typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200339 TRD_NODE_ELSE = 0, /**< For some node which does not require special treatment. \<name\> */
340 TRD_NODE_CASE, /**< For case node. :(\<name\>) */
341 TRD_NODE_CHOICE, /**< For choice node. (\<name\>) */
342 TRD_NODE_OPTIONAL_CHOICE, /**< For choice node with optional mark. (\<name\>)? */
343 TRD_NODE_OPTIONAL, /**< For an optional leaf, anydata, or anyxml. \<name\>? */
344 TRD_NODE_CONTAINER, /**< For a presence container. \<name\>! */
345 TRD_NODE_LISTLEAFLIST, /**< For a leaf-list or list (without keys). \<name\>* */
346 TRD_NODE_KEYS, /**< For a list's keys. \<name\>* [\<keys\>] */
347 TRD_NODE_TOP_LEVEL1, /**< For a top-level data node in a mounted module. \<name\>/ */
348 TRD_NODE_TOP_LEVEL2, /**< For a top-level data node of a module identified in a mount point parent reference. \<name\>@ */
349 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 +0100350} trt_node_type;
351
352/**
353 * @brief Type of node and his name.
354 *
aPiecek874ea4d2021-04-19 12:26:36 +0200355 * @see TRP_EMPTY_NODE_NAME, TRP_NODE_NAME_IS_EMPTY,
aPiecek61d062b2020-11-02 11:05:09 +0100356 * trp_print_node_name, trp_mark_is_used, trp_print_opts_keys
357 */
358struct trt_node_name {
359 trt_node_type type; /**< Type of the node relevant for printing. */
aPiecek34fa3772021-05-21 12:35:46 +0200360 const char *module_prefix; /**< If the node is augmented into the tree from another module,
361 so this is the prefix of that module. */
aPiecek61d062b2020-11-02 11:05:09 +0100362 const char *str; /**< Name of the node. */
363};
364
365/**
366 * @brief Create struct trt_node_name as empty.
367 */
368#define TRP_EMPTY_NODE_NAME \
aPiecek874ea4d2021-04-19 12:26:36 +0200369 (struct trt_node_name) { \
370 .type = TRD_NODE_ELSE, .module_prefix = NULL, .str = NULL \
371 }
aPiecek61d062b2020-11-02 11:05:09 +0100372
373/**
374 * @brief Check if struct trt_node_name is empty.
375 */
376#define TRP_NODE_NAME_IS_EMPTY(NODE_NAME) \
377 !NODE_NAME.str
378
aPiecek874ea4d2021-04-19 12:26:36 +0200379/**
380 * @brief Every \<opts\> mark except string of list's keys
381 * has a length of one.
382 */
aPiecek61d062b2020-11-02 11:05:09 +0100383#define TRD_OPTS_MARK_LENGTH 1
384
aPiecek874ea4d2021-04-19 12:26:36 +0200385/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100386 * type
aPiecek874ea4d2021-04-19 12:26:36 +0200387 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100388
389/**
390 * @brief Type of the \<type\>
391 */
392typedef enum {
393 TRD_TYPE_NAME = 0, /**< Type is just a name that does not require special treatment. */
394 TRD_TYPE_TARGET, /**< Should have a form "-> TARGET", where TARGET is the leafref path. */
aPiecek874ea4d2021-04-19 12:26:36 +0200395 TRD_TYPE_LEAFREF, /**< This type is set automatically by the 'trp' algorithm.
396 So set type as ::TRD_TYPE_TARGET. */
aPiecek61d062b2020-11-02 11:05:09 +0100397 TRD_TYPE_EMPTY /**< Type is not used at all. */
398} trt_type_type;
399
400/**
401 * @brief \<type\> in the \<node\>.
402 *
aPiecek874ea4d2021-04-19 12:26:36 +0200403 * @see TRP_EMPTY_TRT_TYPE, TRP_TRT_TYPE_IS_EMPTY, trp_print_type
aPiecek61d062b2020-11-02 11:05:09 +0100404 */
405struct trt_type {
406 trt_type_type type; /**< Type of the \<type\>. */
407 const char *str; /**< Path or name of the type. */
408};
409
410/**
411 * @brief Create empty struct trt_type.
412 */
413#define TRP_EMPTY_TRT_TYPE \
414 (struct trt_type) {.type = TRD_TYPE_EMPTY, .str = NULL}
415
416/**
417 * @brief Check if struct trt_type is empty.
418 */
419#define TRP_TRT_TYPE_IS_EMPTY(TYPE_OF_TYPE) \
420 TYPE_OF_TYPE.type == TRD_TYPE_EMPTY
421
422/**
423 * @brief Initialize struct trt_type by parameters.
424 */
425#define TRP_INIT_TRT_TYPE(TYPE_OF_TYPE, STRING) \
426 (struct trt_type) {.type = TYPE_OF_TYPE, .str = STRING}
427
aPiecek874ea4d2021-04-19 12:26:36 +0200428/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100429 * node
aPiecek874ea4d2021-04-19 12:26:36 +0200430 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100431
432/**
433 * @brief \<node\> data for printing.
434 *
aPiecek874ea4d2021-04-19 12:26:36 +0200435 * It contains RFC's:
436 * \<status\>--\<flags\> \<name\>\<opts\> \<type\> \<if-features\>.
aPiecek61d062b2020-11-02 11:05:09 +0100437 * Item \<opts\> is moved to part struct trt_node_name.
aPiecek874ea4d2021-04-19 12:26:36 +0200438 * For printing [\<keys\>] and if-features is required special
439 * functions which prints them.
aPiecek61d062b2020-11-02 11:05:09 +0100440 *
aPiecek874ea4d2021-04-19 12:26:36 +0200441 * @see TRP_EMPTY_NODE, trp_node_is_empty, trp_node_body_is_empty,
442 * trp_print_node_up_to_name, trp_print_divided_node_up_to_name,
443 * trp_print_node
aPiecek61d062b2020-11-02 11:05:09 +0100444 */
445struct trt_node {
aPiecek874ea4d2021-04-19 12:26:36 +0200446 trt_status_type status; /**< \<status\>. */
447 trt_flags_type flags; /**< \<flags\>. */
448 struct trt_node_name name; /**< \<node\> with \<opts\> mark or [\<keys\>]. */
449 struct trt_type type; /**< \<type\> contains the name of the type or type for leafref. */
450 ly_bool iffeatures; /**< \<if-features\>. Value 1 means that iffeatures are present and
451 will be printed by trt_fp_print.print_features_names callback. */
452 ly_bool last_one; /**< Information about whether the node is the last. */
aPiecek61d062b2020-11-02 11:05:09 +0100453};
454
455/**
456 * @brief Create struct trt_node as empty.
457 */
458#define TRP_EMPTY_NODE \
aPiecek874ea4d2021-04-19 12:26:36 +0200459 (struct trt_node) { \
460 .status = TRD_STATUS_TYPE_EMPTY, \
461 .flags = TRD_FLAGS_TYPE_EMPTY, \
462 .name = TRP_EMPTY_NODE_NAME, \
463 .type = TRP_EMPTY_TRT_TYPE, \
464 .iffeatures = 0, \
465 .last_one = 1 \
466 }
aPiecek61d062b2020-11-02 11:05:09 +0100467
468/**
469 * @brief Package which only groups indent and node.
470 */
471struct trt_pair_indent_node {
472 struct trt_indent_in_node indent;
473 struct trt_node node;
474};
475
476/**
477 * @brief Initialize struct trt_pair_indent_node by parameters.
478 */
479#define TRP_INIT_PAIR_INDENT_NODE(INDENT_IN_NODE, NODE) \
aPiecek874ea4d2021-04-19 12:26:36 +0200480 (struct trt_pair_indent_node) { \
481 .indent = INDENT_IN_NODE, .node = NODE \
482 }
aPiecek61d062b2020-11-02 11:05:09 +0100483
aPiecek874ea4d2021-04-19 12:26:36 +0200484/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100485 * statement
aPiecek874ea4d2021-04-19 12:26:36 +0200486 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100487
488#define TRD_TOP_KEYWORD_MODULE "module"
489#define TRD_TOP_KEYWORD_SUBMODULE "submodule"
490
491#define TRD_BODY_KEYWORD_AUGMENT "augment"
492#define TRD_BODY_KEYWORD_RPC "rpcs"
493#define TRD_BODY_KEYWORD_NOTIF "notifications"
494#define TRD_BODY_KEYWORD_GROUPING "grouping"
495#define TRD_BODY_KEYWORD_YANG_DATA "yang-data"
496
497/**
498 * @brief Type of the trt_keyword.
499 */
500typedef enum {
501 TRD_KEYWORD_EMPTY = 0,
502 TRD_KEYWORD_MODULE,
503 TRD_KEYWORD_SUBMODULE,
504 TRD_KEYWORD_AUGMENT,
505 TRD_KEYWORD_RPC,
506 TRD_KEYWORD_NOTIF,
507 TRD_KEYWORD_GROUPING,
508 TRD_KEYWORD_YANG_DATA
509} trt_keyword_type;
510
511/**
512 * @brief Main sign of the tree nodes.
513 *
aPiecek874ea4d2021-04-19 12:26:36 +0200514 * @see TRP_EMPTY_KEYWORD_STMT, TRP_KEYWORD_STMT_IS_EMPTY
aPiecek61d062b2020-11-02 11:05:09 +0100515 * trt_print_keyword_stmt_begin, trt_print_keyword_stmt_str,
516 * trt_print_keyword_stmt_end, trp_print_keyword_stmt
517 * trp_keyword_type_strlen
518 *
519 */
520struct trt_keyword_stmt {
aPiecek874ea4d2021-04-19 12:26:36 +0200521 trt_keyword_type type; /**< String containing some of the top or body keyword. */
522 const char *str; /**< Name or path, it determines the type. */
aPiecek61d062b2020-11-02 11:05:09 +0100523};
524
525/**
526 * @brief Create struct trt_keyword_stmt as empty.
527 */
528#define TRP_EMPTY_KEYWORD_STMT \
529 (struct trt_keyword_stmt) {.type = TRD_KEYWORD_EMPTY, .str = NULL}
530
531/**
532 * @brief Check if struct trt_keyword_stmt is empty.
533 */
534#define TRP_KEYWORD_STMT_IS_EMPTY(KEYWORD_TYPE) \
535 KEYWORD_TYPE.type == TRD_KEYWORD_EMPTY
536
537/**
538 * @brief Initialize struct trt_keyword_stmt by parameters.
539 */
540#define TRP_INIT_KEYWORD_STMT(KEYWORD_TYPE, STRING) \
541 (struct trt_keyword_stmt) {.type = KEYWORD_TYPE, .str = STRING}
542
aPiecek874ea4d2021-04-19 12:26:36 +0200543/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100544 * Modify getters
aPiecek874ea4d2021-04-19 12:26:36 +0200545 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100546
547struct trt_parent_cache;
548
549/**
550 * @brief Functions that change the state of the tree_ctx structure.
551 *
aPiecek3f247652021-04-19 13:40:25 +0200552 * The 'trop' or 'troc' functions are set here, which provide data
aPiecek874ea4d2021-04-19 12:26:36 +0200553 * for the 'trp' printing functions and are also called from the
554 * 'trb' browsing functions when walking through a tree. These callback
555 * functions need to be checked or reformulated if changes to the
556 * libyang library affect the printing tree. For all, if the value
557 * cannot be returned, its empty version obtained by relevant TRP_EMPTY
558 * macro is returned.
aPiecek61d062b2020-11-02 11:05:09 +0100559 */
560struct trt_fp_modify_ctx {
561 ly_bool (*parent)(struct trt_tree_ctx *); /**< Jump to parent node. Return true if parent exists. */
562 void (*first_sibling)(struct trt_tree_ctx *); /**< Jump on the first of the siblings. */
563 struct trt_node (*next_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to next sibling of the current node. */
564 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 +0100565};
566
aPiecek874ea4d2021-04-19 12:26:36 +0200567/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100568 * Read getters
aPiecek874ea4d2021-04-19 12:26:36 +0200569 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100570
571/**
572 * @brief Functions that do not change the state of the tree_structure.
573 *
574 * For details see trt_fp_modify_ctx.
575 */
576struct trt_fp_read {
aPiecek874ea4d2021-04-19 12:26:36 +0200577 struct trt_keyword_stmt (*module_name)(const struct trt_tree_ctx *); /**< Get name of the module. */
578 struct trt_node (*node)(struct trt_parent_cache, const struct trt_tree_ctx *); /**< Get current node. */
579 ly_bool (*if_sibling_exists)(const struct trt_tree_ctx *); /**< Check if node's sibling exists. */
aPiecek61d062b2020-11-02 11:05:09 +0100580};
581
aPiecek874ea4d2021-04-19 12:26:36 +0200582/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100583 * All getters
aPiecek874ea4d2021-04-19 12:26:36 +0200584 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100585
586/**
aPiecek874ea4d2021-04-19 12:26:36 +0200587 * @brief A set of all necessary functions that must be provided
588 * for the printer.
aPiecek61d062b2020-11-02 11:05:09 +0100589 */
590struct trt_fp_all {
591 struct trt_fp_modify_ctx modify; /**< Function pointers which modify state of trt_tree_ctx. */
592 struct trt_fp_read read; /**< Function pointers which only reads state of trt_tree_ctx. */
593 struct trt_fp_print print; /**< Functions pointers for printing special items in node. */
594};
595
aPiecek874ea4d2021-04-19 12:26:36 +0200596/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100597 * Printer context
aPiecek874ea4d2021-04-19 12:26:36 +0200598 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100599
600/**
aPiecek01598c02021-04-23 14:18:24 +0200601 * @brief Main structure for @ref TRP_trp part.
aPiecek61d062b2020-11-02 11:05:09 +0100602 */
603struct trt_printer_ctx {
604 struct ly_out *out; /**< Handler to printing. */
aPiecek01598c02021-04-23 14:18:24 +0200605 struct trt_fp_all fp; /**< @ref TRP_tro functions callbacks. */
aPiecek61d062b2020-11-02 11:05:09 +0100606 size_t max_line_length; /**< The maximum number of characters that can be
607 printed on one line, including the last. */
608};
609
aPiecek874ea4d2021-04-19 12:26:36 +0200610/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100611 * Tro functions
aPiecek874ea4d2021-04-19 12:26:36 +0200612 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100613
614/**
615 * @brief The name of the section to which the node belongs.
616 */
617typedef enum {
618 TRD_SECT_MODULE = 0, /**< The node belongs to the "module: <module_name>:" label. */
619 TRD_SECT_AUGMENT, /**< The node belongs to some "augment <target-node>:" label. */
620 TRD_SECT_RPCS, /**< The node belongs to the "rpcs:" label. */
621 TRD_SECT_NOTIF, /**< The node belongs to the "notifications:" label. */
622 TRD_SECT_GROUPING, /**< The node belongs to some "grouping <grouping-name>:" label. */
623 TRD_SECT_YANG_DATA /**< The node belongs to some "yang-data <yang-data-name>:" label. */
624} trt_actual_section;
625
626/**
627 * @brief Types of nodes that have some effect on their children.
628 */
629typedef enum {
aPiecek874ea4d2021-04-19 12:26:36 +0200630 TRD_ANCESTOR_ELSE = 0, /**< Everything not listed. */
631 TRD_ANCESTOR_RPC_INPUT, /**< ::LYS_INPUT */
632 TRD_ANCESTOR_RPC_OUTPUT, /**< ::LYS_OUTPUT */
633 TRD_ANCESTOR_NOTIF /**< ::LYS_NOTIF */
aPiecek61d062b2020-11-02 11:05:09 +0100634} trt_ancestor_type;
635
636/**
637 * @brief Saved information when browsing the tree downwards.
638 *
aPiecek874ea4d2021-04-19 12:26:36 +0200639 * This structure helps prevent frequent retrieval of information
aPiecek01598c02021-04-23 14:18:24 +0200640 * from the tree. Functions @ref TRP_trb are designed to preserve
aPiecek874ea4d2021-04-19 12:26:36 +0200641 * this structures during their recursive calls. This functions do not
642 * interfere in any way with this data. This structure
aPiecek01598c02021-04-23 14:18:24 +0200643 * is used by @ref TRP_trop functions which, thanks to this
aPiecek874ea4d2021-04-19 12:26:36 +0200644 * structure, can return a node with the correct data. The word
645 * \b parent is in the structure name, because this data refers to
646 * the last parent and at the same time the states of its
647 * ancestors data. Only the function jumping on the child
648 * (next_child(...)) creates this structure, because the pointer
649 * to the current node moves down the tree. It's like passing
650 * the genetic code to children. Some data must be inherited and
651 * there are two approaches to this problem. Either it will always
652 * be determined which inheritance states belong to the current node
653 * (which can lead to regular travel to the root node) or
654 * the inheritance states will be stored during the recursive calls.
655 * So the problem was solved by the second option. Why does
656 * the structure contain this data? Because it walks through
aPiecek3f247652021-04-19 13:40:25 +0200657 * the lysp tree. For walks through the lysc tree is trt_parent_cache
658 * useless.
aPiecek61d062b2020-11-02 11:05:09 +0100659 *
aPiecek874ea4d2021-04-19 12:26:36 +0200660 * @see TRO_EMPTY_PARENT_CACHE, tro_parent_cache_for_child
aPiecek61d062b2020-11-02 11:05:09 +0100661 */
662struct trt_parent_cache {
aPiecek874ea4d2021-04-19 12:26:36 +0200663 trt_ancestor_type ancestor; /**< Some types of nodes have a special effect on their children. */
664 uint16_t lys_status; /**< Inherited status CURR, DEPRC, OBSLT. */
665 uint16_t lys_config; /**< Inherited config W or R. */
666 const struct lysp_node_list *last_list; /**< The last ::LYS_LIST passed. */
aPiecek61d062b2020-11-02 11:05:09 +0100667};
668
669/**
670 * @brief Return trt_parent_cache filled with default values.
671 */
672#define TRP_EMPTY_PARENT_CACHE \
aPiecek874ea4d2021-04-19 12:26:36 +0200673 (struct trt_parent_cache) { \
674 .ancestor = TRD_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \
675 .lys_config = LYS_CONFIG_W, .last_list = NULL \
676 }
aPiecek61d062b2020-11-02 11:05:09 +0100677
678/**
679 * @brief Main structure for browsing the libyang tree
680 */
681struct trt_tree_ctx {
aPiecek96baa7f2021-04-23 12:32:00 +0200682 ly_bool lysc_tree; /**< The lysc nodes are used for browsing through the tree.
683 It is assumed that once set, it does not change.
684 If it is true then trt_tree_ctx.pn and
685 trt_tree_ctx.tpn are not used.
686 If it is false then trt_tree_ctx.cn is not used. */
687 trt_actual_section section; /**< To which section pn points. */
688 const struct lysp_module *pmod; /**< Parsed YANG schema tree. */
689 const struct lysc_module *cmod; /**< Compiled YANG schema tree. */
690 const struct lysp_node *pn; /**< Actual pointer to parsed node. */
691 union {
692 const struct lysp_node *tpn; /**< Pointer to actual top-node. */
693 const struct lysp_ext_instance *tpn_ext; /**< Actual top-node is extension. Item trt_tree_ctx.section
694 is set to TRD_SECT_YANG_DATA. */
695 };
696 const struct lysc_node *cn; /**< Actual pointer to compiled node. */
aPiecek61d062b2020-11-02 11:05:09 +0100697};
698
aPiecek3f247652021-04-19 13:40:25 +0200699/**
aPiecekbbc02932021-05-21 07:19:41 +0200700 * @brief Check if lysp node is available from
701 * the current compiled node.
702 *
703 * Use only if trt_tree_ctx.lysc_tree is set to true.
704 */
705#define TRP_TREE_CTX_LYSP_NODE_PRESENT(CN) \
706 (CN->priv)
707
708/**
aPiecek3f247652021-04-19 13:40:25 +0200709 * @brief Get lysp_node from trt_tree_ctx.cn.
aPiecekbbc02932021-05-21 07:19:41 +0200710 *
711 * Use only if :TRP_TREE_CTX_LYSP_NODE_PRESENT returns true
712 * for that node.
aPiecek3f247652021-04-19 13:40:25 +0200713 */
714#define TRP_TREE_CTX_GET_LYSP_NODE(CN) \
715 ((const struct lysp_node *)CN->priv)
716
aPiecek01598c02021-04-23 14:18:24 +0200717/** Getter function for ::trop_node_charptr(). */
aPiecek61d062b2020-11-02 11:05:09 +0100718typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
719
aPiecekef1e58e2021-04-19 13:19:44 +0200720/**
721 * @brief Simple getter functions for lysp and lysc nodes.
722 *
723 * This structure is useful if we have a general algorithm
724 * (tro function) that can be used for both lysc and lysp nodes.
725 * Thanks to this structure, we prevent code redundancy.
726 * We don't have to write basically the same algorithm twice
727 * for lysp and lysc trees.
728 */
729struct tro_getters
730{
731 uint16_t (*nodetype)(const void *); /**< Get nodetype. */
732 const void *(*next)(const void *); /**< Get sibling. */
733 const void *(*parent)(const void *); /**< Get parent. */
734 const void *(*child)(const void *); /**< Get child. */
735 const void *(*actions)(const void *); /**< Get actions. */
736 const void *(*action_input)(const void *); /**< Get input action from action node. */
737 const void *(*action_output)(const void *); /**< Get output action from action node. */
738 const void *(*notifs)(const void *); /**< Get notifs. */
739};
740
aPiecek874ea4d2021-04-19 12:26:36 +0200741/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100742 * Definition of the general Trg functions
aPiecek874ea4d2021-04-19 12:26:36 +0200743 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100744
745/**
746 * @brief Print a substring but limited to the maximum length.
747 * @param[in] str is pointer to source.
748 * @param[in] len is number of characters to be printed.
749 * @param[in,out] out is output handler.
750 * @return str parameter shifted by len.
751 */
752static const char *
753trg_print_substr(const char *str, size_t len, struct ly_out *out)
754{
755 for (size_t i = 0; i < len; i++) {
756 ly_print_(out, "%c", str[0]);
757 str++;
758 }
759 return str;
760}
761
762/**
763 * @brief Pointer is not NULL and does not point to an empty string.
764 * @param[in] str is pointer to string to be checked.
765 * @return 1 if str pointing to non empty string otherwise 0.
766 */
767static ly_bool
768trg_charptr_has_data(const char *str)
769{
770 return (str) && (str[0] != '\0');
771}
772
773/**
aPiecek874ea4d2021-04-19 12:26:36 +0200774 * @brief Check if @p word in @p src is present where words are
775 * delimited by @p delim.
776 * @param[in] src is source where words are separated by @p delim.
aPiecek61d062b2020-11-02 11:05:09 +0100777 * @param[in] word to be searched.
aPiecek874ea4d2021-04-19 12:26:36 +0200778 * @param[in] delim is delimiter between @p words in @p src.
779 * @return 1 if src contains @p word otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +0100780 */
781static ly_bool
782trg_word_is_present(const char *src, const char *word, char delim)
783{
784 const char *hit;
785
786 if ((!src) || (src[0] == '\0') || (!word)) {
787 return 0;
788 }
789
790 hit = strstr(src, word);
791
792 if (hit) {
793 /* word was founded at the begin of src
794 * OR it match somewhere after delim
795 */
796 if ((hit == src) || (hit[-1] == delim)) {
797 /* end of word was founded at the end of src
798 * OR end of word was match somewhere before delim
799 */
800 char delim_or_end = (hit + strlen(word))[0];
801 if ((delim_or_end == '\0') || (delim_or_end == delim)) {
802 return 1;
803 }
804 }
805 /* after -> hit is just substr and it's not the whole word */
806 /* jump to the next word */
807 for ( ; (src[0] != '\0') && (src[0] != delim); src++) {}
808 /* skip delim */
809 src = src[0] == '\0' ? src : src + 1;
810 /* continue with searching */
811 return trg_word_is_present(src, word, delim);
812 } else {
813 return 0;
814 }
815}
816
aPiecek874ea4d2021-04-19 12:26:36 +0200817/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +0100818 * Definition of printer functions
aPiecek874ea4d2021-04-19 12:26:36 +0200819 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +0100820
821/**
aPiecek01598c02021-04-23 14:18:24 +0200822 * @brief Write callback for ::ly_out_new_clb().
aPiecek61d062b2020-11-02 11:05:09 +0100823 *
aPiecek874ea4d2021-04-19 12:26:36 +0200824 * @param[in] user_data is type of struct ly_out_clb_arg.
aPiecek61d062b2020-11-02 11:05:09 +0100825 * @param[in] buf contains input characters
826 * @param[in] count is number of characters in buf.
827 * @return Number of printed bytes.
828 * @return Negative value in case of error.
829 */
830static ssize_t
831trp_ly_out_clb_func(void *user_data, const void *buf, size_t count)
832{
833 LY_ERR erc = LY_SUCCESS;
834 struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data;
835
836 switch (data->mode) {
837 case TRD_PRINT:
838 erc = ly_write_(data->out, buf, count);
839 break;
840 case TRD_CHAR_COUNT:
841 data->counter = data->counter + count;
842 break;
843 default:
844 break;
845 }
846
847 if (erc != LY_SUCCESS) {
848 data->last_error = erc;
849 return -1;
850 } else {
851 return count;
852 }
853}
854
855/**
856 * @brief Check that indent in node can be considered as equivalent.
857 * @param[in] first is the first indent in node.
858 * @param[in] second is the second indent in node.
859 * @return 1 if indents are equivalent otherwise 0.
860 */
861static ly_bool
862trp_indent_in_node_are_eq(struct trt_indent_in_node first, struct trt_indent_in_node second)
863{
864 const ly_bool a = first.type == second.type;
865 const ly_bool b = first.btw_name_opts == second.btw_name_opts;
866 const ly_bool c = first.btw_opts_type == second.btw_opts_type;
867 const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures;
868
869 return a && b && c && d;
870}
871
872/**
aPiecek874ea4d2021-04-19 12:26:36 +0200873 * @brief Setting space character because node is last sibling.
874 * @param[in] wr is wrapper over which the shift operation
875 * is to be performed.
aPiecek61d062b2020-11-02 11:05:09 +0100876 * @return New shifted wrapper.
877 */
878static struct trt_wrapper
879trp_wrapper_set_shift(struct trt_wrapper wr)
880{
881 assert(wr.actual_pos < 64);
882 /* +--<node>
883 * +--<node>
884 */
885 wr.actual_pos++;
886 return wr;
887}
888
889/**
aPiecek874ea4d2021-04-19 12:26:36 +0200890 * @brief Setting '|' symbol because node is divided or
891 * it is not last sibling.
aPiecek61d062b2020-11-02 11:05:09 +0100892 * @param[in] wr is source of wrapper.
893 * @return New wrapper which is marked at actual position and shifted.
894 */
895static struct trt_wrapper
896trp_wrapper_set_mark(struct trt_wrapper wr)
897{
898 assert(wr.actual_pos < 64);
899 wr.bit_marks1 |= 1U << wr.actual_pos;
900 return trp_wrapper_set_shift(wr);
901}
902
903/**
904 * @brief Setting ' ' symbol if node is last sibling otherwise set '|'.
905 * @param[in] wr is actual wrapper.
aPiecek874ea4d2021-04-19 12:26:36 +0200906 * @param[in] last_one is flag. Value 1 saying if the node is the last
907 * and has no more siblings.
aPiecek61d062b2020-11-02 11:05:09 +0100908 * @return New wrapper for the actual node.
909 */
910static struct trt_wrapper
911trp_wrapper_if_last_sibling(struct trt_wrapper wr, ly_bool last_one)
912{
913 return last_one ? trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
914}
915
916/**
917 * @brief Test if the wrappers are equivalent.
918 * @param[in] first is the first wrapper.
919 * @param[in] second is the second wrapper.
920 * @return 1 if the wrappers are equivalent otherwise 0.
921 */
922static ly_bool
923trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second)
924{
925 const ly_bool a = first.type == second.type;
926 const ly_bool b = first.bit_marks1 == second.bit_marks1;
927 const ly_bool c = first.actual_pos == second.actual_pos;
928
929 return a && b && c;
930}
931
932/**
933 * @brief Print " | " sequence on line.
934 * @param[in] wr is wrapper to be printed.
935 * @param[in,out] out is output handler.
936 */
937static void
938trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out)
939{
940 uint32_t lb;
941
942 if (wr.type == TRD_WRAPPER_TOP) {
943 lb = TRD_INDENT_LINE_BEGIN;
944 } else if (wr.type == TRD_WRAPPER_BODY) {
945 lb = TRD_INDENT_LINE_BEGIN * 2;
946 } else {
947 lb = TRD_INDENT_LINE_BEGIN;
948 }
949
950 ly_print_(out, "%*c", lb, ' ');
951
952 if (trp_wrapper_eq(wr, TRP_INIT_WRAPPER_TOP)) {
953 return;
954 }
955
956 for (uint32_t i = 0; i < wr.actual_pos; i++) {
957 /** Test if the bit on the index is set. */
958 if ((wr.bit_marks1 >> i) & 1U) {
959 ly_print_(out, "|");
960 } else {
961 ly_print_(out, " ");
962 }
963
964 if (i != wr.actual_pos) {
965 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
966 }
967 }
968}
969
970/**
971 * @brief Check if struct trt_node is empty.
972 * @param[in] node is item to test.
973 * @return 1 if node is considered empty otherwise 0.
974 */
975static ly_bool
976trp_node_is_empty(struct trt_node node)
977{
978 const ly_bool a = !node.iffeatures;
979 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
980 const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node.name);
981 const ly_bool d = node.flags == TRD_FLAGS_TYPE_EMPTY;
982 const ly_bool e = node.status == TRD_STATUS_TYPE_EMPTY;
983
984 return a && b && c && d && e;
985}
986
987/**
aPiecek874ea4d2021-04-19 12:26:36 +0200988 * @brief Check if [\<keys\>], \<type\> and
989 * \<iffeatures\> are empty/not_set.
aPiecek61d062b2020-11-02 11:05:09 +0100990 * @param[in] node is item to test.
aPiecek874ea4d2021-04-19 12:26:36 +0200991 * @return 1 if node has no \<keys\> \<type\> or \<iffeatures\>
992 * otherwise 0.
aPiecek61d062b2020-11-02 11:05:09 +0100993 */
994static ly_bool
995trp_node_body_is_empty(struct trt_node node)
996{
997 const ly_bool a = !node.iffeatures;
998 const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
999 const ly_bool c = node.name.type != TRD_NODE_KEYS;
1000
1001 return a && b && c;
1002}
1003
1004/**
1005 * @brief Print \<status\> of the node.
1006 * @param[in] status_type is type of status.
1007 * @param[in,out] out is output handler.
1008 */
1009static void
1010trp_print_status(trt_status_type status_type, struct ly_out *out)
1011{
1012 switch (status_type) {
1013 case TRD_STATUS_TYPE_CURRENT:
1014 ly_print_(out, "%c", '+');
1015 break;
1016 case TRD_STATUS_TYPE_DEPRECATED:
1017 ly_print_(out, "%c", 'x');
1018 break;
1019 case TRD_STATUS_TYPE_OBSOLETE:
1020 ly_print_(out, "%c", 'o');
1021 break;
1022 default:
1023 break;
1024 }
1025}
1026
1027/**
1028 * @brief Print \<flags\>.
1029 * @param[in] flags_type is type of \<flags\>.
1030 * @param[in,out] out is output handler.
1031 */
1032static void
1033trp_print_flags(trt_flags_type flags_type, struct ly_out *out)
1034{
1035 switch (flags_type) {
1036 case TRD_FLAGS_TYPE_RW:
1037 ly_print_(out, "%s", "rw");
1038 break;
1039 case TRD_FLAGS_TYPE_RO:
1040 ly_print_(out, "%s", "ro");
1041 break;
1042 case TRD_FLAGS_TYPE_RPC_INPUT_PARAMS:
1043 ly_print_(out, "%s", "-w");
1044 break;
1045 case TRD_FLAGS_TYPE_USES_OF_GROUPING:
1046 ly_print_(out, "%s", "-u");
1047 break;
1048 case TRD_FLAGS_TYPE_RPC:
1049 ly_print_(out, "%s", "-x");
1050 break;
1051 case TRD_FLAGS_TYPE_NOTIF:
1052 ly_print_(out, "%s", "-n");
1053 break;
1054 case TRD_FLAGS_TYPE_MOUNT_POINT:
1055 ly_print_(out, "%s", "mp");
1056 break;
1057 default:
aPiecekdc8fd572021-04-19 10:47:23 +02001058 ly_print_(out, "%s", "--");
aPiecek61d062b2020-11-02 11:05:09 +01001059 break;
1060 }
1061}
1062
1063/**
1064 * @brief Get size of the \<flags\>.
1065 * @param[in] flags_type is type of \<flags\>.
1066 * @return 0 if flags_type is not set otherwise 2.
1067 */
1068static size_t
1069trp_get_flags_strlen(trt_flags_type flags_type)
1070{
1071 return flags_type == TRD_FLAGS_TYPE_EMPTY ? 0 : 2;
1072}
1073
1074/**
1075 * @brief Print entire struct trt_node_name structure.
1076 * @param[in] node_name is item to print.
1077 * @param[in,out] out is output handler.
1078 */
1079static void
1080trp_print_node_name(struct trt_node_name node_name, struct ly_out *out)
1081{
1082 const char *mod_prefix;
1083 const char *colon;
1084 const char trd_node_name_suffix_choice[] = ")";
1085 const char trd_node_name_suffix_case[] = ")";
1086 const char trd_opts_optional[] = "?"; /**< For an optional leaf, choice, anydata, or anyxml. */
1087 const char trd_opts_container[] = "!"; /**< For a presence container. */
1088 const char trd_opts_list[] = "*"; /**< For a leaf-list or list. */
1089 const char trd_opts_slash[] = "/"; /**< For a top-level data node in a mounted module. */
1090 const char trd_opts_at_sign[] = "@"; /**< For a top-level data node of a module identified in a mount point parent reference. */
1091
1092 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1093 return;
1094 }
1095
1096 if (node_name.module_prefix) {
1097 mod_prefix = node_name.module_prefix;
1098 colon = ":";
1099 } else {
1100 mod_prefix = "";
1101 colon = "";
1102 }
1103
1104 switch (node_name.type) {
1105 case TRD_NODE_ELSE:
1106 ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
1107 break;
1108 case TRD_NODE_CASE:
1109 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, trd_node_name_suffix_case);
1110 break;
1111 case TRD_NODE_CHOICE:
1112 ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice);
1113 break;
1114 case TRD_NODE_OPTIONAL_CHOICE:
1115 ly_print_(out, "%s%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice, trd_opts_optional);
1116 break;
1117 case TRD_NODE_OPTIONAL:
1118 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_optional);
1119 break;
1120 case TRD_NODE_CONTAINER:
1121 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_container);
1122 break;
1123 case TRD_NODE_LISTLEAFLIST:
1124 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1125 break;
1126 case TRD_NODE_KEYS:
1127 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1128 break;
1129 case TRD_NODE_TOP_LEVEL1:
1130 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_slash);
1131 break;
1132 case TRD_NODE_TOP_LEVEL2:
1133 ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_at_sign);
1134 break;
1135 case TRD_NODE_TRIPLE_DOT:
1136 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
1137 break;
1138 default:
1139 break;
1140 }
1141}
1142
1143/**
aPiecek874ea4d2021-04-19 12:26:36 +02001144 * @brief Check if mark (?, !, *, /, @) is implicitly contained in
1145 * struct trt_node_name.
aPiecek61d062b2020-11-02 11:05:09 +01001146 * @param[in] node_name is structure containing the 'mark'.
1147 * @return 1 if contain otherwise 0.
1148 */
1149static ly_bool
1150trp_mark_is_used(struct trt_node_name node_name)
1151{
1152 if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1153 return 0;
1154 }
1155
1156 switch (node_name.type) {
1157 case TRD_NODE_ELSE:
1158 case TRD_NODE_CASE:
1159 case TRD_NODE_KEYS:
1160 return 0;
1161 default:
1162 return 1;
1163 }
1164}
1165
1166/**
1167 * @brief Print opts keys.
1168 * @param[in] node_name contains type of the node with his name.
1169 * @param[in] btw_name_opts is number of spaces between name and [keys].
aPiecek874ea4d2021-04-19 12:26:36 +02001170 * @param[in] cf is basically a pointer to the function that prints
1171 * the keys.
aPiecek61d062b2020-11-02 11:05:09 +01001172 * @param[in,out] out is output handler.
1173 */
1174static void
1175trp_print_opts_keys(struct trt_node_name node_name, int16_t btw_name_opts, struct trt_cf_print cf, struct ly_out *out)
1176{
1177 if (node_name.type != TRD_NODE_KEYS) {
1178 return;
1179 }
1180
1181 /* <name><mark>___<keys>*/
1182 if (btw_name_opts > 0) {
1183 ly_print_(out, "%*c", btw_name_opts, ' ');
1184 }
1185 ly_print_(out, "[");
1186 cf.pf(cf.ctx, out);
1187 ly_print_(out, "]");
1188}
1189
1190/**
1191 * @brief Print entire struct trt_type structure.
1192 * @param[in] type is item to print.
1193 * @param[in,out] out is output handler.
1194 */
1195static void
1196trp_print_type(struct trt_type type, struct ly_out *out)
1197{
1198 if (TRP_TRT_TYPE_IS_EMPTY(type)) {
1199 return;
1200 }
1201
1202 switch (type.type) {
1203 case TRD_TYPE_NAME:
1204 ly_print_(out, "%s", type.str);
1205 break;
1206 case TRD_TYPE_TARGET:
1207 ly_print_(out, "-> %s", type.str);
1208 break;
1209 case TRD_TYPE_LEAFREF:
1210 ly_print_(out, "leafref");
1211 default:
1212 break;
1213 }
1214}
1215
1216/**
1217 * @brief Print all iffeatures of node
1218 *
1219 * @param[in] iffeature_flag contains if if-features is present.
aPiecek874ea4d2021-04-19 12:26:36 +02001220 * @param[in] cf is basically a pointer to the function that prints
1221 * the list of features.
aPiecek61d062b2020-11-02 11:05:09 +01001222 * @param[in,out] out is output handler.
1223 */
1224static void
1225trp_print_iffeatures(ly_bool iffeature_flag, struct trt_cf_print cf, struct ly_out *out)
1226{
1227 if (iffeature_flag) {
1228 ly_print_(out, "{");
1229 cf.pf(cf.ctx, out);
1230 ly_print_(out, "}?");
1231 }
1232}
1233
1234/**
1235 * @brief Print just \<status\>--\<flags\> \<name\> with opts mark.
1236 * @param[in] node contains items to print.
1237 * @param[in] out is output handler.
1238 */
1239static void
1240trp_print_node_up_to_name(struct trt_node node, struct ly_out *out)
1241{
1242 if (node.name.type == TRD_NODE_TRIPLE_DOT) {
1243 trp_print_node_name(node.name, out);
1244 return;
1245 }
1246 /* <status>--<flags> */
1247 trp_print_status(node.status, out);
1248 ly_print_(out, "--");
aPiecek874ea4d2021-04-19 12:26:36 +02001249 /* If the node is a case node, there is no space before the <name>
1250 * also case node has no flags.
1251 */
aPiecek61d062b2020-11-02 11:05:09 +01001252 if (node.name.type != TRD_NODE_CASE) {
1253 trp_print_flags(node.flags, out);
1254 ly_print_(out, " ");
1255 }
1256 /* <name> */
1257 trp_print_node_name(node.name, out);
1258}
1259
1260/**
aPiecek874ea4d2021-04-19 12:26:36 +02001261 * @brief Print alignment (spaces) instead of
1262 * \<status\>--\<flags\> \<name\> for divided node.
aPiecek61d062b2020-11-02 11:05:09 +01001263 * @param[in] node contains items to print.
1264 * @param[in] out is output handler.
1265 */
1266static void
1267trp_print_divided_node_up_to_name(struct trt_node node, struct ly_out *out)
1268{
1269 uint32_t space = trp_get_flags_strlen(node.flags);
1270
1271 if (node.name.type == TRD_NODE_CASE) {
1272 /* :(<name> */
1273 space += strlen(TRD_NODE_NAME_PREFIX_CASE);
1274 } else if (node.name.type == TRD_NODE_CHOICE) {
1275 /* (<name> */
1276 space += strlen(TRD_NODE_NAME_PREFIX_CHOICE);
1277 } else {
1278 /* _<name> */
1279 space += strlen(" ");
1280 }
1281
1282 /* <name>
1283 * __
1284 */
1285 space += TRD_INDENT_LONG_LINE_BREAK;
1286
1287 ly_print_(out, "%*c", space, ' ');
1288}
1289
1290/**
1291 * @brief Print struct trt_node structure.
1292 * @param[in] node is item to print.
aPiecek874ea4d2021-04-19 12:26:36 +02001293 * @param[in] pck package of functions for
1294 * printing [\<keys\>] and \<iffeatures\>.
aPiecek61d062b2020-11-02 11:05:09 +01001295 * @param[in] indent is the indent in node.
1296 * @param[in,out] out is output handler.
1297 */
1298static void
1299trp_print_node(struct trt_node node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out)
1300{
1301 ly_bool triple_dot;
1302 ly_bool divided;
1303 struct trt_cf_print cf_print_keys;
1304 struct trt_cf_print cf_print_iffeatures;
1305
1306 if (trp_node_is_empty(node)) {
1307 return;
1308 }
1309
1310 /* <status>--<flags> <name><opts> <type> <if-features> */
1311 triple_dot = node.name.type == TRD_NODE_TRIPLE_DOT;
1312 divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED;
1313
1314 if (triple_dot) {
1315 trp_print_node_name(node.name, out);
1316 return;
1317 } else if (!divided) {
1318 trp_print_node_up_to_name(node, out);
1319 } else {
1320 trp_print_divided_node_up_to_name(node, out);
1321 }
1322
1323 /* <opts> */
1324 /* <name>___<opts>*/
1325 cf_print_keys.ctx = pck.tree_ctx;
1326 cf_print_keys.pf = pck.fps.print_keys;
1327
1328 trp_print_opts_keys(node.name, indent.btw_name_opts, cf_print_keys, out);
1329
1330 /* <opts>__<type> */
1331 if (indent.btw_opts_type > 0) {
1332 ly_print_(out, "%*c", indent.btw_opts_type, ' ');
1333 }
1334
1335 /* <type> */
1336 trp_print_type(node.type, out);
1337
1338 /* <type>__<iffeatures> */
1339 if (indent.btw_type_iffeatures > 0) {
1340 ly_print_(out, "%*c", indent.btw_type_iffeatures, ' ');
1341 }
1342
1343 /* <iffeatures> */
1344 cf_print_iffeatures.ctx = pck.tree_ctx;
1345 cf_print_iffeatures.pf = pck.fps.print_features_names;
1346
1347 trp_print_iffeatures(node.iffeatures, cf_print_iffeatures, out);
1348}
1349
1350/**
aPiecek874ea4d2021-04-19 12:26:36 +02001351 * @brief Print keyword based on trt_keyword_stmt.type.
aPiecek61d062b2020-11-02 11:05:09 +01001352 * @param[in] ks is keyword statement to print.
1353 * @param[in,out] out is output handler
1354 */
1355static void
1356trt_print_keyword_stmt_begin(struct trt_keyword_stmt ks, struct ly_out *out)
1357{
1358 switch (ks.type) {
1359 case TRD_KEYWORD_MODULE:
1360 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_MODULE);
1361 return;
1362 case TRD_KEYWORD_SUBMODULE:
1363 ly_print_(out, "%s: ", TRD_TOP_KEYWORD_SUBMODULE);
1364 return;
1365 default:
1366 ly_print_(out, "%*c", TRD_INDENT_LINE_BEGIN, ' ');
1367 switch (ks.type) {
1368 case TRD_KEYWORD_AUGMENT:
1369 ly_print_(out, "%s ", TRD_BODY_KEYWORD_AUGMENT);
1370 break;
1371 case TRD_KEYWORD_RPC:
1372 ly_print_(out, "%s", TRD_BODY_KEYWORD_RPC);
1373 break;
1374 case TRD_KEYWORD_NOTIF:
1375 ly_print_(out, "%s", TRD_BODY_KEYWORD_NOTIF);
1376 break;
1377 case TRD_KEYWORD_GROUPING:
1378 ly_print_(out, "%s ", TRD_BODY_KEYWORD_GROUPING);
1379 break;
1380 case TRD_KEYWORD_YANG_DATA:
1381 ly_print_(out, "%s ", TRD_BODY_KEYWORD_YANG_DATA);
1382 break;
1383 default:
1384 break;
1385 }
1386 break;
1387 }
1388}
1389
1390/**
1391 * @brief Get string length of stored keyword.
1392 * @param[in] type is type of the keyword statement.
1393 * @return length of the keyword statement name.
1394 */
1395static size_t
1396trp_keyword_type_strlen(trt_keyword_type type)
1397{
1398 switch (type) {
1399 case TRD_KEYWORD_MODULE:
1400 return sizeof(TRD_TOP_KEYWORD_MODULE) - 1;
1401 case TRD_KEYWORD_SUBMODULE:
1402 return sizeof(TRD_TOP_KEYWORD_SUBMODULE) - 1;
1403 case TRD_KEYWORD_AUGMENT:
1404 return sizeof(TRD_BODY_KEYWORD_AUGMENT) - 1;
1405 case TRD_KEYWORD_RPC:
1406 return sizeof(TRD_BODY_KEYWORD_RPC) - 1;
1407 case TRD_KEYWORD_NOTIF:
1408 return sizeof(TRD_BODY_KEYWORD_NOTIF) - 1;
1409 case TRD_KEYWORD_GROUPING:
1410 return sizeof(TRD_BODY_KEYWORD_GROUPING) - 1;
1411 case TRD_KEYWORD_YANG_DATA:
1412 return sizeof(TRD_BODY_KEYWORD_YANG_DATA) - 1;
1413 default:
1414 return 0;
1415 }
1416}
1417
1418/**
aPiecek874ea4d2021-04-19 12:26:36 +02001419 * @brief Print trt_keyword_stmt.str which is string of name or path.
aPiecek61d062b2020-11-02 11:05:09 +01001420 * @param[in] ks is keyword statement structure.
1421 * @param[in] mll is max line length.
1422 * @param[in,out] out is output handler.
1423 */
1424static void
1425trt_print_keyword_stmt_str(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
1426{
1427 uint32_t ind_initial;
1428 uint32_t ind_divided;
1429 /* flag if path must be splitted to more lines */
1430 ly_bool linebreak_was_set;
1431 /* flag if at least one subpath was printed */
1432 ly_bool subpath_printed;
1433 /* the sum of the sizes of the substrings on the current line */
1434 uint32_t how_far;
1435 /* pointer to start of the subpath */
1436 const char *sub_ptr;
1437 /* size of subpath from sub_ptr */
1438 size_t sub_len;
1439
1440 if ((!ks.str) || (ks.str[0] == '\0')) {
1441 return;
1442 }
1443
1444 /* module name cannot be splitted */
1445 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
1446 ly_print_(out, "%s", ks.str);
1447 return;
1448 }
1449
1450 /* after -> for trd_keyword_stmt_body do */
1451
1452 /* set begin indentation */
1453 ind_initial = TRD_INDENT_LINE_BEGIN + trp_keyword_type_strlen(ks.type) + 1;
1454 ind_divided = ind_initial + TRD_INDENT_LONG_LINE_BREAK;
1455 linebreak_was_set = 0;
1456 subpath_printed = 0;
1457 how_far = 0;
1458 sub_ptr = ks.str;
1459 sub_len = 0;
1460
1461 while (sub_ptr[0] != '\0') {
1462 uint32_t ind;
1463 /* skip slash */
1464 const char *tmp = sub_ptr[0] == '/' ? sub_ptr + 1 : sub_ptr;
1465 /* get position of the end of substr */
1466 tmp = strchr(tmp, '/');
1467 /* set correct size if this is a last substring */
1468 sub_len = !tmp ? strlen(sub_ptr) : (size_t)(tmp - sub_ptr);
1469 /* actualize sum of the substring's sizes on the current line */
1470 how_far += sub_len;
1471 /* correction due to colon character if it this is last substring */
1472 how_far = *(sub_ptr + sub_len) == '\0' ? how_far + 1 : how_far;
1473 /* choose indentation which depends on
1474 * whether the string is printed on multiple lines or not
1475 */
1476 ind = linebreak_was_set ? ind_divided : ind_initial;
1477 if (ind + how_far <= mll) {
1478 /* printing before max line length */
1479 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1480 subpath_printed = 1;
1481 } else {
1482 /* printing on new line */
1483 if (subpath_printed == 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001484 /* first subpath is too long
1485 * but print it at first line anyway
1486 */
aPiecek61d062b2020-11-02 11:05:09 +01001487 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1488 subpath_printed = 1;
1489 continue;
1490 }
1491 ly_print_(out, "\n");
1492 ly_print_(out, "%*c", ind_divided, ' ');
1493 linebreak_was_set = 1;
1494 sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1495 how_far = sub_len;
1496 subpath_printed = 1;
1497 }
1498 }
1499}
1500
1501/**
aPiecek874ea4d2021-04-19 12:26:36 +02001502 * @brief Print separator based on trt_keyword_stmt.type
aPiecek61d062b2020-11-02 11:05:09 +01001503 * @param[in] ks is keyword statement structure.
aPiecekdc8fd572021-04-19 10:47:23 +02001504 * @param[in] grp_has_data is flag only for grouping section.
1505 * Set to 1 if grouping section has some nodes.
1506 * Set to 0 if it doesn't have nodes or it's not grouping section.
aPiecek61d062b2020-11-02 11:05:09 +01001507 * @param[in,out] out is output handler.
1508 */
1509static void
aPiecekdc8fd572021-04-19 10:47:23 +02001510trt_print_keyword_stmt_end(struct trt_keyword_stmt ks, ly_bool grp_has_data, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001511{
1512 if ((ks.type != TRD_KEYWORD_MODULE) && (ks.type != TRD_KEYWORD_SUBMODULE)) {
aPiecekdc8fd572021-04-19 10:47:23 +02001513 if ((ks.type == TRD_KEYWORD_GROUPING) && !grp_has_data) {
1514 return;
1515 } else {
1516 ly_print_(out, ":");
1517 }
aPiecek61d062b2020-11-02 11:05:09 +01001518 }
1519}
1520
1521/**
1522 * @brief Print entire struct trt_keyword_stmt structure.
1523 * @param[in] ks is item to print.
1524 * @param[in] mll is max line length.
aPiecekdc8fd572021-04-19 10:47:23 +02001525 * @param[in] grp_has_data is flag only for grouping section.
1526 * Set to 1 if grouping section has some nodes.
1527 * Set to 0 if it doesn't have nodes or it's not grouping section.
aPiecek61d062b2020-11-02 11:05:09 +01001528 * @param[in,out] out is output handler.
1529 */
1530static void
aPiecek874ea4d2021-04-19 12:26:36 +02001531trp_print_keyword_stmt(struct trt_keyword_stmt ks, size_t mll, ly_bool grp_has_data, struct ly_out *out)
aPiecek61d062b2020-11-02 11:05:09 +01001532{
1533 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
1534 return;
1535 }
1536 trt_print_keyword_stmt_begin(ks, out);
1537 trt_print_keyword_stmt_str(ks, mll, out);
aPiecekdc8fd572021-04-19 10:47:23 +02001538 trt_print_keyword_stmt_end(ks, grp_has_data, out);
aPiecek61d062b2020-11-02 11:05:09 +01001539}
1540
aPiecek874ea4d2021-04-19 12:26:36 +02001541/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01001542 * Main trp functions
aPiecek874ea4d2021-04-19 12:26:36 +02001543 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01001544
1545/**
aPiecek874ea4d2021-04-19 12:26:36 +02001546 * @brief Printing one line including wrapper and node
1547 * which can be incomplete (divided).
aPiecek61d062b2020-11-02 11:05:09 +01001548 * @param[in] node is \<node\> representation.
1549 * @param[in] pck contains special printing functions callback.
1550 * @param[in] indent contains wrapper and indent in node numbers.
1551 * @param[in,out] out is output handler.
1552 */
1553static void
1554trp_print_line(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out)
1555{
1556 trp_print_wrapper(indent.wrapper, out);
1557 trp_print_node(node, pck, indent.in_node, out);
1558}
1559
1560/**
aPiecek874ea4d2021-04-19 12:26:36 +02001561 * @brief Printing one line including wrapper and
1562 * \<status\>--\<flags\> \<name\>\<option_mark\>.
aPiecek61d062b2020-11-02 11:05:09 +01001563 * @param[in] node is \<node\> representation.
1564 * @param[in] wr is wrapper for printing indentation before node.
1565 * @param[in] out is output handler.
1566 */
1567static void
1568trp_print_line_up_to_node_name(struct trt_node node, struct trt_wrapper wr, struct ly_out *out)
1569{
1570 trp_print_wrapper(wr, out);
1571 trp_print_node_up_to_name(node, out);
1572}
1573
1574/**
aPiecek874ea4d2021-04-19 12:26:36 +02001575 * @brief Check if leafref target must be change to string 'leafref'
1576 * because his target string is too long.
aPiecek61d062b2020-11-02 11:05:09 +01001577 * @param[in] node containing leafref target.
1578 * @param[in] wr is wrapper for printing indentation before node.
1579 * @param[in] mll is max line length.
1580 * @param[in] out is output handler.
1581 * @return true if leafref must be changed to string 'leafref'.
1582 */
1583static ly_bool
1584trp_leafref_target_is_too_long(struct trt_node node, struct trt_wrapper wr, size_t mll, struct ly_out *out)
1585{
1586 struct ly_out_clb_arg *data;
1587
1588 if (node.type.type != TRD_TYPE_TARGET) {
1589 return 0;
1590 }
1591
1592 /* set ly_out to counting characters */
1593 data = out->method.clb.arg;
1594
1595 data->counter = 0;
1596 data->mode = TRD_CHAR_COUNT;
1597 /* count number of printed bytes */
1598 trp_print_wrapper(wr, out);
1599 ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1600 trp_print_divided_node_up_to_name(node, out);
1601 data->mode = TRD_PRINT;
1602
1603 return data->counter + strlen(node.type.str) > mll;
1604}
1605
1606/**
1607 * @brief Get default indent in node based on node values.
1608 * @param[in] node is \<node\> representation.
aPiecek874ea4d2021-04-19 12:26:36 +02001609 * @return Default indent in node assuming that the node
1610 * will not be divided.
aPiecek61d062b2020-11-02 11:05:09 +01001611 */
1612static struct trt_indent_in_node
1613trp_default_indent_in_node(struct trt_node node)
1614{
1615 struct trt_indent_in_node ret;
1616
1617 ret.type = TRD_INDENT_IN_NODE_NORMAL;
1618
1619 /* btw_name_opts */
1620 ret.btw_name_opts = node.name.type == TRD_NODE_KEYS ? TRD_INDENT_BEFORE_KEYS : 0;
1621
1622 /* btw_opts_type */
1623 if (!(TRP_TRT_TYPE_IS_EMPTY(node.type))) {
1624 ret.btw_opts_type = trp_mark_is_used(node.name) ?
1625 TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
1626 TRD_INDENT_BEFORE_TYPE;
1627 } else {
1628 ret.btw_opts_type = 0;
1629 }
1630
1631 /* btw_type_iffeatures */
1632 ret.btw_type_iffeatures = node.iffeatures ? TRD_INDENT_BEFORE_IFFEATURES : 0;
1633
1634 return ret;
1635}
1636
1637/**
1638 * @brief Setting linebreaks in trt_indent_in_node.
1639 *
1640 * The order where the linebreak tag can be placed is from the end.
1641 *
aPiecek874ea4d2021-04-19 12:26:36 +02001642 * @param[in] indent containing alignment lengths
1643 * or already linebreak marks.
aPiecek61d062b2020-11-02 11:05:09 +01001644 * @return indent with a newly placed linebreak tag.
aPiecek874ea4d2021-04-19 12:26:36 +02001645 * @return .type set to TRD_INDENT_IN_NODE_FAILED if it is not possible
1646 * to place a more linebreaks.
aPiecek61d062b2020-11-02 11:05:09 +01001647 */
1648static struct trt_indent_in_node
1649trp_indent_in_node_place_break(struct trt_indent_in_node indent)
1650{
1651 /* somewhere must be set a line break in node */
1652 struct trt_indent_in_node ret = indent;
1653
1654 /* gradually break the node from the end */
1655 if ((indent.btw_type_iffeatures != TRD_LINEBREAK) && (indent.btw_type_iffeatures != 0)) {
1656 ret.btw_type_iffeatures = TRD_LINEBREAK;
1657 } else if ((indent.btw_opts_type != TRD_LINEBREAK) && (indent.btw_opts_type != 0)) {
1658 ret.btw_opts_type = TRD_LINEBREAK;
1659 } else if ((indent.btw_name_opts != TRD_LINEBREAK) && (indent.btw_name_opts != 0)) {
1660 /* set line break between name and opts */
1661 ret.btw_name_opts = TRD_LINEBREAK;
1662 } else {
1663 /* it is not possible to place a more line breaks,
1664 * unfortunately the max_line_length constraint is violated
1665 */
1666 ret.type = TRD_INDENT_IN_NODE_FAILED;
1667 }
1668 return ret;
1669}
1670
1671/**
1672 * @brief Get the first half of the node based on the linebreak mark.
1673 *
1674 * Items in the second half of the node will be empty.
1675 *
1676 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001677 * @param[in] indent contains information in which part of the \<node\>
1678 * the first half ends.
aPiecek61d062b2020-11-02 11:05:09 +01001679 * @return first half of the node, indent is unchanged.
1680 */
1681static struct trt_pair_indent_node
1682trp_first_half_node(struct trt_node node, struct trt_indent_in_node indent)
1683{
1684 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1685
1686 if (indent.btw_name_opts == TRD_LINEBREAK) {
1687 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1688 ret.node.type = TRP_EMPTY_TRT_TYPE;
1689 ret.node.iffeatures = 0;
1690 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1691 ret.node.type = TRP_EMPTY_TRT_TYPE;
1692 ret.node.iffeatures = 0;
1693 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1694 ret.node.iffeatures = 0;
1695 }
1696
1697 return ret;
1698}
1699
1700/**
1701 * @brief Get the second half of the node based on the linebreak mark.
1702 *
1703 * Items in the first half of the node will be empty.
1704 * Indentations belonging to the first node will be reset to zero.
1705 *
1706 * @param[in] node the whole \<node\> to be split.
aPiecek874ea4d2021-04-19 12:26:36 +02001707 * @param[in] indent contains information in which part of the \<node\>
1708 * the second half starts.
aPiecek61d062b2020-11-02 11:05:09 +01001709 * @return second half of the node, indent is newly set.
1710 */
1711static struct trt_pair_indent_node
1712trp_second_half_node(struct trt_node node, struct trt_indent_in_node indent)
1713{
1714 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1715
1716 if (indent.btw_name_opts < 0) {
aPiecek874ea4d2021-04-19 12:26:36 +02001717 /* Logically, the information up to token <opts> should
1718 * be deleted, but the the trp_print_node function needs it to
1719 * create the correct indent.
aPiecek61d062b2020-11-02 11:05:09 +01001720 */
1721 ret.indent.btw_name_opts = 0;
1722 ret.indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(node.type) ? 0 : TRD_INDENT_BEFORE_TYPE;
1723 ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1724 } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1725 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1726 ret.indent.btw_name_opts = 0;
1727 ret.indent.btw_opts_type = 0;
1728 ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1729 } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1730 ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1731 ret.node.type = TRP_EMPTY_TRT_TYPE;
1732 ret.indent.btw_name_opts = 0;
1733 ret.indent.btw_opts_type = 0;
1734 ret.indent.btw_type_iffeatures = 0;
1735 }
1736 return ret;
1737}
1738
1739/**
1740 * @brief Get the correct alignment for the node.
1741 *
aPiecek874ea4d2021-04-19 12:26:36 +02001742 * This function is recursively called itself. It's like a backend
aPiecek01598c02021-04-23 14:18:24 +02001743 * function for a function ::trp_try_normal_indent_in_node().
aPiecek61d062b2020-11-02 11:05:09 +01001744 *
1745 * @param[in] node is \<node\> representation.
1746 * @param[in] pck contains speciall callback functions for printing.
1747 * @param[in] indent contains wrapper and indent in node numbers.
1748 * @param[in] mll is max line length.
1749 * @param[in,out] cnt counting number of characters to print.
1750 * @param[in,out] out is output handler.
1751 * @return pair of node and indentation numbers of that node.
1752 */
1753static struct trt_pair_indent_node
1754trp_try_normal_indent_in_node_(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, size_t mll, size_t *cnt, struct ly_out *out)
1755{
1756 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1757
1758 trp_print_line(node, pck, indent, out);
1759
1760 if (*cnt <= mll) {
1761 /* success */
1762 return ret;
1763 } else {
1764 ret.indent = trp_indent_in_node_place_break(ret.indent);
1765 if (ret.indent.type != TRD_INDENT_IN_NODE_FAILED) {
1766 /* erase information in node due to line break */
1767 ret = trp_first_half_node(node, ret.indent);
1768 /* check if line fits, recursive call */
1769 *cnt = 0;
1770 ret = trp_try_normal_indent_in_node_(ret.node, pck, TRP_INIT_PCK_INDENT(indent.wrapper, ret.indent), mll, cnt, out);
1771 /* make sure that the result will be with the status divided
1772 * or eventually with status failed */
1773 ret.indent.type = ret.indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED;
1774 }
1775 return ret;
1776 }
1777}
1778
1779/**
1780 * @brief Get the correct alignment for the node.
1781 *
1782 * @param[in] node is \<node\> representation.
1783 * @param[in] pck contains speciall callback functions for printing.
1784 * @param[in] indent contains wrapper and indent in node numbers.
1785 * @param[in] mll is max line length.
1786 * @param[in,out] out is output handler.
aPiecek874ea4d2021-04-19 12:26:36 +02001787 * @return ::TRD_INDENT_IN_NODE_DIVIDED - the node does not fit in the
1788 * line, some indent variable has negative value as a line break sign.
1789 * @return ::TRD_INDENT_IN_NODE_NORMAL - the node fits into the line,
1790 * all indent variables values has non-negative number.
1791 * @return ::TRD_INDENT_IN_NODE_FAILED - the node does not fit into the
1792 * line, all indent variables has negative or zero values,
1793 * function failed.
aPiecek61d062b2020-11-02 11:05:09 +01001794 */
1795static struct trt_pair_indent_node
1796trp_try_normal_indent_in_node(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, size_t mll, struct ly_out *out)
1797{
1798 struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1799 struct ly_out_clb_arg *data;
1800
1801 /* set ly_out to counting characters */
1802 data = out->method.clb.arg;
1803
1804 data->counter = 0;
1805 data->mode = TRD_CHAR_COUNT;
1806 ret = trp_try_normal_indent_in_node_(node, pck, indent, mll, &data->counter, out);
1807 data->mode = TRD_PRINT;
1808
1809 return ret;
1810}
1811
1812/**
aPiecek01598c02021-04-23 14:18:24 +02001813 * @brief Auxiliary function for ::trp_print_entire_node()
aPiecek874ea4d2021-04-19 12:26:36 +02001814 * that prints split nodes.
aPiecek61d062b2020-11-02 11:05:09 +01001815 * @param[in] node is node representation.
1816 * @param[in] ppck contains speciall callback functions for printing.
1817 * @param[in] ipck contains wrapper and indent in node numbers.
1818 * @param[in] mll is max line length.
1819 * @param[in,out] out is output handler.
1820 */
1821static void
1822trp_print_divided_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1823{
1824 ly_bool entire_node_was_printed;
1825 struct trt_pair_indent_node ind_node = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1826
1827 if (ind_node.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1828 /* nothing can be done, continue as usual */
1829 ind_node.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1830 }
1831
1832 trp_print_line(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), out);
1833 entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, ind_node.indent);
1834
1835 if (!entire_node_was_printed) {
1836 ly_print_(out, "\n");
1837 /* continue with second half node */
1838 ind_node = trp_second_half_node(node, ind_node.indent);
1839 /* continue with printing node */
1840 trp_print_divided_node(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), mll, out);
1841 } else {
1842 return;
1843 }
1844}
1845
1846/**
aPiecek874ea4d2021-04-19 12:26:36 +02001847 * @brief Printing of the wrapper and the whole node,
1848 * which can be divided into several lines.
aPiecek61d062b2020-11-02 11:05:09 +01001849 * @param[in] node is node representation.
1850 * @param[in] ppck contains speciall callback functions for printing.
1851 * @param[in] ipck contains wrapper and indent in node numbers.
1852 * @param[in] mll is max line length.
1853 * @param[in,out] out is output handler.
1854 */
1855static void
1856trp_print_entire_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1857{
1858 struct trt_pair_indent_node ind_node1;
1859 struct trt_pair_indent_node ind_node2;
1860 struct trt_pck_indent tmp;
1861
1862 if (trp_leafref_target_is_too_long(node, ipck.wrapper, mll, out)) {
1863 node.type.type = TRD_TYPE_LEAFREF;
1864 }
1865
1866 /* check if normal indent is possible */
1867 ind_node1 = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1868
1869 if (ind_node1.indent.type == TRD_INDENT_IN_NODE_NORMAL) {
1870 /* node fits to one line */
1871 trp_print_line(node, ppck, ipck, out);
1872 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_DIVIDED) {
1873 /* node will be divided */
1874 /* print first half */
1875 tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node1.indent);
1876 /* pretend that this is normal node */
1877 tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL;
1878
1879 trp_print_line(ind_node1.node, ppck, tmp, out);
1880 ly_print_(out, "\n");
1881
1882 /* continue with second half on new line */
1883 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1884 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1885
1886 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1887 } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1888 /* node name is too long */
1889 trp_print_line_up_to_node_name(node, ipck.wrapper, out);
1890
1891 if (trp_node_body_is_empty(node)) {
1892 return;
1893 } else {
1894 ly_print_(out, "\n");
1895
1896 ind_node2 = trp_second_half_node(node, ind_node1.indent);
1897 ind_node2.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1898 tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1899
1900 trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1901 }
1902
1903 }
1904}
1905
aPiecek874ea4d2021-04-19 12:26:36 +02001906/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02001907 * trop and troc getters
aPiecekef1e58e2021-04-19 13:19:44 +02001908 *********************************************************************/
1909
1910/**
1911 * @brief Get nodetype.
1912 * @param[in] node is any lysp_node.
1913 */
1914static uint16_t
1915trop_nodetype(const void *node)
1916{
1917 return ((const struct lysp_node *)node)->nodetype;
1918}
1919
1920/**
1921 * @brief Get sibling.
1922 * @param[in] node is any lysp_node.
1923 */
1924static const void *
1925trop_next(const void *node)
1926{
1927 return ((const struct lysp_node *)node)->next;
1928}
1929
1930/**
1931 * @brief Get parent.
1932 * @param[in] node is any lysp_node.
1933 */
1934static const void *
1935trop_parent(const void *node)
1936{
1937 return ((const struct lysp_node *)node)->parent;
1938}
1939
1940/**
1941 * @brief Try to get child.
1942 * @param[in] node is any lysp_node.
1943 */
1944static const void *
1945trop_child(const void *node)
1946{
1947 return lysp_node_child(node);
1948}
1949
1950/**
1951 * @brief Try to get action.
1952 * @param[in] node is any lysp_node.
1953 */
1954static const void *
1955trop_actions(const void *node)
1956{
1957 return lysp_node_actions(node);
1958}
1959
1960/**
1961 * @brief Try to get action.
1962 * @param[in] node must be of type lysp_node_action.
1963 */
1964static const void *
1965trop_action_input(const void *node)
1966{
1967 return &((const struct lysp_node_action *)node)->input;
1968}
1969
1970/**
1971 * @brief Try to get action.
1972 * @param[in] node must be of type lysp_node_action.
1973 */
1974static const void *
1975trop_action_output(const void *node)
1976{
1977 return &((const struct lysp_node_action *)node)->output;
1978}
1979
1980/**
1981 * @brief Try to get action.
1982 * @param[in] node is any lysp_node.
1983 */
1984static const void *
1985trop_notifs(const void *node)
1986{
1987 return lysp_node_notifs(node);
1988}
1989
1990/**
aPiecek01598c02021-04-23 14:18:24 +02001991 * @brief Fill struct tro_getters with @ref TRP_trop getters
aPiecekef1e58e2021-04-19 13:19:44 +02001992 * which are adapted to lysp nodes.
1993 */
1994static struct tro_getters
1995trop_init_getters()
1996{
1997 return (struct tro_getters) {
1998 .nodetype = trop_nodetype,
1999 .next = trop_next,
2000 .parent = trop_parent,
2001 .child = trop_child,
2002 .actions = trop_actions,
2003 .action_input = trop_action_input,
2004 .action_output = trop_action_output,
2005 .notifs = trop_notifs
2006 };
2007}
2008
aPiecek3f247652021-04-19 13:40:25 +02002009/**
2010 * @brief Get nodetype.
2011 * @param[in] node is any lysc_node.
2012 */
2013static uint16_t
2014troc_nodetype(const void *node)
2015{
2016 return ((const struct lysc_node *)node)->nodetype;
2017}
2018
2019/**
2020 * @brief Get sibling.
2021 * @param[in] node is any lysc_node.
2022 */
2023static const void *
2024troc_next(const void *node)
2025{
2026 return ((const struct lysc_node *)node)->next;
2027}
2028
2029/**
2030 * @brief Get parent.
2031 * @param[in] node is any lysc_node.
2032 */
2033static const void *
2034troc_parent(const void *node)
2035{
2036 return ((const struct lysc_node *)node)->parent;
2037}
2038
2039/**
2040 * @brief Try to get child.
2041 * @param[in] node is any lysc_node.
2042 */
2043static const void *
2044troc_child(const void *node)
2045{
2046 return lysc_node_child(node);
2047}
2048
2049/**
2050 * @brief Try to get action.
2051 * @param[in] node is any lysc_node.
2052 */
2053static const void *
2054troc_actions(const void *node)
2055{
2056 return lysc_node_actions(node);
2057}
2058
2059/**
2060 * @brief Try to get action.
2061 * @param[in] node must be of type lysc_node_action.
2062 */
2063static const void *
2064troc_action_input(const void *node)
2065{
2066 return &((const struct lysc_node_action *)node)->input;
2067}
2068
2069/**
2070 * @brief Try to get action.
2071 * @param[in] node must be of type lysc_node_action.
2072 */
2073static const void *
2074troc_action_output(const void *node)
2075{
2076 return &((const struct lysc_node_action *)node)->output;
2077}
2078
2079/**
2080 * @brief Try to get action.
2081 * @param[in] node is any lysc_node.
2082 */
2083static const void *
2084troc_notifs(const void *node)
2085{
2086 return lysc_node_notifs(node);
2087}
2088
2089/**
aPiecek01598c02021-04-23 14:18:24 +02002090 * @brief Fill struct tro_getters with @ref TRP_troc getters
aPiecek3f247652021-04-19 13:40:25 +02002091 * which are adapted to lysc nodes.
2092 */
2093static struct tro_getters
2094troc_init_getters()
2095{
2096 return (struct tro_getters) {
2097 .nodetype = troc_nodetype,
2098 .next = troc_next,
2099 .parent = troc_parent,
2100 .child = troc_child,
2101 .actions = troc_actions,
2102 .action_input = troc_action_input,
2103 .action_output = troc_action_output,
2104 .notifs = troc_notifs
2105 };
2106}
2107
aPiecekef1e58e2021-04-19 13:19:44 +02002108/**********************************************************************
2109 * tro functions
2110 *********************************************************************/
2111
2112/**
2113 * @brief Get next sibling of the current node.
aPiecek3f247652021-04-19 13:40:25 +02002114 *
2115 * This is a general algorithm that is able to
2116 * work with lysp_node or lysc_node.
2117 *
2118 * @param[in] node points to lysp_node or lysc_node.
2119 * @param[in] lysc_tree flag to determine what type the @p node is.
2120 * If set to true, then @p points to lysc_node otherwise lysp_node.
2121 * This flag should be the same as trt_tree_ctx.lysc_tree.
aPiecekef1e58e2021-04-19 13:19:44 +02002122 */
2123static const void *
aPiecek3f247652021-04-19 13:40:25 +02002124tro_next_sibling(const void *node, ly_bool lysc_tree)
aPiecekef1e58e2021-04-19 13:19:44 +02002125{
2126 struct tro_getters get;
2127 const void *tmp, *parent;
2128 const void *ret;
2129
2130 assert(node);
2131
aPiecek3f247652021-04-19 13:40:25 +02002132 get = lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002133
2134 if (get.nodetype(node) & (LYS_RPC | LYS_ACTION)) {
2135 if ((tmp = get.next(node))) {
2136 /* next action exists */
2137 ret = tmp;
2138 } else if ((parent = get.parent(node))) {
2139 /* maybe if notif exists as sibling */
2140 ret = get.notifs(parent);
2141 } else {
2142 ret = NULL;
2143 }
2144 } else if (get.nodetype(node) & LYS_INPUT) {
2145 if ((parent = get.parent(node))) {
2146 /* if output action has data */
2147 if (get.child(get.action_output(parent))) {
2148 /* then next sibling is output action */
2149 ret = get.action_output(parent);
2150 } else {
2151 /* input action cannot have siblings other
2152 * than output action.
2153 */
2154 ret = NULL;
2155 }
2156 } else {
2157 /* there is no way how to get output action */
2158 ret = NULL;
2159 }
2160 } else if (get.nodetype(node) & LYS_OUTPUT) {
2161 /* output action cannot have siblings */
2162 ret = NULL;
2163 } else if (get.nodetype(node) & LYS_NOTIF) {
2164 /* must have as a sibling only notif */
2165 ret = get.next(node);
2166 } else {
2167 /* for rest of nodes */
2168 if ((tmp = get.next(node))) {
2169 /* some sibling exists */
2170 ret = tmp;
2171 } else if ((parent = get.parent(node))) {
2172 /* Action and notif are siblings too.
2173 * They can be reached through parent.
2174 */
2175 if ((tmp = get.actions(parent))) {
2176 /* next sibling is action */
2177 ret = tmp;
2178 } else if ((tmp = get.notifs(parent))) {
2179 /* next sibling is notif */
2180 ret = tmp;
2181 } else {
2182 /* sibling not exists */
2183 ret = NULL;
2184 }
2185 } else {
2186 /* sibling not exists */
2187 ret = NULL;
2188 }
2189 }
2190
2191 return ret;
2192}
2193
2194/**
2195 * @brief Get child 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.
2201 * @param[in] lysc_tree flag to determine what type the @p node is.
2202 * If set to true, then @p points to lysc_node otherwise lysp_node.
2203 * This flag should be the same as trt_tree_ctx.lysc_tree.
aPiecekef1e58e2021-04-19 13:19:44 +02002204 */
2205static const void *
aPiecek3f247652021-04-19 13:40:25 +02002206tro_next_child(const void *node, ly_bool lysc_tree)
aPiecekef1e58e2021-04-19 13:19:44 +02002207{
2208 struct tro_getters get;
2209 const void *tmp;
2210 const void *ret;
2211
2212 assert(node);
2213
aPiecek3f247652021-04-19 13:40:25 +02002214 get = lysc_tree ? troc_init_getters() : trop_init_getters();
aPiecekef1e58e2021-04-19 13:19:44 +02002215
2216 if (get.nodetype(node) & (LYS_ACTION | LYS_RPC)) {
2217 if (get.child(get.action_input(node))) {
2218 /* go to LYS_INPUT */
2219 ret = get.action_input(node);
2220 } else if (get.child(get.action_output(node))) {
2221 /* go to LYS_OUTPUT */
2222 ret = get.action_output(node);
2223 } else {
2224 /* input action and output action have no data */
2225 ret = NULL;
2226 }
2227 } else {
2228 if ((tmp = get.child(node))) {
2229 ret = tmp;
2230 } else {
2231 /* current node can't have children or has no children */
2232 /* but maybe has some actions or notifs */
2233 if ((tmp = get.actions(node))) {
2234 ret = tmp;
2235 } else if ((tmp = get.notifs(node))) {
2236 ret = tmp;
2237 } else {
2238 ret = NULL;
2239 }
2240 }
2241 }
2242
2243 return ret;
2244}
2245
2246/**
aPiecek3f247652021-04-19 13:40:25 +02002247 * @brief Get new trt_parent_cache if we apply the transfer
2248 * to the child node in the tree.
2249 * @param[in] ca is parent cache for current node.
2250 * @param[in] tc contains current tree node.
2251 * @return Cache for the current node.
2252 */
2253static struct trt_parent_cache
2254tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2255{
2256 struct trt_parent_cache ret = TRP_EMPTY_PARENT_CACHE;
2257
2258 if (!tc->lysc_tree) {
2259 const struct lysp_node *pn = tc->pn;
2260
2261 ret.ancestor =
2262 pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT :
2263 pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT :
2264 pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF :
2265 ca.ancestor;
2266
2267 ret.lys_status =
2268 pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
2269 ca.lys_status;
2270
2271 ret.lys_config =
2272 ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because <flags> will be -w */
2273 ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
2274 pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
2275 ca.lys_config;
2276
2277 ret.last_list =
2278 pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
2279 ca.last_list;
2280 }
2281
2282 return ret;
2283}
2284
2285/**
aPiecekef1e58e2021-04-19 13:19:44 +02002286 * @brief Transformation of the Schema nodes flags to
2287 * Tree diagram \<status\>.
2288 * @param[in] flags is node's flags obtained from the tree.
2289 */
2290static trt_status_type
2291tro_flags2status(uint16_t flags)
2292{
2293 return flags & LYS_STATUS_OBSLT ? TRD_STATUS_TYPE_OBSOLETE :
2294 flags & LYS_STATUS_DEPRC ? TRD_STATUS_TYPE_DEPRECATED :
2295 TRD_STATUS_TYPE_CURRENT;
2296}
2297
2298/**
2299 * @brief Transformation of the Schema nodes flags to Tree diagram
2300 * \<flags\> but more specifically 'ro' or 'rw'.
2301 * @param[in] flags is node's flags obtained from the tree.
2302 */
2303static trt_flags_type
2304tro_flags2config(uint16_t flags)
2305{
2306 return flags & LYS_CONFIG_R ? TRD_FLAGS_TYPE_RO :
2307 flags & LYS_CONFIG_W ? TRD_FLAGS_TYPE_RW :
2308 TRD_FLAGS_TYPE_EMPTY;
2309}
2310
2311/**
aPiecek3f247652021-04-19 13:40:25 +02002312 * @brief Print current node's iffeatures.
2313 * @param[in] tc is tree context.
2314 * @param[in,out] out is output handler.
2315 */
2316static void
2317tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out)
2318{
2319 const struct lysp_qname *iffs;
2320
aPiecekbbc02932021-05-21 07:19:41 +02002321 if (tc->lysc_tree) {
2322 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2323 iffs = TRP_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures;
2324 } else {
2325 iffs = tc->pn->iffeatures;
2326 }
aPiecek3f247652021-04-19 13:40:25 +02002327 LY_ARRAY_COUNT_TYPE i;
2328
2329 LY_ARRAY_FOR(iffs, i) {
2330 if (i == 0) {
2331 ly_print_(out, "%s", iffs[i].str);
2332 } else {
2333 ly_print_(out, ",%s", iffs[i].str);
2334 }
2335 }
2336
2337}
2338
2339/**
2340 * @brief Print current list's keys.
2341 *
2342 * Well, actually printing keys in the lysp_tree is trivial,
2343 * because char* points to all keys. However, special functions have
2344 * been reserved for this, because in principle the list of elements
2345 * can have more implementations.
2346 *
2347 * @param[in] tc is tree context.
2348 * @param[in,out] out is output handler.
2349 */
2350static void
2351tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out)
2352{
2353 const struct lysp_node_list *list;
2354
aPiecekbbc02932021-05-21 07:19:41 +02002355 if (tc->lysc_tree) {
2356 assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
2357 list = (const struct lysp_node_list *)TRP_TREE_CTX_GET_LYSP_NODE(tc->cn);
2358 } else {
2359 list = (const struct lysp_node_list *)tc->pn;
2360 }
aPiecek3f247652021-04-19 13:40:25 +02002361 assert(list->nodetype & LYS_LIST);
2362
2363 if (trg_charptr_has_data(list->key)) {
2364 ly_print_(out, "%s", list->key);
2365 }
2366}
2367
2368/**
2369 * @brief Get rpcs section if exists.
2370 * @param[in,out] tc is tree context.
2371 * @return Section representation if it exists. The @p tc is modified
2372 * and his pointer points to the first node in rpcs section.
2373 * @return Empty section representation otherwise.
2374 */
2375static struct trt_keyword_stmt
2376tro_modi_get_rpcs(struct trt_tree_ctx *tc)
2377{
aPiecek9f792e52021-04-21 08:33:56 +02002378 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002379 const void *actions;
2380
2381 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002382 actions = tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002383 if (actions) {
2384 tc->cn = actions;
2385 }
2386 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002387 actions = tc->pmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02002388 if (actions) {
2389 tc->pn = actions;
2390 tc->tpn = tc->pn;
2391 }
2392 }
2393
2394 if (actions) {
2395 tc->section = TRD_SECT_RPCS;
2396 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_RPC, NULL);
2397 } else {
2398 return TRP_EMPTY_KEYWORD_STMT;
2399 }
2400}
2401
2402/**
2403 * @brief Get notification section if exists
2404 * @param[in,out] tc is tree context.
2405 * @return Section representation if it exists.
2406 * The @p tc is modified and his pointer points to the
2407 * first node in notification section.
2408 * @return Empty section representation otherwise.
2409 */
2410static struct trt_keyword_stmt
2411tro_modi_get_notifications(struct trt_tree_ctx *tc)
2412{
aPiecek9f792e52021-04-21 08:33:56 +02002413 assert(tc);
aPiecek3f247652021-04-19 13:40:25 +02002414 const void *notifs;
2415
2416 if (tc->lysc_tree) {
aPiecek9f792e52021-04-21 08:33:56 +02002417 notifs = tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002418 if (notifs) {
2419 tc->cn = notifs;
2420 }
2421 } else {
aPiecek9f792e52021-04-21 08:33:56 +02002422 notifs = tc->pmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02002423 if (notifs) {
2424 tc->pn = notifs;
2425 tc->tpn = tc->pn;
2426 }
2427 }
2428
2429 if (notifs) {
2430 tc->section = TRD_SECT_NOTIF;
2431 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_NOTIF, NULL);
2432 } else {
2433 return TRP_EMPTY_KEYWORD_STMT;
2434 }
2435}
2436
2437/**
aPiecek96baa7f2021-04-23 12:32:00 +02002438 * @brief Get next yang-data section if it is possible.
aPiecekef1e58e2021-04-19 13:19:44 +02002439 *
2440 * @param[in,out] tc is tree context.
aPiecek96baa7f2021-04-23 12:32:00 +02002441 * @param[in] u is index to the array of extensions (lysc_ext_instance
2442 * or struct lysp_ext_instance).
aPiecekef1e58e2021-04-19 13:19:44 +02002443 * @return Section representation if it exists.
2444 * @return Empty section representation otherwise.
2445 */
2446static struct trt_keyword_stmt
aPiecek96baa7f2021-04-23 12:32:00 +02002447tro_modi_next_yang_data(struct trt_tree_ctx *tc, LY_ARRAY_COUNT_TYPE u)
aPiecekef1e58e2021-04-19 13:19:44 +02002448{
aPiecek96baa7f2021-04-23 12:32:00 +02002449 assert(tc);
2450 const void *node;
2451 const char *yang_data_name;
2452
2453 if (tc->lysc_tree) {
2454 struct lysc_ext_instance *exts;
2455 struct lysc_ext_substmt *substmts;
2456
2457 exts = tc->cmod->exts;
2458 substmts = exts[u].substmts;
2459 if (!substmts) {
2460 return TRP_EMPTY_KEYWORD_STMT;
2461 }
2462 node = *(const struct lysc_node **)substmts->storage;
2463 yang_data_name = exts[u].argument;
2464 } else {
2465 struct lysp_ext_instance *exts;
2466
2467 exts = tc->pmod->exts;
2468 node = exts[u].parsed;
2469 yang_data_name = exts[u].argument;
2470 }
2471
2472 if (tc->lysc_tree) {
2473 tc->cn = node;
2474 } else {
2475 tc->tpn_ext = &tc->pmod->exts[u];
2476 tc->pn = node;
2477 }
2478
2479 if (node) {
2480 tc->section = TRD_SECT_YANG_DATA;
2481 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_YANG_DATA, yang_data_name);
2482 } else {
2483 return TRP_EMPTY_KEYWORD_STMT;
2484 }
aPiecekef1e58e2021-04-19 13:19:44 +02002485}
2486
2487/**
2488 * @brief Get name of the module.
2489 * @param[in] tc is context of the tree.
2490 */
2491static struct trt_keyword_stmt
2492tro_read_module_name(const struct trt_tree_ctx *tc)
2493{
aPiecek9f792e52021-04-21 08:33:56 +02002494 assert(tc);
2495
2496 struct trt_keyword_stmt ret;
2497
2498 ret.type = !tc->lysc_tree && tc->pmod->is_submod ?
2499 TRD_KEYWORD_SUBMODULE :
2500 TRD_KEYWORD_MODULE;
2501
2502 ret.str = !tc->lysc_tree ?
2503 LYSP_MODULE_NAME(tc->pmod) :
2504 tc->cmod->mod->name;
2505
2506 return ret;
aPiecekef1e58e2021-04-19 13:19:44 +02002507}
2508
aPiecekb8d5a0a2021-05-20 08:20:24 +02002509/**
2510 * @brief Create implicit "case" node as parent of @p node.
2511 * @param[in] node child of implicit case node.
2512 * @return The case node ready to print.
2513 */
2514static struct trt_node
2515tro_create_implicit_case_node(struct trt_node node)
2516{
2517 struct trt_node ret;
2518
2519 ret.status = node.status;
2520 ret.flags = TRD_FLAGS_TYPE_EMPTY;
2521 ret.name.type = TRD_NODE_CASE;
2522 ret.name.module_prefix = node.name.module_prefix;
2523 ret.name.str = node.name.str;
2524 ret.type = TRP_EMPTY_TRT_TYPE;
aPiecek7a28e2f2021-05-21 07:27:03 +02002525 ret.iffeatures = 0;
aPiecekb8d5a0a2021-05-20 08:20:24 +02002526 ret.last_one = node.last_one;
2527
2528 return ret;
2529}
2530
aPiecekef1e58e2021-04-19 13:19:44 +02002531/**********************************************************************
2532 * Definition of trop reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02002533 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002534
2535/**
aPiecek61d062b2020-11-02 11:05:09 +01002536 * @brief Check if list statement has keys.
2537 * @param[in] pn is pointer to the list.
2538 * @return 1 if has keys, otherwise 0.
2539 */
2540static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002541trop_list_has_keys(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002542{
aPiecekef1e58e2021-04-19 13:19:44 +02002543 return trg_charptr_has_data(((const struct lysp_node_list *)pn)->key);
aPiecek61d062b2020-11-02 11:05:09 +01002544}
2545
2546/**
2547 * @brief Check if it contains at least one feature.
aPiecek3f247652021-04-19 13:40:25 +02002548 * @param[in] pn is current node.
aPiecek61d062b2020-11-02 11:05:09 +01002549 * @return 1 if has if-features, otherwise 0.
2550 */
2551static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002552trop_node_has_iffeature(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002553{
2554 LY_ARRAY_COUNT_TYPE u;
aPiecekef1e58e2021-04-19 13:19:44 +02002555 const struct lysp_qname *iffs;
2556
aPiecek61d062b2020-11-02 11:05:09 +01002557 ly_bool ret = 0;
2558
aPiecekef1e58e2021-04-19 13:19:44 +02002559 iffs = pn->iffeatures;
aPiecek61d062b2020-11-02 11:05:09 +01002560 LY_ARRAY_FOR(iffs, u) {
2561 ret = 1;
2562 break;
2563 }
2564 return ret;
2565}
2566
2567/**
2568 * @brief Find out if leaf is also the key in last list.
2569 * @param[in] pn is pointer to leaf.
aPiecek874ea4d2021-04-19 12:26:36 +02002570 * @param[in] ca_last_list is pointer to last visited list.
2571 * Obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002572 * @return 1 if leaf is also the key, otherwise 0.
2573 */
2574static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002575trop_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
aPiecek61d062b2020-11-02 11:05:09 +01002576{
2577 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2578 const struct lysp_node_list *list = ca_last_list;
2579
2580 if (!list) {
2581 return 0;
2582 }
2583 return trg_charptr_has_data(list->key) ?
2584 trg_word_is_present(list->key, leaf->name, ' ') : 0;
2585}
2586
2587/**
2588 * @brief Check if container's type is presence.
2589 * @param[in] pn is pointer to container.
2590 * @return 1 if container has presence statement, otherwise 0.
2591 */
2592static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002593trop_container_has_presence(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002594{
2595 return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence);
2596}
2597
2598/**
2599 * @brief Get leaflist's path without lysp_node type control.
2600 * @param[in] pn is pointer to the leaflist.
2601 */
2602static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002603trop_leaflist_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002604{
2605 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2606
2607 return list->type.path ? list->type.path->expr : NULL;
2608}
2609
2610/**
2611 * @brief Get leaflist's type name without lysp_node type control.
2612 * @param[in] pn is pointer to the leaflist.
2613 */
2614static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002615trop_leaflist_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002616{
2617 const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2618
2619 return list->type.name;
2620}
2621
2622/**
2623 * @brief Get leaf's path without lysp_node type control.
2624 * @param[in] pn is pointer to the leaf node.
2625 */
2626static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002627trop_leaf_refpath(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002628{
2629 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2630
2631 return leaf->type.path ? leaf->type.path->expr : NULL;
2632}
2633
2634/**
2635 * @brief Get leaf's type name without lysp_node type control.
2636 * @param[in] pn is pointer to the leaf's type name.
2637 */
2638static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002639trop_leaf_type_name(const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002640{
2641 const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2642
2643 return leaf->type.name;
2644}
2645
2646/**
aPiecek874ea4d2021-04-19 12:26:36 +02002647 * @brief Get pointer to data using node type specification
2648 * and getter function.
aPiecek61d062b2020-11-02 11:05:09 +01002649 *
aPiecek874ea4d2021-04-19 12:26:36 +02002650 * @param[in] flags is node type specification.
2651 * If it is the correct node, the getter function is called.
2652 * @param[in] f is getter function which provides the desired
2653 * char pointer from the structure.
aPiecek61d062b2020-11-02 11:05:09 +01002654 * @param[in] pn pointer to node.
aPiecek874ea4d2021-04-19 12:26:36 +02002655 * @return NULL if node has wrong type or getter function return
2656 * pointer to NULL.
aPiecek61d062b2020-11-02 11:05:09 +01002657 * @return Pointer to desired char pointer obtained from the node.
2658 */
2659static const char *
aPiecekef1e58e2021-04-19 13:19:44 +02002660trop_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn)
aPiecek61d062b2020-11-02 11:05:09 +01002661{
2662 if (pn->nodetype & flags) {
2663 const char *ret = f(pn);
2664 return trg_charptr_has_data(ret) ? ret : NULL;
2665 } else {
2666 return NULL;
2667 }
2668}
2669
2670/**
aPiecek61d062b2020-11-02 11:05:09 +01002671 * @brief Resolve \<status\> of the current node.
2672 * @param[in] nodetype is node's type obtained from the tree.
2673 * @param[in] flags is node's flags obtained from the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002674 * @param[in] ca_lys_status is inherited status
2675 * obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002676 * @return The status type.
2677 */
2678static trt_status_type
aPiecekef1e58e2021-04-19 13:19:44 +02002679trop_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
aPiecek61d062b2020-11-02 11:05:09 +01002680{
2681 /* LYS_INPUT and LYS_OUTPUT is special case */
2682 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
aPiecekef1e58e2021-04-19 13:19:44 +02002683 return tro_flags2status(ca_lys_status);
2684 /* if ancestor's status is deprc or obslt
2685 * and also node's status is not set
2686 */
aPiecek61d062b2020-11-02 11:05:09 +01002687 } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
2688 /* get ancestor's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002689 return tro_flags2status(ca_lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002690 } else {
2691 /* else get node's status */
aPiecekef1e58e2021-04-19 13:19:44 +02002692 return tro_flags2status(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002693 }
2694}
2695
2696/**
2697 * @brief Resolve \<flags\> of the current node.
2698 * @param[in] nodetype is node's type obtained from the tree.
2699 * @param[in] flags is node's flags obtained from the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002700 * @param[in] ca_ancestor is ancestor type obtained
2701 * from trt_parent_cache.
2702 * @param[in] ca_lys_config is inherited config item
2703 * obtained from trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002704 * @return The flags type.
2705 */
2706static trt_flags_type
aPiecekef1e58e2021-04-19 13:19:44 +02002707trop_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config)
aPiecek61d062b2020-11-02 11:05:09 +01002708{
2709 if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) {
2710 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
2711 } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) {
2712 return TRD_FLAGS_TYPE_RO;
2713 } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) {
2714 return TRD_FLAGS_TYPE_RO;
2715 } else if (nodetype & LYS_NOTIF) {
2716 return TRD_FLAGS_TYPE_NOTIF;
2717 } else if (nodetype & LYS_USES) {
2718 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
2719 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
2720 return TRD_FLAGS_TYPE_RPC;
aPiecek61d062b2020-11-02 11:05:09 +01002721 } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002722 /* config is not set. Look at ancestor's config */
2723 return tro_flags2config(ca_lys_config);
aPiecek61d062b2020-11-02 11:05:09 +01002724 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02002725 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01002726 }
2727}
2728
2729/**
2730 * @brief Resolve node type of the current node.
2731 * @param[in] pn is pointer to the current node in the tree.
aPiecek874ea4d2021-04-19 12:26:36 +02002732 * @param[in] ca_last_list is pointer to the last visited list.
2733 * Obtained from the trt_parent_cache.
aPiecek61d062b2020-11-02 11:05:09 +01002734 */
2735static trt_node_type
aPiecekef1e58e2021-04-19 13:19:44 +02002736trop_resolve_node_type(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
aPiecek61d062b2020-11-02 11:05:09 +01002737{
2738 if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
2739 return TRD_NODE_ELSE;
2740 } else if (pn->nodetype & LYS_CASE) {
2741 return TRD_NODE_CASE;
2742 } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) {
2743 return TRD_NODE_OPTIONAL_CHOICE;
2744 } else if (pn->nodetype & LYS_CHOICE) {
2745 return TRD_NODE_CHOICE;
aPiecekef1e58e2021-04-19 13:19:44 +02002746 } else if ((pn->nodetype & LYS_CONTAINER) && (trop_container_has_presence(pn))) {
aPiecek61d062b2020-11-02 11:05:09 +01002747 return TRD_NODE_CONTAINER;
aPiecekef1e58e2021-04-19 13:19:44 +02002748 } else if ((pn->nodetype & LYS_LIST) && (trop_list_has_keys(pn))) {
aPiecek61d062b2020-11-02 11:05:09 +01002749 return TRD_NODE_KEYS;
2750 } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
2751 return TRD_NODE_LISTLEAFLIST;
2752 } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) {
2753 return TRD_NODE_OPTIONAL;
aPiecekef1e58e2021-04-19 13:19:44 +02002754 } else if ((pn->nodetype & LYS_LEAF) && !(pn->flags & LYS_MAND_TRUE) && (!trop_leaf_is_key(pn, ca_last_list))) {
aPiecek61d062b2020-11-02 11:05:09 +01002755 return TRD_NODE_OPTIONAL;
2756 } else {
2757 return TRD_NODE_ELSE;
2758 }
2759}
2760
2761/**
aPiecekef1e58e2021-04-19 13:19:44 +02002762 * @brief Resolve \<type\> of the current node.
2763 * @param[in] pn is current node.
2764 */
2765static struct trt_type
2766trop_resolve_type(const struct lysp_node *pn)
2767{
2768 const char *tmp = NULL;
2769
2770 if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_refpath, pn))) {
2771 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2772 } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_type_name, pn))) {
2773 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2774 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_refpath, pn))) {
2775 return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2776 } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_type_name, pn))) {
2777 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2778 } else if (pn->nodetype == LYS_ANYDATA) {
2779 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata");
2780 } else if (pn->nodetype & LYS_ANYXML) {
2781 return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml");
2782 } else {
2783 return TRP_EMPTY_TRT_TYPE;
2784 }
2785}
2786
2787/**
aPiecek61d062b2020-11-02 11:05:09 +01002788 * @brief Transformation of current lysp_node to struct trt_node.
aPiecek874ea4d2021-04-19 12:26:36 +02002789 * @param[in] ca contains stored important data
2790 * when browsing the tree downwards.
aPiecek61d062b2020-11-02 11:05:09 +01002791 * @param[in] tc is context of the tree.
2792 */
2793static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02002794trop_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002795{
aPiecekef1e58e2021-04-19 13:19:44 +02002796 const struct lysp_node *pn;
2797 struct trt_node ret;
2798
aPiecek61d062b2020-11-02 11:05:09 +01002799 assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
aPiecekef1e58e2021-04-19 13:19:44 +02002800
2801 pn = tc->pn;
2802 ret = TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01002803
2804 /* <status> */
aPiecekef1e58e2021-04-19 13:19:44 +02002805 ret.status = trop_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
aPiecek61d062b2020-11-02 11:05:09 +01002806
2807 /* TODO: TRD_FLAGS_TYPE_MOUNT_POINT aka "mp" is not supported right now. */
2808 /* <flags> */
aPiecekef1e58e2021-04-19 13:19:44 +02002809 ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config);
aPiecek61d062b2020-11-02 11:05:09 +01002810
2811 /* TODO: TRD_NODE_TOP_LEVEL1 aka '/' is not supported right now. */
2812 /* TODO: TRD_NODE_TOP_LEVEL2 aka '@' is not supported right now. */
2813 /* set type of the node */
aPiecekef1e58e2021-04-19 13:19:44 +02002814 ret.name.type = trop_resolve_node_type(pn, ca.last_list);
aPiecek61d062b2020-11-02 11:05:09 +01002815
aPiecek34fa3772021-05-21 12:35:46 +02002816 /* The parsed tree is not compiled, so no node can be augmented
2817 * from another module. This means that nodes from the parsed tree
2818 * will never have the prefix.
2819 */
aPiecek61d062b2020-11-02 11:05:09 +01002820 ret.name.module_prefix = NULL;
2821
2822 /* set node's name */
2823 ret.name.str = pn->name;
2824
2825 /* <type> */
aPiecekef1e58e2021-04-19 13:19:44 +02002826 ret.type = trop_resolve_type(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002827
2828 /* <iffeature> */
aPiecekef1e58e2021-04-19 13:19:44 +02002829 ret.iffeatures = trop_node_has_iffeature(pn);
aPiecek61d062b2020-11-02 11:05:09 +01002830
aPiecek3f247652021-04-19 13:40:25 +02002831 ret.last_one = !tro_next_sibling(pn, tc->lysc_tree);
aPiecek61d062b2020-11-02 11:05:09 +01002832
2833 return ret;
2834}
2835
aPiecekef1e58e2021-04-19 13:19:44 +02002836/**
2837 * @brief Find out if the current node has siblings.
2838 * @param[in] tc is context of the tree.
2839 * @return 1 if sibling exists otherwise 0.
2840 */
2841static ly_bool
2842trop_read_if_sibling_exists(const struct trt_tree_ctx *tc)
2843{
aPiecek3f247652021-04-19 13:40:25 +02002844 return tro_next_sibling(tc->pn, tc->lysc_tree) != NULL;
aPiecekef1e58e2021-04-19 13:19:44 +02002845}
2846
aPiecek96baa7f2021-04-23 12:32:00 +02002847/**
2848 * @brief Print all yang-data sections and print three dots instead
2849 * of nodes.
2850 * @param[in] exts is array of YANG extension instances from parsed
2851 * module (@ref sizedarrays).
2852 * @param[in] mll is maximum number of characters that can be printed
2853 * on one line.
2854 * @param[in,out] out is output handler.
2855 */
2856static void
2857trop_yang_data_sections(const struct lysp_ext_instance *exts, size_t mll, struct ly_out *out)
2858{
2859 struct trt_keyword_stmt ks;
2860 LY_ARRAY_COUNT_TYPE u;
2861 struct trt_wrapper wr;
2862
2863 if (!exts) {
2864 return;
2865 }
2866
2867 ly_print_(out, "\n");
2868 ks.type = TRD_KEYWORD_YANG_DATA;
2869 wr = TRP_INIT_WRAPPER_BODY;
2870
2871 LY_ARRAY_FOR(exts, u) {
2872 ly_print_(out, "\n");
2873
2874 /* yang-data <yang-data-name>: */
2875 ks.str = exts[u].argument;
2876 trp_print_keyword_stmt(ks, mll, 0, out);
2877 ly_print_(out, "\n");
2878
2879 /* ... */
2880 trp_print_wrapper(wr, out);
2881 ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
2882 }
2883}
2884
aPiecek874ea4d2021-04-19 12:26:36 +02002885/**********************************************************************
aPiecekef1e58e2021-04-19 13:19:44 +02002886 * Modify trop getters
aPiecek874ea4d2021-04-19 12:26:36 +02002887 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01002888
2889/**
aPiecek874ea4d2021-04-19 12:26:36 +02002890 * @brief Change current node pointer to its parent
2891 * but only if parent exists.
2892 * @param[in,out] tc is tree context.
2893 * Contains pointer to the current node.
aPiecek61d062b2020-11-02 11:05:09 +01002894 * @return 1 if the node had parents and the change was successful.
aPiecek874ea4d2021-04-19 12:26:36 +02002895 * @return 0 if the node did not have parents.
2896 * The pointer to the current node did not change.
aPiecek61d062b2020-11-02 11:05:09 +01002897 */
2898static ly_bool
aPiecekef1e58e2021-04-19 13:19:44 +02002899trop_modi_parent(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002900{
2901 assert(tc && tc->pn);
2902 /* If no parent exists, stay in actual node. */
aPiecek96baa7f2021-04-23 12:32:00 +02002903 if ((tc->pn != tc->tpn) && (tc->pn->parent)) {
aPiecek61d062b2020-11-02 11:05:09 +01002904 tc->pn = tc->pn->parent;
2905 return 1;
2906 } else {
2907 return 0;
2908 }
2909}
2910
2911/**
aPiecek874ea4d2021-04-19 12:26:36 +02002912 * @brief Change the current node pointer to its child
2913 * but only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01002914 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02002915 * @param[in,out] tc is context of the tree.
2916 * Contains pointer to the current node.
2917 * @return Non-empty \<node\> representation of the current
2918 * node's child. The @p tc is modified.
2919 * @return Empty \<node\> representation if child don't exists.
2920 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01002921 */
2922static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02002923trop_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002924{
aPiecekef1e58e2021-04-19 13:19:44 +02002925 const struct lysp_node *tmp;
2926
aPiecek61d062b2020-11-02 11:05:09 +01002927 assert(tc && tc->pn);
2928
aPiecek3f247652021-04-19 13:40:25 +02002929 if ((tmp = tro_next_child(tc->pn, tc->lysc_tree))) {
aPiecekef1e58e2021-04-19 13:19:44 +02002930 tc->pn = tmp;
aPiecek3f247652021-04-19 13:40:25 +02002931 return trop_read_node(tro_parent_cache_for_child(ca, tc), tc);
aPiecek61d062b2020-11-02 11:05:09 +01002932 } else {
aPiecekef1e58e2021-04-19 13:19:44 +02002933 return TRP_EMPTY_NODE;
aPiecek61d062b2020-11-02 11:05:09 +01002934 }
2935}
2936
2937/**
aPiecek874ea4d2021-04-19 12:26:36 +02002938 * @brief Change the current node pointer to the first child of node's
2939 * parent. If current node is already first sibling/child then nothing
2940 * will change.
aPiecek61d062b2020-11-02 11:05:09 +01002941 * @param[in,out] tc is tree context.
2942 */
2943static void
aPiecekef1e58e2021-04-19 13:19:44 +02002944trop_modi_first_sibling(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002945{
aPiecek9f792e52021-04-21 08:33:56 +02002946 assert(tc && tc->pn && tc->pmod);
aPiecek61d062b2020-11-02 11:05:09 +01002947
aPiecekef1e58e2021-04-19 13:19:44 +02002948 if (trop_modi_parent(tc)) {
2949 trop_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
aPiecek61d062b2020-11-02 11:05:09 +01002950 } else {
2951 /* current node is top-node */
aPiecek61d062b2020-11-02 11:05:09 +01002952 switch (tc->section) {
2953 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02002954 tc->pn = tc->pmod->data;
aPiecek96baa7f2021-04-23 12:32:00 +02002955 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002956 break;
2957 case TRD_SECT_AUGMENT:
aPiecek9f792e52021-04-21 08:33:56 +02002958 tc->pn = (const struct lysp_node *)tc->pmod->augments;
aPiecek96baa7f2021-04-23 12:32:00 +02002959 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002960 break;
2961 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02002962 tc->pn = (const struct lysp_node *)tc->pmod->rpcs;
aPiecek96baa7f2021-04-23 12:32:00 +02002963 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002964 break;
2965 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02002966 tc->pn = (const struct lysp_node *)tc->pmod->notifs;
aPiecek96baa7f2021-04-23 12:32:00 +02002967 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002968 break;
2969 case TRD_SECT_GROUPING:
aPiecek9f792e52021-04-21 08:33:56 +02002970 tc->pn = (const struct lysp_node *)tc->pmod->groupings;
aPiecek96baa7f2021-04-23 12:32:00 +02002971 tc->tpn = tc->pn;
aPiecek61d062b2020-11-02 11:05:09 +01002972 break;
2973 case TRD_SECT_YANG_DATA:
aPiecek96baa7f2021-04-23 12:32:00 +02002974 /* tpn in this case is of type lysp_ext_instance */
2975 tc->pn = tc->tpn_ext->parsed;
aPiecek61d062b2020-11-02 11:05:09 +01002976 break;
aPiecek96baa7f2021-04-23 12:32:00 +02002977 default:
2978 assert(0);
aPiecek61d062b2020-11-02 11:05:09 +01002979 }
aPiecek61d062b2020-11-02 11:05:09 +01002980 }
2981}
2982
2983/**
aPiecek874ea4d2021-04-19 12:26:36 +02002984 * @brief Change the pointer to the current node to its next sibling
2985 * only if exists.
aPiecek61d062b2020-11-02 11:05:09 +01002986 * @param[in] ca contains inherited data from ancestors.
aPiecek874ea4d2021-04-19 12:26:36 +02002987 * @param[in,out] tc is tree context.
2988 * Contains pointer to the current node.
2989 * @return Non-empty \<node\> representation if sibling exists.
2990 * The @p tc is modified.
2991 * @return Empty \<node\> representation otherwise.
2992 * The @p tc is not modified.
aPiecek61d062b2020-11-02 11:05:09 +01002993 */
2994static struct trt_node
aPiecekef1e58e2021-04-19 13:19:44 +02002995trop_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01002996{
aPiecekef1e58e2021-04-19 13:19:44 +02002997 const struct lysp_node *pn;
aPiecekef1e58e2021-04-19 13:19:44 +02002998
2999 assert(tc && tc->pn);
3000
aPiecek3f247652021-04-19 13:40:25 +02003001 pn = tro_next_sibling(tc->pn, tc->lysc_tree);
aPiecek61d062b2020-11-02 11:05:09 +01003002
aPiecekef1e58e2021-04-19 13:19:44 +02003003 if (pn) {
aPiecek96baa7f2021-04-23 12:32:00 +02003004 if ((tc->tpn == tc->pn) && (tc->section != TRD_SECT_YANG_DATA)) {
3005 tc->tpn = pn;
3006 }
aPiecekef1e58e2021-04-19 13:19:44 +02003007 tc->pn = pn;
aPiecekef1e58e2021-04-19 13:19:44 +02003008 return trop_read_node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003009 } else {
3010 return TRP_EMPTY_NODE;
3011 }
3012}
3013
3014/**
3015 * @brief Get next (or first) augment section if exists.
aPiecek874ea4d2021-04-19 12:26:36 +02003016 * @param[in,out] tc is tree context. It is modified and his current
3017 * node is set to the lysp_node_augment.
aPiecek61d062b2020-11-02 11:05:09 +01003018 * @return Section's representation if (next augment) section exists.
aPiecek61d062b2020-11-02 11:05:09 +01003019 * @return Empty section structure otherwise.
3020 */
3021static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003022trop_modi_next_augment(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003023{
aPiecek9f792e52021-04-21 08:33:56 +02003024 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003025 const struct lysp_node_augment *augs;
3026
3027 /* if next_augment func was called for the first time */
3028 if (tc->section != TRD_SECT_AUGMENT) {
3029 tc->section = TRD_SECT_AUGMENT;
aPiecek9f792e52021-04-21 08:33:56 +02003030 augs = tc->pmod->augments;
aPiecek61d062b2020-11-02 11:05:09 +01003031 } else {
3032 /* get augment sibling from top-node pointer */
aPiecekdc8fd572021-04-19 10:47:23 +02003033 augs = (const struct lysp_node_augment *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003034 }
3035
aPiecekdc8fd572021-04-19 10:47:23 +02003036 if (augs) {
3037 tc->pn = &augs->node;
aPiecek61d062b2020-11-02 11:05:09 +01003038 tc->tpn = tc->pn;
3039 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_AUGMENT, augs->nodeid);
3040 } else {
3041 return TRP_EMPTY_KEYWORD_STMT;
3042 }
3043}
3044
3045/**
aPiecek61d062b2020-11-02 11:05:09 +01003046 * @brief Get next (or first) grouping section if exists
aPiecek874ea4d2021-04-19 12:26:36 +02003047 * @param[in,out] tc is tree context. It is modified and his current
3048 * node is set to the lysp_node_grp.
aPiecek61d062b2020-11-02 11:05:09 +01003049 * @return The next (or first) section representation if it exists.
aPiecek61d062b2020-11-02 11:05:09 +01003050 * @return Empty section representation otherwise.
3051 */
3052static struct trt_keyword_stmt
aPiecekef1e58e2021-04-19 13:19:44 +02003053trop_modi_next_grouping(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003054{
aPiecek9f792e52021-04-21 08:33:56 +02003055 assert(tc);
aPiecek61d062b2020-11-02 11:05:09 +01003056 const struct lysp_node_grp *grps;
3057
3058 if (tc->section != TRD_SECT_GROUPING) {
3059 tc->section = TRD_SECT_GROUPING;
aPiecek9f792e52021-04-21 08:33:56 +02003060 grps = tc->pmod->groupings;
aPiecek61d062b2020-11-02 11:05:09 +01003061 } else {
aPiecekdc8fd572021-04-19 10:47:23 +02003062 grps = (const struct lysp_node_grp *)tc->tpn->next;
aPiecek61d062b2020-11-02 11:05:09 +01003063 }
3064
aPiecekdc8fd572021-04-19 10:47:23 +02003065 if (grps) {
3066 tc->pn = &grps->node;
aPiecek61d062b2020-11-02 11:05:09 +01003067 tc->tpn = tc->pn;
3068 return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_GROUPING, grps->name);
3069 } else {
3070 return TRP_EMPTY_KEYWORD_STMT;
3071 }
3072}
3073
aPiecek874ea4d2021-04-19 12:26:36 +02003074/**********************************************************************
aPiecek3f247652021-04-19 13:40:25 +02003075 * Definition of troc reading functions
aPiecek874ea4d2021-04-19 12:26:36 +02003076 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003077
3078/**
aPiecek3f247652021-04-19 13:40:25 +02003079 * @copydoc trop_read_if_sibling_exists
aPiecek61d062b2020-11-02 11:05:09 +01003080 */
aPiecek3f247652021-04-19 13:40:25 +02003081static ly_bool
3082troc_read_if_sibling_exists(const struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003083{
aPiecek3f247652021-04-19 13:40:25 +02003084 return tro_next_sibling(tc->cn, tc->lysc_tree) != NULL;
3085}
aPiecek61d062b2020-11-02 11:05:09 +01003086
aPiecek3f247652021-04-19 13:40:25 +02003087/**
3088 * @brief Resolve \<flags\> of the current node.
3089 *
3090 * Use this function only if trt_tree_ctx.lysc_tree is true.
3091 *
3092 * @param[in] nodetype is current lysc_node.nodetype.
3093 * @param[in] flags is current lysc_node.flags.
3094 * @return The flags type.
3095 */
3096static trt_flags_type
3097troc_resolve_flags(uint16_t nodetype, uint16_t flags)
3098{
3099 if ((nodetype & LYS_INPUT) || (flags & LYS_IS_INPUT)) {
3100 return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
3101 } else if ((nodetype & LYS_OUTPUT) || (flags & LYS_IS_OUTPUT)) {
3102 return TRD_FLAGS_TYPE_RO;
3103 } else if (nodetype & LYS_IS_NOTIF) {
3104 return TRD_FLAGS_TYPE_RO;
3105 } else if (nodetype & LYS_NOTIF) {
3106 return TRD_FLAGS_TYPE_NOTIF;
3107 } else if (nodetype & LYS_USES) {
3108 return TRD_FLAGS_TYPE_USES_OF_GROUPING;
3109 } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
3110 return TRD_FLAGS_TYPE_RPC;
3111 } else {
3112 return tro_flags2config(flags);
aPiecek61d062b2020-11-02 11:05:09 +01003113 }
aPiecek61d062b2020-11-02 11:05:09 +01003114}
3115
3116/**
aPiecek3f247652021-04-19 13:40:25 +02003117 * @brief Resolve node type of the current node.
aPiecek61d062b2020-11-02 11:05:09 +01003118 *
aPiecek3f247652021-04-19 13:40:25 +02003119 * Use this function only if trt_tree_ctx.lysc_tree is true.
aPiecek61d062b2020-11-02 11:05:09 +01003120 *
aPiecek3f247652021-04-19 13:40:25 +02003121 * @param[in] nodetype is current lysc_node.nodetype.
3122 * @param[in] flags is current lysc_node.flags.
3123 */
3124static trt_node_type
3125troc_resolve_node_type(uint16_t nodetype, uint16_t flags)
3126{
3127 if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
3128 return TRD_NODE_ELSE;
3129 } else if (nodetype & LYS_CASE) {
3130 return TRD_NODE_CASE;
3131 } else if ((nodetype & LYS_CHOICE) && !(flags & LYS_MAND_TRUE)) {
3132 return TRD_NODE_OPTIONAL_CHOICE;
3133 } else if (nodetype & LYS_CHOICE) {
3134 return TRD_NODE_CHOICE;
3135 } else if ((nodetype & LYS_CONTAINER) && (flags & LYS_PRESENCE)) {
3136 return TRD_NODE_CONTAINER;
3137 } else if ((nodetype & LYS_LIST) && !(flags & LYS_KEYLESS)) {
3138 return TRD_NODE_KEYS;
3139 } else if (nodetype & (LYS_LIST | LYS_LEAFLIST)) {
3140 return TRD_NODE_LISTLEAFLIST;
3141 } else if ((nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(flags & LYS_MAND_TRUE)) {
3142 return TRD_NODE_OPTIONAL;
3143 } else if ((nodetype & LYS_LEAF) && !(flags & (LYS_MAND_TRUE | LYS_KEY))) {
3144 return TRD_NODE_OPTIONAL;
3145 } else {
3146 return TRD_NODE_ELSE;
3147 }
3148}
3149
3150/**
aPiecek34fa3772021-05-21 12:35:46 +02003151 * @brief Resolve prefix (<prefix>:<name>) of node that has been
3152 * placed from another module via an augment statement.
3153 *
3154 * @param[in] cn is current compiled node.
3155 * @param[in] current_compiled_module is module whose nodes are
3156 * currently being printed.
3157 * @return Prefix of foreign module or NULL.
3158 */
3159static const char *
3160troc_resolve_node_prefix(const struct lysc_node *cn, const struct lysc_module *current_compiled_module)
3161{
3162 const struct lys_module *node_module;
3163 const char *ret = NULL;
3164
3165 node_module = cn->module;
3166 if (node_module->compiled != current_compiled_module) {
3167 ret = node_module->prefix;
3168 }
3169
3170 return ret;
3171}
3172
3173/**
aPiecek3f247652021-04-19 13:40:25 +02003174 * @brief Transformation of current lysc_node to struct trt_node.
3175 * @param[in] ca is not used.
3176 * @param[in] tc is context of the tree.
3177 */
3178static struct trt_node
3179troc_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
3180{
3181 (void) ca;
3182 const struct lysc_node *cn;
3183 struct trt_node ret;
3184
aPiecek082c7dc2021-05-20 08:55:07 +02003185 assert(tc && tc->cn);
aPiecek3f247652021-04-19 13:40:25 +02003186
3187 cn = tc->cn;
3188 ret = TRP_EMPTY_NODE;
3189
3190 /* <status> */
3191 ret.status = tro_flags2status(cn->flags);
3192
3193 /* TODO: TRD_FLAGS_TYPE_MOUNT_POINT aka "mp" is not supported right now. */
3194 /* <flags> */
3195 ret.flags = troc_resolve_flags(cn->nodetype, cn->flags);
3196
3197 /* TODO: TRD_NODE_TOP_LEVEL1 aka '/' is not supported right now. */
3198 /* TODO: TRD_NODE_TOP_LEVEL2 aka '@' is not supported right now. */
3199 /* set type of the node */
3200 ret.name.type = troc_resolve_node_type(cn->nodetype, cn->flags);
3201
aPiecek34fa3772021-05-21 12:35:46 +02003202 /* <prefix> */
3203 ret.name.module_prefix = troc_resolve_node_prefix(cn, tc->cmod);
aPiecek3f247652021-04-19 13:40:25 +02003204
3205 /* set node's name */
3206 ret.name.str = cn->name;
3207
aPiecekbbc02932021-05-21 07:19:41 +02003208 if (TRP_TREE_CTX_LYSP_NODE_PRESENT(cn)) {
aPiecek082c7dc2021-05-20 08:55:07 +02003209 /* <type> */
3210 ret.type = trop_resolve_type(TRP_TREE_CTX_GET_LYSP_NODE(cn));
aPiecek3f247652021-04-19 13:40:25 +02003211
aPiecek082c7dc2021-05-20 08:55:07 +02003212 /* <iffeature> */
3213 ret.iffeatures = trop_node_has_iffeature(TRP_TREE_CTX_GET_LYSP_NODE(cn));
3214 } else {
aPiecekbbc02932021-05-21 07:19:41 +02003215 /* only the implicit case node doesn't have access to lysp node */
aPiecek082c7dc2021-05-20 08:55:07 +02003216 assert(tc->cn->nodetype & LYS_CASE);
3217
3218 /* <type> */
3219 ret.type = TRP_EMPTY_TRT_TYPE;
3220
aPiecek7a28e2f2021-05-21 07:27:03 +02003221 /* <iffeature> */
3222 ret.iffeatures = 0;
aPiecek082c7dc2021-05-20 08:55:07 +02003223 }
aPiecek3f247652021-04-19 13:40:25 +02003224
3225 ret.last_one = !tro_next_sibling(cn, tc->lysc_tree);
3226
3227 return ret;
3228}
3229
3230/**********************************************************************
3231 * Modify troc getters
3232 *********************************************************************/
3233
3234/**
aPiecek01598c02021-04-23 14:18:24 +02003235 * @copydoc ::trop_modi_parent()
aPiecek3f247652021-04-19 13:40:25 +02003236 */
3237static ly_bool
3238troc_modi_parent(struct trt_tree_ctx *tc)
3239{
3240 assert(tc && tc->cn);
3241 /* If no parent exists, stay in actual node. */
3242 if (tc->cn->parent) {
3243 tc->cn = tc->cn->parent;
3244 return 1;
3245 } else {
3246 return 0;
3247 }
3248}
3249
3250/**
aPiecek01598c02021-04-23 14:18:24 +02003251 * @copydoc ::trop_modi_next_sibling()
aPiecek3f247652021-04-19 13:40:25 +02003252 */
3253static struct trt_node
3254troc_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3255{
3256 const struct lysc_node *cn;
3257
3258 assert(tc && tc->cn);
3259
3260 cn = tro_next_sibling(tc->cn, tc->lysc_tree);
3261
3262 /* if next sibling exists */
3263 if (cn) {
3264 /* update trt_tree_ctx */
3265 tc->cn = cn;
3266 return troc_read_node(ca, tc);
3267 } else {
3268 return TRP_EMPTY_NODE;
3269 }
3270}
3271
3272/**
3273 * @copydoc trop_modi_next_child()
3274 */
3275static struct trt_node
3276troc_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3277{
3278 const struct lysc_node *tmp;
3279
3280 assert(tc && tc->cn);
3281
3282 if ((tmp = tro_next_child(tc->cn, tc->lysc_tree))) {
3283 tc->cn = tmp;
3284 return troc_read_node(ca, tc);
3285 } else {
3286 return TRP_EMPTY_NODE;
3287 }
3288}
3289
3290/**
aPiecek01598c02021-04-23 14:18:24 +02003291 * @copydoc ::trop_modi_first_sibling()
aPiecek61d062b2020-11-02 11:05:09 +01003292 */
3293static void
aPiecek3f247652021-04-19 13:40:25 +02003294troc_modi_first_sibling(struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003295{
aPiecek3f247652021-04-19 13:40:25 +02003296 assert(tc && tc->cn);
aPiecek61d062b2020-11-02 11:05:09 +01003297
aPiecek3f247652021-04-19 13:40:25 +02003298 if (troc_modi_parent(tc)) {
3299 troc_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
3300 } else {
3301 /* current node is top-node */
aPiecek3f247652021-04-19 13:40:25 +02003302 switch (tc->section) {
3303 case TRD_SECT_MODULE:
aPiecek9f792e52021-04-21 08:33:56 +02003304 tc->cn = tc->cmod->data;
aPiecek3f247652021-04-19 13:40:25 +02003305 break;
3306 case TRD_SECT_RPCS:
aPiecek9f792e52021-04-21 08:33:56 +02003307 tc->cn = (const struct lysc_node *)tc->cmod->rpcs;
aPiecek3f247652021-04-19 13:40:25 +02003308 break;
3309 case TRD_SECT_NOTIF:
aPiecek9f792e52021-04-21 08:33:56 +02003310 tc->cn = (const struct lysc_node *)tc->cmod->notifs;
aPiecek3f247652021-04-19 13:40:25 +02003311 break;
3312 case TRD_SECT_YANG_DATA:
aPiecek96baa7f2021-04-23 12:32:00 +02003313 /* nothing to do */
aPiecek3f247652021-04-19 13:40:25 +02003314 break;
3315 default:
3316 assert(0);
3317 }
aPiecek61d062b2020-11-02 11:05:09 +01003318 }
3319}
3320
aPiecek874ea4d2021-04-19 12:26:36 +02003321/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01003322 * Definition of tree browsing functions
aPiecek874ea4d2021-04-19 12:26:36 +02003323 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003324
3325/**
3326 * @brief Get size of node name.
3327 * @param[in] name contains name and mark.
3328 * @return positive value total size of the node name.
aPiecek874ea4d2021-04-19 12:26:36 +02003329 * @return negative value as an indication that option mark
3330 * is included in the total size.
aPiecek61d062b2020-11-02 11:05:09 +01003331 */
3332static int32_t
3333trb_strlen_of_name_and_mark(struct trt_node_name name)
3334{
3335 size_t name_len = strlen(name.str);
3336
3337 if ((name.type == TRD_NODE_CHOICE) || (name.type == TRD_NODE_CASE)) {
3338 /* counting also parentheses */
3339 name_len += 2;
3340 }
3341
3342 return trp_mark_is_used(name) ?
3343 ((int32_t)(name_len + TRD_OPTS_MARK_LENGTH)) * (-1) :
3344 (int32_t)name_len;
3345}
3346
3347/**
aPiecek874ea4d2021-04-19 12:26:36 +02003348 * @brief Calculate the trt_indent_in_node.btw_opts_type indent size
3349 * for a particular node.
aPiecek61d062b2020-11-02 11:05:09 +01003350 * @param[in] name is the node for which we get btw_opts_type.
aPiecek874ea4d2021-04-19 12:26:36 +02003351 * @param[in] max_len4all is the maximum value of btw_opts_type
3352 * that it can have.
3353 * @return Indent between \<opts\> and \<type\> for node.
aPiecek61d062b2020-11-02 11:05:09 +01003354 */
3355static int16_t
3356trb_calc_btw_opts_type(struct trt_node_name name, int16_t max_len4all)
3357{
3358 int32_t name_len;
3359 int16_t min_len;
3360 int16_t ret;
3361
3362 name_len = trb_strlen_of_name_and_mark(name);
3363
3364 /* negative value indicate that in name is some opt mark */
3365 min_len = name_len < 0 ?
3366 TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
3367 TRD_INDENT_BEFORE_TYPE;
3368 ret = abs(max_len4all) - abs(name_len);
3369
3370 /* correction -> negative indicate that name is too long. */
3371 return ret < 0 ? min_len : ret;
3372}
3373
3374/**
3375 * @brief Print node.
3376 *
aPiecek01598c02021-04-23 14:18:24 +02003377 * This function is wrapper for ::trp_print_entire_node().
aPiecek874ea4d2021-04-19 12:26:36 +02003378 * But difference is that take @p max_gap_before_type which will be
3379 * used to set the unified alignment.
aPiecek61d062b2020-11-02 11:05:09 +01003380 *
aPiecek9bdd7592021-05-20 08:13:20 +02003381 * @param[in] node to print.
aPiecek61d062b2020-11-02 11:05:09 +01003382 * @param[in] max_gap_before_type is number of indent before \<type\>.
3383 * @param[in] wr is wrapper for printing indentation before node.
aPiecek61d062b2020-11-02 11:05:09 +01003384 * @param[in] pc contains mainly functions for printing.
3385 * @param[in] tc is tree context.
3386 */
3387static void
aPiecek9bdd7592021-05-20 08:13:20 +02003388trb_print_entire_node(struct trt_node node, uint32_t max_gap_before_type, struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003389{
aPiecek61d062b2020-11-02 11:05:09 +01003390 struct trt_indent_in_node ind = trp_default_indent_in_node(node);
3391
3392 if ((max_gap_before_type > 0) && (node.type.type != TRD_TYPE_EMPTY)) {
3393 /* print actual node with unified indent */
3394 ind.btw_opts_type = trb_calc_btw_opts_type(node.name, max_gap_before_type);
3395 }
3396 /* after -> print actual node with default indent */
3397 trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print),
3398 TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out);
3399}
3400
3401/**
aPiecek874ea4d2021-04-19 12:26:36 +02003402 * @brief Check if parent of the current node is the last
3403 * of his siblings.
aPiecek61d062b2020-11-02 11:05:09 +01003404 *
aPiecek874ea4d2021-04-19 12:26:36 +02003405 * To mantain stability use this function only if the current node is
3406 * the first of the siblings.
3407 * Side-effect -> current node is set to the first sibling
3408 * if node has a parent otherwise no side-effect.
aPiecek61d062b2020-11-02 11:05:09 +01003409 *
aPiecek01598c02021-04-23 14:18:24 +02003410 * @param[in] fp contains all @ref TRP_tro callback functions.
aPiecek61d062b2020-11-02 11:05:09 +01003411 * @param[in,out] tc is tree context.
3412 * @return 1 if parent is last sibling otherwise 0.
3413 */
3414static ly_bool
3415trb_parent_is_last_sibling(struct trt_fp_all fp, struct trt_tree_ctx *tc)
3416{
3417 if (fp.modify.parent(tc)) {
3418 ly_bool ret = fp.read.if_sibling_exists(tc);
3419 fp.modify.next_child(TRP_EMPTY_PARENT_CACHE, tc);
3420 return !ret;
3421 } else {
3422 return !fp.read.if_sibling_exists(tc);
3423 }
3424}
3425
3426/**
3427 * @brief Find sibling with the biggest node name and return that size.
3428 *
3429 * Side-effect -> Current node is set to the first sibling.
3430 *
3431 * @param[in] ca contains inherited data from ancestors.
3432 * @param[in] pc contains mainly functions for printing.
3433 * @param[in,out] tc is tree context.
aPiecek874ea4d2021-04-19 12:26:36 +02003434 * @return positive number as a sign that only the node name is
3435 * included in the size.
3436 * @return negative number sign that node name and his opt mark is
3437 * included in the size.
aPiecek61d062b2020-11-02 11:05:09 +01003438 */
3439static int32_t
3440trb_maxlen_node_name(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3441{
3442 int32_t ret = 0;
3443
3444 pc->fp.modify.first_sibling(tc);
3445
3446 for (struct trt_node node = pc->fp.read.node(ca, tc);
3447 !trp_node_is_empty(node);
3448 node = pc->fp.modify.next_sibling(ca, tc)) {
3449 int32_t maxlen = trb_strlen_of_name_and_mark(node.name);
3450 ret = abs(maxlen) > abs(ret) ? maxlen : ret;
3451 }
3452 pc->fp.modify.first_sibling(tc);
3453 return ret;
3454}
3455
3456/**
aPiecek874ea4d2021-04-19 12:26:36 +02003457 * @brief Find maximal indent between
3458 * \<opts\> and \<type\> for siblings.
aPiecek61d062b2020-11-02 11:05:09 +01003459 *
3460 * Side-effect -> Current node is set to the first sibling.
3461 *
3462 * @param[in] ca contains inherited data from ancestors.
3463 * @param[in] pc contains mainly functions for printing.
3464 * @param[in,out] tc is tree context.
3465 * @return max btw_opts_type value for rest of the siblings
3466 */
3467static int16_t
3468trb_max_btw_opts_type4siblings(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3469{
3470 int32_t maxlen_node_name = trb_maxlen_node_name(ca, pc, tc);
3471 int16_t ind_before_type = maxlen_node_name < 0 ?
3472 TRD_INDENT_BEFORE_TYPE - 1 : /* mark was present */
3473 TRD_INDENT_BEFORE_TYPE;
3474
3475 return abs(maxlen_node_name) + ind_before_type;
3476}
3477
3478/**
aPiecek874ea4d2021-04-19 12:26:36 +02003479 * @brief Find out if it is possible to unify
3480 * the alignment before \<type\>.
aPiecek61d062b2020-11-02 11:05:09 +01003481 *
aPiecek874ea4d2021-04-19 12:26:36 +02003482 * The goal is for all node siblings to have the same alignment
3483 * for \<type\> as if they were in a column. All siblings who cannot
3484 * adapt because they do not fit on the line at all are ignored.
aPiecek61d062b2020-11-02 11:05:09 +01003485 * Side-effect -> Current node is set to the first sibling.
3486 *
3487 * @param[in] ca contains inherited data from ancestors.
3488 * @param[in] pc contains mainly functions for printing.
3489 * @param[in,out] tc is tree context.
3490 * @return 0 if all siblings cannot fit on the line.
aPiecek874ea4d2021-04-19 12:26:36 +02003491 * @return positive number indicating the maximum number of spaces
3492 * before \<type\> if the length of the node name is 0. To calculate
3493 * the trt_indent_in_node.btw_opts_type indent size for a particular
aPiecek01598c02021-04-23 14:18:24 +02003494 * node, use the ::trb_calc_btw_opts_type().
aPiecek61d062b2020-11-02 11:05:09 +01003495*/
3496static uint32_t
3497trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3498{
3499 return trb_max_btw_opts_type4siblings(ca, pc, tc);
3500}
3501
3502/**
aPiecekb8d5a0a2021-05-20 08:20:24 +02003503 * @brief Check if there is no case statement
3504 * under the choice statement.
3505 *
3506 * It can return true only if the Parsed schema tree
3507 * is used for browsing.
3508 *
3509 * @param[in] tc is tree context.
3510 * @return 1 if implicit case statement is present otherwise 0.
3511 */
3512static ly_bool
3513trb_need_implicit_node_case(struct trt_tree_ctx *tc)
3514{
3515 return !tc->lysc_tree && tc->pn->parent &&
3516 (tc->pn->parent->nodetype & LYS_CHOICE) &&
3517 (tc->pn->nodetype & (LYS_ANYDATA | LYS_CHOICE | LYS_CONTAINER |
3518 LYS_LEAF | LYS_LEAFLIST));
3519}
3520
3521static void trb_print_subtree_nodes(struct trt_node node, uint32_t max_gap_before_type,
3522 struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc);
3523
3524/**
3525 * @brief Print implicit case node and his subtree.
3526 *
3527 * @param[in] node is child of implicit case.
3528 * @param[in] wr is wrapper for printing identation before node.
3529 * @param[in] ca contains inherited data from ancestors.
3530 * @param[in] pc contains mainly functions for printing.
3531 * @param[in] tc is tree context. Its settings should be the same as
3532 * before the function call.
3533 */
3534static void
3535trb_print_implicit_node_case_subtree(struct trt_node node, struct trt_wrapper wr,
3536 struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3537{
3538 struct trt_node case_node;
3539 struct trt_wrapper wr_case_child;
3540
3541 case_node = tro_create_implicit_case_node(node);
3542 ly_print_(pc->out, "\n");
3543 trb_print_entire_node(case_node, 0, wr, pc, tc);
3544 wr_case_child = pc->fp.read.if_sibling_exists(tc) ?
3545 trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr);
3546 ly_print_(pc->out, "\n");
3547 trb_print_subtree_nodes(node, 0, wr_case_child, ca, pc, tc);
3548}
3549
3550/**
aPiecek874ea4d2021-04-19 12:26:36 +02003551 * @brief For the current node: recursively print all of its child
3552 * nodes and all of its siblings, including their children.
aPiecek61d062b2020-11-02 11:05:09 +01003553 *
aPiecek01598c02021-04-23 14:18:24 +02003554 * This function is an auxiliary function for ::trb_print_subtree_nodes().
aPiecek61d062b2020-11-02 11:05:09 +01003555 * The parent of the current node is expected to exist.
aPiecek874ea4d2021-04-19 12:26:36 +02003556 * Nodes are printed, including unified sibling node alignment
3557 * (align \<type\> to column).
aPiecek61d062b2020-11-02 11:05:09 +01003558 * Side-effect -> current node is set to the last sibling.
3559 *
3560 * @param[in] wr is wrapper for printing identation before node.
3561 * @param[in] ca contains inherited data from ancestors.
3562 * @param[in] pc contains mainly functions for printing.
3563 * @param[in,out] tc is tree context.
3564 */
3565static void
3566trb_print_nodes(struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3567{
3568 uint32_t max_gap_before_type;
3569 ly_bool sibling_flag = 0;
3570 ly_bool child_flag = 0;
3571
3572 /* if node is last sibling, then do not add '|' to wrapper */
3573 wr = trb_parent_is_last_sibling(pc->fp, tc) ?
3574 trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
3575
3576 /* try unified indentation in node */
3577 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
3578
3579 /* print all siblings */
3580 do {
3581 struct trt_parent_cache new_ca;
3582 struct trt_node node;
aPiecek9bdd7592021-05-20 08:13:20 +02003583 node = pc->fp.read.node(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003584
aPiecekb8d5a0a2021-05-20 08:20:24 +02003585 if (!trb_need_implicit_node_case(tc)) {
3586 /* normal behavior */
3587 ly_print_(pc->out, "\n");
3588 trb_print_entire_node(node, max_gap_before_type, wr, pc, tc);
3589 new_ca = tro_parent_cache_for_child(ca, tc);
3590 /* go to the actual node's child or stay in actual node */
3591 node = pc->fp.modify.next_child(ca, tc);
3592 child_flag = !trp_node_is_empty(node);
aPiecek61d062b2020-11-02 11:05:09 +01003593
aPiecekb8d5a0a2021-05-20 08:20:24 +02003594 if (child_flag) {
3595 /* print all childs - recursive call */
3596 trb_print_nodes(wr, new_ca, pc, tc);
3597 /* get back from child node to actual node */
3598 pc->fp.modify.parent(tc);
3599 }
3600 } else {
3601 /* The case statement is omitted (shorthand).
3602 * Print implicit case node and his subtree.
3603 */
3604 trb_print_implicit_node_case_subtree(node, wr, ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003605 }
3606
3607 /* go to the actual node's sibling */
3608 node = pc->fp.modify.next_sibling(ca, tc);
3609 sibling_flag = !trp_node_is_empty(node);
3610
3611 /* go to the next sibling or stay in actual node */
3612 } while (sibling_flag);
3613}
3614
3615/**
aPiecek153b00f2021-04-20 13:52:57 +02003616 * @brief Calculate the wrapper about how deep in the tree the node is.
3617 * @param[in] node from which to count.
3618 * @return wrapper for @p node.
3619 */
3620static struct trt_wrapper
3621trb_count_depth(const struct lysc_node *node)
3622{
3623 struct trt_wrapper wr = TRP_INIT_WRAPPER_TOP;
3624 const struct lysc_node *parent;
3625
3626 if (!node) {
3627 return wr;
3628 }
3629
3630 for (parent = node->parent; parent; parent = parent->parent) {
3631 wr = trp_wrapper_set_shift(wr);
3632 }
3633
3634 return wr;
3635}
3636
3637/**
3638 * @brief Print all parent nodes of @p node and the @p node itself.
3639 *
3640 * Side-effect -> trt_tree_ctx.cn will be set to @p node.
3641 *
3642 * @param[in] node on which the function is focused.
aPiecek01598c02021-04-23 14:18:24 +02003643 * @param[in] pc is @ref TRP_trp settings.
aPiecek153b00f2021-04-20 13:52:57 +02003644 * @param[in,out] tc is context of tree printer.
3645 * @return wrapper for @p node.
3646 */
3647static void
3648trb_print_parents(const struct lysc_node *node, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3649{
3650 struct trt_wrapper wr;
aPiecek9bdd7592021-05-20 08:13:20 +02003651 struct trt_node print_node;
aPiecek153b00f2021-04-20 13:52:57 +02003652
3653 assert(pc && tc && tc->section == TRD_SECT_MODULE);
3654
3655 /* stop recursion */
3656 if (!node) {
3657 return;
3658 }
3659 trb_print_parents(node->parent, pc, tc);
3660
3661 /* setup for printing */
3662 tc->cn = node;
3663 wr = trb_count_depth(node);
3664
3665 /* print node */
3666 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02003667 print_node = pc->fp.read.node(TRP_EMPTY_PARENT_CACHE, tc);
3668 trb_print_entire_node(print_node, 0, wr, pc, tc);
aPiecek153b00f2021-04-20 13:52:57 +02003669}
3670
3671/**
aPiecekdc8fd572021-04-19 10:47:23 +02003672 * @brief Get address of the current node.
3673 * @param[in] tc contains current node.
aPiecek3f247652021-04-19 13:40:25 +02003674 * @return Address of lysc_node or lysp_node, or NULL.
aPiecekdc8fd572021-04-19 10:47:23 +02003675 */
3676static const void *
3677trb_tree_ctx_get_node(struct trt_tree_ctx *tc)
3678{
aPiecek3f247652021-04-19 13:40:25 +02003679 return tc->lysc_tree ?
3680 (const void *)tc->cn :
3681 (const void *)tc->pn;
aPiecekdc8fd572021-04-19 10:47:23 +02003682}
3683
3684/**
3685 * @brief Get address of current node's child.
3686 * @param[in,out] tc contains current node.
3687 */
3688static const void *
3689trb_tree_ctx_get_child(struct trt_tree_ctx *tc)
3690{
3691 if (!trb_tree_ctx_get_node(tc)) {
3692 return NULL;
3693 }
3694
aPiecek3f247652021-04-19 13:40:25 +02003695 if (tc->lysc_tree) {
3696 return lysc_node_child(tc->cn);
3697 } else {
3698 return lysp_node_child(tc->pn);
3699 }
aPiecekdc8fd572021-04-19 10:47:23 +02003700}
3701
3702/**
3703 * @brief Set current node on its child.
3704 * @param[in,out] tc contains current node.
3705 */
3706static void
3707trb_tree_ctx_set_child(struct trt_tree_ctx *tc)
3708{
aPiecek3f247652021-04-19 13:40:25 +02003709 const void *node = trb_tree_ctx_get_child(tc);
3710
3711 if (tc->lysc_tree) {
3712 tc->cn = node;
3713 } else {
3714 tc->pn = node;
3715 }
aPiecekdc8fd572021-04-19 10:47:23 +02003716}
3717
3718/**
aPiecek61d062b2020-11-02 11:05:09 +01003719 * @brief Print subtree of nodes.
3720 *
3721 * The current node is expected to be the root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02003722 * Before root node is no linebreak printing. This must be addressed by
3723 * the caller. Root node will also be printed. Behind last printed node
3724 * is no linebreak.
aPiecek61d062b2020-11-02 11:05:09 +01003725 *
aPiecek9bdd7592021-05-20 08:13:20 +02003726 * @param[in] node is root of the subtree.
aPiecek874ea4d2021-04-19 12:26:36 +02003727 * @param[in] max_gap_before_type is result from
aPiecek01598c02021-04-23 14:18:24 +02003728 * ::trb_try_unified_indent() function for root node.
3729 * Set parameter to 0 if distance does not matter.
aPiecek874ea4d2021-04-19 12:26:36 +02003730 * @param[in] wr is wrapper saying how deep in the whole tree
3731 * is the root of the subtree.
3732 * @param[in] ca is parent_cache from root's parent.
3733 * If root is top-level node, insert ::TRP_EMPTY_PARENT_CACHE.
aPiecek01598c02021-04-23 14:18:24 +02003734 * @param[in] pc is @ref TRP_trp settings.
aPiecek874ea4d2021-04-19 12:26:36 +02003735 * @param[in,out] tc is context of tree printer.
aPiecek61d062b2020-11-02 11:05:09 +01003736 */
3737static void
aPiecek9bdd7592021-05-20 08:13:20 +02003738trb_print_subtree_nodes(struct trt_node node, uint32_t max_gap_before_type, struct trt_wrapper wr,
3739 struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003740{
3741 struct trt_parent_cache new_ca;
aPiecek61d062b2020-11-02 11:05:09 +01003742
aPiecek9bdd7592021-05-20 08:13:20 +02003743 trb_print_entire_node(node, max_gap_before_type, wr, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003744 /* go to the actual node's child */
aPiecek3f247652021-04-19 13:40:25 +02003745 new_ca = tro_parent_cache_for_child(ca, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003746 node = pc->fp.modify.next_child(ca, tc);
3747
3748 if (!trp_node_is_empty(node)) {
3749 /* print root's nodes */
3750 trb_print_nodes(wr, new_ca, pc, tc);
3751 /* get back from child node to actual node */
3752 pc->fp.modify.parent(tc);
3753 }
3754}
3755
3756/**
3757 * @brief Get number of siblings.
3758 *
3759 * Side-effect -> current node is set to the first sibling.
3760 *
3761 * @param[in] fp contains callback functions which modify tree context
3762 * @param[in,out] tc is the tree context.
3763 * @return Number of siblings of the current node.
3764 */
3765static uint32_t
3766trb_get_number_of_siblings(struct trt_fp_modify_ctx fp, struct trt_tree_ctx *tc)
3767{
3768 uint32_t ret = 1;
3769 struct trt_node node = TRP_EMPTY_NODE;
3770
3771 /* including actual node */
3772 fp.first_sibling(tc);
3773 while (!trp_node_is_empty(node = fp.next_sibling(TRP_EMPTY_PARENT_CACHE, tc))) {
3774 ret++;
3775 }
3776 fp.first_sibling(tc);
3777 return ret;
3778}
3779
3780/**
3781 * @brief Print all parents and their children.
3782 *
aPiecek874ea4d2021-04-19 12:26:36 +02003783 * This function is suitable for printing top-level nodes that
aPiecek01598c02021-04-23 14:18:24 +02003784 * do not have ancestors. Function call ::trb_print_subtree_nodes()
aPiecek153b00f2021-04-20 13:52:57 +02003785 * for all top-level siblings. Use this function after 'module' keyword
3786 * or 'augment' and so. The nodes may not be exactly top-level in the
3787 * tree, but the function considers them that way.
aPiecek61d062b2020-11-02 11:05:09 +01003788 *
aPiecek153b00f2021-04-20 13:52:57 +02003789 * @param[in] wr is wrapper saying how deeply the top-level nodes are
3790 * immersed in the tree.
aPiecek61d062b2020-11-02 11:05:09 +01003791 * @param[pc] pc contains mainly functions for printing.
3792 * @param[in,out] tc is tree context.
3793 */
3794static void
aPiecek153b00f2021-04-20 13:52:57 +02003795trb_print_family_tree(struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003796{
aPiecek61d062b2020-11-02 11:05:09 +01003797 struct trt_parent_cache ca;
aPiecek9bdd7592021-05-20 08:13:20 +02003798 struct trt_node node;
aPiecek61d062b2020-11-02 11:05:09 +01003799 uint32_t total_parents;
3800 uint32_t max_gap_before_type;
3801
aPiecekdc8fd572021-04-19 10:47:23 +02003802 if (!trb_tree_ctx_get_node(tc)) {
3803 return;
3804 }
3805
aPiecek61d062b2020-11-02 11:05:09 +01003806 ca = TRP_EMPTY_PARENT_CACHE;
3807 total_parents = trb_get_number_of_siblings(pc->fp.modify, tc);
3808 max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
3809
aPiecek3f247652021-04-19 13:40:25 +02003810 if (!tc->lysc_tree) {
aPiecek96baa7f2021-04-23 12:32:00 +02003811 if (((tc->section == TRD_SECT_GROUPING) && (tc->tpn == tc->pn->parent)) ||
3812 (tc->section == TRD_SECT_YANG_DATA)) {
aPiecek3f247652021-04-19 13:40:25 +02003813 ca.lys_config = 0x0;
3814 }
aPiecekdc8fd572021-04-19 10:47:23 +02003815 }
3816
aPiecek61d062b2020-11-02 11:05:09 +01003817 for (uint32_t i = 0; i < total_parents; i++) {
3818 ly_print_(pc->out, "\n");
aPiecek9bdd7592021-05-20 08:13:20 +02003819 node = pc->fp.read.node(ca, tc);
3820 trb_print_subtree_nodes(node, max_gap_before_type, wr, ca, pc, tc);
aPiecek61d062b2020-11-02 11:05:09 +01003821 pc->fp.modify.next_sibling(ca, tc);
3822 }
3823}
3824
aPiecek874ea4d2021-04-19 12:26:36 +02003825/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01003826 * Definition of trm main functions
aPiecek874ea4d2021-04-19 12:26:36 +02003827 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01003828
3829/**
aPiecekdc8fd572021-04-19 10:47:23 +02003830 * @brief Settings if lysp_node are used for browsing through the tree.
aPiecek61d062b2020-11-02 11:05:09 +01003831 *
aPiecekdc8fd572021-04-19 10:47:23 +02003832 * @param[in] module YANG schema tree structure representing
3833 * YANG module.
aPiecek61d062b2020-11-02 11:05:09 +01003834 * @param[in] out is output handler.
aPiecekdc8fd572021-04-19 10:47:23 +02003835 * @param[in] max_line_length is the maximum line length limit
3836 * that should not be exceeded.
3837 * @param[in,out] pc will be adapted to lysp_tree.
3838 * @param[in,out] tc will be adapted to lysp_tree.
aPiecek61d062b2020-11-02 11:05:09 +01003839 */
3840static void
aPiecekdc8fd572021-04-19 10:47:23 +02003841trm_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecek61d062b2020-11-02 11:05:09 +01003842{
aPiecekdc8fd572021-04-19 10:47:23 +02003843 *tc = (struct trt_tree_ctx) {
aPiecek3f247652021-04-19 13:40:25 +02003844 .lysc_tree = 0,
aPiecekdc8fd572021-04-19 10:47:23 +02003845 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02003846 .pmod = module->parsed,
3847 .cmod = NULL,
3848 .pn = module->parsed ? module->parsed->data : NULL,
3849 .tpn = module->parsed ? module->parsed->data : NULL,
aPiecek3f247652021-04-19 13:40:25 +02003850 .cn = NULL
aPiecekdc8fd572021-04-19 10:47:23 +02003851 };
aPiecek61d062b2020-11-02 11:05:09 +01003852
aPiecekdc8fd572021-04-19 10:47:23 +02003853 pc->out = out;
3854
3855 pc->fp.modify = (struct trt_fp_modify_ctx) {
aPiecekef1e58e2021-04-19 13:19:44 +02003856 .parent = trop_modi_parent,
3857 .first_sibling = trop_modi_first_sibling,
3858 .next_sibling = trop_modi_next_sibling,
3859 .next_child = trop_modi_next_child,
aPiecek61d062b2020-11-02 11:05:09 +01003860 };
3861
aPiecekdc8fd572021-04-19 10:47:23 +02003862 pc->fp.read = (struct trt_fp_read) {
aPiecek61d062b2020-11-02 11:05:09 +01003863 .module_name = tro_read_module_name,
aPiecekef1e58e2021-04-19 13:19:44 +02003864 .node = trop_read_node,
3865 .if_sibling_exists = trop_read_if_sibling_exists
aPiecek61d062b2020-11-02 11:05:09 +01003866 };
3867
aPiecekdc8fd572021-04-19 10:47:23 +02003868 pc->fp.print = (struct trt_fp_print) {
aPiecek3f247652021-04-19 13:40:25 +02003869 .print_features_names = tro_print_features_names,
3870 .print_keys = tro_print_keys
aPiecek61d062b2020-11-02 11:05:09 +01003871 };
3872
aPiecekdc8fd572021-04-19 10:47:23 +02003873 pc->max_line_length = max_line_length;
aPiecek61d062b2020-11-02 11:05:09 +01003874}
3875
3876/**
aPiecek3f247652021-04-19 13:40:25 +02003877 * @brief Settings if lysc_node are used for browsing through the tree.
3878 *
3879 * Pointers to current nodes will be set to module data.
3880 *
3881 * @param[in] module YANG schema tree structure representing
3882 * YANG module.
3883 * @param[in] out is output handler.
3884 * @param[in] max_line_length is the maximum line length limit
3885 * that should not be exceeded.
3886 * @param[in,out] pc will be adapted to lysc_tree.
3887 * @param[in,out] tc will be adapted to lysc_tree.
3888 */
3889static void
3890trm_lysc_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3891{
3892 *tc = (struct trt_tree_ctx) {
3893 .lysc_tree = 1,
3894 .section = TRD_SECT_MODULE,
aPiecek9f792e52021-04-21 08:33:56 +02003895 .pmod = module->parsed,
3896 .cmod = module->compiled,
aPiecek3f247652021-04-19 13:40:25 +02003897 .tpn = NULL,
3898 .pn = NULL,
3899 .cn = module->compiled->data
3900 };
3901
3902 pc->out = out;
3903
3904 pc->fp.modify = (struct trt_fp_modify_ctx) {
3905 .parent = troc_modi_parent,
3906 .first_sibling = troc_modi_first_sibling,
3907 .next_sibling = troc_modi_next_sibling,
3908 .next_child = troc_modi_next_child,
aPiecek3f247652021-04-19 13:40:25 +02003909 };
3910
3911 pc->fp.read = (struct trt_fp_read) {
3912 .module_name = tro_read_module_name,
3913 .node = troc_read_node,
3914 .if_sibling_exists = troc_read_if_sibling_exists
3915 };
3916
3917 pc->fp.print = (struct trt_fp_print) {
3918 .print_features_names = tro_print_features_names,
3919 .print_keys = tro_print_keys
3920 };
3921
3922 pc->max_line_length = max_line_length;
3923}
3924
3925/**
3926 * @brief Reset settings to browsing through the lysc tree.
aPiecek01598c02021-04-23 14:18:24 +02003927 * @param[in,out] pc resets to @ref TRP_troc functions.
aPiecek3f247652021-04-19 13:40:25 +02003928 * @param[in,out] tc resets to lysc browsing.
3929 */
3930static void
3931trm_reset_to_lysc_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3932{
aPiecek9f792e52021-04-21 08:33:56 +02003933 trm_lysc_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc);
aPiecek3f247652021-04-19 13:40:25 +02003934}
3935
3936/**
3937 * @brief Reset settings to browsing through the lysp tree.
aPiecek01598c02021-04-23 14:18:24 +02003938 * @param[in,out] pc resets to @ref TRP_trop functions.
aPiecek3f247652021-04-19 13:40:25 +02003939 * @param[in,out] tc resets to lysp browsing.
3940 */
3941static void
3942trm_reset_to_lysp_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3943{
aPiecek9f792e52021-04-21 08:33:56 +02003944 trm_lysp_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc);
aPiecek3f247652021-04-19 13:40:25 +02003945}
3946
3947/**
3948 * @brief If augment's target node is located on the current module.
3949 * @param[in] pn is examined augment.
3950 * @param[in] pmod is current module.
3951 * @return 1 if nodeid refers to the local node, otherwise 0.
3952 */
3953static ly_bool
3954trm_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod)
3955{
3956 const char *id, *prefix, *name;
3957 size_t prefix_len, name_len;
3958 const struct lys_module *mod;
3959 ly_bool ret = 0;
3960
3961 if (pn == NULL) {
3962 return ret;
3963 }
3964
3965 id = pn->nodeid;
3966 if (!id) {
3967 return ret;
3968 }
3969 /* only absolute-schema-nodeid is taken into account */
3970 assert(id[0] == '/');
3971 ++id;
3972
3973 ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len);
3974 if (prefix) {
Radek Krejci8df109d2021-04-23 12:19:08 +02003975 mod = ly_resolve_prefix(pmod->mod->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, pmod);
aPiecek3f247652021-04-19 13:40:25 +02003976 ret = mod->parsed == pmod;
3977 } else {
3978 ret = 1;
3979 }
3980
3981 return ret;
3982}
3983
3984/**
aPiecek96baa7f2021-04-23 12:32:00 +02003985 * @brief Printing section module, rpcs, notifications or yang-data.
aPiecek61d062b2020-11-02 11:05:09 +01003986 *
aPiecekdc8fd572021-04-19 10:47:23 +02003987 * First node must be the first child of 'module',
aPiecek96baa7f2021-04-23 12:32:00 +02003988 * 'rpcs', 'notifications' or 'yang-data'.
aPiecek61d062b2020-11-02 11:05:09 +01003989 *
aPiecekdc8fd572021-04-19 10:47:23 +02003990 * @param[in] ks is section representation.
3991 * @param[in] pc contains mainly functions for printing.
3992 * @param[in,out] tc is the tree context.
aPiecek61d062b2020-11-02 11:05:09 +01003993 */
3994static void
aPiecekdc8fd572021-04-19 10:47:23 +02003995trm_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 +01003996{
aPiecekdc8fd572021-04-19 10:47:23 +02003997 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
3998 return;
3999 }
4000
4001 trp_print_keyword_stmt(ks, pc->max_line_length, 0, pc->out);
4002 if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
aPiecek153b00f2021-04-20 13:52:57 +02004003 trb_print_family_tree(TRP_INIT_WRAPPER_TOP, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004004 } else {
aPiecek153b00f2021-04-20 13:52:57 +02004005 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004006 }
4007}
4008
4009/**
aPiecek96baa7f2021-04-23 12:32:00 +02004010 * @brief Printing section augment or grouping.
aPiecekdc8fd572021-04-19 10:47:23 +02004011 *
aPiecek96baa7f2021-04-23 12:32:00 +02004012 * First node is 'augment' or 'grouping' itself.
aPiecekdc8fd572021-04-19 10:47:23 +02004013 *
4014 * @param[in] ks is section representation.
4015 * @param[in] pc contains mainly functions for printing.
4016 * @param[in,out] tc is the tree context.
4017 */
4018static void
4019trm_print_section_as_subtree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4020{
4021 ly_bool grp_has_data = 0;
4022
4023 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4024 return;
4025 }
4026
4027 if (ks.type == TRD_KEYWORD_GROUPING) {
4028 grp_has_data = trb_tree_ctx_get_child(tc) ? 1 : 0;
4029 }
4030
4031 trp_print_keyword_stmt(ks, pc->max_line_length, grp_has_data, pc->out);
4032 trb_tree_ctx_set_child(tc);
aPiecek153b00f2021-04-20 13:52:57 +02004033 trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004034}
4035
4036/**
4037 * @brief Print 'module' keyword, its name and all nodes.
4038 * @param[in] pc contains mainly functions for printing.
4039 * @param[in,out] tc is the tree context.
4040 */
4041static void
4042trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4043{
4044 trm_print_section_as_family_tree(pc->fp.read.module_name(tc), pc, tc);
4045}
4046
4047/**
4048 * @brief For all augment sections: print 'augment' keyword,
4049 * its target node and all nodes.
4050 * @param[in] pc contains mainly functions for printing.
4051 * @param[in,out] tc is the tree context.
4052 */
4053static void
4054trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4055{
4056 ly_bool once;
aPiecek3f247652021-04-19 13:40:25 +02004057 ly_bool origin_was_lysc_tree = 0;
aPiecekdc8fd572021-04-19 10:47:23 +02004058
aPiecek3f247652021-04-19 13:40:25 +02004059 if (tc->lysc_tree) {
4060 origin_was_lysc_tree = 1;
4061 trm_reset_to_lysp_tree_ctx(pc, tc);
4062 }
4063
aPiecekdc8fd572021-04-19 10:47:23 +02004064 once = 1;
aPiecek01598c02021-04-23 14:18:24 +02004065 for (struct trt_keyword_stmt ks = trop_modi_next_augment(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004066 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
aPiecek01598c02021-04-23 14:18:24 +02004067 ks = trop_modi_next_augment(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004068
aPiecek3f247652021-04-19 13:40:25 +02004069 if (origin_was_lysc_tree) {
4070 /* if lysc tree is used, then only augments targeting
4071 * another module are printed
4072 */
aPiecek9f792e52021-04-21 08:33:56 +02004073 if (trm_nodeid_target_is_local((const struct lysp_node_augment *)tc->tpn, tc->pmod)) {
aPiecek3f247652021-04-19 13:40:25 +02004074 continue;
4075 }
4076 }
4077
aPiecekdc8fd572021-04-19 10:47:23 +02004078 if (once) {
4079 ly_print_(pc->out, "\n");
4080 ly_print_(pc->out, "\n");
4081 once = 0;
4082 } else {
4083 ly_print_(pc->out, "\n");
4084 }
4085
4086 trm_print_section_as_subtree(ks, pc, tc);
4087 }
aPiecek3f247652021-04-19 13:40:25 +02004088
4089 if (origin_was_lysc_tree) {
4090 trm_reset_to_lysc_tree_ctx(pc, tc);
4091 }
aPiecekdc8fd572021-04-19 10:47:23 +02004092}
4093
4094/**
4095 * @brief For rpcs section: print 'rpcs' keyword and all its nodes.
4096 * @param[in] pc contains mainly functions for printing.
4097 * @param[in,out] tc is the tree context.
4098 */
4099static void
4100trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4101{
4102 struct trt_keyword_stmt rpc;
4103
aPiecek01598c02021-04-23 14:18:24 +02004104 rpc = tro_modi_get_rpcs(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004105
4106 if (!(TRP_KEYWORD_STMT_IS_EMPTY(rpc))) {
4107 ly_print_(pc->out, "\n");
4108 ly_print_(pc->out, "\n");
4109 trm_print_section_as_family_tree(rpc, pc, tc);
4110 }
4111}
4112
4113/**
4114 * @brief For notifications section: print 'notifications' keyword
4115 * and all its nodes.
4116 * @param[in] pc contains mainly functions for printing.
4117 * @param[in,out] tc is the tree context.
4118 */
4119static void
4120trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4121{
4122 struct trt_keyword_stmt notifs;
4123
aPiecek01598c02021-04-23 14:18:24 +02004124 notifs = tro_modi_get_notifications(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004125
4126 if (!(TRP_KEYWORD_STMT_IS_EMPTY(notifs))) {
4127 ly_print_(pc->out, "\n");
4128 ly_print_(pc->out, "\n");
4129 trm_print_section_as_family_tree(notifs, pc, tc);
4130 }
4131}
4132
4133/**
4134 * @brief For all grouping sections: print 'grouping' keyword, its name
4135 * and all nodes.
4136 * @param[in] pc contains mainly functions for printing.
4137 * @param[in,out] tc is the tree context.
4138 */
4139static void
4140trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4141{
4142 ly_bool once;
4143
aPiecek01598c02021-04-23 14:18:24 +02004144 if (tc->lysc_tree) {
aPiecekdc8fd572021-04-19 10:47:23 +02004145 return;
4146 }
4147
4148 once = 1;
aPiecek01598c02021-04-23 14:18:24 +02004149 for (struct trt_keyword_stmt ks = trop_modi_next_grouping(tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004150 !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
aPiecek01598c02021-04-23 14:18:24 +02004151 ks = trop_modi_next_grouping(tc)) {
aPiecekdc8fd572021-04-19 10:47:23 +02004152 if (once) {
4153 ly_print_(pc->out, "\n");
4154 ly_print_(pc->out, "\n");
4155 once = 0;
4156 } else {
4157 ly_print_(pc->out, "\n");
4158 }
4159 trm_print_section_as_subtree(ks, pc, tc);
4160 }
4161}
4162
4163/**
4164 * @brief For all yang-data sections: print 'yang-data' keyword
4165 * and all its nodes.
4166 * @param[in] pc contains mainly functions for printing.
4167 * @param[in,out] tc is the tree context.
4168 */
4169static void
aPiecek96baa7f2021-04-23 12:32:00 +02004170trm_print_yang_data(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
aPiecekdc8fd572021-04-19 10:47:23 +02004171{
aPiecek96baa7f2021-04-23 12:32:00 +02004172 ly_bool once;
4173 LY_ARRAY_COUNT_TYPE count;
4174
4175 count = LY_ARRAY_COUNT(tc->pmod->exts);
4176 if (count == 0) {
4177 return;
4178 }
4179
4180 once = 1;
4181 for (LY_ARRAY_COUNT_TYPE u = 0; u < count; ++u) {
4182 struct trt_keyword_stmt ks;
4183
aPiecek01598c02021-04-23 14:18:24 +02004184 /* Only ::lys_compile_extension_instance() can set item
aPiecek96baa7f2021-04-23 12:32:00 +02004185 * ::lysp_ext_instance.parsed.
4186 */
4187 if (!tc->pmod->exts[u].parsed) {
4188 /* print at least the yang-data names */
4189 trop_yang_data_sections(tc->pmod->exts, pc->max_line_length, pc->out);
4190 continue;
4191 }
4192
4193 ks = tro_modi_next_yang_data(tc, u);
4194 if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4195 break;
4196 }
4197
4198 if (once) {
4199 ly_print_(pc->out, "\n");
4200 ly_print_(pc->out, "\n");
4201 once = 0;
4202 } else {
4203 ly_print_(pc->out, "\n");
4204 }
4205
4206 trm_print_section_as_family_tree(ks, pc, tc);
4207 }
aPiecekdc8fd572021-04-19 10:47:23 +02004208}
4209
4210/**
4211 * @brief Print sections module, augment, rpcs, notifications,
4212 * grouping, yang-data.
4213 * @param[in] pc contains mainly functions for printing.
4214 * @param[in,out] tc is the tree context.
4215 */
4216static void
4217trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4218{
4219 trm_print_module_section(pc, tc);
4220 trm_print_augmentations(pc, tc);
4221 trm_print_rpcs(pc, tc);
4222 trm_print_notifications(pc, tc);
4223 trm_print_groupings(pc, tc);
4224 trm_print_yang_data(pc, tc);
4225 ly_print_(pc->out, "\n");
aPiecek61d062b2020-11-02 11:05:09 +01004226}
4227
aPiecek874ea4d2021-04-19 12:26:36 +02004228/**********************************************************************
aPiecek61d062b2020-11-02 11:05:09 +01004229 * Definition of module interface
aPiecek874ea4d2021-04-19 12:26:36 +02004230 *********************************************************************/
aPiecek61d062b2020-11-02 11:05:09 +01004231
4232LY_ERR
aPiecek3f247652021-04-19 13:40:25 +02004233tree_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 +01004234{
4235 struct trt_printer_ctx pc;
4236 struct trt_tree_ctx tc;
4237 struct ly_out *new_out;
4238 LY_ERR erc;
4239 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4240
aPiecekdc8fd572021-04-19 10:47:23 +02004241 LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL);
4242
aPiecek61d062b2020-11-02 11:05:09 +01004243 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4244 return erc;
4245 }
4246
4247 line_length = line_length == 0 ? SIZE_MAX : line_length;
aPiecek3f247652021-04-19 13:40:25 +02004248 if ((module->ctx->flags & LY_CTX_SET_PRIV_PARSED) && module->compiled) {
4249 trm_lysc_tree_ctx(module, new_out, line_length, &pc, &tc);
4250 } else {
4251 trm_lysp_tree_ctx(module, new_out, line_length, &pc, &tc);
4252 }
aPiecek61d062b2020-11-02 11:05:09 +01004253
4254 trm_print_sections(&pc, &tc);
aPiecekdc8fd572021-04-19 10:47:23 +02004255 erc = clb_arg.last_error;
aPiecek61d062b2020-11-02 11:05:09 +01004256
4257 ly_out_free(new_out, NULL, 1);
4258
aPiecekdc8fd572021-04-19 10:47:23 +02004259 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004260}
4261
4262LY_ERR
aPiecek153b00f2021-04-20 13:52:57 +02004263tree_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 +01004264{
aPiecek153b00f2021-04-20 13:52:57 +02004265 struct trt_printer_ctx pc;
4266 struct trt_tree_ctx tc;
4267 struct ly_out *new_out;
4268 struct trt_wrapper wr;
4269 LY_ERR erc;
4270 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4271
4272 assert(out && node);
4273
4274 if (!(node->module->ctx->flags & LY_CTX_SET_PRIV_PARSED)) {
4275 return LY_EINVAL;
4276 }
4277
4278 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4279 return erc;
4280 }
4281
4282 line_length = line_length == 0 ? SIZE_MAX : line_length;
4283 trm_lysc_tree_ctx(node->module, new_out, line_length, &pc, &tc);
4284
4285 trp_print_keyword_stmt(pc.fp.read.module_name(&tc), pc.max_line_length, 0, pc.out);
4286 trb_print_parents(node, &pc, &tc);
4287
4288 if (!(options & LYS_PRINT_NO_SUBSTMT)) {
4289 tc.cn = lysc_node_child(node);
4290 wr = trb_count_depth(tc.cn);
4291 trb_print_family_tree(wr, &pc, &tc);
4292 }
4293 ly_print_(out, "\n");
4294
4295 erc = clb_arg.last_error;
4296 ly_out_free(new_out, NULL, 1);
4297
4298 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004299}
4300
4301LY_ERR
aPiecek9f792e52021-04-21 08:33:56 +02004302tree_print_parsed_submodule(struct ly_out *out, const struct lysp_submodule *submodp, uint32_t UNUSED(options), size_t line_length)
aPiecek61d062b2020-11-02 11:05:09 +01004303{
aPiecek9f792e52021-04-21 08:33:56 +02004304 struct trt_printer_ctx pc;
4305 struct trt_tree_ctx tc;
4306 struct ly_out *new_out;
4307 LY_ERR erc;
4308 struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4309
4310 assert(submodp);
4311 LY_CHECK_ARG_RET(submodp->mod->ctx, out, LY_EINVAL);
4312
4313 if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4314 return erc;
4315 }
4316
4317 line_length = line_length == 0 ? SIZE_MAX : line_length;
4318 trm_lysp_tree_ctx(submodp->mod, new_out, line_length, &pc, &tc);
4319 tc.pmod = (struct lysp_module *)submodp;
4320 tc.tpn = submodp->data;
4321 tc.pn = tc.tpn;
4322
4323 trm_print_sections(&pc, &tc);
4324 erc = clb_arg.last_error;
4325
4326 ly_out_free(new_out, NULL, 1);
4327
4328 return erc;
aPiecek61d062b2020-11-02 11:05:09 +01004329}