blob: 17f12439d9756b70924b1e512cefb4955a8a534d [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) {
883 switch (target->nodetype) {
884 case LYS_CONTAINER:
885 break;
886 default:
887 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
888 }
889
Michal Vaskoe180ed02021-02-05 16:31:20 +0100890 lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200891 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
892 }
893
894 /* must */
895 if (rfn->musts) {
896 switch (target->nodetype) {
897 case LYS_CONTAINER:
898 case LYS_LIST:
899 case LYS_LEAF:
900 case LYS_LEAFLIST:
901 case LYS_ANYDATA:
902 case LYS_ANYXML:
903 musts = &((struct lysp_node_container *)target)->musts;
904 break;
905 default:
906 AMEND_WRONG_NODETYPE("refine", "add", "must");
907 }
908
909 LY_ARRAY_FOR(rfn->musts, u) {
910 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100911 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, rfn_pmod, &rfn->musts[u], must), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200912 }
913 }
914
915 /* min-elements */
916 if (rfn->flags & LYS_SET_MIN) {
917 switch (target->nodetype) {
918 case LYS_LEAFLIST:
919 num = &((struct lysp_node_leaflist *)target)->min;
920 break;
921 case LYS_LIST:
922 num = &((struct lysp_node_list *)target)->min;
923 break;
924 default:
925 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
926 }
927
928 *num = rfn->min;
929 }
930
931 /* max-elements */
932 if (rfn->flags & LYS_SET_MAX) {
933 switch (target->nodetype) {
934 case LYS_LEAFLIST:
935 num = &((struct lysp_node_leaflist *)target)->max;
936 break;
937 case LYS_LIST:
938 num = &((struct lysp_node_list *)target)->max;
939 break;
940 default:
941 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
942 }
943
944 *num = rfn->max;
945 }
946
947 /* if-feature */
948 if (rfn->iffeatures) {
949 switch (target->nodetype) {
950 case LYS_LEAF:
951 case LYS_LEAFLIST:
952 case LYS_LIST:
953 case LYS_CONTAINER:
954 case LYS_CHOICE:
955 case LYS_CASE:
956 case LYS_ANYDATA:
957 case LYS_ANYXML:
958 break;
959 default:
960 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
961 }
962
963 LY_ARRAY_FOR(rfn->iffeatures, u) {
964 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100965 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->iffeatures[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200966 }
967 }
968
Michal Vasko193dacd2022-10-13 08:43:05 +0200969 /* extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +0100970 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 +0200971
972cleanup:
Michal Vasko193dacd2022-10-13 08:43:05 +0200973 ctx->cur_mod = orig_mod;
974 ctx->pmod = orig_pmod;
975
976 lysc_update_path(ctx, NULL, NULL);
977 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200978 return ret;
979}
980
981/**
982 * @brief Apply deviate add.
983 *
984 * @param[in] ctx Compile context.
985 * @param[in] d Deviate add to apply.
986 * @param[in,out] target Deviation target.
987 * @return LY_ERR value.
988 */
989static LY_ERR
990lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
991{
992 LY_ERR ret = LY_SUCCESS;
993 LY_ARRAY_COUNT_TYPE u;
994 struct lysp_qname *qname;
995 uint32_t *num;
996 struct lysp_restr **musts, *must;
997
998#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
999 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001000 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001001 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
1002 ret = LY_EVALID; \
1003 goto cleanup; \
1004 }
1005
1006 /* [units-stmt] */
1007 if (d->units) {
1008 switch (target->nodetype) {
1009 case LYS_LEAF:
1010 case LYS_LEAFLIST:
1011 break;
1012 default:
1013 AMEND_WRONG_NODETYPE("deviation", "add", "units");
1014 }
1015
1016 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
1017 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1018 }
1019
1020 /* *must-stmt */
1021 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001022 musts = lysp_node_musts_p(target);
1023 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001024 AMEND_WRONG_NODETYPE("deviation", "add", "must");
1025 }
1026
1027 LY_ARRAY_FOR(d->musts, u) {
1028 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001029 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, ctx->pmod, &d->musts[u], must), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001030 }
1031 }
1032
1033 /* *unique-stmt */
1034 if (d->uniques) {
1035 switch (target->nodetype) {
1036 case LYS_LIST:
1037 break;
1038 default:
1039 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
1040 }
1041
1042 LY_ARRAY_FOR(d->uniques, u) {
1043 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001044 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->uniques[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001045 }
1046 }
1047
1048 /* *default-stmt */
1049 if (d->dflts) {
1050 switch (target->nodetype) {
1051 case LYS_LEAF:
1052 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1053 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
1054
Michal Vaskoc621d862022-11-08 14:23:45 +01001055 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 +02001056 break;
1057 case LYS_LEAFLIST:
1058 LY_ARRAY_FOR(d->dflts, u) {
1059 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001060 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflts[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001061 }
1062 break;
1063 case LYS_CHOICE:
1064 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1065 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
1066
Michal Vaskoc621d862022-11-08 14:23:45 +01001067 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 +02001068 break;
1069 default:
1070 AMEND_WRONG_NODETYPE("deviation", "add", "default");
1071 }
1072 }
1073
1074 /* [config-stmt] */
1075 if (d->flags & LYS_CONFIG_MASK) {
1076 switch (target->nodetype) {
1077 case LYS_CONTAINER:
1078 case LYS_LEAF:
1079 case LYS_LEAFLIST:
1080 case LYS_LIST:
1081 case LYS_CHOICE:
1082 case LYS_ANYDATA:
1083 case LYS_ANYXML:
1084 break;
1085 default:
1086 AMEND_WRONG_NODETYPE("deviation", "add", "config");
1087 }
1088
1089 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001090 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001091 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
1092 target->flags & LYS_CONFIG_W ? "true" : "false");
1093 ret = LY_EVALID;
1094 goto cleanup;
1095 }
1096
1097 target->flags |= d->flags & LYS_CONFIG_MASK;
1098 }
1099
1100 /* [mandatory-stmt] */
1101 if (d->flags & LYS_MAND_MASK) {
1102 switch (target->nodetype) {
1103 case LYS_LEAF:
1104 case LYS_CHOICE:
1105 case LYS_ANYDATA:
1106 case LYS_ANYXML:
1107 break;
1108 default:
1109 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
1110 }
1111
1112 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001113 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001114 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
1115 target->flags & LYS_MAND_TRUE ? "true" : "false");
1116 ret = LY_EVALID;
1117 goto cleanup;
1118 }
1119
1120 target->flags |= d->flags & LYS_MAND_MASK;
1121 }
1122
1123 /* [min-elements-stmt] */
1124 if (d->flags & LYS_SET_MIN) {
1125 switch (target->nodetype) {
1126 case LYS_LEAFLIST:
1127 num = &((struct lysp_node_leaflist *)target)->min;
1128 break;
1129 case LYS_LIST:
1130 num = &((struct lysp_node_list *)target)->min;
1131 break;
1132 default:
1133 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
1134 }
1135
1136 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001137 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001138 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
1139 ret = LY_EVALID;
1140 goto cleanup;
1141 }
1142
1143 *num = d->min;
1144 }
1145
1146 /* [max-elements-stmt] */
1147 if (d->flags & LYS_SET_MAX) {
1148 switch (target->nodetype) {
1149 case LYS_LEAFLIST:
1150 num = &((struct lysp_node_leaflist *)target)->max;
1151 break;
1152 case LYS_LIST:
1153 num = &((struct lysp_node_list *)target)->max;
1154 break;
1155 default:
1156 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1157 }
1158
1159 if (target->flags & LYS_SET_MAX) {
1160 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001161 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001162 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1163 *num);
1164 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001165 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001166 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1167 }
1168 ret = LY_EVALID;
1169 goto cleanup;
1170 }
1171
1172 *num = d->max;
1173 }
1174
1175cleanup:
1176 return ret;
1177}
1178
1179/**
1180 * @brief Apply deviate delete.
1181 *
1182 * @param[in] ctx Compile context.
1183 * @param[in] d Deviate delete to apply.
1184 * @param[in,out] target Deviation target.
1185 * @return LY_ERR value.
1186 */
1187static LY_ERR
1188lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1189{
1190 LY_ERR ret = LY_SUCCESS;
1191 struct lysp_restr **musts;
1192 LY_ARRAY_COUNT_TYPE u, v;
1193 struct lysp_qname **uniques, **dflts;
1194
Michal Vaskoc636ea42022-09-16 10:20:31 +02001195#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, FREE_CTX, PROPERTY) \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001196 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1197 int found = 0; \
1198 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1199 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1200 found = 1; \
1201 break; \
1202 } \
1203 } \
1204 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001205 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001206 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1207 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1208 ret = LY_EVALID; \
1209 goto cleanup; \
1210 } \
1211 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
Michal Vaskoc636ea42022-09-16 10:20:31 +02001212 FREE_FUNC(FREE_CTX, &(ORIG_ARRAY)[v]); \
Michal Vasko08e9b112021-06-11 15:41:17 +02001213 if (v < LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1214 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1215 } \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001216 } \
1217 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1218 LY_ARRAY_FREE(ORIG_ARRAY); \
1219 ORIG_ARRAY = NULL; \
1220 }
1221
1222#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1223 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001224 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001225 ret = LY_EVALID; \
1226 goto cleanup; \
1227 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001228 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001229 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1230 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1231 ret = LY_EVALID; \
1232 goto cleanup; \
1233 }
1234
1235 /* [units-stmt] */
1236 if (d->units) {
1237 switch (target->nodetype) {
1238 case LYS_LEAF:
1239 case LYS_LEAFLIST:
1240 break;
1241 default:
1242 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1243 }
1244
1245 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001246 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001247 ((struct lysp_node_leaf *)target)->units = NULL;
1248 }
1249
1250 /* *must-stmt */
1251 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001252 musts = lysp_node_musts_p(target);
1253 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001254 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1255 }
1256
Michal Vaskoc636ea42022-09-16 10:20:31 +02001257 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, &ctx->free_ctx, "must");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001258 }
1259
1260 /* *unique-stmt */
1261 if (d->uniques) {
1262 switch (target->nodetype) {
1263 case LYS_LIST:
1264 break;
1265 default:
1266 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1267 }
1268
1269 uniques = &((struct lysp_node_list *)target)->uniques;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001270 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, ctx->ctx, "unique");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001271 }
1272
1273 /* *default-stmt */
1274 if (d->dflts) {
1275 switch (target->nodetype) {
1276 case LYS_LEAF:
1277 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1278 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1279
Michal Vaskoe180ed02021-02-05 16:31:20 +01001280 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001281 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1282 break;
1283 case LYS_LEAFLIST:
1284 dflts = &((struct lysp_node_leaflist *)target)->dflts;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001285 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, ctx->ctx, "default");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001286 break;
1287 case LYS_CHOICE:
1288 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1289 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1290
Michal Vaskoe180ed02021-02-05 16:31:20 +01001291 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001292 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1293 break;
1294 default:
1295 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1296 }
1297 }
1298
1299cleanup:
1300 return ret;
1301}
1302
1303/**
1304 * @brief Apply deviate replace.
1305 *
1306 * @param[in] ctx Compile context.
1307 * @param[in] d Deviate replace to apply.
1308 * @param[in,out] target Deviation target.
1309 * @return LY_ERR value.
1310 */
1311static LY_ERR
1312lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1313{
1314 LY_ERR ret = LY_SUCCESS;
1315 uint32_t *num;
1316
1317#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1318 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001319 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001320 ret = LY_EVALID; \
1321 goto cleanup; \
1322 }
1323
1324 /* [type-stmt] */
1325 if (d->type) {
1326 switch (target->nodetype) {
1327 case LYS_LEAF:
1328 case LYS_LEAFLIST:
1329 break;
1330 default:
1331 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1332 }
1333
Michal Vaskoc636ea42022-09-16 10:20:31 +02001334 lysp_type_free(&ctx->free_ctx, &((struct lysp_node_leaf *)target)->type);
Michal Vaskoc621d862022-11-08 14:23:45 +01001335 lysp_type_dup(ctx->ctx, ctx->pmod, d->type, &((struct lysp_node_leaf *)target)->type);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001336 }
1337
1338 /* [units-stmt] */
1339 if (d->units) {
1340 switch (target->nodetype) {
1341 case LYS_LEAF:
1342 case LYS_LEAFLIST:
1343 break;
1344 default:
1345 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1346 }
1347
1348 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001349 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001350 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1351 }
1352
1353 /* [default-stmt] */
1354 if (d->dflt.str) {
1355 switch (target->nodetype) {
1356 case LYS_LEAF:
1357 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1358
Michal Vaskoe180ed02021-02-05 16:31:20 +01001359 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +01001360 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 +02001361 break;
1362 case LYS_CHOICE:
1363 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
1364
Michal Vaskoe180ed02021-02-05 16:31:20 +01001365 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +01001366 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 +02001367 break;
1368 default:
1369 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1370 }
1371 }
1372
1373 /* [config-stmt] */
1374 if (d->flags & LYS_CONFIG_MASK) {
1375 switch (target->nodetype) {
1376 case LYS_CONTAINER:
1377 case LYS_LEAF:
1378 case LYS_LEAFLIST:
1379 case LYS_LIST:
1380 case LYS_CHOICE:
1381 case LYS_ANYDATA:
1382 case LYS_ANYXML:
1383 break;
1384 default:
1385 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1386 }
1387
1388 if (!(target->flags & LYS_CONFIG_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001389 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "config",
1390 d->flags & LYS_CONFIG_W ? "config true" : "config false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001391 ret = LY_EVALID;
1392 goto cleanup;
1393 }
1394
1395 target->flags &= ~LYS_CONFIG_MASK;
1396 target->flags |= d->flags & LYS_CONFIG_MASK;
1397 }
1398
1399 /* [mandatory-stmt] */
1400 if (d->flags & LYS_MAND_MASK) {
1401 switch (target->nodetype) {
1402 case LYS_LEAF:
1403 case LYS_CHOICE:
1404 case LYS_ANYDATA:
1405 case LYS_ANYXML:
1406 break;
1407 default:
1408 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1409 }
1410
1411 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001412 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1413 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001414 ret = LY_EVALID;
1415 goto cleanup;
1416 }
1417
1418 target->flags &= ~LYS_MAND_MASK;
1419 target->flags |= d->flags & LYS_MAND_MASK;
1420 }
1421
1422 /* [min-elements-stmt] */
1423 if (d->flags & LYS_SET_MIN) {
1424 switch (target->nodetype) {
1425 case LYS_LEAFLIST:
1426 num = &((struct lysp_node_leaflist *)target)->min;
1427 break;
1428 case LYS_LIST:
1429 num = &((struct lysp_node_list *)target)->min;
1430 break;
1431 default:
1432 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1433 }
1434
1435 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001436 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001437 ret = LY_EVALID;
1438 goto cleanup;
1439 }
1440
1441 *num = d->min;
1442 }
1443
1444 /* [max-elements-stmt] */
1445 if (d->flags & LYS_SET_MAX) {
1446 switch (target->nodetype) {
1447 case LYS_LEAFLIST:
1448 num = &((struct lysp_node_leaflist *)target)->max;
1449 break;
1450 case LYS_LIST:
1451 num = &((struct lysp_node_list *)target)->max;
1452 break;
1453 default:
1454 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1455 }
1456
1457 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001458 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001459 ret = LY_EVALID;
1460 goto cleanup;
1461 }
1462
1463 *num = d->max;
1464 }
1465
1466cleanup:
1467 return ret;
1468}
1469
1470/**
Michal Vasko193dacd2022-10-13 08:43:05 +02001471 * @brief Apply deviation with all its deviates.
1472 *
1473 * @param[in] ctx Compile context.
1474 * @param[in] dev Deviation to apply.
1475 * @param[in] dev_pmod Local module of the deviation.
1476 * @param[in,out] target Deviation target.
1477 * @return LY_ERR value.
1478 */
1479static LY_ERR
1480lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const struct lysp_module *dev_pmod,
1481 struct lysp_node *target)
1482{
1483 LY_ERR ret = LY_SUCCESS;
1484 struct lys_module *orig_mod = ctx->cur_mod;
1485 struct lysp_module *orig_pmod = ctx->pmod;
1486 char orig_path[LYSC_CTX_BUFSIZE];
1487 struct lysp_deviate *d;
1488
1489 /* clear path and set modules */
1490 strcpy(orig_path, ctx->path);
1491 ctx->path_len = 1;
1492 ctx->cur_mod = dev_pmod->mod;
1493 ctx->pmod = (struct lysp_module *)dev_pmod;
1494
1495 /* generate correct path */
1496 lysc_update_path(ctx, NULL, "{deviation}");
1497 lysc_update_path(ctx, NULL, dev->nodeid);
1498
1499 LY_LIST_FOR(dev->deviates, d) {
1500 switch (d->mod) {
1501 case LYS_DEV_ADD:
1502 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, target);
1503 break;
1504 case LYS_DEV_DELETE:
1505 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, target);
1506 break;
1507 case LYS_DEV_REPLACE:
1508 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, target);
1509 break;
1510 default:
1511 LOGINT(ctx->ctx);
1512 ret = LY_EINT;
1513 }
1514 LY_CHECK_GOTO(ret, cleanup);
1515 }
1516
1517 /* deviation extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +01001518 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 +02001519
1520cleanup:
1521 ctx->cur_mod = orig_mod;
1522 ctx->pmod = orig_pmod;
1523
1524 strcpy(ctx->path, orig_path);
1525 ctx->path_len = strlen(ctx->path);
1526 return ret;
1527}
1528
1529/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001530 * @brief Check whether a compiled node matches a single schema nodeid name test.
1531 *
1532 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1533 * @param[in] mod Expected module.
1534 * @param[in] name Expected name.
1535 * @param[in] name_len Length of @p name.
1536 * @return Whether it is a match or not.
1537 */
1538static ly_bool
1539lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1540 size_t name_len)
1541{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001542 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001543 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001544 return 0;
1545 }
1546
1547 /* compare names */
Michal Vasko544e58a2021-01-28 14:33:41 +01001548 if (ly_strncmp((*node)->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001549 return 0;
1550 }
1551
Michal Vasko2a668712020-10-21 11:48:09 +02001552 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001553 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001554
1555 return 1;
1556}
1557
1558/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001559 * @brief Check whether a compiled ext instance matches a single schema nodeid name test.
1560 *
1561 * @param[in,out] ext Compiled ext instance to consider. On a match it is zeroed to not match again.
1562 * @param[in] mod Expected module.
1563 * @param[in] name Expected name.
1564 * @param[in] name_len Length of @p name.
1565 * @return Whether it is a match or not.
1566 */
1567static ly_bool
1568lysp_schema_nodeid_match_ext(const struct lysc_ext_instance **ext, const struct lys_module *mod, const char *name,
1569 size_t name_len)
1570{
1571 /* compare with the module */
1572 if ((*ext)->module != mod) {
1573 return 0;
1574 }
1575
1576 /* compare names (argument) */
1577 if (ly_strncmp((*ext)->argument, name, name_len)) {
1578 return 0;
1579 }
1580
1581 /* zero */
1582 *ext = NULL;
1583
1584 return 1;
1585}
1586
1587/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001588 * @brief Check whether a node matches specific schema nodeid.
1589 *
1590 * @param[in] exp Parsed nodeid to match.
1591 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001592 * @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 +02001593 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1594 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1595 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1596 * @param[in] pnode_mod Compiled @p pnode to-be module.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001597 * @param[in] pnode_ext Extension instance in which @p pnode is defined.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001598 * @return Whether it is a match or not.
1599 */
1600static ly_bool
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001601lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod,
1602 const struct lysp_ext_instance *exp_ext, const struct lysc_node *ctx_node, const struct lysc_node *parent,
1603 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 +02001604{
1605 uint32_t i;
1606 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001607 const char *name = NULL;
1608 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001609
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001610 if (exp_ext && !pnode_ext) {
1611 /* extension instance augment and standard node, will never match */
1612 return 0;
1613 } else if (!exp_ext && pnode_ext) {
1614 /* standard augment and extension instance node, will never match */
1615 return 0;
1616 }
1617
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001618 /* compare last node in the node ID */
1619 i = exp->used - 1;
1620
1621 /* get exp node ID module */
1622 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);
1623 assert(mod);
1624
1625 if (pnode) {
1626 /* compare on the last parsed-only node */
Radek Krejci2d5f6df2021-01-28 14:00:13 +01001627 if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001628 return 0;
1629 }
1630 } else {
1631 /* using parent directly */
1632 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1633 return 0;
1634 }
1635 }
1636
1637 /* now compare all the compiled parents */
1638 while (i > 1) {
1639 i -= 2;
1640 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1641
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001642 if (!parent && !pnode_ext) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001643 /* no more parents but path continues */
1644 return 0;
1645 }
1646
1647 /* get exp node ID module */
1648 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1649 &name_len);
1650 assert(mod);
1651
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001652 if (parent) {
1653 /* compare with the parent */
1654 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1655 return 0;
1656 }
1657 } else {
1658 /* compare with the ext instance */
1659 if (!lysp_schema_nodeid_match_ext(&pnode_ext, mod, name, name_len)) {
1660 return 0;
1661 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001662 }
1663 }
1664
1665 if (ctx_node && (ctx_node != parent)) {
1666 /* descendant path has not finished in the context node */
1667 return 0;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001668 } else if (!ctx_node && (parent || pnode_ext)) {
1669 /* some parent/extension was not matched */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001670 return 0;
1671 }
1672
1673 return 1;
1674}
1675
1676void
1677lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1678{
1679 if (aug) {
1680 lyxp_expr_free(ctx, aug->nodeid);
1681
1682 free(aug);
1683 }
1684}
1685
1686void
1687lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1688{
1689 if (dev) {
1690 lyxp_expr_free(ctx, dev->nodeid);
1691 LY_ARRAY_FREE(dev->devs);
1692 LY_ARRAY_FREE(dev->dev_pmods);
1693
1694 free(dev);
1695 }
1696}
1697
1698void
1699lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1700{
1701 if (rfn) {
1702 lyxp_expr_free(ctx, rfn->nodeid);
1703 LY_ARRAY_FREE(rfn->rfns);
1704
1705 free(rfn);
1706 }
1707}
1708
1709void
Michal Vaskoc636ea42022-09-16 10:20:31 +02001710lysp_dev_node_free(struct lysc_ctx *cctx, struct lysp_node *dev_pnode)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001711{
1712 if (!dev_pnode) {
1713 return;
1714 }
1715
1716 switch (dev_pnode->nodetype) {
1717 case LYS_CONTAINER:
1718 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001719 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1720 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001721 break;
1722 case LYS_LIST:
1723 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001724 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1725 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001726 break;
1727 case LYS_CHOICE:
1728 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1729 break;
1730 case LYS_CASE:
1731 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1732 break;
1733 case LYS_LEAF:
1734 case LYS_LEAFLIST:
1735 case LYS_ANYXML:
1736 case LYS_ANYDATA:
1737 /* no children */
1738 break;
1739 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001740 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001741 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001742 case LYS_RPC:
1743 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001744 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1745 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001746 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001747 case LYS_INPUT:
1748 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001749 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001750 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001751 free(dev_pnode);
1752 return;
1753 default:
Michal Vaskoc636ea42022-09-16 10:20:31 +02001754 LOGINT(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001755 return;
1756 }
1757
Michal Vaskoc636ea42022-09-16 10:20:31 +02001758 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001759}
1760
1761LY_ERR
1762lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1763 struct lysp_node **dev_pnode, ly_bool *not_supported)
1764{
1765 LY_ERR ret = LY_SUCCESS;
1766 uint32_t i;
1767 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001768 struct lysc_refine *rfn;
1769 struct lysc_deviation *dev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001770
1771 *dev_pnode = NULL;
1772 *not_supported = 0;
1773
Michal Vaskoee057572022-05-26 08:31:52 +02001774 for (i = 0; i < ctx->uses_rfns.count; ) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001775 rfn = ctx->uses_rfns.objs[i];
1776
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001777 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, NULL, rfn->nodeid_ctx_node, parent, pnode,
1778 ctx->cur_mod, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001779 /* not our target node */
Michal Vaskoee057572022-05-26 08:31:52 +02001780 ++i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001781 continue;
1782 }
1783
1784 if (!*dev_pnode) {
1785 /* first refine on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001786 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001787 }
1788
1789 /* apply all the refines by changing (the copy of) the parsed node */
1790 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001791 LY_CHECK_GOTO(ret = lys_apply_refine(ctx, rfn->rfns[u], rfn->nodeid_pmod, *dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001792 }
1793
1794 /* refine was applied, remove it */
1795 lysc_refine_free(ctx->ctx, rfn);
1796 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1797
Michal Vaskoee057572022-05-26 08:31:52 +02001798 /* refines use relative paths so more may apply to a single node */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001799 }
1800
1801 for (i = 0; i < ctx->devs.count; ++i) {
1802 dev = ctx->devs.objs[i];
1803
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001804 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 +02001805 /* not our target node */
1806 continue;
1807 }
1808
1809 if (dev->not_supported) {
1810 /* it is not supported, no more deviations */
1811 *not_supported = 1;
1812 goto dev_applied;
1813 }
1814
1815 if (!*dev_pnode) {
1816 /* first deviation on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001817 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001818 }
1819
1820 /* apply all the deviates by changing (the copy of) the parsed node */
1821 LY_ARRAY_FOR(dev->devs, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001822 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 +02001823 }
1824
1825dev_applied:
1826 /* deviation was applied, remove it */
1827 lysc_deviation_free(ctx->ctx, dev);
1828 ly_set_rm_index(&ctx->devs, i, NULL);
1829
1830 /* all the deviations for one target node are in one structure, we are done */
1831 break;
1832 }
1833
1834cleanup:
1835 if (ret) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001836 lysp_dev_node_free(ctx, *dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001837 *dev_pnode = NULL;
1838 *not_supported = 0;
1839 }
1840 return ret;
1841}
1842
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001843/**
1844 * @brief Compile augment children.
1845 *
1846 * @param[in] ctx Compile context.
1847 * @param[in] aug_when Parsed augment when to inherit.
1848 * @param[in] aug_flags Parsed augment flags.
1849 * @param[in] child First augment child to compile.
1850 * @param[in] target Target node of the augment.
1851 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
1852 * @return LY_SUCCESS on success.
1853 * @return LY_EVALID on failure.
1854 */
1855static LY_ERR
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001856lys_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 +02001857 struct lysc_node *target, ly_bool child_unres_disabled)
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001858{
1859 LY_ERR rc = LY_SUCCESS;
1860 struct lysp_node *pnode;
1861 struct lysc_node *node;
1862 struct lysc_when *when_shared = NULL;
1863 ly_bool enabled, allow_mand = 0;
1864 struct ly_set child_set = {0};
1865 uint32_t i, opt_prev = ctx->compile_opts;
1866
1867 /* check for mandatory nodes
1868 * - new cases augmenting some choice can have mandatory nodes
1869 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1870 */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001871 if (aug_when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001872 allow_mand = 1;
1873 }
1874
1875 LY_LIST_FOR(child, pnode) {
1876 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1877 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1878 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1879 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1880 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1881 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1882 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1883 rc = LY_EVALID;
1884 goto cleanup;
1885 }
1886
1887 /* compile the children */
1888 if (target->nodetype == LYS_CHOICE) {
1889 LY_CHECK_GOTO(rc = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1890 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1891 if (target->nodetype == LYS_INPUT) {
1892 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
1893 } else {
1894 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
1895 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001896 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001897 } else {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001898 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001899 }
1900
1901 /* eval if-features again for the rest of this node processing */
1902 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1903 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001904 ctx->compile_opts |= LYS_COMPILE_DISABLED;
1905 }
1906
1907 /* since the augment node is not present in the compiled tree, we need to pass some of its
1908 * statements to all its children */
1909 for (i = 0; i < child_set.count; ++i) {
1910 node = child_set.snodes[i];
1911 if (!allow_mand && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1912 node->flags &= ~LYS_MAND_TRUE;
1913 lys_compile_mandatory_parents(target, 0);
1914 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
1915 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
1916 node->name);
1917 rc = LY_EVALID;
1918 goto cleanup;
1919 }
1920
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001921 if (aug_when) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001922 /* pass augment's when to all the children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001923 rc = lys_compile_when(ctx, aug_when, aug_flags, target, lysc_data_node(target), node, &when_shared);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001924 LY_CHECK_GOTO(rc, cleanup);
1925 }
1926
Michal Vaskoa084fa32022-05-16 11:32:58 +02001927 if (child_unres_disabled) {
Michal Vaskoad0980a2022-05-09 11:43:47 +02001928 /* child is disabled by the augment if-features */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001929 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
1930 }
1931 }
1932
1933 /* next iter */
1934 ly_set_erase(&child_set, NULL);
1935 ctx->compile_opts = opt_prev;
1936 }
1937
1938cleanup:
1939 ly_set_erase(&child_set, NULL);
1940 ctx->compile_opts = opt_prev;
1941 return rc;
1942}
1943
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001944/**
1945 * @brief Compile the parsed augment connecting it into its target.
1946 *
1947 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1948 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1949 * are already implemented and compiled.
1950 *
1951 * @param[in] ctx Compile context.
1952 * @param[in] aug_p Parsed augment to compile.
1953 * @param[in] target Target node of the augment.
1954 * @return LY_SUCCESS on success.
1955 * @return LY_EVALID on failure.
1956 */
1957static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001958lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001959{
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001960 LY_ERR rc = LY_SUCCESS;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001961 ly_bool enabled, child_unres_disabled = 0;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001962 uint32_t opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001963
Michal Vasko95f736c2022-06-08 12:03:31 +02001964 assert(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
1965
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001966 /* nodetype checks */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001967 if (aug_p->actions && !lysc_node_actions_p(target)) {
1968 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1969 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
1970 lys_nodetype2str(target->nodetype), aug_p->actions->name);
1971 rc = LY_EVALID;
1972 goto cleanup;
1973 }
1974 if (aug_p->notifs && !lysc_node_notifs_p(target)) {
1975 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1976 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
1977 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
1978 rc = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001979 goto cleanup;
1980 }
1981
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001982 /* augment if-features */
1983 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, aug_p->iffeatures, &enabled), cleanup);
1984 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001985 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001986 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001987 }
1988
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001989 /* augment children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001990 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, aug_p->child, target, child_unres_disabled);
1991 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001992
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001993 /* augment actions */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001994 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->actions, target,
1995 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001996 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001997
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001998 /* augment notifications */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001999 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->notifs, target,
2000 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002001 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002002
Michal Vasko193dacd2022-10-13 08:43:05 +02002003 /* compile extensions into the target */
2004 COMPILE_EXTS_GOTO(ctx, aug_p->exts, target->exts, target, rc, cleanup);
2005
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002006cleanup:
Michal Vasko7c565922021-06-10 14:58:27 +02002007 ctx->compile_opts = opt_prev;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002008 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002009}
2010
2011LY_ERR
2012lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
2013{
2014 LY_ERR ret = LY_SUCCESS;
2015 struct lys_module *orig_mod = ctx->cur_mod;
2016 struct lysp_module *orig_pmod = ctx->pmod;
2017 uint32_t i;
2018 char orig_path[LYSC_CTX_BUFSIZE];
2019 struct lysc_augment *aug;
2020
2021 /* uses augments */
2022 for (i = 0; i < ctx->uses_augs.count; ) {
2023 aug = ctx->uses_augs.objs[i];
2024
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002025 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->ext, aug->nodeid_ctx_node, node, NULL, NULL,
2026 ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002027 /* not our target node */
2028 ++i;
2029 continue;
2030 }
2031
Michal Vaskob8df5762021-01-12 15:15:53 +01002032 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002033 lysc_update_path(ctx, NULL, "{augment}");
2034 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01002035 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01002036
2037 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002038 ret = lys_compile_augment(ctx, aug->aug_p, node);
2039 lysc_update_path(ctx, NULL, NULL);
2040 lysc_update_path(ctx, NULL, NULL);
2041 LY_CHECK_GOTO(ret, cleanup);
2042
Michal Vaskoc75f2042021-06-08 14:57:03 +02002043 /* augment was applied, remove it (index and the whole set may have changed because other augments
2044 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002045 ly_set_rm(&ctx->uses_augs, aug, NULL);
2046 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002047 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002048 }
2049
2050 /* top-level augments */
2051 for (i = 0; i < ctx->augs.count; ) {
2052 aug = ctx->augs.objs[i];
2053
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002054 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 +02002055 /* not our target node */
2056 ++i;
2057 continue;
2058 }
2059
Michal Vaskob8df5762021-01-12 15:15:53 +01002060 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002061 strcpy(orig_path, ctx->path);
2062 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002063 ctx->cur_mod = aug->aug_pmod->mod;
2064 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02002065 lysc_update_path(ctx, NULL, "{augment}");
2066 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01002067
2068 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002069 ret = lys_compile_augment(ctx, aug->aug_p, node);
2070 strcpy(ctx->path, orig_path);
2071 ctx->path_len = strlen(ctx->path);
2072 LY_CHECK_GOTO(ret, cleanup);
2073
2074 /* augment was applied, remove it */
2075 ly_set_rm(&ctx->augs, aug, NULL);
2076 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002077 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002078 }
2079
2080cleanup:
2081 ctx->cur_mod = orig_mod;
2082 ctx->pmod = orig_pmod;
2083 return ret;
2084}
2085
2086/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002087 * @brief Prepare an absolute-nodeid augment to be applied during data nodes compilation.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002088 *
2089 * @param[in] ctx Compile context.
2090 * @param[in] aug_p Parsed augment to be applied.
2091 * @param[in] pmod Both current and prefix module for @p aug_p.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002092 * @param[in] ext Extension instance in case @p aug_p is defined in one.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002093 * @return LY_ERR value.
2094 */
2095static LY_ERR
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002096lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, const struct lysp_module *pmod,
2097 const struct lysp_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002098{
2099 LY_ERR ret = LY_SUCCESS;
2100 struct lyxp_expr *exp = NULL;
2101 struct lysc_augment *aug;
2102 const struct lys_module *mod;
2103
2104 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2105 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
2106 LY_CHECK_GOTO(ret, cleanup);
2107
2108 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2109 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2110 if (mod != ctx->cur_mod) {
2111 /* augment for another module, ignore */
2112 goto cleanup;
2113 }
2114
2115 /* allocate new compiled augment and store it in the set */
2116 aug = calloc(1, sizeof *aug);
2117 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2118 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2119
2120 aug->nodeid = exp;
2121 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002122 aug->aug_pmod = pmod;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002123 aug->ext = ext;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002124 aug->aug_p = aug_p;
2125
2126cleanup:
2127 lyxp_expr_free(ctx->ctx, exp);
2128 return ret;
2129}
2130
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002131/**
2132 * @brief Prepare all top-level augments and extension instance augments to be applied during data nodes compilation.
2133 *
2134 * @param[in] ctx Compile context.
2135 * @param[in] pmod Parsed mod to use.
2136 * @return LY_ERR value.
2137 */
2138static LY_ERR
2139lys_precompile_own_augments_mod(struct lysc_ctx *ctx, const struct lysp_module *pmod)
2140{
2141 LY_ARRAY_COUNT_TYPE u, v;
2142 struct lysp_node_augment *aug_p;
2143
2144 /* module */
2145 LY_LIST_FOR(pmod->augments, aug_p) {
2146 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, NULL));
2147 }
2148
2149 /* parsed extension instances */
2150 LY_ARRAY_FOR(pmod->exts, u) {
2151 aug_p = NULL;
2152 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2153 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2154 aug_p = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2155 break;
2156 }
2157 }
2158 if (!aug_p) {
2159 continue;
2160 }
2161
2162 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, &pmod->exts[u]));
2163 }
2164
2165 return LY_SUCCESS;
2166}
2167
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002168LY_ERR
2169lys_precompile_own_augments(struct lysc_ctx *ctx)
2170{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002171 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002172 const struct lys_module *aug_mod;
2173 const struct lysp_module *submod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002174
2175 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002176 aug_mod = ctx->cur_mod->augmented_by[u];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002177
2178 /* collect all module augments */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002179 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002180
2181 /* collect all submodules augments */
2182 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002183 submod = (struct lysp_module *)aug_mod->parsed->includes[v].submodule;
2184
2185 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, submod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002186 }
2187 }
2188
2189 return LY_SUCCESS;
2190}
2191
2192/**
2193 * @brief Prepare a deviation to be applied during data nodes compilation.
2194 *
2195 * @param[in] ctx Compile context.
2196 * @param[in] dev_p Parsed deviation to be applied.
2197 * @param[in] pmod Both current and prefix module for @p dev_p.
2198 * @return LY_ERR value.
2199 */
2200static LY_ERR
2201lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2202{
2203 LY_ERR ret = LY_SUCCESS;
2204 struct lysc_deviation *dev = NULL;
2205 struct lyxp_expr *exp = NULL;
2206 struct lysp_deviation **new_dev;
2207 const struct lys_module *mod;
2208 const struct lysp_module **new_dev_pmod;
2209 uint32_t i;
2210
2211 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2212 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2213 LY_CHECK_GOTO(ret, cleanup);
2214
2215 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2216 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2217 if (mod != ctx->cur_mod) {
2218 /* deviation for another module, ignore */
2219 goto cleanup;
2220 }
2221
2222 /* try to find the node in already compiled deviations */
2223 for (i = 0; i < ctx->devs.count; ++i) {
2224 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2225 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2226 dev = ctx->devs.objs[i];
2227 break;
2228 }
2229 }
2230
2231 if (!dev) {
2232 /* allocate new compiled deviation */
2233 dev = calloc(1, sizeof *dev);
2234 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2235 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2236
2237 dev->nodeid = exp;
2238 exp = NULL;
2239 }
2240
2241 /* add new parsed deviation structure */
2242 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2243 *new_dev = dev_p;
2244 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2245 *new_dev_pmod = pmod;
2246
2247cleanup:
2248 lyxp_expr_free(ctx->ctx, exp);
2249 return ret;
2250}
2251
2252LY_ERR
2253lys_precompile_own_deviations(struct lysc_ctx *ctx)
2254{
2255 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002256 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002257 const struct lys_module *dev_mod;
2258 struct lysc_deviation *dev;
2259 struct lysp_deviate *d;
2260 int not_supported;
2261 uint32_t i;
2262
2263 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2264 dev_mod = ctx->cur_mod->deviated_by[u];
2265
2266 /* compile all module deviations */
2267 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2268 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2269 }
2270
2271 /* compile all submodules deviations */
2272 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2273 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2274 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2275 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2276 }
2277 }
2278 }
2279
2280 /* set not-supported flags for all the deviations */
2281 for (i = 0; i < ctx->devs.count; ++i) {
2282 dev = ctx->devs.objs[i];
2283 not_supported = 0;
2284
2285 LY_ARRAY_FOR(dev->devs, u) {
2286 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2287 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2288 not_supported = 1;
2289 break;
2290 }
2291 }
2292 if (not_supported) {
2293 break;
2294 }
2295 }
2296 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002297 orig_cur_mod = ctx->cur_mod;
2298 ctx->cur_mod = dev->dev_pmods[u]->mod;
2299 lysc_update_path(ctx, NULL, "{deviation}");
2300 lysc_update_path(ctx, NULL, dev->nodeid->expr);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002301 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002302 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002303 lysc_update_path(ctx, NULL, NULL);
2304 lysc_update_path(ctx, NULL, NULL);
2305 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002306 return LY_EVALID;
2307 }
2308
2309 dev->not_supported = not_supported;
2310 }
2311
2312 return LY_SUCCESS;
2313}
2314
2315/**
2316 * @brief Add a module reference into an array, checks for duplicities.
2317 *
2318 * @param[in] ctx Compile context.
2319 * @param[in] mod Module reference to add.
2320 * @param[in,out] mod_array Module sized array to add to.
2321 * @return LY_ERR value.
2322 */
2323static LY_ERR
2324lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2325{
2326 LY_ARRAY_COUNT_TYPE u;
2327 struct lys_module **new_mod;
2328
2329 LY_ARRAY_FOR(*mod_array, u) {
2330 if ((*mod_array)[u] == mod) {
2331 /* already there */
2332 return LY_EEXIST;
2333 }
2334 }
2335
2336 /* add the new module ref */
2337 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2338 *new_mod = mod;
2339
2340 return LY_SUCCESS;
2341}
2342
Michal Vasko1ccbf542021-04-19 11:35:00 +02002343/**
2344 * @brief Check whether all modules in a set are implemented.
2345 *
2346 * @param[in] mod_set Module set to check.
2347 * @return Whether all modules are implemented or not.
2348 */
2349static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002350lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002351{
2352 uint32_t i;
2353 const struct lys_module *mod;
2354
2355 for (i = 0; i < mod_set->count; ++i) {
2356 mod = mod_set->objs[i];
2357 if (!mod->implemented) {
2358 return 0;
2359 }
2360 }
2361
2362 return 1;
2363}
2364
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002365/**
2366 * @brief Add references to target modules of top-level augments, deviations, and augments in extension instances
2367 * in a module and all its submodules.
2368 *
2369 * @param[in] pmod Module to process.
2370 * @param[in,out] mod_set Module set to add referenced modules into.
2371 * @return LY_SUCCESS on success.
2372 * @return LY_ERR on error.
2373 */
2374static LY_ERR
2375lys_precompile_mod_augments_deviations(struct lysp_module *pmod, struct ly_set *mod_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002376{
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002377 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002378 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002379 struct lysc_ctx ctx;
Michal Vasko65333882021-06-10 14:12:16 +02002380 struct lys_module *m;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002381 struct lysp_node_augment *aug;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002382 struct ly_set set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002383
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002384 LYSC_CTX_INIT_PMOD(ctx, pmod, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002385
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002386 LY_LIST_FOR(pmod->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002387 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002388 lysc_update_path(&ctx, NULL, "{augment}");
2389 lysc_update_path(&ctx, NULL, aug->nodeid);
2390 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2391 lysc_update_path(&ctx, NULL, NULL);
2392 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002393 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002394
Michal Vasko1ccbf542021-04-19 11:35:00 +02002395 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002396 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002397 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002398 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002399 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002400 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002401 }
2402
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002403 LY_ARRAY_FOR(pmod->deviations, u) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002404 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002405 lysc_update_path(&ctx, NULL, "{deviation}");
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002406 lysc_update_path(&ctx, NULL, pmod->deviations[u].nodeid);
2407 ret = lys_nodeid_mod_check(&ctx, pmod->deviations[u].nodeid, 1, &set, NULL, &m);
Michal Vasko65333882021-06-10 14:12:16 +02002408 lysc_update_path(&ctx, NULL, NULL);
2409 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002410 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002411
Michal Vasko1ccbf542021-04-19 11:35:00 +02002412 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002413 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002414 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002415 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002416 }
2417 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002418 }
2419
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002420 LY_ARRAY_FOR(pmod->exts, u) {
2421 aug = NULL;
2422 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2423 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2424 aug = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2425 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002426 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002427 }
2428 if (!aug) {
2429 continue;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002430 }
2431
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002432 /* get target module */
2433 lysc_update_path(&ctx, NULL, "{ext-augment}");
2434 lysc_update_path(&ctx, NULL, aug->nodeid);
2435 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2436 lysc_update_path(&ctx, NULL, NULL);
2437 lysc_update_path(&ctx, NULL, NULL);
2438 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002439
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002440 /* add this module into the target module augmented_by, if not there and implemented */
2441 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
2442 !lys_precompile_mod_set_is_all_implemented(&set)) {
2443 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002444 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002445 ly_set_erase(&set, NULL);
2446 }
2447
2448cleanup:
2449 ly_set_erase(&set, NULL);
2450 return ret;
2451}
2452
2453LY_ERR
2454lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
2455{
2456 LY_ERR ret = LY_SUCCESS, r;
2457 LY_ARRAY_COUNT_TYPE u;
2458 struct lys_module *m;
2459 struct lysp_module *submod;
2460 const char **imp_f, *all_f[] = {"*", NULL};
2461 uint32_t i;
2462 struct ly_set mod_set = {0};
2463
2464 /* module */
2465 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(mod->parsed, &mod_set), cleanup);
2466
2467 /* submodules */
2468 LY_ARRAY_FOR(mod->parsed->includes, u) {
2469 submod = (struct lysp_module *)mod->parsed->includes[u].submodule;
2470 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(submod, &mod_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002471 }
2472
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002473 for (i = 0; i < mod_set.count; ++i) {
2474 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002475
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002476 if (m == mod) {
2477 /* will be applied normally later */
2478 continue;
2479 }
2480
2481 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2482 * not compiled yet and marked for compilation */
2483
2484 if (!m->implemented) {
2485 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002486 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2487 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002488 if (r == LY_ERECOMPILE) {
2489 /* implement all the modules right away to save possible later recompilation */
2490 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002491 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002492 } else if (r) {
2493 /* error */
2494 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002495 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002496 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002497 } else if (m->compiled) {
2498 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2499 m->to_compile = 1;
2500 ret = LY_ERECOMPILE;
2501 continue;
2502 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002503 }
2504
Michal Vasko1ccbf542021-04-19 11:35:00 +02002505cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +02002506 ly_set_erase(&mod_set, NULL);
2507 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002508}
2509
2510void
2511lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2512{
2513 uint32_t i;
2514 LY_ARRAY_COUNT_TYPE u, count;
2515 struct lys_module *m;
2516
2517 for (i = 0; i < ctx->list.count; ++i) {
2518 m = ctx->list.objs[i];
2519
2520 if (m->augmented_by) {
2521 count = LY_ARRAY_COUNT(m->augmented_by);
2522 for (u = 0; u < count; ++u) {
2523 if (m->augmented_by[u] == mod) {
2524 /* keep the order */
2525 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002526 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002527 }
2528 LY_ARRAY_DECREMENT(m->augmented_by);
2529 break;
2530 }
2531 }
2532 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2533 LY_ARRAY_FREE(m->augmented_by);
2534 m->augmented_by = NULL;
2535 }
2536 }
2537
2538 if (m->deviated_by) {
2539 count = LY_ARRAY_COUNT(m->deviated_by);
2540 for (u = 0; u < count; ++u) {
2541 if (m->deviated_by[u] == mod) {
2542 /* keep the order */
2543 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002544 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002545 }
2546 LY_ARRAY_DECREMENT(m->deviated_by);
2547 break;
2548 }
2549 }
2550 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2551 LY_ARRAY_FREE(m->deviated_by);
2552 m->deviated_by = NULL;
2553 }
2554 }
2555 }
2556}