yanglint FEATURE schema mount support (#1901)
* modify existing context if provided
In ly_ctx_new_yldata(), check if *ctx is NULL. If so, proceed as before
with allocating a new context. Otherwise, load modules into the existing
context.
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
* add parent-reference xpath helper to schema-mount plugin
This new function produces a list of schema nodes from the expanded
parent-reference xpath expressions.
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
* add context lookup to schema-mount plugin
This function allocates a new context for a particular instance of the
yangmnt:mount-point extension.
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
* yanglint: schema-mount extension callback
Add a commandline argument "-x" that accepts a file containing extension
data, used to create a context for the schema-mount extension. This file
has the same format as what is provided to the "-Y" option. A callback
function for the schema-mount extenion is registered if the new option
is specified.
This allows validating instance data for models that include a schema
mount point.
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
* yanglint: print mounted schema trees
Display "mp" flag for mount point and print mounted tree. Also display
the / and @ opts in node names.
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
* add unit test for tree mount-point flag
Test is courtesy of aPiecek <piecek@cesnet.cz>.
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
* add example data files for validation with schema-mount
From tools/lint/examples directory:
% ../../../build/yanglint \
-f json -t config -p ../../../models -p . \
-Y ./sm-context-main.xml -x ./sm-context-extension.xml sm-data.xml
% ../../../build/yanglint \
-f tree -p ../../../models -p . \
-Y ./sm-context-main.xml -x ./sm-context-extension.xml sm-main.yang
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
Co-authored-by: Eric Kinzie <ekinzie@labn.net>
diff --git a/src/context.c b/src/context.c
index 3a3c10b..98ae10f 100644
--- a/src/context.c
+++ b/src/context.c
@@ -454,7 +454,11 @@
LY_CHECK_ARG_RET(NULL, tree, ctx, LY_EINVAL);
/* create a new context */
- LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
+ if (*ctx == NULL) {
+ LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
+ } else {
+ ctx_new = *ctx;
+ }
/* redundant to compile modules one-by-one */
if (!(options & LY_CTX_EXPLICIT_COMPILE)) {
@@ -519,10 +523,12 @@
cleanup:
ly_set_free(set, NULL);
ly_set_erase(&features, NULL);
- *ctx = ctx_new;
- if (ret) {
- ly_ctx_destroy(*ctx);
- *ctx = NULL;
+ if (*ctx == NULL) {
+ *ctx = ctx_new;
+ if (ret) {
+ ly_ctx_destroy(*ctx);
+ *ctx = NULL;
+ }
}
return ret;
}
diff --git a/src/context.h b/src/context.h
index 71cc590..331a89f 100644
--- a/src/context.h
+++ b/src/context.h
@@ -241,7 +241,8 @@
* @param[in] path Path to the file containing yang-library-data in the specified format
* @param[in] format Format of the data in the provided file.
* @param[in] options Context options, see @ref contextoptions.
- * @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
+ * @param[in,out] ctx If *ctx is not NULL, the existing libyang context is modified. Otherwise, a pointer to a
+ * newly created context is returned here if LY_SUCCESS.
* @return LY_ERR return value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options,
@@ -257,7 +258,8 @@
* @param[in] data String containing yang-library data in the specified format.
* @param[in] format Format of the data in the provided file.
* @param[in] options Context options, see @ref contextoptions.
- * @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
+ * @param[in,out] ctx If *ctx is not NULL, the existing libyang context is modified. Otherwise, a pointer to a
+ * newly created context is returned here if LY_SUCCESS.
* @return LY_ERR return value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options,
@@ -272,7 +274,8 @@
* If no such directory is available, NULL is accepted.
* @param[in] tree Data tree containing yang-library data.
* @param[in] options Context options, see @ref contextoptions.
- * @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
+ * @param[in,out] ctx If *ctx is not NULL, the existing libyang context is modified. Otherwise, a pointer to a
+ * newly created context is returned here if LY_SUCCESS.
* @return LY_ERR return value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_new_yldata(const char *search_dir, const struct lyd_node *tree, int options,
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index c473158..298557c 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -281,6 +281,27 @@
LIBYANG_API_DECL void lyplg_ext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path,
const char *format, ...);
+/**
+ * @brief Expand parent-reference xpath expressions
+ *
+ * @param ext[in] context allocated for extension
+ * @param refs[out] set of lysc nodes matching parent-refernce xpaths
+ * @return LY_ERR value.
+ */
+LIBYANG_API_DECL LY_ERR lyplg_ext_schema_mount_get_parent_ref(const struct lysc_ext_instance *ext, struct ly_set **refs);
+
+/**
+ * @brief Allocate a new context for a particular instance of the
+ * yangmnt:mount-point extension. Caller is responsible for destroying
+ * the resulting context.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[out] ctx A context with modules loaded from the list found in
+ * the extension data.
+ * @return LY_ERR value.
+ */
+LIBYANG_API_DECL LY_ERR lyplg_ext_schema_mount_create_context(const struct lysc_ext_instance *ext, struct ly_ctx **ctx);
+
/** @} pluginsExtensions */
#ifdef __cplusplus
diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c
index 7aed9a9..8661894 100644
--- a/src/plugins_exts/schema_mount.c
+++ b/src/plugins_exts/schema_mount.c
@@ -351,7 +351,7 @@
struct lyplg_ext_sm *sm_data = ext->data;
LY_ERR ret = LY_SUCCESS, r;
struct lyd_node *node = NULL;
- struct ly_ctx *new_ctx;
+ struct ly_ctx *new_ctx = NULL;
uint32_t i;
const char *content_id = NULL;
void *mem;
@@ -442,7 +442,7 @@
{
struct lyplg_ext_sm *sm_data = ext->data;
LY_ERR r;
- struct ly_ctx *new_ctx;
+ struct ly_ctx *new_ctx = NULL;
uint32_t i;
void *mem;
@@ -538,7 +538,7 @@
{
LY_ERR r;
const struct lys_module *mod;
- const struct ly_ctx *ext_ctx;
+ const struct ly_ctx *ext_ctx = NULL;
/* get context based on ietf-yang-library data */
if ((r = schema_mount_get_ctx(ext, &ext_ctx))) {
@@ -556,6 +556,27 @@
return *snode ? LY_SUCCESS : LY_ENOT;
}
+static LY_ERR
+schema_mount_get_parent_ref(const struct lysc_ext_instance *ext, const struct lyd_node *ext_data,
+ struct ly_set **set)
+{
+ LY_ERR ret = LY_SUCCESS;
+ char *path = NULL;
+
+ /* get all parent references of this mount point */
+ if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']"
+ "/shared-schema/parent-reference", ext->module->name, ext->argument) == -1) {
+ EXT_LOGERR_MEM_GOTO(ext, ret, cleanup);
+ }
+ if ((ret = lyd_find_xpath(ext_data, path, set))) {
+ goto cleanup;
+ }
+
+cleanup:
+ free(path);
+ return ret;
+}
+
/**
* @brief Duplicate all accessible parent references for a shared-schema mount point.
*
@@ -587,12 +608,7 @@
goto cleanup;
}
- /* get all parent references of this mount point */
- if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']"
- "/shared-schema/parent-reference", ext->module->name, ext->argument) == -1) {
- EXT_LOGERR_MEM_GOTO(ext, ret, cleanup);
- }
- if ((ret = lyd_find_xpath(ext_data, path, &set))) {
+ if ((ret = schema_mount_get_parent_ref(ext, ext_data, &set))) {
goto cleanup;
}
@@ -671,6 +687,61 @@
return ret;
}
+LY_ERR
+lyplg_ext_schema_mount_get_parent_ref(const struct lysc_ext_instance *ext, struct ly_set **refs)
+{
+ LY_ERR res;
+ struct ly_set *pref_set = NULL;
+ struct ly_set *snode_set;
+ struct ly_set *results_set = NULL;
+ struct lyd_node *ext_data;
+ ly_bool ext_data_free;
+
+ /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
+ if ((res = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
+ return res;
+ }
+
+ LY_CHECK_GOTO(res = schema_mount_get_parent_ref(ext, ext_data, &pref_set), out);
+ if (pref_set->count == 0) {
+ goto out;
+ }
+
+ LY_CHECK_GOTO(res = ly_set_new(&results_set), out);
+
+ for (uint32_t i = 0; i < pref_set->count; ++i) {
+ struct lyd_node_term *term;
+ struct lyd_value_xpath10 *xp_val;
+ char *value;
+ struct ly_err_item *err;
+
+ term = (struct lyd_node_term *)pref_set->dnodes[i];
+ LYD_VALUE_GET(&term->value, xp_val);
+ LY_CHECK_GOTO(res = lyplg_type_print_xpath10_value(xp_val, LY_VALUE_JSON, NULL, &value, &err), out);
+ LY_CHECK_ERR_GOTO(res = lys_find_xpath(ext->module->ctx, NULL, value, 0, &snode_set), free(value), out);
+ free(value);
+ for (uint32_t sn = 0; sn < snode_set->count; sn++) {
+ struct lysc_node *snode = snode_set->snodes[sn];
+
+ if ((res = ly_set_add(results_set, snode, 0, NULL))) {
+ ly_set_free(snode_set, NULL);
+ ly_set_free(results_set, NULL);
+ goto out;
+ }
+ }
+ ly_set_free(snode_set, NULL);
+ }
+
+ *refs = results_set;
+
+out:
+ if (ext_data_free) {
+ lyd_free_all(ext_data);
+ }
+ ly_set_free(pref_set, NULL);
+ return res;
+}
+
/**
* @brief Validate callback for schema mount.
*/
@@ -836,6 +907,43 @@
free(sm_data);
}
+LIBYANG_API_DEF LY_ERR
+lyplg_ext_schema_mount_create_context(const struct lysc_ext_instance *ext, struct ly_ctx **ctx)
+{
+ struct lyd_node *ext_data;
+ ly_bool ext_data_free;
+ ly_bool config;
+ ly_bool shared;
+ LY_ERR res;
+
+ if (!ext->module->ctx->ext_clb) {
+ return LY_EINVAL;
+ }
+
+ if (strcmp(ext->def->module->name, "ietf-yang-schema-mount") ||
+ strcmp(ext->def->name, "mount-point")) {
+ return LY_EINVAL;
+ }
+
+ /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
+ if ((res = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
+ return res;
+ }
+
+ /* learn about this mount point */
+ if ((res = schema_mount_get_smount(ext, ext_data, &config, &shared))) {
+ goto out;
+ }
+
+ res = schema_mount_create_ctx(ext, ext_data, config, ctx);
+
+out:
+ if (ext_data_free) {
+ lyd_free_all(ext_data);
+ }
+ return res;
+}
+
/**
* @brief Plugin descriptions for the Yang Schema Mount extension.
*
diff --git a/src/printer_tree.c b/src/printer_tree.c
index 963dc4c..d0d1024 100644
--- a/src/printer_tree.c
+++ b/src/printer_tree.c
@@ -93,6 +93,8 @@
#include "common.h"
#include "compat.h"
#include "out_internal.h"
+#include "plugins_exts.h"
+#include "plugins_types.h"
#include "printer_schema.h"
#include "tree_schema_internal.h"
#include "xpath.h"
@@ -453,6 +455,8 @@
ly_bool iffeatures; /**< \<if-features\>. Value 1 means that iffeatures are present and
will be printed by trt_fp_print.print_features_names callback. */
ly_bool last_one; /**< Information about whether the node is the last. */
+ struct lysc_ext_instance
+ *mount; /**< Mount-point extension if flags == TRD_FLAGS_TYPE_MOUNT_POINT */
};
/**
@@ -465,7 +469,8 @@
.name = TRP_EMPTY_NODE_NAME, \
.type = TRP_EMPTY_TRT_TYPE, \
.iffeatures = 0, \
- .last_one = 1 \
+ .last_one = 1, \
+ .mount = NULL \
}
/**
@@ -687,6 +692,7 @@
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. */
+ ly_bool mounted; /**< This tree is a mounted schema */
trt_actual_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. */
@@ -698,6 +704,8 @@
is set to TRD_SECT_YANG_DATA. */
};
const struct lysc_node *cn; /**< Actual pointer to compiled node. */
+ const struct ly_set *parent_refs; /**< List of schema nodes for top-level nodes found in mount
+ point parent references */
};
/**
@@ -718,6 +726,15 @@
#define TRP_TREE_CTX_GET_LYSP_NODE(CN) \
((const struct lysp_node *)CN->priv)
+/**
+ * @brief Context for mounted module
+ *
+ */
+struct trt_mount_ctx {
+ struct trt_printer_ctx pc;
+ struct trt_tree_ctx tc;
+};
+
/** Getter function for ::trop_node_charptr(). */
typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
@@ -742,6 +759,12 @@
};
/**********************************************************************
+ * Forward declarations
+ *********************************************************************/
+static LY_ERR trb_print_mount_point(struct trt_node *node, struct trt_wrapper wr,
+ struct trt_printer_ctx *pc, struct trt_tree_ctx *tc);
+
+/**********************************************************************
* Definition of the general Trg functions
*********************************************************************/
@@ -905,6 +928,20 @@
}
/**
+ * @brief Set '|' symbol to connect current level nodes in a module.
+ * This is only used to connect all top-level nodes in all modules under
+ * a schema mount point.
+ * @param[in] wr is the wrapper to be marked
+ * @return New wrapper which is marked at actual position.
+ */
+static struct trt_wrapper
+trp_wrapper_set_mark_top(struct trt_wrapper wr)
+{
+ wr.bit_marks1 |= 1U << wr.actual_pos;
+ return 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
@@ -2601,6 +2638,49 @@
}
/**
+ * @brief Check if container has yangmt:mount-point extension.
+ * @param[in] cn is pointer to container or list.
+ * @param[out] mount is assigned a pointer to the extension instance, if found
+ * @return 1 if container has mount-point.
+ */
+static ly_bool
+troc_node_has_mount(const struct lysc_node *cn, struct lysc_ext_instance **mount)
+{
+ struct lysc_ext_instance *ext;
+ uint64_t u;
+
+ /* The schema-mount extension plugin has already made sure that
+ * there is only one mount-point here.
+ */
+ LY_ARRAY_FOR(cn->exts, u) {
+ ext = &cn->exts[u];
+ if (strcmp(ext->def->module->name, "ietf-yang-schema-mount") ||
+ strcmp(ext->def->name, "mount-point")) {
+ continue;
+ }
+ *mount = ext;
+ return 1;
+ }
+ return 0;
+}
+
+static ly_bool
+trop_node_has_mount(const struct lysp_node *pn)
+{
+ struct lysp_ext_instance *ext;
+ uint64_t u;
+
+ LY_ARRAY_FOR(pn->exts, u) {
+ ext = &pn->exts[u];
+ if (strcmp(ext->name, "yangmnt:mount-point")) {
+ continue;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/**
* @brief Get leaflist's path without lysp_node type control.
* @param[in] pn is pointer to the leaflist.
*/
@@ -2739,8 +2819,10 @@
* Obtained from the trt_parent_cache.
*/
static trt_node_type
-trop_resolve_node_type(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
+trop_resolve_node_type(const struct trt_tree_ctx *tc, const struct lysp_node_list *ca_last_list)
{
+ const struct lysp_node *pn = tc->pn;
+
if (pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
return TRD_NODE_ELSE;
} else if (pn->nodetype & LYS_CASE) {
@@ -2749,6 +2831,15 @@
return TRD_NODE_OPTIONAL_CHOICE;
} else if (pn->nodetype & LYS_CHOICE) {
return TRD_NODE_CHOICE;
+ } else if (tc->mounted && (tc->pn->parent == NULL)) {
+ if (tc->parent_refs) {
+ for (uint32_t v = 0; v < tc->parent_refs->count; v++) {
+ if (!strcmp(tc->pmod->mod->ns, tc->parent_refs->snodes[v]->module->ns)) {
+ return TRD_NODE_TOP_LEVEL2;
+ }
+ }
+ }
+ return TRD_NODE_TOP_LEVEL1;
} else if ((pn->nodetype & LYS_CONTAINER) && (trop_container_has_presence(pn))) {
return TRD_NODE_CONTAINER;
} else if ((pn->nodetype & LYS_LIST) && (trop_list_has_keys(pn))) {
@@ -2810,14 +2901,15 @@
/* <status> */
ret.status = trop_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
- /* TODO: TRD_FLAGS_TYPE_MOUNT_POINT aka "mp" is not supported right now. */
/* <flags> */
- ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config);
+ if (trop_node_has_mount(pn)) {
+ ret.flags = TRD_FLAGS_TYPE_MOUNT_POINT;
+ } else {
+ ret.flags = trop_resolve_flags(pn->nodetype, pn->flags, ca.ancestor, ca.lys_config);
+ }
- /* TODO: TRD_NODE_TOP_LEVEL1 aka '/' is not supported right now. */
- /* TODO: TRD_NODE_TOP_LEVEL2 aka '@' is not supported right now. */
/* set type of the node */
- ret.name.type = trop_resolve_node_type(pn, ca.last_list);
+ ret.name.type = trop_resolve_node_type(tc, ca.last_list);
/* The parsed tree is not compiled, so no node can be augmented
* from another module. This means that nodes from the parsed tree
@@ -3128,7 +3220,7 @@
* @param[in] flags is current lysc_node.flags.
*/
static trt_node_type
-troc_resolve_node_type(uint16_t nodetype, uint16_t flags)
+troc_resolve_node_type(const struct trt_tree_ctx *tc, uint16_t nodetype, uint16_t flags)
{
if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
return TRD_NODE_ELSE;
@@ -3138,6 +3230,15 @@
return TRD_NODE_OPTIONAL_CHOICE;
} else if (nodetype & LYS_CHOICE) {
return TRD_NODE_CHOICE;
+ } else if (tc->mounted && (tc->cn->parent == NULL)) {
+ if (tc->parent_refs) {
+ for (uint32_t v = 0; v < tc->parent_refs->count; v++) {
+ if (!strcmp(tc->cn->module->ns, tc->parent_refs->snodes[v]->module->ns)) {
+ return TRD_NODE_TOP_LEVEL2;
+ }
+ }
+ }
+ return TRD_NODE_TOP_LEVEL1;
} else if ((nodetype & LYS_CONTAINER) && (flags & LYS_PRESENCE)) {
return TRD_NODE_CONTAINER;
} else if ((nodetype & LYS_LIST) && !(flags & LYS_KEYLESS)) {
@@ -3196,14 +3297,15 @@
/* <status> */
ret.status = tro_flags2status(cn->flags);
- /* TODO: TRD_FLAGS_TYPE_MOUNT_POINT aka "mp" is not supported right now. */
/* <flags> */
- ret.flags = troc_resolve_flags(cn->nodetype, cn->flags);
+ if (troc_node_has_mount(cn, &ret.mount)) {
+ ret.flags = TRD_FLAGS_TYPE_MOUNT_POINT;
+ } else {
+ ret.flags = troc_resolve_flags(cn->nodetype, cn->flags);
+ }
- /* TODO: TRD_NODE_TOP_LEVEL1 aka '/' is not supported right now. */
- /* TODO: TRD_NODE_TOP_LEVEL2 aka '@' is not supported right now. */
/* set type of the node */
- ret.name.type = troc_resolve_node_type(cn->nodetype, cn->flags);
+ ret.name.type = troc_resolve_node_type(tc, cn->nodetype, cn->flags);
/* <prefix> */
ret.name.module_prefix = troc_resolve_node_prefix(cn, tc->cmod);
@@ -3402,6 +3504,23 @@
/* 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);
+ if (node.flags == TRD_FLAGS_TYPE_MOUNT_POINT) {
+ struct trt_wrapper wr_mount;
+ struct tro_getters get;
+
+ wr_mount = pc->fp.read.if_sibling_exists(tc) ?
+ trp_wrapper_set_mark(wr) : trp_wrapper_set_shift(wr);
+
+ get = tc->lysc_tree ? troc_init_getters() : trop_init_getters();
+ if (get.child(tc->lysc_tree ? (void *)tc->cn : (void *)tc->pn)) {
+ /* If this node has a child, we need to draw a vertical line
+ * from the last mounted module to the first child
+ */
+ wr_mount = trp_wrapper_set_mark_top(wr_mount);
+ }
+
+ trb_print_mount_point(&node, wr_mount, pc, tc);
+ }
}
/**
@@ -3623,13 +3742,14 @@
/**
* @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.
*/
static struct trt_wrapper
-trb_count_depth(const struct lysc_node *node)
+trb_count_depth(const struct trt_wrapper *wr_in, const struct lysc_node *node)
{
- struct trt_wrapper wr = TRP_INIT_WRAPPER_TOP;
+ struct trt_wrapper wr = wr_in ? *wr_in : TRP_INIT_WRAPPER_TOP;
const struct lysc_node *parent;
if (!node) {
@@ -3654,7 +3774,7 @@
* @return wrapper for @p node.
*/
static void
-trb_print_parents(const struct lysc_node *node, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
+trb_print_parents(const struct lysc_node *node, struct trt_wrapper *wr_in, struct trt_printer_ctx *pc, struct trt_tree_ctx *tc)
{
struct trt_wrapper wr;
struct trt_node print_node;
@@ -3665,11 +3785,11 @@
if (!node) {
return;
}
- trb_print_parents(node->parent, pc, tc);
+ trb_print_parents(node->parent, wr_in, pc, tc);
/* setup for printing */
tc->cn = node;
- wr = trb_count_depth(node);
+ wr = trb_count_depth(wr_in, node);
/* print node */
ly_print_(pc->out, "\n");
@@ -3750,6 +3870,7 @@
struct trt_parent_cache new_ca;
trb_print_entire_node(node, max_gap_before_type, wr, pc, tc);
+
/* go to the actual node's child */
new_ca = tro_parent_cache_for_child(ca, tc);
node = pc->fp.modify.next_child(ca, tc);
@@ -4292,11 +4413,11 @@
trm_lysc_tree_ctx(node->module, new_out, line_length, &pc, &tc);
trp_print_keyword_stmt(pc.fp.read.module_name(&tc), pc.max_line_length, 0, pc.out);
- trb_print_parents(node, &pc, &tc);
+ trb_print_parents(node, NULL, &pc, &tc);
if (!(options & LYS_PRINT_NO_SUBSTMT)) {
tc.cn = lysc_node_child(node);
- wr = trb_count_depth(tc.cn);
+ wr = trb_count_depth(NULL, tc.cn);
trb_print_family_tree(wr, &pc, &tc);
}
ly_print_(out, "\n");
@@ -4337,3 +4458,101 @@
return erc;
}
+
+static LY_ERR
+trb_print_mount_point(struct trt_node *node, struct trt_wrapper wr, struct trt_printer_ctx *pc,
+ struct trt_tree_ctx *UNUSED(tc))
+{
+ struct ly_ctx *ext_ctx = NULL;
+ const struct lys_module *mod;
+ struct trt_tree_ctx tmptc;
+ struct trt_wrapper tmpwr;
+ struct trt_printer_ctx tmppc;
+ struct trt_mount_ctx *mc;
+ struct ly_set *modules;
+ struct ly_set *refs = NULL;
+ LY_ERR err = LY_SUCCESS;
+
+ if (!node->mount) {
+ /* modules are parsed only */
+ return LY_SUCCESS;
+ }
+
+ if (lyplg_ext_schema_mount_create_context(node->mount, &ext_ctx)) {
+ /* Void mount point */
+ return LY_SUCCESS;
+ }
+
+ if (ly_set_new(&modules)) {
+ err = LY_SUCCESS;
+ goto out_ctx;
+ }
+
+ lyplg_ext_schema_mount_get_parent_ref(node->mount, &refs);
+
+ /* 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.
+ */
+ uint32_t v = ly_ctx_internal_modules_count(ext_ctx);
+
+ tmppc = *pc;
+ while ((mod = ly_ctx_get_module_iter(ext_ctx, &v))) {
+ uint32_t siblings;
+ ly_bool from_parent_ref = 0;
+
+ for (uint32_t pr = 0; refs && pr < refs->count; pr++) {
+ if (!strcmp(mod->ns, refs->snodes[pr]->module->ns)) {
+ from_parent_ref = 1;
+ break;
+ }
+ }
+ if (from_parent_ref) {
+ continue;
+ }
+
+ if ((ext_ctx->flags & LY_CTX_SET_PRIV_PARSED) && mod->compiled) {
+ trm_lysc_tree_ctx(mod, pc->out, pc->max_line_length, &tmppc, &tmptc);
+ } else {
+ trm_lysp_tree_ctx(mod, pc->out, pc->max_line_length, &tmppc, &tmptc);
+ }
+
+ siblings = (tmptc.pn || tmptc.cn) ?
+ trb_get_number_of_siblings(tmppc.fp.modify, &tmptc) : 0;
+ if (siblings == 0) {
+ continue;
+ }
+ tmptc.mounted = 1;
+ tmptc.parent_refs = refs;
+
+ mc = malloc(sizeof *mc);
+ if (mc == NULL) {
+ err = LY_EMEM;
+ goto out;
+ }
+
+ mc->tc = tmptc;
+ mc->pc = tmppc;
+ ly_set_add(modules, (void *)mc, 1, NULL);
+ }
+
+ for (uint32_t v = 0; v < modules->count; ++v) {
+ mc = modules->objs[v];
+ tmpwr = (v == modules->count - 1) ? wr : trp_wrapper_set_mark_top(wr);
+ trb_print_family_tree(tmpwr, &mc->pc, &mc->tc);
+ }
+
+ for (uint32_t pr = 0; refs && pr < refs->count; pr++) {
+ trm_lysc_tree_ctx(refs->snodes[pr]->module, pc->out, pc->max_line_length, &tmppc, &tmptc);
+ tmptc.mounted = 1;
+ tmptc.parent_refs = refs;
+ trb_print_parents(refs->snodes[pr], &tmpwr, pc, &tmptc);
+ }
+
+out:
+ ly_set_free(modules, free);
+ ly_set_free(refs, NULL);
+out_ctx:
+ ly_ctx_destroy(ext_ctx);
+ return err;
+}