schema compile CHANGE partial support for deviations
Currently supported deviations:
- not-supported
- add - units, must, default
- delete - units, must, default
- replace - units, default
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 9f8d3e7..88d164c 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -3056,9 +3056,12 @@
LY_ERR ret = LY_SUCCESS;
COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, options, u, lys_compile_must, ret, done);
- DUP_STRING(ctx->ctx, leaf_p->units, leaf->units);
- DUP_STRING(ctx->ctx, leaf_p->dflt, leaf->dflt);
- if (leaf->dflt) {
+ if (leaf_p->units) {
+ leaf->units = lydict_insert(ctx->ctx, leaf_p->units, 0);
+ leaf->flags |= LYS_SET_UNITS;
+ }
+ if (leaf_p->dflt) {
+ leaf->dflt = lydict_insert(ctx->ctx, leaf_p->dflt, 0);
leaf->flags |= LYS_SET_DFLT;
}
@@ -3108,7 +3111,10 @@
LY_ERR ret = LY_SUCCESS;
COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, options, u, lys_compile_must, ret, done);
- DUP_STRING(ctx->ctx, llist_p->units, llist->units);
+ if (llist_p->units) {
+ llist->units = lydict_insert(ctx->ctx, llist_p->units, 0);
+ llist->flags |= LYS_SET_UNITS;
+ }
if (llist_p->dflts) {
LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts, LY_ARRAY_SIZE(llist_p->dflts), ret, done);
@@ -3116,6 +3122,7 @@
DUP_STRING(ctx->ctx, llist_p->dflts[u], llist->dflts[u]);
LY_ARRAY_INCREMENT(llist->dflts);
}
+ llist->flags |= LYS_SET_DFLT;
}
llist->min = llist_p->min;
@@ -3398,6 +3405,62 @@
return LY_SUCCESS;
}
+static LY_ERR
+lys_compile_deviation_set_choice_dflt(struct lysc_ctx *ctx, const char *devnodeid, const char *dflt, struct lysc_node_choice *ch)
+{
+ struct lys_module *mod;
+ const char *prefix = NULL, *name;
+ size_t prefix_len = 0;
+ struct lysc_node_case *cs;
+ struct lysc_node *node;
+
+ /* could use lys_parse_nodeid(), but it checks syntax which is already done in this case by the parsers */
+ name = strchr(dflt, ':');
+ if (name) {
+ prefix = dflt;
+ prefix_len = name - prefix;
+ ++name;
+ } else {
+ name = dflt;
+ }
+ /* this code is for deviation, so we allow as the default case even the cases from other modules than the choice (augments) */
+ if (prefix) {
+ if (!(mod = lys_module_find_prefix(ctx->mod, prefix, prefix_len))) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation (%s) adding \"default\" property \"%s\" of choice. "
+ "The prefix does not match any imported module of the deviation module.",
+ devnodeid, dflt);
+ return LY_EVALID;
+ }
+ } else {
+ mod = ctx->mod;
+ }
+ /* get the default case */
+ cs = (struct lysc_node_case*)lys_child((struct lysc_node*)ch, mod, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
+ if (!cs) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation (%s) adding \"default\" property \"%s\" of choice - the specified case does not exists.",
+ devnodeid, dflt);
+ return LY_EVALID;
+ }
+
+ /* check that there is no mandatory node */
+ LY_LIST_FOR(cs->child, node) {
+ if (node->flags & LYS_MAND_TRUE) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid deviation (%s) adding \"default\" property \"%s\" of choice - "
+ "mandatory node \"%s\" under the default case.", devnodeid, dflt, node->name);
+ return LY_EVALID;
+ }
+ }
+
+ /* set the default case in choice */
+ ch->dflt = cs;
+ cs->flags |= LYS_SET_DFLT;
+
+ return LY_SUCCESS;
+}
+
/**
* @brief Compile parsed choice node information.
* @param[in] ctx Compile context
@@ -4522,6 +4585,470 @@
return ret;
}
+static void
+lysc_disconnect(struct lysc_node *node)
+{
+ struct lysc_node *parent, *child, *nextchild;
+ struct lysc_node_case *cs;
+ int remove_cs = 0;
+
+ parent = node->parent;
+
+ /* parent's first child */
+ if (!parent) {
+ return;
+ }
+ if (parent->nodetype == LYS_CHOICE) {
+ if (node->nodetype == LYS_CASE) {
+ cs = (struct lysc_node_case*)node;
+ } else {
+ /* disconnecting some node in a case */
+ for (cs = ((struct lysc_node_choice*)parent)->cases; cs; cs = (struct lysc_node_case*)cs->next) {
+ nextchild = cs->next ? ((struct lysc_node_case*)cs->next)->child : NULL;
+ for (child = cs->child; child != nextchild && child != node; child = child->next);
+ if (child != nextchild) {
+ /* we are at the node being removed */
+ if (cs->child == node) {
+ if (node->next != nextchild) {
+ cs->child = node->next;
+ } else {
+ /* case with a single child -> remove also the case */
+ remove_cs = 1;
+ }
+ }
+ }
+ }
+ }
+ if (cs) {
+ if (((struct lysc_node_choice*)parent)->dflt == cs) {
+ /* default case removed */
+ ((struct lysc_node_choice*)parent)->dflt = NULL;
+ }
+ if (((struct lysc_node_choice*)parent)->cases == cs) {
+ /* first case removed */
+ ((struct lysc_node_choice*)parent)->cases = (struct lysc_node_case*)cs->next;
+ }
+ if (remove_cs) {
+ lysc_disconnect((struct lysc_node*)cs);
+ lysc_node_free(cs->module->ctx, (struct lysc_node*)cs);
+ }
+ }
+ } else if (lysc_node_children(parent) == node) {
+ *lysc_node_children_p(node) = node->next;
+ }
+
+ /* siblings */
+ node->prev->next = node->next;
+ if (node->next) {
+ node->next->prev = node->prev;
+ }
+}
+
+LY_ERR
+lys_compile_deviations(struct lysc_ctx *ctx, struct lysp_module *mod_p, int options)
+{
+ LY_ERR ret = LY_EVALID;
+ struct ly_set devs_p = {0};
+ struct ly_set targets = {0};
+ struct lysc_node *target; /* target target of the deviation */
+ struct lysp_deviation *dev;
+ struct lysp_deviate *d, **dp_new;
+ struct lysp_deviate_add *d_add;
+ struct lysp_deviate_del *d_del;
+ struct lysp_deviate_rpl *d_rpl;
+ unsigned int u, v, x, y;
+ struct lysc_deviation {
+ 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 */
+ uint8_t not_supported; /* flag if deviates contains not-supported deviate */
+ } **devs = NULL;
+ int i;
+ size_t prefix_len, name_len;
+ const char *prefix, *name, *nodeid;
+ struct lys_module *mod;
+
+ /* get all deviations from the module and all its submodules ... */
+ LY_ARRAY_FOR(mod_p->deviations, u) {
+ ly_set_add(&devs_p, &mod_p->deviations[u], LY_SET_OPT_USEASLIST);
+ }
+ LY_ARRAY_FOR(mod_p->includes, v) {
+ LY_ARRAY_FOR(mod_p->includes[v].submodule->deviations, u) {
+ ly_set_add(&devs_p, &mod_p->includes[v].submodule->deviations[u], LY_SET_OPT_USEASLIST);
+ }
+ }
+ if (!devs_p.count) {
+ /* nothing to do */
+ return LY_SUCCESS;
+ }
+
+ /* ... and group them by the target node */
+ devs = calloc(devs_p.count, sizeof *devs);
+ for (u = 0; u < devs_p.count; ++u) {
+ dev = devs_p.objs[u];
+
+ /* resolve the target */
+ LY_CHECK_GOTO(lys_resolve_schema_nodeid(ctx, dev->nodeid, 0, NULL, 0, 1, (const struct lysc_node**)&target), cleanup);
+
+ /* insert into the set of targets with duplicity detection */
+ i = ly_set_add(&targets, target, 0);
+ if (!devs[i]) {
+ /* new record */
+ devs[i] = calloc(1, sizeof **devs);
+ devs[i]->target = target;
+ devs[i]->nodeid = dev->nodeid;
+ }
+ /* add deviates into the deviation's list of deviates */
+ for (d = dev->deviates; d; d = d->next) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, devs[i]->deviates, dp_new, ret, cleanup);
+ *dp_new = d;
+ if (d->mod == LYS_DEV_NOT_SUPPORTED) {
+ devs[i]->not_supported = 1;
+ }
+ }
+ }
+
+ /* MACROS for deviates checking */
+#define DEV_CHECK_NODETYPE(NODETYPES, DEVTYPE, PROPERTY) \
+ if (!(devs[u]->target->nodetype & (NODETYPES))) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE, devs[u]->nodeid, lys_nodetype2str(devs[u]->target->nodetype), DEVTYPE, PROPERTY);\
+ goto cleanup; \
+ }
+
+#define DEV_CHECK_CARDINALITY(ARRAY, MAX, PROPERTY) \
+ if (LY_ARRAY_SIZE(ARRAY) > MAX) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid deviation (%s) of %s with too many (%u) %s properties.", \
+ devs[u]->nodeid, lys_nodetype2str(devs[u]->target->nodetype), LY_ARRAY_SIZE(ARRAY), PROPERTY); \
+ goto cleanup; \
+ }
+
+#define DEV_CHECK_NONPRESENCE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER) \
+ if (((TYPE)devs[u]->target)->MEMBER && COND) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation (%s) adding \"%s\" property which already exists (with value \"%s\").", \
+ devs[u]->nodeid, PROPERTY, ((TYPE)devs[u]->target)->VALUEMEMBER); \
+ goto cleanup; \
+ }
+
+#define DEV_CHECK_PRESENCE(TYPE, COND, MEMBER, DEVTYPE, PROPERTY, VALUE) \
+ if (!((TYPE)devs[u]->target)->MEMBER || COND) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, devs[u]->nodeid, DEVTYPE, PROPERTY, VALUE); \
+ goto cleanup; \
+ }
+
+#define DEV_DEL_MEMBER(TYPE, MEMBER_TRG, MEMBER_DEV, DELFUNC, PROPERTY) \
+ DEV_CHECK_PRESENCE(TYPE, 0, MEMBER_TRG, "deleting", PROPERTY, d_del->MEMBER_DEV); \
+ if (strcmp(((TYPE)devs[u]->target)->MEMBER_TRG, d_del->MEMBER_DEV)) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation (%s) deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
+ devs[u]->nodeid, PROPERTY, d_del->MEMBER_DEV, ((TYPE)devs[u]->target)->MEMBER_TRG); \
+ goto cleanup; \
+ } \
+ 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; } \
+ } \
+ if (y == LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY)) { \
+ 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); \
+ 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)); \
+ } \
+ if (!LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY)) { \
+ LY_ARRAY_FREE(((TYPE)devs[u]->target)->ARRAY); \
+ ((TYPE)devs[u]->target)->ARRAY = NULL; \
+ }
+
+ /* apply deviations */
+ for (u = 0; u < devs_p.count && devs[u]; ++u) {
+ /* not-supported */
+ if (devs[u]->not_supported) {
+ if (LY_ARRAY_SIZE(devs[u]->deviates) > 1) {
+ 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);
+ }
+ /* remove the target node */
+ lysc_disconnect(devs[u]->target);
+ lysc_node_free(ctx->ctx, devs[u]->target);
+
+ continue;
+ }
+
+ /* list of deviates (not-supported is not present in the list) */
+ LY_ARRAY_FOR(devs[u]->deviates, v) {
+ d = devs[u]->deviates[v];
+
+ switch (d->mod) {
+ case LYS_DEV_ADD:
+ d_add = (struct lysp_deviate_add*)d;
+ /* [units-stmt] */
+ if (d_add->units) {
+ DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "add", "units");
+ DEV_CHECK_NONPRESENCE(struct lysc_node_leaf*, (devs[u]->target->flags & LYS_SET_UNITS), units, "units", units);
+
+ FREE_STRING(ctx->ctx, ((struct lysc_node_leaf*)devs[u]->target)->units);
+ DUP_STRING(ctx->ctx, d_add->units, ((struct lysc_node_leaf*)devs[u]->target)->units);
+ }
+
+ /* *must-stmt */
+ if (d_add->musts) {
+ switch (devs[u]->target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_node_container*)devs[u]->target)->musts,
+ options, x, lys_compile_must, ret, cleanup);
+ break;
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_ANYDATA:
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_node_leaf*)devs[u]->target)->musts,
+ options, x, lys_compile_must, ret, cleanup);
+ break;
+ case LYS_NOTIF:
+ case LYS_INOUT:
+ /* TODO */
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ devs[u]->nodeid, lys_nodetype2str(target->nodetype), "add", "must");
+ goto cleanup;
+ }
+ }
+
+ /* *unique-stmt */
+
+ /* *default-stmt */
+ if (d_add->dflts) {
+ if (devs[u]->target->flags & LYS_MAND_TRUE) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid deviation (%s) adding \"default\" property \"%s\" into a mandatory node.", devs[u]->nodeid, d_add->dflts[0]);
+ goto cleanup;
+ }
+ switch (devs[u]->target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_CARDINALITY(d_add->dflts, 1, "default");
+ DEV_CHECK_NONPRESENCE(struct lysc_node_leaf*, (devs[u]->target->flags & LYS_SET_DFLT), dflt, "default", dflt);
+ if (((struct lysc_node_leaf*)devs[u]->target)->dflt) {
+ /* first, remove the default value taken from the type */
+ lydict_remove(ctx->ctx, ((struct lysc_node_leaf*)devs[u]->target)->dflt);
+ ((struct lysc_node_leaf*)devs[u]->target)->dflt = NULL;
+ }
+ DUP_STRING(ctx->ctx, d_add->dflts[0], ((struct lysc_node_leaf*)devs[u]->target)->dflt);
+ break;
+ case LYS_LEAFLIST:
+ if (((struct lysc_node_leaflist*)devs[u]->target)->dflts && !(devs[u]->target->flags & LYS_SET_DFLT)) {
+ /* first, remove the default value taken from the type */
+ LY_ARRAY_FOR(((struct lysc_node_leaflist*)devs[u]->target)->dflts, x) {
+ lydict_remove(ctx->ctx, ((struct lysc_node_leaflist*)devs[u]->target)->dflts[x]);
+ }
+ LY_ARRAY_FREE(((struct lysc_node_leaflist*)devs[u]->target)->dflts);
+ ((struct lysc_node_leaflist*)devs[u]->target)->dflts = NULL;
+ }
+ /* add new default value(s) */
+ LY_ARRAY_CREATE_GOTO(ctx->ctx, ((struct lysc_node_leaflist*)devs[u]->target)->dflts,
+ LY_ARRAY_SIZE(d_add->dflts), ret, cleanup);
+ for (x = y = LY_ARRAY_SIZE(((struct lysc_node_leaflist*)devs[u]->target)->dflts);
+ x < LY_ARRAY_SIZE(d_add->dflts) + y; ++x) {
+ DUP_STRING(ctx->ctx, d_add->dflts[x - y], ((struct lysc_node_leaflist*)devs[u]->target)->dflts[x]);
+ LY_ARRAY_INCREMENT(((struct lysc_node_leaflist*)devs[u]->target)->dflts);
+ }
+ /* mark the new default values as leafref's own */
+ devs[u]->target->flags |= LYS_SET_DFLT;
+ break;
+ case LYS_CHOICE:
+ DEV_CHECK_CARDINALITY(d_add->dflts, 1, "default");
+ DEV_CHECK_NONPRESENCE(struct lysc_node_choice*, 1, dflt, "default", dflt->name);
+ /* in contrast to delete, here we strictly resolve the prefix in the module of the deviation
+ * to allow making the default case even the augmented case from the deviating module */
+ if (lys_compile_deviation_set_choice_dflt(ctx, devs[u]->nodeid, d_add->dflts[0],
+ (struct lysc_node_choice*)devs[u]->target)) {
+ goto cleanup;
+ }
+ break;
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ devs[u]->nodeid, lys_nodetype2str(target->nodetype), "add", "default");
+ goto cleanup;
+ }
+ }
+
+ /* [config-stmt] */
+
+ /* [mandatory-stmt] */
+
+ /* [min-elements-stmt] */
+
+ /* [max-elements-stmt] */
+
+ break;
+ case LYS_DEV_DELETE:
+ d_del = (struct lysp_deviate_del*)d;
+
+ /* [units-stmt] */
+ if (d_del->units) {
+ DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "delete", "units");
+ DEV_DEL_MEMBER(struct lysc_node_leaf*, units, units, lydict_remove, "units");
+ }
+
+ /* *must-stmt */
+ if (d_del->musts) {
+ 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");
+ 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");
+ break;
+ case LYS_NOTIF:
+ case LYS_INOUT:
+ /* TODO */
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ devs[u]->nodeid, lys_nodetype2str(target->nodetype), "delete", "must");
+ goto cleanup;
+ }
+ }
+
+ /* *unique-stmt */
+
+ /* *default-stmt */
+ if (d_del->dflts) {
+ switch (devs[u]->target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_CARDINALITY(d_del->dflts, 1, "default");
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf*, !(devs[u]->target->flags & LYS_SET_DFLT),
+ dflt, "deleting", "default", d_del->dflts[0]);
+
+ DEV_DEL_MEMBER(struct lysc_node_leaf*, dflt, dflts[0], lydict_remove, "default");
+ break;
+ case LYS_LEAFLIST:
+ DEV_DEL_ARRAY(struct lysc_node_leaflist*, dflts, , , , lydict_remove, "default");
+ break;
+ case LYS_CHOICE:
+ DEV_CHECK_CARDINALITY(d_del->dflts, 1, "default");
+ DEV_CHECK_PRESENCE(struct lysc_node_choice*, 0, dflt, "deleting", "default", d_del->dflts[0]);
+ nodeid = d_del->dflts[0];
+ LY_CHECK_GOTO(lys_parse_nodeid(&nodeid, &prefix, &prefix_len, &name, &name_len), cleanup);
+ if (prefix) {
+ /* use module prefixes from the deviation module to match the module of the default case */
+ if (!(mod = lys_module_find_prefix(ctx->mod, prefix, prefix_len))) {
+ LOGVAL(ctx->ctx,LY_VLOG_STR,ctx->path,LYVE_REFERENCE,
+ "Invalid deviation (%s) deleting \"default\" property \"%s\" of choice. "
+ "The prefix does not match any imported module of the deviation module.",
+ devs[u]->nodeid, d_del->dflts[0]);
+ goto cleanup;
+ }
+ if (mod != ((struct lysc_node_choice*)devs[u]->target)->dflt->module) {
+ LOGVAL(ctx->ctx,LY_VLOG_STR,ctx->path,LYVE_REFERENCE,
+ "Invalid deviation (%s) deleting \"default\" property \"%s\" of choice. "
+ "The prefix does not match the default case's module.",
+ devs[u]->nodeid, d_del->dflts[0]);
+ goto cleanup;
+ }
+ }
+ /* else {
+ * strictly, the default prefix would point to the deviation module, but the value should actually
+ * match the default string in the original module (usually unprefixed), so in this case we do not check
+ * the module of the default case, just matching its name */
+ if (strcmp(name, ((struct lysc_node_choice*)devs[u]->target)->dflt->name)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation (%s) deleting \"default\" property \"%s\" of choice does not match the default case name \"%s\".",
+ devs[u]->nodeid, d_del->dflts[0], ((struct lysc_node_choice*)devs[u]->target)->dflt->name);
+ goto cleanup;
+ }
+ ((struct lysc_node_choice*)devs[u]->target)->dflt->flags &= ~LYS_SET_DFLT;
+ ((struct lysc_node_choice*)devs[u]->target)->dflt = NULL;
+ break;
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ devs[u]->nodeid, lys_nodetype2str(target->nodetype), "delete", "default");
+ goto cleanup;
+ }
+ }
+
+ break;
+ case LYS_DEV_REPLACE:
+ d_rpl = (struct lysp_deviate_rpl*)d;
+
+ /* [type-stmt] */
+
+ /* [units-stmt] */
+ if (d_rpl->units) {
+ DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "replace", "units");
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf*, !(devs[u]->target->flags & LYS_SET_UNITS),
+ units, "replacing", "units", d_rpl->units);
+
+ lydict_remove(ctx->ctx, ((struct lysc_node_leaf*)devs[u]->target)->units);
+ DUP_STRING(ctx->ctx, d_rpl->units, ((struct lysc_node_leaf*)devs[u]->target)->units);
+ }
+
+ /* [default-stmt] */
+ if (d_rpl->dflt) {
+ switch (devs[u]->target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf*, !(devs[u]->target->flags & LYS_SET_DFLT),
+ dflt, "replacing", "default", d_rpl->dflt);
+
+ lydict_remove(ctx->ctx, ((struct lysc_node_leaf*)devs[u]->target)->dflt);
+ DUP_STRING(ctx->ctx, d_rpl->dflt, ((struct lysc_node_leaf*)devs[u]->target)->dflt);
+ break;
+ case LYS_CHOICE:
+ DEV_CHECK_PRESENCE(struct lysc_node_choice*, 0, dflt, "replacing", "default", d_rpl->dflt);
+ if (lys_compile_deviation_set_choice_dflt(ctx, devs[u]->nodeid, d_rpl->dflt,
+ (struct lysc_node_choice*)devs[u]->target)) {
+ goto cleanup;
+ }
+ break;
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ devs[u]->nodeid, lys_nodetype2str(target->nodetype), "replace", "default");
+ goto cleanup;
+ }
+ }
+
+ /* [config-stmt] */
+
+ /* [mandatory-stmt] */
+
+ /* [min-elements-stmt] */
+
+ /* [max-elements-stmt] */
+
+ break;
+ default:
+ LOGINT(ctx->ctx);
+ goto cleanup;
+ }
+ }
+ }
+
+ ret = LY_SUCCESS;
+
+cleanup:
+ for (u = 0; u < devs_p.count && devs[u]; ++u) {
+ LY_ARRAY_FREE(devs[u]->deviates);
+ free(devs[u]);
+ }
+ free(devs);
+ ly_set_erase(&targets, NULL);
+ ly_set_erase(&devs_p, NULL);
+
+ return ret;
+}
+
/**
* @brief Compile the given YANG submodule into the main module.
* @param[in] ctx Compile context
@@ -4623,6 +5150,9 @@
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);
+
/* augments - sort first to cover augments augmenting other augments */
ret = lys_compile_augment_sort(&ctx, sp->augments, sp->includes, &augments);
LY_CHECK_GOTO(ret, error);
@@ -4630,8 +5160,10 @@
ret = lys_compile_augment(&ctx, augments[u], options, NULL);
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);
+
+ /* deviations */
+ ret = lys_compile_deviations(&ctx, sp, options);
+ LY_CHECK_GOTO(ret, error);
COMPILE_ARRAY_GOTO(&ctx, sp->exts, mod_c->exts, options, u, lys_compile_ext, ret, error);