Coverage Report

Created: 2025-07-14 06:48

/src/libyang/src/printer_tree.c
Line
Count
Source (jump to first uncovered line)
1
/**
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
13
 *
14
 * @section TRP_DESIGN Design
15
 *
16
 * @code
17
 *          +---------+    +---------+    +---------+
18
 *   output |   trp   |    |   trb   |    |   tro   |
19
 *      <---+  Print  +<---+  Browse +<-->+  Obtain |
20
 *          |         |    |         |    |         |
21
 *          +---------+    +----+----+    +---------+
22
 *                              ^
23
 *                              |
24
 *                         +----+----+
25
 *                         |   trm   |
26
 *                         | Manager |
27
 *                         |         |
28
 *                         +----+----+
29
 *                              ^
30
 *                              | input
31
 *                              +
32
 * @endcode
33
 *
34
 * @subsection TRP_GLOSSARY Glossary
35
 *
36
 * @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
40
 * Browse functions (@ref TRP_trb).
41
 *
42
 * @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
45
 * the tree contains (@ref lysc_node or @ref lysp_node), because it
46
 * requires a ready-made getter functions for traversing the tree
47
 * (@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
50
 * traverse nodes in the tree, for example, to calculate the alignment
51
 * gap before the nodes \<type\> in the YANG Tree Diagram.
52
 * The obtained @ref trt_node is passed to the @ref TRP_trp functions
53
 * to print the Tree diagram.
54
 *
55
 * @subsubsection TRP_tro tro
56
 * Functions that provide an extra wrapper for the libyang library.
57
 * The Obtain functions are further specialized according to whether
58
 * they operate on lysp_tree (@ref TRP_trop) or lysc_tree
59
 * (@ref TRP_troc). If they are general algorithms, then they have the
60
 * prefix \b tro_. The Obtain functions provide information to
61
 * @ref TRP_trb functions for printing the Tree diagram.
62
 *
63
 * @subsubsection TRP_trop trop
64
 * Functions for Obtaining information from Parsed schema tree.
65
 *
66
 * @subsubsection TRP_troc troc
67
 * Functions for Obtaining information from Compiled schema tree.
68
 *
69
 * @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
82
 * @ref TRP_tro, @ref TRP_trop or @ref TRP_troc functions because
83
 * they are the only ones dependent on libyang implementation.
84
 * In special cases, changes will also need to be made to the
85
 * @ref TRP_trp functions if a special algorithm is needed to print
86
 * (right now this is prepared for printing list's keys
87
 * and if-features).
88
 */
89
90
#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
99
/**
100
 * @brief List of available actions.
101
 */
102
typedef enum {
103
    TRD_PRINT = 0,  /**< Normal behavior. It just prints. */
104
    TRD_CHAR_COUNT  /**< Characters will be counted instead of printing. */
105
} trt_ly_out_clb_arg_flag;
106
107
/**
108
 * @brief Structure is passed as 'writeclb' argument
109
 * to the ::ly_out_new_clb().
110
 */
111
struct ly_out_clb_arg {
112
    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. */
116
};
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) \
122
0
    (struct ly_out_clb_arg) { \
123
0
        .mode = MODE, .out = OUT, \
124
0
        .counter = COUNTER, .last_error = LAST_ERROR \
125
0
    }
126
127
/**********************************************************************
128
 * Print getters
129
 *********************************************************************/
130
131
/**
132
 * @brief Callback functions that prints special cases.
133
 *
134
 * It just groups together tree context with trt_fp_print.
135
 */
136
struct trt_cf_print {
137
    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. */
139
};
140
141
/**
142
 * @brief Callback functions for printing special cases.
143
 *
144
 * 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.
148
 * However, this depends on how the libyang library is implemented.
149
 * 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.
152
 * Functions must print including spaces or delimiters between names.
153
 */
154
struct 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
 */
162
struct 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) \
171
0
    (struct trt_pck_print) {.tree_ctx = TREE_CTX, .fps = FP_PRINT}
172
173
/**********************************************************************
174
 * Indent
175
 *********************************************************************/
176
177
/**
178
 * @brief Constants which are defined in the RFC or are observable
179
 * from the pyang tool.
180
 */
181
typedef 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
 */
194
typedef 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
0
#define TRD_LINEBREAK -1
202
203
/**
204
 * @brief Records the alignment between the individual
205
 * elements of the node.
206
 *
207
 * @see trp_default_indent_in_node, trp_try_normal_indent_in_node
208
 */
209
struct trt_indent_in_node {
210
    trt_indent_in_node_type type;   /**< Type of indent in node. */
211
    int16_t btw_name_opts;          /**< Indent between node name and \<opts\>. */
212
    int16_t btw_opts_type;          /**< Indent between \<opts\> and \<type\>. */
213
    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
 */
219
typedef 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.
228
 * This place is in multiples of ::TRD_INDENT_BTW_SIBLINGS.
229
 *
230
 * @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
233
 */
234
struct 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 \
251
0
    (struct trt_wrapper) { \
252
0
        .type = TRD_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0 \
253
0
    }
254
255
/**
256
 * @brief Get wrapper related to subsection
257
 * e.g. Augmenations or Groupings.
258
 *
259
 * @code
260
 * module: <module-name>
261
 *   +--<node>
262
 *
263
 *   augment <target-node>:
264
 *     +--<node>
265
 * @endcode
266
 */
267
#define TRP_INIT_WRAPPER_BODY \
268
0
    (struct trt_wrapper) { \
269
0
        .type = TRD_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0 \
270
0
    }
271
272
/**
273
 * @brief Package which only groups wrapper and indent in node.
274
 */
275
struct 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) \
284
0
    (struct trt_pck_indent){ \
285
0
        .wrapper = WRAPPER, .in_node = INDENT_IN_NODE \
286
0
    }
287
288
/**********************************************************************
289
 * status
290
 *********************************************************************/
291
292
/**
293
 * @brief Status of the node.
294
 *
295
 * @see trp_print_status
296
 */
297
typedef enum {
298
    TRD_STATUS_TYPE_EMPTY = 0,
299
    TRD_STATUS_TYPE_CURRENT,    /**< ::LYS_STATUS_CURR */
300
    TRD_STATUS_TYPE_DEPRECATED, /**< ::LYS_STATUS_DEPRC */
301
    TRD_STATUS_TYPE_OBSOLETE    /**< ::LYS_STATUS_OBSLT */
302
} trt_status_type;
303
304
/**********************************************************************
305
 * flags
306
 *********************************************************************/
307
308
/**
309
 * @brief Flag of the node.
310
 *
311
 * @see trp_print_flags, trp_get_flags_strlen
312
 */
313
typedef enum {
314
    TRD_FLAGS_TYPE_EMPTY = 0,           /**< -- */
315
    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
324
/**********************************************************************
325
 * node_name and opts
326
 *********************************************************************/
327
328
0
#define TRD_NODE_NAME_PREFIX_CHOICE "("
329
0
#define TRD_NODE_NAME_PREFIX_CASE ":("
330
0
#define TRD_NODE_NAME_TRIPLE_DOT "..."
331
332
/**
333
 * @brief Type of the node.
334
 *
335
 * Used mainly to complete the correct \<opts\> next to or
336
 * around the \<name\>.
337
 */
338
typedef enum {
339
    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. */
350
} trt_node_type;
351
352
/**
353
 * @brief Type of node and his name.
354
 *
355
 * @see TRP_EMPTY_NODE_NAME, TRP_NODE_NAME_IS_EMPTY,
356
 * trp_print_node_name, trp_mark_is_used, trp_print_opts_keys
357
 */
358
struct trt_node_name {
359
    trt_node_type type;         /**< Type of the node relevant for printing. */
360
    const char *module_prefix;  /**< Prefix defined in the module where the node is defined. */
361
    const char *str;            /**< Name of the node. */
362
};
363
364
/**
365
 * @brief Create struct trt_node_name as empty.
366
 */
367
#define TRP_EMPTY_NODE_NAME \
368
0
    (struct trt_node_name) { \
369
0
        .type = TRD_NODE_ELSE, .module_prefix = NULL, .str = NULL \
370
0
    }
371
372
/**
373
 * @brief Check if struct trt_node_name is empty.
374
 */
375
#define TRP_NODE_NAME_IS_EMPTY(NODE_NAME) \
376
0
    !NODE_NAME.str
377
378
/**
379
 * @brief Every \<opts\> mark except string of list's keys
380
 * has a length of one.
381
 */
382
0
#define TRD_OPTS_MARK_LENGTH 1
383
384
/**********************************************************************
385
 * type
386
 *********************************************************************/
387
388
/**
389
 * @brief Type of the \<type\>
390
 */
391
typedef enum {
392
    TRD_TYPE_NAME = 0,  /**< Type is just a name that does not require special treatment. */
393
    TRD_TYPE_TARGET,    /**< Should have a form "-> TARGET", where TARGET is the leafref path. */
394
    TRD_TYPE_LEAFREF,   /**< This type is set automatically by the 'trp' algorithm.
395
                             So set type as ::TRD_TYPE_TARGET. */
396
    TRD_TYPE_EMPTY      /**< Type is not used at all. */
397
} trt_type_type;
398
399
/**
400
 * @brief \<type\> in the \<node\>.
401
 *
402
 * @see TRP_EMPTY_TRT_TYPE, TRP_TRT_TYPE_IS_EMPTY, trp_print_type
403
 */
404
struct trt_type {
405
    trt_type_type type; /**< Type of the \<type\>. */
406
    const char *str;    /**< Path or name of the type. */
407
};
408
409
/**
410
 * @brief Create empty struct trt_type.
411
 */
412
#define TRP_EMPTY_TRT_TYPE \
413
0
    (struct trt_type) {.type = TRD_TYPE_EMPTY, .str = NULL}
414
415
/**
416
 * @brief Check if struct trt_type is empty.
417
 */
418
#define TRP_TRT_TYPE_IS_EMPTY(TYPE_OF_TYPE) \
419
0
    TYPE_OF_TYPE.type == TRD_TYPE_EMPTY
420
421
/**
422
 * @brief Initialize struct trt_type by parameters.
423
 */
424
#define TRP_INIT_TRT_TYPE(TYPE_OF_TYPE, STRING) \
425
0
    (struct trt_type) {.type = TYPE_OF_TYPE, .str = STRING}
426
427
/**********************************************************************
428
 * node
429
 *********************************************************************/
430
431
/**
432
 * @brief \<node\> data for printing.
433
 *
434
 * It contains RFC's:
435
 * \<status\>--\<flags\> \<name\>\<opts\> \<type\> \<if-features\>.
436
 * Item \<opts\> is moved to part struct trt_node_name.
437
 * For printing [\<keys\>] and if-features is required special
438
 * functions which prints them.
439
 *
440
 * @see TRP_EMPTY_NODE, trp_node_is_empty, trp_node_body_is_empty,
441
 * trp_print_node_up_to_name, trp_print_divided_node_up_to_name,
442
 * trp_print_node
443
 */
444
struct trt_node {
445
    trt_status_type status;     /**< \<status\>. */
446
    trt_flags_type flags;       /**< \<flags\>. */
447
    struct trt_node_name name;  /**< \<node\> with \<opts\> mark or [\<keys\>]. */
448
    struct trt_type type;       /**< \<type\> contains the name of the type or type for leafref. */
449
    ly_bool iffeatures;         /**< \<if-features\>. Value 1 means that iffeatures are present and
450
                                     will be printed by trt_fp_print.print_features_names callback. */
451
    ly_bool last_one;           /**< Information about whether the node is the last. */
452
};
453
454
/**
455
 * @brief Create struct trt_node as empty.
456
 */
457
#define TRP_EMPTY_NODE \
458
0
    (struct trt_node) { \
459
0
        .status = TRD_STATUS_TYPE_EMPTY, \
460
0
        .flags = TRD_FLAGS_TYPE_EMPTY, \
461
0
        .name = TRP_EMPTY_NODE_NAME, \
462
0
        .type = TRP_EMPTY_TRT_TYPE, \
463
0
        .iffeatures = 0, \
464
0
        .last_one = 1 \
465
0
    }
466
467
/**
468
 * @brief Package which only groups indent and node.
469
 */
470
struct trt_pair_indent_node {
471
    struct trt_indent_in_node indent;
472
    struct trt_node node;
473
};
474
475
/**
476
 * @brief Initialize struct trt_pair_indent_node by parameters.
477
 */
478
#define TRP_INIT_PAIR_INDENT_NODE(INDENT_IN_NODE, NODE) \
479
0
    (struct trt_pair_indent_node) { \
480
0
        .indent = INDENT_IN_NODE, .node = NODE \
481
0
    }
482
483
/**********************************************************************
484
 * statement
485
 *********************************************************************/
486
487
0
#define TRD_TOP_KEYWORD_MODULE "module"
488
0
#define TRD_TOP_KEYWORD_SUBMODULE "submodule"
489
490
0
#define TRD_BODY_KEYWORD_AUGMENT "augment"
491
0
#define TRD_BODY_KEYWORD_RPC "rpcs"
492
0
#define TRD_BODY_KEYWORD_NOTIF "notifications"
493
0
#define TRD_BODY_KEYWORD_GROUPING "grouping"
494
0
#define TRD_BODY_KEYWORD_YANG_DATA "yang-data"
495
496
/**
497
 * @brief Type of the trt_keyword.
498
 */
499
typedef enum {
500
    TRD_KEYWORD_EMPTY = 0,
501
    TRD_KEYWORD_MODULE,
502
    TRD_KEYWORD_SUBMODULE,
503
    TRD_KEYWORD_AUGMENT,
504
    TRD_KEYWORD_RPC,
505
    TRD_KEYWORD_NOTIF,
506
    TRD_KEYWORD_GROUPING,
507
    TRD_KEYWORD_YANG_DATA
508
} trt_keyword_type;
509
510
/**
511
 * @brief Main sign of the tree nodes.
512
 *
513
 * @see TRP_EMPTY_KEYWORD_STMT, TRP_KEYWORD_STMT_IS_EMPTY
514
 * trt_print_keyword_stmt_begin, trt_print_keyword_stmt_str,
515
 * trt_print_keyword_stmt_end, trp_print_keyword_stmt
516
 * trp_keyword_type_strlen
517
 *
518
 */
519
struct trt_keyword_stmt {
520
    trt_keyword_type type;  /**< String containing some of the top or body keyword. */
521
    const char *str;        /**< Name or path, it determines the type. */
522
};
523
524
/**
525
 * @brief Create struct trt_keyword_stmt as empty.
526
 */
527
#define TRP_EMPTY_KEYWORD_STMT \
528
0
    (struct trt_keyword_stmt) {.type = TRD_KEYWORD_EMPTY, .str = NULL}
529
530
/**
531
 * @brief Check if struct trt_keyword_stmt is empty.
532
 */
533
#define TRP_KEYWORD_STMT_IS_EMPTY(KEYWORD_TYPE) \
534
0
    KEYWORD_TYPE.type == TRD_KEYWORD_EMPTY
535
536
/**
537
 * @brief Initialize struct trt_keyword_stmt by parameters.
538
 */
539
#define TRP_INIT_KEYWORD_STMT(KEYWORD_TYPE, STRING) \
540
0
    (struct trt_keyword_stmt) {.type = KEYWORD_TYPE, .str = STRING}
541
542
/**********************************************************************
543
 * Modify getters
544
 *********************************************************************/
545
546
struct trt_parent_cache;
547
548
/**
549
 * @brief Functions that change the state of the tree_ctx structure.
550
 *
551
 * The 'trop' or 'troc' functions are set here, which provide data
552
 * for the 'trp' printing functions and are also called from the
553
 * 'trb' browsing functions when walking through a tree. These callback
554
 * functions need to be checked or reformulated if changes to the
555
 * libyang library affect the printing tree. For all, if the value
556
 * cannot be returned, its empty version obtained by relevant TRP_EMPTY
557
 * macro is returned.
558
 */
559
struct trt_fp_modify_ctx {
560
    ly_bool (*parent)(struct trt_tree_ctx *);                                           /**< Jump to parent node. Return true if parent exists. */
561
    void (*first_sibling)(struct trt_tree_ctx *);                                       /**< Jump on the first of the siblings. */
562
    struct trt_node (*next_sibling)(struct trt_parent_cache, struct trt_tree_ctx *);    /**< Jump to next sibling of the current node. */
563
    struct trt_node (*next_child)(struct trt_parent_cache, struct trt_tree_ctx *);      /**< Jump to the child of the current node. */
564
};
565
566
/**********************************************************************
567
 * Read getters
568
 *********************************************************************/
569
570
/**
571
 * @brief Functions that do not change the state of the tree_structure.
572
 *
573
 * For details see trt_fp_modify_ctx.
574
 */
575
struct trt_fp_read {
576
    struct trt_keyword_stmt (*module_name)(const struct trt_tree_ctx *);            /**< Get name of the module. */
577
    struct trt_node (*node)(struct trt_parent_cache, const struct trt_tree_ctx *);  /**< Get current node. */
578
    ly_bool (*if_sibling_exists)(const struct trt_tree_ctx *);                      /**< Check if node's sibling exists. */
579
};
580
581
/**********************************************************************
582
 * All getters
583
 *********************************************************************/
584
585
/**
586
 * @brief A set of all necessary functions that must be provided
587
 * for the printer.
588
 */
589
struct trt_fp_all {
590
    struct trt_fp_modify_ctx modify;    /**< Function pointers which modify state of trt_tree_ctx. */
591
    struct trt_fp_read read;            /**< Function pointers which only reads state of trt_tree_ctx. */
592
    struct trt_fp_print print;          /**< Functions pointers for printing special items in node. */
593
};
594
595
/**********************************************************************
596
 * Printer context
597
 *********************************************************************/
598
599
/**
600
 * @brief Main structure for @ref TRP_trp part.
601
 */
602
struct trt_printer_ctx {
603
    struct ly_out *out;     /**< Handler to printing. */
604
    struct trt_fp_all fp;   /**< @ref TRP_tro functions callbacks. */
605
    size_t max_line_length; /**< The maximum number of characters that can be
606
                               printed on one line, including the last. */
607
};
608
609
/**********************************************************************
610
 * Tro functions
611
 *********************************************************************/
612
613
/**
614
 * @brief The name of the section to which the node belongs.
615
 */
616
typedef enum {
617
    TRD_SECT_MODULE = 0,    /**< The node belongs to the "module: <module_name>:" label. */
618
    TRD_SECT_AUGMENT,       /**< The node belongs to some "augment <target-node>:" label. */
619
    TRD_SECT_RPCS,          /**< The node belongs to the "rpcs:" label. */
620
    TRD_SECT_NOTIF,         /**< The node belongs to the "notifications:" label. */
621
    TRD_SECT_GROUPING,      /**< The node belongs to some "grouping <grouping-name>:" label. */
622
    TRD_SECT_YANG_DATA      /**< The node belongs to some "yang-data <yang-data-name>:" label. */
623
} trt_actual_section;
624
625
/**
626
 * @brief Types of nodes that have some effect on their children.
627
 */
628
typedef enum {
629
    TRD_ANCESTOR_ELSE = 0,      /**< Everything not listed. */
630
    TRD_ANCESTOR_RPC_INPUT,     /**< ::LYS_INPUT */
631
    TRD_ANCESTOR_RPC_OUTPUT,    /**< ::LYS_OUTPUT */
632
    TRD_ANCESTOR_NOTIF          /**< ::LYS_NOTIF */
633
} trt_ancestor_type;
634
635
/**
636
 * @brief Saved information when browsing the tree downwards.
637
 *
638
 * This structure helps prevent frequent retrieval of information
639
 * from the tree. Functions @ref TRP_trb are designed to preserve
640
 * this structures during their recursive calls. This functions do not
641
 * interfere in any way with this data. This structure
642
 * is used by @ref TRP_trop functions which, thanks to this
643
 * structure, can return a node with the correct data. The word
644
 * \b parent is in the structure name, because this data refers to
645
 * the last parent and at the same time the states of its
646
 * ancestors data. Only the function jumping on the child
647
 * (next_child(...)) creates this structure, because the pointer
648
 * to the current node moves down the tree. It's like passing
649
 * the genetic code to children. Some data must be inherited and
650
 * there are two approaches to this problem. Either it will always
651
 * be determined which inheritance states belong to the current node
652
 * (which can lead to regular travel to the root node) or
653
 * the inheritance states will be stored during the recursive calls.
654
 * So the problem was solved by the second option. Why does
655
 * the structure contain this data? Because it walks through
656
 * the lysp tree. For walks through the lysc tree is trt_parent_cache
657
 * useless.
658
 *
659
 * @see TRO_EMPTY_PARENT_CACHE, tro_parent_cache_for_child
660
 */
661
struct trt_parent_cache {
662
    trt_ancestor_type ancestor; /**< Some types of nodes have a special effect on their children. */
663
    uint16_t lys_status;        /**< Inherited status CURR, DEPRC, OBSLT. */
664
    uint16_t lys_config;        /**< Inherited config W or R. */
665
    const struct lysp_node_list *last_list; /**< The last ::LYS_LIST passed. */
666
};
667
668
/**
669
 * @brief Return trt_parent_cache filled with default values.
670
 */
671
#define TRP_EMPTY_PARENT_CACHE \
672
0
    (struct trt_parent_cache) { \
673
0
        .ancestor = TRD_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \
674
0
        .lys_config = LYS_CONFIG_W, .last_list = NULL \
675
0
    }
676
677
/**
678
 * @brief Main structure for browsing the libyang tree
679
 */
680
struct trt_tree_ctx {
681
    ly_bool lysc_tree;                              /**< The lysc nodes are used for browsing through the tree.
682
                                                         It is assumed that once set, it does not change.
683
                                                         If it is true then trt_tree_ctx.pn and
684
                                                         trt_tree_ctx.tpn are not used.
685
                                                         If it is false then trt_tree_ctx.cn is not used. */
686
    trt_actual_section section;                     /**< To which section pn points. */
687
    const struct lysp_module *pmod;                 /**< Parsed YANG schema tree. */
688
    const struct lysc_module *cmod;                 /**< Compiled YANG schema tree. */
689
    const struct lysp_node *pn;                     /**< Actual pointer to parsed node. */
690
    union {
691
        const struct lysp_node *tpn;                /**< Pointer to actual top-node. */
692
        const struct lysp_ext_instance *tpn_ext;    /**< Actual top-node is extension. Item trt_tree_ctx.section
693
                                                         is set to TRD_SECT_YANG_DATA. */
694
    };
695
    const struct lysc_node *cn;                     /**< Actual pointer to compiled node. */
696
};
697
698
/**
699
 * @brief Get lysp_node from trt_tree_ctx.cn.
700
 */
701
#define TRP_TREE_CTX_GET_LYSP_NODE(CN) \
702
0
    ((const struct lysp_node *)CN->priv)
703
704
/** Getter function for ::trop_node_charptr(). */
705
typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
706
707
/**
708
 * @brief Simple getter functions for lysp and lysc nodes.
709
 *
710
 * This structure is useful if we have a general algorithm
711
 * (tro function) that can be used for both lysc and lysp nodes.
712
 * Thanks to this structure, we prevent code redundancy.
713
 * We don't have to write basically the same algorithm twice
714
 * for lysp and lysc trees.
715
 */
716
struct tro_getters
717
{
718
    uint16_t (*nodetype)(const void *);         /**< Get nodetype. */
719
    const void *(*next)(const void *);          /**< Get sibling. */
720
    const void *(*parent)(const void *);        /**< Get parent. */
721
    const void *(*child)(const void *);         /**< Get child. */
722
    const void *(*actions)(const void *);       /**< Get actions. */
723
    const void *(*action_input)(const void *);  /**< Get input action from action node. */
724
    const void *(*action_output)(const void *); /**< Get output action from action node. */
725
    const void *(*notifs)(const void *);        /**< Get notifs. */
726
};
727
728
/**********************************************************************
729
 * Definition of the general Trg functions
730
 *********************************************************************/
731
732
/**
733
 * @brief Print a substring but limited to the maximum length.
734
 * @param[in] str is pointer to source.
735
 * @param[in] len is number of characters to be printed.
736
 * @param[in,out] out is output handler.
737
 * @return str parameter shifted by len.
738
 */
739
static const char *
740
trg_print_substr(const char *str, size_t len, struct ly_out *out)
741
0
{
742
0
    for (size_t i = 0; i < len; i++) {
743
0
        ly_print_(out, "%c", str[0]);
744
0
        str++;
745
0
    }
746
0
    return str;
747
0
}
748
749
/**
750
 * @brief Pointer is not NULL and does not point to an empty string.
751
 * @param[in] str is pointer to string to be checked.
752
 * @return 1 if str pointing to non empty string otherwise 0.
753
 */
754
static ly_bool
755
trg_charptr_has_data(const char *str)
756
0
{
757
0
    return (str) && (str[0] != '\0');
758
0
}
759
760
/**
761
 * @brief Check if @p word in @p src is present where words are
762
 * delimited by @p delim.
763
 * @param[in] src is source where words are separated by @p delim.
764
 * @param[in] word to be searched.
765
 * @param[in] delim is delimiter between @p words in @p src.
766
 * @return 1 if src contains @p word otherwise 0.
767
 */
768
static ly_bool
769
trg_word_is_present(const char *src, const char *word, char delim)
770
0
{
771
0
    const char *hit;
772
773
0
    if ((!src) || (src[0] == '\0') || (!word)) {
774
0
        return 0;
775
0
    }
776
777
0
    hit = strstr(src, word);
778
779
0
    if (hit) {
780
        /* word was founded at the begin of src
781
         * OR it match somewhere after delim
782
         */
783
0
        if ((hit == src) || (hit[-1] == delim)) {
784
            /* end of word was founded at the end of src
785
             * OR end of word was match somewhere before delim
786
             */
787
0
            char delim_or_end = (hit + strlen(word))[0];
788
0
            if ((delim_or_end == '\0') || (delim_or_end == delim)) {
789
0
                return 1;
790
0
            }
791
0
        }
792
        /* after -> hit is just substr and it's not the whole word */
793
        /* jump to the next word */
794
0
        for ( ; (src[0] != '\0') && (src[0] != delim); src++) {}
795
        /* skip delim */
796
0
        src = src[0] == '\0' ? src : src + 1;
797
        /* continue with searching */
798
0
        return trg_word_is_present(src, word, delim);
799
0
    } else {
800
0
        return 0;
801
0
    }
802
0
}
803
804
/**********************************************************************
805
 * Definition of printer functions
806
 *********************************************************************/
807
808
/**
809
 * @brief Write callback for ::ly_out_new_clb().
810
 *
811
 * @param[in] user_data is type of struct ly_out_clb_arg.
812
 * @param[in] buf contains input characters
813
 * @param[in] count is number of characters in buf.
814
 * @return Number of printed bytes.
815
 * @return Negative value in case of error.
816
 */
817
static ssize_t
818
trp_ly_out_clb_func(void *user_data, const void *buf, size_t count)
819
0
{
820
0
    LY_ERR erc = LY_SUCCESS;
821
0
    struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data;
822
823
0
    switch (data->mode) {
824
0
    case TRD_PRINT:
825
0
        erc = ly_write_(data->out, buf, count);
826
0
        break;
827
0
    case TRD_CHAR_COUNT:
828
0
        data->counter = data->counter + count;
829
0
        break;
830
0
    default:
831
0
        break;
832
0
    }
833
834
0
    if (erc != LY_SUCCESS) {
835
0
        data->last_error = erc;
836
0
        return -1;
837
0
    } else {
838
0
        return count;
839
0
    }
840
0
}
841
842
/**
843
 * @brief Check that indent in node can be considered as equivalent.
844
 * @param[in] first is the first indent in node.
845
 * @param[in] second is the second indent in node.
846
 * @return 1 if indents are equivalent otherwise 0.
847
 */
848
static ly_bool
849
trp_indent_in_node_are_eq(struct trt_indent_in_node first, struct trt_indent_in_node second)
850
0
{
851
0
    const ly_bool a = first.type == second.type;
852
0
    const ly_bool b = first.btw_name_opts == second.btw_name_opts;
853
0
    const ly_bool c = first.btw_opts_type == second.btw_opts_type;
854
0
    const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures;
855
856
0
    return a && b && c && d;
857
0
}
858
859
/**
860
 * @brief Setting space character because node is last sibling.
861
 * @param[in] wr is wrapper over which the shift operation
862
 * is to be performed.
863
 * @return New shifted wrapper.
864
 */
865
static struct trt_wrapper
866
trp_wrapper_set_shift(struct trt_wrapper wr)
867
0
{
868
0
    assert(wr.actual_pos < 64);
869
    /* +--<node>
870
     *    +--<node>
871
     */
872
0
    wr.actual_pos++;
873
0
    return wr;
874
0
}
875
876
/**
877
 * @brief Setting '|' symbol because node is divided or
878
 * it is not last sibling.
879
 * @param[in] wr is source of wrapper.
880
 * @return New wrapper which is marked at actual position and shifted.
881
 */
882
static struct trt_wrapper
883
trp_wrapper_set_mark(struct trt_wrapper wr)
884
0
{
885
0
    assert(wr.actual_pos < 64);
886
0
    wr.bit_marks1 |= 1U << wr.actual_pos;
887
0
    return trp_wrapper_set_shift(wr);
888
0
}
889
890
/**
891
 * @brief Setting ' ' symbol if node is last sibling otherwise set '|'.
892
 * @param[in] wr is actual wrapper.
893
 * @param[in] last_one is flag. Value 1 saying if the node is the last
894
 * and has no more siblings.
895
 * @return New wrapper for the actual node.
896
 */
897
static struct trt_wrapper
898
trp_wrapper_if_last_sibling(struct trt_wrapper wr, ly_bool last_one)
899
0
{
900
0
    return last_one ? trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
901
0
}
902
903
/**
904
 * @brief Test if the wrappers are equivalent.
905
 * @param[in] first is the first wrapper.
906
 * @param[in] second is the second wrapper.
907
 * @return 1 if the wrappers are equivalent otherwise 0.
908
 */
909
static ly_bool
910
trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second)
911
0
{
912
0
    const ly_bool a = first.type == second.type;
913
0
    const ly_bool b = first.bit_marks1 == second.bit_marks1;
914
0
    const ly_bool c = first.actual_pos == second.actual_pos;
915
916
0
    return a && b && c;
917
0
}
918
919
/**
920
 * @brief Print "  |  " sequence on line.
921
 * @param[in] wr is wrapper to be printed.
922
 * @param[in,out] out is output handler.
923
 */
