blob: 8b570f609f1af7f629a47771ca96b04a168ce30c [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
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001379 target->flags &= ~LYS_CONFIG_MASK;
1380 target->flags |= d->flags & LYS_CONFIG_MASK;
1381 }
1382
1383 /* [mandatory-stmt] */
1384 if (d->flags & LYS_MAND_MASK) {
1385 switch (target->nodetype) {
1386 case LYS_LEAF:
1387 case LYS_CHOICE:
1388 case LYS_ANYDATA:
1389 case LYS_ANYXML:
1390 break;
1391 default:
1392 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1393 }
1394
1395 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001396 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1397 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001398 ret = LY_EVALID;
1399 goto cleanup;
1400 }
1401
1402 target->flags &= ~LYS_MAND_MASK;
1403 target->flags |= d->flags & LYS_MAND_MASK;
1404 }
1405
1406 /* [min-elements-stmt] */
1407 if (d->flags & LYS_SET_MIN) {
1408 switch (target->nodetype) {
1409 case LYS_LEAFLIST:
1410 num = &((struct lysp_node_leaflist *)target)->min;
1411 break;
1412 case LYS_LIST:
1413 num = &((struct lysp_node_list *)target)->min;
1414 break;
1415 default:
1416 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1417 }
1418
1419 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001420 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001421 ret = LY_EVALID;
1422 goto cleanup;
1423 }
1424
1425 *num = d->min;
1426 }
1427
1428 /* [max-elements-stmt] */
1429 if (d->flags & LYS_SET_MAX) {
1430 switch (target->nodetype) {
1431 case LYS_LEAFLIST:
1432 num = &((struct lysp_node_leaflist *)target)->max;
1433 break;
1434 case LYS_LIST:
1435 num = &((struct lysp_node_list *)target)->max;
1436 break;
1437 default:
1438 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1439 }
1440
1441 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001442 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001443 ret = LY_EVALID;
1444 goto cleanup;
1445 }
1446
1447 *num = d->max;
1448 }
1449
1450cleanup:
1451 return ret;
1452}
1453
1454/**
Michal Vasko193dacd2022-10-13 08:43:05 +02001455 * @brief Apply deviation with all its deviates.
1456 *
1457 * @param[in] ctx Compile context.
1458 * @param[in] dev Deviation to apply.
1459 * @param[in] dev_pmod Local module of the deviation.
1460 * @param[in,out] target Deviation target.
1461 * @return LY_ERR value.
1462 */
1463static LY_ERR
1464lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const struct lysp_module *dev_pmod,
1465 struct lysp_node *target)
1466{
1467 LY_ERR ret = LY_SUCCESS;
1468 struct lys_module *orig_mod = ctx->cur_mod;
1469 struct lysp_module *orig_pmod = ctx->pmod;
1470 char orig_path[LYSC_CTX_BUFSIZE];
1471 struct lysp_deviate *d;
1472
1473 /* clear path and set modules */
1474 strcpy(orig_path, ctx->path);
1475 ctx->path_len = 1;
1476 ctx->cur_mod = dev_pmod->mod;
1477 ctx->pmod = (struct lysp_module *)dev_pmod;
1478
1479 /* generate correct path */
1480 lysc_update_path(ctx, NULL, "{deviation}");
1481 lysc_update_path(ctx, NULL, dev->nodeid);
1482
1483 LY_LIST_FOR(dev->deviates, d) {
1484 switch (d->mod) {
1485 case LYS_DEV_ADD:
1486 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, target);
1487 break;
1488 case LYS_DEV_DELETE:
1489 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, target);
1490 break;
1491 case LYS_DEV_REPLACE:
1492 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, target);
1493 break;
1494 default:
1495 LOGINT(ctx->ctx);
1496 ret = LY_EINT;
1497 }
1498 LY_CHECK_GOTO(ret, cleanup);
1499 }
1500
1501 /* deviation extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +01001502 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 +02001503
1504cleanup:
1505 ctx->cur_mod = orig_mod;
1506 ctx->pmod = orig_pmod;
1507
1508 strcpy(ctx->path, orig_path);
1509 ctx->path_len = strlen(ctx->path);
1510 return ret;
1511}
1512
1513/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001514 * @brief Check whether a compiled node matches a single schema nodeid name test.
1515 *
1516 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1517 * @param[in] mod Expected module.
1518 * @param[in] name Expected name.
1519 * @param[in] name_len Length of @p name.
1520 * @return Whether it is a match or not.
1521 */
1522static ly_bool
1523lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1524 size_t name_len)
1525{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001526 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001527 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001528 return 0;
1529 }
1530
1531 /* compare names */
Michal Vasko544e58a2021-01-28 14:33:41 +01001532 if (ly_strncmp((*node)->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001533 return 0;
1534 }
1535
Michal Vasko2a668712020-10-21 11:48:09 +02001536 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001537 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001538
1539 return 1;
1540}
1541
1542/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001543 * @brief Check whether a compiled ext instance matches a single schema nodeid name test.
1544 *
1545 * @param[in,out] ext Compiled ext instance to consider. On a match it is zeroed to not match again.
1546 * @param[in] mod Expected module.
1547 * @param[in] name Expected name.
1548 * @param[in] name_len Length of @p name.
1549 * @return Whether it is a match or not.
1550 */
1551static ly_bool
1552lysp_schema_nodeid_match_ext(const struct lysc_ext_instance **ext, const struct lys_module *mod, const char *name,
1553 size_t name_len)
1554{
1555 /* compare with the module */
1556 if ((*ext)->module != mod) {
1557 return 0;
1558 }
1559
1560 /* compare names (argument) */
1561 if (ly_strncmp((*ext)->argument, name, name_len)) {
1562 return 0;
1563 }
1564
1565 /* zero */
1566 *ext = NULL;
1567
1568 return 1;
1569}
1570
1571/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001572 * @brief Check whether a node matches specific schema nodeid.
1573 *
1574 * @param[in] exp Parsed nodeid to match.
1575 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001576 * @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 +02001577 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1578 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1579 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1580 * @param[in] pnode_mod Compiled @p pnode to-be module.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001581 * @param[in] pnode_ext Extension instance in which @p pnode is defined.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001582 * @return Whether it is a match or not.
1583 */
1584static ly_bool
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001585lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod,
1586 const struct lysp_ext_instance *exp_ext, const struct lysc_node *ctx_node, const struct lysc_node *parent,
1587 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 +02001588{
1589 uint32_t i;
1590 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001591 const char *name = NULL;
1592 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001593
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001594 if (exp_ext && !pnode_ext) {
1595 /* extension instance augment and standard node, will never match */
1596 return 0;
1597 } else if (!exp_ext && pnode_ext) {
1598 /* standard augment and extension instance node, will never match */
1599 return 0;
1600 }
1601
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001602 /* compare last node in the node ID */
1603 i = exp->used - 1;
1604
1605 /* get exp node ID module */
1606 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);
1607 assert(mod);
1608
1609 if (pnode) {
1610 /* compare on the last parsed-only node */
Radek Krejci2d5f6df2021-01-28 14:00:13 +01001611 if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001612 return 0;
1613 }
1614 } else {
1615 /* using parent directly */
1616 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1617 return 0;
1618 }
1619 }
1620
1621 /* now compare all the compiled parents */
1622 while (i > 1) {
1623 i -= 2;
1624 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1625
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001626 if (!parent && !pnode_ext) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001627 /* no more parents but path continues */
1628 return 0;
1629 }
1630
1631 /* get exp node ID module */
1632 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1633 &name_len);
1634 assert(mod);
1635
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001636 if (parent) {
1637 /* compare with the parent */
1638 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1639 return 0;
1640 }
1641 } else {
1642 /* compare with the ext instance */
1643 if (!lysp_schema_nodeid_match_ext(&pnode_ext, mod, name, name_len)) {
1644 return 0;
1645 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001646 }
1647 }
1648
1649 if (ctx_node && (ctx_node != parent)) {
1650 /* descendant path has not finished in the context node */
1651 return 0;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001652 } else if (!ctx_node && (parent || pnode_ext)) {
1653 /* some parent/extension was not matched */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001654 return 0;
1655 }
1656
1657 return 1;
1658}
1659
1660void
1661lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1662{
1663 if (aug) {
1664 lyxp_expr_free(ctx, aug->nodeid);
1665
1666 free(aug);
1667 }
1668}
1669
1670void
1671lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1672{
1673 if (dev) {
1674 lyxp_expr_free(ctx, dev->nodeid);
1675 LY_ARRAY_FREE(dev->devs);
1676 LY_ARRAY_FREE(dev->dev_pmods);
1677
1678 free(dev);
1679 }
1680}
1681
1682void
1683lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1684{
1685 if (rfn) {
1686 lyxp_expr_free(ctx, rfn->nodeid);
1687 LY_ARRAY_FREE(rfn->rfns);
1688
1689 free(rfn);
1690 }
1691}
1692
1693void
Michal Vaskoc636ea42022-09-16 10:20:31 +02001694lysp_dev_node_free(struct lysc_ctx *cctx, struct lysp_node *dev_pnode)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001695{
1696 if (!dev_pnode) {
1697 return;
1698 }
1699
1700 switch (dev_pnode->nodetype) {
1701 case LYS_CONTAINER:
1702 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001703 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1704 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001705 break;
1706 case LYS_LIST:
1707 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001708 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1709 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001710 break;
1711 case LYS_CHOICE:
1712 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1713 break;
1714 case LYS_CASE:
1715 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1716 break;
1717 case LYS_LEAF:
1718 case LYS_LEAFLIST:
1719 case LYS_ANYXML:
1720 case LYS_ANYDATA:
1721 /* no children */
1722 break;
1723 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001724 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001725 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001726 case LYS_RPC:
1727 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001728 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1729 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001730 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001731 case LYS_INPUT:
1732 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001733 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001734 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001735 free(dev_pnode);
1736 return;
1737 default:
Michal Vaskoc636ea42022-09-16 10:20:31 +02001738 LOGINT(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001739 return;
1740 }
1741
Michal Vaskoc636ea42022-09-16 10:20:31 +02001742 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001743}
1744
1745LY_ERR
1746lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1747 struct lysp_node **dev_pnode, ly_bool *not_supported)
1748{
1749 LY_ERR ret = LY_SUCCESS;
1750 uint32_t i;
1751 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001752 struct lysc_refine *rfn;
1753 struct lysc_deviation *dev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001754
1755 *dev_pnode = NULL;
1756 *not_supported = 0;
1757
Michal Vaskoee057572022-05-26 08:31:52 +02001758 for (i = 0; i < ctx->uses_rfns.count; ) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001759 rfn = ctx->uses_rfns.objs[i];
1760
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001761 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, NULL, rfn->nodeid_ctx_node, parent, pnode,
1762 ctx->cur_mod, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001763 /* not our target node */
Michal Vaskoee057572022-05-26 08:31:52 +02001764 ++i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001765 continue;
1766 }
1767
1768 if (!*dev_pnode) {
1769 /* first refine on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001770 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001771 }
1772
1773 /* apply all the refines by changing (the copy of) the parsed node */
1774 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001775 LY_CHECK_GOTO(ret = lys_apply_refine(ctx, rfn->rfns[u], rfn->nodeid_pmod, *dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001776 }
1777
1778 /* refine was applied, remove it */
1779 lysc_refine_free(ctx->ctx, rfn);
1780 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1781
Michal Vaskoee057572022-05-26 08:31:52 +02001782 /* refines use relative paths so more may apply to a single node */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001783 }
1784
1785 for (i = 0; i < ctx->devs.count; ++i) {
1786 dev = ctx->devs.objs[i];
1787
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001788 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 +02001789 /* not our target node */
1790 continue;
1791 }
1792
1793 if (dev->not_supported) {
1794 /* it is not supported, no more deviations */
1795 *not_supported = 1;
1796 goto dev_applied;
1797 }
1798
1799 if (!*dev_pnode) {
1800 /* first deviation on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001801 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001802 }
1803
1804 /* apply all the deviates by changing (the copy of) the parsed node */
1805 LY_ARRAY_FOR(dev->devs, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001806 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 +02001807 }
1808
1809dev_applied:
1810 /* deviation was applied, remove it */
1811 lysc_deviation_free(ctx->ctx, dev);
1812 ly_set_rm_index(&ctx->devs, i, NULL);
1813
1814 /* all the deviations for one target node are in one structure, we are done */
1815 break;
1816 }
1817
1818cleanup:
1819 if (ret) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001820 lysp_dev_node_free(ctx, *dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001821 *dev_pnode = NULL;
1822 *not_supported = 0;
1823 }
1824 return ret;
1825}
1826
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001827/**
1828 * @brief Compile augment children.
1829 *
1830 * @param[in] ctx Compile context.
1831 * @param[in] aug_when Parsed augment when to inherit.
1832 * @param[in] aug_flags Parsed augment flags.
1833 * @param[in] child First augment child to compile.
1834 * @param[in] target Target node of the augment.
1835 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
1836 * @return LY_SUCCESS on success.
1837 * @return LY_EVALID on failure.
1838 */
1839static LY_ERR
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001840lys_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 +02001841 struct lysc_node *target, ly_bool child_unres_disabled)
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001842{
1843 LY_ERR rc = LY_SUCCESS;
1844 struct lysp_node *pnode;
1845 struct lysc_node *node;
1846 struct lysc_when *when_shared = NULL;
1847 ly_bool enabled, allow_mand = 0;
1848 struct ly_set child_set = {0};
1849 uint32_t i, opt_prev = ctx->compile_opts;
1850
1851 /* check for mandatory nodes
1852 * - new cases augmenting some choice can have mandatory nodes
1853 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1854 */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001855 if (aug_when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001856 allow_mand = 1;
1857 }
1858
1859 LY_LIST_FOR(child, pnode) {
1860 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1861 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1862 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1863 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1864 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1865 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1866 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1867 rc = LY_EVALID;
1868 goto cleanup;
1869 }
1870
1871 /* compile the children */
1872 if (target->nodetype == LYS_CHOICE) {
1873 LY_CHECK_GOTO(rc = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1874 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1875 if (target->nodetype == LYS_INPUT) {
1876 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
1877 } else {
1878 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
1879 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001880 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001881 } else {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001882 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001883 }
1884
1885 /* eval if-features again for the rest of this node processing */
1886 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1887 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001888 ctx->compile_opts |= LYS_COMPILE_DISABLED;
1889 }
1890
1891 /* since the augment node is not present in the compiled tree, we need to pass some of its
1892 * statements to all its children */
1893 for (i = 0; i < child_set.count; ++i) {
1894 node = child_set.snodes[i];
1895 if (!allow_mand && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1896 node->flags &= ~LYS_MAND_TRUE;
1897 lys_compile_mandatory_parents(target, 0);
1898 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
1899 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
1900 node->name);
1901 rc = LY_EVALID;
1902 goto cleanup;
1903 }
1904
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001905 if (aug_when) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001906 /* pass augment's when to all the children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001907 rc = lys_compile_when(ctx, aug_when, aug_flags, target, lysc_data_node(target), node, &when_shared);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001908 LY_CHECK_GOTO(rc, cleanup);
1909 }
1910
Michal Vaskoa084fa32022-05-16 11:32:58 +02001911 if (child_unres_disabled) {
Michal Vaskoad0980a2022-05-09 11:43:47 +02001912 /* child is disabled by the augment if-features */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001913 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
1914 }
1915 }
1916
1917 /* next iter */
1918 ly_set_erase(&child_set, NULL);
1919 ctx->compile_opts = opt_prev;
1920 }
1921
1922cleanup:
1923 ly_set_erase(&child_set, NULL);
1924 ctx->compile_opts = opt_prev;
1925 return rc;
1926}
1927
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001928/**
1929 * @brief Compile the parsed augment connecting it into its target.
1930 *
1931 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1932 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1933 * are already implemented and compiled.
1934 *
1935 * @param[in] ctx Compile context.
1936 * @param[in] aug_p Parsed augment to compile.
1937 * @param[in] target Target node of the augment.
1938 * @return LY_SUCCESS on success.
1939 * @return LY_EVALID on failure.
1940 */
1941static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001942lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001943{
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001944 LY_ERR rc = LY_SUCCESS;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001945 ly_bool enabled, child_unres_disabled = 0;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001946 uint32_t opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001947
Michal Vasko95f736c2022-06-08 12:03:31 +02001948 assert(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
1949
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001950 /* nodetype checks */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001951 if (aug_p->actions && !lysc_node_actions_p(target)) {
1952 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1953 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
1954 lys_nodetype2str(target->nodetype), aug_p->actions->name);
1955 rc = LY_EVALID;
1956 goto cleanup;
1957 }
1958 if (aug_p->notifs && !lysc_node_notifs_p(target)) {
1959 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1960 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
1961 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
1962 rc = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001963 goto cleanup;
1964 }
1965
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001966 /* augment if-features */
1967 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, aug_p->iffeatures, &enabled), cleanup);
1968 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001969 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001970 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001971 }
1972
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001973 /* augment children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001974 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, aug_p->child, target, child_unres_disabled);
1975 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001976
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001977 /* augment actions */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001978 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->actions, target,
1979 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001980 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001981
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001982 /* augment notifications */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001983 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->notifs, target,
1984 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001985 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001986
Michal Vasko193dacd2022-10-13 08:43:05 +02001987 /* compile extensions into the target */
1988 COMPILE_EXTS_GOTO(ctx, aug_p->exts, target->exts, target, rc, cleanup);
1989
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001990cleanup:
Michal Vasko7c565922021-06-10 14:58:27 +02001991 ctx->compile_opts = opt_prev;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001992 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001993}
1994
1995LY_ERR
1996lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
1997{
1998 LY_ERR ret = LY_SUCCESS;
1999 struct lys_module *orig_mod = ctx->cur_mod;
2000 struct lysp_module *orig_pmod = ctx->pmod;
2001 uint32_t i;
2002 char orig_path[LYSC_CTX_BUFSIZE];
2003 struct lysc_augment *aug;
2004
2005 /* uses augments */
2006 for (i = 0; i < ctx->uses_augs.count; ) {
2007 aug = ctx->uses_augs.objs[i];
2008
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002009 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->ext, aug->nodeid_ctx_node, node, NULL, NULL,
2010 ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002011 /* not our target node */
2012 ++i;
2013 continue;
2014 }
2015
Michal Vaskob8df5762021-01-12 15:15:53 +01002016 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002017 lysc_update_path(ctx, NULL, "{augment}");
2018 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01002019 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01002020
2021 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002022 ret = lys_compile_augment(ctx, aug->aug_p, node);
2023 lysc_update_path(ctx, NULL, NULL);
2024 lysc_update_path(ctx, NULL, NULL);
2025 LY_CHECK_GOTO(ret, cleanup);
2026
Michal Vaskoc75f2042021-06-08 14:57:03 +02002027 /* augment was applied, remove it (index and the whole set may have changed because other augments
2028 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002029 ly_set_rm(&ctx->uses_augs, aug, NULL);
2030 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002031 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002032 }
2033
2034 /* top-level augments */
2035 for (i = 0; i < ctx->augs.count; ) {
2036 aug = ctx->augs.objs[i];
2037
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002038 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 +02002039 /* not our target node */
2040 ++i;
2041 continue;
2042 }
2043
Michal Vaskob8df5762021-01-12 15:15:53 +01002044 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002045 strcpy(orig_path, ctx->path);
2046 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002047 ctx->cur_mod = aug->aug_pmod->mod;
2048 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02002049 lysc_update_path(ctx, NULL, "{augment}");
2050 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01002051
2052 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002053 ret = lys_compile_augment(ctx, aug->aug_p, node);
2054 strcpy(ctx->path, orig_path);
2055 ctx->path_len = strlen(ctx->path);
2056 LY_CHECK_GOTO(ret, cleanup);
2057
2058 /* augment was applied, remove it */
2059 ly_set_rm(&ctx->augs, aug, NULL);
2060 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002061 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002062 }
2063
2064cleanup:
2065 ctx->cur_mod = orig_mod;
2066 ctx->pmod = orig_pmod;
2067 return ret;
2068}
2069
2070/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002071 * @brief Prepare an absolute-nodeid augment to be applied during data nodes compilation.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002072 *
2073 * @param[in] ctx Compile context.
2074 * @param[in] aug_p Parsed augment to be applied.
2075 * @param[in] pmod Both current and prefix module for @p aug_p.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002076 * @param[in] ext Extension instance in case @p aug_p is defined in one.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002077 * @return LY_ERR value.
2078 */
2079static LY_ERR
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002080lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, const struct lysp_module *pmod,
2081 const struct lysp_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002082{
2083 LY_ERR ret = LY_SUCCESS;
2084 struct lyxp_expr *exp = NULL;
2085 struct lysc_augment *aug;
2086 const struct lys_module *mod;
2087
2088 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2089 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
2090 LY_CHECK_GOTO(ret, cleanup);
2091
2092 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2093 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2094 if (mod != ctx->cur_mod) {
2095 /* augment for another module, ignore */
2096 goto cleanup;
2097 }
2098
2099 /* allocate new compiled augment and store it in the set */
2100 aug = calloc(1, sizeof *aug);
2101 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2102 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2103
2104 aug->nodeid = exp;
2105 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002106 aug->aug_pmod = pmod;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002107 aug->ext = ext;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002108 aug->aug_p = aug_p;
2109
2110cleanup:
2111 lyxp_expr_free(ctx->ctx, exp);
2112 return ret;
2113}
2114
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002115/**
2116 * @brief Prepare all top-level augments and extension instance augments to be applied during data nodes compilation.
2117 *
2118 * @param[in] ctx Compile context.
2119 * @param[in] pmod Parsed mod to use.
2120 * @return LY_ERR value.
2121 */
2122static LY_ERR
2123lys_precompile_own_augments_mod(struct lysc_ctx *ctx, const struct lysp_module *pmod)
2124{
2125 LY_ARRAY_COUNT_TYPE u, v;
2126 struct lysp_node_augment *aug_p;
2127
2128 /* module */
2129 LY_LIST_FOR(pmod->augments, aug_p) {
2130 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, NULL));
2131 }
2132
2133 /* parsed extension instances */
2134 LY_ARRAY_FOR(pmod->exts, u) {
2135 aug_p = NULL;
2136 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2137 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2138 aug_p = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2139 break;
2140 }
2141 }
2142 if (!aug_p) {
2143 continue;
2144 }
2145
2146 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, &pmod->exts[u]));
2147 }
2148
2149 return LY_SUCCESS;
2150}
2151
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002152LY_ERR
2153lys_precompile_own_augments(struct lysc_ctx *ctx)
2154{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002155 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002156 const struct lys_module *aug_mod;
2157 const struct lysp_module *submod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002158
2159 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002160 aug_mod = ctx->cur_mod->augmented_by[u];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002161
2162 /* collect all module augments */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002163 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002164
2165 /* collect all submodules augments */
2166 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002167 submod = (struct lysp_module *)aug_mod->parsed->includes[v].submodule;
2168
2169 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, submod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002170 }
2171 }
2172
2173 return LY_SUCCESS;
2174}
2175
2176/**
2177 * @brief Prepare a deviation to be applied during data nodes compilation.
2178 *
2179 * @param[in] ctx Compile context.
2180 * @param[in] dev_p Parsed deviation to be applied.
2181 * @param[in] pmod Both current and prefix module for @p dev_p.
2182 * @return LY_ERR value.
2183 */
2184static LY_ERR
2185lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2186{
2187 LY_ERR ret = LY_SUCCESS;
2188 struct lysc_deviation *dev = NULL;
2189 struct lyxp_expr *exp = NULL;
2190 struct lysp_deviation **new_dev;
2191 const struct lys_module *mod;
2192 const struct lysp_module **new_dev_pmod;
2193 uint32_t i;
2194
2195 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2196 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2197 LY_CHECK_GOTO(ret, cleanup);
2198
2199 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2200 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2201 if (mod != ctx->cur_mod) {
2202 /* deviation for another module, ignore */
2203 goto cleanup;
2204 }
2205
2206 /* try to find the node in already compiled deviations */
2207 for (i = 0; i < ctx->devs.count; ++i) {
2208 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2209 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2210 dev = ctx->devs.objs[i];
2211 break;
2212 }
2213 }
2214
2215 if (!dev) {
2216 /* allocate new compiled deviation */
2217 dev = calloc(1, sizeof *dev);
2218 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2219 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2220
2221 dev->nodeid = exp;
2222 exp = NULL;
2223 }
2224
2225 /* add new parsed deviation structure */
2226 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2227 *new_dev = dev_p;
2228 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2229 *new_dev_pmod = pmod;
2230
2231cleanup:
2232 lyxp_expr_free(ctx->ctx, exp);
2233 return ret;
2234}
2235
2236LY_ERR
2237lys_precompile_own_deviations(struct lysc_ctx *ctx)
2238{
2239 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002240 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002241 const struct lys_module *dev_mod;
2242 struct lysc_deviation *dev;
2243 struct lysp_deviate *d;
2244 int not_supported;
2245 uint32_t i;
2246
2247 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2248 dev_mod = ctx->cur_mod->deviated_by[u];
2249
2250 /* compile all module deviations */
2251 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2252 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2253 }
2254
2255 /* compile all submodules deviations */
2256 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2257 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2258 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2259 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2260 }
2261 }
2262 }
2263
2264 /* set not-supported flags for all the deviations */
2265 for (i = 0; i < ctx->devs.count; ++i) {
2266 dev = ctx->devs.objs[i];
2267 not_supported = 0;
2268
2269 LY_ARRAY_FOR(dev->devs, u) {
2270 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2271 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2272 not_supported = 1;
2273 break;
2274 }
2275 }
2276 if (not_supported) {
2277 break;
2278 }
2279 }
2280 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002281 orig_cur_mod = ctx->cur_mod;
2282 ctx->cur_mod = dev->dev_pmods[u]->mod;
2283 lysc_update_path(ctx, NULL, "{deviation}");
2284 lysc_update_path(ctx, NULL, dev->nodeid->expr);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002285 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002286 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002287 lysc_update_path(ctx, NULL, NULL);
2288 lysc_update_path(ctx, NULL, NULL);
2289 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002290 return LY_EVALID;
2291 }
2292
2293 dev->not_supported = not_supported;
2294 }
2295
2296 return LY_SUCCESS;
2297}
2298
2299/**
2300 * @brief Add a module reference into an array, checks for duplicities.
2301 *
2302 * @param[in] ctx Compile context.
2303 * @param[in] mod Module reference to add.
2304 * @param[in,out] mod_array Module sized array to add to.
2305 * @return LY_ERR value.
2306 */
2307static LY_ERR
2308lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2309{
2310 LY_ARRAY_COUNT_TYPE u;
2311 struct lys_module **new_mod;
2312
2313 LY_ARRAY_FOR(*mod_array, u) {
2314 if ((*mod_array)[u] == mod) {
2315 /* already there */
2316 return LY_EEXIST;
2317 }
2318 }
2319
2320 /* add the new module ref */
2321 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2322 *new_mod = mod;
2323
2324 return LY_SUCCESS;
2325}
2326
Michal Vasko1ccbf542021-04-19 11:35:00 +02002327/**
2328 * @brief Check whether all modules in a set are implemented.
2329 *
2330 * @param[in] mod_set Module set to check.
2331 * @return Whether all modules are implemented or not.
2332 */
2333static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002334lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002335{
2336 uint32_t i;
2337 const struct lys_module *mod;
2338
2339 for (i = 0; i < mod_set->count; ++i) {
2340 mod = mod_set->objs[i];
2341 if (!mod->implemented) {
2342 return 0;
2343 }
2344 }
2345
2346 return 1;
2347}
2348
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002349/**
2350 * @brief Add references to target modules of top-level augments, deviations, and augments in extension instances
2351 * in a module and all its submodules.
2352 *
2353 * @param[in] pmod Module to process.
2354 * @param[in,out] mod_set Module set to add referenced modules into.
2355 * @return LY_SUCCESS on success.
2356 * @return LY_ERR on error.
2357 */
2358static LY_ERR
2359lys_precompile_mod_augments_deviations(struct lysp_module *pmod, struct ly_set *mod_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002360{
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002361 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002362 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002363 struct lysc_ctx ctx;
Michal Vasko65333882021-06-10 14:12:16 +02002364 struct lys_module *m;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002365 struct lysp_node_augment *aug;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002366 struct ly_set set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002367
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002368 LYSC_CTX_INIT_PMOD(ctx, pmod, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002369
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002370 LY_LIST_FOR(pmod->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002371 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002372 lysc_update_path(&ctx, NULL, "{augment}");
2373 lysc_update_path(&ctx, NULL, aug->nodeid);
2374 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2375 lysc_update_path(&ctx, NULL, NULL);
2376 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002377 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002378
Michal Vasko1ccbf542021-04-19 11:35:00 +02002379 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002380 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002381 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002382 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002383 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002384 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002385 }
2386
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002387 LY_ARRAY_FOR(pmod->deviations, u) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002388 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002389 lysc_update_path(&ctx, NULL, "{deviation}");
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002390 lysc_update_path(&ctx, NULL, pmod->deviations[u].nodeid);
2391 ret = lys_nodeid_mod_check(&ctx, pmod->deviations[u].nodeid, 1, &set, NULL, &m);
Michal Vasko65333882021-06-10 14:12:16 +02002392 lysc_update_path(&ctx, NULL, NULL);
2393 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002394 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002395
Michal Vasko1ccbf542021-04-19 11:35:00 +02002396 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002397 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002398 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002399 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002400 }
2401 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002402 }
2403
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002404 LY_ARRAY_FOR(pmod->exts, u) {
2405 aug = NULL;
2406 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2407 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2408 aug = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2409 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002410 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002411 }
2412 if (!aug) {
2413 continue;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002414 }
2415
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002416 /* get target module */
2417 lysc_update_path(&ctx, NULL, "{ext-augment}");
2418 lysc_update_path(&ctx, NULL, aug->nodeid);
2419 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2420 lysc_update_path(&ctx, NULL, NULL);
2421 lysc_update_path(&ctx, NULL, NULL);
2422 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002423
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002424 /* add this module into the target module augmented_by, if not there and implemented */
2425 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
2426 !lys_precompile_mod_set_is_all_implemented(&set)) {
2427 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002428 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002429 ly_set_erase(&set, NULL);
2430 }
2431
2432cleanup:
2433 ly_set_erase(&set, NULL);
2434 return ret;
2435}
2436
2437LY_ERR
2438lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
2439{
2440 LY_ERR ret = LY_SUCCESS, r;
2441 LY_ARRAY_COUNT_TYPE u;
2442 struct lys_module *m;
2443 struct lysp_module *submod;
2444 const char **imp_f, *all_f[] = {"*", NULL};
2445 uint32_t i;
2446 struct ly_set mod_set = {0};
2447
2448 /* module */
2449 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(mod->parsed, &mod_set), cleanup);
2450
2451 /* submodules */
2452 LY_ARRAY_FOR(mod->parsed->includes, u) {
2453 submod = (struct lysp_module *)mod->parsed->includes[u].submodule;
2454 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(submod, &mod_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002455 }
2456
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002457 for (i = 0; i < mod_set.count; ++i) {
2458 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002459
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002460 if (m == mod) {
2461 /* will be applied normally later */
2462 continue;
2463 }
2464
2465 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2466 * not compiled yet and marked for compilation */
2467
2468 if (!m->implemented) {
2469 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002470 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2471 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002472 if (r == LY_ERECOMPILE) {
2473 /* implement all the modules right away to save possible later recompilation */
2474 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002475 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002476 } else if (r) {
2477 /* error */
2478 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002479 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002480 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002481 } else if (m->compiled) {
2482 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2483 m->to_compile = 1;
2484 ret = LY_ERECOMPILE;
2485 continue;
2486 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002487 }
2488
Michal Vasko1ccbf542021-04-19 11:35:00 +02002489cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +02002490 ly_set_erase(&mod_set, NULL);
2491 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002492}
2493
2494void
2495lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2496{
2497 uint32_t i;
2498 LY_ARRAY_COUNT_TYPE u, count;
2499 struct lys_module *m;
2500
2501 for (i = 0; i < ctx->list.count; ++i) {
2502 m = ctx->list.objs[i];
2503
2504 if (m->augmented_by) {
2505 count = LY_ARRAY_COUNT(m->augmented_by);
2506 for (u = 0; u < count; ++u) {
2507 if (m->augmented_by[u] == mod) {
2508 /* keep the order */
2509 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002510 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002511 }
2512 LY_ARRAY_DECREMENT(m->augmented_by);
2513 break;
2514 }
2515 }
2516 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2517 LY_ARRAY_FREE(m->augmented_by);
2518 m->augmented_by = NULL;
2519 }
2520 }
2521
2522 if (m->deviated_by) {
2523 count = LY_ARRAY_COUNT(m->deviated_by);
2524 for (u = 0; u < count; ++u) {
2525 if (m->deviated_by[u] == mod) {
2526 /* keep the order */
2527 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002528 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002529 }
2530 LY_ARRAY_DECREMENT(m->deviated_by);
2531 break;
2532 }
2533 }
2534 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2535 LY_ARRAY_FREE(m->deviated_by);
2536 m->deviated_by = NULL;
2537 }
2538 }
2539 }
2540}