blob: 5f1a5614d281c8a9773b85f18afbb3a124bea5a8 [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 Vasko21eaa392024-02-20 15:48:42 +0100226 nodeid_type, str, (int)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 Vasko21eaa392024-02-20 15:48:42 +0100237 nodeid_type, str, (int)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 Vasko21eaa392024-02-20 15:48:42 +0100247 nodeid_type, str, (int)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 Vasko21eaa392024-02-20 15:48:42 +01001238 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%" PRIu32 "\").",
1239 *num);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001240 ret = LY_EVALID;
1241 goto cleanup;
1242 }
1243
1244 *num = d->min;
1245 }
1246
1247 /* [max-elements-stmt] */
1248 if (d->flags & LYS_SET_MAX) {
1249 switch (target->nodetype) {
1250 case LYS_LEAFLIST:
1251 num = &((struct lysp_node_leaflist *)target)->max;
1252 break;
1253 case LYS_LIST:
1254 num = &((struct lysp_node_list *)target)->max;
1255 break;
1256 default:
1257 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
1258 }
1259
1260 if (target->flags & LYS_SET_MAX) {
1261 if (*num) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001262 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko21eaa392024-02-20 15:48:42 +01001263 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%" PRIu32 "\").",
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001264 *num);
1265 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001266 LOGVAL(ctx->ctx, LYVE_REFERENCE,
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001267 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
1268 }
1269 ret = LY_EVALID;
1270 goto cleanup;
1271 }
1272
1273 *num = d->max;
1274 }
1275
1276cleanup:
1277 return ret;
1278}
1279
1280/**
1281 * @brief Apply deviate delete.
1282 *
1283 * @param[in] ctx Compile context.
1284 * @param[in] d Deviate delete to apply.
1285 * @param[in,out] target Deviation target.
1286 * @return LY_ERR value.
1287 */
1288static LY_ERR
1289lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
1290{
1291 LY_ERR ret = LY_SUCCESS;
1292 struct lysp_restr **musts;
1293 LY_ARRAY_COUNT_TYPE u, v;
1294 struct lysp_qname **uniques, **dflts;
1295
Michal Vaskoc636ea42022-09-16 10:20:31 +02001296#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, FREE_CTX, PROPERTY) \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001297 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
1298 int found = 0; \
1299 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
1300 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
1301 found = 1; \
1302 break; \
1303 } \
1304 } \
1305 if (!found) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001306 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001307 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
1308 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
1309 ret = LY_EVALID; \
1310 goto cleanup; \
1311 } \
1312 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
Michal Vaskoc636ea42022-09-16 10:20:31 +02001313 FREE_FUNC(FREE_CTX, &(ORIG_ARRAY)[v]); \
Michal Vasko08e9b112021-06-11 15:41:17 +02001314 if (v < LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1315 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
1316 } \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001317 } \
1318 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
1319 LY_ARRAY_FREE(ORIG_ARRAY); \
1320 ORIG_ARRAY = NULL; \
1321 }
1322
1323#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1324 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001325 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001326 ret = LY_EVALID; \
1327 goto cleanup; \
1328 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001329 LOGVAL(ctx->ctx, LYVE_REFERENCE, \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001330 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
1331 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
1332 ret = LY_EVALID; \
1333 goto cleanup; \
1334 }
1335
1336 /* [units-stmt] */
1337 if (d->units) {
1338 switch (target->nodetype) {
1339 case LYS_LEAF:
1340 case LYS_LEAFLIST:
1341 break;
1342 default:
1343 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
1344 }
1345
1346 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001347 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001348 ((struct lysp_node_leaf *)target)->units = NULL;
1349 }
1350
1351 /* *must-stmt */
1352 if (d->musts) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001353 musts = lysp_node_musts_p(target);
1354 if (!musts) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001355 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
1356 }
1357
Michal Vaskoc636ea42022-09-16 10:20:31 +02001358 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, &ctx->free_ctx, "must");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001359 }
1360
1361 /* *unique-stmt */
1362 if (d->uniques) {
Michal Vasko4e55f5a2022-12-14 12:15:00 +01001363 if (target->nodetype != LYS_LIST) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001364 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
1365 }
1366
1367 uniques = &((struct lysp_node_list *)target)->uniques;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001368 DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, ctx->ctx, "unique");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001369 }
1370
1371 /* *default-stmt */
1372 if (d->dflts) {
1373 switch (target->nodetype) {
1374 case LYS_LEAF:
1375 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1376 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str);
1377
Michal Vaskoe180ed02021-02-05 16:31:20 +01001378 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001379 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
1380 break;
1381 case LYS_LEAFLIST:
1382 dflts = &((struct lysp_node_leaflist *)target)->dflts;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001383 DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, ctx->ctx, "default");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001384 break;
1385 case LYS_CHOICE:
1386 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
1387 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str);
1388
Michal Vaskoe180ed02021-02-05 16:31:20 +01001389 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001390 ((struct lysp_node_choice *)target)->dflt.str = NULL;
1391 break;
1392 default:
1393 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
1394 }
1395 }
1396
1397cleanup:
1398 return ret;
1399}
1400
1401/**
1402 * @brief Apply deviate replace.
1403 *
1404 * @param[in] ctx Compile context.
1405 * @param[in] d Deviate replace to apply.
1406 * @param[in,out] target Deviation target.
1407 * @return LY_ERR value.
1408 */
1409static LY_ERR
1410lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
1411{
1412 LY_ERR ret = LY_SUCCESS;
1413 uint32_t *num;
1414
1415#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
1416 if (!((TYPE)target)->MEMBER) { \
Radek Krejci2efc45b2020-12-22 16:25:44 +01001417 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001418 ret = LY_EVALID; \
1419 goto cleanup; \
1420 }
1421
1422 /* [type-stmt] */
1423 if (d->type) {
1424 switch (target->nodetype) {
1425 case LYS_LEAF:
1426 case LYS_LEAFLIST:
1427 break;
1428 default:
1429 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
1430 }
1431
Michal Vaskoc636ea42022-09-16 10:20:31 +02001432 lysp_type_free(&ctx->free_ctx, &((struct lysp_node_leaf *)target)->type);
Michal Vaskoc621d862022-11-08 14:23:45 +01001433 lysp_type_dup(ctx->ctx, ctx->pmod, d->type, &((struct lysp_node_leaf *)target)->type);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001434 }
1435
1436 /* [units-stmt] */
1437 if (d->units) {
1438 switch (target->nodetype) {
1439 case LYS_LEAF:
1440 case LYS_LEAFLIST:
1441 break;
1442 default:
1443 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
1444 }
1445
1446 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
Michal Vaskoe180ed02021-02-05 16:31:20 +01001447 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001448 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
1449 }
1450
1451 /* [default-stmt] */
1452 if (d->dflt.str) {
1453 switch (target->nodetype) {
1454 case LYS_LEAF:
1455 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str);
1456
Michal Vaskoe180ed02021-02-05 16:31:20 +01001457 lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +01001458 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 +02001459 break;
1460 case LYS_CHOICE:
Michal Vasko7b3a00e2023-08-09 11:58:03 +02001461 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt.str);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001462
Michal Vaskoe180ed02021-02-05 16:31:20 +01001463 lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
Michal Vaskoc621d862022-11-08 14:23:45 +01001464 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 +02001465 break;
1466 default:
1467 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
1468 }
1469 }
1470
1471 /* [config-stmt] */
1472 if (d->flags & LYS_CONFIG_MASK) {
1473 switch (target->nodetype) {
1474 case LYS_CONTAINER:
1475 case LYS_LEAF:
1476 case LYS_LEAFLIST:
1477 case LYS_LIST:
1478 case LYS_CHOICE:
1479 case LYS_ANYDATA:
1480 case LYS_ANYXML:
1481 break;
1482 default:
1483 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
1484 }
1485
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001486 target->flags &= ~LYS_CONFIG_MASK;
1487 target->flags |= d->flags & LYS_CONFIG_MASK;
1488 }
1489
1490 /* [mandatory-stmt] */
1491 if (d->flags & LYS_MAND_MASK) {
1492 switch (target->nodetype) {
1493 case LYS_LEAF:
1494 case LYS_CHOICE:
1495 case LYS_ANYDATA:
1496 case LYS_ANYXML:
1497 break;
1498 default:
1499 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
1500 }
1501
1502 if (!(target->flags & LYS_MAND_MASK)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001503 LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory",
1504 d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001505 ret = LY_EVALID;
1506 goto cleanup;
1507 }
1508
1509 target->flags &= ~LYS_MAND_MASK;
1510 target->flags |= d->flags & LYS_MAND_MASK;
1511 }
1512
1513 /* [min-elements-stmt] */
1514 if (d->flags & LYS_SET_MIN) {
1515 switch (target->nodetype) {
1516 case LYS_LEAFLIST:
1517 num = &((struct lysp_node_leaflist *)target)->min;
1518 break;
1519 case LYS_LIST:
1520 num = &((struct lysp_node_list *)target)->min;
1521 break;
1522 default:
1523 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1524 }
1525
1526 if (!(target->flags & LYS_SET_MIN)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001527 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001528 ret = LY_EVALID;
1529 goto cleanup;
1530 }
1531
1532 *num = d->min;
1533 }
1534
1535 /* [max-elements-stmt] */
1536 if (d->flags & LYS_SET_MAX) {
1537 switch (target->nodetype) {
1538 case LYS_LEAFLIST:
1539 num = &((struct lysp_node_leaflist *)target)->max;
1540 break;
1541 case LYS_LIST:
1542 num = &((struct lysp_node_list *)target)->max;
1543 break;
1544 default:
1545 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1546 }
1547
1548 if (!(target->flags & LYS_SET_MAX)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001549 LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present.");
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001550 ret = LY_EVALID;
1551 goto cleanup;
1552 }
1553
1554 *num = d->max;
1555 }
1556
1557cleanup:
1558 return ret;
1559}
1560
1561/**
Michal Vasko193dacd2022-10-13 08:43:05 +02001562 * @brief Apply deviation with all its deviates.
1563 *
1564 * @param[in] ctx Compile context.
1565 * @param[in] dev Deviation to apply.
1566 * @param[in] dev_pmod Local module of the deviation.
1567 * @param[in,out] target Deviation target.
1568 * @return LY_ERR value.
1569 */
1570static LY_ERR
1571lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const struct lysp_module *dev_pmod,
1572 struct lysp_node *target)
1573{
1574 LY_ERR ret = LY_SUCCESS;
1575 struct lys_module *orig_mod = ctx->cur_mod;
1576 struct lysp_module *orig_pmod = ctx->pmod;
1577 char orig_path[LYSC_CTX_BUFSIZE];
1578 struct lysp_deviate *d;
1579
1580 /* clear path and set modules */
1581 strcpy(orig_path, ctx->path);
1582 ctx->path_len = 1;
1583 ctx->cur_mod = dev_pmod->mod;
1584 ctx->pmod = (struct lysp_module *)dev_pmod;
1585
1586 /* generate correct path */
1587 lysc_update_path(ctx, NULL, "{deviation}");
1588 lysc_update_path(ctx, NULL, dev->nodeid);
1589
1590 LY_LIST_FOR(dev->deviates, d) {
1591 switch (d->mod) {
1592 case LYS_DEV_ADD:
1593 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, target);
1594 break;
1595 case LYS_DEV_DELETE:
1596 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, target);
1597 break;
1598 case LYS_DEV_REPLACE:
1599 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, target);
1600 break;
1601 default:
1602 LOGINT(ctx->ctx);
1603 ret = LY_EINT;
1604 }
1605 LY_CHECK_GOTO(ret, cleanup);
1606 }
1607
1608 /* deviation extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +01001609 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 +02001610
1611cleanup:
1612 ctx->cur_mod = orig_mod;
1613 ctx->pmod = orig_pmod;
1614
1615 strcpy(ctx->path, orig_path);
1616 ctx->path_len = strlen(ctx->path);
1617 return ret;
1618}
1619
1620/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001621 * @brief Check whether a compiled node matches a single schema nodeid name test.
1622 *
1623 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1624 * @param[in] mod Expected module.
Michal Vasko8824a6e2024-01-19 12:42:21 +01001625 * @param[in] name_dict Expected name, in the dictionary.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001626 * @return Whether it is a match or not.
1627 */
1628static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001629lysp_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 +02001630{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001631 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001632 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001633 return 0;
1634 }
1635
1636 /* compare names */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001637 if ((*node)->name != name_dict) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001638 return 0;
1639 }
1640
Michal Vasko2a668712020-10-21 11:48:09 +02001641 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001642 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001643
1644 return 1;
1645}
1646
1647/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001648 * @brief Check whether a compiled ext instance matches a single schema nodeid name test.
1649 *
1650 * @param[in,out] ext Compiled ext instance to consider. On a match it is zeroed to not match again.
1651 * @param[in] mod Expected module.
Michal Vasko8824a6e2024-01-19 12:42:21 +01001652 * @param[in] name Expected name, in the dictionary.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001653 * @return Whether it is a match or not.
1654 */
1655static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001656lysp_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 +02001657{
1658 /* compare with the module */
1659 if ((*ext)->module != mod) {
1660 return 0;
1661 }
1662
1663 /* compare names (argument) */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001664 if ((*ext)->argument != name_dict) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001665 return 0;
1666 }
1667
1668 /* zero */
1669 *ext = NULL;
1670
1671 return 1;
1672}
1673
1674/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001675 * @brief Check whether a node matches specific schema nodeid.
1676 *
Michal Vasko8824a6e2024-01-19 12:42:21 +01001677 * @param[in] nodeid Compiled nodeid to match.
1678 * @param[in] nodeid_pmod Module to use for nodes in @p nodeid without a prefix.
1679 * @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 +02001680 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1681 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1682 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1683 * @param[in] pnode_mod Compiled @p pnode to-be module.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001684 * @param[in] pnode_ext Extension instance in which @p pnode is defined.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001685 * @return Whether it is a match or not.
1686 */
1687static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001688lysp_schema_nodeid_match(const struct lysc_nodeid *nodeid, const struct lysp_module *nodeid_pmod,
1689 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 +02001690 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 +02001691{
1692 uint32_t i;
1693 const struct lys_module *mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001694
Michal Vasko8824a6e2024-01-19 12:42:21 +01001695 if (nodeid_ext && !pnode_ext) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001696 /* extension instance augment and standard node, will never match */
1697 return 0;
Michal Vasko8824a6e2024-01-19 12:42:21 +01001698 } else if (!nodeid_ext && pnode_ext) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001699 /* standard augment and extension instance node, will never match */
1700 return 0;
1701 }
1702
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001703 /* compare last node in the node ID */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001704 i = nodeid->count - 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001705
1706 /* get exp node ID module */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001707 mod = lys_schema_node_get_module(nodeid_pmod->mod->ctx, nodeid->prefix[i], nodeid_pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001708 assert(mod);
1709
1710 if (pnode) {
1711 /* compare on the last parsed-only node */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001712 if ((pnode_mod != mod) || (pnode->name != nodeid->name[i])) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001713 return 0;
1714 }
1715 } else {
1716 /* using parent directly */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001717 if (!lysp_schema_nodeid_match_node(&parent, mod, nodeid->name[i])) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001718 return 0;
1719 }
1720 }
1721
1722 /* now compare all the compiled parents */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001723 while (i) {
1724 --i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001725
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001726 if (!parent && !pnode_ext) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001727 /* no more parents but path continues */
1728 return 0;
1729 }
1730
1731 /* get exp node ID module */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001732 mod = lys_schema_node_get_module(nodeid_pmod->mod->ctx, nodeid->prefix[i], nodeid_pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001733 assert(mod);
1734
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001735 if (parent) {
1736 /* compare with the parent */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001737 if (!lysp_schema_nodeid_match_node(&parent, mod, nodeid->name[i])) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001738 return 0;
1739 }
1740 } else {
1741 /* compare with the ext instance */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001742 if (!lysp_schema_nodeid_match_ext(&pnode_ext, mod, nodeid->name[i])) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001743 return 0;
1744 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001745 }
1746 }
1747
1748 if (ctx_node && (ctx_node != parent)) {
1749 /* descendant path has not finished in the context node */
1750 return 0;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001751 } else if (!ctx_node && (parent || pnode_ext)) {
1752 /* some parent/extension was not matched */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001753 return 0;
1754 }
1755
1756 return 1;
1757}
1758
1759void
1760lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1761{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001762 if (!aug) {
1763 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001764 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001765
1766 lysc_nodeid_free(ctx, aug->nodeid);
1767 free(aug);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001768}
1769
1770void
1771lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1772{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001773 if (!dev) {
1774 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001775 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001776
1777 lysc_nodeid_free(ctx, dev->nodeid);
1778 LY_ARRAY_FREE(dev->devs);
1779 LY_ARRAY_FREE(dev->dev_pmods);
1780 free(dev);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001781}
1782
1783void
1784lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1785{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001786 if (!rfn) {
1787 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001788 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001789
1790 lysc_nodeid_free(ctx, rfn->nodeid);
1791 LY_ARRAY_FREE(rfn->rfns);
1792 free(rfn);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001793}
1794
1795void
Michal Vaskoc636ea42022-09-16 10:20:31 +02001796lysp_dev_node_free(struct lysc_ctx *cctx, struct lysp_node *dev_pnode)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001797{
1798 if (!dev_pnode) {
1799 return;
1800 }
1801
1802 switch (dev_pnode->nodetype) {
1803 case LYS_CONTAINER:
1804 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001805 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1806 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001807 break;
1808 case LYS_LIST:
1809 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001810 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1811 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001812 break;
1813 case LYS_CHOICE:
1814 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1815 break;
1816 case LYS_CASE:
1817 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1818 break;
1819 case LYS_LEAF:
1820 case LYS_LEAFLIST:
1821 case LYS_ANYXML:
1822 case LYS_ANYDATA:
1823 /* no children */
1824 break;
1825 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001826 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001827 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001828 case LYS_RPC:
1829 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001830 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1831 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001832 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001833 case LYS_INPUT:
1834 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001835 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001836 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001837 free(dev_pnode);
1838 return;
1839 default:
Michal Vaskoc636ea42022-09-16 10:20:31 +02001840 LOGINT(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001841 return;
1842 }
1843
Michal Vaskoc636ea42022-09-16 10:20:31 +02001844 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001845}
1846
1847LY_ERR
1848lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1849 struct lysp_node **dev_pnode, ly_bool *not_supported)
1850{
1851 LY_ERR ret = LY_SUCCESS;
1852 uint32_t i;
1853 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001854 struct lysc_refine *rfn;
1855 struct lysc_deviation *dev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001856
1857 *dev_pnode = NULL;
1858 *not_supported = 0;
1859
Michal Vaskoee057572022-05-26 08:31:52 +02001860 for (i = 0; i < ctx->uses_rfns.count; ) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001861 rfn = ctx->uses_rfns.objs[i];
1862
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001863 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, NULL, rfn->nodeid_ctx_node, parent, pnode,
1864 ctx->cur_mod, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001865 /* not our target node */
Michal Vaskoee057572022-05-26 08:31:52 +02001866 ++i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001867 continue;
1868 }
1869
1870 if (!*dev_pnode) {
1871 /* first refine on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001872 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001873 }
1874
1875 /* apply all the refines by changing (the copy of) the parsed node */
1876 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001877 LY_CHECK_GOTO(ret = lys_apply_refine(ctx, rfn->rfns[u], rfn->nodeid_pmod, *dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001878 }
1879
1880 /* refine was applied, remove it */
1881 lysc_refine_free(ctx->ctx, rfn);
1882 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1883
Michal Vaskoee057572022-05-26 08:31:52 +02001884 /* refines use relative paths so more may apply to a single node */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001885 }
1886
1887 for (i = 0; i < ctx->devs.count; ++i) {
1888 dev = ctx->devs.objs[i];
1889
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001890 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 +02001891 /* not our target node */
1892 continue;
1893 }
1894
1895 if (dev->not_supported) {
1896 /* it is not supported, no more deviations */
1897 *not_supported = 1;
1898 goto dev_applied;
1899 }
1900
1901 if (!*dev_pnode) {
1902 /* first deviation on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001903 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001904 }
1905
1906 /* apply all the deviates by changing (the copy of) the parsed node */
1907 LY_ARRAY_FOR(dev->devs, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001908 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 +02001909 }
1910
1911dev_applied:
1912 /* deviation was applied, remove it */
1913 lysc_deviation_free(ctx->ctx, dev);
1914 ly_set_rm_index(&ctx->devs, i, NULL);
1915
1916 /* all the deviations for one target node are in one structure, we are done */
1917 break;
1918 }
1919
1920cleanup:
1921 if (ret) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001922 lysp_dev_node_free(ctx, *dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001923 *dev_pnode = NULL;
1924 *not_supported = 0;
1925 }
1926 return ret;
1927}
1928
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001929/**
1930 * @brief Compile augment children.
1931 *
1932 * @param[in] ctx Compile context.
1933 * @param[in] aug_when Parsed augment when to inherit.
1934 * @param[in] aug_flags Parsed augment flags.
1935 * @param[in] child First augment child to compile.
1936 * @param[in] target Target node of the augment.
1937 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
1938 * @return LY_SUCCESS on success.
1939 * @return LY_EVALID on failure.
1940 */
1941static LY_ERR
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001942lys_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 +02001943 struct lysc_node *target, ly_bool child_unres_disabled)
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001944{
1945 LY_ERR rc = LY_SUCCESS;
1946 struct lysp_node *pnode;
1947 struct lysc_node *node;
1948 struct lysc_when *when_shared = NULL;
1949 ly_bool enabled, allow_mand = 0;
1950 struct ly_set child_set = {0};
1951 uint32_t i, opt_prev = ctx->compile_opts;
1952
1953 /* check for mandatory nodes
1954 * - new cases augmenting some choice can have mandatory nodes
1955 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1956 */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001957 if (aug_when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001958 allow_mand = 1;
1959 }
1960
1961 LY_LIST_FOR(child, pnode) {
1962 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1963 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1964 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1965 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1966 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1967 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1968 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1969 rc = LY_EVALID;
1970 goto cleanup;
1971 }
1972
1973 /* compile the children */
1974 if (target->nodetype == LYS_CHOICE) {
1975 LY_CHECK_GOTO(rc = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1976 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1977 if (target->nodetype == LYS_INPUT) {
1978 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
1979 } else {
1980 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
1981 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001982 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001983 } else {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001984 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001985 }
1986
1987 /* eval if-features again for the rest of this node processing */
1988 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1989 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001990 ctx->compile_opts |= LYS_COMPILE_DISABLED;
1991 }
1992
1993 /* since the augment node is not present in the compiled tree, we need to pass some of its
1994 * statements to all its children */
1995 for (i = 0; i < child_set.count; ++i) {
1996 node = child_set.snodes[i];
1997 if (!allow_mand && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1998 node->flags &= ~LYS_MAND_TRUE;
1999 lys_compile_mandatory_parents(target, 0);
2000 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
2001 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
2002 node->name);
2003 rc = LY_EVALID;
2004 goto cleanup;
2005 }
2006
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002007 if (aug_when) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002008 /* pass augment's when to all the children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002009 rc = lys_compile_when(ctx, aug_when, aug_flags, target, lysc_data_node(target), node, &when_shared);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002010 LY_CHECK_GOTO(rc, cleanup);
2011 }
2012
Michal Vaskoa084fa32022-05-16 11:32:58 +02002013 if (child_unres_disabled) {
Michal Vaskoad0980a2022-05-09 11:43:47 +02002014 /* child is disabled by the augment if-features */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002015 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
2016 }
2017 }
2018
2019 /* next iter */
2020 ly_set_erase(&child_set, NULL);
2021 ctx->compile_opts = opt_prev;
2022 }
2023
2024cleanup:
2025 ly_set_erase(&child_set, NULL);
2026 ctx->compile_opts = opt_prev;
2027 return rc;
2028}
2029
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002030/**
2031 * @brief Compile the parsed augment connecting it into its target.
2032 *
2033 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
2034 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
2035 * are already implemented and compiled.
2036 *
2037 * @param[in] ctx Compile context.
2038 * @param[in] aug_p Parsed augment to compile.
2039 * @param[in] target Target node of the augment.
2040 * @return LY_SUCCESS on success.
2041 * @return LY_EVALID on failure.
2042 */
2043static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01002044lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002045{
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002046 LY_ERR rc = LY_SUCCESS;
Michal Vaskoa084fa32022-05-16 11:32:58 +02002047 ly_bool enabled, child_unres_disabled = 0;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002048 uint32_t opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002049
Michal Vasko95f736c2022-06-08 12:03:31 +02002050 assert(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
2051
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002052 /* nodetype checks */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002053 if (aug_p->actions && !lysc_node_actions_p(target)) {
2054 LOGVAL(ctx->ctx, LYVE_REFERENCE,
2055 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
2056 lys_nodetype2str(target->nodetype), aug_p->actions->name);
2057 rc = LY_EVALID;
2058 goto cleanup;
2059 }
2060 if (aug_p->notifs && !lysc_node_notifs_p(target)) {
2061 LOGVAL(ctx->ctx, LYVE_REFERENCE,
2062 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
2063 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
2064 rc = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002065 goto cleanup;
2066 }
2067
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002068 /* augment if-features */
2069 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, aug_p->iffeatures, &enabled), cleanup);
2070 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002071 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vaskoa084fa32022-05-16 11:32:58 +02002072 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002073 }
2074
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002075 /* augment children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002076 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, aug_p->child, target, child_unres_disabled);
2077 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002078
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002079 /* augment actions */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002080 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->actions, target,
2081 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002082 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002083
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002084 /* augment notifications */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002085 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->notifs, target,
2086 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002087 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002088
Michal Vasko193dacd2022-10-13 08:43:05 +02002089 /* compile extensions into the target */
2090 COMPILE_EXTS_GOTO(ctx, aug_p->exts, target->exts, target, rc, cleanup);
2091
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002092cleanup:
Michal Vasko7c565922021-06-10 14:58:27 +02002093 ctx->compile_opts = opt_prev;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002094 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002095}
2096
2097LY_ERR
2098lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
2099{
2100 LY_ERR ret = LY_SUCCESS;
2101 struct lys_module *orig_mod = ctx->cur_mod;
2102 struct lysp_module *orig_pmod = ctx->pmod;
2103 uint32_t i;
2104 char orig_path[LYSC_CTX_BUFSIZE];
2105 struct lysc_augment *aug;
2106
2107 /* uses augments */
2108 for (i = 0; i < ctx->uses_augs.count; ) {
2109 aug = ctx->uses_augs.objs[i];
2110
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002111 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->ext, aug->nodeid_ctx_node, node, NULL, NULL,
2112 ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002113 /* not our target node */
2114 ++i;
2115 continue;
2116 }
2117
Michal Vaskob8df5762021-01-12 15:15:53 +01002118 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002119 lysc_update_path(ctx, NULL, "{augment}");
2120 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01002121 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01002122
2123 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002124 ret = lys_compile_augment(ctx, aug->aug_p, node);
2125 lysc_update_path(ctx, NULL, NULL);
2126 lysc_update_path(ctx, NULL, NULL);
2127 LY_CHECK_GOTO(ret, cleanup);
2128
Michal Vaskoc75f2042021-06-08 14:57:03 +02002129 /* augment was applied, remove it (index and the whole set may have changed because other augments
2130 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002131 ly_set_rm(&ctx->uses_augs, aug, NULL);
2132 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002133 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002134 }
2135
2136 /* top-level augments */
2137 for (i = 0; i < ctx->augs.count; ) {
2138 aug = ctx->augs.objs[i];
2139
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002140 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 +02002141 /* not our target node */
2142 ++i;
2143 continue;
2144 }
2145
Michal Vaskob8df5762021-01-12 15:15:53 +01002146 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002147 strcpy(orig_path, ctx->path);
2148 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002149 ctx->cur_mod = aug->aug_pmod->mod;
2150 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02002151 lysc_update_path(ctx, NULL, "{augment}");
2152 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01002153
2154 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002155 ret = lys_compile_augment(ctx, aug->aug_p, node);
2156 strcpy(ctx->path, orig_path);
2157 ctx->path_len = strlen(ctx->path);
2158 LY_CHECK_GOTO(ret, cleanup);
2159
2160 /* augment was applied, remove it */
2161 ly_set_rm(&ctx->augs, aug, NULL);
2162 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002163 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002164 }
2165
2166cleanup:
2167 ctx->cur_mod = orig_mod;
2168 ctx->pmod = orig_pmod;
2169 return ret;
2170}
2171
2172/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002173 * @brief Prepare an absolute-nodeid augment to be applied during data nodes compilation.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002174 *
2175 * @param[in] ctx Compile context.
2176 * @param[in] aug_p Parsed augment to be applied.
2177 * @param[in] pmod Both current and prefix module for @p aug_p.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002178 * @param[in] ext Extension instance in case @p aug_p is defined in one.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002179 * @return LY_ERR value.
2180 */
2181static LY_ERR
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002182lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, const struct lysp_module *pmod,
2183 const struct lysp_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002184{
2185 LY_ERR ret = LY_SUCCESS;
Michal Vasko8824a6e2024-01-19 12:42:21 +01002186 struct lysc_nodeid *nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002187 struct lysc_augment *aug;
2188 const struct lys_module *mod;
2189
Michal Vasko8824a6e2024-01-19 12:42:21 +01002190 /* compile its target, it was already parsed and fully checked (except for the existence of the nodes) */
2191 ret = lys_precompile_nodeid(ctx->ctx, aug_p->nodeid, &nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002192 LY_CHECK_GOTO(ret, cleanup);
2193
Michal Vasko8824a6e2024-01-19 12:42:21 +01002194 mod = lys_schema_node_get_module(ctx->ctx, nodeid->prefix[0], pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002195 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2196 if (mod != ctx->cur_mod) {
2197 /* augment for another module, ignore */
2198 goto cleanup;
2199 }
2200
2201 /* allocate new compiled augment and store it in the set */
2202 aug = calloc(1, sizeof *aug);
2203 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2204 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2205
Michal Vasko8824a6e2024-01-19 12:42:21 +01002206 aug->nodeid = nodeid;
2207 nodeid = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002208 aug->aug_pmod = pmod;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002209 aug->ext = ext;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002210 aug->aug_p = aug_p;
2211
2212cleanup:
Michal Vasko8824a6e2024-01-19 12:42:21 +01002213 lysc_nodeid_free(ctx->ctx, nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002214 return ret;
2215}
2216
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002217/**
2218 * @brief Prepare all top-level augments and extension instance augments to be applied during data nodes compilation.
2219 *
2220 * @param[in] ctx Compile context.
2221 * @param[in] pmod Parsed mod to use.
2222 * @return LY_ERR value.
2223 */
2224static LY_ERR
2225lys_precompile_own_augments_mod(struct lysc_ctx *ctx, const struct lysp_module *pmod)
2226{
2227 LY_ARRAY_COUNT_TYPE u, v;
2228 struct lysp_node_augment *aug_p;
2229
2230 /* module */
2231 LY_LIST_FOR(pmod->augments, aug_p) {
2232 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, NULL));
2233 }
2234
2235 /* parsed extension instances */
2236 LY_ARRAY_FOR(pmod->exts, u) {
2237 aug_p = NULL;
2238 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2239 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2240 aug_p = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2241 break;
2242 }
2243 }
2244 if (!aug_p) {
2245 continue;
2246 }
2247
2248 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, &pmod->exts[u]));
2249 }
2250
2251 return LY_SUCCESS;
2252}
2253
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002254LY_ERR
2255lys_precompile_own_augments(struct lysc_ctx *ctx)
2256{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002257 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002258 const struct lys_module *aug_mod;
2259 const struct lysp_module *submod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002260
2261 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002262 aug_mod = ctx->cur_mod->augmented_by[u];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002263
2264 /* collect all module augments */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002265 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002266
2267 /* collect all submodules augments */
2268 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002269 submod = (struct lysp_module *)aug_mod->parsed->includes[v].submodule;
2270
2271 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, submod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002272 }
2273 }
2274
2275 return LY_SUCCESS;
2276}
2277
2278/**
2279 * @brief Prepare a deviation to be applied during data nodes compilation.
2280 *
2281 * @param[in] ctx Compile context.
2282 * @param[in] dev_p Parsed deviation to be applied.
2283 * @param[in] pmod Both current and prefix module for @p dev_p.
2284 * @return LY_ERR value.
2285 */
2286static LY_ERR
2287lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2288{
2289 LY_ERR ret = LY_SUCCESS;
2290 struct lysc_deviation *dev = NULL;
Michal Vasko8824a6e2024-01-19 12:42:21 +01002291 struct lysc_nodeid *nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002292 struct lysp_deviation **new_dev;
2293 const struct lys_module *mod;
2294 const struct lysp_module **new_dev_pmod;
2295 uint32_t i;
2296
2297 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
Michal Vasko8824a6e2024-01-19 12:42:21 +01002298 ret = lys_precompile_nodeid(ctx->ctx, dev_p->nodeid, &nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002299 LY_CHECK_GOTO(ret, cleanup);
2300
Michal Vasko8824a6e2024-01-19 12:42:21 +01002301 mod = lys_schema_node_get_module(ctx->ctx, nodeid->prefix[0], pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002302 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2303 if (mod != ctx->cur_mod) {
2304 /* deviation for another module, ignore */
2305 goto cleanup;
2306 }
2307
2308 /* try to find the node in already compiled deviations */
2309 for (i = 0; i < ctx->devs.count; ++i) {
Michal Vasko8824a6e2024-01-19 12:42:21 +01002310 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 +02002311 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2312 dev = ctx->devs.objs[i];
2313 break;
2314 }
2315 }
2316
2317 if (!dev) {
2318 /* allocate new compiled deviation */
2319 dev = calloc(1, sizeof *dev);
2320 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2321 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2322
Michal Vasko8824a6e2024-01-19 12:42:21 +01002323 dev->nodeid = nodeid;
2324 nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002325 }
2326
2327 /* add new parsed deviation structure */
2328 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2329 *new_dev = dev_p;
2330 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2331 *new_dev_pmod = pmod;
2332
2333cleanup:
Michal Vasko8824a6e2024-01-19 12:42:21 +01002334 lysc_nodeid_free(ctx->ctx, nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002335 return ret;
2336}
2337
2338LY_ERR
2339lys_precompile_own_deviations(struct lysc_ctx *ctx)
2340{
2341 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002342 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002343 const struct lys_module *dev_mod;
2344 struct lysc_deviation *dev;
2345 struct lysp_deviate *d;
2346 int not_supported;
2347 uint32_t i;
2348
2349 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2350 dev_mod = ctx->cur_mod->deviated_by[u];
2351
2352 /* compile all module deviations */
2353 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2354 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2355 }
2356
2357 /* compile all submodules deviations */
2358 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2359 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2360 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2361 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2362 }
2363 }
2364 }
2365
2366 /* set not-supported flags for all the deviations */
2367 for (i = 0; i < ctx->devs.count; ++i) {
2368 dev = ctx->devs.objs[i];
2369 not_supported = 0;
2370
2371 LY_ARRAY_FOR(dev->devs, u) {
2372 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2373 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2374 not_supported = 1;
2375 break;
2376 }
2377 }
2378 if (not_supported) {
2379 break;
2380 }
2381 }
2382 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002383 orig_cur_mod = ctx->cur_mod;
2384 ctx->cur_mod = dev->dev_pmods[u]->mod;
2385 lysc_update_path(ctx, NULL, "{deviation}");
Michal Vasko8824a6e2024-01-19 12:42:21 +01002386 lysc_update_path(ctx, NULL, dev->nodeid->str);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002387 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko8824a6e2024-01-19 12:42:21 +01002388 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->str);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002389 lysc_update_path(ctx, NULL, NULL);
2390 lysc_update_path(ctx, NULL, NULL);
2391 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002392 return LY_EVALID;
2393 }
2394
2395 dev->not_supported = not_supported;
2396 }
2397
2398 return LY_SUCCESS;
2399}
2400
2401/**
2402 * @brief Add a module reference into an array, checks for duplicities.
2403 *
2404 * @param[in] ctx Compile context.
2405 * @param[in] mod Module reference to add.
2406 * @param[in,out] mod_array Module sized array to add to.
2407 * @return LY_ERR value.
2408 */
2409static LY_ERR
2410lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2411{
2412 LY_ARRAY_COUNT_TYPE u;
2413 struct lys_module **new_mod;
2414
2415 LY_ARRAY_FOR(*mod_array, u) {
2416 if ((*mod_array)[u] == mod) {
2417 /* already there */
2418 return LY_EEXIST;
2419 }
2420 }
2421
2422 /* add the new module ref */
2423 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2424 *new_mod = mod;
2425
2426 return LY_SUCCESS;
2427}
2428
Michal Vasko1ccbf542021-04-19 11:35:00 +02002429/**
2430 * @brief Check whether all modules in a set are implemented.
2431 *
2432 * @param[in] mod_set Module set to check.
2433 * @return Whether all modules are implemented or not.
2434 */
2435static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002436lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002437{
2438 uint32_t i;
2439 const struct lys_module *mod;
2440
2441 for (i = 0; i < mod_set->count; ++i) {
2442 mod = mod_set->objs[i];
2443 if (!mod->implemented) {
2444 return 0;
2445 }
2446 }
2447
2448 return 1;
2449}
2450
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002451/**
2452 * @brief Add references to target modules of top-level augments, deviations, and augments in extension instances
2453 * in a module and all its submodules.
2454 *
2455 * @param[in] pmod Module to process.
2456 * @param[in,out] mod_set Module set to add referenced modules into.
2457 * @return LY_SUCCESS on success.
2458 * @return LY_ERR on error.
2459 */
2460static LY_ERR
2461lys_precompile_mod_augments_deviations(struct lysp_module *pmod, struct ly_set *mod_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002462{
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002463 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002464 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002465 struct lysc_ctx ctx;
Michal Vasko65333882021-06-10 14:12:16 +02002466 struct lys_module *m;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002467 struct lysp_node_augment *aug;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002468 struct ly_set set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002469
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002470 LYSC_CTX_INIT_PMOD(ctx, pmod, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002471
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002472 LY_LIST_FOR(pmod->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002473 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002474 lysc_update_path(&ctx, NULL, "{augment}");
2475 lysc_update_path(&ctx, NULL, aug->nodeid);
2476 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2477 lysc_update_path(&ctx, NULL, NULL);
2478 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002479 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002480
Michal Vasko1ccbf542021-04-19 11:35:00 +02002481 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002482 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002483 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002484 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002485 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002486 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002487 }
2488
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002489 LY_ARRAY_FOR(pmod->deviations, u) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002490 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002491 lysc_update_path(&ctx, NULL, "{deviation}");
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002492 lysc_update_path(&ctx, NULL, pmod->deviations[u].nodeid);
2493 ret = lys_nodeid_mod_check(&ctx, pmod->deviations[u].nodeid, 1, &set, NULL, &m);
Michal Vasko65333882021-06-10 14:12:16 +02002494 lysc_update_path(&ctx, NULL, NULL);
2495 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002496 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002497
Michal Vasko1ccbf542021-04-19 11:35:00 +02002498 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002499 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002500 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002501 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002502 }
2503 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002504 }
2505
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002506 LY_ARRAY_FOR(pmod->exts, u) {
2507 aug = NULL;
2508 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2509 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
2510 aug = *(struct lysp_node_augment **)pmod->exts[u].substmts[v].storage;
2511 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002512 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002513 }
2514 if (!aug) {
2515 continue;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002516 }
2517
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002518 /* get target module */
2519 lysc_update_path(&ctx, NULL, "{ext-augment}");
2520 lysc_update_path(&ctx, NULL, aug->nodeid);
2521 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2522 lysc_update_path(&ctx, NULL, NULL);
2523 lysc_update_path(&ctx, NULL, NULL);
2524 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002525
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002526 /* add this module into the target module augmented_by, if not there and implemented */
2527 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
2528 !lys_precompile_mod_set_is_all_implemented(&set)) {
2529 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002530 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002531 ly_set_erase(&set, NULL);
2532 }
2533
2534cleanup:
2535 ly_set_erase(&set, NULL);
2536 return ret;
2537}
2538
2539LY_ERR
2540lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
2541{
2542 LY_ERR ret = LY_SUCCESS, r;
2543 LY_ARRAY_COUNT_TYPE u;
2544 struct lys_module *m;
2545 struct lysp_module *submod;
2546 const char **imp_f, *all_f[] = {"*", NULL};
2547 uint32_t i;
2548 struct ly_set mod_set = {0};
2549
2550 /* module */
2551 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(mod->parsed, &mod_set), cleanup);
2552
2553 /* submodules */
2554 LY_ARRAY_FOR(mod->parsed->includes, u) {
2555 submod = (struct lysp_module *)mod->parsed->includes[u].submodule;
2556 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(submod, &mod_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002557 }
2558
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002559 for (i = 0; i < mod_set.count; ++i) {
2560 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002561
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002562 if (m == mod) {
2563 /* will be applied normally later */
2564 continue;
2565 }
2566
2567 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2568 * not compiled yet and marked for compilation */
2569
2570 if (!m->implemented) {
2571 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002572 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2573 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002574 if (r == LY_ERECOMPILE) {
2575 /* implement all the modules right away to save possible later recompilation */
2576 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002577 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002578 } else if (r) {
2579 /* error */
2580 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002581 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002582 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002583 } else if (m->compiled) {
2584 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2585 m->to_compile = 1;
2586 ret = LY_ERECOMPILE;
2587 continue;
2588 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002589 }
2590
Michal Vasko1ccbf542021-04-19 11:35:00 +02002591cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +02002592 ly_set_erase(&mod_set, NULL);
2593 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002594}
2595
2596void
2597lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2598{
2599 uint32_t i;
2600 LY_ARRAY_COUNT_TYPE u, count;
2601 struct lys_module *m;
2602
2603 for (i = 0; i < ctx->list.count; ++i) {
2604 m = ctx->list.objs[i];
2605
2606 if (m->augmented_by) {
2607 count = LY_ARRAY_COUNT(m->augmented_by);
2608 for (u = 0; u < count; ++u) {
2609 if (m->augmented_by[u] == mod) {
2610 /* keep the order */
2611 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002612 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002613 }
2614 LY_ARRAY_DECREMENT(m->augmented_by);
2615 break;
2616 }
2617 }
2618 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2619 LY_ARRAY_FREE(m->augmented_by);
2620 m->augmented_by = NULL;
2621 }
2622 }
2623
2624 if (m->deviated_by) {
2625 count = LY_ARRAY_COUNT(m->deviated_by);
2626 for (u = 0; u < count; ++u) {
2627 if (m->deviated_by[u] == mod) {
2628 /* keep the order */
2629 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002630 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002631 }
2632 LY_ARRAY_DECREMENT(m->deviated_by);
2633 break;
2634 }
2635 }
2636 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2637 LY_ARRAY_FREE(m->deviated_by);
2638 m->deviated_by = NULL;
2639 }
2640 }
2641 }
2642}