blob: b898c0b1c36bd0f67e99af3a5be9d839cdca2ab2 [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 Vaskoee029832022-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
41static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
42 size_t nametest_len, const struct lysp_module *mod, const char **name, size_t *name_len);
43
Michal Vasko1ccbf542021-04-19 11:35:00 +020044/**
45 * @brief Check the syntax of a node-id and collect all the referenced modules.
46 *
47 * @param[in] ctx Compile context.
48 * @param[in] nodeid Node-id to check.
49 * @param[in] abs Whether @p nodeid is absolute.
50 * @param[in,out] mod_set Set to add referenced modules into.
51 * @param[out] expr Optional node-id parsed into an expression.
52 * @param[out] target_mod Optional target module of the node-id.
53 * @return LY_ERR value.
54 */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020055static LY_ERR
Michal Vasko1ccbf542021-04-19 11:35:00 +020056lys_nodeid_mod_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct ly_set *mod_set,
57 struct lyxp_expr **expr, struct lys_module **target_mod)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020058{
59 LY_ERR ret = LY_SUCCESS;
60 struct lyxp_expr *e = NULL;
61 struct lys_module *tmod = NULL, *mod;
62 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
63 uint32_t i;
64
65 /* parse */
66 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
67 if (ret) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010068 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020069 nodeid_type, nodeid);
70 ret = LY_EVALID;
71 goto cleanup;
72 }
73
74 if (abs) {
75 /* absolute schema nodeid */
76 i = 0;
77 } else {
78 /* descendant schema nodeid */
79 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010080 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020081 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
82 ret = LY_EVALID;
83 goto cleanup;
84 }
85 i = 1;
86 }
87
88 /* check all the tokens */
89 for ( ; i < e->used; i += 2) {
90 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010091 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020092 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
93 ret = LY_EVALID;
94 goto cleanup;
95 } else if (e->used == i + 1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010096 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020097 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
98 ret = LY_EVALID;
99 goto cleanup;
100 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100101 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200102 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
103 ret = LY_EVALID;
104 goto cleanup;
105 } else if (abs) {
106 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
107 e->tok_len[i + 1], ctx->pmod, NULL, NULL);
108 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
109
110 /* only keep the first module */
111 if (!tmod) {
112 tmod = mod;
113 }
114
Michal Vasko1ccbf542021-04-19 11:35:00 +0200115 /* store the referenced module */
116 LY_CHECK_GOTO(ret = ly_set_add(mod_set, mod, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200117 }
118 }
119
120cleanup:
121 if (ret || !expr) {
122 lyxp_expr_free(ctx->ctx, e);
123 e = NULL;
124 }
125 if (expr) {
126 *expr = ret ? NULL : e;
127 }
128 if (target_mod) {
129 *target_mod = ret ? NULL : tmod;
130 }
131 return ret;
132}
133
134/**
135 * @brief Check whether 2 schema nodeids match.
136 *
137 * @param[in] ctx libyang context.
138 * @param[in] exp1 First schema nodeid.
139 * @param[in] exp1p_mod Module of @p exp1 nodes without any prefix.
140 * @param[in] exp2 Second schema nodeid.
141 * @param[in] exp2_pmod Module of @p exp2 nodes without any prefix.
142 * @return Whether the schema nodeids match or not.
143 */
144static ly_bool
145lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lysp_module *exp1_pmod,
146 const struct lyxp_expr *exp2, const struct lysp_module *exp2_pmod)
147{
148 uint32_t i;
149 const struct lys_module *mod1, *mod2;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100150 const char *name1 = NULL, *name2 = NULL;
151 size_t name1_len = 0, name2_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200152
153 if (exp1->used != exp2->used) {
154 return 0;
155 }
156
157 for (i = 0; i < exp1->used; ++i) {
158 assert(exp1->tokens[i] == exp2->tokens[i]);
159
160 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
161 /* check modules of all the nodes in the node ID */
162 mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_pmod,
163 &name1, &name1_len);
164 assert(mod1);
165 mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_pmod,
166 &name2, &name2_len);
167 assert(mod2);
168
169 /* compare modules */
170 if (mod1 != mod2) {
171 return 0;
172 }
173
174 /* compare names */
175 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
176 return 0;
177 }
178 }
179 }
180
181 return 1;
182}
183
184LY_ERR
185lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
186{
187 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200188 struct lyxp_expr *exp = NULL;
189 struct lysc_augment *aug;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100190 struct lysp_node_augment *aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200191 struct lysc_refine *rfn;
192 struct lysp_refine **new_rfn;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100193 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200194 uint32_t i;
Michal Vasko1ccbf542021-04-19 11:35:00 +0200195 struct ly_set mod_set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200196
Radek Krejci2a9fc652021-01-22 17:44:34 +0100197 LY_LIST_FOR(uses_p->augments, aug_p) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200198 lysc_update_path(ctx, NULL, "{augment}");
Radek Krejci2a9fc652021-01-22 17:44:34 +0100199 lysc_update_path(ctx, NULL, aug_p->nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200200
201 /* parse the nodeid */
Michal Vasko1ccbf542021-04-19 11:35:00 +0200202 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 +0200203
204 /* allocate new compiled augment and store it in the set */
205 aug = calloc(1, sizeof *aug);
206 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
207 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
208
209 aug->nodeid = exp;
210 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +0100211 aug->aug_pmod = ctx->pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200212 aug->nodeid_ctx_node = ctx_node;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100213 aug->aug_p = aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200214
215 lysc_update_path(ctx, NULL, NULL);
216 lysc_update_path(ctx, NULL, NULL);
217 }
218
219 LY_ARRAY_FOR(uses_p->refines, u) {
220 lysc_update_path(ctx, NULL, "{refine}");
221 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
222
223 /* parse the nodeid */
Michal Vasko1ccbf542021-04-19 11:35:00 +0200224 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 +0200225
226 /* try to find the node in already compiled refines */
227 rfn = NULL;
228 for (i = 0; i < ctx->uses_rfns.count; ++i) {
229 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
230 ctx->pmod)) {
231 rfn = ctx->uses_rfns.objs[i];
232 break;
233 }
234 }
235
236 if (!rfn) {
237 /* allocate new compiled refine */
238 rfn = calloc(1, sizeof *rfn);
239 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
240 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
241
242 rfn->nodeid = exp;
243 exp = NULL;
Michal Vasko7d3708f2021-02-03 10:50:24 +0100244 rfn->nodeid_pmod = ctx->cur_mod->parsed;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200245 rfn->nodeid_ctx_node = ctx_node;
Michal Vaskod8655722021-01-12 15:20:36 +0100246 rfn->uses_p = uses_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200247 } else {
248 /* just free exp */
249 lyxp_expr_free(ctx->ctx, exp);
250 exp = NULL;
251 }
252
253 /* add new parsed refine structure */
254 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
255 *new_rfn = &uses_p->refines[u];
256
257 lysc_update_path(ctx, NULL, NULL);
258 lysc_update_path(ctx, NULL, NULL);
259 }
260
261cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +0200262 if (ret) {
263 lysc_update_path(ctx, NULL, NULL);
264 lysc_update_path(ctx, NULL, NULL);
265 }
266 /* should include only this module, will fail later if not */
267 ly_set_erase(&mod_set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200268 lyxp_expr_free(ctx->ctx, exp);
269 return ret;
270}
271
272static LY_ERR
Michal Vaskoee029832022-02-18 09:18:37 +0100273lysp_ext_children_dup(const struct ly_ctx *ctx, struct lysp_stmt **child, const struct lysp_stmt *orig_child)
274{
275 LY_LIST_FOR(orig_child, orig_child) {
276 /* new child */
277 if (!*child) {
278 *child = calloc(1, sizeof **child);
279 LY_CHECK_ERR_RET(!*child, LOGMEM(ctx), LY_EMEM);
280 } else {
281 (*child)->next = calloc(1, sizeof **child);
282 LY_CHECK_ERR_RET(!(*child)->next, LOGMEM(ctx), LY_EMEM);
283 *child = (*child)->next;
284 }
285
286 /* fill */
287 DUP_STRING_RET(ctx, orig_child->stmt, (*child)->stmt);
288 (*child)->flags = orig_child->flags;
289 DUP_STRING_RET(ctx, orig_child->arg, (*child)->arg);
290 (*child)->format = orig_child->format;
291 LY_CHECK_RET(ly_dup_prefix_data(ctx, orig_child->format, orig_child->prefix_data, &((*child)->prefix_data)));
292 (*child)->kw = orig_child->kw;
293
294 /* recursive children */
295 LY_CHECK_RET(lysp_ext_children_dup(ctx, &(*child)->child, orig_child->child));
296 }
297
298 return LY_SUCCESS;
299}
300
301static LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200302lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
303{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200304 *ext = *orig_ext;
Michal Vaskoee029832022-02-18 09:18:37 +0100305 DUP_STRING_RET(ctx, orig_ext->name, ext->name);
306 DUP_STRING_RET(ctx, orig_ext->argument, ext->argument);
307 ext->parsed = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200308
Michal Vaskoee029832022-02-18 09:18:37 +0100309 ext->child = NULL;
310 LY_CHECK_RET(lysp_ext_children_dup(ctx, &ext->child, orig_ext->child));
311
312 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200313}
314
315static LY_ERR
316lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
317{
318 LY_ERR ret = LY_SUCCESS;
319
320 if (orig_restr) {
321 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
322 restr->arg.mod = orig_restr->arg.mod;
323 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
324 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
325 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
326 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
327 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
328 }
329
330 return ret;
331}
332
333static LY_ERR
334lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
335{
336 LY_ERR ret = LY_SUCCESS;
337
338 DUP_STRING(ctx, *orig_str, *str, ret);
339
340 return ret;
341}
342
343LY_ERR
344lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
345{
346 LY_ERR ret = LY_SUCCESS;
347
348 if (!orig_qname->str) {
349 return LY_SUCCESS;
350 }
351
352 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
353 assert(orig_qname->mod);
354 qname->mod = orig_qname->mod;
355
356 return ret;
357}
358
359static LY_ERR
360lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
361{
362 LY_ERR ret = LY_SUCCESS;
363
364 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
365 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
366 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
367 enm->value = orig_enm->value;
368 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
369 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
370 enm->flags = orig_enm->flags;
371
372 return ret;
373}
374
375static LY_ERR
376lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
377{
378 LY_ERR ret = LY_SUCCESS;
379
Michal Vaskoea868242021-06-21 09:28:32 +0200380 /* array macros read previous data so we must zero it */
381 memset(type, 0, sizeof *type);
382
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200383 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
384
385 if (orig_type->range) {
386 type->range = calloc(1, sizeof *type->range);
387 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
388 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
389 }
390
391 if (orig_type->length) {
392 type->length = calloc(1, sizeof *type->length);
393 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
394 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
395 }
396
397 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
398 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
399 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
400 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
401 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
402 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
403 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
404
405 type->pmod = orig_type->pmod;
406 type->compiled = orig_type->compiled;
407
408 type->fraction_digits = orig_type->fraction_digits;
409 type->require_instance = orig_type->require_instance;
410 type->flags = orig_type->flags;
411
412done:
413 return ret;
414}
415
416static LY_ERR
417lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
418{
419 LY_ERR ret = LY_SUCCESS;
420
421 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
422 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
423 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
424 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
425
426 return ret;
427}
428
429static LY_ERR
430lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
431{
432 LY_ERR ret = LY_SUCCESS;
433
434 node->parent = NULL;
435 node->nodetype = orig->nodetype;
436 node->flags = orig->flags;
437 node->next = NULL;
438 DUP_STRING(ctx, orig->name, node->name, ret);
439 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
440 DUP_STRING(ctx, orig->ref, node->ref, ret);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200441 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
442 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
443
444 return ret;
445}
446
Radek Krejci9a3823e2021-01-27 20:26:46 +0100447#define DUP_PWHEN(CTX, ORIG, NEW) \
448 if (ORIG) { \
449 NEW = calloc(1, sizeof *NEW); \
450 LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \
451 LY_CHECK_RET(lysp_when_dup(CTX, NEW, ORIG)); \
452 }
453
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200454static LY_ERR
455lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
456{
457 LY_ERR ret = LY_SUCCESS;
458 struct lysp_node_container *cont;
459 const struct lysp_node_container *orig_cont;
460 struct lysp_node_leaf *leaf;
461 const struct lysp_node_leaf *orig_leaf;
462 struct lysp_node_leaflist *llist;
463 const struct lysp_node_leaflist *orig_llist;
464 struct lysp_node_list *list;
465 const struct lysp_node_list *orig_list;
466 struct lysp_node_choice *choice;
467 const struct lysp_node_choice *orig_choice;
468 struct lysp_node_case *cas;
469 const struct lysp_node_case *orig_cas;
470 struct lysp_node_anydata *any;
471 const struct lysp_node_anydata *orig_any;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100472 struct lysp_node_action *action;
473 const struct lysp_node_action *orig_action;
474 struct lysp_node_action_inout *action_inout;
475 const struct lysp_node_action_inout *orig_action_inout;
476 struct lysp_node_notif *notif;
477 const struct lysp_node_notif *orig_notif;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200478
Radek Krejci2a9fc652021-01-22 17:44:34 +0100479 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA |
480 LYS_RPC | LYS_ACTION | LYS_NOTIF));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200481
482 /* common part */
483 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
484
485 /* specific part */
486 switch (node->nodetype) {
487 case LYS_CONTAINER:
488 cont = (struct lysp_node_container *)node;
489 orig_cont = (const struct lysp_node_container *)orig;
490
Radek Krejci9a3823e2021-01-27 20:26:46 +0100491 DUP_PWHEN(ctx, orig_cont->when, cont->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200492 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
493 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
494 /* we do not need the rest */
495 break;
496 case LYS_LEAF:
497 leaf = (struct lysp_node_leaf *)node;
498 orig_leaf = (const struct lysp_node_leaf *)orig;
499
Radek Krejci9a3823e2021-01-27 20:26:46 +0100500 DUP_PWHEN(ctx, orig_leaf->when, leaf->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200501 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
502 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
503 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
504 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
505 break;
506 case LYS_LEAFLIST:
507 llist = (struct lysp_node_leaflist *)node;
508 orig_llist = (const struct lysp_node_leaflist *)orig;
509
Radek Krejci9a3823e2021-01-27 20:26:46 +0100510 DUP_PWHEN(ctx, orig_llist->when, llist->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200511 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
512 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
513 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
514 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
515 llist->min = orig_llist->min;
516 llist->max = orig_llist->max;
517 break;
518 case LYS_LIST:
519 list = (struct lysp_node_list *)node;
520 orig_list = (const struct lysp_node_list *)orig;
521
Radek Krejci9a3823e2021-01-27 20:26:46 +0100522 DUP_PWHEN(ctx, orig_list->when, list->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200523 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
524 DUP_STRING(ctx, orig_list->key, list->key, ret);
525 /* we do not need these arrays */
526 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
527 list->min = orig_list->min;
528 list->max = orig_list->max;
529 break;
530 case LYS_CHOICE:
531 choice = (struct lysp_node_choice *)node;
532 orig_choice = (const struct lysp_node_choice *)orig;
533
Radek Krejci9a3823e2021-01-27 20:26:46 +0100534 DUP_PWHEN(ctx, orig_choice->when, choice->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200535 /* we do not need children */
536 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
537 break;
538 case LYS_CASE:
539 cas = (struct lysp_node_case *)node;
540 orig_cas = (const struct lysp_node_case *)orig;
541
Radek Krejci9a3823e2021-01-27 20:26:46 +0100542 DUP_PWHEN(ctx, orig_cas->when, cas->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200543 /* we do not need children */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200544 break;
545 case LYS_ANYDATA:
546 case LYS_ANYXML:
547 any = (struct lysp_node_anydata *)node;
548 orig_any = (const struct lysp_node_anydata *)orig;
549
Radek Krejci9a3823e2021-01-27 20:26:46 +0100550 DUP_PWHEN(ctx, orig_any->when, any->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200551 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
552 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100553 case LYS_RPC:
554 case LYS_ACTION:
555 action = (struct lysp_node_action *)node;
556 orig_action = (const struct lysp_node_action *)orig;
557
558 action->input.nodetype = orig_action->input.nodetype;
559 action->output.nodetype = orig_action->output.nodetype;
560 /* we do not need the rest */
561 break;
562 case LYS_INPUT:
563 case LYS_OUTPUT:
564 action_inout = (struct lysp_node_action_inout *)node;
565 orig_action_inout = (const struct lysp_node_action_inout *)orig;
566
567 DUP_ARRAY(ctx, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
568 /* we do not need the rest */
569 break;
570 case LYS_NOTIF:
571 notif = (struct lysp_node_notif *)node;
572 orig_notif = (const struct lysp_node_notif *)orig;
573
574 DUP_ARRAY(ctx, orig_notif->musts, notif->musts, lysp_restr_dup);
575 /* we do not need the rest */
576 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200577 default:
578 LOGINT_RET(ctx);
579 }
580
581 return ret;
582}
583
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200584/**
585 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
586 *
587 * @param[in] ctx libyang context.
588 * @param[in] pnode Node to duplicate.
589 * @param[in] with_links Whether to also copy any links (child, parent pointers).
590 * @param[out] dup_p Duplicated parsed node.
591 * @return LY_ERR value.
592 */
593static LY_ERR
594lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
595{
596 LY_ERR ret = LY_SUCCESS;
597 void *mem = NULL;
598
599 if (!pnode) {
600 *dup_p = NULL;
601 return LY_SUCCESS;
602 }
603
604 switch (pnode->nodetype) {
605 case LYS_CONTAINER:
606 mem = calloc(1, sizeof(struct lysp_node_container));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200607 break;
608 case LYS_LEAF:
609 mem = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200610 break;
611 case LYS_LEAFLIST:
612 mem = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200613 break;
614 case LYS_LIST:
615 mem = calloc(1, sizeof(struct lysp_node_list));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200616 break;
617 case LYS_CHOICE:
618 mem = calloc(1, sizeof(struct lysp_node_choice));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200619 break;
620 case LYS_CASE:
621 mem = calloc(1, sizeof(struct lysp_node_case));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200622 break;
623 case LYS_ANYDATA:
624 case LYS_ANYXML:
625 mem = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200626 break;
627 case LYS_INPUT:
628 case LYS_OUTPUT:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100629 mem = calloc(1, sizeof(struct lysp_node_action_inout));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200630 break;
631 case LYS_ACTION:
632 case LYS_RPC:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100633 mem = calloc(1, sizeof(struct lysp_node_action));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200634 break;
635 case LYS_NOTIF:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100636 mem = calloc(1, sizeof(struct lysp_node_notif));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200637 break;
638 default:
639 LOGINT_RET(ctx);
640 }
Radek Krejci2a9fc652021-01-22 17:44:34 +0100641 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
642 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200643
644 if (with_links) {
Michal Vaskoec8f4272021-10-27 09:14:03 +0200645 /* copy also parent, child, action, and notification pointers */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200646 ((struct lysp_node *)mem)->parent = pnode->parent;
647 switch (pnode->nodetype) {
648 case LYS_CONTAINER:
649 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
Michal Vaskoec8f4272021-10-27 09:14:03 +0200650 ((struct lysp_node_container *)mem)->actions = ((struct lysp_node_container *)pnode)->actions;
651 ((struct lysp_node_container *)mem)->notifs = ((struct lysp_node_container *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200652 break;
653 case LYS_LIST:
654 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
Michal Vaskoec8f4272021-10-27 09:14:03 +0200655 ((struct lysp_node_list *)mem)->actions = ((struct lysp_node_list *)pnode)->actions;
656 ((struct lysp_node_list *)mem)->notifs = ((struct lysp_node_list *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200657 break;
658 case LYS_CHOICE:
659 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
660 break;
661 case LYS_CASE:
662 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
663 break;
664 default:
665 break;
666 }
667 }
668
669cleanup:
670 if (ret) {
671 free(mem);
672 } else {
673 *dup_p = mem;
674 }
675 return ret;
676}
677
678#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100679 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 +0200680 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
681 ret = LY_EVALID; \
682 goto cleanup;
683
684#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
685 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100686 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 +0200687 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
688 ret = LY_EVALID; \
689 goto cleanup; \
690 }
691
692/**
693 * @brief Apply refine.
694 *
695 * @param[in] ctx Compile context.
696 * @param[in] rfn Refine to apply.
697 * @param[in,out] target Refine target.
698 * @return LY_ERR value.
699 */
700static LY_ERR
701lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
702{
703 LY_ERR ret = LY_SUCCESS;
704 LY_ARRAY_COUNT_TYPE u;
705 struct lysp_qname *qname;
706 struct lysp_restr **musts, *must;
707 uint32_t *num;
708
709 /* default value */
710 if (rfn->dflts) {
711 switch (target->nodetype) {
712 case LYS_LEAF:
713 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
714
Michal Vaskoe180ed02021-02-05 16:31:20 +0100715 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200716 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &rfn->dflts[0]), cleanup);
717 break;
718 case LYS_LEAFLIST:
719 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100720 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200721 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
722 ret = LY_EVALID;
723 goto cleanup;
724 }
725
726 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
727 ((struct lysp_node_leaflist *)target)->dflts = NULL;
728 LY_ARRAY_FOR(rfn->dflts, u) {
729 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
730 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup);
731 }
732 break;
733 case LYS_CHOICE:
734 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
735
Michal Vaskoe180ed02021-02-05 16:31:20 +0100736 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200737 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &rfn->dflts[0]), cleanup);
738 break;
739 default:
740 AMEND_WRONG_NODETYPE("refine", "replace", "default");
741 }
742 }
743
744 /* description */
745 if (rfn->dsc) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100746 lydict_remove(ctx->ctx, target->dsc);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200747 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
748 }
749
750 /* reference */
751 if (rfn->ref) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100752 lydict_remove(ctx->ctx, target->ref);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200753 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
754 }
755
756 /* config */
757 if (rfn->flags & LYS_CONFIG_MASK) {
Michal Vasko7c565922021-06-10 14:58:27 +0200758 if (ctx->compile_opts & LYS_COMPILE_NO_CONFIG) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200759 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Michal Vasko7c565922021-06-10 14:58:27 +0200760 (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT)) ? "RPC/action" :
761 ctx->compile_opts & LYS_IS_NOTIF ? "notification" : "a subtree ignoring config", ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200762 } else {
763 target->flags &= ~LYS_CONFIG_MASK;
764 target->flags |= rfn->flags & LYS_CONFIG_MASK;
765 }
766 }
767
768 /* mandatory */
769 if (rfn->flags & LYS_MAND_MASK) {
770 switch (target->nodetype) {
771 case LYS_LEAF:
772 case LYS_CHOICE:
773 case LYS_ANYDATA:
774 case LYS_ANYXML:
775 break;
776 default:
777 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
778 }
779
780 target->flags &= ~LYS_MAND_MASK;
781 target->flags |= rfn->flags & LYS_MAND_MASK;
782 }
783
784 /* presence */
785 if (rfn->presence) {
786 switch (target->nodetype) {
787 case LYS_CONTAINER:
788 break;
789 default:
790 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
791 }
792
Michal Vaskoe180ed02021-02-05 16:31:20 +0100793 lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200794 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
795 }
796
797 /* must */
798 if (rfn->musts) {
799 switch (target->nodetype) {
800 case LYS_CONTAINER:
801 case LYS_LIST:
802 case LYS_LEAF:
803 case LYS_LEAFLIST:
804 case LYS_ANYDATA:
805 case LYS_ANYXML:
806 musts = &((struct lysp_node_container *)target)->musts;
807 break;
808 default:
809 AMEND_WRONG_NODETYPE("refine", "add", "must");
810 }
811
812 LY_ARRAY_FOR(rfn->musts, u) {
813 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
814 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
815 }
816 }
817
818 /* min-elements */
819 if (rfn->flags & LYS_SET_MIN) {
820 switch (target->nodetype) {
821 case LYS_LEAFLIST:
822 num = &((struct lysp_node_leaflist *)target)->min;
823 break;
824 case LYS_LIST:
825 num = &((struct lysp_node_list *)target)->min;
826 break;
827 default:
828 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
829 }
830
831 *num = rfn->min;
832 }
833
834 /* max-elements */
835 if (rfn->flags & LYS_SET_MAX) {
836 switch (target->nodetype) {
837 case LYS_LEAFLIST:
838 num = &((struct lysp_node_leaflist *)target)->max;
839 break;
840 case LYS_LIST:
841 num = &((struct lysp_node_list *)target)->max;
842 break;
843 default:
844 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
845 }
846
847 *num = rfn->max;
848 }
849
850 /* if-feature */
851 if (rfn->iffeatures) {
852 switch (target->nodetype) {
853 case LYS_LEAF:
854 case LYS_LEAFLIST:
855 case LYS_LIST:
856 case LYS_CONTAINER:
857 case LYS_CHOICE:
858 case LYS_CASE:
859 case LYS_ANYDATA:
860 case LYS_ANYXML:
861 break;
862 default:
863 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
864 }
865
866 LY_ARRAY_FOR(rfn->iffeatures, u) {
867 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
868 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup);
869 }
870 }
871
872 /* extension */
873 /* TODO refine extensions */
874
875cleanup:
876 return ret;
877}
878
879/**
880 * @brief Apply deviate add.
881 *
882 * @param[in] ctx Compile context.
883 * @param[in] d Deviate add to apply.
884 * @param[in,out] target Deviation target.
885 * @return LY_ERR value.
886 */
887static LY_ERR
888lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
889{
890 LY_ERR ret = LY_SUCCESS;
891 LY_ARRAY_COUNT_TYPE u;
892 struct lysp_qname *qname;
893 uint32_t *num;
894 struct lysp_restr **musts, *must;
895
896#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
897 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100898 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200899 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
900 ret = LY_EVALID; \
901 goto cleanup; \
902 }
903
904 /* [units-stmt] */
905 if (d->units) {
906 switch (target->nodetype) {
907 case LYS_LEAF:
908 case LYS_LEAFLIST:
909 break;
910 default:
911 AMEND_WRONG_NODETYPE("deviation", "add", "units");
912 }
913
914 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
915 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
916 }
917
918 /* *must-stmt */
919 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100920 musts = lysp_node_musts_p(target);
921 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200922 AMEND_WRONG_NODETYPE("deviation", "add", "must");
923 }
924
925 LY_ARRAY_FOR(d->musts, u) {
926 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
927 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
928 }
929 }
930
931 /* *unique-stmt */
932 if (d->uniques) {
933 switch (target->nodetype) {
934 case LYS_LIST:
935 break;
936 default:
937 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
938 }
939
940 LY_ARRAY_FOR(d->uniques, u) {
941 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
942 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup);
943 }
944 }
945
946 /* *default-stmt */
947 if (d->dflts) {
948 switch (target->nodetype) {
949 case LYS_LEAF:
950 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
951 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
952
953 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflts[0]), cleanup);
954 break;
955 case LYS_LEAFLIST:
956 LY_ARRAY_FOR(d->dflts, u) {
957 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
958 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup);
959 }
960 break;
961 case LYS_CHOICE:
962 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
963 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
964
965 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflts[0]), cleanup);
966 break;
967 default:
968 AMEND_WRONG_NODETYPE("deviation", "add", "default");
969 }
970 }
971
972 /* [config-stmt] */
973 if (d->flags & LYS_CONFIG_MASK) {
974 switch (target->nodetype) {
975 case LYS_CONTAINER:
976 case LYS_LEAF:
977 case LYS_LEAFLIST:
978 case LYS_LIST:
979 case LYS_CHOICE:
980 case LYS_ANYDATA:
981 case LYS_ANYXML:
982 break;
983 default:
984 AMEND_WRONG_NODETYPE("deviation", "add", "config");
985 }
986
987 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100988 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200989 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
990 target->flags & LYS_CONFIG_W ? "true" : "false");
991 ret = LY_EVALID;
992 goto cleanup;
993 }
994
995 target->flags |= d->flags & LYS_CONFIG_MASK;
996 }
997
998 /* [mandatory-stmt] */
999 if (d->flags & LYS_MAND_MASK) {
1000 switch (target->nodetype) {
1001 case LYS_LEAF:
1002 case LYS_CHOICE:
1003 case LYS_ANYDATA:
1004 case LYS_ANYXML:
1005 break;
1006 default:
1007 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
1008 }
1009
1010 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001011 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001012 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
1013 target->flags & LYS_MAND_TRUE ? "true" : "false");
1014 ret = LY_EVALID;
1015 goto cleanup;
1016 }
1017
1018 target->flags |= d->flags & LYS_MAND_MASK;
1019 }
1020
1021 /* [min-elements-stmt] */
1022 if (d->flags & LYS_SET_MIN) {
1023 switch (target->nodetype) {
1024 case LYS_LEAFLIST:
1025 num = &((struct lysp_node_leaflist *)target)->min;
1026 break;
1027 case LYS_LIST:
1028 num = &((struct lysp_node_list *)target)->min;
1029 break;
1030 default:
1031 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
1032 }
1033
1034 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001035 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001036 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
1037 ret = LY_EVALID;
1038 goto cleanup;
1039 }
1040
1041 *num = d->min;
1042 }
1043
1044 /* [max-elements-stmt] */
1045 if (d->flags & LYS_SET_MAX) {
1046 switch (target->nodetype) {
1047 case LYS_LEAFLIST:
1048 num = &((struct lysp_node_leaflist *)target)->max;
1049 break;
1050 case LYS_LIST:
1051 num = &((struct lysp_node_list *)target)->max;
1052 break;
1053 default:
1054 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1055 }
1056
1057 if (target->flags & LYS_SET_MAX) {
1058 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001059 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001060 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1061 *num);
1062 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001063 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001064 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1065 }
1066 ret = LY_EVALID;
1067 goto cleanup;
1068 }
1069
1070 *num = d->max;
1071 }
1072
1073cleanup:
1074 return ret;
1075}
1076
1077/**
1078 * @brief Apply deviate delete.
1079 *
1080 * @param[in] ctx Compile context.
1081 * @param[in] d Deviate delete to apply.
1082 * @param[in,out] target Deviation target.
1083 * @return LY_ERR value.
1084 */
1085static LY_ERR
1086lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1087{
1088 LY_ERR ret = LY_SUCCESS;
1089 struct lysp_restr **musts;
1090 LY_ARRAY_COUNT_TYPE u, v;
1091 struct lysp_qname **uniques, **dflts;
1092
1093#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
1094 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1095 int found = 0; \
1096 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1097 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1098 found = 1; \
1099 break; \
1100 } \
1101 } \
1102 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001103 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001104 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1105 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1106 ret = LY_EVALID; \
1107 goto cleanup; \
1108 } \
1109 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
1110 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
Michal Vasko08e9b112021-06-11 15:41:17 +02001111 if (v < LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1112 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1113 } \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001114 } \
1115 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1116 LY_ARRAY_FREE(ORIG_ARRAY); \
1117 ORIG_ARRAY = NULL; \
1118 }
1119
1120#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1121 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001122 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001123 ret = LY_EVALID; \
1124 goto cleanup; \
1125 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001126 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001127 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1128 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1129 ret = LY_EVALID; \
1130 goto cleanup; \
1131 }
1132
1133 /* [units-stmt] */
1134 if (d->units) {
1135 switch (target->nodetype) {
1136 case LYS_LEAF:
1137 case LYS_LEAFLIST:
1138 break;
1139 default:
1140 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1141 }
1142
1143 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001144 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001145 ((struct lysp_node_leaf *)target)->units = NULL;
1146 }
1147
1148 /* *must-stmt */
1149 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001150 musts = lysp_node_musts_p(target);
1151 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001152 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1153 }
1154
1155 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
1156 }
1157
1158 /* *unique-stmt */
1159 if (d->uniques) {
1160 switch (target->nodetype) {
1161 case LYS_LIST:
1162 break;
1163 default:
1164 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1165 }
1166
1167 uniques = &((struct lysp_node_list *)target)->uniques;
1168 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, "unique");
1169 }
1170
1171 /* *default-stmt */
1172 if (d->dflts) {
1173 switch (target->nodetype) {
1174 case LYS_LEAF:
1175 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1176 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1177
Michal Vaskoe180ed02021-02-05 16:31:20 +01001178 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001179 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1180 break;
1181 case LYS_LEAFLIST:
1182 dflts = &((struct lysp_node_leaflist *)target)->dflts;
1183 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, "default");
1184 break;
1185 case LYS_CHOICE:
1186 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1187 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1188
Michal Vaskoe180ed02021-02-05 16:31:20 +01001189 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001190 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1191 break;
1192 default:
1193 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1194 }
1195 }
1196
1197cleanup:
1198 return ret;
1199}
1200
1201/**
1202 * @brief Apply deviate replace.
1203 *
1204 * @param[in] ctx Compile context.
1205 * @param[in] d Deviate replace to apply.
1206 * @param[in,out] target Deviation target.
1207 * @return LY_ERR value.
1208 */
1209static LY_ERR
1210lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1211{
1212 LY_ERR ret = LY_SUCCESS;
1213 uint32_t *num;
1214
1215#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1216 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001217 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001218 ret = LY_EVALID; \
1219 goto cleanup; \
1220 }
1221
1222 /* [type-stmt] */
1223 if (d->type) {
1224 switch (target->nodetype) {
1225 case LYS_LEAF:
1226 case LYS_LEAFLIST:
1227 break;
1228 default:
1229 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1230 }
1231
1232 lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
1233 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
1234 }
1235
1236 /* [units-stmt] */
1237 if (d->units) {
1238 switch (target->nodetype) {
1239 case LYS_LEAF:
1240 case LYS_LEAFLIST:
1241 break;
1242 default:
1243 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1244 }
1245
1246 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001247 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001248 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1249 }
1250
1251 /* [default-stmt] */
1252 if (d->dflt.str) {
1253 switch (target->nodetype) {
1254 case LYS_LEAF:
1255 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1256
Michal Vaskoe180ed02021-02-05 16:31:20 +01001257 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001258 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflt), cleanup);
1259 break;
1260 case LYS_CHOICE:
1261 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
1262
Michal Vaskoe180ed02021-02-05 16:31:20 +01001263 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001264 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflt), cleanup);
1265 break;
1266 default:
1267 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1268 }
1269 }
1270
1271 /* [config-stmt] */
1272 if (d->flags & LYS_CONFIG_MASK) {
1273 switch (target->nodetype) {
1274 case LYS_CONTAINER:
1275 case LYS_LEAF:
1276 case LYS_LEAFLIST:
1277 case LYS_LIST:
1278 case LYS_CHOICE:
1279 case LYS_ANYDATA:
1280 case LYS_ANYXML:
1281 break;
1282 default:
1283 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1284 }
1285
1286 if (!(target->flags & LYS_CONFIG_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001287 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "config",
1288 d->flags & LYS_CONFIG_W ? "config true" : "config false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001289 ret = LY_EVALID;
1290 goto cleanup;
1291 }
1292
1293 target->flags &= ~LYS_CONFIG_MASK;
1294 target->flags |= d->flags & LYS_CONFIG_MASK;
1295 }
1296
1297 /* [mandatory-stmt] */
1298 if (d->flags & LYS_MAND_MASK) {
1299 switch (target->nodetype) {
1300 case LYS_LEAF:
1301 case LYS_CHOICE:
1302 case LYS_ANYDATA:
1303 case LYS_ANYXML:
1304 break;
1305 default:
1306 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1307 }
1308
1309 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001310 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1311 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001312 ret = LY_EVALID;
1313 goto cleanup;
1314 }
1315
1316 target->flags &= ~LYS_MAND_MASK;
1317 target->flags |= d->flags & LYS_MAND_MASK;
1318 }
1319
1320 /* [min-elements-stmt] */
1321 if (d->flags & LYS_SET_MIN) {
1322 switch (target->nodetype) {
1323 case LYS_LEAFLIST:
1324 num = &((struct lysp_node_leaflist *)target)->min;
1325 break;
1326 case LYS_LIST:
1327 num = &((struct lysp_node_list *)target)->min;
1328 break;
1329 default:
1330 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1331 }
1332
1333 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001334 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001335 ret = LY_EVALID;
1336 goto cleanup;
1337 }
1338
1339 *num = d->min;
1340 }
1341
1342 /* [max-elements-stmt] */
1343 if (d->flags & LYS_SET_MAX) {
1344 switch (target->nodetype) {
1345 case LYS_LEAFLIST:
1346 num = &((struct lysp_node_leaflist *)target)->max;
1347 break;
1348 case LYS_LIST:
1349 num = &((struct lysp_node_list *)target)->max;
1350 break;
1351 default:
1352 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1353 }
1354
1355 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001356 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001357 ret = LY_EVALID;
1358 goto cleanup;
1359 }
1360
1361 *num = d->max;
1362 }
1363
1364cleanup:
1365 return ret;
1366}
1367
1368/**
1369 * @brief Get module of a single nodeid node name test.
1370 *
1371 * @param[in] ctx libyang context.
1372 * @param[in] nametest Nametest with an optional prefix.
1373 * @param[in] nametest_len Length of @p nametest.
1374 * @param[in] mod Both current and prefix module for resolving prefixes and to return in case of no prefix.
1375 * @param[out] name Optional pointer to the name test without the prefix.
1376 * @param[out] name_len Length of @p name.
1377 * @return Resolved module.
1378 */
1379static const struct lys_module *
1380lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
1381 const struct lysp_module *mod, const char **name, size_t *name_len)
1382{
1383 const struct lys_module *target_mod;
1384 const char *ptr;
1385
1386 ptr = ly_strnchr(nametest, ':', nametest_len);
1387 if (ptr) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001388 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_VALUE_SCHEMA, (void *)mod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001389 if (!target_mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001390 LOGVAL(ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001391 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001392 (int)nametest_len, nametest, (int)(ptr - nametest), nametest, LYSP_MODULE_NAME(mod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001393 return NULL;
1394 }
1395
1396 if (name) {
1397 *name = ptr + 1;
1398 *name_len = nametest_len - ((ptr - nametest) + 1);
1399 }
1400 } else {
1401 target_mod = mod->mod;
1402 if (name) {
1403 *name = nametest;
1404 *name_len = nametest_len;
1405 }
1406 }
1407
1408 return target_mod;
1409}
1410
1411/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001412 * @brief Check whether a compiled node matches a single schema nodeid name test.
1413 *
1414 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1415 * @param[in] mod Expected module.
1416 * @param[in] name Expected name.
1417 * @param[in] name_len Length of @p name.
1418 * @return Whether it is a match or not.
1419 */
1420static ly_bool
1421lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1422 size_t name_len)
1423{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001424 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001425 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001426 return 0;
1427 }
1428
1429 /* compare names */
Michal Vasko544e58a2021-01-28 14:33:41 +01001430 if (ly_strncmp((*node)->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001431 return 0;
1432 }
1433
Michal Vasko2a668712020-10-21 11:48:09 +02001434 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001435 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001436
1437 return 1;
1438}
1439
1440/**
1441 * @brief Check whether a node matches specific schema nodeid.
1442 *
1443 * @param[in] exp Parsed nodeid to match.
1444 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
1445 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1446 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1447 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1448 * @param[in] pnode_mod Compiled @p pnode to-be module.
1449 * @return Whether it is a match or not.
1450 */
1451static ly_bool
1452lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node,
1453 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
1454{
1455 uint32_t i;
1456 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001457 const char *name = NULL;
1458 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001459
1460 /* compare last node in the node ID */
1461 i = exp->used - 1;
1462
1463 /* get exp node ID module */
1464 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);
1465 assert(mod);
1466
1467 if (pnode) {
1468 /* compare on the last parsed-only node */
Radek Krejci2d5f6df2021-01-28 14:00:13 +01001469 if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001470 return 0;
1471 }
1472 } else {
1473 /* using parent directly */
1474 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1475 return 0;
1476 }
1477 }
1478
1479 /* now compare all the compiled parents */
1480 while (i > 1) {
1481 i -= 2;
1482 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1483
1484 if (!parent) {
1485 /* no more parents but path continues */
1486 return 0;
1487 }
1488
1489 /* get exp node ID module */
1490 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1491 &name_len);
1492 assert(mod);
1493
1494 /* compare with the parent */
1495 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1496 return 0;
1497 }
1498 }
1499
1500 if (ctx_node && (ctx_node != parent)) {
1501 /* descendant path has not finished in the context node */
1502 return 0;
1503 } else if (!ctx_node && parent) {
1504 /* some parent was not matched */
1505 return 0;
1506 }
1507
1508 return 1;
1509}
1510
1511void
1512lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1513{
1514 if (aug) {
1515 lyxp_expr_free(ctx, aug->nodeid);
1516
1517 free(aug);
1518 }
1519}
1520
1521void
1522lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1523{
1524 if (dev) {
1525 lyxp_expr_free(ctx, dev->nodeid);
1526 LY_ARRAY_FREE(dev->devs);
1527 LY_ARRAY_FREE(dev->dev_pmods);
1528
1529 free(dev);
1530 }
1531}
1532
1533void
1534lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1535{
1536 if (rfn) {
1537 lyxp_expr_free(ctx, rfn->nodeid);
1538 LY_ARRAY_FREE(rfn->rfns);
1539
1540 free(rfn);
1541 }
1542}
1543
1544void
1545lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
1546{
Michal Vasko426aa7e2021-06-21 13:30:52 +02001547 LY_ARRAY_COUNT_TYPE u;
1548
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001549 if (!dev_pnode) {
1550 return;
1551 }
1552
1553 switch (dev_pnode->nodetype) {
1554 case LYS_CONTAINER:
1555 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001556 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1557 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001558 break;
1559 case LYS_LIST:
1560 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001561 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1562 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001563 break;
1564 case LYS_CHOICE:
1565 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1566 break;
1567 case LYS_CASE:
1568 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1569 break;
1570 case LYS_LEAF:
1571 case LYS_LEAFLIST:
1572 case LYS_ANYXML:
1573 case LYS_ANYDATA:
1574 /* no children */
1575 break;
1576 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001577 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001578 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001579 case LYS_RPC:
1580 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001581 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1582 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001583 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001584 case LYS_INPUT:
1585 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001586 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001587 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001588 free(dev_pnode);
1589 return;
1590 default:
1591 LOGINT(ctx);
1592 return;
1593 }
1594
Michal Vasko426aa7e2021-06-21 13:30:52 +02001595 /* extension parsed tree and children were not duplicated */
1596 LY_ARRAY_FOR(dev_pnode->exts, u) {
1597 dev_pnode->exts[u].parsed = NULL;
1598 dev_pnode->exts[u].child = NULL;
1599 }
1600
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001601 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
1602}
1603
1604LY_ERR
1605lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1606 struct lysp_node **dev_pnode, ly_bool *not_supported)
1607{
1608 LY_ERR ret = LY_SUCCESS;
1609 uint32_t i;
1610 LY_ARRAY_COUNT_TYPE u;
1611 struct lys_module *orig_mod = ctx->cur_mod;
1612 struct lysp_module *orig_pmod = ctx->pmod;
1613 char orig_path[LYSC_CTX_BUFSIZE];
1614 struct lysc_refine *rfn;
1615 struct lysc_deviation *dev;
1616 struct lysp_deviation *dev_p;
1617 struct lysp_deviate *d;
1618
1619 *dev_pnode = NULL;
1620 *not_supported = 0;
1621
1622 for (i = 0; i < ctx->uses_rfns.count; ++i) {
1623 rfn = ctx->uses_rfns.objs[i];
1624
Michal Vasko28fe5f62021-03-03 16:37:39 +01001625 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 +02001626 /* not our target node */
1627 continue;
1628 }
1629
1630 if (!*dev_pnode) {
1631 /* first refine on this node, create a copy first */
1632 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1633 }
1634
Michal Vaskob8df5762021-01-12 15:15:53 +01001635 /* use modules from the refine */
1636 ctx->cur_mod = rfn->nodeid_pmod->mod;
1637 ctx->pmod = (struct lysp_module *)rfn->nodeid_pmod;
1638
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001639 /* apply all the refines by changing (the copy of) the parsed node */
1640 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vaskob8df5762021-01-12 15:15:53 +01001641 /* keep the current path and add to it */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001642 lysc_update_path(ctx, NULL, "{refine}");
1643 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001644
1645 /* apply refine and restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001646 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
1647 lysc_update_path(ctx, NULL, NULL);
1648 lysc_update_path(ctx, NULL, NULL);
1649 LY_CHECK_GOTO(ret, cleanup);
1650 }
1651
1652 /* refine was applied, remove it */
1653 lysc_refine_free(ctx->ctx, rfn);
1654 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1655
1656 /* all the refines for one target node are in one structure, we are done */
1657 break;
1658 }
1659
1660 for (i = 0; i < ctx->devs.count; ++i) {
1661 dev = ctx->devs.objs[i];
1662
Michal Vasko28fe5f62021-03-03 16:37:39 +01001663 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, orig_mod)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001664 /* not our target node */
1665 continue;
1666 }
1667
1668 if (dev->not_supported) {
1669 /* it is not supported, no more deviations */
1670 *not_supported = 1;
1671 goto dev_applied;
1672 }
1673
1674 if (!*dev_pnode) {
1675 /* first deviation on this node, create a copy first */
1676 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1677 }
1678
1679 /* apply all the deviates by changing (the copy of) the parsed node */
1680 LY_ARRAY_FOR(dev->devs, u) {
1681 dev_p = dev->devs[u];
1682 LY_LIST_FOR(dev_p->deviates, d) {
1683 /* generate correct path */
1684 strcpy(orig_path, ctx->path);
1685 ctx->path_len = 1;
1686 ctx->cur_mod = dev->dev_pmods[u]->mod;
1687 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
1688 lysc_update_path(ctx, NULL, "{deviation}");
1689 lysc_update_path(ctx, NULL, dev_p->nodeid);
1690
1691 switch (d->mod) {
1692 case LYS_DEV_ADD:
1693 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
1694 break;
1695 case LYS_DEV_DELETE:
1696 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
1697 break;
1698 case LYS_DEV_REPLACE:
1699 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
1700 break;
1701 default:
1702 LOGINT(ctx->ctx);
1703 ret = LY_EINT;
1704 }
1705
1706 /* restore previous path */
1707 strcpy(ctx->path, orig_path);
1708 ctx->path_len = strlen(ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001709
1710 LY_CHECK_GOTO(ret, cleanup);
1711 }
1712 }
1713
1714dev_applied:
1715 /* deviation was applied, remove it */
1716 lysc_deviation_free(ctx->ctx, dev);
1717 ly_set_rm_index(&ctx->devs, i, NULL);
1718
1719 /* all the deviations for one target node are in one structure, we are done */
1720 break;
1721 }
1722
1723cleanup:
Michal Vasko20316b32021-01-12 15:16:54 +01001724 ctx->cur_mod = orig_mod;
1725 ctx->pmod = orig_pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001726 if (ret) {
1727 lysp_dev_node_free(ctx->ctx, *dev_pnode);
1728 *dev_pnode = NULL;
1729 *not_supported = 0;
1730 }
1731 return ret;
1732}
1733
1734/**
1735 * @brief Compile the parsed augment connecting it into its target.
1736 *
1737 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1738 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1739 * are already implemented and compiled.
1740 *
1741 * @param[in] ctx Compile context.
1742 * @param[in] aug_p Parsed augment to compile.
1743 * @param[in] target Target node of the augment.
1744 * @return LY_SUCCESS on success.
1745 * @return LY_EVALID on failure.
1746 */
1747static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001748lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001749{
1750 LY_ERR ret = LY_SUCCESS;
1751 struct lysp_node *pnode;
1752 struct lysc_node *node;
1753 struct lysc_when *when_shared = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001754 struct lysc_node_action **actions;
1755 struct lysc_node_notif **notifs;
Michal Vasko29dd11e2020-11-23 16:52:22 +01001756 ly_bool allow_mandatory = 0, enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001757 struct ly_set child_set = {0};
Michal Vasko7c565922021-06-10 14:58:27 +02001758 uint32_t i, opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001759
1760 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001761 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001762 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
1763 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
1764 ret = LY_EVALID;
1765 goto cleanup;
1766 }
1767
1768 /* check for mandatory nodes
1769 * - new cases augmenting some choice can have mandatory nodes
1770 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1771 */
1772 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
1773 allow_mandatory = 1;
1774 }
1775
1776 LY_LIST_FOR(aug_p->child, pnode) {
1777 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1778 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1779 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1780 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001781 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001782 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1783 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1784 ret = LY_EVALID;
1785 goto cleanup;
1786 }
1787
1788 /* compile the children */
1789 if (target->nodetype == LYS_CHOICE) {
1790 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
Michal Vasko6fb4c042020-11-24 18:05:26 +01001791 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1792 if (target->nodetype == LYS_INPUT) {
Michal Vasko7c565922021-06-10 14:58:27 +02001793 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
Michal Vasko6fb4c042020-11-24 18:05:26 +01001794 } else {
Michal Vasko7c565922021-06-10 14:58:27 +02001795 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
Michal Vasko6fb4c042020-11-24 18:05:26 +01001796 }
Radek Krejci2a9fc652021-01-22 17:44:34 +01001797 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001798 } else {
1799 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1800 }
1801
Michal Vasko29dd11e2020-11-23 16:52:22 +01001802 /* eval if-features again for the rest of this node processing */
1803 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1804 if (!enabled) {
Michal Vasko7c565922021-06-10 14:58:27 +02001805 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vasko29dd11e2020-11-23 16:52:22 +01001806 }
1807
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001808 /* since the augment node is not present in the compiled tree, we need to pass some of its
1809 * statements to all its children */
1810 for (i = 0; i < child_set.count; ++i) {
1811 node = child_set.snodes[i];
1812 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1813 node->flags &= ~LYS_MAND_TRUE;
1814 lys_compile_mandatory_parents(target, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001815 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko23864e02021-06-24 09:23:58 +02001816 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
1817 node->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001818 ret = LY_EVALID;
1819 goto cleanup;
1820 }
1821
1822 if (aug_p->when) {
1823 /* pass augment's when to all the children */
Michal Vaskodfd254d2021-06-24 09:24:59 +02001824 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, lysc_data_node(target), node, &when_shared);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001825 LY_CHECK_GOTO(ret, cleanup);
1826 }
1827 }
1828 ly_set_erase(&child_set, NULL);
Michal Vasko29dd11e2020-11-23 16:52:22 +01001829
1830 /* restore options */
Michal Vasko7c565922021-06-10 14:58:27 +02001831 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001832 }
1833
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001834 actions = lysc_node_actions_p(target);
1835 notifs = lysc_node_notifs_p(target);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001836
1837 if (aug_p->actions) {
1838 if (!actions) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001839 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001840 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
Radek Krejci2a9fc652021-01-22 17:44:34 +01001841 lys_nodetype2str(target->nodetype), aug_p->actions->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001842 ret = LY_EVALID;
1843 goto cleanup;
1844 }
1845
1846 /* compile actions into the target */
Radek Krejci2a9fc652021-01-22 17:44:34 +01001847 LY_LIST_FOR((struct lysp_node *)aug_p->actions, pnode) {
Michal Vasko012807e2021-02-03 09:52:18 +01001848 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001849
Michal Vasko012807e2021-02-03 09:52:18 +01001850 /* eval if-features again for the rest of this node processing */
1851 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1852 if (!enabled) {
Michal Vasko7c565922021-06-10 14:58:27 +02001853 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001854 }
Michal Vasko012807e2021-02-03 09:52:18 +01001855
1856 /* since the augment node is not present in the compiled tree, we need to pass some of its
1857 * statements to all its children */
1858 for (i = 0; i < child_set.count; ++i) {
1859 node = child_set.snodes[i];
1860 if (aug_p->when) {
1861 /* pass augment's when to all the actions */
Michal Vaskodfd254d2021-06-24 09:24:59 +02001862 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, lysc_data_node(target), node, &when_shared);
Michal Vasko012807e2021-02-03 09:52:18 +01001863 LY_CHECK_GOTO(ret, cleanup);
1864 }
1865 }
1866 ly_set_erase(&child_set, NULL);
1867
1868 /* restore options */
Michal Vasko7c565922021-06-10 14:58:27 +02001869 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001870 }
1871 }
1872 if (aug_p->notifs) {
1873 if (!notifs) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001874 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001875 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
Radek Krejci2a9fc652021-01-22 17:44:34 +01001876 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001877 ret = LY_EVALID;
1878 goto cleanup;
1879 }
1880
1881 /* compile notifications into the target */
Radek Krejci2a9fc652021-01-22 17:44:34 +01001882 LY_LIST_FOR((struct lysp_node *)aug_p->notifs, pnode) {
Michal Vasko012807e2021-02-03 09:52:18 +01001883 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001884
Michal Vasko012807e2021-02-03 09:52:18 +01001885 /* eval if-features again for the rest of this node processing */
1886 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1887 if (!enabled) {
Michal Vasko7c565922021-06-10 14:58:27 +02001888 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001889 }
Michal Vasko012807e2021-02-03 09:52:18 +01001890
1891 /* since the augment node is not present in the compiled tree, we need to pass some of its
1892 * statements to all its children */
1893 for (i = 0; i < child_set.count; ++i) {
1894 node = child_set.snodes[i];
1895 if (aug_p->when) {
1896 /* pass augment's when to all the actions */
Michal Vaskodfd254d2021-06-24 09:24:59 +02001897 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, lysc_data_node(target), node, &when_shared);
Michal Vasko012807e2021-02-03 09:52:18 +01001898 LY_CHECK_GOTO(ret, cleanup);
1899 }
1900 }
1901 ly_set_erase(&child_set, NULL);
1902
1903 /* restore options */
Michal Vasko7c565922021-06-10 14:58:27 +02001904 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001905 }
1906 }
1907
1908cleanup:
1909 ly_set_erase(&child_set, NULL);
Michal Vasko7c565922021-06-10 14:58:27 +02001910 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001911 return ret;
1912}
1913
1914LY_ERR
1915lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
1916{
1917 LY_ERR ret = LY_SUCCESS;
1918 struct lys_module *orig_mod = ctx->cur_mod;
1919 struct lysp_module *orig_pmod = ctx->pmod;
1920 uint32_t i;
1921 char orig_path[LYSC_CTX_BUFSIZE];
1922 struct lysc_augment *aug;
1923
1924 /* uses augments */
1925 for (i = 0; i < ctx->uses_augs.count; ) {
1926 aug = ctx->uses_augs.objs[i];
1927
Michal Vasko28fe5f62021-03-03 16:37:39 +01001928 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->nodeid_ctx_node, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001929 /* not our target node */
1930 ++i;
1931 continue;
1932 }
1933
Michal Vaskob8df5762021-01-12 15:15:53 +01001934 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001935 lysc_update_path(ctx, NULL, "{augment}");
1936 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01001937 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01001938
1939 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001940 ret = lys_compile_augment(ctx, aug->aug_p, node);
1941 lysc_update_path(ctx, NULL, NULL);
1942 lysc_update_path(ctx, NULL, NULL);
1943 LY_CHECK_GOTO(ret, cleanup);
1944
Michal Vaskoc75f2042021-06-08 14:57:03 +02001945 /* augment was applied, remove it (index and the whole set may have changed because other augments
1946 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001947 ly_set_rm(&ctx->uses_augs, aug, NULL);
1948 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02001949 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001950 }
1951
1952 /* top-level augments */
1953 for (i = 0; i < ctx->augs.count; ) {
1954 aug = ctx->augs.objs[i];
1955
Michal Vasko28fe5f62021-03-03 16:37:39 +01001956 if (!lysp_schema_nodeid_match(aug->nodeid, aug->aug_pmod, NULL, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001957 /* not our target node */
1958 ++i;
1959 continue;
1960 }
1961
Michal Vaskob8df5762021-01-12 15:15:53 +01001962 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001963 strcpy(orig_path, ctx->path);
1964 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01001965 ctx->cur_mod = aug->aug_pmod->mod;
1966 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02001967 lysc_update_path(ctx, NULL, "{augment}");
1968 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001969
1970 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001971 ret = lys_compile_augment(ctx, aug->aug_p, node);
1972 strcpy(ctx->path, orig_path);
1973 ctx->path_len = strlen(ctx->path);
1974 LY_CHECK_GOTO(ret, cleanup);
1975
1976 /* augment was applied, remove it */
1977 ly_set_rm(&ctx->augs, aug, NULL);
1978 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02001979 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001980 }
1981
1982cleanup:
1983 ctx->cur_mod = orig_mod;
1984 ctx->pmod = orig_pmod;
1985 return ret;
1986}
1987
1988/**
1989 * @brief Prepare a top-level augment to be applied during data nodes compilation.
1990 *
1991 * @param[in] ctx Compile context.
1992 * @param[in] aug_p Parsed augment to be applied.
1993 * @param[in] pmod Both current and prefix module for @p aug_p.
1994 * @return LY_ERR value.
1995 */
1996static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001997lys_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 +02001998{
1999 LY_ERR ret = LY_SUCCESS;
2000 struct lyxp_expr *exp = NULL;
2001 struct lysc_augment *aug;
2002 const struct lys_module *mod;
2003
2004 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2005 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
2006 LY_CHECK_GOTO(ret, cleanup);
2007
2008 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2009 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2010 if (mod != ctx->cur_mod) {
2011 /* augment for another module, ignore */
2012 goto cleanup;
2013 }
2014
2015 /* allocate new compiled augment and store it in the set */
2016 aug = calloc(1, sizeof *aug);
2017 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2018 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2019
2020 aug->nodeid = exp;
2021 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002022 aug->aug_pmod = pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002023 aug->aug_p = aug_p;
2024
2025cleanup:
2026 lyxp_expr_free(ctx->ctx, exp);
2027 return ret;
2028}
2029
2030LY_ERR
2031lys_precompile_own_augments(struct lysc_ctx *ctx)
2032{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002033 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002034
2035 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002036 const struct lys_module *aug_mod = ctx->cur_mod->augmented_by[u];
2037 struct lysp_node_augment *aug;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002038
2039 /* collect all module augments */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002040 LY_LIST_FOR(aug_mod->parsed->augments, aug) {
2041 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002042 }
2043
2044 /* collect all submodules augments */
2045 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002046 LY_LIST_FOR(aug_mod->parsed->includes[v].submodule->augments, aug) {
2047 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 +02002048 }
2049 }
2050 }
2051
2052 return LY_SUCCESS;
2053}
2054
2055/**
2056 * @brief Prepare a deviation to be applied during data nodes compilation.
2057 *
2058 * @param[in] ctx Compile context.
2059 * @param[in] dev_p Parsed deviation to be applied.
2060 * @param[in] pmod Both current and prefix module for @p dev_p.
2061 * @return LY_ERR value.
2062 */
2063static LY_ERR
2064lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2065{
2066 LY_ERR ret = LY_SUCCESS;
2067 struct lysc_deviation *dev = NULL;
2068 struct lyxp_expr *exp = NULL;
2069 struct lysp_deviation **new_dev;
2070 const struct lys_module *mod;
2071 const struct lysp_module **new_dev_pmod;
2072 uint32_t i;
2073
2074 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2075 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2076 LY_CHECK_GOTO(ret, cleanup);
2077
2078 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2079 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2080 if (mod != ctx->cur_mod) {
2081 /* deviation for another module, ignore */
2082 goto cleanup;
2083 }
2084
2085 /* try to find the node in already compiled deviations */
2086 for (i = 0; i < ctx->devs.count; ++i) {
2087 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2088 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2089 dev = ctx->devs.objs[i];
2090 break;
2091 }
2092 }
2093
2094 if (!dev) {
2095 /* allocate new compiled deviation */
2096 dev = calloc(1, sizeof *dev);
2097 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2098 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2099
2100 dev->nodeid = exp;
2101 exp = NULL;
2102 }
2103
2104 /* add new parsed deviation structure */
2105 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2106 *new_dev = dev_p;
2107 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2108 *new_dev_pmod = pmod;
2109
2110cleanup:
2111 lyxp_expr_free(ctx->ctx, exp);
2112 return ret;
2113}
2114
2115LY_ERR
2116lys_precompile_own_deviations(struct lysc_ctx *ctx)
2117{
2118 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002119 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002120 const struct lys_module *dev_mod;
2121 struct lysc_deviation *dev;
2122 struct lysp_deviate *d;
2123 int not_supported;
2124 uint32_t i;
2125
2126 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2127 dev_mod = ctx->cur_mod->deviated_by[u];
2128
2129 /* compile all module deviations */
2130 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2131 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2132 }
2133
2134 /* compile all submodules deviations */
2135 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2136 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2137 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2138 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2139 }
2140 }
2141 }
2142
2143 /* set not-supported flags for all the deviations */
2144 for (i = 0; i < ctx->devs.count; ++i) {
2145 dev = ctx->devs.objs[i];
2146 not_supported = 0;
2147
2148 LY_ARRAY_FOR(dev->devs, u) {
2149 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2150 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2151 not_supported = 1;
2152 break;
2153 }
2154 }
2155 if (not_supported) {
2156 break;
2157 }
2158 }
2159 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002160 orig_cur_mod = ctx->cur_mod;
2161 ctx->cur_mod = dev->dev_pmods[u]->mod;
2162 lysc_update_path(ctx, NULL, "{deviation}");
2163 lysc_update_path(ctx, NULL, dev->nodeid->expr);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002164 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002165 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002166 lysc_update_path(ctx, NULL, NULL);
2167 lysc_update_path(ctx, NULL, NULL);
2168 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002169 return LY_EVALID;
2170 }
2171
2172 dev->not_supported = not_supported;
2173 }
2174
2175 return LY_SUCCESS;
2176}
2177
2178/**
2179 * @brief Add a module reference into an array, checks for duplicities.
2180 *
2181 * @param[in] ctx Compile context.
2182 * @param[in] mod Module reference to add.
2183 * @param[in,out] mod_array Module sized array to add to.
2184 * @return LY_ERR value.
2185 */
2186static LY_ERR
2187lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2188{
2189 LY_ARRAY_COUNT_TYPE u;
2190 struct lys_module **new_mod;
2191
2192 LY_ARRAY_FOR(*mod_array, u) {
2193 if ((*mod_array)[u] == mod) {
2194 /* already there */
2195 return LY_EEXIST;
2196 }
2197 }
2198
2199 /* add the new module ref */
2200 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2201 *new_mod = mod;
2202
2203 return LY_SUCCESS;
2204}
2205
Michal Vasko1ccbf542021-04-19 11:35:00 +02002206/**
2207 * @brief Check whether all modules in a set are implemented.
2208 *
2209 * @param[in] mod_set Module set to check.
2210 * @return Whether all modules are implemented or not.
2211 */
2212static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002213lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002214{
2215 uint32_t i;
2216 const struct lys_module *mod;
2217
2218 for (i = 0; i < mod_set->count; ++i) {
2219 mod = mod_set->objs[i];
2220 if (!mod->implemented) {
2221 return 0;
2222 }
2223 }
2224
2225 return 1;
2226}
2227
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002228LY_ERR
Michal Vasko65333882021-06-10 14:12:16 +02002229lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002230{
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002231 LY_ERR ret = LY_SUCCESS, r;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002232 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko65333882021-06-10 14:12:16 +02002233 struct lysc_ctx ctx = {0};
2234 struct lysp_module *mod_p;
2235 struct lys_module *m;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002236 struct lysp_submodule *submod;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002237 struct lysp_node_augment *aug;
Michal Vaskoc56d6372021-10-19 12:29:00 +02002238 const char **imp_f, *all_f[] = {"*", NULL};
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002239 uint32_t i;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002240 struct ly_set mod_set = {0}, set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002241
Michal Vasko65333882021-06-10 14:12:16 +02002242 mod_p = mod->parsed;
2243
2244 /* prepare context */
2245 ctx.ctx = mod->ctx;
2246 ctx.cur_mod = mod;
2247 ctx.pmod = mod_p;
2248 ctx.path_len = 1;
2249 ctx.path[0] = '/';
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002250
Radek Krejci2a9fc652021-01-22 17:44:34 +01002251 LY_LIST_FOR(mod_p->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002252 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002253 lysc_update_path(&ctx, NULL, "{augment}");
2254 lysc_update_path(&ctx, NULL, aug->nodeid);
2255 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2256 lysc_update_path(&ctx, NULL, NULL);
2257 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002258 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002259
Michal Vasko1ccbf542021-04-19 11:35:00 +02002260 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vasko65333882021-06-10 14:12:16 +02002261 if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002262 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002263 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002264 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002265 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002266 }
2267
2268 LY_ARRAY_FOR(mod_p->deviations, u) {
2269 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002270 lysc_update_path(&ctx, NULL, "{deviation}");
2271 lysc_update_path(&ctx, NULL, mod_p->deviations[u].nodeid);
2272 ret = lys_nodeid_mod_check(&ctx, mod_p->deviations[u].nodeid, 1, &set, NULL, &m);
2273 lysc_update_path(&ctx, NULL, NULL);
2274 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002275 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002276
Michal Vasko1ccbf542021-04-19 11:35:00 +02002277 /* add this module into the target module deviated_by, if not there and implemented */
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 /* the same for augments and deviations in submodules */
2286 LY_ARRAY_FOR(mod_p->includes, v) {
2287 submod = mod_p->includes[v].submodule;
Michal Vasko65333882021-06-10 14:12:16 +02002288 ctx.pmod = (struct lysp_module *)submod;
Michal Vaskoce3d6172021-06-08 14:59:49 +02002289
Radek Krejci2a9fc652021-01-22 17:44:34 +01002290 LY_LIST_FOR(submod->augments, aug) {
Michal Vasko65333882021-06-10 14:12:16 +02002291 lysc_update_path(&ctx, NULL, "{augment}");
2292 lysc_update_path(&ctx, NULL, aug->nodeid);
2293 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2294 lysc_update_path(&ctx, NULL, NULL);
2295 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002296 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002297
Michal Vasko65333882021-06-10 14:12:16 +02002298 if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002299 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002300 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002301 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002302 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002303 }
2304
2305 LY_ARRAY_FOR(submod->deviations, u) {
Michal Vasko65333882021-06-10 14:12:16 +02002306 lysc_update_path(&ctx, NULL, "{deviation}");
2307 lysc_update_path(&ctx, NULL, submod->deviations[u].nodeid);
2308 ret = lys_nodeid_mod_check(&ctx, submod->deviations[u].nodeid, 1, &set, NULL, &m);
2309 lysc_update_path(&ctx, NULL, NULL);
2310 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002311 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002312
Michal Vasko65333882021-06-10 14:12:16 +02002313 if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002314 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002315 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
2316 }
2317 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002318 }
2319 }
2320
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002321 for (i = 0; i < mod_set.count; ++i) {
2322 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002323
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002324 if (m == mod) {
2325 /* will be applied normally later */
2326 continue;
2327 }
2328
2329 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2330 * not compiled yet and marked for compilation */
2331
2332 if (!m->implemented) {
2333 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002334 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2335 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002336 if (r == LY_ERECOMPILE) {
2337 /* implement all the modules right away to save possible later recompilation */
2338 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002339 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002340 } else if (r) {
2341 /* error */
2342 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002343 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002344 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002345 } else if (m->compiled) {
2346 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2347 m->to_compile = 1;
2348 ret = LY_ERECOMPILE;
2349 continue;
2350 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002351 }
2352
Michal Vasko1ccbf542021-04-19 11:35:00 +02002353cleanup:
2354 ly_set_erase(&set, NULL);
2355 ly_set_erase(&mod_set, NULL);
2356 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002357}
2358
2359void
2360lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2361{
2362 uint32_t i;
2363 LY_ARRAY_COUNT_TYPE u, count;
2364 struct lys_module *m;
2365
2366 for (i = 0; i < ctx->list.count; ++i) {
2367 m = ctx->list.objs[i];
2368
2369 if (m->augmented_by) {
2370 count = LY_ARRAY_COUNT(m->augmented_by);
2371 for (u = 0; u < count; ++u) {
2372 if (m->augmented_by[u] == mod) {
2373 /* keep the order */
2374 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002375 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002376 }
2377 LY_ARRAY_DECREMENT(m->augmented_by);
2378 break;
2379 }
2380 }
2381 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2382 LY_ARRAY_FREE(m->augmented_by);
2383 m->augmented_by = NULL;
2384 }
2385 }
2386
2387 if (m->deviated_by) {
2388 count = LY_ARRAY_COUNT(m->deviated_by);
2389 for (u = 0; u < count; ++u) {
2390 if (m->deviated_by[u] == mod) {
2391 /* keep the order */
2392 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002393 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002394 }
2395 LY_ARRAY_DECREMENT(m->deviated_by);
2396 break;
2397 }
2398 }
2399 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2400 LY_ARRAY_FREE(m->deviated_by);
2401 m->deviated_by = NULL;
2402 }
2403 }
2404 }
2405}