924
static void
925
trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out)
926
0
{
927
0
    uint32_t lb;
928
929
0
    if (wr.type == TRD_WRAPPER_TOP) {
930
0
        lb = TRD_INDENT_LINE_BEGIN;
931
0
    } else if (wr.type == TRD_WRAPPER_BODY) {
932
0
        lb = TRD_INDENT_LINE_BEGIN * 2;
933
0
    } else {
934
0
        lb = TRD_INDENT_LINE_BEGIN;
935
0
    }
936
937
0
    ly_print_(out, "%*c", lb, ' ');
938
939
0
    if (trp_wrapper_eq(wr, TRP_INIT_WRAPPER_TOP)) {
940
0
        return;
941
0
    }
942
943
0
    for (uint32_t i = 0; i < wr.actual_pos; i++) {
944
        /** Test if the bit on the index is set. */
945
0
        if ((wr.bit_marks1 >> i) & 1U) {
946
0
            ly_print_(out, "|");
947
0
        } else {
948
0
            ly_print_(out, " ");
949
0
        }
950
951
0
        if (i != wr.actual_pos) {
952
0
            ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
953
0
        }
954
0
    }
955
0
}
956
957
/**
958
 * @brief Check if struct trt_node is empty.
959
 * @param[in] node is item to test.
960
 * @return 1 if node is considered empty otherwise 0.
961
 */
962
static ly_bool
963
trp_node_is_empty(struct trt_node node)
964
0
{
965
0
    const ly_bool a = !node.iffeatures;
966
0
    const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
967
0
    const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node.name);
968
0
    const ly_bool d = node.flags == TRD_FLAGS_TYPE_EMPTY;
969
0
    const ly_bool e = node.status == TRD_STATUS_TYPE_EMPTY;
970
971
0
    return a && b && c && d && e;
972
0
}
973
974
/**
975
 * @brief Check if [\<keys\>], \<type\> and
976
 * \<iffeatures\> are empty/not_set.
977
 * @param[in] node is item to test.
978
 * @return 1 if node has no \<keys\> \<type\> or \<iffeatures\>
979
 * otherwise 0.
980
 */
981
static ly_bool
982
trp_node_body_is_empty(struct trt_node node)
983
0
{
984
0
    const ly_bool a = !node.iffeatures;
985
0
    const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node.type);
986
0
    const ly_bool c = node.name.type != TRD_NODE_KEYS;
987
988
0
    return a && b && c;
989
0
}
990
991
/**
992
 * @brief Print \<status\> of the node.
993
 * @param[in] status_type is type of status.
994
 * @param[in,out] out is output handler.
995
 */
996
static void
997
trp_print_status(trt_status_type status_type, struct ly_out *out)
998
0
{
999
0
    switch (status_type) {
1000
0
    case TRD_STATUS_TYPE_CURRENT:
1001
0
        ly_print_(out, "%c", '+');
1002
0
        break;
1003
0
    case TRD_STATUS_TYPE_DEPRECATED:
1004
0
        ly_print_(out, "%c", 'x');
1005
0
        break;
1006
0
    case TRD_STATUS_TYPE_OBSOLETE:
1007
0
        ly_print_(out, "%c", 'o');
1008
0
        break;
1009
0
    default:
1010
0
        break;
1011
0
    }
1012
0
}
1013
1014
/**
1015
 * @brief Print \<flags\>.
1016
 * @param[in] flags_type is type of \<flags\>.
1017
 * @param[in,out] out is output handler.
1018
 */
1019
static void
1020
trp_print_flags(trt_flags_type flags_type, struct ly_out *out)
1021
0
{
1022
0
    switch (flags_type) {
1023
0
    case TRD_FLAGS_TYPE_RW:
1024
0
        ly_print_(out, "%s", "rw");
1025
0
        break;
1026
0
    case TRD_FLAGS_TYPE_RO:
1027
0
        ly_print_(out, "%s", "ro");
1028
0
        break;
1029
0
    case TRD_FLAGS_TYPE_RPC_INPUT_PARAMS:
1030
0
        ly_print_(out, "%s", "-w");
1031
0
        break;
1032
0
    case TRD_FLAGS_TYPE_USES_OF_GROUPING:
1033
0
        ly_print_(out, "%s", "-u");
1034
0
        break;
1035
0
    case TRD_FLAGS_TYPE_RPC:
1036
0
        ly_print_(out, "%s", "-x");
1037
0
        break;
1038
0
    case TRD_FLAGS_TYPE_NOTIF:
1039
0
        ly_print_(out, "%s", "-n");
1040
0
        break;
1041
0
    case TRD_FLAGS_TYPE_MOUNT_POINT:
1042
0
        ly_print_(out, "%s", "mp");
1043
0
        break;
1044
0
    default:
1045
0
        ly_print_(out, "%s", "--");
1046
0
        break;
1047
0
    }
1048
0
}
1049
1050
/**
1051
 * @brief Get size of the \<flags\>.
1052
 * @param[in] flags_type is type of \<flags\>.
1053
 * @return 0 if flags_type is not set otherwise 2.
1054
 */
1055
static size_t
1056
trp_get_flags_strlen(trt_flags_type flags_type)
1057
0
{
1058
0
    return flags_type == TRD_FLAGS_TYPE_EMPTY ? 0 : 2;
1059
0
}
1060
1061
/**
1062
 * @brief Print entire struct trt_node_name structure.
1063
 * @param[in] node_name is item to print.
1064
 * @param[in,out] out is output handler.
1065
 */
1066
static void
1067
trp_print_node_name(struct trt_node_name node_name, struct ly_out *out)
1068
0
{
1069
0
    const char *mod_prefix;
1070
0
    const char *colon;
1071
0
    const char trd_node_name_suffix_choice[] = ")";
1072
0
    const char trd_node_name_suffix_case[] = ")";
1073
0
    const char trd_opts_optional[] = "?";        /**< For an optional leaf, choice, anydata, or anyxml. */
1074
0
    const char trd_opts_container[] = "!";       /**< For a presence container. */
1075
0
    const char trd_opts_list[] = "*";            /**< For a leaf-list or list. */
1076
0
    const char trd_opts_slash[] = "/";           /**< For a top-level data node in a mounted module. */
1077
0
    const char trd_opts_at_sign[] = "@";         /**< For a top-level data node of a module identified in a mount point parent reference. */
1078
1079
0
    if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1080
0
        return;
1081
0
    }
1082
1083
0
    if (node_name.module_prefix) {
1084
0
        mod_prefix = node_name.module_prefix;
1085
0
        colon = ":";
1086
0
    } else {
1087
0
        mod_prefix = "";
1088
0
        colon = "";
1089
0
    }
1090
1091
0
    switch (node_name.type) {
1092
0
    case TRD_NODE_ELSE:
1093
0
        ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
1094
0
        break;
1095
0
    case TRD_NODE_CASE:
1096
0
        ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, trd_node_name_suffix_case);
1097
0
        break;
1098
0
    case TRD_NODE_CHOICE:
1099
0
        ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE,  mod_prefix, colon, node_name.str, trd_node_name_suffix_choice);
1100
0
        break;
1101
0
    case TRD_NODE_OPTIONAL_CHOICE:
1102
0
        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);
1103
0
        break;
1104
0
    case TRD_NODE_OPTIONAL:
1105
0
        ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_optional);
1106
0
        break;
1107
0
    case TRD_NODE_CONTAINER:
1108
0
        ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_container);
1109
0
        break;
1110
0
    case TRD_NODE_LISTLEAFLIST:
1111
0
        ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1112
0
        break;
1113
0
    case TRD_NODE_KEYS:
1114
0
        ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_list);
1115
0
        break;
1116
0
    case TRD_NODE_TOP_LEVEL1:
1117
0
        ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_slash);
1118
0
        break;
1119
0
    case TRD_NODE_TOP_LEVEL2:
1120
0
        ly_print_(out, "%s%s%s%s", mod_prefix, colon, node_name.str, trd_opts_at_sign);
1121
0
        break;
1122
0
    case TRD_NODE_TRIPLE_DOT:
1123
0
        ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
1124
0
        break;
1125
0
    default:
1126
0
        break;
1127
0
    }
1128
0
}
1129
1130
/**
1131
 * @brief Check if mark (?, !, *, /, @) is implicitly contained in
1132
 * struct trt_node_name.
1133
 * @param[in] node_name is structure containing the 'mark'.
1134
 * @return 1 if contain otherwise 0.
1135
 */
1136
static ly_bool
1137
trp_mark_is_used(struct trt_node_name node_name)
1138
0
{
1139
0
    if (TRP_NODE_NAME_IS_EMPTY(node_name)) {
1140
0
        return 0;
1141
0
    }
1142
1143
0
    switch (node_name.type) {
1144
0
    case TRD_NODE_ELSE:
1145
0
    case TRD_NODE_CASE:
1146
0
    case TRD_NODE_KEYS:
1147
0
        return 0;
1148
0
    default:
1149
0
        return 1;
1150
0
    }
1151
0
}
1152
1153
/**
1154
 * @brief Print opts keys.
1155
 * @param[in] node_name contains type of the node with his name.
1156
 * @param[in] btw_name_opts is number of spaces between name and [keys].
1157
 * @param[in] cf is basically a pointer to the function that prints
1158
 * the keys.
1159
 * @param[in,out] out is output handler.
1160
 */
