blob: 7ef044b3dab26508c207e02f5773fe21e15a25a8 [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"
Michal Vaskoafac7822020-10-20 14:22:26 +020032#include "in.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020033#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 */
Michal Vasko2a668712020-10-21 11:48:09 +02001480 if ((*node)->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1481 node_mod = lysc_node_parent_all(*node)->module;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001482 } else {
1483 node_mod = (*node)->module;
1484 }
1485 if (node_mod != mod) {
1486 return 0;
1487 }
1488
1489 /* compare names */
1490 if ((*node)->nodetype == LYS_INPUT) {
1491 node_name = "input";
1492 } else if ((*node)->nodetype == LYS_OUTPUT) {
1493 node_name = "output";
1494 } else {
1495 node_name = (*node)->name;
1496 }
1497 if (ly_strncmp(node_name, name, name_len)) {
1498 return 0;
1499 }
1500
Michal Vasko2a668712020-10-21 11:48:09 +02001501 /* move to next parent */
1502 *node = lysc_node_parent_all(*node);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001503
1504 return 1;
1505}
1506
1507/**
1508 * @brief Check whether a node matches specific schema nodeid.
1509 *
1510 * @param[in] exp Parsed nodeid to match.
1511 * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix.
1512 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1513 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1514 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1515 * @param[in] pnode_mod Compiled @p pnode to-be module.
1516 * @return Whether it is a match or not.
1517 */
1518static ly_bool
1519lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node,
1520 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
1521{
1522 uint32_t i;
1523 const struct lys_module *mod;
1524 const char *name;
1525 size_t name_len;
1526
1527 /* compare last node in the node ID */
1528 i = exp->used - 1;
1529
1530 /* get exp node ID module */
1531 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);
1532 assert(mod);
1533
1534 if (pnode) {
1535 /* compare on the last parsed-only node */
1536 if (!lysp_schema_nodeid_match_pnode(pnode, pnode_mod, mod, name, name_len)) {
1537 return 0;
1538 }
1539 } else {
1540 /* using parent directly */
1541 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1542 return 0;
1543 }
1544 }
1545
1546 /* now compare all the compiled parents */
1547 while (i > 1) {
1548 i -= 2;
1549 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
1550
1551 if (!parent) {
1552 /* no more parents but path continues */
1553 return 0;
1554 }
1555
1556 /* get exp node ID module */
1557 mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name,
1558 &name_len);
1559 assert(mod);
1560
1561 /* compare with the parent */
1562 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
1563 return 0;
1564 }
1565 }
1566
1567 if (ctx_node && (ctx_node != parent)) {
1568 /* descendant path has not finished in the context node */
1569 return 0;
1570 } else if (!ctx_node && parent) {
1571 /* some parent was not matched */
1572 return 0;
1573 }
1574
1575 return 1;
1576}
1577
1578void
1579lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1580{
1581 if (aug) {
1582 lyxp_expr_free(ctx, aug->nodeid);
1583
1584 free(aug);
1585 }
1586}
1587
1588void
1589lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1590{
1591 if (dev) {
1592 lyxp_expr_free(ctx, dev->nodeid);
1593 LY_ARRAY_FREE(dev->devs);
1594 LY_ARRAY_FREE(dev->dev_pmods);
1595
1596 free(dev);
1597 }
1598}
1599
1600void
1601lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1602{
1603 if (rfn) {
1604 lyxp_expr_free(ctx, rfn->nodeid);
1605 LY_ARRAY_FREE(rfn->rfns);
1606
1607 free(rfn);
1608 }
1609}
1610
1611void
1612lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
1613{
1614 if (!dev_pnode) {
1615 return;
1616 }
1617
1618 switch (dev_pnode->nodetype) {
1619 case LYS_CONTAINER:
1620 ((struct lysp_node_container *)dev_pnode)->child = NULL;
1621 break;
1622 case LYS_LIST:
1623 ((struct lysp_node_list *)dev_pnode)->child = NULL;
1624 break;
1625 case LYS_CHOICE:
1626 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1627 break;
1628 case LYS_CASE:
1629 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1630 break;
1631 case LYS_LEAF:
1632 case LYS_LEAFLIST:
1633 case LYS_ANYXML:
1634 case LYS_ANYDATA:
1635 /* no children */
1636 break;
1637 case LYS_NOTIF:
1638 ((struct lysp_notif *)dev_pnode)->data = NULL;
1639 lysp_notif_free((struct ly_ctx *)ctx, (struct lysp_notif *)dev_pnode);
1640 free(dev_pnode);
1641 return;
1642 case LYS_RPC:
1643 case LYS_ACTION:
1644 ((struct lysp_action *)dev_pnode)->input.data = NULL;
1645 ((struct lysp_action *)dev_pnode)->output.data = NULL;
1646 lysp_action_free((struct ly_ctx *)ctx, (struct lysp_action *)dev_pnode);
1647 free(dev_pnode);
1648 return;
1649 case LYS_INPUT:
1650 case LYS_OUTPUT:
1651 ((struct lysp_action_inout *)dev_pnode)->data = NULL;
1652 lysp_action_inout_free((struct ly_ctx *)ctx, (struct lysp_action_inout *)dev_pnode);
1653 free(dev_pnode);
1654 return;
1655 default:
1656 LOGINT(ctx);
1657 return;
1658 }
1659
1660 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
1661}
1662
1663LY_ERR
1664lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1665 struct lysp_node **dev_pnode, ly_bool *not_supported)
1666{
1667 LY_ERR ret = LY_SUCCESS;
1668 uint32_t i;
1669 LY_ARRAY_COUNT_TYPE u;
1670 struct lys_module *orig_mod = ctx->cur_mod;
1671 struct lysp_module *orig_pmod = ctx->pmod;
1672 char orig_path[LYSC_CTX_BUFSIZE];
1673 struct lysc_refine *rfn;
1674 struct lysc_deviation *dev;
1675 struct lysp_deviation *dev_p;
1676 struct lysp_deviate *d;
1677
1678 *dev_pnode = NULL;
1679 *not_supported = 0;
1680
1681 for (i = 0; i < ctx->uses_rfns.count; ++i) {
1682 rfn = ctx->uses_rfns.objs[i];
1683
1684 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, rfn->nodeid_ctx_node, parent, pnode, ctx->cur_mod)) {
1685 /* not our target node */
1686 continue;
1687 }
1688
1689 if (!*dev_pnode) {
1690 /* first refine on this node, create a copy first */
1691 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1692 }
1693
1694 /* apply all the refines by changing (the copy of) the parsed node */
1695 LY_ARRAY_FOR(rfn->rfns, u) {
1696 /* apply refine, keep the current path and add to it */
1697 lysc_update_path(ctx, NULL, "{refine}");
1698 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
1699 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
1700 lysc_update_path(ctx, NULL, NULL);
1701 lysc_update_path(ctx, NULL, NULL);
1702 LY_CHECK_GOTO(ret, cleanup);
1703 }
1704
1705 /* refine was applied, remove it */
1706 lysc_refine_free(ctx->ctx, rfn);
1707 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1708
1709 /* all the refines for one target node are in one structure, we are done */
1710 break;
1711 }
1712
1713 for (i = 0; i < ctx->devs.count; ++i) {
1714 dev = ctx->devs.objs[i];
1715
1716 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, ctx->cur_mod)) {
1717 /* not our target node */
1718 continue;
1719 }
1720
1721 if (dev->not_supported) {
1722 /* it is not supported, no more deviations */
1723 *not_supported = 1;
1724 goto dev_applied;
1725 }
1726
1727 if (!*dev_pnode) {
1728 /* first deviation on this node, create a copy first */
1729 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
1730 }
1731
1732 /* apply all the deviates by changing (the copy of) the parsed node */
1733 LY_ARRAY_FOR(dev->devs, u) {
1734 dev_p = dev->devs[u];
1735 LY_LIST_FOR(dev_p->deviates, d) {
1736 /* generate correct path */
1737 strcpy(orig_path, ctx->path);
1738 ctx->path_len = 1;
1739 ctx->cur_mod = dev->dev_pmods[u]->mod;
1740 ctx->pmod = (struct lysp_module *)dev->dev_pmods[u];
1741 lysc_update_path(ctx, NULL, "{deviation}");
1742 lysc_update_path(ctx, NULL, dev_p->nodeid);
1743
1744 switch (d->mod) {
1745 case LYS_DEV_ADD:
1746 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
1747 break;
1748 case LYS_DEV_DELETE:
1749 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
1750 break;
1751 case LYS_DEV_REPLACE:
1752 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
1753 break;
1754 default:
1755 LOGINT(ctx->ctx);
1756 ret = LY_EINT;
1757 }
1758
1759 /* restore previous path */
1760 strcpy(ctx->path, orig_path);
1761 ctx->path_len = strlen(ctx->path);
1762 ctx->cur_mod = orig_mod;
1763 ctx->pmod = orig_pmod;
1764
1765 LY_CHECK_GOTO(ret, cleanup);
1766 }
1767 }
1768
1769dev_applied:
1770 /* deviation was applied, remove it */
1771 lysc_deviation_free(ctx->ctx, dev);
1772 ly_set_rm_index(&ctx->devs, i, NULL);
1773
1774 /* all the deviations for one target node are in one structure, we are done */
1775 break;
1776 }
1777
1778cleanup:
1779 if (ret) {
1780 lysp_dev_node_free(ctx->ctx, *dev_pnode);
1781 *dev_pnode = NULL;
1782 *not_supported = 0;
1783 }
1784 return ret;
1785}
1786
1787/**
1788 * @brief Compile the parsed augment connecting it into its target.
1789 *
1790 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
1791 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
1792 * are already implemented and compiled.
1793 *
1794 * @param[in] ctx Compile context.
1795 * @param[in] aug_p Parsed augment to compile.
1796 * @param[in] target Target node of the augment.
1797 * @return LY_SUCCESS on success.
1798 * @return LY_EVALID on failure.
1799 */
1800static LY_ERR
1801lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysc_node *target)
1802{
1803 LY_ERR ret = LY_SUCCESS;
1804 struct lysp_node *pnode;
1805 struct lysc_node *node;
1806 struct lysc_when *when_shared = NULL;
1807 struct lysc_action **actions;
1808 struct lysc_notif **notifs;
1809 ly_bool allow_mandatory = 0;
1810 LY_ARRAY_COUNT_TYPE u;
1811 struct ly_set child_set = {0};
1812 uint32_t i;
1813
1814 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
1815 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1816 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
1817 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
1818 ret = LY_EVALID;
1819 goto cleanup;
1820 }
1821
1822 /* check for mandatory nodes
1823 * - new cases augmenting some choice can have mandatory nodes
1824 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1825 */
1826 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
1827 allow_mandatory = 1;
1828 }
1829
1830 LY_LIST_FOR(aug_p->child, pnode) {
1831 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1832 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1833 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1834 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1835 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1836 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1837 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1838 ret = LY_EVALID;
1839 goto cleanup;
1840 }
1841
1842 /* compile the children */
1843 if (target->nodetype == LYS_CHOICE) {
1844 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1845 } else {
1846 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
1847 }
1848
1849 /* since the augment node is not present in the compiled tree, we need to pass some of its
1850 * statements to all its children */
1851 for (i = 0; i < child_set.count; ++i) {
1852 node = child_set.snodes[i];
1853 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1854 node->flags &= ~LYS_MAND_TRUE;
1855 lys_compile_mandatory_parents(target, 0);
1856 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
1857 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
1858 ret = LY_EVALID;
1859 goto cleanup;
1860 }
1861
1862 if (aug_p->when) {
1863 /* pass augment's when to all the children */
1864 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target), node, &when_shared);
1865 LY_CHECK_GOTO(ret, cleanup);
1866 }
1867 }
1868 ly_set_erase(&child_set, NULL);
1869 }
1870
1871 switch (target->nodetype) {
1872 case LYS_CONTAINER:
1873 actions = &((struct lysc_node_container *)target)->actions;
1874 notifs = &((struct lysc_node_container *)target)->notifs;
1875 break;
1876 case LYS_LIST:
1877 actions = &((struct lysc_node_list *)target)->actions;
1878 notifs = &((struct lysc_node_list *)target)->notifs;
1879 break;
1880 default:
1881 actions = NULL;
1882 notifs = NULL;
1883 break;
1884 }
1885
1886 if (aug_p->actions) {
1887 if (!actions) {
1888 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1889 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
1890 lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
1891 ret = LY_EVALID;
1892 goto cleanup;
1893 }
1894
1895 /* compile actions into the target */
1896 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, *actions, target, u, lys_compile_action, 0, ret, cleanup);
1897
1898 if (aug_p->when) {
1899 /* inherit when */
1900 LY_ARRAY_FOR(*actions, u) {
1901 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
1902 (struct lysc_node *)&(*actions)[u], &when_shared);
1903 LY_CHECK_GOTO(ret, cleanup);
1904 }
1905 }
1906 }
1907 if (aug_p->notifs) {
1908 if (!notifs) {
1909 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
1910 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
1911 lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
1912 ret = LY_EVALID;
1913 goto cleanup;
1914 }
1915
1916 /* compile notifications into the target */
1917 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, *notifs, target, u, lys_compile_notif, 0, ret, cleanup);
1918
1919 if (aug_p->when) {
1920 /* inherit when */
1921 LY_ARRAY_FOR(*notifs, u) {
1922 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
1923 (struct lysc_node *)&(*notifs)[u], &when_shared);
1924 LY_CHECK_GOTO(ret, cleanup);
1925 }
1926 }
1927 }
1928
1929cleanup:
1930 ly_set_erase(&child_set, NULL);
1931 return ret;
1932}
1933
1934LY_ERR
1935lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
1936{
1937 LY_ERR ret = LY_SUCCESS;
1938 struct lys_module *orig_mod = ctx->cur_mod;
1939 struct lysp_module *orig_pmod = ctx->pmod;
1940 uint32_t i;
1941 char orig_path[LYSC_CTX_BUFSIZE];
1942 struct lysc_augment *aug;
1943
1944 /* uses augments */
1945 for (i = 0; i < ctx->uses_augs.count; ) {
1946 aug = ctx->uses_augs.objs[i];
1947
1948 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_pmod, aug->nodeid_ctx_node, node, NULL, NULL)) {
1949 /* not our target node */
1950 ++i;
1951 continue;
1952 }
1953
1954 /* apply augment, keep the current path and add to it */
1955 lysc_update_path(ctx, NULL, "{augment}");
1956 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
1957 ret = lys_compile_augment(ctx, aug->aug_p, node);
1958 lysc_update_path(ctx, NULL, NULL);
1959 lysc_update_path(ctx, NULL, NULL);
1960 LY_CHECK_GOTO(ret, cleanup);
1961
1962 /* augment was applied, remove it (index may have changed because other augments could have been applied) */
1963 ly_set_rm(&ctx->uses_augs, aug, NULL);
1964 lysc_augment_free(ctx->ctx, aug);
1965 }
1966
1967 /* top-level augments */
1968 for (i = 0; i < ctx->augs.count; ) {
1969 aug = ctx->augs.objs[i];
1970
1971 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_pmod, NULL, node, NULL, NULL)) {
1972 /* not our target node */
1973 ++i;
1974 continue;
1975 }
1976
1977 /* apply augment, use the path and modules from the augment */
1978 strcpy(orig_path, ctx->path);
1979 ctx->path_len = 1;
1980 lysc_update_path(ctx, NULL, "{augment}");
1981 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
1982 ctx->cur_mod = aug->nodeid_pmod->mod;
1983 ctx->pmod = (struct lysp_module *)aug->nodeid_pmod;
1984 ret = lys_compile_augment(ctx, aug->aug_p, node);
1985 strcpy(ctx->path, orig_path);
1986 ctx->path_len = strlen(ctx->path);
1987 LY_CHECK_GOTO(ret, cleanup);
1988
1989 /* augment was applied, remove it */
1990 ly_set_rm(&ctx->augs, aug, NULL);
1991 lysc_augment_free(ctx->ctx, aug);
1992 }
1993
1994cleanup:
1995 ctx->cur_mod = orig_mod;
1996 ctx->pmod = orig_pmod;
1997 return ret;
1998}
1999
2000/**
2001 * @brief Prepare a top-level augment to be applied during data nodes compilation.
2002 *
2003 * @param[in] ctx Compile context.
2004 * @param[in] aug_p Parsed augment to be applied.
2005 * @param[in] pmod Both current and prefix module for @p aug_p.
2006 * @return LY_ERR value.
2007 */
2008static LY_ERR
2009lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lysp_module *pmod)
2010{
2011 LY_ERR ret = LY_SUCCESS;
2012 struct lyxp_expr *exp = NULL;
2013 struct lysc_augment *aug;
2014 const struct lys_module *mod;
2015
2016 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2017 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
2018 LY_CHECK_GOTO(ret, cleanup);
2019
2020 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2021 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2022 if (mod != ctx->cur_mod) {
2023 /* augment for another module, ignore */
2024 goto cleanup;
2025 }
2026
2027 /* allocate new compiled augment and store it in the set */
2028 aug = calloc(1, sizeof *aug);
2029 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2030 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2031
2032 aug->nodeid = exp;
2033 exp = NULL;
2034 aug->nodeid_pmod = pmod;
2035 aug->aug_p = aug_p;
2036
2037cleanup:
2038 lyxp_expr_free(ctx->ctx, exp);
2039 return ret;
2040}
2041
2042LY_ERR
2043lys_precompile_own_augments(struct lysc_ctx *ctx)
2044{
2045 LY_ARRAY_COUNT_TYPE u, v, w;
2046 const struct lys_module *aug_mod;
2047
2048 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
2049 aug_mod = ctx->cur_mod->augmented_by[u];
2050
2051 /* collect all module augments */
2052 LY_ARRAY_FOR(aug_mod->parsed->augments, v) {
2053 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->augments[v], aug_mod->parsed));
2054 }
2055
2056 /* collect all submodules augments */
2057 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
2058 LY_ARRAY_FOR(aug_mod->parsed->includes[v].submodule->augments, w) {
2059 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->includes[v].submodule->augments[w],
2060 (struct lysp_module *)aug_mod->parsed->includes[v].submodule));
2061 }
2062 }
2063 }
2064
2065 return LY_SUCCESS;
2066}
2067
2068/**
2069 * @brief Prepare a deviation to be applied during data nodes compilation.
2070 *
2071 * @param[in] ctx Compile context.
2072 * @param[in] dev_p Parsed deviation to be applied.
2073 * @param[in] pmod Both current and prefix module for @p dev_p.
2074 * @return LY_ERR value.
2075 */
2076static LY_ERR
2077lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2078{
2079 LY_ERR ret = LY_SUCCESS;
2080 struct lysc_deviation *dev = NULL;
2081 struct lyxp_expr *exp = NULL;
2082 struct lysp_deviation **new_dev;
2083 const struct lys_module *mod;
2084 const struct lysp_module **new_dev_pmod;
2085 uint32_t i;
2086
2087 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
2088 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
2089 LY_CHECK_GOTO(ret, cleanup);
2090
2091 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL);
2092 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2093 if (mod != ctx->cur_mod) {
2094 /* deviation for another module, ignore */
2095 goto cleanup;
2096 }
2097
2098 /* try to find the node in already compiled deviations */
2099 for (i = 0; i < ctx->devs.count; ++i) {
2100 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
2101 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2102 dev = ctx->devs.objs[i];
2103 break;
2104 }
2105 }
2106
2107 if (!dev) {
2108 /* allocate new compiled deviation */
2109 dev = calloc(1, sizeof *dev);
2110 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2111 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2112
2113 dev->nodeid = exp;
2114 exp = NULL;
2115 }
2116
2117 /* add new parsed deviation structure */
2118 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2119 *new_dev = dev_p;
2120 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2121 *new_dev_pmod = pmod;
2122
2123cleanup:
2124 lyxp_expr_free(ctx->ctx, exp);
2125 return ret;
2126}
2127
2128LY_ERR
2129lys_precompile_own_deviations(struct lysc_ctx *ctx)
2130{
2131 LY_ARRAY_COUNT_TYPE u, v, w;
2132 const struct lys_module *dev_mod;
2133 struct lysc_deviation *dev;
2134 struct lysp_deviate *d;
2135 int not_supported;
2136 uint32_t i;
2137
2138 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2139 dev_mod = ctx->cur_mod->deviated_by[u];
2140
2141 /* compile all module deviations */
2142 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2143 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2144 }
2145
2146 /* compile all submodules deviations */
2147 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2148 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2149 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2150 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2151 }
2152 }
2153 }
2154
2155 /* set not-supported flags for all the deviations */
2156 for (i = 0; i < ctx->devs.count; ++i) {
2157 dev = ctx->devs.objs[i];
2158 not_supported = 0;
2159
2160 LY_ARRAY_FOR(dev->devs, u) {
2161 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2162 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2163 not_supported = 1;
2164 break;
2165 }
2166 }
2167 if (not_supported) {
2168 break;
2169 }
2170 }
2171 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
2172 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
2173 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
2174 return LY_EVALID;
2175 }
2176
2177 dev->not_supported = not_supported;
2178 }
2179
2180 return LY_SUCCESS;
2181}
2182
2183/**
2184 * @brief Add a module reference into an array, checks for duplicities.
2185 *
2186 * @param[in] ctx Compile context.
2187 * @param[in] mod Module reference to add.
2188 * @param[in,out] mod_array Module sized array to add to.
2189 * @return LY_ERR value.
2190 */
2191static LY_ERR
2192lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2193{
2194 LY_ARRAY_COUNT_TYPE u;
2195 struct lys_module **new_mod;
2196
2197 LY_ARRAY_FOR(*mod_array, u) {
2198 if ((*mod_array)[u] == mod) {
2199 /* already there */
2200 return LY_EEXIST;
2201 }
2202 }
2203
2204 /* add the new module ref */
2205 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2206 *new_mod = mod;
2207
2208 return LY_SUCCESS;
2209}
2210
2211LY_ERR
2212lys_precompile_augments_deviations(struct lysc_ctx *ctx)
2213{
2214 LY_ERR ret = LY_SUCCESS;
2215 LY_ARRAY_COUNT_TYPE u, v;
2216 const struct lysp_module *mod_p;
2217 const struct lysc_node *target;
2218 struct lys_module *mod;
2219 struct lysp_submodule *submod;
2220 ly_bool has_dev = 0;
2221 uint16_t flags;
2222 uint32_t idx, opt_prev = ctx->options;
2223
2224 for (idx = 0; idx < ctx->ctx->implementing.count; ++idx) {
2225 if (ctx->cur_mod == ctx->ctx->implementing.objs[idx]) {
2226 break;
2227 }
2228 }
2229 if (idx == ctx->ctx->implementing.count) {
2230 /* it was already implemented and all the augments and deviations fully applied */
2231 return LY_SUCCESS;
2232 }
2233
2234 mod_p = ctx->cur_mod->parsed;
2235
2236 LY_ARRAY_FOR(mod_p->augments, u) {
2237 lysc_update_path(ctx, NULL, "{augment}");
2238 lysc_update_path(ctx, NULL, mod_p->augments[u].nodeid);
2239
2240 /* get target module */
2241 ret = lys_nodeid_check(ctx, mod_p->augments[u].nodeid, 1, &mod, NULL);
2242 LY_CHECK_RET(ret);
2243
2244 /* add this module into the target module augmented_by, if not there already from previous augments */
2245 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
2246
2247 /* if we are compiling this module, we cannot add augments to it yet */
2248 if (mod != ctx->cur_mod) {
2249 /* apply the augment, find the target node first */
2250 flags = 0;
2251 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
2252 (void *)mod_p, 0, &target, &flags);
2253 LY_CHECK_RET(ret);
2254
2255 /* apply the augment */
2256 ctx->options |= flags;
2257 ret = lys_compile_augment(ctx, &mod_p->augments[u], (struct lysc_node *)target);
2258 ctx->options = opt_prev;
2259 LY_CHECK_RET(ret);
2260 }
2261
2262 lysc_update_path(ctx, NULL, NULL);
2263 lysc_update_path(ctx, NULL, NULL);
2264 }
2265
2266 LY_ARRAY_FOR(mod_p->deviations, u) {
2267 /* get target module */
2268 lysc_update_path(ctx, NULL, "{deviation}");
2269 lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
2270 ret = lys_nodeid_check(ctx, mod_p->deviations[u].nodeid, 1, &mod, NULL);
2271 lysc_update_path(ctx, NULL, NULL);
2272 lysc_update_path(ctx, NULL, NULL);
2273 LY_CHECK_RET(ret);
2274
2275 /* add this module into the target module deviated_by, if not there already from previous deviations */
2276 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
2277
2278 /* new deviation added to the target module */
2279 has_dev = 1;
2280 }
2281
2282 /* the same for augments and deviations in submodules */
2283 LY_ARRAY_FOR(mod_p->includes, v) {
2284 submod = mod_p->includes[v].submodule;
2285 LY_ARRAY_FOR(submod->augments, u) {
2286 lysc_update_path(ctx, NULL, "{augment}");
2287 lysc_update_path(ctx, NULL, submod->augments[u].nodeid);
2288
2289 ret = lys_nodeid_check(ctx, submod->augments[u].nodeid, 1, &mod, NULL);
2290 LY_CHECK_RET(ret);
2291
2292 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by);
2293 if (mod != ctx->cur_mod) {
2294 flags = 0;
2295 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->cur_mod, LY_PREF_SCHEMA,
2296 submod, 0, &target, &flags);
2297 LY_CHECK_RET(ret);
2298
2299 ctx->options |= flags;
2300 ret = lys_compile_augment(ctx, &submod->augments[u], (struct lysc_node *)target);
2301 ctx->options = opt_prev;
2302 LY_CHECK_RET(ret);
2303 }
2304
2305 lysc_update_path(ctx, NULL, NULL);
2306 lysc_update_path(ctx, NULL, NULL);
2307 }
2308
2309 LY_ARRAY_FOR(submod->deviations, u) {
2310 lysc_update_path(ctx, NULL, "{deviation}");
2311 lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
2312 ret = lys_nodeid_check(ctx, submod->deviations[u].nodeid, 1, &mod, NULL);
2313 lysc_update_path(ctx, NULL, NULL);
2314 lysc_update_path(ctx, NULL, NULL);
2315 LY_CHECK_RET(ret);
2316
2317 lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by);
2318 has_dev = 1;
2319 }
2320 }
2321
2322 if (!has_dev) {
2323 /* no need to recompile any modules */
2324 return LY_SUCCESS;
2325 }
2326
2327 /* free all the modules in descending order */
2328 idx = ctx->ctx->list.count;
2329 do {
2330 --idx;
2331 mod = ctx->ctx->list.objs[idx];
2332 /* skip this module */
2333 if (mod == mod_p->mod) {
2334 continue;
2335 }
2336
2337 if (mod->implemented && mod->compiled) {
2338 /* keep information about features state in the module */
2339 lys_feature_precompile_revert(ctx, mod);
2340
2341 /* free the module */
2342 lysc_module_free(mod->compiled, NULL);
2343 mod->compiled = NULL;
2344 }
2345 } while (idx);
2346
2347 /* recompile all the modules in ascending order */
2348 for (idx = 0; idx < ctx->ctx->list.count; ++idx) {
2349 mod = ctx->ctx->list.objs[idx];
2350
2351 /* skip this module */
2352 if (mod == mod_p->mod) {
2353 continue;
2354 }
2355
2356 if (mod->implemented) {
2357 /* compile */
2358 LY_CHECK_GOTO(ret = lys_compile(mod, 0), cleanup);
2359 }
2360 }
2361
2362cleanup:
2363 return ret;
2364}
2365
2366void
2367lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2368{
2369 uint32_t i;
2370 LY_ARRAY_COUNT_TYPE u, count;
2371 struct lys_module *m;
2372
2373 for (i = 0; i < ctx->list.count; ++i) {
2374 m = ctx->list.objs[i];
2375
2376 if (m->augmented_by) {
2377 count = LY_ARRAY_COUNT(m->augmented_by);
2378 for (u = 0; u < count; ++u) {
2379 if (m->augmented_by[u] == mod) {
2380 /* keep the order */
2381 if (u < count - 1) {
2382 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by);
2383 }
2384 LY_ARRAY_DECREMENT(m->augmented_by);
2385 break;
2386 }
2387 }
2388 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2389 LY_ARRAY_FREE(m->augmented_by);
2390 m->augmented_by = NULL;
2391 }
2392 }
2393
2394 if (m->deviated_by) {
2395 count = LY_ARRAY_COUNT(m->deviated_by);
2396 for (u = 0; u < count; ++u) {
2397 if (m->deviated_by[u] == mod) {
2398 /* keep the order */
2399 if (u < count - 1) {
2400 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by);
2401 }
2402 LY_ARRAY_DECREMENT(m->deviated_by);
2403 break;
2404 }
2405 }
2406 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2407 LY_ARRAY_FREE(m->deviated_by);
2408 m->deviated_by = NULL;
2409 }
2410 }
2411 }
2412}