blob: 2888c4f74b4acdb30bc2e0bcd25b8d8c5a575f95 [file] [log] [blame]
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001/**
2 * @file schema_compile_amend.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema compilation of augments, deviations, and refines.
5 *
6 * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#define _GNU_SOURCE
16
17#include "schema_compile_amend.h"
18
19#include <assert.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020020#include <stddef.h>
21#include <stdint.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020022#include <stdlib.h>
23#include <string.h>
24
25#include "common.h"
Radek Krejci77114102021-03-10 15:21:57 +010026#include "dict.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020027#include "log.h"
Radek Krejci77114102021-03-10 15:21:57 +010028#include "plugins_exts_compile.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020029#include "schema_compile.h"
30#include "schema_compile_node.h"
Michal Vasko29dd11e2020-11-23 16:52:22 +010031#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020032#include "set.h"
33#include "tree.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010034#include "tree_edit.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020035#include "tree_schema.h"
36#include "tree_schema_internal.h"
37#include "xpath.h"
38
39static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
40 size_t nametest_len, const struct lysp_module *mod, const char **name, size_t *name_len);
41
42static LY_ERR
43lys_nodeid_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct lys_module **target_mod,
44 struct lyxp_expr **expr)
45{
46 LY_ERR ret = LY_SUCCESS;
47 struct lyxp_expr *e = NULL;
48 struct lys_module *tmod = NULL, *mod;
49 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
50 uint32_t i;
51
52 /* parse */
53 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
54 if (ret) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010055 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020056 nodeid_type, nodeid);
57 ret = LY_EVALID;
58 goto cleanup;
59 }
60
61 if (abs) {
62 /* absolute schema nodeid */
63 i = 0;
64 } else {
65 /* descendant schema nodeid */
66 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010067 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020068 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
69 ret = LY_EVALID;
70 goto cleanup;
71 }
72 i = 1;
73 }
74
75 /* check all the tokens */
76 for ( ; i < e->used; i += 2) {
77 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010078 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020079 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
80 ret = LY_EVALID;
81 goto cleanup;
82 } else if (e->used == i + 1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010083 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020084 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
85 ret = LY_EVALID;
86 goto cleanup;
87 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010088 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020089 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
90 ret = LY_EVALID;
91 goto cleanup;
92 } else if (abs) {
93 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
94 e->tok_len[i + 1], ctx->pmod, NULL, NULL);
95 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
96
97 /* only keep the first module */
98 if (!tmod) {
99 tmod = mod;
100 }
101
102 /* all the modules must be implemented */
103 if (!mod->implemented) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100104 ret = lys_set_implemented_r(mod, NULL, ctx->unres);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200105 LY_CHECK_GOTO(ret, cleanup);
106 }
107 }
108 }
109
110cleanup:
111 if (ret || !expr) {
112 lyxp_expr_free(ctx->ctx, e);
113 e = NULL;
114 }
115 if (expr) {
116 *expr = ret ? NULL : e;
117 }
118 if (target_mod) {
119 *target_mod = ret ? NULL : tmod;
120 }
121 return ret;
122}
123
124/**
125 * @brief Check whether 2 schema nodeids match.
126 *
127 * @param[in] ctx libyang context.
128 * @param[in] exp1 First schema nodeid.
129 * @param[in] exp1p_mod Module of @p exp1 nodes without any prefix.
130 * @param[in] exp2 Second schema nodeid.
131 * @param[in] exp2_pmod Module of @p exp2 nodes without any prefix.
132 * @return Whether the schema nodeids match or not.
133 */
134static ly_bool
135lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lysp_module *exp1_pmod,
136 const struct lyxp_expr *exp2, const struct lysp_module *exp2_pmod)
137{
138 uint32_t i;
139 const struct lys_module *mod1, *mod2;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100140 const char *name1 = NULL, *name2 = NULL;
141 size_t name1_len = 0, name2_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200142
143 if (exp1->used != exp2->used) {
144 return 0;
145 }
146
147 for (i = 0; i < exp1->used; ++i) {
148 assert(exp1->tokens[i] == exp2->tokens[i]);
149
150 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
151 /* check modules of all the nodes in the node ID */
152 mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_pmod,
153 &name1, &name1_len);
154 assert(mod1);
155 mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_pmod,
156 &name2, &name2_len);
157 assert(mod2);
158
159 /* compare modules */
160 if (mod1 != mod2) {
161 return 0;
162 }
163
164 /* compare names */
165 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
166 return 0;
167 }
168 }
169 }
170
171 return 1;
172}
173
174LY_ERR
175lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
176{
177 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200178 struct lyxp_expr *exp = NULL;
179 struct lysc_augment *aug;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100180 struct lysp_node_augment *aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200181 struct lysc_refine *rfn;
182 struct lysp_refine **new_rfn;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100183 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200184 uint32_t i;
185
Radek Krejci2a9fc652021-01-22 17:44:34 +0100186 LY_LIST_FOR(uses_p->augments, aug_p) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200187 lysc_update_path(ctx, NULL, "{augment}");
Radek Krejci2a9fc652021-01-22 17:44:34 +0100188 lysc_update_path(ctx, NULL, aug_p->nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200189
190 /* parse the nodeid */
Radek Krejci2a9fc652021-01-22 17:44:34 +0100191 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, aug_p->nodeid, 0, NULL, &exp), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200192
193 /* allocate new compiled augment and store it in the set */
194 aug = calloc(1, sizeof *aug);
195 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
196 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
197
198 aug->nodeid = exp;
199 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +0100200 aug->aug_pmod = ctx->pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200201 aug->nodeid_ctx_node = ctx_node;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100202 aug->aug_p = aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200203
204 lysc_update_path(ctx, NULL, NULL);
205 lysc_update_path(ctx, NULL, NULL);
206 }
207
208 LY_ARRAY_FOR(uses_p->refines, u) {
209 lysc_update_path(ctx, NULL, "{refine}");
210 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
211
212 /* parse the nodeid */
213 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->refines[u].nodeid, 0, NULL, &exp), cleanup);
214
215 /* try to find the node in already compiled refines */
216 rfn = NULL;
217 for (i = 0; i < ctx->uses_rfns.count; ++i) {
218 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
219 ctx->pmod)) {
220 rfn = ctx->uses_rfns.objs[i];
221 break;
222 }
223 }
224
225 if (!rfn) {
226 /* allocate new compiled refine */
227 rfn = calloc(1, sizeof *rfn);
228 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
229 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
230
231 rfn->nodeid = exp;
232 exp = NULL;
Michal Vasko7d3708f2021-02-03 10:50:24 +0100233 rfn->nodeid_pmod = ctx->cur_mod->parsed;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200234 rfn->nodeid_ctx_node = ctx_node;
Michal Vaskod8655722021-01-12 15:20:36 +0100235 rfn->uses_p = uses_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200236 } else {
237 /* just free exp */
238 lyxp_expr_free(ctx->ctx, exp);
239 exp = NULL;
240 }
241
242 /* add new parsed refine structure */
243 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
244 *new_rfn = &uses_p->refines[u];
245
246 lysc_update_path(ctx, NULL, NULL);
247 lysc_update_path(ctx, NULL, NULL);
248 }
249
250cleanup:
251 lyxp_expr_free(ctx->ctx, exp);
252 return ret;
253}
254
255static LY_ERR
256lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
257{
258 LY_ERR ret = LY_SUCCESS;
259
260 *ext = *orig_ext;
261 DUP_STRING(ctx, orig_ext->name, ext->name, ret);
262 DUP_STRING(ctx, orig_ext->argument, ext->argument, ret);
263
264 return ret;
265}
266
267static LY_ERR
268lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
269{
270 LY_ERR ret = LY_SUCCESS;
271
272 if (orig_restr) {
273 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
274 restr->arg.mod = orig_restr->arg.mod;
275 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
276 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
277 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
278 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
279 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
280 }
281
282 return ret;
283}
284
285static LY_ERR
286lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
287{
288 LY_ERR ret = LY_SUCCESS;
289
290 DUP_STRING(ctx, *orig_str, *str, ret);
291
292 return ret;
293}
294
295LY_ERR
296lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
297{
298 LY_ERR ret = LY_SUCCESS;
299
300 if (!orig_qname->str) {
301 return LY_SUCCESS;
302 }
303
304 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
305 assert(orig_qname->mod);
306 qname->mod = orig_qname->mod;
307
308 return ret;
309}
310
311static LY_ERR
312lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
313{
314 LY_ERR ret = LY_SUCCESS;
315
316 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
317 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
318 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
319 enm->value = orig_enm->value;
320 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
321 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
322 enm->flags = orig_enm->flags;
323
324 return ret;
325}
326
327static LY_ERR
328lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
329{
330 LY_ERR ret = LY_SUCCESS;
331
332 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
333
334 if (orig_type->range) {
335 type->range = calloc(1, sizeof *type->range);
336 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
337 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
338 }
339
340 if (orig_type->length) {
341 type->length = calloc(1, sizeof *type->length);
342 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
343 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
344 }
345
346 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
347 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
348 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
349 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
350 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
351 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
352 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
353
354 type->pmod = orig_type->pmod;
355 type->compiled = orig_type->compiled;
356
357 type->fraction_digits = orig_type->fraction_digits;
358 type->require_instance = orig_type->require_instance;
359 type->flags = orig_type->flags;
360
361done:
362 return ret;
363}
364
365static LY_ERR
366lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
367{
368 LY_ERR ret = LY_SUCCESS;
369
370 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
371 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
372 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
373 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
374
375 return ret;
376}
377
378static LY_ERR
379lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
380{
381 LY_ERR ret = LY_SUCCESS;
382
383 node->parent = NULL;
384 node->nodetype = orig->nodetype;
385 node->flags = orig->flags;
386 node->next = NULL;
387 DUP_STRING(ctx, orig->name, node->name, ret);
388 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
389 DUP_STRING(ctx, orig->ref, node->ref, ret);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200390 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
391 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
392
393 return ret;
394}
395
Radek Krejci9a3823e2021-01-27 20:26:46 +0100396#define DUP_PWHEN(CTX, ORIG, NEW) \
397 if (ORIG) { \
398 NEW = calloc(1, sizeof *NEW); \
399 LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \
400 LY_CHECK_RET(lysp_when_dup(CTX, NEW, ORIG)); \
401 }
402
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200403static LY_ERR
404lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
405{
406 LY_ERR ret = LY_SUCCESS;
407 struct lysp_node_container *cont;
408 const struct lysp_node_container *orig_cont;
409 struct lysp_node_leaf *leaf;
410 const struct lysp_node_leaf *orig_leaf;
411 struct lysp_node_leaflist *llist;
412 const struct lysp_node_leaflist *orig_llist;
413 struct lysp_node_list *list;
414 const struct lysp_node_list *orig_list;
415 struct lysp_node_choice *choice;
416 const struct lysp_node_choice *orig_choice;
417 struct lysp_node_case *cas;
418 const struct lysp_node_case *orig_cas;
419 struct lysp_node_anydata *any;
420 const struct lysp_node_anydata *orig_any;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100421 struct lysp_node_action *action;
422 const struct lysp_node_action *orig_action;
423 struct lysp_node_action_inout *action_inout;
424 const struct lysp_node_action_inout *orig_action_inout;
425 struct lysp_node_notif *notif;
426 const struct lysp_node_notif *orig_notif;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200427
Radek Krejci2a9fc652021-01-22 17:44:34 +0100428 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA |
429 LYS_RPC | LYS_ACTION | LYS_NOTIF));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200430
431 /* common part */
432 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
433
434 /* specific part */
435 switch (node->nodetype) {
436 case LYS_CONTAINER:
437 cont = (struct lysp_node_container *)node;
438 orig_cont = (const struct lysp_node_container *)orig;
439
Radek Krejci9a3823e2021-01-27 20:26:46 +0100440 DUP_PWHEN(ctx, orig_cont->when, cont->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200441 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
442 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
443 /* we do not need the rest */
444 break;
445 case LYS_LEAF:
446 leaf = (struct lysp_node_leaf *)node;
447 orig_leaf = (const struct lysp_node_leaf *)orig;
448
Radek Krejci9a3823e2021-01-27 20:26:46 +0100449 DUP_PWHEN(ctx, orig_leaf->when, leaf->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200450 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
451 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
452 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
453 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
454 break;
455 case LYS_LEAFLIST:
456 llist = (struct lysp_node_leaflist *)node;
457 orig_llist = (const struct lysp_node_leaflist *)orig;
458
Radek Krejci9a3823e2021-01-27 20:26:46 +0100459 DUP_PWHEN(ctx, orig_llist->when, llist->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200460 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
461 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
462 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
463 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
464 llist->min = orig_llist->min;
465 llist->max = orig_llist->max;
466 break;
467 case LYS_LIST:
468 list = (struct lysp_node_list *)node;
469 orig_list = (const struct lysp_node_list *)orig;
470
Radek Krejci9a3823e2021-01-27 20:26:46 +0100471 DUP_PWHEN(ctx, orig_list->when, list->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200472 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
473 DUP_STRING(ctx, orig_list->key, list->key, ret);
474 /* we do not need these arrays */
475 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
476 list->min = orig_list->min;
477 list->max = orig_list->max;
478 break;
479 case LYS_CHOICE:
480 choice = (struct lysp_node_choice *)node;
481 orig_choice = (const struct lysp_node_choice *)orig;
482
Radek Krejci9a3823e2021-01-27 20:26:46 +0100483 DUP_PWHEN(ctx, orig_choice->when, choice->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200484 /* we do not need children */
485 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
486 break;
487 case LYS_CASE:
488 cas = (struct lysp_node_case *)node;
489 orig_cas = (const struct lysp_node_case *)orig;
490
Radek Krejci9a3823e2021-01-27 20:26:46 +0100491 DUP_PWHEN(ctx, orig_cas->when, cas->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200492 /* we do not need children */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200493 break;
494 case LYS_ANYDATA:
495 case LYS_ANYXML:
496 any = (struct lysp_node_anydata *)node;
497 orig_any = (const struct lysp_node_anydata *)orig;
498
Radek Krejci9a3823e2021-01-27 20:26:46 +0100499 DUP_PWHEN(ctx, orig_any->when, any->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200500 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
501 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100502 case LYS_RPC:
503 case LYS_ACTION:
504 action = (struct lysp_node_action *)node;
505 orig_action = (const struct lysp_node_action *)orig;
506
507 action->input.nodetype = orig_action->input.nodetype;
508 action->output.nodetype = orig_action->output.nodetype;
509 /* we do not need the rest */
510 break;
511 case LYS_INPUT:
512 case LYS_OUTPUT:
513 action_inout = (struct lysp_node_action_inout *)node;
514 orig_action_inout = (const struct lysp_node_action_inout *)orig;
515
516 DUP_ARRAY(ctx, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
517 /* we do not need the rest */
518 break;
519 case LYS_NOTIF:
520 notif = (struct lysp_node_notif *)node;
521 orig_notif = (const struct lysp_node_notif *)orig;
522
523 DUP_ARRAY(ctx, orig_notif->musts, notif->musts, lysp_restr_dup);
524 /* we do not need the rest */
525 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200526 default:
527 LOGINT_RET(ctx);
528 }
529
530 return ret;
531}
532
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200533/**
534 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
535 *
536 * @param[in] ctx libyang context.
537 * @param[in] pnode Node to duplicate.
538 * @param[in] with_links Whether to also copy any links (child, parent pointers).
539 * @param[out] dup_p Duplicated parsed node.
540 * @return LY_ERR value.
541 */
542static LY_ERR
543lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
544{
545 LY_ERR ret = LY_SUCCESS;
546 void *mem = NULL;
547
548 if (!pnode) {
549 *dup_p = NULL;
550 return LY_SUCCESS;
551 }
552
553 switch (pnode->nodetype) {
554 case LYS_CONTAINER:
555 mem = calloc(1, sizeof(struct lysp_node_container));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200556 break;
557 case LYS_LEAF:
558 mem = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200559 break;
560 case LYS_LEAFLIST:
561 mem = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200562 break;
563 case LYS_LIST:
564 mem = calloc(1, sizeof(struct lysp_node_list));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200565 break;
566 case LYS_CHOICE:
567 mem = calloc(1, sizeof(struct lysp_node_choice));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200568 break;
569 case LYS_CASE:
570 mem = calloc(1, sizeof(struct lysp_node_case));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200571 break;
572 case LYS_ANYDATA:
573 case LYS_ANYXML:
574 mem = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200575 break;
576 case LYS_INPUT:
577 case LYS_OUTPUT:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100578 mem = calloc(1, sizeof(struct lysp_node_action_inout));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200579 break;
580 case LYS_ACTION:
581 case LYS_RPC:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100582 mem = calloc(1, sizeof(struct lysp_node_action));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200583 break;
584 case LYS_NOTIF:
Radek Krejci2a9fc652021-01-22 17:44:34 +0100585 mem = calloc(1, sizeof(struct lysp_node_notif));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200586 break;
587 default:
588 LOGINT_RET(ctx);
589 }
Radek Krejci2a9fc652021-01-22 17:44:34 +0100590 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
591 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200592
593 if (with_links) {
594 /* copy also parent and child pointers */
595 ((struct lysp_node *)mem)->parent = pnode->parent;
596 switch (pnode->nodetype) {
597 case LYS_CONTAINER:
598 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
599 break;
600 case LYS_LIST:
601 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
602 break;
603 case LYS_CHOICE:
604 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
605 break;
606 case LYS_CASE:
607 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
608 break;
609 default:
610 break;
611 }
612 }
613
614cleanup:
615 if (ret) {
616 free(mem);
617 } else {
618 *dup_p = mem;
619 }
620 return ret;
621}
622
623#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100624 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 +0200625 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
626 ret = LY_EVALID; \
627 goto cleanup;
628
629#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
630 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100631 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 +0200632 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
633 ret = LY_EVALID; \
634 goto cleanup; \
635 }
636
637/**
638 * @brief Apply refine.
639 *
640 * @param[in] ctx Compile context.
641 * @param[in] rfn Refine to apply.
642 * @param[in,out] target Refine target.
643 * @return LY_ERR value.
644 */
645static LY_ERR
646lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
647{
648 LY_ERR ret = LY_SUCCESS;
649 LY_ARRAY_COUNT_TYPE u;
650 struct lysp_qname *qname;
651 struct lysp_restr **musts, *must;
652 uint32_t *num;
653
654 /* default value */
655 if (rfn->dflts) {
656 switch (target->nodetype) {
657 case LYS_LEAF:
658 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
659
Michal Vaskoe180ed02021-02-05 16:31:20 +0100660 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200661 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &rfn->dflts[0]), cleanup);
662 break;
663 case LYS_LEAFLIST:
664 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100665 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200666 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
667 ret = LY_EVALID;
668 goto cleanup;
669 }
670
671 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
672 ((struct lysp_node_leaflist *)target)->dflts = NULL;
673 LY_ARRAY_FOR(rfn->dflts, u) {
674 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
675 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup);
676 }
677 break;
678 case LYS_CHOICE:
679 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
680
Michal Vaskoe180ed02021-02-05 16:31:20 +0100681 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200682 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &rfn->dflts[0]), cleanup);
683 break;
684 default:
685 AMEND_WRONG_NODETYPE("refine", "replace", "default");
686 }
687 }
688
689 /* description */
690 if (rfn->dsc) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100691 lydict_remove(ctx->ctx, target->dsc);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200692 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
693 }
694
695 /* reference */
696 if (rfn->ref) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100697 lydict_remove(ctx->ctx, target->ref);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200698 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
699 }
700
701 /* config */
702 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci91531e12021-02-08 19:57:54 +0100703 if (ctx->options & LYS_COMPILE_NO_CONFIG) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200704 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Radek Krejci91531e12021-02-08 19:57:54 +0100705 (ctx->options & (LYS_IS_INPUT | LYS_IS_OUTPUT)) ? "RPC/action" :
706 ctx->options & LYS_IS_NOTIF ? "notification" : "a subtree ignoring config", ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200707 } else {
708 target->flags &= ~LYS_CONFIG_MASK;
709 target->flags |= rfn->flags & LYS_CONFIG_MASK;
710 }
711 }
712
713 /* mandatory */
714 if (rfn->flags & LYS_MAND_MASK) {
715 switch (target->nodetype) {
716 case LYS_LEAF:
717 case LYS_CHOICE:
718 case LYS_ANYDATA:
719 case LYS_ANYXML:
720 break;
721 default:
722 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
723 }
724
725 target->flags &= ~LYS_MAND_MASK;
726 target->flags |= rfn->flags & LYS_MAND_MASK;
727 }
728
729 /* presence */
730 if (rfn->presence) {
731 switch (target->nodetype) {
732 case LYS_CONTAINER:
733 break;
734 default:
735 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
736 }
737
Michal Vaskoe180ed02021-02-05 16:31:20 +0100738 lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200739 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
740 }
741
742 /* must */
743 if (rfn->musts) {
744 switch (target->nodetype) {
745 case LYS_CONTAINER:
746 case LYS_LIST:
747 case LYS_LEAF:
748 case LYS_LEAFLIST:
749 case LYS_ANYDATA:
750 case LYS_ANYXML:
751 musts = &((struct lysp_node_container *)target)->musts;
752 break;
753 default:
754 AMEND_WRONG_NODETYPE("refine", "add", "must");
755 }
756
757 LY_ARRAY_FOR(rfn->musts, u) {
758 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
759 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
760 }
761 }
762
763 /* min-elements */
764 if (rfn->flags & LYS_SET_MIN) {
765 switch (target->nodetype) {
766 case LYS_LEAFLIST:
767 num = &((struct lysp_node_leaflist *)target)->min;
768 break;
769 case LYS_LIST:
770 num = &((struct lysp_node_list *)target)->min;
771 break;
772 default:
773 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
774 }
775
776 *num = rfn->min;
777 }
778
779 /* max-elements */
780 if (rfn->flags & LYS_SET_MAX) {
781 switch (target->nodetype) {
782 case LYS_LEAFLIST:
783 num = &((struct lysp_node_leaflist *)target)->max;
784 break;
785 case LYS_LIST:
786 num = &((struct lysp_node_list *)target)->max;
787 break;
788 default:
789 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
790 }
791
792 *num = rfn->max;
793 }
794
795 /* if-feature */
796 if (rfn->iffeatures) {
797 switch (target->nodetype) {
798 case LYS_LEAF:
799 case LYS_LEAFLIST:
800 case LYS_LIST:
801 case LYS_CONTAINER:
802 case LYS_CHOICE:
803 case LYS_CASE:
804 case LYS_ANYDATA:
805 case LYS_ANYXML:
806 break;
807 default:
808 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
809 }
810
811 LY_ARRAY_FOR(rfn->iffeatures, u) {
812 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
813 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup);
814 }
815 }
816
817 /* extension */
818 /* TODO refine extensions */
819
820cleanup:
821 return ret;
822}
823
824/**
825 * @brief Apply deviate add.
826 *
827 * @param[in] ctx Compile context.
828 * @param[in] d Deviate add to apply.
829 * @param[in,out] target Deviation target.
830 * @return LY_ERR value.
831 */
832static LY_ERR
833lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
834{
835 LY_ERR ret = LY_SUCCESS;
836 LY_ARRAY_COUNT_TYPE u;
837 struct lysp_qname *qname;
838 uint32_t *num;
839 struct lysp_restr **musts, *must;
840
841#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
842 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100843 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200844 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
845 ret = LY_EVALID; \
846 goto cleanup; \
847 }
848
849 /* [units-stmt] */
850 if (d->units) {
851 switch (target->nodetype) {
852 case LYS_LEAF:
853 case LYS_LEAFLIST:
854 break;
855 default:
856 AMEND_WRONG_NODETYPE("deviation", "add", "units");
857 }
858
859 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
860 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
861 }
862
863 /* *must-stmt */
864 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100865 musts = lysp_node_musts_p(target);
866 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200867 AMEND_WRONG_NODETYPE("deviation", "add", "must");
868 }
869
870 LY_ARRAY_FOR(d->musts, u) {
871 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
872 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
873 }
874 }
875
876 /* *unique-stmt */
877 if (d->uniques) {
878 switch (target->nodetype) {
879 case LYS_LIST:
880 break;
881 default:
882 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
883 }
884
885 LY_ARRAY_FOR(d->uniques, u) {
886 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
887 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup);
888 }
889 }
890
891 /* *default-stmt */
892 if (d->dflts) {
893 switch (target->nodetype) {
894 case LYS_LEAF:
895 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
896 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
897
898 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflts[0]), cleanup);
899 break;
900 case LYS_LEAFLIST:
901 LY_ARRAY_FOR(d->dflts, u) {
902 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
903 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup);
904 }
905 break;
906 case LYS_CHOICE:
907 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
908 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
909
910 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflts[0]), cleanup);
911 break;
912 default:
913 AMEND_WRONG_NODETYPE("deviation", "add", "default");
914 }
915 }
916
917 /* [config-stmt] */
918 if (d->flags & LYS_CONFIG_MASK) {
919 switch (target->nodetype) {
920 case LYS_CONTAINER:
921 case LYS_LEAF:
922 case LYS_LEAFLIST:
923 case LYS_LIST:
924 case LYS_CHOICE:
925 case LYS_ANYDATA:
926 case LYS_ANYXML:
927 break;
928 default:
929 AMEND_WRONG_NODETYPE("deviation", "add", "config");
930 }
931
932 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100933 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200934 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
935 target->flags & LYS_CONFIG_W ? "true" : "false");
936 ret = LY_EVALID;
937 goto cleanup;
938 }
939
940 target->flags |= d->flags & LYS_CONFIG_MASK;
941 }
942
943 /* [mandatory-stmt] */
944 if (d->flags & LYS_MAND_MASK) {
945 switch (target->nodetype) {
946 case LYS_LEAF:
947 case LYS_CHOICE:
948 case LYS_ANYDATA:
949 case LYS_ANYXML:
950 break;
951 default:
952 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
953 }
954
955 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100956 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200957 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
958 target->flags & LYS_MAND_TRUE ? "true" : "false");
959 ret = LY_EVALID;
960 goto cleanup;
961 }
962
963 target->flags |= d->flags & LYS_MAND_MASK;
964 }
965
966 /* [min-elements-stmt] */
967 if (d->flags & LYS_SET_MIN) {
968 switch (target->nodetype) {
969 case LYS_LEAFLIST:
970 num = &((struct lysp_node_leaflist *)target)->min;
971 break;
972 case LYS_LIST:
973 num = &((struct lysp_node_list *)target)->min;
974 break;
975 default:
976 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
977 }
978
979 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100980 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200981 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
982 ret = LY_EVALID;
983 goto cleanup;
984 }
985
986 *num = d->min;
987 }
988
989 /* [max-elements-stmt] */
990 if (d->flags & LYS_SET_MAX) {
991 switch (target->nodetype) {
992 case LYS_LEAFLIST:
993 num = &((struct lysp_node_leaflist *)target)->max;
994 break;
995 case LYS_LIST:
996 num = &((struct lysp_node_list *)target)->max;
997 break;
998 default:
999 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1000 }
1001
1002 if (target->flags & LYS_SET_MAX) {
1003 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001004 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001005 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1006 *num);
1007 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001008 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001009 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1010 }
1011 ret = LY_EVALID;
1012 goto cleanup;
1013 }
1014
1015 *num = d->max;
1016 }
1017
1018cleanup:
1019 return ret;
1020}
1021
1022/**
1023 * @brief Apply deviate delete.
1024 *
1025 * @param[in] ctx Compile context.
1026 * @param[in] d Deviate delete to apply.
1027 * @param[in,out] target Deviation target.
1028 * @return LY_ERR value.
1029 */
1030static LY_ERR
1031lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1032{
1033 LY_ERR ret = LY_SUCCESS;
1034 struct lysp_restr **musts;
1035 LY_ARRAY_COUNT_TYPE u, v;
1036 struct lysp_qname **uniques, **dflts;
1037
1038#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
1039 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1040 int found = 0; \
1041 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1042 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1043 found = 1; \
1044 break; \
1045 } \
1046 } \
1047 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001048 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001049 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1050 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1051 ret = LY_EVALID; \
1052 goto cleanup; \
1053 } \
1054 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
1055 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
1056 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1057 } \
1058 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1059 LY_ARRAY_FREE(ORIG_ARRAY); \
1060 ORIG_ARRAY = NULL; \
1061 }
1062
1063#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1064 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001065 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001066 ret = LY_EVALID; \
1067 goto cleanup; \
1068 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001069 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001070 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1071 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1072 ret = LY_EVALID; \
1073 goto cleanup; \
1074 }
1075
1076 /* [units-stmt] */
1077 if (d->units) {
1078 switch (target->nodetype) {
1079 case LYS_LEAF:
1080 case LYS_LEAFLIST:
1081 break;
1082 default:
1083 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1084 }
1085
1086 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001087 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001088 ((struct lysp_node_leaf *)target)->units = NULL;
1089 }
1090
1091 /* *must-stmt */
1092 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001093 musts = lysp_node_musts_p(target);
1094 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001095 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1096 }
1097
1098 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
1099 }
1100
1101 /* *unique-stmt */
1102 if (d->uniques) {
1103 switch (target->nodetype) {
1104 case LYS_LIST:
1105 break;
1106 default:
1107 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1108 }
1109
1110 uniques = &((struct lysp_node_list *)target)->uniques;
1111 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, "unique");
1112 }
1113
1114 /* *default-stmt */
1115 if (d->dflts) {
1116 switch (target->nodetype) {
1117 case LYS_LEAF:
1118 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1119 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1120
Michal Vaskoe180ed02021-02-05 16:31:20 +01001121 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001122 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1123 break;
1124 case LYS_LEAFLIST:
1125 dflts = &((struct lysp_node_leaflist *)target)->dflts;
1126 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, "default");
1127 break;
1128 case LYS_CHOICE:
1129 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1130 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1131
Michal Vaskoe180ed02021-02-05 16:31:20 +01001132 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001133 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1134 break;
1135 default:
1136 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1137 }
1138 }
1139
1140cleanup:
1141 return ret;
1142}
1143
1144/**
1145 * @brief Apply deviate replace.
1146 *
1147 * @param[in] ctx Compile context.
1148 * @param[in] d Deviate replace to apply.
1149 * @param[in,out] target Deviation target.
1150 * @return LY_ERR value.
1151 */
1152static LY_ERR
1153lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1154{
1155 LY_ERR ret = LY_SUCCESS;
1156 uint32_t *num;
1157
1158#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1159 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001160 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001161 ret = LY_EVALID; \
1162 goto cleanup; \
1163 }
1164
1165 /* [type-stmt] */
1166 if (d->type) {
1167 switch (target->nodetype) {
1168 case LYS_LEAF:
1169 case LYS_LEAFLIST:
1170 break;
1171 default:
1172 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1173 }
1174
1175 lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
1176 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
1177 }
1178
1179 /* [units-stmt] */
1180 if (d->units) {
1181 switch (target->nodetype) {
1182 case LYS_LEAF:
1183 case LYS_LEAFLIST:
1184 break;
1185 default:
1186 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1187 }
1188
1189 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001190 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001191 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1192 }
1193
1194 /* [default-stmt] */
1195 if (d->dflt.str) {
1196 switch (target->nodetype) {
1197 case LYS_LEAF:
1198 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1199
Michal Vaskoe180ed02021-02-05 16:31:20 +01001200 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001201 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflt), cleanup);
1202 break;
1203 case LYS_CHOICE:
1204 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
1205
Michal Vaskoe180ed02021-02-05 16:31:20 +01001206 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001207 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflt), cleanup);
1208 break;
1209 default:
1210 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1211 }
1212 }
1213
1214 /* [config-stmt] */
1215 if (d->flags & LYS_CONFIG_MASK) {
1216 switch (target->nodetype) {
1217 case LYS_CONTAINER:
1218 case LYS_LEAF:
1219 case LYS_LEAFLIST:
1220 case LYS_LIST:
1221 case LYS_CHOICE:
1222 case LYS_ANYDATA:
1223 case LYS_ANYXML:
1224 break;
1225 default:
1226 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1227 }
1228
1229 if (!(target->flags & LYS_CONFIG_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001230 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "config",
1231 d->flags & LYS_CONFIG_W ? "config true" : "config false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001232 ret = LY_EVALID;
1233 goto cleanup;
1234 }
1235
1236 target->flags &= ~LYS_CONFIG_MASK;
1237 target->flags |= d->flags & LYS_CONFIG_MASK;
1238 }
1239
1240 /* [mandatory-stmt] */
1241 if (d->flags & LYS_MAND_MASK) {
1242 switch (target->nodetype) {
1243 case LYS_LEAF:
1244 case LYS_CHOICE:
1245 case LYS_ANYDATA:
1246 case LYS_ANYXML:
1247 break;
1248 default:
1249 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1250 }
1251
1252 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001253 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1254 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001255 ret = LY_EVALID;
1256 goto cleanup;
1257 }
1258
1259 target->flags &= ~LYS_MAND_MASK;
1260 target->flags |= d->flags & LYS_MAND_MASK;
1261 }
1262
1263 /* [min-elements-stmt] */
1264 if (d->flags & LYS_SET_MIN) {
1265 switch (target->nodetype) {
1266 case LYS_LEAFLIST:
1267 num = &((struct lysp_node_leaflist *)target)->min;
1268 break;
1269 case LYS_LIST:
1270 num = &((struct lysp_node_list *)target)->min;
1271 break;
1272 default:
1273 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1274 }
1275
1276 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001277 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001278 ret = LY_EVALID;
1279 goto cleanup;
1280 }
1281
1282 *num = d->min;
1283 }
1284
1285 /* [max-elements-stmt] */
1286 if (d->flags & LYS_SET_MAX) {
1287 switch (target->nodetype) {
1288 case LYS_LEAFLIST:
1289 num = &((struct lysp_node_leaflist *)target)->max;
1290 break;
1291 case LYS_LIST:
1292 num = &((struct lysp_node_list *)target)->max;
1293 break;
1294 default:
1295 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1296 }
1297
1298 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001299 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001300 ret = LY_EVALID;
1301 goto cleanup;
1302 }
1303
1304 *num = d->max;
1305 }
1306
1307cleanup:
1308 return ret;
1309}
1310
1311/**
1312 * @brief Get module of a single nodeid node name test.
1313 *
1314 * @param[in] ctx libyang context.
1315 * @param[in] nametest Nametest with an optional prefix.
1316 * @param[in] nametest_len Length of @p nametest.
1317 * @param[in] mod Both current and prefix module for resolving prefixes and to return in case of no prefix.
1318 * @param[out] name Optional pointer to the name test without the prefix.
1319 * @param[out] name_len Length of @p name.
1320 * @return Resolved module.
1321 */
1322static const struct lys_module *
1323lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
1324 const struct lysp_module *mod, const char **name, size_t *name_len)
1325{
1326 const struct lys_module *target_mod;
1327 const char *ptr;
1328
1329 ptr = ly_strnchr(nametest, ':', nametest_len);
1330 if (ptr) {
1331 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_PREF_SCHEMA, (void *)mod);
1332 if (!target_mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001333 LOGVAL(ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001334 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001335 (int)nametest_len, nametest, (int)(ptr - nametest), nametest, LYSP_MODULE_NAME(mod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001336 return NULL;
1337 }
1338
1339 if (name) {
1340 *name = ptr + 1;
1341 *name_len = nametest_len - ((ptr - nametest) + 1);
1342 }
1343 } else {
1344 target_mod = mod->mod;
1345 if (name) {
1346 *name = nametest;
1347 *name_len = nametest_len;
1348 }
1349 }
1350
1351 return target_mod;
1352}
1353
1354/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001355 * @brief Check whether a compiled node matches a single schema nodeid name test.
1356 *
1357 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1358 * @param[in] mod Expected module.
1359 * @param[in] name Expected name.
1360 * @param[in] name_len Length of @p name.
1361 * @return Whether it is a match or not.
1362 */
1363static ly_bool
1364lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1365 size_t name_len)
1366{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001367 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001368 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001369 return 0;
1370 }
1371
1372 /* compare names */
Michal Vasko544e58a2021-01-28 14:33:41 +01001373 if (ly_strncmp((*node)->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001374 return 0;
1375 }
1376
Michal Vasko2a668712020-10-21 11:48:09 +02001377 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001378 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001379
1380 return 1;
1381}
1382
1383/**
1384 * @brief Check whether a node matches specific schema nodeid.
1385 *
1386 * @param[in] exp Parsed nodeid to match.
1387 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
1388 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1389 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1390 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1391 * @param[in] pnode_mod Compiled @p pnode to-be module.
1392 * @return Whether it is a match or not.
1393 */
1394static ly_bool
1395lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node,
1396 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
1397{
1398 uint32_t i;
1399 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001400 const char *name = NULL;
1401 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001402
1403 /* compare last node in the node ID */
1404 i = exp->used - 1;
1405
1406 /* get exp node ID module */
1407 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);
1408 assert(mod);
1409
1410 if (pnode) {
1411 /* compare on the last parsed-only node */
Radek Krejci2d5f6df2021-01-28 14:00:13 +01001412 if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001413 return 0;
1414 }
1415 } else {
1416 /* using parent directly */
1417 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1418 return 0;
1419 }
1420 }
1421
1422 /* now compare all the compiled parents */
1423 while (i > 1) {
1424 i -= 2;
1425 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1426
1427 if (!parent) {
1428 /* no more parents but path continues */
1429 return 0;
1430 }
1431
1432 /* get exp node ID module */
1433 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1434 &name_len);
1435 assert(mod);
1436
1437 /* compare with the parent */
1438 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1439 return 0;
1440 }
1441 }
1442
1443 if (ctx_node && (ctx_node != parent)) {
1444 /* descendant path has not finished in the context node */
1445 return 0;
1446 } else if (!ctx_node && parent) {
1447 /* some parent was not matched */
1448 return 0;
1449 }
1450
1451 return 1;
1452}
1453
1454void
1455lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1456{
1457 if (aug) {
1458 lyxp_expr_free(ctx, aug->nodeid);
1459
1460 free(aug);
1461 }
1462}
1463
1464void
1465lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1466{
1467 if (dev) {
1468 lyxp_expr_free(ctx, dev->nodeid);
1469 LY_ARRAY_FREE(dev->devs);
1470 LY_ARRAY_FREE(dev->dev_pmods);
1471
1472 free(dev);
1473 }
1474}
1475
1476void
1477lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1478{
1479 if (rfn) {
1480 lyxp_expr_free(ctx, rfn->nodeid);
1481 LY_ARRAY_FREE(rfn->rfns);
1482
1483 free(rfn);
1484 }
1485}
1486
1487void
1488lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
1489{
1490 if (!dev_pnode) {
1491 return;
1492 }
1493
1494 switch (dev_pnode->nodetype) {
1495 case LYS_CONTAINER:
1496 ((struct lysp_node_container *)dev_pnode)->child = NULL;
1497 break;
1498 case LYS_LIST:
1499 ((struct lysp_node_list *)dev_pnode)->child = NULL;
1500 break;
1501 case LYS_CHOICE:
1502 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1503 break;
1504 case LYS_CASE:
1505 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1506 break;
1507 case LYS_LEAF:
1508 case LYS_LEAFLIST:
1509 case LYS_ANYXML:
1510 case LYS_ANYDATA:
1511 /* no children */
1512 break;
1513 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001514 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001515 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001516 case LYS_RPC:
1517 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001518 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1519 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001520 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001521 case LYS_INPUT:
1522 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001523 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001524 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001525 free(dev_pnode);
1526 return;
1527 default:
1528 LOGINT(ctx);
1529 return;
1530 }
1531
1532 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
1533}
1534
1535LY_ERR
1536lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1537 struct lysp_node **dev_pnode, ly_bool *not_supported)
1538{
1539 LY_ERR ret = LY_SUCCESS;
1540 uint32_t i;
1541 LY_ARRAY_COUNT_TYPE u;
1542 struct lys_module *orig_mod = ctx->cur_mod;
1543 struct lysp_module *orig_pmod = ctx->pmod;
1544 char orig_path[LYSC_CTX_BUFSIZE];
1545 struct lysc_refine *rfn;
1546 struct lysc_deviation *dev;
1547 struct lysp_deviation *dev_p;
1548 struct lysp_deviate *d;
1549
1550 *dev_pnode = NULL;
1551 *not_supported = 0;
1552
1553 for (i = 0; i < ctx->uses_rfns.count; ++i) {
1554 rfn = ctx->uses_rfns.objs[i];
1555
Michal Vasko28fe5f62021-03-03 16:37:39 +01001556 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 +02001557 /* not our target node */
1558 continue;
1559 }
1560
1561 if (!*dev_pnode) {
1562 /* first refine on this node, create a copy first */
1563 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1564 }
1565
Michal Vaskob8df5762021-01-12 15:15:53 +01001566 /* use modules from the refine */
1567 ctx->cur_mod = rfn->nodeid_pmod->mod;
1568 ctx->pmod = (struct lysp_module *)rfn->nodeid_pmod;
1569
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001570 /* apply all the refines by changing (the copy of) the parsed node */
1571 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vaskob8df5762021-01-12 15:15:53 +01001572 /* keep the current path and add to it */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001573 lysc_update_path(ctx, NULL, "{refine}");
1574 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001575
1576 /* apply refine and restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001577 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
1578 lysc_update_path(ctx, NULL, NULL);
1579 lysc_update_path(ctx, NULL, NULL);
1580 LY_CHECK_GOTO(ret, cleanup);
1581 }
1582
1583 /* refine was applied, remove it */
1584 lysc_refine_free(ctx->ctx, rfn);
1585 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1586
1587 /* all the refines for one target node are in one structure, we are done */
1588 break;
1589 }
1590
1591 for (i = 0; i < ctx->devs.count; ++i) {
1592 dev = ctx->devs.objs[i];
1593
Michal Vasko28fe5f62021-03-03 16:37:39 +01001594 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, orig_mod)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001595 /* not our target node */
1596 continue;
1597 }
1598
1599 if (dev->not_supported) {
1600 /* it is not supported, no more deviations */
1601 *not_supported = 1;
1602 goto dev_applied;
1603 }
1604
1605 if (!*dev_pnode) {
1606 /* first deviation on this node, create a copy first */
1607 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1608 }
1609
1610 /* apply all the deviates by changing (the copy of) the parsed node */
1611 LY_ARRAY_FOR(dev->devs, u) {
1612 dev_p = dev->devs[u];
1613 LY_LIST_FOR(dev_p->deviates, d) {
1614 /* generate correct path */
1615 strcpy(orig_path, ctx->path);
1616 ctx->path_len = 1;
1617 ctx->cur_mod = dev->dev_pmods[u]->mod;
1618 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
1619 lysc_update_path(ctx, NULL, "{deviation}");
1620 lysc_update_path(ctx, NULL, dev_p->nodeid);
1621
1622 switch (d->mod) {
1623 case LYS_DEV_ADD:
1624 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
1625 break;
1626 case LYS_DEV_DELETE:
1627 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
1628 break;
1629 case LYS_DEV_REPLACE:
1630 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
1631 break;
1632 default:
1633 LOGINT(ctx->ctx);
1634 ret = LY_EINT;
1635 }
1636
1637 /* restore previous path */
1638 strcpy(ctx->path, orig_path);
1639 ctx->path_len = strlen(ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001640
1641 LY_CHECK_GOTO(ret, cleanup);
1642 }
1643 }
1644
1645dev_applied:
1646 /* deviation was applied, remove it */
1647 lysc_deviation_free(ctx->ctx, dev);
1648 ly_set_rm_index(&ctx->devs, i, NULL);
1649
1650 /* all the deviations for one target node are in one structure, we are done */
1651 break;
1652 }
1653
1654cleanup:
Michal Vasko20316b32021-01-12 15:16:54 +01001655 ctx->cur_mod = orig_mod;
1656 ctx->pmod = orig_pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001657 if (ret) {
1658 lysp_dev_node_free(ctx->ctx, *dev_pnode);
1659 *dev_pnode = NULL;
1660 *not_supported = 0;
1661 }
1662 return ret;
1663}
1664
1665/**
1666 * @brief Compile the parsed augment connecting it into its target.
1667 *
1668 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1669 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1670 * are already implemented and compiled.
1671 *
1672 * @param[in] ctx Compile context.
1673 * @param[in] aug_p Parsed augment to compile.
1674 * @param[in] target Target node of the augment.
1675 * @return LY_SUCCESS on success.
1676 * @return LY_EVALID on failure.
1677 */
1678static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001679lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001680{
1681 LY_ERR ret = LY_SUCCESS;
1682 struct lysp_node *pnode;
1683 struct lysc_node *node;
1684 struct lysc_when *when_shared = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001685 struct lysc_node_action **actions;
1686 struct lysc_node_notif **notifs;
Michal Vasko29dd11e2020-11-23 16:52:22 +01001687 ly_bool allow_mandatory = 0, enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001688 struct ly_set child_set = {0};
Michal Vasko29dd11e2020-11-23 16:52:22 +01001689 uint32_t i, opt_prev = ctx->options;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001690
1691 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001692 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001693 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
1694 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
1695 ret = LY_EVALID;
1696 goto cleanup;
1697 }
1698
1699 /* check for mandatory nodes
1700 * - new cases augmenting some choice can have mandatory nodes
1701 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1702 */
1703 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
1704 allow_mandatory = 1;
1705 }
1706
1707 LY_LIST_FOR(aug_p->child, pnode) {
1708 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1709 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1710 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1711 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001712 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001713 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1714 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1715 ret = LY_EVALID;
1716 goto cleanup;
1717 }
1718
1719 /* compile the children */
1720 if (target->nodetype == LYS_CHOICE) {
1721 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
Michal Vasko6fb4c042020-11-24 18:05:26 +01001722 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1723 if (target->nodetype == LYS_INPUT) {
1724 ctx->options |= LYS_COMPILE_RPC_INPUT;
1725 } else {
1726 ctx->options |= LYS_COMPILE_RPC_OUTPUT;
1727 }
Radek Krejci2a9fc652021-01-22 17:44:34 +01001728 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001729 } else {
1730 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1731 }
1732
Michal Vasko29dd11e2020-11-23 16:52:22 +01001733 /* eval if-features again for the rest of this node processing */
1734 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1735 if (!enabled) {
1736 ctx->options |= LYS_COMPILE_DISABLED;
1737 }
1738
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001739 /* since the augment node is not present in the compiled tree, we need to pass some of its
1740 * statements to all its children */
1741 for (i = 0; i < child_set.count; ++i) {
1742 node = child_set.snodes[i];
1743 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1744 node->flags &= ~LYS_MAND_TRUE;
1745 lys_compile_mandatory_parents(target, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001746 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001747 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
1748 ret = LY_EVALID;
1749 goto cleanup;
1750 }
1751
1752 if (aug_p->when) {
1753 /* pass augment's when to all the children */
Michal Vasko72244882021-01-12 15:21:05 +01001754 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_data_node(target), node, &when_shared);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001755 LY_CHECK_GOTO(ret, cleanup);
1756 }
1757 }
1758 ly_set_erase(&child_set, NULL);
Michal Vasko29dd11e2020-11-23 16:52:22 +01001759
1760 /* restore options */
1761 ctx->options = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001762 }
1763
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001764 actions = lysc_node_actions_p(target);
1765 notifs = lysc_node_notifs_p(target);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001766
1767 if (aug_p->actions) {
1768 if (!actions) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001769 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001770 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
Radek Krejci2a9fc652021-01-22 17:44:34 +01001771 lys_nodetype2str(target->nodetype), aug_p->actions->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001772 ret = LY_EVALID;
1773 goto cleanup;
1774 }
1775
1776 /* compile actions into the target */
Radek Krejci2a9fc652021-01-22 17:44:34 +01001777 LY_LIST_FOR((struct lysp_node *)aug_p->actions, pnode) {
Michal Vasko012807e2021-02-03 09:52:18 +01001778 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001779
Michal Vasko012807e2021-02-03 09:52:18 +01001780 /* eval if-features again for the rest of this node processing */
1781 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1782 if (!enabled) {
1783 ctx->options |= LYS_COMPILE_DISABLED;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001784 }
Michal Vasko012807e2021-02-03 09:52:18 +01001785
1786 /* since the augment node is not present in the compiled tree, we need to pass some of its
1787 * statements to all its children */
1788 for (i = 0; i < child_set.count; ++i) {
1789 node = child_set.snodes[i];
1790 if (aug_p->when) {
1791 /* pass augment's when to all the actions */
1792 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_data_node(target), node, &when_shared);
1793 LY_CHECK_GOTO(ret, cleanup);
1794 }
1795 }
1796 ly_set_erase(&child_set, NULL);
1797
1798 /* restore options */
1799 ctx->options = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001800 }
1801 }
1802 if (aug_p->notifs) {
1803 if (!notifs) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001804 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001805 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
Radek Krejci2a9fc652021-01-22 17:44:34 +01001806 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001807 ret = LY_EVALID;
1808 goto cleanup;
1809 }
1810
1811 /* compile notifications into the target */
Radek Krejci2a9fc652021-01-22 17:44:34 +01001812 LY_LIST_FOR((struct lysp_node *)aug_p->notifs, pnode) {
Michal Vasko012807e2021-02-03 09:52:18 +01001813 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001814
Michal Vasko012807e2021-02-03 09:52:18 +01001815 /* eval if-features again for the rest of this node processing */
1816 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1817 if (!enabled) {
1818 ctx->options |= LYS_COMPILE_DISABLED;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001819 }
Michal Vasko012807e2021-02-03 09:52:18 +01001820
1821 /* since the augment node is not present in the compiled tree, we need to pass some of its
1822 * statements to all its children */
1823 for (i = 0; i < child_set.count; ++i) {
1824 node = child_set.snodes[i];
1825 if (aug_p->when) {
1826 /* pass augment's when to all the actions */
1827 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_data_node(target), node, &when_shared);
1828 LY_CHECK_GOTO(ret, cleanup);
1829 }
1830 }
1831 ly_set_erase(&child_set, NULL);
1832
1833 /* restore options */
1834 ctx->options = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001835 }
1836 }
1837
1838cleanup:
1839 ly_set_erase(&child_set, NULL);
Michal Vasko29dd11e2020-11-23 16:52:22 +01001840 ctx->options = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001841 return ret;
1842}
1843
1844LY_ERR
1845lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
1846{
1847 LY_ERR ret = LY_SUCCESS;
1848 struct lys_module *orig_mod = ctx->cur_mod;
1849 struct lysp_module *orig_pmod = ctx->pmod;
1850 uint32_t i;
1851 char orig_path[LYSC_CTX_BUFSIZE];
1852 struct lysc_augment *aug;
1853
1854 /* uses augments */
1855 for (i = 0; i < ctx->uses_augs.count; ) {
1856 aug = ctx->uses_augs.objs[i];
1857
Michal Vasko28fe5f62021-03-03 16:37:39 +01001858 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->nodeid_ctx_node, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001859 /* not our target node */
1860 ++i;
1861 continue;
1862 }
1863
Michal Vaskob8df5762021-01-12 15:15:53 +01001864 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001865 lysc_update_path(ctx, NULL, "{augment}");
1866 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01001867 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01001868
1869 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001870 ret = lys_compile_augment(ctx, aug->aug_p, node);
1871 lysc_update_path(ctx, NULL, NULL);
1872 lysc_update_path(ctx, NULL, NULL);
1873 LY_CHECK_GOTO(ret, cleanup);
1874
1875 /* augment was applied, remove it (index may have changed because other augments could have been applied) */
1876 ly_set_rm(&ctx->uses_augs, aug, NULL);
1877 lysc_augment_free(ctx->ctx, aug);
1878 }
1879
1880 /* top-level augments */
1881 for (i = 0; i < ctx->augs.count; ) {
1882 aug = ctx->augs.objs[i];
1883
Michal Vasko28fe5f62021-03-03 16:37:39 +01001884 if (!lysp_schema_nodeid_match(aug->nodeid, aug->aug_pmod, NULL, node, NULL, NULL)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001885 /* not our target node */
1886 ++i;
1887 continue;
1888 }
1889
Michal Vaskob8df5762021-01-12 15:15:53 +01001890 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001891 strcpy(orig_path, ctx->path);
1892 ctx->path_len = 1;
1893 lysc_update_path(ctx, NULL, "{augment}");
1894 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01001895 ctx->cur_mod = aug->aug_pmod->mod;
1896 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01001897
1898 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001899 ret = lys_compile_augment(ctx, aug->aug_p, node);
1900 strcpy(ctx->path, orig_path);
1901 ctx->path_len = strlen(ctx->path);
1902 LY_CHECK_GOTO(ret, cleanup);
1903
1904 /* augment was applied, remove it */
1905 ly_set_rm(&ctx->augs, aug, NULL);
1906 lysc_augment_free(ctx->ctx, aug);
1907 }
1908
1909cleanup:
1910 ctx->cur_mod = orig_mod;
1911 ctx->pmod = orig_pmod;
1912 return ret;
1913}
1914
1915/**
1916 * @brief Prepare a top-level augment to be applied during data nodes compilation.
1917 *
1918 * @param[in] ctx Compile context.
1919 * @param[in] aug_p Parsed augment to be applied.
1920 * @param[in] pmod Both current and prefix module for @p aug_p.
1921 * @return LY_ERR value.
1922 */
1923static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01001924lys_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 +02001925{
1926 LY_ERR ret = LY_SUCCESS;
1927 struct lyxp_expr *exp = NULL;
1928 struct lysc_augment *aug;
1929 const struct lys_module *mod;
1930
1931 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
1932 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
1933 LY_CHECK_GOTO(ret, cleanup);
1934
1935 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
1936 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
1937 if (mod != ctx->cur_mod) {
1938 /* augment for another module, ignore */
1939 goto cleanup;
1940 }
1941
1942 /* allocate new compiled augment and store it in the set */
1943 aug = calloc(1, sizeof *aug);
1944 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
1945 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
1946
1947 aug->nodeid = exp;
1948 exp = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01001949 aug->aug_pmod = pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001950 aug->aug_p = aug_p;
1951
1952cleanup:
1953 lyxp_expr_free(ctx->ctx, exp);
1954 return ret;
1955}
1956
1957LY_ERR
1958lys_precompile_own_augments(struct lysc_ctx *ctx)
1959{
Radek Krejci2a9fc652021-01-22 17:44:34 +01001960 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001961
1962 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01001963 const struct lys_module *aug_mod = ctx->cur_mod->augmented_by[u];
1964 struct lysp_node_augment *aug;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001965
1966 /* collect all module augments */
Radek Krejci2a9fc652021-01-22 17:44:34 +01001967 LY_LIST_FOR(aug_mod->parsed->augments, aug) {
1968 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001969 }
1970
1971 /* collect all submodules augments */
1972 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Radek Krejci2a9fc652021-01-22 17:44:34 +01001973 LY_LIST_FOR(aug_mod->parsed->includes[v].submodule->augments, aug) {
1974 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 +02001975 }
1976 }
1977 }
1978
1979 return LY_SUCCESS;
1980}
1981
1982/**
1983 * @brief Prepare a deviation to be applied during data nodes compilation.
1984 *
1985 * @param[in] ctx Compile context.
1986 * @param[in] dev_p Parsed deviation to be applied.
1987 * @param[in] pmod Both current and prefix module for @p dev_p.
1988 * @return LY_ERR value.
1989 */
1990static LY_ERR
1991lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
1992{
1993 LY_ERR ret = LY_SUCCESS;
1994 struct lysc_deviation *dev = NULL;
1995 struct lyxp_expr *exp = NULL;
1996 struct lysp_deviation **new_dev;
1997 const struct lys_module *mod;
1998 const struct lysp_module **new_dev_pmod;
1999 uint32_t i;
2000
2001 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2002 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2003 LY_CHECK_GOTO(ret, cleanup);
2004
2005 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2006 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2007 if (mod != ctx->cur_mod) {
2008 /* deviation for another module, ignore */
2009 goto cleanup;
2010 }
2011
2012 /* try to find the node in already compiled deviations */
2013 for (i = 0; i < ctx->devs.count; ++i) {
2014 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2015 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2016 dev = ctx->devs.objs[i];
2017 break;
2018 }
2019 }
2020
2021 if (!dev) {
2022 /* allocate new compiled deviation */
2023 dev = calloc(1, sizeof *dev);
2024 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2025 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2026
2027 dev->nodeid = exp;
2028 exp = NULL;
2029 }
2030
2031 /* add new parsed deviation structure */
2032 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2033 *new_dev = dev_p;
2034 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2035 *new_dev_pmod = pmod;
2036
2037cleanup:
2038 lyxp_expr_free(ctx->ctx, exp);
2039 return ret;
2040}
2041
2042LY_ERR
2043lys_precompile_own_deviations(struct lysc_ctx *ctx)
2044{
2045 LY_ARRAY_COUNT_TYPE u, v, w;
2046 const struct lys_module *dev_mod;
2047 struct lysc_deviation *dev;
2048 struct lysp_deviate *d;
2049 int not_supported;
2050 uint32_t i;
2051
2052 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2053 dev_mod = ctx->cur_mod->deviated_by[u];
2054
2055 /* compile all module deviations */
2056 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2057 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2058 }
2059
2060 /* compile all submodules deviations */
2061 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2062 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2063 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2064 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2065 }
2066 }
2067 }
2068
2069 /* set not-supported flags for all the deviations */
2070 for (i = 0; i < ctx->devs.count; ++i) {
2071 dev = ctx->devs.objs[i];
2072 not_supported = 0;
2073
2074 LY_ARRAY_FOR(dev->devs, u) {
2075 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2076 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2077 not_supported = 1;
2078 break;
2079 }
2080 }
2081 if (not_supported) {
2082 break;
2083 }
2084 }
2085 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002086 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002087 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
2088 return LY_EVALID;
2089 }
2090
2091 dev->not_supported = not_supported;
2092 }
2093
2094 return LY_SUCCESS;
2095}
2096
2097/**
2098 * @brief Add a module reference into an array, checks for duplicities.
2099 *
2100 * @param[in] ctx Compile context.
2101 * @param[in] mod Module reference to add.
2102 * @param[in,out] mod_array Module sized array to add to.
2103 * @return LY_ERR value.
2104 */
2105static LY_ERR
2106lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2107{
2108 LY_ARRAY_COUNT_TYPE u;
2109 struct lys_module **new_mod;
2110
2111 LY_ARRAY_FOR(*mod_array, u) {
2112 if ((*mod_array)[u] == mod) {
2113 /* already there */
2114 return LY_EEXIST;
2115 }
2116 }
2117
2118 /* add the new module ref */
2119 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2120 *new_mod = mod;
2121
2122 return LY_SUCCESS;
2123}
2124
2125LY_ERR
2126lys_precompile_augments_deviations(struct lysc_ctx *ctx)
2127{
Michal Vasko405cc9e2020-12-01 12:01:27 +01002128 LY_ERR ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002129 LY_ARRAY_COUNT_TYPE u, v;
2130 const struct lysp_module *mod_p;
2131 const struct lysc_node *target;
2132 struct lys_module *mod;
2133 struct lysp_submodule *submod;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002134 struct lysp_node_augment *aug;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002135 ly_bool has_dev = 0;
2136 uint16_t flags;
2137 uint32_t idx, opt_prev = ctx->options;
2138
Michal Vasko405cc9e2020-12-01 12:01:27 +01002139 for (idx = 0; idx < ctx->unres->implementing.count; ++idx) {
2140 if (ctx->cur_mod == ctx->unres->implementing.objs[idx]) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002141 break;
2142 }
2143 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01002144 if (idx == ctx->unres->implementing.count) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002145 /* it was already implemented and all the augments and deviations fully applied */
2146 return LY_SUCCESS;
2147 }
2148
2149 mod_p = ctx->cur_mod->parsed;
2150
Radek Krejci2a9fc652021-01-22 17:44:34 +01002151 LY_LIST_FOR(mod_p->augments, aug) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002152 lysc_update_path(ctx, NULL, "{augment}");
Radek Krejci2a9fc652021-01-22 17:44:34 +01002153 lysc_update_path(ctx, NULL, aug->nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002154
2155 /* get target module */
Radek Krejci2a9fc652021-01-22 17:44:34 +01002156 ret = lys_nodeid_check(ctx, aug->nodeid, 1, &mod, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002157 LY_CHECK_RET(ret);
2158
2159 /* add this module into the target module augmented_by, if not there already from previous augments */
2160 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
2161
2162 /* if we are compiling this module, we cannot add augments to it yet */
2163 if (mod != ctx->cur_mod) {
2164 /* apply the augment, find the target node first */
2165 flags = 0;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002166 ret = lysc_resolve_schema_nodeid(ctx, aug->nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002167 (void *)mod_p, 0, &target, &flags);
2168 LY_CHECK_RET(ret);
2169
2170 /* apply the augment */
2171 ctx->options |= flags;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002172 ret = lys_compile_augment(ctx, aug, (struct lysc_node *)target);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002173 ctx->options = opt_prev;
2174 LY_CHECK_RET(ret);
2175 }
2176
2177 lysc_update_path(ctx, NULL, NULL);
2178 lysc_update_path(ctx, NULL, NULL);
2179 }
2180
2181 LY_ARRAY_FOR(mod_p->deviations, u) {
2182 /* get target module */
2183 lysc_update_path(ctx, NULL, "{deviation}");
2184 lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
2185 ret = lys_nodeid_check(ctx, mod_p->deviations[u].nodeid, 1, &mod, NULL);
2186 lysc_update_path(ctx, NULL, NULL);
2187 lysc_update_path(ctx, NULL, NULL);
2188 LY_CHECK_RET(ret);
2189
2190 /* add this module into the target module deviated_by, if not there already from previous deviations */
2191 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
2192
2193 /* new deviation added to the target module */
2194 has_dev = 1;
2195 }
2196
2197 /* the same for augments and deviations in submodules */
2198 LY_ARRAY_FOR(mod_p->includes, v) {
2199 submod = mod_p->includes[v].submodule;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002200 LY_LIST_FOR(submod->augments, aug) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002201 lysc_update_path(ctx, NULL, "{augment}");
Radek Krejci2a9fc652021-01-22 17:44:34 +01002202 lysc_update_path(ctx, NULL, aug->nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002203
Radek Krejci2a9fc652021-01-22 17:44:34 +01002204 ret = lys_nodeid_check(ctx, aug->nodeid, 1, &mod, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002205 LY_CHECK_RET(ret);
2206
2207 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
2208 if (mod != ctx->cur_mod) {
2209 flags = 0;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002210 ret = lysc_resolve_schema_nodeid(ctx, aug->nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002211 submod, 0, &target, &flags);
2212 LY_CHECK_RET(ret);
2213
2214 ctx->options |= flags;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002215 ret = lys_compile_augment(ctx, aug, (struct lysc_node *)target);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002216 ctx->options = opt_prev;
2217 LY_CHECK_RET(ret);
2218 }
2219
2220 lysc_update_path(ctx, NULL, NULL);
2221 lysc_update_path(ctx, NULL, NULL);
2222 }
2223
2224 LY_ARRAY_FOR(submod->deviations, u) {
2225 lysc_update_path(ctx, NULL, "{deviation}");
2226 lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
2227 ret = lys_nodeid_check(ctx, submod->deviations[u].nodeid, 1, &mod, NULL);
2228 lysc_update_path(ctx, NULL, NULL);
2229 lysc_update_path(ctx, NULL, NULL);
2230 LY_CHECK_RET(ret);
2231
2232 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
2233 has_dev = 1;
2234 }
2235 }
2236
Michal Vasko405cc9e2020-12-01 12:01:27 +01002237 if (has_dev) {
2238 /* all modules (may) need to be recompiled */
2239 ctx->unres->recompile = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002240 }
2241
Michal Vasko405cc9e2020-12-01 12:01:27 +01002242 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002243}
2244
2245void
2246lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2247{
2248 uint32_t i;
2249 LY_ARRAY_COUNT_TYPE u, count;
2250 struct lys_module *m;
2251
2252 for (i = 0; i < ctx->list.count; ++i) {
2253 m = ctx->list.objs[i];
2254
2255 if (m->augmented_by) {
2256 count = LY_ARRAY_COUNT(m->augmented_by);
2257 for (u = 0; u < count; ++u) {
2258 if (m->augmented_by[u] == mod) {
2259 /* keep the order */
2260 if (u < count - 1) {
2261 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by);
2262 }
2263 LY_ARRAY_DECREMENT(m->augmented_by);
2264 break;
2265 }
2266 }
2267 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2268 LY_ARRAY_FREE(m->augmented_by);
2269 m->augmented_by = NULL;
2270 }
2271 }
2272
2273 if (m->deviated_by) {
2274 count = LY_ARRAY_COUNT(m->deviated_by);
2275 for (u = 0; u < count; ++u) {
2276 if (m->deviated_by[u] == mod) {
2277 /* keep the order */
2278 if (u < count - 1) {
2279 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by);
2280 }
2281 LY_ARRAY_DECREMENT(m->deviated_by);
2282 break;
2283 }
2284 }
2285 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2286 LY_ARRAY_FREE(m->deviated_by);
2287 m->deviated_by = NULL;
2288 }
2289 }
2290 }
2291}