1161
static void
1162
trp_print_opts_keys(struct trt_node_name node_name, int16_t btw_name_opts, struct trt_cf_print cf, struct ly_out *out)
1163
0
{
1164
0
    if (node_name.type != TRD_NODE_KEYS) {
1165
0
        return;
1166
0
    }
1167
1168
    /* <name><mark>___<keys>*/
1169
0
    if (btw_name_opts > 0) {
1170
0
        ly_print_(out, "%*c", btw_name_opts, ' ');
1171
0
    }
1172
0
    ly_print_(out, "[");
1173
0
    cf.pf(cf.ctx, out);
1174
0
    ly_print_(out, "]");
1175
0
}
1176
1177
/**
1178
 * @brief Print entire struct trt_type structure.
1179
 * @param[in] type is item to print.
1180
 * @param[in,out] out is output handler.
1181
 */
1182
static void
1183
trp_print_type(struct trt_type type, struct ly_out *out)
1184
0
{
1185
0
    if (TRP_TRT_TYPE_IS_EMPTY(type)) {
1186
0
        return;
1187
0
    }
1188
1189
0
    switch (type.type) {
1190
0
    case TRD_TYPE_NAME:
1191
0
        ly_print_(out, "%s", type.str);
1192
0
        break;
1193
0
    case TRD_TYPE_TARGET:
1194
0
        ly_print_(out, "-> %s", type.str);
1195
0
        break;
1196
0
    case TRD_TYPE_LEAFREF:
1197
0
        ly_print_(out, "leafref");
1198
0
    default:
1199
0
        break;
1200
0
    }
1201
0
}
1202
1203
/**
1204
 * @brief Print all iffeatures of node
1205
 *
1206
 * @param[in] iffeature_flag contains if if-features is present.
1207
 * @param[in] cf is basically a pointer to the function that prints
1208
 * the list of features.
1209
 * @param[in,out] out is output handler.
1210
 */
1211
static void
1212
trp_print_iffeatures(ly_bool iffeature_flag, struct trt_cf_print cf, struct ly_out *out)
1213
0
{
1214
0
    if (iffeature_flag) {
1215
0
        ly_print_(out, "{");
1216
0
        cf.pf(cf.ctx, out);
1217
0
        ly_print_(out, "}?");
1218
0
    }
1219
0
}
1220
1221
/**
1222
 * @brief Print just \<status\>--\<flags\> \<name\> with opts mark.
1223
 * @param[in] node contains items to print.
1224
 * @param[in] out is output handler.
1225
 */
1226
static void
1227
trp_print_node_up_to_name(struct trt_node node, struct ly_out *out)
1228
0
{
1229
0
    if (node.name.type == TRD_NODE_TRIPLE_DOT) {
1230
0
        trp_print_node_name(node.name, out);
1231
0
        return;
1232
0
    }
1233
    /* <status>--<flags> */
1234
0
    trp_print_status(node.status, out);
1235
0
    ly_print_(out, "--");
1236
    /* If the node is a case node, there is no space before the <name>
1237
     * also case node has no flags.
1238
     */
1239
0
    if (node.name.type != TRD_NODE_CASE) {
1240
0
        trp_print_flags(node.flags, out);
1241
0
        ly_print_(out, " ");
1242
0
    }
1243
    /* <name> */
1244
0
    trp_print_node_name(node.name, out);
1245
0
}
1246
1247
/**
1248
 * @brief Print alignment (spaces) instead of
1249
 * \<status\>--\<flags\> \<name\> for divided node.
1250
 * @param[in] node contains items to print.
1251
 * @param[in] out is output handler.
1252
 */
1253
static void
1254
trp_print_divided_node_up_to_name(struct trt_node node, struct ly_out *out)
1255
0
{
1256
0
    uint32_t space = trp_get_flags_strlen(node.flags);
1257
1258
0
    if (node.name.type == TRD_NODE_CASE) {
1259
        /* :(<name> */
1260
0
        space += strlen(TRD_NODE_NAME_PREFIX_CASE);
1261
0
    } else if (node.name.type == TRD_NODE_CHOICE) {
1262
        /* (<name> */
1263
0
        space += strlen(TRD_NODE_NAME_PREFIX_CHOICE);
1264
0
    } else {
1265
        /* _<name> */
1266
0
        space += strlen(" ");
1267
0
    }
1268
1269
    /* <name>
1270
     * __
1271
     */
1272
0
    space += TRD_INDENT_LONG_LINE_BREAK;
1273
1274
0
    ly_print_(out, "%*c", space, ' ');
1275
0
}
1276
1277
/**
1278
 * @brief Print struct trt_node structure.
1279
 * @param[in] node is item to print.
1280
 * @param[in] pck package of functions for
1281
 * printing [\<keys\>] and \<iffeatures\>.
1282
 * @param[in] indent is the indent in node.
1283
 * @param[in,out] out is output handler.
1284
 */
1285
static void
1286
trp_print_node(struct trt_node node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out)
1287
0
{
1288
0
    ly_bool triple_dot;
1289
0
    ly_bool divided;
1290
0
    struct trt_cf_print cf_print_keys;
1291
0
    struct trt_cf_print cf_print_iffeatures;
1292
1293
0
    if (trp_node_is_empty(node)) {
1294
0
        return;
1295
0
    }
1296
1297
    /* <status>--<flags> <name><opts> <type> <if-features> */
1298
0
    triple_dot = node.name.type == TRD_NODE_TRIPLE_DOT;
1299
0
    divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED;
1300
1301
0
    if (triple_dot) {
1302
0
        trp_print_node_name(node.name, out);
1303
0
        return;
1304
0
    } else if (!divided) {
1305
0
        trp_print_node_up_to_name(node, out);
1306
0
    } else {
1307
0
        trp_print_divided_node_up_to_name(node, out);
1308
0
    }
1309
1310
    /* <opts> */
1311
    /* <name>___<opts>*/
1312
0
    cf_print_keys.ctx = pck.tree_ctx;
1313
0
    cf_print_keys.pf = pck.fps.print_keys;
1314
1315
0
    trp_print_opts_keys(node.name, indent.btw_name_opts, cf_print_keys, out);
1316
1317
    /* <opts>__<type> */
1318
0
    if (indent.btw_opts_type > 0) {
1319
0
        ly_print_(out, "%*c", indent.btw_opts_type, ' ');
1320
0
    }
1321
1322
    /* <type> */
1323
0
    trp_print_type(node.type, out);
1324
1325
    /* <type>__<iffeatures> */
1326
0
    if (indent.btw_type_iffeatures > 0) {
1327
0
        ly_print_(out, "%*c", indent.btw_type_iffeatures, ' ');
1328
0
    }
1329
1330
    /* <iffeatures> */
1331
0
    cf_print_iffeatures.ctx = pck.tree_ctx;
1332
0
    cf_print_iffeatures.pf = pck.fps.print_features_names;
1333
1334
0
    trp_print_iffeatures(node.iffeatures, cf_print_iffeatures, out);
1335
0
}
1336
1337
/**
1338
 * @brief Print keyword based on trt_keyword_stmt.type.
1339
 * @param[in] ks is keyword statement to print.
1340
 * @param[in,out] out is output handler
1341
 */
1342
static void
1343
trt_print_keyword_stmt_begin(struct trt_keyword_stmt ks, struct ly_out *out)
1344
0
{
1345
0
    switch (ks.type) {
1346
0
    case TRD_KEYWORD_MODULE:
1347
0
        ly_print_(out, "%s: ", TRD_TOP_KEYWORD_MODULE);
1348
0
        return;
1349
0
    case TRD_KEYWORD_SUBMODULE:
1350
0
        ly_print_(out, "%s: ", TRD_TOP_KEYWORD_SUBMODULE);
1351
0
        return;
1352
0
    default:
1353
0
        ly_print_(out, "%*c", TRD_INDENT_LINE_BEGIN, ' ');
1354
0
        switch (ks.type) {
1355
0
        case TRD_KEYWORD_AUGMENT:
1356
0
            ly_print_(out, "%s ", TRD_BODY_KEYWORD_AUGMENT);
1357
0
            break;
1358
0
        case TRD_KEYWORD_RPC:
1359
0
            ly_print_(out, "%s", TRD_BODY_KEYWORD_RPC);
1360
0
            break;
1361
0
        case TRD_KEYWORD_NOTIF:
1362
0
            ly_print_(out, "%s", TRD_BODY_KEYWORD_NOTIF);
1363
0
            break;
1364
0
        case TRD_KEYWORD_GROUPING:
1365
0
            ly_print_(out, "%s ", TRD_BODY_KEYWORD_GROUPING);
1366
0
            break;
1367
0
        case TRD_KEYWORD_YANG_DATA:
1368
0
            ly_print_(out, "%s ", TRD_BODY_KEYWORD_YANG_DATA);
1369
0
            break;
1370
0
        default:
1371
0
            break;
1372
0
        }
1373
0
        break;
1374
0
    }
1375
0
}
1376
1377
/**
1378
 * @brief Get string length of stored keyword.
1379
 * @param[in] type is type of the keyword statement.
1380
 * @return length of the keyword statement name.
1381
 */
1382
static size_t
1383
trp_keyword_type_strlen(trt_keyword_type type)
1384
0
{
1385
0
    switch (type) {
1386
0
    case TRD_KEYWORD_MODULE:
1387
0
        return sizeof(TRD_TOP_KEYWORD_MODULE) - 1;
1388
0
    case TRD_KEYWORD_SUBMODULE:
1389
0
        return sizeof(TRD_TOP_KEYWORD_SUBMODULE) - 1;
1390
0
    case TRD_KEYWORD_AUGMENT:
1391
0
        return sizeof(TRD_BODY_KEYWORD_AUGMENT) - 1;
1392
0
    case TRD_KEYWORD_RPC:
1393
0
        return sizeof(TRD_BODY_KEYWORD_RPC) - 1;
1394
0
    case TRD_KEYWORD_NOTIF:
1395
0
        return sizeof(TRD_BODY_KEYWORD_NOTIF) - 1;
1396
0
    case TRD_KEYWORD_GROUPING:
1397
0
        return sizeof(TRD_BODY_KEYWORD_GROUPING) - 1;
1398
0
    case TRD_KEYWORD_YANG_DATA:
1399
0
        return sizeof(TRD_BODY_KEYWORD_YANG_DATA) - 1;
1400
0
    default:
1401
0
        return 0;
1402
0
    }
1403
0
}
1404
1405
/**
1406
 * @brief Print trt_keyword_stmt.str which is string of name or path.
1407
 * @param[in] ks is keyword statement structure.
1408
 * @param[in] mll is max line length.
1409
 * @param[in,out] out is output handler.
1410
 */
1411
static void
1412
trt_print_keyword_stmt_str(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out)
1413
0
{
1414
0
    uint32_t ind_initial;
1415
0
    uint32_t ind_divided;
1416
    /* flag if path must be splitted to more lines */
1417
0
    ly_bool linebreak_was_set;
1418
    /* flag if at least one subpath was printed */
1419
0
    ly_bool subpath_printed;
1420
    /* the sum of the sizes of the substrings on the current line */
1421
0
    uint32_t how_far;
1422
    /* pointer to start of the subpath */
1423
0
    const char *sub_ptr;
1424
    /* size of subpath from sub_ptr */
1425
0
    size_t sub_len;
1426
1427
0
    if ((!ks.str) || (ks.str[0] == '\0')) {
1428
0
        return;
1429
0
    }
1430
1431
    /* module name cannot be splitted */
1432
0
    if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
1433
0
        ly_print_(out, "%s", ks.str);
1434
0
        return;
1435
0
    }
1436
1437
    /* after -> for trd_keyword_stmt_body do */
1438
1439
    /* set begin indentation */
1440
0
    ind_initial = TRD_INDENT_LINE_BEGIN + trp_keyword_type_strlen(ks.type) + 1;
1441
0
    ind_divided = ind_initial + TRD_INDENT_LONG_LINE_BREAK;
1442
0
    linebreak_was_set = 0;
1443
0
    subpath_printed = 0;
1444
0
    how_far = 0;
1445
0
    sub_ptr = ks.str;
1446
0
    sub_len = 0;
1447
1448
0
    while (sub_ptr[0] != '\0') {
1449
0
        uint32_t ind;
1450
        /* skip slash */
1451
0
        const char *tmp = sub_ptr[0] == '/' ? sub_ptr + 1 : sub_ptr;
1452
        /* get position of the end of substr */
1453
0
        tmp = strchr(tmp, '/');
1454
        /* set correct size if this is a last substring */
1455
0
        sub_len = !tmp ? strlen(sub_ptr) : (size_t)(tmp - sub_ptr);
1456
        /* actualize sum of the substring's sizes on the current line */
1457
0
        how_far += sub_len;
1458
        /* correction due to colon character if it this is last substring */
1459
0
        how_far = *(sub_ptr + sub_len) == '\0' ? how_far + 1 : how_far;
1460
        /* choose indentation which depends on
1461
         * whether the string is printed on multiple lines or not
1462
         */
1463
0
        ind = linebreak_was_set ? ind_divided : ind_initial;
1464
0
        if (ind + how_far <= mll) {
1465
            /* printing before max line length */
1466
0
            sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1467
0
            subpath_printed = 1;
1468
0
        } else {
1469
            /* printing on new line */
1470
0
            if (subpath_printed == 0) {
1471
                /* first subpath is too long
1472
                 * but print it at first line anyway
1473
                 */
1474
0
                sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1475
0
                subpath_printed = 1;
1476
0
                continue;
1477
0
            }
1478
0
            ly_print_(out, "\n");
1479
0
            ly_print_(out, "%*c", ind_divided, ' ');
1480
0
            linebreak_was_set = 1;
1481
0
            sub_ptr = trg_print_substr(sub_ptr, sub_len, out);
1482
0
            how_far = sub_len;
1483
0
            subpath_printed = 1;
1484
0
        }
1485
0
    }
1486
0
}
1487
1488
/**
1489
 * @brief Print separator based on trt_keyword_stmt.type
1490
 * @param[in] ks is keyword statement structure.
1491
 * @param[in] grp_has_data is flag only for grouping section.
1492
 * Set to 1 if grouping section has some nodes.
1493
 * Set to 0 if it doesn't have nodes or it's not grouping section.
1494
 * @param[in,out] out is output handler.
1495
 */
1496
static void
1497
trt_print_keyword_stmt_end(struct trt_keyword_stmt ks, ly_bool grp_has_data, struct ly_out *out)
1498
0
{
1499
0
    if ((ks.type != TRD_KEYWORD_MODULE) && (ks.type != TRD_KEYWORD_SUBMODULE)) {
1500
0
        if ((ks.type == TRD_KEYWORD_GROUPING) && !grp_has_data) {
1501
0
            return;
1502
0
        } else {
1503
0
            ly_print_(out, ":");
1504
0
        }
1505
0
    }
1506
0
}
1507
1508
/**
1509
 * @brief Print entire struct trt_keyword_stmt structure.
1510
 * @param[in] ks is item to print.
1511
 * @param[in] mll is max line length.
1512
 * @param[in] grp_has_data is flag only for grouping section.
1513
 * Set to 1 if grouping section has some nodes.
1514
 * Set to 0 if it doesn't have nodes or it's not grouping section.
1515
 * @param[in,out] out is output handler.
1516
 */
1517
static void
1518
trp_print_keyword_stmt(struct trt_keyword_stmt ks, size_t mll, ly_bool grp_has_data, struct ly_out *out)
1519
0
{
1520
0
    if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
1521
0
        return;
1522
0
    }
1523
0
    trt_print_keyword_stmt_begin(ks, out);
1524
0
    trt_print_keyword_stmt_str(ks, mll, out);
1525
0
    trt_print_keyword_stmt_end(ks, grp_has_data, out);
1526
0
}
1527
1528
/**********************************************************************
1529
 * Main trp functions
1530
 *********************************************************************/
1531
1532
/**
1533
 * @brief Printing one line including wrapper and node
1534
 * which can be incomplete (divided).
1535
 * @param[in] node is \<node\> representation.
1536
 * @param[in] pck contains special printing functions callback.
1537
 * @param[in] indent contains wrapper and indent in node numbers.
1538
 * @param[in,out] out is output handler.
1539
 */
1540
static void
1541
trp_print_line(struct trt_node node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out)
1542
0
{
1543
0
    trp_print_wrapper(indent.wrapper, out);
1544
0
    trp_print_node(node, pck, indent.in_node, out);
1545
0
}
1546
1547
/**
1548
 * @brief Printing one line including wrapper and
1549
 * \<status\>--\<flags\> \<name\>\<option_mark\>.
1550
 * @param[in] node is \<node\> representation.
1551
 * @param[in] wr is wrapper for printing indentation before node.
1552
 * @param[in] out is output handler.
1553
 */
1554
static void
1555
trp_print_line_up_to_node_name(struct trt_node node, struct trt_wrapper wr, struct ly_out *out)
1556
0
{
1557
0
    trp_print_wrapper(wr, out);
1558
0
    trp_print_node_up_to_name(node, out);
1559
0
}
1560
1561
/**
1562
 * @brief Check if leafref target must be change to string 'leafref'
1563
 * because his target string is too long.
1564
 * @param[in] node containing leafref target.
1565
 * @param[in] wr is wrapper for printing indentation before node.
1566
 * @param[in] mll is max line length.
1567
 * @param[in] out is output handler.
1568
 * @return true if leafref must be changed to string 'leafref'.
1569
 */
1570
static ly_bool
1571
trp_leafref_target_is_too_long(struct trt_node node, struct trt_wrapper wr, size_t mll, struct ly_out *out)
1572
0
{
1573
0
    struct ly_out_clb_arg *data;
1574
1575
0
    if (node.type.type != TRD_TYPE_TARGET) {
1576
0
        return 0;
1577
0
    }
1578
1579
    /* set ly_out to counting characters */
1580
0
    data = out->method.clb.arg;
1581
1582
0
    data->counter = 0;
1583
0
    data->mode = TRD_CHAR_COUNT;
1584
    /* count number of printed bytes */
1585
0
    trp_print_wrapper(wr, out);
1586
0
    ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' ');
1587
0
    trp_print_divided_node_up_to_name(node, out);
1588
0
    data->mode = TRD_PRINT;
1589
1590
0
    return data->counter + strlen(node.type.str) > mll;
1591
0
}
1592
1593
/**
1594
 * @brief Get default indent in node based on node values.
1595
 * @param[in] node is \<node\> representation.
1596
 * @return Default indent in node assuming that the node
1597
 * will not be divided.
1598
 */
1599
static struct trt_indent_in_node
1600
trp_default_indent_in_node(struct trt_node node)
1601
0
{
1602
0
    struct trt_indent_in_node ret;
1603
1604
0
    ret.type = TRD_INDENT_IN_NODE_NORMAL;
1605
1606
    /* btw_name_opts */
1607
0
    ret.btw_name_opts = node.name.type == TRD_NODE_KEYS ? TRD_INDENT_BEFORE_KEYS : 0;
1608
1609
    /* btw_opts_type */
1610
0
    if (!(TRP_TRT_TYPE_IS_EMPTY(node.type))) {
1611
0
        ret.btw_opts_type = trp_mark_is_used(node.name) ?
1612
0
                TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
1613
0
                TRD_INDENT_BEFORE_TYPE;
1614
0
    } else {
1615
0
        ret.btw_opts_type = 0;
1616
0
    }
1617
1618
    /* btw_type_iffeatures */
1619
0
    ret.btw_type_iffeatures = node.iffeatures ? TRD_INDENT_BEFORE_IFFEATURES : 0;
1620
1621
0
    return ret;
1622
0
}
1623
1624
/**
1625
 * @brief Setting linebreaks in trt_indent_in_node.
1626
 *
1627
 * The order where the linebreak tag can be placed is from the end.
1628
 *
1629
 * @param[in] indent containing alignment lengths
1630
 * or already linebreak marks.
1631
 * @return indent with a newly placed linebreak tag.
1632
 * @return .type set to TRD_INDENT_IN_NODE_FAILED if it is not possible
1633
 * to place a more linebreaks.
1634
 */
