blob: 199dc96453ea3fd8c6c12e000792fe903ba0f9d9 [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 Vasko1a7a7bd2020-10-16 14:39:15 +0200308 *ext = *orig_ext;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100309 DUP_STRING_RET(ctx, orig_ext->name, ext->name);
310 DUP_STRING_RET(ctx, orig_ext->argument, ext->argument);
311 ext->parsed = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200312
Michal Vasko899c7ce2022-02-18 09:18:37 +0100313 ext->child = NULL;
314 LY_CHECK_RET(lysp_ext_children_dup(ctx, &ext->child, orig_ext->child));
315
316 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200317}
318
319static LY_ERR
320lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
321{
322 LY_ERR ret = LY_SUCCESS;
323
324 if (orig_restr) {
325 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
326 restr->arg.mod = orig_restr->arg.mod;
327 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
328 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
329 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
330 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
331 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
332 }
333
334 return ret;
335}
336
337static LY_ERR
338lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
339{
340 LY_ERR ret = LY_SUCCESS;
341
342 DUP_STRING(ctx, *orig_str, *str, ret);
343
344 return ret;
345}
346
347LY_ERR
348lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
349{
350 LY_ERR ret = LY_SUCCESS;
351
352 if (!orig_qname->str) {
353 return LY_SUCCESS;
354 }
355
356 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
357 assert(orig_qname->mod);
358 qname->mod = orig_qname->mod;
359
360 return ret;
361}
362
363static LY_ERR
364lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
365{
366 LY_ERR ret = LY_SUCCESS;
367
368 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
369 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
370 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
371 enm->value = orig_enm->value;
372 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
373 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
374 enm->flags = orig_enm->flags;
375
376 return ret;
377}
378
379static LY_ERR
380lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
381{
382 LY_ERR ret = LY_SUCCESS;
383
Michal Vaskoea868242021-06-21 09:28:32 +0200384 /* array macros read previous data so we must zero it */
385 memset(type, 0, sizeof *type);
386
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200387 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
388
389 if (orig_type->range) {
390 type->range = calloc(1, sizeof *type->range);
391 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
392 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
393 }
394
395 if (orig_type->length) {
396 type->length = calloc(1, sizeof *type->length);
397 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
398 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
399 }
400
401 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
402 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
403 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
404 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
405 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
406 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
407 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
408
409 type->pmod = orig_type->pmod;
410 type->compiled = orig_type->compiled;
411
412 type->fraction_digits = orig_type->fraction_digits;
413 type->require_instance = orig_type->require_instance;
414 type->flags = orig_type->flags;
415
416done:
417 return ret;
418}
419
420static LY_ERR
421lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
422{
423 LY_ERR ret = LY_SUCCESS;
424
425 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
426 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
427 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
428 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
429
430 return ret;
431}
432
433static LY_ERR
434lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
435{
436 LY_ERR ret = LY_SUCCESS;
437
438 node->parent = NULL;
439 node->nodetype = orig->nodetype;
440 node->flags = orig->flags;
441 node->next = NULL;
442 DUP_STRING(ctx, orig->name, node->name, ret);
443 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
444 DUP_STRING(ctx, orig->ref, node->ref, ret);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200445 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
446 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
447
448 return ret;
449}
450
Radek Krejci9a3823e2021-01-27 20:26:46 +0100451#define DUP_PWHEN(CTX, ORIG, NEW) \
452 if (ORIG) { \
453 NEW = calloc(1, sizeof *NEW); \
454 LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \
455 LY_CHECK_RET(lysp_when_dup(CTX, NEW, ORIG)); \
456 }
457
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200458static LY_ERR
459lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
460{
461 LY_ERR ret = LY_SUCCESS;
462 struct lysp_node_container *cont;
463 const struct lysp_node_container *orig_cont;
464 struct lysp_node_leaf *leaf;
465 const struct lysp_node_leaf *orig_leaf;
466 struct lysp_node_leaflist *llist;
467 const struct lysp_node_leaflist *orig_llist;
468 struct lysp_node_list *list;
469 const struct lysp_node_list *orig_list;
470 struct lysp_node_choice *choice;
471 const struct lysp_node_choice *orig_choice;
472 struct lysp_node_case *cas;
473 const struct lysp_node_case *orig_cas;
474 struct lysp_node_anydata *any;
475 const struct lysp_node_anydata *orig_any;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100476 struct lysp_node_action *action;
477 const struct lysp_node_action *orig_action;
478 struct lysp_node_action_inout *action_inout;
479 const struct lysp_node_action_inout *orig_action_inout;
480 struct lysp_node_notif *notif;
481 const struct lysp_node_notif *orig_notif;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200482
Radek Krejci2a9fc652021-01-22 17:44:34 +0100483 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA |
484 LYS_RPC | LYS_ACTION | LYS_NOTIF));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200485
486 /* common part */
487 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
488
489 /* specific part */
490 switch (node->nodetype) {
491 case LYS_CONTAINER:
492 cont = (struct lysp_node_container *)node;
493 orig_cont = (const struct lysp_node_container *)orig;
494
Radek Krejci9a3823e2021-01-27 20:26:46 +0100495 DUP_PWHEN(ctx, orig_cont->when, cont->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200496 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
497 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
498 /* we do not need the rest */
499 break;
500 case LYS_LEAF:
501 leaf = (struct lysp_node_leaf *)node;
502 orig_leaf = (const struct lysp_node_leaf *)orig;
503
Radek Krejci9a3823e2021-01-27 20:26:46 +0100504 DUP_PWHEN(ctx, orig_leaf->when, leaf->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200505 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
506 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
507 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
508 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
509 break;
510 case LYS_LEAFLIST:
511 llist = (struct lysp_node_leaflist *)node;
512 orig_llist = (const struct lysp_node_leaflist *)orig;
513
Radek Krejci9a3823e2021-01-27 20:26:46 +0100514 DUP_PWHEN(ctx, orig_llist->when, llist->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200515 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
516 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
517 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
518 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
519 llist->min = orig_llist->min;
520 llist->max = orig_llist->max;
521 break;
522 case LYS_LIST:
523 list = (struct lysp_node_list *)node;
524 orig_list = (const struct lysp_node_list *)orig;
525
Radek Krejci9a3823e2021-01-27 20:26:46 +0100526 DUP_PWHEN(ctx, orig_list->when, list->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200527 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
528 DUP_STRING(ctx, orig_list->key, list->key, ret);
529 /* we do not need these arrays */
530 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
531 list->min = orig_list->min;
532 list->max = orig_list->max;
533 break;
534 case LYS_CHOICE:
535 choice = (struct lysp_node_choice *)node;
536 orig_choice = (const struct lysp_node_choice *)orig;
537
Radek Krejci9a3823e2021-01-27 20:26:46 +0100538 DUP_PWHEN(ctx, orig_choice->when, choice->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200539 /* we do not need children */
540 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
541 break;
542 case LYS_CASE:
543 cas = (struct lysp_node_case *)node;
544 orig_cas = (const struct lysp_node_case *)orig;
545
Radek Krejci9a3823e2021-01-27 20:26:46 +0100546 DUP_PWHEN(ctx, orig_cas->when, cas->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200547 /* we do not need children */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200548 break;
549 case LYS_ANYDATA:
550 case LYS_ANYXML:
551 any = (struct lysp_node_anydata *)node;
552 orig_any = (const struct lysp_node_anydata *)orig;
553
Radek Krejci9a3823e2021-01-27 20:26:46 +0100554 DUP_PWHEN(ctx, orig_any->when, any->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200555 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
556 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100557 case LYS_RPC:
558 case LYS_ACTION:
559 action = (struct lysp_node_action *)node;
560 orig_action = (const struct lysp_node_action *)orig;
561
562 action->input.nodetype = orig_action->input.nodetype;
563 action->output.nodetype = orig_action->output.nodetype;
564 /* we do not need the rest */
565 break;
566 case LYS_INPUT:
567 case LYS_OUTPUT:
568 action_inout = (struct lysp_node_action_inout *)node;
569 orig_action_inout = (const struct lysp_node_action_inout *)orig;
570
571 DUP_ARRAY(ctx, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
572 /* we do not need the rest */
573 break;
574 case LYS_NOTIF:
575 notif = (struct lysp_node_notif *)node;
576 orig_notif = (const struct lysp_node_notif *)orig;
577
578 DUP_ARRAY(ctx, orig_notif->musts, notif->musts, lysp_restr_dup);
579 /* we do not need the rest */
580 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200581 default:
582 LOGINT_RET(ctx);
583 }
584
585 return ret;
586}
587
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200588/**
589 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
590 *
591 * @param[in] ctx libyang context.
592 * @param[in] pnode Node to duplicate.
593 * @param[in] with_links Whether to also copy any links (child, parent pointers).
594 * @param[out] dup_p Duplicated parsed node.
595 * @return LY_ERR value.
596 */
597static LY_ERR
598lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
599{
600 LY_ERR ret = LY_SUCCESS;
601 void *mem = NULL;
602
603 if (!pnode) {
604 *dup_p = NULL;
605 return LY_SUCCESS;
606 }
607
608 switch (pnode->nodetype) {
609 case LYS_CONTAINER:
610 mem = calloc(1, sizeof(struct lysp_node_container));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200611 break;
612 case LYS_LEAF:
613 mem = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200614 break;
615 case LYS_LEAFLIST:
616 mem = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200617 break;
618 case LYS_LIST:
619 mem = calloc(1, sizeof(struct lysp_node_list));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200620 break;
621 case LYS_CHOICE:
622 mem = calloc(1, sizeof(struct lysp_node_choice));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200623 break;
624 case LYS_CASE:
625 mem = calloc(1, sizeof(struct lysp_node_case));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200626 break;
627 case LYS_ANYDATA:
628 case LYS_ANYXML:
629 mem = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200630 break;
631 case LYS_INPUT:
632 case LYS_OUTPUT:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100633 mem = calloc(1, sizeof(struct lysp_node_action_inout));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200634 break;
635 case LYS_ACTION:
636 case LYS_RPC:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100637 mem = calloc(1, sizeof(struct lysp_node_action));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200638 break;
639 case LYS_NOTIF:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100640 mem = calloc(1, sizeof(struct lysp_node_notif));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200641 break;
642 default:
643 LOGINT_RET(ctx);
644 }
Radek Krejci2a9fc652021-01-22 17:44:34 +0100645 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
646 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200647
648 if (with_links) {
Michal Vaskoec8f4272021-10-27 09:14:03 +0200649 /* copy also parent, child, action, and notification pointers */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200650 ((struct lysp_node *)mem)->parent = pnode->parent;
651 switch (pnode->nodetype) {
652 case LYS_CONTAINER:
653 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
Michal Vaskoec8f4272021-10-27 09:14:03 +0200654 ((struct lysp_node_container *)mem)->actions = ((struct lysp_node_container *)pnode)->actions;
655 ((struct lysp_node_container *)mem)->notifs = ((struct lysp_node_container *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200656 break;
657 case LYS_LIST:
658 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
Michal Vaskoec8f4272021-10-27 09:14:03 +0200659 ((struct lysp_node_list *)mem)->actions = ((struct lysp_node_list *)pnode)->actions;
660 ((struct lysp_node_list *)mem)->notifs = ((struct lysp_node_list *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200661 break;
662 case LYS_CHOICE:
663 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
664 break;
665 case LYS_CASE:
666 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
667 break;
668 default:
669 break;
670 }
671 }
672
673cleanup:
674 if (ret) {
675 free(mem);
676 } else {
677 *dup_p = mem;
678 }
679 return ret;
680}
681
682#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100683 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 +0200684 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
685 ret = LY_EVALID; \
686 goto cleanup;
687
688#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
689 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100690 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 +0200691 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
692 ret = LY_EVALID; \
693 goto cleanup; \
694 }
695
696/**
697 * @brief Apply refine.
698 *
699 * @param[in] ctx Compile context.
700 * @param[in] rfn Refine to apply.
701 * @param[in,out] target Refine target.
702 * @return LY_ERR value.
703 */
704static LY_ERR
705lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
706{
707 LY_ERR ret = LY_SUCCESS;
708 LY_ARRAY_COUNT_TYPE u;
709 struct lysp_qname *qname;
710 struct lysp_restr **musts, *must;
711 uint32_t *num;
712
713 /* default value */
714 if (rfn->dflts) {
715 switch (target->nodetype) {
716 case LYS_LEAF:
717 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
718
Michal Vaskoe180ed02021-02-05 16:31:20 +0100719 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200720 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &rfn->dflts[0]), cleanup);
721 break;
722 case LYS_LEAFLIST:
723 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100724 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200725 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
726 ret = LY_EVALID;
727 goto cleanup;
728 }
729
730 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
731 ((struct lysp_node_leaflist *)target)->dflts = NULL;
732 LY_ARRAY_FOR(rfn->dflts, u) {
733 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
734 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup);
735 }
736 break;
737 case LYS_CHOICE:
738 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
739
Michal Vaskoe180ed02021-02-05 16:31:20 +0100740 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200741 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &rfn->dflts[0]), cleanup);
742 break;
743 default:
744 AMEND_WRONG_NODETYPE("refine", "replace", "default");
745 }
746 }
747
748 /* description */
749 if (rfn->dsc) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100750 lydict_remove(ctx->ctx, target->dsc);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200751 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
752 }
753
754 /* reference */
755 if (rfn->ref) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100756 lydict_remove(ctx->ctx, target->ref);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200757 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
758 }
759
760 /* config */
761 if (rfn->flags & LYS_CONFIG_MASK) {
Michal Vasko7c565922021-06-10 14:58:27 +0200762 if (ctx->compile_opts & LYS_COMPILE_NO_CONFIG) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200763 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Michal Vasko7c565922021-06-10 14:58:27 +0200764 (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT)) ? "RPC/action" :
765 ctx->compile_opts & LYS_IS_NOTIF ? "notification" : "a subtree ignoring config", ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200766 } else {
767 target->flags &= ~LYS_CONFIG_MASK;
768 target->flags |= rfn->flags & LYS_CONFIG_MASK;
769 }
770 }
771
772 /* mandatory */
773 if (rfn->flags & LYS_MAND_MASK) {
774 switch (target->nodetype) {
775 case LYS_LEAF:
776 case LYS_CHOICE:
777 case LYS_ANYDATA:
778 case LYS_ANYXML:
779 break;
780 default:
781 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
782 }
783
784 target->flags &= ~LYS_MAND_MASK;
785 target->flags |= rfn->flags & LYS_MAND_MASK;
786 }
787
788 /* presence */
789 if (rfn->presence) {
790 switch (target->nodetype) {
791 case LYS_CONTAINER:
792 break;
793 default:
794 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
795 }
796
Michal Vaskoe180ed02021-02-05 16:31:20 +0100797 lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200798 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
799 }
800
801 /* must */
802 if (rfn->musts) {
803 switch (target->nodetype) {
804 case LYS_CONTAINER:
805 case LYS_LIST:
806 case LYS_LEAF:
807 case LYS_LEAFLIST:
808 case LYS_ANYDATA:
809 case LYS_ANYXML:
810 musts = &((struct lysp_node_container *)target)->musts;
811 break;
812 default:
813 AMEND_WRONG_NODETYPE("refine", "add", "must");
814 }
815
816 LY_ARRAY_FOR(rfn->musts, u) {
817 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
818 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
819 }
820 }
821
822 /* min-elements */
823 if (rfn->flags & LYS_SET_MIN) {
824 switch (target->nodetype) {
825 case LYS_LEAFLIST:
826 num = &((struct lysp_node_leaflist *)target)->min;
827 break;
828 case LYS_LIST:
829 num = &((struct lysp_node_list *)target)->min;
830 break;
831 default:
832 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
833 }
834
835 *num = rfn->min;
836 }
837
838 /* max-elements */
839 if (rfn->flags & LYS_SET_MAX) {
840 switch (target->nodetype) {
841 case LYS_LEAFLIST:
842 num = &((struct lysp_node_leaflist *)target)->max;
843 break;
844 case LYS_LIST:
845 num = &((struct lysp_node_list *)target)->max;
846 break;
847 default:
848 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
849 }
850
851 *num = rfn->max;
852 }
853
854 /* if-feature */
855 if (rfn->iffeatures) {
856 switch (target->nodetype) {
857 case LYS_LEAF:
858 case LYS_LEAFLIST:
859 case LYS_LIST:
860 case LYS_CONTAINER:
861 case LYS_CHOICE:
862 case LYS_CASE:
863 case LYS_ANYDATA:
864 case LYS_ANYXML:
865 break;
866 default:
867 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
868 }
869
870 LY_ARRAY_FOR(rfn->iffeatures, u) {
871 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
872 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup);
873 }
874 }
875
876 /* extension */
877 /* TODO refine extensions */
878
879cleanup:
880 return ret;
881}
882
883/**
884 * @brief Apply deviate add.
885 *
886 * @param[in] ctx Compile context.
887 * @param[in] d Deviate add to apply.
888 * @param[in,out] target Deviation target.
889 * @return LY_ERR value.
890 */
891static LY_ERR
892lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
893{
894 LY_ERR ret = LY_SUCCESS;
895 LY_ARRAY_COUNT_TYPE u;
896 struct lysp_qname *qname;
897 uint32_t *num;
898 struct lysp_restr **musts, *must;
899
900#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
901 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100902 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200903 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
904 ret = LY_EVALID; \
905 goto cleanup; \
906 }
907
908 /* [units-stmt] */
909 if (d->units) {
910 switch (target->nodetype) {
911 case LYS_LEAF:
912 case LYS_LEAFLIST:
913 break;
914 default:
915 AMEND_WRONG_NODETYPE("deviation", "add", "units");
916 }
917
918 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
919 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
920 }
921
922 /* *must-stmt */
923 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100924 musts = lysp_node_musts_p(target);
925 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200926 AMEND_WRONG_NODETYPE("deviation", "add", "must");
927 }
928
929 LY_ARRAY_FOR(d->musts, u) {
930 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
931 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
932 }
933 }
934
935 /* *unique-stmt */
936 if (d->uniques) {
937 switch (target->nodetype) {
938 case LYS_LIST:
939 break;
940 default:
941 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
942 }
943
944 LY_ARRAY_FOR(d->uniques, u) {
945 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
946 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup);
947 }
948 }
949
950 /* *default-stmt */
951 if (d->dflts) {
952 switch (target->nodetype) {
953 case LYS_LEAF:
954 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
955 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
956
957 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflts[0]), cleanup);
958 break;
959 case LYS_LEAFLIST:
960 LY_ARRAY_FOR(d->dflts, u) {
961 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
962 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup);
963 }
964 break;
965 case LYS_CHOICE:
966 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
967 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
968
969 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflts[0]), cleanup);
970 break;
971 default:
972 AMEND_WRONG_NODETYPE("deviation", "add", "default");
973 }
974 }
975
976 /* [config-stmt] */
977 if (d->flags & LYS_CONFIG_MASK) {
978 switch (target->nodetype) {
979 case LYS_CONTAINER:
980 case LYS_LEAF:
981 case LYS_LEAFLIST:
982 case LYS_LIST:
983 case LYS_CHOICE:
984 case LYS_ANYDATA:
985 case LYS_ANYXML:
986 break;
987 default:
988 AMEND_WRONG_NODETYPE("deviation", "add", "config");
989 }
990
991 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100992 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200993 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
994 target->flags & LYS_CONFIG_W ? "true" : "false");
995 ret = LY_EVALID;
996 goto cleanup;
997 }
998
999 target->flags |= d->flags & LYS_CONFIG_MASK;
1000 }
1001
1002 /* [mandatory-stmt] */
1003 if (d->flags & LYS_MAND_MASK) {
1004 switch (target->nodetype) {
1005 case LYS_LEAF:
1006 case LYS_CHOICE:
1007 case LYS_ANYDATA:
1008 case LYS_ANYXML:
1009 break;
1010 default:
1011 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
1012 }
1013
1014 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001015 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001016 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
1017 target->flags & LYS_MAND_TRUE ? "true" : "false");
1018 ret = LY_EVALID;
1019 goto cleanup;
1020 }
1021
1022 target->flags |= d->flags & LYS_MAND_MASK;
1023 }
1024
1025 /* [min-elements-stmt] */
1026 if (d->flags & LYS_SET_MIN) {
1027 switch (target->nodetype) {
1028 case LYS_LEAFLIST:
1029 num = &((struct lysp_node_leaflist *)target)->min;
1030 break;
1031 case LYS_LIST:
1032 num = &((struct lysp_node_list *)target)->min;
1033 break;
1034 default:
1035 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
1036 }
1037
1038 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001039 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001040 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
1041 ret = LY_EVALID;
1042 goto cleanup;
1043 }
1044
1045 *num = d->min;
1046 }
1047
1048 /* [max-elements-stmt] */
1049 if (d->flags & LYS_SET_MAX) {
1050 switch (target->nodetype) {
1051 case LYS_LEAFLIST:
1052 num = &((struct lysp_node_leaflist *)target)->max;
1053 break;
1054 case LYS_LIST:
1055 num = &((struct lysp_node_list *)target)->max;
1056 break;
1057 default:
1058 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1059 }
1060
1061 if (target->flags & LYS_SET_MAX) {
1062 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001063 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001064 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1065 *num);
1066 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001067 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001068 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1069 }
1070 ret = LY_EVALID;
1071 goto cleanup;
1072 }
1073
1074 *num = d->max;
1075 }
1076
1077cleanup:
1078 return ret;
1079}
1080
1081/**
1082 * @brief Apply deviate delete.
1083 *
1084 * @param[in] ctx Compile context.
1085 * @param[in] d Deviate delete to apply.
1086 * @param[in,out] target Deviation target.
1087 * @return LY_ERR value.
1088 */
1089static LY_ERR
1090lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1091{
1092 LY_ERR ret = LY_SUCCESS;
1093 struct lysp_restr **musts;
1094 LY_ARRAY_COUNT_TYPE u, v;
1095 struct lysp_qname **uniques, **dflts;
1096
1097#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
1098 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1099 int found = 0; \
1100 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1101 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1102 found = 1; \
1103 break; \
1104 } \
1105 } \
1106 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001107 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001108 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1109 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1110 ret = LY_EVALID; \
1111 goto cleanup; \
1112 } \
1113 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
1114 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
Michal Vasko08e9b112021-06-11 15:41:17 +02001115 if (v < LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1116 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1117 } \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001118 } \
1119 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1120 LY_ARRAY_FREE(ORIG_ARRAY); \
1121 ORIG_ARRAY = NULL; \
1122 }
1123
1124#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1125 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001126 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001127 ret = LY_EVALID; \
1128 goto cleanup; \
1129 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001130 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001131 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1132 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1133 ret = LY_EVALID; \
1134 goto cleanup; \
1135 }
1136
1137 /* [units-stmt] */
1138 if (d->units) {
1139 switch (target->nodetype) {
1140 case LYS_LEAF:
1141 case LYS_LEAFLIST:
1142 break;
1143 default:
1144 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1145 }
1146
1147 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001148 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001149 ((struct lysp_node_leaf *)target)->units = NULL;
1150 }
1151
1152 /* *must-stmt */
1153 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001154 musts = lysp_node_musts_p(target);
1155 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001156 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1157 }
1158
1159 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
1160 }
1161
1162 /* *unique-stmt */
1163 if (d->uniques) {
1164 switch (target->nodetype) {
1165 case LYS_LIST:
1166 break;
1167 default:
1168 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1169 }
1170
1171 uniques = &((struct lysp_node_list *)target)->uniques;
1172 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, "unique");
1173 }
1174
1175 /* *default-stmt */
1176 if (d->dflts) {
1177 switch (target->nodetype) {
1178 case LYS_LEAF:
1179 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1180 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1181
Michal Vaskoe180ed02021-02-05 16:31:20 +01001182 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001183 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1184 break;
1185 case LYS_LEAFLIST:
1186 dflts = &((struct lysp_node_leaflist *)target)->dflts;
1187 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, "default");
1188 break;
1189 case LYS_CHOICE:
1190 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1191 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1192
Michal Vaskoe180ed02021-02-05 16:31:20 +01001193 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001194 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1195 break;
1196 default:
1197 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1198 }
1199 }
1200
1201cleanup:
1202 return ret;
1203}
1204
1205/**
1206 * @brief Apply deviate replace.
1207 *
1208 * @param[in] ctx Compile context.
1209 * @param[in] d Deviate replace to apply.
1210 * @param[in,out] target Deviation target.
1211 * @return LY_ERR value.
1212 */
1213static LY_ERR
1214lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1215{
1216 LY_ERR ret = LY_SUCCESS;
1217 uint32_t *num;
1218
1219#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1220 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001221 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001222 ret = LY_EVALID; \
1223 goto cleanup; \
1224 }
1225
1226 /* [type-stmt] */
1227 if (d->type) {
1228 switch (target->nodetype) {
1229 case LYS_LEAF:
1230 case LYS_LEAFLIST:
1231 break;
1232 default:
1233 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1234 }
1235
1236 lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
1237 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
1238 }
1239
1240 /* [units-stmt] */
1241 if (d->units) {
1242 switch (target->nodetype) {
1243 case LYS_LEAF:
1244 case LYS_LEAFLIST:
1245 break;
1246 default:
1247 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1248 }
1249
1250 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001251 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001252 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1253 }
1254
1255 /* [default-stmt] */
1256 if (d->dflt.str) {
1257 switch (target->nodetype) {
1258 case LYS_LEAF:
1259 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1260
Michal Vaskoe180ed02021-02-05 16:31:20 +01001261 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001262 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflt), cleanup);
1263 break;
1264 case LYS_CHOICE:
1265 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
1266
Michal Vaskoe180ed02021-02-05 16:31:20 +01001267 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001268 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflt), cleanup);
1269 break;
1270 default:
1271 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1272 }
1273 }
1274
1275 /* [config-stmt] */
1276 if (d->flags & LYS_CONFIG_MASK) {
1277 switch (target->nodetype) {
1278 case LYS_CONTAINER:
1279 case LYS_LEAF:
1280 case LYS_LEAFLIST:
1281 case LYS_LIST:
1282 case LYS_CHOICE:
1283 case LYS_ANYDATA:
1284 case LYS_ANYXML:
1285 break;
1286 default:
1287 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1288 }
1289
1290 if (!(target->flags & LYS_CONFIG_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001291 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "config",
1292 d->flags & LYS_CONFIG_W ? "config true" : "config false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001293 ret = LY_EVALID;
1294 goto cleanup;
1295 }
1296
1297 target->flags &= ~LYS_CONFIG_MASK;
1298 target->flags |= d->flags & LYS_CONFIG_MASK;
1299 }
1300
1301 /* [mandatory-stmt] */
1302 if (d->flags & LYS_MAND_MASK) {
1303 switch (target->nodetype) {
1304 case LYS_LEAF:
1305 case LYS_CHOICE:
1306 case LYS_ANYDATA:
1307 case LYS_ANYXML:
1308 break;
1309 default:
1310 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1311 }
1312
1313 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001314 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1315 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001316 ret = LY_EVALID;
1317 goto cleanup;
1318 }
1319
1320 target->flags &= ~LYS_MAND_MASK;
1321 target->flags |= d->flags & LYS_MAND_MASK;
1322 }
1323
1324 /* [min-elements-stmt] */
1325 if (d->flags & LYS_SET_MIN) {
1326 switch (target->nodetype) {
1327 case LYS_LEAFLIST:
1328 num = &((struct lysp_node_leaflist *)target)->min;
1329 break;
1330 case LYS_LIST:
1331 num = &((struct lysp_node_list *)target)->min;
1332 break;
1333 default:
1334 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1335 }
1336
1337 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001338 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001339 ret = LY_EVALID;
1340 goto cleanup;
1341 }
1342
1343 *num = d->min;
1344 }
1345
1346 /* [max-elements-stmt] */
1347 if (d->flags & LYS_SET_MAX) {
1348 switch (target->nodetype) {
1349 case LYS_LEAFLIST:
1350 num = &((struct lysp_node_leaflist *)target)->max;
1351 break;
1352 case LYS_LIST:
1353 num = &((struct lysp_node_list *)target)->max;
1354 break;
1355 default:
1356 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1357 }
1358
1359 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001360 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001361 ret = LY_EVALID;
1362 goto cleanup;
1363 }
1364
1365 *num = d->max;
1366 }
1367
1368cleanup:
1369 return ret;
1370}
1371
1372/**
1373 * @brief Get module of a single nodeid node name test.
1374 *
1375 * @param[in] ctx libyang context.
1376 * @param[in] nametest Nametest with an optional prefix.
1377 * @param[in] nametest_len Length of @p nametest.
1378 * @param[in] mod Both current and prefix module for resolving prefixes and to return in case of no prefix.
1379 * @param[out] name Optional pointer to the name test without the prefix.
1380 * @param[out] name_len Length of @p name.
1381 * @return Resolved module.
1382 */
1383static const struct lys_module *
1384lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
1385 const struct lysp_module *mod, const char **name, size_t *name_len)
1386{
1387 const struct lys_module *target_mod;
1388 const char *ptr;
1389
1390 ptr = ly_strnchr(nametest, ':', nametest_len);
1391 if (ptr) {
Radek Krejci8df109d2021-04-23 12:19:08 +02001392 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_VALUE_SCHEMA, (void *)mod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001393 if (!target_mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001394 LOGVAL(ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001395 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001396 (int)nametest_len, nametest, (int)(ptr - nametest), nametest, LYSP_MODULE_NAME(mod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001397 return NULL;
1398 }
1399
1400 if (name) {
1401 *name = ptr + 1;
1402 *name_len = nametest_len - ((ptr - nametest) + 1);
1403 }
1404 } else {
1405 target_mod = mod->mod;
1406 if (name) {
1407 *name = nametest;
1408 *name_len = nametest_len;
1409 }
1410 }
1411
1412 return target_mod;
1413}
1414
1415/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001416 * @brief Check whether a compiled node matches a single schema nodeid name test.
1417 *
1418 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1419 * @param[in] mod Expected module.
1420 * @param[in] name Expected name.
1421 * @param[in] name_len Length of @p name.
1422 * @return Whether it is a match or not.
1423 */
1424static ly_bool
1425lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1426 size_t name_len)
1427{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001428 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001429 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001430 return 0;
1431 }
1432
1433 /* compare names */
Michal Vasko544e58a2021-01-28 14:33:41 +01001434 if (ly_strncmp((*node)->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001435 return 0;
1436 }
1437
Michal Vasko2a668712020-10-21 11:48:09 +02001438 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001439 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001440
1441 return 1;
1442}
1443
1444/**
1445 * @brief Check whether a node matches specific schema nodeid.
1446 *
1447 * @param[in] exp Parsed nodeid to match.
1448 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
1449 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1450 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1451 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1452 * @param[in] pnode_mod Compiled @p pnode to-be module.
1453 * @return Whether it is a match or not.
1454 */
1455static ly_bool
1456lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node,
1457 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
1458{
1459 uint32_t i;
1460 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001461 const char *name = NULL;
1462 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001463
1464 /* compare last node in the node ID */
1465 i = exp->used - 1;
1466
1467 /* get exp node ID module */
1468 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);
1469 assert(mod);
1470
1471 if (pnode) {
1472 /* compare on the last parsed-only node */
Radek Krejci2d5f6df2021-01-28 14:00:13 +01001473 if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001474 return 0;
1475 }
1476 } else {
1477 /* using parent directly */
1478 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1479 return 0;
1480 }
1481 }
1482
1483 /* now compare all the compiled parents */
1484 while (i > 1) {
1485 i -= 2;
1486 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1487
1488 if (!parent) {
1489 /* no more parents but path continues */
1490 return 0;
1491 }
1492
1493 /* get exp node ID module */
1494 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1495 &name_len);
1496 assert(mod);
1497
1498 /* compare with the parent */
1499 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1500 return 0;
1501 }
1502 }
1503
1504 if (ctx_node && (ctx_node != parent)) {
1505 /* descendant path has not finished in the context node */
1506 return 0;
1507 } else if (!ctx_node && parent) {
1508 /* some parent was not matched */
1509 return 0;
1510 }
1511
1512 return 1;
1513}
1514
1515void
1516lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1517{
1518 if (aug) {
1519 lyxp_expr_free(ctx, aug->nodeid);
1520
1521 free(aug);
1522 }
1523}
1524
1525void
1526lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1527{
1528 if (dev) {
1529 lyxp_expr_free(ctx, dev->nodeid);
1530 LY_ARRAY_FREE(dev->devs);
1531 LY_ARRAY_FREE(dev->dev_pmods);
1532
1533 free(dev);
1534 }
1535}
1536
1537void
1538lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1539{
1540 if (rfn) {
1541 lyxp_expr_free(ctx, rfn->nodeid);
1542 LY_ARRAY_FREE(rfn->rfns);
1543
1544 free(rfn);
1545 }
1546}
1547
1548void
1549lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
1550{
1551 if (!dev_pnode) {
1552 return;
1553 }
1554
1555 switch (dev_pnode->nodetype) {
1556 case LYS_CONTAINER:
1557 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001558 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1559 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001560 break;
1561 case LYS_LIST:
1562 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001563 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1564 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001565 break;
1566 case LYS_CHOICE:
1567 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1568 break;
1569 case LYS_CASE:
1570 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1571 break;
1572 case LYS_LEAF:
1573 case LYS_LEAFLIST:
1574 case LYS_ANYXML:
1575 case LYS_ANYDATA:
1576 /* no children */
1577 break;
1578 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001579 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001580 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001581 case LYS_RPC:
1582 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001583 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1584 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001585 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001586 case LYS_INPUT:
1587 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001588 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001589 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001590 free(dev_pnode);
1591 return;
1592 default:
1593 LOGINT(ctx);
1594 return;
1595 }
1596
1597 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
1598}
1599
1600LY_ERR
1601lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1602 struct lysp_node **dev_pnode, ly_bool *not_supported)
1603{
1604 LY_ERR ret = LY_SUCCESS;
1605 uint32_t i;
1606 LY_ARRAY_COUNT_TYPE u;
1607 struct lys_module *orig_mod = ctx->cur_mod;
1608 struct lysp_module *orig_pmod = ctx->pmod;
1609 char orig_path[LYSC_CTX_BUFSIZE];
1610 struct lysc_refine *rfn;
1611 struct lysc_deviation *dev;
1612 struct lysp_deviation *dev_p;
1613 struct lysp_deviate *d;
1614
1615 *dev_pnode = NULL;
1616 *not_supported = 0;
1617
1618 for (i = 0; i < ctx->uses_rfns.count; ++i) {
1619 rfn = ctx->uses_rfns.objs[i];
1620
Michal Vasko28fe5f62021-03-03 16:37:39 +01001621 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 +02001622 /* not our target node */
1623 continue;
1624 }
1625
1626 if (!*dev_pnode) {
1627 /* first refine on this node, create a copy first */
1628 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1629 }
1630
Michal Vaskob8df5762021-01-12 15:15:53 +01001631 /* use modules from the refine */
1632 ctx->cur_mod = rfn->nodeid_pmod->mod;
1633 ctx->pmod = (struct lysp_module *)rfn->nodeid_pmod;
1634
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001635 /* apply all the refines by changing (the copy of) the parsed node */
1636 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vaskob8df5762021-01-12 15:15:53 +01001637 /* keep the current path and add to it */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001638 lysc_update_path(ctx, NULL, "{refine}");
1639 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001640
1641 /* apply refine and restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001642 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
1643 lysc_update_path(ctx, NULL, NULL);
1644 lysc_update_path(ctx, NULL, NULL);
1645 LY_CHECK_GOTO(ret, cleanup);
1646 }
1647
1648 /* refine was applied, remove it */
1649 lysc_refine_free(ctx->ctx, rfn);
1650 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1651
1652 /* all the refines for one target node are in one structure, we are done */
1653 break;
1654 }
1655
1656 for (i = 0; i < ctx->devs.count; ++i) {
1657 dev = ctx->devs.objs[i];
1658
Michal Vasko28fe5f62021-03-03 16:37:39 +01001659 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, orig_mod)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001660 /* not our target node */
1661 continue;
1662 }
1663
1664 if (dev->not_supported) {
1665 /* it is not supported, no more deviations */
1666 *not_supported = 1;
1667 goto dev_applied;
1668 }
1669
1670 if (!*dev_pnode) {
1671 /* first deviation on this node, create a copy first */
1672 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1673 }
1674
1675 /* apply all the deviates by changing (the copy of) the parsed node */
1676 LY_ARRAY_FOR(dev->devs, u) {
1677 dev_p = dev->devs[u];
1678 LY_LIST_FOR(dev_p->deviates, d) {
1679 /* generate correct path */
1680 strcpy(orig_path, ctx->path);
1681 ctx->path_len = 1;
1682 ctx->cur_mod = dev->dev_pmods[u]->mod;
1683 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
1684 lysc_update_path(ctx, NULL, "{deviation}");
1685 lysc_update_path(ctx, NULL, dev_p->nodeid);
1686
1687 switch (d->mod) {
1688 case LYS_DEV_ADD:
1689 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
1690 break;
1691 case LYS_DEV_DELETE:
1692 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
1693 break;
1694 case LYS_DEV_REPLACE:
1695 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
1696 break;
1697 default:
1698 LOGINT(ctx->ctx);
1699 ret = LY_EINT;
1700 }
1701
1702 /* restore previous path */
1703 strcpy(ctx->path, orig_path);
1704 ctx->path_len = strlen(ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001705
1706 LY_CHECK_GOTO(ret, cleanup);
1707 }
1708 }
1709
1710dev_applied:
1711 /* deviation was applied, remove it */
1712 lysc_deviation_free(ctx->ctx, dev);
1713 ly_set_rm_index(&ctx->devs, i, NULL);
1714
1715 /* all the deviations for one target node are in one structure, we are done */
1716 break;
1717 }
1718
1719cleanup:
Michal Vasko20316b32021-01-12 15:16:54 +01001720 ctx->cur_mod = orig_mod;
1721 ctx->pmod = orig_pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001722 if (ret) {
1723 lysp_dev_node_free(ctx->ctx, *dev_pnode);
1724 *dev_pnode = NULL;
1725 *not_supported = 0;
1726 }
1727 return ret;
1728}
1729
1730/**
1731 * @brief Compile the parsed augment connecting it into its target.
1732 *
1733 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1734 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1735 * are already implemented and compiled.
1736 *
1737 * @param[in] ctx Compile context.
1738 * @param[in] aug_p Parsed augment to compile.
1739 * @param[in] target Target node of the augment.
1740 * @return LY_SUCCESS on success.
1741 * @return LY_EVALID on failure.
1742 */
1743static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001744lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001745{
1746 LY_ERR ret = LY_SUCCESS;
1747 struct lysp_node *pnode;
1748 struct lysc_node *node;
1749 struct lysc_when *when_shared = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001750 struct lysc_node_action **actions;
1751 struct lysc_node_notif **notifs;
Michal Vasko29dd11e2020-11-23 16:52:22 +01001752 ly_bool allow_mandatory = 0, enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001753 struct ly_set child_set = {0};
Michal Vasko7c565922021-06-10 14:58:27 +02001754 uint32_t i, opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001755
1756 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001757 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001758 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
1759 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
1760 ret = LY_EVALID;
1761 goto cleanup;
1762 }
1763
1764 /* check for mandatory nodes
1765 * - new cases augmenting some choice can have mandatory nodes
1766 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1767 */
1768 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
1769 allow_mandatory = 1;
1770 }
1771
1772 LY_LIST_FOR(aug_p->child, pnode) {
1773 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1774 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1775 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1776 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001777 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001778 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1779 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1780 ret = LY_EVALID;
1781 goto cleanup;
1782 }
1783
1784 /* compile the children */
1785 if (target->nodetype == LYS_CHOICE) {
1786 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
Michal Vasko6fb4c042020-11-24 18:05:26 +01001787 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1788 if (target->nodetype == LYS_INPUT) {
Michal Vasko7c565922021-06-10 14:58:27 +02001789 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
Michal Vasko6fb4c042020-11-24 18:05:26 +01001790 } else {
Michal Vasko7c565922021-06-10 14:58:27 +02001791 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
Michal Vasko6fb4c042020-11-24 18:05:26 +01001792 }
Radek Krejci2a9fc652021-01-22 17:44:34 +01001793 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001794 } else {
1795 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1796 }
1797
Michal Vasko29dd11e2020-11-23 16:52:22 +01001798 /* eval if-features again for the rest of this node processing */
1799 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1800 if (!enabled) {
Michal Vasko7c565922021-06-10 14:58:27 +02001801 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vasko29dd11e2020-11-23 16:52:22 +01001802 }
1803
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001804 /* since the augment node is not present in the compiled tree, we need to pass some of its
1805 * statements to all its children */
1806 for (i = 0; i < child_set.count; ++i) {
1807 node = child_set.snodes[i];
1808 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1809 node->flags &= ~LYS_MAND_TRUE;
1810 lys_compile_mandatory_parents(target, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001811 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko23864e02021-06-24 09:23:58 +02001812 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
1813 node->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001814 ret = LY_EVALID;
1815 goto cleanup;
1816 }
1817
1818 if (aug_p->when) {
1819 /* pass augment's when to all the children */
Michal Vaskodfd254d2021-06-24 09:24:59 +02001820 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, lysc_data_node(target), node, &when_shared);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001821 LY_CHECK_GOTO(ret, cleanup);
1822 }
1823 }
1824 ly_set_erase(&child_set, NULL);
Michal Vasko29dd11e2020-11-23 16:52:22 +01001825
1826 /* restore options */
Michal Vasko7c565922021-06-10 14:58:27 +02001827 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001828 }
1829
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001830 actions = lysc_node_actions_p(target);
1831 notifs = lysc_node_notifs_p(target);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001832
1833 if (aug_p->actions) {
1834 if (!actions) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001835 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001836 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
Radek Krejci2a9fc652021-01-22 17:44:34 +01001837 lys_nodetype2str(target->nodetype), aug_p->actions->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001838 ret = LY_EVALID;
1839 goto cleanup;
1840 }
1841
1842 /* compile actions into the target */
Radek Krejci2a9fc652021-01-22 17:44:34 +01001843 LY_LIST_FOR((struct lysp_node *)aug_p->actions, pnode) {
Michal Vasko012807e2021-02-03 09:52:18 +01001844 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001845
Michal Vasko012807e2021-02-03 09:52:18 +01001846 /* eval if-features again for the rest of this node processing */
1847 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1848 if (!enabled) {
Michal Vasko7c565922021-06-10 14:58:27 +02001849 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001850 }
Michal Vasko012807e2021-02-03 09:52:18 +01001851
1852 /* since the augment node is not present in the compiled tree, we need to pass some of its
1853 * statements to all its children */
1854 for (i = 0; i < child_set.count; ++i) {
1855 node = child_set.snodes[i];
1856 if (aug_p->when) {
1857 /* pass augment's when to all the actions */
Michal Vaskodfd254d2021-06-24 09:24:59 +02001858 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, lysc_data_node(target), node, &when_shared);
Michal Vasko012807e2021-02-03 09:52:18 +01001859 LY_CHECK_GOTO(ret, cleanup);
1860 }
1861 }
1862 ly_set_erase(&child_set, NULL);
1863
1864 /* restore options */
Michal Vasko7c565922021-06-10 14:58:27 +02001865 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001866 }
1867 }
1868 if (aug_p->notifs) {
1869 if (!notifs) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001870 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001871 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
Radek Krejci2a9fc652021-01-22 17:44:34 +01001872 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001873 ret = LY_EVALID;
1874 goto cleanup;
1875 }
1876
1877 /* compile notifications into the target */
Radek Krejci2a9fc652021-01-22 17:44:34 +01001878 LY_LIST_FOR((struct lysp_node *)aug_p->notifs, pnode) {
Michal Vasko012807e2021-02-03 09:52:18 +01001879 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001880
Michal Vasko012807e2021-02-03 09:52:18 +01001881 /* eval if-features again for the rest of this node processing */
1882 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1883 if (!enabled) {
Michal Vasko7c565922021-06-10 14:58:27 +02001884 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001885 }
Michal Vasko012807e2021-02-03 09:52:18 +01001886
1887 /* since the augment node is not present in the compiled tree, we need to pass some of its
1888 * statements to all its children */
1889 for (i = 0; i < child_set.count; ++i) {
1890 node = child_set.snodes[i];
1891 if (aug_p->when) {
1892 /* pass augment's when to all the actions */
Michal Vaskodfd254d2021-06-24 09:24:59 +02001893 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, target, lysc_data_node(target), node, &when_shared);
Michal Vasko012807e2021-02-03 09:52:18 +01001894 LY_CHECK_GOTO(ret, cleanup);
1895 }
1896 }
1897 ly_set_erase(&child_set, NULL);
1898
1899 /* restore options */
Michal Vasko7c565922021-06-10 14:58:27 +02001900 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001901 }
1902 }
1903
1904cleanup:
1905 ly_set_erase(&child_set, NULL);
Michal Vasko7c565922021-06-10 14:58:27 +02001906 ctx->compile_opts = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001907 return ret;
1908}
1909
1910LY_ERR
1911lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
1912{
1913 LY_ERR ret = LY_SUCCESS;
1914 struct lys_module *orig_mod = ctx->cur_mod;
1915 struct lysp_module *orig_pmod = ctx->pmod;
1916 uint32_t i;
1917 char orig_path[LYSC_CTX_BUFSIZE];
1918 struct lysc_augment *aug;
1919
1920 /* uses augments */
1921 for (i = 0; i < ctx->uses_augs.count; ) {
1922 aug = ctx->uses_augs.objs[i];
1923
Michal Vasko28fe5f62021-03-03 16:37:39 +01001924 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->nodeid_ctx_node, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001925 /* not our target node */
1926 ++i;
1927 continue;
1928 }
1929
Michal Vaskob8df5762021-01-12 15:15:53 +01001930 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001931 lysc_update_path(ctx, NULL, "{augment}");
1932 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01001933 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01001934
1935 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001936 ret = lys_compile_augment(ctx, aug->aug_p, node);
1937 lysc_update_path(ctx, NULL, NULL);
1938 lysc_update_path(ctx, NULL, NULL);
1939 LY_CHECK_GOTO(ret, cleanup);
1940
Michal Vaskoc75f2042021-06-08 14:57:03 +02001941 /* augment was applied, remove it (index and the whole set may have changed because other augments
1942 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001943 ly_set_rm(&ctx->uses_augs, aug, NULL);
1944 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02001945 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001946 }
1947
1948 /* top-level augments */
1949 for (i = 0; i < ctx->augs.count; ) {
1950 aug = ctx->augs.objs[i];
1951
Michal Vasko28fe5f62021-03-03 16:37:39 +01001952 if (!lysp_schema_nodeid_match(aug->nodeid, aug->aug_pmod, NULL, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001953 /* not our target node */
1954 ++i;
1955 continue;
1956 }
1957
Michal Vaskob8df5762021-01-12 15:15:53 +01001958 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001959 strcpy(orig_path, ctx->path);
1960 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01001961 ctx->cur_mod = aug->aug_pmod->mod;
1962 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02001963 lysc_update_path(ctx, NULL, "{augment}");
1964 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001965
1966 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001967 ret = lys_compile_augment(ctx, aug->aug_p, node);
1968 strcpy(ctx->path, orig_path);
1969 ctx->path_len = strlen(ctx->path);
1970 LY_CHECK_GOTO(ret, cleanup);
1971
1972 /* augment was applied, remove it */
1973 ly_set_rm(&ctx->augs, aug, NULL);
1974 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02001975 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001976 }
1977
1978cleanup:
1979 ctx->cur_mod = orig_mod;
1980 ctx->pmod = orig_pmod;
1981 return ret;
1982}
1983
1984/**
1985 * @brief Prepare a top-level augment to be applied during data nodes compilation.
1986 *
1987 * @param[in] ctx Compile context.
1988 * @param[in] aug_p Parsed augment to be applied.
1989 * @param[in] pmod Both current and prefix module for @p aug_p.
1990 * @return LY_ERR value.
1991 */
1992static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001993lys_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 +02001994{
1995 LY_ERR ret = LY_SUCCESS;
1996 struct lyxp_expr *exp = NULL;
1997 struct lysc_augment *aug;
1998 const struct lys_module *mod;
1999
2000 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2001 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
2002 LY_CHECK_GOTO(ret, cleanup);
2003
2004 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2005 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2006 if (mod != ctx->cur_mod) {
2007 /* augment for another module, ignore */
2008 goto cleanup;
2009 }
2010
2011 /* allocate new compiled augment and store it in the set */
2012 aug = calloc(1, sizeof *aug);
2013 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2014 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2015
2016 aug->nodeid = exp;
2017 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002018 aug->aug_pmod = pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002019 aug->aug_p = aug_p;
2020
2021cleanup:
2022 lyxp_expr_free(ctx->ctx, exp);
2023 return ret;
2024}
2025
2026LY_ERR
2027lys_precompile_own_augments(struct lysc_ctx *ctx)
2028{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002029 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002030
2031 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002032 const struct lys_module *aug_mod = ctx->cur_mod->augmented_by[u];
2033 struct lysp_node_augment *aug;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002034
2035 /* collect all module augments */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002036 LY_LIST_FOR(aug_mod->parsed->augments, aug) {
2037 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002038 }
2039
2040 /* collect all submodules augments */
2041 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01002042 LY_LIST_FOR(aug_mod->parsed->includes[v].submodule->augments, aug) {
2043 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 +02002044 }
2045 }
2046 }
2047
2048 return LY_SUCCESS;
2049}
2050
2051/**
2052 * @brief Prepare a deviation to be applied during data nodes compilation.
2053 *
2054 * @param[in] ctx Compile context.
2055 * @param[in] dev_p Parsed deviation to be applied.
2056 * @param[in] pmod Both current and prefix module for @p dev_p.
2057 * @return LY_ERR value.
2058 */
2059static LY_ERR
2060lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2061{
2062 LY_ERR ret = LY_SUCCESS;
2063 struct lysc_deviation *dev = NULL;
2064 struct lyxp_expr *exp = NULL;
2065 struct lysp_deviation **new_dev;
2066 const struct lys_module *mod;
2067 const struct lysp_module **new_dev_pmod;
2068 uint32_t i;
2069
2070 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2071 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2072 LY_CHECK_GOTO(ret, cleanup);
2073
2074 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2075 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2076 if (mod != ctx->cur_mod) {
2077 /* deviation for another module, ignore */
2078 goto cleanup;
2079 }
2080
2081 /* try to find the node in already compiled deviations */
2082 for (i = 0; i < ctx->devs.count; ++i) {
2083 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2084 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2085 dev = ctx->devs.objs[i];
2086 break;
2087 }
2088 }
2089
2090 if (!dev) {
2091 /* allocate new compiled deviation */
2092 dev = calloc(1, sizeof *dev);
2093 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2094 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2095
2096 dev->nodeid = exp;
2097 exp = NULL;
2098 }
2099
2100 /* add new parsed deviation structure */
2101 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2102 *new_dev = dev_p;
2103 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2104 *new_dev_pmod = pmod;
2105
2106cleanup:
2107 lyxp_expr_free(ctx->ctx, exp);
2108 return ret;
2109}
2110
2111LY_ERR
2112lys_precompile_own_deviations(struct lysc_ctx *ctx)
2113{
2114 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002115 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002116 const struct lys_module *dev_mod;
2117 struct lysc_deviation *dev;
2118 struct lysp_deviate *d;
2119 int not_supported;
2120 uint32_t i;
2121
2122 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2123 dev_mod = ctx->cur_mod->deviated_by[u];
2124
2125 /* compile all module deviations */
2126 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2127 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2128 }
2129
2130 /* compile all submodules deviations */
2131 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2132 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2133 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2134 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2135 }
2136 }
2137 }
2138
2139 /* set not-supported flags for all the deviations */
2140 for (i = 0; i < ctx->devs.count; ++i) {
2141 dev = ctx->devs.objs[i];
2142 not_supported = 0;
2143
2144 LY_ARRAY_FOR(dev->devs, u) {
2145 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2146 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2147 not_supported = 1;
2148 break;
2149 }
2150 }
2151 if (not_supported) {
2152 break;
2153 }
2154 }
2155 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002156 orig_cur_mod = ctx->cur_mod;
2157 ctx->cur_mod = dev->dev_pmods[u]->mod;
2158 lysc_update_path(ctx, NULL, "{deviation}");
2159 lysc_update_path(ctx, NULL, dev->nodeid->expr);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002160 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002161 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002162 lysc_update_path(ctx, NULL, NULL);
2163 lysc_update_path(ctx, NULL, NULL);
2164 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002165 return LY_EVALID;
2166 }
2167
2168 dev->not_supported = not_supported;
2169 }
2170
2171 return LY_SUCCESS;
2172}
2173
2174/**
2175 * @brief Add a module reference into an array, checks for duplicities.
2176 *
2177 * @param[in] ctx Compile context.
2178 * @param[in] mod Module reference to add.
2179 * @param[in,out] mod_array Module sized array to add to.
2180 * @return LY_ERR value.
2181 */
2182static LY_ERR
2183lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2184{
2185 LY_ARRAY_COUNT_TYPE u;
2186 struct lys_module **new_mod;
2187
2188 LY_ARRAY_FOR(*mod_array, u) {
2189 if ((*mod_array)[u] == mod) {
2190 /* already there */
2191 return LY_EEXIST;
2192 }
2193 }
2194
2195 /* add the new module ref */
2196 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2197 *new_mod = mod;
2198
2199 return LY_SUCCESS;
2200}
2201
Michal Vasko1ccbf542021-04-19 11:35:00 +02002202/**
2203 * @brief Check whether all modules in a set are implemented.
2204 *
2205 * @param[in] mod_set Module set to check.
2206 * @return Whether all modules are implemented or not.
2207 */
2208static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002209lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002210{
2211 uint32_t i;
2212 const struct lys_module *mod;
2213
2214 for (i = 0; i < mod_set->count; ++i) {
2215 mod = mod_set->objs[i];
2216 if (!mod->implemented) {
2217 return 0;
2218 }
2219 }
2220
2221 return 1;
2222}
2223
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002224LY_ERR
Michal Vasko65333882021-06-10 14:12:16 +02002225lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002226{
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002227 LY_ERR ret = LY_SUCCESS, r;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002228 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko65333882021-06-10 14:12:16 +02002229 struct lysc_ctx ctx = {0};
2230 struct lysp_module *mod_p;
2231 struct lys_module *m;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002232 struct lysp_submodule *submod;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002233 struct lysp_node_augment *aug;
Michal Vaskoc56d6372021-10-19 12:29:00 +02002234 const char **imp_f, *all_f[] = {"*", NULL};
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002235 uint32_t i;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002236 struct ly_set mod_set = {0}, set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002237
Michal Vasko65333882021-06-10 14:12:16 +02002238 mod_p = mod->parsed;
2239
2240 /* prepare context */
2241 ctx.ctx = mod->ctx;
2242 ctx.cur_mod = mod;
2243 ctx.pmod = mod_p;
2244 ctx.path_len = 1;
2245 ctx.path[0] = '/';
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002246
Radek Krejci2a9fc652021-01-22 17:44:34 +01002247 LY_LIST_FOR(mod_p->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002248 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002249 lysc_update_path(&ctx, NULL, "{augment}");
2250 lysc_update_path(&ctx, NULL, aug->nodeid);
2251 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2252 lysc_update_path(&ctx, NULL, NULL);
2253 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002254 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002255
Michal Vasko1ccbf542021-04-19 11:35:00 +02002256 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vasko65333882021-06-10 14:12:16 +02002257 if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002258 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002259 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002260 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002261 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002262 }
2263
2264 LY_ARRAY_FOR(mod_p->deviations, u) {
2265 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002266 lysc_update_path(&ctx, NULL, "{deviation}");
2267 lysc_update_path(&ctx, NULL, mod_p->deviations[u].nodeid);
2268 ret = lys_nodeid_mod_check(&ctx, mod_p->deviations[u].nodeid, 1, &set, NULL, &m);
2269 lysc_update_path(&ctx, NULL, NULL);
2270 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002271 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002272
Michal Vasko1ccbf542021-04-19 11:35:00 +02002273 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vasko65333882021-06-10 14:12:16 +02002274 if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002275 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002276 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
2277 }
2278 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002279 }
2280
2281 /* the same for augments and deviations in submodules */
2282 LY_ARRAY_FOR(mod_p->includes, v) {
2283 submod = mod_p->includes[v].submodule;
Michal Vasko65333882021-06-10 14:12:16 +02002284 ctx.pmod = (struct lysp_module *)submod;
Michal Vaskoce3d6172021-06-08 14:59:49 +02002285
Radek Krejci2a9fc652021-01-22 17:44:34 +01002286 LY_LIST_FOR(submod->augments, aug) {
Michal Vasko65333882021-06-10 14:12:16 +02002287 lysc_update_path(&ctx, NULL, "{augment}");
2288 lysc_update_path(&ctx, NULL, aug->nodeid);
2289 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2290 lysc_update_path(&ctx, NULL, NULL);
2291 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002292 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002293
Michal Vasko65333882021-06-10 14:12:16 +02002294 if ((lys_array_add_mod_ref(&ctx, mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002295 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002296 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002297 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002298 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002299 }
2300
2301 LY_ARRAY_FOR(submod->deviations, u) {
Michal Vasko65333882021-06-10 14:12:16 +02002302 lysc_update_path(&ctx, NULL, "{deviation}");
2303 lysc_update_path(&ctx, NULL, submod->deviations[u].nodeid);
2304 ret = lys_nodeid_mod_check(&ctx, submod->deviations[u].nodeid, 1, &set, NULL, &m);
2305 lysc_update_path(&ctx, NULL, NULL);
2306 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002307 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002308
Michal Vasko65333882021-06-10 14:12:16 +02002309 if ((lys_array_add_mod_ref(&ctx, mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002310 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002311 LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup);
2312 }
2313 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002314 }
2315 }
2316
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002317 for (i = 0; i < mod_set.count; ++i) {
2318 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002319
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002320 if (m == mod) {
2321 /* will be applied normally later */
2322 continue;
2323 }
2324
2325 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2326 * not compiled yet and marked for compilation */
2327
2328 if (!m->implemented) {
2329 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002330 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2331 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002332 if (r == LY_ERECOMPILE) {
2333 /* implement all the modules right away to save possible later recompilation */
2334 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002335 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002336 } else if (r) {
2337 /* error */
2338 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002339 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002340 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002341 } else if (m->compiled) {
2342 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2343 m->to_compile = 1;
2344 ret = LY_ERECOMPILE;
2345 continue;
2346 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002347 }
2348
Michal Vasko1ccbf542021-04-19 11:35:00 +02002349cleanup:
2350 ly_set_erase(&set, NULL);
2351 ly_set_erase(&mod_set, NULL);
2352 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002353}
2354
2355void
2356lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2357{
2358 uint32_t i;
2359 LY_ARRAY_COUNT_TYPE u, count;
2360 struct lys_module *m;
2361
2362 for (i = 0; i < ctx->list.count; ++i) {
2363 m = ctx->list.objs[i];
2364
2365 if (m->augmented_by) {
2366 count = LY_ARRAY_COUNT(m->augmented_by);
2367 for (u = 0; u < count; ++u) {
2368 if (m->augmented_by[u] == mod) {
2369 /* keep the order */
2370 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002371 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002372 }
2373 LY_ARRAY_DECREMENT(m->augmented_by);
2374 break;
2375 }
2376 }
2377 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2378 LY_ARRAY_FREE(m->augmented_by);
2379 m->augmented_by = NULL;
2380 }
2381 }
2382
2383 if (m->deviated_by) {
2384 count = LY_ARRAY_COUNT(m->deviated_by);
2385 for (u = 0; u < count; ++u) {
2386 if (m->deviated_by[u] == mod) {
2387 /* keep the order */
2388 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002389 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002390 }
2391 LY_ARRAY_DECREMENT(m->deviated_by);
2392 break;
2393 }
2394 }
2395 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2396 LY_ARRAY_FREE(m->deviated_by);
2397 m->deviated_by = NULL;
2398 }
2399 }
2400 }
2401}