schema compile CHANGE Notifications support
diff --git a/src/tree_schema.h b/src/tree_schema.h
index ea5d3e1..f53499b 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1000,9 +1000,9 @@
const char *name; /**< identity name (mandatory), including possible prefix */
const char *dsc; /**< description */
const char *ref; /**< reference */
- struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
struct lysc_ident **derived; /**< list of (pointers to the) derived identities ([sized array](@ref sizedarrays)) */
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)) */
uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_ values are allowed */
};
@@ -1014,8 +1014,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_feature **depfeatures;/**< list of pointers to other features depending on this one ([sized array](@ref sizedarrays)) */
- struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
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)) */
uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_* and
#LYS_FENABLED values allowed */
};
@@ -1124,8 +1124,8 @@
const char *name; /**< enumeration identifier */
const char *dsc; /**< description */
const char *ref; /**< reference */
- struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
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)) */
int32_t value; /**< integer value associated with the enumeration */
} *enums; /**< enumerations list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
};
@@ -1167,8 +1167,8 @@
const char *name; /**< bit identifier */
const char *dsc; /**< description */
const char *ref; /**< reference */
- struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
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)) */
uint32_t position; /**< non-negative integer value associated with the bit */
} *bits; /**< bits list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
};
@@ -1191,7 +1191,6 @@
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)) */
};
@@ -1202,13 +1201,16 @@
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)) */
+ struct lysc_ext_instance *input_exts; /**< list of the extension instances of input ([sized array](@ref sizedarrays)) */
+ struct lysc_ext_instance *output_exts; /**< list of the extension instances of outpu ([sized array](@ref sizedarrays)) */
const char *name; /**< action/RPC name (mandatory) */
const char *dsc; /**< description */
const char *ref; /**< reference */
+ 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)) */
+
struct lysc_action_inout input; /**< RPC's/action's input */
struct lysc_action_inout output; /**< RPC's/action's output */
@@ -1218,13 +1220,18 @@
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 lysp_notif *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) */
+ struct lysc_node *data; /**< first child node (linked list) */
+ struct lysc_must *musts; /**< list of must restrictions ([sized array](@ref sizedarrays)) */
+
const char *name; /**< Notification name (mandatory) */
const char *dsc; /**< description */
const char *ref; /**< reference */
- /* TODO */
+
+ 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)) */
};
/**
@@ -1245,8 +1252,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+ struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
};
struct lysc_node_container {
@@ -1264,8 +1271,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+ struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_node *child; /**< first child node (linked list) */
struct lysc_must *musts; /**< list of must restrictions ([sized array](@ref sizedarrays)) */
@@ -1288,8 +1295,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+ struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_node *child; /**< first child node of the case (linked list). Note that all the children of all the sibling cases are linked
each other as siblings with the parent pointer pointing to appropriate case node. */
@@ -1310,8 +1317,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+ struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_node_case *cases; /**< list of the cases (linked list). Note that all the children of all the cases are linked each other
as siblings. Their parent pointers points to the specific case they belongs to, so distinguish the
@@ -1334,8 +1341,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+ struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_must *musts; /**< list of must restrictions ([sized array](@ref sizedarrays)) */
struct lysc_type *type; /**< type of the leaf node (mandatory) */
@@ -1359,8 +1366,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+ struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_must *musts; /**< list of must restrictions ([sized array](@ref sizedarrays)) */
struct lysc_type *type; /**< type of the leaf node (mandatory) */
@@ -1387,8 +1394,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+ struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_node *child; /**< first child node (linked list) */
struct lysc_must *musts; /**< list of must restrictions ([sized array](@ref sizedarrays)) */
@@ -1416,8 +1423,8 @@
const char *dsc; /**< description */
const char *ref; /**< reference */
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
- struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+ struct lysc_when **when; /**< list of pointers to when statements ([sized array](@ref sizedarrays)) */
struct lysc_must *musts; /**< list of must restrictions ([sized array](@ref sizedarrays)) */
};
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index da5e9c0..8eb993b 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -3133,9 +3133,10 @@
return LY_EVALID;
}
- if (options & LYSC_OPT_RPC_MASK) {
+ if (options & (LYSC_OPT_RPC_MASK | LYSC_OPT_NOTIFICATION)) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Action \"%s\" is placed inside another RPC/action.", action_p->name);
+ "Action \"%s\" is placed inside %s.", action_p->name,
+ options & LYSC_OPT_RPC_MASK ? "another RPC/action" : "Notification");
return LY_EVALID;
}
@@ -3159,14 +3160,14 @@
/* 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);
+ 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);
+ 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));
}
@@ -3176,6 +3177,65 @@
}
/**
+ * @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_notif(struct lysc_ctx *ctx, struct lysp_notif *notif_p, int options,
+ struct lysc_node *parent, struct lysc_notif *notif, uint16_t uses_status)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lysp_node *child_p;
+ unsigned int u;
+
+ if (lys_compile_node_uniqness(ctx, parent ? lysc_node_children(parent, 0) : ctx->mod->compiled->data,
+ parent ? lysc_node_actions(parent) : ctx->mod->compiled->rpcs,
+ parent ? lysc_node_notifs(parent) : ctx->mod->compiled->notifs,
+ notif_p->name, notif)) {
+ return LY_EVALID;
+ }
+
+ if (options & (LYSC_OPT_RPC_MASK | LYSC_OPT_NOTIFICATION)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Notification \"%s\" is placed inside %s.", notif_p->name,
+ options & LYSC_OPT_RPC_MASK ? "RPC/action" : "another Notification");
+ return LY_EVALID;
+ }
+
+ notif->nodetype = LYS_NOTIF;
+ notif->module = ctx->mod;
+ notif->parent = parent;
+ if (!(options & LYSC_OPT_FREE_SP)) {
+ notif->sp = notif_p;
+ }
+ notif->flags = notif_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, ¬if->flags, uses_status ? uses_status : (parent ? parent->flags : 0)));
+
+ DUP_STRING(ctx->ctx, notif_p->name, notif->name);
+ DUP_STRING(ctx->ctx, notif_p->dsc, notif->dsc);
+ DUP_STRING(ctx->ctx, notif_p->ref, notif->ref);
+ COMPILE_ARRAY_GOTO(ctx, notif_p->iffeatures, notif->iffeatures, options, u, lys_compile_iffeature, ret, cleanup);
+ COMPILE_ARRAY_GOTO(ctx, notif_p->exts, notif->exts, options, u, lys_compile_ext, ret, cleanup);
+ COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, options, u, lys_compile_must, ret, cleanup);
+
+ LY_LIST_FOR(notif_p->data, child_p) {
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, options | LYSC_OPT_NOTIFICATION, (struct lysc_node*)notif, uses_status));
+ }
+
+cleanup:
+ return ret;
+}
+
+/**
* @brief Compile parsed container node information.
* @param[in] ctx Compile context
* @param[in] node_p Parsed container node.
@@ -3203,7 +3263,7 @@
COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, options, u, lys_compile_must, 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);
+ COMPILE_ARRAY1_GOTO(ctx, cont_p->notifs, cont->notifs, node, options, u, lys_compile_notif, 0, ret, done);
done:
return ret;
@@ -3551,7 +3611,7 @@
}
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);
+ COMPILE_ARRAY1_GOTO(ctx, list_p->notifs, list->notifs, node, options, u, lys_compile_notif, 0, ret, done);
done:
return ret;
@@ -4157,12 +4217,14 @@
case LYS_CONTAINER:
COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_container*)target)->actions, target,
options | flags, u, lys_compile_action, 0, ret, error);
- /* TODO notifications */
+ COMPILE_ARRAY1_GOTO(ctx, aug_p->notifs, ((struct lysc_node_container*)target)->notifs, target,
+ options | flags, u, lys_compile_notif, 0, ret, error);
break;
case LYS_LIST:
COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_list*)target)->actions, target,
options | flags, u, lys_compile_action, 0, ret, error);
- /* TODO notifications */
+ COMPILE_ARRAY1_GOTO(ctx, aug_p->notifs, ((struct lysc_node_list*)target)->notifs, target,
+ options | flags, u, lys_compile_notif, 0, ret, error);
break;
default:
if (aug_p->actions) {
@@ -4272,7 +4334,8 @@
.module = ctx->mod,
.flags = parent ? parent->flags : 0,
.child = NULL, .next = NULL,
- .prev = (struct lysc_node*)&context_node_fake};
+ .prev = (struct lysc_node*)&context_node_fake,
+ .actions = NULL, .notifs = NULL};
const struct lysp_grp *grp = NULL;
unsigned int u, v, grp_stack_count;
int found;
@@ -4286,6 +4349,9 @@
struct ly_set refined = {0};
struct lysc_when **when, *when_shared;
struct lysp_augment **augments = NULL;
+ unsigned int actions_index, notifs_index;
+ struct lysc_notif **notifs = NULL;
+ struct lysc_action **actions = NULL;
/* search for the grouping definition */
found = 0;
@@ -4360,11 +4426,12 @@
ctx->mod_def = mod;
/* check status */
- LY_CHECK_GOTO(lysc_check_status(ctx, uses_p->flags, mod_old, uses_p->name, grp->flags, mod, grp->name), error);
+ LY_CHECK_GOTO(lysc_check_status(ctx, uses_p->flags, mod_old, uses_p->name, grp->flags, mod, grp->name), cleanup);
+ /* compile data nodes */
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);
+ LY_CHECK_GOTO(lys_compile_node(ctx, node_p, options, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3), cleanup);
child = parent ? lysc_node_children(parent, options & LYSC_OPT_RPC_MASK)->prev : ctx->mod->compiled->data->prev;
/* some preparation for applying refines */
@@ -4377,11 +4444,11 @@
LY_LIST_FOR(context_node_fake.child, child) {
child->parent = (struct lysc_node*)&context_node_fake;
- /* pass uses's when to all the children */
+ /* pass uses's when to all the data children, actions and notifications are ignored */
if (uses_p->when) {
- LY_ARRAY_NEW_GOTO(ctx->ctx, child->when, when, ret, error);
+ LY_ARRAY_NEW_GOTO(ctx->ctx, child->when, when, ret, cleanup);
if (!when_shared) {
- LY_CHECK_GOTO(lys_compile_when(ctx, uses_p->when, options, when), error);
+ LY_CHECK_GOTO(lys_compile_when(ctx, uses_p->when, options, when), cleanup);
(*when)->context = lysc_xpath_context(parent);
when_shared = *when;
} else {
@@ -4391,14 +4458,43 @@
}
}
if (context_node_fake.child) {
+ /* child is the last data node added by grouping */
child = context_node_fake.child->prev;
+ /* fix child link of our fake container to point to the first child of the original list */
context_node_fake.child->prev = parent ? lysc_node_children(parent, options & LYSC_OPT_RPC_MASK)->prev : ctx->mod->compiled->data->prev;
}
+ /* compile actions */
+ actions = parent ? lysc_node_actions_p(parent) : &ctx->mod->compiled->rpcs;
+ if (actions) {
+ actions_index = *actions ? LY_ARRAY_SIZE(*actions) : 0;
+ COMPILE_ARRAY1_GOTO(ctx, grp->actions, *actions, parent, options, u, lys_compile_action, 0, ret, cleanup);
+ if (*actions && (uses_p->augments || uses_p->refines)) {
+ /* but for augment and refine, we need to separate the compiled grouping's actions to avoid modification of others */
+ LY_ARRAY_CREATE_GOTO(ctx->ctx, context_node_fake.actions, LY_ARRAY_SIZE(*actions) - actions_index, ret, cleanup);
+ LY_ARRAY_SIZE(context_node_fake.actions) = LY_ARRAY_SIZE(*actions) - actions_index;
+ memcpy(context_node_fake.actions, &(*actions)[actions_index], LY_ARRAY_SIZE(context_node_fake.actions) * sizeof **actions);
+ }
+ }
+
+ /* compile notifications */
+ notifs = parent ? lysc_node_notifs_p(parent) : &ctx->mod->compiled->notifs;
+ if (notifs) {
+ notifs_index = *notifs ? LY_ARRAY_SIZE(*notifs) : 0;
+ COMPILE_ARRAY1_GOTO(ctx, grp->notifs, *notifs, parent, options, u, lys_compile_notif, 0, ret, cleanup);
+ if (*notifs && (uses_p->augments || uses_p->refines)) {
+ /* but for augment and refine, we need to separate the compiled grouping's notification to avoid modification of others */
+ LY_ARRAY_CREATE_GOTO(ctx->ctx, context_node_fake.notifs, LY_ARRAY_SIZE(*notifs) - notifs_index, ret, cleanup);
+ LY_ARRAY_SIZE(context_node_fake.notifs) = LY_ARRAY_SIZE(*notifs) - notifs_index;
+ memcpy(context_node_fake.notifs, &(*notifs)[notifs_index], LY_ARRAY_SIZE(context_node_fake.notifs) * sizeof **notifs);
+ }
+ }
+
+
/* sort and apply augments */
- LY_CHECK_GOTO(lys_compile_augment_sort(ctx, uses_p->augments, NULL, &augments), error);
+ LY_CHECK_GOTO(lys_compile_augment_sort(ctx, uses_p->augments, NULL, &augments), cleanup);
LY_ARRAY_FOR(augments, u) {
- LY_CHECK_GOTO(lys_compile_augment(ctx, augments[u], options, (struct lysc_node*)&context_node_fake), error);
+ LY_CHECK_GOTO(lys_compile_augment(ctx, augments[u], options, (struct lysc_node*)&context_node_fake), cleanup);
}
/* reload previous context's mod_def */
@@ -4408,7 +4504,7 @@
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, &flags),
- error);
+ cleanup);
ly_set_add(&refined, node, LY_SET_OPT_USEASLIST);
/* default value */
@@ -4417,13 +4513,13 @@
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid refine of default in \"%s\" - %s cannot hold %d default values.",
rfn->nodeid, lys_nodetype2str(node->nodetype), LY_ARRAY_SIZE(rfn->dflts));
- goto error;
+ goto cleanup;
}
if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_CHOICE))) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid refine of default in \"%s\" - %s cannot hold default value(s).",
rfn->nodeid, lys_nodetype2str(node->nodetype));
- goto error;
+ goto cleanup;
}
if (node->nodetype == LYS_LEAF) {
FREE_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->dflt);
@@ -4434,14 +4530,14 @@
if (ctx->mod->version < 2) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
- goto error;
+ goto cleanup;
}
LY_ARRAY_FOR(((struct lysc_node_leaflist*)node)->dflts, u) {
lydict_remove(ctx->ctx, ((struct lysc_node_leaflist*)node)->dflts[u]);
}
LY_ARRAY_FREE(((struct lysc_node_leaflist*)node)->dflts);
((struct lysc_node_leaflist*)node)->dflts = NULL;
- LY_ARRAY_CREATE_GOTO(ctx->ctx, ((struct lysc_node_leaflist*)node)->dflts, LY_ARRAY_SIZE(rfn->dflts), ret, error);
+ LY_ARRAY_CREATE_GOTO(ctx->ctx, ((struct lysc_node_leaflist*)node)->dflts, LY_ARRAY_SIZE(rfn->dflts), ret, cleanup);
LY_ARRAY_FOR(rfn->dflts, u) {
LY_ARRAY_INCREMENT(((struct lysc_node_leaflist*)node)->dflts);
DUP_STRING(ctx->ctx, rfn->dflts[u], ((struct lysc_node_leaflist*)node)->dflts[u]);
@@ -4452,7 +4548,7 @@
/* unset LYS_SET_DFLT from the current default case */
((struct lysc_node_choice*)node)->dflt->flags &= ~LYS_SET_DFLT;
}
- LY_CHECK_GOTO(lys_compile_node_choice_dflt(ctx, rfn->dflts[0], (struct lysc_node_choice*)node), error);
+ LY_CHECK_GOTO(lys_compile_node_choice_dflt(ctx, rfn->dflts[0], (struct lysc_node_choice*)node), cleanup);
}
}
@@ -4471,7 +4567,7 @@
/* config */
if (rfn->flags & LYS_CONFIG_MASK) {
if (!flags) {
- LY_CHECK_GOTO(lys_compile_change_config(ctx, node, rfn->flags, rfn->nodeid, 0, 1), error);
+ LY_CHECK_GOTO(lys_compile_change_config(ctx, node, rfn->flags, rfn->nodeid, 0, 1), cleanup);
} else {
LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
flags & LYSC_OPT_NOTIFICATION ? "Notification" : "RPC/action", ctx->path);
@@ -4480,7 +4576,7 @@
/* mandatory */
if (rfn->flags & LYS_MAND_MASK) {
- LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, node, rfn->flags, rfn->nodeid, 1), error);
+ LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, node, rfn->flags, rfn->nodeid, 1), cleanup);
}
/* presence */
@@ -4489,7 +4585,7 @@
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid refine of presence statement in \"%s\" - %s cannot hold the presence statement.",
rfn->nodeid, lys_nodetype2str(node->nodetype));
- goto error;
+ goto cleanup;
}
node->flags |= LYS_PRESENCE;
}
@@ -4498,26 +4594,26 @@
if (rfn->musts) {
switch (node->nodetype) {
case LYS_LEAF:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_leaf*)node)->musts, options, u, lys_compile_must, ret, error);
+ COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_leaf*)node)->musts, options, u, lys_compile_must, ret, cleanup);
break;
case LYS_LEAFLIST:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_leaflist*)node)->musts, options, u, lys_compile_must, ret, error);
+ COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_leaflist*)node)->musts, options, u, lys_compile_must, ret, cleanup);
break;
case LYS_LIST:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_list*)node)->musts, options, u, lys_compile_must, ret, error);
+ COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_list*)node)->musts, options, u, lys_compile_must, ret, cleanup);
break;
case LYS_CONTAINER:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_container*)node)->musts, options, u, lys_compile_must, ret, error);
+ COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_container*)node)->musts, options, u, lys_compile_must, ret, cleanup);
break;
case LYS_ANYXML:
case LYS_ANYDATA:
- COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_anydata*)node)->musts, options, u, lys_compile_must, ret, error);
+ COMPILE_ARRAY_GOTO(ctx, rfn->musts, ((struct lysc_node_anydata*)node)->musts, options, u, lys_compile_must, ret, cleanup);
break;
default:
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid refine of must statement in \"%s\" - %s cannot hold any must statement.",
rfn->nodeid, lys_nodetype2str(node->nodetype));
- goto error;
+ goto cleanup;
}
}
@@ -4558,23 +4654,16 @@
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid refine of %s statement in \"%s\" - %s cannot hold this statement.",
(rfn->flags & LYS_SET_MAX) ? "max-elements" : "min-elements", rfn->nodeid, lys_nodetype2str(node->nodetype));
- goto error;
+ goto cleanup;
}
}
/* if-feature */
if (rfn->iffeatures) {
/* any node in compiled tree can get additional if-feature, so do not check nodetype */
- COMPILE_ARRAY_GOTO(ctx, rfn->iffeatures, node->iffeatures, options, u, lys_compile_iffeature, ret, error);
+ COMPILE_ARRAY_GOTO(ctx, rfn->iffeatures, node->iffeatures, options, u, lys_compile_iffeature, ret, cleanup);
}
}
- /* fix connection of the children nodes from fake context node back into the parent */
- if (context_node_fake.child) {
- context_node_fake.child->prev = child;
- }
- LY_LIST_FOR(context_node_fake.child, child) {
- child->parent = parent;
- }
/* do some additional checks of the changed nodes when all the refines are applied */
for (u = 0; u < refined.count; ++u) {
@@ -4587,7 +4676,7 @@
((node->nodetype & LYS_LEAF) && (node->flags & LYS_SET_DFLT)))) {
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid refine of default in \"%s\" - the node is mandatory.", rfn->nodeid);
- goto error;
+ goto cleanup;
}
if (rfn->flags & (LYS_SET_MAX | LYS_SET_MIN)) {
@@ -4602,13 +4691,34 @@
LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
"Invalid refine of %s statement in \"%s\" - \"min-elements\" is bigger than \"max-elements\".",
(rfn->flags & LYS_SET_MAX) ? "max-elements" : "min-elements", rfn->nodeid);
- goto error;
+ goto cleanup;
}
}
}
ret = LY_SUCCESS;
-error:
+
+cleanup:
+ /* fix connection of the children nodes from fake context node back into the parent */
+ if (context_node_fake.child) {
+ context_node_fake.child->prev = child;
+ }
+ LY_LIST_FOR(context_node_fake.child, child) {
+ child->parent = parent;
+ }
+
+ if (uses_p->augments || uses_p->refines) {
+ /* return back actions and notifications in case they were separated for augment/refine processing */
+ if (actions && *actions) {
+ memcpy(&(*actions)[actions_index], context_node_fake.actions, LY_ARRAY_SIZE(context_node_fake.actions) * sizeof **actions);
+ LY_ARRAY_FREE(context_node_fake.actions);
+ }
+ if (notifs && *notifs) {
+ memcpy(&(*notifs)[notifs_index], context_node_fake.notifs, LY_ARRAY_SIZE(context_node_fake.notifs) * sizeof **notifs);
+ LY_ARRAY_FREE(context_node_fake.notifs);
+ }
+ }
+
/* reload previous context's mod_def */
ctx->mod_def = mod_old;
/* remove the grouping from the stack for circular groupings dependency check */
@@ -4684,11 +4794,11 @@
/* config */
if (options & (LYSC_OPT_RPC_INPUT | LYSC_OPT_RPC_OUTPUT)) {
/* ignore config statements inside RPC/action data */
- node->flags &= LYS_CONFIG_MASK;
+ 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_MASK;
node->flags |= LYS_CONFIG_R;
} else if (!(node->flags & LYS_CONFIG_MASK)) {
/* config not explicitely set, inherit it from parent */
@@ -4711,8 +4821,9 @@
/* *list ordering */
if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
if ((node->flags & LYS_CONFIG_R) && (node->flags & LYS_ORDBY_MASK)) {
- LOGWRN(ctx->ctx, "The ordered-by statement is ignored in lists representing state data, "
- "RPC/action output parameters or notification content (%s).", ctx->path);
+ LOGWRN(ctx->ctx, "The ordered-by statement is ignored in lists representing %s (%s).",
+ (options & LYSC_OPT_RPC_OUTPUT) ? "RPC/action output parameters" :
+ (options & LYSC_OPT_NOTIFICATION) ? "notification content" : "state data", ctx->path);
node->flags &= ~LYS_ORDBY_MASK;
node->flags |= LYS_ORDBY_SYSTEM;
} else if (!(node->flags & LYS_ORDBY_MASK)) {
@@ -4896,7 +5007,8 @@
struct ly_set targets = {0};
struct lysc_node *target; /* target target of the deviation */
struct lysc_node_list *list;
- struct lysc_action *actions;
+ struct lysc_action *rpcs;
+ struct lysc_notif *notifs;
struct lysp_deviation *dev;
struct lysp_deviate *d, **dp_new;
struct lysp_deviate_add *d_add;
@@ -5066,35 +5178,42 @@
LOGWRN(ctx->ctx, "Useless multiple (%u) deviates on node \"%s\" since the node is not-supported.",
LY_ARRAY_SIZE(devs[u]->deviates), devs[u]->nodeid);
}
+
+#define REMOVE_NONDATA(ARRAY, TYPE, GETFUNC, FREEFUNC) \
+ if (devs[u]->target->parent) { \
+ ARRAY = (TYPE*)GETFUNC(devs[u]->target->parent); \
+ } else { \
+ ARRAY = devs[u]->target->module->compiled->ARRAY; \
+ } \
+ LY_ARRAY_FOR(ARRAY, x) { \
+ if (&ARRAY[x] == (TYPE*)devs[u]->target) { break; } \
+ } \
+ if (x < LY_ARRAY_SIZE(ARRAY)) { \
+ FREEFUNC(ctx->ctx, &ARRAY[x]); \
+ memmove(&ARRAY[x], &ARRAY[x + 1], (LY_ARRAY_SIZE(ARRAY) - (x + 1)) * sizeof *ARRAY); \
+ LY_ARRAY_DECREMENT(ARRAY); \
+ }
+
if (devs[u]->target->nodetype == LYS_ACTION) {
if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
/* remove RPC's/action's input */
lysc_action_inout_free(ctx->ctx, &((struct lysc_action*)devs[u]->target)->input);
memset(&((struct lysc_action*)devs[u]->target)->input, 0, sizeof ((struct lysc_action*)devs[u]->target)->input);
+ FREE_ARRAY(ctx->ctx, ((struct lysc_action*)devs[u]->target)->input_exts, lysc_ext_instance_free);
+ ((struct lysc_action*)devs[u]->target)->input_exts = NULL;
} else if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
/* remove RPC's/action's output */
lysc_action_inout_free(ctx->ctx, &((struct lysc_action*)devs[u]->target)->output);
memset(&((struct lysc_action*)devs[u]->target)->output, 0, sizeof ((struct lysc_action*)devs[u]->target)->output);
+ FREE_ARRAY(ctx->ctx, ((struct lysc_action*)devs[u]->target)->output_exts, lysc_ext_instance_free);
+ ((struct lysc_action*)devs[u]->target)->output_exts = NULL;
} else {
/* remove RPC/action */
- if (devs[u]->target->parent) {
- actions = (struct lysc_action*)lysc_node_actions(devs[u]->target->parent);
- } else {
- actions = devs[u]->target->module->compiled->rpcs;
- }
- LY_ARRAY_FOR(actions, x) {
- if (&actions[x] == (struct lysc_action*)devs[u]->target) {
- break;
- }
- }
- if (x < LY_ARRAY_SIZE(actions)) {
- lysc_action_free(ctx->ctx, &actions[x]);
- memmove(&actions[x], &actions[x + 1], (LY_ARRAY_SIZE(actions) - (x + 1)) * sizeof *actions);
- LY_ARRAY_DECREMENT(actions);
- }
+ REMOVE_NONDATA(rpcs, struct lysc_action, lysc_node_actions, lysc_action_free);
}
} else if (devs[u]->target->nodetype == LYS_NOTIF) {
- /* TODO Notification */
+ /* remove Notification */
+ REMOVE_NONDATA(notifs, struct lysc_notif, lysc_node_notifs, lysc_notif_free);
} else {
/* remove the target node */
lysc_disconnect(devs[u]->target);
@@ -5135,7 +5254,8 @@
options, x, lys_compile_must, ret, cleanup);
break;
case LYS_NOTIF:
- /* TODO */
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_notif*)devs[u]->target)->musts,
+ options, x, lys_compile_must, ret, cleanup);
break;
case LYS_ACTION:
if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
@@ -5304,7 +5424,7 @@
DEV_DEL_ARRAY(struct lysc_node_leaf*, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
break;
case LYS_NOTIF:
- /* TODO */
+ DEV_DEL_ARRAY(struct lysc_notif*, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
break;
case LYS_ACTION:
if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
@@ -5629,7 +5749,7 @@
/* TODO data nodes */
COMPILE_ARRAY1_GOTO(ctx, submod->rpcs, mainmod->rpcs, NULL, options, u, lys_compile_action, 0, ret, error);
- // TODO COMPILE_ARRAY1_GOTO(&ctx, submod->notifs, mainmod->notifs, NULL, options, u, lys_compile_notif, 0, ret, error);
+ COMPILE_ARRAY1_GOTO(ctx, submod->notifs, mainmod->notifs, NULL, options, u, lys_compile_notif, 0, ret, error);
error:
return ret;
@@ -5706,7 +5826,7 @@
}
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);
+ 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 062524d..1c94ae7 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -19,10 +19,6 @@
#include "tree_schema_internal.h"
#include "xpath.h"
-#define FREE_ARRAY(CTX, ARRAY, FUNC) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FUNC(CTX, &(ARRAY)[c__]);}LY_ARRAY_FREE(ARRAY);}
-#define FREE_MEMBER(CTX, MEMBER, FUNC) if (MEMBER) {FUNC(CTX, MEMBER);free(MEMBER);}
-#define FREE_STRINGS(CTX, ARRAY) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FREE_STRING(CTX, ARRAY[c__]);}LY_ARRAY_FREE(ARRAY);}
-
static void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp);
static void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node);
@@ -634,7 +630,6 @@
{
struct lysc_node *child, *child_next;
- FREE_ARRAY(ctx, inout->exts, lysc_ext_instance_free);
FREE_ARRAY(ctx, inout->musts, lysc_must_free);
LY_LIST_FOR_SAFE(inout->data, child_next, child) {
lysc_node_free(ctx, child);
@@ -649,10 +644,28 @@
FREE_STRING(ctx, action->ref);
FREE_ARRAY(ctx, action->iffeatures, lysc_iffeature_free);
FREE_ARRAY(ctx, action->exts, lysc_ext_instance_free);
+ FREE_ARRAY(ctx, action->input_exts, lysc_ext_instance_free);
lysc_action_inout_free(ctx, &action->input);
+ FREE_ARRAY(ctx, action->output_exts, lysc_ext_instance_free);
lysc_action_inout_free(ctx, &action->output);
}
+void
+lysc_notif_free(struct ly_ctx *ctx, struct lysc_notif *notif)
+{
+ struct lysc_node *child, *child_next;
+
+ FREE_STRING(ctx, notif->name);
+ FREE_STRING(ctx, notif->dsc);
+ FREE_STRING(ctx, notif->ref);
+ FREE_ARRAY(ctx, notif->iffeatures, lysc_iffeature_free);
+ FREE_ARRAY(ctx, notif->exts, lysc_ext_instance_free);
+ FREE_ARRAY(ctx, notif->musts, lysc_must_free);
+ LY_LIST_FOR_SAFE(notif->data, child_next, child) {
+ lysc_node_free(ctx, child);
+ }
+}
+
static void
lysc_node_container_free(struct ly_ctx *ctx, struct lysc_node_container *node)
{
@@ -663,8 +676,7 @@
}
FREE_ARRAY(ctx, node->musts, lysc_must_free);
FREE_ARRAY(ctx, node->actions, lysc_action_free);
-
- /* TODO notifs */
+ FREE_ARRAY(ctx, node->notifs, lysc_notif_free);
}
static void
@@ -712,8 +724,7 @@
LY_ARRAY_FREE(node->uniques);
FREE_ARRAY(ctx, node->actions, lysc_action_free);
-
- /* TODO notifs */
+ FREE_ARRAY(ctx, node->notifs, lysc_notif_free);
}
static void
@@ -796,7 +807,7 @@
lysc_node_free(ctx, node);
}
FREE_ARRAY(ctx, module->rpcs, lysc_action_free);
- /* TODO notifications */
+ FREE_ARRAY(ctx, module->notifs, lysc_notif_free);
FREE_ARRAY(ctx, module->exts, lysc_ext_instance_free);
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index d4567dc..ef83436 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -1183,7 +1183,8 @@
/* LYS_CONFIG_W, but also the default case */
return &((struct lysc_action*)node)->input.data;
}
- /* TODO Notification */
+ case LYS_NOTIF:
+ return &((struct lysc_notif*)node)->data;
default:
return NULL;
}
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index c20daad..0db6a1f 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -156,7 +156,7 @@
*/
#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_RPC_MASK LYS_CONFIG_MASK /**< mask for the internal RPC options */
#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 */
@@ -210,6 +210,24 @@
struct lysc_node **lysc_node_children_p(const struct lysc_node *node, uint16_t flags);
/**
+ * @brief Get address of a node's notifs pointer if any.
+ *
+ * Decides the node's type and in case it has a notifs array, returns its address.
+ * @param[in] node Node to check.
+ * @return Address of the node's notifs member if any, NULL otherwise.
+ */
+struct lysc_notif **lysc_node_notifs_p(struct lysc_node *node);
+
+/**
+ * @brief Get address of a node's actions pointer if any.
+ *
+ * Decides the node's type and in case it has a actions array, returns its address.
+ * @param[in] node Node to check.
+ * @return Address of the node's actions member if any, NULL otherwise.
+ */
+struct lysc_action **lysc_node_actions_p(struct lysc_node *node);
+
+/**
* @brief Get the covering schema module structure for the given parsed module structure.
* @param[in] ctx libyang context to search.
* @param[in] mod Parsed schema structure.
@@ -470,6 +488,23 @@
LY_ERR lys_feature_precompile(struct ly_ctx *ctx, struct lysp_feature *features_p, struct lysc_feature **features);
/**
+ * @brief Macro to free [sized array](@ref sizedarrays) of items using the provided free function. The ARRAY itself is also freed,
+ * but the memory is not sanitized.
+ */
+#define FREE_ARRAY(CTX, ARRAY, FUNC) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FUNC(CTX, &(ARRAY)[c__]);}LY_ARRAY_FREE(ARRAY);}
+
+/**
+ * @brief Macro to free the specified MEMBER of a structure using the provided free function. The memory is not sanitized.
+ */
+#define FREE_MEMBER(CTX, MEMBER, FUNC) if (MEMBER) {FUNC(CTX, MEMBER);free(MEMBER);}
+
+/**
+ * @brief Macro to free [sized array](@ref sizedarrays) of strings stored in the context's dictionary. The ARRAY itself is also freed,
+ * but the memory is not sanitized.
+ */
+#define FREE_STRINGS(CTX, ARRAY) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FREE_STRING(CTX, ARRAY[c__]);}LY_ARRAY_FREE(ARRAY);}
+
+/**
* @brief Free the parsed submodule structure.
* @param[in] ctx libyang context where the string data resides in a dictionary.
* @param[in,out] submod Parsed schema submodule structure to free.
@@ -516,6 +551,14 @@
void lysc_action_free(struct ly_ctx *ctx, struct lysc_action *action);
/**
+ * @brief Free the items inside the compiled Notification structure.
+ * @param[in] ctx libyang context where the string data resides in a dictionary.
+ * @param[in,out] action Compiled Notification structure to be cleaned.
+ * Since the structure is typically part of the sized array, the structure itself is not freed.
+ */
+void lysc_notif_free(struct ly_ctx *ctx, struct lysc_notif *notif);
+
+/**
* @brief Free the compiled extension instance structure.
* @param[in] ctx libyang context where the string data resides in a dictionary.
* @param[in,out] ext Compiled extension instance structure to be cleaned.
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index 92e4ec8..2c68caf 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -1943,6 +1943,66 @@
}
static void
+test_notification(void **state)
+{
+ *state = test_notification;
+
+ struct ly_parser_ctx ctx = {0};
+ struct lysp_notif *notifs = NULL;
+ struct lysp_node_container *c = NULL;
+ const char *str;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+ assert_non_null(ctx.ctx);
+ ctx.line = 1;
+ ctx.mod_version = 2; /* simulate YANG 1.1 */
+
+ /* invalid cardinality */
+#define TEST_DUP(MEMBER, VALUE1, VALUE2) \
+ str = "func {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
+ assert_int_equal(LY_EVALID, parse_notif(&ctx, &str, NULL, ¬ifs)); \
+ logbuf_assert("Duplicate keyword \""MEMBER"\". Line number 1."); \
+ FREE_ARRAY(ctx.ctx, notifs, lysp_notif_free); notifs = NULL;
+
+ TEST_DUP("description", "text1", "text2");
+ TEST_DUP("reference", "1", "2");
+ TEST_DUP("status", "current", "obsolete");
+#undef TEST_DUP
+
+ /* full content */
+ str = "top;";
+ assert_int_equal(LY_SUCCESS, parse_container(&ctx, &str, NULL, (struct lysp_node**)&c));
+ str = "ntf {anydata a1; anyxml a2; choice ch; container c; description test; grouping grp; if-feature f; leaf l {type int8;}"
+ "leaf-list ll {type int8;} list li; must 1; reference test; status current; typedef mytype {type int8;} uses grp; m:ext;}";
+ assert_int_equal(LY_SUCCESS, parse_notif(&ctx, &str, (struct lysp_node*)c, ¬ifs));
+ assert_non_null(notifs);
+ assert_int_equal(LYS_NOTIF, notifs->nodetype);
+ assert_string_equal("ntf", notifs->name);
+ assert_string_equal("test", notifs->dsc);
+ assert_non_null(notifs->exts);
+ assert_non_null(notifs->iffeatures);
+ assert_string_equal("test", notifs->ref);
+ assert_non_null(notifs->groupings);
+ assert_non_null(notifs->typedefs);
+ assert_non_null(notifs->musts);
+ assert_non_null(notifs->data);
+ assert_int_equal(LYS_STATUS_CURR, notifs->flags);
+
+ ly_set_erase(&ctx.tpdfs_nodes, NULL);
+ FREE_ARRAY(ctx.ctx, notifs, lysp_notif_free); notifs = NULL;
+
+ /* invalid content */
+ str = "ntf {config true} ...";
+ assert_int_equal(LY_EVALID, parse_notif(&ctx, &str, NULL, ¬ifs));
+ logbuf_assert("Invalid keyword \"config\" as a child of \"notification\". Line number 1.");
+ FREE_ARRAY(ctx.ctx, notifs, lysp_notif_free); notifs = NULL;
+
+ *state = NULL;
+ lysp_node_free(ctx.ctx, (struct lysp_node*)c);
+ ly_ctx_destroy(ctx.ctx, NULL);
+}
+
+static void
test_uses(void **state)
{
*state = test_uses;
@@ -2061,6 +2121,7 @@
cmocka_unit_test_setup_teardown(test_anydata, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_anyxml, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_action, logger_setup, logger_teardown),
+ cmocka_unit_test_setup_teardown(test_notification, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_grouping, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_uses, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_augment, logger_setup, logger_teardown),
diff --git a/tests/src/test_tree_schema.c b/tests/src/test_tree_schema.c
index 0a91f03..48fdfc1 100644
--- a/tests/src/test_tree_schema.c
+++ b/tests/src/test_tree_schema.c
@@ -135,12 +135,10 @@
rpc = (const struct lysc_action*)node;
assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
assert_string_equal("i", node->name);
- /* TODO Notifications
assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
assert_string_equal("j", node->name);
assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
assert_string_equal("k", node->name);
- */
assert_null(node = lys_getnext(node, NULL, mod->compiled, 0));
/* Inside container */
assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
@@ -159,10 +157,8 @@
assert_string_equal("seven", node->name);
assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
assert_string_equal("eight", node->name);
- /* TODO Notifications
assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
assert_string_equal("nine", node->name);
- */
assert_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
/* Inside RPC */
assert_non_null(node = lys_getnext(node, (const struct lysc_node*)rpc, mod->compiled, 0));
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 8f50ead..b098ead 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -521,15 +521,24 @@
assert_string_equal("10", ll->dflts[0]);
assert_int_equal(LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_USER, ll->flags);
- /* ordered-by is ignored for state data, RPC/action output parameters and notification content
- * TODO test also, RPC output parameters and notification content */
+ /* ordered-by is ignored for state data, RPC/action output parameters and notification content */
assert_non_null(mod = lys_parse_mem(ctx, "module d {yang-version 1.1;namespace urn:d;prefix d;"
"leaf-list ll {config false; type string; ordered-by user;}}", LYS_IN_YANG));
/* but warning is present: */
- logbuf_assert("The ordered-by statement is ignored in lists representing state data, RPC/action output parameters or notification content ().");
+ logbuf_assert("The ordered-by statement is ignored in lists representing state data ().");
assert_non_null(mod->compiled);
assert_non_null((ll = (struct lysc_node_leaflist*)mod->compiled->data));
assert_int_equal(LYS_CONFIG_R | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM | LYS_SET_CONFIG, ll->flags);
+ logbuf_clean();
+
+ assert_non_null(mod = lys_parse_mem(ctx, "module e {yang-version 1.1;namespace urn:e;prefix e;"
+ "rpc oper {output {leaf-list ll {type string; ordered-by user;}}}}", LYS_IN_YANG));
+ logbuf_assert("The ordered-by statement is ignored in lists representing RPC/action output parameters ().");
+ logbuf_clean();
+
+ assert_non_null(mod = lys_parse_mem(ctx, "module f {yang-version 1.1;namespace urn:f;prefix f;"
+ "notification event {leaf-list ll {type string; ordered-by user;}}}", LYS_IN_YANG));
+ logbuf_assert("The ordered-by statement is ignored in lists representing notification content ().");
/* invalid */
assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;leaf-list ll {type empty;}}", LYS_IN_YANG));
@@ -817,10 +826,93 @@
logbuf_assert("Duplicate identifier \"y\" of data definition/RPC/action/Notification statement.");
assert_null(lys_parse_mem(ctx, "module dd {yang-version 1.1; namespace urn:dd;prefix dd;container c {action z; action z;}}", LYS_IN_YANG));
logbuf_assert("Duplicate identifier \"z\" of data definition/RPC/action/Notification statement.");
- ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule eesub {belongs-to ee {prefix ee;} rpc w;}");
+ ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule eesub {belongs-to ee {prefix ee;} notification w;}");
assert_null(lys_parse_mem(ctx, "module ee {yang-version 1.1; namespace urn:ee;prefix ee;include eesub; rpc w;}", LYS_IN_YANG));
logbuf_assert("Duplicate identifier \"w\" of data definition/RPC/action/Notification statement.");
+ assert_null(lys_parse_mem(ctx, "module ff {yang-version 1.1; namespace urn:ff;prefix ff; rpc test {input {container a {leaf b {type string;}}}}"
+ "augment /test/input/a {action invalid {input {leaf x {type string;}}}}}", LYS_IN_YANG));
+ logbuf_assert("Action \"invalid\" is placed inside another RPC/action.");
+
+ assert_null(lys_parse_mem(ctx, "module gg {yang-version 1.1; namespace urn:gg;prefix gg; notification test {container a {leaf b {type string;}}}"
+ "augment /test/a {action invalid {input {leaf x {type string;}}}}}", LYS_IN_YANG));
+ logbuf_assert("Action \"invalid\" is placed inside Notification.");
+
+ assert_null(lys_parse_mem(ctx, "module hh {yang-version 1.1; namespace urn:hh;prefix hh; notification test {container a {uses grp;}}"
+ "grouping grp {action invalid {input {leaf x {type string;}}}}}", LYS_IN_YANG));
+ logbuf_assert("Action \"invalid\" is placed inside Notification.");
+
+ *state = NULL;
+ ly_ctx_destroy(ctx, NULL);
+}
+
+static void
+test_notification(void **state)
+{
+ *state = test_notification;
+
+ struct ly_ctx *ctx;
+ struct lys_module *mod;
+ const struct lysc_notif *notif;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
+
+ assert_non_null(mod = lys_parse_mem(ctx, "module a {namespace urn:a;prefix a;"
+ "notification a1 {leaf x {type int8;}} notification a2;}", LYS_IN_YANG));
+ notif = mod->compiled->notifs;
+ assert_non_null(notif);
+ assert_int_equal(2, LY_ARRAY_SIZE(notif));
+ assert_int_equal(LYS_NOTIF, notif->nodetype);
+ assert_int_equal(LYS_STATUS_CURR, notif->flags);
+ assert_string_equal("a1", notif->name);
+ assert_non_null(notif->data);
+ assert_string_equal("x", notif->data->name);
+ assert_int_equal(LYS_NOTIF, notif[1].nodetype);
+ assert_int_equal(LYS_STATUS_CURR, notif[1].flags);
+ assert_string_equal("a2", notif[1].name);
+ assert_null(notif[1].data);
+
+ assert_non_null(mod = lys_parse_mem(ctx, "module b {yang-version 1.1; namespace urn:b;prefix b; container top {"
+ "notification b1 {leaf x {type int8;}} notification b2;}}", LYS_IN_YANG));
+ notif = lysc_node_notifs(mod->compiled->data);
+ assert_non_null(notif);
+ assert_int_equal(2, LY_ARRAY_SIZE(notif));
+ assert_int_equal(LYS_NOTIF, notif->nodetype);
+ assert_int_equal(LYS_STATUS_CURR, notif->flags);
+ assert_string_equal("b1", notif->name);
+ assert_non_null(notif->data);
+ assert_string_equal("x", notif->data->name);
+ assert_int_equal(LYS_NOTIF, notif[1].nodetype);
+ assert_int_equal(LYS_STATUS_CURR, notif[1].flags);
+ assert_string_equal("b2", notif[1].name);
+ assert_null(notif[1].data);
+
+ /* invalid */
+ assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa;container top {notification x;}}", LYS_IN_YANG));
+ logbuf_assert("Invalid keyword \"notification\" as a child of \"container\" - the statement is allowed only in YANG 1.1 modules. Line number 1.");
+
+ assert_null(lys_parse_mem(ctx, "module bb {namespace urn:bb;prefix bb;leaf x{type string;} notification x;}", LYS_IN_YANG));
+ logbuf_assert("Duplicate identifier \"x\" of data definition/RPC/action/Notification statement.");
+ assert_null(lys_parse_mem(ctx, "module cc {yang-version 1.1; namespace urn:cc;prefix cc;container c {leaf y {type string;} notification y;}}", LYS_IN_YANG));
+ logbuf_assert("Duplicate identifier \"y\" of data definition/RPC/action/Notification statement.");
+ assert_null(lys_parse_mem(ctx, "module dd {yang-version 1.1; namespace urn:dd;prefix dd;container c {notification z; notification z;}}", LYS_IN_YANG));
+ logbuf_assert("Duplicate identifier \"z\" of data definition/RPC/action/Notification statement.");
+ ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule eesub {belongs-to ee {prefix ee;} rpc w;}");
+ assert_null(lys_parse_mem(ctx, "module ee {yang-version 1.1; namespace urn:ee;prefix ee;include eesub; notification w;}", LYS_IN_YANG));
+ logbuf_assert("Duplicate identifier \"w\" of data definition/RPC/action/Notification statement.");
+
+ assert_null(lys_parse_mem(ctx, "module ff {yang-version 1.1; namespace urn:ff;prefix ff; rpc test {input {container a {leaf b {type string;}}}}"
+ "augment /test/input/a {notification invalid {leaf x {type string;}}}}", LYS_IN_YANG));
+ logbuf_assert("Notification \"invalid\" is placed inside RPC/action.");
+
+ assert_null(lys_parse_mem(ctx, "module gg {yang-version 1.1; namespace urn:gg;prefix gg; notification test {container a {leaf b {type string;}}}"
+ "augment /test/a {notification invalid {leaf x {type string;}}}}", LYS_IN_YANG));
+ logbuf_assert("Notification \"invalid\" is placed inside another Notification.");
+
+ assert_null(lys_parse_mem(ctx, "module hh {yang-version 1.1; namespace urn:hh;prefix hh; rpc test {input {container a {uses grp;}}}"
+ "grouping grp {notification invalid {leaf x {type string;}}}}", LYS_IN_YANG));
+ logbuf_assert("Notification \"invalid\" is placed inside RPC/action.");
+
*state = NULL;
ly_ctx_destroy(ctx, NULL);
}
@@ -3017,10 +3109,6 @@
"deviation /x {deviate replace {type empty;}}}", LYS_IN_YANG));
logbuf_assert("Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
- assert_null(lys_parse_mem(ctx, "module oo {yang-version 1.1; namespace urn:oo;prefix oo; rpc test {input {container a {leaf b {type string;}}}}"
- "augment /test/input/a {action invalid {input {leaf x {type string;}}}}}", LYS_IN_YANG));
- logbuf_assert("Action \"invalid\" is placed inside another RPC/action.");
-
*state = NULL;
ly_ctx_destroy(ctx, NULL);
}
@@ -3050,6 +3138,7 @@
cmocka_unit_test_setup_teardown(test_node_choice, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_node_anydata, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_action, logger_setup, logger_teardown),
+ cmocka_unit_test_setup_teardown(test_notification, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_uses, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_refine, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_augment, logger_setup, logger_teardown),