1635
static struct trt_indent_in_node
1636
trp_indent_in_node_place_break(struct trt_indent_in_node indent)
1637
0
{
1638
    /* somewhere must be set a line break in node */
1639
0
    struct trt_indent_in_node ret = indent;
1640
1641
    /* gradually break the node from the end */
1642
0
    if ((indent.btw_type_iffeatures != TRD_LINEBREAK) && (indent.btw_type_iffeatures != 0)) {
1643
0
        ret.btw_type_iffeatures = TRD_LINEBREAK;
1644
0
    } else if ((indent.btw_opts_type != TRD_LINEBREAK) && (indent.btw_opts_type != 0)) {
1645
0
        ret.btw_opts_type = TRD_LINEBREAK;
1646
0
    } else if ((indent.btw_name_opts != TRD_LINEBREAK) && (indent.btw_name_opts != 0)) {
1647
        /* set line break between name and opts */
1648
0
        ret.btw_name_opts = TRD_LINEBREAK;
1649
0
    } else {
1650
        /* it is not possible to place a more line breaks,
1651
         * unfortunately the max_line_length constraint is violated
1652
         */
1653
0
        ret.type = TRD_INDENT_IN_NODE_FAILED;
1654
0
    }
1655
0
    return ret;
1656
0
}
1657
1658
/**
1659
 * @brief Get the first half of the node based on the linebreak mark.
1660
 *
1661
 * Items in the second half of the node will be empty.
1662
 *
1663
 * @param[in] node the whole \<node\> to be split.
1664
 * @param[in] indent contains information in which part of the \<node\>
1665
 * the first half ends.
1666
 * @return first half of the node, indent is unchanged.
1667
 */
1668
static struct trt_pair_indent_node
1669
trp_first_half_node(struct trt_node node, struct trt_indent_in_node indent)
1670
0
{
1671
0
    struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1672
1673
0
    if (indent.btw_name_opts == TRD_LINEBREAK) {
1674
0
        ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1675
0
        ret.node.type = TRP_EMPTY_TRT_TYPE;
1676
0
        ret.node.iffeatures = 0;
1677
0
    } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1678
0
        ret.node.type = TRP_EMPTY_TRT_TYPE;
1679
0
        ret.node.iffeatures = 0;
1680
0
    } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1681
0
        ret.node.iffeatures = 0;
1682
0
    }
1683
1684
0
    return ret;
1685
0
}
1686
1687
/**
1688
 * @brief Get the second half of the node based on the linebreak mark.
1689
 *
1690
 * Items in the first half of the node will be empty.
1691
 * Indentations belonging to the first node will be reset to zero.
1692
 *
1693
 * @param[in] node the whole \<node\> to be split.
1694
 * @param[in] indent contains information in which part of the \<node\>
1695
 * the second half starts.
1696
 * @return second half of the node, indent is newly set.
1697
 */
1698
static struct trt_pair_indent_node
1699
trp_second_half_node(struct trt_node node, struct trt_indent_in_node indent)
1700
0
{
1701
0
    struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent, node);
1702
1703
0
    if (indent.btw_name_opts < 0) {
1704
        /* Logically, the information up to token <opts> should
1705
         * be deleted, but the the trp_print_node function needs it to
1706
         * create the correct indent.
1707
         */
1708
0
        ret.indent.btw_name_opts = 0;
1709
0
        ret.indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(node.type) ? 0 : TRD_INDENT_BEFORE_TYPE;
1710
0
        ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1711
0
    } else if (indent.btw_opts_type == TRD_LINEBREAK) {
1712
0
        ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1713
0
        ret.indent.btw_name_opts = 0;
1714
0
        ret.indent.btw_opts_type = 0;
1715
0
        ret.indent.btw_type_iffeatures = !node.iffeatures ? 0 : TRD_INDENT_BEFORE_IFFEATURES;
1716
0
    } else if (indent.btw_type_iffeatures == TRD_LINEBREAK) {
1717
0
        ret.node.name.type = node.name.type == TRD_NODE_KEYS ? TRD_NODE_LISTLEAFLIST : node.name.type;
1718
0
        ret.node.type = TRP_EMPTY_TRT_TYPE;
1719
0
        ret.indent.btw_name_opts = 0;
1720
0
        ret.indent.btw_opts_type = 0;
1721
0
        ret.indent.btw_type_iffeatures = 0;
1722
0
    }
1723
0
    return ret;
1724
0
}
1725
1726
/**
1727
 * @brief Get the correct alignment for the node.
1728
 *
1729
 * This function is recursively called itself. It's like a backend
1730
 * function for a function ::trp_try_normal_indent_in_node().
1731
 *
1732
 * @param[in] node is \<node\> representation.
1733
 * @param[in] pck contains speciall callback functions for printing.
1734
 * @param[in] indent contains wrapper and indent in node numbers.
1735
 * @param[in] mll is max line length.
1736
 * @param[in,out] cnt counting number of characters to print.
1737
 * @param[in,out] out is output handler.
1738
 * @return pair of node and indentation numbers of that node.
1739
 */
1740
static struct trt_pair_indent_node
1741
trp_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)
1742
0
{
1743
0
    struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1744
1745
0
    trp_print_line(node, pck, indent, out);
1746
1747
0
    if (*cnt <= mll) {
1748
        /* success */
1749
0
        return ret;
1750
0
    } else {
1751
0
        ret.indent = trp_indent_in_node_place_break(ret.indent);
1752
0
        if (ret.indent.type != TRD_INDENT_IN_NODE_FAILED) {
1753
            /* erase information in node due to line break */
1754
0
            ret = trp_first_half_node(node, ret.indent);
1755
            /* check if line fits, recursive call */
1756
0
            *cnt = 0;
1757
0
            ret = trp_try_normal_indent_in_node_(ret.node, pck, TRP_INIT_PCK_INDENT(indent.wrapper, ret.indent), mll, cnt, out);
1758
            /* make sure that the result will be with the status divided
1759
             * or eventually with status failed */
1760
0
            ret.indent.type = ret.indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED;
1761
0
        }
1762
0
        return ret;
1763
0
    }
1764
0
}
1765
1766
/**
1767
 * @brief Get the correct alignment for the node.
1768
 *
1769
 * @param[in] node is \<node\> representation.
1770
 * @param[in] pck contains speciall callback functions for printing.
1771
 * @param[in] indent contains wrapper and indent in node numbers.
1772
 * @param[in] mll is max line length.
1773
 * @param[in,out] out is output handler.
1774
 * @return ::TRD_INDENT_IN_NODE_DIVIDED - the node does not fit in the
1775
 * line, some indent variable has negative value as a line break sign.
1776
 * @return ::TRD_INDENT_IN_NODE_NORMAL - the node fits into the line,
1777
 * all indent variables values has non-negative number.
1778
 * @return ::TRD_INDENT_IN_NODE_FAILED - the node does not fit into the
1779
 * line, all indent variables has negative or zero values,
1780
 * function failed.
1781
 */
1782
static struct trt_pair_indent_node
1783
trp_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)
1784
0
{
1785
0
    struct trt_pair_indent_node ret = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, node);
1786
0
    struct ly_out_clb_arg *data;
1787
1788
    /* set ly_out to counting characters */
1789
0
    data = out->method.clb.arg;
1790
1791
0
    data->counter = 0;
1792
0
    data->mode = TRD_CHAR_COUNT;
1793
0
    ret = trp_try_normal_indent_in_node_(node, pck, indent, mll, &data->counter, out);
1794
0
    data->mode = TRD_PRINT;
1795
1796
0
    return ret;
1797
0
}
1798
1799
/**
1800
 * @brief Auxiliary function for ::trp_print_entire_node()
1801
 * that prints split nodes.
1802
 * @param[in] node is node representation.
1803
 * @param[in] ppck contains speciall callback functions for printing.
1804
 * @param[in] ipck contains wrapper and indent in node numbers.
1805
 * @param[in] mll is max line length.
1806
 * @param[in,out] out is output handler.
1807
 */
1808
static void
1809
trp_print_divided_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1810
0
{
1811
0
    ly_bool entire_node_was_printed;
1812
0
    struct trt_pair_indent_node ind_node = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1813
1814
0
    if (ind_node.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1815
        /* nothing can be done, continue as usual */
1816
0
        ind_node.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1817
0
    }
1818
1819
0
    trp_print_line(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), out);
1820
0
    entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, ind_node.indent);
1821
1822
0
    if (!entire_node_was_printed) {
1823
0
        ly_print_(out, "\n");
1824
        /* continue with second half node */
1825
0
        ind_node = trp_second_half_node(node, ind_node.indent);
1826
        /* continue with printing node */
1827
0
        trp_print_divided_node(ind_node.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node.indent), mll, out);
1828
0
    } else {
1829
0
        return;
1830
0
    }
1831
0
}
1832
1833
/**
1834
 * @brief Printing of the wrapper and the whole node,
1835
 * which can be divided into several lines.
1836
 * @param[in] node is node representation.
1837
 * @param[in] ppck contains speciall callback functions for printing.
1838
 * @param[in] ipck contains wrapper and indent in node numbers.
1839
 * @param[in] mll is max line length.
1840
 * @param[in,out] out is output handler.
1841
 */
1842
static void
1843
trp_print_entire_node(struct trt_node node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out)
1844
0
{
1845
0
    struct trt_pair_indent_node ind_node1;
1846
0
    struct trt_pair_indent_node ind_node2;
1847
0
    struct trt_pck_indent tmp;
1848
1849
0
    if (trp_leafref_target_is_too_long(node, ipck.wrapper, mll, out)) {
1850
0
        node.type.type = TRD_TYPE_LEAFREF;
1851
0
    }
1852
1853
    /* check if normal indent is possible */
1854
0
    ind_node1 = trp_try_normal_indent_in_node(node, ppck, ipck, mll, out);
1855
1856
0
    if (ind_node1.indent.type == TRD_INDENT_IN_NODE_NORMAL) {
1857
        /* node fits to one line */
1858
0
        trp_print_line(node, ppck, ipck, out);
1859
0
    } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_DIVIDED) {
1860
        /* node will be divided */
1861
        /* print first half */
1862
0
        tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, ind_node1.indent);
1863
        /* pretend that this is normal node */
1864
0
        tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL;
1865
1866
0
        trp_print_line(ind_node1.node, ppck, tmp, out);
1867
0
        ly_print_(out, "\n");
1868
1869
        /* continue with second half on new line */
1870
0
        ind_node2 = trp_second_half_node(node, ind_node1.indent);
1871
0
        tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1872
1873
0
        trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1874
0
    } else if (ind_node1.indent.type == TRD_INDENT_IN_NODE_FAILED) {
1875
        /* node name is too long */
1876
0
        trp_print_line_up_to_node_name(node, ipck.wrapper, out);
1877
1878
0
        if (trp_node_body_is_empty(node)) {
1879
0
            return;
1880
0
        } else {
1881
0
            ly_print_(out, "\n");
1882
1883
0
            ind_node2 = trp_second_half_node(node, ind_node1.indent);
1884
0
            ind_node2.indent.type = TRD_INDENT_IN_NODE_DIVIDED;
1885
0
            tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), ind_node2.indent);
1886
1887
0
            trp_print_divided_node(ind_node2.node, ppck, tmp, mll, out);
1888
0
        }
1889
1890
0
    }
1891
0
}
1892
1893
/**********************************************************************
1894
 * trop and troc getters
1895
 *********************************************************************/
1896
1897
/**
1898
 * @brief Get nodetype.
1899
 * @param[in] node is any lysp_node.
1900
 */
1901
static uint16_t
1902
trop_nodetype(const void *node)
1903
0
{
1904
0
    return ((const struct lysp_node *)node)->nodetype;
1905
0
}
1906
1907
/**
1908
 * @brief Get sibling.
1909
 * @param[in] node is any lysp_node.
1910
 */
1911
static const void *
1912
trop_next(const void *node)
1913
0
{
1914
0
    return ((const struct lysp_node *)node)->next;
1915
0
}
1916
1917
/**
1918
 * @brief Get parent.
1919
 * @param[in] node is any lysp_node.
1920
 */
1921
static const void *
1922
trop_parent(const void *node)
1923
0
{
1924
0
    return ((const struct lysp_node *)node)->parent;
1925
0
}
1926
1927
/**
1928
 * @brief Try to get child.
1929
 * @param[in] node is any lysp_node.
1930
 */
1931
static const void *
1932
trop_child(const void *node)
1933
0
{
1934
0
    return lysp_node_child(node);
1935
0
}
1936
1937
/**
1938
 * @brief Try to get action.
1939
 * @param[in] node is any lysp_node.
1940
 */
1941
static const void *
1942
trop_actions(const void *node)
1943
0
{
1944
0
    return lysp_node_actions(node);
1945
0
}
1946
1947
/**
1948
 * @brief Try to get action.
1949
 * @param[in] node must be of type lysp_node_action.
1950
 */
1951
static const void *
1952
trop_action_input(const void *node)
1953
0
{
1954
0
    return &((const struct lysp_node_action *)node)->input;
1955
0
}
1956
1957
/**
1958
 * @brief Try to get action.
1959
 * @param[in] node must be of type lysp_node_action.
1960
 */
1961
static const void *
1962
trop_action_output(const void *node)
1963
0
{
1964
0
    return &((const struct lysp_node_action *)node)->output;
1965
0
}
1966
1967
/**
1968
 * @brief Try to get action.
1969
 * @param[in] node is any lysp_node.
1970
 */
1971
static const void *
1972
trop_notifs(const void *node)
1973
0
{
1974
0
    return lysp_node_notifs(node);
1975
0
}
1976
1977
/**
1978
 * @brief Fill struct tro_getters with @ref TRP_trop getters
1979
 * which are adapted to lysp nodes.
1980
 */
1981
static struct tro_getters
1982
trop_init_getters()
1983
0
{
1984
0
    return (struct tro_getters) {
1985
0
               .nodetype = trop_nodetype,
1986
0
               .next = trop_next,
1987
0
               .parent = trop_parent,
1988
0
               .child = trop_child,
1989
0
               .actions = trop_actions,
1990
0
               .action_input = trop_action_input,
1991
0
               .action_output = trop_action_output,
1992
0
               .notifs = trop_notifs
1993
0
    };
1994
0
}
1995
1996
/**
1997
 * @brief Get nodetype.
1998
 * @param[in] node is any lysc_node.
1999
 */
2000
static uint16_t
2001
troc_nodetype(const void *node)
2002
0
{
2003
0
    return ((const struct lysc_node *)node)->nodetype;
2004
0
}
2005
2006
/**
2007
 * @brief Get sibling.
2008
 * @param[in] node is any lysc_node.
2009
 */
2010
static const void *
2011
troc_next(const void *node)
2012
0
{
2013
0
    return ((const struct lysc_node *)node)->next;
2014
0
}
2015
2016
/**
2017
 * @brief Get parent.
2018
 * @param[in] node is any lysc_node.
2019
 */
2020
static const void *
2021
troc_parent(const void *node)
2022
0
{
2023
0
    return ((const struct lysc_node *)node)->parent;
2024
0
}
2025
2026
/**
2027
 * @brief Try to get child.
2028
 * @param[in] node is any lysc_node.
2029
 */
2030
static const void *
2031
troc_child(const void *node)
2032
0
{
2033
0
    return lysc_node_child(node);
2034
0
}
2035
2036
/**
2037
 * @brief Try to get action.
2038
 * @param[in] node is any lysc_node.
2039
 */
2040
static const void *
2041
troc_actions(const void *node)
2042
0
{
2043
0
    return lysc_node_actions(node);
2044
0
}
2045
2046
/**
2047
 * @brief Try to get action.
2048
 * @param[in] node must be of type lysc_node_action.
2049
 */
2050
static const void *
2051
troc_action_input(const void *node)
2052
0
{
2053
0
    return &((const struct lysc_node_action *)node)->input;
2054
0
}
2055
2056
/**
2057
 * @brief Try to get action.
2058
 * @param[in] node must be of type lysc_node_action.
2059
 */
2060
static const void *
2061
troc_action_output(const void *node)
2062
0
{
2063
0
    return &((const struct lysc_node_action *)node)->output;
2064
0
}
2065
2066
/**
2067
 * @brief Try to get action.
2068
 * @param[in] node is any lysc_node.
2069
 */
2070
static const void *
2071
troc_notifs(const void *node)
2072
0
{
2073
0
    return lysc_node_notifs(node);
2074
0
}
2075
2076
/**
2077
 * @brief Fill struct tro_getters with @ref TRP_troc getters
2078
 * which are adapted to lysc nodes.
2079
 */
2080
static struct tro_getters
2081
troc_init_getters()
2082
0
{
2083
0
    return (struct tro_getters) {
2084
0
               .nodetype = troc_nodetype,
2085
0
               .next = troc_next,
2086
0
               .parent = troc_parent,
2087
0
               .child = troc_child,
2088
0
               .actions = troc_actions,
2089
0
               .action_input = troc_action_input,
2090
0
               .action_output = troc_action_output,
2091
0
               .notifs = troc_notifs
2092
0
    };
2093
0
}
2094
2095
/**********************************************************************
2096
 * tro functions
2097
 *********************************************************************/
2098
2099
/**
2100
 * @brief Get next sibling of the current node.
2101
 *
2102
 * This is a general algorithm that is able to
2103
 * work with lysp_node or lysc_node.
2104
 *
2105
 * @param[in] node points to lysp_node or lysc_node.
2106
 * @param[in] lysc_tree flag to determine what type the @p node is.
2107
 * If set to true, then @p points to lysc_node otherwise lysp_node.
2108
 * This flag should be the same as trt_tree_ctx.lysc_tree.
2109
 */
