blob: 6876ea425602c4dc4bbf050654983a2d05dc0a47 [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"
Radek Krejci77114102021-03-10 15:21:57 +010029#include "plugins_exts_compile.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020030#include "schema_compile.h"
31#include "schema_compile_node.h"
Michal Vasko29dd11e2020-11-23 16:52:22 +010032#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020033#include "set.h"
34#include "tree.h"
Michal Vasko899c7ce2022-02-18 09:18:37 +010035#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010036#include "tree_edit.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020037#include "tree_schema.h"
38#include "tree_schema_internal.h"
39#include "xpath.h"
40
Michal Vasko0b50f6b2022-10-05 15:07:55 +020041/**
42 * @brief Get module of a single nodeid node name test.
43 *
44 * @param[in] ctx libyang context.
45 * @param[in] nametest Nametest with an optional prefix.
46 * @param[in] nametest_len Length of @p nametest.
47 * @param[in] mod Both current and prefix module for resolving prefixes and to return in case of no prefix.
48 * @param[out] name Optional pointer to the name test without the prefix.
49 * @param[out] name_len Length of @p name.
50 * @return Resolved module.
51 */
52static const struct lys_module *
53lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
54 const struct lysp_module *mod, const char **name, size_t *name_len)
55{
56 const struct lys_module *target_mod;
57 const char *ptr;
58
59 ptr = ly_strnchr(nametest, ':', nametest_len);
60 if (ptr) {
61 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_VALUE_SCHEMA, (void *)mod);
62 if (!target_mod) {
63 LOGVAL(ctx, LYVE_REFERENCE,
64 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
65 (int)nametest_len, nametest, (int)(ptr - nametest), nametest, LYSP_MODULE_NAME(mod));
66 return NULL;
67 }
68
69 if (name) {
70 *name = ptr + 1;
71 *name_len = nametest_len - ((ptr - nametest) + 1);
72 }
73 } else {
74 target_mod = mod->mod;
75 if (name) {
76 *name = nametest;
77 *name_len = nametest_len;
78 }
79 }
80
81 return target_mod;
82}
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020083
Michal Vasko1ccbf542021-04-19 11:35:00 +020084/**
85 * @brief Check the syntax of a node-id and collect all the referenced modules.
86 *
87 * @param[in] ctx Compile context.
88 * @param[in] nodeid Node-id to check.
89 * @param[in] abs Whether @p nodeid is absolute.
90 * @param[in,out] mod_set Set to add referenced modules into.
91 * @param[out] expr Optional node-id parsed into an expression.
92 * @param[out] target_mod Optional target module of the node-id.
93 * @return LY_ERR value.
94 */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020095static LY_ERR
Michal Vasko1ccbf542021-04-19 11:35:00 +020096lys_nodeid_mod_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct ly_set *mod_set,
97 struct lyxp_expr **expr, struct lys_module **target_mod)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020098{
99 LY_ERR ret = LY_SUCCESS;
100 struct lyxp_expr *e = NULL;
101 struct lys_module *tmod = NULL, *mod;
102 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
103 uint32_t i;
104
105 /* parse */
106 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
107 if (ret) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100108 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200109 nodeid_type, nodeid);
110 ret = LY_EVALID;
111 goto cleanup;
112 }
113
114 if (abs) {
115 /* absolute schema nodeid */
116 i = 0;
117 } else {
118 /* descendant schema nodeid */
119 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100120 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200121 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
122 ret = LY_EVALID;
123 goto cleanup;
124 }
125 i = 1;
126 }
127
128 /* check all the tokens */
129 for ( ; i < e->used; i += 2) {
130 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100131 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200132 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
133 ret = LY_EVALID;
134 goto cleanup;
135 } else if (e->used == i + 1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100136 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200137 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
138 ret = LY_EVALID;
139 goto cleanup;
140 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100141 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200142 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
143 ret = LY_EVALID;
144 goto cleanup;
145 } else if (abs) {
146 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
147 e->tok_len[i + 1], ctx->pmod, NULL, NULL);
148 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
149
150 /* only keep the first module */
151 if (!tmod) {
152 tmod = mod;
153 }
154
Michal Vasko1ccbf542021-04-19 11:35:00 +0200155 /* store the referenced module */
156 LY_CHECK_GOTO(ret = ly_set_add(mod_set, mod, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200157 }
158 }
159
160cleanup:
161 if (ret || !expr) {
162 lyxp_expr_free(ctx->ctx, e);
163 e = NULL;
164 }
165 if (expr) {
166 *expr = ret ? NULL : e;
167 }
168 if (target_mod) {
169 *target_mod = ret ? NULL : tmod;
170 }
171 return ret;
172}
173
174/**
175 * @brief Check whether 2 schema nodeids match.
176 *
177 * @param[in] ctx libyang context.
178 * @param[in] exp1 First schema nodeid.
179 * @param[in] exp1p_mod Module of @p exp1 nodes without any prefix.
180 * @param[in] exp2 Second schema nodeid.
181 * @param[in] exp2_pmod Module of @p exp2 nodes without any prefix.
182 * @return Whether the schema nodeids match or not.
183 */
184static ly_bool
185lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lysp_module *exp1_pmod,
186 const struct lyxp_expr *exp2, const struct lysp_module *exp2_pmod)
187{
188 uint32_t i;
189 const struct lys_module *mod1, *mod2;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100190 const char *name1 = NULL, *name2 = NULL;
191 size_t name1_len = 0, name2_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200192
193 if (exp1->used != exp2->used) {
194 return 0;
195 }
196
197 for (i = 0; i < exp1->used; ++i) {
198 assert(exp1->tokens[i] == exp2->tokens[i]);
199
200 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
201 /* check modules of all the nodes in the node ID */
202 mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_pmod,
203 &name1, &name1_len);
204 assert(mod1);
205 mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_pmod,
206 &name2, &name2_len);
207 assert(mod2);
208
209 /* compare modules */
210 if (mod1 != mod2) {
211 return 0;
212 }
213
214 /* compare names */
215 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
216 return 0;
217 }
218 }
219 }
220
221 return 1;
222}
223
224LY_ERR
225lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
226{
227 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200228 struct lyxp_expr *exp = NULL;
229 struct lysc_augment *aug;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100230 struct lysp_node_augment *aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200231 struct lysc_refine *rfn;
232 struct lysp_refine **new_rfn;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100233 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200234 uint32_t i;
Michal Vasko1ccbf542021-04-19 11:35:00 +0200235 struct ly_set mod_set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200236
Radek Krejci2a9fc652021-01-22 17:44:34 +0100237 LY_LIST_FOR(uses_p->augments, aug_p) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200238 lysc_update_path(ctx, NULL, "{augment}");
Radek Krejci2a9fc652021-01-22 17:44:34 +0100239 lysc_update_path(ctx, NULL, aug_p->nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200240
241 /* parse the nodeid */
Michal Vasko1ccbf542021-04-19 11:35:00 +0200242 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 +0200243
244 /* allocate new compiled augment and store it in the set */
245 aug = calloc(1, sizeof *aug);
246 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
247 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
248
249 aug->nodeid = exp;
250 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +0100251 aug->aug_pmod = ctx->pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200252 aug->nodeid_ctx_node = ctx_node;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100253 aug->aug_p = aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200254
255 lysc_update_path(ctx, NULL, NULL);
256 lysc_update_path(ctx, NULL, NULL);
257 }
258
259 LY_ARRAY_FOR(uses_p->refines, u) {
260 lysc_update_path(ctx, NULL, "{refine}");
261 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
262
263 /* parse the nodeid */
Michal Vasko1ccbf542021-04-19 11:35:00 +0200264 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 +0200265
266 /* try to find the node in already compiled refines */
267 rfn = NULL;
268 for (i = 0; i < ctx->uses_rfns.count; ++i) {
269 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
270 ctx->pmod)) {
271 rfn = ctx->uses_rfns.objs[i];
272 break;
273 }
274 }
275
276 if (!rfn) {
277 /* allocate new compiled refine */
278 rfn = calloc(1, sizeof *rfn);
279 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
280 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
281
282 rfn->nodeid = exp;
283 exp = NULL;
Michal Vasko7d3708f2021-02-03 10:50:24 +0100284 rfn->nodeid_pmod = ctx->cur_mod->parsed;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200285 rfn->nodeid_ctx_node = ctx_node;
Michal Vaskod8655722021-01-12 15:20:36 +0100286 rfn->uses_p = uses_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200287 } else {
288 /* just free exp */
289 lyxp_expr_free(ctx->ctx, exp);
290 exp = NULL;
291 }
292
293 /* add new parsed refine structure */
294 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
295 *new_rfn = &uses_p->refines[u];
296
297 lysc_update_path(ctx, NULL, NULL);
298 lysc_update_path(ctx, NULL, NULL);
299 }
300
301cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +0200302 if (ret) {
303 lysc_update_path(ctx, NULL, NULL);
304 lysc_update_path(ctx, NULL, NULL);
305 }
306 /* should include only this module, will fail later if not */
307 ly_set_erase(&mod_set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200308 lyxp_expr_free(ctx->ctx, exp);
309 return ret;
310}
311
312static LY_ERR
Michal Vasko899c7ce2022-02-18 09:18:37 +0100313lysp_ext_children_dup(const struct ly_ctx *ctx, struct lysp_stmt **child, const struct lysp_stmt *orig_child)
314{
Michal Vaskod84b8132022-03-15 10:45:44 +0100315 struct lysp_stmt *ch = NULL;
Michal Vasko4316c9d2022-02-21 10:00:10 +0100316
Michal Vasko9464f422022-02-21 10:18:28 +0100317 assert(!*child);
318
Michal Vasko899c7ce2022-02-18 09:18:37 +0100319 LY_LIST_FOR(orig_child, orig_child) {
320 /* new child */
321 if (!*child) {
Michal Vasko4316c9d2022-02-21 10:00:10 +0100322 *child = ch = calloc(1, sizeof *ch);
323 LY_CHECK_ERR_RET(!ch, LOGMEM(ctx), LY_EMEM);
Michal Vasko899c7ce2022-02-18 09:18:37 +0100324 } else {
Michal Vasko4316c9d2022-02-21 10:00:10 +0100325 ch->next = calloc(1, sizeof *ch);
326 LY_CHECK_ERR_RET(!ch->next, LOGMEM(ctx), LY_EMEM);
327 ch = ch->next;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100328 }
329
330 /* fill */
Michal Vasko4316c9d2022-02-21 10:00:10 +0100331 DUP_STRING_RET(ctx, orig_child->stmt, ch->stmt);
332 ch->flags = orig_child->flags;
333 DUP_STRING_RET(ctx, orig_child->arg, ch->arg);
334 ch->format = orig_child->format;
335 LY_CHECK_RET(ly_dup_prefix_data(ctx, orig_child->format, orig_child->prefix_data, &(ch->prefix_data)));
336 ch->kw = orig_child->kw;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100337
338 /* recursive children */
Michal Vasko4316c9d2022-02-21 10:00:10 +0100339 LY_CHECK_RET(lysp_ext_children_dup(ctx, &ch->child, orig_child->child));
Michal Vasko899c7ce2022-02-18 09:18:37 +0100340 }
341
342 return LY_SUCCESS;
343}
344
345static LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200346lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
347{
Michal Vasko899c7ce2022-02-18 09:18:37 +0100348 DUP_STRING_RET(ctx, orig_ext->name, ext->name);
349 DUP_STRING_RET(ctx, orig_ext->argument, ext->argument);
Michal Vasko91bb76c2022-03-24 13:34:18 +0100350 ext->format = orig_ext->format;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100351 ext->parsed = NULL;
Michal Vasko91bb76c2022-03-24 13:34:18 +0100352 LY_CHECK_RET(ly_dup_prefix_data(ctx, orig_ext->format, orig_ext->prefix_data, &ext->prefix_data));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200353
Michal Vasko899c7ce2022-02-18 09:18:37 +0100354 ext->child = NULL;
355 LY_CHECK_RET(lysp_ext_children_dup(ctx, &ext->child, orig_ext->child));
356
Michal Vasko91bb76c2022-03-24 13:34:18 +0100357 ext->parent = orig_ext->parent;
358 ext->parent_stmt = orig_ext->parent_stmt;
359 ext->parent_stmt_index = orig_ext->parent_stmt_index;
360 ext->flags = orig_ext->flags;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100361 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200362}
363
364static LY_ERR
365lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
366{
367 LY_ERR ret = LY_SUCCESS;
368
369 if (orig_restr) {
370 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
371 restr->arg.mod = orig_restr->arg.mod;
372 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
373 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
374 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
375 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
376 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
377 }
378
379 return ret;
380}
381
382static LY_ERR
383lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
384{
385 LY_ERR ret = LY_SUCCESS;
386
387 DUP_STRING(ctx, *orig_str, *str, ret);
388
389 return ret;
390}
391
392LY_ERR
393lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
394{
395 LY_ERR ret = LY_SUCCESS;
396
397 if (!orig_qname->str) {
398 return LY_SUCCESS;
399 }
400
401 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
402 assert(orig_qname->mod);
403 qname->mod = orig_qname->mod;
404
405 return ret;
406}
407
408static LY_ERR
409lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
410{
411 LY_ERR ret = LY_SUCCESS;
412
413 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
414 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
415 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
416 enm->value = orig_enm->value;
417 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
418 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
419 enm->flags = orig_enm->flags;
420
421 return ret;
422}
423
424static LY_ERR
425lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
426{
427 LY_ERR ret = LY_SUCCESS;
428
Michal Vaskoea868242021-06-21 09:28:32 +0200429 /* array macros read previous data so we must zero it */
430 memset(type, 0, sizeof *type);
431
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200432 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
433
434 if (orig_type->range) {
435 type->range = calloc(1, sizeof *type->range);
436 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
437 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
438 }
439
440 if (orig_type->length) {
441 type->length = calloc(1, sizeof *type->length);
442 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
443 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
444 }
445
446 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
447 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
448 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
Michal Vaskoe33134a2022-07-29 14:54:40 +0200449 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, 0, 0, &type->path), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200450 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
451 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
452 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
453
454 type->pmod = orig_type->pmod;
455 type->compiled = orig_type->compiled;
456
457 type->fraction_digits = orig_type->fraction_digits;
458 type->require_instance = orig_type->require_instance;
459 type->flags = orig_type->flags;
460
461done:
462 return ret;
463}
464
465static LY_ERR
466lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
467{
468 LY_ERR ret = LY_SUCCESS;
469
470 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
471 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
472 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
473 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
474
475 return ret;
476}
477
478static LY_ERR
479lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
480{
481 LY_ERR ret = LY_SUCCESS;
482
483 node->parent = NULL;
484 node->nodetype = orig->nodetype;
485 node->flags = orig->flags;
486 node->next = NULL;
487 DUP_STRING(ctx, orig->name, node->name, ret);
488 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
489 DUP_STRING(ctx, orig->ref, node->ref, ret);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200490 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
491 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
492
493 return ret;
494}
495
Radek Krejci9a3823e2021-01-27 20:26:46 +0100496#define DUP_PWHEN(CTX, ORIG, NEW) \
497 if (ORIG) { \
498 NEW = calloc(1, sizeof *NEW); \
499 LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \
500 LY_CHECK_RET(lysp_when_dup(CTX, NEW, ORIG)); \
501 }
502
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200503static LY_ERR
504lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
505{
506 LY_ERR ret = LY_SUCCESS;
507 struct lysp_node_container *cont;
508 const struct lysp_node_container *orig_cont;
509 struct lysp_node_leaf *leaf;
510 const struct lysp_node_leaf *orig_leaf;
511 struct lysp_node_leaflist *llist;
512 const struct lysp_node_leaflist *orig_llist;
513 struct lysp_node_list *list;
514 const struct lysp_node_list *orig_list;
515 struct lysp_node_choice *choice;
516 const struct lysp_node_choice *orig_choice;
517 struct lysp_node_case *cas;
518 const struct lysp_node_case *orig_cas;
519 struct lysp_node_anydata *any;
520 const struct lysp_node_anydata *orig_any;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100521 struct lysp_node_action *action;
522 const struct lysp_node_action *orig_action;
523 struct lysp_node_action_inout *action_inout;
524 const struct lysp_node_action_inout *orig_action_inout;
525 struct lysp_node_notif *notif;
526 const struct lysp_node_notif *orig_notif;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200527
Radek Krejci2a9fc652021-01-22 17:44:34 +0100528 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA |
529 LYS_RPC | LYS_ACTION | LYS_NOTIF));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200530
531 /* common part */
532 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
533
534 /* specific part */
535 switch (node->nodetype) {
536 case LYS_CONTAINER:
537 cont = (struct lysp_node_container *)node;
538 orig_cont = (const struct lysp_node_container *)orig;
539
Radek Krejci9a3823e2021-01-27 20:26:46 +0100540 DUP_PWHEN(ctx, orig_cont->when, cont->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200541 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
542 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
543 /* we do not need the rest */
544 break;
545 case LYS_LEAF:
546 leaf = (struct lysp_node_leaf *)node;
547 orig_leaf = (const struct lysp_node_leaf *)orig;
548
Radek Krejci9a3823e2021-01-27 20:26:46 +0100549 DUP_PWHEN(ctx, orig_leaf->when, leaf->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200550 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
551 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
552 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
553 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
554 break;
555 case LYS_LEAFLIST:
556 llist = (struct lysp_node_leaflist *)node;
557 orig_llist = (const struct lysp_node_leaflist *)orig;
558
Radek Krejci9a3823e2021-01-27 20:26:46 +0100559 DUP_PWHEN(ctx, orig_llist->when, llist->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200560 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
561 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
562 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
563 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
564 llist->min = orig_llist->min;
565 llist->max = orig_llist->max;
566 break;
567 case LYS_LIST:
568 list = (struct lysp_node_list *)node;
569 orig_list = (const struct lysp_node_list *)orig;
570
Radek Krejci9a3823e2021-01-27 20:26:46 +0100571 DUP_PWHEN(ctx, orig_list->when, list->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200572 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
573 DUP_STRING(ctx, orig_list->key, list->key, ret);
574 /* we do not need these arrays */
575 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
576 list->min = orig_list->min;
577 list->max = orig_list->max;
578 break;
579 case LYS_CHOICE:
580 choice = (struct lysp_node_choice *)node;
581 orig_choice = (const struct lysp_node_choice *)orig;
582
Radek Krejci9a3823e2021-01-27 20:26:46 +0100583 DUP_PWHEN(ctx, orig_choice->when, choice->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200584 /* we do not need children */
585 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
586 break;
587 case LYS_CASE:
588 cas = (struct lysp_node_case *)node;
589 orig_cas = (const struct lysp_node_case *)orig;
590
Radek Krejci9a3823e2021-01-27 20:26:46 +0100591 DUP_PWHEN(ctx, orig_cas->when, cas->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200592 /* we do not need children */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200593 break;
594 case LYS_ANYDATA:
595 case LYS_ANYXML:
596 any = (struct lysp_node_anydata *)node;
597 orig_any = (const struct lysp_node_anydata *)orig;
598
Radek Krejci9a3823e2021-01-27 20:26:46 +0100599 DUP_PWHEN(ctx, orig_any->when, any->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200600 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
601 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100602 case LYS_RPC:
603 case LYS_ACTION:
604 action = (struct lysp_node_action *)node;
605 orig_action = (const struct lysp_node_action *)orig;
606
607 action->input.nodetype = orig_action->input.nodetype;
608 action->output.nodetype = orig_action->output.nodetype;
609 /* we do not need the rest */
610 break;
611 case LYS_INPUT:
612 case LYS_OUTPUT:
613 action_inout = (struct lysp_node_action_inout *)node;
614 orig_action_inout = (const struct lysp_node_action_inout *)orig;
615
616 DUP_ARRAY(ctx, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
617 /* we do not need the rest */
618 break;
619 case LYS_NOTIF:
620 notif = (struct lysp_node_notif *)node;
621 orig_notif = (const struct lysp_node_notif *)orig;
622
623 DUP_ARRAY(ctx, orig_notif->musts, notif->musts, lysp_restr_dup);
624 /* we do not need the rest */
625 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200626 default:
627 LOGINT_RET(ctx);
628 }
629
630 return ret;
631}
632
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200633/**
634 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
635 *
636 * @param[in] ctx libyang context.
637 * @param[in] pnode Node to duplicate.
638 * @param[in] with_links Whether to also copy any links (child, parent pointers).
639 * @param[out] dup_p Duplicated parsed node.
640 * @return LY_ERR value.
641 */
642static LY_ERR
643lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
644{
645 LY_ERR ret = LY_SUCCESS;
646 void *mem = NULL;
647
648 if (!pnode) {
649 *dup_p = NULL;
650 return LY_SUCCESS;
651 }
652
653 switch (pnode->nodetype) {
654 case LYS_CONTAINER:
655 mem = calloc(1, sizeof(struct lysp_node_container));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200656 break;
657 case LYS_LEAF:
658 mem = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200659 break;
660 case LYS_LEAFLIST:
661 mem = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200662 break;
663 case LYS_LIST:
664 mem = calloc(1, sizeof(struct lysp_node_list));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200665 break;
666 case LYS_CHOICE:
667 mem = calloc(1, sizeof(struct lysp_node_choice));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200668 break;
669 case LYS_CASE:
670 mem = calloc(1, sizeof(struct lysp_node_case));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200671 break;
672 case LYS_ANYDATA:
673 case LYS_ANYXML:
674 mem = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200675 break;
676 case LYS_INPUT:
677 case LYS_OUTPUT:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100678 mem = calloc(1, sizeof(struct lysp_node_action_inout));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200679 break;
680 case LYS_ACTION:
681 case LYS_RPC:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100682 mem = calloc(1, sizeof(struct lysp_node_action));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200683 break;
684 case LYS_NOTIF:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100685 mem = calloc(1, sizeof(struct lysp_node_notif));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200686 break;
687 default:
688 LOGINT_RET(ctx);
689 }
Radek Krejci2a9fc652021-01-22 17:44:34 +0100690 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
691 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200692
693 if (with_links) {
Michal Vaskoec8f4272021-10-27 09:14:03 +0200694 /* copy also parent, child, action, and notification pointers */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200695 ((struct lysp_node *)mem)->parent = pnode->parent;
696 switch (pnode->nodetype) {
697 case LYS_CONTAINER:
698 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
Michal Vaskoec8f4272021-10-27 09:14:03 +0200699 ((struct lysp_node_container *)mem)->actions = ((struct lysp_node_container *)pnode)->actions;
700 ((struct lysp_node_container *)mem)->notifs = ((struct lysp_node_container *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200701 break;
702 case LYS_LIST:
703 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
Michal Vaskoec8f4272021-10-27 09:14:03 +0200704 ((struct lysp_node_list *)mem)->actions = ((struct lysp_node_list *)pnode)->actions;
705 ((struct lysp_node_list *)mem)->notifs = ((struct lysp_node_list *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200706 break;
707 case LYS_CHOICE:
708 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
709 break;
710 case LYS_CASE:
711 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
712 break;
713 default:
714 break;
715 }
716 }
717
718cleanup:
719 if (ret) {
720 free(mem);
721 } else {
722 *dup_p = mem;
723 }
724 return ret;
725}
726
727#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100728 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 +0200729 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
730 ret = LY_EVALID; \
731 goto cleanup;
732
733#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
734 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100735 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 +0200736 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
737 ret = LY_EVALID; \
738 goto cleanup; \
739 }
740
741/**
742 * @brief Apply refine.
743 *
744 * @param[in] ctx Compile context.
745 * @param[in] rfn Refine to apply.
746 * @param[in,out] target Refine target.
747 * @return LY_ERR value.
748 */
749static LY_ERR
750lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
751{
752 LY_ERR ret = LY_SUCCESS;
753 LY_ARRAY_COUNT_TYPE u;
754 struct lysp_qname *qname;
755 struct lysp_restr **musts, *must;
756 uint32_t *num;
757
758 /* default value */
759 if (rfn->dflts) {
760 switch (target->nodetype) {
761 case LYS_LEAF:
762 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
763
Michal Vaskoe180ed02021-02-05 16:31:20 +0100764 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200765 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &rfn->dflts[0]), cleanup);
766 break;
767 case LYS_LEAFLIST:
768 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100769 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200770 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
771 ret = LY_EVALID;
772 goto cleanup;
773 }
774
775 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
776 ((struct lysp_node_leaflist *)target)->dflts = NULL;
777 LY_ARRAY_FOR(rfn->dflts, u) {
778 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
779 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup);
780 }
781 break;
782 case LYS_CHOICE:
783 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
784
Michal Vaskoe180ed02021-02-05 16:31:20 +0100785 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200786 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &rfn->dflts[0]), cleanup);
787 break;
788 default:
789 AMEND_WRONG_NODETYPE("refine", "replace", "default");
790 }
791 }
792
793 /* description */
794 if (rfn->dsc) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100795 lydict_remove(ctx->ctx, target->dsc);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200796 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
797 }
798
799 /* reference */
800 if (rfn->ref) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100801 lydict_remove(ctx->ctx, target->ref);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200802 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
803 }
804
805 /* config */
806 if (rfn->flags & LYS_CONFIG_MASK) {
Michal Vasko7c565922021-06-10 14:58:27 +0200807 if (ctx->compile_opts & LYS_COMPILE_NO_CONFIG) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200808 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Michal Vasko7c565922021-06-10 14:58:27 +0200809 (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT)) ? "RPC/action" :
810 ctx->compile_opts & LYS_IS_NOTIF ? "notification" : "a subtree ignoring config", ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200811 } else {
812 target->flags &= ~LYS_CONFIG_MASK;
813 target->flags |= rfn->flags & LYS_CONFIG_MASK;
814 }
815 }
816
817 /* mandatory */
818 if (rfn->flags & LYS_MAND_MASK) {
819 switch (target->nodetype) {
820 case LYS_LEAF:
821 case LYS_CHOICE:
822 case LYS_ANYDATA:
823 case LYS_ANYXML:
824 break;
825 default:
826 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
827 }
828
829 target->flags &= ~LYS_MAND_MASK;
830 target->flags |= rfn->flags & LYS_MAND_MASK;
831 }
832
833 /* presence */
834 if (rfn->presence) {
835 switch (target->nodetype) {
836 case LYS_CONTAINER:
837 break;
838 default:
839 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
840 }
841
Michal Vaskoe180ed02021-02-05 16:31:20 +0100842 lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200843 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
844 }
845
846 /* must */
847 if (rfn->musts) {
848 switch (target->nodetype) {
849 case LYS_CONTAINER:
850 case LYS_LIST:
851 case LYS_LEAF:
852 case LYS_LEAFLIST:
853 case LYS_ANYDATA:
854 case LYS_ANYXML:
855 musts = &((struct lysp_node_container *)target)->musts;
856 break;
857 default:
858 AMEND_WRONG_NODETYPE("refine", "add", "must");
859 }
860
861 LY_ARRAY_FOR(rfn->musts, u) {
862 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
863 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
864 }
865 }
866
867 /* min-elements */
868 if (rfn->flags & LYS_SET_MIN) {
869 switch (target->nodetype) {
870 case LYS_LEAFLIST:
871 num = &((struct lysp_node_leaflist *)target)->min;
872 break;
873 case LYS_LIST:
874 num = &((struct lysp_node_list *)target)->min;
875 break;
876 default:
877 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
878 }
879
880 *num = rfn->min;
881 }
882
883 /* max-elements */
884 if (rfn->flags & LYS_SET_MAX) {
885 switch (target->nodetype) {
886 case LYS_LEAFLIST:
887 num = &((struct lysp_node_leaflist *)target)->max;
888 break;
889 case LYS_LIST:
890 num = &((struct lysp_node_list *)target)->max;
891 break;
892 default:
893 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
894 }
895
896 *num = rfn->max;
897 }
898
899 /* if-feature */
900 if (rfn->iffeatures) {
901 switch (target->nodetype) {
902 case LYS_LEAF:
903 case LYS_LEAFLIST:
904 case LYS_LIST:
905 case LYS_CONTAINER:
906 case LYS_CHOICE:
907 case LYS_CASE:
908 case LYS_ANYDATA:
909 case LYS_ANYXML:
910 break;
911 default:
912 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
913 }
914
915 LY_ARRAY_FOR(rfn->iffeatures, u) {
916 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
917 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup);
918 }
919 }
920
921 /* extension */
922 /* TODO refine extensions */
923
924cleanup:
925 return ret;
926}
927
928/**
929 * @brief Apply deviate add.
930 *
931 * @param[in] ctx Compile context.
932 * @param[in] d Deviate add to apply.
933 * @param[in,out] target Deviation target.
934 * @return LY_ERR value.
935 */
936static LY_ERR
937lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
938{
939 LY_ERR ret = LY_SUCCESS;
940 LY_ARRAY_COUNT_TYPE u;
941 struct lysp_qname *qname;
942 uint32_t *num;
943 struct lysp_restr **musts, *must;
944
945#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
946 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100947 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200948 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
949 ret = LY_EVALID; \
950 goto cleanup; \
951 }
952
953 /* [units-stmt] */
954 if (d->units) {
955 switch (target->nodetype) {
956 case LYS_LEAF:
957 case LYS_LEAFLIST:
958 break;
959 default:
960 AMEND_WRONG_NODETYPE("deviation", "add", "units");
961 }
962
963 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
964 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
965 }
966
967 /* *must-stmt */
968 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100969 musts = lysp_node_musts_p(target);
970 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200971 AMEND_WRONG_NODETYPE("deviation", "add", "must");
972 }
973
974 LY_ARRAY_FOR(d->musts, u) {
975 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
976 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
977 }
978 }
979
980 /* *unique-stmt */
981 if (d->uniques) {
982 switch (target->nodetype) {
983 case LYS_LIST:
984 break;
985 default:
986 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
987 }
988
989 LY_ARRAY_FOR(d->uniques, u) {
990 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
991 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup);
992 }
993 }
994
995 /* *default-stmt */
996 if (d->dflts) {
997 switch (target->nodetype) {
998 case LYS_LEAF:
999 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1000 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
1001
1002 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflts[0]), cleanup);
1003 break;
1004 case LYS_LEAFLIST:
1005 LY_ARRAY_FOR(d->dflts, u) {
1006 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
1007 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup);
1008 }
1009 break;
1010 case LYS_CHOICE:
1011 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1012 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
1013
1014 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflts[0]), cleanup);
1015 break;
1016 default:
1017 AMEND_WRONG_NODETYPE("deviation", "add", "default");
1018 }
1019 }
1020
1021 /* [config-stmt] */
1022 if (d->flags & LYS_CONFIG_MASK) {
1023 switch (target->nodetype) {
1024 case LYS_CONTAINER:
1025 case LYS_LEAF:
1026 case LYS_LEAFLIST:
1027 case LYS_LIST:
1028 case LYS_CHOICE:
1029 case LYS_ANYDATA:
1030 case LYS_ANYXML:
1031 break;
1032 default:
1033 AMEND_WRONG_NODETYPE("deviation", "add", "config");
1034 }
1035
1036 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001037 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001038 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
1039 target->flags & LYS_CONFIG_W ? "true" : "false");
1040 ret = LY_EVALID;
1041 goto cleanup;
1042 }
1043
1044 target->flags |= d->flags & LYS_CONFIG_MASK;
1045 }
1046
1047 /* [mandatory-stmt] */
1048 if (d->flags & LYS_MAND_MASK) {
1049 switch (target->nodetype) {
1050 case LYS_LEAF:
1051 case LYS_CHOICE:
1052 case LYS_ANYDATA:
1053 case LYS_ANYXML:
1054 break;
1055 default:
1056 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
1057 }
1058
1059 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001060 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001061 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
1062 target->flags & LYS_MAND_TRUE ? "true" : "false");
1063 ret = LY_EVALID;
1064 goto cleanup;
1065 }
1066
1067 target->flags |= d->flags & LYS_MAND_MASK;
1068 }
1069
1070 /* [min-elements-stmt] */
1071 if (d->flags & LYS_SET_MIN) {
1072 switch (target->nodetype) {
1073 case LYS_LEAFLIST:
1074 num = &((struct lysp_node_leaflist *)target)->min;
1075 break;
1076 case LYS_LIST:
1077 num = &((struct lysp_node_list *)target)->min;
1078 break;
1079 default:
1080 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
1081 }
1082
1083 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001084 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001085 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
1086 ret = LY_EVALID;
1087 goto cleanup;
1088 }
1089
1090 *num = d->min;
1091 }
1092
1093 /* [max-elements-stmt] */
1094 if (d->flags & LYS_SET_MAX) {
1095 switch (target->nodetype) {
1096 case LYS_LEAFLIST:
1097 num = &((struct lysp_node_leaflist *)target)->max;
1098 break;
1099 case LYS_LIST:
1100 num = &((struct lysp_node_list *)target)->max;
1101 break;
1102 default:
1103 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1104 }
1105
1106 if (target->flags & LYS_SET_MAX) {
1107 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001108 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001109 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1110 *num);
1111 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001112 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001113 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1114 }
1115 ret = LY_EVALID;
1116 goto cleanup;
1117 }
1118
1119 *num = d->max;
1120 }
1121
1122cleanup:
1123 return ret;
1124}
1125
1126/**
1127 * @brief Apply deviate delete.
1128 *
1129 * @param[in] ctx Compile context.
1130 * @param[in] d Deviate delete to apply.
1131 * @param[in,out] target Deviation target.
1132 * @return LY_ERR value.
1133 */
1134static LY_ERR
1135lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1136{
1137 LY_ERR ret = LY_SUCCESS;
1138 struct lysp_restr **musts;
1139 LY_ARRAY_COUNT_TYPE u, v;
1140 struct lysp_qname **uniques, **dflts;
1141
Michal Vaskoc636ea42022-09-16 10:20:31 +02001142#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, FREE_CTX, PROPERTY) \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001143 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1144 int found = 0; \
1145 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1146 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1147 found = 1; \
1148 break; \
1149 } \
1150 } \
1151 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001152 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001153 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1154 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1155 ret = LY_EVALID; \
1156 goto cleanup; \
1157 } \
1158 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
Michal Vaskoc636ea42022-09-16 10:20:31 +02001159 FREE_FUNC(FREE_CTX, &(ORIG_ARRAY)[v]); \
Michal Vasko08e9b112021-06-11 15:41:17 +02001160 if (v < LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1161 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1162 } \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001163 } \
1164 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1165 LY_ARRAY_FREE(ORIG_ARRAY); \
1166 ORIG_ARRAY = NULL; \
1167 }
1168
1169#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1170 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001171 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001172 ret = LY_EVALID; \
1173 goto cleanup; \
1174 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001175 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001176 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1177 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1178 ret = LY_EVALID; \
1179 goto cleanup; \
1180 }
1181
1182 /* [units-stmt] */
1183 if (d->units) {
1184 switch (target->nodetype) {
1185 case LYS_LEAF:
1186 case LYS_LEAFLIST:
1187 break;
1188 default:
1189 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1190 }
1191
1192 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001193 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001194 ((struct lysp_node_leaf *)target)->units = NULL;
1195 }
1196
1197 /* *must-stmt */
1198 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001199 musts = lysp_node_musts_p(target);
1200 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001201 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1202 }
1203
Michal Vaskoc636ea42022-09-16 10:20:31 +02001204 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, &ctx->free_ctx, "must");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001205 }
1206
1207 /* *unique-stmt */
1208 if (d->uniques) {
1209 switch (target->nodetype) {
1210 case LYS_LIST:
1211 break;
1212 default:
1213 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1214 }
1215
1216 uniques = &((struct lysp_node_list *)target)->uniques;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001217 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, ctx->ctx, "unique");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001218 }
1219
1220 /* *default-stmt */
1221 if (d->dflts) {
1222 switch (target->nodetype) {
1223 case LYS_LEAF:
1224 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1225 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1226
Michal Vaskoe180ed02021-02-05 16:31:20 +01001227 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001228 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1229 break;
1230 case LYS_LEAFLIST:
1231 dflts = &((struct lysp_node_leaflist *)target)->dflts;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001232 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, ctx->ctx, "default");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001233 break;
1234 case LYS_CHOICE:
1235 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1236 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1237
Michal Vaskoe180ed02021-02-05 16:31:20 +01001238 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001239 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1240 break;
1241 default:
1242 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1243 }
1244 }
1245
1246cleanup:
1247 return ret;
1248}
1249
1250/**
1251 * @brief Apply deviate replace.
1252 *
1253 * @param[in] ctx Compile context.
1254 * @param[in] d Deviate replace to apply.
1255 * @param[in,out] target Deviation target.
1256 * @return LY_ERR value.
1257 */
1258static LY_ERR
1259lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1260{
1261 LY_ERR ret = LY_SUCCESS;
1262 uint32_t *num;
1263
1264#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1265 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001266 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001267 ret = LY_EVALID; \
1268 goto cleanup; \
1269 }
1270
1271 /* [type-stmt] */
1272 if (d->type) {
1273 switch (target->nodetype) {
1274 case LYS_LEAF:
1275 case LYS_LEAFLIST:
1276 break;
1277 default:
1278 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1279 }
1280
Michal Vaskoc636ea42022-09-16 10:20:31 +02001281 lysp_type_free(&ctx->free_ctx, &((struct lysp_node_leaf *)target)->type);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001282 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
1283 }
1284
1285 /* [units-stmt] */
1286 if (d->units) {
1287 switch (target->nodetype) {
1288 case LYS_LEAF:
1289 case LYS_LEAFLIST:
1290 break;
1291 default:
1292 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1293 }
1294
1295 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001296 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001297 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1298 }
1299
1300 /* [default-stmt] */
1301 if (d->dflt.str) {
1302 switch (target->nodetype) {
1303 case LYS_LEAF:
1304 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1305
Michal Vaskoe180ed02021-02-05 16:31:20 +01001306 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001307 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflt), cleanup);
1308 break;
1309 case LYS_CHOICE:
1310 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
1311
Michal Vaskoe180ed02021-02-05 16:31:20 +01001312 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001313 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflt), cleanup);
1314 break;
1315 default:
1316 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1317 }
1318 }
1319
1320 /* [config-stmt] */
1321 if (d->flags & LYS_CONFIG_MASK) {
1322 switch (target->nodetype) {
1323 case LYS_CONTAINER:
1324 case LYS_LEAF:
1325 case LYS_LEAFLIST:
1326 case LYS_LIST:
1327 case LYS_CHOICE:
1328 case LYS_ANYDATA:
1329 case LYS_ANYXML:
1330 break;
1331 default:
1332 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1333 }
1334
1335 if (!(target->flags & LYS_CONFIG_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001336 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "config",
1337 d->flags & LYS_CONFIG_W ? "config true" : "config false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001338 ret = LY_EVALID;
1339 goto cleanup;
1340 }
1341
1342 target->flags &= ~LYS_CONFIG_MASK;
1343 target->flags |= d->flags & LYS_CONFIG_MASK;
1344 }
1345
1346 /* [mandatory-stmt] */
1347 if (d->flags & LYS_MAND_MASK) {
1348 switch (target->nodetype) {
1349 case LYS_LEAF:
1350 case LYS_CHOICE:
1351 case LYS_ANYDATA:
1352 case LYS_ANYXML:
1353 break;
1354 default:
1355 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1356 }
1357
1358 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001359 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1360 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001361 ret = LY_EVALID;
1362 goto cleanup;
1363 }
1364
1365 target->flags &= ~LYS_MAND_MASK;
1366 target->flags |= d->flags & LYS_MAND_MASK;
1367 }
1368
1369 /* [min-elements-stmt] */
1370 if (d->flags & LYS_SET_MIN) {
1371 switch (target->nodetype) {
1372 case LYS_LEAFLIST:
1373 num = &((struct lysp_node_leaflist *)target)->min;
1374 break;
1375 case LYS_LIST:
1376 num = &((struct lysp_node_list *)target)->min;
1377 break;
1378 default:
1379 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1380 }
1381
1382 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001383 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001384 ret = LY_EVALID;
1385 goto cleanup;
1386 }
1387
1388 *num = d->min;
1389 }
1390
1391 /* [max-elements-stmt] */
1392 if (d->flags & LYS_SET_MAX) {
1393 switch (target->nodetype) {
1394 case LYS_LEAFLIST:
1395 num = &((struct lysp_node_leaflist *)target)->max;
1396 break;
1397 case LYS_LIST:
1398 num = &((struct lysp_node_list *)target)->max;
1399 break;
1400 default:
1401 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1402 }
1403
1404 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001405 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001406 ret = LY_EVALID;
1407 goto cleanup;
1408 }
1409
1410 *num = d->max;
1411 }
1412
1413cleanup:
1414 return ret;
1415}
1416
1417/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001418 * @brief Check whether a compiled node matches a single schema nodeid name test.
1419 *
1420 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1421 * @param[in] mod Expected module.
1422 * @param[in] name Expected name.
1423 * @param[in] name_len Length of @p name.
1424 * @return Whether it is a match or not.
1425 */
1426static ly_bool
1427lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1428 size_t name_len)
1429{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001430 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001431 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001432 return 0;
1433 }
1434
1435 /* compare names */
Michal Vasko544e58a2021-01-28 14:33:41 +01001436 if (ly_strncmp((*node)->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001437 return 0;
1438 }
1439
Michal Vasko2a668712020-10-21 11:48:09 +02001440 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001441 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001442
1443 return 1;
1444}
1445
1446/**
1447 * @brief Check whether a node matches specific schema nodeid.
1448 *
1449 * @param[in] exp Parsed nodeid to match.
1450 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
1451 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1452 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1453 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1454 * @param[in] pnode_mod Compiled @p pnode to-be module.
1455 * @return Whether it is a match or not.
1456 */
1457static ly_bool
1458lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node,
1459 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
1460{
1461 uint32_t i;
1462 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001463 const char *name = NULL;
1464 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001465
1466 /* compare last node in the node ID */
1467 i = exp->used - 1;
1468
1469 /* get exp node ID module */
1470 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);
1471 assert(mod);
1472
1473 if (pnode) {
1474 /* compare on the last parsed-only node */
Radek Krejci2d5f6df2021-01-28 14:00:13 +01001475 if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001476 return 0;
1477 }
1478 } else {
1479 /* using parent directly */
1480 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1481 return 0;
1482 }
1483 }
1484
1485 /* now compare all the compiled parents */
1486 while (i > 1) {
1487 i -= 2;
1488 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1489
1490 if (!parent) {
1491 /* no more parents but path continues */
1492 return 0;
1493 }
1494
1495 /* get exp node ID module */
1496 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1497 &name_len);
1498 assert(mod);
1499
1500 /* compare with the parent */
1501 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1502 return 0;
1503 }
1504 }
1505
1506 if (ctx_node && (ctx_node != parent)) {
1507 /* descendant path has not finished in the context node */
1508 return 0;
1509 } else if (!ctx_node && parent) {
1510 /* some parent was not matched */
1511 return 0;
1512 }
1513
1514 return 1;
1515}
1516
1517void
1518lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1519{
1520 if (aug) {
1521 lyxp_expr_free(ctx, aug->nodeid);
1522
1523 free(aug);
1524 }
1525}
1526
1527void
1528lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1529{
1530 if (dev) {
1531 lyxp_expr_free(ctx, dev->nodeid);
1532 LY_ARRAY_FREE(dev->devs);
1533 LY_ARRAY_FREE(dev->dev_pmods);
1534
1535 free(dev);
1536 }
1537}
1538
1539void
1540lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1541{
1542 if (rfn) {
1543 lyxp_expr_free(ctx, rfn->nodeid);
1544 LY_ARRAY_FREE(rfn->rfns);
1545
1546 free(rfn);
1547 }
1548}
1549
1550void
Michal Vaskoc636ea42022-09-16 10:20:31 +02001551lysp_dev_node_free(struct lysc_ctx *cctx, struct lysp_node *dev_pnode)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001552{
1553 if (!dev_pnode) {
1554 return;
1555 }
1556
1557 switch (dev_pnode->nodetype) {
1558 case LYS_CONTAINER:
1559 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001560 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1561 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001562 break;
1563 case LYS_LIST:
1564 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001565 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1566 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001567 break;
1568 case LYS_CHOICE:
1569 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1570 break;
1571 case LYS_CASE:
1572 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1573 break;
1574 case LYS_LEAF:
1575 case LYS_LEAFLIST:
1576 case LYS_ANYXML:
1577 case LYS_ANYDATA:
1578 /* no children */
1579 break;
1580 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001581 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001582 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001583 case LYS_RPC:
1584 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001585 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1586 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001587 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001588 case LYS_INPUT:
1589 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001590 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001591 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001592 free(dev_pnode);
1593 return;
1594 default:
Michal Vaskoc636ea42022-09-16 10:20:31 +02001595 LOGINT(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001596 return;
1597 }
1598
Michal Vaskoc636ea42022-09-16 10:20:31 +02001599 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001600}
1601
1602LY_ERR
1603lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1604 struct lysp_node **dev_pnode, ly_bool *not_supported)
1605{
1606 LY_ERR ret = LY_SUCCESS;
1607 uint32_t i;
1608 LY_ARRAY_COUNT_TYPE u;
1609 struct lys_module *orig_mod = ctx->cur_mod;
1610 struct lysp_module *orig_pmod = ctx->pmod;
1611 char orig_path[LYSC_CTX_BUFSIZE];
1612 struct lysc_refine *rfn;
1613 struct lysc_deviation *dev;
1614 struct lysp_deviation *dev_p;
1615 struct lysp_deviate *d;
1616
1617 *dev_pnode = NULL;
1618 *not_supported = 0;
1619
Michal Vaskoee057572022-05-26 08:31:52 +02001620 for (i = 0; i < ctx->uses_rfns.count; ) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001621 rfn = ctx->uses_rfns.objs[i];
1622
Michal Vasko28fe5f62021-03-03 16:37:39 +01001623 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, rfn->nodeid_ctx_node, parent, pnode, orig_mod)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001624 /* not our target node */
Michal Vaskoee057572022-05-26 08:31:52 +02001625 ++i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001626 continue;
1627 }
1628
1629 if (!*dev_pnode) {
1630 /* first refine on this node, create a copy first */
1631 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1632 }
1633
Michal Vaskob8df5762021-01-12 15:15:53 +01001634 /* use modules from the refine */
1635 ctx->cur_mod = rfn->nodeid_pmod->mod;
1636 ctx->pmod = (struct lysp_module *)rfn->nodeid_pmod;
1637
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001638 /* apply all the refines by changing (the copy of) the parsed node */
1639 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vaskob8df5762021-01-12 15:15:53 +01001640 /* keep the current path and add to it */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001641 lysc_update_path(ctx, NULL, "{refine}");
1642 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001643
1644 /* apply refine and restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001645 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
1646 lysc_update_path(ctx, NULL, NULL);
1647 lysc_update_path(ctx, NULL, NULL);
1648 LY_CHECK_GOTO(ret, cleanup);
1649 }
1650
1651 /* refine was applied, remove it */
1652 lysc_refine_free(ctx->ctx, rfn);
1653 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1654
Michal Vaskoee057572022-05-26 08:31:52 +02001655 /* refines use relative paths so more may apply to a single node */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001656 }
1657
1658 for (i = 0; i < ctx->devs.count; ++i) {
1659 dev = ctx->devs.objs[i];
1660
Michal Vasko28fe5f62021-03-03 16:37:39 +01001661 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, orig_mod)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001662 /* not our target node */
1663 continue;
1664 }
1665
1666 if (dev->not_supported) {
1667 /* it is not supported, no more deviations */
1668 *not_supported = 1;
1669 goto dev_applied;
1670 }
1671
1672 if (!*dev_pnode) {
1673 /* first deviation on this node, create a copy first */
1674 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1675 }
1676
1677 /* apply all the deviates by changing (the copy of) the parsed node */
1678 LY_ARRAY_FOR(dev->devs, u) {
1679 dev_p = dev->devs[u];
1680 LY_LIST_FOR(dev_p->deviates, d) {
1681 /* generate correct path */
1682 strcpy(orig_path, ctx->path);
1683 ctx->path_len = 1;
1684 ctx->cur_mod = dev->dev_pmods[u]->mod;
1685 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
1686 lysc_update_path(ctx, NULL, "{deviation}");
1687 lysc_update_path(ctx, NULL, dev_p->nodeid);
1688
1689 switch (d->mod) {
1690 case LYS_DEV_ADD:
1691 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
1692 break;
1693 case LYS_DEV_DELETE:
1694 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
1695 break;
1696 case LYS_DEV_REPLACE:
1697 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
1698 break;
1699 default:
1700 LOGINT(ctx->ctx);
1701 ret = LY_EINT;
1702 }
1703
1704 /* restore previous path */
1705 strcpy(ctx->path, orig_path);
1706 ctx->path_len = strlen(ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001707
1708 LY_CHECK_GOTO(ret, cleanup);
1709 }
1710 }
1711
1712dev_applied:
1713 /* deviation was applied, remove it */
1714 lysc_deviation_free(ctx->ctx, dev);
1715 ly_set_rm_index(&ctx->devs, i, NULL);
1716
1717 /* all the deviations for one target node are in one structure, we are done */
1718 break;
1719 }
1720
1721cleanup:
Michal Vasko20316b32021-01-12 15:16:54 +01001722 ctx->cur_mod = orig_mod;
1723 ctx->pmod = orig_pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001724 if (ret) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001725 lysp_dev_node_free(ctx, *dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001726 *dev_pnode = NULL;
1727 *not_supported = 0;
1728 }
1729 return ret;
1730}
1731
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001732LY_ERR
1733lys_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 +02001734 struct lysc_node *target, ly_bool child_unres_disabled)
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001735{
1736 LY_ERR rc = LY_SUCCESS;
1737 struct lysp_node *pnode;
1738 struct lysc_node *node;
1739 struct lysc_when *when_shared = NULL;
1740 ly_bool enabled, allow_mand = 0;
1741 struct ly_set child_set = {0};
1742 uint32_t i, opt_prev = ctx->compile_opts;
1743
1744 /* check for mandatory nodes
1745 * - new cases augmenting some choice can have mandatory nodes
1746 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1747 */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001748 if (aug_when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001749 allow_mand = 1;
1750 }
1751
1752 LY_LIST_FOR(child, pnode) {
1753 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1754 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1755 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1756 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1757 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1758 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1759 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1760 rc = LY_EVALID;
1761 goto cleanup;
1762 }
1763
1764 /* compile the children */
1765 if (target->nodetype == LYS_CHOICE) {
1766 LY_CHECK_GOTO(rc = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1767 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1768 if (target->nodetype == LYS_INPUT) {
1769 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
1770 } else {
1771 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
1772 }
1773 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1774 } else {
1775 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1776 }
1777
1778 /* eval if-features again for the rest of this node processing */
1779 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1780 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001781 ctx->compile_opts |= LYS_COMPILE_DISABLED;
1782 }
1783
1784 /* since the augment node is not present in the compiled tree, we need to pass some of its
1785 * statements to all its children */
1786 for (i = 0; i < child_set.count; ++i) {
1787 node = child_set.snodes[i];
1788 if (!allow_mand && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1789 node->flags &= ~LYS_MAND_TRUE;
1790 lys_compile_mandatory_parents(target, 0);
1791 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
1792 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
1793 node->name);
1794 rc = LY_EVALID;
1795 goto cleanup;
1796 }
1797
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001798 if (aug_when) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001799 /* pass augment's when to all the children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001800 rc = lys_compile_when(ctx, aug_when, aug_flags, target, lysc_data_node(target), node, &when_shared);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001801 LY_CHECK_GOTO(rc, cleanup);
1802 }
1803
Michal Vaskoa084fa32022-05-16 11:32:58 +02001804 if (child_unres_disabled) {
Michal Vaskoad0980a2022-05-09 11:43:47 +02001805 /* child is disabled by the augment if-features */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001806 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
1807 }
1808 }
1809
1810 /* next iter */
1811 ly_set_erase(&child_set, NULL);
1812 ctx->compile_opts = opt_prev;
1813 }
1814
1815cleanup:
1816 ly_set_erase(&child_set, NULL);
1817 ctx->compile_opts = opt_prev;
1818 return rc;
1819}
1820
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001821/**
1822 * @brief Compile the parsed augment connecting it into its target.
1823 *
1824 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1825 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1826 * are already implemented and compiled.
1827 *
1828 * @param[in] ctx Compile context.
1829 * @param[in] aug_p Parsed augment to compile.
1830 * @param[in] target Target node of the augment.
1831 * @return LY_SUCCESS on success.
1832 * @return LY_EVALID on failure.
1833 */
1834static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001835lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001836{
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001837 LY_ERR rc = LY_SUCCESS;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001838 ly_bool enabled, child_unres_disabled = 0;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001839 uint32_t opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001840
Michal Vasko95f736c2022-06-08 12:03:31 +02001841 assert(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
1842
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001843 /* nodetype checks */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001844 if (aug_p->actions && !lysc_node_actions_p(target)) {
1845 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1846 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
1847 lys_nodetype2str(target->nodetype), aug_p->actions->name);
1848 rc = LY_EVALID;
1849 goto cleanup;
1850 }
1851 if (aug_p->notifs && !lysc_node_notifs_p(target)) {
1852 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1853 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
1854 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
1855 rc = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001856 goto cleanup;
1857 }
1858
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001859 /* augment if-features */
1860 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, aug_p->iffeatures, &enabled), cleanup);
1861 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001862 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001863 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001864 }
1865
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001866 /* augment children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001867 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, aug_p->child, target, child_unres_disabled);
1868 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001869
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001870 /* augment actions */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001871 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->actions, target,
1872 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001873 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001874
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001875 /* augment notifications */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001876 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->notifs, target,
1877 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001878 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001879
1880cleanup:
Michal Vasko7c565922021-06-10 14:58:27 +02001881 ctx->compile_opts = opt_prev;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001882 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001883}
1884
1885LY_ERR
1886lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
1887{
1888 LY_ERR ret = LY_SUCCESS;
1889 struct lys_module *orig_mod = ctx->cur_mod;
1890 struct lysp_module *orig_pmod = ctx->pmod;
1891 uint32_t i;
1892 char orig_path[LYSC_CTX_BUFSIZE];
1893 struct lysc_augment *aug;
1894
1895 /* uses augments */
1896 for (i = 0; i < ctx->uses_augs.count; ) {
1897 aug = ctx->uses_augs.objs[i];
1898
Michal Vasko28fe5f62021-03-03 16:37:39 +01001899 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->nodeid_ctx_node, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001900 /* not our target node */
1901 ++i;
1902 continue;
1903 }
1904
Michal Vaskob8df5762021-01-12 15:15:53 +01001905 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001906 lysc_update_path(ctx, NULL, "{augment}");
1907 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01001908 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01001909
1910 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001911 ret = lys_compile_augment(ctx, aug->aug_p, node);
1912 lysc_update_path(ctx, NULL, NULL);
1913 lysc_update_path(ctx, NULL, NULL);
1914 LY_CHECK_GOTO(ret, cleanup);
1915
Michal Vaskoc75f2042021-06-08 14:57:03 +02001916 /* augment was applied, remove it (index and the whole set may have changed because other augments
1917 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001918 ly_set_rm(&ctx->uses_augs, aug, NULL);
1919 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02001920 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001921 }
1922
1923 /* top-level augments */
1924 for (i = 0; i < ctx->augs.count; ) {
1925 aug = ctx->augs.objs[i];
1926
Michal Vasko28fe5f62021-03-03 16:37:39 +01001927 if (!lysp_schema_nodeid_match(aug->nodeid, aug->aug_pmod, NULL, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001928 /* not our target node */
1929 ++i;
1930 continue;
1931 }
1932
Michal Vaskob8df5762021-01-12 15:15:53 +01001933 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001934 strcpy(orig_path, ctx->path);
1935 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01001936 ctx->cur_mod = aug->aug_pmod->mod;
1937 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02001938 lysc_update_path(ctx, NULL, "{augment}");
1939 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001940
1941 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001942 ret = lys_compile_augment(ctx, aug->aug_p, node);
1943 strcpy(ctx->path, orig_path);
1944 ctx->path_len = strlen(ctx->path);
1945 LY_CHECK_GOTO(ret, cleanup);
1946
1947 /* augment was applied, remove it */
1948 ly_set_rm(&ctx->augs, aug, NULL);
1949 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02001950 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001951 }
1952
1953cleanup:
1954 ctx->cur_mod = orig_mod;
1955 ctx->pmod = orig_pmod;
1956 return ret;
1957}
1958
1959/**
1960 * @brief Prepare a top-level augment to be applied during data nodes compilation.
1961 *
1962 * @param[in] ctx Compile context.
1963 * @param[in] aug_p Parsed augment to be applied.
1964 * @param[in] pmod Both current and prefix module for @p aug_p.
1965 * @return LY_ERR value.
1966 */
1967static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001968lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, const struct lysp_module *pmod)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001969{
1970 LY_ERR ret = LY_SUCCESS;
1971 struct lyxp_expr *exp = NULL;
1972 struct lysc_augment *aug;
1973 const struct lys_module *mod;
1974
1975 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
1976 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
1977 LY_CHECK_GOTO(ret, cleanup);
1978
1979 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
1980 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
1981 if (mod != ctx->cur_mod) {
1982 /* augment for another module, ignore */
1983 goto cleanup;
1984 }
1985
1986 /* allocate new compiled augment and store it in the set */
1987 aug = calloc(1, sizeof *aug);
1988 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
1989 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
1990
1991 aug->nodeid = exp;
1992 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01001993 aug->aug_pmod = pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001994 aug->aug_p = aug_p;
1995
1996cleanup:
1997 lyxp_expr_free(ctx->ctx, exp);
1998 return ret;
1999}
2000
2001LY_ERR
2002lys_precompile_own_augments(struct lysc_ctx *ctx)
2003{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002004 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002005
2006 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002007 const struct lys_module *aug_mod = ctx->cur_mod->augmented_by[u];
2008 struct lysp_node_augment *aug;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002009
2010 /* collect all module augments */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002011 LY_LIST_FOR(aug_mod->parsed->augments, aug) {
2012 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002013 }
2014
2015 /* collect all submodules augments */
2016 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002017 LY_LIST_FOR(aug_mod->parsed->includes[v].submodule->augments, aug) {
2018 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug, (struct lysp_module *)aug_mod->parsed->includes[v].submodule));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002019 }
2020 }
2021 }
2022
2023 return LY_SUCCESS;
2024}
2025
2026/**
2027 * @brief Prepare a deviation to be applied during data nodes compilation.
2028 *
2029 * @param[in] ctx Compile context.
2030 * @param[in] dev_p Parsed deviation to be applied.
2031 * @param[in] pmod Both current and prefix module for @p dev_p.
2032 * @return LY_ERR value.
2033 */
2034static LY_ERR
2035lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2036{
2037 LY_ERR ret = LY_SUCCESS;
2038 struct lysc_deviation *dev = NULL;
2039 struct lyxp_expr *exp = NULL;
2040 struct lysp_deviation **new_dev;
2041 const struct lys_module *mod;
2042 const struct lysp_module **new_dev_pmod;
2043 uint32_t i;
2044
2045 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2046 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2047 LY_CHECK_GOTO(ret, cleanup);
2048
2049 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2050 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2051 if (mod != ctx->cur_mod) {
2052 /* deviation for another module, ignore */
2053 goto cleanup;
2054 }
2055
2056 /* try to find the node in already compiled deviations */
2057 for (i = 0; i < ctx->devs.count; ++i) {
2058 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2059 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2060 dev = ctx->devs.objs[i];
2061 break;
2062 }
2063 }
2064
2065 if (!dev) {
2066 /* allocate new compiled deviation */
2067 dev = calloc(1, sizeof *dev);
2068 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2069 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2070
2071 dev->nodeid = exp;
2072 exp = NULL;
2073 }
2074
2075 /* add new parsed deviation structure */
2076 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2077 *new_dev = dev_p;
2078 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2079 *new_dev_pmod = pmod;
2080
2081cleanup:
2082 lyxp_expr_free(ctx->ctx, exp);
2083 return ret;
2084}
2085
2086LY_ERR
2087lys_precompile_own_deviations(struct lysc_ctx *ctx)
2088{
2089 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002090 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002091 const struct lys_module *dev_mod;
2092 struct lysc_deviation *dev;
2093 struct lysp_deviate *d;
2094 int not_supported;
2095 uint32_t i;
2096
2097 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2098 dev_mod = ctx->cur_mod->deviated_by[u];
2099
2100 /* compile all module deviations */
2101 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2102 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2103 }
2104
2105 /* compile all submodules deviations */
2106 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2107 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2108 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2109 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2110 }
2111 }
2112 }
2113
2114 /* set not-supported flags for all the deviations */
2115 for (i = 0; i < ctx->devs.count; ++i) {
2116 dev = ctx->devs.objs[i];
2117 not_supported = 0;
2118
2119 LY_ARRAY_FOR(dev->devs, u) {
2120 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2121 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2122 not_supported = 1;
2123 break;
2124 }
2125 }
2126 if (not_supported) {
2127 break;
2128 }
2129 }
2130 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002131 orig_cur_mod = ctx->cur_mod;
2132 ctx->cur_mod = dev->dev_pmods[u]->mod;
2133 lysc_update_path(ctx, NULL, "{deviation}");
2134 lysc_update_path(ctx, NULL, dev->nodeid->expr);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002135 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002136 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002137 lysc_update_path(ctx, NULL, NULL);
2138 lysc_update_path(ctx, NULL, NULL);
2139 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002140 return LY_EVALID;
2141 }
2142
2143 dev->not_supported = not_supported;
2144 }
2145
2146 return LY_SUCCESS;
2147}
2148
2149/**
2150 * @brief Add a module reference into an array, checks for duplicities.
2151 *
2152 * @param[in] ctx Compile context.
2153 * @param[in] mod Module reference to add.
2154 * @param[in,out] mod_array Module sized array to add to.
2155 * @return LY_ERR value.
2156 */
2157static LY_ERR
2158lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2159{
2160 LY_ARRAY_COUNT_TYPE u;
2161 struct lys_module **new_mod;
2162
2163 LY_ARRAY_FOR(*mod_array, u) {
2164 if ((*mod_array)[u] == mod) {
2165 /* already there */
2166 return LY_EEXIST;
2167 }
2168 }
2169
2170 /* add the new module ref */
2171 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2172 *new_mod = mod;
2173
2174 return LY_SUCCESS;
2175}
2176
Michal Vasko1ccbf542021-04-19 11:35:00 +02002177/**
2178 * @brief Check whether all modules in a set are implemented.
2179 *
2180 * @param[in] mod_set Module set to check.
2181 * @return Whether all modules are implemented or not.
2182 */
2183static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002184lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002185{
2186 uint32_t i;
2187 const struct lys_module *mod;
2188
2189 for (i = 0; i < mod_set->count; ++i) {
2190 mod = mod_set->objs[i];
2191 if (!mod->implemented) {
2192 return 0;
2193 }
2194 }
2195
2196 return 1;
2197}
2198
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002199LY_ERR
Michal Vasko65333882021-06-10 14:12:16 +02002200lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002201{
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002202 LY_ERR ret = LY_SUCCESS, r;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002203 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002204 struct lysc_ctx ctx;
Michal Vasko65333882021-06-10 14:12:16 +02002205 struct lysp_module *mod_p;
2206 struct lys_module *m;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002207 struct lysp_submodule *submod;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002208 struct lysp_node_augment *aug;
Michal Vaskoc56d6372021-10-19 12:29:00 +02002209 const char **imp_f, *all_f[] = {"*", NULL};
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002210 uint32_t i;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002211 struct ly_set mod_set = {0}, set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002212
Michal Vasko65333882021-06-10 14:12:16 +02002213 mod_p = mod->parsed;
Michal Vaskoedb0fa52022-10-04 10:36:00 +02002214 LYSC_CTX_INIT_PMOD(ctx, mod_p, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002215
Radek Krejci2a9fc652021-01-22 17:44:34 +01002216 LY_LIST_FOR(mod_p->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002217 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002218 lysc_update_path(&ctx, NULL, "{augment}");
2219 lysc_update_path(&ctx, NULL, aug->nodeid);
2220 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2221 lysc_update_path(&ctx, NULL, NULL);
2222 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002223 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002224
Michal Vasko1ccbf542021-04-19 11:35:00 +02002225 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vasko65333882021-06-10 14:12:16 +02002226 if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002227 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002228 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002229 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002230 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002231 }
2232
2233 LY_ARRAY_FOR(mod_p->deviations, u) {
2234 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002235 lysc_update_path(&ctx, NULL, "{deviation}");
2236 lysc_update_path(&ctx, NULL, mod_p->deviations[u].nodeid);
2237 ret = lys_nodeid_mod_check(&ctx, mod_p->deviations[u].nodeid, 1, &set, NULL, &m);
2238 lysc_update_path(&ctx, NULL, NULL);
2239 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002240 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002241
Michal Vasko1ccbf542021-04-19 11:35:00 +02002242 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vasko65333882021-06-10 14:12:16 +02002243 if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002244 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002245 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
2246 }
2247 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002248 }
2249
2250 /* the same for augments and deviations in submodules */
2251 LY_ARRAY_FOR(mod_p->includes, v) {
2252 submod = mod_p->includes[v].submodule;
Michal Vasko65333882021-06-10 14:12:16 +02002253 ctx.pmod = (struct lysp_module *)submod;
Michal Vaskoce3d6172021-06-08 14:59:49 +02002254
Radek Krejci2a9fc652021-01-22 17:44:34 +01002255 LY_LIST_FOR(submod->augments, aug) {
Michal Vasko65333882021-06-10 14:12:16 +02002256 lysc_update_path(&ctx, NULL, "{augment}");
2257 lysc_update_path(&ctx, NULL, aug->nodeid);
2258 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2259 lysc_update_path(&ctx, NULL, NULL);
2260 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002261 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002262
Michal Vasko65333882021-06-10 14:12:16 +02002263 if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002264 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002265 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002266 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002267 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002268 }
2269
2270 LY_ARRAY_FOR(submod->deviations, u) {
Michal Vasko65333882021-06-10 14:12:16 +02002271 lysc_update_path(&ctx, NULL, "{deviation}");
2272 lysc_update_path(&ctx, NULL, submod->deviations[u].nodeid);
2273 ret = lys_nodeid_mod_check(&ctx, submod->deviations[u].nodeid, 1, &set, NULL, &m);
2274 lysc_update_path(&ctx, NULL, NULL);
2275 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002276 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002277
Michal Vasko65333882021-06-10 14:12:16 +02002278 if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002279 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002280 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
2281 }
2282 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002283 }
2284 }
2285
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002286 for (i = 0; i < mod_set.count; ++i) {
2287 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002288
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002289 if (m == mod) {
2290 /* will be applied normally later */
2291 continue;
2292 }
2293
2294 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2295 * not compiled yet and marked for compilation */
2296
2297 if (!m->implemented) {
2298 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002299 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2300 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002301 if (r == LY_ERECOMPILE) {
2302 /* implement all the modules right away to save possible later recompilation */
2303 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002304 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002305 } else if (r) {
2306 /* error */
2307 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002308 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002309 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002310 } else if (m->compiled) {
2311 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2312 m->to_compile = 1;
2313 ret = LY_ERECOMPILE;
2314 continue;
2315 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002316 }
2317
Michal Vasko1ccbf542021-04-19 11:35:00 +02002318cleanup:
2319 ly_set_erase(&set, NULL);
2320 ly_set_erase(&mod_set, NULL);
2321 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002322}
2323
2324void
2325lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2326{
2327 uint32_t i;
2328 LY_ARRAY_COUNT_TYPE u, count;
2329 struct lys_module *m;
2330
2331 for (i = 0; i < ctx->list.count; ++i) {
2332 m = ctx->list.objs[i];
2333
2334 if (m->augmented_by) {
2335 count = LY_ARRAY_COUNT(m->augmented_by);
2336 for (u = 0; u < count; ++u) {
2337 if (m->augmented_by[u] == mod) {
2338 /* keep the order */
2339 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002340 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002341 }
2342 LY_ARRAY_DECREMENT(m->augmented_by);
2343 break;
2344 }
2345 }
2346 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2347 LY_ARRAY_FREE(m->augmented_by);
2348 m->augmented_by = NULL;
2349 }
2350 }
2351
2352 if (m->deviated_by) {
2353 count = LY_ARRAY_COUNT(m->deviated_by);
2354 for (u = 0; u < count; ++u) {
2355 if (m->deviated_by[u] == mod) {
2356 /* keep the order */
2357 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002358 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002359 }
2360 LY_ARRAY_DECREMENT(m->deviated_by);
2361 break;
2362 }
2363 }
2364 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2365 LY_ARRAY_FREE(m->deviated_by);
2366 m->deviated_by = NULL;
2367 }
2368 }
2369 }
2370}
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002371
2372LIBYANG_API_DEF LY_ERR
2373lys_compile_extension_instance_find_augment_target(struct lysc_ctx *ctx, const char *path,
2374 struct lysc_ext_instance **aug_ext, struct lysc_node **aug_target)
2375{
2376 LY_ERR rc;
2377 LY_ARRAY_COUNT_TYPE u;
2378 struct lys_module *target_mod;
2379 struct lysc_ext_instance *target_ext = NULL, *prev_ext;
2380 const struct lysc_node *target;
2381 const char *id, *id2, *name;
2382 size_t name_len;
2383 uint16_t flag;
2384
2385 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, ctx, path, aug_target, LY_EINVAL);
2386
2387 /* skip first slash */
2388 id = path;
2389 if (id[0] != '/') {
2390 LOGVAL(ctx->ctx, LYVE_SYNTAX, "Invalid absolute-schema-nodeid \"%s\".", path);
2391 return LY_EVALID;
2392 }
2393 ++id;
2394
2395 /* find the next slash */
2396 id2 = strchr(id, '/');
2397 if (!id2) {
2398 LOGVAL(ctx->ctx, LYVE_SYNTAX, "Invalid absolute-schema-nodeid \"%s\".", path);
2399 return LY_EVALID;
2400 }
2401
2402 /* find the target module */
2403 target_mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, id, id2 - id, ctx->pmod, &name, &name_len);
2404 if (!target_mod) {
2405 return LY_ENOTFOUND;
2406 } else if (!target_mod->implemented) {
2407 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Augment target extension instance \"%*.s\" in a non-implemented module \"%s\".",
2408 (int)name_len, name, target_mod->name);
2409 return LY_ENOTFOUND;
2410 }
2411
2412 /* find the extension instance */
2413 LY_ARRAY_FOR(target_mod->compiled->exts, u) {
2414 if (!ly_strncmp(target_mod->compiled->exts[u].argument, name, name_len)) {
2415 target_ext = &target_mod->compiled->exts[u];
2416 break;
2417 }
2418 }
2419 if (!target_ext) {
2420 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Augment target extension instance \"%*.s\" not found in module \"%s\".",
2421 (int)name_len, name, target_mod->name);
2422 return LY_ENOTFOUND;
2423 }
2424
2425 /* find the augment target with the correct compile context */
2426 prev_ext = ctx->ext;
2427 ctx->ext = target_ext;
2428 rc = lysc_resolve_schema_nodeid(ctx, id2, strlen(id2), NULL, LY_VALUE_SCHEMA, ctx->pmod, 0, &target, &flag);
2429 ctx->ext = prev_ext;
2430 LY_CHECK_RET(rc);
2431
2432 /* add this module into the target module augmented_by, if not there */
2433 lys_array_add_mod_ref(ctx, ctx->cur_mod, &target_mod->augmented_by);
2434
2435 if (aug_ext) {
2436 *aug_ext = target_ext;
2437 }
2438 *aug_target = (struct lysc_node *)target;
2439 return LY_SUCCESS;
2440}