data tree FEATURE support for NETCONF messages
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index f75e57c..e755160 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -358,7 +358,7 @@
LY_CHECK_GOTO(ret, cleanup);
/* find model */
- ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_options, &mod);
+ ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_opts, &mod);
LY_CHECK_GOTO(ret, cleanup);
if (!mod) {
@@ -650,7 +650,7 @@
}
}
- if (!sibling && (lybctx->parse_options & LYD_PARSE_STRICT)) {
+ if (!sibling && (lybctx->parse_opts & LYD_PARSE_STRICT)) {
if (mod) {
LOGVAL(lybctx->lybctx->ctx, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
" from \"%s\".", mod->name);
@@ -693,7 +693,7 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyb_parse_subtree_r(struct lyd_lyb_ctx *lybctx, struct lyd_node_inner *parent, struct lyd_node **first)
+lyb_parse_subtree_r(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_node *node = NULL, *tree;
@@ -715,7 +715,7 @@
if (!parent) {
/* top-level, read module name */
- ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_options, &mod);
+ ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_opts, &mod);
LY_CHECK_GOTO(ret, cleanup);
/* read hash, find the schema node starting from mod */
@@ -727,7 +727,7 @@
LY_CHECK_GOTO(ret, cleanup);
}
- if (!snode && !(lybctx->parse_options & LYD_PARSE_OPAQ)) {
+ if (!snode && !(lybctx->parse_opts & LYD_PARSE_OPAQ)) {
/* unknown data, skip them */
lyb_skip_subtree(lybctx->lybctx);
goto stop_subtree;
@@ -777,7 +777,7 @@
/* process children */
while (LYB_LAST_SUBTREE(lybctx->lybctx).written) {
- ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
+ ret = lyb_parse_subtree_r(lybctx, node, NULL, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
} else if (snode->nodetype & LYD_NODE_TERM) {
@@ -802,19 +802,18 @@
/* process children */
while (LYB_LAST_SUBTREE(lybctx->lybctx).written) {
- ret = lyb_parse_subtree_r(lybctx, (struct lyd_node_inner *)node, NULL);
+ ret = lyb_parse_subtree_r(lybctx, node, NULL, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
- if (!(lybctx->parse_options & LYD_PARSE_ONLY)) {
+ if (!(lybctx->parse_opts & LYD_PARSE_ONLY)) {
/* new node validation, autodelete CANNOT occur, all nodes are new */
- ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
+ ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
LY_CHECK_GOTO(ret, cleanup);
/* add any missing default children */
- ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, &lybctx->unres_node_type,
- &lybctx->when_check, (lybctx->validate_options & LYD_VALIDATE_NO_STATE) ?
- LYD_IMPLICIT_NO_STATE : 0, NULL);
+ ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lybctx->node_types,
+ &lybctx->node_when, (lybctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
LY_CHECK_GOTO(ret, cleanup);
}
@@ -903,9 +902,14 @@
}
/* insert, keep first pointer correct */
- lyd_insert_node(&parent->node, first, node);
- while (!parent && (*first)->prev->next) {
- *first = (*first)->prev;
+ lyd_insert_node(parent, first_p, node);
+ while (!parent && (*first_p)->prev->next) {
+ *first_p = (*first_p)->prev;
+ }
+
+ /* rememeber a successfully parsed node */
+ if (parsed) {
+ ly_set_add(parsed, node, 1, NULL);
}
node = NULL;
@@ -1013,130 +1017,98 @@
return LY_SUCCESS;
}
-/**
- * @param[in] ctx libyang context for logging
- * @param[in] parent Parent node where to connect the parsed data, required for reply where the reply data are connected
- * with the request operation
- * @param[in] in Input structure.
- * @param[in] parse_options Options for parser, see @ref dataparseroptions.
- * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
- * @param[in] data_type Internal data parser flag to distnguish type of the data to parse (RPC/Reply/Notification/regular data].
- * @param[out] tree_p Parsed data tree. Note that NULL can be a valid result.
- * @param[out] op_p Optional pointer to the actual operation. Useful for action and inner notifications.
- * @param[out] lydctx_p Data parser context to finish validation.
- */
-static LY_ERR
-lyd_parse_lyb_(const struct ly_ctx *ctx, struct lyd_node_inner **parent, struct ly_in *in, uint32_t parse_options,
- uint32_t validate_options, uint32_t data_type, struct lyd_node **tree_p, struct lyd_node **op_p,
- struct lyd_ctx **lydctx_p)
+LY_ERR
+lyd_parse_lyb(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
+ uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR rc = LY_SUCCESS;
struct lyd_lyb_ctx *lybctx;
- struct lyd_node *tree = NULL;
+ uint32_t int_opts;
- assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
- assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
+ assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
+ assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
lybctx = calloc(1, sizeof *lybctx);
LY_CHECK_ERR_RET(!lybctx, LOGMEM(ctx), LY_EMEM);
lybctx->lybctx = calloc(1, sizeof *lybctx->lybctx);
- LY_CHECK_ERR_GOTO(!lybctx->lybctx, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+ LY_CHECK_ERR_GOTO(!lybctx->lybctx, LOGMEM(ctx); rc = LY_EMEM, cleanup);
lybctx->lybctx->in = in;
lybctx->lybctx->ctx = ctx;
- lybctx->parse_options = parse_options;
- lybctx->validate_options = validate_options;
- lybctx->int_opts = data_type;
+ lybctx->parse_opts = parse_opts;
+ lybctx->val_opts = val_opts;
lybctx->free = lyd_lyb_ctx_free;
+ switch (data_type) {
+ case LYD_TYPE_YANG_DATA:
+ int_opts = LYD_INTOPT_WITH_SIBLINGS;
+ break;
+ case LYD_TYPE_YANG_RPC:
+ int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
+ break;
+ case LYD_TYPE_YANG_NOTIF:
+ int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
+ break;
+ case LYD_TYPE_YANG_REPLY:
+ int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
+ break;
+ default:
+ LOGINT(ctx);
+ rc = LY_EINT;
+ goto cleanup;
+ }
+ lybctx->int_opts = int_opts;
+
+ /* find the operation node if it exists already */
+ LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lybctx->op_node), cleanup);
+
/* read magic number */
- ret = lyb_parse_magic_number(lybctx->lybctx);
- LY_CHECK_GOTO(ret, cleanup);
+ rc = lyb_parse_magic_number(lybctx->lybctx);
+ LY_CHECK_GOTO(rc, cleanup);
/* read header */
- ret = lyb_parse_header(lybctx->lybctx);
- LY_CHECK_GOTO(ret, cleanup);
+ rc = lyb_parse_header(lybctx->lybctx);
+ LY_CHECK_GOTO(rc, cleanup);
/* read used models */
- ret = lyb_parse_data_models(lybctx->lybctx, lybctx->parse_options);
- LY_CHECK_GOTO(ret, cleanup);
+ rc = lyb_parse_data_models(lybctx->lybctx, lybctx->parse_opts);
+ LY_CHECK_GOTO(rc, cleanup);
/* read subtree(s) */
while (lybctx->lybctx->in->current[0]) {
- ret = lyb_parse_subtree_r(lybctx, parent ? *parent : NULL, &tree);
- LY_CHECK_GOTO(ret, cleanup);
+ rc = lyb_parse_subtree_r(lybctx, parent, first_p, parsed);
+ LY_CHECK_GOTO(rc, cleanup);
+
+ if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
+ break;
+ }
+ }
+
+ if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && lybctx->lybctx->in->current[0]) {
+ LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lybctx->op_node) {
+ LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
+ rc = LY_EVALID;
+ goto cleanup;
}
/* read the last zero, parsing finished */
ly_in_skip(lybctx->lybctx->in, 1);
- if (data_type == (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) {
- /* make sure we have parsed some operation */
- if (!lybctx->op_node) {
- LOGVAL(ctx, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
- ret = LY_EVALID;
- goto cleanup;
- }
-
- if (op_p) {
- *op_p = lybctx->op_node;
- }
- assert(tree);
-
- } else if (data_type == LYD_INTOPT_NOTIF) {
- /* make sure we have parsed some notification */
- if (!lybctx->op_node) {
- LOGVAL(ctx, LYVE_DATA, "Missing the \"notification\" node.");
- ret = LY_EVALID;
- goto cleanup;
- }
-
- if (op_p) {
- *op_p = lybctx->op_node;
- }
- assert(tree);
- }
-
cleanup:
- if (ret) {
+ /* there should be no unres stored if validation should be skipped */
+ assert(!(parse_opts & LYD_PARSE_ONLY) || (!lybctx->node_types.count && !lybctx->meta_types.count &&
+ !lybctx->node_when.count));
+
+ if (rc) {
lyd_lyb_ctx_free((struct lyd_ctx *)lybctx);
- lyd_free_all(tree);
} else {
- if (lydctx_p) {
- *lydctx_p = (struct lyd_ctx *)lybctx;
- } else {
- lyd_lyb_ctx_free((struct lyd_ctx *)lybctx);
- }
- if (tree_p) {
- *tree_p = tree;
- }
+ *lydctx_p = (struct lyd_ctx *)lybctx;
}
- return ret;
-}
-
-LY_ERR
-lyd_parse_lyb_data(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_options, uint32_t validate_options,
- struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
-{
- return lyd_parse_lyb_(ctx, NULL, in, parse_options, validate_options, 0, tree_p, NULL, lydctx_p);
-}
-
-LY_ERR
-lyd_parse_lyb_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
-{
- return lyd_parse_lyb_(ctx, NULL, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LYD_INTOPT_RPC, tree_p, op_p, NULL);
-}
-
-LY_ERR
-lyd_parse_lyb_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p)
-{
- return lyd_parse_lyb_(ctx, NULL, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LYD_INTOPT_NOTIF, tree_p, ntf_p, NULL);
-}
-
-LY_ERR
-lyd_parse_lyb_reply(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
-{
- return lyd_parse_lyb_(ctx, NULL, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LYD_INTOPT_REPLY, tree_p, op_p, NULL);
+ return rc;
}
API int