2110
static const void *
2111
tro_next_sibling(const void *node, ly_bool lysc_tree)
2112
0
{
2113
0
    struct tro_getters get;
2114
0
    const void *tmp, *parent;
2115
0
    const void *ret;
2116
2117
0
    assert(node);
2118
2119
0
    get = lysc_tree ? troc_init_getters() : trop_init_getters();
2120
2121
0
    if (get.nodetype(node) & (LYS_RPC | LYS_ACTION)) {
2122
0
        if ((tmp = get.next(node))) {
2123
            /* next action exists */
2124
0
            ret = tmp;
2125
0
        } else if ((parent = get.parent(node))) {
2126
            /* maybe if notif exists as sibling */
2127
0
            ret = get.notifs(parent);
2128
0
        } else {
2129
0
            ret = NULL;
2130
0
        }
2131
0
    } else if (get.nodetype(node) & LYS_INPUT) {
2132
0
        if ((parent = get.parent(node))) {
2133
            /* if output action has data */
2134
0
            if (get.child(get.action_output(parent))) {
2135
                /* then next sibling is output action */
2136
0
                ret = get.action_output(parent);
2137
0
            } else {
2138
                /* input action cannot have siblings other
2139
                 * than output action.
2140
                 */
2141
0
                ret = NULL;
2142
0
            }
2143
0
        } else {
2144
            /* there is no way how to get output action */
2145
0
            ret = NULL;
2146
0
        }
2147
0
    } else if (get.nodetype(node) & LYS_OUTPUT) {
2148
        /* output action cannot have siblings */
2149
0
        ret = NULL;
2150
0
    } else if (get.nodetype(node) & LYS_NOTIF) {
2151
        /* must have as a sibling only notif */
2152
0
        ret = get.next(node);
2153
0
    } else {
2154
        /* for rest of nodes */
2155
0
        if ((tmp = get.next(node))) {
2156
            /* some sibling exists */
2157
0
            ret = tmp;
2158
0
        } else if ((parent = get.parent(node))) {
2159
            /* Action and notif are siblings too.
2160
             * They can be reached through parent.
2161
             */
2162
0
            if ((tmp = get.actions(parent))) {
2163
                /* next sibling is action */
2164
0
                ret = tmp;
2165
0
            } else if ((tmp = get.notifs(parent))) {
2166
                /* next sibling is notif */
2167
0
                ret = tmp;
2168
0
            } else {
2169
                /* sibling not exists */
2170
0
                ret = NULL;
2171
0
            }
2172
0
        } else {
2173
            /* sibling not exists */
2174
0
            ret = NULL;
2175
0
        }
2176
0
    }
2177
2178
0
    return ret;
2179
0
}
2180
2181
/**
2182
 * @brief Get child of the current node.
2183
 *
2184
 * This is a general algorithm that is able to
2185
 * work with lysp_node or lysc_node.
2186
 *
2187
 * @param[in] node points to lysp_node or lysc_node.
2188
 * @param[in] lysc_tree flag to determine what type the @p node is.
2189
 * If set to true, then @p points to lysc_node otherwise lysp_node.
2190
 * This flag should be the same as trt_tree_ctx.lysc_tree.
2191
 */
2192
static const void *
2193
tro_next_child(const void *node, ly_bool lysc_tree)
2194
0
{
2195
0
    struct tro_getters get;
2196
0
    const void *tmp;
2197
0
    const void *ret;
2198
2199
0
    assert(node);
2200
2201
0
    get = lysc_tree ? troc_init_getters() : trop_init_getters();
2202
2203
0
    if (get.nodetype(node) & (LYS_ACTION | LYS_RPC)) {
2204
0
        if (get.child(get.action_input(node))) {
2205
            /* go to LYS_INPUT */
2206
0
            ret = get.action_input(node);
2207
0
        } else if (get.child(get.action_output(node))) {
2208
            /* go to LYS_OUTPUT */
2209
0
            ret = get.action_output(node);
2210
0
        } else {
2211
            /* input action and output action have no data */
2212
0
            ret = NULL;
2213
0
        }
2214
0
    } else {
2215
0
        if ((tmp = get.child(node))) {
2216
0
            ret = tmp;
2217
0
        } else {
2218
            /* current node can't have children or has no children */
2219
            /* but maybe has some actions or notifs */
2220
0
            if ((tmp = get.actions(node))) {
2221
0
                ret = tmp;
2222
0
            } else if ((tmp = get.notifs(node))) {
2223
0
                ret = tmp;
2224
0
            } else {
2225
0
                ret = NULL;
2226
0
            }
2227
0
        }
2228
0
    }
2229
2230
0
    return ret;
2231
0
}
2232
2233
/**
2234
 * @brief Get new trt_parent_cache if we apply the transfer
2235
 * to the child node in the tree.
2236
 * @param[in] ca is parent cache for current node.
2237
 * @param[in] tc contains current tree node.
2238
 * @return Cache for the current node.
2239
 */
2240
static struct trt_parent_cache
2241
tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2242
0
{
2243
0
    struct trt_parent_cache ret = TRP_EMPTY_PARENT_CACHE;
2244
2245
0
    if (!tc->lysc_tree) {
2246
0
        const struct lysp_node *pn = tc->pn;
2247
2248
0
        ret.ancestor =
2249
0
                pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT :
2250
0
                pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT :
2251
0
                pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF :
2252
0
                ca.ancestor;
2253
2254
0
        ret.lys_status =
2255
0
                pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
2256
0
                ca.lys_status;
2257
2258
0
        ret.lys_config =
2259
0
                ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because <flags> will be -w */
2260
0
                ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
2261
0
                pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
2262
0
                ca.lys_config;
2263
2264
0
        ret.last_list =
2265
0
                pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
2266
0
                ca.last_list;
2267
0
    }
2268
2269
0
    return ret;
2270
0
}
2271
2272
/**
2273
 * @brief Transformation of the Schema nodes flags to
2274
 * Tree diagram \<status\>.
2275
 * @param[in] flags is node's flags obtained from the tree.
2276
 */
2277
static trt_status_type
2278
tro_flags2status(uint16_t flags)
2279
0
{
2280
0
    return flags & LYS_STATUS_OBSLT ? TRD_STATUS_TYPE_OBSOLETE :
2281
0
           flags & LYS_STATUS_DEPRC ? TRD_STATUS_TYPE_DEPRECATED :
2282
0
           TRD_STATUS_TYPE_CURRENT;
2283
0
}
2284
2285
/**
2286
 * @brief Transformation of the Schema nodes flags to Tree diagram
2287
 * \<flags\> but more specifically 'ro' or 'rw'.
2288
 * @param[in] flags is node's flags obtained from the tree.
2289
 */
2290
static trt_flags_type
2291
tro_flags2config(uint16_t flags)
2292
0
{
2293
0
    return flags & LYS_CONFIG_R ? TRD_FLAGS_TYPE_RO :
2294
0
           flags & LYS_CONFIG_W ? TRD_FLAGS_TYPE_RW :
2295
0
           TRD_FLAGS_TYPE_EMPTY;
2296
0
}
2297
2298
/**
2299
 * @brief Print current node's iffeatures.
2300
 * @param[in] tc is tree context.
2301
 * @param[in,out] out is output handler.
2302
 */
2303
static void
2304
tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out)
2305
0
{
2306
0
    const struct lysp_qname *iffs;
2307
2308
0
    iffs = tc->lysc_tree ?
2309
0
            TRP_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures :
2310
0
            tc->pn->iffeatures;
2311
2312
0
    LY_ARRAY_COUNT_TYPE i;
2313
2314
0
    LY_ARRAY_FOR(iffs, i) {
2315
0
        if (i == 0) {
2316
0
            ly_print_(out, "%s", iffs[i].str);
2317
0
        } else {
2318
0
            ly_print_(out, ",%s", iffs[i].str);
2319
0
        }
2320
0
    }
2321
2322
0
}
2323
2324
/**
2325
 * @brief Print current list's keys.
2326
 *
2327
 * Well, actually printing keys in the lysp_tree is trivial,
2328
 * because char* points to all keys. However, special functions have
2329
 * been reserved for this, because in principle the list of elements
2330
 * can have more implementations.
2331
 *
2332
 * @param[in] tc is tree context.
2333
 * @param[in,out] out is output handler.
2334
 */
2335
static void
2336
tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out)
2337
0
{
2338
0
    const struct lysp_node_list *list;
2339
2340
0
    list = tc->lysc_tree ?
2341
0
            (const struct lysp_node_list *)TRP_TREE_CTX_GET_LYSP_NODE(tc->cn) :
2342
0
            (const struct lysp_node_list *)tc->pn;
2343
0
    assert(list->nodetype & LYS_LIST);
2344
2345
0
    if (trg_charptr_has_data(list->key)) {
2346
0
        ly_print_(out, "%s", list->key);
2347
0
    }
2348
0
}
2349
2350
/**
2351
 * @brief Get rpcs section if exists.
2352
 * @param[in,out] tc is tree context.
2353
 * @return Section representation if it exists. The @p tc is modified
2354
 * and his pointer points to the first node in rpcs section.
2355
 * @return Empty section representation otherwise.
2356
 */
2357
static struct trt_keyword_stmt
2358
tro_modi_get_rpcs(struct trt_tree_ctx *tc)
2359
0
{
2360
0
    assert(tc);
2361
0
    const void *actions;
2362
2363
0
    if (tc->lysc_tree) {
2364
0
        actions = tc->cmod->rpcs;
2365
0
        if (actions) {
2366
0
            tc->cn = actions;
2367
0
        }
2368
0
    } else {
2369
0
        actions = tc->pmod->rpcs;
2370
0
        if (actions) {
2371
0
            tc->pn = actions;
2372
0
            tc->tpn = tc->pn;
2373
0
        }
2374
0
    }
2375
2376
0
    if (actions) {
2377
0
        tc->section = TRD_SECT_RPCS;
2378
0
        return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_RPC, NULL);
2379
0
    } else {
2380
0
        return TRP_EMPTY_KEYWORD_STMT;
2381
0
    }
2382
0
}
2383
2384
/**
2385
 * @brief Get notification section if exists
2386
 * @param[in,out] tc is tree context.
2387
 * @return Section representation if it exists.
2388
 * The @p tc is modified and his pointer points to the
2389
 * first node in notification section.
2390
 * @return Empty section representation otherwise.
2391
 */
2392
static struct trt_keyword_stmt
2393
tro_modi_get_notifications(struct trt_tree_ctx *tc)
2394
0
{
2395
0
    assert(tc);
2396
0
    const void *notifs;
2397
2398
0
    if (tc->lysc_tree) {
2399
0
        notifs = tc->cmod->notifs;
2400
0
        if (notifs) {
2401
0
            tc->cn = notifs;
2402
0
        }
2403
0
    } else {
2404
0
        notifs = tc->pmod->notifs;
2405
0
        if (notifs) {
2406
0
            tc->pn = notifs;
2407
0
            tc->tpn = tc->pn;
2408
0
        }
2409
0
    }
2410
2411
0
    if (notifs) {
2412
0
        tc->section = TRD_SECT_NOTIF;
2413
0
        return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_NOTIF, NULL);
2414
0
    } else {
2415
0
        return TRP_EMPTY_KEYWORD_STMT;
2416
0
    }
2417
0
}
2418
2419
/**
2420
 * @brief Get next yang-data section if it is possible.
2421
 *
2422
 * @param[in,out] tc is tree context.
2423
 * @param[in] u is index to the array of extensions (lysc_ext_instance
2424
 * or struct lysp_ext_instance).
2425
 * @return Section representation if it exists.
2426
 * @return Empty section representation otherwise.
2427
 */
2428
static struct trt_keyword_stmt
2429
tro_modi_next_yang_data(struct trt_tree_ctx *tc, LY_ARRAY_COUNT_TYPE u)
2430
0
{
2431
0
    assert(tc);
2432
0
    const void *node;
2433
0
    const char *yang_data_name;
2434
2435
0
    if (tc->lysc_tree) {
2436
0
        struct lysc_ext_instance *exts;
2437
0
        struct lysc_ext_substmt *substmts;
2438
2439
0
        exts = tc->cmod->exts;
2440
0
        substmts = exts[u].substmts;
2441
0
        if (!substmts) {
2442
0
            return TRP_EMPTY_KEYWORD_STMT;
2443
0
        }
2444
0
        node = *(const struct lysc_node **)substmts->storage;
2445
0
        yang_data_name = exts[u].argument;
2446
0
    } else {
2447
0
        struct lysp_ext_instance *exts;
2448
2449
0
        exts = tc->pmod->exts;
2450
0
        node = exts[u].parsed;
2451
0
        yang_data_name = exts[u].argument;
2452
0
    }
2453
2454
0
    if (tc->lysc_tree) {
2455
0
        tc->cn = node;
2456
0
    } else {
2457
0
        tc->tpn_ext = &tc->pmod->exts[u];
2458
0
        tc->pn = node;
2459
0
    }
2460
2461
0
    if (node) {
2462
0
        tc->section = TRD_SECT_YANG_DATA;
2463
0
        return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_YANG_DATA, yang_data_name);
2464
0
    } else {
2465
0
        return TRP_EMPTY_KEYWORD_STMT;
2466
0
    }
2467
0
}
2468
2469
/**
2470
 * @brief Get name of the module.
2471
 * @param[in] tc is context of the tree.
2472
 */
2473
static struct trt_keyword_stmt
2474
tro_read_module_name(const struct trt_tree_ctx *tc)
2475
0
{
2476
0
    assert(tc);
2477
2478
0
    struct trt_keyword_stmt ret;
2479
2480
0
    ret.type = !tc->lysc_tree && tc->pmod->is_submod ?
2481
0
            TRD_KEYWORD_SUBMODULE :
2482
0
            TRD_KEYWORD_MODULE;
2483
2484
0
    ret.str = !tc->lysc_tree ?
2485
0
            LYSP_MODULE_NAME(tc->pmod) :
2486
0
            tc->cmod->mod->name;
2487
2488
0
    return ret;
2489
0
}
2490
2491
/**********************************************************************
2492
 * Definition of trop reading functions
2493
 *********************************************************************/
2494
2495
/**
2496
 * @brief Check if list statement has keys.
2497
 * @param[in] pn is pointer to the list.
2498
 * @return 1 if has keys, otherwise 0.
2499
 */
2500
static ly_bool
2501
trop_list_has_keys(const struct lysp_node *pn)
2502
0
{
2503
0
    return trg_charptr_has_data(((const struct lysp_node_list *)pn)->key);
2504
0
}
2505
2506
/**
2507
 * @brief Check if it contains at least one feature.
2508
 * @param[in] pn is current node.
2509
 * @return 1 if has if-features, otherwise 0.
2510
 */
2511
static ly_bool
2512
trop_node_has_iffeature(const struct lysp_node *pn)
2513
0
{
2514
0
    LY_ARRAY_COUNT_TYPE u;
2515
0
    const struct lysp_qname *iffs;
2516
2517
0
    ly_bool ret = 0;
2518
2519
0
    iffs = pn->iffeatures;
2520
0
    LY_ARRAY_FOR(iffs, u) {
2521
0
        ret = 1;
2522
0
        break;
2523
0
    }
2524
0
    return ret;
2525
0
}
2526
2527
/**
2528
 * @brief Find out if leaf is also the key in last list.
2529
 * @param[in] pn is pointer to leaf.
2530
 * @param[in] ca_last_list is pointer to last visited list.
2531
 * Obtained from trt_parent_cache.
2532
 * @return 1 if leaf is also the key, otherwise 0.
2533
 */
2534
static ly_bool
2535
trop_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
2536
0
{
2537
0
    const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2538
0
    const struct lysp_node_list *list = ca_last_list;
2539
2540
0
    if (!list) {
2541
0
        return 0;
2542
0
    }
2543
0
    return trg_charptr_has_data(list->key) ?
2544
0
           trg_word_is_present(list->key, leaf->name, ' ') : 0;
2545
0
}
2546
2547
/**
2548
 * @brief Check if container's type is presence.
2549
 * @param[in] pn is pointer to container.
2550
 * @return 1 if container has presence statement, otherwise 0.
2551
 */
2552
static ly_bool
2553
trop_container_has_presence(const struct lysp_node *pn)
2554
0
{
2555
0
    return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence);
2556
0
}
2557
2558
/**
2559
 * @brief Get leaflist's path without lysp_node type control.
2560
 * @param[in] pn is pointer to the leaflist.
2561
 */
2562
static const char *
2563
trop_leaflist_refpath(const struct lysp_node *pn)
2564
0
{
2565
0
    const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2566
2567
0
    return list->type.path ? list->type.path->expr : NULL;
2568
0
}
2569
2570
/**
2571
 * @brief Get leaflist's type name without lysp_node type control.
2572
 * @param[in] pn is pointer to the leaflist.
2573
 */
2574
static const char *
2575
trop_leaflist_type_name(const struct lysp_node *pn)
2576
0
{
2577
0
    const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn;
2578
2579
0
    return list->type.name;
2580
0
}
2581
2582
/**
2583
 * @brief Get leaf's path without lysp_node type control.
2584
 * @param[in] pn is pointer to the leaf node.
2585
 */
2586
static const char *
2587
trop_leaf_refpath(const struct lysp_node *pn)
2588
0
{
2589
0
    const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2590
2591
0
    return leaf->type.path ? leaf->type.path->expr : NULL;
2592
0
}
2593
2594
/**
2595
 * @brief Get leaf's type name without lysp_node type control.
2596
 * @param[in] pn is pointer to the leaf's type name.
2597
 */
2598
static const char *
2599
trop_leaf_type_name(const struct lysp_node *pn)
2600
0
{
2601
0
    const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
2602
2603
0
    return leaf->type.name;
2604
0
}
2605
2606
/**
2607
 * @brief Get pointer to data using node type specification
2608
 * and getter function.
2609
 *
2610
 * @param[in] flags is node type specification.
2611
 * If it is the correct node, the getter function is called.
2612
 * @param[in] f is getter function which provides the desired
2613
 * char pointer from the structure.
2614
 * @param[in] pn pointer to node.
2615
 * @return NULL if node has wrong type or getter function return
2616
 * pointer to NULL.
2617
 * @return Pointer to desired char pointer obtained from the node.
2618
 */
2619
static const char *
2620
trop_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn)
2621
0
{
2622
0
    if (pn->nodetype & flags) {
2623
0
        const char *ret = f(pn);
2624
0
        return trg_charptr_has_data(ret) ? ret : NULL;
2625
0
    } else {
2626
0
        return NULL;
2627
0
    }
2628
0
}
2629
2630
/**
2631
 * @brief Resolve \<status\> of the current node.
2632
 * @param[in] nodetype is node's type obtained from the tree.
2633
 * @param[in] flags is node's flags obtained from the tree.
2634
 * @param[in] ca_lys_status is inherited status
2635
 * obtained from trt_parent_cache.
2636
 * @return The status type.
2637
 */
2638
static trt_status_type
2639
trop_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
2640
0
{
2641
    /* LYS_INPUT and LYS_OUTPUT is special case */
2642
0
    if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
2643
0
        return tro_flags2status(ca_lys_status);
2644
        /* if ancestor's status is deprc or obslt
2645
         * and also node's status is not set
2646
         */
2647
0
    } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
2648
        /* get ancestor's status */
2649
0
        return tro_flags2status(ca_lys_status);
2650
0
    } else {
2651
        /* else get node's status */
2652
0
        return tro_flags2status(flags);
2653
0
    }
2654
0
}
2655
2656
/**
2657
 * @brief Resolve \<flags\> of the current node.
2658
 * @param[in] nodetype is node's type obtained from the tree.
2659
 * @param[in] flags is node's flags obtained from the tree.
2660
 * @param[in] ca_ancestor is ancestor type obtained
2661
 * from trt_parent_cache.
2662
 * @param[in] ca_lys_config is inherited config item
2663
 * obtained from trt_parent_cache.
2664
 * @return The flags type.
2665
 */
2666
static trt_flags_type
2667
trop_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config)
2668
0
{
2669
0
    if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) {
2670
0
        return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
2671
0
    } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) {
2672
0
        return TRD_FLAGS_TYPE_RO;
2673
0
    } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) {
2674
0
        return TRD_FLAGS_TYPE_RO;
2675
0
    } else if (nodetype & LYS_NOTIF) {
2676
0
        return TRD_FLAGS_TYPE_NOTIF;
2677
0
    } else if (nodetype & LYS_USES) {
2678
0
        return TRD_FLAGS_TYPE_USES_OF_GROUPING;
2679
0
    } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
2680
0
        return TRD_FLAGS_TYPE_RPC;
2681
0
    } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
2682
        /* config is not set. Look at ancestor's config */
2683
0
        return tro_flags2config(ca_lys_config);
2684
0
    } else {
2685
0
        return tro_flags2config(flags);
2686
0
    }
2687
0
}
2688
2689
/**
2690
 * @brief Resolve node type of the current node.
2691
 * @param[in] pn is pointer to the current node in the tree.
2692
 * @param[in] ca_last_list is pointer to the last visited list.
2693
 * Obtained from the trt_parent_cache.
2694
 */
