blob: b05076c2d41477ff4b30fb2408a7731478235b87 [file] [log] [blame]
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001/**
2 * @file schema_compile_amend.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko19a09022021-06-15 11:54:08 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02005 * @brief Schema compilation of augments, deviations, and refines.
6 *
Michal Vasko19a09022021-06-15 11:54:08 +02007 * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#define _GNU_SOURCE
17
18#include "schema_compile_amend.h"
19
20#include <assert.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020021#include <stddef.h>
22#include <stdint.h>
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020023#include <stdlib.h>
24#include <string.h>
25
Radek Krejci77114102021-03-10 15:21:57 +010026#include "dict.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020027#include "log.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010028#include "ly_common.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020029#include "schema_compile.h"
30#include "schema_compile_node.h"
Michal Vasko29dd11e2020-11-23 16:52:22 +010031#include "schema_features.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020032#include "set.h"
33#include "tree.h"
Michal Vasko899c7ce2022-02-18 09:18:37 +010034#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010035#include "tree_edit.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020036#include "tree_schema.h"
37#include "tree_schema_internal.h"
38#include "xpath.h"
39
Michal Vasko0b50f6b2022-10-05 15:07:55 +020040/**
Michal Vasko8824a6e2024-01-19 12:42:21 +010041 * @brief Free a nodeid structure.
42 *
43 * @param[in] ctx Context to use.
44 * @param[in] nodeid Nodeid to free.
45 */
46static void
47lysc_nodeid_free(const struct ly_ctx *ctx, struct lysc_nodeid *nodeid)
48{
49 uint32_t i;
50
51 if (!nodeid) {
52 return;
53 }
54
55 for (i = 0; i < nodeid->count; ++i) {
56 lydict_remove(ctx, nodeid->prefix[i]);
57 lydict_remove(ctx, nodeid->name[i]);
58 }
59 free(nodeid->prefix);
60 free(nodeid->name);
61 free(nodeid);
62}
63
64/**
65 * @brief Compile a schema-node-id into a temporary array of prefixes and node names.
66 *
67 * @param[in] ctx Context to use.
68 * @param[in] str Schema-node-id to compile.
69 * @param[out] nodeid Compiled nodeid.
70 * @return LY_ERR value.
71 */
72static LY_ERR
73lys_precompile_nodeid(const struct ly_ctx *ctx, const char *str, struct lysc_nodeid **nodeid)
74{
75 LY_ERR rc = LY_SUCCESS;
76 struct lyxp_expr *exp = NULL;
77 void *mem;
78 const char *ptr, *name;
79 size_t len;
80 uint32_t i;
81
82 *nodeid = NULL;
83
84 /* parse */
85 rc = lyxp_expr_parse(ctx, str, strlen(str), 0, &exp);
86 LY_CHECK_GOTO(rc, cleanup);
87
88 /* alloc */
89 *nodeid = calloc(1, sizeof **nodeid);
90 LY_CHECK_ERR_GOTO(!*nodeid, LOGMEM(ctx); rc = LY_EMEM, cleanup);
91
92 /* store the full schema-node-id */
93 (*nodeid)->str = str;
94
95 /* absolute vs. relative path */
96 i = 0;
97 if (exp->tokens[0] == LYXP_TOKEN_NAMETEST) {
98 goto relative_path;
99 }
100
101 while (i < exp->used) {
102 /* skip '/' */
103 assert(exp->tokens[i] == LYXP_TOKEN_OPER_PATH);
104 ++i;
105
106relative_path:
107 /* new node */
108 mem = realloc((*nodeid)->prefix, ((*nodeid)->count + 1) * sizeof *(*nodeid)->prefix);
109 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); rc = LY_EMEM, cleanup);
110 (*nodeid)->prefix = mem;
111 (*nodeid)->prefix[(*nodeid)->count] = NULL;
112
113 mem = realloc((*nodeid)->name, ((*nodeid)->count + 1) * sizeof *(*nodeid)->name);
114 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); rc = LY_EMEM, cleanup);
115 (*nodeid)->name = mem;
116 (*nodeid)->name[(*nodeid)->count] = NULL;
117
118 ++(*nodeid)->count;
119
120 /* compile the name test */
121 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
122 name = str + exp->tok_pos[i];
123 len = exp->tok_len[i];
124 ptr = ly_strnchr(name, ':', len);
125 if (ptr) {
126 /* store prefix */
127 rc = lydict_insert(ctx, name, ptr - name, &(*nodeid)->prefix[(*nodeid)->count - 1]);
128 LY_CHECK_GOTO(rc, cleanup);
129
130 /* move name */
131 len -= (ptr - name) + 1;
132 name = ptr + 1;
133 }
134
135 /* store name */
136 rc = lydict_insert(ctx, name, len, &(*nodeid)->name[(*nodeid)->count - 1]);
137 LY_CHECK_GOTO(rc, cleanup);
138
139 ++i;
140 }
141
142cleanup:
143 lyxp_expr_free(ctx, exp);
144 if (rc) {
145 lysc_nodeid_free(ctx, *nodeid);
146 *nodeid = NULL;
147 }
148 return rc;
149}
150
151/**
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200152 * @brief Get module of a single nodeid node name test.
153 *
154 * @param[in] ctx libyang context.
Michal Vasko8824a6e2024-01-19 12:42:21 +0100155 * @param[in] prefix_dict Optional prefix of the node test, in the dictionary.
156 * @param[in] pmod Both current and prefix module for resolving prefixes and to return in case of no prefix.
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200157 * @return Resolved module.
158 */
159static const struct lys_module *
Michal Vasko8824a6e2024-01-19 12:42:21 +0100160lys_schema_node_get_module(const struct ly_ctx *ctx, const char *prefix_dict, const struct lysp_module *pmod)
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200161{
Michal Vasko8824a6e2024-01-19 12:42:21 +0100162 const char *local_prefix;
163 LY_ARRAY_COUNT_TYPE u;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200164
Michal Vasko8824a6e2024-01-19 12:42:21 +0100165 if (!prefix_dict) {
166 /* local module */
167 return pmod->mod;
168 }
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200169
Michal Vasko8824a6e2024-01-19 12:42:21 +0100170 local_prefix = pmod->is_submod ? ((struct lysp_submodule *)pmod)->prefix : pmod->mod->prefix;
171 if (local_prefix == prefix_dict) {
172 /* local module prefix */
173 return pmod->mod;
174 }
175
176 LY_ARRAY_FOR(pmod->imports, u) {
177 if (pmod->imports[u].prefix == prefix_dict) {
178 /* import module prefix */
179 return pmod->imports[u].module;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200180 }
181 }
182
Michal Vasko8824a6e2024-01-19 12:42:21 +0100183 /* prefix module not found */
184 LOGVAL(ctx, LYVE_REFERENCE, "Invalid absolute-schema-nodeid nametest - prefix \"%s\" not defined in module \"%s\".",
185 prefix_dict, LYSP_MODULE_NAME(pmod));
186 return NULL;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200187}
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200188
Michal Vasko1ccbf542021-04-19 11:35:00 +0200189/**
190 * @brief Check the syntax of a node-id and collect all the referenced modules.
191 *
192 * @param[in] ctx Compile context.
Michal Vasko8824a6e2024-01-19 12:42:21 +0100193 * @param[in] str Node-id to check.
194 * @param[in] abs Whether @p str must be absolute or relative.
Michal Vasko1ccbf542021-04-19 11:35:00 +0200195 * @param[in,out] mod_set Set to add referenced modules into.
Michal Vasko8824a6e2024-01-19 12:42:21 +0100196 * @param[out] nodeid Optional compiled node-id.
Michal Vasko1ccbf542021-04-19 11:35:00 +0200197 * @param[out] target_mod Optional target module of the node-id.
198 * @return LY_ERR value.
199 */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200200static LY_ERR
Michal Vasko8824a6e2024-01-19 12:42:21 +0100201lys_nodeid_mod_check(struct lysc_ctx *ctx, const char *str, ly_bool abs, struct ly_set *mod_set,
202 struct lysc_nodeid **nodeid, struct lys_module **target_mod)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200203{
204 LY_ERR ret = LY_SUCCESS;
205 struct lyxp_expr *e = NULL;
Michal Vasko8824a6e2024-01-19 12:42:21 +0100206 struct lysc_nodeid *ni = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200207 struct lys_module *tmod = NULL, *mod;
208 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
209 uint32_t i;
210
211 /* parse */
Michal Vasko8824a6e2024-01-19 12:42:21 +0100212 ret = lyxp_expr_parse(ctx->ctx, str, strlen(str), 0, &e);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200213 if (ret) {
Michal Vasko8824a6e2024-01-19 12:42:21 +0100214 LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.", nodeid_type, str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200215 ret = LY_EVALID;
216 goto cleanup;
217 }
218
219 if (abs) {
220 /* absolute schema nodeid */
221 i = 0;
222 } else {
223 /* descendant schema nodeid */
224 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100225 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko8824a6e2024-01-19 12:42:21 +0100226 nodeid_type, str, e->tok_len[0], e->expr + e->tok_pos[0]);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200227 ret = LY_EVALID;
228 goto cleanup;
229 }
230 i = 1;
231 }
232
233 /* check all the tokens */
234 for ( ; i < e->used; i += 2) {
235 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100236 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
Michal Vasko8824a6e2024-01-19 12:42:21 +0100237 nodeid_type, str, e->tok_len[i], e->expr + e->tok_pos[i]);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200238 ret = LY_EVALID;
239 goto cleanup;
240 } else if (e->used == i + 1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100241 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200242 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
243 ret = LY_EVALID;
244 goto cleanup;
245 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100246 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
Michal Vasko8824a6e2024-01-19 12:42:21 +0100247 nodeid_type, str, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200248 ret = LY_EVALID;
249 goto cleanup;
Michal Vasko8824a6e2024-01-19 12:42:21 +0100250 }
251 }
252
253 if (abs || nodeid) {
254 /* compile into nodeid, only if needed */
255 LY_CHECK_GOTO(ret = lys_precompile_nodeid(ctx->ctx, str, &ni), cleanup);
256 }
257
258 if (abs) {
259 for (i = 0; i < ni->count; ++i) {
260 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, ni->prefix[i], ctx->pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200261 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
262
263 /* only keep the first module */
264 if (!tmod) {
265 tmod = mod;
266 }
267
Michal Vasko1ccbf542021-04-19 11:35:00 +0200268 /* store the referenced module */
269 LY_CHECK_GOTO(ret = ly_set_add(mod_set, mod, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200270 }
271 }
272
Michal Vasko8824a6e2024-01-19 12:42:21 +0100273 if (nodeid) {
274 *nodeid = ni;
275 ni = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200276 }
277 if (target_mod) {
Michal Vasko8824a6e2024-01-19 12:42:21 +0100278 *target_mod = tmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200279 }
Michal Vasko8824a6e2024-01-19 12:42:21 +0100280
281cleanup:
282 lyxp_expr_free(ctx->ctx, e);
283 lysc_nodeid_free(ctx->ctx, ni);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200284 return ret;
285}
286
287/**
288 * @brief Check whether 2 schema nodeids match.
289 *
290 * @param[in] ctx libyang context.
Michal Vasko8824a6e2024-01-19 12:42:21 +0100291 * @param[in] nodeid1 First schema nodeid.
292 * @param[in] nodeid1_pmod Module of @p nodeid1 nodes without any prefix.
293 * @param[in] nodeid2 Second schema nodeid.
294 * @param[in] nodeid2_pmod Module of @p nodeid2 nodes without any prefix.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200295 * @return Whether the schema nodeids match or not.
296 */
297static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +0100298lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lysc_nodeid *nodeid1, const struct lysp_module *nodeid1_pmod,
299 const struct lysc_nodeid *nodeid2, const struct lysp_module *nodeid2_pmod)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200300{
301 uint32_t i;
302 const struct lys_module *mod1, *mod2;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200303
Michal Vasko8824a6e2024-01-19 12:42:21 +0100304 if (nodeid1->count != nodeid2->count) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200305 return 0;
306 }
307
Michal Vasko8824a6e2024-01-19 12:42:21 +0100308 for (i = 0; i < nodeid1->count; ++i) {
309 /* check modules of all the nodes in the node ID */
310 mod1 = lys_schema_node_get_module(ctx, nodeid1->prefix[i], nodeid1_pmod);
311 assert(mod1);
312 mod2 = lys_schema_node_get_module(ctx, nodeid2->prefix[i], nodeid2_pmod);
313 assert(mod2);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200314
Michal Vasko8824a6e2024-01-19 12:42:21 +0100315 /* compare modules */
316 if (mod1 != mod2) {
317 return 0;
318 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200319
Michal Vasko8824a6e2024-01-19 12:42:21 +0100320 /* compare names, both in the dictionary */
321 if (nodeid1->name[i] != nodeid2->name[i]) {
322 return 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200323 }
324 }
325
326 return 1;
327}
328
329LY_ERR
330lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
331{
332 LY_ERR ret = LY_SUCCESS;
Michal Vasko8824a6e2024-01-19 12:42:21 +0100333 struct lysc_nodeid *nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200334 struct lysc_augment *aug;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100335 struct lysp_node_augment *aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200336 struct lysc_refine *rfn;
337 struct lysp_refine **new_rfn;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100338 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200339 uint32_t i;
Michal Vasko1ccbf542021-04-19 11:35:00 +0200340 struct ly_set mod_set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200341
Radek Krejci2a9fc652021-01-22 17:44:34 +0100342 LY_LIST_FOR(uses_p->augments, aug_p) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200343 lysc_update_path(ctx, NULL, "{augment}");
Radek Krejci2a9fc652021-01-22 17:44:34 +0100344 lysc_update_path(ctx, NULL, aug_p->nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200345
346 /* parse the nodeid */
Michal Vasko8824a6e2024-01-19 12:42:21 +0100347 LY_CHECK_GOTO(ret = lys_nodeid_mod_check(ctx, aug_p->nodeid, 0, &mod_set, &nodeid, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200348
349 /* allocate new compiled augment and store it in the set */
350 aug = calloc(1, sizeof *aug);
351 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
352 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
353
Michal Vasko8824a6e2024-01-19 12:42:21 +0100354 aug->nodeid = nodeid;
355 nodeid = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +0100356 aug->aug_pmod = ctx->pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200357 aug->nodeid_ctx_node = ctx_node;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100358 aug->aug_p = aug_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200359
360 lysc_update_path(ctx, NULL, NULL);
361 lysc_update_path(ctx, NULL, NULL);
362 }
363
364 LY_ARRAY_FOR(uses_p->refines, u) {
365 lysc_update_path(ctx, NULL, "{refine}");
366 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
367
368 /* parse the nodeid */
Michal Vasko8824a6e2024-01-19 12:42:21 +0100369 LY_CHECK_GOTO(ret = lys_nodeid_mod_check(ctx, uses_p->refines[u].nodeid, 0, &mod_set, &nodeid, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200370
371 /* try to find the node in already compiled refines */
372 rfn = NULL;
373 for (i = 0; i < ctx->uses_rfns.count; ++i) {
Michal Vasko8824a6e2024-01-19 12:42:21 +0100374 if (lys_abs_schema_nodeid_match(ctx->ctx, nodeid, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200375 ctx->pmod)) {
376 rfn = ctx->uses_rfns.objs[i];
377 break;
378 }
379 }
380
381 if (!rfn) {
382 /* allocate new compiled refine */
383 rfn = calloc(1, sizeof *rfn);
384 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
385 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
386
Michal Vasko8824a6e2024-01-19 12:42:21 +0100387 rfn->nodeid = nodeid;
388 nodeid = NULL;
Michal Vasko7d3708f2021-02-03 10:50:24 +0100389 rfn->nodeid_pmod = ctx->cur_mod->parsed;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200390 rfn->nodeid_ctx_node = ctx_node;
Michal Vaskod8655722021-01-12 15:20:36 +0100391 rfn->uses_p = uses_p;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200392 } else {
Michal Vasko8824a6e2024-01-19 12:42:21 +0100393 /* just free nodeid */
394 lysc_nodeid_free(ctx->ctx, nodeid);
395 nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200396 }
397
398 /* add new parsed refine structure */
399 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
400 *new_rfn = &uses_p->refines[u];
401
402 lysc_update_path(ctx, NULL, NULL);
403 lysc_update_path(ctx, NULL, NULL);
404 }
405
406cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +0200407 if (ret) {
408 lysc_update_path(ctx, NULL, NULL);
409 lysc_update_path(ctx, NULL, NULL);
410 }
411 /* should include only this module, will fail later if not */
412 ly_set_erase(&mod_set, NULL);
Michal Vasko8824a6e2024-01-19 12:42:21 +0100413 lysc_nodeid_free(ctx->ctx, nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200414 return ret;
415}
416
Michal Vaskoc621d862022-11-08 14:23:45 +0100417/**
418 * @brief Duplicate parsed extension children, recursively.
419 *
420 * @param[in] ctx Context.
421 * @param[in] orig_child First original child to duplicate.
422 * @param[in,out] child Duplicated children to add to.
423 * @return LY_ERR value.
424 */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200425static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100426lysp_ext_children_dup(const struct ly_ctx *ctx, const struct lysp_stmt *orig_child, struct lysp_stmt **child)
Michal Vasko899c7ce2022-02-18 09:18:37 +0100427{
Michal Vaskod84b8132022-03-15 10:45:44 +0100428 struct lysp_stmt *ch = NULL;
Michal Vasko4316c9d2022-02-21 10:00:10 +0100429
Michal Vasko9464f422022-02-21 10:18:28 +0100430 assert(!*child);
431
Michal Vasko899c7ce2022-02-18 09:18:37 +0100432 LY_LIST_FOR(orig_child, orig_child) {
433 /* new child */
434 if (!*child) {
Michal Vasko4316c9d2022-02-21 10:00:10 +0100435 *child = ch = calloc(1, sizeof *ch);
436 LY_CHECK_ERR_RET(!ch, LOGMEM(ctx), LY_EMEM);
Michal Vasko899c7ce2022-02-18 09:18:37 +0100437 } else {
Michal Vasko4316c9d2022-02-21 10:00:10 +0100438 ch->next = calloc(1, sizeof *ch);
439 LY_CHECK_ERR_RET(!ch->next, LOGMEM(ctx), LY_EMEM);
440 ch = ch->next;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100441 }
442
443 /* fill */
Michal Vasko4316c9d2022-02-21 10:00:10 +0100444 DUP_STRING_RET(ctx, orig_child->stmt, ch->stmt);
445 ch->flags = orig_child->flags;
446 DUP_STRING_RET(ctx, orig_child->arg, ch->arg);
447 ch->format = orig_child->format;
448 LY_CHECK_RET(ly_dup_prefix_data(ctx, orig_child->format, orig_child->prefix_data, &(ch->prefix_data)));
449 ch->kw = orig_child->kw;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100450
451 /* recursive children */
Michal Vaskoc621d862022-11-08 14:23:45 +0100452 LY_CHECK_RET(lysp_ext_children_dup(ctx, orig_child->child, &ch->child));
Michal Vasko899c7ce2022-02-18 09:18:37 +0100453 }
454
455 return LY_SUCCESS;
456}
457
Michal Vaskoc621d862022-11-08 14:23:45 +0100458/**
459 * @brief Duplicate parsed extension instance.
460 *
461 * @param[in] ctx Context.
462 * @param[in] pmod Current parsed module.
463 * @param[in] parent Parent of the duplicated ext instance.
464 * @param[in] parent_stmt Parent statement of the duplicated ext instance (should be @p parent).
465 * @param[out] ext Duplicated ext instance to fill.
466 * @return LY_ERR value.
467 */
Michal Vasko899c7ce2022-02-18 09:18:37 +0100468static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100469lysp_ext_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, void *parent, enum ly_stmt parent_stmt,
470 const struct lysp_ext_instance *orig_ext, struct lysp_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200471{
Michal Vasko193dacd2022-10-13 08:43:05 +0200472 LY_ERR ret = LY_SUCCESS;
473 struct ly_set pmods = {0};
474 struct lysp_ctx pctx = {.parsed_mods = &pmods};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200475
Michal Vasko193dacd2022-10-13 08:43:05 +0200476 DUP_STRING_GOTO(ctx, orig_ext->name, ext->name, ret, cleanup);
477 DUP_STRING_GOTO(ctx, orig_ext->argument, ext->argument, ret, cleanup);
478 ext->format = orig_ext->format;
479 LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, orig_ext->format, orig_ext->prefix_data, &ext->prefix_data), cleanup);
480 ext->def = orig_ext->def;
Michal Vasko899c7ce2022-02-18 09:18:37 +0100481
Michal Vaskoc621d862022-11-08 14:23:45 +0100482 ext->parent = parent;
483 ext->parent_stmt = parent_stmt;
Michal Vasko91bb76c2022-03-24 13:34:18 +0100484 ext->parent_stmt_index = orig_ext->parent_stmt_index;
485 ext->flags = orig_ext->flags;
Michal Vasko193dacd2022-10-13 08:43:05 +0200486 ext->record = orig_ext->record;
487
Michal Vaskoc621d862022-11-08 14:23:45 +0100488 LY_CHECK_GOTO(ret = lysp_ext_children_dup(ctx, orig_ext->child, &ext->child), cleanup);
Michal Vasko193dacd2022-10-13 08:43:05 +0200489 if (ext->record && ext->record->plugin.parse) {
490 /* parse again */
491 LY_CHECK_GOTO(ret = ly_set_add(&pmods, pmod, 1, NULL), cleanup);
492 LY_CHECK_GOTO(ret = ext->record->plugin.parse(&pctx, ext), cleanup);
493 }
494
495cleanup:
496 ly_set_erase(&pmods, NULL);
497 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200498}
499
500static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100501lysp_restr_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, const struct lysp_restr *orig_restr,
502 struct lysp_restr *restr)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200503{
504 LY_ERR ret = LY_SUCCESS;
505
506 if (orig_restr) {
507 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
508 restr->arg.mod = orig_restr->arg.mod;
509 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
510 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
511 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
512 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
Michal Vaskoc621d862022-11-08 14:23:45 +0100513 DUP_EXTS(ctx, pmod, restr, LY_STMT_MUST, orig_restr->exts, restr->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200514 }
515
516 return ret;
517}
518
519static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100520lysp_string_dup(const struct ly_ctx *ctx, const char **orig_str, const char **str)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200521{
522 LY_ERR ret = LY_SUCCESS;
523
524 DUP_STRING(ctx, *orig_str, *str, ret);
525
526 return ret;
527}
528
529LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100530lysp_qname_dup(const struct ly_ctx *ctx, const struct lysp_qname *orig_qname, struct lysp_qname *qname)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200531{
532 LY_ERR ret = LY_SUCCESS;
533
534 if (!orig_qname->str) {
535 return LY_SUCCESS;
536 }
537
538 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
539 assert(orig_qname->mod);
540 qname->mod = orig_qname->mod;
541
542 return ret;
543}
544
545static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100546lysp_type_enum_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, const struct lysp_type_enum *orig_enm,
547 struct lysp_type_enum *enm)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200548{
549 LY_ERR ret = LY_SUCCESS;
550
551 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
552 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
553 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
554 enm->value = orig_enm->value;
555 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100556 DUP_EXTS(ctx, pmod, enm, LY_STMT_ENUM, orig_enm->exts, enm->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200557 enm->flags = orig_enm->flags;
558
559 return ret;
560}
561
562static LY_ERR
Michal Vaskoc621d862022-11-08 14:23:45 +0100563lysp_type_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, const struct lysp_type *orig_type,
564 struct lysp_type *type)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200565{
566 LY_ERR ret = LY_SUCCESS;
567
Michal Vaskoea868242021-06-21 09:28:32 +0200568 /* array macros read previous data so we must zero it */
569 memset(type, 0, sizeof *type);
570
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200571 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
572
573 if (orig_type->range) {
574 type->range = calloc(1, sizeof *type->range);
575 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
Michal Vaskoc621d862022-11-08 14:23:45 +0100576 LY_CHECK_RET(lysp_restr_dup(ctx, pmod, orig_type->range, type->range));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200577 }
578
579 if (orig_type->length) {
580 type->length = calloc(1, sizeof *type->length);
581 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
Michal Vaskoc621d862022-11-08 14:23:45 +0100582 LY_CHECK_RET(lysp_restr_dup(ctx, pmod, orig_type->length, type->length));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200583 }
584
Michal Vasko193dacd2022-10-13 08:43:05 +0200585 DUP_ARRAY2(ctx, pmod, orig_type->patterns, type->patterns, lysp_restr_dup);
586 DUP_ARRAY2(ctx, pmod, orig_type->enums, type->enums, lysp_type_enum_dup);
587 DUP_ARRAY2(ctx, pmod, orig_type->bits, type->bits, lysp_type_enum_dup);
Michal Vaskoe33134a2022-07-29 14:54:40 +0200588 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, 0, 0, &type->path), done);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200589 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
Michal Vasko193dacd2022-10-13 08:43:05 +0200590 DUP_ARRAY2(ctx, pmod, orig_type->types, type->types, lysp_type_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100591 DUP_EXTS(ctx, pmod, type, LY_STMT_TYPE, orig_type->exts, type->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200592
593 type->pmod = orig_type->pmod;
594 type->compiled = orig_type->compiled;
595
596 type->fraction_digits = orig_type->fraction_digits;
597 type->require_instance = orig_type->require_instance;
598 type->flags = orig_type->flags;
599
600done:
601 return ret;
602}
603
604static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200605lysp_when_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_when *when,
606 const struct lysp_when *orig_when)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200607{
608 LY_ERR ret = LY_SUCCESS;
609
610 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
611 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
612 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
Michal Vaskoc621d862022-11-08 14:23:45 +0100613 DUP_EXTS(ctx, pmod, when, LY_STMT_WHEN, orig_when->exts, when->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200614
615 return ret;
616}
617
618static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200619lysp_node_common_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_node *node,
620 const struct lysp_node *orig)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200621{
622 LY_ERR ret = LY_SUCCESS;
623
624 node->parent = NULL;
625 node->nodetype = orig->nodetype;
626 node->flags = orig->flags;
627 node->next = NULL;
628 DUP_STRING(ctx, orig->name, node->name, ret);
629 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
630 DUP_STRING(ctx, orig->ref, node->ref, ret);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200631 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100632 DUP_EXTS(ctx, pmod, node, lyplg_ext_nodetype2stmt(node->nodetype), orig->exts, node->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200633
634 return ret;
635}
636
Michal Vasko193dacd2022-10-13 08:43:05 +0200637#define DUP_PWHEN(CTX, PMOD, ORIG, NEW) \
Radek Krejci9a3823e2021-01-27 20:26:46 +0100638 if (ORIG) { \
639 NEW = calloc(1, sizeof *NEW); \
640 LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \
Michal Vasko193dacd2022-10-13 08:43:05 +0200641 LY_CHECK_RET(lysp_when_dup(CTX, PMOD, NEW, ORIG)); \
Radek Krejci9a3823e2021-01-27 20:26:46 +0100642 }
643
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200644static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200645lysp_node_dup(const struct ly_ctx *ctx, const struct lysp_module *pmod, struct lysp_node *node,
646 const struct lysp_node *orig)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200647{
648 LY_ERR ret = LY_SUCCESS;
649 struct lysp_node_container *cont;
650 const struct lysp_node_container *orig_cont;
651 struct lysp_node_leaf *leaf;
652 const struct lysp_node_leaf *orig_leaf;
653 struct lysp_node_leaflist *llist;
654 const struct lysp_node_leaflist *orig_llist;
655 struct lysp_node_list *list;
656 const struct lysp_node_list *orig_list;
657 struct lysp_node_choice *choice;
658 const struct lysp_node_choice *orig_choice;
659 struct lysp_node_case *cas;
660 const struct lysp_node_case *orig_cas;
661 struct lysp_node_anydata *any;
662 const struct lysp_node_anydata *orig_any;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100663 struct lysp_node_action *action;
664 const struct lysp_node_action *orig_action;
665 struct lysp_node_action_inout *action_inout;
666 const struct lysp_node_action_inout *orig_action_inout;
667 struct lysp_node_notif *notif;
668 const struct lysp_node_notif *orig_notif;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200669
Radek Krejci2a9fc652021-01-22 17:44:34 +0100670 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA |
671 LYS_RPC | LYS_ACTION | LYS_NOTIF));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200672
673 /* common part */
Michal Vasko193dacd2022-10-13 08:43:05 +0200674 LY_CHECK_RET(lysp_node_common_dup(ctx, pmod, node, orig));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200675
676 /* specific part */
677 switch (node->nodetype) {
678 case LYS_CONTAINER:
679 cont = (struct lysp_node_container *)node;
680 orig_cont = (const struct lysp_node_container *)orig;
681
Michal Vasko193dacd2022-10-13 08:43:05 +0200682 DUP_PWHEN(ctx, pmod, orig_cont->when, cont->when);
683 DUP_ARRAY2(ctx, pmod, orig_cont->musts, cont->musts, lysp_restr_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200684 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
685 /* we do not need the rest */
686 break;
687 case LYS_LEAF:
688 leaf = (struct lysp_node_leaf *)node;
689 orig_leaf = (const struct lysp_node_leaf *)orig;
690
Michal Vasko193dacd2022-10-13 08:43:05 +0200691 DUP_PWHEN(ctx, pmod, orig_leaf->when, leaf->when);
692 DUP_ARRAY2(ctx, pmod, orig_leaf->musts, leaf->musts, lysp_restr_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100693 LY_CHECK_RET(lysp_type_dup(ctx, pmod, &orig_leaf->type, &leaf->type));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200694 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
Michal Vaskoc621d862022-11-08 14:23:45 +0100695 LY_CHECK_RET(lysp_qname_dup(ctx, &orig_leaf->dflt, &leaf->dflt));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200696 break;
697 case LYS_LEAFLIST:
698 llist = (struct lysp_node_leaflist *)node;
699 orig_llist = (const struct lysp_node_leaflist *)orig;
700
Michal Vasko193dacd2022-10-13 08:43:05 +0200701 DUP_PWHEN(ctx, pmod, orig_llist->when, llist->when);
702 DUP_ARRAY2(ctx, pmod, orig_llist->musts, llist->musts, lysp_restr_dup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100703 LY_CHECK_RET(lysp_type_dup(ctx, pmod, &orig_llist->type, &llist->type));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200704 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
705 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
706 llist->min = orig_llist->min;
707 llist->max = orig_llist->max;
708 break;
709 case LYS_LIST:
710 list = (struct lysp_node_list *)node;
711 orig_list = (const struct lysp_node_list *)orig;
712
Michal Vasko193dacd2022-10-13 08:43:05 +0200713 DUP_PWHEN(ctx, pmod, orig_list->when, list->when);
714 DUP_ARRAY2(ctx, pmod, orig_list->musts, list->musts, lysp_restr_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200715 DUP_STRING(ctx, orig_list->key, list->key, ret);
716 /* we do not need these arrays */
717 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
718 list->min = orig_list->min;
719 list->max = orig_list->max;
720 break;
721 case LYS_CHOICE:
722 choice = (struct lysp_node_choice *)node;
723 orig_choice = (const struct lysp_node_choice *)orig;
724
Michal Vasko193dacd2022-10-13 08:43:05 +0200725 DUP_PWHEN(ctx, pmod, orig_choice->when, choice->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200726 /* we do not need children */
Michal Vaskoc621d862022-11-08 14:23:45 +0100727 LY_CHECK_RET(lysp_qname_dup(ctx, &orig_choice->dflt, &choice->dflt));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200728 break;
729 case LYS_CASE:
730 cas = (struct lysp_node_case *)node;
731 orig_cas = (const struct lysp_node_case *)orig;
732
Michal Vasko193dacd2022-10-13 08:43:05 +0200733 DUP_PWHEN(ctx, pmod, orig_cas->when, cas->when);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200734 /* we do not need children */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200735 break;
736 case LYS_ANYDATA:
737 case LYS_ANYXML:
738 any = (struct lysp_node_anydata *)node;
739 orig_any = (const struct lysp_node_anydata *)orig;
740
Michal Vasko193dacd2022-10-13 08:43:05 +0200741 DUP_PWHEN(ctx, pmod, orig_any->when, any->when);
742 DUP_ARRAY2(ctx, pmod, orig_any->musts, any->musts, lysp_restr_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200743 break;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100744 case LYS_RPC:
745 case LYS_ACTION:
746 action = (struct lysp_node_action *)node;
747 orig_action = (const struct lysp_node_action *)orig;
748
749 action->input.nodetype = orig_action->input.nodetype;
750 action->output.nodetype = orig_action->output.nodetype;
751 /* we do not need the rest */
752 break;
753 case LYS_INPUT:
754 case LYS_OUTPUT:
755 action_inout = (struct lysp_node_action_inout *)node;
756 orig_action_inout = (const struct lysp_node_action_inout *)orig;
757
Michal Vasko193dacd2022-10-13 08:43:05 +0200758 DUP_ARRAY2(ctx, pmod, orig_action_inout->musts, action_inout->musts, lysp_restr_dup);
Radek Krejci2a9fc652021-01-22 17:44:34 +0100759 /* we do not need the rest */
760 break;
761 case LYS_NOTIF:
762 notif = (struct lysp_node_notif *)node;
763 orig_notif = (const struct lysp_node_notif *)orig;
764
Michal Vasko193dacd2022-10-13 08:43:05 +0200765 DUP_ARRAY2(ctx, pmod, orig_notif->musts, notif->musts, lysp_restr_dup);
Radek Krejci2a9fc652021-01-22 17:44:34 +0100766 /* we do not need the rest */
767 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200768 default:
769 LOGINT_RET(ctx);
770 }
771
772 return ret;
773}
774
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200775/**
776 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
777 *
778 * @param[in] ctx libyang context.
Michal Vasko193dacd2022-10-13 08:43:05 +0200779 * @param[in] pmod Current parsed module.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200780 * @param[in] pnode Node to duplicate.
781 * @param[in] with_links Whether to also copy any links (child, parent pointers).
782 * @param[out] dup_p Duplicated parsed node.
783 * @return LY_ERR value.
784 */
785static LY_ERR
Michal Vaskod7e8c532022-11-08 13:44:51 +0100786lysp_dup_single(struct lysc_ctx *cctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200787{
788 LY_ERR ret = LY_SUCCESS;
Michal Vaskod7e8c532022-11-08 13:44:51 +0100789 struct lysp_node *dup = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200790
791 if (!pnode) {
792 *dup_p = NULL;
793 return LY_SUCCESS;
794 }
795
796 switch (pnode->nodetype) {
797 case LYS_CONTAINER:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100798 dup = calloc(1, sizeof(struct lysp_node_container));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200799 break;
800 case LYS_LEAF:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100801 dup = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200802 break;
803 case LYS_LEAFLIST:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100804 dup = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200805 break;
806 case LYS_LIST:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100807 dup = calloc(1, sizeof(struct lysp_node_list));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200808 break;
809 case LYS_CHOICE:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100810 dup = calloc(1, sizeof(struct lysp_node_choice));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200811 break;
812 case LYS_CASE:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100813 dup = calloc(1, sizeof(struct lysp_node_case));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200814 break;
815 case LYS_ANYDATA:
816 case LYS_ANYXML:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100817 dup = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200818 break;
819 case LYS_INPUT:
820 case LYS_OUTPUT:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100821 dup = calloc(1, sizeof(struct lysp_node_action_inout));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200822 break;
823 case LYS_ACTION:
824 case LYS_RPC:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100825 dup = calloc(1, sizeof(struct lysp_node_action));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200826 break;
827 case LYS_NOTIF:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100828 dup = calloc(1, sizeof(struct lysp_node_notif));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200829 break;
830 default:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100831 LOGINT_RET(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200832 }
Michal Vaskod7e8c532022-11-08 13:44:51 +0100833 LY_CHECK_ERR_GOTO(!dup, LOGMEM(cctx->ctx); ret = LY_EMEM, cleanup);
834 LY_CHECK_GOTO(ret = lysp_node_dup(cctx->ctx, cctx->pmod, dup, pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200835
836 if (with_links) {
Michal Vaskoec8f4272021-10-27 09:14:03 +0200837 /* copy also parent, child, action, and notification pointers */
Michal Vaskod7e8c532022-11-08 13:44:51 +0100838 dup->parent = pnode->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200839 switch (pnode->nodetype) {
840 case LYS_CONTAINER:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100841 ((struct lysp_node_container *)dup)->child = ((struct lysp_node_container *)pnode)->child;
842 ((struct lysp_node_container *)dup)->actions = ((struct lysp_node_container *)pnode)->actions;
843 ((struct lysp_node_container *)dup)->notifs = ((struct lysp_node_container *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200844 break;
845 case LYS_LIST:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100846 ((struct lysp_node_list *)dup)->child = ((struct lysp_node_list *)pnode)->child;
847 ((struct lysp_node_list *)dup)->actions = ((struct lysp_node_list *)pnode)->actions;
848 ((struct lysp_node_list *)dup)->notifs = ((struct lysp_node_list *)pnode)->notifs;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200849 break;
850 case LYS_CHOICE:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100851 ((struct lysp_node_choice *)dup)->child = ((struct lysp_node_choice *)pnode)->child;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200852 break;
853 case LYS_CASE:
Michal Vaskod7e8c532022-11-08 13:44:51 +0100854 ((struct lysp_node_case *)dup)->child = ((struct lysp_node_case *)pnode)->child;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200855 break;
856 default:
857 break;
858 }
859 }
860
861cleanup:
862 if (ret) {
Michal Vaskod7e8c532022-11-08 13:44:51 +0100863 lysp_dev_node_free(cctx, dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200864 } else {
Michal Vaskod7e8c532022-11-08 13:44:51 +0100865 *dup_p = dup;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200866 }
867 return ret;
868}
869
870#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100871 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s of %s node - it is not possible to %s \"%s\" property.", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200872 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
873 ret = LY_EVALID; \
874 goto cleanup;
875
876#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
877 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +0100878 LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid %s of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200879 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
880 ret = LY_EVALID; \
881 goto cleanup; \
882 }
883
884/**
885 * @brief Apply refine.
886 *
887 * @param[in] ctx Compile context.
888 * @param[in] rfn Refine to apply.
Michal Vasko193dacd2022-10-13 08:43:05 +0200889 * @param[in] rfn_pmod Local module fo the refine.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200890 * @param[in,out] target Refine target.
891 * @return LY_ERR value.
892 */
893static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200894lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, const struct lysp_module *rfn_pmod, struct lysp_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200895{
896 LY_ERR ret = LY_SUCCESS;
Michal Vasko193dacd2022-10-13 08:43:05 +0200897 struct lys_module *orig_mod = ctx->cur_mod;
898 struct lysp_module *orig_pmod = ctx->pmod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200899 LY_ARRAY_COUNT_TYPE u;
900 struct lysp_qname *qname;
901 struct lysp_restr **musts, *must;
902 uint32_t *num;
903
Michal Vasko193dacd2022-10-13 08:43:05 +0200904 /* use module from the refine */
905 ctx->cur_mod = rfn_pmod->mod;
906 ctx->pmod = (struct lysp_module *)rfn_pmod;
907
908 /* keep the current path and add to it */
909 lysc_update_path(ctx, NULL, "{refine}");
910 lysc_update_path(ctx, NULL, rfn->nodeid);
911
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200912 /* default value */
913 if (rfn->dflts) {
914 switch (target->nodetype) {
915 case LYS_LEAF:
916 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
917
Michal Vaskoe180ed02021-02-05 16:31:20 +0100918 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +0100919 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->dflts[0], &((struct lysp_node_leaf *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200920 break;
921 case LYS_LEAFLIST:
922 if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100923 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200924 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
925 ret = LY_EVALID;
926 goto cleanup;
927 }
928
929 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
930 ((struct lysp_node_leaflist *)target)->dflts = NULL;
931 LY_ARRAY_FOR(rfn->dflts, u) {
932 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +0100933 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->dflts[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200934 }
935 break;
936 case LYS_CHOICE:
937 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
938
Michal Vaskoe180ed02021-02-05 16:31:20 +0100939 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +0100940 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->dflts[0], &((struct lysp_node_choice *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200941 break;
942 default:
943 AMEND_WRONG_NODETYPE("refine", "replace", "default");
944 }
945 }
946
947 /* description */
948 if (rfn->dsc) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100949 lydict_remove(ctx->ctx, target->dsc);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200950 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
951 }
952
953 /* reference */
954 if (rfn->ref) {
Michal Vaskoe180ed02021-02-05 16:31:20 +0100955 lydict_remove(ctx->ctx, target->ref);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200956 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
957 }
958
959 /* config */
960 if (rfn->flags & LYS_CONFIG_MASK) {
Michal Vasko7c565922021-06-10 14:58:27 +0200961 if (ctx->compile_opts & LYS_COMPILE_NO_CONFIG) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200962 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Michal Vasko7c565922021-06-10 14:58:27 +0200963 (ctx->compile_opts & (LYS_IS_INPUT | LYS_IS_OUTPUT)) ? "RPC/action" :
964 ctx->compile_opts & LYS_IS_NOTIF ? "notification" : "a subtree ignoring config", ctx->path);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200965 } else {
966 target->flags &= ~LYS_CONFIG_MASK;
967 target->flags |= rfn->flags & LYS_CONFIG_MASK;
968 }
969 }
970
971 /* mandatory */
972 if (rfn->flags & LYS_MAND_MASK) {
973 switch (target->nodetype) {
974 case LYS_LEAF:
975 case LYS_CHOICE:
976 case LYS_ANYDATA:
977 case LYS_ANYXML:
978 break;
979 default:
980 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
981 }
982
983 target->flags &= ~LYS_MAND_MASK;
984 target->flags |= rfn->flags & LYS_MAND_MASK;
985 }
986
987 /* presence */
988 if (rfn->presence) {
Michal Vasko4e55f5a2022-12-14 12:15:00 +0100989 if (target->nodetype != LYS_CONTAINER) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200990 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
991 }
992
Michal Vaskoe180ed02021-02-05 16:31:20 +0100993 lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +0200994 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
995 }
996
997 /* must */
998 if (rfn->musts) {
999 switch (target->nodetype) {
1000 case LYS_CONTAINER:
1001 case LYS_LIST:
1002 case LYS_LEAF:
1003 case LYS_LEAFLIST:
1004 case LYS_ANYDATA:
1005 case LYS_ANYXML:
1006 musts = &((struct lysp_node_container *)target)->musts;
1007 break;
1008 default:
1009 AMEND_WRONG_NODETYPE("refine", "add", "must");
1010 }
1011
1012 LY_ARRAY_FOR(rfn->musts, u) {
1013 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001014 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, rfn_pmod, &rfn->musts[u], must), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001015 }
1016 }
1017
1018 /* min-elements */
1019 if (rfn->flags & LYS_SET_MIN) {
1020 switch (target->nodetype) {
1021 case LYS_LEAFLIST:
1022 num = &((struct lysp_node_leaflist *)target)->min;
1023 break;
1024 case LYS_LIST:
1025 num = &((struct lysp_node_list *)target)->min;
1026 break;
1027 default:
1028 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
1029 }
1030
1031 *num = rfn->min;
1032 }
1033
1034 /* max-elements */
1035 if (rfn->flags & LYS_SET_MAX) {
1036 switch (target->nodetype) {
1037 case LYS_LEAFLIST:
1038 num = &((struct lysp_node_leaflist *)target)->max;
1039 break;
1040 case LYS_LIST:
1041 num = &((struct lysp_node_list *)target)->max;
1042 break;
1043 default:
1044 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
1045 }
1046
1047 *num = rfn->max;
1048 }
1049
1050 /* if-feature */
1051 if (rfn->iffeatures) {
1052 switch (target->nodetype) {
1053 case LYS_LEAF:
1054 case LYS_LEAFLIST:
1055 case LYS_LIST:
1056 case LYS_CONTAINER:
1057 case LYS_CHOICE:
1058 case LYS_CASE:
1059 case LYS_ANYDATA:
1060 case LYS_ANYXML:
1061 break;
1062 default:
1063 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
1064 }
1065
1066 LY_ARRAY_FOR(rfn->iffeatures, u) {
1067 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001068 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &rfn->iffeatures[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001069 }
1070 }
1071
Michal Vasko193dacd2022-10-13 08:43:05 +02001072 /* extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +01001073 DUP_EXTS(ctx->ctx, rfn_pmod, target, lyplg_ext_nodetype2stmt(target->nodetype), rfn->exts, target->exts, lysp_ext_dup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001074
1075cleanup:
Michal Vasko193dacd2022-10-13 08:43:05 +02001076 ctx->cur_mod = orig_mod;
1077 ctx->pmod = orig_pmod;
1078
1079 lysc_update_path(ctx, NULL, NULL);
1080 lysc_update_path(ctx, NULL, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001081 return ret;
1082}
1083
1084/**
1085 * @brief Apply deviate add.
1086 *
1087 * @param[in] ctx Compile context.
1088 * @param[in] d Deviate add to apply.
1089 * @param[in,out] target Deviation target.
1090 * @return LY_ERR value.
1091 */
1092static LY_ERR
1093lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
1094{
1095 LY_ERR ret = LY_SUCCESS;
1096 LY_ARRAY_COUNT_TYPE u;
1097 struct lysp_qname *qname;
1098 uint32_t *num;
1099 struct lysp_restr **musts, *must;
1100
1101#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
1102 if (((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001103 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001104 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
1105 ret = LY_EVALID; \
1106 goto cleanup; \
1107 }
1108
1109 /* [units-stmt] */
1110 if (d->units) {
1111 switch (target->nodetype) {
1112 case LYS_LEAF:
1113 case LYS_LEAFLIST:
1114 break;
1115 default:
1116 AMEND_WRONG_NODETYPE("deviation", "add", "units");
1117 }
1118
1119 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
1120 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1121 }
1122
1123 /* *must-stmt */
1124 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001125 musts = lysp_node_musts_p(target);
1126 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001127 AMEND_WRONG_NODETYPE("deviation", "add", "must");
1128 }
1129
1130 LY_ARRAY_FOR(d->musts, u) {
1131 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001132 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, ctx->pmod, &d->musts[u], must), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001133 }
1134 }
1135
1136 /* *unique-stmt */
1137 if (d->uniques) {
Michal Vasko4e55f5a2022-12-14 12:15:00 +01001138 if (target->nodetype != LYS_LIST) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001139 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
1140 }
1141
1142 LY_ARRAY_FOR(d->uniques, u) {
1143 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001144 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->uniques[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001145 }
1146 }
1147
1148 /* *default-stmt */
1149 if (d->dflts) {
1150 switch (target->nodetype) {
1151 case LYS_LEAF:
1152 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1153 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
1154
Michal Vaskoc621d862022-11-08 14:23:45 +01001155 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflts[0], &((struct lysp_node_leaf *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001156 break;
1157 case LYS_LEAFLIST:
1158 LY_ARRAY_FOR(d->dflts, u) {
1159 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
Michal Vaskoc621d862022-11-08 14:23:45 +01001160 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflts[u], qname), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001161 }
1162 break;
1163 case LYS_CHOICE:
1164 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1165 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
1166
Michal Vaskoc621d862022-11-08 14:23:45 +01001167 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflts[0], &((struct lysp_node_choice *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001168 break;
1169 default:
1170 AMEND_WRONG_NODETYPE("deviation", "add", "default");
1171 }
1172 }
1173
1174 /* [config-stmt] */
1175 if (d->flags & LYS_CONFIG_MASK) {
1176 switch (target->nodetype) {
1177 case LYS_CONTAINER:
1178 case LYS_LEAF:
1179 case LYS_LEAFLIST:
1180 case LYS_LIST:
1181 case LYS_CHOICE:
1182 case LYS_ANYDATA:
1183 case LYS_ANYXML:
1184 break;
1185 default:
1186 AMEND_WRONG_NODETYPE("deviation", "add", "config");
1187 }
1188
1189 if (target->flags & LYS_CONFIG_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001190 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001191 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
1192 target->flags & LYS_CONFIG_W ? "true" : "false");
1193 ret = LY_EVALID;
1194 goto cleanup;
1195 }
1196
1197 target->flags |= d->flags & LYS_CONFIG_MASK;
1198 }
1199
1200 /* [mandatory-stmt] */
1201 if (d->flags & LYS_MAND_MASK) {
1202 switch (target->nodetype) {
1203 case LYS_LEAF:
1204 case LYS_CHOICE:
1205 case LYS_ANYDATA:
1206 case LYS_ANYXML:
1207 break;
1208 default:
1209 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
1210 }
1211
1212 if (target->flags & LYS_MAND_MASK) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001213 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001214 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
1215 target->flags & LYS_MAND_TRUE ? "true" : "false");
1216 ret = LY_EVALID;
1217 goto cleanup;
1218 }
1219
1220 target->flags |= d->flags & LYS_MAND_MASK;
1221 }
1222
1223 /* [min-elements-stmt] */
1224 if (d->flags & LYS_SET_MIN) {
1225 switch (target->nodetype) {
1226 case LYS_LEAFLIST:
1227 num = &((struct lysp_node_leaflist *)target)->min;
1228 break;
1229 case LYS_LIST:
1230 num = &((struct lysp_node_list *)target)->min;
1231 break;
1232 default:
1233 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
1234 }
1235
1236 if (target->flags & LYS_SET_MIN) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001237 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001238 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
1239 ret = LY_EVALID;
1240 goto cleanup;
1241 }
1242
1243 *num = d->min;
1244 }
1245
1246 /* [max-elements-stmt] */
1247 if (d->flags & LYS_SET_MAX) {
1248 switch (target->nodetype) {
1249 case LYS_LEAFLIST:
1250 num = &((struct lysp_node_leaflist *)target)->max;
1251 break;
1252 case LYS_LIST:
1253 num = &((struct lysp_node_list *)target)->max;
1254 break;
1255 default:
1256 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1257 }
1258
1259 if (target->flags & LYS_SET_MAX) {
1260 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001261 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001262 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
1263 *num);
1264 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001265 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001266 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1267 }
1268 ret = LY_EVALID;
1269 goto cleanup;
1270 }
1271
1272 *num = d->max;
1273 }
1274
1275cleanup:
1276 return ret;
1277}
1278
1279/**
1280 * @brief Apply deviate delete.
1281 *
1282 * @param[in] ctx Compile context.
1283 * @param[in] d Deviate delete to apply.
1284 * @param[in,out] target Deviation target.
1285 * @return LY_ERR value.
1286 */
1287static LY_ERR
1288lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1289{
1290 LY_ERR ret = LY_SUCCESS;
1291 struct lysp_restr **musts;
1292 LY_ARRAY_COUNT_TYPE u, v;
1293 struct lysp_qname **uniques, **dflts;
1294
Michal Vaskoc636ea42022-09-16 10:20:31 +02001295#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, FREE_CTX, PROPERTY) \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001296 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1297 int found = 0; \
1298 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1299 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1300 found = 1; \
1301 break; \
1302 } \
1303 } \
1304 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001305 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001306 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1307 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1308 ret = LY_EVALID; \
1309 goto cleanup; \
1310 } \
1311 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
Michal Vaskoc636ea42022-09-16 10:20:31 +02001312 FREE_FUNC(FREE_CTX, &(ORIG_ARRAY)[v]); \
Michal Vasko08e9b112021-06-11 15:41:17 +02001313 if (v < LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1314 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1315 } \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001316 } \
1317 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1318 LY_ARRAY_FREE(ORIG_ARRAY); \
1319 ORIG_ARRAY = NULL; \
1320 }
1321
1322#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1323 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001324 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001325 ret = LY_EVALID; \
1326 goto cleanup; \
1327 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001328 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001329 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1330 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1331 ret = LY_EVALID; \
1332 goto cleanup; \
1333 }
1334
1335 /* [units-stmt] */
1336 if (d->units) {
1337 switch (target->nodetype) {
1338 case LYS_LEAF:
1339 case LYS_LEAFLIST:
1340 break;
1341 default:
1342 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1343 }
1344
1345 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001346 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001347 ((struct lysp_node_leaf *)target)->units = NULL;
1348 }
1349
1350 /* *must-stmt */
1351 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001352 musts = lysp_node_musts_p(target);
1353 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001354 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1355 }
1356
Michal Vaskoc636ea42022-09-16 10:20:31 +02001357 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, &ctx->free_ctx, "must");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001358 }
1359
1360 /* *unique-stmt */
1361 if (d->uniques) {
Michal Vasko4e55f5a2022-12-14 12:15:00 +01001362 if (target->nodetype != LYS_LIST) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001363 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1364 }
1365
1366 uniques = &((struct lysp_node_list *)target)->uniques;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001367 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, ctx->ctx, "unique");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001368 }
1369
1370 /* *default-stmt */
1371 if (d->dflts) {
1372 switch (target->nodetype) {
1373 case LYS_LEAF:
1374 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1375 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1376
Michal Vaskoe180ed02021-02-05 16:31:20 +01001377 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001378 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1379 break;
1380 case LYS_LEAFLIST:
1381 dflts = &((struct lysp_node_leaflist *)target)->dflts;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001382 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, ctx->ctx, "default");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001383 break;
1384 case LYS_CHOICE:
1385 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1386 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1387
Michal Vaskoe180ed02021-02-05 16:31:20 +01001388 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001389 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1390 break;
1391 default:
1392 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1393 }
1394 }
1395
1396cleanup:
1397 return ret;
1398}
1399
1400/**
1401 * @brief Apply deviate replace.
1402 *
1403 * @param[in] ctx Compile context.
1404 * @param[in] d Deviate replace to apply.
1405 * @param[in,out] target Deviation target.
1406 * @return LY_ERR value.
1407 */
1408static LY_ERR
1409lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1410{
1411 LY_ERR ret = LY_SUCCESS;
1412 uint32_t *num;
1413
1414#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1415 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001416 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001417 ret = LY_EVALID; \
1418 goto cleanup; \
1419 }
1420
1421 /* [type-stmt] */
1422 if (d->type) {
1423 switch (target->nodetype) {
1424 case LYS_LEAF:
1425 case LYS_LEAFLIST:
1426 break;
1427 default:
1428 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1429 }
1430
Michal Vaskoc636ea42022-09-16 10:20:31 +02001431 lysp_type_free(&ctx->free_ctx, &((struct lysp_node_leaf *)target)->type);
Michal Vaskoc621d862022-11-08 14:23:45 +01001432 lysp_type_dup(ctx->ctx, ctx->pmod, d->type, &((struct lysp_node_leaf *)target)->type);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001433 }
1434
1435 /* [units-stmt] */
1436 if (d->units) {
1437 switch (target->nodetype) {
1438 case LYS_LEAF:
1439 case LYS_LEAFLIST:
1440 break;
1441 default:
1442 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1443 }
1444
1445 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001446 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001447 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1448 }
1449
1450 /* [default-stmt] */
1451 if (d->dflt.str) {
1452 switch (target->nodetype) {
1453 case LYS_LEAF:
1454 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1455
Michal Vaskoe180ed02021-02-05 16:31:20 +01001456 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +01001457 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflt, &((struct lysp_node_leaf *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001458 break;
1459 case LYS_CHOICE:
Michal Vasko7b3a00e2023-08-09 11:58:03 +02001460 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001461
Michal Vaskoe180ed02021-02-05 16:31:20 +01001462 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +01001463 LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &d->dflt, &((struct lysp_node_choice *)target)->dflt), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001464 break;
1465 default:
1466 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1467 }
1468 }
1469
1470 /* [config-stmt] */
1471 if (d->flags & LYS_CONFIG_MASK) {
1472 switch (target->nodetype) {
1473 case LYS_CONTAINER:
1474 case LYS_LEAF:
1475 case LYS_LEAFLIST:
1476 case LYS_LIST:
1477 case LYS_CHOICE:
1478 case LYS_ANYDATA:
1479 case LYS_ANYXML:
1480 break;
1481 default:
1482 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1483 }
1484
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001485 target->flags &= ~LYS_CONFIG_MASK;
1486 target->flags |= d->flags & LYS_CONFIG_MASK;
1487 }
1488
1489 /* [mandatory-stmt] */
1490 if (d->flags & LYS_MAND_MASK) {
1491 switch (target->nodetype) {
1492 case LYS_LEAF:
1493 case LYS_CHOICE:
1494 case LYS_ANYDATA:
1495 case LYS_ANYXML:
1496 break;
1497 default:
1498 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1499 }
1500
1501 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001502 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1503 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001504 ret = LY_EVALID;
1505 goto cleanup;
1506 }
1507
1508 target->flags &= ~LYS_MAND_MASK;
1509 target->flags |= d->flags & LYS_MAND_MASK;
1510 }
1511
1512 /* [min-elements-stmt] */
1513 if (d->flags & LYS_SET_MIN) {
1514 switch (target->nodetype) {
1515 case LYS_LEAFLIST:
1516 num = &((struct lysp_node_leaflist *)target)->min;
1517 break;
1518 case LYS_LIST:
1519 num = &((struct lysp_node_list *)target)->min;
1520 break;
1521 default:
1522 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1523 }
1524
1525 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001526 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001527 ret = LY_EVALID;
1528 goto cleanup;
1529 }
1530
1531 *num = d->min;
1532 }
1533
1534 /* [max-elements-stmt] */
1535 if (d->flags & LYS_SET_MAX) {
1536 switch (target->nodetype) {
1537 case LYS_LEAFLIST:
1538 num = &((struct lysp_node_leaflist *)target)->max;
1539 break;
1540 case LYS_LIST:
1541 num = &((struct lysp_node_list *)target)->max;
1542 break;
1543 default:
1544 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1545 }
1546
1547 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001548 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001549 ret = LY_EVALID;
1550 goto cleanup;
1551 }
1552
1553 *num = d->max;
1554 }
1555
1556cleanup:
1557 return ret;
1558}
1559
1560/**
Michal Vasko193dacd2022-10-13 08:43:05 +02001561 * @brief Apply deviation with all its deviates.
1562 *
1563 * @param[in] ctx Compile context.
1564 * @param[in] dev Deviation to apply.
1565 * @param[in] dev_pmod Local module of the deviation.
1566 * @param[in,out] target Deviation target.
1567 * @return LY_ERR value.
1568 */
1569static LY_ERR
1570lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const struct lysp_module *dev_pmod,
1571 struct lysp_node *target)
1572{
1573 LY_ERR ret = LY_SUCCESS;
1574 struct lys_module *orig_mod = ctx->cur_mod;
1575 struct lysp_module *orig_pmod = ctx->pmod;
1576 char orig_path[LYSC_CTX_BUFSIZE];
1577 struct lysp_deviate *d;
1578
1579 /* clear path and set modules */
1580 strcpy(orig_path, ctx->path);
1581 ctx->path_len = 1;
1582 ctx->cur_mod = dev_pmod->mod;
1583 ctx->pmod = (struct lysp_module *)dev_pmod;
1584
1585 /* generate correct path */
1586 lysc_update_path(ctx, NULL, "{deviation}");
1587 lysc_update_path(ctx, NULL, dev->nodeid);
1588
1589 LY_LIST_FOR(dev->deviates, d) {
1590 switch (d->mod) {
1591 case LYS_DEV_ADD:
1592 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, target);
1593 break;
1594 case LYS_DEV_DELETE:
1595 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, target);
1596 break;
1597 case LYS_DEV_REPLACE:
1598 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, target);
1599 break;
1600 default:
1601 LOGINT(ctx->ctx);
1602 ret = LY_EINT;
1603 }
1604 LY_CHECK_GOTO(ret, cleanup);
1605 }
1606
1607 /* deviation extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +01001608 DUP_EXTS(ctx->ctx, dev_pmod, target, lyplg_ext_nodetype2stmt(target->nodetype), dev->exts, target->exts, lysp_ext_dup);
Michal Vasko193dacd2022-10-13 08:43:05 +02001609
1610cleanup:
1611 ctx->cur_mod = orig_mod;
1612 ctx->pmod = orig_pmod;
1613
1614 strcpy(ctx->path, orig_path);
1615 ctx->path_len = strlen(ctx->path);
1616 return ret;
1617}
1618
1619/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001620 * @brief Check whether a compiled node matches a single schema nodeid name test.
1621 *
1622 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1623 * @param[in] mod Expected module.
Michal Vasko8824a6e2024-01-19 12:42:21 +01001624 * @param[in] name_dict Expected name, in the dictionary.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001625 * @return Whether it is a match or not.
1626 */
1627static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001628lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name_dict)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001629{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001630 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001631 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001632 return 0;
1633 }
1634
1635 /* compare names */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001636 if ((*node)->name != name_dict) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001637 return 0;
1638 }
1639
Michal Vasko2a668712020-10-21 11:48:09 +02001640 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001641 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001642
1643 return 1;
1644}
1645
1646/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001647 * @brief Check whether a compiled ext instance matches a single schema nodeid name test.
1648 *
1649 * @param[in,out] ext Compiled ext instance to consider. On a match it is zeroed to not match again.
1650 * @param[in] mod Expected module.
Michal Vasko8824a6e2024-01-19 12:42:21 +01001651 * @param[in] name Expected name, in the dictionary.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001652 * @return Whether it is a match or not.
1653 */
1654static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001655lysp_schema_nodeid_match_ext(const struct lysc_ext_instance **ext, const struct lys_module *mod, const char *name_dict)
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001656{
1657 /* compare with the module */
1658 if ((*ext)->module != mod) {
1659 return 0;
1660 }
1661
1662 /* compare names (argument) */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001663 if ((*ext)->argument != name_dict) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001664 return 0;
1665 }
1666
1667 /* zero */
1668 *ext = NULL;
1669
1670 return 1;
1671}
1672
1673/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001674 * @brief Check whether a node matches specific schema nodeid.
1675 *
Michal Vasko8824a6e2024-01-19 12:42:21 +01001676 * @param[in] nodeid Compiled nodeid to match.
1677 * @param[in] nodeid_pmod Module to use for nodes in @p nodeid without a prefix.
1678 * @param[in] nodeid_ext Extension instance in which @p nodeid is defined, it means it targets an extension instance.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001679 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1680 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1681 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1682 * @param[in] pnode_mod Compiled @p pnode to-be module.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001683 * @param[in] pnode_ext Extension instance in which @p pnode is defined.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001684 * @return Whether it is a match or not.
1685 */
1686static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001687lysp_schema_nodeid_match(const struct lysc_nodeid *nodeid, const struct lysp_module *nodeid_pmod,
1688 const struct lysp_ext_instance *nodeid_ext, const struct lysc_node *ctx_node, const struct lysc_node *parent,
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001689 const struct lysp_node *pnode, const struct lys_module *pnode_mod, const struct lysc_ext_instance *pnode_ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001690{
1691 uint32_t i;
1692 const struct lys_module *mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001693
Michal Vasko8824a6e2024-01-19 12:42:21 +01001694 if (nodeid_ext && !pnode_ext) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001695 /* extension instance augment and standard node, will never match */
1696 return 0;
Michal Vasko8824a6e2024-01-19 12:42:21 +01001697 } else if (!nodeid_ext && pnode_ext) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001698 /* standard augment and extension instance node, will never match */
1699 return 0;
1700 }
1701
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001702 /* compare last node in the node ID */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001703 i = nodeid->count - 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001704
1705 /* get exp node ID module */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001706 mod = lys_schema_node_get_module(nodeid_pmod->mod->ctx, nodeid->prefix[i], nodeid_pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001707 assert(mod);
1708
1709 if (pnode) {
1710 /* compare on the last parsed-only node */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001711 if ((pnode_mod != mod) || (pnode->name != nodeid->name[i])) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001712 return 0;
1713 }
1714 } else {
1715 /* using parent directly */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001716 if (!lysp_schema_nodeid_match_node(&parent, mod, nodeid->name[i])) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001717 return 0;
1718 }
1719 }
1720
1721 /* now compare all the compiled parents */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001722 while (i) {
1723 --i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001724
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001725 if (!parent && !pnode_ext) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001726 /* no more parents but path continues */
1727 return 0;
1728 }
1729
1730 /* get exp node ID module */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001731 mod = lys_schema_node_get_module(nodeid_pmod->mod->ctx, nodeid->prefix[i], nodeid_pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001732 assert(mod);
1733
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001734 if (parent) {
1735 /* compare with the parent */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001736 if (!lysp_schema_nodeid_match_node(&parent, mod, nodeid->name[i])) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001737 return 0;
1738 }
1739 } else {
1740 /* compare with the ext instance */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001741 if (!lysp_schema_nodeid_match_ext(&pnode_ext, mod, nodeid->name[i])) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001742 return 0;
1743 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001744 }
1745 }
1746
1747 if (ctx_node && (ctx_node != parent)) {
1748 /* descendant path has not finished in the context node */
1749 return 0;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001750 } else if (!ctx_node && (parent || pnode_ext)) {
1751 /* some parent/extension was not matched */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001752 return 0;
1753 }
1754
1755 return 1;
1756}
1757
1758void
1759lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1760{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001761 if (!aug) {
1762 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001763 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001764
1765 lysc_nodeid_free(ctx, aug->nodeid);
1766 free(aug);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001767}
1768
1769void
1770lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1771{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001772 if (!dev) {
1773 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001774 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001775
1776 lysc_nodeid_free(ctx, dev->nodeid);
1777 LY_ARRAY_FREE(dev->devs);
1778 LY_ARRAY_FREE(dev->dev_pmods);
1779 free(dev);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001780}
1781
1782void
1783lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1784{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001785 if (!rfn) {
1786 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001787 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001788
1789 lysc_nodeid_free(ctx, rfn->nodeid);
1790 LY_ARRAY_FREE(rfn->rfns);
1791 free(rfn);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001792}
1793
1794void
Michal Vaskoc636ea42022-09-16 10:20:31 +02001795lysp_dev_node_free(struct lysc_ctx *cctx, struct lysp_node *dev_pnode)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001796{
1797 if (!dev_pnode) {
1798 return;
1799 }
1800
1801 switch (dev_pnode->nodetype) {
1802 case LYS_CONTAINER:
1803 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001804 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1805 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001806 break;
1807 case LYS_LIST:
1808 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001809 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1810 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001811 break;
1812 case LYS_CHOICE:
1813 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1814 break;
1815 case LYS_CASE:
1816 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1817 break;
1818 case LYS_LEAF:
1819 case LYS_LEAFLIST:
1820 case LYS_ANYXML:
1821 case LYS_ANYDATA:
1822 /* no children */
1823 break;
1824 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001825 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001826 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001827 case LYS_RPC:
1828 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001829 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1830 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001831 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001832 case LYS_INPUT:
1833 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001834 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001835 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001836 free(dev_pnode);
1837 return;
1838 default:
Michal Vaskoc636ea42022-09-16 10:20:31 +02001839 LOGINT(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001840 return;
1841 }
1842
Michal Vaskoc636ea42022-09-16 10:20:31 +02001843 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001844}
1845
1846LY_ERR
1847lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1848 struct lysp_node **dev_pnode, ly_bool *not_supported)
1849{
1850 LY_ERR ret = LY_SUCCESS;
1851 uint32_t i;
1852 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001853 struct lysc_refine *rfn;
1854 struct lysc_deviation *dev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001855
1856 *dev_pnode = NULL;
1857 *not_supported = 0;
1858
Michal Vaskoee057572022-05-26 08:31:52 +02001859 for (i = 0; i < ctx->uses_rfns.count; ) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001860 rfn = ctx->uses_rfns.objs[i];
1861
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001862 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, NULL, rfn->nodeid_ctx_node, parent, pnode,
1863 ctx->cur_mod, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001864 /* not our target node */
Michal Vaskoee057572022-05-26 08:31:52 +02001865 ++i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001866 continue;
1867 }
1868
1869 if (!*dev_pnode) {
1870 /* first refine on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001871 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001872 }
1873
1874 /* apply all the refines by changing (the copy of) the parsed node */
1875 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001876 LY_CHECK_GOTO(ret = lys_apply_refine(ctx, rfn->rfns[u], rfn->nodeid_pmod, *dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001877 }
1878
1879 /* refine was applied, remove it */
1880 lysc_refine_free(ctx->ctx, rfn);
1881 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1882
Michal Vaskoee057572022-05-26 08:31:52 +02001883 /* refines use relative paths so more may apply to a single node */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001884 }
1885
1886 for (i = 0; i < ctx->devs.count; ++i) {
1887 dev = ctx->devs.objs[i];
1888
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001889 if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, NULL, parent, pnode, ctx->cur_mod, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001890 /* not our target node */
1891 continue;
1892 }
1893
1894 if (dev->not_supported) {
1895 /* it is not supported, no more deviations */
1896 *not_supported = 1;
1897 goto dev_applied;
1898 }
1899
1900 if (!*dev_pnode) {
1901 /* first deviation on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001902 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001903 }
1904
1905 /* apply all the deviates by changing (the copy of) the parsed node */
1906 LY_ARRAY_FOR(dev->devs, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001907 LY_CHECK_GOTO(ret = lys_apply_deviation(ctx, dev->devs[u], dev->dev_pmods[u], *dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001908 }
1909
1910dev_applied:
1911 /* deviation was applied, remove it */
1912 lysc_deviation_free(ctx->ctx, dev);
1913 ly_set_rm_index(&ctx->devs, i, NULL);
1914
1915 /* all the deviations for one target node are in one structure, we are done */
1916 break;
1917 }
1918
1919cleanup:
1920 if (ret) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001921 lysp_dev_node_free(ctx, *dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001922 *dev_pnode = NULL;
1923 *not_supported = 0;
1924 }
1925 return ret;
1926}
1927
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001928/**
1929 * @brief Compile augment children.
1930 *
1931 * @param[in] ctx Compile context.
1932 * @param[in] aug_when Parsed augment when to inherit.
1933 * @param[in] aug_flags Parsed augment flags.
1934 * @param[in] child First augment child to compile.
1935 * @param[in] target Target node of the augment.
1936 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
1937 * @return LY_SUCCESS on success.
1938 * @return LY_EVALID on failure.
1939 */
1940static LY_ERR
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001941lys_compile_augment_children(struct lysc_ctx *ctx, struct lysp_when *aug_when, uint16_t aug_flags, struct lysp_node *child,
Michal Vaskoa084fa32022-05-16 11:32:58 +02001942 struct lysc_node *target, ly_bool child_unres_disabled)
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001943{
1944 LY_ERR rc = LY_SUCCESS;
1945 struct lysp_node *pnode;
1946 struct lysc_node *node;
1947 struct lysc_when *when_shared = NULL;
1948 ly_bool enabled, allow_mand = 0;
1949 struct ly_set child_set = {0};
1950 uint32_t i, opt_prev = ctx->compile_opts;
1951
1952 /* check for mandatory nodes
1953 * - new cases augmenting some choice can have mandatory nodes
1954 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1955 */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001956 if (aug_when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001957 allow_mand = 1;
1958 }
1959
1960 LY_LIST_FOR(child, pnode) {
1961 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1962 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1963 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1964 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1965 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1966 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1967 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1968 rc = LY_EVALID;
1969 goto cleanup;
1970 }
1971
1972 /* compile the children */
1973 if (target->nodetype == LYS_CHOICE) {
1974 LY_CHECK_GOTO(rc = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1975 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1976 if (target->nodetype == LYS_INPUT) {
1977 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
1978 } else {
1979 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
1980 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001981 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001982 } else {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001983 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001984 }
1985
1986 /* eval if-features again for the rest of this node processing */
1987 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1988 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001989 ctx->compile_opts |= LYS_COMPILE_DISABLED;
1990 }
1991
1992 /* since the augment node is not present in the compiled tree, we need to pass some of its
1993 * statements to all its children */
1994 for (i = 0; i < child_set.count; ++i) {
1995 node = child_set.snodes[i];
1996 if (!allow_mand && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1997 node->flags &= ~LYS_MAND_TRUE;
1998 lys_compile_mandatory_parents(target, 0);
1999 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
2000 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
2001 node->name);
2002 rc = LY_EVALID;
2003 goto cleanup;
2004 }
2005
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002006 if (aug_when) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002007 /* pass augment's when to all the children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002008 rc = lys_compile_when(ctx, aug_when, aug_flags, target, lysc_data_node(target), node, &when_shared);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002009 LY_CHECK_GOTO(rc, cleanup);
2010 }
2011
Michal Vaskoa084fa32022-05-16 11:32:58 +02002012 if (child_unres_disabled) {
Michal Vaskoad0980a2022-05-09 11:43:47 +02002013 /* child is disabled by the augment if-features */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002014 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
2015 }
2016 }
2017
2018 /* next iter */
2019 ly_set_erase(&child_set, NULL);
2020 ctx->compile_opts = opt_prev;
2021 }
2022
2023cleanup:
2024 ly_set_erase(&child_set, NULL);
2025 ctx->compile_opts = opt_prev;
2026 return rc;
2027}
2028
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002029/**
2030 * @brief Compile the parsed augment connecting it into its target.
2031 *
2032 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
2033 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
2034 * are already implemented and compiled.
2035 *
2036 * @param[in] ctx Compile context.
2037 * @param[in] aug_p Parsed augment to compile.
2038 * @param[in] target Target node of the augment.
2039 * @return LY_SUCCESS on success.
2040 * @return LY_EVALID on failure.
2041 */
2042static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01002043lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002044{
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002045 LY_ERR rc = LY_SUCCESS;
Michal Vaskoa084fa32022-05-16 11:32:58 +02002046 ly_bool enabled, child_unres_disabled = 0;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002047 uint32_t opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002048
Michal Vasko95f736c2022-06-08 12:03:31 +02002049 assert(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
2050
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002051 /* nodetype checks */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002052 if (aug_p->actions && !lysc_node_actions_p(target)) {
2053 LOGVAL(ctx->ctx, LYVE_REFERENCE,
2054 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
2055 lys_nodetype2str(target->nodetype), aug_p->actions->name);
2056 rc = LY_EVALID;
2057 goto cleanup;
2058 }
2059 if (aug_p->notifs && !lysc_node_notifs_p(target)) {
2060 LOGVAL(ctx->ctx, LYVE_REFERENCE,
2061 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
2062 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
2063 rc = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002064 goto cleanup;
2065 }
2066
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002067 /* augment if-features */
2068 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, aug_p->iffeatures, &enabled), cleanup);
2069 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002070 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vaskoa084fa32022-05-16 11:32:58 +02002071 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002072 }
2073
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002074 /* augment children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002075 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, aug_p->child, target, child_unres_disabled);
2076 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002077
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002078 /* augment actions */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002079 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->actions, target,
2080 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002081 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002082
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002083 /* augment notifications */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002084 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->notifs, target,
2085 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002086 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002087
Michal Vasko193dacd2022-10-13 08:43:05 +02002088 /* compile extensions into the target */
2089 COMPILE_EXTS_GOTO(ctx, aug_p->exts, target->exts, target, rc, cleanup);
2090
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002091cleanup:
Michal Vasko7c565922021-06-10 14:58:27 +02002092 ctx->compile_opts = opt_prev;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002093 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002094}
2095
2096LY_ERR
2097lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
2098{
2099 LY_ERR ret = LY_SUCCESS;
2100 struct lys_module *orig_mod = ctx->cur_mod;
2101 struct lysp_module *orig_pmod = ctx->pmod;
2102 uint32_t i;
2103 char orig_path[LYSC_CTX_BUFSIZE];
2104 struct lysc_augment *aug;
2105
2106 /* uses augments */
2107 for (i = 0; i < ctx->uses_augs.count; ) {
2108 aug = ctx->uses_augs.objs[i];
2109
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002110 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->ext, aug->nodeid_ctx_node, node, NULL, NULL,
2111 ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002112 /* not our target node */
2113 ++i;
2114 continue;
2115 }
2116
Michal Vaskob8df5762021-01-12 15:15:53 +01002117 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002118 lysc_update_path(ctx, NULL, "{augment}");
2119 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01002120 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01002121
2122 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002123 ret = lys_compile_augment(ctx, aug->aug_p, node);
2124 lysc_update_path(ctx, NULL, NULL);
2125 lysc_update_path(ctx, NULL, NULL);
2126 LY_CHECK_GOTO(ret, cleanup);
2127
Michal Vaskoc75f2042021-06-08 14:57:03 +02002128 /* augment was applied, remove it (index and the whole set may have changed because other augments
2129 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002130 ly_set_rm(&ctx->uses_augs, aug, NULL);
2131 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002132 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002133 }
2134
2135 /* top-level augments */
2136 for (i = 0; i < ctx->augs.count; ) {
2137 aug = ctx->augs.objs[i];
2138
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002139 if (!lysp_schema_nodeid_match(aug->nodeid, aug->aug_pmod, aug->ext, NULL, node, NULL, NULL, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002140 /* not our target node */
2141 ++i;
2142 continue;
2143 }
2144
Michal Vaskob8df5762021-01-12 15:15:53 +01002145 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002146 strcpy(orig_path, ctx->path);
2147 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002148 ctx->cur_mod = aug->aug_pmod->mod;
2149 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02002150 lysc_update_path(ctx, NULL, "{augment}");
2151 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01002152
2153 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002154 ret = lys_compile_augment(ctx, aug->aug_p, node);
2155 strcpy(ctx->path, orig_path);
2156 ctx->path_len = strlen(ctx->path);
2157 LY_CHECK_GOTO(ret, cleanup);
2158
2159 /* augment was applied, remove it */
2160 ly_set_rm(&ctx->augs, aug, NULL);
2161 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002162 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002163 }
2164
2165cleanup:
2166 ctx->cur_mod = orig_mod;
2167 ctx->pmod = orig_pmod;
2168 return ret;
2169}
2170
2171/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002172 * @brief Prepare an absolute-nodeid augment to be applied during data nodes compilation.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002173 *
2174 * @param[in] ctx Compile context.
2175 * @param[in] aug_p Parsed augment to be applied.
2176 * @param[in] pmod Both current and prefix module for @p aug_p.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002177 * @param[in] ext Extension instance in case @p aug_p is defined in one.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002178 * @return LY_ERR value.
2179 */
2180static LY_ERR
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002181lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, const struct lysp_module *pmod,
2182 const struct lysp_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002183{
2184 LY_ERR ret = LY_SUCCESS;
Michal Vasko8824a6e2024-01-19 12:42:21 +01002185 struct lysc_nodeid *nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002186 struct lysc_augment *aug;
2187 const struct lys_module *mod;
2188
Michal Vasko8824a6e2024-01-19 12:42:21 +01002189 /* compile its target, it was already parsed and fully checked (except for the existence of the nodes) */
2190 ret = lys_precompile_nodeid(ctx->ctx, aug_p->nodeid, &nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002191 LY_CHECK_GOTO(ret, cleanup);
2192
Michal Vasko8824a6e2024-01-19 12:42:21 +01002193 mod = lys_schema_node_get_module(ctx->ctx, nodeid->prefix[0], pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002194 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2195 if (mod != ctx->cur_mod) {
2196 /* augment for another module, ignore */
2197 goto cleanup;
2198 }
2199
2200 /* allocate new compiled augment and store it in the set */
2201 aug = calloc(1, sizeof *aug);
2202 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2203 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2204
Michal Vasko8824a6e2024-01-19 12:42:21 +01002205 aug->nodeid = nodeid;
2206 nodeid = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002207 aug->aug_pmod = pmod;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002208 aug->ext = ext;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002209 aug->aug_p = aug_p;
2210
2211cleanup:
Michal Vasko8824a6e2024-01-19 12:42:21 +01002212 lysc_nodeid_free(ctx->ctx, nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002213 return ret;
2214}
2215
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002216/**
2217 * @brief Prepare all top-level augments and extension instance augments to be applied during data nodes compilation.
2218 *
2219 * @param[in] ctx Compile context.
2220 * @param[in] pmod Parsed mod to use.
2221 * @return LY_ERR value.
2222 */
2223static LY_ERR
2224lys_precompile_own_augments_mod(struct lysc_ctx *ctx, const struct lysp_module *pmod)
2225{
2226 LY_ARRAY_COUNT_TYPE u, v;
2227 struct lysp_node_augment *aug_p;
2228
2229 /* module */
2230 LY_LIST_FOR(pmod->augments, aug_p) {
2231 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, NULL));
2232 }
2233
2234 /* parsed extension instances */
2235 LY_ARRAY_FOR(pmod->exts, u) {
2236 aug_p = NULL;
2237 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2238 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2239 aug_p = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2240 break;
2241 }
2242 }
2243 if (!aug_p) {
2244 continue;
2245 }
2246
2247 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, &pmod->exts[u]));
2248 }
2249
2250 return LY_SUCCESS;
2251}
2252
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002253LY_ERR
2254lys_precompile_own_augments(struct lysc_ctx *ctx)
2255{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002256 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002257 const struct lys_module *aug_mod;
2258 const struct lysp_module *submod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002259
2260 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002261 aug_mod = ctx->cur_mod->augmented_by[u];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002262
2263 /* collect all module augments */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002264 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002265
2266 /* collect all submodules augments */
2267 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002268 submod = (struct lysp_module *)aug_mod->parsed->includes[v].submodule;
2269
2270 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, submod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002271 }
2272 }
2273
2274 return LY_SUCCESS;
2275}
2276
2277/**
2278 * @brief Prepare a deviation to be applied during data nodes compilation.
2279 *
2280 * @param[in] ctx Compile context.
2281 * @param[in] dev_p Parsed deviation to be applied.
2282 * @param[in] pmod Both current and prefix module for @p dev_p.
2283 * @return LY_ERR value.
2284 */
2285static LY_ERR
2286lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2287{
2288 LY_ERR ret = LY_SUCCESS;
2289 struct lysc_deviation *dev = NULL;
Michal Vasko8824a6e2024-01-19 12:42:21 +01002290 struct lysc_nodeid *nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002291 struct lysp_deviation **new_dev;
2292 const struct lys_module *mod;
2293 const struct lysp_module **new_dev_pmod;
2294 uint32_t i;
2295
2296 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
Michal Vasko8824a6e2024-01-19 12:42:21 +01002297 ret = lys_precompile_nodeid(ctx->ctx, dev_p->nodeid, &nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002298 LY_CHECK_GOTO(ret, cleanup);
2299
Michal Vasko8824a6e2024-01-19 12:42:21 +01002300 mod = lys_schema_node_get_module(ctx->ctx, nodeid->prefix[0], pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002301 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2302 if (mod != ctx->cur_mod) {
2303 /* deviation for another module, ignore */
2304 goto cleanup;
2305 }
2306
2307 /* try to find the node in already compiled deviations */
2308 for (i = 0; i < ctx->devs.count; ++i) {
Michal Vasko8824a6e2024-01-19 12:42:21 +01002309 if (lys_abs_schema_nodeid_match(ctx->ctx, nodeid, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002310 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2311 dev = ctx->devs.objs[i];
2312 break;
2313 }
2314 }
2315
2316 if (!dev) {
2317 /* allocate new compiled deviation */
2318 dev = calloc(1, sizeof *dev);
2319 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2320 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2321
Michal Vasko8824a6e2024-01-19 12:42:21 +01002322 dev->nodeid = nodeid;
2323 nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002324 }
2325
2326 /* add new parsed deviation structure */
2327 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2328 *new_dev = dev_p;
2329 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2330 *new_dev_pmod = pmod;
2331
2332cleanup:
Michal Vasko8824a6e2024-01-19 12:42:21 +01002333 lysc_nodeid_free(ctx->ctx, nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002334 return ret;
2335}
2336
2337LY_ERR
2338lys_precompile_own_deviations(struct lysc_ctx *ctx)
2339{
2340 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002341 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002342 const struct lys_module *dev_mod;
2343 struct lysc_deviation *dev;
2344 struct lysp_deviate *d;
2345 int not_supported;
2346 uint32_t i;
2347
2348 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2349 dev_mod = ctx->cur_mod->deviated_by[u];
2350
2351 /* compile all module deviations */
2352 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2353 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2354 }
2355
2356 /* compile all submodules deviations */
2357 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2358 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2359 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2360 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2361 }
2362 }
2363 }
2364
2365 /* set not-supported flags for all the deviations */
2366 for (i = 0; i < ctx->devs.count; ++i) {
2367 dev = ctx->devs.objs[i];
2368 not_supported = 0;
2369
2370 LY_ARRAY_FOR(dev->devs, u) {
2371 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2372 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2373 not_supported = 1;
2374 break;
2375 }
2376 }
2377 if (not_supported) {
2378 break;
2379 }
2380 }
2381 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002382 orig_cur_mod = ctx->cur_mod;
2383 ctx->cur_mod = dev->dev_pmods[u]->mod;
2384 lysc_update_path(ctx, NULL, "{deviation}");
Michal Vasko8824a6e2024-01-19 12:42:21 +01002385 lysc_update_path(ctx, NULL, dev->nodeid->str);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002386 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko8824a6e2024-01-19 12:42:21 +01002387 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->str);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002388 lysc_update_path(ctx, NULL, NULL);
2389 lysc_update_path(ctx, NULL, NULL);
2390 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002391 return LY_EVALID;
2392 }
2393
2394 dev->not_supported = not_supported;
2395 }
2396
2397 return LY_SUCCESS;
2398}
2399
2400/**
2401 * @brief Add a module reference into an array, checks for duplicities.
2402 *
2403 * @param[in] ctx Compile context.
2404 * @param[in] mod Module reference to add.
2405 * @param[in,out] mod_array Module sized array to add to.
2406 * @return LY_ERR value.
2407 */
2408static LY_ERR
2409lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2410{
2411 LY_ARRAY_COUNT_TYPE u;
2412 struct lys_module **new_mod;
2413
2414 LY_ARRAY_FOR(*mod_array, u) {
2415 if ((*mod_array)[u] == mod) {
2416 /* already there */
2417 return LY_EEXIST;
2418 }
2419 }
2420
2421 /* add the new module ref */
2422 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2423 *new_mod = mod;
2424
2425 return LY_SUCCESS;
2426}
2427
Michal Vasko1ccbf542021-04-19 11:35:00 +02002428/**
2429 * @brief Check whether all modules in a set are implemented.
2430 *
2431 * @param[in] mod_set Module set to check.
2432 * @return Whether all modules are implemented or not.
2433 */
2434static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002435lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002436{
2437 uint32_t i;
2438 const struct lys_module *mod;
2439
2440 for (i = 0; i < mod_set->count; ++i) {
2441 mod = mod_set->objs[i];
2442 if (!mod->implemented) {
2443 return 0;
2444 }
2445 }
2446
2447 return 1;
2448}
2449
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002450/**
2451 * @brief Add references to target modules of top-level augments, deviations, and augments in extension instances
2452 * in a module and all its submodules.
2453 *
2454 * @param[in] pmod Module to process.
2455 * @param[in,out] mod_set Module set to add referenced modules into.
2456 * @return LY_SUCCESS on success.
2457 * @return LY_ERR on error.
2458 */
2459static LY_ERR
2460lys_precompile_mod_augments_deviations(struct lysp_module *pmod, struct ly_set *mod_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002461{
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002462 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002463 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002464 struct lysc_ctx ctx;
Michal Vasko65333882021-06-10 14:12:16 +02002465 struct lys_module *m;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002466 struct lysp_node_augment *aug;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002467 struct ly_set set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002468
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002469 LYSC_CTX_INIT_PMOD(ctx, pmod, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002470
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002471 LY_LIST_FOR(pmod->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002472 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002473 lysc_update_path(&ctx, NULL, "{augment}");
2474 lysc_update_path(&ctx, NULL, aug->nodeid);
2475 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2476 lysc_update_path(&ctx, NULL, NULL);
2477 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002478 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002479
Michal Vasko1ccbf542021-04-19 11:35:00 +02002480 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002481 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002482 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002483 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002484 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002485 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002486 }
2487
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002488 LY_ARRAY_FOR(pmod->deviations, u) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002489 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002490 lysc_update_path(&ctx, NULL, "{deviation}");
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002491 lysc_update_path(&ctx, NULL, pmod->deviations[u].nodeid);
2492 ret = lys_nodeid_mod_check(&ctx, pmod->deviations[u].nodeid, 1, &set, NULL, &m);
Michal Vasko65333882021-06-10 14:12:16 +02002493 lysc_update_path(&ctx, NULL, NULL);
2494 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002495 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002496
Michal Vasko1ccbf542021-04-19 11:35:00 +02002497 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002498 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002499 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002500 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002501 }
2502 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002503 }
2504
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002505 LY_ARRAY_FOR(pmod->exts, u) {
2506 aug = NULL;
2507 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2508 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2509 aug = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2510 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002511 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002512 }
2513 if (!aug) {
2514 continue;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002515 }
2516
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002517 /* get target module */
2518 lysc_update_path(&ctx, NULL, "{ext-augment}");
2519 lysc_update_path(&ctx, NULL, aug->nodeid);
2520 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2521 lysc_update_path(&ctx, NULL, NULL);
2522 lysc_update_path(&ctx, NULL, NULL);
2523 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002524
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002525 /* add this module into the target module augmented_by, if not there and implemented */
2526 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
2527 !lys_precompile_mod_set_is_all_implemented(&set)) {
2528 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002529 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002530 ly_set_erase(&set, NULL);
2531 }
2532
2533cleanup:
2534 ly_set_erase(&set, NULL);
2535 return ret;
2536}
2537
2538LY_ERR
2539lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
2540{
2541 LY_ERR ret = LY_SUCCESS, r;
2542 LY_ARRAY_COUNT_TYPE u;
2543 struct lys_module *m;
2544 struct lysp_module *submod;
2545 const char **imp_f, *all_f[] = {"*", NULL};
2546 uint32_t i;
2547 struct ly_set mod_set = {0};
2548
2549 /* module */
2550 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(mod->parsed, &mod_set), cleanup);
2551
2552 /* submodules */
2553 LY_ARRAY_FOR(mod->parsed->includes, u) {
2554 submod = (struct lysp_module *)mod->parsed->includes[u].submodule;
2555 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(submod, &mod_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002556 }
2557
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002558 for (i = 0; i < mod_set.count; ++i) {
2559 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002560
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002561 if (m == mod) {
2562 /* will be applied normally later */
2563 continue;
2564 }
2565
2566 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2567 * not compiled yet and marked for compilation */
2568
2569 if (!m->implemented) {
2570 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002571 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2572 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002573 if (r == LY_ERECOMPILE) {
2574 /* implement all the modules right away to save possible later recompilation */
2575 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002576 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002577 } else if (r) {
2578 /* error */
2579 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002580 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002581 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002582 } else if (m->compiled) {
2583 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2584 m->to_compile = 1;
2585 ret = LY_ERECOMPILE;
2586 continue;
2587 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002588 }
2589
Michal Vasko1ccbf542021-04-19 11:35:00 +02002590cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +02002591 ly_set_erase(&mod_set, NULL);
2592 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002593}
2594
2595void
2596lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2597{
2598 uint32_t i;
2599 LY_ARRAY_COUNT_TYPE u, count;
2600 struct lys_module *m;
2601
2602 for (i = 0; i < ctx->list.count; ++i) {
2603 m = ctx->list.objs[i];
2604
2605 if (m->augmented_by) {
2606 count = LY_ARRAY_COUNT(m->augmented_by);
2607 for (u = 0; u < count; ++u) {
2608 if (m->augmented_by[u] == mod) {
2609 /* keep the order */
2610 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002611 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002612 }
2613 LY_ARRAY_DECREMENT(m->augmented_by);
2614 break;
2615 }
2616 }
2617 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2618 LY_ARRAY_FREE(m->augmented_by);
2619 m->augmented_by = NULL;
2620 }
2621 }
2622
2623 if (m->deviated_by) {
2624 count = LY_ARRAY_COUNT(m->deviated_by);
2625 for (u = 0; u < count; ++u) {
2626 if (m->deviated_by[u] == mod) {
2627 /* keep the order */
2628 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002629 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002630 }
2631 LY_ARRAY_DECREMENT(m->deviated_by);
2632 break;
2633 }
2634 }
2635 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2636 LY_ARRAY_FREE(m->deviated_by);
2637 m->deviated_by = NULL;
2638 }
2639 }
2640 }
2641}