diff --git a/src/plugins_exts.c b/src/plugins_exts.c index 174beefc0..8bde5b2b8 100644 --- a/src/plugins_exts.c +++ b/src/plugins_exts.c @@ -434,133 +434,6 @@ lyplg_ext_print_get_level(const struct lyspr_ctx *ctx) return &((struct lyspr_ctx *)ctx)->level; } -LIBYANG_API_DEF LY_ERR -lyplg_ext_sprinter_ctree_add_ext_nodes(const struct lyspr_tree_ctx *ctx, struct lysc_ext_instance *ext, - lyplg_ext_sprinter_ctree_override_clb clb) -{ - LY_ERR rc = LY_SUCCESS; - uint32_t i; - struct lysc_node *schema; - - LY_CHECK_ARG_RET(NULL, ctx, ext, LY_EINVAL); - - LY_ARRAY_FOR(ext->substmts, i) { - switch (ext->substmts[i].stmt) { - case LY_STMT_NOTIFICATION: - case LY_STMT_INPUT: - case LY_STMT_OUTPUT: - case LY_STMT_ACTION: - case LY_STMT_RPC: - case LY_STMT_ANYDATA: - case LY_STMT_ANYXML: - case LY_STMT_CASE: - case LY_STMT_CHOICE: - case LY_STMT_CONTAINER: - case LY_STMT_LEAF: - case LY_STMT_LEAF_LIST: - case LY_STMT_LIST: - schema = *ext->substmts[i].storage_p; - if (schema) { - rc = lyplg_ext_sprinter_ctree_add_nodes(ctx, schema, clb); - return rc; - } - default: - break; - } - } - - return rc; -} - -LIBYANG_API_DEF LY_ERR -lyplg_ext_sprinter_ptree_add_ext_nodes(const struct lyspr_tree_ctx *ctx, struct lysp_ext_instance *ext, - lyplg_ext_sprinter_ptree_override_clb clb) -{ - LY_ERR rc = LY_SUCCESS; - uint32_t i; - struct lysp_node *schema; - - LY_CHECK_ARG_RET(NULL, ctx, ext, LY_EINVAL); - - LY_ARRAY_FOR(ext->substmts, i) { - switch (ext->substmts[i].stmt) { - case LY_STMT_NOTIFICATION: - case LY_STMT_INPUT: - case LY_STMT_OUTPUT: - case LY_STMT_ACTION: - case LY_STMT_RPC: - case LY_STMT_ANYDATA: - case LY_STMT_ANYXML: - case LY_STMT_CASE: - case LY_STMT_CHOICE: - case LY_STMT_CONTAINER: - case LY_STMT_LEAF: - case LY_STMT_LEAF_LIST: - case LY_STMT_LIST: - schema = *ext->substmts[i].storage_p; - if (schema) { - rc = lyplg_ext_sprinter_ptree_add_nodes(ctx, schema, clb); - return rc; - } - default: - break; - } - } - - return rc; -} - -LIBYANG_API_DEF LY_ERR -lyplg_ext_sprinter_ctree_add_nodes(const struct lyspr_tree_ctx *ctx, struct lysc_node *nodes, - lyplg_ext_sprinter_ctree_override_clb clb) -{ - struct lyspr_tree_schema *new; - - LY_CHECK_ARG_RET(NULL, ctx, LY_EINVAL); - - if (!nodes) { - return LY_SUCCESS; - } - - LY_ARRAY_NEW_RET(NULL, ((struct lyspr_tree_ctx *)ctx)->schemas, new, LY_EMEM); - new->compiled = 1; - new->ctree = nodes; - new->cn_overr = clb; - - return LY_SUCCESS; -} - -LIBYANG_API_DEF LY_ERR -lyplg_ext_sprinter_ptree_add_nodes(const struct lyspr_tree_ctx *ctx, struct lysp_node *nodes, - lyplg_ext_sprinter_ptree_override_clb clb) -{ - struct lyspr_tree_schema *new; - - LY_CHECK_ARG_RET(NULL, ctx, LY_EINVAL); - - if (!nodes) { - return LY_SUCCESS; - } - - LY_ARRAY_NEW_RET(NULL, ((struct lyspr_tree_ctx *)ctx)->schemas, new, LY_EMEM); - new->compiled = 0; - new->ptree = nodes; - new->pn_overr = clb; - - return LY_SUCCESS; -} - -LIBYANG_API_DEF LY_ERR -lyplg_ext_sprinter_tree_set_priv(const struct lyspr_tree_ctx *ctx, void *plugin_priv, void (*free_clb)(void *plugin_priv)) -{ - LY_CHECK_ARG_RET(NULL, ctx, LY_EINVAL); - - ((struct lyspr_tree_ctx *)ctx)->plugin_priv = plugin_priv; - ((struct lyspr_tree_ctx *)ctx)->free_plugin_priv = free_clb; - - return LY_SUCCESS; -} - LIBYANG_API_DEF int lyplg_ext_compiled_stmts_storage_size(const struct lysc_ext_substmt *substmts, struct ly_ht *addr_ht) { diff --git a/src/plugins_exts.h b/src/plugins_exts.h index c18d9fc31..cd4830ab6 100644 --- a/src/plugins_exts.h +++ b/src/plugins_exts.h @@ -77,13 +77,6 @@ extern "C" { * [helper functions](@ref pluginsExtensionsSprinterInfo) to access printer's context and to print standard YANG statements * placed in the extension instance by libyang itself. * - * The ::lyplg_ext.printer_ctree and ::lyplg_ext.printer_ptree callbacks implement printing of YANG tree diagrams - * (RFC 8340) for extension instance data. These callbacks are called for extension instances that have - * parents of type ::LY_STMT_MODULE, ::LY_STMT_SUBMODULE. Or these callbacks are called if the printer_tree finds - * a compiled/parsed data-node containing an extension instance. The callbacks should then decide which nodes - * should be printed within the extension instance. In addition, it is possible to register additional callbacks - * to the printer_tree context to override the form of the each node in the extension instance. - * * The last callback, ::lyplg_ext.cfree, is supposed to free all the data allocated by the ::lyplg_ext.compile callback. * To free the data created by helper function ::lyplg_ext_compile_extension_instance(), the plugin can used * ::lyplg_ext_cfree_instance_substatements(). @@ -109,7 +102,7 @@ extern "C" { /** * @brief Extensions API version */ -#define LYPLG_EXT_API_VERSION 11 +#define LYPLG_EXT_API_VERSION 12 /** * @brief Mask for an operation statement. @@ -729,109 +722,6 @@ LIBYANG_API_DECL void lyplg_ext_print_info_extension_instance(struct lyspr_ctx * /** @} pluginsExtensionsSprinterInfo */ -/** - * @defgroup pluginsExtensionsSprinterTree Plugins: Extensions schema parsed and compiled tree printer support - * @ingroup pluginsExtensions - * - * Implementing extension plugin schema parsed and compiled tree printer callback. - * - * @{ - */ - -/** - * @brief Callback to print parent node of @p ext or to print the contents of the extension. - * - * Function is called in two different cases. If the printer_tree needs the tree-diagram form of a parent node, - * then @p ctx is set to NULL. In the second case, if printer_tree needs to print the contents of the extension, - * then @p ctx is set and function must prepare the nodes that should be printed using the - * lyplg_ext_sprinter_tree* functions. - * - * @param[in] ext Extension instance. - * @param[in,out] ctx Context for the tree printer. Extension contents can be inserted into it by functions - * lyplg_ext_sprinter_ctree_add_ext_nodes(), lyplg_ext_sprinter_ctree_add_nodes() or by their ptree alternatives. - * It parameter is set to NULL, then @p flags and @p add_opts are used by printer_tree. - * @param[out] flags Optional override tree-diagram \ in a parent node. If @p ctx is set, ignore this parameter. - * @param[out] add_opts Additional tree-diagram \ string in a parent node which is printed before \. If @p ctx - * is set, ignore this parameter. - * @return LY_ERR value. - */ -typedef LY_ERR (*lyplg_ext_sprinter_ctree_clb)(struct lysc_ext_instance *ext, const struct lyspr_tree_ctx *ctx, - const char **flags, const char **add_opts); - -/** - * @brief Callback for rewriting the tree-diagram form of a specific node. - * - * If this callback is set, then it is called for each node that belongs to the extension instance. - * - * @param[in] node Node whose tree-diagram form can be modified by the function. - * @param[in,out] plugin_priv Private context set by plugin. - * @param[out] skip Flag set to 1 removes the node from printed diagram. - * @param[out] flags Override tree-diagram \ string in the @p node. - * @param[out] add_opts Additional tree-diagram \ string in the @p node which is printed before \. - * @return LY_ERR value. - */ -typedef LY_ERR (*lyplg_ext_sprinter_ctree_override_clb)(const struct lysc_node *node, const void *plugin_priv, - ly_bool *skip, const char **flags, const char **add_opts); - -/** - * @brief Registration of printing a group of nodes, which is already in the extension. - * - * @param[in] ctx Context of printer_tree in which the group of nodes is saved and later printed. - * @param[in] ext Extension in which the group of nodes will be searched. - * @param[in] clb Override function that will be applied to each delivered node. - * @return LY_ERR value. - */ -LIBYANG_API_DECL LY_ERR lyplg_ext_sprinter_ctree_add_ext_nodes(const struct lyspr_tree_ctx *ctx, - struct lysc_ext_instance *ext, lyplg_ext_sprinter_ctree_override_clb clb); - -/** - * @brief Registration of printing the group of nodes which were defined in the plugin. - * - * @param[in] ctx Context of printer_tree in which the group of nodes is saved and later printed. - * @param[in] nodes Points to the first node in group. - * @param[in] clb Override function that will be applied to each delivered node. - * @return LY_ERR value. - */ -LIBYANG_API_DECL LY_ERR lyplg_ext_sprinter_ctree_add_nodes(const struct lyspr_tree_ctx *ctx, struct lysc_node *nodes, - lyplg_ext_sprinter_ctree_override_clb clb); - -/** - * @brief Registration of plugin-private data defined by the plugin that is shared between override_clb calls. - * - * @param[in] ctx Context of printer_tree in which plugin-private data will be saved. - * @param[in] plugin_priv Plugin-private data shared between oberride_clb calls. - * @param[in] free_clb Release function for @p plugin_priv. - * @return LY_ERR value. - */ -LIBYANG_API_DECL LY_ERR lyplg_ext_sprinter_tree_set_priv(const struct lyspr_tree_ctx *ctx, void *plugin_priv, - void (*free_clb)(void *plugin_priv)); - -/** - * @copydoc lyplg_ext_sprinter_ctree_clb - */ -typedef LY_ERR (*lyplg_ext_sprinter_ptree_clb)(struct lysp_ext_instance *ext, const struct lyspr_tree_ctx *ctx, - const char **flags, const char **add_opts); - -/** - * @copydoc lyplg_ext_sprinter_ctree_override_clb - */ -typedef LY_ERR (*lyplg_ext_sprinter_ptree_override_clb)(const struct lysp_node *node, const void *plugin_priv, - ly_bool *skip, const char **flags, const char **add_opts); - -/** - * @copydoc lyplg_ext_sprinter_ctree_add_ext_nodes - */ -LIBYANG_API_DECL LY_ERR lyplg_ext_sprinter_ptree_add_ext_nodes(const struct lyspr_tree_ctx *ctx, - struct lysp_ext_instance *ext, lyplg_ext_sprinter_ptree_override_clb clb); - -/** - * @copydoc lyplg_ext_sprinter_ctree_add_nodes - */ -LIBYANG_API_DECL LY_ERR lyplg_ext_sprinter_ptree_add_nodes(const struct lyspr_tree_ctx *ctx, struct lysp_node *nodes, - lyplg_ext_sprinter_ptree_override_clb clb); - -/** @} pluginsExtensionsSprinterTree */ - /* * node xpath */ @@ -1077,8 +967,6 @@ struct lyplg_ext { lyplg_ext_parse_clb parse; /**< callback to parse the extension instance substatements */ lyplg_ext_compile_clb compile; /**< callback to compile extension instance from the parsed data */ lyplg_ext_sprinter_info_clb printer_info; /**< callback to print the compiled content (info format) */ - lyplg_ext_sprinter_ctree_clb printer_ctree; /**< callback to print tree format of a compiled node */ - lyplg_ext_sprinter_ptree_clb printer_ptree; /**< callback to print tree format of a parsed node */ lyplg_ext_node_xpath_clb node_xpath; /**< callback to get first XPath document root data child node */ lyplg_ext_snode_xpath_clb snode_xpath; /**< callback to get first XPath document root schema child node */ lyplg_ext_data_snode_clb snode; /**< callback to get schema node in various use-cases */ diff --git a/src/plugins_exts/metadata.c b/src/plugins_exts/metadata.c index 0262ee237..ea2977d40 100644 --- a/src/plugins_exts/metadata.c +++ b/src/plugins_exts/metadata.c @@ -262,8 +262,6 @@ const struct lyplg_ext_record plugins_metadata[] = { .plugin.parse = annotation_parse, .plugin.compile = annotation_compile, .plugin.printer_info = annotation_printer_info, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode_xpath = NULL, .plugin.snode = NULL, diff --git a/src/plugins_exts/nacm.c b/src/plugins_exts/nacm.c index 467004fbd..06bb49c59 100644 --- a/src/plugins_exts/nacm.c +++ b/src/plugins_exts/nacm.c @@ -183,8 +183,6 @@ const struct lyplg_ext_record plugins_nacm[] = { .plugin.parse = nacm_parse, .plugin.compile = nacm_compile, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode_xpath = NULL, .plugin.snode = NULL, @@ -202,8 +200,6 @@ const struct lyplg_ext_record plugins_nacm[] = { .plugin.parse = nacm_parse, .plugin.compile = nacm_compile, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode_xpath = NULL, .plugin.snode = NULL, @@ -221,8 +217,6 @@ const struct lyplg_ext_record plugins_nacm[] = { .plugin.parse = nacm_parse, .plugin.compile = nacm_compile, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode_xpath = NULL, .plugin.snode = NULL, @@ -240,8 +234,6 @@ const struct lyplg_ext_record plugins_nacm[] = { .plugin.parse = nacm_parse, .plugin.compile = nacm_compile, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode_xpath = NULL, .plugin.snode = NULL, diff --git a/src/plugins_exts/openconfig.c b/src/plugins_exts/openconfig.c index 89432a14f..ea85cd8aa 100644 --- a/src/plugins_exts/openconfig.c +++ b/src/plugins_exts/openconfig.c @@ -169,8 +169,6 @@ const struct lyplg_ext_record plugins_openconfig[] = { .plugin.parse = regexp_posix_parse, .plugin.compile = NULL, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode_xpath = NULL, .plugin.snode = NULL, @@ -188,8 +186,6 @@ const struct lyplg_ext_record plugins_openconfig[] = { .plugin.parse = posix_pattern_parse, .plugin.compile = posix_pattern_compile, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode_xpath = NULL, .plugin.snode = NULL, diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c index a75074ec4..308e41059 100644 --- a/src/plugins_exts/schema_mount.c +++ b/src/plugins_exts/schema_mount.c @@ -61,11 +61,6 @@ struct lyplg_ext_sm { } inln; /**< inline mount points */ }; -struct sprinter_tree_priv { - struct ly_ctx *ext_ctx; - struct ly_set *refs; -}; - #define EXT_LOGERR_MEM_RET(cctx, ext) \ lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \ return LY_EMEM @@ -1451,38 +1446,6 @@ lyplg_ext_schema_mount_create_context(const struct lysc_ext_instance *ext, const return rc; } -/** - * @brief Schema mount schema parsed tree printer. - * - * Implementation of ::lyplg_ext_sprinter_ptree_clb callback set as lyext_plugin::printer_ptree. - */ -static LY_ERR -schema_mount_sprinter_ptree(struct lysp_ext_instance *UNUSED(ext), const struct lyspr_tree_ctx *ctx, - const char **flags, const char **UNUSED(add_opts)) -{ - if (!ctx) { - *flags = "mp"; - } - - return LY_SUCCESS; -} - -/** - * @brief Schema mount schema compiled tree printer. - * - * Implementation of ::lyplg_ext_sprinter_ctree_clb callback set as lyext_plugin::printer_ctree. - */ -static LY_ERR -schema_mount_sprinter_ctree(struct lysc_ext_instance *UNUSED(ext), const struct lyspr_tree_ctx *ctx, - const char **flags, const char **UNUSED(add_opts)) -{ - if (!ctx) { - *flags = "mp"; - } - - return LY_SUCCESS; -} - static int schema_mount_compiled_size(const struct lysc_ext_instance *ext, struct ly_ht *addr_ht) { @@ -1596,8 +1559,6 @@ const struct lyplg_ext_record plugins_schema_mount[] = { .plugin.parse = schema_mount_parse, .plugin.compile = schema_mount_compile, .plugin.printer_info = NULL, - .plugin.printer_ctree = schema_mount_sprinter_ctree, - .plugin.printer_ptree = schema_mount_sprinter_ptree, .plugin.node_xpath = NULL, .plugin.snode_xpath = schema_mount_snode_xpath, .plugin.snode = schema_mount_snode, diff --git a/src/plugins_exts/structure.c b/src/plugins_exts/structure.c index 67797a465..7771bfb6c 100644 --- a/src/plugins_exts/structure.c +++ b/src/plugins_exts/structure.c @@ -510,52 +510,6 @@ structure_aug_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext) return LY_EMEM; } -static LY_ERR -structure_sprinter_pnode(const struct lysp_node *UNUSED(node), const void *UNUSED(plugin_priv), - ly_bool *UNUSED(skip), const char **flags, const char **UNUSED(add_opts)) -{ - *flags = ""; - return LY_SUCCESS; -} - -static LY_ERR -structure_sprinter_cnode(const struct lysc_node *UNUSED(node), const void *UNUSED(plugin_priv), - ly_bool *UNUSED(skip), const char **flags, const char **UNUSED(add_opts)) -{ - *flags = ""; - return LY_SUCCESS; -} - -/** - * @brief Structure schema compiled tree printer. - * - * Implementation of ::lyplg_ext_sprinter_ctree_clb callback set as lyext_plugin::printer_ctree. - */ -static LY_ERR -structure_sprinter_ctree(struct lysc_ext_instance *ext, const struct lyspr_tree_ctx *ctx, - const char **UNUSED(flags), const char **UNUSED(add_opts)) -{ - LY_ERR rc; - - rc = lyplg_ext_sprinter_ctree_add_ext_nodes(ctx, ext, structure_sprinter_cnode); - return rc; -} - -/** - * @brief Structure schema parsed tree printer. - * - * Implementation of ::lyplg_ext_sprinter_ptree_clb callback set as lyext_plugin::printer_ptree. - */ -static LY_ERR -structure_sprinter_ptree(struct lysp_ext_instance *ext, const struct lyspr_tree_ctx *ctx, - const char **UNUSED(flags), const char **UNUSED(add_opts)) -{ - LY_ERR rc; - - rc = lyplg_ext_sprinter_ptree_add_ext_nodes(ctx, ext, structure_sprinter_pnode); - return rc; -} - /** * @brief Node xpath callback for structure. */ @@ -663,56 +617,6 @@ structure_validate(struct lysc_ext_instance *ext, struct lyd_node *node, const s return lyd_validate_ext(&node, ext, val_opts, diff); } -/** - * @brief Augment structure schema parsed tree printer. - * - * Implementation of ::lyplg_ext_sprinter_ptree_clb callback set as lyext_plugin::printer_ptree. - */ -static LY_ERR -structure_aug_sprinter_ptree(struct lysp_ext_instance *ext, const struct lyspr_tree_ctx *ctx, - const char **UNUSED(flags), const char **UNUSED(add_opts)) -{ - LY_ERR rc = LY_SUCCESS; - struct lysp_node_augment **aug; - - assert(ctx); - - aug = (struct lysp_node_augment **)ext->substmts[12].storage_p; - rc = lyplg_ext_sprinter_ptree_add_nodes(ctx, (*aug)->child, structure_sprinter_pnode); - - return rc; -} - -/** - * @brief Augment structure schema compiled tree printer. - * - * Implementation of ::lyplg_ext_sprinter_ctree_clb callback set as lyext_plugin::printer_ctree. - */ -static LY_ERR -structure_aug_sprinter_ctree(struct lysc_ext_instance *ext, const struct lyspr_tree_ctx *ctx, const char **flags, - const char **add_opts) -{ - LY_ERR rc = LY_SUCCESS; - - LY_ARRAY_COUNT_TYPE i; - struct lysp_ext_instance *parsed_ext; - - assert(ctx); - - /* find the parsed ext structure */ - parsed_ext = ext->module->parsed->exts; - LY_ARRAY_FOR(parsed_ext, i) { - if (!strcmp(parsed_ext[i].name, "sx:augment-structure") && !strcmp(parsed_ext[i].argument, ext->argument)) { - break; - } - } - assert(i < LY_ARRAY_COUNT(parsed_ext)); - - /* for augments print the parsed tree */ - rc = structure_aug_sprinter_ptree(parsed_ext, ctx, flags, add_opts); - return rc; -} - /** * @brief Plugin descriptions for the structure extension * @@ -730,8 +634,6 @@ const struct lyplg_ext_record plugins_structure[] = { .plugin.parse = structure_parse, .plugin.compile = structure_compile, .plugin.printer_info = structure_printer_info, - .plugin.printer_ctree = structure_sprinter_ctree, - .plugin.printer_ptree = structure_sprinter_ptree, .plugin.node_xpath = structure_node_xpath, .plugin.snode_xpath = structure_snode_xpath, .plugin.snode = structure_snode, @@ -750,8 +652,6 @@ const struct lyplg_ext_record plugins_structure[] = { .plugin.parse = structure_aug_parse, .plugin.compile = NULL, .plugin.printer_info = NULL, - .plugin.printer_ctree = structure_aug_sprinter_ctree, - .plugin.printer_ptree = structure_aug_sprinter_ptree, .plugin.node_xpath = NULL, .plugin.snode_xpath = NULL, .plugin.snode = NULL, diff --git a/src/plugins_exts/yangdata.c b/src/plugins_exts/yangdata.c index ac7334e04..111d93106 100644 --- a/src/plugins_exts/yangdata.c +++ b/src/plugins_exts/yangdata.c @@ -269,54 +269,6 @@ yangdata_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext) lyplg_ext_cfree_instance_substatements(ctx, ext->substmts); } -static void -yangdata_sprinter_node(uint16_t nodetype, const char **flags) -{ - if (nodetype & LYS_USES) { - *flags = "-u"; - } else { - *flags = "--"; - } -} - -static LY_ERR -yangdata_sprinter_cnode(const struct lysc_node *node, const void *UNUSED(plugin_priv), ly_bool *UNUSED(skip), - const char **flags, const char **UNUSED(add_opts)) -{ - yangdata_sprinter_node(node->nodetype, flags); - return LY_SUCCESS; -} - -static LY_ERR -yangdata_sprinter_pnode(const struct lysp_node *node, const void *UNUSED(plugin_priv), ly_bool *UNUSED(skip), - const char **flags, const char **UNUSED(add_opts)) -{ - yangdata_sprinter_node(node->nodetype, flags); - return LY_SUCCESS; -} - -static LY_ERR -yangdata_sprinter_ctree(struct lysc_ext_instance *ext, const struct lyspr_tree_ctx *ctx, - const char **UNUSED(flags), const char **UNUSED(add_opts)) -{ - LY_ERR rc = LY_SUCCESS; - - assert(ctx); - rc = lyplg_ext_sprinter_ctree_add_ext_nodes(ctx, ext, yangdata_sprinter_cnode); - return rc; -} - -static LY_ERR -yangdata_sprinter_ptree(struct lysp_ext_instance *ext, const struct lyspr_tree_ctx *ctx, - const char **UNUSED(flags), const char **UNUSED(add_opts)) -{ - LY_ERR rc = LY_SUCCESS; - - assert(ctx); - rc = lyplg_ext_sprinter_ptree_add_ext_nodes(ctx, ext, yangdata_sprinter_pnode); - return rc; -} - static int yandgata_compiled_size(const struct lysc_ext_instance *ext, struct ly_ht *addr_ht) { @@ -352,8 +304,6 @@ const struct lyplg_ext_record plugins_yangdata[] = { .plugin.parse = yangdata_parse, .plugin.compile = yangdata_compile, .plugin.printer_info = yangdata_printer_info, - .plugin.printer_ctree = yangdata_sprinter_ctree, - .plugin.printer_ptree = yangdata_sprinter_ptree, .plugin.node_xpath = NULL, .plugin.snode_xpath = yangdata_snode_xpath, .plugin.snode = yangdata_snode, diff --git a/src/printer_internal.h b/src/printer_internal.h index c835567d3..5cf205e77 100644 --- a/src/printer_internal.h +++ b/src/printer_internal.h @@ -36,36 +36,6 @@ struct lyspr_ctx { const struct lys_module *module; /**< schema to print */ }; -/** - * @brief YANG schema provided from plugin extension for printer_tree. - * - * The YANG extensions API provides setting functions. - */ -struct lyspr_tree_schema { - ly_bool compiled; /**< Flag if it is a compiled schema. */ - - union { - struct lysc_node *ctree; /**< Compiled schema. */ - struct lysp_node *ptree; /**< Parsed schema. */ - }; - union { - lyplg_ext_sprinter_ctree_override_clb cn_overr; /**< Override clb function for compiled node. */ - lyplg_ext_sprinter_ptree_override_clb pn_overr; /**< Override clb function for parsed node. */ - }; -}; - -/** - * @brief Context used between plugin extension and printer_tree. - * - * The YANG extensions API provides setting functions. - */ -struct lyspr_tree_ctx { - struct lyspr_tree_schema *schemas; /**< Parsed or compiled schemas ([sized array](@ref sizedarrays)) */ - void *plugin_priv; /**< Private data from plugin which printer_tree does not use. */ - - void (*free_plugin_priv)(void *plugin_priv); /**< Release function for lyspr_tree_ctx.plugin_priv. */ -}; - /** * @brief YANG printer of the parsed module. Full YANG printer. * diff --git a/src/printer_tree.c b/src/printer_tree.c index 070171208..ba01aff68 100644 --- a/src/printer_tree.c +++ b/src/printer_tree.c @@ -3,88 +3,13 @@ * @author Adam Piecek * @brief RFC tree printer for libyang data structure * - * Copyright (c) 2015 - 2021 CESNET, z.s.p.o. + * Copyright (c) 2015 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause - * - * @section TRP_DESIGN Design - * - * @code - * +---------+ +---------+ +---------+ - * output | trp | | trb | | tro | - * <---+ Print +<---+ Browse +<-->+ Obtain | - * | | | | | | - * +---------+ +----+----+ +---------+ - * ^ - * | - * +----+----+ - * | trm | - * | Manager | - * | | - * +----+----+ - * ^ - * | input - * + - * @endcode - * - * @subsection TRP_GLOSSARY Glossary - * - * @subsubsection TRP_trm trm - * Manager functions are at the peak of abstraction. They are - * able to print individual sections of the YANG tree diagram - * (eg module, notifications, rpcs ...) and they call - * Browse functions (@ref TRP_trb). - * - * @subsubsection TRP_trb trb - * Browse functions contain a general algorithm (Preorder DFS) - * for traversing the tree. It does not matter what data type - * the tree contains (@ref lysc_node or @ref lysp_node), because it - * requires a ready-made getter functions for traversing the tree - * (@ref trt_fp_all) and transformation function to its own node - * data type (@ref trt_node). These getter functions are generally - * referred to as @ref TRP_tro. Browse functions can repeatedly - * traverse nodes in the tree, for example, to calculate the alignment - * gap before the nodes \ in the YANG Tree Diagram. - * The obtained @ref trt_node is passed to the @ref TRP_trp functions - * to print the Tree diagram. - * - * @subsubsection TRP_tro tro - * Functions that provide an extra wrapper for the libyang library. - * The Obtain functions are further specialized according to whether - * they operate on lysp_tree (@ref TRP_trop) or lysc_tree - * (@ref TRP_troc). If they are general algorithms, then they have the - * prefix \b tro_. The Obtain functions provide information to - * @ref TRP_trb functions for printing the Tree diagram. - * - * @subsubsection TRP_trop trop - * Functions for Obtaining information from Parsed schema tree. - * - * @subsubsection TRP_troc troc - * Functions for Obtaining information from Compiled schema tree. - * - * @subsubsection TRP_trp trp - * Print functions take care of the printing YANG diagram. They can - * also split one node into multiple lines if the node does not fit - * on one line. - * - * @subsubsection TRP_trt trt - * Data type marking in the printer_tree module. - * - * @subsubsection TRP_trg trg - * General functions. - * - * @subsection TRP_ADJUSTMENTS Adjustments - * It is assumed that the changes are likely to take place mainly for - * @ref TRP_tro, @ref TRP_trop or @ref TRP_troc functions because - * they are the only ones dependent on libyang implementation. - * In special cases, changes will also need to be made to the - * @ref TRP_trp functions if a special algorithm is needed to print - * (right now this is prepared for printing list's keys - * and if-features). */ #include @@ -94,27 +19,30 @@ #include "ly_common.h" #include "out_internal.h" #include "plugins_exts.h" -#include "plugins_internal.h" #include "plugins_types.h" #include "printer_internal.h" #include "printer_schema.h" #include "tree_schema_internal.h" #include "xpath.h" +/********************************************************************** + * ly_out callback + *********************************************************************/ + /** * @brief List of available actions. */ typedef enum { - TRD_PRINT = 0, /**< Normal behavior. It just prints. */ - TRD_CHAR_COUNT /**< Characters will be counted instead of printing. */ -} trt_ly_out_clb_arg_flag; + PT_PRINT = 0, /**< Normal behavior. It just prints. */ + PT_CHAR_COUNT /**< Characters will be counted instead of printing. */ +} pt_ly_out_clb_arg_flag; /** * @brief Structure is passed as 'writeclb' argument * to the ::ly_out_new_clb(). */ struct ly_out_clb_arg { - trt_ly_out_clb_arg_flag mode; /**< flag specifying which action to take. */ + pt_ly_out_clb_arg_flag mode; /**< flag specifying which action to take. */ struct ly_out *out; /**< The ly_out pointer delivered to the printer tree module via the main interface. */ size_t counter; /**< Counter of printed characters. */ LY_ERR last_error; /**< The last error that occurred. If no error has occurred, it will be ::LY_SUCCESS. */ @@ -123,98 +51,51 @@ struct ly_out_clb_arg { /** * @brief Initialize struct ly_out_clb_arg with default settings. */ -#define TRP_INIT_LY_OUT_CLB_ARG(MODE, OUT, COUNTER, LAST_ERROR) \ +#define PT_INIT_LY_OUT_CLB_ARG(MODE, OUT, COUNTER, LAST_ERROR) \ (struct ly_out_clb_arg) { \ .mode = MODE, .out = OUT, \ .counter = COUNTER, .last_error = LAST_ERROR \ } -/********************************************************************** - * Print getters - *********************************************************************/ - -/** - * @brief Callback functions that prints special cases. - * - * It just groups together tree context with trt_fp_print. - */ -struct trt_cf_print { - const struct trt_tree_ctx *ctx; /**< Context of libyang tree. */ - - void (*pf)(const struct trt_tree_ctx *, struct ly_out *); /**< Pointing to function which printing list's keys or features. */ -}; - -/** - * @brief Callback functions for printing special cases. - * - * Functions with the suffix 'trp' can print most of the text on - * output, just by setting the pointer to the string. But in some - * cases, it's not that simple, because its entire string is fragmented - * in memory. For example, for printing list's keys or if-features. - * However, this depends on how the libyang library is implemented. - * This implementation of the printer_tree module goes through - * a lysp tree, but if it goes through a lysc tree, these special cases - * would be different. - * Functions must print including spaces or delimiters between names. - */ -struct trt_fp_print { - void (*print_features_names)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list of features without {}? wrapper. */ - void (*print_keys)(const struct trt_tree_ctx *, struct ly_out *); /**< Print list's keys without [] wrapper. */ -}; - -/** - * @brief Package which only groups getter function. - */ -struct trt_pck_print { - const struct trt_tree_ctx *tree_ctx; /**< Context of libyang tree. */ - struct trt_fp_print fps; /**< Print function. */ -}; - -/** - * @brief Initialize struct trt_pck_print by parameters. - */ -#define TRP_INIT_PCK_PRINT(TREE_CTX, FP_PRINT) \ - (struct trt_pck_print) {.tree_ctx = TREE_CTX, .fps = FP_PRINT} - /********************************************************************** * Indent *********************************************************************/ +/** Constant to indicate the need to break a line. */ +#define PT_LINEBREAK -1 + /** * @brief Constants which are defined in the RFC or are observable * from the pyang tool. */ typedef enum { - TRD_INDENT_EMPTY = 0, /**< If the node is a case node, there is no space before the \. */ - TRD_INDENT_LONG_LINE_BREAK = 2, /**< The new line should be indented so that it starts below \ with + PT_INDENT_EMPTY = 0, /**< If the node is a case node, there is no space before the \. */ + PT_INDENT_LONG_LINE_BREAK = 2, /**< The new line should be indented so that it starts below \ with a whitespace offset of at least two characters. */ - TRD_INDENT_LINE_BEGIN = 2, /**< Indent below the keyword (module, augment ...). */ - TRD_INDENT_BTW_SIBLINGS = 2, /**< Indent between | and | characters. */ - TRD_INDENT_BEFORE_KEYS = 1, /**< "..."___\. */ - TRD_INDENT_BEFORE_TYPE = 4, /**< "..."___\, but if mark is set then indent == 3. */ - TRD_INDENT_BEFORE_IFFEATURES = 1 /**< "..."___\. */ -} trt_cnf_indent; + PT_INDENT_LINE_BEGIN = 2, /**< Indent below the keyword (module, augment ...). */ + PT_INDENT_BTW_SIBLINGS = 2, /**< Indent between | and | characters. */ + PT_INDENT_BEFORE_KEYS = 1, /**< "..."___\. */ + PT_INDENT_BEFORE_TYPE = 4, /**< "..."___\, but if mark is set then indent == 3. */ + PT_INDENT_BEFORE_IFFEATURES = 1 /**< "..."___\. */ +} pt_cnf_indent; /** * @brief Type of indent in node. */ typedef enum { - TRD_INDENT_IN_NODE_NORMAL = 0, /**< Node fits on one line. */ - TRD_INDENT_IN_NODE_DIVIDED, /**< The node must be split into multiple rows. */ - TRD_INDENT_IN_NODE_FAILED /**< Cannot be crammed into one line. The condition for the maximum line length is violated. */ -} trt_indent_in_node_type; - -/** Constant to indicate the need to break a line. */ -#define TRD_LINEBREAK -1 + PT_INDENT_IN_NODE_NORMAL = 0, /**< Node fits on one line. */ + PT_INDENT_IN_NODE_DIVIDED, /**< The node must be split into multiple rows. */ + PT_INDENT_IN_NODE_FAILED /**< Cannot be crammed into one line. The condition for the maximum line length is violated. */ +} pt_indent_in_node_type; /** * @brief Records the alignment between the individual * elements of the node. * - * @see trp_default_indent_in_node, trp_try_normal_indent_in_node + * @see pt_default_indent_in_node, pt_try_normal_indent_in_node */ -struct trt_indent_in_node { - trt_indent_in_node_type type; /**< Type of indent in node. */ +struct pt_indent_in_node { + pt_indent_in_node_type type; /**< Type of indent in node. */ int16_t btw_name_opts; /**< Indent between node name and \. */ int16_t btw_opts_type; /**< Indent between \ and \. */ int16_t btw_type_iffeatures; /**< Indent between type and features. Ignored if \ missing. */ @@ -224,22 +105,22 @@ struct trt_indent_in_node { * @brief Type of wrappers to be printed. */ typedef enum { - TRD_WRAPPER_TOP = 0, /**< Related to the module. */ - TRD_WRAPPER_BODY /**< Related to e.g. Augmentations or Groupings */ -} trd_wrapper_type; + PT_WRAPPER_TOP = 0, /**< Related to the module. */ + PT_WRAPPER_BODY /**< Related to e.g. Augmentations or Groupings */ +} pt_wrapper_type; /** * @brief For resolving sibling symbol ('|') placement. * * Bit indicates where the sibling symbol must be printed. - * This place is in multiples of ::TRD_INDENT_BTW_SIBLINGS. + * This place is in multiples of ::PT_INDENT_BTW_SIBLINGS. * - * @see TRP_INIT_WRAPPER_TOP, TRP_INIT_WRAPPER_BODY, - * trp_wrapper_set_mark, trp_wrapper_set_shift, - * trp_wrapper_if_last_sibling, trp_wrapper_eq, trp_print_wrapper + * @see PT_INIT_WRAPPER_TOP, PT_INIT_WRAPPER_BODY, + * pt_wrapper_set_mark, pt_wrapper_set_shift, + * pt_wrapper_if_last_sibling, pt_wrapper_eq, pt_print_wrapper */ -struct trt_wrapper { - trd_wrapper_type type; /**< Location of the wrapper. */ +struct pt_wrapper { + pt_wrapper_type type; /**< Location of the wrapper. */ uint64_t bit_marks1; /**< The set bits indicate where the '|' character is to be printed. It follows that the maximum immersion of the printable node is 64. */ uint32_t actual_pos; /**< Actual position in bit_marks. */ @@ -254,9 +135,9 @@ struct trt_wrapper { * | * @endcode */ -#define TRP_INIT_WRAPPER_TOP \ - (struct trt_wrapper) { \ - .type = TRD_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0 \ +#define PT_INIT_WRAPPER_TOP \ + (struct pt_wrapper) { \ + .type = PT_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0 \ } /** @@ -271,47 +152,46 @@ struct trt_wrapper { * +-- * @endcode */ -#define TRP_INIT_WRAPPER_BODY \ - (struct trt_wrapper) { \ - .type = TRD_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0 \ +#define PT_INIT_WRAPPER_BODY \ + (struct pt_wrapper) { \ + .type = PT_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0 \ } /** - * @brief Package which only groups wrapper and indent in node. + * @brief Structure that only groups wrapper and indent in node. */ -struct trt_pck_indent { - struct trt_wrapper wrapper; /**< Coded " | | " sequence. */ - struct trt_indent_in_node in_node; /**< Indent in node. */ +struct pt_indent { + struct pt_wrapper wrapper; /**< Coded " | | " sequence. */ + struct pt_indent_in_node in_node; /**< Indent in node. */ }; /** - * @brief Initialize struct trt_pck_indent by parameters. + * @brief Initialize struct pt_indent by parameters. */ -#define TRP_INIT_PCK_INDENT(WRAPPER, INDENT_IN_NODE) \ - (struct trt_pck_indent){ \ +#define PT_INIT_INDENT(WRAPPER, INDENT_IN_NODE) \ + (struct pt_indent){ \ .wrapper = WRAPPER, .in_node = INDENT_IN_NODE \ } /********************************************************************** - * flags - *********************************************************************/ - -#define TRD_FLAGS_TYPE_EMPTY "--" -#define TRD_FLAGS_TYPE_RW "rw" -#define TRD_FLAGS_TYPE_RO "ro" -#define TRD_FLAGS_TYPE_RPC_INPUT_PARAMS "-w" -#define TRD_FLAGS_TYPE_USES_OF_GROUPING "-u" -#define TRD_FLAGS_TYPE_RPC "-x" -#define TRD_FLAGS_TYPE_NOTIF "-n" -#define TRD_FLAGS_TYPE_MOUNT_POINT "mp" - -/********************************************************************** - * node_name and opts + * node *********************************************************************/ -#define TRD_NODE_NAME_PREFIX_CHOICE "(" -#define TRD_NODE_NAME_PREFIX_CASE ":(" -#define TRD_NODE_NAME_TRIPLE_DOT "..." +#define PT_FLAGS_TYPE_EMPTY "--" +#define PT_FLAGS_TYPE_RW "rw" +#define PT_FLAGS_TYPE_RO "ro" +#define PT_FLAGS_TYPE_RPC_INPUT_PARAMS "-w" +#define PT_FLAGS_TYPE_USES_OF_GROUPING "-u" +#define PT_FLAGS_TYPE_RPC "-x" +#define PT_FLAGS_TYPE_NOTIF "-n" +#define PT_FLAGS_TYPE_EXT "" +#define PT_FLAGS_TYPE_MOUNT_POINT "mp" +#define PT_NODE_NAME_PREFIX_CHOICE "(" +#define PT_NODE_NAME_PREFIX_CASE ":(" +#define PT_NODE_NAME_TRIPLE_DOT "..." +#define PT_STATUS_CURRENT "+" +#define PT_STATUS_DEPRECATED "x" +#define PT_STATUS_OBSOLETE "o" /** * @brief Type of the node. @@ -320,506 +200,346 @@ struct trt_pck_indent { * around the \. */ typedef enum { - TRD_NODE_ELSE = 0, /**< For some node which does not require special treatment. \ */ - TRD_NODE_CASE, /**< For case node. :(\) */ - TRD_NODE_CHOICE, /**< For choice node. (\) */ - TRD_NODE_TRIPLE_DOT /**< For collapsed sibling nodes and their children. Special case which doesn't belong here very well. */ -} trt_node_type; + PT_NODE_ELSE = 0, /**< For some node which does not require special treatment. \ */ + PT_NODE_CASE, /**< For case node. :(\) */ + PT_NODE_CHOICE, /**< For choice node. (\) */ + PT_NODE_TRIPLE_DOT /**< For collapsed sibling nodes and their children. Special case which doesn't belong here very well. */ +} pt_node_type; -#define TRD_NODE_OPTIONAL "?" /**< For an optional leaf, anydata, or anyxml. \? */ -#define TRD_NODE_CONTAINER "!" /**< For a presence container. \! */ -#define TRD_NODE_LISTLEAFLIST "*" /**< For a leaf-list or list. \* */ +#define PT_NODE_OPTIONAL "?" /**< For an optional leaf, anydata, or anyxml. \? */ +#define PT_NODE_CONTAINER "!" /**< For a presence container. \! */ +#define PT_NODE_LISTLEAFLIST "*" /**< For a leaf-list or list. \* */ +#define PT_NODE_MOUNTED "/" /**< For a top-level data node in a mounted module */ +#define PT_NODE_MOUNTED_PARENT_REF "@" /**< for a top-level data node of a module identified + in a mount point parent reference */ /** * @brief Type of node and his name. * - * @see TRP_EMPTY_NODE_NAME, TRP_NODE_NAME_IS_EMPTY, - * trp_print_node_name, trp_mark_is_used, trp_print_opts_keys + * @see PT_EMPTY_NODE_NAME, PT_NODE_NAME_IS_EMPTY, + * pt_print_node_name, pt_mark_is_used, pt_print_opts_keys */ -struct trt_node_name { - trt_node_type type; /**< Type of the node relevant for printing. */ +struct pt_node_name { + pt_node_type type; /**< Type of the node relevant for printing. */ ly_bool keys; /**< Set to 1 if [\] are to be printed. Valid for some types only. */ const char *module_prefix; /**< If the node is augmented into the tree from another module, so this is the prefix of that module. */ const char *str; /**< Name of the node. */ - const char *add_opts; /**< Additional opts symbol from plugin. */ const char *opts; /**< The \ symbol. */ }; /** - * @brief Create struct trt_node_name as empty. + * @brief Create struct pt_node_name as empty. */ -#define TRP_EMPTY_NODE_NAME \ - (struct trt_node_name) { \ - .type = TRD_NODE_ELSE, .keys = 0, .module_prefix = NULL, .str = NULL, .opts = NULL, .add_opts = NULL \ +#define PT_EMPTY_NODE_NAME \ + (struct pt_node_name) { \ + .type = PT_NODE_ELSE, .keys = 0, .module_prefix = NULL, .str = NULL, .opts = NULL \ } /** - * @brief Check if struct trt_node_name is empty. + * @brief Check if struct pt_node_name is empty. */ -#define TRP_NODE_NAME_IS_EMPTY(NODE_NAME) \ +#define PT_NODE_NAME_IS_EMPTY(NODE_NAME) \ !NODE_NAME.str -/********************************************************************** - * type - *********************************************************************/ - /** * @brief Type of the \ */ typedef enum { - TRD_TYPE_NAME = 0, /**< Type is just a name that does not require special treatment. */ - TRD_TYPE_TARGET, /**< Should have a form "-> TARGET", where TARGET is the leafref path. */ - TRD_TYPE_LEAFREF, /**< This type is set automatically by the 'trp' algorithm. - So set type as ::TRD_TYPE_TARGET. */ - TRD_TYPE_EMPTY /**< Type is not used at all. */ -} trt_type_type; + PT_TYPE_NAME = 0, /**< Type is just a name that does not require special treatment. */ + PT_TYPE_TARGET, /**< Should have a form "-> TARGET", where TARGET is the leafref path. */ + PT_TYPE_LEAFREF, /**< leafref abbreviation when ::PT_TYPE_TARGET is too long */ + PT_TYPE_EMPTY /**< Type is not used at all. */ +} pt_lf_type_id; /** * @brief \ in the \. * - * @see TRP_EMPTY_TRT_TYPE, TRP_TRT_TYPE_IS_EMPTY, trp_print_type + * @see PT_EMPTY_LF_TYPE, PT_LF_TYPE_IS_EMPTY, pt_print_type */ -struct trt_type { - trt_type_type type; /**< Type of the \. */ +struct pt_lf_type { + pt_lf_type_id type; /**< Type of the \. */ const char *str; /**< Path or name of the type. */ }; /** - * @brief Create empty struct trt_type. + * @brief Create empty struct pt_type. */ -#define TRP_EMPTY_TRT_TYPE \ - (struct trt_type) {.type = TRD_TYPE_EMPTY, .str = NULL} +#define PT_EMPTY_LF_TYPE \ + (struct pt_lf_type) {.type = PT_TYPE_EMPTY, .str = NULL} /** - * @brief Check if struct trt_type is empty. + * @brief Check if struct pt_type is empty. */ -#define TRP_TRT_TYPE_IS_EMPTY(TYPE_OF_TYPE) \ - TYPE_OF_TYPE.type == TRD_TYPE_EMPTY +#define PT_LF_TYPE_IS_EMPTY(LF_TYPE) \ + LF_TYPE.type == PT_TYPE_EMPTY /** - * @brief Initialize struct trt_type by parameters. + * @brief Initialize struct pt_type by parameters. */ -#define TRP_INIT_TRT_TYPE(TYPE_OF_TYPE, STRING) \ - (struct trt_type) {.type = TYPE_OF_TYPE, .str = STRING} +#define PT_INIT_LF_TYPE(LF_TYPE, STRING) \ + (struct pt_lf_type) {.type = LF_TYPE, .str = STRING} /** * @brief If-feature type. */ typedef enum { - TRD_IFF_NON_PRESENT = 0, /**< iffeatures are not present. */ - TRD_IFF_PRESENT, /**< iffeatures are present and will be printed by - trt_fp_print.print_features_names callback */ - TRD_IFF_OVERR /**< iffeatures are override by plugin */ -} trt_iffeatures_type; + PT_IFF_NON_PRESENT = 0, /**< iffeatures are not present. */ + PT_IFF_PRESENT /**< iffeatures are present and will be printed. */ +} pt_iffeatures_type; /** * @brief \. */ -struct trt_iffeatures { - trt_iffeatures_type type; /**< Type of iffeature. */ - char *str; /**< iffeatures string ready to print. Set if TRD_IFF_OVERR is set. */ +struct pt_iffeatures { + pt_iffeatures_type type; /**< Type of iffeature. */ }; /** * @brief Create empty iffeatures. */ -#define TRP_EMPTY_TRT_IFFEATURES \ - (struct trt_iffeatures) {.type = TRD_IFF_NON_PRESENT} +#define PT_EMPTY_IFFEATURES \ + (struct pt_iffeatures) {.type = PT_IFF_NON_PRESENT} /** * @brief Check if iffeatures is empty. * - * @param[in] IFF_TYPE value from trt_iffeatures.type. + * @param[in] IFF_TYPE value from pt_iffeatures.type. * @return 1 if is empty. */ -#define TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(IFF_TYPE) \ - (IFF_TYPE == TRD_IFF_NON_PRESENT) - -/********************************************************************** - * node - *********************************************************************/ +#define PT_EMPTY_IFFEATURES_IS_EMPTY(IFF_TYPE) \ + (IFF_TYPE == PT_IFF_NON_PRESENT) /** * @brief \ data for printing. * * It contains RFC's: * \--\ \\ \ \. - * Item \ is moved to part struct trt_node_name. + * Item \ is moved to part struct pt_node_name. * For printing [\] and if-features is required special * functions which prints them. * - * @see TRP_EMPTY_NODE, trp_node_is_empty, trp_node_body_is_empty, - * trp_print_node_up_to_name, trp_print_divided_node_up_to_name, - * trp_print_node + * @see PT_EMPTY_NODE, pt_node_is_empty, pt_node_body_is_empty, + * pt_print_node_up_to_name, pt_print_divided_node_up_to_name, + * pt_print_node */ -struct trt_node { +struct pt_node { const char *status; /**< \. */ const char *flags; /**< \. */ - struct trt_node_name name; /**< \ with \ mark or [\]. */ - struct trt_type type; /**< \ contains the name of the type or type for leafref. */ - struct trt_iffeatures iffeatures; /**< \. */ + struct pt_node_name name; /**< \ with \ mark or [\]. */ + struct pt_lf_type type; /**< \ contains the name of the type or type for leafref. */ + struct pt_iffeatures iffeatures; /**< \. */ ly_bool last_one; /**< Information about whether the node is the last. */ }; /** - * @brief Create struct trt_node as empty. + * @brief Create struct pt_node as empty. */ -#define TRP_EMPTY_NODE \ - (struct trt_node) { \ +#define PT_EMPTY_NODE \ + (struct pt_node) { \ .status = NULL, \ .flags = NULL, \ - .name = TRP_EMPTY_NODE_NAME, \ - .type = TRP_EMPTY_TRT_TYPE, \ - .iffeatures = TRP_EMPTY_TRT_IFFEATURES, \ + .name = PT_EMPTY_NODE_NAME, \ + .type = PT_EMPTY_LF_TYPE, \ + .iffeatures = PT_EMPTY_IFFEATURES, \ .last_one = 1 \ } -/** - * @brief Package which only groups indent and node. - */ -struct trt_pair_indent_node { - struct trt_indent_in_node indent; - struct trt_node node; -}; - -/** - * @brief Initialize struct trt_pair_indent_node by parameters. - */ -#define TRP_INIT_PAIR_INDENT_NODE(INDENT_IN_NODE, NODE) \ - (struct trt_pair_indent_node) { \ - .indent = INDENT_IN_NODE, .node = NODE \ - } - /********************************************************************** - * statement + * parent cache *********************************************************************/ -#define TRD_KEYWORD_MODULE "module" -#define TRD_KEYWORD_SUBMODULE "submodule" -#define TRD_KEYWORD_AUGMENT "augment" -#define TRD_KEYWORD_RPC "rpcs" -#define TRD_KEYWORD_NOTIF "notifications" -#define TRD_KEYWORD_GROUPING "grouping" - -/** - * @brief Main sign of the tree nodes. - * - * @see TRP_EMPTY_KEYWORD_STMT, TRP_KEYWORD_STMT_IS_EMPTY - * trt_print_keyword_stmt_begin, trt_print_keyword_stmt_str, - * trt_print_keyword_stmt_end, trp_print_keyword_stmt - */ -struct trt_keyword_stmt { - const char *section_name; /**< String containing section name. */ - const char *argument; /**< Name or path located begind section name. */ - ly_bool has_node; /**< Flag if section has any nodes. */ -}; - /** - * @brief Create struct trt_keyword_stmt as empty. + * @brief Types of nodes that have some effect on their children. */ -#define TRP_EMPTY_KEYWORD_STMT \ - (struct trt_keyword_stmt) {.section_name = NULL, .argument = NULL, .has_node = 0} - -/********************************************************************** - * Modify getters - *********************************************************************/ - -struct trt_parent_cache; +typedef enum { + PT_ANCESTOR_ELSE = 0, /**< Everything not listed. */ + PT_ANCESTOR_RPC_INPUT, /**< ::LYS_INPUT */ + PT_ANCESTOR_RPC_OUTPUT, /**< ::LYS_OUTPUT */ + PT_ANCESTOR_NOTIF /**< ::LYS_NOTIF */ +} pt_parent_type; /** - * @brief Functions that change the state of the tree_ctx structure. * - * The 'trop' or 'troc' functions are set here, which provide data - * for the 'trp' printing functions and are also called from the - * 'trb' browsing functions when walking through a tree. These callback - * functions need to be checked or reformulated if changes to the - * libyang library affect the printing tree. For all, if the value - * cannot be returned, its empty version obtained by relevant TRP_EMPTY - * macro is returned. - */ -struct trt_fp_modify_ctx { - ly_bool (*parent)(struct trt_tree_ctx *); /**< Jump to parent node. Return true if parent exists. */ - struct trt_node (*first_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump on the first of the siblings. */ - struct trt_node (*next_sibling)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to next sibling of the current node. */ - struct trt_node (*next_child)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Jump to the child of the current node. */ -}; - -/** - * @brief Create modify functions for compiled tree. + * @brief Cached information when browsing the lysp tree downwards. + * + * Structure should contain the resolved flags of the parent. + * It prevent frequent retrieval of information from the all parents. + * Only the function jumping on the child (next_child(...)) deal with + * the structure when the pointer to the current node moves + * down in the lysp tree. + * + * @see PT_EMPTY_PARENT_CACHE, pt_parent_cache_for_child */ -#define TRP_TRT_FP_MODIFY_COMPILED \ - (struct trt_fp_modify_ctx) { \ - .parent = troc_modi_parent, \ - .first_sibling = troc_modi_first_sibling, \ - .next_sibling = troc_modi_next_sibling, \ - .next_child = troc_modi_next_child, \ - } +struct pt_parent_cache { + pt_parent_type ancestor; /**< Some types of nodes have a special effect on their children. */ + uint16_t lys_status; /**< Inherited status CURR, DEPRC, OBSLT. */ + uint16_t lys_config; /**< Inherited config W or R. */ + const struct lysp_node_list *last_list; /**< The last ::LYS_LIST passed. */ +}; /** - * @brief Create modify functions for parsed tree. + * @brief Return pt_parent_cache filled with default values. */ -#define TRP_TRT_FP_MODIFY_PARSED \ - (struct trt_fp_modify_ctx) { \ - .parent = trop_modi_parent, \ - .first_sibling = trop_modi_first_sibling, \ - .next_sibling = trop_modi_next_sibling, \ - .next_child = trop_modi_next_child, \ +#define PT_EMPTY_PARENT_CACHE \ + (struct pt_parent_cache) { \ + .ancestor = PT_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \ + .lys_config = LYS_CONFIG_W, .last_list = NULL \ } /********************************************************************** - * Read getters + * statement *********************************************************************/ +#define PT_KEYWORD_MODULE "module" +#define PT_KEYWORD_SUBMODULE "submodule" +#define PT_KEYWORD_AUGMENT "augment" +#define PT_KEYWORD_RPC "rpcs" +#define PT_KEYWORD_NOTIF "notifications" +#define PT_KEYWORD_GROUPING "grouping" + /** - * @brief Functions that do not change the state of the tree_structure. + * @brief Main sign of the tree nodes. * - * For details see trt_fp_modify_ctx. + * @see PT_EMPTY_KEYWORD_STMT, PT_KEYWORD_STMT_IS_EMPTY + * pt_print_keyword_stmt_begin, pt_print_keyword_stmt_str, + * pt_print_keyword_stmt_end, pt_print_keyword_stmt */ -struct trt_fp_read { - struct trt_keyword_stmt (*module_name)(const struct trt_tree_ctx *); /**< Get name of the module. */ - struct trt_node (*node)(struct trt_parent_cache, struct trt_tree_ctx *); /**< Get current node. */ - ly_bool (*if_sibling_exists)(const struct trt_tree_ctx *); /**< Check if node's sibling exists. */ - ly_bool (*if_parent_exists)(const struct trt_tree_ctx *); /**< Check if node's parent exists. */ +struct pt_keyword_stmt { + const char *section_name; /**< String containing section name. */ + const char *argument; /**< Name or path located behind section name. */ + ly_bool has_node; /**< Flag if section has any nodes. */ }; /** - * @brief Create read functions for compiled tree. - */ -#define TRP_TRT_FP_READ_COMPILED \ - (struct trt_fp_read) { \ - .module_name = tro_read_module_name, \ - .node = troc_read_node, \ - .if_sibling_exists = troc_read_if_sibling_exists, \ - .if_parent_exists = tro_read_if_parent_exists \ - } - -/** - * @brief Create read functions for parsed tree. - */ -#define TRP_TRT_FP_READ_PARSED \ - (struct trt_fp_read) { \ - .module_name = tro_read_module_name, \ - .node = trop_read_node, \ - .if_sibling_exists = trop_read_if_sibling_exists, \ - .if_parent_exists = tro_read_if_parent_exists \ - } - -/********************************************************************** - * All getters - *********************************************************************/ - -/** - * @brief A set of all necessary functions that must be provided - * for the printer. + * @brief Create struct pt_keyword_stmt as empty. */ -struct trt_fp_all { - struct trt_fp_modify_ctx modify; /**< Function pointers which modify state of trt_tree_ctx. */ - struct trt_fp_read read; /**< Function pointers which only reads state of trt_tree_ctx. */ - struct trt_fp_print print; /**< Functions pointers for printing special items in node. */ -}; - -/********************************************************************** - * Printer context - *********************************************************************/ +#define PT_EMPTY_KEYWORD_STMT \ + (struct pt_keyword_stmt) {.section_name = NULL, .argument = NULL, .has_node = 0} /** - * @brief Main structure for @ref TRP_trp part. + * @brief The name of the section to which the node belongs. */ -struct trt_printer_ctx { - struct ly_out *out; /**< Handler to printing. */ - struct trt_fp_all fp; /**< @ref TRP_tro functions callbacks. */ - size_t max_line_length; /**< The maximum number of characters that can be - printed on one line, including the last. */ -}; +typedef enum { + PT_SECT_MODULE = 0, /**< The node belongs to the "module: :" label. */ + PT_SECT_AUGMENT, /**< The node belongs to some "augment :" label. */ + PT_SECT_RPCS, /**< The node belongs to the "rpcs:" label. */ + PT_SECT_NOTIF, /**< The node belongs to the "notifications:" label. */ + PT_SECT_GROUPING, /**< The node belongs to some "grouping :" label. */ + PT_SECT_PLUG_DATA /**< The node belongs to some plugin section. */ +} pt_current_section; /********************************************************************** - * Tro functions + * extension *********************************************************************/ /** - * @brief The name of the section to which the node belongs. + * @brief Type of extension to print. */ typedef enum { - TRD_SECT_MODULE = 0, /**< The node belongs to the "module: :" label. */ - TRD_SECT_AUGMENT, /**< The node belongs to some "augment :" label. */ - TRD_SECT_RPCS, /**< The node belongs to the "rpcs:" label. */ - TRD_SECT_NOTIF, /**< The node belongs to the "notifications:" label. */ - TRD_SECT_GROUPING, /**< The node belongs to some "grouping :" label. */ - TRD_SECT_PLUG_DATA /**< The node belongs to some plugin section. */ -} trt_actual_section; + PT_EXT_GENERIC, + PT_EXT_SCHEMA_MOUNT, /**< schema-mount subtree '\/', RFC 8340 */ + PT_EXT_SCHEMA_MOUNT_REF /**< schema-mount parent reference subtree '\@' , RFC 8340 */ +} pt_extension_type; /** - * @brief Types of nodes that have some effect on their children. + * @brief Extension schema. */ -typedef enum { - TRD_ANCESTOR_ELSE = 0, /**< Everything not listed. */ - TRD_ANCESTOR_RPC_INPUT, /**< ::LYS_INPUT */ - TRD_ANCESTOR_RPC_OUTPUT, /**< ::LYS_OUTPUT */ - TRD_ANCESTOR_NOTIF /**< ::LYS_NOTIF */ -} trt_ancestor_type; +struct pt_ext_tree_schema { + pt_extension_type ext; /**< extension type */ + ly_bool compiled; /**< Flag if it is a compiled schema. */ -/** - * @brief Saved information when browsing the tree downwards. - * - * This structure helps prevent frequent retrieval of information - * from the tree. Functions @ref TRP_trb are designed to preserve - * this structures during their recursive calls. This functions do not - * interfere in any way with this data. This structure - * is used by @ref TRP_trop functions which, thanks to this - * structure, can return a node with the correct data. The word - * \b parent is in the structure name, because this data refers to - * the last parent and at the same time the states of its - * ancestors data. Only the function jumping on the child - * (next_child(...)) creates this structure, because the pointer - * to the current node moves down the tree. It's like passing - * the genetic code to children. Some data must be inherited and - * there are two approaches to this problem. Either it will always - * be determined which inheritance states belong to the current node - * (which can lead to regular travel to the root node) or - * the inheritance states will be stored during the recursive calls. - * So the problem was solved by the second option. Why does - * the structure contain this data? Because it walks through - * the lysp tree. For walks through the lysc tree is trt_parent_cache - * useless. - * - * @see TRO_EMPTY_PARENT_CACHE, tro_parent_cache_for_child - */ -struct trt_parent_cache { - trt_ancestor_type ancestor; /**< Some types of nodes have a special effect on their children. */ - uint16_t lys_status; /**< Inherited status CURR, DEPRC, OBSLT. */ - uint16_t lys_config; /**< Inherited config W or R. */ - const struct lysp_node_list *last_list; /**< The last ::LYS_LIST passed. */ + union { + const struct lysc_node *ctree; /**< Compiled schema. */ + const struct lysp_node *ptree; /**< Parsed schema. */ + }; }; /** - * @brief Return trt_parent_cache filled with default values. - */ -#define TRP_EMPTY_PARENT_CACHE \ - (struct trt_parent_cache) { \ - .ancestor = TRD_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \ - .lys_config = LYS_CONFIG_W, .last_list = NULL \ - } - -/** - * @brief Node override from plugin. + * @brief Schema mount structure. */ -struct lyplg_ext_sprinter_tree_node_override { - const char *flags; /**< Override for \. */ - const char *add_opts; /**< Additional symbols for \. */ +struct pt_ext_schema_mount { + const struct lysc_node *mount_point; /**< mount-point (--mp node) */ + struct pt_ext_tree_schema *schemas; /**< Parsed or compiled schemas ([sized array](@ref sizedarrays)) */ + struct ly_set *parent_refs; /**< Set of lysc nodes matching parent-reference XPaths. */ + ly_bool mp_has_normal_node; /**< Set to 1 if mount-point node has other node besides schema-mount subtrees. */ }; /** * @brief Context for plugin extension. */ -struct trt_plugin_ctx { - struct lyspr_tree_ctx *ctx; /**< Pointer to main context. */ - struct lyspr_tree_schema *schema; /**< Current schema to print. */ - ly_bool filtered; /**< Flag if current node is filtered. */ - struct lyplg_ext_sprinter_tree_node_override node_overr; /**< Current node override. */ - ly_bool last_schema; /**< Flag if schema is last. */ - ly_bool last_error; /**< Last error from plugin. */ +struct pt_extension { + struct pt_ext_tree_schema *schema; /**< Current schema to print. */ + struct pt_ext_schema_mount *schema_mount; /**< Schema-mount data. */ }; +/********************************************************************** + * printer tree context + *********************************************************************/ + /** * @brief Main structure for browsing the libyang tree */ -struct trt_tree_ctx { +struct pt_tree_ctx { ly_bool lysc_tree; /**< The lysc nodes are used for browsing through the tree. It is assumed that once set, it does not change. - If it is true then trt_tree_ctx.pn and - trt_tree_ctx.tpn are not used. - If it is false then trt_tree_ctx.cn is not used. */ - trt_actual_section section; /**< To which section pn points. */ + If it is true then pt_tree_ctx.pn and + pt_tree_ctx.tpn are not used. + If it is false then pt_tree_ctx.cn is not used. */ + pt_current_section section; /**< To which section pn points. */ const struct lysp_module *pmod; /**< Parsed YANG schema tree. */ const struct lysc_module *cmod; /**< Compiled YANG schema tree. */ const struct lysp_node *pn; /**< Actual pointer to parsed node. */ - const struct lysp_node *tpn; /**< Pointer to actual top-node. */ const struct lysc_node *cn; /**< Actual pointer to compiled node. */ LY_ERR last_error; /**< Error value during printing. */ - struct trt_plugin_ctx plugin_ctx; /**< Context for plugin. */ -}; + struct pt_extension plugin_ctx; /**< Context for extension. */ -/** - * @brief Create empty node override. - */ -#define TRP_TREE_CTX_EMPTY_NODE_OVERR \ - (struct lyplg_ext_sprinter_tree_node_override) { \ - .flags = NULL, \ - .add_opts = NULL, \ - } + struct ly_out *out; /**< Handler to printing. */ + size_t max_line_length; /**< The maximum number of characters that can be + printed on one line, including the last. */ +}; /** * @brief Check if lysp node is available from * the current compiled node. * - * Use only if trt_tree_ctx.lysc_tree is set to true. + * Use only if pt_tree_ctx.lysc_tree is set to true. */ -#define TRP_TREE_CTX_LYSP_NODE_PRESENT(CN) \ +#define PT_TREE_CTX_LYSP_NODE_PRESENT(CN) \ (CN->priv) /** - * @brief Get lysp_node from trt_tree_ctx.cn. + * @brief Get lysp_node from pt_tree_ctx.cn. * - * Use only if :TRP_TREE_CTX_LYSP_NODE_PRESENT returns true + * Use only if :PT_TREE_CTX_LYSP_NODE_PRESENT returns true * for that node. */ -#define TRP_TREE_CTX_GET_LYSP_NODE(CN) \ +#define PT_TREE_CTX_GET_LYSP_NODE(CN) \ ((const struct lysp_node *)CN->priv) -/** Getter function for ::trop_node_charptr(). */ -typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn); +#define PT_LAST_ARRAY_ITEM(ARR, ITEM) \ + (&ARR[LY_ARRAY_COUNT(ARR) - 1] == ITEM) -/** - * @brief Simple getter functions for lysp and lysc nodes. - * - * This structure is useful if we have a general algorithm - * (tro function) that can be used for both lysc and lysp nodes. - * Thanks to this structure, we prevent code redundancy. - * We don't have to write basically the same algorithm twice - * for lysp and lysc trees. - */ -struct tro_getters { - uint16_t (*nodetype)(const void *); /**< Get nodetype. */ - uint16_t (*lysp_flags)(const void *); /**< Get flags from lysp_node. */ - const void *(*next)(const void *); /**< Get sibling. */ - const void *(*parent)(const void *); /**< Get parent. */ - const void *(*child)(const void *); /**< Get child. */ - const void *(*actions)(const void *); /**< Get actions. */ - const void *(*action_input)(const void *); /**< Get input action from action node. */ - const void *(*action_output)(const void *); /**< Get output action from action node. */ - const void *(*notifs)(const void *); /**< Get notifs. */ -}; +#define PT_LAST_SCHEMA_MOUNT(PT_EXTENSION) \ + (PT_EXTENSION.schema ? \ + PT_LAST_ARRAY_ITEM(PT_EXTENSION.schema_mount->schemas, PT_EXTENSION.schema): \ + 1) + +#define PT_LAST_SCHEMA(PT_EXTENSION) \ + (PT_EXTENSION.schema_mount ? PT_LAST_SCHEMA_MOUNT(PT_EXTENSION) : 1) /********************************************************************** - * Definition of the general Trg functions + * String functions *********************************************************************/ -/** - * @brief Print a substring but limited to the maximum length. - * @param[in] str is pointer to source. - * @param[in] len is number of characters to be printed. - * @param[in,out] out is output handler. - * @return str parameter shifted by len. - */ -static const char * -trg_print_substr(const char *str, size_t len, struct ly_out *out) -{ - for (size_t i = 0; i < len; i++) { - ly_print_(out, "%c", str[0]); - str++; - } - return str; -} - /** * @brief Pointer is not NULL and does not point to an empty string. - * @param[in] str is pointer to string to be checked. + * @param[in] str Pointer to string to be checked. * @return 1 if str pointing to non empty string otherwise 0. */ static ly_bool -trg_charptr_has_data(const char *str) +pt_charptr_has_data(const char *str) { return (str) && (str[0] != '\0'); } @@ -827,13 +547,13 @@ trg_charptr_has_data(const char *str) /** * @brief Check if @p word in @p src is present where words are * delimited by @p delim. - * @param[in] src is source where words are separated by @p delim. - * @param[in] word to be searched. - * @param[in] delim is delimiter between @p words in @p src. + * @param[in] src Source where words are separated by @p delim. + * @param[in] word Word to be searched. + * @param[in] delim Delimiter between @p words in @p src. * @return 1 if src contains @p word otherwise 0. */ static ly_bool -trg_word_is_present(const char *src, const char *word, char delim) +pt_word_is_present(const char *src, const char *word, char delim) { const char *hit; @@ -863,75 +583,24 @@ trg_word_is_present(const char *src, const char *word, char delim) /* skip delim */ src = src[0] == '\0' ? src : src + 1; /* continue with searching */ - return trg_word_is_present(src, word, delim); + return pt_word_is_present(src, word, delim); } else { return 0; } } /********************************************************************** - * Definition of printer functions + * '|' wrapper *********************************************************************/ -/** - * @brief Write callback for ::ly_out_new_clb(). - * - * @param[in] user_data is type of struct ly_out_clb_arg. - * @param[in] buf contains input characters - * @param[in] count is number of characters in buf. - * @return Number of printed bytes. - * @return Negative value in case of error. - */ -static ssize_t -trp_ly_out_clb_func(void *user_data, const void *buf, size_t count) -{ - LY_ERR erc = LY_SUCCESS; - struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data; - - switch (data->mode) { - case TRD_PRINT: - erc = ly_write_(data->out, buf, count); - break; - case TRD_CHAR_COUNT: - data->counter = data->counter + count; - break; - default: - break; - } - - if (erc != LY_SUCCESS) { - data->last_error = erc; - return -1; - } else { - return count; - } -} - -/** - * @brief Check that indent in node can be considered as equivalent. - * @param[in] first is the first indent in node. - * @param[in] second is the second indent in node. - * @return 1 if indents are equivalent otherwise 0. - */ -static ly_bool -trp_indent_in_node_are_eq(struct trt_indent_in_node first, struct trt_indent_in_node second) -{ - const ly_bool a = first.type == second.type; - const ly_bool b = first.btw_name_opts == second.btw_name_opts; - const ly_bool c = first.btw_opts_type == second.btw_opts_type; - const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures; - - return a && b && c && d; -} - /** * @brief Setting space character because node is last sibling. - * @param[in] wr is wrapper over which the shift operation + * @param[in] wr Wrapper over which the shift operation * is to be performed. * @return New shifted wrapper. */ -static struct trt_wrapper -trp_wrapper_set_shift(struct trt_wrapper wr) +static struct pt_wrapper +pt_wrapper_set_shift(struct pt_wrapper wr) { assert(wr.actual_pos < 64); /* +-- @@ -944,38 +613,38 @@ trp_wrapper_set_shift(struct trt_wrapper wr) /** * @brief Setting '|' symbol because node is divided or * it is not last sibling. - * @param[in] wr is source of wrapper. + * @param[in] wr Source of wrapper. * @return New wrapper which is marked at actual position and shifted. */ -static struct trt_wrapper -trp_wrapper_set_mark(struct trt_wrapper wr) +static struct pt_wrapper +pt_wrapper_set_mark(struct pt_wrapper wr) { assert(wr.actual_pos < 64); wr.bit_marks1 |= 1U << wr.actual_pos; - return trp_wrapper_set_shift(wr); + return pt_wrapper_set_shift(wr); } /** * @brief Setting ' ' symbol if node is last sibling otherwise set '|'. - * @param[in] wr is actual wrapper. - * @param[in] last_one is flag. Value 1 saying if the node is the last + * @param[in] wr Current wrapper. + * @param[in] last_one If set to 1 then the node is the last * and has no more siblings. * @return New wrapper for the actual node. */ -static struct trt_wrapper -trp_wrapper_if_last_sibling(struct trt_wrapper wr, ly_bool last_one) +static struct pt_wrapper +pt_wrapper_if_last_sibling(struct pt_wrapper wr, ly_bool last_one) { - return last_one ? trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr); + return last_one ? pt_wrapper_set_shift(wr) : pt_wrapper_set_mark(wr); } /** * @brief Test if the wrappers are equivalent. - * @param[in] first is the first wrapper. - * @param[in] second is the second wrapper. + * @param[in] first First wrapper. + * @param[in] second Second wrapper. * @return 1 if the wrappers are equivalent otherwise 0. */ static ly_bool -trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second) +pt_wrapper_eq(struct pt_wrapper first, struct pt_wrapper second) { const ly_bool a = first.type == second.type; const ly_bool b = first.bit_marks1 == second.bit_marks1; @@ -986,25 +655,28 @@ trp_wrapper_eq(struct trt_wrapper first, struct trt_wrapper second) /** * @brief Print " | " sequence on line. - * @param[in] wr is wrapper to be printed. - * @param[in,out] out is output handler. + * @param[in] wr Wrapper to be printed. + * @param[in,out] out Output handler. */ static void -trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out) +pt_print_wrapper(struct pt_wrapper wr, struct ly_out *out) { uint32_t lb; - if (wr.type == TRD_WRAPPER_TOP) { - lb = TRD_INDENT_LINE_BEGIN; - } else if (wr.type == TRD_WRAPPER_BODY) { - lb = TRD_INDENT_LINE_BEGIN * 2; - } else { - lb = TRD_INDENT_LINE_BEGIN; + switch (wr.type) { + case PT_WRAPPER_TOP: + lb = PT_INDENT_LINE_BEGIN; + break; + case PT_WRAPPER_BODY: + lb = PT_INDENT_LINE_BEGIN * 2; + break; + default: + assert(0); } ly_print_(out, "%*c", lb, ' '); - if (trp_wrapper_eq(wr, TRP_INIT_WRAPPER_TOP)) { + if (pt_wrapper_eq(wr, PT_INIT_WRAPPER_TOP)) { return; } @@ -1017,577 +689,283 @@ trp_print_wrapper(struct trt_wrapper wr, struct ly_out *out) } if (i != wr.actual_pos) { - ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' '); + ly_print_(out, "%*c", PT_INDENT_BTW_SIBLINGS, ' '); } } } -/** - * @brief Check if struct trt_node is empty. - * @param[in] node is item to test. - * @return 1 if node is considered empty otherwise 0. - */ -static ly_bool -trp_node_is_empty(const struct trt_node *node) -{ - const ly_bool a = TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(node->iffeatures.type); - const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node->type); - const ly_bool c = TRP_NODE_NAME_IS_EMPTY(node->name); - const ly_bool d = node->flags == NULL; - const ly_bool e = node->status == NULL; - - return a && b && c && d && e; -} - -/** - * @brief Check if [\], \ and - * \ are empty/not_set. - * @param[in] node is item to test. - * @return 1 if node has no \ \ or \ - * otherwise 0. - */ -static ly_bool -trp_node_body_is_empty(const struct trt_node *node) -{ - const ly_bool a = TRP_EMPTY_TRT_IFFEATURES_IS_EMPTY(node->iffeatures.type); - const ly_bool b = TRP_TRT_TYPE_IS_EMPTY(node->type); - const ly_bool c = !node->name.keys; - - return a && b && c; -} +/********************************************************************** + * Alignment of \ for all siblings + *********************************************************************/ /** - * @brief Print entire struct trt_node_name structure. - * @param[in] node_name is item to print. - * @param[in,out] out is output handler. + * @brief Count gap from \ to \. + * @param[in] node Node in which the calculation is made. + * @return gap from '--' to \. */ -static void -trp_print_node_name(struct trt_node_name node_name, struct ly_out *out) +static uint32_t +pt_gap_to_opts(const struct pt_node *node) { - const char *mod_prefix; - const char *colon; - const char trd_node_name_suffix_choice[] = ")"; - const char trd_node_name_suffix_case[] = ")"; + uint32_t len = 0; - if (TRP_NODE_NAME_IS_EMPTY(node_name)) { - return; + if (node->name.keys) { + return 0; } - if (node_name.module_prefix) { - mod_prefix = node_name.module_prefix; - colon = ":"; - } else { - mod_prefix = ""; - colon = ""; - } + assert(node->flags); + len += strlen(node->flags); + /* space between flags and name */ + len += 1; - switch (node_name.type) { - case TRD_NODE_ELSE: - ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str); - break; - case TRD_NODE_CASE: - ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, trd_node_name_suffix_case); - break; - case TRD_NODE_CHOICE: - ly_print_(out, "%s%s%s%s%s", TRD_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, trd_node_name_suffix_choice); + switch (node->name.type) { + case PT_NODE_CASE: + /* ':' is already counted. Plus parentheses. */ + len += 2; break; - case TRD_NODE_TRIPLE_DOT: - ly_print_(out, "%s", TRD_NODE_NAME_TRIPLE_DOT); + case PT_NODE_CHOICE: + /* Plus parentheses. */ + len += 2; break; default: break; } - if (node_name.add_opts) { - ly_print_(out, "%s", node_name.add_opts); + if (node->name.module_prefix) { + /* prefix_name and ':' */ + len += strlen(node->name.module_prefix) + 1; } - if (node_name.opts) { - ly_print_(out, "%s", node_name.opts); + if (node->name.str) { + len += strlen(node->name.str); } -} - -/** - * @brief Check if mark (?, !, *, /, @) is implicitly contained in - * struct trt_node_name. - * @param[in] node_name is structure containing the 'mark'. - * @return 1 if contain otherwise 0. - */ -static ly_bool -trp_mark_is_used(struct trt_node_name node_name) -{ - if (TRP_NODE_NAME_IS_EMPTY(node_name)) { - return 0; - } else if (node_name.keys) { - return 0; - } - - switch (node_name.type) { - case TRD_NODE_ELSE: - case TRD_NODE_CASE: - return 0; - default: - if (node_name.add_opts || node_name.opts) { - return 1; - } else { - return 0; - } - } -} - -/** - * @brief Print opts keys. - * @param[in] node_name contains type of the node with his name. - * @param[in] btw_name_opts is number of spaces between name and [keys]. - * @param[in] cf is basically a pointer to the function that prints - * the keys. - * @param[in,out] out is output handler. - */ -static void -trp_print_opts_keys(struct trt_node_name node_name, int16_t btw_name_opts, struct trt_cf_print cf, struct ly_out *out) -{ - if (!node_name.keys) { - return; + if (node->name.opts) { + len += strlen(node->name.opts); } - /* ___*/ - if (btw_name_opts > 0) { - ly_print_(out, "%*c", btw_name_opts, ' '); - } - ly_print_(out, "["); - cf.pf(cf.ctx, out); - ly_print_(out, "]"); + return len; } /** - * @brief Print entire struct trt_type structure. - * @param[in] type is item to print. - * @param[in,out] out is output handler. + * @brief Count gap from \ to \. + * @param[in] node Node in which the calculation is made. + * @return gap from '--' to \. */ -static void -trp_print_type(struct trt_type type, struct ly_out *out) +static uint32_t +pt_gap_to_type(const struct pt_node *node) { - if (TRP_TRT_TYPE_IS_EMPTY(type)) { - return; - } + uint32_t len, opts_len; - switch (type.type) { - case TRD_TYPE_NAME: - ly_print_(out, "%s", type.str); - break; - case TRD_TYPE_TARGET: - ly_print_(out, "-> %s", type.str); - break; - case TRD_TYPE_LEAFREF: - ly_print_(out, "leafref"); - default: - break; + if (node->name.keys) { + return 0; } -} -/** - * @brief Print all iffeatures of node - * - * @param[in] iff is iffeatures to print. - * @param[in] cf is basically a pointer to the function that prints the list of features. - * @param[in,out] out is output handler. - */ -static void -trp_print_iffeatures(struct trt_iffeatures iff, struct trt_cf_print cf, struct ly_out *out) -{ - if (iff.type == TRD_IFF_PRESENT) { - ly_print_(out, "{"); - cf.pf(cf.ctx, out); - ly_print_(out, "}?"); - } else if (iff.type == TRD_IFF_OVERR) { - ly_print_(out, "%s", iff.str); + len = pt_gap_to_opts(node); + /* Gap between opts and type. */ + opts_len = 0; + opts_len += node->name.opts ? strlen(node->name.opts) : 0; + if (opts_len >= PT_INDENT_BEFORE_TYPE) { + /* At least one space should be there. */ + len += 1; + } else if (node->name.opts) { + len += PT_INDENT_BEFORE_TYPE - opts_len; + } else { + len += PT_INDENT_BEFORE_TYPE; } -} -/** - * @brief Print just \--\ \ with opts mark. - * @param[in] node contains items to print. - * @param[in] out is output handler. - */ -static void -trp_print_node_up_to_name(const struct trt_node *node, struct ly_out *out) -{ - if (node->name.type == TRD_NODE_TRIPLE_DOT) { - trp_print_node_name(node->name, out); - return; - } - /* -- */ - ly_print_(out, "%s", node->status); - ly_print_(out, "--"); - /* If the node is a case node, there is no space before the - * also case node has no flags. - */ - if (node->flags && (node->name.type != TRD_NODE_CASE)) { - ly_print_(out, "%s", node->flags); - ly_print_(out, " "); - } - /* */ - trp_print_node_name(node->name, out); + return len; } /** - * @brief Print alignment (spaces) instead of - * \--\ \ for divided node. - * @param[in] node contains items to print. - * @param[in] out is output handler. + * @brief Calculate the pt_indent_in_node.btw_opts_type indent size + * for a particular node. + * @param[in] node Node for which the btw_opts_type is get. + * @param[in] max_gap_before_type Maximum value of btw_opts_type + * that it can have. + * @return Indent between \ and \ for node. */ -static void -trp_print_divided_node_up_to_name(const struct trt_node *node, struct ly_out *out) +static int16_t +pt_calc_btw_opts_type(const struct pt_node *node, int16_t max_gap_before_type) { - uint32_t space = strlen(node->flags); + uint32_t to_opts_len; - if (node->name.type == TRD_NODE_CASE) { - /* :( */ - space += strlen(TRD_NODE_NAME_PREFIX_CASE); - } else if (node->name.type == TRD_NODE_CHOICE) { - /* ( */ - space += strlen(TRD_NODE_NAME_PREFIX_CHOICE); + to_opts_len = pt_gap_to_opts(node); + if (to_opts_len == 0) { + return 1; } else { - /* _ */ - space += strlen(" "); + return max_gap_before_type - to_opts_len; } - - /* - * __ - */ - space += TRD_INDENT_LONG_LINE_BREAK; - - ly_print_(out, "%*c", space, ' '); } /** - * @brief Print struct trt_node structure. - * @param[in] node is item to print. - * @param[in] pck package of functions for - * printing [\] and \. - * @param[in] indent is the indent in node. - * @param[in,out] out is output handler. + * @brief Calculate the wrapper about how deep in the tree the node is. + * @param[in] wr_in Wrapper to use as a starting point. + * @param[in] node Node from which to count. + * @return wrapper for @p node. */ -static void -trp_print_node(const struct trt_node *node, struct trt_pck_print pck, struct trt_indent_in_node indent, struct ly_out *out) +static struct pt_wrapper +pt_count_depth(const struct pt_wrapper *wr_in, const struct lysc_node *node) { - ly_bool triple_dot; - ly_bool divided; - struct trt_cf_print cf_print_keys; - struct trt_cf_print cf_print_iffeatures; - - if (trp_node_is_empty(node)) { - return; - } - - /* -- */ - triple_dot = node->name.type == TRD_NODE_TRIPLE_DOT; - divided = indent.type == TRD_INDENT_IN_NODE_DIVIDED; - - if (triple_dot) { - trp_print_node_name(node->name, out); - return; - } else if (!divided) { - trp_print_node_up_to_name(node, out); - } else { - trp_print_divided_node_up_to_name(node, out); - } - - /* */ - /* ___*/ - cf_print_keys.ctx = pck.tree_ctx; - cf_print_keys.pf = pck.fps.print_keys; - - trp_print_opts_keys(node->name, indent.btw_name_opts, cf_print_keys, out); + struct pt_wrapper wr = wr_in ? *wr_in : PT_INIT_WRAPPER_TOP; + const struct lysc_node *parent; - /* __ */ - if (indent.btw_opts_type > 0) { - ly_print_(out, "%*c", indent.btw_opts_type, ' '); + if (!node) { + return wr; } - /* */ - trp_print_type(node->type, out); - - /* __ */ - if (indent.btw_type_iffeatures > 0) { - ly_print_(out, "%*c", indent.btw_type_iffeatures, ' '); + for (parent = node->parent; parent; parent = parent->parent) { + wr = pt_wrapper_set_shift(wr); } - /* */ - cf_print_iffeatures.ctx = pck.tree_ctx; - cf_print_iffeatures.pf = pck.fps.print_features_names; - - trp_print_iffeatures(node->iffeatures, cf_print_iffeatures, out); + return wr; } -/** - * @brief Print keyword based on trt_keyword_stmt.type. - * @param[in] ks is keyword statement to print. - * @param[in,out] out is output handler - */ -static void -trt_print_keyword_stmt_begin(struct trt_keyword_stmt ks, struct ly_out *out) -{ - if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) || - !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) { - ly_print_(out, "%s: ", ks.section_name); - return; - } +static struct pt_node pt_modi_first_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc); - ly_print_(out, "%*c", TRD_INDENT_LINE_BEGIN, ' '); - if (ks.argument) { - ly_print_(out, "%s ", ks.section_name); - } else { - ly_print_(out, "%s", ks.section_name); - } -} +static ly_bool pt_node_is_empty(const struct pt_node *node); + +static struct pt_node pt_modi_next_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc); /** - * @brief Print trt_keyword_stmt.str which is string of name or path. - * @param[in] ks is keyword statement structure. - * @param[in] mll is max line length. - * @param[in,out] out is output handler. + * @brief For all siblings find maximal space from '--' to \. + * + * Side-effect -> Current node is set to the first sibling. + * + * @param[in] ca Contains inherited data from ancestors. + * @param[in,out] tc Tree context. + * @return max space. */ -static void -trt_print_keyword_stmt_str(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out) +static uint32_t +pt_max_gap_to_type(struct pt_parent_cache ca, struct pt_tree_ctx *tc) { - uint32_t ind_initial; - uint32_t ind_divided; - /* flag if path must be splitted to more lines */ - ly_bool linebreak_was_set; - /* flag if at least one subpath was printed */ - ly_bool subpath_printed; - /* the sum of the sizes of the substrings on the current line */ - uint32_t how_far; - /* pointer to start of the subpath */ - const char *sub_ptr; - /* size of subpath from sub_ptr */ - size_t sub_len; - - if ((!ks.argument) || (ks.argument[0] == '\0')) { - return; - } - - /* module name cannot be splitted */ - if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) || !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) { - ly_print_(out, "%s", ks.argument); - return; - } + struct pt_node node; + int32_t maxlen, len; - /* after -> for trd_keyword_stmt_body do */ - - /* set begin indentation */ - ind_initial = TRD_INDENT_LINE_BEGIN + strlen(ks.section_name) + 1; - ind_divided = ind_initial + TRD_INDENT_LONG_LINE_BREAK; - linebreak_was_set = 0; - subpath_printed = 0; - how_far = 0; - sub_ptr = ks.argument; - sub_len = 0; - - while (sub_ptr[0] != '\0') { - uint32_t ind; - /* skip slash */ - const char *tmp = sub_ptr[0] == '/' ? sub_ptr + 1 : sub_ptr; - - /* get position of the end of substr */ - tmp = strchr(tmp, '/'); - /* set correct size if this is a last substring */ - sub_len = !tmp ? strlen(sub_ptr) : (size_t)(tmp - sub_ptr); - /* actualize sum of the substring's sizes on the current line */ - how_far += sub_len; - /* correction due to colon character if it this is last substring */ - how_far = *(sub_ptr + sub_len) == '\0' ? how_far + 1 : how_far; - /* choose indentation which depends on - * whether the string is printed on multiple lines or not - */ - ind = linebreak_was_set ? ind_divided : ind_initial; - if (ind + how_far <= mll) { - /* printing before max line length */ - sub_ptr = trg_print_substr(sub_ptr, sub_len, out); - subpath_printed = 1; - } else { - /* printing on new line */ - if (subpath_printed == 0) { - /* first subpath is too long - * but print it at first line anyway - */ - sub_ptr = trg_print_substr(sub_ptr, sub_len, out); - subpath_printed = 1; - continue; - } - ly_print_(out, "\n"); - ly_print_(out, "%*c", ind_divided, ' '); - linebreak_was_set = 1; - sub_ptr = trg_print_substr(sub_ptr, sub_len, out); - how_far = sub_len; - subpath_printed = 1; - } + maxlen = 0; + for (node = pt_modi_first_sibling(ca, tc); + !pt_node_is_empty(&node); + node = pt_modi_next_sibling(ca, tc)) { + len = pt_gap_to_type(&node); + maxlen = maxlen < len ? len : maxlen; } -} + pt_modi_first_sibling(ca, tc); -/** - * @brief Print separator based on trt_keyword_stmt.type - * @param[in] ks is keyword statement structure. - * @param[in,out] out is output handler. - */ -static void -trt_print_keyword_stmt_end(struct trt_keyword_stmt ks, struct ly_out *out) -{ - if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) || !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) { - return; - } else if (ks.has_node) { - ly_print_(out, ":"); - } + return maxlen; } /** - * @brief Print entire struct trt_keyword_stmt structure. - * @param[in] ks is item to print. - * @param[in] mll is max line length. - * @param[in,out] out is output handler. - */ -static void -trp_print_keyword_stmt(struct trt_keyword_stmt ks, size_t mll, struct ly_out *out) + * @brief Find out if it is possible to unify + * the alignment before \. + * + * The goal is for all node siblings to have the same alignment + * for \ as if they were in a column. All siblings who cannot + * adapt because they do not fit on the line at all are ignored. + * Side-effect -> Current node is set to the first sibling. + * + * @param[in] ca Contains inherited data from ancestors. + * @param[in,out] tc Tree context. + * @return positive number indicating the maximum number of spaces + * before \ if the length of the flags, node name and opts is 0. To calculate + * the pt_indent_in_node.btw_opts_type indent size for a particular + * node, use the ::pt_calc_btw_opts_type(). +*/ +static uint32_t +pt_try_unified_indent(struct pt_parent_cache ca, struct pt_tree_ctx tc) { - assert(ks.section_name); - trt_print_keyword_stmt_begin(ks, out); - trt_print_keyword_stmt_str(ks, mll, out); - trt_print_keyword_stmt_end(ks, out); + return pt_max_gap_to_type(ca, &tc); } /********************************************************************** - * Main trp functions + * Splitting a node into one or more lines. *********************************************************************/ /** - * @brief Printing one line including wrapper and node - * which can be incomplete (divided). - * @param[in] node is \ representation. - * @param[in] pck contains special printing functions callback. - * @param[in] indent contains wrapper and indent in node numbers. - * @param[in,out] out is output handler. - */ -static void -trp_print_line(const struct trt_node *node, struct trt_pck_print pck, struct trt_pck_indent indent, struct ly_out *out) -{ - trp_print_wrapper(indent.wrapper, out); - trp_print_node(node, pck, indent.in_node, out); -} - -/** - * @brief Printing one line including wrapper and - * \--\ \\. - * @param[in] node is \ representation. - * @param[in] wr is wrapper for printing indentation before node. - * @param[in] out is output handler. - */ -static void -trp_print_line_up_to_node_name(const struct trt_node *node, struct trt_wrapper wr, struct ly_out *out) -{ - trp_print_wrapper(wr, out); - trp_print_node_up_to_name(node, out); -} - -/** - * @brief Check if leafref target must be change to string 'leafref' - * because his target string is too long. - * @param[in] node containing leafref target. - * @param[in] wr is wrapper for printing indentation before node. - * @param[in] mll is max line length. - * @param[in] out is output handler. - * @return true if leafref must be changed to string 'leafref'. + * @brief Check if mark (?, !, *, /, @) is implicitly contained in + * struct pt_node_name. + * @param[in] node_name Structure containing the 'mark'. + * @return 1 if contain otherwise 0. */ static ly_bool -trp_leafref_target_is_too_long(const struct trt_node *node, struct trt_wrapper wr, size_t mll, struct ly_out *out) +pt_mark_is_used(struct pt_node_name node_name) { - size_t type_len; - struct ly_out_clb_arg *data; - - if (node->type.type != TRD_TYPE_TARGET) { + if (PT_NODE_NAME_IS_EMPTY(node_name)) { + return 0; + } else if (node_name.keys) { return 0; } - /* set ly_out to counting characters */ - data = out->method.clb.arg; - - data->counter = 0; - data->mode = TRD_CHAR_COUNT; - /* count number of printed bytes */ - trp_print_wrapper(wr, out); - ly_print_(out, "%*c", TRD_INDENT_BTW_SIBLINGS, ' '); - trp_print_divided_node_up_to_name(node, out); - data->mode = TRD_PRINT; - type_len = strlen(node->type.str); - - return data->counter + type_len > mll; + switch (node_name.type) { + case PT_NODE_ELSE: + case PT_NODE_CASE: + return 0; + default: + return node_name.opts ? 1 : 0; + } } /** * @brief Get default indent in node based on node values. - * @param[in] node is \ representation. + * @param[in] node Node to process. * @return Default indent in node assuming that the node * will not be divided. */ -static struct trt_indent_in_node -trp_default_indent_in_node(const struct trt_node *node) +static struct pt_indent_in_node +pt_default_indent_in_node(const struct pt_node *node) { - struct trt_indent_in_node ret; + struct pt_indent_in_node ret; uint32_t opts_len = 0; - ret.type = TRD_INDENT_IN_NODE_NORMAL; + ret.type = PT_INDENT_IN_NODE_NORMAL; /* btw_name_opts */ - ret.btw_name_opts = node->name.keys ? TRD_INDENT_BEFORE_KEYS : 0; + ret.btw_name_opts = node->name.keys ? PT_INDENT_BEFORE_KEYS : 0; /* btw_opts_type */ - if (!(TRP_TRT_TYPE_IS_EMPTY(node->type))) { - if (trp_mark_is_used(node->name)) { - opts_len += node->name.add_opts ? strlen(node->name.add_opts) : 0; + if (!(PT_LF_TYPE_IS_EMPTY(node->type))) { + if (pt_mark_is_used(node->name)) { opts_len += node->name.opts ? strlen(node->name.opts) : 0; - ret.btw_opts_type = TRD_INDENT_BEFORE_TYPE > opts_len ? 1 : TRD_INDENT_BEFORE_TYPE - opts_len; + ret.btw_opts_type = PT_INDENT_BEFORE_TYPE > opts_len ? 1 : PT_INDENT_BEFORE_TYPE - opts_len; } else { - ret.btw_opts_type = TRD_INDENT_BEFORE_TYPE; + ret.btw_opts_type = PT_INDENT_BEFORE_TYPE; } } else { ret.btw_opts_type = 0; } /* btw_type_iffeatures */ - ret.btw_type_iffeatures = node->iffeatures.type == TRD_IFF_PRESENT ? TRD_INDENT_BEFORE_IFFEATURES : 0; + ret.btw_type_iffeatures = node->iffeatures.type == PT_IFF_PRESENT ? PT_INDENT_BEFORE_IFFEATURES : 0; return ret; } /** - * @brief Setting linebreaks in trt_indent_in_node. + * @brief Setting linebreaks in pt_indent_in_node. * * The order where the linebreak tag can be placed is from the end. * - * @param[in] indent containing alignment lengths + * @param[in] indent Indent containing alignment lengths * or already linebreak marks. * @return indent with a newly placed linebreak tag. - * @return .type set to TRD_INDENT_IN_NODE_FAILED if it is not possible + * @return .type set to PT_INDENT_IN_NODE_FAILED if it is not possible * to place a more linebreaks. */ -static struct trt_indent_in_node -trp_indent_in_node_place_break(struct trt_indent_in_node indent) +static struct pt_indent_in_node +pt_indent_in_node_place_break(struct pt_indent_in_node indent) { /* somewhere must be set a line break in node */ - struct trt_indent_in_node ret = indent; + struct pt_indent_in_node ret = indent; /* gradually break the node from the end */ - if ((indent.btw_type_iffeatures != TRD_LINEBREAK) && (indent.btw_type_iffeatures != 0)) { - ret.btw_type_iffeatures = TRD_LINEBREAK; - } else if ((indent.btw_opts_type != TRD_LINEBREAK) && (indent.btw_opts_type != 0)) { - ret.btw_opts_type = TRD_LINEBREAK; - } else if ((indent.btw_name_opts != TRD_LINEBREAK) && (indent.btw_name_opts != 0)) { + if ((indent.btw_type_iffeatures != PT_LINEBREAK) && (indent.btw_type_iffeatures != 0)) { + ret.btw_type_iffeatures = PT_LINEBREAK; + } else if ((indent.btw_opts_type != PT_LINEBREAK) && (indent.btw_opts_type != 0)) { + ret.btw_opts_type = PT_LINEBREAK; + } else if ((indent.btw_name_opts != PT_LINEBREAK) && (indent.btw_name_opts != 0)) { /* set line break between name and opts */ - ret.btw_name_opts = TRD_LINEBREAK; + ret.btw_name_opts = PT_LINEBREAK; } else { /* it is not possible to place a more line breaks, * unfortunately the max_line_length constraint is violated */ - ret.type = TRD_INDENT_IN_NODE_FAILED; + ret.type = PT_INDENT_IN_NODE_FAILED; } return ret; } @@ -1597,20 +975,20 @@ trp_indent_in_node_place_break(struct trt_indent_in_node indent) * * Items in the second half of the node will be empty. * - * @param[in,out] innod contains information in which part of the \ - * the first half ends. Set first half of the node, indent is unchanged. + * @param[in] indent Indentation in the node. + * @param[out] node Set where the first half of the \ ends. */ static void -trp_first_half_node(struct trt_pair_indent_node *innod) +pt_first_half_node(const struct pt_indent_in_node *indent, struct pt_node *node) { - if (innod->indent.btw_name_opts == TRD_LINEBREAK) { - innod->node.type = TRP_EMPTY_TRT_TYPE; - innod->node.iffeatures = TRP_EMPTY_TRT_IFFEATURES; - } else if (innod->indent.btw_opts_type == TRD_LINEBREAK) { - innod->node.type = TRP_EMPTY_TRT_TYPE; - innod->node.iffeatures = TRP_EMPTY_TRT_IFFEATURES; - } else if (innod->indent.btw_type_iffeatures == TRD_LINEBREAK) { - innod->node.iffeatures = TRP_EMPTY_TRT_IFFEATURES; + if (indent->btw_name_opts == PT_LINEBREAK) { + node->type = PT_EMPTY_LF_TYPE; + node->iffeatures = PT_EMPTY_IFFEATURES; + } else if (indent->btw_opts_type == PT_LINEBREAK) { + node->type = PT_EMPTY_LF_TYPE; + node->iffeatures = PT_EMPTY_IFFEATURES; + } else if (indent->btw_type_iffeatures == PT_LINEBREAK) { + node->iffeatures = PT_EMPTY_IFFEATURES; } } @@ -1620,65 +998,67 @@ trp_first_half_node(struct trt_pair_indent_node *innod) * Items in the first half of the node will be empty. * Indentations belonging to the first node will be reset to zero. * - * @param[in,out] innod contains information in which part of the \ - * the second half starts. Set second half of the node, indent is newly set. + * @param[in] indent Indentation in the node. + * @param[out] node Set where the second half of the \. */ static void -trp_second_half_node(struct trt_pair_indent_node *innod) +pt_second_half_node(struct pt_indent_in_node *indent, struct pt_node *node) { - if (innod->indent.btw_name_opts < 0) { + if (indent->btw_name_opts < 0) { /* Logically, the information up to token should - * be deleted, but the the trp_print_node function needs it to + * be deleted, but the pt_print_node function needs it to * create the correct indent. */ - innod->indent.btw_name_opts = 0; - innod->indent.btw_opts_type = TRP_TRT_TYPE_IS_EMPTY(innod->node.type) ? 0 : TRD_INDENT_BEFORE_TYPE; - innod->indent.btw_type_iffeatures = innod->node.iffeatures.type == TRD_IFF_NON_PRESENT ? 0 : TRD_INDENT_BEFORE_IFFEATURES; - } else if (innod->indent.btw_opts_type == TRD_LINEBREAK) { - innod->indent.btw_name_opts = 0; - innod->indent.btw_opts_type = 0; - innod->indent.btw_type_iffeatures = innod->node.iffeatures.type == TRD_IFF_NON_PRESENT ? 0 : TRD_INDENT_BEFORE_IFFEATURES; - } else if (innod->indent.btw_type_iffeatures == TRD_LINEBREAK) { - innod->node.type = TRP_EMPTY_TRT_TYPE; - innod->indent.btw_name_opts = 0; - innod->indent.btw_opts_type = 0; - innod->indent.btw_type_iffeatures = 0; + indent->btw_name_opts = 0; + indent->btw_opts_type = PT_LF_TYPE_IS_EMPTY(node->type) ? 0 : PT_INDENT_BEFORE_TYPE; + indent->btw_type_iffeatures = node->iffeatures.type == PT_IFF_NON_PRESENT ? 0 : PT_INDENT_BEFORE_IFFEATURES; + } else if (indent->btw_opts_type == PT_LINEBREAK) { + indent->btw_name_opts = 0; + indent->btw_opts_type = 0; + indent->btw_type_iffeatures = node->iffeatures.type == PT_IFF_NON_PRESENT ? 0 : PT_INDENT_BEFORE_IFFEATURES; + } else if (indent->btw_type_iffeatures == PT_LINEBREAK) { + node->type = PT_EMPTY_LF_TYPE; + indent->btw_name_opts = 0; + indent->btw_opts_type = 0; + indent->btw_type_iffeatures = 0; } } +static void pt_print_line(const struct pt_node *node, struct pt_tree_ctx *tc, + struct pt_indent indent); + /** * @brief Get the correct alignment for the node. * * This function is recursively called itself. It's like a backend - * function for a function ::trp_try_normal_indent_in_node(). + * function for a function ::pt_try_normal_indent_in_node(). * - * @param[in] pck contains speciall callback functions for printing. - * @param[in] wrapper contains information about '|' context. - * @param[in] mll is max line length. - * @param[in,out] cnt counting number of characters to print. - * @param[in,out] out is output handler. - * @param[in,out] innod pair of node and indentation numbers of that node. + * @param[in] tc Tree context. + * @param[in] node Node to print. + * @param[out] indent Indentation data. + * @param[in,out] cnt Counting number of characters to print. */ static void -trp_try_normal_indent_in_node_(struct trt_pck_print pck, struct trt_wrapper wrapper, size_t mll, size_t *cnt, - struct ly_out *out, struct trt_pair_indent_node *innod) +pt_try_normal_indent_in_node_(struct pt_tree_ctx *tc, struct pt_node *node, + struct pt_indent *indent, size_t *cnt) { - trp_print_line(&innod->node, pck, TRP_INIT_PCK_INDENT(wrapper, innod->indent), out); + pt_print_line(node, tc, PT_INIT_INDENT(indent->wrapper, indent->in_node)); - if (*cnt <= mll) { + if (*cnt <= tc->max_line_length) { /* success */ return; } else { - innod->indent = trp_indent_in_node_place_break(innod->indent); - if (innod->indent.type != TRD_INDENT_IN_NODE_FAILED) { + indent->in_node = pt_indent_in_node_place_break(indent->in_node); + if (indent->in_node.type != PT_INDENT_IN_NODE_FAILED) { /* erase information in node due to line break */ - trp_first_half_node(innod); + pt_first_half_node(&indent->in_node, node); /* check if line fits, recursive call */ *cnt = 0; - trp_try_normal_indent_in_node_(pck, wrapper, mll, cnt, out, innod); + pt_try_normal_indent_in_node_(tc, node, indent, cnt); /* make sure that the result will be with the status divided * or eventually with status failed */ - innod->indent.type = innod->indent.type == TRD_INDENT_IN_NODE_FAILED ? TRD_INDENT_IN_NODE_FAILED : TRD_INDENT_IN_NODE_DIVIDED; + indent->in_node.type = indent->in_node.type == PT_INDENT_IN_NODE_FAILED ? + PT_INDENT_IN_NODE_FAILED : PT_INDENT_IN_NODE_DIVIDED; } return; } @@ -1686,579 +1066,926 @@ trp_try_normal_indent_in_node_(struct trt_pck_print pck, struct trt_wrapper wrap /** * @brief Get the correct alignment for the node. - * - * @param[in] node is \ representation. - * @param[in] pck contains speciall callback functions for printing. - * @param[in] indent contains wrapper and indent in node numbers. - * @param[in] mll is max line length. - * @param[in,out] out is output handler. - * @param[out] innod If the node does not fit in the line, some indent variable has negative value as a line break sign - * and therefore ::TRD_INDENT_IN_NODE_DIVIDED is set. - * If the node fits into the line, all indent variables values has non-negative number and therefore - * ::TRD_INDENT_IN_NODE_NORMAL is set. - * If the node does not fit into the line, all indent variables has negative or zero values, function failed - * and therefore ::TRD_INDENT_IN_NODE_FAILED is set. + * @param[in] node Node to process. + * @param[in] tc Tree context. + * @param[out] indent Indentation data. If the node does not fit in the line, + * some indent variable has negative value as a line break sign and therefore + * ::PT_INDENT_IN_NODE_DIVIDED is set. If the node fits into the line, + * all indent variables values has non-negative number and therefore + * ::PT_INDENT_IN_NODE_NORMAL is set. If the node does not fit into the line, + * all indent variables has negative or zero values, function failed + * and therefore ::PT_INDENT_IN_NODE_FAILED is set. */ static void -trp_try_normal_indent_in_node(const struct trt_node *node, struct trt_pck_print pck, struct trt_pck_indent indent, - size_t mll, struct ly_out *out, struct trt_pair_indent_node *innod) +pt_try_normal_indent_in_node(struct pt_node *node, struct pt_tree_ctx *tc, + struct pt_indent *indent) { struct ly_out_clb_arg *data; - *innod = TRP_INIT_PAIR_INDENT_NODE(indent.in_node, *node); - /* set ly_out to counting characters */ - data = out->method.clb.arg; + data = tc->out->method.clb.arg; data->counter = 0; - data->mode = TRD_CHAR_COUNT; - trp_try_normal_indent_in_node_(pck, indent.wrapper, mll, &data->counter, out, innod); - data->mode = TRD_PRINT; + data->mode = PT_CHAR_COUNT; + pt_try_normal_indent_in_node_(tc, node, indent, &data->counter); + data->mode = PT_PRINT; } +/********************************************************************** + * Print keyword + *********************************************************************/ + /** - * @brief Auxiliary function for ::trp_print_entire_node() - * that prints split nodes. - * @param[in] node is node representation. - * @param[in] ppck contains speciall callback functions for printing. - * @param[in] ipck contains wrapper and indent in node numbers. - * @param[in] mll is max line length. - * @param[in,out] out is output handler. + * @brief Print keyword based on pt_keyword_stmt.type. + * @param[in] ks Section keyword to print. + * @param[in,out] out Output handler. */ static void -trp_print_divided_node(const struct trt_node *node, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, struct ly_out *out) +pt_print_keyword_stmt_begin(const struct pt_keyword_stmt *ks, struct ly_out *out) { - ly_bool entire_node_was_printed; - struct trt_pair_indent_node innod; - - trp_try_normal_indent_in_node(node, ppck, ipck, mll, out, &innod); - - if (innod.indent.type == TRD_INDENT_IN_NODE_FAILED) { - /* nothing can be done, continue as usual */ - innod.indent.type = TRD_INDENT_IN_NODE_DIVIDED; + if (!strcmp(ks->section_name, PT_KEYWORD_MODULE) || + !strcmp(ks->section_name, PT_KEYWORD_SUBMODULE)) { + ly_print_(out, "%s: ", ks->section_name); + return; } - trp_print_line(&innod.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, innod.indent), out); - entire_node_was_printed = trp_indent_in_node_are_eq(ipck.in_node, innod.indent); - - if (!entire_node_was_printed) { - ly_print_(out, "\n"); - /* continue with second half node */ - innod.node = *node; - trp_second_half_node(&innod); - /* continue with printing node */ - trp_print_divided_node(&innod.node, ppck, TRP_INIT_PCK_INDENT(ipck.wrapper, innod.indent), mll, out); + ly_print_(out, "%*c", PT_INDENT_LINE_BEGIN, ' '); + if (ks->argument) { + ly_print_(out, "%s ", ks->section_name); } else { - return; + ly_print_(out, "%s", ks->section_name); } } /** - * @brief Printing of the wrapper and the whole node, - * which can be divided into several lines. - * @param[in] node_p is node representation. - * @param[in] ppck contains speciall callback functions for printing. - * @param[in] ipck contains wrapper and indent in node numbers. - * @param[in] mll is max line length. - * @param[in,out] out is output handler. + * @brief Print pt_keyword_stmt.str which is string of name or path. + * @param[in] ks Section keyword to print. + * @param[in,out] out Output handler. */ static void -trp_print_entire_node(const struct trt_node *node_p, struct trt_pck_print ppck, struct trt_pck_indent ipck, size_t mll, - struct ly_out *out) +pt_print_keyword_stmt_str(const struct pt_keyword_stmt *ks, struct ly_out *out) { - struct trt_pair_indent_node innod; - struct trt_pck_indent tmp; - struct trt_node node; - - node = *node_p; - if (trp_leafref_target_is_too_long(&node, ipck.wrapper, mll, out)) { - node.type.type = TRD_TYPE_LEAFREF; + if ((!ks->argument) || (ks->argument[0] == '\0')) { + return; } - /* check if normal indent is possible */ - trp_try_normal_indent_in_node(&node, ppck, ipck, mll, out, &innod); + ly_print_(out, "%s", ks->argument); +} - if (innod.indent.type == TRD_INDENT_IN_NODE_NORMAL) { - /* node fits to one line */ - trp_print_line(&node, ppck, ipck, out); - } else if (innod.indent.type == TRD_INDENT_IN_NODE_DIVIDED) { - /* node will be divided */ - /* print first half */ - tmp = TRP_INIT_PCK_INDENT(ipck.wrapper, innod.indent); - /* pretend that this is normal node */ - tmp.in_node.type = TRD_INDENT_IN_NODE_NORMAL; - - trp_print_line(&innod.node, ppck, tmp, out); - ly_print_(out, "\n"); - - /* continue with second half on new line */ - innod.node = node; - trp_second_half_node(&innod); - tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), innod.indent); - - trp_print_divided_node(&innod.node, ppck, tmp, mll, out); - } else if (innod.indent.type == TRD_INDENT_IN_NODE_FAILED) { - /* node name is too long */ - trp_print_line_up_to_node_name(&node, ipck.wrapper, out); - - if (trp_node_body_is_empty(&node)) { - return; - } else { - ly_print_(out, "\n"); - - innod.node = node; - trp_second_half_node(&innod); - innod.indent.type = TRD_INDENT_IN_NODE_DIVIDED; - tmp = TRP_INIT_PCK_INDENT(trp_wrapper_if_last_sibling(ipck.wrapper, node.last_one), innod.indent); - - trp_print_divided_node(&innod.node, ppck, tmp, mll, out); - } +/** + * @brief Print separator based on pt_keyword_stmt.type + * @param[in] ks Section keyword to print. + * @param[in,out] out Output handler. + */ +static void +pt_print_keyword_stmt_end(const struct pt_keyword_stmt *ks, struct ly_out *out) +{ + if (!strcmp(ks->section_name, PT_KEYWORD_MODULE) || !strcmp(ks->section_name, PT_KEYWORD_SUBMODULE)) { + return; + } else if (ks->has_node) { + ly_print_(out, ":"); } } /** - * @brief Check if parent-stmt is valid for printing extensinon. + * @brief Print entire struct pt_keyword_stmt structure. * - * @param[in] lysc_tree flag if ext is from compiled tree. - * @param[in] ext Extension to check. - * @return 1 if extension is valid. + * Print section like module , augment , rpcs:, notification:... + * + * @param[in] ks Section keyword to print. + * @param[in,out] once Flag for extra newline if keyword is printed for the first time. + * Set to NULL if no newline is desired. + * @param[in,out] out Printing handler. */ -static ly_bool -trp_ext_parent_is_valid(ly_bool lysc_tree, void *ext) +static void +pt_print_keyword_stmt(const struct pt_keyword_stmt *ks, + ly_bool *once, struct ly_out *out) { - enum ly_stmt parent_stmt; - - if (lysc_tree) { - parent_stmt = ((struct lysc_ext_instance *)ext)->parent_stmt; - } else { - parent_stmt = ((struct lysp_ext_instance *)ext)->parent_stmt; - } - if ((parent_stmt & LY_STMT_OP_MASK) || (parent_stmt & LY_STMT_DATA_NODE_MASK) || - (parent_stmt & LY_STMT_SUBMODULE) || parent_stmt & LY_STMT_MODULE) { - return 1; - } else { - return 0; + if (once && *once) { + ly_print_(out, "\n"); + ly_print_(out, "\n"); + *once = 0; + } else if (once) { + ly_print_(out, "\n"); } + assert(ks->section_name); + pt_print_keyword_stmt_begin(ks, out); + pt_print_keyword_stmt_str(ks, out); + pt_print_keyword_stmt_end(ks, out); } +/********************************************************************** + * Print node + *********************************************************************/ + /** - * @brief Check if printer_tree can use node extension. + * @brief Write callback for ::ly_out_new_clb(). * - * @param[in] lysc_tree Flag if @p node is compiled. - * @param[in] node to check. Its type is lysc_node or lysp_node. - * @return Pointer to extension instance which printer_tree can used. + * @param[in] user_data Type of struct ly_out_clb_arg. + * @param[in] buf Contains input characters + * @param[in] count Number of characters in @p buf. + * @return Number of printed bytes. + * @return Negative value in case of error. */ -static void * -trp_ext_is_present(ly_bool lysc_tree, const void *node) +static ssize_t +pt_ly_out_clb_func(void *user_data, const void *buf, size_t count) { - const struct lysp_node *pn; - const struct lysc_node *cn; - LY_ARRAY_COUNT_TYPE i; - void *ret = NULL; + LY_ERR erc = LY_SUCCESS; + struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data; - if (!node) { - return NULL; + switch (data->mode) { + case PT_PRINT: + erc = ly_write_(data->out, buf, count); + break; + case PT_CHAR_COUNT: + data->counter = data->counter + count; + break; + default: + break; } - if (lysc_tree) { - cn = (const struct lysc_node *)node; - LY_ARRAY_FOR(cn->exts, i) { - if (!cn->exts[i].def->plugin_ref || !LYSC_GET_EXT_PLG(cn->exts[i].def->plugin_ref)->printer_ctree) { - continue; - } - if (!trp_ext_parent_is_valid(1, &cn->exts[i])) { - continue; - } - ret = &cn->exts[i]; - break; - } + if (erc != LY_SUCCESS) { + data->last_error = erc; + return -1; } else { - pn = (const struct lysp_node *)node; - LY_ARRAY_FOR(pn->exts, i) { - if (!pn->exts[i].plugin_ref || !LYSC_GET_EXT_PLG(pn->exts[i].plugin_ref)->printer_ptree) { - continue; - } - if (!trp_ext_parent_is_valid(0, &pn->exts[i])) { - continue; - } - ret = &pn->exts[i]; - break; - } + return count; } - - return ret; } /** - * @brief Check if printer_tree can use node extension. - * - * @param[in] tc Context with current node. - * @return 1 if some extension for printer_tree is valid. + * @brief Check if struct pt_node is empty. + * @param[in] node Node to test. + * @return 1 if node is considered empty otherwise 0. */ static ly_bool -trp_ext_is_present_in_node(struct trt_tree_ctx *tc) +pt_node_is_empty(const struct pt_node *node) { - if (tc->lysc_tree && trp_ext_is_present(tc->lysc_tree, tc->cn)) { - return 1; - } else if (trp_ext_is_present(tc->lysc_tree, tc->pn)) { - return 1; - } + const ly_bool a = PT_EMPTY_IFFEATURES_IS_EMPTY(node->iffeatures.type); + const ly_bool b = PT_LF_TYPE_IS_EMPTY(node->type); + const ly_bool c = PT_NODE_NAME_IS_EMPTY(node->name); + const ly_bool d = node->flags == NULL; + const ly_bool e = node->status == NULL; - return 0; + return a && b && c && d && e; } /** - * @brief Release allocated memory and set pointers to NULL. - * - * @param[in,out] overr is override structure to release. - * @param[out] filtered is flag to reset. + * @brief Check if [\], \ and + * \ are empty/not_set. + * @param[in] node Node to test. + * @return 1 if node has no \ \ or \ + * otherwise 0. */ -static void -trp_ext_free_node_override(struct lyplg_ext_sprinter_tree_node_override *overr, ly_bool *filtered) +static ly_bool +pt_node_body_is_empty(const struct pt_node *node) { - *filtered = 0; - overr->flags = NULL; - overr->add_opts = NULL; + const ly_bool a = PT_EMPTY_IFFEATURES_IS_EMPTY(node->iffeatures.type); + const ly_bool b = PT_LF_TYPE_IS_EMPTY(node->type); + const ly_bool c = !node->name.keys; + + return a && b && c; } /** - * @brief Release private plugin data. - * - * @param[in,out] plug_ctx is plugin context. + * @brief Print entire struct pt_node_name structure. + * @param[in] node_name Node name to print. + * @param[in,out] out Output handler. */ static void -trp_ext_free_plugin_ctx(struct lyspr_tree_ctx *plug_ctx) +pt_print_node_name(struct pt_node_name node_name, struct ly_out *out) { - LY_ARRAY_FREE(plug_ctx->schemas); - if (plug_ctx->free_plugin_priv) { - plug_ctx->free_plugin_priv(plug_ctx->plugin_priv); + const char *mod_prefix; + const char *colon; + const char pt_node_name_suffix_choice[] = ")"; + const char pt_node_name_suffix_case[] = ")"; + + assert(!PT_NODE_NAME_IS_EMPTY(node_name)); + + if (node_name.module_prefix) { + mod_prefix = node_name.module_prefix; + colon = ":"; + } else { + mod_prefix = ""; + colon = ""; } -} -/********************************************************************** - * trop and troc getters - *********************************************************************/ + switch (node_name.type) { + case PT_NODE_ELSE: + ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str); + break; + case PT_NODE_CASE: + ly_print_(out, "%s%s%s%s%s", PT_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, pt_node_name_suffix_case); + break; + case PT_NODE_CHOICE: + ly_print_(out, "%s%s%s%s%s", PT_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, pt_node_name_suffix_choice); + break; + case PT_NODE_TRIPLE_DOT: + ly_print_(out, "%s", PT_NODE_NAME_TRIPLE_DOT); + break; + default: + break; + } -/** - * @brief Get nodetype. - * @param[in] node is any lysp_node. - */ -static uint16_t -trop_nodetype(const void *node) -{ - return ((const struct lysp_node *)node)->nodetype; + if (node_name.opts) { + ly_print_(out, "%s", node_name.opts); + } } /** - * @brief Get lysp_node flags. - * @param[in] node is any lysp_node. + * @brief Transformation of the Schema nodes flags to + * Tree diagram \. + * @param[in] flags Node's flags obtained from the tree. + * @return Status string. */ -static uint16_t -trop_flags(const void *node) +static char * +pt_flags2status(uint16_t flags) { - return ((const struct lysp_node *)node)->flags; + return flags & LYS_STATUS_OBSLT ? PT_STATUS_OBSOLETE : + flags & LYS_STATUS_DEPRC ? PT_STATUS_DEPRECATED : + PT_STATUS_CURRENT; } /** - * @brief Get sibling. - * @param[in] node is any lysp_node. + * @brief Transformation of the Schema nodes flags to Tree diagram + * \ but more specifically 'ro' or 'rw'. + * @param[in] flags Node's flags obtained from the tree. + * @return Flags string. */ -static const void * -trop_next(const void *node) +static char * +pt_flags2config(uint16_t flags) { - return ((const struct lysp_node *)node)->next; + return flags & LYS_CONFIG_R ? PT_FLAGS_TYPE_RO : + flags & LYS_CONFIG_W ? PT_FLAGS_TYPE_RW : + PT_FLAGS_TYPE_EMPTY; } /** - * @brief Get parent. - * @param[in] node is any lysp_node. + * @brief Print current list's keys. + * @param[in] tc Tree context. */ -static const void * -trop_parent(const void *node) +static void +pt_print_keys(const struct pt_tree_ctx *tc) { - return ((const struct lysp_node *)node)->parent; -} + const struct lysp_node_list *list; -/** - * @brief Try to get child. - * @param[in] node is any lysp_node. - */ -static const void * -trop_child(const void *node) -{ - return lysp_node_child(node); -} + if (tc->lysc_tree) { + assert(PT_TREE_CTX_LYSP_NODE_PRESENT(tc->cn)); + list = (const struct lysp_node_list *)PT_TREE_CTX_GET_LYSP_NODE(tc->cn); + } else { + list = (const struct lysp_node_list *)tc->pn; + } + assert(list->nodetype & LYS_LIST); -/** - * @brief Try to get action. - * @param[in] node is any lysp_node. - */ -static const void * -trop_actions(const void *node) -{ - return lysp_node_actions(node); + if (pt_charptr_has_data(list->key)) { + ly_print_(tc->out, "%s", list->key); + } } /** - * @brief Try to get action. - * @param[in] node must be of type lysp_node_action. + * @brief Print opts keys. + * @param[in] node_name Contains type of the node with his name. + * @param[in] btw_name_opts Number of spaces between name and [keys]. + * @param[in] tc Tree context. */ -static const void * -trop_action_input(const void *node) +static void +pt_print_opts_keys(struct pt_node_name node_name, int16_t btw_name_opts, + struct pt_tree_ctx *tc) { - return &((const struct lysp_node_action *)node)->input; + if (!node_name.keys) { + return; + } + + /* ___*/ + if (btw_name_opts > 0) { + ly_print_(tc->out, "%*c", btw_name_opts, ' '); + } + ly_print_(tc->out, "["); + pt_print_keys(tc); + ly_print_(tc->out, "]"); } /** - * @brief Try to get action. - * @param[in] node must be of type lysp_node_action. + * @brief Print entire struct pt_type structure. + * @param[in] type Item to print. + * @param[in,out] out Output handler. */ -static const void * -trop_action_output(const void *node) +static void +pt_print_type(struct pt_lf_type type, struct ly_out *out) { - return &((const struct lysp_node_action *)node)->output; + if (PT_LF_TYPE_IS_EMPTY(type)) { + return; + } + + switch (type.type) { + case PT_TYPE_NAME: + ly_print_(out, "%s", type.str); + break; + case PT_TYPE_TARGET: + ly_print_(out, "-> %s", type.str); + break; + case PT_TYPE_LEAFREF: + ly_print_(out, "leafref"); + default: + break; + } } /** - * @brief Try to get action. - * @param[in] node is any lysp_node. + * @brief Print current node's iffeatures. + * @param[in] tc Tree context. */ -static const void * -trop_notifs(const void *node) +static void +pt_print_features_names(const struct pt_tree_ctx *tc) { - return lysp_node_notifs(node); + const struct lysp_qname *iffs; + + if (tc->lysc_tree) { + assert(PT_TREE_CTX_LYSP_NODE_PRESENT(tc->cn)); + iffs = PT_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures; + } else { + iffs = tc->pn->iffeatures; + } + LY_ARRAY_COUNT_TYPE i; + + LY_ARRAY_FOR(iffs, i) { + if (i == 0) { + ly_print_(tc->out, "%s", iffs[i].str); + } else { + ly_print_(tc->out, ",%s", iffs[i].str); + } + } + } /** - * @brief Fill struct tro_getters with @ref TRP_trop getters - * which are adapted to lysp nodes. + * @brief Print all iffeatures of node + * @param[in] iff Iffeatures to print. + * @param[in] tc Tree context. */ -static struct tro_getters -trop_init_getters(void) +static void +pt_print_iffeatures(struct pt_iffeatures iff, struct pt_tree_ctx *tc) { - return (struct tro_getters) { - .nodetype = trop_nodetype, - .lysp_flags = trop_flags, - .next = trop_next, - .parent = trop_parent, - .child = trop_child, - .actions = trop_actions, - .action_input = trop_action_input, - .action_output = trop_action_output, - .notifs = trop_notifs - }; + if (iff.type == PT_IFF_PRESENT) { + ly_print_(tc->out, "{"); + pt_print_features_names(tc); + ly_print_(tc->out, "}?"); + } } /** - * @brief Get nodetype. - * @param[in] node is any lysc_node. + * @brief Print just \--\ \ with opts mark. + * @param[in] node Node name to print. + * @param[in] out Output handler. */ -static uint16_t -troc_nodetype(const void *node) +static void +pt_print_node_up_to_name(const struct pt_node *node, struct ly_out *out) { - return ((const struct lysc_node *)node)->nodetype; + if (node->name.type == PT_NODE_TRIPLE_DOT) { + pt_print_node_name(node->name, out); + return; + } + /* -- */ + ly_print_(out, "%s", node->status); + ly_print_(out, "--"); + /* If the node is a case node, there is no space before the + * also case node has no flags. + */ + if (node->flags && (node->name.type != PT_NODE_CASE)) { + ly_print_(out, "%s", node->flags); + ly_print_(out, " "); + } + /* */ + pt_print_node_name(node->name, out); } /** - * @brief Get lysp_node flags. - * @param[in] node is any lysc_node. + * @brief Print alignment (spaces) instead of + * \--\ \ for divided node. + * @param[in] node Node to print. + * @param[in] out Output handler. */ -static uint16_t -troc_lysp_flags(const void *node) +static void +pt_print_divided_node_up_to_name(const struct pt_node *node, struct ly_out *out) { - const struct lysc_node *cn; + uint32_t space = strlen(node->flags); - cn = (const struct lysc_node *)node; - if (TRP_TREE_CTX_LYSP_NODE_PRESENT(cn)) { - return TRP_TREE_CTX_GET_LYSP_NODE(cn)->flags; + if (node->name.type == PT_NODE_CASE) { + /* :( */ + space += strlen(PT_NODE_NAME_PREFIX_CASE); + } else if (node->name.type == PT_NODE_CHOICE) { + /* ( */ + space += strlen(PT_NODE_NAME_PREFIX_CHOICE); } else { - return 0; + /* _ */ + space += strlen(" "); } -} -/** - * @brief Get sibling. - * @param[in] node is any lysc_node. - */ -static const void * -troc_next(const void *node) -{ - return ((const struct lysc_node *)node)->next; -} + /* + * __ + */ + space += PT_INDENT_LONG_LINE_BREAK; -/** - * @brief Get parent. - * @param[in] node is any lysc_node. - */ -static const void * -troc_parent(const void *node) -{ - return ((const struct lysc_node *)node)->parent; + ly_print_(out, "%*c", space, ' '); } /** - * @brief Try to get child. - * @param[in] node is any lysc_node. + * @brief Print struct pt_node structure. + * @param[in] node Node to print. + * @param[in] tc Tree context. + * @param[in] indent Indent in node. */ -static const void * -troc_child(const void *node) +static void +pt_print_node(const struct pt_node *node, struct pt_tree_ctx *tc, + struct pt_indent_in_node indent) { - return lysc_node_child(node); -} + ly_bool triple_dot; + ly_bool divided; -/** - * @brief Try to get action. - * @param[in] node is any lysc_node. - */ -static const void * -troc_actions(const void *node) + assert(!pt_node_is_empty(node)); + + /* -- */ + triple_dot = node->name.type == PT_NODE_TRIPLE_DOT; + divided = indent.type == PT_INDENT_IN_NODE_DIVIDED; + + if (triple_dot) { + pt_print_node_name(node->name, tc->out); + return; + } else if (!divided) { + pt_print_node_up_to_name(node, tc->out); + } else { + pt_print_divided_node_up_to_name(node, tc->out); + } + + /* */ + /* ___*/ + pt_print_opts_keys(node->name, indent.btw_name_opts, tc); + + /* __ */ + if (indent.btw_opts_type > 0) { + ly_print_(tc->out, "%*c", indent.btw_opts_type, ' '); + } + + /* */ + pt_print_type(node->type, tc->out); + + /* __ */ + if (indent.btw_type_iffeatures > 0) { + ly_print_(tc->out, "%*c", indent.btw_type_iffeatures, ' '); + } + + /* */ + pt_print_iffeatures(node->iffeatures, tc); +} + +/** + * @brief Printing one line including wrapper and node + * which can be incomplete (divided). + * @param[in] node Node to process. + * @param[in] tc Tree context. + * @param[in] indent Contains wrapper and indent in node numbers. + */ +static void +pt_print_line(const struct pt_node *node, struct pt_tree_ctx *tc, + struct pt_indent indent) { - return lysc_node_actions(node); + pt_print_wrapper(indent.wrapper, tc->out); + pt_print_node(node, tc, indent.in_node); } /** - * @brief Try to get action. - * @param[in] node must be of type lysc_node_action. + * @brief Printing one line including wrapper and + * \--\ \\. + * @param[in] node Node to process. + * @param[in] wr Wrapper for printing indentation before node. + * @param[in] out Output handler. */ -static const void * -troc_action_input(const void *node) +static void +pt_print_line_up_to_node_name(const struct pt_node *node, struct pt_wrapper wr, struct ly_out *out) { - return &((const struct lysc_node_action *)node)->input; + pt_print_wrapper(wr, out); + pt_print_node_up_to_name(node, out); } /** - * @brief Try to get action. - * @param[in] node must be of type lysc_node_action. + * @brief Check that indent in node can be considered as equivalent. + * @param[in] first First indent in node. + * @param[in] second Second indent in node. + * @return 1 if indents are equivalent otherwise 0. */ -static const void * -troc_action_output(const void *node) +static ly_bool +pt_indent_in_node_are_eq(struct pt_indent_in_node first, struct pt_indent_in_node second) { - return &((const struct lysc_node_action *)node)->output; + const ly_bool a = first.type == second.type; + const ly_bool b = first.btw_name_opts == second.btw_name_opts; + const ly_bool c = first.btw_opts_type == second.btw_opts_type; + const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures; + + return a && b && c && d; } /** - * @brief Try to get action. - * @param[in] node is any lysc_node. + * @brief Auxiliary function for ::pt_print_entire_node() + * that prints split nodes. + * @param[in] node_p Node representation. + * @param[in] tc Tree context. + * @param[in] indent_p Contains wrapper and indent in node numbers. */ -static const void * -troc_notifs(const void *node) +static void +pt_print_divided_node(const struct pt_node *node_p, struct pt_tree_ctx *tc, + struct pt_indent indent_p) { - return lysc_node_notifs(node); + struct pt_node node; + struct pt_indent indent; + ly_bool entire_node_was_printed; + + indent = indent_p; + node = *node_p; + pt_try_normal_indent_in_node(&node, tc, &indent); + + if (indent.in_node.type == PT_INDENT_IN_NODE_FAILED) { + /* nothing can be done, continue as usual */ + indent.in_node.type = PT_INDENT_IN_NODE_DIVIDED; + } + + pt_print_line(&node, tc, PT_INIT_INDENT(indent_p.wrapper, indent.in_node)); + entire_node_was_printed = pt_indent_in_node_are_eq(indent_p.in_node, indent.in_node); + + if (!entire_node_was_printed) { + ly_print_(tc->out, "\n"); + /* continue with second half node */ + node = *node_p; + pt_second_half_node(&indent.in_node, &node); + /* continue with printing node */ + pt_print_divided_node(&node, tc, PT_INIT_INDENT(indent.wrapper, indent.in_node)); + } else { + return; + } } /** - * @brief Fill struct tro_getters with @ref TRP_troc getters - * which are adapted to lysc nodes. + * @brief Printing of the wrapper and the whole node, + * which can be divided into several lines. + * @param[in] node_p Node to print. + * @param[in] tc Tree context. + * @param[in] indent_p Contains wrapper and indent in node numbers. */ -static struct tro_getters -troc_init_getters(void) +static void +pt_print_entire_node_(const struct pt_node *node_p, struct pt_tree_ctx *tc, + struct pt_indent indent_p) { - return (struct tro_getters) { - .nodetype = troc_nodetype, - .lysp_flags = troc_lysp_flags, - .next = troc_next, - .parent = troc_parent, - .child = troc_child, - .actions = troc_actions, - .action_input = troc_action_input, - .action_output = troc_action_output, - .notifs = troc_notifs - }; + struct pt_wrapper wr; + struct pt_node node_try; + struct pt_indent indent_try; + struct pt_indent indent_merge; + + /* check if normal indent is possible */ + indent_try = indent_p; + node_try = *node_p; + pt_try_normal_indent_in_node(&node_try, tc, &indent_try); + + if (indent_try.in_node.type == PT_INDENT_IN_NODE_NORMAL) { + /* node fits to one line */ + pt_print_line(node_p, tc, indent_p); + } else if (indent_try.in_node.type == PT_INDENT_IN_NODE_DIVIDED) { + /* node will be divided */ + /* print first half */ + indent_merge = PT_INIT_INDENT(indent_p.wrapper, indent_try.in_node); + /* pretend that this is normal node */ + indent_merge.in_node.type = PT_INDENT_IN_NODE_NORMAL; + + pt_print_line(&node_try, tc, indent_merge); + ly_print_(tc->out, "\n"); + + /* continue with second half on new line */ + node_try = *node_p; + pt_second_half_node(&indent_try.in_node, &node_try); + wr = pt_wrapper_if_last_sibling(indent_p.wrapper, node_try.last_one); + indent_merge = PT_INIT_INDENT(wr, indent_try.in_node); + + pt_print_divided_node(&node_try, tc, indent_merge); + } else if (indent_try.in_node.type == PT_INDENT_IN_NODE_FAILED) { + /* node name is too long */ + pt_print_line_up_to_node_name(node_p, indent_p.wrapper, tc->out); + + if (pt_node_body_is_empty(node_p)) { + return; + } + ly_print_(tc->out, "\n"); + + node_try = *node_p; + pt_second_half_node(&indent_try.in_node, &node_try); + indent_try.in_node.type = PT_INDENT_IN_NODE_DIVIDED; + wr = pt_wrapper_if_last_sibling(indent_p.wrapper, node_try.last_one); + indent_merge = PT_INIT_INDENT(wr, indent_try.in_node); + + pt_print_divided_node(&node_try, tc, indent_merge); + } } -/********************************************************************** - * tro functions - *********************************************************************/ +/** + * @brief Check if leafref target must be change to string 'leafref' + * because his target string is too long. + * @param[in] node Containing leafref target. + * @param[in] wr Wrapper for printing indentation before node. + * @param[in] mll Max line length. + * @param[in] out Output handler. + * @return true if leafref must be changed to string 'leafref'. + */ +static ly_bool +pt_leafref_target_is_too_long(const struct pt_node *node, struct pt_wrapper wr, + size_t mll, struct ly_out *out) +{ + size_t type_len; + struct ly_out_clb_arg *data; + + if (node->type.type != PT_TYPE_TARGET) { + return 0; + } + + /* set ly_out to counting characters */ + data = out->method.clb.arg; + + data->counter = 0; + data->mode = PT_CHAR_COUNT; + /* count number of printed bytes */ + pt_print_wrapper(wr, out); + ly_print_(out, "%*c", PT_INDENT_BTW_SIBLINGS, ' '); + pt_print_divided_node_up_to_name(node, out); + data->mode = PT_PRINT; + type_len = strlen(node->type.str); + + return data->counter + type_len > mll; +} /** - * @brief Call override function for @p node. + * @brief Print node. * - * @param[in] lysc_tree if @p node is compiled. - * @param[in] node to create override. - * @param[in] erase_node_overr if override structure must be reseted. - * @param[in,out] plc current plugin context. - * @return pointer to override structure or NULL. Override structure in @p plc is updated too. - */ -static struct lyplg_ext_sprinter_tree_node_override * -tro_set_node_overr(ly_bool lysc_tree, const void *node, ly_bool erase_node_overr, struct trt_plugin_ctx *plc) + * This function is wrapper for ::pt_print_entire_node(). + * But difference is that take @p max_gap_before_type which will be + * used to set the unified alignment. + * + * @param[in] node Node to print. + * @param[in] max_gap_before_type Number of indent before \. + * @param[in] wr Wrapper for printing indentation before node. + * @param[in] tc Tree context. + */ +static void +pt_print_entire_node(struct pt_node node, uint32_t max_gap_before_type, struct pt_wrapper wr, + struct pt_tree_ctx *tc) { - LY_ERR rc = LY_SUCCESS; - struct lyplg_ext_sprinter_tree_node_override *no; - struct lyspr_tree_ctx *plug_ctx; - struct lysc_ext_instance *ce; - struct lysp_ext_instance *pe; + struct pt_indent_in_node indent = pt_default_indent_in_node(&node); - if (erase_node_overr) { - trp_ext_free_node_override(&plc->node_overr, &plc->filtered); - } - no = &plc->node_overr; - if (!plc->ctx && lysc_tree && (ce = trp_ext_is_present(lysc_tree, node))) { - rc = LYSC_GET_EXT_PLG(ce->def->plugin_ref)->printer_ctree(ce, NULL, &no->flags, &no->add_opts); - } else if (!plc->ctx && (pe = trp_ext_is_present(lysc_tree, node))) { - rc = LYSC_GET_EXT_PLG(pe->plugin_ref)->printer_ptree(pe, NULL, &no->flags, &no->add_opts); - } else if (plc->ctx) { - if (plc->schema && plc->schema->compiled && plc->schema->cn_overr) { - rc = plc->schema->cn_overr(node, plc->ctx->plugin_priv, &plc->filtered, &no->flags, &no->add_opts); - } else if (plc->schema && plc->schema->pn_overr) { - rc = plc->schema->pn_overr(node, plc->ctx->plugin_priv, &plc->filtered, &no->flags, &no->add_opts); - } else { - no = NULL; - } - if (trp_ext_is_present(lysc_tree, node)) { - plug_ctx = plc->ctx; - plc->ctx = NULL; - tro_set_node_overr(lysc_tree, node, 0, plc); - plc->ctx = plug_ctx; - } + if ((max_gap_before_type > 0) && (node.type.type != PT_TYPE_EMPTY)) { + /* print actual node with unified indent */ + indent.btw_opts_type = pt_calc_btw_opts_type(&node, max_gap_before_type); + } + if (pt_leafref_target_is_too_long(&node, wr, tc->max_line_length, tc->out)) { + node.type.type = PT_TYPE_LEAFREF; + } + /* after -> print actual node with default indent */ + pt_print_entire_node_(&node, tc, PT_INIT_INDENT(wr, indent)); +} + +/** + * @brief Create implicit "case" node as parent of @p node. + * @param[in] node Child of implicit case node. + * @param[out] case_node Created case node. + */ +static void +pt_create_implicit_case_node(const struct pt_node *node, struct pt_node *case_node) +{ + case_node->status = node->status; + case_node->flags = PT_FLAGS_TYPE_EMPTY; + case_node->name.type = PT_NODE_CASE; + case_node->name.keys = node->name.keys; + case_node->name.module_prefix = node->name.module_prefix; + case_node->name.str = node->name.str; + case_node->name.opts = node->name.opts; + case_node->type = PT_EMPTY_LF_TYPE; + case_node->iffeatures = PT_EMPTY_IFFEATURES; + case_node->last_one = node->last_one; +} + +static const void *pt_next_sibling(const void *node, struct pt_tree_ctx *tc, ly_bool update); + +/** + * @brief Print implicit case node and his subtree. + * @param[in] node Child of implicit case. + * @param[in] wr Wrapper for printing indentation before node. + * @param[in] tc Tree context. Its settings should be the same as + * before the function call. + * @return new indentation wrapper for @p node. + */ +static struct pt_wrapper +pt_print_implicit_node(const struct pt_node *node, struct pt_wrapper wr, + struct pt_tree_ctx *tc) +{ + const void *sibl; + struct pt_node case_node; + struct pt_wrapper wr_case_child; + + pt_create_implicit_case_node(node, &case_node); + ly_print_(tc->out, "\n"); + pt_print_entire_node(case_node, 0, wr, tc); + ly_print_(tc->out, "\n"); + sibl = tc->lysc_tree ? pt_next_sibling(tc->cn, tc, 0) : pt_next_sibling(tc->pn, tc, 0); + wr_case_child = sibl ? + pt_wrapper_set_mark(wr) : pt_wrapper_set_shift(wr); + return wr_case_child; +} + +/** + * @brief Check if there is no case statement under the choice statement. + * + * It can return true only if the Parsed schema tree + * is used for browsing. + * + * @param[in] tc Tree context. + * @return 1 if implicit case statement is present otherwise 0. + */ +static ly_bool +pt_need_implicit_node_case(struct pt_tree_ctx *tc) +{ + return !tc->lysc_tree && tc->pn->parent && + (tc->pn->parent->nodetype & LYS_CHOICE) && + (tc->pn->nodetype & (LYS_ANYDATA | LYS_CHOICE | LYS_CONTAINER | + LYS_LEAF | LYS_LEAFLIST)); +} + +/********************************************************************** + * Primitive getters + *********************************************************************/ + +static const void * +pt_get_node(const struct pt_tree_ctx *tc) +{ + return tc->lysc_tree ? + (const void *)tc->cn : + (const void *)tc->pn; +} + +static const void * +pt_get_child(const struct pt_tree_ctx *tc) +{ + if (!pt_get_node(tc)) { + return NULL; + } + + if (tc->lysc_tree) { + return lysc_node_child(tc->cn); } else { - no = NULL; + return lysp_node_child(tc->pn); } +} - if (rc) { - plc->last_error = rc; - no = NULL; +static uint16_t +pt_nodetype(const struct pt_tree_ctx *tc, const void *node) +{ + return tc->lysc_tree ? + ((const struct lysc_node *)node)->nodetype : + ((const struct lysp_node *)node)->nodetype; +} + +static uint16_t +pt_lysp_flags(const struct pt_tree_ctx *tc, const void *node) +{ + const struct lysc_node *cn; + + if (!tc->lysc_tree) { + return ((const struct lysp_node *)node)->flags; } - return no; + cn = (const struct lysc_node *)node; + if (PT_TREE_CTX_LYSP_NODE_PRESENT(cn)) { + return PT_TREE_CTX_GET_LYSP_NODE(cn)->flags; + } else { + return 0; + } +} + +static const void * +pt_next(const struct pt_tree_ctx *tc, const void *node) +{ + return tc->lysc_tree ? + (const void *)((const struct lysc_node *)node)->next : + (const void *)((const struct lysp_node *)node)->next; +} + +static const void * +pt_parent(const struct pt_tree_ctx *tc, const void *node) +{ + return tc->lysc_tree ? + (const void *)((const struct lysc_node *)node)->parent : + (const void *)((const struct lysp_node *)node)->parent; +} + +static const void * +pt_child(const struct pt_tree_ctx *tc, const void *node) +{ + return tc->lysc_tree ? + (const void *)lysc_node_child(node) : + (const void *)lysp_node_child(node); +} + +static const void * +pt_actions(const struct pt_tree_ctx *tc, const void *node) +{ + return tc->lysc_tree ? + (const void *)lysc_node_actions(node) : + (const void *)lysp_node_actions(node); +} + +static const void * +pt_action_input(const struct pt_tree_ctx *tc, const void *node) +{ + return tc->lysc_tree ? + (const void *)&((const struct lysc_node_action *)node)->input : + (const void *)&((const struct lysp_node_action *)node)->input; +} + +static const void * +pt_action_output(const struct pt_tree_ctx *tc, const void *node) +{ + return tc->lysc_tree ? + (const void *)&((const struct lysc_node_action *)node)->output : + (const void *)&((const struct lysp_node_action *)node)->output; +} + +static const void * +pt_notifs(const struct pt_tree_ctx *tc, const void *node) +{ + return tc->lysc_tree ? + (const void *)lysc_node_notifs(node) : + (const void *)lysp_node_notifs(node); +} + +/********************************************************************** + * Read functions. + *********************************************************************/ + +static ly_bool pt_schema_mount_skip(const struct lysc_node *node, const struct ly_set *refs); + +/** + * @brief Determine whether the node should be ignored and not printed. + * @param[in] node Node to test. + * @param[in] tc Current tree context. + * @return 1 if node should be ignored otherwise 0. + */ +static ly_bool +pt_ignore_node(const void *node, const struct pt_tree_ctx *tc) +{ + struct pt_extension plugin_ctx; + + plugin_ctx = tc->plugin_ctx; + + if (node && plugin_ctx.schema_mount && (plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF) && + pt_schema_mount_skip(node, plugin_ctx.schema_mount->parent_refs)) { + return 1; + } else if (node && (pt_lysp_flags(tc, node) & LYS_INTERNAL)) { + return 1; + } else { + return 0; + } } +static void pt_ext_set_next_schema_mount(struct pt_tree_ctx *tc); + /** * @brief Get next sibling of the current node. * * This is a general algorithm that is able to * work with lysp_node or lysc_node. * - * @param[in] node points to lysp_node or lysc_node. - * @param[in] tc current tree context. + * @param[in] node Node lysp_node or lysc_node. + * @param[in] tc Current tree context. + * @param[in] update Set to 1 if the transition to siblings should be + * reflected directly in @p tc. Parameter originally added for schema-mount. * @return next sibling node. */ static const void * -tro_next_sibling(const void *node, const struct trt_tree_ctx *tc) +pt_next_sibling(const void *node, struct pt_tree_ctx *tc, ly_bool update) { - struct tro_getters get; - struct trt_plugin_ctx plugin_ctx; const void *tmp, *parent, *sibl; + struct pt_tree_ctx tc_copy; assert(node); - get = tc->lysc_tree ? troc_init_getters() : trop_init_getters(); - - if (get.nodetype(node) & (LYS_RPC | LYS_ACTION)) { - if ((tmp = get.next(node))) { + if (pt_nodetype(tc, node) & (LYS_RPC | LYS_ACTION)) { + if ((tmp = pt_next(tc, node))) { /* next action exists */ sibl = tmp; - } else if ((parent = get.parent(node))) { + } else if ((parent = pt_parent(tc, node))) { /* maybe if notif exists as sibling */ - sibl = get.notifs(parent); + sibl = pt_notifs(tc, parent); } else { sibl = NULL; } - } else if (get.nodetype(node) & LYS_INPUT) { - if ((parent = get.parent(node))) { + } else if (pt_nodetype(tc, node) & LYS_INPUT) { + if ((parent = pt_parent(tc, node))) { /* if output action has data */ - if (get.child(get.action_output(parent))) { + if (pt_child(tc, pt_action_output(tc, parent))) { /* then next sibling is output action */ - sibl = get.action_output(parent); + sibl = pt_action_output(tc, parent); } else { /* input action cannot have siblings other * than output action. @@ -2269,25 +1996,25 @@ tro_next_sibling(const void *node, const struct trt_tree_ctx *tc) /* there is no way how to get output action */ sibl = NULL; } - } else if (get.nodetype(node) & LYS_OUTPUT) { + } else if (pt_nodetype(tc, node) & LYS_OUTPUT) { /* output action cannot have siblings */ sibl = NULL; - } else if (get.nodetype(node) & LYS_NOTIF) { + } else if (pt_nodetype(tc, node) & LYS_NOTIF) { /* must have as a sibling only notif */ - sibl = get.next(node); + sibl = pt_next(tc, node); } else { /* for rest of nodes */ - if ((tmp = get.next(node))) { + if ((tmp = pt_next(tc, node))) { /* some sibling exists */ sibl = tmp; - } else if ((parent = get.parent(node))) { + } else if ((parent = pt_parent(tc, node))) { /* Action and notif are siblings too. * They can be reached through parent. */ - if ((tmp = get.actions(parent))) { + if ((tmp = pt_actions(tc, parent))) { /* next sibling is action */ sibl = tmp; - } else if ((tmp = get.notifs(parent))) { + } else if ((tmp = pt_notifs(tc, parent))) { /* next sibling is notif */ sibl = tmp; } else { @@ -2300,57 +2027,74 @@ tro_next_sibling(const void *node, const struct trt_tree_ctx *tc) } } - plugin_ctx = tc->plugin_ctx; - if (sibl && tro_set_node_overr(tc->lysc_tree, sibl, 1, &plugin_ctx) && plugin_ctx.filtered) { - return tro_next_sibling(sibl, tc); - } else if (sibl && (get.lysp_flags(node) & LYS_INTERNAL)) { - return tro_next_sibling(sibl, tc); + if (pt_ignore_node(sibl, tc)) { + return pt_next_sibling(sibl, tc, update); } - return sibl; -} - -/** + if (!sibl && !pt_parent(tc, node) && tc->plugin_ctx.schema_mount && + !PT_LAST_SCHEMA_MOUNT(tc->plugin_ctx)) { + tc_copy = *tc; + pt_ext_set_next_schema_mount(tc); + if (tc->lysc_tree) { + sibl = (const void *)tc->plugin_ctx.schema->ctree; + } else { + sibl = (const void *)tc->plugin_ctx.schema->ptree; + } + if (pt_ignore_node(sibl, tc)) { + sibl = pt_next_sibling(sibl, tc, update); + } + if (!update) { + *tc = tc_copy; + } + } + + return sibl; +} + +/** * @brief Get child of the current node. * * This is a general algorithm that is able to * work with lysp_node or lysc_node. * - * @param[in] node points to lysp_node or lysc_node. - * @param[in] tc current tree context. + * @param[in] node Node lysp_node or lysc_node. + * @param[in] tc Current tree context. + * @param[in] update Set to 1 if the transition to child should be + * reflected directly in @p tc. Parameter originally added for schema-mount. * @return child node. */ static const void * -tro_next_child(const void *node, const struct trt_tree_ctx *tc) +pt_next_child(const void *node, struct pt_tree_ctx *tc, ly_bool update) { - struct tro_getters get; - struct trt_plugin_ctx plugin_ctx; const void *tmp, *child; assert(node); - get = tc->lysc_tree ? troc_init_getters() : trop_init_getters(); - - if (get.nodetype(node) & (LYS_ACTION | LYS_RPC)) { - if (get.child(get.action_input(node))) { + if (tc->plugin_ctx.schema_mount && (tc->plugin_ctx.schema_mount->mount_point == node)) { + child = tc->plugin_ctx.schema_mount->schemas->ctree; + if (update) { + tc->plugin_ctx.schema = tc->plugin_ctx.schema_mount->schemas; + } + } else if (pt_nodetype(tc, node) & (LYS_ACTION | LYS_RPC)) { + if (pt_child(tc, pt_action_input(tc, node))) { /* go to LYS_INPUT */ - child = get.action_input(node); - } else if (get.child(get.action_output(node))) { + child = pt_action_input(tc, node); + } else if (pt_child(tc, pt_action_output(tc, node))) { /* go to LYS_OUTPUT */ - child = get.action_output(node); + child = pt_action_output(tc, node); } else { /* input action and output action have no data */ child = NULL; } } else { - if ((tmp = get.child(node))) { + if ((tmp = pt_child(tc, node))) { child = tmp; } else { /* current node can't have children or has no children */ /* but maybe has some actions or notifs */ - if ((tmp = get.actions(node))) { + if ((tmp = pt_actions(tc, node))) { child = tmp; - } else if ((tmp = get.notifs(node))) { + } else if ((tmp = pt_notifs(tc, node))) { child = tmp; } else { child = NULL; @@ -2358,35 +2102,62 @@ tro_next_child(const void *node, const struct trt_tree_ctx *tc) } } - plugin_ctx = tc->plugin_ctx; - if (child && tro_set_node_overr(tc->lysc_tree, child, 1, &plugin_ctx) && plugin_ctx.filtered) { - return tro_next_sibling(child, tc); - } else if (child && (get.lysp_flags(node) & LYS_INTERNAL)) { - return tro_next_sibling(child, tc); + if (pt_ignore_node(child, tc)) { + return pt_next_sibling(child, tc, update); } return child; } /** - * @brief Get new trt_parent_cache if we apply the transfer + * @brief Check if parent of the current node is the last + * of his siblings. + * + * To maintain stability use this function only if the current node is + * the first of the siblings. + * Side-effect -> current node is set to the first sibling + * if node has a parent otherwise no side-effect. + * + * @param[in,out] tc Tree context. + * @return 1 if parent is last sibling otherwise 0. + */ +static ly_bool +pt_node_is_last_sibling(struct pt_tree_ctx *tc) +{ + const void *sibl; + const void *parent; + + sibl = tc->lysc_tree ? pt_next_sibling(tc->cn, tc, 0) : pt_next_sibling(tc->pn, tc, 0); + parent = tc->lysc_tree ? pt_parent(tc, tc->cn) : pt_parent(tc, tc->pn); + + if (parent) { + return !sibl; + } else if (tc->plugin_ctx.schema_mount) { + return !sibl && !tc->plugin_ctx.schema_mount->mp_has_normal_node; + } else { + return !sibl && PT_LAST_SCHEMA(tc->plugin_ctx); + } +} + +/** + * @brief Get new pt_parent_cache if we apply the transfer * to the child node in the tree. - * @param[in] ca is parent cache for current node. - * @param[in] tc contains current tree node. + * @param[in] ca Parent cache for current node. + * @param[in] tc Contains current tree node. * @return Cache for the current node. */ -static struct trt_parent_cache -tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx *tc) +static struct pt_parent_cache +pt_parent_cache_for_child(struct pt_parent_cache ca, const struct pt_tree_ctx *tc) { - struct trt_parent_cache ret = TRP_EMPTY_PARENT_CACHE; + struct pt_parent_cache ret = PT_EMPTY_PARENT_CACHE; if (!tc->lysc_tree) { const struct lysp_node *pn = tc->pn; ret.ancestor = - pn->nodetype & (LYS_INPUT) ? TRD_ANCESTOR_RPC_INPUT : - pn->nodetype & (LYS_OUTPUT) ? TRD_ANCESTOR_RPC_OUTPUT : - pn->nodetype & (LYS_NOTIF) ? TRD_ANCESTOR_NOTIF : + pn->nodetype & (LYS_INPUT) ? PT_ANCESTOR_RPC_INPUT : + pn->nodetype & (LYS_OUTPUT) ? PT_ANCESTOR_RPC_OUTPUT : + pn->nodetype & (LYS_NOTIF) ? PT_ANCESTOR_NOTIF : ca.ancestor; ret.lys_status = @@ -2394,8 +2165,8 @@ tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx ca.lys_status; ret.lys_config = - ca.ancestor == TRD_ANCESTOR_RPC_INPUT ? 0 : /* because will be -w */ - ca.ancestor == TRD_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R : + ca.ancestor == PT_ANCESTOR_RPC_INPUT ? 0 : /* because will be -w */ + ca.ancestor == PT_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R : pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags : ca.lys_config; @@ -2407,295 +2178,73 @@ tro_parent_cache_for_child(struct trt_parent_cache ca, const struct trt_tree_ctx return ret; } -/** - * @brief Transformation of the Schema nodes flags to - * Tree diagram \. - * @param[in] flags is node's flags obtained from the tree. - */ -static char * -tro_flags2status(uint16_t flags) -{ - return flags & LYS_STATUS_OBSLT ? "o" : - flags & LYS_STATUS_DEPRC ? "x" : - "+"; -} - -/** - * @brief Transformation of the Schema nodes flags to Tree diagram - * \ but more specifically 'ro' or 'rw'. - * @param[in] flags is node's flags obtained from the tree. - */ -static char * -tro_flags2config(uint16_t flags) -{ - return flags & LYS_CONFIG_R ? TRD_FLAGS_TYPE_RO : - flags & LYS_CONFIG_W ? TRD_FLAGS_TYPE_RW : - TRD_FLAGS_TYPE_EMPTY; -} - -/** - * @brief Print current node's iffeatures. - * @param[in] tc is tree context. - * @param[in,out] out is output handler. - */ -static void -tro_print_features_names(const struct trt_tree_ctx *tc, struct ly_out *out) -{ - const struct lysp_qname *iffs; - - if (tc->lysc_tree) { - assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn)); - iffs = TRP_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures; - } else { - iffs = tc->pn->iffeatures; - } - LY_ARRAY_COUNT_TYPE i; - - LY_ARRAY_FOR(iffs, i) { - if (i == 0) { - ly_print_(out, "%s", iffs[i].str); - } else { - ly_print_(out, ",%s", iffs[i].str); - } - } - -} - -/** - * @brief Print current list's keys. - * - * Well, actually printing keys in the lysp_tree is trivial, - * because char* points to all keys. However, special functions have - * been reserved for this, because in principle the list of elements - * can have more implementations. - * - * @param[in] tc is tree context. - * @param[in,out] out is output handler. - */ -static void -tro_print_keys(const struct trt_tree_ctx *tc, struct ly_out *out) -{ - const struct lysp_node_list *list; - - if (tc->lysc_tree) { - assert(TRP_TREE_CTX_LYSP_NODE_PRESENT(tc->cn)); - list = (const struct lysp_node_list *)TRP_TREE_CTX_GET_LYSP_NODE(tc->cn); - } else { - list = (const struct lysp_node_list *)tc->pn; - } - assert(list->nodetype & LYS_LIST); - - if (trg_charptr_has_data(list->key)) { - ly_print_(out, "%s", list->key); - } -} - -/** - * @brief Get address of the current node. - * @param[in] tc contains current node. - * @return Address of lysc_node or lysp_node, or NULL. - */ -static const void * -tro_tree_ctx_get_node(const struct trt_tree_ctx *tc) -{ - return tc->lysc_tree ? - (const void *)tc->cn : - (const void *)tc->pn; -} - -/** - * @brief Get address of current node's child. - * @param[in,out] tc contains current node. - */ -static const void * -tro_tree_ctx_get_child(const struct trt_tree_ctx *tc) -{ - if (!tro_tree_ctx_get_node(tc)) { - return NULL; - } - - if (tc->lysc_tree) { - return lysc_node_child(tc->cn); - } else { - return lysp_node_child(tc->pn); - } -} - -/** - * @brief Get rpcs section if exists. - * @param[in,out] tc is tree context. - * @return Section representation if it exists. The @p tc is modified - * and his pointer points to the first node in rpcs section. - * @return Empty section representation otherwise. - */ -static struct trt_keyword_stmt -tro_modi_get_rpcs(struct trt_tree_ctx *tc) -{ - assert(tc); - const void *actions; - struct trt_keyword_stmt ret = {0}; - - if (tc->lysc_tree) { - actions = tc->cmod->rpcs; - if (actions) { - tc->cn = actions; - } - } else { - actions = tc->pmod->rpcs; - if (actions) { - tc->pn = actions; - tc->tpn = tc->pn; - } - } - - if (actions) { - tc->section = TRD_SECT_RPCS; - ret.section_name = TRD_KEYWORD_RPC; - ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0; - } - - return ret; -} - -/** - * @brief Get notification section if exists - * @param[in,out] tc is tree context. - * @return Section representation if it exists. - * The @p tc is modified and his pointer points to the - * first node in notification section. - * @return Empty section representation otherwise. - */ -static struct trt_keyword_stmt -tro_modi_get_notifications(struct trt_tree_ctx *tc) -{ - assert(tc); - const void *notifs; - struct trt_keyword_stmt ret = {0}; - - if (tc->lysc_tree) { - notifs = tc->cmod->notifs; - if (notifs) { - tc->cn = notifs; - } - } else { - notifs = tc->pmod->notifs; - if (notifs) { - tc->pn = notifs; - tc->tpn = tc->pn; - } - } - - if (notifs) { - tc->section = TRD_SECT_NOTIF; - ret.section_name = TRD_KEYWORD_NOTIF; - ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0; - } - - return ret; -} - -static struct trt_keyword_stmt -tro_get_ext_section(struct trt_tree_ctx *tc, void *ext, struct lyspr_tree_ctx *plug_ctx) -{ - struct trt_keyword_stmt ret = {0}; - struct lysc_ext_instance *ce = NULL; - struct lysp_ext_instance *pe = NULL; - - if (tc->lysc_tree) { - ce = ext; - ret.section_name = ce->def->name; - ret.argument = ce->argument; - ret.has_node = plug_ctx->schemas->ctree ? 1 : 0; - } else { - pe = ext; - ret.section_name = strchr(pe->name, ':') + 1; - ret.argument = pe->argument; - ret.has_node = plug_ctx->schemas->ptree ? 1 : 0; - } - - return ret; -} - /** * @brief Get name of the module. - * @param[in] tc is context of the tree. + * @param[in] tc Context of the tree. + * @return Filled keyword structure. */ -static struct trt_keyword_stmt -tro_read_module_name(const struct trt_tree_ctx *tc) +static struct pt_keyword_stmt +pt_read_module_name(const struct pt_tree_ctx *tc) { assert(tc); - struct trt_keyword_stmt ret; + struct pt_keyword_stmt module = PT_EMPTY_KEYWORD_STMT; - ret.section_name = !tc->lysc_tree && tc->pmod->is_submod ? - TRD_KEYWORD_SUBMODULE : - TRD_KEYWORD_MODULE; + module.section_name = !tc->lysc_tree && tc->pmod->is_submod ? + PT_KEYWORD_SUBMODULE : + PT_KEYWORD_MODULE; - ret.argument = !tc->lysc_tree ? + module.argument = !tc->lysc_tree ? LYSP_MODULE_NAME(tc->pmod) : tc->cmod->mod->name; - ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0; + module.has_node = pt_get_node(tc) ? 1 : 0; - return ret; + return module; } -static ly_bool -tro_read_if_parent_exists(const struct trt_tree_ctx *tc) -{ - const void *parent; +static struct pt_node pt_pnode_read(struct pt_parent_cache ca, struct pt_tree_ctx *tc); - if (tc->lysc_tree) { - parent = troc_parent(tc->cn); - } else { - parent = trop_parent(tc->pn); - } - - return parent ? 1 : 0; -} +static struct pt_node pt_cnode_read(struct pt_tree_ctx *tc); /** - * @brief Create implicit "case" node as parent of @p node. - * @param[in] node child of implicit case node. - * @param[out] case_node created case node. + * @brief Transformation of current lysp_node to struct pt_node. + * @param[in] ca Contains stored important data + * when browsing the tree downwards. + * @param[in] tc Context of the tree. + * @return the read node. */ -static void -tro_create_implicit_case_node(const struct trt_node *node, struct trt_node *case_node) +static struct pt_node +pt_read_node(struct pt_parent_cache ca, struct pt_tree_ctx *tc) { - case_node->status = node->status; - case_node->flags = TRD_FLAGS_TYPE_EMPTY; - case_node->name.type = TRD_NODE_CASE; - case_node->name.keys = node->name.keys; - case_node->name.module_prefix = node->name.module_prefix; - case_node->name.str = node->name.str; - case_node->name.opts = node->name.opts; - case_node->name.add_opts = node->name.add_opts; - case_node->type = TRP_EMPTY_TRT_TYPE; - case_node->iffeatures = TRP_EMPTY_TRT_IFFEATURES; - case_node->last_one = node->last_one; + if (tc->lysc_tree) { + return pt_cnode_read(tc); + } else { + return pt_pnode_read(ca, tc); + } } /********************************************************************** - * Definition of trop reading functions + * Definition of lysp_node reading functions *********************************************************************/ /** * @brief Check if list statement has keys. - * @param[in] pn is pointer to the list. + * @param[in] pn Pointer to the list. * @return 1 if has keys, otherwise 0. */ static ly_bool -trop_list_has_keys(const struct lysp_node *pn) +pt_pnode_list_has_keys(const struct lysp_node *pn) { - return trg_charptr_has_data(((const struct lysp_node_list *)pn)->key); + return pt_charptr_has_data(((const struct lysp_node_list *)pn)->key); } /** * @brief Check if it contains at least one feature. - * @param[in] pn is current node. + * @param[in] pn Current node. * @return 1 if has if-features, otherwise 0. */ static ly_bool -trop_node_has_iffeature(const struct lysp_node *pn) +pt_pnode_has_iffeature(const struct lysp_node *pn) { LY_ARRAY_COUNT_TYPE u; const struct lysp_qname *iffs; @@ -2712,618 +2261,340 @@ trop_node_has_iffeature(const struct lysp_node *pn) /** * @brief Find out if leaf is also the key in last list. - * @param[in] pn is pointer to leaf. - * @param[in] ca_last_list is pointer to last visited list. - * Obtained from trt_parent_cache. + * @param[in] pn Pointer to leaf. + * @param[in] ca_last_list Pointer to last visited list. + * Obtained from pt_parent_cache. * @return 1 if leaf is also the key, otherwise 0. */ static ly_bool -trop_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list) -{ - const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn; - const struct lysp_node_list *list = ca_last_list; - - if (!list) { - return 0; - } - return trg_charptr_has_data(list->key) ? - trg_word_is_present(list->key, leaf->name, ' ') : 0; -} - -/** - * @brief Check if container's type is presence. - * @param[in] pn is pointer to container. - * @return 1 if container has presence statement, otherwise 0. - */ -static ly_bool -trop_container_has_presence(const struct lysp_node *pn) -{ - return trg_charptr_has_data(((struct lysp_node_container *)pn)->presence); -} - -/** - * @brief Get leaflist's path without lysp_node type control. - * @param[in] pn is pointer to the leaflist. - */ -static const char * -trop_leaflist_refpath(const struct lysp_node *pn) -{ - const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn; - - return list->type.path ? list->type.path->expr : NULL; -} - -/** - * @brief Get leaflist's type name without lysp_node type control. - * @param[in] pn is pointer to the leaflist. - */ -static const char * -trop_leaflist_type_name(const struct lysp_node *pn) -{ - const struct lysp_node_leaflist *list = (const struct lysp_node_leaflist *)pn; - - return list->type.name; -} - -/** - * @brief Get leaf's path without lysp_node type control. - * @param[in] pn is pointer to the leaf node. - */ -static const char * -trop_leaf_refpath(const struct lysp_node *pn) -{ - const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn; - - return leaf->type.path ? leaf->type.path->expr : NULL; -} - -/** - * @brief Get leaf's type name without lysp_node type control. - * @param[in] pn is pointer to the leaf's type name. - */ -static const char * -trop_leaf_type_name(const struct lysp_node *pn) +pt_pnode_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list) { const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn; - - return leaf->type.name; -} - -/** - * @brief Get pointer to data using node type specification - * and getter function. - * - * @param[in] flags is node type specification. - * If it is the correct node, the getter function is called. - * @param[in] f is getter function which provides the desired - * char pointer from the structure. - * @param[in] pn pointer to node. - * @return NULL if node has wrong type or getter function return - * pointer to NULL. - * @return Pointer to desired char pointer obtained from the node. - */ -static const char * -trop_node_charptr(uint16_t flags, trt_get_charptr_func f, const struct lysp_node *pn) -{ - if (pn->nodetype & flags) { - const char *ret = f(pn); - - return trg_charptr_has_data(ret) ? ret : NULL; - } else { - return NULL; - } -} - -/** - * @brief Resolve \ of the current node. - * @param[in] nodetype is node's type obtained from the tree. - * @param[in] flags is node's flags obtained from the tree. - * @param[in] ca_lys_status is inherited status obtained from trt_parent_cache. - * @return The status type. - */ -static char * -trop_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status) -{ - if (nodetype & (LYS_INPUT | LYS_OUTPUT)) { - /* LYS_INPUT and LYS_OUTPUT is special case */ - return tro_flags2status(ca_lys_status); - /* if ancestor's status is deprc or obslt - * and also node's status is not set - */ - } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) { - /* get ancestor's status */ - return tro_flags2status(ca_lys_status); - } else { - /* else get node's status */ - return tro_flags2status(flags); - } -} - -/** - * @brief Resolve \ of the current node. - * @param[in] nodetype is node's type obtained from the tree. - * @param[in] flags is node's flags obtained from the tree. - * @param[in] ca_ancestor is ancestor type obtained from trt_parent_cache. - * @param[in] ca_lys_config is inherited config item obtained from trt_parent_cache. - * @param[in] no Override structure for flags. - * @return The flags type. - */ -static const char * -trop_resolve_flags(uint16_t nodetype, uint16_t flags, trt_ancestor_type ca_ancestor, uint16_t ca_lys_config, - struct lyplg_ext_sprinter_tree_node_override *no) -{ - if (no && no->flags) { - return no->flags; - } else if ((nodetype & LYS_INPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_INPUT)) { - return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS; - } else if ((nodetype & LYS_OUTPUT) || (ca_ancestor == TRD_ANCESTOR_RPC_OUTPUT)) { - return TRD_FLAGS_TYPE_RO; - } else if (ca_ancestor == TRD_ANCESTOR_NOTIF) { - return TRD_FLAGS_TYPE_RO; - } else if (nodetype & LYS_NOTIF) { - return TRD_FLAGS_TYPE_NOTIF; - } else if (nodetype & LYS_USES) { - return TRD_FLAGS_TYPE_USES_OF_GROUPING; - } else if (nodetype & (LYS_RPC | LYS_ACTION)) { - return TRD_FLAGS_TYPE_RPC; - } else if (!(flags & (LYS_CONFIG_R | LYS_CONFIG_W))) { - /* config is not set. Look at ancestor's config */ - return tro_flags2config(ca_lys_config); - } else { - return tro_flags2config(flags); - } -} - -/** - * @brief Resolve node type of the current node. - * @param[in] pn is pointer to the current node in the tree. - * @param[in] ca_last_list is pointer to the last visited list. Obtained from the trt_parent_cache. - * @param[out] type Resolved type of node. - * @param[out] opts Resolved opts of node. - */ -static void -trop_resolve_node_opts(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list, trt_node_type *type, - const char **opts) -{ - if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) { - *type = TRD_NODE_ELSE; - } else if (pn->nodetype & LYS_CASE) { - *type = TRD_NODE_CASE; - } else if ((pn->nodetype & LYS_CHOICE) && !(pn->flags & LYS_MAND_TRUE)) { - *type = TRD_NODE_CHOICE; - *opts = TRD_NODE_OPTIONAL; - } else if (pn->nodetype & LYS_CHOICE) { - *type = TRD_NODE_CHOICE; - } else if ((pn->nodetype & LYS_CONTAINER) && (trop_container_has_presence(pn))) { - *opts = TRD_NODE_CONTAINER; - } else if (pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) { - *opts = TRD_NODE_LISTLEAFLIST; - } else if ((pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(pn->flags & LYS_MAND_TRUE)) { - *opts = TRD_NODE_OPTIONAL; - } else if ((pn->nodetype & LYS_LEAF) && !(pn->flags & LYS_MAND_TRUE) && (!trop_leaf_is_key(pn, ca_last_list))) { - *opts = TRD_NODE_OPTIONAL; - } else { - *type = TRD_NODE_ELSE; - } -} - -/** - * @brief Resolve \ of the current node. - * @param[in] pn is current node. - * @return Resolved type. - */ -static struct trt_type -trop_resolve_type(const struct lysp_node *pn) -{ - const char *tmp = NULL; - - if (!pn) { - return TRP_EMPTY_TRT_TYPE; - } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_refpath, pn))) { - return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp); - } else if ((tmp = trop_node_charptr(LYS_LEAFLIST, trop_leaflist_type_name, pn))) { - return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp); - } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_refpath, pn))) { - return TRP_INIT_TRT_TYPE(TRD_TYPE_TARGET, tmp); - } else if ((tmp = trop_node_charptr(LYS_LEAF, trop_leaf_type_name, pn))) { - return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, tmp); - } else if (pn->nodetype == LYS_ANYDATA) { - return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anydata"); - } else if (pn->nodetype & LYS_ANYXML) { - return TRP_INIT_TRT_TYPE(TRD_TYPE_NAME, "anyxml"); - } else { - return TRP_EMPTY_TRT_TYPE; - } -} - -/** - * @brief Resolve iffeatures. - * - * @param[in] pn is current parsed node. - * @return Resolved iffeatures. - */ -static struct trt_iffeatures -trop_resolve_iffeatures(const struct lysp_node *pn) -{ - struct trt_iffeatures iff; - - if (pn && trop_node_has_iffeature(pn)) { - iff.type = TRD_IFF_PRESENT; - iff.str = NULL; - } else { - iff.type = TRD_IFF_NON_PRESENT; - iff.str = NULL; - } - - return iff; -} - -/** - * @brief Transformation of current lysp_node to struct trt_node. - * @param[in] ca contains stored important data - * when browsing the tree downwards. - * @param[in] tc is context of the tree. - */ -static struct trt_node -trop_read_node(struct trt_parent_cache ca, struct trt_tree_ctx *tc) -{ - const struct lysp_node *pn; - struct trt_node ret; - struct lyplg_ext_sprinter_tree_node_override *no; - - assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN); - - no = tro_set_node_overr(tc->lysc_tree, tc->pn, 1, &tc->plugin_ctx); - - pn = tc->pn; - ret = TRP_EMPTY_NODE; - - /* */ - ret.status = trop_resolve_status(pn->nodetype, pn->flags, ca.lys_status); - - /* */ - ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config, no); - - /* set type of the node */ - trop_resolve_node_opts(pn, ca.last_list, &ret.name.type, &ret.name.opts); - ret.name.add_opts = no && no->add_opts ? no->add_opts : NULL; - ret.name.keys = (tc->pn->nodetype & LYS_LIST) && trop_list_has_keys(tc->pn); - - /* The parsed tree is not compiled, so no node can be augmented - * from another module. This means that nodes from the parsed tree - * will never have the prefix. - */ - ret.name.module_prefix = NULL; - - /* set node's name */ - ret.name.str = pn->name; - - /* */ - ret.type = trop_resolve_type(pn); - - /* */ - ret.iffeatures = trop_resolve_iffeatures(pn); - - ret.last_one = !tro_next_sibling(pn, tc); - - return ret; -} - -/** - * @brief Find out if the current node has siblings. - * @param[in] tc is context of the tree. - * @return 1 if sibling exists otherwise 0. - */ -static ly_bool -trop_read_if_sibling_exists(const struct trt_tree_ctx *tc) -{ - return tro_next_sibling(tc->pn, tc) != NULL; -} - -/********************************************************************** - * Modify trop getters - *********************************************************************/ - -/** - * @brief Change current node pointer to its parent - * but only if parent exists. - * @param[in,out] tc is tree context. - * Contains pointer to the current node. - * @return 1 if the node had parents and the change was successful. - * @return 0 if the node did not have parents. - * The pointer to the current node did not change. - */ -static ly_bool -trop_modi_parent(struct trt_tree_ctx *tc) -{ - assert(tc && tc->pn); - /* If no parent exists, stay in actual node. */ - if ((tc->pn != tc->tpn) && (tc->pn->parent)) { - tc->pn = tc->pn->parent; - return 1; - } else { + const struct lysp_node_list *list = ca_last_list; + + if (!list) { return 0; } + return pt_charptr_has_data(list->key) ? + pt_word_is_present(list->key, leaf->name, ' ') : 0; } /** - * @brief Change the current node pointer to its child - * but only if exists. - * @param[in] ca contains inherited data from ancestors. - * @param[in,out] tc is context of the tree. - * Contains pointer to the current node. - * @return Non-empty \ representation of the current - * node's child. The @p tc is modified. - * @return Empty \ representation if child don't exists. - * The @p tc is not modified. + * @brief Check if container's type is presence. + * @param[in] pn Pointer to container. + * @return 1 if container has presence statement, otherwise 0. */ -static struct trt_node -trop_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc) +static ly_bool +pt_pnode_container_has_presence(const struct lysp_node *pn) { - const struct lysp_node *tmp; - - assert(tc && tc->pn); + return pt_charptr_has_data(((struct lysp_node_container *)pn)->presence); +} - if ((tmp = tro_next_child(tc->pn, tc))) { - tc->pn = tmp; - return trop_read_node(ca, tc); +/** + * @brief Resolve \ of the current node. + * @param[in] nodetype Node's type obtained from the tree. + * @param[in] flags Node's flags obtained from the tree. + * @param[in] ca_lys_status Inherited status obtained from pt_parent_cache. + * @return The status type. + */ +static char * +pt_pnode_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status) +{ + if (nodetype & (LYS_INPUT | LYS_OUTPUT)) { + /* LYS_INPUT and LYS_OUTPUT is special case */ + return pt_flags2status(ca_lys_status); + /* if ancestor's status is deprc or obslt + * and also node's status is not set + */ + } else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) { + /* get ancestor's status */ + return pt_flags2status(ca_lys_status); } else { - return TRP_EMPTY_NODE; + /* else get node's status */ + return pt_flags2status(flags); } } +static ly_bool pt_ext_is_present(struct pt_tree_ctx *tc, const char *ext_name); + /** - * @brief Change the pointer to the current node to its next sibling - * only if exists. - * @param[in] ca contains inherited data from ancestors. - * @param[in,out] tc is tree context. - * Contains pointer to the current node. - * @return Non-empty \ representation if sibling exists. - * The @p tc is modified. - * @return Empty \ representation otherwise. - * The @p tc is not modified. + * @brief Resolve \ of the current node. + * @param[in] tc Current tree context. + * @param[in] ca_ancestor Ancestor type obtained from pt_parent_cache. + * @param[in] ca_lys_config Inherited config item obtained from pt_parent_cache. + * @return The flags type. */ -static struct trt_node -trop_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc) +static const char * +pt_pnode_resolve_flags(struct pt_tree_ctx *tc, pt_parent_type ca_ancestor, + uint16_t ca_lys_config) { const struct lysp_node *pn; - assert(tc && tc->pn); + pn = tc->pn; - pn = tro_next_sibling(tc->pn, tc); + if (pt_ext_is_present(tc, "mount-point")) { + return PT_FLAGS_TYPE_MOUNT_POINT; + } else if (pn->nodetype & LYS_USES) { + return PT_FLAGS_TYPE_USES_OF_GROUPING; + } else if (tc->plugin_ctx.schema && (tc->plugin_ctx.schema->ext == PT_EXT_GENERIC)) { + return PT_FLAGS_TYPE_EXT; + } else if ((pn->nodetype & LYS_INPUT) || (ca_ancestor == PT_ANCESTOR_RPC_INPUT)) { + return PT_FLAGS_TYPE_RPC_INPUT_PARAMS; + } else if ((pn->nodetype & LYS_OUTPUT) || (ca_ancestor == PT_ANCESTOR_RPC_OUTPUT)) { + return PT_FLAGS_TYPE_RO; + } else if (ca_ancestor == PT_ANCESTOR_NOTIF) { + return PT_FLAGS_TYPE_RO; + } else if (pn->nodetype & LYS_NOTIF) { + return PT_FLAGS_TYPE_NOTIF; + } else if (pn->nodetype & (LYS_RPC | LYS_ACTION)) { + return PT_FLAGS_TYPE_RPC; + } else if (!(pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W))) { + /* config is not set. Look at ancestor's config */ + return pt_flags2config(ca_lys_config); + } else { + return pt_flags2config(pn->flags); + } +} - if (pn) { - if ((tc->tpn == tc->pn) && (tc->section != TRD_SECT_PLUG_DATA)) { - tc->tpn = pn; - } - tc->pn = pn; - return trop_read_node(ca, tc); +/** + * @brief Resolve node type of the current node. + * @param[in] tc Current tree context. + * @param[in] ca_last_list Pointer to the last visited list. Obtained from the pt_parent_cache. + * @param[out] type Resolved type of node. + * @param[out] opts Resolved opts of node. + */ +static void +pt_pnode_resolve_opts(struct pt_tree_ctx *tc, const struct lysp_node_list *ca_last_list, + pt_node_type *type, const char **opts) +{ + if (tc->plugin_ctx.schema && !tc->pn->parent && + (tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT)) { + *opts = PT_NODE_MOUNTED; + } else if (tc->plugin_ctx.schema && !tc->pn->parent && + (tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF)) { + *opts = PT_NODE_MOUNTED_PARENT_REF; + } else if (tc->pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) { + *type = PT_NODE_ELSE; + } else if (tc->pn->nodetype & LYS_CASE) { + *type = PT_NODE_CASE; + } else if ((tc->pn->nodetype & LYS_CHOICE) && !(tc->pn->flags & LYS_MAND_TRUE)) { + *type = PT_NODE_CHOICE; + *opts = PT_NODE_OPTIONAL; + } else if (tc->pn->nodetype & LYS_CHOICE) { + *type = PT_NODE_CHOICE; + } else if ((tc->pn->nodetype & LYS_CONTAINER) && (pt_pnode_container_has_presence(tc->pn))) { + *opts = PT_NODE_CONTAINER; + } else if (tc->pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) { + *opts = PT_NODE_LISTLEAFLIST; + } else if ((tc->pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(tc->pn->flags & LYS_MAND_TRUE)) { + *opts = PT_NODE_OPTIONAL; + } else if ((tc->pn->nodetype & LYS_LEAF) && !(tc->pn->flags & LYS_MAND_TRUE) && (!pt_pnode_leaf_is_key(tc->pn, ca_last_list))) { + *opts = PT_NODE_OPTIONAL; } else { - return TRP_EMPTY_NODE; + *type = PT_NODE_ELSE; } } /** - * @brief Change the current node pointer to the first child of node's - * parent. If current node is already first sibling/child then nothing - * will change. - * @param[in] ca Settings of parent. - * @param[in,out] tc is tree context. - * @return node for printing. + * @brief Resolve \ of the current node. + * @param[in] pn Current node. + * @return Resolved type. */ -static struct trt_node -trop_modi_first_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc) +static struct pt_lf_type +pt_pnode_resolve_type(const struct lysp_node *pn) { - struct trt_node node; + const char *str = NULL; + const struct lysp_node_leaf *leaf; + const struct lysp_node_leaflist *list; - assert(tc && tc->pn); - - if (trop_modi_parent(tc)) { - node = trop_modi_next_child(ca, tc); - } else if (tc->plugin_ctx.schema) { - tc->pn = tc->plugin_ctx.schema->ptree; - tc->tpn = tc->pn; - node = trop_read_node(ca, tc); - } else { - /* current node is top-node */ - switch (tc->section) { - case TRD_SECT_MODULE: - tc->pn = tc->pmod->data; - tc->tpn = tc->pn; - break; - case TRD_SECT_AUGMENT: - tc->pn = (const struct lysp_node *)tc->pmod->augments; - tc->tpn = tc->pn; - break; - case TRD_SECT_RPCS: - tc->pn = (const struct lysp_node *)tc->pmod->rpcs; - tc->tpn = tc->pn; - break; - case TRD_SECT_NOTIF: - tc->pn = (const struct lysp_node *)tc->pmod->notifs; - tc->tpn = tc->pn; - break; - case TRD_SECT_GROUPING: - tc->pn = (const struct lysp_node *)tc->pmod->groupings; - tc->tpn = tc->pn; - break; - case TRD_SECT_PLUG_DATA: - /* Nothing to do. */ - break; - default: - assert(0); + if (!pn) { + return PT_EMPTY_LF_TYPE; + } else if (pn->nodetype & LYS_LEAFLIST) { + list = (const struct lysp_node_leaflist *)pn; + str = list->type.path ? list->type.path->expr : NULL; + if (pt_charptr_has_data(str)) { + return PT_INIT_LF_TYPE(PT_TYPE_TARGET, str); } - if (tc->pn && (trop_flags(tc->pn) & LYS_INTERNAL)) { - node = trop_modi_next_sibling(ca, tc); + str = list->type.name; + if (pt_charptr_has_data(str)) { + return PT_INIT_LF_TYPE(PT_TYPE_NAME, str); } else { - node = trop_read_node(ca, tc); + return PT_EMPTY_LF_TYPE; } + } else if (pn->nodetype & LYS_LEAF) { + leaf = (const struct lysp_node_leaf *)pn; + str = leaf->type.path ? leaf->type.path->expr : NULL; + if (pt_charptr_has_data(str)) { + return PT_INIT_LF_TYPE(PT_TYPE_TARGET, str); + } + str = leaf->type.name; + if (pt_charptr_has_data(str)) { + return PT_INIT_LF_TYPE(PT_TYPE_NAME, str); + } else { + return PT_EMPTY_LF_TYPE; + } + } else if (pn->nodetype == LYS_ANYDATA) { + return PT_INIT_LF_TYPE(PT_TYPE_NAME, "anydata"); + } else if (pn->nodetype & LYS_ANYXML) { + return PT_INIT_LF_TYPE(PT_TYPE_NAME, "anyxml"); + } else { + return PT_EMPTY_LF_TYPE; } - - if (tc->plugin_ctx.filtered) { - node = trop_modi_next_sibling(ca, tc); - } - - return node; } /** - * @brief Get next (or first) augment section if exists. - * @param[in,out] tc is tree context. It is modified and his current - * node is set to the lysp_node_augment. - * @return Section's representation if (next augment) section exists. - * @return Empty section structure otherwise. + * @brief Resolve iffeatures. + * @param[in] pn Current parsed node. + * @return Resolved iffeatures. */ -static struct trt_keyword_stmt -trop_modi_next_augment(struct trt_tree_ctx *tc) +static struct pt_iffeatures +pt_pnode_resolve_iffeatures(const struct lysp_node *pn) { - assert(tc); - const struct lysp_node_augment *augs; - struct trt_keyword_stmt ret = {0}; + struct pt_iffeatures iff; - /* if next_augment func was called for the first time */ - if (tc->section != TRD_SECT_AUGMENT) { - tc->section = TRD_SECT_AUGMENT; - augs = tc->pmod->augments; + if (pn && pt_pnode_has_iffeature(pn)) { + iff.type = PT_IFF_PRESENT; } else { - /* get augment sibling from top-node pointer */ - augs = (const struct lysp_node_augment *)tc->tpn->next; - } - - if (augs) { - tc->pn = &augs->node; - tc->tpn = tc->pn; - ret.section_name = TRD_KEYWORD_AUGMENT; - ret.argument = augs->nodeid; - ret.has_node = tro_tree_ctx_get_node(tc) ? 1 : 0; + iff.type = PT_IFF_NON_PRESENT; } - return ret; + return iff; } /** - * @brief Get next (or first) grouping section if exists - * @param[in,out] tc is tree context. It is modified and his current - * node is set to the lysp_node_grp. - * @return The next (or first) section representation if it exists. - * @return Empty section representation otherwise. + * @brief Transformation of current lysp_node to struct pt_node. + * @param[in] ca Contains stored important data + * when browsing the tree downwards. + * @param[in] tc Context of the tree. + * @return the read node. */ -static struct trt_keyword_stmt -trop_modi_next_grouping(struct trt_tree_ctx *tc) +static struct pt_node +pt_pnode_read(struct pt_parent_cache ca, struct pt_tree_ctx *tc) { - assert(tc); - const struct lysp_node_grp *grps; - struct trt_keyword_stmt ret = {0}; + const struct lysp_node *pn; + struct pt_node ret; - if (tc->section != TRD_SECT_GROUPING) { - tc->section = TRD_SECT_GROUPING; - grps = tc->pmod->groupings; - } else { - grps = (const struct lysp_node_grp *)tc->tpn->next; - } + assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN); - if (grps) { - tc->pn = &grps->node; - tc->tpn = tc->pn; - ret.section_name = TRD_KEYWORD_GROUPING; - ret.argument = grps->name; - ret.has_node = tro_tree_ctx_get_child(tc) ? 1 : 0; - } + pn = tc->pn; + ret = PT_EMPTY_NODE; + + /* */ + ret.status = pt_pnode_resolve_status(pn->nodetype, pn->flags, ca.lys_status); + + /* */ + ret.flags = pt_pnode_resolve_flags(tc, ca.ancestor, ca.lys_config); + + /* set type of the node */ + pt_pnode_resolve_opts(tc, ca.last_list, &ret.name.type, &ret.name.opts); + ret.name.keys = (tc->pn->nodetype & LYS_LIST) && pt_pnode_list_has_keys(tc->pn); + + /* The parsed tree is not compiled, so no node can be augmented + * from another module. This means that nodes from the parsed tree + * will never have the prefix. + */ + ret.name.module_prefix = NULL; + + /* set node's name */ + ret.name.str = pn->name; + + /* */ + ret.type = pt_pnode_resolve_type(pn); + + /* */ + ret.iffeatures = pt_pnode_resolve_iffeatures(pn); + + ret.last_one = !pt_next_sibling(pn, tc, 0); return ret; } /********************************************************************** - * Definition of troc reading functions + * Definition of lysc_node reading functions *********************************************************************/ -/** - * @copydoc trop_read_if_sibling_exists - */ -static ly_bool -troc_read_if_sibling_exists(const struct trt_tree_ctx *tc) -{ - return tro_next_sibling(tc->cn, tc) != NULL; -} - /** * @brief Resolve \ of the current node. * - * Use this function only if trt_tree_ctx.lysc_tree is true. + * Use this function only if pt_tree_ctx.lysc_tree is true. * - * @param[in] nodetype is current lysc_node.nodetype. - * @param[in] flags is current lysc_node.flags. - * @param[in] no Override structure for flags. + * @param[in] tc Current tree context. * @return The flags type. */ static const char * -troc_resolve_flags(uint16_t nodetype, uint16_t flags, struct lyplg_ext_sprinter_tree_node_override *no) +pt_cnode_resolve_flags(struct pt_tree_ctx *tc) { - if (no && no->flags) { - return no->flags; - } else if ((nodetype & LYS_INPUT) || (flags & LYS_IS_INPUT)) { - return TRD_FLAGS_TYPE_RPC_INPUT_PARAMS; - } else if ((nodetype & LYS_OUTPUT) || (flags & LYS_IS_OUTPUT)) { - return TRD_FLAGS_TYPE_RO; - } else if (nodetype & LYS_IS_NOTIF) { - return TRD_FLAGS_TYPE_RO; - } else if (nodetype & LYS_NOTIF) { - return TRD_FLAGS_TYPE_NOTIF; - } else if (nodetype & LYS_USES) { - return TRD_FLAGS_TYPE_USES_OF_GROUPING; - } else if (nodetype & (LYS_RPC | LYS_ACTION)) { - return TRD_FLAGS_TYPE_RPC; + const struct lysc_node *cn; + + cn = tc->cn; + + if (pt_ext_is_present(tc, "mount-point")) { + return PT_FLAGS_TYPE_MOUNT_POINT; + } else if (tc->plugin_ctx.schema && (tc->plugin_ctx.schema->ext == PT_EXT_GENERIC)) { + return PT_FLAGS_TYPE_EXT; + } else if ((cn->nodetype & LYS_INPUT) || (cn->flags & LYS_IS_INPUT)) { + return PT_FLAGS_TYPE_RPC_INPUT_PARAMS; + } else if ((cn->nodetype & LYS_OUTPUT) || (cn->flags & LYS_IS_OUTPUT)) { + return PT_FLAGS_TYPE_RO; + } else if (cn->nodetype & LYS_NOTIF) { + return PT_FLAGS_TYPE_NOTIF; + } else if (cn->nodetype & (LYS_RPC | LYS_ACTION)) { + return PT_FLAGS_TYPE_RPC; } else { - return tro_flags2config(flags); + return pt_flags2config(cn->flags); } } /** * @brief Resolve node type of the current node. * - * Use this function only if trt_tree_ctx.lysc_tree is true. + * Use this function only if pt_tree_ctx.lysc_tree is true. * - * @param[in] nodetype is current lysc_node.nodetype. - * @param[in] flags is current lysc_node.flags. + * @param[in] tc Current tree context. * @param[out] type Resolved type of node. * @param[out] opts Resolved opts. */ static void -troc_resolve_node_opts(uint16_t nodetype, uint16_t flags, trt_node_type *type, const char **opts) -{ - if (nodetype & (LYS_INPUT | LYS_OUTPUT)) { - *type = TRD_NODE_ELSE; - } else if (nodetype & LYS_CASE) { - *type = TRD_NODE_CASE; - } else if ((nodetype & LYS_CHOICE) && !(flags & LYS_MAND_TRUE)) { - *type = TRD_NODE_CHOICE; - *opts = TRD_NODE_OPTIONAL; - } else if (nodetype & LYS_CHOICE) { - *type = TRD_NODE_CHOICE; - } else if ((nodetype & LYS_CONTAINER) && (flags & LYS_PRESENCE)) { - *opts = TRD_NODE_CONTAINER; - } else if (nodetype & (LYS_LIST | LYS_LEAFLIST)) { - *opts = TRD_NODE_LISTLEAFLIST; - } else if ((nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(flags & LYS_MAND_TRUE)) { - *opts = TRD_NODE_OPTIONAL; - } else if ((nodetype & LYS_LEAF) && !(flags & (LYS_MAND_TRUE | LYS_KEY))) { - *opts = TRD_NODE_OPTIONAL; +pt_cnode_resolve_opts(struct pt_tree_ctx *tc, pt_node_type *type, const char **opts) +{ + if (tc->plugin_ctx.schema && !tc->cn->parent && + (tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT)) { + *opts = PT_NODE_MOUNTED; + } else if (tc->plugin_ctx.schema && !tc->cn->parent && + (tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF)) { + *opts = PT_NODE_MOUNTED_PARENT_REF; + } else if (tc->cn->nodetype & (LYS_INPUT | LYS_OUTPUT)) { + *type = PT_NODE_ELSE; + } else if (tc->cn->nodetype & LYS_CASE) { + *type = PT_NODE_CASE; + } else if ((tc->cn->nodetype & LYS_CHOICE) && !(tc->cn->flags & LYS_MAND_TRUE)) { + *type = PT_NODE_CHOICE; + *opts = PT_NODE_OPTIONAL; + } else if (tc->cn->nodetype & LYS_CHOICE) { + *type = PT_NODE_CHOICE; + } else if ((tc->cn->nodetype & LYS_CONTAINER) && (tc->cn->flags & LYS_PRESENCE)) { + *opts = PT_NODE_CONTAINER; + } else if (tc->cn->nodetype & (LYS_LIST | LYS_LEAFLIST)) { + *opts = PT_NODE_LISTLEAFLIST; + } else if ((tc->cn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(tc->cn->flags & LYS_MAND_TRUE)) { + *opts = PT_NODE_OPTIONAL; + } else if ((tc->cn->nodetype & LYS_LEAF) && !(tc->cn->flags & (LYS_MAND_TRUE | LYS_KEY))) { + *opts = PT_NODE_OPTIONAL; } else { - *type = TRD_NODE_ELSE; + *type = PT_NODE_ELSE; } } /** * @brief Resolve prefix (\:\) of node that has been * placed from another module via an augment statement. - * - * @param[in] cn is current compiled node. - * @param[in] current_compiled_module is module whose nodes are + * @param[in] cn Current compiled node. + * @param[in] current_compiled_module Module whose nodes are * currently being printed. * @return Prefix of foreign module or NULL. */ static const char * -troc_resolve_node_prefix(const struct lysc_node *cn, const struct lysc_module *current_compiled_module) +pt_cnode_resolve_prefix(const struct lysc_node *cn, const struct lysc_module *current_compiled_module) { const struct lys_module *node_module; const char *ret = NULL; @@ -3339,497 +2610,495 @@ troc_resolve_node_prefix(const struct lysc_node *cn, const struct lysc_module *c } /** - * @brief Transformation of current lysc_node to struct trt_node. - * @param[in] ca is not used. - * @param[in] tc is context of the tree. + * @brief Transformation of current lysc_node to struct pt_node. + * @param[in] tc Context of the tree. + * @return the read node. */ -static struct trt_node -troc_read_node(struct trt_parent_cache ca, struct trt_tree_ctx *tc) +static struct pt_node +pt_cnode_read(struct pt_tree_ctx *tc) { - (void) ca; const struct lysc_node *cn; - struct trt_node ret; - struct lyplg_ext_sprinter_tree_node_override *no; + struct pt_node ret; assert(tc && tc->cn); - no = tro_set_node_overr(tc->lysc_tree, tc->cn, 1, &tc->plugin_ctx); - cn = tc->cn; - ret = TRP_EMPTY_NODE; + ret = PT_EMPTY_NODE; /* */ - ret.status = tro_flags2status(cn->flags); + ret.status = pt_flags2status(cn->flags); /* */ - ret.flags = troc_resolve_flags(cn->nodetype, cn->flags, no); + ret.flags = pt_cnode_resolve_flags(tc); /* set type of the node */ - troc_resolve_node_opts(cn->nodetype, cn->flags, &ret.name.type, &ret.name.opts); - ret.name.add_opts = no && no->add_opts ? no->add_opts : NULL; + pt_cnode_resolve_opts(tc, &ret.name.type, &ret.name.opts); ret.name.keys = (cn->nodetype & LYS_LIST) && !(cn->flags & LYS_KEYLESS); /* */ - ret.name.module_prefix = troc_resolve_node_prefix(cn, tc->cmod); + ret.name.module_prefix = pt_cnode_resolve_prefix(cn, tc->cmod); /* set node's name */ ret.name.str = cn->name; /* */ - ret.type = trop_resolve_type(TRP_TREE_CTX_GET_LYSP_NODE(cn)); + ret.type = pt_pnode_resolve_type(PT_TREE_CTX_GET_LYSP_NODE(cn)); /* */ - ret.iffeatures = trop_resolve_iffeatures(TRP_TREE_CTX_GET_LYSP_NODE(cn)); + ret.iffeatures = pt_pnode_resolve_iffeatures(PT_TREE_CTX_GET_LYSP_NODE(cn)); - ret.last_one = !tro_next_sibling(cn, tc); + ret.last_one = !pt_next_sibling(cn, tc, 0); return ret; } /********************************************************************** - * Modify troc getters + * Traversing the nodes. *********************************************************************/ /** - * @copydoc ::trop_modi_parent() + * @brief Change the pointer to the current node to its next sibling + * only if exists. + * @param[in] ca Contains inherited data from ancestors. + * @param[in,out] tc Tree context. + * Contains pointer to the current node. + * @return Non-empty \ representation if sibling exists. + * The @p tc is modified. + * @return Empty \ representation. + * The @p tc is not modified. */ -static ly_bool -troc_modi_parent(struct trt_tree_ctx *tc) +static struct pt_node +pt_modi_next_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc) { - assert(tc && tc->cn); - /* If no parent exists, stay in actual node. */ - if (tc->cn->parent) { - tc->cn = tc->cn->parent; - return 1; + const void *node, *sibl; + + node = pt_get_node(tc); + sibl = pt_next_sibling(node, tc, 1); + + /* if next sibling exists */ + if (!sibl) { + return PT_EMPTY_NODE; + } + + if (tc->plugin_ctx.schema) { + tc->lysc_tree = tc->plugin_ctx.schema->compiled; + } + + /* update pt_tree_ctx */ + if (tc->lysc_tree) { + tc->cn = sibl; + return pt_cnode_read(tc); } else { - return 0; + tc->pn = sibl; + return pt_pnode_read(ca, tc); } } /** - * @copydoc ::trop_modi_next_sibling() + * @brief Change the current node pointer to its child + * but only if exists. + * @param[in] ca Contains inherited data from ancestors. + * @param[in,out] tc Context of the tree. + * Contains pointer to the current node. + * @return Non-empty \ representation of the current + * node's child. The @p tc is modified. + * @return Empty \ representation if child don't exists. + * The @p tc is not modified. */ -static struct trt_node -troc_modi_next_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc) +static struct pt_node +pt_modi_next_child(struct pt_parent_cache ca, struct pt_tree_ctx *tc) { - const struct lysc_node *cn; + const void *node, *child; - assert(tc && tc->cn); + node = pt_get_node(tc); + child = pt_next_child(node, tc, 1); + + if (!child) { + return PT_EMPTY_NODE; + } - cn = tro_next_sibling(tc->cn, tc); + if (tc->plugin_ctx.schema) { + tc->lysc_tree = tc->plugin_ctx.schema->compiled; + } - /* if next sibling exists */ - if (cn) { - /* update trt_tree_ctx */ - tc->cn = cn; - return troc_read_node(ca, tc); + if (tc->lysc_tree) { + tc->cn = child; + return pt_cnode_read(tc); } else { - return TRP_EMPTY_NODE; + tc->pn = child; + return pt_pnode_read(ca, tc); } } /** - * @copydoc trop_modi_next_child() + * @brief Reset current node to child. + * @param[in,out] tc Contains current node. */ -static struct trt_node -troc_modi_next_child(struct trt_parent_cache ca, struct trt_tree_ctx *tc) +static void +pt_modi_next_child2(struct pt_tree_ctx *tc) { - const struct lysc_node *tmp; - - assert(tc && tc->cn); + const void *node = pt_get_child(tc); - if ((tmp = tro_next_child(tc->cn, tc))) { - tc->cn = tmp; - return troc_read_node(ca, tc); + if (tc->lysc_tree) { + tc->cn = node; } else { - return TRP_EMPTY_NODE; + tc->pn = node; } } /** - * @copydoc ::trop_modi_first_sibling() + * @brief Change current node pointer to its parent + * but only if parent exists. + * @param[in,out] tc Tree context. + * Contains pointer to the current node. + * @return 1 if the node had parents and the change was successful. + * @return 0 if the node did not have parents. + * The pointer to the current node did not change. */ -static struct trt_node -troc_modi_first_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc) +static ly_bool +pt_modi_parent(struct pt_tree_ctx *tc) { - struct trt_node node; - - assert(tc && tc->cn); - - if (troc_modi_parent(tc)) { - node = troc_modi_next_child(ca, tc); - } else if (tc->plugin_ctx.schema) { - tc->cn = tc->plugin_ctx.schema->ctree; - node = troc_read_node(ca, tc); - } else { - /* current node is top-node */ - switch (tc->section) { - case TRD_SECT_MODULE: - tc->cn = tc->cn->module->compiled->data; - break; - case TRD_SECT_RPCS: - tc->cn = (const struct lysc_node *)tc->cmod->rpcs; - break; - case TRD_SECT_NOTIF: - tc->cn = (const struct lysc_node *)tc->cmod->notifs; - break; - case TRD_SECT_PLUG_DATA: - /* nothing to do */ - break; - default: - assert(0); - } - if (tc->cn && (troc_lysp_flags(tc->cn) & LYS_INTERNAL)) { - node = troc_modi_next_sibling(ca, tc); + if (tc->lysc_tree) { + assert(tc && tc->cn); + /* If no parent exists, stay in actual node. */ + if (tc->cn->parent) { + tc->cn = tc->cn->parent; + return 1; } else { - node = troc_read_node(ca, tc); + return 0; } - } - - if (tc->plugin_ctx.filtered) { - node = troc_modi_next_sibling(ca, tc); - } - - return node; -} - -/********************************************************************** - * Definition of tree browsing functions - *********************************************************************/ - -static uint32_t -trb_gap_to_opts(const struct trt_node *node) -{ - uint32_t len = 0; - - if (node->name.keys) { - return 0; - } - - if (node->flags) { - len += strlen(node->flags); - /* space between flags and name */ - len += 1; } else { - /* space between -- and name */ - len += 1; - } - - switch (node->name.type) { - case TRD_NODE_CASE: - /* ':' is already counted. Plus parentheses. */ - len += 2; - break; - case TRD_NODE_CHOICE: - /* Plus parentheses. */ - len += 2; - break; - default: - break; - } - - if (node->name.module_prefix) { - /* prefix_name and ':' */ - len += strlen(node->name.module_prefix) + 1; - } - if (node->name.str) { - len += strlen(node->name.str); - } - if (node->name.add_opts) { - len += strlen(node->name.add_opts); - } - if (node->name.opts) { - len += strlen(node->name.opts); + assert(tc && tc->pn); + /* If no parent exists, stay in actual node. */ + if (!tc->pn->parent) { + return 0; + } + if (((tc->section == PT_SECT_AUGMENT) || (tc->section == PT_SECT_GROUPING)) && + !tc->pn->parent->parent) { + /* augment and grouping themselves are nodes, stay in subtree */ + return 0; + } + tc->pn = tc->pn->parent; + return 1; } - - return len; } -static uint32_t -trb_gap_to_type(const struct trt_node *node) +/** + * @copydoc ::pt_pnode_modi_first_sibling() + */ +static struct pt_node +pt_cnode_modi_first_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc) { - uint32_t len, opts_len; + struct pt_node node; - if (node->name.keys) { - return 0; - } + assert(tc && tc->cn); - len = trb_gap_to_opts(node); - /* Gap between opts and type. */ - opts_len = 0; - opts_len += node->name.add_opts ? strlen(node->name.add_opts) : 0; - opts_len += node->name.opts ? strlen(node->name.opts) : 0; - if (opts_len >= TRD_INDENT_BEFORE_TYPE) { - /* At least one space should be there. */ - len += 1; - } else if (node->name.add_opts || node->name.opts) { - len += TRD_INDENT_BEFORE_TYPE - opts_len; + if (pt_modi_parent(tc)) { + node = pt_modi_next_child(ca, tc); } else { - len += TRD_INDENT_BEFORE_TYPE; + /* current node is top-node */ + switch (tc->section) { + case PT_SECT_MODULE: + tc->cn = tc->cn->module->compiled->data; + break; + case PT_SECT_RPCS: + tc->cn = (const struct lysc_node *)tc->cmod->rpcs; + break; + case PT_SECT_NOTIF: + tc->cn = (const struct lysc_node *)tc->cmod->notifs; + break; + case PT_SECT_PLUG_DATA: + if ((tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT) || + (tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF)) { + tc->cn = tc->plugin_ctx.schema_mount->schemas->ctree; + tc->plugin_ctx.schema = tc->plugin_ctx.schema_mount->schemas; + } else { + tc->cn = tc->plugin_ctx.schema->ctree; + } + break; + default: + assert(0); + } + if (pt_ignore_node(tc->cn, tc)) { + node = pt_modi_next_sibling(ca, tc); + } else { + node = pt_cnode_read(tc); + } } - return len; + return node; } /** - * @brief Calculate the trt_indent_in_node.btw_opts_type indent size - * for a particular node. - * @param[in] node for which we get btw_opts_type. - * @param[in] max_gap_before_type is the maximum value of btw_opts_type - * that it can have. - * @return Indent between \ and \ for node. + * @brief Change the current node pointer to the first child of node's + * parent. If current node is already first sibling/child then nothing + * will change. + * @param[in] ca Settings of parent. + * @param[in,out] tc Tree context. + * @return node for printing. */ -static int16_t -trb_calc_btw_opts_type(const struct trt_node *node, int16_t max_gap_before_type) +static struct pt_node +pt_pnode_modi_first_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc) { - uint32_t to_opts_len; + struct pt_node node; - to_opts_len = trb_gap_to_opts(node); - if (to_opts_len == 0) { - return 1; + assert(tc && tc->pn); + + if (pt_modi_parent(tc)) { + node = pt_modi_next_child(ca, tc); } else { - return max_gap_before_type - to_opts_len; + /* current node is top-node */ + switch (tc->section) { + case PT_SECT_MODULE: + tc->pn = tc->pmod->data; + break; + case PT_SECT_AUGMENT: + tc->pn = lysp_node_child(tc->pn->parent); + break; + case PT_SECT_RPCS: + tc->pn = (const struct lysp_node *)tc->pmod->rpcs; + break; + case PT_SECT_NOTIF: + tc->pn = (const struct lysp_node *)tc->pmod->notifs; + break; + case PT_SECT_GROUPING: + tc->pn = lysp_node_child(tc->pn->parent); + break; + case PT_SECT_PLUG_DATA: + if ((tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT) || + (tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF)) { + tc->pn = tc->plugin_ctx.schema_mount->schemas->ptree; + tc->plugin_ctx.schema = tc->plugin_ctx.schema_mount->schemas; + } else { + tc->pn = tc->plugin_ctx.schema->ptree; + } + break; + default: + assert(0); + } + if (pt_ignore_node(tc->pn, tc)) { + node = pt_modi_next_sibling(ca, tc); + } else { + node = pt_pnode_read(ca, tc); + } } + + return node; } /** - * @brief Print node. - * - * This function is wrapper for ::trp_print_entire_node(). - * But difference is that take @p max_gap_before_type which will be - * used to set the unified alignment. - * - * @param[in] node to print. - * @param[in] max_gap_before_type is number of indent before \. - * @param[in] wr is wrapper for printing indentation before node. - * @param[in] pc contains mainly functions for printing. - * @param[in] tc is tree context. + * @brief Change the current node pointer to the first child of node's + * parent. If current node is already first sibling/child then nothing + * will change. + * @param[in] ca Settings of parent. + * @param[in,out] tc Tree context. + * @return node for printing. */ -static void -trb_print_entire_node(const struct trt_node *node, uint32_t max_gap_before_type, struct trt_wrapper wr, - struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +static struct pt_node +pt_modi_first_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc) { - struct trt_indent_in_node ind = trp_default_indent_in_node(node); - - if ((max_gap_before_type > 0) && (node->type.type != TRD_TYPE_EMPTY)) { - /* print actual node with unified indent */ - ind.btw_opts_type = trb_calc_btw_opts_type(node, max_gap_before_type); - } - /* after -> print actual node with default indent */ - trp_print_entire_node(node, TRP_INIT_PCK_PRINT(tc, pc->fp.print), - TRP_INIT_PCK_INDENT(wr, ind), pc->max_line_length, pc->out); + return tc->lysc_tree ? pt_cnode_modi_first_sibling(ca, tc) : pt_pnode_modi_first_sibling(ca, tc); } /** - * @brief Check if parent of the current node is the last - * of his siblings. - * - * To mantain stability use this function only if the current node is - * the first of the siblings. - * Side-effect -> current node is set to the first sibling - * if node has a parent otherwise no side-effect. - * - * @param[in] fp contains all @ref TRP_tro callback functions. - * @param[in,out] tc is tree context. - * @return 1 if parent is last sibling otherwise 0. + * @brief Get rpcs section if exists. + * @param[in,out] tc Tree context. + * @return Section representation if it exists. The @p tc is modified + * and his pointer points to the first node in rpcs section. + * @return Empty section representation otherwise. */ -static ly_bool -trb_node_is_last_sibling(const struct trt_fp_all *fp, struct trt_tree_ctx *tc) +static struct pt_keyword_stmt +pt_modi_get_rpcs(struct pt_tree_ctx *tc) { - if (fp->read.if_parent_exists(tc)) { - return !fp->read.if_sibling_exists(tc); + assert(tc); + const void *actions; + struct pt_keyword_stmt rpc = PT_EMPTY_KEYWORD_STMT; + + if (tc->lysc_tree) { + actions = tc->cmod->rpcs; + if (actions) { + tc->cn = actions; + } } else { - return !fp->read.if_sibling_exists(tc) && tc->plugin_ctx.last_schema; + actions = tc->pmod->rpcs; + if (actions) { + tc->pn = actions; + } + } + + if (actions) { + tc->section = PT_SECT_RPCS; + rpc.section_name = PT_KEYWORD_RPC; + rpc.has_node = pt_get_node(tc) ? 1 : 0; } + + return rpc; } /** - * @brief For all siblings find maximal space from '--' to \. - * - * Side-effect -> Current node is set to the first sibling. - * - * @param[in] ca contains inherited data from ancestors. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is tree context. - * @return max space. + * @brief Get notification section if exists + * @param[in,out] tc Tree context. + * @return Section representation if it exists. + * The @p tc is modified and his pointer points to the + * first node in notification section. + * @return Empty section representation otherwise. */ -static uint32_t -trb_max_gap_to_type(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +static struct pt_keyword_stmt +pt_modi_get_notifications(struct pt_tree_ctx *tc) { - struct trt_node node; - int32_t maxlen, len; + assert(tc); + const void *notifs; + struct pt_keyword_stmt notif = PT_EMPTY_KEYWORD_STMT; - maxlen = 0; - for (node = pc->fp.modify.first_sibling(ca, tc); - !trp_node_is_empty(&node); - node = pc->fp.modify.next_sibling(ca, tc)) { - len = trb_gap_to_type(&node); - maxlen = maxlen < len ? len : maxlen; + if (tc->lysc_tree) { + notifs = tc->cmod->notifs; + if (notifs) { + tc->cn = notifs; + } + } else { + notifs = tc->pmod->notifs; + if (notifs) { + tc->pn = notifs; + } } - pc->fp.modify.first_sibling(ca, tc); - return maxlen; -} + if (notifs) { + tc->section = PT_SECT_NOTIF; + notif.section_name = PT_KEYWORD_NOTIF; + notif.has_node = pt_get_node(tc) ? 1 : 0; + } -/** - * @brief Find out if it is possible to unify - * the alignment before \. - * - * The goal is for all node siblings to have the same alignment - * for \ as if they were in a column. All siblings who cannot - * adapt because they do not fit on the line at all are ignored. - * Side-effect -> Current node is set to the first sibling. - * - * @param[in] ca contains inherited data from ancestors. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is tree context. - * @return positive number indicating the maximum number of spaces - * before \ if the length of the flags, node name and opts is 0. To calculate - * the trt_indent_in_node.btw_opts_type indent size for a particular - * node, use the ::trb_calc_btw_opts_type(). -*/ -static uint32_t -trb_try_unified_indent(struct trt_parent_cache ca, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) -{ - return trb_max_gap_to_type(ca, pc, tc); + return notif; } /** - * @brief Check if there is no case statement - * under the choice statement. - * - * It can return true only if the Parsed schema tree - * is used for browsing. - * - * @param[in] tc is tree context. - * @return 1 if implicit case statement is present otherwise 0. + * @brief Get next (or first) augment section if exists. + * @param[in,out] tc Tree context. It is modified and his current + * node is set to the lysp_node_augment. + * @param[in] index Index of augments to get. + * @return Section's representation if (next augment) section exists. + * @return Empty section structure otherwise. */ -static ly_bool -trb_need_implicit_node_case(struct trt_tree_ctx *tc) +static struct pt_keyword_stmt +pt_modi_get_augment(struct pt_tree_ctx *tc, uint32_t index) { - return !tc->lysc_tree && tc->pn->parent && - (tc->pn->parent->nodetype & LYS_CHOICE) && - (tc->pn->nodetype & (LYS_ANYDATA | LYS_CHOICE | LYS_CONTAINER | - LYS_LEAF | LYS_LEAFLIST)); -} + assert(tc); + const struct lysp_node_augment *augs, *elem; + struct pt_keyword_stmt aug = PT_EMPTY_KEYWORD_STMT; + uint32_t i; -static void trb_print_subtree_nodes(struct trt_node *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); + i = 0; + augs = tc->pmod->augments; + LY_LIST_FOR(augs, elem) { + if (i == index) { + tc->pn = &elem->node; + aug.section_name = PT_KEYWORD_AUGMENT; + aug.argument = elem->nodeid; + aug.has_node = pt_get_child(tc) ? 1 : 0; + return aug; + } + i++; + } -/** - * @brief Print implicit case node and his subtree. - * - * @param[in] node is child of implicit case. - * @param[in] wr is wrapper for printing identation before node. - * @param[in] pc contains mainly functions for printing. - * @param[in] tc is tree context. Its settings should be the same as - * before the function call. - * @return new indentation wrapper for @p node. - */ -static struct trt_wrapper -trb_print_implicit_node(const struct trt_node *node, struct trt_wrapper wr, struct trt_printer_ctx *pc, - struct trt_tree_ctx *tc) -{ - struct trt_node case_node; - struct trt_wrapper wr_case_child; - - tro_create_implicit_case_node(node, &case_node); - ly_print_(pc->out, "\n"); - trb_print_entire_node(&case_node, 0, wr, pc, tc); - ly_print_(pc->out, "\n"); - wr_case_child = pc->fp.read.if_sibling_exists(tc) ? - trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr); - return wr_case_child; + return PT_EMPTY_KEYWORD_STMT; } /** - * @brief Calculate the wrapper about how deep in the tree the node is. - * @param[in] wr_in A wrapper to use as a starting point - * @param[in] node from which to count. - * @return wrapper for @p node. + * @brief Get next (or first) grouping section if exists + * @param[in,out] tc Tree context. It is modified and his current + * node is set to the lysp_node_grp. + * @param[in] index Index of grouping to get. + * @return The next (or first) section representation if it exists. + * @return Empty section representation otherwise. */ -static struct trt_wrapper -trb_count_depth(const struct trt_wrapper *wr_in, const struct lysc_node *node) +static struct pt_keyword_stmt +pt_modi_get_grouping(struct pt_tree_ctx *tc, uint32_t index) { - struct trt_wrapper wr = wr_in ? *wr_in : TRP_INIT_WRAPPER_TOP; - const struct lysc_node *parent; - - if (!node) { - return wr; - } + assert(tc); + const struct lysp_node_grp *grps, *elem; + struct pt_keyword_stmt group = PT_EMPTY_KEYWORD_STMT; + uint32_t i; - for (parent = node->parent; parent; parent = parent->parent) { - wr = trp_wrapper_set_shift(wr); + i = 0; + grps = tc->pmod->groupings; + LY_LIST_FOR(grps, elem) { + if (i == index) { + tc->pn = &elem->node; + group.section_name = PT_KEYWORD_GROUPING; + group.argument = elem->name; + group.has_node = pt_get_child(tc) ? 1 : 0; + return group; + } + i++; } - return wr; + return PT_EMPTY_KEYWORD_STMT; } +/********************************************************************** + * Extension functions + *********************************************************************/ + /** - * @brief Print all parent nodes of @p node and the @p node itself. - * - * Side-effect -> trt_tree_ctx.cn will be set to @p node. - * - * @param[in] node on which the function is focused. - * @param[in] wr_in for printing identation before node. - * @param[in] pc is @ref TRP_trp settings. - * @param[in,out] tc is context of tree printer. + * @brief Set printer tree context to the next schema. + * @param[in,out] tc Printer tree schema. */ static void -trb_print_parents(const struct lysc_node *node, struct trt_wrapper *wr_in, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_ext_set_next_schema_mount(struct pt_tree_ctx *tc) { - uint32_t max_gap_before_type; - struct trt_wrapper wr; - struct trt_node print_node; + LY_ARRAY_COUNT_TYPE i; + struct pt_ext_tree_schema *schemas; + ly_bool set_next = 0; - assert(pc && tc && tc->section == TRD_SECT_MODULE); + assert(!PT_LAST_SCHEMA_MOUNT(tc->plugin_ctx)); - /* stop recursion */ - if (!node) { - return; + schemas = tc->plugin_ctx.schema_mount->schemas; + LY_ARRAY_FOR(schemas, i) { + if (set_next) { + tc->plugin_ctx.schema = &schemas[i]; + tc->lysc_tree = tc->plugin_ctx.schema->compiled; + break; + } else if (&schemas[i] == tc->plugin_ctx.schema) { + set_next = 1; + } } - trb_print_parents(node->parent, wr_in, pc, tc); - - /* setup for printing */ - tc->cn = node; - wr = trb_count_depth(wr_in, node); - /* print node */ - ly_print_(pc->out, "\n"); - print_node = pc->fp.read.node(TRP_EMPTY_PARENT_CACHE, tc); - /* siblings do not print, so the node is always considered the last */ - print_node.last_one = 1; - max_gap_before_type = trb_max_gap_to_type(TRP_EMPTY_PARENT_CACHE, pc, tc); - tc->cn = node; - trb_print_entire_node(&print_node, max_gap_before_type, wr, pc, tc); + assert(set_next); } /** - * @brief Set current node on its child. - * @param[in,out] tc contains current node. + * @brief Check if parent-stmt is valid for printing extension. + * @param[in] lysc_tree Set to 1 if ext is from compiled tree. + * @param[in] ext Extension to check. + * @return 1 if extension is valid. */ -static void -trb_tree_ctx_set_child(struct trt_tree_ctx *tc) +static ly_bool +pt_ext_parent_is_valid(ly_bool lysc_tree, void *ext) { - const void *node = tro_tree_ctx_get_child(tc); + enum ly_stmt parent_stmt; - if (tc->lysc_tree) { - tc->cn = node; + if (lysc_tree) { + parent_stmt = ((struct lysc_ext_instance *)ext)->parent_stmt; } else { - tc->pn = node; + parent_stmt = ((struct lysp_ext_instance *)ext)->parent_stmt; + } + if ((parent_stmt & LY_STMT_OP_MASK) || (parent_stmt & LY_STMT_DATA_NODE_MASK) || + (parent_stmt & LY_STMT_SUBMODULE) || parent_stmt & LY_STMT_MODULE) { + return 1; + } else { + return 0; } } /** * @brief Move extension iterator to the next position. - * - * @param[in] lysc_tree flag if exts is from compiled tree. - * @param[in] exts is current array of extensions. - * @param[in,out] i is state of iterator. + * @param[in] lysc_tree Set to 1 if exts is from compiled tree. + * @param[in] exts Current array of extensions. + * @param[in,out] i State of iterator. * @return Pointer to the first/next extension. */ static void * -trb_ext_iter_next(ly_bool lysc_tree, void *exts, LY_ARRAY_COUNT_TYPE *i) +pt_ext_iter_next(ly_bool lysc_tree, void *exts, LY_ARRAY_COUNT_TYPE *i) { void *ext = NULL; struct lysc_ext_instance *ce; @@ -3842,7 +3111,7 @@ trb_ext_iter_next(ly_bool lysc_tree, void *exts, LY_ARRAY_COUNT_TYPE *i) if (lysc_tree) { ce = exts; while (*i < LY_ARRAY_COUNT(ce)) { - if (ce->def->plugin_ref && trp_ext_parent_is_valid(1, &ce[*i])) { + if (ce->def->plugin_ref && pt_ext_parent_is_valid(1, &ce[*i])) { ext = &ce[*i]; break; } @@ -3851,7 +3120,7 @@ trb_ext_iter_next(ly_bool lysc_tree, void *exts, LY_ARRAY_COUNT_TYPE *i) } else { pe = exts; while (*i < LY_ARRAY_COUNT(pe)) { - if (trp_ext_parent_is_valid(0, &pe[*i])) { + if (pt_ext_parent_is_valid(0, &pe[*i])) { ext = &pe[*i]; break; } @@ -3864,405 +3133,516 @@ trb_ext_iter_next(ly_bool lysc_tree, void *exts, LY_ARRAY_COUNT_TYPE *i) } /** - * @brief Iterate over extensions in module. - * - * @param[in] tc contains current node. - * @param[in,out] i is state of iterator. - * @return First/next extension or NULL. + * @brief Iterate over extensions in module or node. + * @param[in] tc Contains current node. + * @param[in] ext_name Extension name to find. + * @param[in] from_module Set to 1 if extensions in the module + * sould be searched otherwise it will search in the node. + * @param[in,out] i State of iterator. + * @return First/next extension or NULL. + */ +static void * +pt_ext_iter(const struct pt_tree_ctx *tc, const char *ext_name, + ly_bool from_module, LY_ARRAY_COUNT_TYPE *i) +{ + struct lysp_ext_instance *ext_pars; + struct lysc_ext_instance *ext_comp; + void *ext = NULL; + const char *name = ""; + + do { + if (tc->lysc_tree) { + ext_comp = from_module ? tc->cmod->exts : tc->cn->exts; + ext_comp = ext = pt_ext_iter_next(1, ext_comp, i); + if (ext_comp) { + name = ext_comp->def->name; + assert(name); + } + } else { + ext_pars = from_module ? tc->pmod->exts : tc->pn->exts; + ext_pars = ext = pt_ext_iter_next(0, ext_pars, i); + if (ext_pars) { + name = strchr(ext_pars->name, ':') + 1; + assert(name); + } + } + } while (ext && ext_name && strcmp(name, ext_name)); + + return ext; +} + +/** + * @brief Check if printer_tree can use node extension. + * @param[in] tc Context with current node. + * @param[in] ext_name Extension name to find. + * @return 1 if some extension for printer_tree is valid. */ -static void * -trb_mod_ext_iter(const struct trt_tree_ctx *tc, LY_ARRAY_COUNT_TYPE *i) +static ly_bool +pt_ext_is_present(struct pt_tree_ctx *tc, const char *ext_name) { - if (tc->lysc_tree) { - return trb_ext_iter_next(1, tc->cmod->exts, i); + uint64_t i = 0; + + if (pt_ext_iter(tc, ext_name, 0, &i)) { + return 1; } else { - return trb_ext_iter_next(0, tc->pmod->exts, i); + return 0; } } /** - * @brief Iterate over extensions in node. - * - * @param[in] tc contains current node. - * @param[in,out] i is state of iterator. - * @return First/next extension or NULL. + * @brief Determine whether the node should be ignored. + * @param[in] node Node to check. + * @param[in] refs Set of lysc nodes matching parent-reference XPaths. + * @return 1 to ignore otherwise 0. */ -static void * -trb_ext_iter(const struct trt_tree_ctx *tc, LY_ARRAY_COUNT_TYPE *i) +static ly_bool +pt_schema_mount_skip(const struct lysc_node *node, const struct ly_set *refs) { - if (tc->lysc_tree) { - return trb_ext_iter_next(1, tc->cn->exts, i); - } else { - return trb_ext_iter_next(0, tc->pn->exts, i); + uint32_t i; + const struct lysc_module *mod; + struct lysc_node *ref, *iter; + ly_bool skip; + + mod = node->module->compiled; + + /* Assume the @p node will be skipped. */ + skip = 1; + for (i = 0; (i < refs->count) && skip; i++) { + ref = refs->snodes[i]; + if (ref->module->compiled != mod) { + /* parent-reference points to different module */ + continue; + } + + for (iter = ref; iter; iter = iter->parent) { + if (iter == node) { + /* @p node is not skipped because it is parent-rererence node or his parent */ + skip = 0; + break; + } + } } + + return skip; } /** - * @brief Initialize plugin context. - * - * @param[in] compiled if @p ext is lysc structure. - * @param[in] ext current processed extension. - * @param[out] plug_ctx is plugin context which will be initialized. - * @param[out] ignore plugin callback is NULL. - * @return LY_ERR value. + * @brief Add lysc schema to the list. + * @param[in] ctx Destination where to add. + * @param[in] nodes Schema to add. + * @param[in] parent_ref Set to 1 if schema is referenced by schema-mount parent-reference. + * @return 1 to ignore otherwise 0. */ static LY_ERR -tro_ext_printer_tree(ly_bool compiled, void *ext, const struct lyspr_tree_ctx *plug_ctx, ly_bool *ignore) +pt_ext_sprinter_ctree_add_nodes(const struct pt_ext_schema_mount *ctx, struct lysc_node *nodes, ly_bool parent_ref) { - struct lysc_ext_instance *ext_comp; - struct lysp_ext_instance *ext_pars; - const struct lyplg_ext *plugin; - const char *flags = NULL, *add_opts = NULL; - - if (compiled) { - ext_comp = ext; - plugin = LYSC_GET_EXT_PLG(ext_comp->def->plugin_ref); - if (!plugin->printer_ctree) { - *ignore = 1; - return LY_SUCCESS; - } - return plugin->printer_ctree(ext, plug_ctx, &flags, &add_opts); - } else { - ext_pars = ext; - plugin = LYSC_GET_EXT_PLG(ext_pars->plugin_ref); - if (!plugin->printer_ptree) { - *ignore = 1; - return LY_SUCCESS; - } - return plugin->printer_ptree(ext, plug_ctx, &flags, &add_opts); + struct pt_ext_tree_schema *new; + + LY_CHECK_ARG_RET(NULL, ctx, LY_EINVAL); + + if (!nodes) { + return LY_SUCCESS; } + LY_ARRAY_NEW_RET(NULL, ((struct pt_ext_schema_mount *)ctx)->schemas, new, LY_EMEM); + new->compiled = 1; + new->ctree = nodes; + new->ext = parent_ref ? PT_EXT_SCHEMA_MOUNT_REF : PT_EXT_SCHEMA_MOUNT; + return LY_SUCCESS; } /** - * @brief Reset tree context by plugin context. - * - * @param[in] plug_ctx is plugin context. - * @param[in] i which index in schemas should be used. - * @param[in] pc are printing functions. - * @param[out] tc tree context which will be updated. + * @brief Add lysp schema to the list. + * @param[in] ctx Destination where to add. + * @param[in] nodes Schema to add. + * @param[in] parent_ref Set to 1 if schema is referenced by schema-mount parent-reference. + * @return LY_ERR value. */ -static void -trm_reset_tree_ctx_by_plugin(struct lyspr_tree_ctx *plug_ctx, LY_ARRAY_COUNT_TYPE i, struct trt_printer_ctx *pc, - struct trt_tree_ctx *tc) +static LY_ERR +pt_ext_sprinter_ptree_add_nodes(const struct pt_ext_schema_mount *ctx, struct lysp_node *nodes, ly_bool parent_ref) { - tc->plugin_ctx.ctx = plug_ctx; - tc->pmod = NULL; - tc->cmod = NULL; - if (plug_ctx->schemas[i].compiled) { - tc->lysc_tree = 1; - tc->cn = plug_ctx->schemas[i].ctree; - tc->plugin_ctx.schema = &plug_ctx->schemas[i]; - pc->fp.modify = TRP_TRT_FP_MODIFY_COMPILED; - pc->fp.read = TRP_TRT_FP_READ_COMPILED; - } else { - tc->lysc_tree = 0; - tc->pn = plug_ctx->schemas[i].ptree; - tc->tpn = tc->pn; - tc->plugin_ctx.schema = &plug_ctx->schemas[i]; - pc->fp.modify = TRP_TRT_FP_MODIFY_PARSED; - pc->fp.read = TRP_TRT_FP_READ_PARSED; + struct pt_ext_tree_schema *new; + + LY_CHECK_ARG_RET(NULL, ctx, LY_EINVAL); + + if (!nodes) { + return LY_SUCCESS; } + + LY_ARRAY_NEW_RET(NULL, ((struct pt_ext_schema_mount *)ctx)->schemas, new, LY_EMEM); + new->compiled = 0; + new->ptree = nodes; + new->ext = parent_ref ? PT_EXT_SCHEMA_MOUNT_REF : PT_EXT_SCHEMA_MOUNT; + + return LY_SUCCESS; } /** - * @brief Print schemas from plugin context. - * - * @param[in] plug_ctx is plugin context. - * @param[in] last_nodes if this schemas will be the last. - * @param[in] max_gap_before_type is gap before type. - * @param[in] wr is indentation wrapper. - * @param[in] ca containing information from parent. - * @param[in] pc functions for tree traversing. - * @param[in] tc current tree context. + * @brief Initialize plugin context. + * @param[in] compiled Set to 1 if @p ext is lysc structure. + * @param[in] ext Current processed extension. + * @param[out] schema_mount Filled schema_mount structure. + * @return LY_ERR value. */ -static void -trb_ext_print_schemas(struct lyspr_tree_ctx *plug_ctx, ly_bool last_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) +static LY_ERR +pt_create_mount_point(ly_bool compiled, void *ext, struct pt_ext_schema_mount *schema_mount) { - LY_ARRAY_COUNT_TYPE i; - struct trt_printer_ctx pc_dupl; - struct trt_tree_ctx tc_dupl; - struct trt_node node; + LY_ERR rc = LY_SUCCESS; + const struct ly_ctx *ext_ctx = NULL; + const struct lys_module *mod; + struct ly_set *refs = NULL; + struct lysc_node *tree1, *tree2; + uint32_t i, j; + ly_bool from_parent_ref, is_first; - tc_dupl = *tc; - pc_dupl = *pc; + if (!compiled) { + return LY_SUCCESS; + } - LY_ARRAY_FOR(plug_ctx->schemas, i) { - trm_reset_tree_ctx_by_plugin(plug_ctx, i, pc, tc); - tc->plugin_ctx.last_schema = last_nodes && ((i + 1) == LY_ARRAY_COUNT(plug_ctx->schemas)); - node = TRP_EMPTY_NODE; - trb_print_subtree_nodes(&node, max_gap_before_type, wr, ca, pc, tc); - *tc = tc_dupl; + if (lyplg_ext_schema_mount_get_ctx(ext, NULL, &ext_ctx)) { + /* Void mount point */ + return LY_SUCCESS; } - *pc = pc_dupl; -} + rc = lyplg_ext_schema_mount_get_parent_ref(ext, NULL, &refs); + LY_CHECK_GOTO(rc, cleanup); -/** - * @brief Count unified indentation across schemas from extension instance. - * - * @param[in] plug_ctx is plugin context. - * @param[in] ca containing parent settings. - * @param[out] max_gap_before_type is result of unified indent. - * @param[in] pc functions for tree traversing. - * @param[in] tc is tree context. - */ -static void -trb_ext_try_unified_indent(struct lyspr_tree_ctx *plug_ctx, struct trt_parent_cache ca, uint32_t *max_gap_before_type, - struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) -{ - LY_ARRAY_COUNT_TYPE i; - struct trt_printer_ctx pc_dupl; - struct trt_tree_ctx tc_dupl; - uint32_t max; + /* build new list of modules to print. This list will omit internal + * modules, modules with no nodes (e.g., iana-if-types) and modules + * that were loaded as the result of a parent-reference. + */ + i = ly_ctx_internal_modules_count(ext_ctx); + while ((mod = ly_ctx_get_module_iter(ext_ctx, &i))) { + from_parent_ref = 0; + + for (j = 0; refs && j < refs->count; j++) { + if (!strcmp(mod->ns, refs->snodes[j]->module->ns)) { + from_parent_ref = 1; + break; + } + } + if (from_parent_ref) { + /* Modules loaded as the result of a parent-reference are added later. */ + continue; + } + + /* Add data nodes, rpcs and notifications. */ + if ((ext_ctx->opts & LY_CTX_SET_PRIV_PARSED) && mod->compiled) { + /* For compiled module. */ + rc = pt_ext_sprinter_ctree_add_nodes(schema_mount, mod->compiled->data, 0); + LY_CHECK_GOTO(rc, cleanup); + if (mod->compiled->rpcs) { + rc = pt_ext_sprinter_ctree_add_nodes(schema_mount, &mod->compiled->rpcs->node, 0); + } + LY_CHECK_GOTO(rc, cleanup); + if (mod->compiled->notifs) { + rc = pt_ext_sprinter_ctree_add_nodes(schema_mount, &mod->compiled->notifs->node, 0); + } + LY_CHECK_GOTO(rc, cleanup); + } else { + /* For parsed module. */ + rc = pt_ext_sprinter_ptree_add_nodes(schema_mount, mod->parsed->data, 0); + LY_CHECK_GOTO(rc, cleanup); + if (mod->parsed->rpcs) { + rc = pt_ext_sprinter_ptree_add_nodes(schema_mount, &mod->parsed->rpcs->node, 0); + } + LY_CHECK_GOTO(rc, cleanup); + if (mod->parsed->notifs) { + rc = pt_ext_sprinter_ptree_add_nodes(schema_mount, &mod->parsed->notifs->node, 0); + } + LY_CHECK_GOTO(rc, cleanup); + } + } + + /* Add modules loaded as the result of a parent-reference. */ + for (i = 0; refs && (i < refs->count); i++) { + tree1 = refs->snodes[i]->module->compiled->data; + + /* Add data nodes from the module only once. */ + is_first = 1; + for (j = 0; j < i; j++) { + tree2 = refs->snodes[j]->module->compiled->data; + if (tree1 == tree2) { + is_first = 0; + break; + } + } + if (is_first) { + /* Add all data nodes but unavailable nodes are skipped in the callback. */ + rc = pt_ext_sprinter_ctree_add_nodes(schema_mount, tree1, 1); + LY_CHECK_GOTO(rc, cleanup); + } + } - tc_dupl = *tc; - pc_dupl = *pc; + schema_mount->parent_refs = refs; - LY_ARRAY_FOR(plug_ctx->schemas, i) { - trm_reset_tree_ctx_by_plugin(plug_ctx, i, pc, tc); - max = trb_try_unified_indent(ca, pc, tc); - *max_gap_before_type = max > *max_gap_before_type ? max : *max_gap_before_type; - *tc = tc_dupl; +cleanup: + if (rc) { + ly_set_free(refs, NULL); } - *pc = pc_dupl; + return rc; } +static void pt_print_subtree(struct pt_node *node, uint32_t max_gap_before_type, struct pt_wrapper wr, + struct pt_parent_cache ca, ly_bool print_root, struct pt_tree_ctx *tc); + /** * @brief For every extension instance print all schemas. - * - * @param[in] wr indentation wrapper for node. - * @param[in] ca parent settings. - * @param[in] pc function used for tree traversing. - * @param[in] tc tree context. + * @param[in] wr Iindentation wrapper for node. + * @param[in] ca Parent settings. + * @param[in] tc Tree context. */ static void -trb_ext_print_instances(struct trt_wrapper wr, struct trt_parent_cache ca, struct trt_printer_ctx *pc, - struct trt_tree_ctx *tc) +pt_print_schema_mount(struct pt_wrapper wr, struct pt_parent_cache ca, + struct pt_tree_ctx tc) { LY_ERR rc; LY_ARRAY_COUNT_TYPE i; - uint64_t last_instance = UINT64_MAX; void *ext; - ly_bool child_exists, ignore = 0; - uint32_t max, max_gap_before_type = 0; + struct pt_ext_schema_mount schema_mount = {0}; + struct pt_node node; - ca = tro_parent_cache_for_child(ca, tc); - /* if node is last sibling, then do not add '|' to wrapper */ - wr = trb_node_is_last_sibling(&pc->fp, tc) ? - trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr); + if (!tc.lysc_tree) { + return; + } - if (tc->lysc_tree) { - child_exists = tro_next_child(tc->cn, tc) ? 1 : 0; - } else { - child_exists = tro_next_child(tc->pn, tc) ? 1 : 0; + if (pt_next_child(pt_get_node(&tc), &tc, 0)) { + schema_mount.mp_has_normal_node = 1; } + tc.section = PT_SECT_PLUG_DATA; + tc.pmod = NULL; + tc.cmod = NULL; + + /* load children of mount-point */ i = 0; - while ((ext = trb_ext_iter(tc, &i))) { - struct lyspr_tree_ctx plug_ctx = {0}; + while ((ext = pt_ext_iter(&tc, "mount-point", 0, &i))) { + rc = pt_create_mount_point(tc.lysc_tree, ext, &schema_mount); + LY_CHECK_ERR_GOTO(rc, tc.last_error = rc, end); - rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx, &ignore); - LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end); - if (ignore) { - ignore = 0; - continue; + if (!schema_mount.schemas) { + /* mount-point not used */ + goto end; } - trb_ext_try_unified_indent(&plug_ctx, ca, &max_gap_before_type, pc, tc); - if (plug_ctx.schemas) { - last_instance = i; - } - trp_ext_free_plugin_ctx(&plug_ctx); + schema_mount.mount_point = tc.cn; + tc.plugin_ctx.schema_mount = &schema_mount; + tc.plugin_ctx.schema = schema_mount.schemas; + tc.lysc_tree = tc.plugin_ctx.schema->compiled; + + /* print schema-mount and parent-reference schemas */ + node = PT_EMPTY_NODE; + pt_print_subtree(&node, 0, wr, ca, 0, &tc); + /* then continue printing the remaining children of the mount-point node */ + + /* only one mount_point is allowed */ + break; } - if (child_exists) { - pc->fp.modify.next_child(ca, tc); - max = trb_try_unified_indent(ca, pc, tc); - max_gap_before_type = max > max_gap_before_type ? max : max_gap_before_type; - pc->fp.modify.parent(tc); +end: + LY_ARRAY_FREE(schema_mount.schemas); + if (schema_mount.parent_refs) { + ly_set_free(schema_mount.parent_refs, NULL); } + return; +} - i = 0; - while ((ext = trb_ext_iter(tc, &i))) { - struct lyspr_tree_ctx plug_ctx = {0}; +/********************************************************************** + * Print subtree + *********************************************************************/ - rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx, &ignore); - LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end); - if (ignore) { - ignore = 0; - continue; - } - if (!child_exists && (last_instance == i)) { - trb_ext_print_schemas(&plug_ctx, 1, max_gap_before_type, wr, ca, pc, tc); - } else { - trb_ext_print_schemas(&plug_ctx, 0, max_gap_before_type, wr, ca, pc, tc); - } - trp_ext_free_plugin_ctx(&plug_ctx); +/** + * @brief Print all parent nodes of @p node and the @p node itself. + * + * Side-effect -> pt_tree_ctx.cn will be set to @p node. + * + * @param[in] node Node to process. + * @param[in] wr_in Indentation before node. + * @param[in,out] tc Context of tree printer. + */ +static void +pt_print_parents(const struct lysc_node *node, struct pt_wrapper *wr_in, struct pt_tree_ctx *tc) +{ + uint32_t max_gap_before_type; + struct pt_wrapper wr; + struct pt_node print_node; + + assert(tc && tc->section == PT_SECT_MODULE); + + /* stop recursion */ + if (!node) { + return; } + pt_print_parents(node->parent, wr_in, tc); -end: - return; + /* setup for printing */ + tc->cn = node; + wr = pt_count_depth(wr_in, node); + + /* print node */ + ly_print_(tc->out, "\n"); + print_node = pt_read_node(PT_EMPTY_PARENT_CACHE, tc); + /* siblings do not print, so the node is always considered the last */ + print_node.last_one = 1; + max_gap_before_type = pt_max_gap_to_type(PT_EMPTY_PARENT_CACHE, tc); + tc->cn = node; + pt_print_entire_node(print_node, max_gap_before_type, wr, tc); +} + +static void pt_print_subtree(struct pt_node *node, uint32_t max_gap_before_type, struct pt_wrapper wr, + struct pt_parent_cache ca, ly_bool print_root, struct pt_tree_ctx *tc); + +/** + * @brief Print node and its siblings. + * @param[in] node Node to print. + * @param[in] wr Indentation on line. + * @param[in] ca Contains inherited data from ancestors. + * @param[in,out] tc Current tree context. + */ +static void +pt_print_siblings(struct pt_node *node, struct pt_wrapper wr, + struct pt_parent_cache ca, struct pt_tree_ctx *tc) +{ + uint32_t max_gap_before_type; + + max_gap_before_type = pt_try_unified_indent(ca, *tc); + do { + if (pt_need_implicit_node_case(tc)) { + struct pt_wrapper wr_case_child; + + wr_case_child = pt_print_implicit_node(node, wr, tc); + pt_print_subtree(node, max_gap_before_type, wr_case_child, ca, 1, tc); + } else { + ly_print_(tc->out, "\n"); + pt_print_subtree(node, max_gap_before_type, wr, ca, 1, tc); + } + /* go to the actual node's sibling */ + *node = pt_modi_next_sibling(ca, tc); + } while (!pt_node_is_empty(node)); } /** - * @brief Print subtree of nodes. + * @brief Print the subtree. * * The current node is expected to be the root of the subtree. * Before root node is no linebreak printing. This must be addressed by * the caller. Root node will also be printed. Behind last printed node * is no linebreak. * - * @param[in,out] node current processed node used as iterator. - * @param[in] max_gap_before_type is result from - * ::trb_try_unified_indent() function for root node. + * @param[in,out] node Current processed node used as iterator. + * @param[in] max_gap_before_type Result from + * ::pt_try_unified_indent() function for root node. * Set parameter to 0 if distance does not matter. - * @param[in] wr is wrapper saying how deep in the whole tree + * @param[in] wr Wrapper saying how deep in the whole tree * is the root of the subtree. - * @param[in] ca is parent_cache from root's parent. - * If root is top-level node, insert ::TRP_EMPTY_PARENT_CACHE. - * @param[in] pc is @ref TRP_trp settings. - * @param[in,out] tc is context of tree printer. + * @param[in] ca Parent cache from root's parent. + * If root is top-level node, insert ::PT_EMPTY_PARENT_CACHE. + * @param[in] print_root Set to 1 for printing root node + * and in that case @p max_gag_before_type is ignored. + * @param[in,out] tc Context of tree printer. */ static void -trb_print_subtree_nodes(struct trt_node *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) -{ - if (!trp_node_is_empty(node)) { - /* Print root node. */ - trb_print_entire_node(node, max_gap_before_type, wr, pc, tc); - if (trp_ext_is_present_in_node(tc)) { - trb_ext_print_instances(wr, ca, pc, tc); - } - /* if node is last sibling, then do not add '|' to wrapper */ - wr = trb_node_is_last_sibling(&pc->fp, tc) ? - trp_wrapper_set_shift(wr) : trp_wrapper_set_mark(wr); - /* go to the child */ - ca = tro_parent_cache_for_child(ca, tc); - *node = pc->fp.modify.next_child(ca, tc); - if (trp_node_is_empty(node)) { - return; +pt_print_subtree(struct pt_node *node, uint32_t max_gap_before_type, struct pt_wrapper wr, + struct pt_parent_cache ca, ly_bool print_root, struct pt_tree_ctx *tc) +{ + /* Print root node. */ + if (print_root && !pt_node_is_empty(node)) { + pt_print_entire_node(*node, max_gap_before_type, wr, tc); + if (pt_ext_is_present(tc, "mount-point")) { + pt_print_schema_mount(wr, ca, *tc); + /* continue with printing normal (not mounted) nodes */ } - /* TODO comment browse through instances + filtered. try unified indentation for children */ - max_gap_before_type = trb_try_unified_indent(ca, pc, tc); - } else { - /* Root node is ignored, continue with child. */ - *node = pc->fp.modify.first_sibling(ca, tc); } - do { - if (!tc->plugin_ctx.filtered && !trb_need_implicit_node_case(tc)) { - /* normal behavior */ - ly_print_(pc->out, "\n"); - trb_print_subtree_nodes(node, max_gap_before_type, wr, ca, pc, tc); - } else if (!tc->plugin_ctx.filtered) { - struct trt_wrapper wr_case_child; - - wr_case_child = trb_print_implicit_node(node, wr, pc, tc); - trb_print_subtree_nodes(node, max_gap_before_type, wr_case_child, ca, pc, tc); - } - /* go to the actual node's sibling */ - *node = pc->fp.modify.next_sibling(ca, tc); - } while (!trp_node_is_empty(node)); + /* if node is last sibling, then do not add '|' to wrapper */ + wr = pt_node_is_last_sibling(tc) ? + pt_wrapper_set_shift(wr) : pt_wrapper_set_mark(wr); + /* go to the child */ + ca = pt_parent_cache_for_child(ca, tc); + *node = pt_modi_next_child(ca, tc); + if (pt_node_is_empty(node)) { + return; + } + pt_print_siblings(node, wr, ca, tc); /* get back from child node to root node */ - pc->fp.modify.parent(tc); + pt_modi_parent(tc); } /** - * @brief Print all parents and their children. + * @brief Print all siblings and their children. * * This function is suitable for printing top-level nodes that - * do not have ancestors. Function call ::trb_print_subtree_nodes() + * do not have ancestors. Function call ::pt_print_subtree_nodes() * for all top-level siblings. Use this function after 'module' keyword * or 'augment' and so. The nodes may not be exactly top-level in the * tree, but the function considers them that way. * - * @param[in] wr is wrapper saying how deeply the top-level nodes are + * @param[in] wr Wrapper saying how deeply the top-level nodes are * immersed in the tree. - * @param[pc] pc contains mainly functions for printing. - * @param[in,out] tc is tree context. + * @param[in,out] tc Tree context. */ static void -trb_print_family_tree(struct trt_wrapper wr, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_print_trees(struct pt_wrapper wr, struct pt_tree_ctx *tc) { - struct trt_parent_cache ca; - struct trt_node node; + struct pt_parent_cache ca; + struct pt_node node; uint32_t max_gap_before_type; - if (!tro_tree_ctx_get_node(tc)) { + if (!pt_get_node(tc)) { return; } - ca = TRP_EMPTY_PARENT_CACHE; - max_gap_before_type = trb_try_unified_indent(ca, pc, tc); + ca = PT_EMPTY_PARENT_CACHE; + max_gap_before_type = pt_try_unified_indent(ca, *tc); if (!tc->lysc_tree) { - if ((tc->section == TRD_SECT_GROUPING) && (tc->tpn == tc->pn->parent)) { + if ((tc->section == PT_SECT_GROUPING) && !tc->pn->parent->parent) { ca.lys_config = 0x0; } } - for (node = pc->fp.modify.first_sibling(ca, tc); - !trp_node_is_empty(&node); - node = pc->fp.modify.next_sibling(ca, tc)) { - ly_print_(pc->out, "\n"); - trb_print_subtree_nodes(&node, max_gap_before_type, wr, ca, pc, tc); + for (node = pt_modi_first_sibling(ca, tc); + !pt_node_is_empty(&node); + node = pt_modi_next_sibling(ca, tc)) { + ly_print_(tc->out, "\n"); + pt_print_subtree(&node, max_gap_before_type, wr, ca, 1, tc); } } /********************************************************************** - * Definition of trm main functions + * Print sections *********************************************************************/ /** * @brief Settings if lysp_node are used for browsing through the tree. - * * @param[in] module YANG schema tree structure representing * YANG module. - * @param[in] out is output handler. - * @param[in] max_line_length is the maximum line length limit + * @param[in] out Output handler. + * @param[in] max_line_length Maximum line length limit * that should not be exceeded. - * @param[in,out] pc will be adapted to lysp_tree. - * @param[in,out] tc will be adapted to lysp_tree. + * @param[in,out] tc Will be adapted to lysp_tree. */ static void -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) +pt_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, + struct pt_tree_ctx *tc) { - *tc = (struct trt_tree_ctx) { + *tc = (struct pt_tree_ctx) { .lysc_tree = 0, - .section = TRD_SECT_MODULE, + .section = PT_SECT_MODULE, .pmod = module->parsed, .cmod = NULL, .pn = module->parsed ? module->parsed->data : NULL, - .tpn = module->parsed ? module->parsed->data : NULL, .cn = NULL, .last_error = 0, .plugin_ctx = { - .ctx = NULL, + .schema_mount = NULL, .schema = NULL, - .filtered = 0, - .node_overr = TRP_TREE_CTX_EMPTY_NODE_OVERR, - .last_schema = 1, - .last_error = 0 - } - - }; - - pc->out = out; - - pc->fp.modify = TRP_TRT_FP_MODIFY_PARSED; - pc->fp.read = TRP_TRT_FP_READ_PARSED; - - pc->fp.print = (struct trt_fp_print) { - .print_features_names = tro_print_features_names, - .print_keys = tro_print_keys + }, + .out = out, + .max_line_length = max_line_length }; - - pc->max_line_length = max_line_length; } /** @@ -4272,89 +3652,54 @@ trm_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t ma * * @param[in] module YANG schema tree structure representing * YANG module. - * @param[in] out is output handler. - * @param[in] max_line_length is the maximum line length limit + * @param[in] out Output handler. + * @param[in] max_line_length Maximum line length limit * that should not be exceeded. - * @param[in,out] pc will be adapted to lysc_tree. - * @param[in,out] tc will be adapted to lysc_tree. + * @param[in,out] tc Will be adapted to lysc_tree. */ static void -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) +pt_lysc_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length, + struct pt_tree_ctx *tc) { - *tc = (struct trt_tree_ctx) { + *tc = (struct pt_tree_ctx) { .lysc_tree = 1, - .section = TRD_SECT_MODULE, + .section = PT_SECT_MODULE, .pmod = module->parsed, .cmod = module->compiled, - .tpn = NULL, .pn = NULL, .cn = module->compiled->data, .last_error = 0, .plugin_ctx = { - .ctx = NULL, + .schema_mount = NULL, .schema = NULL, - .filtered = 0, - .node_overr = TRP_TREE_CTX_EMPTY_NODE_OVERR, - .last_schema = 1, - .last_error = 0 - } - - }; - - pc->out = out; - - pc->fp.modify = TRP_TRT_FP_MODIFY_COMPILED; - pc->fp.read = TRP_TRT_FP_READ_COMPILED; - - pc->fp.print = (struct trt_fp_print) { - .print_features_names = tro_print_features_names, - .print_keys = tro_print_keys + }, + .out = out, + .max_line_length = max_line_length }; - - pc->max_line_length = max_line_length; -} - -/** - * @brief Reset settings to browsing through the lysc tree. - * @param[in,out] pc resets to @ref TRP_troc functions. - * @param[in,out] tc resets to lysc browsing. - */ -static void -trm_reset_to_lysc_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) -{ - LY_ERR erc; - - erc = tc->last_error; - trp_ext_free_node_override(&tc->plugin_ctx.node_overr, &tc->plugin_ctx.filtered); - trm_lysc_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc); - tc->last_error = erc; } /** * @brief Reset settings to browsing through the lysp tree. - * @param[in,out] pc resets to @ref TRP_trop functions. - * @param[in,out] tc resets to lysp browsing. + * @param[in,out] tc Resets to lysp browsing. */ static void -trm_reset_to_lysp_tree_ctx(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_reset_to_lysp_tree_ctx(struct pt_tree_ctx *tc) { LY_ERR erc; erc = tc->last_error; - trp_ext_free_node_override(&tc->plugin_ctx.node_overr, &tc->plugin_ctx.filtered); - trm_lysp_tree_ctx(tc->pmod->mod, pc->out, pc->max_line_length, pc, tc); + pt_lysp_tree_ctx(tc->pmod->mod, tc->out, tc->max_line_length, tc); tc->last_error = erc; } /** - * @brief If augment's target node is located on the current module. - * @param[in] pn is examined augment. - * @param[in] pmod is current module. + * @brief Check if augment's target node is located on the current module. + * @param[in] pn Examined augment. + * @param[in] pmod Current module. * @return 1 if nodeid refers to the local node, otherwise 0. */ static ly_bool -trm_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod) +pt_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod) { const char *id, *prefix, *name; uint32_t prefix_len, name_len; @@ -4384,257 +3729,268 @@ trm_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp return ret; } -/** - * @brief Printing section module, rpcs, notifications or yang-data. - * - * First node must be the first child of 'module', - * 'rpcs', 'notifications' or 'yang-data'. - * - * @param[in] ks is section representation. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. - */ -static void -trm_print_section_as_family_tree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) -{ - assert(ks.section_name); - - trp_print_keyword_stmt(ks, pc->max_line_length, pc->out); - if (!strcmp(ks.section_name, TRD_KEYWORD_MODULE) || !strcmp(ks.section_name, TRD_KEYWORD_SUBMODULE)) { - trb_print_family_tree(TRP_INIT_WRAPPER_TOP, pc, tc); - } else { - trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc); - } -} - -/** - * @brief Printing section augment or grouping. - * - * First node is 'augment' or 'grouping' itself. - * - * @param[in] ks is section representation. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. - */ -static void -trm_print_section_as_subtree(struct trt_keyword_stmt ks, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) -{ - assert(ks.section_name); - trp_print_keyword_stmt(ks, pc->max_line_length, pc->out); - trb_tree_ctx_set_child(tc); - trb_print_family_tree(TRP_INIT_WRAPPER_BODY, pc, tc); -} - /** * @brief Print 'module' keyword, its name and all nodes. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. + * @param[in,out] tc Tree context. */ static void -trm_print_module_section(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_print_module_section(struct pt_tree_ctx *tc) { - trm_print_section_as_family_tree(pc->fp.read.module_name(tc), pc, tc); + struct pt_keyword_stmt module = PT_EMPTY_KEYWORD_STMT; + + module = pt_read_module_name(tc); + pt_print_keyword_stmt(&module, NULL, tc->out); + pt_print_trees(PT_INIT_WRAPPER_TOP, tc); } /** * @brief For all augment sections: print 'augment' keyword, * its target node and all nodes. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. + * @param[in,out] tc Tree context. */ static void -trm_print_augmentations(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_print_augmentations(struct pt_tree_ctx tc) { - ly_bool once; + uint32_t i; + ly_bool once = 1; ly_bool origin_was_lysc_tree = 0; - struct trt_keyword_stmt ks; + struct pt_keyword_stmt aug = PT_EMPTY_KEYWORD_STMT; - if (tc->lysc_tree) { + if (tc.lysc_tree) { origin_was_lysc_tree = 1; - trm_reset_to_lysp_tree_ctx(pc, tc); + pt_reset_to_lysp_tree_ctx(&tc); } - once = 1; - for (ks = trop_modi_next_augment(tc); ks.section_name; ks = trop_modi_next_augment(tc)) { - + for (i = 0; ((aug = pt_modi_get_augment(&tc, i))).section_name; i++) { + tc.section = PT_SECT_AUGMENT; if (origin_was_lysc_tree) { /* if lysc tree is used, then only augments targeting * another module are printed */ - if (trm_nodeid_target_is_local((const struct lysp_node_augment *)tc->tpn, tc->pmod)) { + if (pt_nodeid_target_is_local((const struct lysp_node_augment *)tc.pn, tc.pmod)) { continue; } } - if (once) { - ly_print_(pc->out, "\n"); - ly_print_(pc->out, "\n"); - once = 0; - } else { - ly_print_(pc->out, "\n"); - } - - trm_print_section_as_subtree(ks, pc, tc); - } - - if (origin_was_lysc_tree) { - trm_reset_to_lysc_tree_ctx(pc, tc); + pt_print_keyword_stmt(&aug, &once, tc.out); + pt_modi_next_child2(&tc); + pt_print_trees(PT_INIT_WRAPPER_BODY, &tc); } } /** * @brief For rpcs section: print 'rpcs' keyword and all its nodes. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. + * @param[in,out] tc Tree context. */ static void -trm_print_rpcs(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_print_rpcs(struct pt_tree_ctx *tc) { - struct trt_keyword_stmt rpc; - - rpc = tro_modi_get_rpcs(tc); + ly_bool once = 1; + struct pt_keyword_stmt rpc = PT_EMPTY_KEYWORD_STMT; + rpc = pt_modi_get_rpcs(tc); if (rpc.section_name) { - ly_print_(pc->out, "\n"); - ly_print_(pc->out, "\n"); - trm_print_section_as_family_tree(rpc, pc, tc); + pt_print_keyword_stmt(&rpc, &once, tc->out); + pt_print_trees(PT_INIT_WRAPPER_BODY, tc); } } /** * @brief For notifications section: print 'notifications' keyword * and all its nodes. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. + * @param[in,out] tc Tree context. */ static void -trm_print_notifications(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_print_notifications(struct pt_tree_ctx *tc) { - struct trt_keyword_stmt notifs; - - notifs = tro_modi_get_notifications(tc); + ly_bool once = 1; + struct pt_keyword_stmt notifs = PT_EMPTY_KEYWORD_STMT; + notifs = pt_modi_get_notifications(tc); if (notifs.section_name) { - ly_print_(pc->out, "\n"); - ly_print_(pc->out, "\n"); - trm_print_section_as_family_tree(notifs, pc, tc); + pt_print_keyword_stmt(¬ifs, &once, tc->out); + pt_print_trees(PT_INIT_WRAPPER_BODY, tc); } } /** * @brief For all grouping sections: print 'grouping' keyword, its name * and all nodes. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. + * @param[in,out] tc Tree context. */ static void -trm_print_groupings(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_print_groupings(struct pt_tree_ctx *tc) { - ly_bool once; - struct trt_keyword_stmt ks; + uint32_t i; + ly_bool once = 1; + struct pt_keyword_stmt group = PT_EMPTY_KEYWORD_STMT; if (tc->lysc_tree) { return; } - once = 1; - for (ks = trop_modi_next_grouping(tc); ks.section_name; ks = trop_modi_next_grouping(tc)) { - if (once) { - ly_print_(pc->out, "\n"); - ly_print_(pc->out, "\n"); - once = 0; + for (i = 0; ((group = pt_modi_get_grouping(tc, i))).section_name; i++) { + tc->section = PT_SECT_GROUPING; + pt_print_keyword_stmt(&group, &once, tc->out); + pt_modi_next_child2(tc); + pt_print_trees(PT_INIT_WRAPPER_BODY, tc); + } +} + +/** + * @brief Read extension and get schema pointer. + * @param[in] ext Extension to read. + * @param[in] stmt_mask First stmt which match will be returned. + * @return pointer to lysp node. + */ +static void * +pt_ext_parsed_read_storage(struct lysp_ext_instance *ext, int stmt_mask) +{ + LY_ARRAY_COUNT_TYPE i; + enum ly_stmt stmt; + void *substmts, **storage_p, *node = NULL; + + substmts = (void *)((struct lysp_ext_instance *)ext)->substmts; + + LY_ARRAY_FOR(substmts, i) { + stmt = ((struct lysp_ext_instance *)ext)->substmts[i].stmt; + storage_p = ((struct lysp_ext_instance *)ext)->substmts[i].storage_p; + + if (storage_p && (stmt & stmt_mask)) { + return *storage_p; + } + } + + return node; +} + +/** + * @brief Read extension and get pointer to schema. + * @param[in] ext Extension to read. + * @param[in,out] compiled For input set to 1 if @p ext is compiled instance. + * For output is set to 1 if returned pointer is from compiled instance. + * @param[out] ks Section name to fill. + * @return pointer to lysp or lysc node. + */ +static void * +pt_ext_read(void *ext, ly_bool *compiled, struct pt_keyword_stmt *ks) +{ + struct lysc_ext_instance *ext_comp; + struct lysp_ext_instance *ext_pars; + const char *name; + void *schema; + + if (!*compiled) { + ext_pars = ext; + ks->argument = ext_pars->argument; + name = strchr(ext_pars->name, ':') + 1; + ks->section_name = name; + if (!strcmp(ks->section_name, "augment-structure")) { + schema = pt_ext_parsed_read_storage(ext_pars, LY_STMT_AUGMENT); + schema = ((struct lysp_node_augment *)schema)->child; } else { - ly_print_(pc->out, "\n"); + schema = pt_ext_parsed_read_storage(ext_pars, LY_STMT_DATA_NODE_MASK); } - trm_print_section_as_subtree(ks, pc, tc); + *compiled = 0; + return schema; + } + + /* for compiled extension instance */ + ext_comp = ext; + ks->argument = ext_comp->argument; + ks->section_name = ext_comp->def->name; + + /* search in lysc_ext_instance */ + lyplg_ext_get_storage(ext, LY_STMT_DATA_NODE_MASK, sizeof schema, (const void **)&schema); + *compiled = 1; + if (schema) { + return schema; + } + + /* no data nodes lysc_ext_instance, so search in lysp_ext_instance */ + *compiled = 0; + if (!strcmp(ks->section_name, "augment-structure")) { + lyplg_ext_parsed_get_storage(ext_comp, LY_STMT_AUGMENT, sizeof schema, (const void **)&schema); + schema = ((struct lysp_node_augment *)schema)->child; + } else { + lyplg_ext_parsed_get_storage(ext_comp, LY_STMT_DATA_NODE_MASK, sizeof schema, (const void **)&schema); } + + return schema; } /** - * @brief Print all sections defined in plugins. - * - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. + * @brief Print top-level extension instances. + * @param[in] tc Tree context. */ static void -trm_print_plugin_ext(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_print_extensions(struct pt_tree_ctx tc) { - LY_ERR rc; - ly_bool once; - LY_ARRAY_COUNT_TYPE i = 0, j; - struct trt_keyword_stmt ks, prev_ks = {0}; - struct trt_printer_ctx pc_dupl; - struct trt_tree_ctx tc_dupl; - struct trt_node node; - ly_bool ignore = 0; - uint32_t max_gap_before_type; + ly_bool once = 1; + LY_ARRAY_COUNT_TYPE i = 0; + struct pt_keyword_stmt ks = PT_EMPTY_KEYWORD_STMT; + struct pt_node node; + void *schema; void *ext; + struct pt_ext_tree_schema ext_schema; + ly_bool origin_lysc_tree = tc.lysc_tree; - tc->section = TRD_SECT_PLUG_DATA; - - tc_dupl = *tc; - pc_dupl = *pc; + tc.section = PT_SECT_PLUG_DATA; + tc.plugin_ctx.schema = &ext_schema; + tc.plugin_ctx.schema->ext = PT_EXT_GENERIC; - once = 1; + while ((ext = pt_ext_iter(&tc, NULL, 1, &i))) { + tc.lysc_tree = origin_lysc_tree; - while ((ext = trb_mod_ext_iter(tc, &i))) { - struct lyspr_tree_ctx plug_ctx = {0}; - - rc = tro_ext_printer_tree(tc->lysc_tree, ext, &plug_ctx, &ignore); - LY_CHECK_ERR_GOTO(rc, tc->last_error = rc, end); - if (!plug_ctx.schemas || ignore) { - ignore = 0; + schema = pt_ext_read(ext, &tc.lysc_tree, &ks); + if (!strcmp(ks.section_name, "mount-point") || + !strcmp(ks.section_name, "annotation")) { + /* extension ignored */ continue; } - - ks = tro_get_ext_section(tc, ext, &plug_ctx); - if (once || (prev_ks.section_name && strcmp(prev_ks.section_name, ks.section_name))) { - ly_print_(pc->out, "\n"); - ly_print_(pc->out, "\n"); - once = 0; + if (tc.lysc_tree) { + tc.cn = schema; + tc.plugin_ctx.schema->ctree = tc.cn; + tc.plugin_ctx.schema->compiled = 1; + ks.has_node = tc.cn ? 1 : 0; } else { - ly_print_(pc->out, "\n"); + tc.pn = schema; + tc.plugin_ctx.schema->ptree = tc.pn; + tc.plugin_ctx.schema->compiled = 0; + ks.has_node = tc.pn ? 1 : 0; } - trp_print_keyword_stmt(ks, pc->max_line_length, pc->out); - - max_gap_before_type = 0; - trb_ext_try_unified_indent(&plug_ctx, TRP_EMPTY_PARENT_CACHE, &max_gap_before_type, pc, tc); - LY_ARRAY_FOR(plug_ctx.schemas, j) { - trm_reset_tree_ctx_by_plugin(&plug_ctx, j, pc, tc); - node = TRP_EMPTY_NODE; - trb_print_subtree_nodes(&node, max_gap_before_type, TRP_INIT_WRAPPER_BODY, TRP_EMPTY_PARENT_CACHE, pc, tc); + pt_print_keyword_stmt(&ks, &once, tc.out); + if (!ks.has_node) { + /* no subtree to print */ + continue; } + /* print subtree */ + node = pt_modi_first_sibling(PT_EMPTY_PARENT_CACHE, &tc); + pt_print_siblings(&node, PT_INIT_WRAPPER_BODY, PT_EMPTY_PARENT_CACHE, &tc); - *tc = tc_dupl; - trp_ext_free_plugin_ctx(&plug_ctx); - prev_ks = ks; + tc.lysc_tree = origin_lysc_tree; } - -end: - *pc = pc_dupl; - return; } /** * @brief Print sections module, augment, rpcs, notifications, * grouping, yang-data. - * @param[in] pc contains mainly functions for printing. - * @param[in,out] tc is the tree context. + * @param[in,out] tc Tree context. */ static void -trm_print_sections(struct trt_printer_ctx *pc, struct trt_tree_ctx *tc) +pt_print_sections(struct pt_tree_ctx *tc) { - trm_print_module_section(pc, tc); - trm_print_augmentations(pc, tc); - trm_print_rpcs(pc, tc); - trm_print_notifications(pc, tc); - trm_print_groupings(pc, tc); - trm_print_plugin_ext(pc, tc); - ly_print_(pc->out, "\n"); + pt_print_module_section(tc); + pt_print_augmentations(*tc); + pt_print_rpcs(tc); + pt_print_notifications(tc); + pt_print_groupings(tc); + pt_print_extensions(*tc); + ly_print_(tc->out, "\n"); } static LY_ERR -tree_print_check_error(struct ly_out_clb_arg *out, struct trt_tree_ctx *tc) +pt_print_check_error(struct ly_out_clb_arg *out, struct pt_tree_ctx *tc) { if (out->last_error) { return out->last_error; @@ -4652,27 +4008,26 @@ tree_print_check_error(struct ly_out_clb_arg *out, struct trt_tree_ctx *tc) LY_ERR tree_print_module(struct ly_out *out, const struct lys_module *module, uint32_t UNUSED(options), size_t line_length) { - struct trt_printer_ctx pc; - struct trt_tree_ctx tc; + struct pt_tree_ctx tc; struct ly_out *new_out; LY_ERR erc; - struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS); + struct ly_out_clb_arg clb_arg = PT_INIT_LY_OUT_CLB_ARG(PT_PRINT, out, 0, LY_SUCCESS); LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL); - if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) { + if ((erc = ly_out_new_clb(&pt_ly_out_clb_func, &clb_arg, &new_out))) { return erc; } line_length = line_length == 0 ? SIZE_MAX : line_length; if ((module->ctx->opts & LY_CTX_SET_PRIV_PARSED) && module->compiled) { - trm_lysc_tree_ctx(module, new_out, line_length, &pc, &tc); + pt_lysc_tree_ctx(module, new_out, line_length, &tc); } else { - trm_lysp_tree_ctx(module, new_out, line_length, &pc, &tc); + pt_lysp_tree_ctx(module, new_out, line_length, &tc); } - trm_print_sections(&pc, &tc); - erc = tree_print_check_error(&clb_arg, &tc); + pt_print_sections(&tc); + erc = pt_print_check_error(&clb_arg, &tc); ly_out_free(new_out, NULL, 1); @@ -4682,12 +4037,12 @@ tree_print_module(struct ly_out *out, const struct lys_module *module, uint32_t LY_ERR tree_print_compiled_node(struct ly_out *out, const struct lysc_node *node, uint32_t options, size_t line_length) { - struct trt_printer_ctx pc; - struct trt_tree_ctx tc; + struct pt_tree_ctx tc; struct ly_out *new_out; - struct trt_wrapper wr; + struct pt_wrapper wr; LY_ERR erc; - struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS); + struct ly_out_clb_arg clb_arg = PT_INIT_LY_OUT_CLB_ARG(PT_PRINT, out, 0, LY_SUCCESS); + struct pt_keyword_stmt module = PT_EMPTY_KEYWORD_STMT; assert(out && node); @@ -4695,24 +4050,25 @@ tree_print_compiled_node(struct ly_out *out, const struct lysc_node *node, uint3 return LY_EINVAL; } - if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) { + if ((erc = ly_out_new_clb(&pt_ly_out_clb_func, &clb_arg, &new_out))) { return erc; } line_length = line_length == 0 ? SIZE_MAX : line_length; - trm_lysc_tree_ctx(node->module, new_out, line_length, &pc, &tc); + pt_lysc_tree_ctx(node->module, new_out, line_length, &tc); - trp_print_keyword_stmt(pc.fp.read.module_name(&tc), pc.max_line_length, pc.out); - trb_print_parents(node, NULL, &pc, &tc); + module = pt_read_module_name(&tc); + pt_print_keyword_stmt(&module, NULL, tc.out); + pt_print_parents(node, NULL, &tc); if (!(options & LYS_PRINT_NO_SUBSTMT)) { tc.cn = lysc_node_child(node); - wr = trb_count_depth(NULL, tc.cn); - trb_print_family_tree(wr, &pc, &tc); + wr = pt_count_depth(NULL, tc.cn); + pt_print_trees(wr, &tc); } ly_print_(out, "\n"); - erc = tree_print_check_error(&clb_arg, &tc); + erc = pt_print_check_error(&clb_arg, &tc); ly_out_free(new_out, NULL, 1); return erc; @@ -4722,27 +4078,25 @@ LY_ERR tree_print_parsed_submodule(struct ly_out *out, const struct lysp_submodule *submodp, uint32_t UNUSED(options), size_t line_length) { - struct trt_printer_ctx pc; - struct trt_tree_ctx tc; + struct pt_tree_ctx tc; struct ly_out *new_out; LY_ERR erc; - struct ly_out_clb_arg clb_arg = TRP_INIT_LY_OUT_CLB_ARG(TRD_PRINT, out, 0, LY_SUCCESS); + struct ly_out_clb_arg clb_arg = PT_INIT_LY_OUT_CLB_ARG(PT_PRINT, out, 0, LY_SUCCESS); assert(submodp); LY_CHECK_ARG_RET(submodp->mod->ctx, out, LY_EINVAL); - if ((erc = ly_out_new_clb(&trp_ly_out_clb_func, &clb_arg, &new_out))) { + if ((erc = ly_out_new_clb(&pt_ly_out_clb_func, &clb_arg, &new_out))) { return erc; } line_length = line_length == 0 ? SIZE_MAX : line_length; - trm_lysp_tree_ctx(submodp->mod, new_out, line_length, &pc, &tc); + pt_lysp_tree_ctx(submodp->mod, new_out, line_length, &tc); tc.pmod = (struct lysp_module *)submodp; - tc.tpn = submodp->data; - tc.pn = tc.tpn; + tc.pn = submodp->data; - trm_print_sections(&pc, &tc); - erc = tree_print_check_error(&clb_arg, &tc); + pt_print_sections(&tc); + erc = pt_print_check_error(&clb_arg, &tc); ly_out_free(new_out, NULL, 1); diff --git a/tests/modules/yang/sm-extension.yang b/tests/modules/yang/sm-extension.yang index 63d164a00..86651e975 100644 --- a/tests/modules/yang/sm-extension.yang +++ b/tests/modules/yang/sm-extension.yang @@ -3,6 +3,10 @@ module sm-extension { namespace "urn:sm-ext"; prefix "sm-ext"; + import sm-modp { + prefix modp; + } + list tlist { key "name"; leaf name { diff --git a/tests/plugins/simple.c b/tests/plugins/simple.c index 0a2b02d1b..f11a52c8a 100644 --- a/tests/plugins/simple.c +++ b/tests/plugins/simple.c @@ -54,8 +54,6 @@ LYPLG_EXTENSIONS = { .plugin.parse = NULL, .plugin.compile = hint_compile, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode = NULL, .plugin.validate = NULL, diff --git a/tests/utests/basic/test_plugins.c b/tests/utests/basic/test_plugins.c index 6bcf1daa2..3926b2ceb 100644 --- a/tests/utests/basic/test_plugins.c +++ b/tests/utests/basic/test_plugins.c @@ -180,8 +180,6 @@ struct lyplg_ext_record memory_recs[] = { .plugin.parse = parse_clb, .plugin.compile = NULL, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode = NULL, .plugin.validate = NULL, @@ -197,8 +195,6 @@ struct lyplg_ext_record memory_recs[] = { .plugin.parse = parse_clb2, .plugin.compile = NULL, .plugin.printer_info = NULL, - .plugin.printer_ctree = NULL, - .plugin.printer_ptree = NULL, .plugin.node_xpath = NULL, .plugin.snode = NULL, .plugin.validate = NULL, diff --git a/tests/utests/schema/test_printer_tree.c b/tests/utests/schema/test_printer_tree.c index 73f947937..e14356433 100644 --- a/tests/utests/schema/test_printer_tree.c +++ b/tests/utests/schema/test_printer_tree.c @@ -629,11 +629,11 @@ node_keys(void **state) " }\n" " }\n" " list l2 {\n" - " key \"a b\";\n" - " leaf a {\n" + " key \"aba a\";\n" + " leaf aba {\n" " type string;\n" " }\n" - " leaf b {\n" + " leaf a {\n" " type string;\n" " }\n" " }\n" @@ -647,9 +647,9 @@ node_keys(void **state) "module: a11\n" " +--rw l1* [a]\n" " | +--rw a string\n" - " +--rw l2* [a b]\n" - " | +--rw a string\n" - " | +--rw b string\n" + " +--rw l2* [aba a]\n" + " | +--rw aba string\n" + " | +--rw a string\n" " +--rw ll* string\n"; UTEST_ADD_MODULE(orig, LYS_IN_YANG, NULL, &mod); @@ -726,15 +726,30 @@ node_type_leafref(void **state) " path \"/x:pretty-long-identifier-name-which-should-exceed-the-limit-of-72-characters\";\n" " }\n" " }\n" + " leaf-list b {\n" + " type leafref {\n" + " path \"/x:pretty-long-identifier-name-which-should-exceed-the-limit-of-72-characters\";\n" + " }\n" + " }\n" + " leaf-list c {\n" + " type leafref {\n" + " path \"/x:a\";\n" + " }\n" + " }\n" "}\n"; - /* yanglint --tree-no-leafref-target --tree-line-length=72 */ + /* pyang -f tree --tree-line-length=72 */ + /* but '/a' edited to '/x:a' */ expect = "module: a13\n" " +--rw pretty-long-identifier-name-which-should-exceed-the-limit-of-72-characters?\n" " | string\n" " +--rw a?\n" - " leafref\n"; + " | leafref\n" + " +--rw b*\n" + " | leafref\n" + " +--rw c*\n" + " -> /x:a\n"; UTEST_ADD_MODULE(orig, LYS_IN_YANG, NULL, &mod); TEST_LOCAL_PRINT(mod, 72); @@ -855,6 +870,17 @@ static void line_length_twiddling(void **state) { TEST_LOCAL_SETUP; + + orig = + "module a01xx {\n" + " yang-version 1.1;\n" + " namespace \"xx:y\";\n" + " prefix xx;\n" + " container c;\n" + "}\n"; + + UTEST_ADD_MODULE(orig, LYS_IN_YANG, NULL, NULL); + /* node_fits_tight */ orig = @@ -863,6 +889,11 @@ line_length_twiddling(void **state) " namespace \"x:y\";\n" " prefix x;\n" "\n" + " import a01xx {\n" + " prefix some-very-long-long-prefix;\n" + " }\n" + "\n" + "\n" " feature f;\n" "\n" " typedef some-long-type {\n" @@ -882,6 +913,9 @@ line_length_twiddling(void **state) " type int32;\n" " }\n" " }\n" + " augment \"/some-very-long-long-prefix:c\" {\n" + " container e;\n" + " }\n" "}\n"; /* pyang --tree-line-length 42 */ @@ -890,7 +924,10 @@ line_length_twiddling(void **state) " +--rw my-list-name* [key]\n" " +--rw key string\n" " +--rw nod-leaf? some-long-type {f}?\n" - " +--rw nos-leaf? int32 {f}?\n"; + " +--rw nos-leaf? int32 {f}?\n" + "\n" + " augment /some-very-long-long-prefix:c:\n" + " +--rw e\n"; const char *feats[] = {"f", NULL}; @@ -917,7 +954,10 @@ line_length_twiddling(void **state) " +--rw key string\n" " +--rw nod-leaf? some-long-type\n" " | {f}?\n" - " +--rw nos-leaf? int32 {f}?\n"; + " +--rw nos-leaf? int32 {f}?\n" + "\n" + " augment /some-very-long-long-prefix:c:\n" + " +--rw e\n"; UTEST_ADD_MODULE(orig, LYS_IN_YANG, feats, &mod); TEST_LOCAL_PRINT(mod, 41); @@ -934,6 +974,7 @@ line_length_twiddling(void **state) ly_out_reset(UTEST_OUT); /* break_before_type */ + /* augment long path is ignored, it just doesn't fit */ /* pyang --tree-line-length 29 */ expect = @@ -944,7 +985,10 @@ line_length_twiddling(void **state) " | some-long-type\n" " | {f}?\n" " +--rw nos-leaf? int32\n" - " {f}?\n"; + " {f}?\n" + "\n" + " augment /some-very-long-long-prefix:c:\n" + " +--rw e\n"; UTEST_ADD_MODULE(orig, LYS_IN_YANG, feats, &mod); TEST_LOCAL_PRINT(mod, 29); @@ -973,7 +1017,10 @@ line_length_twiddling(void **state) " | some-long-type\n" " | {f}?\n" " +--rw nos-leaf?\n" - " int32 {f}?\n"; + " int32 {f}?\n" + "\n" + " augment /some-very-long-long-prefix:c:\n" + " +--rw e\n"; UTEST_ADD_MODULE(orig, LYS_IN_YANG, feats, &mod); TEST_LOCAL_PRINT(mod, 23); @@ -1003,7 +1050,10 @@ line_length_twiddling(void **state) " | {f}?\n" " +--rw nos-leaf?\n" " int32\n" - " {f}?\n"; + " {f}?\n" + "\n" + " augment /some-very-long-long-prefix:c:\n" + " +--rw e\n"; UTEST_ADD_MODULE(orig, LYS_IN_YANG, feats, &mod); TEST_LOCAL_PRINT(mod, 14); @@ -1848,9 +1898,9 @@ yang_data(void **state) /* from pyang (--tree-print-yang-data --tree-print-groupings -p "...") * but with these adjustments: - * - is always '--' for yang-data nodes * - yang-data tmp3 has two 'uses' nodes - * - grouping g2 has ':' character at the end + * - grouping g1 has not ':' character at the end + * - grouping has ---- cont3 node (not -- cont3) */ expect = "module: a28\n" @@ -1861,23 +1911,23 @@ yang_data(void **state) " +---- cont3\n" "\n" " yang-data tmp1:\n" - " +---- cont1\n" - " +---- lf? string\n" - " +---- l2* [a b]\n" - " +---- a string\n" - " +---- b string\n" + " +-- cont1\n" + " +-- lf? string\n" + " +-- l2* [a b]\n" + " +-- a string\n" + " +-- b string\n" " yang-data tmp2:\n" - " +---- con2\n" - " +---- lf? string\n" + " +-- con2\n" + " +-- lf? string\n" " yang-data tmp3:\n" " +---u g1\n" " +---u g2\n" " yang-data tmp4:\n" - " +---- (x)?\n" + " +-- (x)?\n" " +--:(a)\n" - " | +---- z\n" + " | +-- z\n" " +--:(b)\n" - " +---- y\n"; + " +-- y\n"; UTEST_ADD_MODULE(orig, LYS_IN_YANG, NULL, &mod); TEST_LOCAL_PRINT(mod, 72); @@ -1887,30 +1937,28 @@ yang_data(void **state) ly_out_reset(UTEST_OUT); /* from pyang (--tree-print-yang-data -p "...") - * but with these adjustments: - * is always '--' for yang-data nodes */ expect = "module: a28\n" " +--rw mont\n" "\n" " yang-data tmp1:\n" - " +---- cont1\n" - " +---- lf? string\n" - " +---- l2* [a b]\n" - " +---- a string\n" - " +---- b string\n" + " +-- cont1\n" + " +-- lf? string\n" + " +-- l2* [a b]\n" + " +-- a string\n" + " +-- b string\n" " yang-data tmp2:\n" - " +---- con2\n" - " +---- lf? string\n" + " +-- con2\n" + " +-- lf? string\n" " yang-data tmp3:\n" - " +---- cont3\n" + " +-- cont3\n" " yang-data tmp4:\n" - " +---- (x)?\n" + " +-- (x)?\n" " +--:(a)\n" - " | +---- z\n" + " | +-- z\n" " +--:(b)\n" - " +---- y\n"; + " +-- y\n"; /* using lysc tree */ ly_ctx_set_options(UTEST_LYCTX, LY_CTX_SET_PRIV_PARSED); @@ -1922,85 +1970,180 @@ yang_data(void **state) TEST_LOCAL_TEARDOWN; } -#define SM_MODNAME_EXT "sm-extension" -#define SM_MOD_EXT_NAMESPACE "urn:sm-ext" -#define SM_PREF "sm" -#define SCHEMA_REF_INLINE "" -#define SCHEMA_REF_SHARED(REF) ""REF"" - -#define EXT_DATA(MP_XML_START, MP_XML_END, MPMOD_NAME, MODULES, SCHEMA_REF) \ - MP_XML_START \ - "\n" \ - "\n" \ - " test-set\n" \ - " \n" \ - " "SM_MODNAME_EXT"\n" \ - " "SM_MOD_EXT_NAMESPACE"\n" \ - " \n" \ - MODULES \ - "\n" \ - "1\n" \ - "\n" \ - "\n" \ - "1\n" \ - "\n" \ - MP_XML_END \ - "\n" \ - "\n" \ - " "SM_PREF"\n" \ - " x:"MPMOD_NAME"\n" \ - "\n" \ - "\n" \ - " "MPMOD_NAME"\n" \ - " \n" \ - SCHEMA_REF \ - "\n" \ - "" - -#define SM_MOD_MAIN(NAME, BODY) \ - "module "NAME" {\n" \ - " yang-version 1.1;\n" \ - " namespace \"x:"NAME"\";\n" \ - " prefix \"x\";\n" \ - " import ietf-yang-schema-mount {\n" \ - " prefix yangmnt;\n" \ - " }\n" \ - BODY \ - "}" +static LY_ERR +ext_data_clb(const struct lysc_ext_instance *ext, const struct lyd_node *UNUSED(parent), void *user_data, + void **ext_data, ly_bool *ext_data_free) +{ + static int recursive_call = 0; + LY_ERR r = LY_SUCCESS; + + *ext_data = NULL; + *ext_data_free = 0; + if (recursive_call) { + return LY_SUCCESS; + } + recursive_call = 1; + if (user_data) { + r = lyd_parse_data_mem(ext->module->ctx, user_data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, (struct lyd_node **)ext_data); + } + recursive_call = 0; + if (r) { + return r; + } + *ext_data_free = 1; + return LY_SUCCESS; +} static void mount_point(void **state) { TEST_LOCAL_SETUP; + char *data; - /* interested in sm-extension.yang and sm-mod.yang */ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG)); - /* - * 'mp' flag for list and container - */ - orig = SM_MOD_MAIN("a29", - "list lt {\n" - " key \"name\";\n" - " leaf name {\n" - " type string;\n" + orig = + "module mp-module {\n" + " yang-version 1.1;\n" + " namespace \"urn:yanglint:mpm\";\n" + " prefix \"mpm\";\n" + "\n" + " import ietf-yang-schema-mount {\n" + " prefix yangmnt;\n" " }\n" - " yangmnt:mount-point \"mnt-root\";\n" - "}\n" - "container cont {\n" - " yangmnt:mount-point \"mnt-root\";\n" - "}\n"); - expect = - "module: a29\n" - " +--mp lt* [name]\n" - " | +--rw name string\n" - " +--mp cont\n"; + " import ietf-interfaces {\n" + " prefix if;\n" + " }\n" + "\n" + " list root {\n" + " key \"node\";\n" + " leaf node {\n" + " type string;\n" + " }\n" + " yangmnt:mount-point \"root\";\n" + " }\n" + " container root2 {\n" + " yangmnt:mount-point \"root\";\n" + " }\n" + " container root3 {\n" + " list my-list {\n" + " key name;\n" + " leaf name {\n" + " type string;\n" + " }\n" + " yangmnt:mount-point \"mnt-root\";\n" + " }\n" + " }\n" + "}"; + + /* data for mountin */ + data = + "\n" + " \n" + " list item 1\n" + " \n" + " \n" + " test-set\n" + " \n" + " ietf-datastores\n" + " 2018-02-14\n" + " urn:ietf:params:xml:ns:yang:ietf-datastores\n" + " \n" + " \n" + " ietf-yang-library\n" + " 2019-01-04\n" + " urn:ietf:params:xml:ns:yang:ietf-yang-library\n" + " \n" + " \n" + " sm-extension\n" + " urn:sm-ext\n" + " \n" + " \n" + " iana-if-type\n" + " urn:ietf:params:xml:ns:yang:iana-if-type\n" + " \n" + " \n" + " ietf-interfaces\n" + " urn:ietf:params:xml:ns:yang:ietf-interfaces\n" + " \n" + " \n" + " ietf-yang-types\n" + " 2013-07-15\n" + " urn:ietf:params:xml:ns:yang:ietf-yang-types\n" + " \n" + " \n" + " sm-modp\n" + " 2017-01-26\n" + " urn:sm-modp\n" + " \n" + " \n" + " \n" + " test-schema\n" + " test-set\n" + " \n" + " \n" + " ds:running\n" + " test-schema\n" + " \n" + " \n" + " ds:operational\n" + " test-schema\n" + " \n" + " 1\n" + " \n" + " \n" + " 1\n" + " \n" + " \n" + "\n" + "\n" + " \n" + " if\n" + " urn:ietf:params:xml:ns:yang:ietf-interfaces\n" + " \n" + " \n" + " mp-module\n" + " \n" + " \n" + " /if:interfaces/if:interface/if:name\n" + " /if:interfaces/if:interface/if:type\n" + " \n" + " \n" + "\n"; + + /* set extension data */ + ly_ctx_set_options(UTEST_LYCTX, LY_CTX_SET_PRIV_PARSED); + assert_int_equal(ly_ctx_set_ext_data_clb(UTEST_LYCTX, ext_data_clb, data), LY_SUCCESS); + assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-interfaces", "2014-05-08", NULL)); UTEST_ADD_MODULE(orig, LYS_IN_YANG, NULL, &mod); + + expect = + "module: mp-module\n" + " +--mp root* [node]\n" + " | +--rw node string\n" + " +--mp root2\n" + " +--rw root3\n" + " +--mp my-list* [name]\n" + " +--rw tlist/ [name]\n" + " | +--rw name uint32\n" + " +--rw tcont/\n" + " | +--rw tleaf? uint32\n" + " +--mp ncmp/\n" + " +--rw not-compiled/\n" + " | +--rw first? string\n" + " | +--rw second? string\n" + " +--rw interfaces@\n" + " | +--rw interface* [name]\n" + " | +--rw name string\n" + " | +--rw type identityref\n" + " +--rw name string\n"; + + /* using lysc tree */ TEST_LOCAL_PRINT(mod, 72); assert_int_equal(strlen(expect), ly_out_printed(UTEST_OUT)); assert_string_equal(printed, expect); - ly_out_reset(UTEST_OUT); + ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_SET_PRIV_PARSED); TEST_LOCAL_TEARDOWN; } diff --git a/tools/lint/common.c b/tools/lint/common.c index b02486488..54c4c4668 100644 --- a/tools/lint/common.c +++ b/tools/lint/common.c @@ -277,12 +277,29 @@ LY_ERR ext_data_clb(const struct lysc_ext_instance *ext, const struct lyd_node *UNUSED(parent), void *user_data, void **ext_data, ly_bool *ext_data_free) { - struct ly_ctx *ctx; struct lyd_node *data = NULL; + static int recursive_call = 0; + LY_ERR r = LY_SUCCESS; - ctx = ext->module->ctx; + *ext_data = NULL; + *ext_data_free = 0; + + if (recursive_call) { + /* called recursively, when processing only `ietf-yang-library` and `ietf-yang-schema-mount` data, + * NULL ext_data can be returned */ + return LY_SUCCESS; + } + + /* the required operational data include mounted data so we must prevent this callback from being called + * recursively again, infinitely */ + recursive_call = 1; if (user_data) { - lyd_parse_data_path(ctx, user_data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &data); + r = lyd_parse_data_path(ext->module->ctx, user_data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &data); + } + recursive_call = 0; + + if (r) { + return r; } *ext_data = data; diff --git a/tools/lint/examples/README.md b/tools/lint/examples/README.md index d24001824..8e663407c 100644 --- a/tools/lint/examples/README.md +++ b/tools/lint/examples/README.md @@ -488,7 +488,7 @@ module: sm-main +--mp root2 +--rw root3 +--mp my-list* [name] - +--rw things/* [name] + +--rw things/ [name] | +--rw name -> /if:interfaces/if:interface/if:name | +--rw attribute? uint32 +--rw not-compiled/ diff --git a/tools/lint/examples/sm-context-extension.xml b/tools/lint/examples/sm-context-extension.xml index 747c60ffc..47b432d05 100644 --- a/tools/lint/examples/sm-context-extension.xml +++ b/tools/lint/examples/sm-context-extension.xml @@ -1,53 +1,62 @@ - - - test-set - - ietf-datastores - 2018-02-14 - urn:ietf:params:xml:ns:yang:ietf-datastores - - - ietf-yang-library - 2019-01-04 - urn:ietf:params:xml:ns:yang:ietf-yang-library - - - sm-extension - urn:sm-ext - - - iana-if-type - urn:ietf:params:xml:ns:yang:iana-if-type - - - ietf-yang-types - 2013-07-15 - urn:ietf:params:xml:ns:yang:ietf-yang-types - - - sm-mod - 2017-01-26 - urn:yanglint:sm-mod - - - - test-schema - test-set - - - ds:running - test-schema - - - ds:operational - test-schema - - 1 - - - 1 - + + + list item 1 + + + test-set + + ietf-datastores + 2018-02-14 + urn:ietf:params:xml:ns:yang:ietf-datastores + + + ietf-yang-library + 2019-01-04 + urn:ietf:params:xml:ns:yang:ietf-yang-library + + + sm-extension + urn:sm-ext + + + iana-if-type + urn:ietf:params:xml:ns:yang:iana-if-type + + + ietf-interfaces + urn:ietf:params:xml:ns:yang:ietf-interfaces + + + ietf-yang-types + 2013-07-15 + urn:ietf:params:xml:ns:yang:ietf-yang-types + + + sm-mod + 2017-01-26 + urn:yanglint:sm-mod + + + + test-schema + test-set + + + ds:running + test-schema + + + ds:operational + test-schema + + 1 + + + 1 + + + if