schema compile REFACTOR apply_deviation function
Applying deviations of a single target node
separated into a function.
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 50f74d8..b5fe792 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -5601,35 +5601,896 @@
}
}
-LY_ERR
-lys_compile_deviations(struct lysc_ctx *ctx, struct lysp_module *mod_p)
+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 */
+ uint16_t flags; /* target's flags from lys_resolve_schema_nodeid() */
+ uint8_t not_supported; /* flag if deviates contains not-supported deviate */
+};
+
+/**
+ * @brief Apply all deviations of one target node.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] dev Deviation structure to apply.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_deviation(struct lysc_ctx *ctx, struct lysc_deviation *dev)
{
LY_ERR ret = LY_EVALID, rc;
- struct ly_set devs_p = {0};
- struct ly_set targets = {0};
- struct lysc_node *target; /* target target of the deviation */
+ struct lysc_node *target = dev->target;
+ struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
+ struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
+ struct ly_err_item *err = NULL;
struct lysc_node_list *list;
struct lysc_action *rpcs;
struct lysc_notif *notifs;
- struct lysp_deviation *dev;
- struct lysp_deviate *d, **dp_new;
+ struct lysp_deviate *d;
struct lysp_deviate_add *d_add;
struct lysp_deviate_del *d_del;
struct lysp_deviate_rpl *d_rpl;
- LY_ARRAY_COUNT_TYPE u, v, x, y, z;
- 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 */
- 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, changed_type;
+ LY_ARRAY_COUNT_TYPE v, x, y, z;
+ int i, changed_type = 0;
size_t prefix_len, name_len;
- const char *prefix, *name, *nodeid, *dflt;
- struct lys_module *mod, **dev_mod;
+ const char *prefix, *name, *nodeid, *dflt = NULL;
+ struct lys_module *mod;
uint32_t min, max;
+
+ /* MACROS for deviates checking */
+#define DEV_CHECK_NODETYPE(NODETYPES, DEVTYPE, PROPERTY) \
+ if (!(target->nodetype & (NODETYPES))) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE, lys_nodetype2str(target->nodetype), DEVTYPE, PROPERTY);\
+ goto cleanup; \
+ }
+
+#define DEV_CHECK_CARDINALITY(ARRAY, MAX, PROPERTY) \
+ if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid deviation of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
+ lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
+ goto cleanup; \
+ }
+
+
+#define DEV_CHECK_NONPRESENCE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER) \
+ if (((TYPE)target)->MEMBER && (COND)) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
+ PROPERTY, ((TYPE)target)->VALUEMEMBER); \
+ goto cleanup; \
+ }
+
+#define DEV_CHECK_NONPRESENCE_VALUE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER, VALUEMODMEMBER) \
+ if (((TYPE)target)->MEMBER && (COND)) { \
+ int dynamic_ = 0; const char *val_; \
+ val_ = ((TYPE)target)->VALUEMEMBER->realtype->plugin->print(((TYPE)target)->VALUEMEMBER, LYD_XML, \
+ lys_get_prefix, ((TYPE)target)->VALUEMODMEMBER, &dynamic_); \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", PROPERTY, val_); \
+ if (dynamic_) {free((void*)val_);} \
+ goto cleanup; \
+ }
+
+#define DEV_CHECK_NONPRESENCE_UINT(TYPE, COND, MEMBER, PROPERTY) \
+ if (((TYPE)target)->MEMBER COND) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation adding \"%s\" property which already exists (with value \"%u\").", \
+ PROPERTY, ((TYPE)target)->MEMBER); \
+ goto cleanup; \
+ }
+
+#define DEV_CHECK_PRESENCE(TYPE, COND, MEMBER, DEVTYPE, PROPERTY, VALUE) \
+ if (!((TYPE)target)->MEMBER || COND) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
+ goto cleanup; \
+ }
+
+#define DEV_CHECK_PRESENCE_UINT(TYPE, COND, MEMBER, PROPERTY) \
+ if (!(((TYPE)target)->MEMBER COND)) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation replacing with \"%s\" property \"%u\" which is not present.", PROPERTY, d_rpl->MEMBER); \
+ goto cleanup; \
+ }
+
+#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)target)->ARRAY_TRG, y) { \
+ if (!strcmp(((TYPE)target)->ARRAY_TRG[y]VALMEMBER_CMP, d_del->ARRAY_DEV[x]VALMEMBER)) { break; } \
+ } \
+ if (y == LY_ARRAY_COUNT(((TYPE)target)->ARRAY_TRG)) { \
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
+ "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
+ PROPERTY, d_del->ARRAY_DEV[x]VALMEMBER); \
+ goto cleanup; \
+ } \
+ LY_ARRAY_DECREMENT(((TYPE)target)->ARRAY_TRG); \
+ DELFUNC(ctx->ctx, DELFUNC_DEREF((TYPE)target)->ARRAY_TRG[y]); \
+ memmove(&((TYPE)target)->ARRAY_TRG[y], \
+ &((TYPE)target)->ARRAY_TRG[y + 1], \
+ (LY_ARRAY_COUNT(((TYPE)target)->ARRAY_TRG) - y) * (sizeof *((TYPE)target)->ARRAY_TRG)); \
+ } \
+ if (!LY_ARRAY_COUNT(((TYPE)target)->ARRAY_TRG)) { \
+ LY_ARRAY_FREE(((TYPE)target)->ARRAY_TRG); \
+ ((TYPE)target)->ARRAY_TRG = NULL; \
+ }
+
+ lysc_update_path(ctx, NULL, dev->nodeid);
+
+ /* not-supported */
+ if (dev->not_supported) {
+ if (LY_ARRAY_COUNT(dev->deviates) > 1) {
+ LOGWRN(ctx->ctx, "Useless multiple (%"LY_PRI_ARRAY_COUNT_TYPE") deviates on node \"%s\" since the node is not-supported.",
+ LY_ARRAY_COUNT(dev->deviates), dev->nodeid);
+ }
+
+#define REMOVE_NONDATA(ARRAY, TYPE, GETFUNC, FREEFUNC) \
+ if (target->parent) { \
+ ARRAY = (TYPE*)GETFUNC(target->parent); \
+ } else { \
+ ARRAY = target->module->compiled->ARRAY; \
+ } \
+ LY_ARRAY_FOR(ARRAY, x) { \
+ if (&ARRAY[x] == (TYPE*)target) { break; } \
+ } \
+ if (x < LY_ARRAY_COUNT(ARRAY)) { \
+ FREEFUNC(ctx->ctx, &ARRAY[x]); \
+ memmove(&ARRAY[x], &ARRAY[x + 1], (LY_ARRAY_COUNT(ARRAY) - (x + 1)) * sizeof *ARRAY); \
+ LY_ARRAY_DECREMENT(ARRAY); \
+ }
+
+ if (target->nodetype & (LYS_RPC | LYS_ACTION)) {
+ if (dev->flags & LYSC_OPT_RPC_INPUT) {
+ /* remove RPC's/action's input */
+ lysc_action_inout_free(ctx->ctx, &((struct lysc_action*)target)->input);
+ memset(&((struct lysc_action*)target)->input, 0, sizeof ((struct lysc_action*)target)->input);
+ FREE_ARRAY(ctx->ctx, ((struct lysc_action*)target)->input_exts, lysc_ext_instance_free);
+ ((struct lysc_action*)target)->input_exts = NULL;
+ } else if (dev->flags & LYSC_OPT_RPC_OUTPUT) {
+ /* remove RPC's/action's output */
+ lysc_action_inout_free(ctx->ctx, &((struct lysc_action*)target)->output);
+ memset(&((struct lysc_action*)target)->output, 0, sizeof ((struct lysc_action*)target)->output);
+ FREE_ARRAY(ctx->ctx, ((struct lysc_action*)target)->output_exts, lysc_ext_instance_free);
+ ((struct lysc_action*)target)->output_exts = NULL;
+ } else {
+ /* remove RPC/action */
+ REMOVE_NONDATA(rpcs, struct lysc_action, lysc_node_actions, lysc_action_free);
+ }
+ } else if (target->nodetype == LYS_NOTIF) {
+ /* remove Notification */
+ REMOVE_NONDATA(notifs, struct lysc_notif, lysc_node_notifs, lysc_notif_free);
+ } else {
+ /* remove the target node */
+ lysc_disconnect(target);
+ lysc_node_free(ctx->ctx, target);
+ }
+
+ /* mark the context for later re-compilation of objects that could reference the curently removed node */
+ ctx->ctx->flags |= LY_CTX_CHANGED_TREE;
+ return LY_SUCCESS;
+ }
+
+ /* list of deviates (not-supported is not present in the list) */
+ LY_ARRAY_FOR(dev->deviates, v) {
+ d = dev->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*, (target->flags & LYS_SET_UNITS), units, "units", units);
+
+ FREE_STRING(ctx->ctx, ((struct lysc_node_leaf*)target)->units);
+ DUP_STRING(ctx->ctx, d_add->units, ((struct lysc_node_leaf*)target)->units);
+ }
+
+ /* *must-stmt */
+ if (d_add->musts) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_node_container*)target)->musts,
+ 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*)target)->musts,
+ x, lys_compile_must, ret, cleanup);
+ break;
+ case LYS_NOTIF:
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_notif*)target)->musts,
+ x, lys_compile_must, ret, cleanup);
+ break;
+ case LYS_RPC:
+ case LYS_ACTION:
+ if (dev->flags & LYSC_OPT_RPC_INPUT) {
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_action*)target)->input.musts,
+ x, lys_compile_must, ret, cleanup);
+ break;
+ } else if (dev->flags & LYSC_OPT_RPC_OUTPUT) {
+ COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_action*)target)->output.musts,
+ x, lys_compile_must, ret, cleanup);
+ break;
+ }
+ /* fall through */
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "add", "must");
+ goto cleanup;
+ }
+ ly_set_add(&ctx->xpath, target, 0);
+ }
+
+ /* *unique-stmt */
+ if (d_add->uniques) {
+ DEV_CHECK_NODETYPE(LYS_LIST, "add", "unique");
+ LY_CHECK_GOTO(lys_compile_node_list_unique(ctx, ctx->mod, d_add->uniques, (struct lysc_node_list*)target), cleanup);
+ }
+
+ /* *default-stmt */
+ if (d_add->dflts) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_CARDINALITY(d_add->dflts, 1, "default");
+ DEV_CHECK_NONPRESENCE_VALUE(struct lysc_node_leaf*, (target->flags & LYS_SET_DFLT), dflt, "default", dflt, dflt_mod);
+ if (leaf->dflt) {
+ /* first, remove the default value taken from the type */
+ lysc_incomplete_dflts_remove(ctx, leaf->dflt);
+ leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+ lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+ } else {
+ /* prepare new default value storage */
+ leaf->dflt = calloc(1, sizeof *leaf->dflt);
+ }
+ dflt = d_add->dflts[0];
+ /* parsing is done at the end after possible replace of the leaf's type */
+
+ /* mark the new default values as leaf's own */
+ target->flags |= LYS_SET_DFLT;
+ break;
+ case LYS_LEAFLIST:
+ if (llist->dflts && !(target->flags & LYS_SET_DFLT)) {
+ /* first, remove the default value taken from the type */
+ LY_ARRAY_FOR(llist->dflts, x) {
+ lysc_incomplete_dflts_remove(ctx, llist->dflts[x]);
+ llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
+ lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
+ free(llist->dflts[x]);
+ }
+ LY_ARRAY_FREE(llist->dflts);
+ llist->dflts = NULL;
+ LY_ARRAY_FREE(llist->dflts_mods);
+ llist->dflts_mods = NULL;
+ }
+ /* add new default value(s) */
+ LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts_mods, LY_ARRAY_COUNT(d_add->dflts), ret, cleanup);
+ LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts, LY_ARRAY_COUNT(d_add->dflts), ret, cleanup);
+ for (x = y = LY_ARRAY_COUNT(llist->dflts);
+ x < LY_ARRAY_COUNT(d_add->dflts) + y; ++x) {
+ LY_ARRAY_INCREMENT(llist->dflts_mods);
+ llist->dflts_mods[x] = ctx->mod_def;
+ LY_ARRAY_INCREMENT(llist->dflts);
+ llist->dflts[x] = calloc(1, sizeof *llist->dflts[x]);
+ llist->dflts[x]->realtype = llist->type;
+ rc = llist->type->plugin->store(ctx->ctx, llist->type, d_add->dflts[x - y], strlen(d_add->dflts[x - y]),
+ LY_TYPE_OPTS_INCOMPLETE_DATA |LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE, lys_resolve_prefix,
+ (void*)llist->dflts_mods[x], LYD_XML, target, NULL, llist->dflts[x], NULL, &err);
+ llist->dflts[x]->realtype->refcount++;
+ if (err) {
+ ly_err_print(err);
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid deviation adding \"default\" property \"%s\" which does not fit the type (%s).",
+ d_add->dflts[x - y], err->msg);
+ ly_err_free(err);
+ }
+ if (rc == LY_EINCOMPLETE) {
+ /* postpone default compilation when the tree is complete */
+ LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, target, llist->dflts[x], llist->dflts_mods[x]), cleanup);
+
+ /* but in general result is so far ok */
+ rc = LY_SUCCESS;
+ }
+ LY_CHECK_GOTO(rc, cleanup);
+ }
+ /* mark the new default values as leaf-list's own */
+ 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, d_add->dflts[0], (struct lysc_node_choice*)target)) {
+ goto cleanup;
+ }
+ break;
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "add", "default");
+ goto cleanup;
+ }
+ }
+
+ /* [config-stmt] */
+ if (d_add->flags & LYS_CONFIG_MASK) {
+ if (target->nodetype & (LYS_CASE | LYS_INOUT | LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "add", "config");
+ goto cleanup;
+ }
+ if (dev->flags) {
+ LOGWRN(ctx->ctx, "Deviating config inside %s has no effect.",
+ dev->flags & LYSC_OPT_NOTIFICATION ? "notification" : "RPC/action");
+ }
+ if (target->flags & LYS_SET_CONFIG) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
+ target->flags & LYS_CONFIG_W ? "true" : "false");
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(lys_compile_change_config(ctx, target, d_add->flags, 0, 0), cleanup);
+ }
+
+ /* [mandatory-stmt] */
+ if (d_add->flags & LYS_MAND_MASK) {
+ if (target->flags & LYS_MAND_MASK) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
+ target->flags & LYS_MAND_TRUE ? "true" : "false");
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, target, d_add->flags, 0), cleanup);
+ }
+
+ /* [min-elements-stmt] */
+ if (d_add->flags & LYS_SET_MIN) {
+ if (target->nodetype == LYS_LEAFLIST) {
+ DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_leaflist*, > 0, min, "min-elements");
+ /* change value */
+ ((struct lysc_node_leaflist*)target)->min = d_add->min;
+ } else if (target->nodetype == LYS_LIST) {
+ DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_list*, > 0, min, "min-elements");
+ /* change value */
+ ((struct lysc_node_list*)target)->min = d_add->min;
+ } else {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "add", "min-elements");
+ goto cleanup;
+ }
+ if (d_add->min) {
+ target->flags |= LYS_MAND_TRUE;
+ }
+ }
+
+ /* [max-elements-stmt] */
+ if (d_add->flags & LYS_SET_MAX) {
+ if (target->nodetype == LYS_LEAFLIST) {
+ DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_leaflist*, < (uint32_t)-1, max, "max-elements");
+ /* change value */
+ ((struct lysc_node_leaflist*)target)->max = d_add->max ? d_add->max : (uint32_t)-1;
+ } else if (target->nodetype == LYS_LIST) {
+ DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_list*, < (uint32_t)-1, max, "max-elements");
+ /* change value */
+ ((struct lysc_node_list*)target)->max = d_add->max ? d_add->max : (uint32_t)-1;
+ } else {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "add", "max-elements");
+ goto cleanup;
+ }
+ }
+
+ 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_CHECK_PRESENCE(struct lysc_node_leaf*, 0, units, "deleting", "units", d_del->units);
+ if (strcmp(((struct lysc_node_leaf*)target)->units, d_del->units)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation deleting \"units\" property \"%s\" which does not match the target's property value \"%s\".",
+ d_del->units, ((struct lysc_node_leaf*)target)->units);
+ goto cleanup;
+ }
+ lydict_remove(ctx->ctx, ((struct lysc_node_leaf*)target)->units);
+ ((struct lysc_node_leaf*)target)->units = NULL;
+ }
+
+ /* *must-stmt */
+ if (d_del->musts) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ 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, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+ break;
+ case LYS_NOTIF:
+ DEV_DEL_ARRAY(struct lysc_notif*, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+ break;
+ case LYS_RPC:
+ case LYS_ACTION:
+ if (dev->flags & LYSC_OPT_RPC_INPUT) {
+ DEV_DEL_ARRAY(struct lysc_action*, input.musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+ break;
+ } else if (dev->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,
+ lys_nodetype2str(target->nodetype), "delete", "must");
+ goto cleanup;
+ }
+ }
+
+ /* *unique-stmt */
+ if (d_del->uniques) {
+ DEV_CHECK_NODETYPE(LYS_LIST, "delete", "unique");
+ list = (struct lysc_node_list*)target; /* shortcut */
+ LY_ARRAY_FOR(d_del->uniques, x) {
+ LY_ARRAY_FOR(list->uniques, z) {
+ for (name = d_del->uniques[x], y = 0; name; name = nodeid, ++y) {
+ nodeid = strpbrk(name, " \t\n");
+ if (nodeid) {
+ if (ly_strncmp(list->uniques[z][y]->name, name, nodeid - name)) {
+ break;
+ }
+ while (isspace(*nodeid)) {
+ ++nodeid;
+ }
+ } else {
+ if (strcmp(name, list->uniques[z][y]->name)) {
+ break;
+ }
+ }
+ }
+ if (!name) {
+ /* complete match - remove the unique */
+ LY_ARRAY_DECREMENT(list->uniques);
+ LY_ARRAY_FREE(list->uniques[z]);
+ memmove(&list->uniques[z], &list->uniques[z + 1], (LY_ARRAY_COUNT(list->uniques) - z) * (sizeof *list->uniques));
+ --z;
+ break;
+ }
+ }
+ if (!list->uniques || z == LY_ARRAY_COUNT(list->uniques)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation deleting \"unique\" property \"%s\" which does not match any of the target's property values.",
+ d_del->uniques[x]);
+ goto cleanup;
+ }
+ }
+ if (!LY_ARRAY_COUNT(list->uniques)) {
+ LY_ARRAY_FREE(list->uniques);
+ list->uniques = NULL;
+ }
+ }
+
+ /* *default-stmt */
+ if (d_del->dflts) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_CARDINALITY(d_del->dflts, 1, "default");
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf*, !(target->flags & LYS_SET_DFLT),
+ dflt, "deleting", "default", d_del->dflts[0]);
+
+ /* check that the values matches */
+ dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LYD_XML, lys_get_prefix, leaf->dflt_mod, &i);
+ if (strcmp(dflt, d_del->dflts[0])) {
+ if (i) {
+ free((char*)dflt);
+ }
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation deleting \"default\" property \"%s\" which does not match the target's property value \"%s\".",
+ d_del->dflts[0], dflt);
+ goto cleanup;
+ }
+ if (i) {
+ free((char*)dflt);
+ }
+ dflt = NULL;
+
+ /* update the list of incomplete default values if needed */
+ lysc_incomplete_dflts_remove(ctx, leaf->dflt);
+
+ /* remove the default specification */
+ leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+ lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+ free(leaf->dflt);
+ leaf->dflt = NULL;
+ leaf->dflt_mod = NULL;
+ target->flags &= ~LYS_SET_DFLT;
+ break;
+ case LYS_LEAFLIST:
+ DEV_CHECK_PRESENCE(struct lysc_node_leaflist*, 0, dflts, "deleting", "default", d_del->dflts[0]);
+ LY_ARRAY_FOR(d_del->dflts, x) {
+ LY_ARRAY_FOR(llist->dflts, y) {
+ dflt = llist->type->plugin->print(llist->dflts[y], LYD_XML, lys_get_prefix, llist->dflts_mods[y], &i);
+ if (!strcmp(dflt, d_del->dflts[x])) {
+ if (i) {
+ free((char*)dflt);
+ }
+ dflt = NULL;
+ break;
+ }
+ if (i) {
+ free((char*)dflt);
+ }
+ dflt = NULL;
+ }
+ if (y == LY_ARRAY_COUNT(llist->dflts)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid deviation deleting \"default\" property \"%s\" "
+ "which does not match any of the target's property values.", d_del->dflts[x]);
+ goto cleanup;
+ }
+
+ /* update the list of incomplete default values if needed */
+ lysc_incomplete_dflts_remove(ctx, llist->dflts[y]);
+
+ LY_ARRAY_DECREMENT(llist->dflts_mods);
+ LY_ARRAY_DECREMENT(llist->dflts);
+ llist->dflts[y]->realtype->plugin->free(ctx->ctx, llist->dflts[y]);
+ lysc_type_free(ctx->ctx, llist->dflts[y]->realtype);
+ free(llist->dflts[y]);
+ memmove(&llist->dflts[y], &llist->dflts[y + 1], (LY_ARRAY_COUNT(llist->dflts) - y) * (sizeof *llist->dflts));
+ memmove(&llist->dflts_mods[y], &llist->dflts_mods[y + 1], (LY_ARRAY_COUNT(llist->dflts_mods) - y) * (sizeof *llist->dflts_mods));
+ }
+ if (!LY_ARRAY_COUNT(llist->dflts)) {
+ LY_ARRAY_FREE(llist->dflts_mods);
+ llist->dflts_mods = NULL;
+ LY_ARRAY_FREE(llist->dflts);
+ llist->dflts = NULL;
+ llist->flags &= ~LYS_SET_DFLT;
+ }
+ 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(ly_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 deleting \"default\" property \"%s\" of choice. "
+ "The prefix does not match any imported module of the deviation module.", d_del->dflts[0]);
+ goto cleanup;
+ }
+ if (mod != ((struct lysc_node_choice*)target)->dflt->module) {
+ LOGVAL(ctx->ctx,LY_VLOG_STR,ctx->path,LYVE_REFERENCE,
+ "Invalid deviation deleting \"default\" property \"%s\" of choice. "
+ "The prefix does not match the default case's module.", 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*)target)->dflt->name)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+ "Invalid deviation deleting \"default\" property \"%s\" of choice does not match the default case name \"%s\".",
+ d_del->dflts[0], ((struct lysc_node_choice*)target)->dflt->name);
+ goto cleanup;
+ }
+ ((struct lysc_node_choice*)target)->dflt->flags &= ~LYS_SET_DFLT;
+ ((struct lysc_node_choice*)target)->dflt = NULL;
+ break;
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "delete", "default");
+ goto cleanup;
+ }
+ }
+
+ break;
+ case LYS_DEV_REPLACE:
+ d_rpl = (struct lysp_deviate_rpl*)d;
+
+ /* [type-stmt] */
+ if (d_rpl->type) {
+ DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "replace", "type");
+ /* type is mandatory, so checking for its presence is not necessary */
+ lysc_type_free(ctx->ctx, ((struct lysc_node_leaf*)target)->type);
+
+ if (leaf->dflt && !(target->flags & LYS_SET_DFLT)) {
+ /* the target has default from the previous type - remove it */
+ if (target->nodetype == LYS_LEAF) {
+ /* update the list of incomplete default values if needed */
+ lysc_incomplete_dflts_remove(ctx, leaf->dflt);
+
+ leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+ lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+ free(leaf->dflt);
+ leaf->dflt = NULL;
+ leaf->dflt_mod = NULL;
+ } else { /* LYS_LEAFLIST */
+ LY_ARRAY_FOR(llist->dflts, x) {
+ lysc_incomplete_dflts_remove(ctx, llist->dflts[x]);
+ llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
+ lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
+ free(llist->dflts[x]);
+ }
+ LY_ARRAY_FREE(llist->dflts);
+ llist->dflts = NULL;
+ LY_ARRAY_FREE(llist->dflts_mods);
+ llist->dflts_mods = NULL;
+ }
+ }
+ if (!leaf->dflt) {
+ /* there is no default value, do not set changed_type after type compilation
+ * which is used to recompile the default value */
+ changed_type = -1;
+ }
+ LY_CHECK_GOTO(lys_compile_node_type(ctx, NULL, d_rpl->type, (struct lysc_node_leaf*)target), cleanup);
+ changed_type++;
+ }
+
+ /* [units-stmt] */
+ if (d_rpl->units) {
+ DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "replace", "units");
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf*, !(target->flags & LYS_SET_UNITS),
+ units, "replacing", "units", d_rpl->units);
+
+ lydict_remove(ctx->ctx, ((struct lysc_node_leaf*)target)->units);
+ DUP_STRING(ctx->ctx, d_rpl->units, ((struct lysc_node_leaf*)target)->units);
+ }
+
+ /* [default-stmt] */
+ if (d_rpl->dflt) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf*, !(target->flags & LYS_SET_DFLT),
+ dflt, "replacing", "default", d_rpl->dflt);
+ /* first, remove the default value taken from the type */
+ lysc_incomplete_dflts_remove(ctx, leaf->dflt);
+ leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+ lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+ dflt = d_rpl->dflt;
+ /* parsing is done at the end after possible replace of the leaf's type */
+ 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, d_rpl->dflt, (struct lysc_node_choice*)target)) {
+ goto cleanup;
+ }
+ break;
+ default:
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "replace", "default");
+ goto cleanup;
+ }
+ }
+
+ /* [config-stmt] */
+ if (d_rpl->flags & LYS_CONFIG_MASK) {
+ if (target->nodetype & (LYS_CASE | LYS_INOUT | LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "replace", "config");
+ goto cleanup;
+ }
+ if (!(target->flags & LYS_SET_CONFIG)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
+ "replacing", "config", d_rpl->flags & LYS_CONFIG_W ? "config true" : "config false");
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(lys_compile_change_config(ctx, target, d_rpl->flags, 0, 0), cleanup);
+ }
+
+ /* [mandatory-stmt] */
+ if (d_rpl->flags & LYS_MAND_MASK) {
+ if (!(target->flags & LYS_MAND_MASK)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
+ "replacing", "mandatory", d_rpl->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, target, d_rpl->flags, 0), cleanup);
+ }
+
+ /* [min-elements-stmt] */
+ if (d_rpl->flags & LYS_SET_MIN) {
+ if (target->nodetype == LYS_LEAFLIST) {
+ DEV_CHECK_PRESENCE_UINT(struct lysc_node_leaflist*, > 0, min, "min-elements");
+ /* change value */
+ ((struct lysc_node_leaflist*)target)->min = d_rpl->min;
+ } else if (target->nodetype == LYS_LIST) {
+ DEV_CHECK_PRESENCE_UINT(struct lysc_node_list*, > 0, min, "min-elements");
+ /* change value */
+ ((struct lysc_node_list*)target)->min = d_rpl->min;
+ } else {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "replace", "min-elements");
+ goto cleanup;
+ }
+ if (d_rpl->min) {
+ target->flags |= LYS_MAND_TRUE;
+ }
+ }
+
+ /* [max-elements-stmt] */
+ if (d_rpl->flags & LYS_SET_MAX) {
+ if (target->nodetype == LYS_LEAFLIST) {
+ DEV_CHECK_PRESENCE_UINT(struct lysc_node_leaflist*, < (uint32_t)-1, max, "max-elements");
+ /* change value */
+ ((struct lysc_node_leaflist*)target)->max = d_rpl->max ? d_rpl->max : (uint32_t)-1;
+ } else if (target->nodetype == LYS_LIST) {
+ DEV_CHECK_PRESENCE_UINT(struct lysc_node_list*, < (uint32_t)-1, max, "max-elements");
+ /* change value */
+ ((struct lysc_node_list*)target)->max = d_rpl->max ? d_rpl->max : (uint32_t)-1;
+ } else {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
+ lys_nodetype2str(target->nodetype), "replace", "max-elements");
+ goto cleanup;
+ }
+ }
+
+ break;
+ default:
+ LOGINT(ctx->ctx);
+ goto cleanup;
+ }
+ }
+
+ /* final check when all deviations of a single target node are applied */
+
+ /* check min-max compatibility */
+ if (target->nodetype == LYS_LEAFLIST) {
+ min = ((struct lysc_node_leaflist*)target)->min;
+ max = ((struct lysc_node_leaflist*)target)->max;
+ } else if (target->nodetype == LYS_LIST) {
+ min = ((struct lysc_node_list*)target)->min;
+ max = ((struct lysc_node_list*)target)->max;
+ } else {
+ min = max = 0;
+ }
+ if (min > max) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements "
+ "after deviation: min value %u is bigger than max value %u.", min, max);
+ goto cleanup;
+ }
+
+ if (dflt) {
+ /* parse added/changed default value after possible change of the type */
+ leaf->dflt_mod = ctx->mod_def;
+ leaf->dflt->realtype = leaf->type;
+ rc = leaf->type->plugin->store(ctx->ctx, leaf->type, dflt, strlen(dflt),
+ LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
+ lys_resolve_prefix, (void*)leaf->dflt_mod, LYD_XML, target, NULL, leaf->dflt, NULL, &err);
+ leaf->dflt->realtype->refcount++;
+ if (err) {
+ ly_err_print(err);
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid deviation setting \"default\" property \"%s\" which does not fit the type (%s).", dflt, err->msg);
+ ly_err_free(err);
+ }
+ if (rc == LY_EINCOMPLETE) {
+ /* postpone default compilation when the tree is complete */
+ LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, target, leaf->dflt, leaf->dflt_mod), cleanup);
+
+ /* but in general result is so far ok */
+ rc = LY_SUCCESS;
+ }
+ LY_CHECK_GOTO(rc, cleanup);
+ } else if (changed_type) {
+ /* the leaf/leaf-list's type has changed, but there is still a default value for the previous type */
+ int dynamic;
+ if (target->nodetype == LYS_LEAF) {
+ dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LYD_XML, lys_get_prefix, leaf->dflt_mod, &dynamic);
+
+ /* update the list of incomplete default values if needed */
+ lysc_incomplete_dflts_remove(ctx, leaf->dflt);
+
+ /* remove the previous default */
+ leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
+ lysc_type_free(ctx->ctx, leaf->dflt->realtype);
+ leaf->dflt->realtype = leaf->type;
+ rc = leaf->type->plugin->store(ctx->ctx, leaf->type, dflt, strlen(dflt),
+ LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
+ lys_resolve_prefix, (void*)leaf->dflt_mod, LYD_XML, target, NULL, leaf->dflt, NULL, &err);
+ leaf->dflt->realtype->refcount++;
+ if (err) {
+ ly_err_print(err);
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid deviation replacing leaf's type - the leaf's default value \"%s\" does not match the type (%s).", dflt, err->msg);
+ ly_err_free(err);
+ }
+ if (dynamic) {
+ free((void*)dflt);
+ }
+ dflt = NULL;
+ if (rc == LY_EINCOMPLETE) {
+ /* postpone default compilation when the tree is complete */
+ LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, target, leaf->dflt, leaf->dflt_mod), cleanup);
+
+ /* but in general result is so far ok */
+ rc = LY_SUCCESS;
+ }
+ LY_CHECK_GOTO(rc, cleanup);
+ } else { /* LYS_LEAFLIST */
+ LY_ARRAY_FOR(llist->dflts, x) {
+ dflt = llist->dflts[x]->realtype->plugin->print(llist->dflts[x], LYD_XML, lys_get_prefix, llist->dflts_mods[x], &dynamic);
+ llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
+ lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
+ llist->dflts[x]->realtype = llist->type;
+ rc = llist->type->plugin->store(ctx->ctx, llist->type, dflt, strlen(dflt),
+ LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
+ lys_resolve_prefix, (void*)llist->dflts_mods[x], LYD_XML, target, NULL,
+ llist->dflts[x], NULL, &err);
+ llist->dflts[x]->realtype->refcount++;
+ if (err) {
+ ly_err_print(err);
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid deviation replacing leaf-list's type - the leaf-list's default value \"%s\" does not match the type (%s).",
+ dflt, err->msg);
+ ly_err_free(err);
+ }
+ if (dynamic) {
+ free((void*)dflt);
+ }
+ dflt = NULL;
+ if (rc == LY_EINCOMPLETE) {
+ /* postpone default compilation when the tree is complete */
+ LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, target, llist->dflts[x], llist->dflts_mods[x]), cleanup);
+
+ /* but in general result is so far ok */
+ rc = LY_SUCCESS;
+ }
+ LY_CHECK_GOTO(rc, cleanup);
+ }
+ }
+ }
+
+ /* check mandatory - default compatibility */
+ if ((target->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (target->flags & LYS_SET_DFLT)
+ && (target->flags & LYS_MAND_TRUE)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid deviation combining default value and mandatory %s.", lys_nodetype2str(target->nodetype));
+ goto cleanup;
+ } else if ((target->nodetype & LYS_CHOICE) && ((struct lysc_node_choice*)target)->dflt
+ && (target->flags & LYS_MAND_TRUE)) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid deviation combining default case and mandatory choice.");
+ goto cleanup;
+ }
+ if (target->parent && (target->parent->flags & LYS_SET_DFLT) && (target->flags & LYS_MAND_TRUE)) {
+ /* mandatory node under a default case */
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Invalid deviation combining mandatory %s \"%s\" in a default choice's case \"%s\".",
+ lys_nodetype2str(target->nodetype), target->name, target->parent->name);
+ goto cleanup;
+ }
+
+ /* success */
+ ret = LY_SUCCESS;
+
+cleanup:
+ lysc_update_path(ctx, NULL, NULL);
+ return ret;
+}
+
+LY_ERR
+lys_compile_deviations(struct lysc_ctx *ctx, struct lysp_module *mod_p)
+{
+ 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;
+ LY_ARRAY_COUNT_TYPE u, v;
+ struct lysc_deviation **devs = NULL;
+ struct lys_module *target_mod, **dev_mod;
uint16_t flags;
+ int i;
/* get all deviations from the module and all its submodules ... */
LY_ARRAY_FOR(mod_p->deviations, u) {
@@ -5690,871 +6551,35 @@
lysc_update_path(ctx, NULL, NULL);
}
- /* 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, lys_nodetype2str(devs[u]->target->nodetype), DEVTYPE, PROPERTY);\
- goto cleanup; \
- }
-
-#define DEV_CHECK_CARDINALITY(ARRAY, MAX, PROPERTY) \
- if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid deviation of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
- lys_nodetype2str(devs[u]->target->nodetype), LY_ARRAY_COUNT(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 adding \"%s\" property which already exists (with value \"%s\").", \
- PROPERTY, ((TYPE)devs[u]->target)->VALUEMEMBER); \
- goto cleanup; \
- }
-
-#define DEV_CHECK_NONPRESENCE_VALUE(TYPE, COND, MEMBER, PROPERTY, VALUEMEMBER, VALUEMODMEMBER) \
- if (((TYPE)devs[u]->target)->MEMBER && (COND)) { \
- int dynamic_ = 0; const char *val_; \
- val_ = ((TYPE)devs[u]->target)->VALUEMEMBER->realtype->plugin->print(((TYPE)devs[u]->target)->VALUEMEMBER, LYD_XML, \
- lys_get_prefix, ((TYPE)devs[u]->target)->VALUEMODMEMBER, &dynamic_); \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", PROPERTY, val_); \
- if (dynamic_) {free((void*)val_);} \
- goto cleanup; \
- }
-
-#define DEV_CHECK_NONPRESENCE_UINT(TYPE, COND, MEMBER, PROPERTY) \
- if (((TYPE)devs[u]->target)->MEMBER COND) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation adding \"%s\" property which already exists (with value \"%u\").", \
- PROPERTY, ((TYPE)devs[u]->target)->MEMBER); \
- 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, DEVTYPE, PROPERTY, VALUE); \
- goto cleanup; \
- }
-
-#define DEV_CHECK_PRESENCE_UINT(TYPE, COND, MEMBER, PROPERTY) \
- if (!(((TYPE)devs[u]->target)->MEMBER COND)) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation replacing with \"%s\" property \"%u\" which is not present.", PROPERTY, d_rpl->MEMBER); \
- goto cleanup; \
- }
-
-#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_COUNT(((TYPE)devs[u]->target)->ARRAY_TRG)) { \
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
- "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
- PROPERTY, d_del->ARRAY_DEV[x]VALMEMBER); \
- goto cleanup; \
- } \
- 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_COUNT(((TYPE)devs[u]->target)->ARRAY_TRG) - y) * (sizeof *((TYPE)devs[u]->target)->ARRAY_TRG)); \
- } \
- if (!LY_ARRAY_COUNT(((TYPE)devs[u]->target)->ARRAY_TRG)) { \
- LY_ARRAY_FREE(((TYPE)devs[u]->target)->ARRAY_TRG); \
- ((TYPE)devs[u]->target)->ARRAY_TRG = NULL; \
- }
-
/* apply deviations */
for (u = 0; u < devs_p.count && devs[u]; ++u) {
- struct lysc_node_leaf *leaf = (struct lysc_node_leaf*)devs[u]->target;
- struct lysc_node_leaflist *llist = (struct lysc_node_leaflist*)devs[u]->target;
- struct ly_err_item *err = NULL;
-
- dflt = NULL;
- changed_type = 0;
-
- lysc_update_path(ctx, NULL, devs[u]->nodeid);
-
if (devs[u]->flags & LYSC_OPT_INTERNAL) {
/* fix the target pointer in case of RPC's/action's input/output */
if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
- devs[u]->target = (struct lysc_node*)((char*)devs[u]->target - offsetof(struct lysc_action, input));
+ devs[u]->target = (struct lysc_node *)((char *)devs[u]->target - offsetof(struct lysc_action, input));
} else if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
- devs[u]->target = (struct lysc_node*)((char*)devs[u]->target - offsetof(struct lysc_action, output));
+ devs[u]->target = (struct lysc_node *)((char *)devs[u]->target - offsetof(struct lysc_action, output));
}
}
- /* not-supported */
- if (devs[u]->not_supported) {
- if (LY_ARRAY_COUNT(devs[u]->deviates) > 1) {
- LOGWRN(ctx->ctx, "Useless multiple (%"LY_PRI_ARRAY_COUNT_TYPE") deviates on node \"%s\" since the node is not-supported.",
- LY_ARRAY_COUNT(devs[u]->deviates), devs[u]->nodeid);
- }
+ /* remember target module (the target node may be removed) */
+ target_mod = devs[u]->target->module;
-#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_COUNT(ARRAY)) { \
- FREEFUNC(ctx->ctx, &ARRAY[x]); \
- memmove(&ARRAY[x], &ARRAY[x + 1], (LY_ARRAY_COUNT(ARRAY) - (x + 1)) * sizeof *ARRAY); \
- LY_ARRAY_DECREMENT(ARRAY); \
- }
-
- if (devs[u]->target->nodetype & (LYS_RPC | 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 */
- REMOVE_NONDATA(rpcs, struct lysc_action, lysc_node_actions, lysc_action_free);
- }
- } else if (devs[u]->target->nodetype == LYS_NOTIF) {
- /* remove Notification */
- REMOVE_NONDATA(notifs, struct lysc_notif, lysc_node_notifs, lysc_notif_free);
- } else {
- /* remove the target node */
- lysc_disconnect(devs[u]->target);
- lysc_node_free(ctx->ctx, devs[u]->target);
- }
-
- /* mark the context for later re-compilation of objects that could reference the curently removed node */
- ctx->ctx->flags |= LY_CTX_CHANGED_TREE;
- 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,
- 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,
- x, lys_compile_must, ret, cleanup);
- break;
- case LYS_NOTIF:
- COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_notif*)devs[u]->target)->musts,
- x, lys_compile_must, ret, cleanup);
- break;
- case LYS_RPC:
- 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,
- 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,
- x, lys_compile_must, ret, cleanup);
- break;
- }
- /* fall through */
- default:
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(devs[u]->target->nodetype), "add", "must");
- goto cleanup;
- }
- ly_set_add(&ctx->xpath, devs[u]->target, 0);
- }
-
- /* *unique-stmt */
- if (d_add->uniques) {
- DEV_CHECK_NODETYPE(LYS_LIST, "add", "unique");
- LY_CHECK_GOTO(lys_compile_node_list_unique(ctx, ctx->mod, d_add->uniques, (struct lysc_node_list*)devs[u]->target), cleanup);
- }
-
- /* *default-stmt */
- if (d_add->dflts) {
- switch (devs[u]->target->nodetype) {
- case LYS_LEAF:
- DEV_CHECK_CARDINALITY(d_add->dflts, 1, "default");
- DEV_CHECK_NONPRESENCE_VALUE(struct lysc_node_leaf*, (devs[u]->target->flags & LYS_SET_DFLT), dflt, "default", dflt, dflt_mod);
- if (leaf->dflt) {
- /* first, remove the default value taken from the type */
- lysc_incomplete_dflts_remove(ctx, leaf->dflt);
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- } else {
- /* prepare new default value storage */
- leaf->dflt = calloc(1, sizeof *leaf->dflt);
- }
- dflt = d_add->dflts[0];
- /* parsing is done at the end after possible replace of the leaf's type */
-
- /* mark the new default values as leaf's own */
- devs[u]->target->flags |= LYS_SET_DFLT;
- break;
- case LYS_LEAFLIST:
- if (llist->dflts && !(devs[u]->target->flags & LYS_SET_DFLT)) {
- /* first, remove the default value taken from the type */
- LY_ARRAY_FOR(llist->dflts, x) {
- lysc_incomplete_dflts_remove(ctx, llist->dflts[x]);
- llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
- lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
- free(llist->dflts[x]);
- }
- LY_ARRAY_FREE(llist->dflts);
- llist->dflts = NULL;
- LY_ARRAY_FREE(llist->dflts_mods);
- llist->dflts_mods = NULL;
- }
- /* add new default value(s) */
- LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts_mods, LY_ARRAY_COUNT(d_add->dflts), ret, cleanup);
- LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts, LY_ARRAY_COUNT(d_add->dflts), ret, cleanup);
- for (x = y = LY_ARRAY_COUNT(llist->dflts);
- x < LY_ARRAY_COUNT(d_add->dflts) + y; ++x) {
- LY_ARRAY_INCREMENT(llist->dflts_mods);
- llist->dflts_mods[x] = ctx->mod_def;
- LY_ARRAY_INCREMENT(llist->dflts);
- llist->dflts[x] = calloc(1, sizeof *llist->dflts[x]);
- llist->dflts[x]->realtype = llist->type;
- rc = llist->type->plugin->store(ctx->ctx, llist->type, d_add->dflts[x - y], strlen(d_add->dflts[x - y]),
- LY_TYPE_OPTS_INCOMPLETE_DATA |LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE, lys_resolve_prefix,
- (void*)llist->dflts_mods[x], LYD_XML, devs[u]->target, NULL, llist->dflts[x], NULL, &err);
- llist->dflts[x]->realtype->refcount++;
- if (err) {
- ly_err_print(err);
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation adding \"default\" property \"%s\" which does not fit the type (%s).",
- d_add->dflts[x - y], err->msg);
- ly_err_free(err);
- }
- if (rc == LY_EINCOMPLETE) {
- /* postpone default compilation when the tree is complete */
- LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, devs[u]->target, llist->dflts[x], llist->dflts_mods[x]), cleanup);
-
- /* but in general result is so far ok */
- rc = LY_SUCCESS;
- }
- LY_CHECK_GOTO(rc, cleanup);
- }
- /* mark the new default values as leaf-list'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, 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,
- lys_nodetype2str(devs[u]->target->nodetype), "add", "default");
- goto cleanup;
- }
- }
-
- /* [config-stmt] */
- if (d_add->flags & LYS_CONFIG_MASK) {
- if (devs[u]->target->nodetype & (LYS_CASE | LYS_INOUT | LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(devs[u]->target->nodetype), "add", "config");
- goto cleanup;
- }
- if (devs[u]->flags) {
- LOGWRN(ctx->ctx, "Deviating config inside %s has no effect.",
- devs[u]->flags & LYSC_OPT_NOTIFICATION ? "notification" : "RPC/action");
- }
- if (devs[u]->target->flags & LYS_SET_CONFIG) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
- devs[u]->target->flags & LYS_CONFIG_W ? "true" : "false");
- goto cleanup;
- }
- LY_CHECK_GOTO(lys_compile_change_config(ctx, devs[u]->target, d_add->flags, 0, 0), cleanup);
- }
-
- /* [mandatory-stmt] */
- if (d_add->flags & LYS_MAND_MASK) {
- if (devs[u]->target->flags & LYS_MAND_MASK) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
- devs[u]->target->flags & LYS_MAND_TRUE ? "true" : "false");
- goto cleanup;
- }
- LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, devs[u]->target, d_add->flags, 0), cleanup);
- }
-
- /* [min-elements-stmt] */
- if (d_add->flags & LYS_SET_MIN) {
- if (devs[u]->target->nodetype == LYS_LEAFLIST) {
- DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_leaflist*, > 0, min, "min-elements");
- /* change value */
- ((struct lysc_node_leaflist*)devs[u]->target)->min = d_add->min;
- } else if (devs[u]->target->nodetype == LYS_LIST) {
- DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_list*, > 0, min, "min-elements");
- /* change value */
- ((struct lysc_node_list*)devs[u]->target)->min = d_add->min;
- } else {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(devs[u]->target->nodetype), "add", "min-elements");
- goto cleanup;
- }
- if (d_add->min) {
- devs[u]->target->flags |= LYS_MAND_TRUE;
- }
- }
-
- /* [max-elements-stmt] */
- if (d_add->flags & LYS_SET_MAX) {
- if (devs[u]->target->nodetype == LYS_LEAFLIST) {
- DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_leaflist*, < (uint32_t)-1, max, "max-elements");
- /* change value */
- ((struct lysc_node_leaflist*)devs[u]->target)->max = d_add->max ? d_add->max : (uint32_t)-1;
- } else if (devs[u]->target->nodetype == LYS_LIST) {
- DEV_CHECK_NONPRESENCE_UINT(struct lysc_node_list*, < (uint32_t)-1, max, "max-elements");
- /* change value */
- ((struct lysc_node_list*)devs[u]->target)->max = d_add->max ? d_add->max : (uint32_t)-1;
- } else {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(devs[u]->target->nodetype), "add", "max-elements");
- goto cleanup;
- }
- }
-
- 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_CHECK_PRESENCE(struct lysc_node_leaf*, 0, units, "deleting", "units", d_del->units);
- if (strcmp(((struct lysc_node_leaf*)devs[u]->target)->units, d_del->units)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"units\" property \"%s\" which does not match the target's property value \"%s\".",
- d_del->units, ((struct lysc_node_leaf*)devs[u]->target)->units);
- goto cleanup;
- }
- lydict_remove(ctx->ctx, ((struct lysc_node_leaf*)devs[u]->target)->units);
- ((struct lysc_node_leaf*)devs[u]->target)->units = NULL;
- }
-
- /* *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, 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, musts, .arg, .cond->expr, &, lysc_must_free, "must");
- break;
- case LYS_NOTIF:
- DEV_DEL_ARRAY(struct lysc_notif*, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
- break;
- case LYS_RPC:
- 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,
- lys_nodetype2str(devs[u]->target->nodetype), "delete", "must");
- goto cleanup;
- }
- }
-
- /* *unique-stmt */
- if (d_del->uniques) {
- DEV_CHECK_NODETYPE(LYS_LIST, "delete", "unique");
- list = (struct lysc_node_list*)devs[u]->target; /* shortcut */
- LY_ARRAY_FOR(d_del->uniques, x) {
- LY_ARRAY_FOR(list->uniques, z) {
- for (name = d_del->uniques[x], y = 0; name; name = nodeid, ++y) {
- nodeid = strpbrk(name, " \t\n");
- if (nodeid) {
- if (ly_strncmp(list->uniques[z][y]->name, name, nodeid - name)) {
- break;
- }
- while (isspace(*nodeid)) {
- ++nodeid;
- }
- } else {
- if (strcmp(name, list->uniques[z][y]->name)) {
- break;
- }
- }
- }
- if (!name) {
- /* complete match - remove the unique */
- LY_ARRAY_DECREMENT(list->uniques);
- LY_ARRAY_FREE(list->uniques[z]);
- memmove(&list->uniques[z], &list->uniques[z + 1], (LY_ARRAY_COUNT(list->uniques) - z) * (sizeof *list->uniques));
- --z;
- break;
- }
- }
- if (!list->uniques || z == LY_ARRAY_COUNT(list->uniques)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"unique\" property \"%s\" which does not match any of the target's property values.",
- d_del->uniques[x]);
- goto cleanup;
- }
- }
- if (!LY_ARRAY_COUNT(list->uniques)) {
- LY_ARRAY_FREE(list->uniques);
- list->uniques = NULL;
- }
- }
-
- /* *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]);
-
- /* check that the values matches */
- dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LYD_XML, lys_get_prefix, leaf->dflt_mod, &i);
- if (strcmp(dflt, d_del->dflts[0])) {
- if (i) {
- free((char*)dflt);
- }
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
- "Invalid deviation deleting \"default\" property \"%s\" which does not match the target's property value \"%s\".",
- d_del->dflts[0], dflt);
- goto cleanup;
- }
- if (i) {
- free((char*)dflt);
- }
- dflt = NULL;
-
- /* update the list of incomplete default values if needed */
- lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-
- /* remove the default specification */
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- free(leaf->dflt);
- leaf->dflt = NULL;
- leaf->dflt_mod = NULL;
- devs[u]->target->flags &= ~LYS_SET_DFLT;
- break;
- case LYS_LEAFLIST:
- DEV_CHECK_PRESENCE(struct lysc_node_leaflist*, 0, dflts, "deleting", "default", d_del->dflts[0]);
- LY_ARRAY_FOR(d_del->dflts, x) {
- LY_ARRAY_FOR(llist->dflts, y) {
- dflt = llist->type->plugin->print(llist->dflts[y], LYD_XML, lys_get_prefix, llist->dflts_mods[y], &i);
- if (!strcmp(dflt, d_del->dflts[x])) {
- if (i) {
- free((char*)dflt);
- }
- dflt = NULL;
- break;
- }
- if (i) {
- free((char*)dflt);
- }
- dflt = NULL;
- }
- if (y == LY_ARRAY_COUNT(llist->dflts)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid deviation deleting \"default\" property \"%s\" "
- "which does not match any of the target's property values.", d_del->dflts[x]);
- goto cleanup;
- }
-
- /* update the list of incomplete default values if needed */
- lysc_incomplete_dflts_remove(ctx, llist->dflts[y]);
-
- LY_ARRAY_DECREMENT(llist->dflts_mods);
- LY_ARRAY_DECREMENT(llist->dflts);
- llist->dflts[y]->realtype->plugin->free(ctx->ctx, llist->dflts[y]);
- lysc_type_free(ctx->ctx, llist->dflts[y]->realtype);
- free(llist->dflts[y]);
- memmove(&llist->dflts[y], &llist->dflts[y + 1], (LY_ARRAY_COUNT(llist->dflts) - y) * (sizeof *llist->dflts));
- memmove(&llist->dflts_mods[y], &llist->dflts_mods[y + 1], (LY_ARRAY_COUNT(llist->dflts_mods) - y) * (sizeof *llist->dflts_mods));
- }
- if (!LY_ARRAY_COUNT(llist->dflts)) {
- LY_ARRAY_FREE(llist->dflts_mods);
- llist->dflts_mods = NULL;
- LY_ARRAY_FREE(llist->dflts);
- llist->dflts = NULL;
- llist->flags &= ~LYS_SET_DFLT;
- }
- 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(ly_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 deleting \"default\" property \"%s\" of choice. "
- "The prefix does not match any imported module of the deviation module.", 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 deleting \"default\" property \"%s\" of choice. "
- "The prefix does not match the default case's module.", 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 deleting \"default\" property \"%s\" of choice does not match the default case name \"%s\".",
- 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,
- lys_nodetype2str(devs[u]->target->nodetype), "delete", "default");
- goto cleanup;
- }
- }
-
- break;
- case LYS_DEV_REPLACE:
- d_rpl = (struct lysp_deviate_rpl*)d;
-
- /* [type-stmt] */
- if (d_rpl->type) {
- DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "replace", "type");
- /* type is mandatory, so checking for its presence is not necessary */
- lysc_type_free(ctx->ctx, ((struct lysc_node_leaf*)devs[u]->target)->type);
-
- if (leaf->dflt && !(devs[u]->target->flags & LYS_SET_DFLT)) {
- /* the target has default from the previous type - remove it */
- if (devs[u]->target->nodetype == LYS_LEAF) {
- /* update the list of incomplete default values if needed */
- lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- free(leaf->dflt);
- leaf->dflt = NULL;
- leaf->dflt_mod = NULL;
- } else { /* LYS_LEAFLIST */
- LY_ARRAY_FOR(llist->dflts, x) {
- lysc_incomplete_dflts_remove(ctx, llist->dflts[x]);
- llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
- lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
- free(llist->dflts[x]);
- }
- LY_ARRAY_FREE(llist->dflts);
- llist->dflts = NULL;
- LY_ARRAY_FREE(llist->dflts_mods);
- llist->dflts_mods = NULL;
- }
- }
- if (!leaf->dflt) {
- /* there is no default value, do not set changed_type after type compilation
- * which is used to recompile the default value */
- changed_type = -1;
- }
- LY_CHECK_GOTO(lys_compile_node_type(ctx, NULL, d_rpl->type, (struct lysc_node_leaf*)devs[u]->target), cleanup);
- changed_type++;
- }
-
- /* [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);
- /* first, remove the default value taken from the type */
- lysc_incomplete_dflts_remove(ctx, leaf->dflt);
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- dflt = d_rpl->dflt;
- /* parsing is done at the end after possible replace of the leaf's type */
- 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, 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,
- lys_nodetype2str(devs[u]->target->nodetype), "replace", "default");
- goto cleanup;
- }
- }
-
- /* [config-stmt] */
- if (d_rpl->flags & LYS_CONFIG_MASK) {
- if (devs[u]->target->nodetype & (LYS_CASE | LYS_INOUT | LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(devs[u]->target->nodetype), "replace", "config");
- goto cleanup;
- }
- if (!(devs[u]->target->flags & LYS_SET_CONFIG)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
- "replacing", "config", d_rpl->flags & LYS_CONFIG_W ? "config true" : "config false");
- goto cleanup;
- }
- LY_CHECK_GOTO(lys_compile_change_config(ctx, devs[u]->target, d_rpl->flags, 0, 0), cleanup);
- }
-
- /* [mandatory-stmt] */
- if (d_rpl->flags & LYS_MAND_MASK) {
- if (!(devs[u]->target->flags & LYS_MAND_MASK)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
- "replacing", "mandatory", d_rpl->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
- goto cleanup;
- }
- LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, devs[u]->target, d_rpl->flags, 0), cleanup);
- }
-
- /* [min-elements-stmt] */
- if (d_rpl->flags & LYS_SET_MIN) {
- if (devs[u]->target->nodetype == LYS_LEAFLIST) {
- DEV_CHECK_PRESENCE_UINT(struct lysc_node_leaflist*, > 0, min, "min-elements");
- /* change value */
- ((struct lysc_node_leaflist*)devs[u]->target)->min = d_rpl->min;
- } else if (devs[u]->target->nodetype == LYS_LIST) {
- DEV_CHECK_PRESENCE_UINT(struct lysc_node_list*, > 0, min, "min-elements");
- /* change value */
- ((struct lysc_node_list*)devs[u]->target)->min = d_rpl->min;
- } else {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(devs[u]->target->nodetype), "replace", "min-elements");
- goto cleanup;
- }
- if (d_rpl->min) {
- devs[u]->target->flags |= LYS_MAND_TRUE;
- }
- }
-
- /* [max-elements-stmt] */
- if (d_rpl->flags & LYS_SET_MAX) {
- if (devs[u]->target->nodetype == LYS_LEAFLIST) {
- DEV_CHECK_PRESENCE_UINT(struct lysc_node_leaflist*, < (uint32_t)-1, max, "max-elements");
- /* change value */
- ((struct lysc_node_leaflist*)devs[u]->target)->max = d_rpl->max ? d_rpl->max : (uint32_t)-1;
- } else if (devs[u]->target->nodetype == LYS_LIST) {
- DEV_CHECK_PRESENCE_UINT(struct lysc_node_list*, < (uint32_t)-1, max, "max-elements");
- /* change value */
- ((struct lysc_node_list*)devs[u]->target)->max = d_rpl->max ? d_rpl->max : (uint32_t)-1;
- } else {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
- lys_nodetype2str(devs[u]->target->nodetype), "replace", "max-elements");
- goto cleanup;
- }
- }
-
- break;
- default:
- LOGINT(ctx->ctx);
- goto cleanup;
- }
- }
-
- /* final check when all deviations of a single target node are applied */
-
- /* check min-max compatibility */
- if (devs[u]->target->nodetype == LYS_LEAFLIST) {
- min = ((struct lysc_node_leaflist*)devs[u]->target)->min;
- max = ((struct lysc_node_leaflist*)devs[u]->target)->max;
- } else if (devs[u]->target->nodetype == LYS_LIST) {
- min = ((struct lysc_node_list*)devs[u]->target)->min;
- max = ((struct lysc_node_list*)devs[u]->target)->max;
- } else {
- min = max = 0;
- }
- if (min > max) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements "
- "after deviation: min value %u is bigger than max value %u.", min, max);
- goto cleanup;
- }
-
- if (dflt) {
- /* parse added/changed default value after possible change of the type */
- leaf->dflt_mod = ctx->mod_def;
- leaf->dflt->realtype = leaf->type;
- rc = leaf->type->plugin->store(ctx->ctx, leaf->type, dflt, strlen(dflt),
- LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
- lys_resolve_prefix, (void*)leaf->dflt_mod, LYD_XML, devs[u]->target, NULL, leaf->dflt, NULL, &err);
- leaf->dflt->realtype->refcount++;
- if (err) {
- ly_err_print(err);
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation setting \"default\" property \"%s\" which does not fit the type (%s).", dflt, err->msg);
- ly_err_free(err);
- }
- if (rc == LY_EINCOMPLETE) {
- /* postpone default compilation when the tree is complete */
- LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, devs[u]->target, leaf->dflt, leaf->dflt_mod), cleanup);
-
- /* but in general result is so far ok */
- rc = LY_SUCCESS;
- }
- LY_CHECK_GOTO(rc, cleanup);
- } else if (changed_type) {
- /* the leaf/leaf-list's type has changed, but there is still a default value for the previous type */
- int dynamic;
- if (devs[u]->target->nodetype == LYS_LEAF) {
- dflt = leaf->dflt->realtype->plugin->print(leaf->dflt, LYD_XML, lys_get_prefix, leaf->dflt_mod, &dynamic);
-
- /* update the list of incomplete default values if needed */
- lysc_incomplete_dflts_remove(ctx, leaf->dflt);
-
- /* remove the previous default */
- leaf->dflt->realtype->plugin->free(ctx->ctx, leaf->dflt);
- lysc_type_free(ctx->ctx, leaf->dflt->realtype);
- leaf->dflt->realtype = leaf->type;
- rc = leaf->type->plugin->store(ctx->ctx, leaf->type, dflt, strlen(dflt),
- LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
- lys_resolve_prefix, (void*)leaf->dflt_mod, LYD_XML, devs[u]->target, NULL, leaf->dflt, NULL, &err);
- leaf->dflt->realtype->refcount++;
- if (err) {
- ly_err_print(err);
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation replacing leaf's type - the leaf's default value \"%s\" does not match the type (%s).", dflt, err->msg);
- ly_err_free(err);
- }
- if (dynamic) {
- free((void*)dflt);
- }
- dflt = NULL;
- if (rc == LY_EINCOMPLETE) {
- /* postpone default compilation when the tree is complete */
- LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, devs[u]->target, leaf->dflt, leaf->dflt_mod), cleanup);
-
- /* but in general result is so far ok */
- rc = LY_SUCCESS;
- }
- LY_CHECK_GOTO(rc, cleanup);
- } else { /* LYS_LEAFLIST */
- LY_ARRAY_FOR(llist->dflts, x) {
- dflt = llist->dflts[x]->realtype->plugin->print(llist->dflts[x], LYD_XML, lys_get_prefix, llist->dflts_mods[x], &dynamic);
- llist->dflts[x]->realtype->plugin->free(ctx->ctx, llist->dflts[x]);
- lysc_type_free(ctx->ctx, llist->dflts[x]->realtype);
- llist->dflts[x]->realtype = llist->type;
- rc = llist->type->plugin->store(ctx->ctx, llist->type, dflt, strlen(dflt),
- LY_TYPE_OPTS_INCOMPLETE_DATA | LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE,
- lys_resolve_prefix, (void*)llist->dflts_mods[x], LYD_XML, devs[u]->target, NULL,
- llist->dflts[x], NULL, &err);
- llist->dflts[x]->realtype->refcount++;
- if (err) {
- ly_err_print(err);
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation replacing leaf-list's type - the leaf-list's default value \"%s\" does not match the type (%s).",
- dflt, err->msg);
- ly_err_free(err);
- }
- if (dynamic) {
- free((void*)dflt);
- }
- dflt = NULL;
- if (rc == LY_EINCOMPLETE) {
- /* postpone default compilation when the tree is complete */
- LY_CHECK_GOTO(lysc_incomplete_dflts_add(ctx, devs[u]->target, llist->dflts[x], llist->dflts_mods[x]), cleanup);
-
- /* but in general result is so far ok */
- rc = LY_SUCCESS;
- }
- LY_CHECK_GOTO(rc, cleanup);
- }
- }
- }
-
- /* check mandatory - default compatibility */
- if ((devs[u]->target->nodetype & (LYS_LEAF | LYS_LEAFLIST))
- && (devs[u]->target->flags & LYS_SET_DFLT)
- && (devs[u]->target->flags & LYS_MAND_TRUE)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation combining default value and mandatory %s.", lys_nodetype2str(devs[u]->target->nodetype));
- goto cleanup;
- } else if ((devs[u]->target->nodetype & LYS_CHOICE)
- && ((struct lysc_node_choice*)devs[u]->target)->dflt
- && (devs[u]->target->flags & LYS_MAND_TRUE)) {
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid deviation combining default case and mandatory choice.");
- goto cleanup;
- }
- if (devs[u]->target->parent && (devs[u]->target->parent->flags & LYS_SET_DFLT) && (devs[u]->target->flags & LYS_MAND_TRUE)) {
- /* mandatory node under a default case */
- LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
- "Invalid deviation combining mandatory %s \"%s\" in a default choice's case \"%s\".",
- lys_nodetype2str(devs[u]->target->nodetype), devs[u]->target->name, devs[u]->target->parent->name);
- goto cleanup;
- }
+ /* apply the deviation */
+ LY_CHECK_GOTO(ret = lys_apply_deviation(ctx, devs[u]), cleanup);
/* add this module into the target module deviated_by, if not there already */
- rc = LY_SUCCESS;
- LY_ARRAY_FOR(devs[u]->target->module->compiled->deviated_by, v) {
- if (devs[u]->target->module->compiled->deviated_by[v] == mod_p->mod) {
- rc = LY_EEXIST;
+ i = 0;
+ LY_ARRAY_FOR(target_mod->compiled->deviated_by, v) {
+ if (target_mod->compiled->deviated_by[v] == mod_p->mod) {
+ i = 1;
break;
}
}
- if (!rc) {
- LY_ARRAY_NEW_GOTO(ctx->ctx, devs[u]->target->module->compiled->deviated_by, dev_mod, ret, cleanup);
+ if (!i) {
+ LY_ARRAY_NEW_GOTO(ctx->ctx, target_mod->compiled->deviated_by, dev_mod, ret, cleanup);
*dev_mod = mod_p->mod;
}
-
- lysc_update_path(ctx, NULL, NULL);
}
lysc_update_path(ctx, NULL, NULL);