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