2695
static trt_node_type
2696
trop_resolve_node_type(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
2697
0
{
2698
0
    if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
2699
0
        return TRD_NODE_ELSE;
2700
0
    } else if (pn->nodetype & LYS_CASE) {
2701
0
        return TRD_NODE_CASE;
2702
0
    } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) {
2703
0
        return TRD_NODE_OPTIONAL_CHOICE;
2704
0
    } else if (pn->nodetype & LYS_CHOICE) {
2705
0
        return TRD_NODE_CHOICE;
2706
0
    } else if ((pn->nodetype & LYS_CONTAINER) && (trop_container_has_presence(pn))) {
2707
0
        return TRD_NODE_CONTAINER;
2708
0
    } else if ((pn->nodetype & LYS_LIST) && (trop_list_has_keys(pn))) {
2709
0
        return TRD_NODE_KEYS;
2710
0
    } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
2711
0
        return TRD_NODE_LISTLEAFLIST;
2712
0
    } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) {
2713
0
        return TRD_NODE_OPTIONAL;
2714
0
    } else if ((pn->nodetype & LYS_LEAF) && !(pn->flags & LYS_MAND_TRUE) && (!trop_leaf_is_key(pn, ca_last_list))) {
2715
0
        return TRD_NODE_OPTIONAL;
2716
0
    } else {
2717
0
        return TRD_NODE_ELSE;
2718
0
    }
2719
0
}
2720
2721
/**
2722
 * @brief Resolve \<type\> of the current node.
2723
 * @param[in] pn is current node.
2724
 */
2725
static struct trt_type
2726
trop_resolve_type(const struct lysp_node *pn)
2727
0
{
2728
0
    const char *tmp = NULL;
2729
2730
0
    if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_refpath, pn))) {
2731
0
        return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2732
0
    } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_type_name, pn))) {
2733
0
        return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2734
0
    } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_refpath, pn))) {
2735
0
        return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp);
2736
0
    } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_type_name, pn))) {
2737
0
        return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp);
2738
0
    } else if (pn->nodetype == LYS_ANYDATA) {
2739
0
        return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata");
2740
0
    } else if (pn->nodetype & LYS_ANYXML) {
2741
0
        return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml");
2742
0
    } else {
2743
0
        return TRP_EMPTY_TRT_TYPE;
2744
0
    }
2745
0
}
2746
2747
/**
2748
 * @brief Transformation of current lysp_node to struct trt_node.
2749
 * @param[in] ca contains stored important data
2750
 * when browsing the tree downwards.
2751
 * @param[in] tc is context of the tree.
2752
 */
2753
static struct trt_node
2754
trop_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
2755
0
{
2756
0
    const struct lysp_node *pn;
2757
0
    struct trt_node ret;
2758
2759
0
    assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
2760
2761
0
    pn = tc->pn;
2762
0
    ret = TRP_EMPTY_NODE;
2763
2764
    /* <status> */
2765
0
    ret.status = trop_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
2766
2767
    /* TODO: TRD_FLAGS_TYPE_MOUNT_POINT aka "mp" is not supported right now. */
2768
    /* <flags> */
2769
0
    ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config);
2770
2771
    /* TODO: TRD_NODE_TOP_LEVEL1 aka '/' is not supported right now. */
2772
    /* TODO: TRD_NODE_TOP_LEVEL2 aka '@' is not supported right now. */
2773
    /* set type of the node */
2774
0
    ret.name.type = trop_resolve_node_type(pn, ca.last_list);
2775
2776
    /* TODO: ret.name.module_prefix is not supported right now. */
2777
0
    ret.name.module_prefix = NULL;
2778
2779
    /* set node's name */
2780
0
    ret.name.str = pn->name;
2781
2782
    /* <type> */
2783
0
    ret.type = trop_resolve_type(pn);
2784
2785
    /* <iffeature> */
2786
0
    ret.iffeatures = trop_node_has_iffeature(pn);
2787
2788
0
    ret.last_one = !tro_next_sibling(pn, tc->lysc_tree);
2789
2790
0
    return ret;
2791
0
}
2792
2793
/**
2794
 * @brief Find out if the current node has siblings.
2795
 * @param[in] tc is context of the tree.
2796
 * @return 1 if sibling exists otherwise 0.
2797
 */
2798
static ly_bool
2799
trop_read_if_sibling_exists(const struct trt_tree_ctx *tc)
2800
0
{
2801
0
    return tro_next_sibling(tc->pn, tc->lysc_tree) != NULL;
2802
0
}
2803
2804
/**
2805
 * @brief Print all yang-data sections and print three dots instead
2806
 * of nodes.
2807
 * @param[in] exts is array of YANG extension instances from parsed
2808
 * module (@ref sizedarrays).
2809
 * @param[in] mll is maximum number of characters that can be printed
2810
 * on one line.
2811
 * @param[in,out] out is output handler.
2812
 */
2813
static void
2814
trop_yang_data_sections(const struct lysp_ext_instance *exts, size_t mll, struct ly_out *out)
2815
0
{
2816
0
    struct trt_keyword_stmt ks;
2817
0
    LY_ARRAY_COUNT_TYPE u;
2818
0
    struct trt_wrapper wr;
2819
2820
0
    if (!exts) {
2821
0
        return;
2822
0
    }
2823
2824
0
    ly_print_(out, "\n");
2825
0
    ks.type = TRD_KEYWORD_YANG_DATA;
2826
0
    wr = TRP_INIT_WRAPPER_BODY;
2827
2828
0
    LY_ARRAY_FOR(exts, u) {
2829
0
        ly_print_(out, "\n");
2830
2831
        /* yang-data <yang-data-name>: */
2832
0
        ks.str = exts[u].argument;
2833
0
        trp_print_keyword_stmt(ks, mll, 0, out);
2834
0
        ly_print_(out, "\n");
2835
2836
        /*   ... */
2837
0
        trp_print_wrapper(wr, out);
2838
0
        ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT);
2839
0
    }
2840
0
}
2841
2842
/**********************************************************************
2843
 * Modify trop getters
2844
 *********************************************************************/
2845
2846
/**
2847
 * @brief Change current node pointer to its parent
2848
 * but only if parent exists.
2849
 * @param[in,out] tc is tree context.
2850
 * Contains pointer to the current node.
2851
 * @return 1 if the node had parents and the change was successful.
2852
 * @return 0 if the node did not have parents.
2853
 * The pointer to the current node did not change.
2854
 */
2855
static ly_bool
2856
trop_modi_parent(struct trt_tree_ctx *tc)
2857
0
{
2858
0
    assert(tc && tc->pn);
2859
    /* If no parent exists, stay in actual node. */
2860
0
    if ((tc->pn != tc->tpn) && (tc->pn->parent)) {
2861
0
        tc->pn = tc->pn->parent;
2862
0
        return 1;
2863
0
    } else {
2864
0
        return 0;
2865
0
    }
2866
0
}
2867
2868
/**
2869
 * @brief Change the current node pointer to its child
2870
 * but only if exists.
2871
 * @param[in] ca contains inherited data from ancestors.
2872
 * @param[in,out] tc is context of the tree.
2873
 * Contains pointer to the current node.
2874
 * @return Non-empty \<node\> representation of the current
2875
 * node's child. The @p tc is modified.
2876
 * @return Empty \<node\> representation if child don't exists.
2877
 * The @p tc is not modified.
2878
 */
2879
static struct trt_node
2880
trop_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
2881
0
{
2882
0
    const struct lysp_node *tmp;
2883
2884
0
    assert(tc && tc->pn);
2885
2886
0
    if ((tmp = tro_next_child(tc->pn, tc->lysc_tree))) {
2887
0
        tc->pn = tmp;
2888
0
        return trop_read_node(tro_parent_cache_for_child(ca, tc), tc);
2889
0
    } else {
2890
0
        return TRP_EMPTY_NODE;
2891
0
    }
2892
0
}
2893
2894
/**
2895
 * @brief Change the current node pointer to the first child of node's
2896
 * parent. If current node is already first sibling/child then nothing
2897
 * will change.
2898
 * @param[in,out] tc is tree context.
2899
 */
2900
static void
2901
trop_modi_first_sibling(struct trt_tree_ctx *tc)
2902
0
{
2903
0
    assert(tc && tc->pn && tc->pmod);
2904
2905
0
    if (trop_modi_parent(tc)) {
2906
0
        trop_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
2907
0
    } else {
2908
        /* current node is top-node */
2909
0
        switch (tc->section) {
2910
0
        case TRD_SECT_MODULE:
2911
0
            tc->pn = tc->pmod->data;
2912
0
            tc->tpn = tc->pn;
2913
0
            break;
2914
0
        case TRD_SECT_AUGMENT:
2915
0
            tc->pn = (const struct lysp_node *)tc->pmod->augments;
2916
0
            tc->tpn = tc->pn;
2917
0
            break;
2918
0
        case TRD_SECT_RPCS:
2919
0
            tc->pn = (const struct lysp_node *)tc->pmod->rpcs;
2920
0
            tc->tpn = tc->pn;
2921
0
            break;
2922
0
        case TRD_SECT_NOTIF:
2923
0
            tc->pn = (const struct lysp_node *)tc->pmod->notifs;
2924
0
            tc->tpn = tc->pn;
2925
0
            break;
2926
0
        case TRD_SECT_GROUPING:
2927
0
            tc->pn = (const struct lysp_node *)tc->pmod->groupings;
2928
0
            tc->tpn = tc->pn;
2929
0
            break;
2930
0
        case TRD_SECT_YANG_DATA:
2931
            /* tpn in this case is of type lysp_ext_instance */
2932
0
            tc->pn = tc->tpn_ext->parsed;
2933
0
            break;
2934
0
        default:
2935
0
            assert(0);
2936
0
        }
2937
0
    }
2938
0
}
2939
2940
/**
2941
 * @brief Change the pointer to the current node to its next sibling
2942
 * only if exists.
2943
 * @param[in] ca contains inherited data from ancestors.
2944
 * @param[in,out] tc is tree context.
2945
 * Contains pointer to the current node.
2946
 * @return Non-empty \<node\> representation if sibling exists.
2947
 * The @p tc is modified.
2948
 * @return Empty \<node\> representation otherwise.
2949
 * The @p tc is not modified.
2950
 */
2951
static struct trt_node
2952
trop_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
2953
0
{
2954
0
    const struct lysp_node *pn;
2955
2956
0
    assert(tc && tc->pn);
2957
2958
0
    pn = tro_next_sibling(tc->pn, tc->lysc_tree);
2959
2960
0
    if (pn) {
2961
0
        if ((tc->tpn == tc->pn) && (tc->section != TRD_SECT_YANG_DATA)) {
2962
0
            tc->tpn = pn;
2963
0
        }
2964
0
        tc->pn = pn;
2965
0
        return trop_read_node(ca, tc);
2966
0
    } else {
2967
0
        return TRP_EMPTY_NODE;
2968
0
    }
2969
0
}
2970
2971
/**
2972
 * @brief Get next (or first) augment section if exists.
2973
 * @param[in,out] tc is tree context. It is modified and his current
2974
 * node is set to the lysp_node_augment.
2975
 * @return Section's representation if (next augment) section exists.
2976
 * @return Empty section structure otherwise.
2977
 */
2978
static struct trt_keyword_stmt
2979
trop_modi_next_augment(struct trt_tree_ctx *tc)
2980
0
{
2981
0
    assert(tc);
2982
0
    const struct lysp_node_augment *augs;
2983
2984
    /* if next_augment func was called for the first time */
2985
0
    if (tc->section != TRD_SECT_AUGMENT) {
2986
0
        tc->section = TRD_SECT_AUGMENT;
2987
0
        augs = tc->pmod->augments;
2988
0
    } else {
2989
        /* get augment sibling from top-node pointer */
2990
0
        augs = (const struct lysp_node_augment *)tc->tpn->next;
2991
0
    }
2992
2993
0
    if (augs) {
2994
0
        tc->pn = &augs->node;
2995
0
        tc->tpn = tc->pn;
2996
0
        return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_AUGMENT, augs->nodeid);
2997
0
    } else {
2998
0
        return TRP_EMPTY_KEYWORD_STMT;
2999
0
    }
3000
0
}
3001
3002
/**
3003
 * @brief Get next (or first) grouping section if exists
3004
 * @param[in,out] tc is tree context. It is modified and his current
3005
 * node is set to the lysp_node_grp.
3006
 * @return The next (or first) section representation if it exists.
3007
 * @return Empty section representation otherwise.
3008
 */
3009
static struct trt_keyword_stmt
3010
trop_modi_next_grouping(struct trt_tree_ctx *tc)
3011
0
{
3012
0
    assert(tc);
3013
0
    const struct lysp_node_grp *grps;
3014
3015
0
    if (tc->section != TRD_SECT_GROUPING) {
3016
0
        tc->section = TRD_SECT_GROUPING;
3017
0
        grps = tc->pmod->groupings;
3018
0
    } else {
3019
0
        grps = (const struct lysp_node_grp *)tc->tpn->next;
3020
0
    }
3021
3022
0
    if (grps) {
3023
0
        tc->pn = &grps->node;
3024
0
        tc->tpn = tc->pn;
3025
0
        return TRP_INIT_KEYWORD_STMT(TRD_KEYWORD_GROUPING, grps->name);
3026
0
    } else {
3027
0
        return TRP_EMPTY_KEYWORD_STMT;
3028
0
    }
3029
0
}
3030
3031
/**********************************************************************
3032
 * Definition of troc reading functions
3033
 *********************************************************************/
3034
3035
/**
3036
 * @copydoc trop_read_if_sibling_exists
3037
 */
3038
static ly_bool
3039
troc_read_if_sibling_exists(const struct trt_tree_ctx *tc)
3040
0
{
3041
0
    return tro_next_sibling(tc->cn, tc->lysc_tree) != NULL;
3042
0
}
3043
3044
/**
3045
 * @brief Resolve \<flags\> of the current node.
3046
 *
3047
 * Use this function only if trt_tree_ctx.lysc_tree is true.
3048
 *
3049
 * @param[in] nodetype is current lysc_node.nodetype.
3050
 * @param[in] flags is current lysc_node.flags.
3051
 * @return The flags type.
3052
 */
3053
static trt_flags_type
3054
troc_resolve_flags(uint16_t nodetype, uint16_t flags)
3055
0
{
3056
0
    if ((nodetype & LYS_INPUT) || (flags & LYS_IS_INPUT)) {
3057
0
        return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS;
3058
0
    } else if ((nodetype & LYS_OUTPUT) || (flags & LYS_IS_OUTPUT)) {
3059
0
        return TRD_FLAGS_TYPE_RO;
3060
0
    } else if (nodetype & LYS_IS_NOTIF) {
3061
0
        return TRD_FLAGS_TYPE_RO;
3062
0
    } else if (nodetype & LYS_NOTIF) {
3063
0
        return TRD_FLAGS_TYPE_NOTIF;
3064
0
    } else if (nodetype & LYS_USES) {
3065
0
        return TRD_FLAGS_TYPE_USES_OF_GROUPING;
3066
0
    } else if (nodetype & (LYS_RPC | LYS_ACTION)) {
3067
0
        return TRD_FLAGS_TYPE_RPC;
3068
0
    } else {
3069
0
        return tro_flags2config(flags);
3070
0
    }
3071
0
}
3072
3073
/**
3074
 * @brief Resolve node type of the current node.
3075
 *
3076
 * Use this function only if trt_tree_ctx.lysc_tree is true.
3077
 *
3078
 * @param[in] nodetype is current lysc_node.nodetype.
3079
 * @param[in] flags is current lysc_node.flags.
3080
 */
3081
static trt_node_type
3082
troc_resolve_node_type(uint16_t nodetype, uint16_t flags)
3083
0
{
3084
0
    if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
3085
0
        return TRD_NODE_ELSE;
3086
0
    } else if (nodetype & LYS_CASE) {
3087
0
        return TRD_NODE_CASE;
3088
0
    } else if ((nodetype & LYS_CHOICE) && !(flags & LYS_MAND_TRUE)) {
3089
0
        return TRD_NODE_OPTIONAL_CHOICE;
3090
0
    } else if (nodetype & LYS_CHOICE) {
3091
0
        return TRD_NODE_CHOICE;
3092
0
    } else if ((nodetype & LYS_CONTAINER) && (flags & LYS_PRESENCE)) {
3093
0
        return TRD_NODE_CONTAINER;
3094
0
    } else if ((nodetype & LYS_LIST) && !(flags & LYS_KEYLESS)) {
3095
0
        return TRD_NODE_KEYS;
3096
0
    } else if (nodetype & (LYS_LIST | LYS_LEAFLIST)) {
3097
0
        return TRD_NODE_LISTLEAFLIST;
3098
0
    } else if ((nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(flags & LYS_MAND_TRUE)) {
3099
0
        return TRD_NODE_OPTIONAL;
3100
0
    } else if ((nodetype & LYS_LEAF) && !(flags & (LYS_MAND_TRUE | LYS_KEY))) {
3101
0
        return TRD_NODE_OPTIONAL;
3102
0
    } else {
3103
0
        return TRD_NODE_ELSE;
3104
0
    }
3105
0
}
3106
3107
/**
3108
 * @brief Transformation of current lysc_node to struct trt_node.
3109
 * @param[in] ca is not used.
3110
 * @param[in] tc is context of the tree.
3111
 */
3112
static struct trt_node
3113
troc_read_node(struct trt_parent_cache ca, const struct trt_tree_ctx *tc)
3114
0
{
3115
0
    (void) ca;
3116
0
    const struct lysc_node *cn;
3117
0
    struct trt_node ret;
3118
3119
0
    assert(tc && tc->cn && tc->cn->priv);
3120
3121
0
    cn = tc->cn;
3122
0
    ret = TRP_EMPTY_NODE;
3123
3124
    /* <status> */
3125
0
    ret.status = tro_flags2status(cn->flags);
3126
3127
    /* TODO: TRD_FLAGS_TYPE_MOUNT_POINT aka "mp" is not supported right now. */
3128
    /* <flags> */
3129
0
    ret.flags = troc_resolve_flags(cn->nodetype, cn->flags);
3130
3131
    /* TODO: TRD_NODE_TOP_LEVEL1 aka '/' is not supported right now. */
3132
    /* TODO: TRD_NODE_TOP_LEVEL2 aka '@' is not supported right now. */
3133
    /* set type of the node */
3134
0
    ret.name.type = troc_resolve_node_type(cn->nodetype, cn->flags);
3135
3136
    /* TODO: ret.name.module_prefix is not supported right now. */
3137
0
    ret.name.module_prefix = NULL;
3138
3139
    /* set node's name */
3140
0
    ret.name.str = cn->name;
3141
3142
    /* <type> */
3143
0
    ret.type = trop_resolve_type(TRP_TREE_CTX_GET_LYSP_NODE(cn));
3144
3145
    /* <iffeature> */
3146
0
    ret.iffeatures = trop_node_has_iffeature(TRP_TREE_CTX_GET_LYSP_NODE(cn));
3147
3148
0
    ret.last_one = !tro_next_sibling(cn, tc->lysc_tree);
3149
3150
0
    return ret;
3151
0
}
3152
3153
/**********************************************************************
3154
 * Modify troc getters
3155
 *********************************************************************/
3156
3157
/**
3158
 * @copydoc ::trop_modi_parent()
3159
 */
3160
static ly_bool
3161
troc_modi_parent(struct trt_tree_ctx *tc)
3162
0
{
3163
0
    assert(tc && tc->cn);
3164
    /* If no parent exists, stay in actual node. */
3165
0
    if (tc->cn->parent) {
3166
0
        tc->cn = tc->cn->parent;
3167
0
        return 1;
3168
0
    } else {
3169
0
        return 0;
3170
0
    }
3171
0
}
3172
3173
/**
3174
 * @copydoc ::trop_modi_next_sibling()
3175
 */
