blob: e9861881331f7fecd84deca037e8b09051f9f76b [file] [log] [blame]
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001/**
2 * @file schema_compile_amend.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko19a09022021-06-15 11:54:08 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02005 * @brief Schema compilation of augments, deviations, and refines.
6 *
Michal Vasko19a09022021-06-15 11:54:08 +02007 * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#define _GNU_SOURCE
17
18#include "schema_compile_amend.h"
19
20#include <assert.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020021#include <stddef.h>
22#include <stdint.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020023#include <stdlib.h>
24#include <string.h>
25
26#include "common.h"
Radek Krejci77114102021-03-10 15:21:57 +010027#include "dict.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020028#include "log.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020029#include "schema_compile.h"
30#include "schema_compile_node.h"
Michal Vasko29dd11e2020-11-23 16:52:22 +010031#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020032#include "set.h"
33#include "tree.h"
Michal Vasko899c7ce2022-02-18 09:18:37 +010034#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010035#include "tree_edit.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020036#include "tree_schema.h"
37#include "tree_schema_internal.h"
38#include "xpath.h"
39
Michal Vasko0b50f6b2022-10-05 15:07:55 +020040/**
41 * @brief Get module of a single nodeid node name test.
42 *
43 * @param[in] ctx libyang context.
44 * @param[in] nametest Nametest with an optional prefix.
45 * @param[in] nametest_len Length of @p nametest.
46 * @param[in] mod Both current and prefix module for resolving prefixes and to return in case of no prefix.
47 * @param[out] name Optional pointer to the name test without the prefix.
48 * @param[out] name_len Length of @p name.
49 * @return Resolved module.
50 */
51static const struct lys_module *
52lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
53 const struct lysp_module *mod, const char **name, size_t *name_len)
54{
55 const struct lys_module *target_mod;
56 const char *ptr;
57
58 ptr = ly_strnchr(nametest, ':', nametest_len);
59 if (ptr) {
60 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_VALUE_SCHEMA, (void *)mod);
61 if (!target_mod) {
62 LOGVAL(ctx, LYVE_REFERENCE,
63 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
64 (int)nametest_len, nametest, (int)(ptr - nametest), nametest, LYSP_MODULE_NAME(mod));
65 return NULL;
66 }
67
68 if (name) {
69 *name = ptr + 1;
70 *name_len = nametest_len - ((ptr - nametest) + 1);
71 }
72 } else {
73 target_mod = mod->mod;
74 if (name) {
75 *name = nametest;
76 *name_len = nametest_len;
77 }
78 }
79
80 return target_mod;
81}
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020082
Michal Vasko1ccbf542021-04-19 11:35:00 +020083/**
84 * @brief Check the syntax of a node-id and collect all the referenced modules.
85 *
86 * @param[in] ctx Compile context.
87 * @param[in] nodeid Node-id to check.
88 * @param[in] abs Whether @p nodeid is absolute.
89 * @param[in,out] mod_set Set to add referenced modules into.
90 * @param[out] expr Optional node-id parsed into an expression.
91 * @param[out] target_mod Optional target module of the node-id.
92 * @return LY_ERR value.
93 */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020094static LY_ERR
Michal Vasko1ccbf542021-04-19 11:35:00 +020095lys_nodeid_mod_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct ly_set *mod_set,
96 struct lyxp_expr **expr, struct lys_module **target_mod)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020097{
98 LY_ERR ret = LY_SUCCESS;
99 struct lyxp_expr *e = NULL;
100 struct lys_module *tmod = NULL, *mod;
101 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
102 uint32_t i;
103
104 /* parse */
105 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
106 if (ret) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100107 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200108 nodeid_type, nodeid);
109 ret = LY_EVALID;
110 goto cleanup;
111 }
112
113 if (abs) {
114 /* absolute schema nodeid */
115 i = 0;
116 } else {
117 /* descendant schema nodeid */
118 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100119 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200120 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
121 ret = LY_EVALID;
122 goto cleanup;
123 }
124 i = 1;
125 }
126
127 /* check all the tokens */
128 for ( ; i < e->used; i += 2) {
129 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100130 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200131 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
132 ret = LY_EVALID;
133 goto cleanup;
134 } else if (e->used == i + 1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100135 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200136 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
137 ret = LY_EVALID;
138 goto cleanup;
139 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100140 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200141 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
142 ret = LY_EVALID;
143 goto cleanup;
144 } else if (abs) {
145 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
146 e->tok_len[i + 1], ctx->pmod, NULL, NULL);
147 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
148
149 /* only keep the first module */
150 if (!tmod) {
151 tmod = mod;
152 }
153
Michal Vasko1ccbf542021-04-19 11:35:00 +0200154 /* store the referenced module */
155 LY_CHECK_GOTO(ret = ly_set_add(mod_set, mod, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200156 }
157 }
158
159cleanup:
160 if (ret || !expr) {
161 lyxp_expr_free(ctx->ctx, e);
162 e = NULL;
163 }
164 if (expr) {
165 *expr = ret ? NULL : e;
166 }
167 if (target_mod) {
168 *target_mod = ret ? NULL : tmod;
169 }
170 return ret;
171}
172
173/**
174 * @brief Check whether 2 schema nodeids match.
175 *
176 * @param[in] ctx libyang context.
177 * @param[in] exp1 First schema nodeid.
178 * @param[in] exp1p_mod Module of @p exp1 nodes without any prefix.
179 * @param[in] exp2 Second schema nodeid.
180 * @param[in] exp2_pmod Module of @p exp2 nodes without any prefix.
181 * @return Whether the schema nodeids match or not.
182 */
183static ly_bool
184lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lysp_module *exp1_pmod,
185 const struct lyxp_expr *exp2, const struct lysp_module *exp2_pmod)
186{
187 uint32_t i;
188 const struct lys_module *mod1, *mod2;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100189 const char *name1 = NULL, *name2 = NULL;
190 size_t name1_len = 0, name2_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200191
192 if (exp1->used != exp2->used) {
193 return 0;
194 }
195
196 for (i = 0; i < exp1->used; ++i) {
197 assert(exp1->tokens[i] == exp2->tokens[i]);
198
199 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
200 /* check modules of all the nodes in the node ID */
201 mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_pmod,
202 &name1, &name1_len);
203 assert(mod1);
204 mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_pmod,
205 &name2, &name2_len);
206 assert(mod2);
207
208 /* compare modules */
209 if (mod1 != mod2) {
210 return 0;
211 }
212
213 /* compare names */
214 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
215 return 0;
216 }
217 }
218 }
219
220 return 1;
221}
222
223LY_ERR
224lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
225{
226 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200227 struct lyxp_expr *exp = NULL;
228 struct lysc_augment *aug;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100229 struct lysp_node_augment *aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200230 struct lysc_refine *rfn;
231 struct lysp_refine **new_rfn;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100232 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200233 uint32_t i;
Michal Vasko1ccbf542021-04-19 11:35:00 +0200234 struct ly_set mod_set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200235
Radek Krejci2a9fc652021-01-22 17:44:34 +0100236 LY_LIST_FOR(uses_p->augments, aug_p) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200237 lysc_update_path(ctx, NULL, "{augment}");
Radek Krejci2a9fc652021-01-22 17:44:34 +0100238 lysc_update_path(ctx, NULL, aug_p->nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200239
240 /* parse the nodeid */
Michal Vasko1ccbf542021-04-19 11:35:00 +0200241 LY_CHECK_GOTO(ret = lys_nodeid_mod_check(ctx, aug_p->nodeid, 0, &mod_set, &exp, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200242
243 /* allocate new compiled augment and store it in the set */
244 aug = calloc(1, sizeof *aug);
245 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
246 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
247
248 aug->nodeid = exp;
249 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +0100250 aug->aug_pmod = ctx->pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200251 aug->nodeid_ctx_node = ctx_node;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100252 aug->aug_p = aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200253
254 lysc_update_path(ctx, NULL, NULL);
255 lysc_update_path(ctx, NULL, NULL);
256 }
257
258 LY_ARRAY_FOR(uses_p->refines, u) {
259 lysc_update_path(ctx, NULL, "{refine}");
260 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
261
262 /* parse the nodeid */
Michal Vasko1ccbf542021-04-19 11:35:00 +0200263 LY_CHECK_GOTO(ret = lys_nodeid_mod_check(ctx, uses_p->refines[u].nodeid, 0, &mod_set, &exp, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200264
265 /* try to find the node in already compiled refines */
266 rfn = NULL;
267 for (i = 0; i < ctx->uses_rfns.count; ++i) {
268 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
269 ctx->pmod)) {
270 rfn = ctx->uses_rfns.objs[i];
271 break;
272 }
273 }
274
275 if (!rfn) {
276 /* allocate new compiled refine */
277 rfn = calloc(1, sizeof *rfn);
278 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
279 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
280
281 rfn->nodeid = exp;
282 exp = NULL;
Michal Vasko7d3708f2021-02-03 10:50:24 +0100283 rfn->nodeid_pmod = ctx->cur_mod->parsed;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200284 rfn->nodeid_ctx_node = ctx_node;
Michal Vaskod8655722021-01-12 15:20:36 +0100285 rfn->uses_p = uses_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200286 } else {
287 /* just free exp */
288 lyxp_expr_free(ctx->ctx, exp);
289 exp = NULL;
290 }
291
292 /* add new parsed refine structure */
293 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
294 *new_rfn = &uses_p->refines[u];
295
296 lysc_update_path(ctx, NULL, NULL);
297 lysc_update_path(ctx, NULL, NULL);
298 }
299
300cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +0200301 if (ret) {
302 lysc_update_path(ctx, NULL, NULL);
303 lysc_update_path(ctx, NULL, NULL);
304 }
305 /* should include only this module, will fail later if not */
306 ly_set_erase(&mod_set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200307 lyxp_expr_free(ctx->ctx, exp);
308 return ret;
309}
310
Michal Vaskoc621d862022-11-08 14:23:45 +0100311/**
312 * @brief Duplicate parsed extension children, recursively.
313 *
314 * @param[in] ctx Context.
315 * @param[in] orig_child First original child to duplicate.
316 * @param[in,out] child Duplicated children to add to.
317 * @return LY_ERR value.
318 */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200319static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100320lysp_ext_children_dup(const struct ly_ctx *ctx, const struct lysp_stmt *orig_child, struct lysp_stmt **child)
Michal Vasko899c7ce2022-02-18 09:18:37 +0100321{
Michal Vaskod84b8132022-03-15 10:45:44 +0100322 struct lysp_stmt *ch = NULL;
Michal Vasko4316c9d2022-02-21 10:00:10 +0100323
Michal Vasko9464f422022-02-21 10:18:28 +0100324 assert(!*child);
325
Michal Vasko899c7ce2022-02-18 09:18:37 +0100326 LY_LIST_FOR(orig_child, orig_child) {
327 /* new child */
328 if (!*child) {
Michal Vasko4316c9d2022-02-21 10:00:10 +0100329 *child = ch = calloc(1, sizeof *ch);
330 LY_CHECK_ERR_RET(!ch, LOGMEM(ctx), LY_EMEM);
Michal Vasko899c7ce2022-02-18 09:18:37 +0100331 } else {
Michal Vasko4316c9d2022-02-21 10:00:10 +0100332 ch->next = calloc(1, sizeof *ch);
333 LY_CHECK_ERR_RET(!ch->next, LOGMEM(ctx), LY_EMEM);
334 ch = ch->next;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100335 }
336
337 /* fill */
Michal Vasko4316c9d2022-02-21 10:00:10 +0100338 DUP_STRING_RET(ctx, orig_child->stmt, ch->stmt);
339 ch->flags = orig_child->flags;
340 DUP_STRING_RET(ctx, orig_child->arg, ch->arg);
341 ch->format = orig_child->format;
342 LY_CHECK_RET(ly_dup_prefix_data(ctx, orig_child->format, orig_child->prefix_data, &(ch->prefix_data)));
343 ch->kw = orig_child->kw;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100344
345 /* recursive children */
Michal Vaskoc621d862022-11-08 14:23:45 +0100346 LY_CHECK_RET(lysp_ext_children_dup(ctx, orig_child->child, &ch->child));
Michal Vasko899c7ce2022-02-18 09:18:37 +0100347 }
348
349 return LY_SUCCESS;
350}
351
Michal Vaskoc621d862022-11-08 14:23:45 +0100352/**
353 * @brief Duplicate parsed extension instance.
354 *
355 * @param[in] ctx Context.
356 * @param[in] pmod Current parsed module.
357 * @param[in] parent Parent of the duplicated ext instance.
358 * @param[in] parent_stmt Parent statement of the duplicated ext instance (should be @p parent).
359 * @param[out] ext Duplicated ext instance to fill.
360 * @return LY_ERR value.
361 */
Michal Vasko899c7ce2022-02-18 09:18:37 +0100362static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100363lysp_ext_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, void *parent, enum ly_stmt parent_stmt,
364 const struct lysp_ext_instance *orig_ext, struct lysp_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200365{
Michal Vasko193dacd2022-10-13 08:43:05 +0200366 LY_ERR ret = LY_SUCCESS;
367 struct ly_set pmods = {0};
368 struct lysp_ctx pctx = {.parsed_mods = &pmods};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200369
Michal Vasko193dacd2022-10-13 08:43:05 +0200370 DUP_STRING_GOTO(ctx, orig_ext->name, ext->name, ret, cleanup);
371 DUP_STRING_GOTO(ctx, orig_ext->argument, ext->argument, ret, cleanup);
372 ext->format = orig_ext->format;
373 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, orig_ext->format, orig_ext->prefix_data, &ext->prefix_data), cleanup);
374 ext->def = orig_ext->def;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100375
Michal Vaskoc621d862022-11-08 14:23:45 +0100376 ext->parent = parent;
377 ext->parent_stmt = parent_stmt;
Michal Vasko91bb76c2022-03-24 13:34:18 +0100378 ext->parent_stmt_index = orig_ext->parent_stmt_index;
379 ext->flags = orig_ext->flags;
Michal Vasko193dacd2022-10-13 08:43:05 +0200380 ext->record = orig_ext->record;
381
Michal Vaskoc621d862022-11-08 14:23:45 +0100382 LY_CHECK_GOTO(ret = lysp_ext_children_dup(ctx, orig_ext->child, &ext->child), cleanup);
Michal Vasko193dacd2022-10-13 08:43:05 +0200383 if (ext->record && ext->record->plugin.parse) {
384 /* parse again */
385 LY_CHECK_GOTO(ret = ly_set_add(&pmods, pmod, 1, NULL), cleanup);
386 LY_CHECK_GOTO(ret = ext->record->plugin.parse(&pctx, ext), cleanup);
387 }
388
389cleanup:
390 ly_set_erase(&pmods, NULL);
391 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200392}
393
394static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100395lysp_restr_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, const struct lysp_restr *orig_restr,
396 struct lysp_restr *restr)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200397{
398 LY_ERR ret = LY_SUCCESS;
399
400 if (orig_restr) {
401 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
402 restr->arg.mod = orig_restr->arg.mod;
403 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
404 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
405 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
406 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
Michal Vaskoc621d862022-11-08 14:23:45 +0100407 DUP_EXTS(ctx, pmod, restr, LY_STMT_MUST, orig_restr->exts, restr->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200408 }
409
410 return ret;
411}
412
413static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100414lysp_string_dup(const struct ly_ctx *ctx, const char **orig_str, const char **str)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200415{
416 LY_ERR ret = LY_SUCCESS;
417
418 DUP_STRING(ctx, *orig_str, *str, ret);
419
420 return ret;
421}
422
423LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100424lysp_qname_dup(const struct ly_ctx *ctx, const struct lysp_qname *orig_qname, struct lysp_qname *qname)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200425{
426 LY_ERR ret = LY_SUCCESS;
427
428 if (!orig_qname->str) {
429 return LY_SUCCESS;
430 }
431
432 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
433 assert(orig_qname->mod);
434 qname->mod = orig_qname->mod;
435
436 return ret;
437}
438
439static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100440lysp_type_enum_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, const struct lysp_type_enum *orig_enm,
441 struct lysp_type_enum *enm)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200442{
443 LY_ERR ret = LY_SUCCESS;
444
445 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
446 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
447 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
448 enm->value = orig_enm->value;
449 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100450 DUP_EXTS(ctx, pmod, enm, LY_STMT_ENUM, orig_enm->exts, enm->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200451 enm->flags = orig_enm->flags;
452
453 return ret;
454}
455
456static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100457lysp_type_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, const struct lysp_type *orig_type,
458 struct lysp_type *type)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200459{
460 LY_ERR ret = LY_SUCCESS;
461
Michal Vaskoea868242021-06-21 09:28:32 +0200462 /* array macros read previous data so we must zero it */
463 memset(type, 0, sizeof *type);
464
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200465 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
466
467 if (orig_type->range) {
468 type->range = calloc(1, sizeof *type->range);
469 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
Michal Vaskoc621d862022-11-08 14:23:45 +0100470 LY_CHECK_RET(lysp_restr_dup(ctx, pmod, orig_type->range, type->range));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200471 }
472
473 if (orig_type->length) {
474 type->length = calloc(1, sizeof *type->length);
475 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
Michal Vaskoc621d862022-11-08 14:23:45 +0100476 LY_CHECK_RET(lysp_restr_dup(ctx, pmod, orig_type->length, type->length));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200477 }
478
Michal Vasko193dacd2022-10-13 08:43:05 +0200479 DUP_ARRAY2(ctx, pmod, orig_type->patterns, type->patterns, lysp_restr_dup);
480 DUP_ARRAY2(ctx, pmod, orig_type->enums, type->enums, lysp_type_enum_dup);
481 DUP_ARRAY2(ctx, pmod, orig_type->bits, type->bits, lysp_type_enum_dup);
Michal Vaskoe33134a2022-07-29 14:54:40 +0200482 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, 0, 0, &type->path), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200483 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
Michal Vasko193dacd2022-10-13 08:43:05 +0200484 DUP_ARRAY2(ctx, pmod, orig_type->types, type->types, lysp_type_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100485 DUP_EXTS(ctx, pmod, type, LY_STMT_TYPE, orig_type->exts, type->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200486
487 type->pmod = orig_type->pmod;
488 type->compiled = orig_type->compiled;
489
490 type->fraction_digits = orig_type->fraction_digits;
491 type->require_instance = orig_type->require_instance;
492 type->flags = orig_type->flags;
493
494done:
495 return ret;
496}
497
498static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200499lysp_when_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_when *when,
500 const struct lysp_when *orig_when)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200501{
502 LY_ERR ret = LY_SUCCESS;
503
504 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
505 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
506 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
Michal Vaskoc621d862022-11-08 14:23:45 +0100507 DUP_EXTS(ctx, pmod, when, LY_STMT_WHEN, orig_when->exts, when->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200508
509 return ret;
510}
511
512static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200513lysp_node_common_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_node *node,
514 const struct lysp_node *orig)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200515{
516 LY_ERR ret = LY_SUCCESS;
517
518 node->parent = NULL;
519 node->nodetype = orig->nodetype;
520 node->flags = orig->flags;
521 node->next = NULL;
522 DUP_STRING(ctx, orig->name, node->name, ret);
523 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
524 DUP_STRING(ctx, orig->ref, node->ref, ret);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200525 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100526 DUP_EXTS(ctx, pmod, node, lyplg_ext_nodetype2stmt(node->nodetype), orig->exts, node->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200527
528 return ret;
529}
530
Michal Vasko193dacd2022-10-13 08:43:05 +0200531#define DUP_PWHEN(CTX, PMOD, ORIG, NEW) \
Radek Krejci9a3823e2021-01-27 20:26:46 +0100532 if (ORIG) { \
533 NEW = calloc(1, sizeof *NEW); \
534 LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \
Michal Vasko193dacd2022-10-13 08:43:05 +0200535 LY_CHECK_RET(lysp_when_dup(CTX, PMOD, NEW, ORIG)); \
Radek Krejci9a3823e2021-01-27 20:26:46 +0100536 }
537
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200538static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200539lysp_node_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_node *node,
540 const struct lysp_node *orig)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200541{
542 LY_ERR ret = LY_SUCCESS;
543 struct lysp_node_container *cont;
544 const struct lysp_node_container *orig_cont;
545 struct lysp_node_leaf *leaf;
546 const struct lysp_node_leaf *orig_leaf;
547 struct lysp_node_leaflist *llist;
548 const struct lysp_node_leaflist *orig_llist;
549 struct lysp_node_list *list;
550 const struct lysp_node_list *orig_list;
551 struct lysp_node_choice *choice;
552 const struct lysp_node_choice *orig_choice;
553 struct lysp_node_case *cas;
554 const struct lysp_node_case *orig_cas;
555 struct lysp_node_anydata *any;
556 const struct lysp_node_anydata *orig_any;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100557 struct lysp_node_action *action;
558 const struct lysp_node_action *orig_action;
559 struct lysp_node_action_inout *action_inout;
560 const struct lysp_node_action_inout *orig_action_inout;
561 struct lysp_node_notif *notif;
562 const struct lysp_node_notif *orig_notif;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200563
Radek Krejci2a9fc652021-01-22 17:44:34 +0100564 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA |
565 LYS_RPC | LYS_ACTION | LYS_NOTIF));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200566
567 /* common part */
Michal Vasko193dacd2022-10-13 08:43:05 +0200568 LY_CHECK_RET(lysp_node_common_dup(ctx, pmod, node, orig));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200569
570 /* specific part */
571 switch (node->nodetype) {
572 case LYS_CONTAINER:
573 cont = (struct lysp_node_container *)node;
574 orig_cont = (const struct lysp_node_container *)orig;
575
Michal Vasko193dacd2022-10-13 08:43:05 +0200576 DUP_PWHEN(ctx, pmod, orig_cont->when, cont->when);
577 DUP_ARRAY2(ctx, pmod, orig_cont->musts, cont->musts, lysp_restr_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200578 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
579 /* we do not need the rest */
580 break;
581 case LYS_LEAF:
582 leaf = (struct lysp_node_leaf *)node;
583 orig_leaf = (const struct lysp_node_leaf *)orig;
584
Michal Vasko193dacd2022-10-13 08:43:05 +0200585 DUP_PWHEN(ctx, pmod, orig_leaf->when, leaf->when);
586 DUP_ARRAY2(ctx, pmod, orig_leaf->musts, leaf->musts, lysp_restr_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100587 LY_CHECK_RET(lysp_type_dup(ctx, pmod, &orig_leaf->type, &leaf->type));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200588 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
Michal Vaskoc621d862022-11-08 14:23:45 +0100589 LY_CHECK_RET(lysp_qname_dup(ctx, &orig_leaf->dflt, &leaf->dflt));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200590 break;
591 case LYS_LEAFLIST:
592 llist = (struct lysp_node_leaflist *)node;
593 orig_llist = (const struct lysp_node_leaflist *)orig;
594
Michal Vasko193dacd2022-10-13 08:43:05 +0200595 DUP_PWHEN(ctx, pmod, orig_llist->when, llist->when);
596 DUP_ARRAY2(ctx, pmod, orig_llist->musts, llist->musts, lysp_restr_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100597 LY_CHECK_RET(lysp_type_dup(ctx, pmod, &orig_llist->type, &llist->type));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200598 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
599 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
600 llist->min = orig_llist->min;
601 llist->max = orig_llist->max;
602 break;
603 case LYS_LIST:
604 list = (struct lysp_node_list *)node;
605 orig_list = (const struct lysp_node_list *)orig;
606
Michal Vasko193dacd2022-10-13 08:43:05 +0200607 DUP_PWHEN(ctx, pmod, orig_list->when, list->when);
608 DUP_ARRAY2(ctx, pmod, orig_list->musts, list->musts, lysp_restr_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200609 DUP_STRING(ctx, orig_list->key, list->key, ret);
610 /* we do not need these arrays */
611 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
612 list->min = orig_list->min;
613 list->max = orig_list->max;
614 break;
615 case LYS_CHOICE:
616 choice = (struct lysp_node_choice *)node;
617 orig_choice = (const struct lysp_node_choice *)orig;
618
Michal Vasko193dacd2022-10-13 08:43:05 +0200619 DUP_PWHEN(ctx, pmod, orig_choice->when, choice->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200620 /* we do not need children */
Michal Vaskoc621d862022-11-08 14:23:45 +0100621 LY_CHECK_RET(lysp_qname_dup(ctx, &orig_choice->dflt, &choice->dflt));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200622 break;
623 case LYS_CASE:
624 cas = (struct lysp_node_case *)node;
625 orig_cas = (const struct lysp_node_case *)orig;
626
Michal Vasko193dacd2022-10-13 08:43:05 +0200627 DUP_PWHEN(ctx, pmod, orig_cas->when, cas->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200628 /* we do not need children */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200629 break;
630 case LYS_ANYDATA:
631 case LYS_ANYXML:
632 any = (struct lysp_node_anydata *)node;
633 orig_any = (const struct lysp_node_anydata *)orig;
634
Michal Vasko193dacd2022-10-13 08:43:05 +0200635 DUP_PWHEN(ctx, pmod, orig_any->when, any->when);
636 DUP_ARRAY2(ctx, pmod, orig_any->musts, any->musts, lysp_restr_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200637 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100638 case LYS_RPC:
639 case LYS_ACTION:
640 action = (struct lysp_node_action *)node;
641 orig_action = (const struct lysp_node_action *)orig;
642
643 action->input.nodetype = orig_action->input.nodetype;
644 action->output.nodetype = orig_action->output.nodetype;
645 /* we do not need the rest */
646 break;
647 case LYS_INPUT:
648 case LYS_OUTPUT:
649 action_inout = (struct lysp_node_action_inout *)node;
650 orig_action_inout = (const struct lysp_node_action_inout *)orig;
651
Michal Vasko193dacd2022-10-13 08:43:05 +0200652 DUP_ARRAY2(ctx, pmod, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
Radek Krejci2a9fc652021-01-22 17:44:34 +0100653 /* we do not need the rest */
654 break;
655 case LYS_NOTIF:
656 notif = (struct lysp_node_notif *)node;
657 orig_notif = (const struct lysp_node_notif *)orig;
658
Michal Vasko193dacd2022-10-13 08:43:05 +0200659 DUP_ARRAY2(ctx, pmod, orig_notif->musts, notif->musts, lysp_restr_dup);
Radek Krejci2a9fc652021-01-22 17:44:34 +0100660 /* we do not need the rest */
661 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200662 default:
663 LOGINT_RET(ctx);
664 }
665
666 return ret;
667}
668
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200669/**
670 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
671 *
672 * @param[in] ctx libyang context.
Michal Vasko193dacd2022-10-13 08:43:05 +0200673 * @param[in] pmod Current parsed module.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200674 * @param[in] pnode Node to duplicate.
675 * @param[in] with_links Whether to also copy any links (child, parent pointers).
676 * @param[out] dup_p Duplicated parsed node.
677 * @return LY_ERR value.
678 */
679static LY_ERR
Michal Vaskod7e8c532022-11-08 13:44:51 +0100680lysp_dup_single(struct lysc_ctx *cctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200681{
682 LY_ERR ret = LY_SUCCESS;
Michal Vaskod7e8c532022-11-08 13:44:51 +0100683 struct lysp_node *dup = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200684
685 if (!pnode) {
686 *dup_p = NULL;
687 return LY_SUCCESS;
688 }
689
690 switch (pnode->nodetype) {
691 case LYS_CONTAINER:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100692 dup = calloc(1, sizeof(struct lysp_node_container));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200693 break;
694 case LYS_LEAF:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100695 dup = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200696 break;
697 case LYS_LEAFLIST:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100698 dup = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200699 break;
700 case LYS_LIST:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100701 dup = calloc(1, sizeof(struct lysp_node_list));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200702 break;
703 case LYS_CHOICE:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100704 dup = calloc(1, sizeof(struct lysp_node_choice));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200705 break;
706 case LYS_CASE:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100707 dup = calloc(1, sizeof(struct lysp_node_case));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200708 break;
709 case LYS_ANYDATA:
710 case LYS_ANYXML:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100711 dup = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200712 break;
713 case LYS_INPUT:
714 case LYS_OUTPUT:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100715 dup = calloc(1, sizeof(struct lysp_node_action_inout));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200716 break;
717 case LYS_ACTION:
718 case LYS_RPC:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100719 dup = calloc(1, sizeof(struct lysp_node_action));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200720 break;
721 case LYS_NOTIF:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100722 dup = calloc(1, sizeof(struct lysp_node_notif));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200723 break;
724 default:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100725 LOGINT_RET(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200726 }
Michal Vaskod7e8c532022-11-08 13:44:51 +0100727 LY_CHECK_ERR_GOTO(!dup, LOGMEM(cctx->ctx); ret = LY_EMEM, cleanup);
728 LY_CHECK_GOTO(ret = lysp_node_dup(cctx->ctx, cctx->pmod, dup, pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200729
730 if (with_links) {
Michal Vaskoec8f4272021-10-27 09:14:03 +0200731 /* copy also parent, child, action, and notification pointers */
Michal Vaskod7e8c532022-11-08 13:44:51 +0100732 dup->parent = pnode->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200733 switch (pnode->nodetype) {
734 case LYS_CONTAINER:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100735 ((struct lysp_node_container *)dup)->child = ((struct lysp_node_container *)pnode)->child;
736 ((struct lysp_node_container *)dup)->actions = ((struct lysp_node_container *)pnode)->actions;
737 ((struct lysp_node_container *)dup)->notifs = ((struct lysp_node_container *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200738 break;
739 case LYS_LIST:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100740 ((struct lysp_node_list *)dup)->child = ((struct lysp_node_list *)pnode)->child;
741 ((struct lysp_node_list *)dup)->actions = ((struct lysp_node_list *)pnode)->actions;
742 ((struct lysp_node_list *)dup)->notifs = ((struct lysp_node_list *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200743 break;
744 case LYS_CHOICE:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100745 ((struct lysp_node_choice *)dup)->child = ((struct lysp_node_choice *)pnode)->child;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200746 break;
747 case LYS_CASE:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100748 ((struct lysp_node_case *)dup)->child = ((struct lysp_node_case *)pnode)->child;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200749 break;
750 default:
751 break;
752 }
753 }
754
755cleanup:
756 if (ret) {
Michal Vaskod7e8c532022-11-08 13:44:51 +0100757 lysp_dev_node_free(cctx, dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200758 } else {
Michal Vaskod7e8c532022-11-08 13:44:51 +0100759 *dup_p = dup;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200760 }
761 return ret;
762}
763
764#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100765 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s of %s node - it is not possible to %s \"%s\" property.", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200766 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
767 ret = LY_EVALID; \
768 goto cleanup;
769
770#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
771 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100772 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid %s of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200773 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
774 ret = LY_EVALID; \
775 goto cleanup; \
776 }
777
778/**
779 * @brief Apply refine.
780 *
781 * @param[in] ctx Compile context.
782 * @param[in] rfn Refine to apply.
Michal Vasko193dacd2022-10-13 08:43:05 +0200783 * @param[in] rfn_pmod Local module fo the refine.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200784 * @param[in,out] target Refine target.
785 * @return LY_ERR value.
786 */
787static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200788lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, const struct lysp_module *rfn_pmod, struct lysp_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200789{
790 LY_ERR ret = LY_SUCCESS;
Michal Vasko193dacd2022-10-13 08:43:05 +0200791 struct lys_module *orig_mod = ctx->cur_mod;
792 struct lysp_module *orig_pmod = ctx->pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200793 LY_ARRAY_COUNT_TYPE u;
794 struct lysp_qname *qname;
795 struct lysp_restr **musts, *must;
796 uint32_t *num;
797
Michal Vasko193dacd2022-10-13 08:43:05 +0200798 /* use module from the refine */
799 ctx->cur_mod = rfn_pmod->mod;
800 ctx->pmod = (struct lysp_module *)rfn_pmod;
801
802 /* keep the current path and add to it */
803 lysc_update_path(ctx, NULL, "{refine}");
804 lysc_update_path(ctx, NULL, rfn->nodeid);
805
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200806 /* default value */
807 if (rfn->dflts) {
808 switch (target->nodetype) {
809 case LYS_LEAF:
810 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
811
Michal Vaskoe180ed02021-02-05 16:31:20 +0100812 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +0100813 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->dflts[0], &((struct lysp_node_leaf *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200814 break;
815 case LYS_LEAFLIST:
816 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100817 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200818 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
819 ret = LY_EVALID;
820 goto cleanup;
821 }
822
823 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
824 ((struct lysp_node_leaflist *)target)->dflts = NULL;
825 LY_ARRAY_FOR(rfn->dflts, u) {
826 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100827 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->dflts[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200828 }
829 break;
830 case LYS_CHOICE:
831 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
832
Michal Vaskoe180ed02021-02-05 16:31:20 +0100833 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +0100834 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->dflts[0], &((struct lysp_node_choice *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200835 break;
836 default:
837 AMEND_WRONG_NODETYPE("refine", "replace", "default");
838 }
839 }
840
841 /* description */
842 if (rfn->dsc) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100843 lydict_remove(ctx->ctx, target->dsc);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200844 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
845 }
846
847 /* reference */
848 if (rfn->ref) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100849 lydict_remove(ctx->ctx, target->ref);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200850 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
851 }
852
853 /* config */
854 if (rfn->flags & LYS_CONFIG_MASK) {
Michal Vasko7c565922021-06-10 14:58:27 +0200855 if (ctx->compile_opts & LYS_COMPILE_NO_CONFIG) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200856 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Michal Vasko7c565922021-06-10 14:58:27 +0200857 (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT)) ? "RPC/action" :
858 ctx->compile_opts & LYS_IS_NOTIF ? "notification" : "a subtree ignoring config", ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200859 } else {
860 target->flags &= ~LYS_CONFIG_MASK;
861 target->flags |= rfn->flags & LYS_CONFIG_MASK;
862 }
863 }
864
865 /* mandatory */
866 if (rfn->flags & LYS_MAND_MASK) {
867 switch (target->nodetype) {
868 case LYS_LEAF:
869 case LYS_CHOICE:
870 case LYS_ANYDATA:
871 case LYS_ANYXML:
872 break;
873 default:
874 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
875 }
876
877 target->flags &= ~LYS_MAND_MASK;
878 target->flags |= rfn->flags & LYS_MAND_MASK;
879 }
880
881 /* presence */
882 if (rfn->presence) {
Michal Vasko4e55f5a2022-12-14 12:15:00 +0100883 if (target->nodetype != LYS_CONTAINER) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200884 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
885 }
886
Michal Vaskoe180ed02021-02-05 16:31:20 +0100887 lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200888 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
889 }
890
891 /* must */
892 if (rfn->musts) {
893 switch (target->nodetype) {
894 case LYS_CONTAINER:
895 case LYS_LIST:
896 case LYS_LEAF:
897 case LYS_LEAFLIST:
898 case LYS_ANYDATA:
899 case LYS_ANYXML:
900 musts = &((struct lysp_node_container *)target)->musts;
901 break;
902 default:
903 AMEND_WRONG_NODETYPE("refine", "add", "must");
904 }
905
906 LY_ARRAY_FOR(rfn->musts, u) {
907 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100908 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, rfn_pmod, &rfn->musts[u], must), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200909 }
910 }
911
912 /* min-elements */
913 if (rfn->flags & LYS_SET_MIN) {
914 switch (target->nodetype) {
915 case LYS_LEAFLIST:
916 num = &((struct lysp_node_leaflist *)target)->min;
917 break;
918 case LYS_LIST:
919 num = &((struct lysp_node_list *)target)->min;
920 break;
921 default:
922 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
923 }
924
925 *num = rfn->min;
926 }
927
928 /* max-elements */
929 if (rfn->flags & LYS_SET_MAX) {
930 switch (target->nodetype) {
931 case LYS_LEAFLIST:
932 num = &((struct lysp_node_leaflist *)target)->max;
933 break;
934 case LYS_LIST:
935 num = &((struct lysp_node_list *)target)->max;
936 break;
937 default:
938 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
939 }
940
941 *num = rfn->max;
942 }
943
944 /* if-feature */
945 if (rfn->iffeatures) {
946 switch (target->nodetype) {
947 case LYS_LEAF:
948 case LYS_LEAFLIST:
949 case LYS_LIST:
950 case LYS_CONTAINER:
951 case LYS_CHOICE:
952 case LYS_CASE:
953 case LYS_ANYDATA:
954 case LYS_ANYXML:
955 break;
956 default:
957 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
958 }
959
960 LY_ARRAY_FOR(rfn->iffeatures, u) {
961 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100962 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->iffeatures[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200963 }
964 }
965
Michal Vasko193dacd2022-10-13 08:43:05 +0200966 /* extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +0100967 DUP_EXTS(ctx->ctx, rfn_pmod, target, lyplg_ext_nodetype2stmt(target->nodetype), rfn->exts, target->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200968
969cleanup:
Michal Vasko193dacd2022-10-13 08:43:05 +0200970 ctx->cur_mod = orig_mod;
971 ctx->pmod = orig_pmod;
972
973 lysc_update_path(ctx, NULL, NULL);
974 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200975 return ret;
976}
977
978/**
979 * @brief Apply deviate add.
980 *
981 * @param[in] ctx Compile context.
982 * @param[in] d Deviate add to apply.
983 * @param[in,out] target Deviation target.
984 * @return LY_ERR value.
985 */
986static LY_ERR
987lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
988{
989 LY_ERR ret = LY_SUCCESS;
990 LY_ARRAY_COUNT_TYPE u;
991 struct lysp_qname *qname;
992 uint32_t *num;
993 struct lysp_restr **musts, *must;
994
995#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
996 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100997 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200998 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
999 ret = LY_EVALID; \
1000 goto cleanup; \
1001 }
1002
1003 /* [units-stmt] */
1004 if (d->units) {
1005 switch (target->nodetype) {
1006 case LYS_LEAF:
1007 case LYS_LEAFLIST:
1008 break;
1009 default:
1010 AMEND_WRONG_NODETYPE("deviation", "add", "units");
1011 }
1012
1013 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
1014 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1015 }
1016
1017 /* *must-stmt */
1018 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001019 musts = lysp_node_musts_p(target);
1020 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001021 AMEND_WRONG_NODETYPE("deviation", "add", "must");
1022 }
1023
1024 LY_ARRAY_FOR(d->musts, u) {
1025 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001026 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, ctx->pmod, &d->musts[u], must), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001027 }
1028 }
1029
1030 /* *unique-stmt */
1031 if (d->uniques) {
Michal Vasko4e55f5a2022-12-14 12:15:00 +01001032 if (target->nodetype != LYS_LIST) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001033 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
1034 }
1035
1036 LY_ARRAY_FOR(d->uniques, u) {
1037 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001038 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->uniques[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001039 }
1040 }
1041
1042 /* *default-stmt */
1043 if (d->dflts) {
1044 switch (target->nodetype) {
1045 case LYS_LEAF:
1046 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1047 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
1048
Michal Vaskoc621d862022-11-08 14:23:45 +01001049 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflts[0], &((struct lysp_node_leaf *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001050 break;
1051 case LYS_LEAFLIST:
1052 LY_ARRAY_FOR(d->dflts, u) {
1053 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001054 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflts[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001055 }
1056 break;
1057 case LYS_CHOICE:
1058 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1059 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
1060
Michal Vaskoc621d862022-11-08 14:23:45 +01001061 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflts[0], &((struct lysp_node_choice *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001062 break;
1063 default:
1064 AMEND_WRONG_NODETYPE("deviation", "add", "default");
1065 }
1066 }
1067
1068 /* [config-stmt] */
1069 if (d->flags & LYS_CONFIG_MASK) {
1070 switch (target->nodetype) {
1071 case LYS_CONTAINER:
1072 case LYS_LEAF:
1073 case LYS_LEAFLIST:
1074 case LYS_LIST:
1075 case LYS_CHOICE:
1076 case LYS_ANYDATA:
1077 case LYS_ANYXML:
1078 break;
1079 default:
1080 AMEND_WRONG_NODETYPE("deviation", "add", "config");
1081 }
1082
1083 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001084 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001085 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
1086 target->flags & LYS_CONFIG_W ? "true" : "false");
1087 ret = LY_EVALID;
1088 goto cleanup;
1089 }
1090
1091 target->flags |= d->flags & LYS_CONFIG_MASK;
1092 }
1093
1094 /* [mandatory-stmt] */
1095 if (d->flags & LYS_MAND_MASK) {
1096 switch (target->nodetype) {
1097 case LYS_LEAF:
1098 case LYS_CHOICE:
1099 case LYS_ANYDATA:
1100 case LYS_ANYXML:
1101 break;
1102 default:
1103 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
1104 }
1105
1106 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001107 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001108 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
1109 target->flags & LYS_MAND_TRUE ? "true" : "false");
1110 ret = LY_EVALID;
1111 goto cleanup;
1112 }
1113
1114 target->flags |= d->flags & LYS_MAND_MASK;
1115 }
1116
1117 /* [min-elements-stmt] */
1118 if (d->flags & LYS_SET_MIN) {
1119 switch (target->nodetype) {
1120 case LYS_LEAFLIST:
1121 num = &((struct lysp_node_leaflist *)target)->min;
1122 break;
1123 case LYS_LIST:
1124 num = &((struct lysp_node_list *)target)->min;
1125 break;
1126 default:
1127 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
1128 }
1129
1130 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001131 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001132 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
1133 ret = LY_EVALID;
1134 goto cleanup;
1135 }
1136
1137 *num = d->min;
1138 }
1139
1140 /* [max-elements-stmt] */
1141 if (d->flags & LYS_SET_MAX) {
1142 switch (target->nodetype) {
1143 case LYS_LEAFLIST:
1144 num = &((struct lysp_node_leaflist *)target)->max;
1145 break;
1146 case LYS_LIST:
1147 num = &((struct lysp_node_list *)target)->max;
1148 break;
1149 default:
1150 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1151 }
1152
1153 if (target->flags & LYS_SET_MAX) {
1154 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001155 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001156 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1157 *num);
1158 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001159 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001160 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1161 }
1162 ret = LY_EVALID;
1163 goto cleanup;
1164 }
1165
1166 *num = d->max;
1167 }
1168
1169cleanup:
1170 return ret;
1171}
1172
1173/**
1174 * @brief Apply deviate delete.
1175 *
1176 * @param[in] ctx Compile context.
1177 * @param[in] d Deviate delete to apply.
1178 * @param[in,out] target Deviation target.
1179 * @return LY_ERR value.
1180 */
1181static LY_ERR
1182lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1183{
1184 LY_ERR ret = LY_SUCCESS;
1185 struct lysp_restr **musts;
1186 LY_ARRAY_COUNT_TYPE u, v;
1187 struct lysp_qname **uniques, **dflts;
1188
Michal Vaskoc636ea42022-09-16 10:20:31 +02001189#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, FREE_CTX, PROPERTY) \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001190 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1191 int found = 0; \
1192 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1193 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1194 found = 1; \
1195 break; \
1196 } \
1197 } \
1198 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001199 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001200 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1201 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1202 ret = LY_EVALID; \
1203 goto cleanup; \
1204 } \
1205 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
Michal Vaskoc636ea42022-09-16 10:20:31 +02001206 FREE_FUNC(FREE_CTX, &(ORIG_ARRAY)[v]); \
Michal Vasko08e9b112021-06-11 15:41:17 +02001207 if (v < LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1208 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1209 } \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001210 } \
1211 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1212 LY_ARRAY_FREE(ORIG_ARRAY); \
1213 ORIG_ARRAY = NULL; \
1214 }
1215
1216#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1217 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001218 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001219 ret = LY_EVALID; \
1220 goto cleanup; \
1221 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001222 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001223 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1224 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1225 ret = LY_EVALID; \
1226 goto cleanup; \
1227 }
1228
1229 /* [units-stmt] */
1230 if (d->units) {
1231 switch (target->nodetype) {
1232 case LYS_LEAF:
1233 case LYS_LEAFLIST:
1234 break;
1235 default:
1236 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1237 }
1238
1239 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001240 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001241 ((struct lysp_node_leaf *)target)->units = NULL;
1242 }
1243
1244 /* *must-stmt */
1245 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001246 musts = lysp_node_musts_p(target);
1247 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001248 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1249 }
1250
Michal Vaskoc636ea42022-09-16 10:20:31 +02001251 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, &ctx->free_ctx, "must");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001252 }
1253
1254 /* *unique-stmt */
1255 if (d->uniques) {
Michal Vasko4e55f5a2022-12-14 12:15:00 +01001256 if (target->nodetype != LYS_LIST) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001257 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1258 }
1259
1260 uniques = &((struct lysp_node_list *)target)->uniques;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001261 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, ctx->ctx, "unique");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001262 }
1263
1264 /* *default-stmt */
1265 if (d->dflts) {
1266 switch (target->nodetype) {
1267 case LYS_LEAF:
1268 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1269 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1270
Michal Vaskoe180ed02021-02-05 16:31:20 +01001271 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001272 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1273 break;
1274 case LYS_LEAFLIST:
1275 dflts = &((struct lysp_node_leaflist *)target)->dflts;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001276 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, ctx->ctx, "default");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001277 break;
1278 case LYS_CHOICE:
1279 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1280 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1281
Michal Vaskoe180ed02021-02-05 16:31:20 +01001282 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001283 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1284 break;
1285 default:
1286 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1287 }
1288 }
1289
1290cleanup:
1291 return ret;
1292}
1293
1294/**
1295 * @brief Apply deviate replace.
1296 *
1297 * @param[in] ctx Compile context.
1298 * @param[in] d Deviate replace to apply.
1299 * @param[in,out] target Deviation target.
1300 * @return LY_ERR value.
1301 */
1302static LY_ERR
1303lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1304{
1305 LY_ERR ret = LY_SUCCESS;
1306 uint32_t *num;
1307
1308#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1309 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001310 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001311 ret = LY_EVALID; \
1312 goto cleanup; \
1313 }
1314
1315 /* [type-stmt] */
1316 if (d->type) {
1317 switch (target->nodetype) {
1318 case LYS_LEAF:
1319 case LYS_LEAFLIST:
1320 break;
1321 default:
1322 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1323 }
1324
Michal Vaskoc636ea42022-09-16 10:20:31 +02001325 lysp_type_free(&ctx->free_ctx, &((struct lysp_node_leaf *)target)->type);
Michal Vaskoc621d862022-11-08 14:23:45 +01001326 lysp_type_dup(ctx->ctx, ctx->pmod, d->type, &((struct lysp_node_leaf *)target)->type);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001327 }
1328
1329 /* [units-stmt] */
1330 if (d->units) {
1331 switch (target->nodetype) {
1332 case LYS_LEAF:
1333 case LYS_LEAFLIST:
1334 break;
1335 default:
1336 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1337 }
1338
1339 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001340 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001341 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1342 }
1343
1344 /* [default-stmt] */
1345 if (d->dflt.str) {
1346 switch (target->nodetype) {
1347 case LYS_LEAF:
1348 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1349
Michal Vaskoe180ed02021-02-05 16:31:20 +01001350 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +01001351 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflt, &((struct lysp_node_leaf *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001352 break;
1353 case LYS_CHOICE:
Michal Vasko7b3a00e2023-08-09 11:58:03 +02001354 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001355
Michal Vaskoe180ed02021-02-05 16:31:20 +01001356 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +01001357 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflt, &((struct lysp_node_choice *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001358 break;
1359 default:
1360 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1361 }
1362 }
1363
1364 /* [config-stmt] */
1365 if (d->flags & LYS_CONFIG_MASK) {
1366 switch (target->nodetype) {
1367 case LYS_CONTAINER:
1368 case LYS_LEAF:
1369 case LYS_LEAFLIST:
1370 case LYS_LIST:
1371 case LYS_CHOICE:
1372 case LYS_ANYDATA:
1373 case LYS_ANYXML:
1374 break;
1375 default:
1376 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1377 }
1378
1379 if (!(target->flags & LYS_CONFIG_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001380 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "config",
1381 d->flags & LYS_CONFIG_W ? "config true" : "config false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001382 ret = LY_EVALID;
1383 goto cleanup;
1384 }
1385
1386 target->flags &= ~LYS_CONFIG_MASK;
1387 target->flags |= d->flags & LYS_CONFIG_MASK;
1388 }
1389
1390 /* [mandatory-stmt] */
1391 if (d->flags & LYS_MAND_MASK) {
1392 switch (target->nodetype) {
1393 case LYS_LEAF:
1394 case LYS_CHOICE:
1395 case LYS_ANYDATA:
1396 case LYS_ANYXML:
1397 break;
1398 default:
1399 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1400 }
1401
1402 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001403 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1404 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001405 ret = LY_EVALID;
1406 goto cleanup;
1407 }
1408
1409 target->flags &= ~LYS_MAND_MASK;
1410 target->flags |= d->flags & LYS_MAND_MASK;
1411 }
1412
1413 /* [min-elements-stmt] */
1414 if (d->flags & LYS_SET_MIN) {
1415 switch (target->nodetype) {
1416 case LYS_LEAFLIST:
1417 num = &((struct lysp_node_leaflist *)target)->min;
1418 break;
1419 case LYS_LIST:
1420 num = &((struct lysp_node_list *)target)->min;
1421 break;
1422 default:
1423 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1424 }
1425
1426 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001427 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001428 ret = LY_EVALID;
1429 goto cleanup;
1430 }
1431
1432 *num = d->min;
1433 }
1434
1435 /* [max-elements-stmt] */
1436 if (d->flags & LYS_SET_MAX) {
1437 switch (target->nodetype) {
1438 case LYS_LEAFLIST:
1439 num = &((struct lysp_node_leaflist *)target)->max;
1440 break;
1441 case LYS_LIST:
1442 num = &((struct lysp_node_list *)target)->max;
1443 break;
1444 default:
1445 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1446 }
1447
1448 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001449 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001450 ret = LY_EVALID;
1451 goto cleanup;
1452 }
1453
1454 *num = d->max;
1455 }
1456
1457cleanup:
1458 return ret;
1459}
1460
1461/**
Michal Vasko193dacd2022-10-13 08:43:05 +02001462 * @brief Apply deviation with all its deviates.
1463 *
1464 * @param[in] ctx Compile context.
1465 * @param[in] dev Deviation to apply.
1466 * @param[in] dev_pmod Local module of the deviation.
1467 * @param[in,out] target Deviation target.
1468 * @return LY_ERR value.
1469 */
1470static LY_ERR
1471lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const struct lysp_module *dev_pmod,
1472 struct lysp_node *target)
1473{
1474 LY_ERR ret = LY_SUCCESS;
1475 struct lys_module *orig_mod = ctx->cur_mod;
1476 struct lysp_module *orig_pmod = ctx->pmod;
1477 char orig_path[LYSC_CTX_BUFSIZE];
1478 struct lysp_deviate *d;
1479
1480 /* clear path and set modules */
1481 strcpy(orig_path, ctx->path);
1482 ctx->path_len = 1;
1483 ctx->cur_mod = dev_pmod->mod;
1484 ctx->pmod = (struct lysp_module *)dev_pmod;
1485
1486 /* generate correct path */
1487 lysc_update_path(ctx, NULL, "{deviation}");
1488 lysc_update_path(ctx, NULL, dev->nodeid);
1489
1490 LY_LIST_FOR(dev->deviates, d) {
1491 switch (d->mod) {
1492 case LYS_DEV_ADD:
1493 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, target);
1494 break;
1495 case LYS_DEV_DELETE:
1496 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, target);
1497 break;
1498 case LYS_DEV_REPLACE:
1499 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, target);
1500 break;
1501 default:
1502 LOGINT(ctx->ctx);
1503 ret = LY_EINT;
1504 }
1505 LY_CHECK_GOTO(ret, cleanup);
1506 }
1507
1508 /* deviation extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +01001509 DUP_EXTS(ctx->ctx, dev_pmod, target, lyplg_ext_nodetype2stmt(target->nodetype), dev->exts, target->exts, lysp_ext_dup);
Michal Vasko193dacd2022-10-13 08:43:05 +02001510
1511cleanup:
1512 ctx->cur_mod = orig_mod;
1513 ctx->pmod = orig_pmod;
1514
1515 strcpy(ctx->path, orig_path);
1516 ctx->path_len = strlen(ctx->path);
1517 return ret;
1518}
1519
1520/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001521 * @brief Check whether a compiled node matches a single schema nodeid name test.
1522 *
1523 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1524 * @param[in] mod Expected module.
1525 * @param[in] name Expected name.
1526 * @param[in] name_len Length of @p name.
1527 * @return Whether it is a match or not.
1528 */
1529static ly_bool
1530lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1531 size_t name_len)
1532{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001533 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001534 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001535 return 0;
1536 }
1537
1538 /* compare names */
Michal Vasko544e58a2021-01-28 14:33:41 +01001539 if (ly_strncmp((*node)->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001540 return 0;
1541 }
1542
Michal Vasko2a668712020-10-21 11:48:09 +02001543 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001544 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001545
1546 return 1;
1547}
1548
1549/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001550 * @brief Check whether a compiled ext instance matches a single schema nodeid name test.
1551 *
1552 * @param[in,out] ext Compiled ext instance to consider. On a match it is zeroed to not match again.
1553 * @param[in] mod Expected module.
1554 * @param[in] name Expected name.
1555 * @param[in] name_len Length of @p name.
1556 * @return Whether it is a match or not.
1557 */
1558static ly_bool
1559lysp_schema_nodeid_match_ext(const struct lysc_ext_instance **ext, const struct lys_module *mod, const char *name,
1560 size_t name_len)
1561{
1562 /* compare with the module */
1563 if ((*ext)->module != mod) {
1564 return 0;
1565 }
1566
1567 /* compare names (argument) */
1568 if (ly_strncmp((*ext)->argument, name, name_len)) {
1569 return 0;
1570 }
1571
1572 /* zero */
1573 *ext = NULL;
1574
1575 return 1;
1576}
1577
1578/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001579 * @brief Check whether a node matches specific schema nodeid.
1580 *
1581 * @param[in] exp Parsed nodeid to match.
1582 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001583 * @param[in] exp_ext Extension instance in which @p exp is defined, it means it targets an extension instance.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001584 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1585 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1586 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1587 * @param[in] pnode_mod Compiled @p pnode to-be module.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001588 * @param[in] pnode_ext Extension instance in which @p pnode is defined.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001589 * @return Whether it is a match or not.
1590 */
1591static ly_bool
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001592lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod,
1593 const struct lysp_ext_instance *exp_ext, const struct lysc_node *ctx_node, const struct lysc_node *parent,
1594 const struct lysp_node *pnode, const struct lys_module *pnode_mod, const struct lysc_ext_instance *pnode_ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001595{
1596 uint32_t i;
1597 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001598 const char *name = NULL;
1599 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001600
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001601 if (exp_ext && !pnode_ext) {
1602 /* extension instance augment and standard node, will never match */
1603 return 0;
1604 } else if (!exp_ext && pnode_ext) {
1605 /* standard augment and extension instance node, will never match */
1606 return 0;
1607 }
1608
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001609 /* compare last node in the node ID */
1610 i = exp->used - 1;
1611
1612 /* get exp node ID module */
1613 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name, &name_len);
1614 assert(mod);
1615
1616 if (pnode) {
1617 /* compare on the last parsed-only node */
Radek Krejci2d5f6df2021-01-28 14:00:13 +01001618 if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001619 return 0;
1620 }
1621 } else {
1622 /* using parent directly */
1623 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1624 return 0;
1625 }
1626 }
1627
1628 /* now compare all the compiled parents */
1629 while (i > 1) {
1630 i -= 2;
1631 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1632
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001633 if (!parent && !pnode_ext) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001634 /* no more parents but path continues */
1635 return 0;
1636 }
1637
1638 /* get exp node ID module */
1639 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1640 &name_len);
1641 assert(mod);
1642
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001643 if (parent) {
1644 /* compare with the parent */
1645 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1646 return 0;
1647 }
1648 } else {
1649 /* compare with the ext instance */
1650 if (!lysp_schema_nodeid_match_ext(&pnode_ext, mod, name, name_len)) {
1651 return 0;
1652 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001653 }
1654 }
1655
1656 if (ctx_node && (ctx_node != parent)) {
1657 /* descendant path has not finished in the context node */
1658 return 0;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001659 } else if (!ctx_node && (parent || pnode_ext)) {
1660 /* some parent/extension was not matched */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001661 return 0;
1662 }
1663
1664 return 1;
1665}
1666
1667void
1668lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1669{
1670 if (aug) {
1671 lyxp_expr_free(ctx, aug->nodeid);
1672
1673 free(aug);
1674 }
1675}
1676
1677void
1678lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1679{
1680 if (dev) {
1681 lyxp_expr_free(ctx, dev->nodeid);
1682 LY_ARRAY_FREE(dev->devs);
1683 LY_ARRAY_FREE(dev->dev_pmods);
1684
1685 free(dev);
1686 }
1687}
1688
1689void
1690lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1691{
1692 if (rfn) {
1693 lyxp_expr_free(ctx, rfn->nodeid);
1694 LY_ARRAY_FREE(rfn->rfns);
1695
1696 free(rfn);
1697 }
1698}
1699
1700void
Michal Vaskoc636ea42022-09-16 10:20:31 +02001701lysp_dev_node_free(struct lysc_ctx *cctx, struct lysp_node *dev_pnode)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001702{
1703 if (!dev_pnode) {
1704 return;
1705 }
1706
1707 switch (dev_pnode->nodetype) {
1708 case LYS_CONTAINER:
1709 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001710 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1711 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001712 break;
1713 case LYS_LIST:
1714 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001715 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1716 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001717 break;
1718 case LYS_CHOICE:
1719 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1720 break;
1721 case LYS_CASE:
1722 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1723 break;
1724 case LYS_LEAF:
1725 case LYS_LEAFLIST:
1726 case LYS_ANYXML:
1727 case LYS_ANYDATA:
1728 /* no children */
1729 break;
1730 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001731 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001732 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001733 case LYS_RPC:
1734 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001735 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1736 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001737 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001738 case LYS_INPUT:
1739 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001740 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001741 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001742 free(dev_pnode);
1743 return;
1744 default:
Michal Vaskoc636ea42022-09-16 10:20:31 +02001745 LOGINT(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001746 return;
1747 }
1748
Michal Vaskoc636ea42022-09-16 10:20:31 +02001749 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001750}
1751
1752LY_ERR
1753lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1754 struct lysp_node **dev_pnode, ly_bool *not_supported)
1755{
1756 LY_ERR ret = LY_SUCCESS;
1757 uint32_t i;
1758 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001759 struct lysc_refine *rfn;
1760 struct lysc_deviation *dev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001761
1762 *dev_pnode = NULL;
1763 *not_supported = 0;
1764
Michal Vaskoee057572022-05-26 08:31:52 +02001765 for (i = 0; i < ctx->uses_rfns.count; ) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001766 rfn = ctx->uses_rfns.objs[i];
1767
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001768 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, NULL, rfn->nodeid_ctx_node, parent, pnode,
1769 ctx->cur_mod, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001770 /* not our target node */
Michal Vaskoee057572022-05-26 08:31:52 +02001771 ++i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001772 continue;
1773 }
1774
1775 if (!*dev_pnode) {
1776 /* first refine on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001777 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001778 }
1779
1780 /* apply all the refines by changing (the copy of) the parsed node */
1781 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001782 LY_CHECK_GOTO(ret = lys_apply_refine(ctx, rfn->rfns[u], rfn->nodeid_pmod, *dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001783 }
1784
1785 /* refine was applied, remove it */
1786 lysc_refine_free(ctx->ctx, rfn);
1787 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1788
Michal Vaskoee057572022-05-26 08:31:52 +02001789 /* refines use relative paths so more may apply to a single node */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001790 }
1791
1792 for (i = 0; i < ctx->devs.count; ++i) {
1793 dev = ctx->devs.objs[i];
1794
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001795 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, NULL, parent, pnode, ctx->cur_mod, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001796 /* not our target node */
1797 continue;
1798 }
1799
1800 if (dev->not_supported) {
1801 /* it is not supported, no more deviations */
1802 *not_supported = 1;
1803 goto dev_applied;
1804 }
1805
1806 if (!*dev_pnode) {
1807 /* first deviation on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001808 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001809 }
1810
1811 /* apply all the deviates by changing (the copy of) the parsed node */
1812 LY_ARRAY_FOR(dev->devs, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001813 LY_CHECK_GOTO(ret = lys_apply_deviation(ctx, dev->devs[u], dev->dev_pmods[u], *dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001814 }
1815
1816dev_applied:
1817 /* deviation was applied, remove it */
1818 lysc_deviation_free(ctx->ctx, dev);
1819 ly_set_rm_index(&ctx->devs, i, NULL);
1820
1821 /* all the deviations for one target node are in one structure, we are done */
1822 break;
1823 }
1824
1825cleanup:
1826 if (ret) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001827 lysp_dev_node_free(ctx, *dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001828 *dev_pnode = NULL;
1829 *not_supported = 0;
1830 }
1831 return ret;
1832}
1833
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001834/**
1835 * @brief Compile augment children.
1836 *
1837 * @param[in] ctx Compile context.
1838 * @param[in] aug_when Parsed augment when to inherit.
1839 * @param[in] aug_flags Parsed augment flags.
1840 * @param[in] child First augment child to compile.
1841 * @param[in] target Target node of the augment.
1842 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
1843 * @return LY_SUCCESS on success.
1844 * @return LY_EVALID on failure.
1845 */
1846static LY_ERR
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001847lys_compile_augment_children(struct lysc_ctx *ctx, struct lysp_when *aug_when, uint16_t aug_flags, struct lysp_node *child,
Michal Vaskoa084fa32022-05-16 11:32:58 +02001848 struct lysc_node *target, ly_bool child_unres_disabled)
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001849{
1850 LY_ERR rc = LY_SUCCESS;
1851 struct lysp_node *pnode;
1852 struct lysc_node *node;
1853 struct lysc_when *when_shared = NULL;
1854 ly_bool enabled, allow_mand = 0;
1855 struct ly_set child_set = {0};
1856 uint32_t i, opt_prev = ctx->compile_opts;
1857
1858 /* check for mandatory nodes
1859 * - new cases augmenting some choice can have mandatory nodes
1860 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1861 */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001862 if (aug_when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001863 allow_mand = 1;
1864 }
1865
1866 LY_LIST_FOR(child, pnode) {
1867 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1868 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1869 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1870 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1871 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1872 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1873 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1874 rc = LY_EVALID;
1875 goto cleanup;
1876 }
1877
1878 /* compile the children */
1879 if (target->nodetype == LYS_CHOICE) {
1880 LY_CHECK_GOTO(rc = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1881 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1882 if (target->nodetype == LYS_INPUT) {
1883 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
1884 } else {
1885 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
1886 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001887 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001888 } else {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001889 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001890 }
1891
1892 /* eval if-features again for the rest of this node processing */
1893 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1894 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001895 ctx->compile_opts |= LYS_COMPILE_DISABLED;
1896 }
1897
1898 /* since the augment node is not present in the compiled tree, we need to pass some of its
1899 * statements to all its children */
1900 for (i = 0; i < child_set.count; ++i) {
1901 node = child_set.snodes[i];
1902 if (!allow_mand && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1903 node->flags &= ~LYS_MAND_TRUE;
1904 lys_compile_mandatory_parents(target, 0);
1905 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
1906 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
1907 node->name);
1908 rc = LY_EVALID;
1909 goto cleanup;
1910 }
1911
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001912 if (aug_when) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001913 /* pass augment's when to all the children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001914 rc = lys_compile_when(ctx, aug_when, aug_flags, target, lysc_data_node(target), node, &when_shared);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001915 LY_CHECK_GOTO(rc, cleanup);
1916 }
1917
Michal Vaskoa084fa32022-05-16 11:32:58 +02001918 if (child_unres_disabled) {
Michal Vaskoad0980a2022-05-09 11:43:47 +02001919 /* child is disabled by the augment if-features */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001920 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
1921 }
1922 }
1923
1924 /* next iter */
1925 ly_set_erase(&child_set, NULL);
1926 ctx->compile_opts = opt_prev;
1927 }
1928
1929cleanup:
1930 ly_set_erase(&child_set, NULL);
1931 ctx->compile_opts = opt_prev;
1932 return rc;
1933}
1934
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001935/**
1936 * @brief Compile the parsed augment connecting it into its target.
1937 *
1938 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1939 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1940 * are already implemented and compiled.
1941 *
1942 * @param[in] ctx Compile context.
1943 * @param[in] aug_p Parsed augment to compile.
1944 * @param[in] target Target node of the augment.
1945 * @return LY_SUCCESS on success.
1946 * @return LY_EVALID on failure.
1947 */
1948static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001949lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001950{
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001951 LY_ERR rc = LY_SUCCESS;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001952 ly_bool enabled, child_unres_disabled = 0;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001953 uint32_t opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001954
Michal Vasko95f736c2022-06-08 12:03:31 +02001955 assert(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
1956
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001957 /* nodetype checks */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001958 if (aug_p->actions && !lysc_node_actions_p(target)) {
1959 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1960 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
1961 lys_nodetype2str(target->nodetype), aug_p->actions->name);
1962 rc = LY_EVALID;
1963 goto cleanup;
1964 }
1965 if (aug_p->notifs && !lysc_node_notifs_p(target)) {
1966 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1967 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
1968 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
1969 rc = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001970 goto cleanup;
1971 }
1972
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001973 /* augment if-features */
1974 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, aug_p->iffeatures, &enabled), cleanup);
1975 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001976 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001977 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001978 }
1979
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001980 /* augment children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001981 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, aug_p->child, target, child_unres_disabled);
1982 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001983
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001984 /* augment actions */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001985 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->actions, target,
1986 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001987 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001988
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001989 /* augment notifications */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001990 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->notifs, target,
1991 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001992 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001993
Michal Vasko193dacd2022-10-13 08:43:05 +02001994 /* compile extensions into the target */
1995 COMPILE_EXTS_GOTO(ctx, aug_p->exts, target->exts, target, rc, cleanup);
1996
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001997cleanup:
Michal Vasko7c565922021-06-10 14:58:27 +02001998 ctx->compile_opts = opt_prev;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001999 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002000}
2001
2002LY_ERR
2003lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
2004{
2005 LY_ERR ret = LY_SUCCESS;
2006 struct lys_module *orig_mod = ctx->cur_mod;
2007 struct lysp_module *orig_pmod = ctx->pmod;
2008 uint32_t i;
2009 char orig_path[LYSC_CTX_BUFSIZE];
2010 struct lysc_augment *aug;
2011
2012 /* uses augments */
2013 for (i = 0; i < ctx->uses_augs.count; ) {
2014 aug = ctx->uses_augs.objs[i];
2015
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002016 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->ext, aug->nodeid_ctx_node, node, NULL, NULL,
2017 ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002018 /* not our target node */
2019 ++i;
2020 continue;
2021 }
2022
Michal Vaskob8df5762021-01-12 15:15:53 +01002023 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002024 lysc_update_path(ctx, NULL, "{augment}");
2025 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01002026 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01002027
2028 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002029 ret = lys_compile_augment(ctx, aug->aug_p, node);
2030 lysc_update_path(ctx, NULL, NULL);
2031 lysc_update_path(ctx, NULL, NULL);
2032 LY_CHECK_GOTO(ret, cleanup);
2033
Michal Vaskoc75f2042021-06-08 14:57:03 +02002034 /* augment was applied, remove it (index and the whole set may have changed because other augments
2035 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002036 ly_set_rm(&ctx->uses_augs, aug, NULL);
2037 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002038 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002039 }
2040
2041 /* top-level augments */
2042 for (i = 0; i < ctx->augs.count; ) {
2043 aug = ctx->augs.objs[i];
2044
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002045 if (!lysp_schema_nodeid_match(aug->nodeid, aug->aug_pmod, aug->ext, NULL, node, NULL, NULL, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002046 /* not our target node */
2047 ++i;
2048 continue;
2049 }
2050
Michal Vaskob8df5762021-01-12 15:15:53 +01002051 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002052 strcpy(orig_path, ctx->path);
2053 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002054 ctx->cur_mod = aug->aug_pmod->mod;
2055 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02002056 lysc_update_path(ctx, NULL, "{augment}");
2057 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01002058
2059 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002060 ret = lys_compile_augment(ctx, aug->aug_p, node);
2061 strcpy(ctx->path, orig_path);
2062 ctx->path_len = strlen(ctx->path);
2063 LY_CHECK_GOTO(ret, cleanup);
2064
2065 /* augment was applied, remove it */
2066 ly_set_rm(&ctx->augs, aug, NULL);
2067 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002068 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002069 }
2070
2071cleanup:
2072 ctx->cur_mod = orig_mod;
2073 ctx->pmod = orig_pmod;
2074 return ret;
2075}
2076
2077/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002078 * @brief Prepare an absolute-nodeid augment to be applied during data nodes compilation.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002079 *
2080 * @param[in] ctx Compile context.
2081 * @param[in] aug_p Parsed augment to be applied.
2082 * @param[in] pmod Both current and prefix module for @p aug_p.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002083 * @param[in] ext Extension instance in case @p aug_p is defined in one.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002084 * @return LY_ERR value.
2085 */
2086static LY_ERR
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002087lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, const struct lysp_module *pmod,
2088 const struct lysp_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002089{
2090 LY_ERR ret = LY_SUCCESS;
2091 struct lyxp_expr *exp = NULL;
2092 struct lysc_augment *aug;
2093 const struct lys_module *mod;
2094
2095 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2096 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
2097 LY_CHECK_GOTO(ret, cleanup);
2098
2099 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2100 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2101 if (mod != ctx->cur_mod) {
2102 /* augment for another module, ignore */
2103 goto cleanup;
2104 }
2105
2106 /* allocate new compiled augment and store it in the set */
2107 aug = calloc(1, sizeof *aug);
2108 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2109 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2110
2111 aug->nodeid = exp;
2112 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002113 aug->aug_pmod = pmod;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002114 aug->ext = ext;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002115 aug->aug_p = aug_p;
2116
2117cleanup:
2118 lyxp_expr_free(ctx->ctx, exp);
2119 return ret;
2120}
2121
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002122/**
2123 * @brief Prepare all top-level augments and extension instance augments to be applied during data nodes compilation.
2124 *
2125 * @param[in] ctx Compile context.
2126 * @param[in] pmod Parsed mod to use.
2127 * @return LY_ERR value.
2128 */
2129static LY_ERR
2130lys_precompile_own_augments_mod(struct lysc_ctx *ctx, const struct lysp_module *pmod)
2131{
2132 LY_ARRAY_COUNT_TYPE u, v;
2133 struct lysp_node_augment *aug_p;
2134
2135 /* module */
2136 LY_LIST_FOR(pmod->augments, aug_p) {
2137 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, NULL));
2138 }
2139
2140 /* parsed extension instances */
2141 LY_ARRAY_FOR(pmod->exts, u) {
2142 aug_p = NULL;
2143 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2144 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2145 aug_p = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2146 break;
2147 }
2148 }
2149 if (!aug_p) {
2150 continue;
2151 }
2152
2153 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, &pmod->exts[u]));
2154 }
2155
2156 return LY_SUCCESS;
2157}
2158
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002159LY_ERR
2160lys_precompile_own_augments(struct lysc_ctx *ctx)
2161{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002162 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002163 const struct lys_module *aug_mod;
2164 const struct lysp_module *submod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002165
2166 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002167 aug_mod = ctx->cur_mod->augmented_by[u];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002168
2169 /* collect all module augments */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002170 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002171
2172 /* collect all submodules augments */
2173 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002174 submod = (struct lysp_module *)aug_mod->parsed->includes[v].submodule;
2175
2176 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, submod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002177 }
2178 }
2179
2180 return LY_SUCCESS;
2181}
2182
2183/**
2184 * @brief Prepare a deviation to be applied during data nodes compilation.
2185 *
2186 * @param[in] ctx Compile context.
2187 * @param[in] dev_p Parsed deviation to be applied.
2188 * @param[in] pmod Both current and prefix module for @p dev_p.
2189 * @return LY_ERR value.
2190 */
2191static LY_ERR
2192lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2193{
2194 LY_ERR ret = LY_SUCCESS;
2195 struct lysc_deviation *dev = NULL;
2196 struct lyxp_expr *exp = NULL;
2197 struct lysp_deviation **new_dev;
2198 const struct lys_module *mod;
2199 const struct lysp_module **new_dev_pmod;
2200 uint32_t i;
2201
2202 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2203 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2204 LY_CHECK_GOTO(ret, cleanup);
2205
2206 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2207 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2208 if (mod != ctx->cur_mod) {
2209 /* deviation for another module, ignore */
2210 goto cleanup;
2211 }
2212
2213 /* try to find the node in already compiled deviations */
2214 for (i = 0; i < ctx->devs.count; ++i) {
2215 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2216 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2217 dev = ctx->devs.objs[i];
2218 break;
2219 }
2220 }
2221
2222 if (!dev) {
2223 /* allocate new compiled deviation */
2224 dev = calloc(1, sizeof *dev);
2225 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2226 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2227
2228 dev->nodeid = exp;
2229 exp = NULL;
2230 }
2231
2232 /* add new parsed deviation structure */
2233 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2234 *new_dev = dev_p;
2235 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2236 *new_dev_pmod = pmod;
2237
2238cleanup:
2239 lyxp_expr_free(ctx->ctx, exp);
2240 return ret;
2241}
2242
2243LY_ERR
2244lys_precompile_own_deviations(struct lysc_ctx *ctx)
2245{
2246 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002247 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002248 const struct lys_module *dev_mod;
2249 struct lysc_deviation *dev;
2250 struct lysp_deviate *d;
2251 int not_supported;
2252 uint32_t i;
2253
2254 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2255 dev_mod = ctx->cur_mod->deviated_by[u];
2256
2257 /* compile all module deviations */
2258 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2259 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2260 }
2261
2262 /* compile all submodules deviations */
2263 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2264 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2265 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2266 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2267 }
2268 }
2269 }
2270
2271 /* set not-supported flags for all the deviations */
2272 for (i = 0; i < ctx->devs.count; ++i) {
2273 dev = ctx->devs.objs[i];
2274 not_supported = 0;
2275
2276 LY_ARRAY_FOR(dev->devs, u) {
2277 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2278 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2279 not_supported = 1;
2280 break;
2281 }
2282 }
2283 if (not_supported) {
2284 break;
2285 }
2286 }
2287 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002288 orig_cur_mod = ctx->cur_mod;
2289 ctx->cur_mod = dev->dev_pmods[u]->mod;
2290 lysc_update_path(ctx, NULL, "{deviation}");
2291 lysc_update_path(ctx, NULL, dev->nodeid->expr);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002292 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002293 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002294 lysc_update_path(ctx, NULL, NULL);
2295 lysc_update_path(ctx, NULL, NULL);
2296 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002297 return LY_EVALID;
2298 }
2299
2300 dev->not_supported = not_supported;
2301 }
2302
2303 return LY_SUCCESS;
2304}
2305
2306/**
2307 * @brief Add a module reference into an array, checks for duplicities.
2308 *
2309 * @param[in] ctx Compile context.
2310 * @param[in] mod Module reference to add.
2311 * @param[in,out] mod_array Module sized array to add to.
2312 * @return LY_ERR value.
2313 */
2314static LY_ERR
2315lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2316{
2317 LY_ARRAY_COUNT_TYPE u;
2318 struct lys_module **new_mod;
2319
2320 LY_ARRAY_FOR(*mod_array, u) {
2321 if ((*mod_array)[u] == mod) {
2322 /* already there */
2323 return LY_EEXIST;
2324 }
2325 }
2326
2327 /* add the new module ref */
2328 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2329 *new_mod = mod;
2330
2331 return LY_SUCCESS;
2332}
2333
Michal Vasko1ccbf542021-04-19 11:35:00 +02002334/**
2335 * @brief Check whether all modules in a set are implemented.
2336 *
2337 * @param[in] mod_set Module set to check.
2338 * @return Whether all modules are implemented or not.
2339 */
2340static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002341lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002342{
2343 uint32_t i;
2344 const struct lys_module *mod;
2345
2346 for (i = 0; i < mod_set->count; ++i) {
2347 mod = mod_set->objs[i];
2348 if (!mod->implemented) {
2349 return 0;
2350 }
2351 }
2352
2353 return 1;
2354}
2355
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002356/**
2357 * @brief Add references to target modules of top-level augments, deviations, and augments in extension instances
2358 * in a module and all its submodules.
2359 *
2360 * @param[in] pmod Module to process.
2361 * @param[in,out] mod_set Module set to add referenced modules into.
2362 * @return LY_SUCCESS on success.
2363 * @return LY_ERR on error.
2364 */
2365static LY_ERR
2366lys_precompile_mod_augments_deviations(struct lysp_module *pmod, struct ly_set *mod_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002367{
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002368 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002369 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002370 struct lysc_ctx ctx;
Michal Vasko65333882021-06-10 14:12:16 +02002371 struct lys_module *m;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002372 struct lysp_node_augment *aug;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002373 struct ly_set set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002374
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002375 LYSC_CTX_INIT_PMOD(ctx, pmod, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002376
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002377 LY_LIST_FOR(pmod->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002378 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002379 lysc_update_path(&ctx, NULL, "{augment}");
2380 lysc_update_path(&ctx, NULL, aug->nodeid);
2381 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2382 lysc_update_path(&ctx, NULL, NULL);
2383 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002384 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002385
Michal Vasko1ccbf542021-04-19 11:35:00 +02002386 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002387 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002388 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002389 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002390 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002391 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002392 }
2393
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002394 LY_ARRAY_FOR(pmod->deviations, u) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002395 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002396 lysc_update_path(&ctx, NULL, "{deviation}");
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002397 lysc_update_path(&ctx, NULL, pmod->deviations[u].nodeid);
2398 ret = lys_nodeid_mod_check(&ctx, pmod->deviations[u].nodeid, 1, &set, NULL, &m);
Michal Vasko65333882021-06-10 14:12:16 +02002399 lysc_update_path(&ctx, NULL, NULL);
2400 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002401 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002402
Michal Vasko1ccbf542021-04-19 11:35:00 +02002403 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002404 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002405 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002406 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002407 }
2408 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002409 }
2410
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002411 LY_ARRAY_FOR(pmod->exts, u) {
2412 aug = NULL;
2413 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2414 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2415 aug = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2416 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002417 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002418 }
2419 if (!aug) {
2420 continue;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002421 }
2422
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002423 /* get target module */
2424 lysc_update_path(&ctx, NULL, "{ext-augment}");
2425 lysc_update_path(&ctx, NULL, aug->nodeid);
2426 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2427 lysc_update_path(&ctx, NULL, NULL);
2428 lysc_update_path(&ctx, NULL, NULL);
2429 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002430
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002431 /* add this module into the target module augmented_by, if not there and implemented */
2432 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
2433 !lys_precompile_mod_set_is_all_implemented(&set)) {
2434 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002435 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002436 ly_set_erase(&set, NULL);
2437 }
2438
2439cleanup:
2440 ly_set_erase(&set, NULL);
2441 return ret;
2442}
2443
2444LY_ERR
2445lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
2446{
2447 LY_ERR ret = LY_SUCCESS, r;
2448 LY_ARRAY_COUNT_TYPE u;
2449 struct lys_module *m;
2450 struct lysp_module *submod;
2451 const char **imp_f, *all_f[] = {"*", NULL};
2452 uint32_t i;
2453 struct ly_set mod_set = {0};
2454
2455 /* module */
2456 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(mod->parsed, &mod_set), cleanup);
2457
2458 /* submodules */
2459 LY_ARRAY_FOR(mod->parsed->includes, u) {
2460 submod = (struct lysp_module *)mod->parsed->includes[u].submodule;
2461 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(submod, &mod_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002462 }
2463
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002464 for (i = 0; i < mod_set.count; ++i) {
2465 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002466
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002467 if (m == mod) {
2468 /* will be applied normally later */
2469 continue;
2470 }
2471
2472 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2473 * not compiled yet and marked for compilation */
2474
2475 if (!m->implemented) {
2476 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002477 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2478 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002479 if (r == LY_ERECOMPILE) {
2480 /* implement all the modules right away to save possible later recompilation */
2481 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002482 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002483 } else if (r) {
2484 /* error */
2485 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002486 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002487 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002488 } else if (m->compiled) {
2489 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2490 m->to_compile = 1;
2491 ret = LY_ERECOMPILE;
2492 continue;
2493 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002494 }
2495
Michal Vasko1ccbf542021-04-19 11:35:00 +02002496cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +02002497 ly_set_erase(&mod_set, NULL);
2498 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002499}
2500
2501void
2502lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2503{
2504 uint32_t i;
2505 LY_ARRAY_COUNT_TYPE u, count;
2506 struct lys_module *m;
2507
2508 for (i = 0; i < ctx->list.count; ++i) {
2509 m = ctx->list.objs[i];
2510
2511 if (m->augmented_by) {
2512 count = LY_ARRAY_COUNT(m->augmented_by);
2513 for (u = 0; u < count; ++u) {
2514 if (m->augmented_by[u] == mod) {
2515 /* keep the order */
2516 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002517 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002518 }
2519 LY_ARRAY_DECREMENT(m->augmented_by);
2520 break;
2521 }
2522 }
2523 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2524 LY_ARRAY_FREE(m->augmented_by);
2525 m->augmented_by = NULL;
2526 }
2527 }
2528
2529 if (m->deviated_by) {
2530 count = LY_ARRAY_COUNT(m->deviated_by);
2531 for (u = 0; u < count; ++u) {
2532 if (m->deviated_by[u] == mod) {
2533 /* keep the order */
2534 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002535 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002536 }
2537 LY_ARRAY_DECREMENT(m->deviated_by);
2538 break;
2539 }
2540 }
2541 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2542 LY_ARRAY_FREE(m->deviated_by);
2543 m->deviated_by = NULL;
2544 }
2545 }
2546 }
2547}