schema compile CHANGE support deviation of config property
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 18f13cb..e04e409 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -3781,21 +3781,24 @@
}
/**
- * @brief Apply refined config to the refine's target node.
+ * @brief Apply refined or deviated config to the target node.
*
* @param[in] ctx Compile context.
- * @param[in] node Refine's target node.
- * @param[in] rfn Parsed refine information.
+ * @param[in] node Target node where the config is supposed to be changed.
+ * @param[in] config_flag Node's config flag to be applied to the @p node.
+ * @param[in] nodeid Schema nodeid used to identify target of refine/deviation (for logging).
* @param[in] inheriting Flag (inverted) to check the refined config compatibility with the node's parent. This is
* done only on the node for which the refine was created. The function applies also recursively to apply the config change
- * to the complete subtree and the test is not needed for the subnodes.
+ * to the complete subtree (except the subnodes with explicit config set) and the test is not needed for the subnodes.
+ * @param[in] refine_flag Flag to distinguish if the change is caused by refine (flag set) or deviation (for logging).
* @return LY_ERR value.
*/
static LY_ERR
-lys_compile_refine_config(struct lysc_ctx *ctx, struct lysc_node *node, struct lysp_refine *rfn, int inheriting)
+lys_compile_change_config(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t config_flag,
+ const char *nodeid, int inheriting, int refine_flag)
{
struct lysc_node *child;
- uint16_t config = rfn->flags & LYS_CONFIG_MASK;
+ uint16_t config = config_flag & LYS_CONFIG_MASK;
if (config == (node->flags & LYS_CONFIG_MASK)) {
/* nothing to do */
@@ -3803,20 +3806,34 @@
}
if (!inheriting) {
- /* explicit refine */
+ /* explicit change */
if (config == LYS_CONFIG_W && node->parent && (node->parent->flags & LYS_CONFIG_R)) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid refine of config in \"%s\" - configuration node cannot be child of any state data node.",
- rfn->nodeid);
+ "Invalid %s of config in \"%s\" - configuration node cannot be child of any state data node.",
+ refine_flag ? "refine" : "deviation", nodeid);
return LY_EVALID;
}
+ node->flags |= LYS_SET_CONFIG;
+ } else {
+ if (node->flags & LYS_SET_CONFIG) {
+ if ((node->flags & LYS_CONFIG_W) && (config == LYS_CONFIG_R)) {
+ /* setting config flags, but have node with explicit config true */
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid %s of config in \"%s\" - configuration node cannot be child of any state data node.",
+ refine_flag ? "refine" : "deviation", nodeid);
+ return LY_EVALID;
+ }
+ /* do not change config on nodes where the config is explicitely set, this does not apply to
+ * nodes, which are being changed explicitly (targets of refine or deviation) */
+ return LY_SUCCESS;
+ }
}
node->flags &= ~LYS_CONFIG_MASK;
node->flags |= config;
/* inherit the change into the children */
LY_LIST_FOR((struct lysc_node*)lysc_node_children(node), child) {
- LY_CHECK_RET(lys_compile_refine_config(ctx, child, rfn, 1));
+ LY_CHECK_RET(lys_compile_change_config(ctx, child, config_flag, nodeid, 1, refine_flag));
}
/* TODO actions and notifications */
@@ -4267,7 +4284,7 @@
/* config */
if (rfn->flags & LYS_CONFIG_MASK) {
- LY_CHECK_GOTO(lys_compile_refine_config(ctx, node, rfn, 0), error);
+ LY_CHECK_GOTO(lys_compile_change_config(ctx, node, rfn->flags, rfn->nodeid, 0, 1), error);
}
/* mandatory */
@@ -4523,6 +4540,9 @@
/* default is config true */
node->flags |= LYS_CONFIG_W;
}
+ } else {
+ /* config set explicitely */
+ node->flags |= LYS_SET_CONFIG;
}
if (parent && (parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
@@ -4790,7 +4810,7 @@
}
#define DEV_CHECK_NONPRESENCE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER) \
- if (((TYPE)devs[u]->target)->MEMBER && COND) { \
+ if (((TYPE)devs[u]->target)->MEMBER && (COND)) { \
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
"Invalid deviation (%s) adding \"%s\" property which already exists (with value \"%s\").", \
devs[u]->nodeid, PROPERTY, ((TYPE)devs[u]->target)->VALUEMEMBER); \
@@ -4954,6 +4974,20 @@
}
/* [config-stmt] */
+ if (d_add->flags & LYS_CONFIG_MASK) {
+ if (devs[u]->target->nodetype & (LYS_CASE | LYS_INOUT | LYS_ACTION | LYS_NOTIF)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE, devs[u]->nodeid,
+ lys_nodetype2str(devs[u]->target->nodetype), "add", "config");
+ goto cleanup;
+ }
+ if (devs[u]->target->flags & LYS_SET_CONFIG) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation (%s) adding \"config\" property which already exists (with value \"config %s\").",
+ devs[u]->nodeid, devs[u]->target->flags & LYS_CONFIG_W ? "true" : "false");
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(lys_compile_change_config(ctx, devs[u]->target, d_add->flags, devs[u]->nodeid, 0, 0), cleanup);
+ }
/* [mandatory-stmt] */
@@ -5133,6 +5167,19 @@
}
/* [config-stmt] */
+ if (d_rpl->flags & LYS_CONFIG_MASK) {
+ if (devs[u]->target->nodetype & (LYS_CASE | LYS_INOUT | LYS_ACTION | LYS_NOTIF)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE, devs[u]->nodeid,
+ lys_nodetype2str(devs[u]->target->nodetype), "replace", "config");
+ goto cleanup;
+ }
+ if (!(devs[u]->target->flags & LYS_SET_CONFIG)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, devs[u]->nodeid,
+ "replacing", "config", d_rpl->flags & LYS_CONFIG_W ? "config true" : "config false");
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(lys_compile_change_config(ctx, devs[u]->target, d_rpl->flags, devs[u]->nodeid, 0, 0), cleanup);
+ }
/* [mandatory-stmt] */