3176
static struct trt_node
3177
troc_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3178
0
{
3179
0
    const struct lysc_node *cn;
3180
3181
0
    assert(tc && tc->cn);
3182
3183
0
    cn = tro_next_sibling(tc->cn, tc->lysc_tree);
3184
3185
    /* if next sibling exists */
3186
0
    if (cn) {
3187
        /* update trt_tree_ctx */
3188
0
        tc->cn = cn;
3189
0
        return troc_read_node(ca, tc);
3190
0
    } else {
3191
0
        return TRP_EMPTY_NODE;
3192
0
    }
3193
0
}
3194
3195
/**
3196
 * @copydoc trop_modi_next_child()
3197
 */
3198
static struct trt_node
3199
troc_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
3200
0
{
3201
0
    const struct lysc_node *tmp;
3202
3203
0
    assert(tc && tc->cn);
3204
3205
0
    if ((tmp = tro_next_child(tc->cn, tc->lysc_tree))) {
3206
0
        tc->cn = tmp;
3207
0
        return troc_read_node(ca, tc);
3208
0
    } else {
3209
0
        return TRP_EMPTY_NODE;
3210
0
    }
3211
0
}
3212
3213
/**
3214
 * @copydoc ::trop_modi_first_sibling()
3215
 */
3216
static void
3217
troc_modi_first_sibling(struct trt_tree_ctx *tc)
3218
0
{
3219
0
    assert(tc && tc->cn);
3220
3221
0
    if (troc_modi_parent(tc)) {
3222
0
        troc_modi_next_child(TRP_EMPTY_PARENT_CACHE, tc);
3223
0
    } else {
3224
        /* current node is top-node */
3225
0
        switch (tc->section) {
3226
0
        case TRD_SECT_MODULE:
3227
0
            tc->cn = tc->cmod->data;
3228
0
            break;
3229
0
        case TRD_SECT_RPCS:
3230
0
            tc->cn = (const struct lysc_node *)tc->cmod->rpcs;
3231
0
            break;
3232
0
        case TRD_SECT_NOTIF:
3233
0
            tc->cn = (const struct lysc_node *)tc->cmod->notifs;
3234
0
            break;
3235
0
        case TRD_SECT_YANG_DATA:
3236
            /* nothing to do */
3237
0
            break;
3238
0
        default:
3239
0
            assert(0);
3240
0
        }
3241
0
    }
3242
0
}
3243
3244
/**********************************************************************
3245
 * Definition of tree browsing functions
3246
 *********************************************************************/
3247
3248
/**
3249
 * @brief Get size of node name.
3250
 * @param[in] name contains name and mark.
3251
 * @return positive value total size of the node name.
3252
 * @return negative value as an indication that option mark
3253
 * is included in the total size.
3254
 */
3255
static int32_t
3256
trb_strlen_of_name_and_mark(struct trt_node_name name)
3257
0
{
3258
0
    size_t name_len = strlen(name.str);
3259
3260
0
    if ((name.type == TRD_NODE_CHOICE) || (name.type == TRD_NODE_CASE)) {
3261
        /* counting also parentheses */
3262
0
        name_len += 2;
3263
0
    }
3264
3265
0
    return trp_mark_is_used(name) ?
3266
0
           ((int32_t)(name_len + TRD_OPTS_MARK_LENGTH)) * (-1) :
3267
0
           (int32_t)name_len;
3268
0
}
3269
3270
/**
3271
 * @brief Calculate the trt_indent_in_node.btw_opts_type indent size
3272
 * for a particular node.
3273
 * @param[in] name is the node for which we get btw_opts_type.
3274
 * @param[in] max_len4all is the maximum value of btw_opts_type
3275
 * that it can have.
3276
 * @return Indent between \<opts\> and \<type\> for node.
3277
 */
3278
static int16_t
3279
trb_calc_btw_opts_type(struct trt_node_name name, int16_t max_len4all)
3280
0
{
3281
0
    int32_t name_len;
3282
0
    int16_t min_len;
3283
0
    int16_t ret;
3284
3285
0
    name_len = trb_strlen_of_name_and_mark(name);
3286
3287
    /* negative value indicate that in name is some opt mark */
3288
0
    min_len = name_len < 0 ?
3289
0
            TRD_INDENT_BEFORE_TYPE - TRD_OPTS_MARK_LENGTH :
3290
0
            TRD_INDENT_BEFORE_TYPE;
3291
0
    ret = abs(max_len4all) - abs(name_len);
3292
3293
    /* correction -> negative indicate that name is too long. */
3294
0
    return ret < 0 ? min_len : ret;
3295
0
}
3296
3297
/**
3298
 * @brief Print node.
3299
 *
3300
 * This function is wrapper for ::trp_print_entire_node().
3301
 * But difference is that take @p max_gap_before_type which will be
3302
 * used to set the unified alignment.
3303
 *
3304
 * @param[in] max_gap_before_type is number of indent before \<type\>.
3305
 * @param[in] wr is wrapper for printing indentation before node.
3306
 * @param[in] ca contains inherited data from ancestors.
3307
 * @param[in] pc contains mainly functions for printing.
3308
 * @param[in] tc is tree context.
3309
 */
3310
static void
3311
trb_print_entire_node(uint32_t max_gap_before_type, struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3312
0
{
3313
0
    struct trt_node node = pc->fp.read.node(ca, tc);
3314
0
    struct trt_indent_in_node ind = trp_default_indent_in_node(node);
3315
3316
0
    if ((max_gap_before_type > 0) && (node.type.type != TRD_TYPE_EMPTY)) {
3317
        /* print actual node with unified indent */
3318
0
        ind.btw_opts_type = trb_calc_btw_opts_type(node.name, max_gap_before_type);
3319
0
    }
3320
    /* after -> print actual node with default indent */
3321
0
    trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print),
3322
0
            TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out);
3323
0
}
3324
3325
/**
3326
 * @brief Check if parent of the current node is the last
3327
 * of his siblings.
3328
 *
3329
 * To mantain stability use this function only if the current node is
3330
 * the first of the siblings.
3331
 * Side-effect -> current node is set to the first sibling
3332
 * if node has a parent otherwise no side-effect.
3333
 *
3334
 * @param[in] fp contains all @ref TRP_tro callback functions.
3335
 * @param[in,out] tc is tree context.
3336
 * @return 1 if parent is last sibling otherwise 0.
3337
 */
3338
static ly_bool
3339
trb_parent_is_last_sibling(struct trt_fp_all fp, struct trt_tree_ctx *tc)
3340
0
{
3341
0
    if (fp.modify.parent(tc)) {
3342
0
        ly_bool ret = fp.read.if_sibling_exists(tc);
3343
0
        fp.modify.next_child(TRP_EMPTY_PARENT_CACHE, tc);
3344
0
        return !ret;
3345
0
    } else {
3346
0
        return !fp.read.if_sibling_exists(tc);
3347
0
    }
3348
0
}
3349
3350
/**
3351
 * @brief Find sibling with the biggest node name and return that size.
3352
 *
3353
 * Side-effect -> Current node is set to the first sibling.
3354
 *
3355
 * @param[in] ca contains inherited data from ancestors.
3356
 * @param[in] pc contains mainly functions for printing.
3357
 * @param[in,out] tc is tree context.
3358
 * @return positive number as a sign that only the node name is
3359
 * included in the size.
3360
 * @return negative number sign that node name and his opt mark is
3361
 * included in the size.
3362
 */
3363
static int32_t
3364
trb_maxlen_node_name(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3365
0
{
3366
0
    int32_t ret = 0;
3367
3368
0
    pc->fp.modify.first_sibling(tc);
3369
3370
0
    for (struct trt_node node = pc->fp.read.node(ca, tc);
3371
0
            !trp_node_is_empty(node);
3372
0
            node = pc->fp.modify.next_sibling(ca, tc)) {
3373
0
        int32_t maxlen = trb_strlen_of_name_and_mark(node.name);
3374
0
        ret = abs(maxlen) > abs(ret) ? maxlen : ret;
3375
0
    }
3376
0
    pc->fp.modify.first_sibling(tc);
3377
0
    return ret;
3378
0
}
3379
3380
/**
3381
 * @brief Find maximal indent between
3382
 * \<opts\> and \<type\> for siblings.
3383
 *
3384
 * Side-effect -> Current node is set to the first sibling.
3385
 *
3386
 * @param[in] ca contains inherited data from ancestors.
3387
 * @param[in] pc contains mainly functions for printing.
3388
 * @param[in,out] tc is tree context.
3389
 * @return max btw_opts_type value for rest of the siblings
3390
 */
3391
static int16_t
3392
trb_max_btw_opts_type4siblings(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3393
0
{
3394
0
    int32_t maxlen_node_name = trb_maxlen_node_name(ca, pc, tc);
3395
0
    int16_t ind_before_type = maxlen_node_name < 0 ?
3396
0
            TRD_INDENT_BEFORE_TYPE - 1 : /* mark was present */
3397
0
            TRD_INDENT_BEFORE_TYPE;
3398
3399
0
    return abs(maxlen_node_name) + ind_before_type;
3400
0
}
3401
3402
/**
3403
 * @brief Find out if it is possible to unify
3404
 * the alignment before \<type\>.
3405
 *
3406
 * The goal is for all node siblings to have the same alignment
3407
 * for \<type\> as if they were in a column. All siblings who cannot
3408
 * adapt because they do not fit on the line at all are ignored.
3409
 * Side-effect -> Current node is set to the first sibling.
3410
 *
3411
 * @param[in] ca contains inherited data from ancestors.
3412
 * @param[in] pc contains mainly functions for printing.
3413
 * @param[in,out] tc is tree context.
3414
 * @return 0 if all siblings cannot fit on the line.
3415
 * @return positive number indicating the maximum number of spaces
3416
 * before \<type\> if the length of the node name is 0. To calculate
3417
 * the trt_indent_in_node.btw_opts_type indent size for a particular
3418
 * node, use the ::trb_calc_btw_opts_type().
3419
*/
3420
static uint32_t
3421
trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3422
0
{
3423
0
    return trb_max_btw_opts_type4siblings(ca, pc, tc);
3424
0
}
3425
3426
/**
3427
 * @brief For the current node: recursively print all of its child
3428
 * nodes and all of its siblings, including their children.
3429
 *
3430
 * This function is an auxiliary function for ::trb_print_subtree_nodes().
3431
 * The parent of the current node is expected to exist.
3432
 * Nodes are printed, including unified sibling node alignment
3433
 * (align \<type\> to column).
3434
 * Side-effect -> current node is set to the last sibling.
3435
 *
3436
 * @param[in] wr is wrapper for printing identation before node.
3437
 * @param[in] ca contains inherited data from ancestors.
3438
 * @param[in] pc contains mainly functions for printing.
3439
 * @param[in,out] tc is tree context.
3440
 */
3441
static void
3442
trb_print_nodes(struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3443
0
{
3444
0
    uint32_t max_gap_before_type;
3445
0
    ly_bool sibling_flag = 0;
3446
0
    ly_bool child_flag = 0;
3447
3448
    /* if node is last sibling, then do not add '|' to wrapper */
3449
0
    wr = trb_parent_is_last_sibling(pc->fp, tc) ?
3450
0
            trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr);
3451
3452
    /* try unified indentation in node */
3453
0
    max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
3454
3455
    /* print all siblings */
3456
0
    do {
3457
0
        struct trt_parent_cache new_ca;
3458
0
        struct trt_node node;
3459
        /* print linebreak before printing actual node */
3460
0
        ly_print_(pc->out, "\n");
3461
        /* print node */
3462
0
        trb_print_entire_node(max_gap_before_type, wr, ca, pc, tc);
3463
3464
0
        new_ca = tro_parent_cache_for_child(ca, tc);
3465
        /* go to the actual node's child or stay in actual node */
3466
0
        node = pc->fp.modify.next_child(ca, tc);
3467
0
        child_flag = !trp_node_is_empty(node);
3468
3469
0
        if (child_flag) {
3470
            /* print all childs - recursive call */
3471
0
            trb_print_nodes(wr, new_ca, pc, tc);
3472
            /* get back from child node to actual node */
3473
0
            pc->fp.modify.parent(tc);
3474
0
        }
3475
3476
        /* go to the actual node's sibling */
3477
0
        node = pc->fp.modify.next_sibling(ca, tc);
3478
0
        sibling_flag = !trp_node_is_empty(node);
3479
3480
        /* go to the next sibling or stay in actual node */
3481
0
    } while (sibling_flag);
3482
0
}
3483
3484
/**
3485
 * @brief Calculate the wrapper about how deep in the tree the node is.
3486
 * @param[in] node from which to count.
3487
 * @return wrapper for @p node.
3488
 */
3489
static struct trt_wrapper
3490
trb_count_depth(const struct lysc_node *node)
3491
0
{
3492
0
    struct trt_wrapper wr = TRP_INIT_WRAPPER_TOP;
3493
0
    const struct lysc_node *parent;
3494
3495
0
    if (!node) {
3496
0
        return wr;
3497
0
    }
3498
3499
0
    for (parent = node->parent; parent; parent = parent->parent) {
3500
0
        wr = trp_wrapper_set_shift(wr);
3501
0
    }
3502
3503
0
    return wr;
3504
0
}
3505
3506
/**
3507
 * @brief Print all parent nodes of @p node and the @p node itself.
3508
 *
3509
 * Side-effect -> trt_tree_ctx.cn will be set to @p node.
3510
 *
3511
 * @param[in] node on which the function is focused.
3512
 * @param[in] pc is @ref TRP_trp settings.
3513
 * @param[in,out] tc is context of tree printer.
3514
 * @return wrapper for @p node.
3515
 */
3516
static void
3517
trb_print_parents(const struct lysc_node *node, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3518
0
{
3519
0
    struct trt_wrapper wr;
3520
3521
0
    assert(pc && tc && tc->section == TRD_SECT_MODULE);
3522
3523
    /* stop recursion */
3524
0
    if (!node) {
3525
0
        return;
3526
0
    }
3527
0
    trb_print_parents(node->parent, pc, tc);
3528
3529
    /* setup for printing */
3530
0
    tc->cn = node;
3531
0
    wr = trb_count_depth(node);
3532
3533
    /* print node */
3534
0
    ly_print_(pc->out, "\n");
3535
0
    trb_print_entire_node(0, wr, TRP_EMPTY_PARENT_CACHE, pc, tc);
3536
0
}
3537
3538
/**
3539
 * @brief Get address of the current node.
3540
 * @param[in] tc contains current node.
3541
 * @return Address of lysc_node or lysp_node, or NULL.
3542
 */
3543
static const void *
3544
trb_tree_ctx_get_node(struct trt_tree_ctx *tc)
3545
0
{
3546
0
    return tc->lysc_tree ?
3547
0
           (const void *)tc->cn :
3548
0
           (const void *)tc->pn;
3549
0
}
3550
3551
/**
3552
 * @brief Get address of current node's child.
3553
 * @param[in,out] tc contains current node.
3554
 */
3555
static const void *
3556
trb_tree_ctx_get_child(struct trt_tree_ctx *tc)
3557
0
{
3558
0
    if (!trb_tree_ctx_get_node(tc)) {
3559
0
        return NULL;
3560
0
    }
3561
3562
0
    if (tc->lysc_tree) {
3563
0
        return lysc_node_child(tc->cn);
3564
0
    } else {
3565
0
        return lysp_node_child(tc->pn);
3566
0
    }
3567
0
}
3568
3569
/**
3570
 * @brief Set current node on its child.
3571
 * @param[in,out] tc contains current node.
3572
 */
3573
static void
3574
trb_tree_ctx_set_child(struct trt_tree_ctx *tc)
3575
0
{
3576
0
    const void *node = trb_tree_ctx_get_child(tc);
3577
3578
0
    if (tc->lysc_tree) {
3579
0
        tc->cn = node;
3580
0
    } else {
3581
0
        tc->pn = node;
3582
0
    }
3583
0
}
3584
3585
/**
3586
 * @brief Print subtree of nodes.
3587
 *
3588
 * The current node is expected to be the root of the subtree.
3589
 * Before root node is no linebreak printing. This must be addressed by
3590
 * the caller. Root node will also be printed. Behind last printed node
3591
 * is no linebreak.
3592
 *
3593
 * @param[in] max_gap_before_type is result from
3594
 * ::trb_try_unified_indent() function for root node.
3595
 * Set parameter to 0 if distance does not matter.
3596
 * @param[in] wr is wrapper saying how deep in the whole tree
3597
 * is the root of the subtree.
3598
 * @param[in] ca is parent_cache from root's parent.
3599
 * If root is top-level node, insert ::TRP_EMPTY_PARENT_CACHE.
3600
 * @param[in] pc is @ref TRP_trp settings.
3601
 * @param[in,out] tc is context of tree printer.
3602
 */
3603
static void
3604
trb_print_subtree_nodes(uint32_t max_gap_before_type, struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3605
0
{
3606
0
    struct trt_parent_cache new_ca;
3607
0
    struct trt_node node;
3608
3609
0
    if (!trb_tree_ctx_get_node(tc)) {
3610
0
        return;
3611
0
    }
3612
3613
0
    trb_print_entire_node(max_gap_before_type, wr, ca, pc, tc);
3614
    /* go to the actual node's child */
3615
0
    new_ca = tro_parent_cache_for_child(ca, tc);
3616
0
    node = pc->fp.modify.next_child(ca, tc);
3617
3618
0
    if (!trp_node_is_empty(node)) {
3619
        /* print root's nodes */
3620
0
        trb_print_nodes(wr, new_ca, pc, tc);
3621
        /* get back from child node to actual node */
3622
0
        pc->fp.modify.parent(tc);
3623
0
    }
3624
0
}
3625
3626
/**
3627
 * @brief Get number of siblings.
3628
 *
3629
 * Side-effect -> current node is set to the first sibling.
3630
 *
3631
 * @param[in] fp contains callback functions which modify tree context
3632
 * @param[in,out] tc is the tree context.
3633
 * @return Number of siblings of the current node.
3634
 */
3635
static uint32_t
3636
trb_get_number_of_siblings(struct trt_fp_modify_ctx fp, struct trt_tree_ctx *tc)
3637
0
{
3638
0
    uint32_t ret = 1;
3639
0
    struct trt_node node = TRP_EMPTY_NODE;
3640
3641
    /* including actual node */
3642
0
    fp.first_sibling(tc);
3643
0
    while (!trp_node_is_empty(node = fp.next_sibling(TRP_EMPTY_PARENT_CACHE, tc))) {
3644
0
        ret++;
3645
0
    }
3646
0
    fp.first_sibling(tc);
3647
0
    return ret;
3648
0
}
3649
3650
/**
3651
 * @brief Print all parents and their children.
3652
 *
3653
 * This function is suitable for printing top-level nodes that
3654
 * do not have ancestors. Function call ::trb_print_subtree_nodes()
3655
 * for all top-level siblings. Use this function after 'module' keyword
3656
 * or 'augment' and so. The nodes may not be exactly top-level in the
3657
 * tree, but the function considers them that way.
3658
 *
3659
 * @param[in] wr is wrapper saying how deeply the top-level nodes are
3660
 * immersed in the tree.
3661
 * @param[pc] pc contains mainly functions for printing.
3662
 * @param[in,out] tc is tree context.
3663
 */
3664
static void
3665
trb_print_family_tree(struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3666
0
{
3667
0
    struct trt_parent_cache ca;
3668
0
    uint32_t total_parents;
3669
0
    uint32_t max_gap_before_type;
3670
3671
0
    if (!trb_tree_ctx_get_node(tc)) {
3672
0
        return;
3673
0
    }
3674
3675
0
    ca = TRP_EMPTY_PARENT_CACHE;
3676
0
    total_parents = trb_get_number_of_siblings(pc->fp.modify, tc);
3677
0
    max_gap_before_type = trb_try_unified_indent(ca, pc, tc);
3678
3679
0
    if (!tc->lysc_tree) {
3680
0
        if (((tc->section == TRD_SECT_GROUPING) && (tc->tpn == tc->pn->parent)) ||
3681
0
                (tc->section == TRD_SECT_YANG_DATA)) {
3682
0
            ca.lys_config = 0x0;
3683
0
        }
3684
0
    }
3685
3686
0
    for (uint32_t i = 0; i < total_parents; i++) {
3687
0
        ly_print_(pc->out, "\n");
3688
0
        trb_print_subtree_nodes(max_gap_before_type, wr, ca, pc, tc);
3689
0
        pc->fp.modify.next_sibling(ca, tc);
3690
0
    }
3691
0
}
3692
3693
/**********************************************************************
3694
 * Definition of trm main functions
3695
 *********************************************************************/
3696
3697
/**
3698
 * @brief Settings if lysp_node are used for browsing through the tree.
3699
 *
3700
 * @param[in] module YANG schema tree structure representing
3701
 * YANG module.
3702
 * @param[in] out is output handler.
3703
 * @param[in] max_line_length is the maximum line length limit
3704
 * that should not be exceeded.
3705
 * @param[in,out] pc will be adapted to lysp_tree.
3706
 * @param[in,out] tc will be adapted to lysp_tree.
3707
 */
3708
static void
3709
trm_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)
3710
0
{
3711
0
    *tc = (struct trt_tree_ctx) {
3712
0
        .lysc_tree = 0,
3713
0
        .section = TRD_SECT_MODULE,
3714
0
        .pmod = module->parsed,
3715
0
        .cmod = NULL,
3716
0
        .pn = module->parsed ? module->parsed->data : NULL,
3717
0
        .tpn = module->parsed ? module->parsed->data : NULL,
3718
0
        .cn = NULL
3719
0
    };
3720
3721
0
    pc->out = out;
3722
3723
0
    pc->fp.modify = (struct trt_fp_modify_ctx) {
3724
0
        .parent = trop_modi_parent,
3725
0
        .first_sibling = trop_modi_first_sibling,
3726
0
        .next_sibling = trop_modi_next_sibling,
3727
0
        .next_child = trop_modi_next_child,
3728
0
    };
3729
3730
0
    pc->fp.read = (struct trt_fp_read) {
3731
0
        .module_name = tro_read_module_name,
3732
0
        .node = trop_read_node,
3733
0
        .if_sibling_exists = trop_read_if_sibling_exists
3734
0
    };
3735
3736
0
    pc->fp.print = (struct trt_fp_print) {
3737
0
        .print_features_names = tro_print_features_names,
3738
0
        .print_keys = tro_print_keys
3739
0
    };
3740
3741
0
    pc->max_line_length = max_line_length;
3742
0
}
3743
3744
/**
3745
 * @brief Settings if lysc_node are used for browsing through the tree.
3746
 *
3747
 * Pointers to current nodes will be set to module data.
3748
 *
3749
 * @param[in] module YANG schema tree structure representing
3750
 * YANG module.
3751
 * @param[in] out is output handler.
3752
 * @param[in] max_line_length is the maximum line length limit
3753
 * that should not be exceeded.
3754
 * @param[in,out] pc will be adapted to lysc_tree.
3755
 * @param[in,out] tc will be adapted to lysc_tree.
3756
 */
3757
static void
3758
trm_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)
3759
0
{
3760
0
    *tc = (struct trt_tree_ctx) {
3761
0
        .lysc_tree = 1,
3762
0
        .section = TRD_SECT_MODULE,
3763
0
        .pmod = module->parsed,
3764
0
        .cmod = module->compiled,
3765
0
        .tpn = NULL,
3766
0
        .pn = NULL,
3767
0
        .cn = module->compiled->data
3768
0
    };
3769
3770
0
    pc->out = out;
3771
3772
0
    pc->fp.modify = (struct trt_fp_modify_ctx) {
3773
0
        .parent = troc_modi_parent,
3774
0
        .first_sibling = troc_modi_first_sibling,
3775
0
        .next_sibling = troc_modi_next_sibling,
3776
0
        .next_child = troc_modi_next_child,
3777
0
    };
3778
3779
0
    pc->fp.read = (struct trt_fp_read) {
3780
0
        .module_name = tro_read_module_name,
3781
0
        .node = troc_read_node,
3782
0
        .if_sibling_exists = troc_read_if_sibling_exists
3783
0
    };
3784
3785
0
    pc->fp.print = (struct trt_fp_print) {
3786
0
        .print_features_names = tro_print_features_names,
3787
0
        .print_keys = tro_print_keys
3788
0
    };
3789
3790
0
    pc->max_line_length = max_line_length;
3791
0
}
3792
3793
/**
3794
 * @brief Reset settings to browsing through the lysc tree.
3795
 * @param[in,out] pc resets to @ref TRP_troc functions.
3796
 * @param[in,out] tc resets to lysc browsing.
3797
 */
3798
static void
3799
trm_reset_to_lysc_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3800
0
{
3801
0
    trm_lysc_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc);
3802
0
}
3803
3804
/**
3805
 * @brief Reset settings to browsing through the lysp tree.
3806
 * @param[in,out] pc resets to @ref TRP_trop functions.
3807
 * @param[in,out] tc resets to lysp browsing.
3808
 */
3809
static void
3810
trm_reset_to_lysp_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3811
0
{
3812
0
    trm_lysp_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc);
3813
0
}
3814
3815
/**
3816
 * @brief If augment's target node is located on the current module.
3817
 * @param[in] pn is examined augment.
3818
 * @param[in] pmod is current module.
3819
 * @return 1 if nodeid refers to the local node, otherwise 0.
3820
 */
3821
static ly_bool
3822
trm_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod)
3823
0
{
3824
0
    const char *id, *prefix, *name;
3825
0
    size_t prefix_len, name_len;
3826
0
    const struct lys_module *mod;
3827
0
    ly_bool ret = 0;
3828
3829
0
    if (pn == NULL) {
3830
0
        return ret;
3831
0
    }
3832
3833
0
    id = pn->nodeid;
3834
0
    if (!id) {
3835
0
        return ret;
3836
0
    }
3837
    /* only absolute-schema-nodeid is taken into account */
3838
0
    assert(id[0] == '/');
3839
0
    ++id;
3840
3841
0
    ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len);
