schema compile REFACTOR separate deviate functions
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 71b2260..d454a2a 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -5611,6 +5611,706 @@
uint8_t not_supported; /* flag if deviates contains not-supported deviate */
};
+/* 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_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; \
+ }
+
+/**
+ * @brief Apply deviate add.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] target Deviation target.
+ * @param[in] dev_flags Internal deviation flags.
+ * @param[in] d Deviate add to apply.
+ * @param[out] dflt Added default value.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysc_node *target, int dev_flags, struct lysp_deviate_add *d,
+ const char **dflt)
+{
+ LY_ERR ret = LY_EVALID, rc;
+ 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;
+ LY_ARRAY_COUNT_TYPE x, y;
+
+#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_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(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; \
+ }
+
+ /* [units-stmt] */
+ if (d->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->units, ((struct lysc_node_leaf *)target)->units);
+ }
+
+ /* *must-stmt */
+ if (d->musts) {
+ switch (target->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ COMPILE_ARRAY_GOTO(ctx, d->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->musts, ((struct lysc_node_leaf *)target)->musts,
+ x, lys_compile_must, ret, cleanup);
+ break;
+ case LYS_NOTIF:
+ COMPILE_ARRAY_GOTO(ctx, d->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->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->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->uniques) {
+ DEV_CHECK_NODETYPE(LYS_LIST, "add", "unique");
+ LY_CHECK_GOTO(lys_compile_node_list_unique(ctx, ctx->mod, d->uniques, (struct lysc_node_list *)target), cleanup);
+ }
+
+ /* *default-stmt */
+ if (d->dflts) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_CARDINALITY(d->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->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->dflts), ret, cleanup);
+ LY_ARRAY_CREATE_GOTO(ctx->ctx, llist->dflts, LY_ARRAY_COUNT(d->dflts), ret, cleanup);
+ for (x = y = LY_ARRAY_COUNT(llist->dflts);
+ x < LY_ARRAY_COUNT(d->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->dflts[x - y], strlen(d->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->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->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->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->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->flags, 0, 0), cleanup);
+ }
+
+ /* [mandatory-stmt] */
+ if (d->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->flags, 0), cleanup);
+ }
+
+ /* [min-elements-stmt] */
+ if (d->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->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->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->min) {
+ target->flags |= LYS_MAND_TRUE;
+ }
+ }
+
+ /* [max-elements-stmt] */
+ if (d->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->max ? d->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->max ? d->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;
+ }
+ }
+
+ ret = LY_SUCCESS;
+
+cleanup:
+ return ret;
+}
+
+/**
+ * @brief Apply deviate delete.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] target Deviation target.
+ * @param[in] dev_flags Internal deviation flags.
+ * @param[in] d Deviate delete to apply.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysc_node *target, int dev_flags, struct lysp_deviate_del *d)
+{
+ LY_ERR ret = LY_EVALID;
+ struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
+ struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
+ struct lysc_node_list *list = (struct lysc_node_list *)target;
+ LY_ARRAY_COUNT_TYPE x, y, z;
+ int i;
+ size_t prefix_len, name_len;
+ const char *prefix, *name, *nodeid, *dflt;
+ struct lys_module *mod;
+
+#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->ARRAY_DEV[0]VALMEMBER); \
+ LY_ARRAY_FOR(d->ARRAY_DEV, x) { \
+ LY_ARRAY_FOR(((TYPE)target)->ARRAY_TRG, y) { \
+ if (!strcmp(((TYPE)target)->ARRAY_TRG[y]VALMEMBER_CMP, d->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->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; \
+ }
+
+ /* [units-stmt] */
+ if (d->units) {
+ DEV_CHECK_NODETYPE(LYS_LEAF | LYS_LEAFLIST, "delete", "units");
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf*, 0, units, "deleting", "units", d->units);
+ if (strcmp(((struct lysc_node_leaf*)target)->units, d->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->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->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->uniques) {
+ DEV_CHECK_NODETYPE(LYS_LIST, "delete", "unique");
+ LY_ARRAY_FOR(d->uniques, x) {
+ LY_ARRAY_FOR(list->uniques, z) {
+ for (name = d->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->uniques[x]);
+ goto cleanup;
+ }
+ }
+ if (!LY_ARRAY_COUNT(list->uniques)) {
+ LY_ARRAY_FREE(list->uniques);
+ list->uniques = NULL;
+ }
+ }
+
+ /* *default-stmt */
+ if (d->dflts) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_CARDINALITY(d->dflts, 1, "default");
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf*, !(target->flags & LYS_SET_DFLT),
+ dflt, "deleting", "default", d->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->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->dflts[0], dflt);
+ goto cleanup;
+ }
+ if (i) {
+ free((char*)dflt);
+ }
+
+ /* 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->dflts[0]);
+ LY_ARRAY_FOR(d->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->dflts[x])) {
+ if (i) {
+ free((char*)dflt);
+ }
+ break;
+ }
+ if (i) {
+ free((char*)dflt);
+ }
+ }
+ 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->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->dflts, 1, "default");
+ DEV_CHECK_PRESENCE(struct lysc_node_choice*, 0, dflt, "deleting", "default", d->dflts[0]);
+ nodeid = d->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->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->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->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;
+ }
+ }
+
+ ret = LY_SUCCESS;
+
+cleanup:
+ return ret;
+}
+
+/**
+ * @brief Apply deviate replace.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] target Deviation target.
+ * @param[in] d Deviate replace to apply.
+ * @param[out] dflt Added default value.
+ * @param[out] changed_type Whether the target type was changed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysc_node *target, struct lysp_deviate_rpl *d, const char **dflt,
+ int *changed_type)
+{
+ LY_ERR ret = LY_EVALID;
+ struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)target;
+ struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)target;
+ LY_ARRAY_COUNT_TYPE x;
+
+#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->MEMBER); \
+ goto cleanup; \
+ }
+
+ /* [type-stmt] */
+ if (d->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->type, leaf), cleanup);
+ (*changed_type)++;
+ }
+
+ /* [units-stmt] */
+ if (d->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->units);
+
+ lydict_remove(ctx->ctx, leaf->units);
+ DUP_STRING(ctx->ctx, d->units, leaf->units);
+ }
+
+ /* [default-stmt] */
+ if (d->dflt) {
+ switch (target->nodetype) {
+ case LYS_LEAF:
+ DEV_CHECK_PRESENCE(struct lysc_node_leaf *, !(target->flags & LYS_SET_DFLT),
+ dflt, "replacing", "default", d->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->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->dflt);
+ if (lys_compile_deviation_set_choice_dflt(ctx, d->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->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->flags & LYS_CONFIG_W ? "config true" : "config false");
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(lys_compile_change_config(ctx, target, d->flags, 0, 0), cleanup);
+ }
+
+ /* [mandatory-stmt] */
+ if (d->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->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, target, d->flags, 0), cleanup);
+ }
+
+ /* [min-elements-stmt] */
+ if (d->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->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->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->min) {
+ target->flags |= LYS_MAND_TRUE;
+ }
+ }
+
+ /* [max-elements-stmt] */
+ if (d->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->max ? d->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->max ? d->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;
+ }
+ }
+
+ ret = LY_SUCCESS;
+
+cleanup:
+ return ret;
+}
+
/**
* @brief Apply all deviations of one target node.
*
@@ -5626,98 +6326,14 @@
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_deviate *d;
- struct lysp_deviate_add *d_add;
- struct lysp_deviate_del *d_del;
- struct lysp_deviate_rpl *d_rpl;
- 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 = NULL;
- struct lys_module *mod;
+ LY_ARRAY_COUNT_TYPE v, x;
+ int changed_type = 0;
+ const char *dflt = NULL;
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 */
@@ -5776,566 +6392,15 @@
/* 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;
- }
- }
-
+ LY_CHECK_GOTO(lys_apply_deviate_add(ctx, target, dev->flags, (struct lysp_deviate_add *)d, &dflt), 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;
- }
- }
-
+ LY_CHECK_GOTO(lys_apply_deviate_delete(ctx, target, dev->flags, (struct lysp_deviate_del *)d), 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;
- }
- }
-
+ LY_CHECK_GOTO(lys_apply_deviate_replace(ctx, target, (struct lysp_deviate_rpl *)d, &dflt, &changed_type), cleanup);
break;
default:
LOGINT(ctx->ctx);