blob: 1dfed53a31e039bb314320bd1fdf190160a3d3d6 [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"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020026#include "log.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020027#include "plugins_exts.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020028#include "schema_compile.h"
29#include "schema_compile_node.h"
Michal Vasko29dd11e2020-11-23 16:52:22 +010030#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020031#include "set.h"
32#include "tree.h"
33#include "tree_data.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020034#include "tree_schema.h"
35#include "tree_schema_internal.h"
36#include "xpath.h"
37
38static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
39 size_t nametest_len, const struct lysp_module *mod, const char **name, size_t *name_len);
40
41static LY_ERR
42lys_nodeid_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct lys_module **target_mod,
43 struct lyxp_expr **expr)
44{
45 LY_ERR ret = LY_SUCCESS;
46 struct lyxp_expr *e = NULL;
47 struct lys_module *tmod = NULL, *mod;
48 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
49 uint32_t i;
50
51 /* parse */
52 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
53 if (ret) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010054 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020055 nodeid_type, nodeid);
56 ret = LY_EVALID;
57 goto cleanup;
58 }
59
60 if (abs) {
61 /* absolute schema nodeid */
62 i = 0;
63 } else {
64 /* descendant schema nodeid */
65 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010066 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020067 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
68 ret = LY_EVALID;
69 goto cleanup;
70 }
71 i = 1;
72 }
73
74 /* check all the tokens */
75 for ( ; i < e->used; i += 2) {
76 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010077 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020078 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
79 ret = LY_EVALID;
80 goto cleanup;
81 } else if (e->used == i + 1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010082 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020083 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
84 ret = LY_EVALID;
85 goto cleanup;
86 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010087 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020088 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
89 ret = LY_EVALID;
90 goto cleanup;
91 } else if (abs) {
92 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
93 e->tok_len[i + 1], ctx->pmod, NULL, NULL);
94 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
95
96 /* only keep the first module */
97 if (!tmod) {
98 tmod = mod;
99 }
100
101 /* all the modules must be implemented */
102 if (!mod->implemented) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100103 ret = lys_set_implemented_r(mod, NULL, ctx->unres);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200104 LY_CHECK_GOTO(ret, cleanup);
105 }
106 }
107 }
108
109cleanup:
110 if (ret || !expr) {
111 lyxp_expr_free(ctx->ctx, e);
112 e = NULL;
113 }
114 if (expr) {
115 *expr = ret ? NULL : e;
116 }
117 if (target_mod) {
118 *target_mod = ret ? NULL : tmod;
119 }
120 return ret;
121}
122
123/**
124 * @brief Check whether 2 schema nodeids match.
125 *
126 * @param[in] ctx libyang context.
127 * @param[in] exp1 First schema nodeid.
128 * @param[in] exp1p_mod Module of @p exp1 nodes without any prefix.
129 * @param[in] exp2 Second schema nodeid.
130 * @param[in] exp2_pmod Module of @p exp2 nodes without any prefix.
131 * @return Whether the schema nodeids match or not.
132 */
133static ly_bool
134lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lysp_module *exp1_pmod,
135 const struct lyxp_expr *exp2, const struct lysp_module *exp2_pmod)
136{
137 uint32_t i;
138 const struct lys_module *mod1, *mod2;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100139 const char *name1 = NULL, *name2 = NULL;
140 size_t name1_len = 0, name2_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200141
142 if (exp1->used != exp2->used) {
143 return 0;
144 }
145
146 for (i = 0; i < exp1->used; ++i) {
147 assert(exp1->tokens[i] == exp2->tokens[i]);
148
149 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
150 /* check modules of all the nodes in the node ID */
151 mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_pmod,
152 &name1, &name1_len);
153 assert(mod1);
154 mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_pmod,
155 &name2, &name2_len);
156 assert(mod2);
157
158 /* compare modules */
159 if (mod1 != mod2) {
160 return 0;
161 }
162
163 /* compare names */
164 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
165 return 0;
166 }
167 }
168 }
169
170 return 1;
171}
172
173LY_ERR
174lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
175{
176 LY_ERR ret = LY_SUCCESS;
177 LY_ARRAY_COUNT_TYPE u;
178 struct lyxp_expr *exp = NULL;
179 struct lysc_augment *aug;
180 struct lysc_refine *rfn;
181 struct lysp_refine **new_rfn;
182 uint32_t i;
183
184 LY_ARRAY_FOR(uses_p->augments, u) {
185 lysc_update_path(ctx, NULL, "{augment}");
186 lysc_update_path(ctx, NULL, uses_p->augments[u].nodeid);
187
188 /* parse the nodeid */
189 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->augments[u].nodeid, 0, NULL, &exp), cleanup);
190
191 /* allocate new compiled augment and store it in the set */
192 aug = calloc(1, sizeof *aug);
193 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
194 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
195
196 aug->nodeid = exp;
197 exp = NULL;
198 aug->nodeid_pmod = ctx->pmod;
199 aug->nodeid_ctx_node = ctx_node;
200 aug->aug_p = &uses_p->augments[u];
201
202 lysc_update_path(ctx, NULL, NULL);
203 lysc_update_path(ctx, NULL, NULL);
204 }
205
206 LY_ARRAY_FOR(uses_p->refines, u) {
207 lysc_update_path(ctx, NULL, "{refine}");
208 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
209
210 /* parse the nodeid */
211 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->refines[u].nodeid, 0, NULL, &exp), cleanup);
212
213 /* try to find the node in already compiled refines */
214 rfn = NULL;
215 for (i = 0; i < ctx->uses_rfns.count; ++i) {
216 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
217 ctx->pmod)) {
218 rfn = ctx->uses_rfns.objs[i];
219 break;
220 }
221 }
222
223 if (!rfn) {
224 /* allocate new compiled refine */
225 rfn = calloc(1, sizeof *rfn);
226 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
227 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
228
229 rfn->nodeid = exp;
230 exp = NULL;
231 rfn->nodeid_pmod = ctx->pmod;
232 rfn->nodeid_ctx_node = ctx_node;
Michal Vaskod8655722021-01-12 15:20:36 +0100233 rfn->uses_p = uses_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200234 } else {
235 /* just free exp */
236 lyxp_expr_free(ctx->ctx, exp);
237 exp = NULL;
238 }
239
240 /* add new parsed refine structure */
241 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
242 *new_rfn = &uses_p->refines[u];
243
244 lysc_update_path(ctx, NULL, NULL);
245 lysc_update_path(ctx, NULL, NULL);
246 }
247
248cleanup:
249 lyxp_expr_free(ctx->ctx, exp);
250 return ret;
251}
252
253static LY_ERR
254lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
255{
256 LY_ERR ret = LY_SUCCESS;
257
258 *ext = *orig_ext;
259 DUP_STRING(ctx, orig_ext->name, ext->name, ret);
260 DUP_STRING(ctx, orig_ext->argument, ext->argument, ret);
261
262 return ret;
263}
264
265static LY_ERR
266lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
267{
268 LY_ERR ret = LY_SUCCESS;
269
270 if (orig_restr) {
271 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
272 restr->arg.mod = orig_restr->arg.mod;
273 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
274 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
275 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
276 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
277 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
278 }
279
280 return ret;
281}
282
283static LY_ERR
284lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
285{
286 LY_ERR ret = LY_SUCCESS;
287
288 DUP_STRING(ctx, *orig_str, *str, ret);
289
290 return ret;
291}
292
293LY_ERR
294lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
295{
296 LY_ERR ret = LY_SUCCESS;
297
298 if (!orig_qname->str) {
299 return LY_SUCCESS;
300 }
301
302 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
303 assert(orig_qname->mod);
304 qname->mod = orig_qname->mod;
305
306 return ret;
307}
308
309static LY_ERR
310lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
311{
312 LY_ERR ret = LY_SUCCESS;
313
314 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
315 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
316 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
317 enm->value = orig_enm->value;
318 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
319 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
320 enm->flags = orig_enm->flags;
321
322 return ret;
323}
324
325static LY_ERR
326lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
327{
328 LY_ERR ret = LY_SUCCESS;
329
330 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
331
332 if (orig_type->range) {
333 type->range = calloc(1, sizeof *type->range);
334 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
335 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
336 }
337
338 if (orig_type->length) {
339 type->length = calloc(1, sizeof *type->length);
340 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
341 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
342 }
343
344 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
345 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
346 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
347 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
348 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
349 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
350 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
351
352 type->pmod = orig_type->pmod;
353 type->compiled = orig_type->compiled;
354
355 type->fraction_digits = orig_type->fraction_digits;
356 type->require_instance = orig_type->require_instance;
357 type->flags = orig_type->flags;
358
359done:
360 return ret;
361}
362
363static LY_ERR
364lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
365{
366 LY_ERR ret = LY_SUCCESS;
367
368 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
369 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
370 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
371 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
372
373 return ret;
374}
375
376static LY_ERR
377lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
378{
379 LY_ERR ret = LY_SUCCESS;
380
381 node->parent = NULL;
382 node->nodetype = orig->nodetype;
383 node->flags = orig->flags;
384 node->next = NULL;
385 DUP_STRING(ctx, orig->name, node->name, ret);
386 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
387 DUP_STRING(ctx, orig->ref, node->ref, ret);
388
389 if (orig->when) {
390 node->when = calloc(1, sizeof *node->when);
391 LY_CHECK_ERR_RET(!node->when, LOGMEM(ctx), LY_EMEM);
392 LY_CHECK_RET(lysp_when_dup(ctx, node->when, orig->when));
393 }
394
395 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
396 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
397
398 return ret;
399}
400
401static LY_ERR
402lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
403{
404 LY_ERR ret = LY_SUCCESS;
405 struct lysp_node_container *cont;
406 const struct lysp_node_container *orig_cont;
407 struct lysp_node_leaf *leaf;
408 const struct lysp_node_leaf *orig_leaf;
409 struct lysp_node_leaflist *llist;
410 const struct lysp_node_leaflist *orig_llist;
411 struct lysp_node_list *list;
412 const struct lysp_node_list *orig_list;
413 struct lysp_node_choice *choice;
414 const struct lysp_node_choice *orig_choice;
415 struct lysp_node_case *cas;
416 const struct lysp_node_case *orig_cas;
417 struct lysp_node_anydata *any;
418 const struct lysp_node_anydata *orig_any;
419
420 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA));
421
422 /* common part */
423 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
424
425 /* specific part */
426 switch (node->nodetype) {
427 case LYS_CONTAINER:
428 cont = (struct lysp_node_container *)node;
429 orig_cont = (const struct lysp_node_container *)orig;
430
431 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
432 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
433 /* we do not need the rest */
434 break;
435 case LYS_LEAF:
436 leaf = (struct lysp_node_leaf *)node;
437 orig_leaf = (const struct lysp_node_leaf *)orig;
438
439 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
440 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
441 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
442 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
443 break;
444 case LYS_LEAFLIST:
445 llist = (struct lysp_node_leaflist *)node;
446 orig_llist = (const struct lysp_node_leaflist *)orig;
447
448 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
449 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
450 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
451 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
452 llist->min = orig_llist->min;
453 llist->max = orig_llist->max;
454 break;
455 case LYS_LIST:
456 list = (struct lysp_node_list *)node;
457 orig_list = (const struct lysp_node_list *)orig;
458
459 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
460 DUP_STRING(ctx, orig_list->key, list->key, ret);
461 /* we do not need these arrays */
462 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
463 list->min = orig_list->min;
464 list->max = orig_list->max;
465 break;
466 case LYS_CHOICE:
467 choice = (struct lysp_node_choice *)node;
468 orig_choice = (const struct lysp_node_choice *)orig;
469
470 /* we do not need children */
471 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
472 break;
473 case LYS_CASE:
474 cas = (struct lysp_node_case *)node;
475 orig_cas = (const struct lysp_node_case *)orig;
476
477 /* we do not need children */
478 (void)cas;
479 (void)orig_cas;
480 break;
481 case LYS_ANYDATA:
482 case LYS_ANYXML:
483 any = (struct lysp_node_anydata *)node;
484 orig_any = (const struct lysp_node_anydata *)orig;
485
486 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
487 break;
488 default:
489 LOGINT_RET(ctx);
490 }
491
492 return ret;
493}
494
495static LY_ERR
496lysp_action_inout_dup(const struct ly_ctx *ctx, struct lysp_action_inout *inout, const struct lysp_action_inout *orig)
497{
498 inout->parent = NULL;
499 inout->nodetype = orig->nodetype;
500 DUP_ARRAY(ctx, orig->musts, inout->musts, lysp_restr_dup);
501 /* we dot need these arrays */
502 DUP_ARRAY(ctx, orig->exts, inout->exts, lysp_ext_dup);
503
504 return LY_SUCCESS;
505}
506
507static LY_ERR
508lysp_action_dup(const struct ly_ctx *ctx, struct lysp_action *act, const struct lysp_action *orig)
509{
510 LY_ERR ret = LY_SUCCESS;
511
512 act->parent = NULL;
513 act->nodetype = orig->nodetype;
514 act->flags = orig->flags;
515 DUP_STRING(ctx, orig->name, act->name, ret);
516 DUP_STRING(ctx, orig->dsc, act->dsc, ret);
517 DUP_STRING(ctx, orig->ref, act->ref, ret);
518 DUP_ARRAY(ctx, orig->iffeatures, act->iffeatures, lysp_qname_dup);
519
520 act->input.nodetype = orig->input.nodetype;
521 act->output.nodetype = orig->output.nodetype;
522 /* we do not need choldren of in/out */
523 DUP_ARRAY(ctx, orig->exts, act->exts, lysp_ext_dup);
524
525 return ret;
526}
527
528static LY_ERR
529lysp_notif_dup(const struct ly_ctx *ctx, struct lysp_notif *notif, const struct lysp_notif *orig)
530{
531 LY_ERR ret = LY_SUCCESS;
532
533 notif->parent = NULL;
534 notif->nodetype = orig->nodetype;
535 notif->flags = orig->flags;
536 DUP_STRING(ctx, orig->name, notif->name, ret);
537 DUP_STRING(ctx, orig->dsc, notif->dsc, ret);
538 DUP_STRING(ctx, orig->ref, notif->ref, ret);
539 DUP_ARRAY(ctx, orig->iffeatures, notif->iffeatures, lysp_qname_dup);
540 DUP_ARRAY(ctx, orig->musts, notif->musts, lysp_restr_dup);
541 /* we do not need these arrays */
542 DUP_ARRAY(ctx, orig->exts, notif->exts, lysp_ext_dup);
543
544 return ret;
545}
546
547/**
548 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
549 *
550 * @param[in] ctx libyang context.
551 * @param[in] pnode Node to duplicate.
552 * @param[in] with_links Whether to also copy any links (child, parent pointers).
553 * @param[out] dup_p Duplicated parsed node.
554 * @return LY_ERR value.
555 */
556static LY_ERR
557lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
558{
559 LY_ERR ret = LY_SUCCESS;
560 void *mem = NULL;
561
562 if (!pnode) {
563 *dup_p = NULL;
564 return LY_SUCCESS;
565 }
566
567 switch (pnode->nodetype) {
568 case LYS_CONTAINER:
569 mem = calloc(1, sizeof(struct lysp_node_container));
570 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
571 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
572 break;
573 case LYS_LEAF:
574 mem = calloc(1, sizeof(struct lysp_node_leaf));
575 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
576 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
577 break;
578 case LYS_LEAFLIST:
579 mem = calloc(1, sizeof(struct lysp_node_leaflist));
580 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
581 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
582 break;
583 case LYS_LIST:
584 mem = calloc(1, sizeof(struct lysp_node_list));
585 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
586 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
587 break;
588 case LYS_CHOICE:
589 mem = calloc(1, sizeof(struct lysp_node_choice));
590 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
591 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
592 break;
593 case LYS_CASE:
594 mem = calloc(1, sizeof(struct lysp_node_case));
595 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
596 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
597 break;
598 case LYS_ANYDATA:
599 case LYS_ANYXML:
600 mem = calloc(1, sizeof(struct lysp_node_anydata));
601 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
602 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
603 break;
604 case LYS_INPUT:
605 case LYS_OUTPUT:
606 mem = calloc(1, sizeof(struct lysp_action_inout));
607 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
608 LY_CHECK_GOTO(ret = lysp_action_inout_dup(ctx, mem, (struct lysp_action_inout *)pnode), cleanup);
609 break;
610 case LYS_ACTION:
611 case LYS_RPC:
612 mem = calloc(1, sizeof(struct lysp_action));
613 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
614 LY_CHECK_GOTO(ret = lysp_action_dup(ctx, mem, (struct lysp_action *)pnode), cleanup);
615 break;
616 case LYS_NOTIF:
617 mem = calloc(1, sizeof(struct lysp_notif));
618 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
619 LY_CHECK_GOTO(ret = lysp_notif_dup(ctx, mem, (struct lysp_notif *)pnode), cleanup);
620 break;
621 default:
622 LOGINT_RET(ctx);
623 }
624
625 if (with_links) {
626 /* copy also parent and child pointers */
627 ((struct lysp_node *)mem)->parent = pnode->parent;
628 switch (pnode->nodetype) {
629 case LYS_CONTAINER:
630 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
631 break;
632 case LYS_LIST:
633 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
634 break;
635 case LYS_CHOICE:
636 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
637 break;
638 case LYS_CASE:
639 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
640 break;
641 default:
642 break;
643 }
644 }
645
646cleanup:
647 if (ret) {
648 free(mem);
649 } else {
650 *dup_p = mem;
651 }
652 return ret;
653}
654
655#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100656 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 +0200657 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
658 ret = LY_EVALID; \
659 goto cleanup;
660
661#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
662 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100663 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 +0200664 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
665 ret = LY_EVALID; \
666 goto cleanup; \
667 }
668
669/**
670 * @brief Apply refine.
671 *
672 * @param[in] ctx Compile context.
673 * @param[in] rfn Refine to apply.
674 * @param[in,out] target Refine target.
675 * @return LY_ERR value.
676 */
677static LY_ERR
678lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
679{
680 LY_ERR ret = LY_SUCCESS;
681 LY_ARRAY_COUNT_TYPE u;
682 struct lysp_qname *qname;
683 struct lysp_restr **musts, *must;
684 uint32_t *num;
685
686 /* default value */
687 if (rfn->dflts) {
688 switch (target->nodetype) {
689 case LYS_LEAF:
690 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
691
692 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
693 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &rfn->dflts[0]), cleanup);
694 break;
695 case LYS_LEAFLIST:
696 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100697 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200698 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
699 ret = LY_EVALID;
700 goto cleanup;
701 }
702
703 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
704 ((struct lysp_node_leaflist *)target)->dflts = NULL;
705 LY_ARRAY_FOR(rfn->dflts, u) {
706 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
707 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup);
708 }
709 break;
710 case LYS_CHOICE:
711 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
712
713 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
714 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &rfn->dflts[0]), cleanup);
715 break;
716 default:
717 AMEND_WRONG_NODETYPE("refine", "replace", "default");
718 }
719 }
720
721 /* description */
722 if (rfn->dsc) {
723 FREE_STRING(ctx->ctx, target->dsc);
724 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
725 }
726
727 /* reference */
728 if (rfn->ref) {
729 FREE_STRING(ctx->ctx, target->ref);
730 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
731 }
732
733 /* config */
734 if (rfn->flags & LYS_CONFIG_MASK) {
735 if (ctx->options & (LYS_COMPILE_NOTIFICATION | LYS_COMPILE_RPC_INPUT | LYS_COMPILE_RPC_OUTPUT)) {
736 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
737 ctx->options & LYS_COMPILE_NOTIFICATION ? "notification" : "RPC/action", ctx->path);
738 } else {
739 target->flags &= ~LYS_CONFIG_MASK;
740 target->flags |= rfn->flags & LYS_CONFIG_MASK;
741 }
742 }
743
744 /* mandatory */
745 if (rfn->flags & LYS_MAND_MASK) {
746 switch (target->nodetype) {
747 case LYS_LEAF:
748 case LYS_CHOICE:
749 case LYS_ANYDATA:
750 case LYS_ANYXML:
751 break;
752 default:
753 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
754 }
755
756 target->flags &= ~LYS_MAND_MASK;
757 target->flags |= rfn->flags & LYS_MAND_MASK;
758 }
759
760 /* presence */
761 if (rfn->presence) {
762 switch (target->nodetype) {
763 case LYS_CONTAINER:
764 break;
765 default:
766 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
767 }
768
769 FREE_STRING(ctx->ctx, ((struct lysp_node_container *)target)->presence);
770 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
771 }
772
773 /* must */
774 if (rfn->musts) {
775 switch (target->nodetype) {
776 case LYS_CONTAINER:
777 case LYS_LIST:
778 case LYS_LEAF:
779 case LYS_LEAFLIST:
780 case LYS_ANYDATA:
781 case LYS_ANYXML:
782 musts = &((struct lysp_node_container *)target)->musts;
783 break;
784 default:
785 AMEND_WRONG_NODETYPE("refine", "add", "must");
786 }
787
788 LY_ARRAY_FOR(rfn->musts, u) {
789 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
790 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
791 }
792 }
793
794 /* min-elements */
795 if (rfn->flags & LYS_SET_MIN) {
796 switch (target->nodetype) {
797 case LYS_LEAFLIST:
798 num = &((struct lysp_node_leaflist *)target)->min;
799 break;
800 case LYS_LIST:
801 num = &((struct lysp_node_list *)target)->min;
802 break;
803 default:
804 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
805 }
806
807 *num = rfn->min;
808 }
809
810 /* max-elements */
811 if (rfn->flags & LYS_SET_MAX) {
812 switch (target->nodetype) {
813 case LYS_LEAFLIST:
814 num = &((struct lysp_node_leaflist *)target)->max;
815 break;
816 case LYS_LIST:
817 num = &((struct lysp_node_list *)target)->max;
818 break;
819 default:
820 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
821 }
822
823 *num = rfn->max;
824 }
825
826 /* if-feature */
827 if (rfn->iffeatures) {
828 switch (target->nodetype) {
829 case LYS_LEAF:
830 case LYS_LEAFLIST:
831 case LYS_LIST:
832 case LYS_CONTAINER:
833 case LYS_CHOICE:
834 case LYS_CASE:
835 case LYS_ANYDATA:
836 case LYS_ANYXML:
837 break;
838 default:
839 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
840 }
841
842 LY_ARRAY_FOR(rfn->iffeatures, u) {
843 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
844 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup);
845 }
846 }
847
848 /* extension */
849 /* TODO refine extensions */
850
851cleanup:
852 return ret;
853}
854
855/**
856 * @brief Apply deviate add.
857 *
858 * @param[in] ctx Compile context.
859 * @param[in] d Deviate add to apply.
860 * @param[in,out] target Deviation target.
861 * @return LY_ERR value.
862 */
863static LY_ERR
864lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
865{
866 LY_ERR ret = LY_SUCCESS;
867 LY_ARRAY_COUNT_TYPE u;
868 struct lysp_qname *qname;
869 uint32_t *num;
870 struct lysp_restr **musts, *must;
871
872#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
873 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100874 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200875 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
876 ret = LY_EVALID; \
877 goto cleanup; \
878 }
879
880 /* [units-stmt] */
881 if (d->units) {
882 switch (target->nodetype) {
883 case LYS_LEAF:
884 case LYS_LEAFLIST:
885 break;
886 default:
887 AMEND_WRONG_NODETYPE("deviation", "add", "units");
888 }
889
890 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
891 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
892 }
893
894 /* *must-stmt */
895 if (d->musts) {
896 switch (target->nodetype) {
897 case LYS_CONTAINER:
898 case LYS_LIST:
899 case LYS_LEAF:
900 case LYS_LEAFLIST:
901 case LYS_ANYDATA:
902 case LYS_ANYXML:
903 musts = &((struct lysp_node_container *)target)->musts;
904 break;
905 case LYS_NOTIF:
906 musts = &((struct lysp_notif *)target)->musts;
907 break;
908 case LYS_INPUT:
909 case LYS_OUTPUT:
910 musts = &((struct lysp_action_inout *)target)->musts;
911 break;
912 default:
913 AMEND_WRONG_NODETYPE("deviation", "add", "must");
914 }
915
916 LY_ARRAY_FOR(d->musts, u) {
917 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
918 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
919 }
920 }
921
922 /* *unique-stmt */
923 if (d->uniques) {
924 switch (target->nodetype) {
925 case LYS_LIST:
926 break;
927 default:
928 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
929 }
930
931 LY_ARRAY_FOR(d->uniques, u) {
932 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
933 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup);
934 }
935 }
936
937 /* *default-stmt */
938 if (d->dflts) {
939 switch (target->nodetype) {
940 case LYS_LEAF:
941 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
942 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
943
944 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflts[0]), cleanup);
945 break;
946 case LYS_LEAFLIST:
947 LY_ARRAY_FOR(d->dflts, u) {
948 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
949 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup);
950 }
951 break;
952 case LYS_CHOICE:
953 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
954 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
955
956 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflts[0]), cleanup);
957 break;
958 default:
959 AMEND_WRONG_NODETYPE("deviation", "add", "default");
960 }
961 }
962
963 /* [config-stmt] */
964 if (d->flags & LYS_CONFIG_MASK) {
965 switch (target->nodetype) {
966 case LYS_CONTAINER:
967 case LYS_LEAF:
968 case LYS_LEAFLIST:
969 case LYS_LIST:
970 case LYS_CHOICE:
971 case LYS_ANYDATA:
972 case LYS_ANYXML:
973 break;
974 default:
975 AMEND_WRONG_NODETYPE("deviation", "add", "config");
976 }
977
978 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100979 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200980 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
981 target->flags & LYS_CONFIG_W ? "true" : "false");
982 ret = LY_EVALID;
983 goto cleanup;
984 }
985
986 target->flags |= d->flags & LYS_CONFIG_MASK;
987 }
988
989 /* [mandatory-stmt] */
990 if (d->flags & LYS_MAND_MASK) {
991 switch (target->nodetype) {
992 case LYS_LEAF:
993 case LYS_CHOICE:
994 case LYS_ANYDATA:
995 case LYS_ANYXML:
996 break;
997 default:
998 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
999 }
1000
1001 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001002 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001003 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
1004 target->flags & LYS_MAND_TRUE ? "true" : "false");
1005 ret = LY_EVALID;
1006 goto cleanup;
1007 }
1008
1009 target->flags |= d->flags & LYS_MAND_MASK;
1010 }
1011
1012 /* [min-elements-stmt] */
1013 if (d->flags & LYS_SET_MIN) {
1014 switch (target->nodetype) {
1015 case LYS_LEAFLIST:
1016 num = &((struct lysp_node_leaflist *)target)->min;
1017 break;
1018 case LYS_LIST:
1019 num = &((struct lysp_node_list *)target)->min;
1020 break;
1021 default:
1022 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
1023 }
1024
1025 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001026 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001027 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
1028 ret = LY_EVALID;
1029 goto cleanup;
1030 }
1031
1032 *num = d->min;
1033 }
1034
1035 /* [max-elements-stmt] */
1036 if (d->flags & LYS_SET_MAX) {
1037 switch (target->nodetype) {
1038 case LYS_LEAFLIST:
1039 num = &((struct lysp_node_leaflist *)target)->max;
1040 break;
1041 case LYS_LIST:
1042 num = &((struct lysp_node_list *)target)->max;
1043 break;
1044 default:
1045 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1046 }
1047
1048 if (target->flags & LYS_SET_MAX) {
1049 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001050 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001051 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1052 *num);
1053 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001054 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001055 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1056 }
1057 ret = LY_EVALID;
1058 goto cleanup;
1059 }
1060
1061 *num = d->max;
1062 }
1063
1064cleanup:
1065 return ret;
1066}
1067
1068/**
1069 * @brief Apply deviate delete.
1070 *
1071 * @param[in] ctx Compile context.
1072 * @param[in] d Deviate delete to apply.
1073 * @param[in,out] target Deviation target.
1074 * @return LY_ERR value.
1075 */
1076static LY_ERR
1077lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1078{
1079 LY_ERR ret = LY_SUCCESS;
1080 struct lysp_restr **musts;
1081 LY_ARRAY_COUNT_TYPE u, v;
1082 struct lysp_qname **uniques, **dflts;
1083
1084#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
1085 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1086 int found = 0; \
1087 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1088 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1089 found = 1; \
1090 break; \
1091 } \
1092 } \
1093 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001094 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001095 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1096 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1097 ret = LY_EVALID; \
1098 goto cleanup; \
1099 } \
1100 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
1101 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
1102 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1103 } \
1104 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1105 LY_ARRAY_FREE(ORIG_ARRAY); \
1106 ORIG_ARRAY = NULL; \
1107 }
1108
1109#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1110 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001111 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001112 ret = LY_EVALID; \
1113 goto cleanup; \
1114 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001115 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001116 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1117 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1118 ret = LY_EVALID; \
1119 goto cleanup; \
1120 }
1121
1122 /* [units-stmt] */
1123 if (d->units) {
1124 switch (target->nodetype) {
1125 case LYS_LEAF:
1126 case LYS_LEAFLIST:
1127 break;
1128 default:
1129 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1130 }
1131
1132 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
1133 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
1134 ((struct lysp_node_leaf *)target)->units = NULL;
1135 }
1136
1137 /* *must-stmt */
1138 if (d->musts) {
1139 switch (target->nodetype) {
1140 case LYS_CONTAINER:
1141 case LYS_LIST:
1142 case LYS_LEAF:
1143 case LYS_LEAFLIST:
1144 case LYS_ANYDATA:
1145 case LYS_ANYXML:
1146 musts = &((struct lysp_node_container *)target)->musts;
1147 break;
1148 case LYS_NOTIF:
1149 musts = &((struct lysp_notif *)target)->musts;
1150 break;
1151 case LYS_INPUT:
1152 case LYS_OUTPUT:
1153 musts = &((struct lysp_action_inout *)target)->musts;
1154 break;
1155 default:
1156 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
1182 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
1183 ((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
1193 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
1194 ((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);
1251 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
1252 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
1261 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
1262 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
1267 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
1268 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) {
1392 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_PREF_SCHEMA, (void *)mod);
1393 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\".",
1396 nametest_len, nametest, ptr - nametest, nametest, LYSP_MODULE_NAME(mod));
1397 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/**
1416 * @brief Check whether a parsed node matches a single schema nodeid name test.
1417 *
1418 * @param[in] pnode Parsed node to consider.
1419 * @param[in] pnode_mod Compiled @p pnode to-be module.
1420 * @param[in] mod Expected module.
1421 * @param[in] name Expected name.
1422 * @param[in] name_len Length of @p name.
1423 * @return Whether it is a match or not.
1424 */
1425static ly_bool
1426lysp_schema_nodeid_match_pnode(const struct lysp_node *pnode, const struct lys_module *pnode_mod,
1427 const struct lys_module *mod, const char *name, size_t name_len)
1428{
1429 const char *pname;
1430
1431 /* compare with the module of the node */
1432 if (pnode_mod != mod) {
1433 return 0;
1434 }
1435
1436 /* compare names */
1437 if (pnode->nodetype & (LYS_ACTION | LYS_RPC)) {
1438 pname = ((struct lysp_action *)pnode)->name;
1439 } else if (pnode->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1440 pname = (pnode->nodetype & LYS_INPUT) ? "input" : "output";
1441 } else {
1442 pname = pnode->name;
1443 }
1444 if (ly_strncmp(pname, name, name_len)) {
1445 return 0;
1446 }
1447
1448 return 1;
1449}
1450
1451/**
1452 * @brief Check whether a compiled node matches a single schema nodeid name test.
1453 *
1454 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1455 * @param[in] mod Expected module.
1456 * @param[in] name Expected name.
1457 * @param[in] name_len Length of @p name.
1458 * @return Whether it is a match or not.
1459 */
1460static ly_bool
1461lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
1462 size_t name_len)
1463{
1464 const struct lys_module *node_mod;
1465 const char *node_name;
1466
1467 /* compare with the module of the node */
Michal Vasko2a668712020-10-21 11:48:09 +02001468 if ((*node)->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
Michal Vasko208a04a2020-10-21 15:17:12 +02001469 node_mod = lysc_node_parent_full(*node)->module;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001470 } else {
1471 node_mod = (*node)->module;
1472 }
1473 if (node_mod != mod) {
1474 return 0;
1475 }
1476
1477 /* compare names */
1478 if ((*node)->nodetype == LYS_INPUT) {
1479 node_name = "input";
1480 } else if ((*node)->nodetype == LYS_OUTPUT) {
1481 node_name = "output";
1482 } else {
1483 node_name = (*node)->name;
1484 }
1485 if (ly_strncmp(node_name, name, name_len)) {
1486 return 0;
1487 }
1488
Michal Vasko2a668712020-10-21 11:48:09 +02001489 /* move to next parent */
Michal Vasko208a04a2020-10-21 15:17:12 +02001490 *node = lysc_node_parent_full(*node);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001491
1492 return 1;
1493}
1494
1495/**
1496 * @brief Check whether a node matches specific schema nodeid.
1497 *
1498 * @param[in] exp Parsed nodeid to match.
1499 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
1500 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1501 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1502 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1503 * @param[in] pnode_mod Compiled @p pnode to-be module.
1504 * @return Whether it is a match or not.
1505 */
1506static ly_bool
1507lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node,
1508 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
1509{
1510 uint32_t i;
1511 const struct lys_module *mod;
Radek Krejci2b18bf12020-11-06 11:20:20 +01001512 const char *name = NULL;
1513 size_t name_len = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001514
1515 /* compare last node in the node ID */
1516 i = exp->used - 1;
1517
1518 /* get exp node ID module */
1519 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);
1520 assert(mod);
1521
1522 if (pnode) {
1523 /* compare on the last parsed-only node */
1524 if (!lysp_schema_nodeid_match_pnode(pnode, pnode_mod, mod, name, name_len)) {
1525 return 0;
1526 }
1527 } else {
1528 /* using parent directly */
1529 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1530 return 0;
1531 }
1532 }
1533
1534 /* now compare all the compiled parents */
1535 while (i > 1) {
1536 i -= 2;
1537 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1538
1539 if (!parent) {
1540 /* no more parents but path continues */
1541 return 0;
1542 }
1543
1544 /* get exp node ID module */
1545 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1546 &name_len);
1547 assert(mod);
1548
1549 /* compare with the parent */
1550 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1551 return 0;
1552 }
1553 }
1554
1555 if (ctx_node && (ctx_node != parent)) {
1556 /* descendant path has not finished in the context node */
1557 return 0;
1558 } else if (!ctx_node && parent) {
1559 /* some parent was not matched */
1560 return 0;
1561 }
1562
1563 return 1;
1564}
1565
1566void
1567lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1568{
1569 if (aug) {
1570 lyxp_expr_free(ctx, aug->nodeid);
1571
1572 free(aug);
1573 }
1574}
1575
1576void
1577lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1578{
1579 if (dev) {
1580 lyxp_expr_free(ctx, dev->nodeid);
1581 LY_ARRAY_FREE(dev->devs);
1582 LY_ARRAY_FREE(dev->dev_pmods);
1583
1584 free(dev);
1585 }
1586}
1587
1588void
1589lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1590{
1591 if (rfn) {
1592 lyxp_expr_free(ctx, rfn->nodeid);
1593 LY_ARRAY_FREE(rfn->rfns);
1594
1595 free(rfn);
1596 }
1597}
1598
1599void
1600lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
1601{
1602 if (!dev_pnode) {
1603 return;
1604 }
1605
1606 switch (dev_pnode->nodetype) {
1607 case LYS_CONTAINER:
1608 ((struct lysp_node_container *)dev_pnode)->child = NULL;
1609 break;
1610 case LYS_LIST:
1611 ((struct lysp_node_list *)dev_pnode)->child = NULL;
1612 break;
1613 case LYS_CHOICE:
1614 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1615 break;
1616 case LYS_CASE:
1617 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1618 break;
1619 case LYS_LEAF:
1620 case LYS_LEAFLIST:
1621 case LYS_ANYXML:
1622 case LYS_ANYDATA:
1623 /* no children */
1624 break;
1625 case LYS_NOTIF:
1626 ((struct lysp_notif *)dev_pnode)->data = NULL;
1627 lysp_notif_free((struct ly_ctx *)ctx, (struct lysp_notif *)dev_pnode);
1628 free(dev_pnode);
1629 return;
1630 case LYS_RPC:
1631 case LYS_ACTION:
1632 ((struct lysp_action *)dev_pnode)->input.data = NULL;
1633 ((struct lysp_action *)dev_pnode)->output.data = NULL;
1634 lysp_action_free((struct ly_ctx *)ctx, (struct lysp_action *)dev_pnode);
1635 free(dev_pnode);
1636 return;
1637 case LYS_INPUT:
1638 case LYS_OUTPUT:
1639 ((struct lysp_action_inout *)dev_pnode)->data = NULL;
1640 lysp_action_inout_free((struct ly_ctx *)ctx, (struct lysp_action_inout *)dev_pnode);
1641 free(dev_pnode);
1642 return;
1643 default:
1644 LOGINT(ctx);
1645 return;
1646 }
1647
1648 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
1649}
1650
1651LY_ERR
1652lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1653 struct lysp_node **dev_pnode, ly_bool *not_supported)
1654{
1655 LY_ERR ret = LY_SUCCESS;
1656 uint32_t i;
1657 LY_ARRAY_COUNT_TYPE u;
1658 struct lys_module *orig_mod = ctx->cur_mod;
1659 struct lysp_module *orig_pmod = ctx->pmod;
1660 char orig_path[LYSC_CTX_BUFSIZE];
1661 struct lysc_refine *rfn;
1662 struct lysc_deviation *dev;
1663 struct lysp_deviation *dev_p;
1664 struct lysp_deviate *d;
1665
1666 *dev_pnode = NULL;
1667 *not_supported = 0;
1668
1669 for (i = 0; i < ctx->uses_rfns.count; ++i) {
1670 rfn = ctx->uses_rfns.objs[i];
1671
1672 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, rfn->nodeid_ctx_node, parent, pnode, ctx->cur_mod)) {
1673 /* not our target node */
1674 continue;
1675 }
1676
1677 if (!*dev_pnode) {
1678 /* first refine on this node, create a copy first */
1679 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1680 }
1681
Michal Vaskob8df5762021-01-12 15:15:53 +01001682 /* use modules from the refine */
1683 ctx->cur_mod = rfn->nodeid_pmod->mod;
1684 ctx->pmod = (struct lysp_module *)rfn->nodeid_pmod;
1685
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001686 /* apply all the refines by changing (the copy of) the parsed node */
1687 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vaskob8df5762021-01-12 15:15:53 +01001688 /* keep the current path and add to it */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001689 lysc_update_path(ctx, NULL, "{refine}");
1690 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001691
1692 /* apply refine and restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001693 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
1694 lysc_update_path(ctx, NULL, NULL);
1695 lysc_update_path(ctx, NULL, NULL);
1696 LY_CHECK_GOTO(ret, cleanup);
1697 }
1698
1699 /* refine was applied, remove it */
1700 lysc_refine_free(ctx->ctx, rfn);
1701 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1702
1703 /* all the refines for one target node are in one structure, we are done */
1704 break;
1705 }
1706
1707 for (i = 0; i < ctx->devs.count; ++i) {
1708 dev = ctx->devs.objs[i];
1709
1710 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, ctx->cur_mod)) {
1711 /* not our target node */
1712 continue;
1713 }
1714
1715 if (dev->not_supported) {
1716 /* it is not supported, no more deviations */
1717 *not_supported = 1;
1718 goto dev_applied;
1719 }
1720
1721 if (!*dev_pnode) {
1722 /* first deviation on this node, create a copy first */
1723 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1724 }
1725
1726 /* apply all the deviates by changing (the copy of) the parsed node */
1727 LY_ARRAY_FOR(dev->devs, u) {
1728 dev_p = dev->devs[u];
1729 LY_LIST_FOR(dev_p->deviates, d) {
1730 /* generate correct path */
1731 strcpy(orig_path, ctx->path);
1732 ctx->path_len = 1;
1733 ctx->cur_mod = dev->dev_pmods[u]->mod;
1734 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
1735 lysc_update_path(ctx, NULL, "{deviation}");
1736 lysc_update_path(ctx, NULL, dev_p->nodeid);
1737
1738 switch (d->mod) {
1739 case LYS_DEV_ADD:
1740 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
1741 break;
1742 case LYS_DEV_DELETE:
1743 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
1744 break;
1745 case LYS_DEV_REPLACE:
1746 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
1747 break;
1748 default:
1749 LOGINT(ctx->ctx);
1750 ret = LY_EINT;
1751 }
1752
1753 /* restore previous path */
1754 strcpy(ctx->path, orig_path);
1755 ctx->path_len = strlen(ctx->path);
1756 ctx->cur_mod = orig_mod;
1757 ctx->pmod = orig_pmod;
1758
1759 LY_CHECK_GOTO(ret, cleanup);
1760 }
1761 }
1762
1763dev_applied:
1764 /* deviation was applied, remove it */
1765 lysc_deviation_free(ctx->ctx, dev);
1766 ly_set_rm_index(&ctx->devs, i, NULL);
1767
1768 /* all the deviations for one target node are in one structure, we are done */
1769 break;
1770 }
1771
1772cleanup:
Michal Vasko20316b32021-01-12 15:16:54 +01001773 ctx->cur_mod = orig_mod;
1774 ctx->pmod = orig_pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001775 if (ret) {
1776 lysp_dev_node_free(ctx->ctx, *dev_pnode);
1777 *dev_pnode = NULL;
1778 *not_supported = 0;
1779 }
1780 return ret;
1781}
1782
1783/**
1784 * @brief Compile the parsed augment connecting it into its target.
1785 *
1786 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1787 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1788 * are already implemented and compiled.
1789 *
1790 * @param[in] ctx Compile context.
1791 * @param[in] aug_p Parsed augment to compile.
1792 * @param[in] target Target node of the augment.
1793 * @return LY_SUCCESS on success.
1794 * @return LY_EVALID on failure.
1795 */
1796static LY_ERR
1797lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysc_node *target)
1798{
1799 LY_ERR ret = LY_SUCCESS;
1800 struct lysp_node *pnode;
1801 struct lysc_node *node;
1802 struct lysc_when *when_shared = NULL;
1803 struct lysc_action **actions;
1804 struct lysc_notif **notifs;
Michal Vasko29dd11e2020-11-23 16:52:22 +01001805 ly_bool allow_mandatory = 0, enabled;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001806 LY_ARRAY_COUNT_TYPE u;
1807 struct ly_set child_set = {0};
Michal Vasko29dd11e2020-11-23 16:52:22 +01001808 uint32_t i, opt_prev = ctx->options;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001809
1810 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001811 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001812 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
1813 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
1814 ret = LY_EVALID;
1815 goto cleanup;
1816 }
1817
1818 /* check for mandatory nodes
1819 * - new cases augmenting some choice can have mandatory nodes
1820 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1821 */
1822 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
1823 allow_mandatory = 1;
1824 }
1825
1826 LY_LIST_FOR(aug_p->child, pnode) {
1827 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1828 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1829 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1830 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001831 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001832 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1833 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1834 ret = LY_EVALID;
1835 goto cleanup;
1836 }
1837
1838 /* compile the children */
1839 if (target->nodetype == LYS_CHOICE) {
1840 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
Michal Vasko6fb4c042020-11-24 18:05:26 +01001841 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1842 if (target->nodetype == LYS_INPUT) {
1843 ctx->options |= LYS_COMPILE_RPC_INPUT;
1844 } else {
1845 ctx->options |= LYS_COMPILE_RPC_OUTPUT;
1846 }
1847 ret = lys_compile_node(ctx, pnode, (struct lysc_node *)lysc_node_parent_full(target), 0, &child_set);
1848 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001849 } else {
1850 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1851 }
1852
Michal Vasko29dd11e2020-11-23 16:52:22 +01001853 /* eval if-features again for the rest of this node processing */
1854 LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1855 if (!enabled) {
1856 ctx->options |= LYS_COMPILE_DISABLED;
1857 }
1858
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001859 /* since the augment node is not present in the compiled tree, we need to pass some of its
1860 * statements to all its children */
1861 for (i = 0; i < child_set.count; ++i) {
1862 node = child_set.snodes[i];
1863 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1864 node->flags &= ~LYS_MAND_TRUE;
1865 lys_compile_mandatory_parents(target, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001866 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001867 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
1868 ret = LY_EVALID;
1869 goto cleanup;
1870 }
1871
1872 if (aug_p->when) {
1873 /* pass augment's when to all the children */
1874 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target), node, &when_shared);
1875 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskod9062b02020-11-04 17:15:50 +01001876
1877 if ((node->nodetype == LYS_CONTAINER) && !(node->flags & LYS_PRESENCE)) {
1878 /* container with a when condition */
1879 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning from its "
1880 "inherited \"when\" condition.", node->name);
1881 node->flags |= LYS_PRESENCE;
1882 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001883 }
1884 }
1885 ly_set_erase(&child_set, NULL);
Michal Vasko29dd11e2020-11-23 16:52:22 +01001886
1887 /* restore options */
1888 ctx->options = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001889 }
1890
1891 switch (target->nodetype) {
1892 case LYS_CONTAINER:
1893 actions = &((struct lysc_node_container *)target)->actions;
1894 notifs = &((struct lysc_node_container *)target)->notifs;
1895 break;
1896 case LYS_LIST:
1897 actions = &((struct lysc_node_list *)target)->actions;
1898 notifs = &((struct lysc_node_list *)target)->notifs;
1899 break;
1900 default:
1901 actions = NULL;
1902 notifs = NULL;
1903 break;
1904 }
1905
1906 if (aug_p->actions) {
1907 if (!actions) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001908 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001909 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
1910 lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
1911 ret = LY_EVALID;
1912 goto cleanup;
1913 }
1914
1915 /* compile actions into the target */
Michal Vasko5347e3a2020-11-03 17:14:57 +01001916 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, *actions, target, lys_compile_action, 0, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001917
1918 if (aug_p->when) {
1919 /* inherit when */
1920 LY_ARRAY_FOR(*actions, u) {
1921 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
1922 (struct lysc_node *)&(*actions)[u], &when_shared);
1923 LY_CHECK_GOTO(ret, cleanup);
1924 }
1925 }
1926 }
1927 if (aug_p->notifs) {
1928 if (!notifs) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001929 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001930 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
1931 lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
1932 ret = LY_EVALID;
1933 goto cleanup;
1934 }
1935
1936 /* compile notifications into the target */
Michal Vasko5347e3a2020-11-03 17:14:57 +01001937 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, *notifs, target, lys_compile_notif, 0, ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001938
1939 if (aug_p->when) {
1940 /* inherit when */
1941 LY_ARRAY_FOR(*notifs, u) {
1942 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
1943 (struct lysc_node *)&(*notifs)[u], &when_shared);
1944 LY_CHECK_GOTO(ret, cleanup);
1945 }
1946 }
1947 }
1948
1949cleanup:
1950 ly_set_erase(&child_set, NULL);
Michal Vasko29dd11e2020-11-23 16:52:22 +01001951 ctx->options = opt_prev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001952 return ret;
1953}
1954
1955LY_ERR
1956lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
1957{
1958 LY_ERR ret = LY_SUCCESS;
1959 struct lys_module *orig_mod = ctx->cur_mod;
1960 struct lysp_module *orig_pmod = ctx->pmod;
1961 uint32_t i;
1962 char orig_path[LYSC_CTX_BUFSIZE];
1963 struct lysc_augment *aug;
1964
1965 /* uses augments */
1966 for (i = 0; i < ctx->uses_augs.count; ) {
1967 aug = ctx->uses_augs.objs[i];
1968
1969 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_pmod, aug->nodeid_ctx_node, node, NULL, NULL)) {
1970 /* not our target node */
1971 ++i;
1972 continue;
1973 }
1974
Michal Vaskob8df5762021-01-12 15:15:53 +01001975 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001976 lysc_update_path(ctx, NULL, "{augment}");
1977 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01001978 ctx->cur_mod = aug->nodeid_pmod->mod;
1979 ctx->pmod = (struct lysp_module *)aug->nodeid_pmod;
1980
1981 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001982 ret = lys_compile_augment(ctx, aug->aug_p, node);
1983 lysc_update_path(ctx, NULL, NULL);
1984 lysc_update_path(ctx, NULL, NULL);
1985 LY_CHECK_GOTO(ret, cleanup);
1986
1987 /* augment was applied, remove it (index may have changed because other augments could have been applied) */
1988 ly_set_rm(&ctx->uses_augs, aug, NULL);
1989 lysc_augment_free(ctx->ctx, aug);
1990 }
1991
1992 /* top-level augments */
1993 for (i = 0; i < ctx->augs.count; ) {
1994 aug = ctx->augs.objs[i];
1995
1996 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_pmod, NULL, node, NULL, NULL)) {
1997 /* not our target node */
1998 ++i;
1999 continue;
2000 }
2001
Michal Vaskob8df5762021-01-12 15:15:53 +01002002 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002003 strcpy(orig_path, ctx->path);
2004 ctx->path_len = 1;
2005 lysc_update_path(ctx, NULL, "{augment}");
2006 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
2007 ctx->cur_mod = aug->nodeid_pmod->mod;
2008 ctx->pmod = (struct lysp_module *)aug->nodeid_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01002009
2010 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002011 ret = lys_compile_augment(ctx, aug->aug_p, node);
2012 strcpy(ctx->path, orig_path);
2013 ctx->path_len = strlen(ctx->path);
2014 LY_CHECK_GOTO(ret, cleanup);
2015
2016 /* augment was applied, remove it */
2017 ly_set_rm(&ctx->augs, aug, NULL);
2018 lysc_augment_free(ctx->ctx, aug);
2019 }
2020
2021cleanup:
2022 ctx->cur_mod = orig_mod;
2023 ctx->pmod = orig_pmod;
2024 return ret;
2025}
2026
2027/**
2028 * @brief Prepare a top-level augment to be applied during data nodes compilation.
2029 *
2030 * @param[in] ctx Compile context.
2031 * @param[in] aug_p Parsed augment to be applied.
2032 * @param[in] pmod Both current and prefix module for @p aug_p.
2033 * @return LY_ERR value.
2034 */
2035static LY_ERR
2036lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lysp_module *pmod)
2037{
2038 LY_ERR ret = LY_SUCCESS;
2039 struct lyxp_expr *exp = NULL;
2040 struct lysc_augment *aug;
2041 const struct lys_module *mod;
2042
2043 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2044 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
2045 LY_CHECK_GOTO(ret, cleanup);
2046
2047 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2048 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2049 if (mod != ctx->cur_mod) {
2050 /* augment for another module, ignore */
2051 goto cleanup;
2052 }
2053
2054 /* allocate new compiled augment and store it in the set */
2055 aug = calloc(1, sizeof *aug);
2056 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2057 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2058
2059 aug->nodeid = exp;
2060 exp = NULL;
2061 aug->nodeid_pmod = pmod;
2062 aug->aug_p = aug_p;
2063
2064cleanup:
2065 lyxp_expr_free(ctx->ctx, exp);
2066 return ret;
2067}
2068
2069LY_ERR
2070lys_precompile_own_augments(struct lysc_ctx *ctx)
2071{
2072 LY_ARRAY_COUNT_TYPE u, v, w;
2073 const struct lys_module *aug_mod;
2074
2075 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
2076 aug_mod = ctx->cur_mod->augmented_by[u];
2077
2078 /* collect all module augments */
2079 LY_ARRAY_FOR(aug_mod->parsed->augments, v) {
2080 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->augments[v], aug_mod->parsed));
2081 }
2082
2083 /* collect all submodules augments */
2084 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
2085 LY_ARRAY_FOR(aug_mod->parsed->includes[v].submodule->augments, w) {
2086 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->includes[v].submodule->augments[w],
2087 (struct lysp_module *)aug_mod->parsed->includes[v].submodule));
2088 }
2089 }
2090 }
2091
2092 return LY_SUCCESS;
2093}
2094
2095/**
2096 * @brief Prepare a deviation to be applied during data nodes compilation.
2097 *
2098 * @param[in] ctx Compile context.
2099 * @param[in] dev_p Parsed deviation to be applied.
2100 * @param[in] pmod Both current and prefix module for @p dev_p.
2101 * @return LY_ERR value.
2102 */
2103static LY_ERR
2104lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2105{
2106 LY_ERR ret = LY_SUCCESS;
2107 struct lysc_deviation *dev = NULL;
2108 struct lyxp_expr *exp = NULL;
2109 struct lysp_deviation **new_dev;
2110 const struct lys_module *mod;
2111 const struct lysp_module **new_dev_pmod;
2112 uint32_t i;
2113
2114 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2115 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2116 LY_CHECK_GOTO(ret, cleanup);
2117
2118 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2119 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2120 if (mod != ctx->cur_mod) {
2121 /* deviation for another module, ignore */
2122 goto cleanup;
2123 }
2124
2125 /* try to find the node in already compiled deviations */
2126 for (i = 0; i < ctx->devs.count; ++i) {
2127 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2128 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2129 dev = ctx->devs.objs[i];
2130 break;
2131 }
2132 }
2133
2134 if (!dev) {
2135 /* allocate new compiled deviation */
2136 dev = calloc(1, sizeof *dev);
2137 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2138 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2139
2140 dev->nodeid = exp;
2141 exp = NULL;
2142 }
2143
2144 /* add new parsed deviation structure */
2145 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2146 *new_dev = dev_p;
2147 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2148 *new_dev_pmod = pmod;
2149
2150cleanup:
2151 lyxp_expr_free(ctx->ctx, exp);
2152 return ret;
2153}
2154
2155LY_ERR
2156lys_precompile_own_deviations(struct lysc_ctx *ctx)
2157{
2158 LY_ARRAY_COUNT_TYPE u, v, w;
2159 const struct lys_module *dev_mod;
2160 struct lysc_deviation *dev;
2161 struct lysp_deviate *d;
2162 int not_supported;
2163 uint32_t i;
2164
2165 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2166 dev_mod = ctx->cur_mod->deviated_by[u];
2167
2168 /* compile all module deviations */
2169 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2170 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2171 }
2172
2173 /* compile all submodules deviations */
2174 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2175 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2176 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2177 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2178 }
2179 }
2180 }
2181
2182 /* set not-supported flags for all the deviations */
2183 for (i = 0; i < ctx->devs.count; ++i) {
2184 dev = ctx->devs.objs[i];
2185 not_supported = 0;
2186
2187 LY_ARRAY_FOR(dev->devs, u) {
2188 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2189 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2190 not_supported = 1;
2191 break;
2192 }
2193 }
2194 if (not_supported) {
2195 break;
2196 }
2197 }
2198 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002199 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002200 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
2201 return LY_EVALID;
2202 }
2203
2204 dev->not_supported = not_supported;
2205 }
2206
2207 return LY_SUCCESS;
2208}
2209
2210/**
2211 * @brief Add a module reference into an array, checks for duplicities.
2212 *
2213 * @param[in] ctx Compile context.
2214 * @param[in] mod Module reference to add.
2215 * @param[in,out] mod_array Module sized array to add to.
2216 * @return LY_ERR value.
2217 */
2218static LY_ERR
2219lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2220{
2221 LY_ARRAY_COUNT_TYPE u;
2222 struct lys_module **new_mod;
2223
2224 LY_ARRAY_FOR(*mod_array, u) {
2225 if ((*mod_array)[u] == mod) {
2226 /* already there */
2227 return LY_EEXIST;
2228 }
2229 }
2230
2231 /* add the new module ref */
2232 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2233 *new_mod = mod;
2234
2235 return LY_SUCCESS;
2236}
2237
2238LY_ERR
2239lys_precompile_augments_deviations(struct lysc_ctx *ctx)
2240{
Michal Vasko405cc9e2020-12-01 12:01:27 +01002241 LY_ERR ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002242 LY_ARRAY_COUNT_TYPE u, v;
2243 const struct lysp_module *mod_p;
2244 const struct lysc_node *target;
2245 struct lys_module *mod;
2246 struct lysp_submodule *submod;
2247 ly_bool has_dev = 0;
2248 uint16_t flags;
2249 uint32_t idx, opt_prev = ctx->options;
2250
Michal Vasko405cc9e2020-12-01 12:01:27 +01002251 for (idx = 0; idx < ctx->unres->implementing.count; ++idx) {
2252 if (ctx->cur_mod == ctx->unres->implementing.objs[idx]) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002253 break;
2254 }
2255 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01002256 if (idx == ctx->unres->implementing.count) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002257 /* it was already implemented and all the augments and deviations fully applied */
2258 return LY_SUCCESS;
2259 }
2260
2261 mod_p = ctx->cur_mod->parsed;
2262
2263 LY_ARRAY_FOR(mod_p->augments, u) {
2264 lysc_update_path(ctx, NULL, "{augment}");
2265 lysc_update_path(ctx, NULL, mod_p->augments[u].nodeid);
2266
2267 /* get target module */
2268 ret = lys_nodeid_check(ctx, mod_p->augments[u].nodeid, 1, &mod, NULL);
2269 LY_CHECK_RET(ret);
2270
2271 /* add this module into the target module augmented_by, if not there already from previous augments */
2272 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
2273
2274 /* if we are compiling this module, we cannot add augments to it yet */
2275 if (mod != ctx->cur_mod) {
2276 /* apply the augment, find the target node first */
2277 flags = 0;
2278 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
2279 (void *)mod_p, 0, &target, &flags);
2280 LY_CHECK_RET(ret);
2281
2282 /* apply the augment */
2283 ctx->options |= flags;
2284 ret = lys_compile_augment(ctx, &mod_p->augments[u], (struct lysc_node *)target);
2285 ctx->options = opt_prev;
2286 LY_CHECK_RET(ret);
2287 }
2288
2289 lysc_update_path(ctx, NULL, NULL);
2290 lysc_update_path(ctx, NULL, NULL);
2291 }
2292
2293 LY_ARRAY_FOR(mod_p->deviations, u) {
2294 /* get target module */
2295 lysc_update_path(ctx, NULL, "{deviation}");
2296 lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
2297 ret = lys_nodeid_check(ctx, mod_p->deviations[u].nodeid, 1, &mod, NULL);
2298 lysc_update_path(ctx, NULL, NULL);
2299 lysc_update_path(ctx, NULL, NULL);
2300 LY_CHECK_RET(ret);
2301
2302 /* add this module into the target module deviated_by, if not there already from previous deviations */
2303 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
2304
2305 /* new deviation added to the target module */
2306 has_dev = 1;
2307 }
2308
2309 /* the same for augments and deviations in submodules */
2310 LY_ARRAY_FOR(mod_p->includes, v) {
2311 submod = mod_p->includes[v].submodule;
2312 LY_ARRAY_FOR(submod->augments, u) {
2313 lysc_update_path(ctx, NULL, "{augment}");
2314 lysc_update_path(ctx, NULL, submod->augments[u].nodeid);
2315
2316 ret = lys_nodeid_check(ctx, submod->augments[u].nodeid, 1, &mod, NULL);
2317 LY_CHECK_RET(ret);
2318
2319 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
2320 if (mod != ctx->cur_mod) {
2321 flags = 0;
2322 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
2323 submod, 0, &target, &flags);
2324 LY_CHECK_RET(ret);
2325
2326 ctx->options |= flags;
2327 ret = lys_compile_augment(ctx, &submod->augments[u], (struct lysc_node *)target);
2328 ctx->options = opt_prev;
2329 LY_CHECK_RET(ret);
2330 }
2331
2332 lysc_update_path(ctx, NULL, NULL);
2333 lysc_update_path(ctx, NULL, NULL);
2334 }
2335
2336 LY_ARRAY_FOR(submod->deviations, u) {
2337 lysc_update_path(ctx, NULL, "{deviation}");
2338 lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
2339 ret = lys_nodeid_check(ctx, submod->deviations[u].nodeid, 1, &mod, NULL);
2340 lysc_update_path(ctx, NULL, NULL);
2341 lysc_update_path(ctx, NULL, NULL);
2342 LY_CHECK_RET(ret);
2343
2344 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
2345 has_dev = 1;
2346 }
2347 }
2348
Michal Vasko405cc9e2020-12-01 12:01:27 +01002349 if (has_dev) {
2350 /* all modules (may) need to be recompiled */
2351 ctx->unres->recompile = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002352 }
2353
Michal Vasko405cc9e2020-12-01 12:01:27 +01002354 return LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002355}
2356
2357void
2358lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2359{
2360 uint32_t i;
2361 LY_ARRAY_COUNT_TYPE u, count;
2362 struct lys_module *m;
2363
2364 for (i = 0; i < ctx->list.count; ++i) {
2365 m = ctx->list.objs[i];
2366
2367 if (m->augmented_by) {
2368 count = LY_ARRAY_COUNT(m->augmented_by);
2369 for (u = 0; u < count; ++u) {
2370 if (m->augmented_by[u] == mod) {
2371 /* keep the order */
2372 if (u < count - 1) {
2373 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by);
2374 }
2375 LY_ARRAY_DECREMENT(m->augmented_by);
2376 break;
2377 }
2378 }
2379 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2380 LY_ARRAY_FREE(m->augmented_by);
2381 m->augmented_by = NULL;
2382 }
2383 }
2384
2385 if (m->deviated_by) {
2386 count = LY_ARRAY_COUNT(m->deviated_by);
2387 for (u = 0; u < count; ++u) {
2388 if (m->deviated_by[u] == mod) {
2389 /* keep the order */
2390 if (u < count - 1) {
2391 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by);
2392 }
2393 LY_ARRAY_DECREMENT(m->deviated_by);
2394 break;
2395 }
2396 }
2397 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2398 LY_ARRAY_FREE(m->deviated_by);
2399 m->deviated_by = NULL;
2400 }
2401 }
2402 }
2403}