3842
0
    if (prefix) {
3843
0
        mod = ly_resolve_prefix(pmod->mod->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, pmod);
3844
0
        ret = mod->parsed == pmod;
3845
0
    } else {
3846
0
        ret = 1;
3847
0
    }
3848
3849
0
    return ret;
3850
0
}
3851
3852
/**
3853
 * @brief Printing section module, rpcs, notifications or yang-data.
3854
 *
3855
 * First node must be the first child of 'module',
3856
 * 'rpcs', 'notifications' or 'yang-data'.
3857
 *
3858
 * @param[in] ks is section representation.
3859
 * @param[in] pc contains mainly functions for printing.
3860
 * @param[in,out] tc is the tree context.
3861
 */
3862
static void
3863
trm_print_section_as_family_tree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3864
0
{
3865
0
    if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
3866
0
        return;
3867
0
    }
3868
3869
0
    trp_print_keyword_stmt(ks, pc->max_line_length, 0, pc->out);
3870
0
    if ((ks.type == TRD_KEYWORD_MODULE) || (ks.type == TRD_KEYWORD_SUBMODULE)) {
3871
0
        trb_print_family_tree(TRP_INIT_WRAPPER_TOP, pc, tc);
3872
0
    } else {
3873
0
        trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
3874
0
    }
3875
0
}
3876
3877
/**
3878
 * @brief Printing section augment or grouping.
3879
 *
3880
 * First node is 'augment' or 'grouping' itself.
3881
 *
3882
 * @param[in] ks is section representation.
3883
 * @param[in] pc contains mainly functions for printing.
3884
 * @param[in,out] tc is the tree context.
3885
 */
3886
static void
3887
trm_print_section_as_subtree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3888
0
{
3889
0
    ly_bool grp_has_data = 0;
3890
3891
0
    if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
3892
0
        return;
3893
0
    }
3894
3895
0
    if (ks.type == TRD_KEYWORD_GROUPING) {
3896
0
        grp_has_data = trb_tree_ctx_get_child(tc) ? 1 : 0;
3897
0
    }
3898
3899
0
    trp_print_keyword_stmt(ks, pc->max_line_length, grp_has_data, pc->out);
3900
0
    trb_tree_ctx_set_child(tc);
3901
0
    trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc);
3902
0
}
3903
3904
/**
3905
 * @brief Print 'module' keyword, its name and all nodes.
3906
 * @param[in] pc contains mainly functions for printing.
3907
 * @param[in,out] tc is the tree context.
3908
 */
3909
static void
3910
trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3911
0
{
3912
0
    trm_print_section_as_family_tree(pc->fp.read.module_name(tc), pc, tc);
3913
0
}
3914
3915
/**
3916
 * @brief For all augment sections: print 'augment' keyword,
3917
 * its target node and all nodes.
3918
 * @param[in] pc contains mainly functions for printing.
3919
 * @param[in,out] tc is the tree context.
3920
 */
3921
static void
3922
trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3923
0
{
3924
0
    ly_bool once;
3925
0
    ly_bool origin_was_lysc_tree = 0;
3926
3927
0
    if (tc->lysc_tree) {
3928
0
        origin_was_lysc_tree = 1;
3929
0
        trm_reset_to_lysp_tree_ctx(pc, tc);
3930
0
    }
3931
3932
0
    once = 1;
3933
0
    for (struct trt_keyword_stmt ks = trop_modi_next_augment(tc);
3934
0
            !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
3935
0
            ks = trop_modi_next_augment(tc)) {
3936
3937
0
        if (origin_was_lysc_tree) {
3938
            /* if lysc tree is used, then only augments targeting
3939
             * another module are printed
3940
             */
3941
0
            if (trm_nodeid_target_is_local((const struct lysp_node_augment *)tc->tpn, tc->pmod)) {
3942
0
                continue;
3943
0
            }
3944
0
        }
3945
3946
0
        if (once) {
3947
0
            ly_print_(pc->out, "\n");
3948
0
            ly_print_(pc->out, "\n");
3949
0
            once = 0;
3950
0
        } else {
3951
0
            ly_print_(pc->out, "\n");
3952
0
        }
3953
3954
0
        trm_print_section_as_subtree(ks, pc, tc);
3955
0
    }
3956
3957
0
    if (origin_was_lysc_tree) {
3958
0
        trm_reset_to_lysc_tree_ctx(pc, tc);
3959
0
    }
3960
0
}
3961
3962
/**
3963
 * @brief For rpcs section: print 'rpcs' keyword and all its nodes.
3964
 * @param[in] pc contains mainly functions for printing.
3965
 * @param[in,out] tc is the tree context.
3966
 */
3967
static void
3968
trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3969
0
{
3970
0
    struct trt_keyword_stmt rpc;
3971
3972
0
    rpc = tro_modi_get_rpcs(tc);
3973
3974
0
    if (!(TRP_KEYWORD_STMT_IS_EMPTY(rpc))) {
3975
0
        ly_print_(pc->out, "\n");
3976
0
        ly_print_(pc->out, "\n");
3977
0
        trm_print_section_as_family_tree(rpc, pc, tc);
3978
0
    }
3979
0
}
3980
3981
/**
3982
 * @brief For notifications section: print 'notifications' keyword
3983
 * and all its nodes.
3984
 * @param[in] pc contains mainly functions for printing.
3985
 * @param[in,out] tc is the tree context.
3986
 */
3987
static void
3988
trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
3989
0
{
3990
0
    struct trt_keyword_stmt notifs;
3991
3992
0
    notifs = tro_modi_get_notifications(tc);
3993
3994
0
    if (!(TRP_KEYWORD_STMT_IS_EMPTY(notifs))) {
3995
0
        ly_print_(pc->out, "\n");
3996
0
        ly_print_(pc->out, "\n");
3997
0
        trm_print_section_as_family_tree(notifs, pc, tc);
3998
0
    }
3999
0
}
4000
4001
/**
4002
 * @brief For all grouping sections: print 'grouping' keyword, its name
4003
 * and all nodes.
4004
 * @param[in] pc contains mainly functions for printing.
4005
 * @param[in,out] tc is the tree context.
4006
 */
4007
static void
4008
trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4009
0
{
4010
0
    ly_bool once;
4011
4012
0
    if (tc->lysc_tree) {
4013
0
        return;
4014
0
    }
4015
4016
0
    once = 1;
4017
0
    for (struct trt_keyword_stmt ks = trop_modi_next_grouping(tc);
4018
0
            !(TRP_KEYWORD_STMT_IS_EMPTY(ks));
4019
0
            ks = trop_modi_next_grouping(tc)) {
4020
0
        if (once) {
4021
0
            ly_print_(pc->out, "\n");
4022
0
            ly_print_(pc->out, "\n");
4023
0
            once = 0;
4024
0
        } else {
4025
0
            ly_print_(pc->out, "\n");
4026
0
        }
4027
0
        trm_print_section_as_subtree(ks, pc, tc);
4028
0
    }
4029
0
}
4030
4031
/**
4032
 * @brief For all yang-data sections: print 'yang-data' keyword
4033
 * and all its nodes.
4034
 * @param[in] pc contains mainly functions for printing.
4035
 * @param[in,out] tc is the tree context.
4036
 */
4037
static void
4038
trm_print_yang_data(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4039
0
{
4040
0
    ly_bool once;
4041
0
    LY_ARRAY_COUNT_TYPE count;
4042
4043
0
    count = LY_ARRAY_COUNT(tc->pmod->exts);
4044
0
    if (count == 0) {
4045
0
        return;
4046
0
    }
4047
4048
0
    once = 1;
4049
0
    for (LY_ARRAY_COUNT_TYPE u = 0; u < count; ++u) {
4050
0
        struct trt_keyword_stmt ks;
4051
4052
        /* Only ::lys_compile_extension_instance() can set item
4053
         * ::lysp_ext_instance.parsed.
4054
         */
4055
0
        if (!tc->pmod->exts[u].parsed) {
4056
            /* print at least the yang-data names */
4057
0
            trop_yang_data_sections(tc->pmod->exts, pc->max_line_length, pc->out);
4058
0
            continue;
4059
0
        }
4060
4061
0
        ks = tro_modi_next_yang_data(tc, u);
4062
0
        if (TRP_KEYWORD_STMT_IS_EMPTY(ks)) {
4063
0
            break;
4064
0
        }
4065
4066
0
        if (once) {
4067
0
            ly_print_(pc->out, "\n");
4068
0
            ly_print_(pc->out, "\n");
4069
0
            once = 0;
4070
0
        } else {
4071
0
            ly_print_(pc->out, "\n");
4072
0
        }
4073
4074
0
        trm_print_section_as_family_tree(ks, pc, tc);
4075
0
    }
4076
0
}
4077
4078
/**
4079
 * @brief Print sections module, augment, rpcs, notifications,
4080
 * grouping, yang-data.
4081
 * @param[in] pc contains mainly functions for printing.
4082
 * @param[in,out] tc is the tree context.
4083
 */
4084
static void
4085
trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
4086
0
{
4087
0
    trm_print_module_section(pc, tc);
4088
0
    trm_print_augmentations(pc, tc);
4089
0
    trm_print_rpcs(pc, tc);
4090
0
    trm_print_notifications(pc, tc);
4091
0
    trm_print_groupings(pc, tc);
4092
0
    trm_print_yang_data(pc, tc);
4093
0
    ly_print_(pc->out, "\n");
4094
0
}
4095
4096
/**********************************************************************
4097
 * Definition of module interface
4098
 *********************************************************************/
4099
4100
LY_ERR
4101
tree_print_module(struct ly_out *out, const struct lys_module *module, uint32_t UNUSED(options), size_t line_length)
4102
0
{
4103
0
    struct trt_printer_ctx pc;
4104
0
    struct trt_tree_ctx tc;
4105
0
    struct ly_out *new_out;
4106
0
    LY_ERR erc;
4107
0
    struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4108
4109
0
    LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL);
4110
4111
0
    if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4112
0
        return erc;
4113
0
    }
4114
4115
0
    line_length = line_length == 0 ? SIZE_MAX : line_length;
4116
0
    if ((module->ctx->flags & LY_CTX_SET_PRIV_PARSED) && module->compiled) {
4117
0
        trm_lysc_tree_ctx(module, new_out, line_length, &pc, &tc);
4118
0
    } else {
4119
0
        trm_lysp_tree_ctx(module, new_out, line_length, &pc, &tc);
4120
0
    }
4121
4122
0
    trm_print_sections(&pc, &tc);
4123
0
    erc = clb_arg.last_error;
4124
4125
0
    ly_out_free(new_out, NULL, 1);
4126
4127
0
    return erc;
4128
0
}
4129
4130
LY_ERR
4131
tree_print_compiled_node(struct ly_out *out, const struct lysc_node *node, uint32_t options, size_t line_length)
4132
0
{
4133
0
    struct trt_printer_ctx pc;
4134
0
    struct trt_tree_ctx tc;
4135
0
    struct ly_out *new_out;
4136
0
    struct trt_wrapper wr;
4137
0
    LY_ERR erc;
4138
0
    struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4139
4140
0
    assert(out && node);
4141
4142
0
    if (!(node->module->ctx->flags & LY_CTX_SET_PRIV_PARSED)) {
4143
0
        return LY_EINVAL;
4144
0
    }
4145
4146
0
    if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4147
0
        return erc;
4148
0
    }
4149
4150
0
    line_length = line_length == 0 ? SIZE_MAX : line_length;
4151
0
    trm_lysc_tree_ctx(node->module, new_out, line_length, &pc, &tc);
4152
4153
0
    trp_print_keyword_stmt(pc.fp.read.module_name(&tc), pc.max_line_length, 0, pc.out);
4154
0
    trb_print_parents(node, &pc, &tc);
4155
4156
0
    if (!(options & LYS_PRINT_NO_SUBSTMT)) {
4157
0
        tc.cn = lysc_node_child(node);
4158
0
        wr = trb_count_depth(tc.cn);
4159
0
        trb_print_family_tree(wr, &pc, &tc);
4160
0
    }
4161
0
    ly_print_(out, "\n");
4162
4163
0
    erc = clb_arg.last_error;
4164
0
    ly_out_free(new_out, NULL, 1);
4165
4166
0
    return erc;
4167
0
}
4168
4169
LY_ERR
4170
tree_print_parsed_submodule(struct ly_out *out, const struct lysp_submodule *submodp, uint32_t UNUSED(options), size_t line_length)
4171
0
{
4172
0
    struct trt_printer_ctx pc;
4173
0
    struct trt_tree_ctx tc;
4174
0
    struct ly_out *new_out;
4175
0
    LY_ERR erc;
4176
0
    struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS);
4177
4178
0
    assert(submodp);
4179
0
    LY_CHECK_ARG_RET(submodp->mod->ctx, out, LY_EINVAL);
4180
4181
0
    if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) {
4182
0
        return erc;
4183
0
    }
4184
4185
0
    line_length = line_length == 0 ? SIZE_MAX : line_length;
4186
0
    trm_lysp_tree_ctx(submodp->mod, new_out, line_length, &pc, &tc);
4187
0
    tc.pmod = (struct lysp_module *)submodp;
4188
0
    tc.tpn = submodp->data;
4189
0
    tc.pn = tc.tpn;
4190
4191
0
    trm_print_sections(&pc, &tc);
4192
0
    erc = clb_arg.last_error;
4193
4194
0
    ly_out_free(new_out, NULL, 1);
4195
4196
0
    return erc;
4197
0
}