blob: 49932ce425ff20d22a78edac3b13f57e7bc56c93 [file] [log] [blame]
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001/**
2 * @file schema_compile_amend.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko19a09022021-06-15 11:54:08 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02005 * @brief Schema compilation of augments, deviations, and refines.
6 *
Michal Vasko19a09022021-06-15 11:54:08 +02007 * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#define _GNU_SOURCE
17
18#include "schema_compile_amend.h"
19
20#include <assert.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020021#include <stddef.h>
22#include <stdint.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020023#include <stdlib.h>
24#include <string.h>
25
26#include "common.h"
Radek Krejci77114102021-03-10 15:21:57 +010027#include "dict.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020028#include "log.h"
Radek Krejci77114102021-03-10 15:21:57 +010029#include "plugins_exts_compile.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020030#include "schema_compile.h"
31#include "schema_compile_node.h"
Michal Vasko29dd11e2020-11-23 16:52:22 +010032#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020033#include "set.h"
34#include "tree.h"
Michal Vasko899c7ce2022-02-18 09:18:37 +010035#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010036#include "tree_edit.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020037#include "tree_schema.h"
38#include "tree_schema_internal.h"
39#include "xpath.h"
40
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 Vasko899c7ce2022-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{
Michal Vaskod84b8132022-03-15 10:45:44 +0100275 struct lysp_stmt *ch = NULL;
Michal Vasko4316c9d2022-02-21 10:00:10 +0100276
Michal Vasko9464f422022-02-21 10:18:28 +0100277 assert(!*child);
278
Michal Vasko899c7ce2022-02-18 09:18:37 +0100279 LY_LIST_FOR(orig_child, orig_child) {
280 /* new child */
281 if (!*child) {
Michal Vasko4316c9d2022-02-21 10:00:10 +0100282 *child = ch = calloc(1, sizeof *ch);
283 LY_CHECK_ERR_RET(!ch, LOGMEM(ctx), LY_EMEM);
Michal Vasko899c7ce2022-02-18 09:18:37 +0100284 } else {
Michal Vasko4316c9d2022-02-21 10:00:10 +0100285 ch->next = calloc(1, sizeof *ch);
286 LY_CHECK_ERR_RET(!ch->next, LOGMEM(ctx), LY_EMEM);
287 ch = ch->next;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100288 }
289
290 /* fill */
Michal Vasko4316c9d2022-02-21 10:00:10 +0100291 DUP_STRING_RET(ctx, orig_child->stmt, ch->stmt);
292 ch->flags = orig_child->flags;
293 DUP_STRING_RET(ctx, orig_child->arg, ch->arg);
294 ch->format = orig_child->format;
295 LY_CHECK_RET(ly_dup_prefix_data(ctx, orig_child->format, orig_child->prefix_data, &(ch->prefix_data)));
296 ch->kw = orig_child->kw;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100297
298 /* recursive children */
Michal Vasko4316c9d2022-02-21 10:00:10 +0100299 LY_CHECK_RET(lysp_ext_children_dup(ctx, &ch->child, orig_child->child));
Michal Vasko899c7ce2022-02-18 09:18:37 +0100300 }
301
302 return LY_SUCCESS;
303}
304
305static LY_ERR
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200306lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
307{
Michal Vasko899c7ce2022-02-18 09:18:37 +0100308 DUP_STRING_RET(ctx, orig_ext->name, ext->name);
309 DUP_STRING_RET(ctx, orig_ext->argument, ext->argument);
Michal Vasko91bb76c2022-03-24 13:34:18 +0100310 ext->format = orig_ext->format;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100311 ext->parsed = NULL;
Michal Vasko91bb76c2022-03-24 13:34:18 +0100312 LY_CHECK_RET(ly_dup_prefix_data(ctx, orig_ext->format, orig_ext->prefix_data, &ext->prefix_data));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200313
Michal Vasko899c7ce2022-02-18 09:18:37 +0100314 ext->child = NULL;
315 LY_CHECK_RET(lysp_ext_children_dup(ctx, &ext->child, orig_ext->child));
316
Michal Vasko91bb76c2022-03-24 13:34:18 +0100317 ext->parent = orig_ext->parent;
318 ext->parent_stmt = orig_ext->parent_stmt;
319 ext->parent_stmt_index = orig_ext->parent_stmt_index;
320 ext->flags = orig_ext->flags;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100321 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200322}
323
324static LY_ERR
325lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
326{
327 LY_ERR ret = LY_SUCCESS;
328
329 if (orig_restr) {
330 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
331 restr->arg.mod = orig_restr->arg.mod;
332 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
333 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
334 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
335 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
336 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
337 }
338
339 return ret;
340}
341
342static LY_ERR
343lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
344{
345 LY_ERR ret = LY_SUCCESS;
346
347 DUP_STRING(ctx, *orig_str, *str, ret);
348
349 return ret;
350}
351
352LY_ERR
353lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
354{
355 LY_ERR ret = LY_SUCCESS;
356
357 if (!orig_qname->str) {
358 return LY_SUCCESS;
359 }
360
361 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
362 assert(orig_qname->mod);
363 qname->mod = orig_qname->mod;
364
365 return ret;
366}
367
368static LY_ERR
369lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
370{
371 LY_ERR ret = LY_SUCCESS;
372
373 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
374 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
375 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
376 enm->value = orig_enm->value;
377 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
378 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
379 enm->flags = orig_enm->flags;
380
381 return ret;
382}
383
384static LY_ERR
385lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
386{
387 LY_ERR ret = LY_SUCCESS;
388
Michal Vaskoea868242021-06-21 09:28:32 +0200389 /* array macros read previous data so we must zero it */
390 memset(type, 0, sizeof *type);
391
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200392 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
393
394 if (orig_type->range) {
395 type->range = calloc(1, sizeof *type->range);
396 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
397 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
398 }
399
400 if (orig_type->length) {
401 type->length = calloc(1, sizeof *type->length);
402 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
403 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
404 }
405
406 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
407 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
408 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
409 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
410 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
411 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
412 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
413
414 type->pmod = orig_type->pmod;
415 type->compiled = orig_type->compiled;
416
417 type->fraction_digits = orig_type->fraction_digits;
418 type->require_instance = orig_type->require_instance;
419 type->flags = orig_type->flags;
420
421done:
422 return ret;
423}
424
425static LY_ERR
426lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
427{
428 LY_ERR ret = LY_SUCCESS;
429
430 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
431 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
432 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
433 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
434
435 return ret;
436}
437
438static LY_ERR
439lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
440{
441 LY_ERR ret = LY_SUCCESS;
442
443 node->parent = NULL;
444 node->nodetype = orig->nodetype;
445 node->flags = orig->flags;
446 node->next = NULL;
447 DUP_STRING(ctx, orig->name, node->name, ret);
448 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
449 DUP_STRING(ctx, orig->ref, node->ref, ret);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200450 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
451 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
452
453 return ret;
454}
455
Radek Krejci9a3823e2021-01-27 20:26:46 +0100456#define DUP_PWHEN(CTX, ORIG, NEW) \
457 if (ORIG) { \
458 NEW = calloc(1, sizeof *NEW); \
459 LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \
460 LY_CHECK_RET(lysp_when_dup(CTX, NEW, ORIG)); \
461 }
462
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200463static LY_ERR
464lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
465{
466 LY_ERR ret = LY_SUCCESS;
467 struct lysp_node_container *cont;
468 const struct lysp_node_container *orig_cont;
469 struct lysp_node_leaf *leaf;
470 const struct lysp_node_leaf *orig_leaf;
471 struct lysp_node_leaflist *llist;
472 const struct lysp_node_leaflist *orig_llist;
473 struct lysp_node_list *list;
474 const struct lysp_node_list *orig_list;
475 struct lysp_node_choice *choice;
476 const struct lysp_node_choice *orig_choice;
477 struct lysp_node_case *cas;
478 const struct lysp_node_case *orig_cas;
479 struct lysp_node_anydata *any;
480 const struct lysp_node_anydata *orig_any;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100481 struct lysp_node_action *action;
482 const struct lysp_node_action *orig_action;
483 struct lysp_node_action_inout *action_inout;
484 const struct lysp_node_action_inout *orig_action_inout;
485 struct lysp_node_notif *notif;
486 const struct lysp_node_notif *orig_notif;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200487
Radek Krejci2a9fc652021-01-22 17:44:34 +0100488 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA |
489 LYS_RPC | LYS_ACTION | LYS_NOTIF));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200490
491 /* common part */
492 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
493
494 /* specific part */
495 switch (node->nodetype) {
496 case LYS_CONTAINER:
497 cont = (struct lysp_node_container *)node;
498 orig_cont = (const struct lysp_node_container *)orig;
499
Radek Krejci9a3823e2021-01-27 20:26:46 +0100500 DUP_PWHEN(ctx, orig_cont->when, cont->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200501 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
502 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
503 /* we do not need the rest */
504 break;
505 case LYS_LEAF:
506 leaf = (struct lysp_node_leaf *)node;
507 orig_leaf = (const struct lysp_node_leaf *)orig;
508
Radek Krejci9a3823e2021-01-27 20:26:46 +0100509 DUP_PWHEN(ctx, orig_leaf->when, leaf->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200510 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
511 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
512 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
513 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
514 break;
515 case LYS_LEAFLIST:
516 llist = (struct lysp_node_leaflist *)node;
517 orig_llist = (const struct lysp_node_leaflist *)orig;
518
Radek Krejci9a3823e2021-01-27 20:26:46 +0100519 DUP_PWHEN(ctx, orig_llist->when, llist->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200520 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
521 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
522 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
523 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
524 llist->min = orig_llist->min;
525 llist->max = orig_llist->max;
526 break;
527 case LYS_LIST:
528 list = (struct lysp_node_list *)node;
529 orig_list = (const struct lysp_node_list *)orig;
530
Radek Krejci9a3823e2021-01-27 20:26:46 +0100531 DUP_PWHEN(ctx, orig_list->when, list->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200532 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
533 DUP_STRING(ctx, orig_list->key, list->key, ret);
534 /* we do not need these arrays */
535 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
536 list->min = orig_list->min;
537 list->max = orig_list->max;
538 break;
539 case LYS_CHOICE:
540 choice = (struct lysp_node_choice *)node;
541 orig_choice = (const struct lysp_node_choice *)orig;
542
Radek Krejci9a3823e2021-01-27 20:26:46 +0100543 DUP_PWHEN(ctx, orig_choice->when, choice->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200544 /* we do not need children */
545 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
546 break;
547 case LYS_CASE:
548 cas = (struct lysp_node_case *)node;
549 orig_cas = (const struct lysp_node_case *)orig;
550
Radek Krejci9a3823e2021-01-27 20:26:46 +0100551 DUP_PWHEN(ctx, orig_cas->when, cas->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200552 /* we do not need children */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200553 break;
554 case LYS_ANYDATA:
555 case LYS_ANYXML:
556 any = (struct lysp_node_anydata *)node;
557 orig_any = (const struct lysp_node_anydata *)orig;
558
Radek Krejci9a3823e2021-01-27 20:26:46 +0100559 DUP_PWHEN(ctx, orig_any->when, any->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200560 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
561 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100562 case LYS_RPC:
563 case LYS_ACTION:
564 action = (struct lysp_node_action *)node;
565 orig_action = (const struct lysp_node_action *)orig;
566
567 action->input.nodetype = orig_action->input.nodetype;
568 action->output.nodetype = orig_action->output.nodetype;
569 /* we do not need the rest */
570 break;
571 case LYS_INPUT:
572 case LYS_OUTPUT:
573 action_inout = (struct lysp_node_action_inout *)node;
574 orig_action_inout = (const struct lysp_node_action_inout *)orig;
575
576 DUP_ARRAY(ctx, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
577 /* we do not need the rest */
578 break;
579 case LYS_NOTIF:
580 notif = (struct lysp_node_notif *)node;
581 orig_notif = (const struct lysp_node_notif *)orig;
582
583 DUP_ARRAY(ctx, orig_notif->musts, notif->musts, lysp_restr_dup);
584 /* we do not need the rest */
585 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200586 default:
587 LOGINT_RET(ctx);
588 }
589
590 return ret;
591}
592
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200593/**
594 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
595 *
596 * @param[in] ctx libyang context.
597 * @param[in] pnode Node to duplicate.
598 * @param[in] with_links Whether to also copy any links (child, parent pointers).
599 * @param[out] dup_p Duplicated parsed node.
600 * @return LY_ERR value.
601 */
602static LY_ERR
603lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
604{
605 LY_ERR ret = LY_SUCCESS;
606 void *mem = NULL;
607
608 if (!pnode) {
609 *dup_p = NULL;
610 return LY_SUCCESS;
611 }
612
613 switch (pnode->nodetype) {
614 case LYS_CONTAINER:
615 mem = calloc(1, sizeof(struct lysp_node_container));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200616 break;
617 case LYS_LEAF:
618 mem = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200619 break;
620 case LYS_LEAFLIST:
621 mem = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200622 break;
623 case LYS_LIST:
624 mem = calloc(1, sizeof(struct lysp_node_list));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200625 break;
626 case LYS_CHOICE:
627 mem = calloc(1, sizeof(struct lysp_node_choice));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200628 break;
629 case LYS_CASE:
630 mem = calloc(1, sizeof(struct lysp_node_case));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200631 break;
632 case LYS_ANYDATA:
633 case LYS_ANYXML:
634 mem = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200635 break;
636 case LYS_INPUT:
637 case LYS_OUTPUT:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100638 mem = calloc(1, sizeof(struct lysp_node_action_inout));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200639 break;
640 case LYS_ACTION:
641 case LYS_RPC:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100642 mem = calloc(1, sizeof(struct lysp_node_action));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200643 break;
644 case LYS_NOTIF:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100645 mem = calloc(1, sizeof(struct lysp_node_notif));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200646 break;
647 default:
648 LOGINT_RET(ctx);
649 }
Radek Krejci2a9fc652021-01-22 17:44:34 +0100650 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
651 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200652
653 if (with_links) {
Michal Vaskoec8f4272021-10-27 09:14:03 +0200654 /* copy also parent, child, action, and notification pointers */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200655 ((struct lysp_node *)mem)->parent = pnode->parent;
656 switch (pnode->nodetype) {
657 case LYS_CONTAINER:
658 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
Michal Vaskoec8f4272021-10-27 09:14:03 +0200659 ((struct lysp_node_container *)mem)->actions = ((struct lysp_node_container *)pnode)->actions;
660 ((struct lysp_node_container *)mem)->notifs = ((struct lysp_node_container *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200661 break;
662 case LYS_LIST:
663 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
Michal Vaskoec8f4272021-10-27 09:14:03 +0200664 ((struct lysp_node_list *)mem)->actions = ((struct lysp_node_list *)pnode)->actions;
665 ((struct lysp_node_list *)mem)->notifs = ((struct lysp_node_list *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200666 break;
667 case LYS_CHOICE:
668 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
669 break;
670 case LYS_CASE:
671 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
672 break;
673 default:
674 break;
675 }
676 }
677
678cleanup:
679 if (ret) {
680 free(mem);
681 } else {
682 *dup_p = mem;
683 }
684 return ret;
685}
686
687#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100688 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 +0200689 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
690 ret = LY_EVALID; \
691 goto cleanup;
692
693#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
694 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100695 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 +0200696 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
697 ret = LY_EVALID; \
698 goto cleanup; \
699 }
700
701/**
702 * @brief Apply refine.
703 *
704 * @param[in] ctx Compile context.
705 * @param[in] rfn Refine to apply.
706 * @param[in,out] target Refine target.
707 * @return LY_ERR value.
708 */
709static LY_ERR
710lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
711{
712 LY_ERR ret = LY_SUCCESS;
713 LY_ARRAY_COUNT_TYPE u;
714 struct lysp_qname *qname;
715 struct lysp_restr **musts, *must;
716 uint32_t *num;
717
718 /* default value */
719 if (rfn->dflts) {
720 switch (target->nodetype) {
721 case LYS_LEAF:
722 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
723
Michal Vaskoe180ed02021-02-05 16:31:20 +0100724 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200725 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &rfn->dflts[0]), cleanup);
726 break;
727 case LYS_LEAFLIST:
728 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100729 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200730 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
731 ret = LY_EVALID;
732 goto cleanup;
733 }
734
735 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
736 ((struct lysp_node_leaflist *)target)->dflts = NULL;
737 LY_ARRAY_FOR(rfn->dflts, u) {
738 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
739 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup);
740 }
741 break;
742 case LYS_CHOICE:
743 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
744
Michal Vaskoe180ed02021-02-05 16:31:20 +0100745 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200746 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &rfn->dflts[0]), cleanup);
747 break;
748 default:
749 AMEND_WRONG_NODETYPE("refine", "replace", "default");
750 }
751 }
752
753 /* description */
754 if (rfn->dsc) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100755 lydict_remove(ctx->ctx, target->dsc);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200756 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
757 }
758
759 /* reference */
760 if (rfn->ref) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100761 lydict_remove(ctx->ctx, target->ref);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200762 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
763 }
764
765 /* config */
766 if (rfn->flags & LYS_CONFIG_MASK) {
Michal Vasko7c565922021-06-10 14:58:27 +0200767 if (ctx->compile_opts & LYS_COMPILE_NO_CONFIG) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200768 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Michal Vasko7c565922021-06-10 14:58:27 +0200769 (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT)) ? "RPC/action" :
770 ctx->compile_opts & LYS_IS_NOTIF ? "notification" : "a subtree ignoring config", ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200771 } else {
772 target->flags &= ~LYS_CONFIG_MASK;
773 target->flags |= rfn->flags & LYS_CONFIG_MASK;
774 }
775 }
776
777 /* mandatory */
778 if (rfn->flags & LYS_MAND_MASK) {
779 switch (target->nodetype) {
780 case LYS_LEAF:
781 case LYS_CHOICE:
782 case LYS_ANYDATA:
783 case LYS_ANYXML:
784 break;
785 default:
786 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
787 }
788
789 target->flags &= ~LYS_MAND_MASK;
790 target->flags |= rfn->flags & LYS_MAND_MASK;
791 }
792
793 /* presence */
794 if (rfn->presence) {
795 switch (target->nodetype) {
796 case LYS_CONTAINER:
797 break;
798 default:
799 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
800 }
801
Michal Vaskoe180ed02021-02-05 16:31:20 +0100802 lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200803 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
804 }
805
806 /* must */
807 if (rfn->musts) {
808 switch (target->nodetype) {
809 case LYS_CONTAINER:
810 case LYS_LIST:
811 case LYS_LEAF:
812 case LYS_LEAFLIST:
813 case LYS_ANYDATA:
814 case LYS_ANYXML:
815 musts = &((struct lysp_node_container *)target)->musts;
816 break;
817 default:
818 AMEND_WRONG_NODETYPE("refine", "add", "must");
819 }
820
821 LY_ARRAY_FOR(rfn->musts, u) {
822 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
823 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
824 }
825 }
826
827 /* min-elements */
828 if (rfn->flags & LYS_SET_MIN) {
829 switch (target->nodetype) {
830 case LYS_LEAFLIST:
831 num = &((struct lysp_node_leaflist *)target)->min;
832 break;
833 case LYS_LIST:
834 num = &((struct lysp_node_list *)target)->min;
835 break;
836 default:
837 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
838 }
839
840 *num = rfn->min;
841 }
842
843 /* max-elements */
844 if (rfn->flags & LYS_SET_MAX) {
845 switch (target->nodetype) {
846 case LYS_LEAFLIST:
847 num = &((struct lysp_node_leaflist *)target)->max;
848 break;
849 case LYS_LIST:
850 num = &((struct lysp_node_list *)target)->max;
851 break;
852 default:
853 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
854 }
855
856 *num = rfn->max;
857 }
858
859 /* if-feature */
860 if (rfn->iffeatures) {
861 switch (target->nodetype) {
862 case LYS_LEAF:
863 case LYS_LEAFLIST:
864 case LYS_LIST:
865 case LYS_CONTAINER:
866 case LYS_CHOICE:
867 case LYS_CASE:
868 case LYS_ANYDATA:
869 case LYS_ANYXML:
870 break;
871 default:
872 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
873 }
874
875 LY_ARRAY_FOR(rfn->iffeatures, u) {
876 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
877 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup);
878 }
879 }
880
881 /* extension */
882 /* TODO refine extensions */
883
884cleanup:
885 return ret;
886}
887
888/**
889 * @brief Apply deviate add.
890 *
891 * @param[in] ctx Compile context.
892 * @param[in] d Deviate add to apply.
893 * @param[in,out] target Deviation target.
894 * @return LY_ERR value.
895 */
896static LY_ERR
897lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
898{
899 LY_ERR ret = LY_SUCCESS;
900 LY_ARRAY_COUNT_TYPE u;
901 struct lysp_qname *qname;
902 uint32_t *num;
903 struct lysp_restr **musts, *must;
904
905#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
906 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100907 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200908 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
909 ret = LY_EVALID; \
910 goto cleanup; \
911 }
912
913 /* [units-stmt] */
914 if (d->units) {
915 switch (target->nodetype) {
916 case LYS_LEAF:
917 case LYS_LEAFLIST:
918 break;
919 default:
920 AMEND_WRONG_NODETYPE("deviation", "add", "units");
921 }
922
923 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
924 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
925 }
926
927 /* *must-stmt */
928 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100929 musts = lysp_node_musts_p(target);
930 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200931 AMEND_WRONG_NODETYPE("deviation", "add", "must");
932 }
933
934 LY_ARRAY_FOR(d->musts, u) {
935 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
936 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
937 }
938 }
939
940 /* *unique-stmt */
941 if (d->uniques) {
942 switch (target->nodetype) {
943 case LYS_LIST:
944 break;
945 default:
946 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
947 }
948
949 LY_ARRAY_FOR(d->uniques, u) {
950 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
951 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup);
952 }
953 }
954
955 /* *default-stmt */
956 if (d->dflts) {
957 switch (target->nodetype) {
958 case LYS_LEAF:
959 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
960 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
961
962 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflts[0]), cleanup);
963 break;
964 case LYS_LEAFLIST:
965 LY_ARRAY_FOR(d->dflts, u) {
966 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
967 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup);
968 }
969 break;
970 case LYS_CHOICE:
971 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
972 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
973
974 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflts[0]), cleanup);
975 break;
976 default:
977 AMEND_WRONG_NODETYPE("deviation", "add", "default");
978 }
979 }
980
981 /* [config-stmt] */
982 if (d->flags & LYS_CONFIG_MASK) {
983 switch (target->nodetype) {
984 case LYS_CONTAINER:
985 case LYS_LEAF:
986 case LYS_LEAFLIST:
987 case LYS_LIST:
988 case LYS_CHOICE:
989 case LYS_ANYDATA:
990 case LYS_ANYXML:
991 break;
992 default:
993 AMEND_WRONG_NODETYPE("deviation", "add", "config");
994 }
995
996 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100997 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200998 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
999 target->flags & LYS_CONFIG_W ? "true" : "false");
1000 ret = LY_EVALID;
1001 goto cleanup;
1002 }
1003
1004 target->flags |= d->flags & LYS_CONFIG_MASK;
1005 }
1006
1007 /* [mandatory-stmt] */
1008 if (d->flags & LYS_MAND_MASK) {
1009 switch (target->nodetype) {
1010 case LYS_LEAF:
1011 case LYS_CHOICE:
1012 case LYS_ANYDATA:
1013 case LYS_ANYXML:
1014 break;
1015 default:
1016 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
1017 }
1018
1019 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001020 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001021 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
1022 target->flags & LYS_MAND_TRUE ? "true" : "false");
1023 ret = LY_EVALID;
1024 goto cleanup;
1025 }
1026
1027 target->flags |= d->flags & LYS_MAND_MASK;
1028 }
1029
1030 /* [min-elements-stmt] */
1031 if (d->flags & LYS_SET_MIN) {
1032 switch (target->nodetype) {
1033 case LYS_LEAFLIST:
1034 num = &((struct lysp_node_leaflist *)target)->min;
1035 break;
1036 case LYS_LIST:
1037 num = &((struct lysp_node_list *)target)->min;
1038 break;
1039 default:
1040 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
1041 }
1042
1043 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001044 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001045 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
1046 ret = LY_EVALID;
1047 goto cleanup;
1048 }
1049
1050 *num = d->min;
1051 }
1052
1053 /* [max-elements-stmt] */
1054 if (d->flags & LYS_SET_MAX) {
1055 switch (target->nodetype) {
1056 case LYS_LEAFLIST:
1057 num = &((struct lysp_node_leaflist *)target)->max;
1058 break;
1059 case LYS_LIST:
1060 num = &((struct lysp_node_list *)target)->max;
1061 break;
1062 default:
1063 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1064 }
1065
1066 if (target->flags & LYS_SET_MAX) {
1067 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001068 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001069 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1070 *num);
1071 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001072 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001073 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1074 }
1075 ret = LY_EVALID;
1076 goto cleanup;
1077 }
1078
1079 *num = d->max;
1080 }
1081
1082cleanup:
1083 return ret;
1084}
1085
1086/**
1087 * @brief Apply deviate delete.
1088 *
1089 * @param[in] ctx Compile context.
1090 * @param[in] d Deviate delete to apply.
1091 * @param[in,out] target Deviation target.
1092 * @return LY_ERR value.
1093 */
1094static LY_ERR
1095lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1096{
1097 LY_ERR ret = LY_SUCCESS;
1098 struct lysp_restr **musts;
1099 LY_ARRAY_COUNT_TYPE u, v;
1100 struct lysp_qname **uniques, **dflts;
1101
1102#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
1103 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1104 int found = 0; \
1105 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1106 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1107 found = 1; \
1108 break; \
1109 } \
1110 } \
1111 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001112 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001113 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1114 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1115 ret = LY_EVALID; \
1116 goto cleanup; \
1117 } \
1118 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
1119 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
Michal Vasko08e9b112021-06-11 15:41:17 +02001120 if (v < LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1121 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1122 } \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001123 } \
1124 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1125 LY_ARRAY_FREE(ORIG_ARRAY); \
1126 ORIG_ARRAY = NULL; \
1127 }
1128
1129#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1130 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001131 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001132 ret = LY_EVALID; \
1133 goto cleanup; \
1134 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001135 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001136 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1137 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1138 ret = LY_EVALID; \
1139 goto cleanup; \
1140 }
1141
1142 /* [units-stmt] */
1143 if (d->units) {
1144 switch (target->nodetype) {
1145 case LYS_LEAF:
1146 case LYS_LEAFLIST:
1147 break;
1148 default:
1149 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1150 }
1151
1152 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001153 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001154 ((struct lysp_node_leaf *)target)->units = NULL;
1155 }
1156
1157 /* *must-stmt */
1158 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001159 musts = lysp_node_musts_p(target);
1160 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001161 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1162 }
1163
1164 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
1165 }
1166
1167 /* *unique-stmt */
1168 if (d->uniques) {
1169 switch (target->nodetype) {
1170 case LYS_LIST:
1171 break;
1172 default:
1173 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1174 }
1175
1176 uniques = &((struct lysp_node_list *)target)->uniques;
1177 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, "unique");
1178 }
1179
1180 /* *default-stmt */
1181 if (d->dflts) {
1182 switch (target->nodetype) {
1183 case LYS_LEAF:
1184 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1185 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1186
Michal Vaskoe180ed02021-02-05 16:31:20 +01001187 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001188 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1189 break;
1190 case LYS_LEAFLIST:
1191 dflts = &((struct lysp_node_leaflist *)target)->dflts;
1192 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, "default");
1193 break;
1194 case LYS_CHOICE:
1195 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1196 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1197
Michal Vaskoe180ed02021-02-05 16:31:20 +01001198 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001199 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1200 break;
1201 default:
1202 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1203 }
1204 }
1205
1206cleanup:
1207 return ret;
1208}
1209
1210/**
1211 * @brief Apply deviate replace.
1212 *
1213 * @param[in] ctx Compile context.
1214 * @param[in] d Deviate replace to apply.
1215 * @param[in,out] target Deviation target.
1216 * @return LY_ERR value.
1217 */
1218static LY_ERR
1219lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1220{
1221 LY_ERR ret = LY_SUCCESS;
1222 uint32_t *num;
1223
1224#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1225 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001226 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001227 ret = LY_EVALID; \
1228 goto cleanup; \
1229 }
1230
1231 /* [type-stmt] */
1232 if (d->type) {
1233 switch (target->nodetype) {
1234 case LYS_LEAF:
1235 case LYS_LEAFLIST:
1236 break;
1237 default:
1238 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1239 }
1240
1241 lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
1242 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
1243 }
1244
1245 /* [units-stmt] */
1246 if (d->units) {
1247 switch (target->nodetype) {
1248 case LYS_LEAF:
1249 case LYS_LEAFLIST:
1250 break;
1251 default:
1252 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1253 }
1254
1255 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001256 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001257 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1258 }
1259
1260 /* [default-stmt] */
1261 if (d->dflt.str) {
1262 switch (target->nodetype) {
1263 case LYS_LEAF:
1264 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1265
Michal Vaskoe180ed02021-02-05 16:31:20 +01001266 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001267 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflt), cleanup);
1268 break;
1269 case LYS_CHOICE:
1270 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
1271
Michal Vaskoe180ed02021-02-05 16:31:20 +01001272 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001273 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflt), cleanup);
1274 break;
1275 default:
1276 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1277 }
1278 }
1279
1280 /* [config-stmt] */
1281 if (d->flags & LYS_CONFIG_MASK) {
1282 switch (target->nodetype) {
1283 case LYS_CONTAINER:
1284 case LYS_LEAF:
1285 case LYS_LEAFLIST:
1286 case LYS_LIST:
1287 case LYS_CHOICE:
1288 case LYS_ANYDATA:
1289 case LYS_ANYXML:
1290 break;
1291 default:
1292 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1293 }
1294
1295 if (!(target->flags & LYS_CONFIG_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001296 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "config",
1297 d->flags & LYS_CONFIG_W ? "config true" : "config false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001298 ret = LY_EVALID;
1299 goto cleanup;
1300 }
1301
1302 target->flags &= ~LYS_CONFIG_MASK;
1303 target->flags |= d->flags & LYS_CONFIG_MASK;
1304 }
1305
1306 /* [mandatory-stmt] */
1307 if (d->flags & LYS_MAND_MASK) {
1308 switch (target->nodetype) {
1309 case LYS_LEAF:
1310 case LYS_CHOICE:
1311 case LYS_ANYDATA:
1312 case LYS_ANYXML:
1313 break;
1314 default:
1315 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1316 }
1317
1318 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001319 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1320 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001321 ret = LY_EVALID;
1322 goto cleanup;
1323 }
1324
1325 target->flags &= ~LYS_MAND_MASK;
1326 target->flags |= d->flags & LYS_MAND_MASK;
1327 }
1328
1329 /* [min-elements-stmt] */
1330 if (d->flags & LYS_SET_MIN) {
1331 switch (target->nodetype) {
1332 case LYS_LEAFLIST:
1333 num = &((struct lysp_node_leaflist *)target)->min;
1334 break;
1335 case LYS_LIST:
1336 num = &((struct lysp_node_list *)target)->min;
1337 break;
1338 default:
1339 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1340 }
1341
1342 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001343 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001344 ret = LY_EVALID;
1345 goto cleanup;
1346 }
1347
1348 *num = d->min;
1349 }
1350
1351 /* [max-elements-stmt] */
1352 if (d->flags & LYS_SET_MAX) {
1353 switch (target->nodetype) {
1354 case LYS_LEAFLIST:
1355 num = &((struct lysp_node_leaflist *)target)->max;
1356 break;
1357 case LYS_LIST:
1358 num = &((struct lysp_node_list *)target)->max;
1359 break;
1360 default:
1361 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1362 }
1363
1364 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001365 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001366 ret = LY_EVALID;
1367 goto cleanup;
1368 }
1369
1370 *num = d->max;
1371 }
1372
1373cleanup:
1374 return ret;
1375}
1376
1377/**
1378 * @brief Get module of a single nodeid node name test.
1379 *
1380 * @param[in] ctx libyang context.
1381 * @param[in] nametest Nametest with an optional prefix.
1382 * @param[in] nametest_len Length of @p nametest.
1383 * @param[in] mod Both current and prefix module for resolving prefixes and to return in case of no prefix.
1384 * @param[out] name Optional pointer to the name test without the prefix.
1385 * @param[out] name_len Length of @p name.
1386 * @return Resolved module.
1387 */
1388static const struct lys_module *
1389lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
1390 const struct lysp_module *mod, const char **name, size_t *name_len)
1391{
1392 const struct lys_module *target_mod;
1393 const char *ptr;
1394
1395 ptr = ly_strnchr(nametest, ':', nametest_len);
1396 if (ptr) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001397 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_VALUE_SCHEMA, (void *)mod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001398 if (!target_mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001399 LOGVAL(ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001400 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001401 (int)nametest_len, nametest, (int)(ptr - nametest), nametest, LYSP_MODULE_NAME(mod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001402 return NULL;
1403 }
1404
1405 if (name) {
1406 *name = ptr + 1;
1407 *name_len = nametest_len - ((ptr - nametest) + 1);
1408 }
1409 } else {
1410 target_mod = mod->mod;
1411 if (name) {
1412 *name = nametest;
1413 *name_len = nametest_len;
1414 }
1415 }
1416
1417 return target_mod;
1418}
1419
1420/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001421 * @brief Check whether a compiled node matches a single schema nodeid name test.
1422 *
1423 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1424 * @param[in] mod Expected module.
1425 * @param[in] name Expected name.
1426 * @param[in] name_len Length of @p name.
1427 * @return Whether it is a match or not.
1428 */
1429static ly_bool
1430lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1431 size_t name_len)
1432{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001433 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001434 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001435 return 0;
1436 }
1437
1438 /* compare names */
Michal Vasko544e58a2021-01-28 14:33:41 +01001439 if (ly_strncmp((*node)->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001440 return 0;
1441 }
1442
Michal Vasko2a668712020-10-21 11:48:09 +02001443 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001444 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001445
1446 return 1;
1447}
1448
1449/**
1450 * @brief Check whether a node matches specific schema nodeid.
1451 *
1452 * @param[in] exp Parsed nodeid to match.
1453 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
1454 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1455 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1456 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1457 * @param[in] pnode_mod Compiled @p pnode to-be module.
1458 * @return Whether it is a match or not.
1459 */
1460static ly_bool
1461lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node,
1462 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
1463{
1464 uint32_t i;
1465 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001466 const char *name = NULL;
1467 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001468
1469 /* compare last node in the node ID */
1470 i = exp->used - 1;
1471
1472 /* get exp node ID module */
1473 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);
1474 assert(mod);
1475
1476 if (pnode) {
1477 /* compare on the last parsed-only node */
Radek Krejci2d5f6df2021-01-28 14:00:13 +01001478 if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001479 return 0;
1480 }
1481 } else {
1482 /* using parent directly */
1483 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1484 return 0;
1485 }
1486 }
1487
1488 /* now compare all the compiled parents */
1489 while (i > 1) {
1490 i -= 2;
1491 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1492
1493 if (!parent) {
1494 /* no more parents but path continues */
1495 return 0;
1496 }
1497
1498 /* get exp node ID module */
1499 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1500 &name_len);
1501 assert(mod);
1502
1503 /* compare with the parent */
1504 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1505 return 0;
1506 }
1507 }
1508
1509 if (ctx_node && (ctx_node != parent)) {
1510 /* descendant path has not finished in the context node */
1511 return 0;
1512 } else if (!ctx_node && parent) {
1513 /* some parent was not matched */
1514 return 0;
1515 }
1516
1517 return 1;
1518}
1519
1520void
1521lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1522{
1523 if (aug) {
1524 lyxp_expr_free(ctx, aug->nodeid);
1525
1526 free(aug);
1527 }
1528}
1529
1530void
1531lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1532{
1533 if (dev) {
1534 lyxp_expr_free(ctx, dev->nodeid);
1535 LY_ARRAY_FREE(dev->devs);
1536 LY_ARRAY_FREE(dev->dev_pmods);
1537
1538 free(dev);
1539 }
1540}
1541
1542void
1543lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1544{
1545 if (rfn) {
1546 lyxp_expr_free(ctx, rfn->nodeid);
1547 LY_ARRAY_FREE(rfn->rfns);
1548
1549 free(rfn);
1550 }
1551}
1552
1553void
1554lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
1555{
1556 if (!dev_pnode) {
1557 return;
1558 }
1559
1560 switch (dev_pnode->nodetype) {
1561 case LYS_CONTAINER:
1562 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001563 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1564 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001565 break;
1566 case LYS_LIST:
1567 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001568 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1569 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001570 break;
1571 case LYS_CHOICE:
1572 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1573 break;
1574 case LYS_CASE:
1575 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1576 break;
1577 case LYS_LEAF:
1578 case LYS_LEAFLIST:
1579 case LYS_ANYXML:
1580 case LYS_ANYDATA:
1581 /* no children */
1582 break;
1583 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001584 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001585 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001586 case LYS_RPC:
1587 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001588 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1589 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001590 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001591 case LYS_INPUT:
1592 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001593 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001594 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001595 free(dev_pnode);
1596 return;
1597 default:
1598 LOGINT(ctx);
1599 return;
1600 }
1601
1602 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
1603}
1604
1605LY_ERR
1606lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1607 struct lysp_node **dev_pnode, ly_bool *not_supported)
1608{
1609 LY_ERR ret = LY_SUCCESS;
1610 uint32_t i;
1611 LY_ARRAY_COUNT_TYPE u;
1612 struct lys_module *orig_mod = ctx->cur_mod;
1613 struct lysp_module *orig_pmod = ctx->pmod;
1614 char orig_path[LYSC_CTX_BUFSIZE];
1615 struct lysc_refine *rfn;
1616 struct lysc_deviation *dev;
1617 struct lysp_deviation *dev_p;
1618 struct lysp_deviate *d;
1619
1620 *dev_pnode = NULL;
1621 *not_supported = 0;
1622
1623 for (i = 0; i < ctx->uses_rfns.count; ++i) {
1624 rfn = ctx->uses_rfns.objs[i];
1625
Michal Vasko28fe5f62021-03-03 16:37:39 +01001626 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 +02001627 /* not our target node */
1628 continue;
1629 }
1630
1631 if (!*dev_pnode) {
1632 /* first refine on this node, create a copy first */
1633 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1634 }
1635
Michal Vaskob8df5762021-01-12 15:15:53 +01001636 /* use modules from the refine */
1637 ctx->cur_mod = rfn->nodeid_pmod->mod;
1638 ctx->pmod = (struct lysp_module *)rfn->nodeid_pmod;
1639
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001640 /* apply all the refines by changing (the copy of) the parsed node */
1641 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vaskob8df5762021-01-12 15:15:53 +01001642 /* keep the current path and add to it */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001643 lysc_update_path(ctx, NULL, "{refine}");
1644 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001645
1646 /* apply refine and restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001647 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
1648 lysc_update_path(ctx, NULL, NULL);
1649 lysc_update_path(ctx, NULL, NULL);
1650 LY_CHECK_GOTO(ret, cleanup);
1651 }
1652
1653 /* refine was applied, remove it */
1654 lysc_refine_free(ctx->ctx, rfn);
1655 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1656
1657 /* all the refines for one target node are in one structure, we are done */
1658 break;
1659 }
1660
1661 for (i = 0; i < ctx->devs.count; ++i) {
1662 dev = ctx->devs.objs[i];
1663
Michal Vasko28fe5f62021-03-03 16:37:39 +01001664 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, orig_mod)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001665 /* not our target node */
1666 continue;
1667 }
1668
1669 if (dev->not_supported) {
1670 /* it is not supported, no more deviations */
1671 *not_supported = 1;
1672 goto dev_applied;
1673 }
1674
1675 if (!*dev_pnode) {
1676 /* first deviation on this node, create a copy first */
1677 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1678 }
1679
1680 /* apply all the deviates by changing (the copy of) the parsed node */
1681 LY_ARRAY_FOR(dev->devs, u) {
1682 dev_p = dev->devs[u];
1683 LY_LIST_FOR(dev_p->deviates, d) {
1684 /* generate correct path */
1685 strcpy(orig_path, ctx->path);
1686 ctx->path_len = 1;
1687 ctx->cur_mod = dev->dev_pmods[u]->mod;
1688 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
1689 lysc_update_path(ctx, NULL, "{deviation}");
1690 lysc_update_path(ctx, NULL, dev_p->nodeid);
1691
1692 switch (d->mod) {
1693 case LYS_DEV_ADD:
1694 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
1695 break;
1696 case LYS_DEV_DELETE:
1697 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
1698 break;
1699 case LYS_DEV_REPLACE:
1700 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
1701 break;
1702 default:
1703 LOGINT(ctx->ctx);
1704 ret = LY_EINT;
1705 }
1706
1707 /* restore previous path */
1708 strcpy(ctx->path, orig_path);
1709 ctx->path_len = strlen(ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001710
1711 LY_CHECK_GOTO(ret, cleanup);
1712 }
1713 }
1714
1715dev_applied:
1716 /* deviation was applied, remove it */
1717 lysc_deviation_free(ctx->ctx, dev);
1718 ly_set_rm_index(&ctx->devs, i, NULL);
1719
1720 /* all the deviations for one target node are in one structure, we are done */
1721 break;
1722 }
1723
1724cleanup:
Michal Vasko20316b32021-01-12 15:16:54 +01001725 ctx->cur_mod = orig_mod;
1726 ctx->pmod = orig_pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001727 if (ret) {
1728 lysp_dev_node_free(ctx->ctx, *dev_pnode);
1729 *dev_pnode = NULL;
1730 *not_supported = 0;
1731 }
1732 return ret;
1733}
1734
Michal Vaskoad0980a2022-05-09 11:43:47 +02001735/**
1736 * @brief Compile augment children.
1737 *
1738 * @param[in] ctx Compile context.
1739 * @param[in] aug_p Parsed augment to compile.
1740 * @param[in] child First augment child to compile.
1741 * @param[in] target Target node of the augment.
Michal Vaskoa084fa32022-05-16 11:32:58 +02001742 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
Michal Vaskoad0980a2022-05-09 11:43:47 +02001743 * @return LY_SUCCESS on success.
1744 * @return LY_EVALID on failure.
1745 */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001746static LY_ERR
1747lys_compile_augment_children(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysp_node *child,
Michal Vaskoa084fa32022-05-16 11:32:58 +02001748 struct lysc_node *target, ly_bool child_unres_disabled)
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001749{
1750 LY_ERR rc = LY_SUCCESS;
1751 struct lysp_node *pnode;
1752 struct lysc_node *node;
1753 struct lysc_when *when_shared = NULL;
1754 ly_bool enabled, allow_mand = 0;
1755 struct ly_set child_set = {0};
1756 uint32_t i, opt_prev = ctx->compile_opts;
1757
1758 /* check for mandatory nodes
1759 * - new cases augmenting some choice can have mandatory nodes
1760 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1761 */
1762 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
1763 allow_mand = 1;
1764 }
1765
1766 LY_LIST_FOR(child, pnode) {
1767 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1768 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1769 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1770 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1771 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1772 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1773 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1774 rc = LY_EVALID;
1775 goto cleanup;
1776 }
1777
1778 /* compile the children */
1779 if (target->nodetype == LYS_CHOICE) {
1780 LY_CHECK_GOTO(rc = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1781 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1782 if (target->nodetype == LYS_INPUT) {
1783 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
1784 } else {
1785 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
1786 }
1787 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1788 } else {
1789 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1790 }
1791
1792 /* eval if-features again for the rest of this node processing */
1793 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1794 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001795 ctx->compile_opts |= LYS_COMPILE_DISABLED;
1796 }
1797
1798 /* since the augment node is not present in the compiled tree, we need to pass some of its
1799 * statements to all its children */
1800 for (i = 0; i < child_set.count; ++i) {
1801 node = child_set.snodes[i];
1802 if (!allow_mand && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1803 node->flags &= ~LYS_MAND_TRUE;
1804 lys_compile_mandatory_parents(target, 0);
1805 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
1806 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
1807 node->name);
1808 rc = LY_EVALID;
1809 goto cleanup;
1810 }
1811
1812 if (aug_p->when) {
1813 /* pass augment's when to all the children */
1814 rc = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, lysc_data_node(target), node, &when_shared);
1815 LY_CHECK_GOTO(rc, cleanup);
1816 }
1817
Michal Vaskoa084fa32022-05-16 11:32:58 +02001818 if (child_unres_disabled) {
Michal Vaskoad0980a2022-05-09 11:43:47 +02001819 /* child is disabled by the augment if-features */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001820 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
1821 }
1822 }
1823
1824 /* next iter */
1825 ly_set_erase(&child_set, NULL);
1826 ctx->compile_opts = opt_prev;
1827 }
1828
1829cleanup:
1830 ly_set_erase(&child_set, NULL);
1831 ctx->compile_opts = opt_prev;
1832 return rc;
1833}
1834
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001835/**
1836 * @brief Compile the parsed augment connecting it into its target.
1837 *
1838 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1839 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1840 * are already implemented and compiled.
1841 *
1842 * @param[in] ctx Compile context.
1843 * @param[in] aug_p Parsed augment to compile.
1844 * @param[in] target Target node of the augment.
1845 * @return LY_SUCCESS on success.
1846 * @return LY_EVALID on failure.
1847 */
1848static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001849lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001850{
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001851 LY_ERR rc = LY_SUCCESS;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001852 ly_bool enabled, child_unres_disabled = 0;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001853 uint32_t opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001854
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001855 /* nodetype checks */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001856 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001857 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001858 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
1859 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001860 rc = LY_EVALID;
1861 goto cleanup;
1862 }
1863 if (aug_p->actions && !lysc_node_actions_p(target)) {
1864 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1865 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
1866 lys_nodetype2str(target->nodetype), aug_p->actions->name);
1867 rc = LY_EVALID;
1868 goto cleanup;
1869 }
1870 if (aug_p->notifs && !lysc_node_notifs_p(target)) {
1871 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1872 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
1873 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
1874 rc = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001875 goto cleanup;
1876 }
1877
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001878 /* augment if-features */
1879 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, aug_p->iffeatures, &enabled), cleanup);
1880 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001881 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vaskoa084fa32022-05-16 11:32:58 +02001882 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001883 }
1884
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001885 /* augment children */
Michal Vaskoa084fa32022-05-16 11:32:58 +02001886 LY_CHECK_GOTO(rc = lys_compile_augment_children(ctx, aug_p, aug_p->child, target, child_unres_disabled), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001887
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001888 /* augment actions */
Michal Vaskoa084fa32022-05-16 11:32:58 +02001889 rc = lys_compile_augment_children(ctx, aug_p, (struct lysp_node *)aug_p->actions, target, child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001890 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001891
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001892 /* augment notifications */
Michal Vaskoa084fa32022-05-16 11:32:58 +02001893 rc = lys_compile_augment_children(ctx, aug_p, (struct lysp_node *)aug_p->notifs, target, child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001894 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001895
1896cleanup:
Michal Vasko7c565922021-06-10 14:58:27 +02001897 ctx->compile_opts = opt_prev;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001898 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001899}
1900
1901LY_ERR
1902lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
1903{
1904 LY_ERR ret = LY_SUCCESS;
1905 struct lys_module *orig_mod = ctx->cur_mod;
1906 struct lysp_module *orig_pmod = ctx->pmod;
1907 uint32_t i;
1908 char orig_path[LYSC_CTX_BUFSIZE];
1909 struct lysc_augment *aug;
1910
1911 /* uses augments */
1912 for (i = 0; i < ctx->uses_augs.count; ) {
1913 aug = ctx->uses_augs.objs[i];
1914
Michal Vasko28fe5f62021-03-03 16:37:39 +01001915 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->nodeid_ctx_node, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001916 /* not our target node */
1917 ++i;
1918 continue;
1919 }
1920
Michal Vaskob8df5762021-01-12 15:15:53 +01001921 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001922 lysc_update_path(ctx, NULL, "{augment}");
1923 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01001924 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01001925
1926 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001927 ret = lys_compile_augment(ctx, aug->aug_p, node);
1928 lysc_update_path(ctx, NULL, NULL);
1929 lysc_update_path(ctx, NULL, NULL);
1930 LY_CHECK_GOTO(ret, cleanup);
1931
Michal Vaskoc75f2042021-06-08 14:57:03 +02001932 /* augment was applied, remove it (index and the whole set may have changed because other augments
1933 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001934 ly_set_rm(&ctx->uses_augs, aug, NULL);
1935 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02001936 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001937 }
1938
1939 /* top-level augments */
1940 for (i = 0; i < ctx->augs.count; ) {
1941 aug = ctx->augs.objs[i];
1942
Michal Vasko28fe5f62021-03-03 16:37:39 +01001943 if (!lysp_schema_nodeid_match(aug->nodeid, aug->aug_pmod, NULL, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001944 /* not our target node */
1945 ++i;
1946 continue;
1947 }
1948
Michal Vaskob8df5762021-01-12 15:15:53 +01001949 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001950 strcpy(orig_path, ctx->path);
1951 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01001952 ctx->cur_mod = aug->aug_pmod->mod;
1953 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02001954 lysc_update_path(ctx, NULL, "{augment}");
1955 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001956
1957 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001958 ret = lys_compile_augment(ctx, aug->aug_p, node);
1959 strcpy(ctx->path, orig_path);
1960 ctx->path_len = strlen(ctx->path);
1961 LY_CHECK_GOTO(ret, cleanup);
1962
1963 /* augment was applied, remove it */
1964 ly_set_rm(&ctx->augs, aug, NULL);
1965 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02001966 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001967 }
1968
1969cleanup:
1970 ctx->cur_mod = orig_mod;
1971 ctx->pmod = orig_pmod;
1972 return ret;
1973}
1974
1975/**
1976 * @brief Prepare a top-level augment to be applied during data nodes compilation.
1977 *
1978 * @param[in] ctx Compile context.
1979 * @param[in] aug_p Parsed augment to be applied.
1980 * @param[in] pmod Both current and prefix module for @p aug_p.
1981 * @return LY_ERR value.
1982 */
1983static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001984lys_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 +02001985{
1986 LY_ERR ret = LY_SUCCESS;
1987 struct lyxp_expr *exp = NULL;
1988 struct lysc_augment *aug;
1989 const struct lys_module *mod;
1990
1991 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
1992 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
1993 LY_CHECK_GOTO(ret, cleanup);
1994
1995 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
1996 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
1997 if (mod != ctx->cur_mod) {
1998 /* augment for another module, ignore */
1999 goto cleanup;
2000 }
2001
2002 /* allocate new compiled augment and store it in the set */
2003 aug = calloc(1, sizeof *aug);
2004 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2005 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2006
2007 aug->nodeid = exp;
2008 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002009 aug->aug_pmod = pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002010 aug->aug_p = aug_p;
2011
2012cleanup:
2013 lyxp_expr_free(ctx->ctx, exp);
2014 return ret;
2015}
2016
2017LY_ERR
2018lys_precompile_own_augments(struct lysc_ctx *ctx)
2019{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002020 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002021
2022 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002023 const struct lys_module *aug_mod = ctx->cur_mod->augmented_by[u];
2024 struct lysp_node_augment *aug;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002025
2026 /* collect all module augments */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002027 LY_LIST_FOR(aug_mod->parsed->augments, aug) {
2028 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002029 }
2030
2031 /* collect all submodules augments */
2032 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002033 LY_LIST_FOR(aug_mod->parsed->includes[v].submodule->augments, aug) {
2034 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 +02002035 }
2036 }
2037 }
2038
2039 return LY_SUCCESS;
2040}
2041
2042/**
2043 * @brief Prepare a deviation to be applied during data nodes compilation.
2044 *
2045 * @param[in] ctx Compile context.
2046 * @param[in] dev_p Parsed deviation to be applied.
2047 * @param[in] pmod Both current and prefix module for @p dev_p.
2048 * @return LY_ERR value.
2049 */
2050static LY_ERR
2051lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2052{
2053 LY_ERR ret = LY_SUCCESS;
2054 struct lysc_deviation *dev = NULL;
2055 struct lyxp_expr *exp = NULL;
2056 struct lysp_deviation **new_dev;
2057 const struct lys_module *mod;
2058 const struct lysp_module **new_dev_pmod;
2059 uint32_t i;
2060
2061 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2062 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2063 LY_CHECK_GOTO(ret, cleanup);
2064
2065 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2066 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2067 if (mod != ctx->cur_mod) {
2068 /* deviation for another module, ignore */
2069 goto cleanup;
2070 }
2071
2072 /* try to find the node in already compiled deviations */
2073 for (i = 0; i < ctx->devs.count; ++i) {
2074 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2075 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2076 dev = ctx->devs.objs[i];
2077 break;
2078 }
2079 }
2080
2081 if (!dev) {
2082 /* allocate new compiled deviation */
2083 dev = calloc(1, sizeof *dev);
2084 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2085 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2086
2087 dev->nodeid = exp;
2088 exp = NULL;
2089 }
2090
2091 /* add new parsed deviation structure */
2092 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2093 *new_dev = dev_p;
2094 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2095 *new_dev_pmod = pmod;
2096
2097cleanup:
2098 lyxp_expr_free(ctx->ctx, exp);
2099 return ret;
2100}
2101
2102LY_ERR
2103lys_precompile_own_deviations(struct lysc_ctx *ctx)
2104{
2105 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002106 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002107 const struct lys_module *dev_mod;
2108 struct lysc_deviation *dev;
2109 struct lysp_deviate *d;
2110 int not_supported;
2111 uint32_t i;
2112
2113 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2114 dev_mod = ctx->cur_mod->deviated_by[u];
2115
2116 /* compile all module deviations */
2117 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2118 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2119 }
2120
2121 /* compile all submodules deviations */
2122 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2123 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2124 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2125 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2126 }
2127 }
2128 }
2129
2130 /* set not-supported flags for all the deviations */
2131 for (i = 0; i < ctx->devs.count; ++i) {
2132 dev = ctx->devs.objs[i];
2133 not_supported = 0;
2134
2135 LY_ARRAY_FOR(dev->devs, u) {
2136 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2137 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2138 not_supported = 1;
2139 break;
2140 }
2141 }
2142 if (not_supported) {
2143 break;
2144 }
2145 }
2146 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002147 orig_cur_mod = ctx->cur_mod;
2148 ctx->cur_mod = dev->dev_pmods[u]->mod;
2149 lysc_update_path(ctx, NULL, "{deviation}");
2150 lysc_update_path(ctx, NULL, dev->nodeid->expr);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002151 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002152 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002153 lysc_update_path(ctx, NULL, NULL);
2154 lysc_update_path(ctx, NULL, NULL);
2155 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002156 return LY_EVALID;
2157 }
2158
2159 dev->not_supported = not_supported;
2160 }
2161
2162 return LY_SUCCESS;
2163}
2164
2165/**
2166 * @brief Add a module reference into an array, checks for duplicities.
2167 *
2168 * @param[in] ctx Compile context.
2169 * @param[in] mod Module reference to add.
2170 * @param[in,out] mod_array Module sized array to add to.
2171 * @return LY_ERR value.
2172 */
2173static LY_ERR
2174lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2175{
2176 LY_ARRAY_COUNT_TYPE u;
2177 struct lys_module **new_mod;
2178
2179 LY_ARRAY_FOR(*mod_array, u) {
2180 if ((*mod_array)[u] == mod) {
2181 /* already there */
2182 return LY_EEXIST;
2183 }
2184 }
2185
2186 /* add the new module ref */
2187 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2188 *new_mod = mod;
2189
2190 return LY_SUCCESS;
2191}
2192
Michal Vasko1ccbf542021-04-19 11:35:00 +02002193/**
2194 * @brief Check whether all modules in a set are implemented.
2195 *
2196 * @param[in] mod_set Module set to check.
2197 * @return Whether all modules are implemented or not.
2198 */
2199static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002200lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002201{
2202 uint32_t i;
2203 const struct lys_module *mod;
2204
2205 for (i = 0; i < mod_set->count; ++i) {
2206 mod = mod_set->objs[i];
2207 if (!mod->implemented) {
2208 return 0;
2209 }
2210 }
2211
2212 return 1;
2213}
2214
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002215LY_ERR
Michal Vasko65333882021-06-10 14:12:16 +02002216lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002217{
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002218 LY_ERR ret = LY_SUCCESS, r;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002219 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko65333882021-06-10 14:12:16 +02002220 struct lysc_ctx ctx = {0};
2221 struct lysp_module *mod_p;
2222 struct lys_module *m;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002223 struct lysp_submodule *submod;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002224 struct lysp_node_augment *aug;
Michal Vaskoc56d6372021-10-19 12:29:00 +02002225 const char **imp_f, *all_f[] = {"*", NULL};
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002226 uint32_t i;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002227 struct ly_set mod_set = {0}, set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002228
Michal Vasko65333882021-06-10 14:12:16 +02002229 mod_p = mod->parsed;
2230
2231 /* prepare context */
2232 ctx.ctx = mod->ctx;
2233 ctx.cur_mod = mod;
2234 ctx.pmod = mod_p;
2235 ctx.path_len = 1;
2236 ctx.path[0] = '/';
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002237
Radek Krejci2a9fc652021-01-22 17:44:34 +01002238 LY_LIST_FOR(mod_p->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002239 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002240 lysc_update_path(&ctx, NULL, "{augment}");
2241 lysc_update_path(&ctx, NULL, aug->nodeid);
2242 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2243 lysc_update_path(&ctx, NULL, NULL);
2244 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002245 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002246
Michal Vasko1ccbf542021-04-19 11:35:00 +02002247 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vasko65333882021-06-10 14:12:16 +02002248 if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002249 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002250 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002251 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002252 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002253 }
2254
2255 LY_ARRAY_FOR(mod_p->deviations, u) {
2256 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002257 lysc_update_path(&ctx, NULL, "{deviation}");
2258 lysc_update_path(&ctx, NULL, mod_p->deviations[u].nodeid);
2259 ret = lys_nodeid_mod_check(&ctx, mod_p->deviations[u].nodeid, 1, &set, NULL, &m);
2260 lysc_update_path(&ctx, NULL, NULL);
2261 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002262 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002263
Michal Vasko1ccbf542021-04-19 11:35:00 +02002264 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vasko65333882021-06-10 14:12:16 +02002265 if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002266 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002267 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
2268 }
2269 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002270 }
2271
2272 /* the same for augments and deviations in submodules */
2273 LY_ARRAY_FOR(mod_p->includes, v) {
2274 submod = mod_p->includes[v].submodule;
Michal Vasko65333882021-06-10 14:12:16 +02002275 ctx.pmod = (struct lysp_module *)submod;
Michal Vaskoce3d6172021-06-08 14:59:49 +02002276
Radek Krejci2a9fc652021-01-22 17:44:34 +01002277 LY_LIST_FOR(submod->augments, aug) {
Michal Vasko65333882021-06-10 14:12:16 +02002278 lysc_update_path(&ctx, NULL, "{augment}");
2279 lysc_update_path(&ctx, NULL, aug->nodeid);
2280 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2281 lysc_update_path(&ctx, NULL, NULL);
2282 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002283 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002284
Michal Vasko65333882021-06-10 14:12:16 +02002285 if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002286 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002287 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002288 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002289 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002290 }
2291
2292 LY_ARRAY_FOR(submod->deviations, u) {
Michal Vasko65333882021-06-10 14:12:16 +02002293 lysc_update_path(&ctx, NULL, "{deviation}");
2294 lysc_update_path(&ctx, NULL, submod->deviations[u].nodeid);
2295 ret = lys_nodeid_mod_check(&ctx, submod->deviations[u].nodeid, 1, &set, NULL, &m);
2296 lysc_update_path(&ctx, NULL, NULL);
2297 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002298 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002299
Michal Vasko65333882021-06-10 14:12:16 +02002300 if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002301 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002302 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
2303 }
2304 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002305 }
2306 }
2307
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002308 for (i = 0; i < mod_set.count; ++i) {
2309 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002310
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002311 if (m == mod) {
2312 /* will be applied normally later */
2313 continue;
2314 }
2315
2316 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2317 * not compiled yet and marked for compilation */
2318
2319 if (!m->implemented) {
2320 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002321 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2322 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002323 if (r == LY_ERECOMPILE) {
2324 /* implement all the modules right away to save possible later recompilation */
2325 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002326 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002327 } else if (r) {
2328 /* error */
2329 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002330 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002331 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002332 } else if (m->compiled) {
2333 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2334 m->to_compile = 1;
2335 ret = LY_ERECOMPILE;
2336 continue;
2337 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002338 }
2339
Michal Vasko1ccbf542021-04-19 11:35:00 +02002340cleanup:
2341 ly_set_erase(&set, NULL);
2342 ly_set_erase(&mod_set, NULL);
2343 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002344}
2345
2346void
2347lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2348{
2349 uint32_t i;
2350 LY_ARRAY_COUNT_TYPE u, count;
2351 struct lys_module *m;
2352
2353 for (i = 0; i < ctx->list.count; ++i) {
2354 m = ctx->list.objs[i];
2355
2356 if (m->augmented_by) {
2357 count = LY_ARRAY_COUNT(m->augmented_by);
2358 for (u = 0; u < count; ++u) {
2359 if (m->augmented_by[u] == mod) {
2360 /* keep the order */
2361 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002362 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002363 }
2364 LY_ARRAY_DECREMENT(m->augmented_by);
2365 break;
2366 }
2367 }
2368 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2369 LY_ARRAY_FREE(m->augmented_by);
2370 m->augmented_by = NULL;
2371 }
2372 }
2373
2374 if (m->deviated_by) {
2375 count = LY_ARRAY_COUNT(m->deviated_by);
2376 for (u = 0; u < count; ++u) {
2377 if (m->deviated_by[u] == mod) {
2378 /* keep the order */
2379 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002380 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002381 }
2382 LY_ARRAY_DECREMENT(m->deviated_by);
2383 break;
2384 }
2385 }
2386 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2387 LY_ARRAY_FREE(m->deviated_by);
2388 m->deviated_by = NULL;
2389 }
2390 }
2391 }
2392}