schema compile CHANGE initial support for RPC/actions
Not yet tested!
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 968bd8e..7916074 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -2853,27 +2853,23 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_inout(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword inout_kw, struct lysp_node *parent, struct lysp_action_inout **inout_p)
+parse_inout(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword inout_kw, struct lysp_node *parent, struct lysp_action_inout *inout_p)
{
LY_ERR ret = LY_SUCCESS;
char *word;
size_t word_len;
- struct lysp_action_inout *inout;
enum yang_keyword kw;
unsigned int u;
struct lysp_node *child;
- if (*inout_p) {
+ if (inout_p->nodetype) {
LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
return LY_EVALID;
}
- /* create structure */
- inout = calloc(1, sizeof *inout);
- LY_CHECK_ERR_RET(!inout, LOGMEM(ctx->ctx), LY_EMEM);
- *inout_p = inout;
- inout->nodetype = LYS_INOUT;
- inout->parent = parent;
+ /* initiate structure */
+ inout_p->nodetype = LYS_INOUT;
+ inout_p->parent = parent;
/* parse substatements */
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -2882,38 +2878,38 @@
YANG_CHECK_STMTVER2_RET(ctx, "anydata", ly_stmt2str(inout_kw));
/* fall through */
case YANG_ANYXML:
- LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)inout, &inout->data));
+ LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)inout_p, &inout_p->data));
break;
case YANG_CHOICE:
- LY_CHECK_RET(parse_choice(ctx, data, (struct lysp_node*)inout, &inout->data));
+ LY_CHECK_RET(parse_choice(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
break;
case YANG_CONTAINER:
- LY_CHECK_RET(parse_container(ctx, data, (struct lysp_node*)inout, &inout->data));
+ LY_CHECK_RET(parse_container(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
break;
case YANG_LEAF:
- LY_CHECK_RET(parse_leaf(ctx, data, (struct lysp_node*)inout, &inout->data));
+ LY_CHECK_RET(parse_leaf(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
break;
case YANG_LEAF_LIST:
- LY_CHECK_RET(parse_leaflist(ctx, data, (struct lysp_node*)inout, &inout->data));
+ LY_CHECK_RET(parse_leaflist(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
break;
case YANG_LIST:
- LY_CHECK_RET(parse_list(ctx, data, (struct lysp_node*)inout, &inout->data));
+ LY_CHECK_RET(parse_list(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
break;
case YANG_USES:
- LY_CHECK_RET(parse_uses(ctx, data, (struct lysp_node*)inout, &inout->data));
+ LY_CHECK_RET(parse_uses(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
break;
case YANG_TYPEDEF:
- LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node*)inout, data, &inout->typedefs));
+ LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node*)inout_p, data, &inout_p->typedefs));
break;
case YANG_MUST:
YANG_CHECK_STMTVER2_RET(ctx, "must", ly_stmt2str(inout_kw));
- LY_CHECK_RET(parse_restrs(ctx, data, kw, &inout->musts));
+ LY_CHECK_RET(parse_restrs(ctx, data, kw, &inout_p->musts));
break;
case YANG_GROUPING:
- LY_CHECK_RET(parse_grouping(ctx, data, (struct lysp_node*)inout, &inout->groupings));
+ LY_CHECK_RET(parse_grouping(ctx, data, (struct lysp_node*)inout_p, &inout_p->groupings));
break;
case YANG_CUSTOM:
- LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout->exts));
+ LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout_p->exts));
break;
default:
LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
@@ -2921,9 +2917,9 @@
}
}
/* finalize parent pointers to the reallocated items */
- LY_ARRAY_FOR(inout->groupings, u) {
- LY_LIST_FOR(inout->groupings[u].data, child) {
- child->parent = (struct lysp_node*)&inout->groupings[u];
+ LY_ARRAY_FOR(inout_p->groupings, u) {
+ LY_LIST_FOR(inout_p->groupings[u].data, child) {
+ child->parent = (struct lysp_node*)&inout_p->groupings[u];
}
}
return ret;
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 6fba4d6..21fc337 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -31,8 +31,12 @@
API const struct lysc_node *
lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, int options)
{
- const struct lysc_node *next;
+ const struct lysc_node *next = NULL;
struct lysc_node **snode;
+ int action_flag = 0, notif_flag = 0;
+ const struct lysc_action *actions;
+ const struct lysc_notif *notifs;
+ unsigned int u;
LY_CHECK_ARG_RET(NULL, parent || module, NULL);
@@ -48,7 +52,7 @@
}
next = last = (const struct lysc_node*)&((struct lysc_node_choice*)parent)->cases[0];
} else {
- snode = lysc_node_children_p(parent);
+ snode = lysc_node_children_p(parent, (options & LYS_GETNEXT_OUTPUT) ? LYS_CONFIG_R : LYS_CONFIG_W);
/* do not return anything if the augment does not have any children */
if (!snode || !(*snode)) {
return NULL;
@@ -60,7 +64,8 @@
next = last = module->data;
}
if (!next) {
- return next;
+ /* try to get action or notification */
+ goto repeat;
} else if (!(options & LYS_GETNEXT_NOSTATECHECK)) {
if (!lys_is_disabled(next, 0)) {
return next;
@@ -69,6 +74,36 @@
} else {
return next;
}
+ } else if (last->nodetype == LYS_ACTION) {
+ if (last->parent) {
+ actions = lysc_node_actions(last->parent);
+ } else {
+ actions = module->rpcs;
+ }
+ LY_ARRAY_FOR(actions, u) {
+ if (&actions[u] == (struct lysc_action*)last) {
+ break;
+ }
+ }
+ if (u + 1 < LY_ARRAY_SIZE(actions)) {
+ next = (struct lysc_node*)(&actions[u + 1]);
+ }
+ goto repeat;
+ } else if (last->nodetype == LYS_NOTIF) {
+ if (last->parent) {
+ notifs = lysc_node_notifs(last->parent);
+ } else {
+ notifs = module->notifs;
+ }
+ LY_ARRAY_FOR(notifs, u) {
+ if (¬ifs[u] == (struct lysc_notif*)last) {
+ break;
+ }
+ }
+ if (u + 1 < LY_ARRAY_SIZE(notifs)) {
+ next = (struct lysc_node*)(¬ifs[u + 1]);
+ }
+ goto repeat;
}
next = last->next;
@@ -83,9 +118,16 @@
if (last->parent != parent) {
last = last->parent;
next = last->next;
- goto repeat;
+ } else if (!action_flag) {
+ action_flag = 1;
+ next = parent ? (struct lysc_node*)lysc_node_actions(parent) : (struct lysc_node*)module->rpcs;
+ } else if (!notif_flag) {
+ notif_flag = 1;
+ next = parent ? (struct lysc_node*)lysc_node_notifs(parent) : (struct lysc_node*)module->notifs;
+ } else {
+ return NULL;
}
- return next;
+ goto repeat;
}
switch (next->nodetype) {
case LYS_ACTION:
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 376bab4..ea5d3e1 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -161,7 +161,7 @@
#define LYS_CASE 0x0040 /**< case statement node */
#define LYS_USES 0x0080 /**< uses statement node */
#define LYS_INOUT 0x200
-#define LYS_ACTION 0x400
+#define LYS_ACTION 0x400 /**< RPC or action */
#define LYS_NOTIF 0x800
#define LYS_GROUPING 0x1000
#define LYS_AUGMENT 0x2000
@@ -554,9 +554,9 @@
* 1 1 1 1 1
* bit name 1 2 3 4 5 6 7 8 9 0 1 2 3 4
* ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 1 LYS_CONFIG_W |x|x|x|x|x|x|x| | |x| | | | |
+ * 1 LYS_CONFIG_W |x|x|x|x|x|x|x| | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 2 LYS_CONFIG_R |x|x|x|x|x|x|x| | | |x| | | |
+ * 2 LYS_CONFIG_R |x|x|x|x|x|x|x| | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* 3 LYS_STATUS_CURR |x|x|x|x|x|x|x|x|x| | |x|x|x|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -841,8 +841,8 @@
const char **iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
struct lysp_tpdf *typedefs; /**< list of typedefs ([sized array](@ref sizedarrays)) */
struct lysp_grp *groupings; /**< list of groupings ([sized array](@ref sizedarrays)) */
- struct lysp_action_inout *input; /**< RPC's/Action's input */
- struct lysp_action_inout *output;/**< RPC's/Action's output */
+ struct lysp_action_inout input; /**< RPC's/Action's input */
+ struct lysp_action_inout output; /**< RPC's/Action's output */
struct lysp_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
};
@@ -1189,19 +1189,41 @@
struct lysc_range *length; /**< Optional length limitation */
};
+struct lysc_action_inout {
+ struct lysc_node *data; /**< first child node (linked list) */
+ struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+ struct lysc_must *musts; /**< list of must restrictions ([sized array](@ref sizedarrays)) */
+};
+
struct lysc_action {
uint16_t nodetype; /**< LYS_ACTION */
uint16_t flags; /**< [schema node flags](@ref snodeflags) */
struct lys_module *module; /**< module structure */
+ struct lysp_action *sp; /**< simply parsed (SP) original of the node, NULL if the SP schema was removed or in case of implicit case node. */
+ struct lysc_node *parent; /**< parent node (NULL in case of top level node - RPC) */
+
+ struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+ struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+
const char *name; /**< action/RPC name (mandatory) */
- /* TODO */
+ const char *dsc; /**< description */
+ const char *ref; /**< reference */
+
+ struct lysc_action_inout input; /**< RPC's/action's input */
+ struct lysc_action_inout output; /**< RPC's/action's output */
+
};
struct lysc_notif {
uint16_t nodetype; /**< LYS_NOTIF */
uint16_t flags; /**< [schema node flags](@ref snodeflags) */
struct lys_module *module; /**< module structure */
+ struct lysp_notification *sp; /**< simply parsed (SP) original of the node, NULL if the SP schema was removed or in case of implicit case node. */
+ struct lysc_node *parent; /**< parent node (NULL in case of top level node) */
+
const char *name; /**< Notification name (mandatory) */
+ const char *dsc; /**< description */
+ const char *ref; /**< reference */
/* TODO */
};
@@ -1478,9 +1500,10 @@
* @brief Get the children linked list of the given (compiled) schema node.
* Decides the node's type and in case it has a children list, returns it.
* @param[in] node Node to examine.
+ * @param[in] flags Config flag to distinguish input (LYS_CONFIG_W) and output (LYS_CONFIG_R) data in case of RPC/action node.
* @return The node's children linked list if any, NULL otherwise.
*/
-const struct lysc_node *lysc_node_children(const struct lysc_node *node);
+const struct lysc_node *lysc_node_children(const struct lysc_node *node, uint16_t flags);
/**
* @brief Get how the if-feature statement currently evaluates.
@@ -1665,6 +1688,8 @@
#define LYS_GETNEXT_INTONPCONT 0x40 /**< lys_getnext() option to look into non-presence container, instead of returning container itself */
#define LYS_GETNEXT_NOSTATECHECK 0x100 /**< lys_getnext() option to skip checking module validity (import-only, disabled) and
relevant if-feature conditions state */
+#define LYS_GETNEXT_OUTPUT 0x200 /**< lys_getnext() option to provide RPC's/action's output schema nodes instead of input schema nodes
+ provided by default */
/** @} sgetnextflags */
/**
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 73cecc9..c2a6a54 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -41,6 +41,17 @@
} \
}
+#define COMPILE_ARRAY1_GOTO(CTX, ARRAY_P, ARRAY_C, PARENT, OPTIONS, ITER, FUNC, USES_STATUS, RET, GOTO) \
+ if (ARRAY_P) { \
+ LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_SIZE(ARRAY_P), RET, GOTO); \
+ size_t __array_offset = LY_ARRAY_SIZE(ARRAY_C); \
+ for (ITER = 0; ITER < LY_ARRAY_SIZE(ARRAY_P); ++ITER) { \
+ LY_ARRAY_INCREMENT(ARRAY_C); \
+ RET = FUNC(CTX, &(ARRAY_P)[ITER], OPTIONS, PARENT, &(ARRAY_C)[ITER + __array_offset], USES_STATUS); \
+ LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
+ } \
+ }
+
#define COMPILE_ARRAY_UNIQUE_GOTO(CTX, ARRAY_P, ARRAY_C, OPTIONS, ITER, FUNC, RET, GOTO) \
if (ARRAY_P) { \
LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_SIZE(ARRAY_P), RET, GOTO); \
@@ -3004,9 +3015,110 @@
return ret;
}
+/**
+ * @brief Compile status information of the given node.
+ *
+ * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
+ * has the status correctly set during the compilation.
+ *
+ * @param[in] ctx Compile context
+ * @param[in,out] node_flags Flags of the compiled node which status is supposed to be resolved.
+ * If the status was set explicitly on the node, it is already set in the flags value and we just check
+ * the compatibility with the parent's status value.
+ * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_status(struct lysc_ctx *ctx, uint16_t *node_flags, uint16_t parent_flags)
+{
+ /* status - it is not inherited by specification, but it does not make sense to have
+ * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
+ if (!((*node_flags) & LYS_STATUS_MASK)) {
+ if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
+ if ((parent_flags & 0x3) != 0x3) {
+ /* do not print the warning when inheriting status from uses - the uses_status value has a special
+ * combination of bits (0x3) which marks the uses_status value */
+ LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
+ (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
+ }
+ (*node_flags) |= parent_flags & LYS_STATUS_MASK;
+ } else {
+ (*node_flags) |= LYS_STATUS_CURR;
+ }
+ } else if (parent_flags & LYS_STATUS_MASK) {
+ /* check status compatibility with the parent */
+ if ((parent_flags & LYS_STATUS_MASK) > ((*node_flags) & LYS_STATUS_MASK)) {
+ if ((*node_flags) & LYS_STATUS_CURR) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "A \"current\" status is in conflict with the parent's \"%s\" status.",
+ (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
+ } else { /* LYS_STATUS_DEPRC */
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
+ }
+ return LY_EVALID;
+ }
+ }
+ return LY_SUCCESS;
+}
+
static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *parent, uint16_t uses_status);
/**
+ * @brief Compile parsed RPC/action schema node information.
+ * @param[in] ctx Compile context
+ * @param[in] node_p Parsed RPC/action schema node.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in,out] action Prepared (empty) compiled action structure to fill.
+ * @param[in] uses_status If the RPC/action is being placed instead of uses, here we have the uses's status value (as node's flags).
+ * Zero means no uses, non-zero value with no status bit set mean the default status.
+ * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ */
+static LY_ERR
+lys_compile_action(struct lysc_ctx *ctx, struct lysp_action *action_p, int options,
+ struct lysc_node *parent, struct lysc_action *action, uint16_t uses_status)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysp_node *child_p;
+ unsigned int u;
+
+ action->nodetype = LYS_ACTION;
+ action->module = ctx->mod;
+ action->parent = parent;
+ if (!(options & LYSC_OPT_FREE_SP)) {
+ action->sp = action_p;
+ }
+ action->flags = action_p->flags & LYS_FLAGS_COMPILED_MASK;
+
+ /* status - it is not inherited by specification, but it does not make sense to have
+ * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
+ LY_CHECK_RET(lys_compile_status(ctx, &action->flags, uses_status ? uses_status : (parent ? parent->flags : 0)));
+
+ DUP_STRING(ctx->ctx, action_p->name, action->name);
+ DUP_STRING(ctx->ctx, action_p->dsc, action->dsc);
+ DUP_STRING(ctx->ctx, action_p->ref, action->ref);
+ COMPILE_ARRAY_GOTO(ctx, action_p->iffeatures, action->iffeatures, options, u, lys_compile_iffeature, ret, cleanup);
+ COMPILE_ARRAY_GOTO(ctx, action_p->exts, action->exts, options, u, lys_compile_ext, ret, cleanup);
+
+ /* input */
+ COMPILE_ARRAY_GOTO(ctx, action_p->input.musts, action->input.musts, options, u, lys_compile_must, ret, cleanup);
+ COMPILE_ARRAY_GOTO(ctx, action_p->input.exts, action->input.exts, options, u, lys_compile_ext, ret, cleanup);
+ LY_LIST_FOR(action_p->input.data, child_p) {
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, options & LYSC_OPT_RPC_INPUT, (struct lysc_node*)action, uses_status));
+ }
+
+ /* output */
+ COMPILE_ARRAY_GOTO(ctx, action_p->output.musts, action->output.musts, options, u, lys_compile_must, ret, cleanup);
+ COMPILE_ARRAY_GOTO(ctx, action_p->output.exts, action->output.exts, options, u, lys_compile_ext, ret, cleanup);
+ LY_LIST_FOR(action_p->output.data, child_p) {
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, options & LYSC_OPT_RPC_OUTPUT, (struct lysc_node*)action, uses_status));
+ }
+
+cleanup:
+ return ret;
+}
+
+/**
* @brief Compile parsed container node information.
* @param[in] ctx Compile context
* @param[in] node_p Parsed container node.
@@ -3033,8 +3145,8 @@
}
COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, options, u, lys_compile_must, ret, done);
- //COMPILE_ARRAY_GOTO(ctx, cont_p->actions, cont->actions, options, u, lys_compile_action, ret, done);
- //COMPILE_ARRAY_GOTO(ctx, cont_p->notifs, cont->notifs, options, u, lys_compile_notif, ret, done);
+ COMPILE_ARRAY1_GOTO(ctx, cont_p->actions, cont->actions, node, options, u, lys_compile_action, 0, ret, done);
+ // TODO COMPILE_ARRAY1_GOTO(ctx, cont_p->notifs, cont->notifs, node, options, u, lys_compile_notif, 0, ret, done);
done:
return ret;
@@ -3203,6 +3315,7 @@
size_t len;
unsigned int v;
int config;
+ uint16_t flags;
for (v = 0; v < LY_ARRAY_SIZE(uniques); ++v) {
config = -1;
@@ -3221,16 +3334,23 @@
/* unique node must be present */
LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
- ret = lys_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node*)list, context_module, LYS_LEAF, 0, (const struct lysc_node**)key);
+ ret = lys_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node*)list, context_module, LYS_LEAF, 0,
+ (const struct lysc_node**)key, &flags);
if (ret != LY_SUCCESS) {
if (ret == LY_EDENIED) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Unique's descendant-schema-nodeid \"%.*s\" refers to a %s node instead of a leaf.",
+ "Unique's descendant-schema-nodeid \"%.*s\" refers to %s node instead of a leaf.",
len, keystr, lys_nodetype2str((*key)->nodetype));
}
return LY_EVALID;
+ } else if (flags) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Unique's descendant-schema-nodeid \"%.*s\" refers into %s node.",
+ len, keystr, flags & LYSC_OPT_NOTIFICATION ? "Notification" : "RPC/action");
+ return LY_EVALID;
}
+
/* all referenced leafs must be of the same config type */
if (config != -1 && ((((*key)->flags & LYS_CONFIG_W) && config == 0) || (((*key)->flags & LYS_CONFIG_R) && config == 1))) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
@@ -3373,8 +3493,8 @@
LY_CHECK_RET(lys_compile_node_list_unique(ctx, list->module, list_p->uniques, list));
}
- //COMPILE_ARRAY_GOTO(ctx, list_p->actions, list->actions, options, u, lys_compile_action, ret, done);
- //COMPILE_ARRAY_GOTO(ctx, list_p->notifs, list->notifs, options, u, lys_compile_notif, ret, done);
+ COMPILE_ARRAY1_GOTO(ctx, list_p->actions, list->actions, node, options, u, lys_compile_action, 0, ret, done);
+ // TODO COMPILE_ARRAY1_GOTO(ctx, list_p->notifs, list->notifs, node, options, u, lys_compile_notif, 0, ret, done);
done:
return ret;
@@ -3558,52 +3678,6 @@
}
/**
- * @brief Compile status information of the given node.
- *
- * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
- * has the status correctly set during the compilation.
- *
- * @param[in] ctx Compile context
- * @param[in,out] node Compiled node which status is supposed to be resolved. If the status was set explicitely on the node, it is already set in the
- * flags value and we just check the compatibility with the parent's status value.
- * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_compile_status(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t parent_flags)
-{
- /* status - it is not inherited by specification, but it does not make sense to have
- * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
- if (!(node->flags & LYS_STATUS_MASK)) {
- if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
- if ((parent_flags & 0x3) != 0x3) {
- /* do not print the warning when inheriting status from uses - the uses_status value has a special
- * combination of bits (0x3) which marks the uses_status value */
- LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
- (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
- }
- node->flags |= parent_flags & LYS_STATUS_MASK;
- } else {
- node->flags |= LYS_STATUS_CURR;
- }
- } else if (parent_flags & LYS_STATUS_MASK) {
- /* check status compatibility with the parent */
- if ((parent_flags & LYS_STATUS_MASK) > (node->flags & LYS_STATUS_MASK)) {
- if (node->flags & LYS_STATUS_CURR) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "A \"current\" status is in conflict with the parent's \"%s\" status.",
- (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
- } else { /* LYS_STATUS_DEPRC */
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
- }
- return LY_EVALID;
- }
- }
- return LY_SUCCESS;
-}
-
-/**
* @brief Check uniqness of the node/action/notification name.
*
* Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
@@ -3664,7 +3738,7 @@
if (node->nodetype == LYS_CASE) {
children = (struct lysc_node**)&((struct lysc_node_choice*)parent)->cases;
} else {
- children = lysc_node_children_p(parent);
+ children = lysc_node_children_p(parent, node->flags);
}
if (children) {
if (!(*children)) {
@@ -3758,7 +3832,7 @@
cs->sp = node_p;
/* check the case's status (don't need to solve uses_status since case statement cannot be directly in grouping statement */
- LY_CHECK_RET(lys_compile_status(ctx, (struct lysc_node*)cs, ch->flags), NULL);
+ LY_CHECK_RET(lys_compile_status(ctx, &cs->flags, ch->flags), NULL);
if (node_p->when) {
LY_ARRAY_NEW_GOTO(ctx->ctx, cs->when, when, ret, error);
@@ -3837,12 +3911,10 @@
node->flags |= config;
/* inherit the change into the children */
- LY_LIST_FOR((struct lysc_node*)lysc_node_children(node), child) {
+ LY_LIST_FOR((struct lysc_node*)lysc_node_children(node, 0), child) {
LY_CHECK_RET(lys_compile_change_config(ctx, child, config_flag, nodeid, 1, refine_flag));
}
- /* TODO actions and notifications */
-
return LY_SUCCESS;
}
@@ -3868,7 +3940,7 @@
}
} else { /* unset flag */
for (; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
- for (iter = (struct lysc_node*)lysc_node_children(parent); iter; iter = iter->next) {
+ for (iter = (struct lysc_node*)lysc_node_children(parent, 0); iter; iter = iter->next) {
if (iter->flags & LYS_MAND_TRUE) {
/* there is another mandatory node */
return;
@@ -3984,10 +4056,12 @@
struct lysc_node *node;
struct lysc_when **when, *when_shared;
int allow_mandatory = 0;
+ uint16_t flags = 0;
+ unsigned int u;
ret = lys_resolve_schema_nodeid(ctx, aug_p->nodeid, 0, parent, parent ? parent->module : ctx->mod_def,
LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INOUT | LYS_NOTIF,
- 1, (const struct lysc_node**)&target);
+ 1, (const struct lysc_node**)&target, &flags);
if (ret != LY_SUCCESS) {
if (ret == LY_EDENIED) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
@@ -4031,13 +4105,13 @@
* here we gets the last created node as last children of our parent */
if (target->nodetype == LYS_CASE) {
/* the compiled node is the last child of the target (but it is a case, so we have to be careful and stop) */
- for (node = (struct lysc_node*)lysc_node_children(target); node->next && node->next->parent == node->parent; node = node->next);
+ for (node = (struct lysc_node*)lysc_node_children(target, flags); node->next && node->next->parent == node->parent; node = node->next);
} else if (target->nodetype == LYS_CHOICE) {
/* to pass when statement, we need the last case no matter if it is explicit or implicit case */
node = ((struct lysc_node_choice*)target)->cases->prev;
} else {
/* the compiled node is the last child of the target */
- node = lysc_node_children(target)->prev;
+ node = lysc_node_children(target, flags)->prev;
}
if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
@@ -4063,7 +4137,32 @@
}
}
}
- /* TODO actions, notifications */
+
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_container*)node)->actions, target,
+ options, u, lys_compile_action, 0, ret, error);
+ /* TODO notifications */
+ break;
+ case LYS_LIST:
+ COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_list*)node)->actions, target,
+ options, u, lys_compile_action, 0, ret, error);
+ /* TODO notifications */
+ break;
+ default:
+ if (aug_p->actions) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid augment (%s) of %s node which is not allowed to contain RPC/action node \"%s\".",
+ aug_p->nodeid, lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
+ return LY_EVALID;
+ }
+ if (aug_p->notifs) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid augment (%s) of %s node which is not allowed to contain Notification node \"%s\".",
+ aug_p->nodeid, lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
+ return LY_EVALID;
+ }
+ }
error:
return ret;
@@ -4168,6 +4267,7 @@
struct lysp_refine *rfn;
LY_ERR ret = LY_EVALID;
uint32_t min, max;
+ uint16_t flags;
struct ly_set refined = {0};
struct lysc_when **when, *when_shared;
struct lysp_augment **augments = NULL;
@@ -4250,7 +4350,7 @@
LY_LIST_FOR(grp->data, node_p) {
/* 0x3 in uses_status is a special bits combination to be able to detect status flags from uses */
LY_CHECK_GOTO(lys_compile_node(ctx, node_p, options, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3), error);
- child = parent ? lysc_node_children(parent)->prev : ctx->mod->compiled->data->prev;
+ child = parent ? lysc_node_children(parent, options & LYSC_OPT_RPC_MASK)->prev : ctx->mod->compiled->data->prev;
/* some preparation for applying refines */
if (grp->data == node_p) {
@@ -4277,7 +4377,7 @@
}
if (context_node_fake.child) {
child = context_node_fake.child->prev;
- context_node_fake.child->prev = parent ? lysc_node_children(parent)->prev : ctx->mod->compiled->data->prev;
+ context_node_fake.child->prev = parent ? lysc_node_children(parent, options & LYSC_OPT_RPC_MASK)->prev : ctx->mod->compiled->data->prev;
}
/* sort and apply augments */
@@ -4292,7 +4392,7 @@
/* apply refine */
LY_ARRAY_FOR(uses_p->refines, struct lysp_refine, rfn) {
LY_CHECK_GOTO(lys_resolve_schema_nodeid(ctx, rfn->nodeid, 0, (struct lysc_node*)&context_node_fake, ctx->mod,
- 0, 0, (const struct lysc_node**)&node),
+ 0, 0, (const struct lysc_node**)&node, &flags),
error);
ly_set_add(&refined, node, LY_SET_OPT_USEASLIST);
@@ -4355,7 +4455,12 @@
/* config */
if (rfn->flags & LYS_CONFIG_MASK) {
- LY_CHECK_GOTO(lys_compile_change_config(ctx, node, rfn->flags, rfn->nodeid, 0, 1), error);
+ if (!flags) {
+ LY_CHECK_GOTO(lys_compile_change_config(ctx, node, rfn->flags, rfn->nodeid, 0, 1), error);
+ } else {
+ LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
+ flags & LYSC_OPT_NOTIFICATION ? "Notification" : "RPC/action", ctx->path);
+ }
}
/* mandatory */
@@ -4562,7 +4667,15 @@
node->flags = node_p->flags & LYS_FLAGS_COMPILED_MASK;
/* config */
- if (!(node->flags & LYS_CONFIG_MASK)) {
+ if (options & (LYSC_OPT_RPC_INPUT | LYSC_OPT_RPC_OUTPUT)) {
+ /* ignore config statements inside RPC/action data */
+ node->flags &= LYS_CONFIG_MASK;
+ node->flags |= (options & LYSC_OPT_RPC_INPUT) ? LYS_CONFIG_W : LYS_CONFIG_R;
+ } else if (options & LYSC_OPT_NOTIFICATION) {
+ /* ignore config statements inside Notification data */
+ node->flags &= LYS_CONFIG_MASK;
+ node->flags |= LYS_CONFIG_R;
+ } else if (!(node->flags & LYS_CONFIG_MASK)) {
/* config not explicitely set, inherit it from parent */
if (parent) {
node->flags |= parent->flags & LYS_CONFIG_MASK;
@@ -4598,7 +4711,7 @@
if (!parent || parent->nodetype != LYS_CHOICE) {
/* in case of choice/case's children, postpone the check to the moment we know if
* the parent is choice (parent here) or some case (so we have to get its flags to check) */
- LY_CHECK_GOTO(lys_compile_status(ctx, node, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
+ LY_CHECK_GOTO(lys_compile_status(ctx, &node->flags, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
}
if (!(options & LYSC_OPT_FREE_SP)) {
@@ -4635,7 +4748,7 @@
/* the postponed status check of the node and its real parent - in case of implicit case,
* it directly gets the same status flags as the choice;
* uses_status cannot be applied here since uses cannot be child statement of choice */
- LY_CHECK_GOTO(lys_compile_status(ctx, node, cs->flags), error);
+ LY_CHECK_GOTO(lys_compile_status(ctx, &node->flags, cs->flags), error);
node->parent = (struct lysc_node*)cs;
} else { /* other than choice */
node->parent = parent;
@@ -4700,8 +4813,8 @@
if (!remove_cs) {
cs = NULL;
}
- } else if (lysc_node_children(parent) == node) {
- *lysc_node_children_p(parent) = node->next;
+ } else if (lysc_node_children(parent, node->flags) == node) {
+ *lysc_node_children_p(parent, node->flags) = node->next;
}
if (cs) {
@@ -4751,7 +4864,7 @@
if (node->next) {
node->next->prev = node->prev;
} else if (node->nodetype != LYS_CASE) {
- child = (struct lysc_node*)lysc_node_children(parent);
+ child = (struct lysc_node*)lysc_node_children(parent, node->flags);
if (child) {
child->prev = node->prev;
}
@@ -4778,6 +4891,7 @@
const char *nodeid;
struct lysc_node *target; /* target node of the deviation */
struct lysp_deviate** deviates;/* sized array of pointers to parsed deviate statements to apply on target */
+ uint16_t flags; /* target's flags from lys_resolve_schema_nodeid() */
uint8_t not_supported; /* flag if deviates contains not-supported deviate */
} **devs = NULL;
int i;
@@ -4785,6 +4899,7 @@
const char *prefix, *name, *nodeid;
struct lys_module *mod;
uint32_t min, max;
+ uint16_t flags;
/* get all deviations from the module and all its submodules ... */
LY_ARRAY_FOR(mod_p->deviations, u) {
@@ -4806,7 +4921,8 @@
dev = devs_p.objs[u];
/* resolve the target */
- LY_CHECK_GOTO(lys_resolve_schema_nodeid(ctx, dev->nodeid, 0, NULL, ctx->mod, 0, 1, (const struct lysc_node**)&target), cleanup);
+ LY_CHECK_GOTO(lys_resolve_schema_nodeid(ctx, dev->nodeid, 0, NULL, ctx->mod, 0, 1,
+ (const struct lysc_node**)&target, &flags), cleanup);
/* insert into the set of targets with duplicity detection */
i = ly_set_add(&targets, target, 0);
@@ -4815,6 +4931,7 @@
devs[i] = calloc(1, sizeof **devs);
devs[i]->target = target;
devs[i]->nodeid = dev->nodeid;
+ devs[i]->flags = flags;
}
/* add deviates into the deviation's list of deviates */
for (d = dev->deviates; d; d = d->next) {
@@ -4881,27 +4998,27 @@
DELFUNC(ctx->ctx, ((TYPE)devs[u]->target)->MEMBER_TRG); \
((TYPE)devs[u]->target)->MEMBER_TRG = NULL;
-#define DEV_DEL_ARRAY(TYPE, ARRAY, VALMEMBER, VALMEMBER_CMP, DELFUNC_DEREF, DELFUNC, PROPERTY) \
- DEV_CHECK_PRESENCE(TYPE, 0, ARRAY, "deleting", PROPERTY, d_del->ARRAY[0]VALMEMBER); \
- LY_ARRAY_FOR(d_del->ARRAY, x) { \
- LY_ARRAY_FOR(((TYPE)devs[u]->target)->ARRAY, y) { \
- if (!strcmp(((TYPE)devs[u]->target)->ARRAY[y]VALMEMBER_CMP, d_del->ARRAY[x]VALMEMBER)) { break; } \
+#define DEV_DEL_ARRAY(TYPE, ARRAY_TRG, ARRAY_DEV, VALMEMBER, VALMEMBER_CMP, DELFUNC_DEREF, DELFUNC, PROPERTY) \
+ DEV_CHECK_PRESENCE(TYPE, 0, ARRAY_TRG, "deleting", PROPERTY, d_del->ARRAY_DEV[0]VALMEMBER); \
+ LY_ARRAY_FOR(d_del->ARRAY_DEV, x) { \
+ LY_ARRAY_FOR(((TYPE)devs[u]->target)->ARRAY_TRG, y) { \
+ if (!strcmp(((TYPE)devs[u]->target)->ARRAY_TRG[y]VALMEMBER_CMP, d_del->ARRAY_DEV[x]VALMEMBER)) { break; } \
} \
- if (y == LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY)) { \
+ if (y == LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY_TRG)) { \
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
"Invalid deviation (%s) deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
- devs[u]->nodeid, PROPERTY, d_del->ARRAY[x]VALMEMBER); \
+ devs[u]->nodeid, PROPERTY, d_del->ARRAY_DEV[x]VALMEMBER); \
goto cleanup; \
} \
- LY_ARRAY_DECREMENT(((TYPE)devs[u]->target)->ARRAY); \
- DELFUNC(ctx->ctx, DELFUNC_DEREF((TYPE)devs[u]->target)->ARRAY[y]); \
- memmove(&((TYPE)devs[u]->target)->ARRAY[y], \
- &((TYPE)devs[u]->target)->ARRAY[y + 1], \
- (LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY) - y) * (sizeof *((TYPE)devs[u]->target)->ARRAY)); \
+ LY_ARRAY_DECREMENT(((TYPE)devs[u]->target)->ARRAY_TRG); \
+ DELFUNC(ctx->ctx, DELFUNC_DEREF((TYPE)devs[u]->target)->ARRAY_TRG[y]); \
+ memmove(&((TYPE)devs[u]->target)->ARRAY_TRG[y], \
+ &((TYPE)devs[u]->target)->ARRAY_TRG[y + 1], \
+ (LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY_TRG) - y) * (sizeof *((TYPE)devs[u]->target)->ARRAY_TRG)); \
} \
- if (!LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY)) { \
- LY_ARRAY_FREE(((TYPE)devs[u]->target)->ARRAY); \
- ((TYPE)devs[u]->target)->ARRAY = NULL; \
+ if (!LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY_TRG)) { \
+ LY_ARRAY_FREE(((TYPE)devs[u]->target)->ARRAY_TRG); \
+ ((TYPE)devs[u]->target)->ARRAY_TRG = NULL; \
}
/* apply deviations */
@@ -4950,8 +5067,19 @@
options, x, lys_compile_must, ret, cleanup);
break;
case LYS_NOTIF:
- case LYS_INOUT:
/* TODO */
+ break;
+ case LYS_ACTION:
+ if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_action*)devs[u]->target)->input.musts,
+ options, x, lys_compile_must, ret, cleanup);
+ break;
+ } else if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_action*)devs[u]->target)->output.musts,
+ options, x, lys_compile_must, ret, cleanup);
+ break;
+ }
+ /* fall through */
default:
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
devs[u]->nodeid, lys_nodetype2str(devs[u]->target->nodetype), "add", "must");
@@ -5024,6 +5152,10 @@
lys_nodetype2str(devs[u]->target->nodetype), "add", "config");
goto cleanup;
}
+ if (devs[u]->flags) {
+ LOGWRN(ctx->ctx, "Deviating config inside %s has no effect (%s).",
+ devs[u]->flags & LYSC_OPT_NOTIFICATION ? "Notification" : "RPC/action", devs[u]->nodeid);
+ }
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\").",
@@ -5096,16 +5228,25 @@
switch (devs[u]->target->nodetype) {
case LYS_CONTAINER:
case LYS_LIST:
- DEV_DEL_ARRAY(struct lysc_node_container*, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+ DEV_DEL_ARRAY(struct lysc_node_container*, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
break;
case LYS_LEAF:
case LYS_LEAFLIST:
case LYS_ANYDATA:
- DEV_DEL_ARRAY(struct lysc_node_leaf*, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+ DEV_DEL_ARRAY(struct lysc_node_leaf*, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
break;
case LYS_NOTIF:
- case LYS_INOUT:
/* TODO */
+ break;
+ case LYS_ACTION:
+ if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
+ DEV_DEL_ARRAY(struct lysc_action*, input.musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+ break;
+ } else if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
+ DEV_DEL_ARRAY(struct lysc_action*, output.musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+ break;
+ }
+ /* fall through */
default:
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
devs[u]->nodeid, lys_nodetype2str(devs[u]->target->nodetype), "delete", "must");
@@ -5169,7 +5310,7 @@
devs[u]->target->flags &= ~LYS_SET_DFLT;
break;
case LYS_LEAFLIST:
- DEV_DEL_ARRAY(struct lysc_node_leaflist*, dflts, , , , lydict_remove, "default");
+ DEV_DEL_ARRAY(struct lysc_node_leaflist*, dflts, dflts, , , , lydict_remove, "default");
if (!((struct lysc_node_leaflist*)devs[u]->target)->dflts) {
devs[u]->target->flags &= ~LYS_SET_DFLT;
}
@@ -5491,8 +5632,8 @@
LY_CHECK_GOTO(ret, error);
}
- //COMPILE_ARRAY_GOTO(ctx, sp->rpcs, mod_c->rpcs, options, u, lys_compile_action, ret, error);
- //COMPILE_ARRAY_GOTO(ctx, sp->notifs, mod_c->notifs, options, u, lys_compile_notif, ret, error);
+ COMPILE_ARRAY1_GOTO(&ctx, sp->rpcs, mod_c->rpcs, NULL, options, u, lys_compile_action, 0, ret, error);
+ // TODO COMPILE_ARRAY1_GOTO(&ctx, sp->notifs, mod_c->notifs, NULL, options, u, lys_compile_notif, 0, ret, error);
/* augments - sort first to cover augments augmenting other augments */
ret = lys_compile_augment_sort(&ctx, sp->augments, sp->includes, &augments);
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 559b635..a17694a 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -194,8 +194,8 @@
FREE_STRINGS(ctx, action->iffeatures);
FREE_ARRAY(ctx, action->typedefs, lysp_tpdf_free);
FREE_ARRAY(ctx, action->groupings, lysp_grp_free);
- FREE_MEMBER(ctx, action->input, lysp_action_inout_free);
- FREE_MEMBER(ctx, action->output, lysp_action_inout_free);
+ lysp_action_inout_free(ctx, &action->input);
+ lysp_action_inout_free(ctx, &action->output);
FREE_ARRAY(ctx, action->exts, lysp_ext_instance_free);
}
@@ -629,6 +629,32 @@
free(type);
}
+void
+lysc_action_free(struct ly_ctx *ctx, struct lysc_action *action)
+{
+ struct lysc_node *child, *child_next;
+
+ FREE_STRING(ctx, action->name);
+ FREE_STRING(ctx, action->dsc);
+ FREE_STRING(ctx, action->ref);
+ FREE_ARRAY(ctx, action->iffeatures, lysc_iffeature_free);
+ FREE_ARRAY(ctx, action->exts, lysc_ext_instance_free);
+
+ /* input */
+ FREE_ARRAY(ctx, action->input.exts, lysc_ext_instance_free);
+ FREE_ARRAY(ctx, action->input.musts, lysc_must_free);
+ LY_LIST_FOR_SAFE(action->input.data, child_next, child) {
+ lysc_node_free(ctx, child);
+ }
+
+ /* output */
+ FREE_ARRAY(ctx, action->output.exts, lysc_ext_instance_free);
+ FREE_ARRAY(ctx, action->output.musts, lysc_must_free);
+ LY_LIST_FOR_SAFE(action->output.data, child_next, child) {
+ lysc_node_free(ctx, child);
+ }
+}
+
static void
lysc_node_container_free(struct ly_ctx *ctx, struct lysc_node_container *node)
{
@@ -638,8 +664,9 @@
lysc_node_free(ctx, child);
}
FREE_ARRAY(ctx, node->musts, lysc_must_free);
+ FREE_ARRAY(ctx, node->actions, lysc_action_free);
- /* TODO actions, notifs */
+ /* TODO notifs */
}
static void
@@ -686,7 +713,9 @@
}
LY_ARRAY_FREE(node->uniques);
- /* TODO actions, notifs */
+ FREE_ARRAY(ctx, node->actions, lysc_action_free);
+
+ /* TODO notifs */
}
static void
@@ -768,6 +797,8 @@
LY_LIST_FOR_SAFE(module->data, node_next, node) {
lysc_node_free(ctx, node);
}
+ FREE_ARRAY(ctx, module->rpcs, lysc_action_free);
+ /* TODO notifications */
FREE_ARRAY(ctx, module->exts, lysc_ext_instance_free);
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 0295995..6b89cb3 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -86,17 +86,21 @@
LY_ERR
lys_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
- const struct lys_module *context_module, int nodetype, int implement, const struct lysc_node **target)
+ const struct lys_module *context_module, int nodetype, int implement,
+ const struct lysc_node **target, uint16_t *result_flag)
{
LY_ERR ret = LY_EVALID;
const char *name, *prefix, *id;
size_t name_len, prefix_len;
const struct lys_module *mod;
const char *nodeid_type;
+ int getnext_extra_flag = 0;
assert(nodeid);
assert(target);
+ assert(result_flag);
*target = NULL;
+ *result_flag = 0;
id = nodeid;
@@ -139,11 +143,27 @@
/* make the module implemented */
ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
}
- context_node = lys_child(context_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
- if (!context_node) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
- return LY_ENOTFOUND;
+ if (context_node && context_node->nodetype == LYS_ACTION) {
+ /* move through input/output manually */
+ if (!strncmp("input", name, name_len)) {
+ (*result_flag) |= LYSC_OPT_RPC_INPUT;
+ } else if (!strncmp("input", name, name_len)) {
+ (*result_flag) |= LYSC_OPT_RPC_OUTPUT;
+ getnext_extra_flag = LYS_GETNEXT_OUTPUT;
+ }
+ } else {
+ context_node = lys_child(context_node, mod, name, name_len, 0,
+ getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
+ if (!context_node) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
+ return LY_ENOTFOUND;
+ }
+ getnext_extra_flag = 0;
+
+ if (context_node->nodetype == LYS_NOTIF) {
+ (*result_flag) |= LYSC_OPT_NOTIFICATION;
+ }
}
if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
break;
@@ -1127,7 +1147,7 @@
}
struct lysc_node **
-lysc_node_children_p(const struct lysc_node *node)
+lysc_node_children_p(const struct lysc_node *node, uint16_t flags)
{
assert(node);
switch (node->nodetype) {
@@ -1143,22 +1163,24 @@
return &((struct lysc_node_case*)node)->child;
case LYS_LIST:
return &((struct lysc_node_list*)node)->child;
-/* TODO
- case LYS_INOUT:
- return &((struct lysc_action_inout*)node)->child;
- case LYS_NOTIF:
- return &((struct lysc_notif*)node)->child;
-*/
+ case LYS_ACTION:
+ if (flags & LYS_CONFIG_R) {
+ return &((struct lysc_action*)node)->output.data;
+ } else {
+ /* LYS_CONFIG_W, but also the default case */
+ return &((struct lysc_action*)node)->input.data;
+ }
+ /* TODO Notification */
default:
return NULL;
}
}
API const struct lysc_node *
-lysc_node_children(const struct lysc_node *node)
+lysc_node_children(const struct lysc_node *node, uint16_t flags)
{
struct lysc_node **children;
- children = lysc_node_children_p((struct lysc_node*)node);
+ children = lysc_node_children_p((struct lysc_node*)node, flags);
if (children) {
return *children;
} else {
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index c2ddf7d..792ce51 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -154,8 +154,12 @@
*
* @{
*/
-#define LYSC_OPT_FREE_SP 1 /**< Free the input printable schema */
-#define LYSC_OPT_INTERNAL 2 /**< Internal compilation caused by dependency */
+#define LYSC_OPT_RPC_INPUT LYS_CONFIG_W /**< Internal option when compiling schema tree of RPC/action input */
+#define LYSC_OPT_RPC_OUTPUT LYS_CONFIG_R /**< Internal option when compiling schema tree of RPC/action output */
+#define LYSC_OPT_RPC_MASK LYS_CONFIG_MASK
+#define LYSC_OPT_FREE_SP 0x04 /**< Free the input printable schema */
+#define LYSC_OPT_INTERNAL 0x08 /**< Internal compilation caused by dependency */
+#define LYSC_OPT_NOTIFICATION 0x10 /**< Internal option when compiling schema tree of Notification */
/** @} scflags */
/**
@@ -200,9 +204,10 @@
*
* Decides the node's type and in case it has a children list, returns its address.
* @param[in] node Node to check.
+ * @param[in] flags Config flag to distinguish input (LYS_CONFIG_W) and output (LYS_CONFIG_R) data in case of RPC/action node.
* @return Address of the node's child member if any, NULL otherwise.
*/
-struct lysc_node **lysc_node_children_p(const struct lysc_node *node);
+struct lysc_node **lysc_node_children_p(const struct lysc_node *node, uint16_t flags);
/**
* @brief Get the covering schema module structure for the given parsed module structure.
@@ -280,11 +285,15 @@
* the given nodetype, LY_EDENIED is returned (and target is provided), but no error message is printed.
* The value can be even an ORed value to allow multiple nodetypes.
* @param[in] implement Flag if the modules mentioned in the nodeid are supposed to be made implemented.
- * @param[out] target Found target node if any.
+ * @param[out] target Found target node if any. In case of RPC/action input/output node, LYS_ACTION node is actually returned
+ * since the input/output has not a standalone node structure and it is part of ::lysc_action which is better compatible with ::lysc_node.
+ * @param[out] result_flag Output parameter to announce if the schema nodeid goes through the action's input/output or a Notification.
+ * The LYSC_OPT_RPC_INPUT, LYSC_OPT_RPC_OUTPUT and LYSC_OPT_NOTIFICATION are used as flags.
* @return LY_ERR values - LY_ENOTFOUND, LY_EVALID, LY_EDENIED or LY_SUCCESS.
*/
LY_ERR lys_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
- const struct lys_module *context_module, int nodetype, int implement, const struct lysc_node **target);
+ const struct lys_module *context_module, int nodetype, int implement,
+ const struct lysc_node **target, uint16_t *result_flag);
/**
* @brief Find the module referenced by prefix in the provided mod.