blob: 21cb632eaba9fa9675b59ee366b3345646d665df [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 Vasko2063f202024-04-02 09:33:05 +02007 * Copyright (c) 2015 - 2024 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
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001502 target->flags &= ~LYS_MAND_MASK;
1503 target->flags |= d->flags & LYS_MAND_MASK;
1504 }
1505
1506 /* [min-elements-stmt] */
1507 if (d->flags & LYS_SET_MIN) {
1508 switch (target->nodetype) {
1509 case LYS_LEAFLIST:
1510 num = &((struct lysp_node_leaflist *)target)->min;
1511 break;
1512 case LYS_LIST:
1513 num = &((struct lysp_node_list *)target)->min;
1514 break;
1515 default:
1516 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
1517 }
1518
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001519 *num = d->min;
1520 }
1521
1522 /* [max-elements-stmt] */
1523 if (d->flags & LYS_SET_MAX) {
1524 switch (target->nodetype) {
1525 case LYS_LEAFLIST:
1526 num = &((struct lysp_node_leaflist *)target)->max;
1527 break;
1528 case LYS_LIST:
1529 num = &((struct lysp_node_list *)target)->max;
1530 break;
1531 default:
1532 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
1533 }
1534
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001535 *num = d->max;
1536 }
1537
1538cleanup:
1539 return ret;
1540}
1541
1542/**
Michal Vasko193dacd2022-10-13 08:43:05 +02001543 * @brief Apply deviation with all its deviates.
1544 *
1545 * @param[in] ctx Compile context.
1546 * @param[in] dev Deviation to apply.
1547 * @param[in] dev_pmod Local module of the deviation.
1548 * @param[in,out] target Deviation target.
1549 * @return LY_ERR value.
1550 */
1551static LY_ERR
1552lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const struct lysp_module *dev_pmod,
1553 struct lysp_node *target)
1554{
1555 LY_ERR ret = LY_SUCCESS;
1556 struct lys_module *orig_mod = ctx->cur_mod;
1557 struct lysp_module *orig_pmod = ctx->pmod;
1558 char orig_path[LYSC_CTX_BUFSIZE];
1559 struct lysp_deviate *d;
1560
1561 /* clear path and set modules */
1562 strcpy(orig_path, ctx->path);
1563 ctx->path_len = 1;
1564 ctx->cur_mod = dev_pmod->mod;
1565 ctx->pmod = (struct lysp_module *)dev_pmod;
1566
1567 /* generate correct path */
1568 lysc_update_path(ctx, NULL, "{deviation}");
1569 lysc_update_path(ctx, NULL, dev->nodeid);
1570
1571 LY_LIST_FOR(dev->deviates, d) {
1572 switch (d->mod) {
1573 case LYS_DEV_ADD:
1574 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, target);
1575 break;
1576 case LYS_DEV_DELETE:
1577 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, target);
1578 break;
1579 case LYS_DEV_REPLACE:
1580 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, target);
1581 break;
1582 default:
1583 LOGINT(ctx->ctx);
1584 ret = LY_EINT;
1585 }
1586 LY_CHECK_GOTO(ret, cleanup);
1587 }
1588
1589 /* deviation extension instances */
Michal Vaskoc621d862022-11-08 14:23:45 +01001590 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 +02001591
1592cleanup:
1593 ctx->cur_mod = orig_mod;
1594 ctx->pmod = orig_pmod;
1595
1596 strcpy(ctx->path, orig_path);
1597 ctx->path_len = strlen(ctx->path);
1598 return ret;
1599}
1600
1601/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001602 * @brief Check whether a compiled node matches a single schema nodeid name test.
1603 *
1604 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
1605 * @param[in] mod Expected module.
Michal Vasko8824a6e2024-01-19 12:42:21 +01001606 * @param[in] name_dict Expected name, in the dictionary.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001607 * @return Whether it is a match or not.
1608 */
1609static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001610lysp_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 +02001611{
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001612 /* compare with the module of the node */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001613 if ((*node)->module != mod) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001614 return 0;
1615 }
1616
1617 /* compare names */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001618 if ((*node)->name != name_dict) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001619 return 0;
1620 }
1621
Michal Vasko2a668712020-10-21 11:48:09 +02001622 /* move to next parent */
Radek Krejci7d95fbb2021-01-26 17:33:13 +01001623 *node = (*node)->parent;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001624
1625 return 1;
1626}
1627
1628/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001629 * @brief Check whether a compiled ext instance matches a single schema nodeid name test.
1630 *
1631 * @param[in,out] ext Compiled ext instance to consider. On a match it is zeroed to not match again.
1632 * @param[in] mod Expected module.
Michal Vasko8824a6e2024-01-19 12:42:21 +01001633 * @param[in] name Expected name, in the dictionary.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001634 * @return Whether it is a match or not.
1635 */
1636static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001637lysp_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 +02001638{
1639 /* compare with the module */
1640 if ((*ext)->module != mod) {
1641 return 0;
1642 }
1643
1644 /* compare names (argument) */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001645 if ((*ext)->argument != name_dict) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001646 return 0;
1647 }
1648
1649 /* zero */
1650 *ext = NULL;
1651
1652 return 1;
1653}
1654
1655/**
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001656 * @brief Check whether a node matches specific schema nodeid.
1657 *
Michal Vasko8824a6e2024-01-19 12:42:21 +01001658 * @param[in] nodeid Compiled nodeid to match.
1659 * @param[in] nodeid_pmod Module to use for nodes in @p nodeid without a prefix.
1660 * @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 +02001661 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
1662 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
1663 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
1664 * @param[in] pnode_mod Compiled @p pnode to-be module.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001665 * @param[in] pnode_ext Extension instance in which @p pnode is defined.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001666 * @return Whether it is a match or not.
1667 */
1668static ly_bool
Michal Vasko8824a6e2024-01-19 12:42:21 +01001669lysp_schema_nodeid_match(const struct lysc_nodeid *nodeid, const struct lysp_module *nodeid_pmod,
1670 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 +02001671 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 +02001672{
1673 uint32_t i;
1674 const struct lys_module *mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001675
Michal Vasko8824a6e2024-01-19 12:42:21 +01001676 if (nodeid_ext && !pnode_ext) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001677 /* extension instance augment and standard node, will never match */
1678 return 0;
Michal Vasko8824a6e2024-01-19 12:42:21 +01001679 } else if (!nodeid_ext && pnode_ext) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001680 /* standard augment and extension instance node, will never match */
1681 return 0;
1682 }
1683
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001684 /* compare last node in the node ID */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001685 i = nodeid->count - 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001686
1687 /* get exp node ID module */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001688 mod = lys_schema_node_get_module(nodeid_pmod->mod->ctx, nodeid->prefix[i], nodeid_pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001689 assert(mod);
1690
1691 if (pnode) {
1692 /* compare on the last parsed-only node */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001693 if ((pnode_mod != mod) || (pnode->name != nodeid->name[i])) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001694 return 0;
1695 }
1696 } else {
1697 /* using parent directly */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001698 if (!lysp_schema_nodeid_match_node(&parent, mod, nodeid->name[i])) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001699 return 0;
1700 }
1701 }
1702
1703 /* now compare all the compiled parents */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001704 while (i) {
1705 --i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001706
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001707 if (!parent && !pnode_ext) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001708 /* no more parents but path continues */
1709 return 0;
1710 }
1711
1712 /* get exp node ID module */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001713 mod = lys_schema_node_get_module(nodeid_pmod->mod->ctx, nodeid->prefix[i], nodeid_pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001714 assert(mod);
1715
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001716 if (parent) {
1717 /* compare with the parent */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001718 if (!lysp_schema_nodeid_match_node(&parent, mod, nodeid->name[i])) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001719 return 0;
1720 }
1721 } else {
1722 /* compare with the ext instance */
Michal Vasko8824a6e2024-01-19 12:42:21 +01001723 if (!lysp_schema_nodeid_match_ext(&pnode_ext, mod, nodeid->name[i])) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001724 return 0;
1725 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001726 }
1727 }
1728
1729 if (ctx_node && (ctx_node != parent)) {
1730 /* descendant path has not finished in the context node */
1731 return 0;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001732 } else if (!ctx_node && (parent || pnode_ext)) {
1733 /* some parent/extension was not matched */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001734 return 0;
1735 }
1736
1737 return 1;
1738}
1739
1740void
1741lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
1742{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001743 if (!aug) {
1744 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001745 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001746
1747 lysc_nodeid_free(ctx, aug->nodeid);
1748 free(aug);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001749}
1750
1751void
1752lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
1753{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001754 if (!dev) {
1755 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001756 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001757
1758 lysc_nodeid_free(ctx, dev->nodeid);
1759 LY_ARRAY_FREE(dev->devs);
1760 LY_ARRAY_FREE(dev->dev_pmods);
1761 free(dev);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001762}
1763
1764void
1765lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
1766{
Michal Vasko8824a6e2024-01-19 12:42:21 +01001767 if (!rfn) {
1768 return;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001769 }
Michal Vasko8824a6e2024-01-19 12:42:21 +01001770
1771 lysc_nodeid_free(ctx, rfn->nodeid);
1772 LY_ARRAY_FREE(rfn->rfns);
1773 free(rfn);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001774}
1775
1776void
Michal Vaskoc636ea42022-09-16 10:20:31 +02001777lysp_dev_node_free(struct lysc_ctx *cctx, struct lysp_node *dev_pnode)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001778{
1779 if (!dev_pnode) {
1780 return;
1781 }
1782
1783 switch (dev_pnode->nodetype) {
1784 case LYS_CONTAINER:
1785 ((struct lysp_node_container *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001786 ((struct lysp_node_container *)dev_pnode)->actions = NULL;
1787 ((struct lysp_node_container *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001788 break;
1789 case LYS_LIST:
1790 ((struct lysp_node_list *)dev_pnode)->child = NULL;
Michal Vaskoec8f4272021-10-27 09:14:03 +02001791 ((struct lysp_node_list *)dev_pnode)->actions = NULL;
1792 ((struct lysp_node_list *)dev_pnode)->notifs = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001793 break;
1794 case LYS_CHOICE:
1795 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
1796 break;
1797 case LYS_CASE:
1798 ((struct lysp_node_case *)dev_pnode)->child = NULL;
1799 break;
1800 case LYS_LEAF:
1801 case LYS_LEAFLIST:
1802 case LYS_ANYXML:
1803 case LYS_ANYDATA:
1804 /* no children */
1805 break;
1806 case LYS_NOTIF:
Radek Krejci01180ac2021-01-27 08:48:22 +01001807 ((struct lysp_node_notif *)dev_pnode)->child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001808 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001809 case LYS_RPC:
1810 case LYS_ACTION:
Radek Krejci01180ac2021-01-27 08:48:22 +01001811 ((struct lysp_node_action *)dev_pnode)->input.child = NULL;
1812 ((struct lysp_node_action *)dev_pnode)->output.child = NULL;
Radek Krejci2a9fc652021-01-22 17:44:34 +01001813 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001814 case LYS_INPUT:
1815 case LYS_OUTPUT:
Radek Krejci01180ac2021-01-27 08:48:22 +01001816 ((struct lysp_node_action_inout *)dev_pnode)->child = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001817 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001818 free(dev_pnode);
1819 return;
1820 default:
Michal Vaskoc636ea42022-09-16 10:20:31 +02001821 LOGINT(cctx->ctx);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001822 return;
1823 }
1824
Michal Vaskoc636ea42022-09-16 10:20:31 +02001825 lysp_node_free(&cctx->free_ctx, dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001826}
1827
1828LY_ERR
1829lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
1830 struct lysp_node **dev_pnode, ly_bool *not_supported)
1831{
1832 LY_ERR ret = LY_SUCCESS;
1833 uint32_t i;
1834 LY_ARRAY_COUNT_TYPE u;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001835 struct lysc_refine *rfn;
1836 struct lysc_deviation *dev;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001837
1838 *dev_pnode = NULL;
1839 *not_supported = 0;
1840
Michal Vaskoee057572022-05-26 08:31:52 +02001841 for (i = 0; i < ctx->uses_rfns.count; ) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001842 rfn = ctx->uses_rfns.objs[i];
1843
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001844 if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, NULL, rfn->nodeid_ctx_node, parent, pnode,
1845 ctx->cur_mod, ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001846 /* not our target node */
Michal Vaskoee057572022-05-26 08:31:52 +02001847 ++i;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001848 continue;
1849 }
1850
1851 if (!*dev_pnode) {
1852 /* first refine on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001853 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001854 }
1855
1856 /* apply all the refines by changing (the copy of) the parsed node */
1857 LY_ARRAY_FOR(rfn->rfns, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001858 LY_CHECK_GOTO(ret = lys_apply_refine(ctx, rfn->rfns[u], rfn->nodeid_pmod, *dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001859 }
1860
1861 /* refine was applied, remove it */
1862 lysc_refine_free(ctx->ctx, rfn);
1863 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
1864
Michal Vaskoee057572022-05-26 08:31:52 +02001865 /* refines use relative paths so more may apply to a single node */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001866 }
1867
1868 for (i = 0; i < ctx->devs.count; ++i) {
1869 dev = ctx->devs.objs[i];
1870
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001871 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 +02001872 /* not our target node */
1873 continue;
1874 }
1875
1876 if (dev->not_supported) {
1877 /* it is not supported, no more deviations */
1878 *not_supported = 1;
1879 goto dev_applied;
1880 }
1881
1882 if (!*dev_pnode) {
1883 /* first deviation on this node, create a copy first */
Michal Vaskod7e8c532022-11-08 13:44:51 +01001884 LY_CHECK_GOTO(ret = lysp_dup_single(ctx, pnode, 1, dev_pnode), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001885 }
1886
1887 /* apply all the deviates by changing (the copy of) the parsed node */
1888 LY_ARRAY_FOR(dev->devs, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001889 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 +02001890 }
1891
1892dev_applied:
1893 /* deviation was applied, remove it */
1894 lysc_deviation_free(ctx->ctx, dev);
1895 ly_set_rm_index(&ctx->devs, i, NULL);
1896
1897 /* all the deviations for one target node are in one structure, we are done */
1898 break;
1899 }
1900
1901cleanup:
1902 if (ret) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001903 lysp_dev_node_free(ctx, *dev_pnode);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02001904 *dev_pnode = NULL;
1905 *not_supported = 0;
1906 }
1907 return ret;
1908}
1909
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001910/**
1911 * @brief Compile augment children.
1912 *
1913 * @param[in] ctx Compile context.
1914 * @param[in] aug_when Parsed augment when to inherit.
1915 * @param[in] aug_flags Parsed augment flags.
1916 * @param[in] child First augment child to compile.
1917 * @param[in] target Target node of the augment.
1918 * @param[in] child_unres_disabled Whether the children are to be put into unres disabled set or not.
1919 * @return LY_SUCCESS on success.
1920 * @return LY_EVALID on failure.
1921 */
1922static LY_ERR
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001923lys_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 +02001924 struct lysc_node *target, ly_bool child_unres_disabled)
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001925{
1926 LY_ERR rc = LY_SUCCESS;
1927 struct lysp_node *pnode;
1928 struct lysc_node *node;
1929 struct lysc_when *when_shared = NULL;
1930 ly_bool enabled, allow_mand = 0;
1931 struct ly_set child_set = {0};
1932 uint32_t i, opt_prev = ctx->compile_opts;
1933
1934 /* check for mandatory nodes
1935 * - new cases augmenting some choice can have mandatory nodes
1936 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
1937 */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001938 if (aug_when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001939 allow_mand = 1;
1940 }
1941
1942 LY_LIST_FOR(child, pnode) {
1943 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
1944 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
1945 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
1946 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
1947 LOGVAL(ctx->ctx, LYVE_REFERENCE,
1948 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
1949 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
1950 rc = LY_EVALID;
1951 goto cleanup;
1952 }
1953
1954 /* compile the children */
1955 if (target->nodetype == LYS_CHOICE) {
1956 LY_CHECK_GOTO(rc = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
1957 } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
1958 if (target->nodetype == LYS_INPUT) {
1959 ctx->compile_opts |= LYS_COMPILE_RPC_INPUT;
1960 } else {
1961 ctx->compile_opts |= LYS_COMPILE_RPC_OUTPUT;
1962 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001963 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001964 } else {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02001965 LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, target, aug_flags, &child_set), cleanup);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001966 }
1967
1968 /* eval if-features again for the rest of this node processing */
1969 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
1970 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001971 ctx->compile_opts |= LYS_COMPILE_DISABLED;
1972 }
1973
1974 /* since the augment node is not present in the compiled tree, we need to pass some of its
1975 * statements to all its children */
1976 for (i = 0; i < child_set.count; ++i) {
1977 node = child_set.snodes[i];
1978 if (!allow_mand && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
1979 node->flags &= ~LYS_MAND_TRUE;
1980 lys_compile_mandatory_parents(target, 0);
1981 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
1982 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.",
1983 node->name);
1984 rc = LY_EVALID;
1985 goto cleanup;
1986 }
1987
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001988 if (aug_when) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001989 /* pass augment's when to all the children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02001990 rc = lys_compile_when(ctx, aug_when, aug_flags, target, lysc_data_node(target), node, &when_shared);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001991 LY_CHECK_GOTO(rc, cleanup);
1992 }
1993
Michal Vaskoa084fa32022-05-16 11:32:58 +02001994 if (child_unres_disabled) {
Michal Vaskoad0980a2022-05-09 11:43:47 +02001995 /* child is disabled by the augment if-features */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02001996 ly_set_add(&ctx->unres->disabled, node, 1, NULL);
1997 }
1998 }
1999
2000 /* next iter */
2001 ly_set_erase(&child_set, NULL);
2002 ctx->compile_opts = opt_prev;
2003 }
2004
2005cleanup:
2006 ly_set_erase(&child_set, NULL);
2007 ctx->compile_opts = opt_prev;
2008 return rc;
2009}
2010
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002011/**
2012 * @brief Compile the parsed augment connecting it into its target.
2013 *
2014 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
2015 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
2016 * are already implemented and compiled.
2017 *
2018 * @param[in] ctx Compile context.
2019 * @param[in] aug_p Parsed augment to compile.
2020 * @param[in] target Target node of the augment.
2021 * @return LY_SUCCESS on success.
2022 * @return LY_EVALID on failure.
2023 */
2024static LY_ERR
Radek Krejci2a9fc652021-01-22 17:44:34 +01002025lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002026{
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002027 LY_ERR rc = LY_SUCCESS;
Michal Vaskoa084fa32022-05-16 11:32:58 +02002028 ly_bool enabled, child_unres_disabled = 0;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002029 uint32_t opt_prev = ctx->compile_opts;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002030
Michal Vasko95f736c2022-06-08 12:03:31 +02002031 assert(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF));
2032
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002033 /* nodetype checks */
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002034 if (aug_p->actions && !lysc_node_actions_p(target)) {
2035 LOGVAL(ctx->ctx, LYVE_REFERENCE,
2036 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
2037 lys_nodetype2str(target->nodetype), aug_p->actions->name);
2038 rc = LY_EVALID;
2039 goto cleanup;
2040 }
2041 if (aug_p->notifs && !lysc_node_notifs_p(target)) {
2042 LOGVAL(ctx->ctx, LYVE_REFERENCE,
2043 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
2044 lys_nodetype2str(target->nodetype), aug_p->notifs->name);
2045 rc = LY_EVALID;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002046 goto cleanup;
2047 }
2048
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002049 /* augment if-features */
2050 LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, aug_p->iffeatures, &enabled), cleanup);
2051 if (!enabled && !(ctx->compile_opts & (LYS_COMPILE_NO_DISABLED | LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING))) {
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002052 ctx->compile_opts |= LYS_COMPILE_DISABLED;
Michal Vaskoa084fa32022-05-16 11:32:58 +02002053 child_unres_disabled = 1;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002054 }
2055
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002056 /* augment children */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002057 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, aug_p->child, target, child_unres_disabled);
2058 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002059
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002060 /* augment actions */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002061 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->actions, target,
2062 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002063 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002064
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002065 /* augment notifications */
Michal Vasko0b50f6b2022-10-05 15:07:55 +02002066 rc = lys_compile_augment_children(ctx, aug_p->when, aug_p->flags, (struct lysp_node *)aug_p->notifs, target,
2067 child_unres_disabled);
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002068 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002069
Michal Vasko193dacd2022-10-13 08:43:05 +02002070 /* compile extensions into the target */
2071 COMPILE_EXTS_GOTO(ctx, aug_p->exts, target->exts, target, rc, cleanup);
2072
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002073cleanup:
Michal Vasko7c565922021-06-10 14:58:27 +02002074 ctx->compile_opts = opt_prev;
Michal Vaskobbb3dee2022-05-09 10:50:28 +02002075 return rc;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002076}
2077
2078LY_ERR
2079lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
2080{
2081 LY_ERR ret = LY_SUCCESS;
2082 struct lys_module *orig_mod = ctx->cur_mod;
2083 struct lysp_module *orig_pmod = ctx->pmod;
2084 uint32_t i;
2085 char orig_path[LYSC_CTX_BUFSIZE];
2086 struct lysc_augment *aug;
2087
2088 /* uses augments */
2089 for (i = 0; i < ctx->uses_augs.count; ) {
2090 aug = ctx->uses_augs.objs[i];
2091
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002092 if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->ext, aug->nodeid_ctx_node, node, NULL, NULL,
2093 ctx->ext)) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002094 /* not our target node */
2095 ++i;
2096 continue;
2097 }
2098
Michal Vaskob8df5762021-01-12 15:15:53 +01002099 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002100 lysc_update_path(ctx, NULL, "{augment}");
2101 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vasko28fe5f62021-03-03 16:37:39 +01002102 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vaskob8df5762021-01-12 15:15:53 +01002103
2104 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002105 ret = lys_compile_augment(ctx, aug->aug_p, node);
2106 lysc_update_path(ctx, NULL, NULL);
2107 lysc_update_path(ctx, NULL, NULL);
2108 LY_CHECK_GOTO(ret, cleanup);
2109
Michal Vaskoc75f2042021-06-08 14:57:03 +02002110 /* augment was applied, remove it (index and the whole set may have changed because other augments
2111 * could have been applied) */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002112 ly_set_rm(&ctx->uses_augs, aug, NULL);
2113 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002114 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002115 }
2116
2117 /* top-level augments */
2118 for (i = 0; i < ctx->augs.count; ) {
2119 aug = ctx->augs.objs[i];
2120
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002121 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 +02002122 /* not our target node */
2123 ++i;
2124 continue;
2125 }
2126
Michal Vaskob8df5762021-01-12 15:15:53 +01002127 /* use the path and modules from the augment */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002128 strcpy(orig_path, ctx->path);
2129 ctx->path_len = 1;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002130 ctx->cur_mod = aug->aug_pmod->mod;
2131 ctx->pmod = (struct lysp_module *)aug->aug_pmod;
Michal Vasko1ade6f12021-04-19 11:32:45 +02002132 lysc_update_path(ctx, NULL, "{augment}");
2133 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
Michal Vaskob8df5762021-01-12 15:15:53 +01002134
2135 /* apply augment, restore the path */
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002136 ret = lys_compile_augment(ctx, aug->aug_p, node);
2137 strcpy(ctx->path, orig_path);
2138 ctx->path_len = strlen(ctx->path);
2139 LY_CHECK_GOTO(ret, cleanup);
2140
2141 /* augment was applied, remove it */
2142 ly_set_rm(&ctx->augs, aug, NULL);
2143 lysc_augment_free(ctx->ctx, aug);
Michal Vaskoc75f2042021-06-08 14:57:03 +02002144 i = 0;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002145 }
2146
2147cleanup:
2148 ctx->cur_mod = orig_mod;
2149 ctx->pmod = orig_pmod;
2150 return ret;
2151}
2152
2153/**
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002154 * @brief Prepare an absolute-nodeid augment to be applied during data nodes compilation.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002155 *
2156 * @param[in] ctx Compile context.
2157 * @param[in] aug_p Parsed augment to be applied.
2158 * @param[in] pmod Both current and prefix module for @p aug_p.
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002159 * @param[in] ext Extension instance in case @p aug_p is defined in one.
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002160 * @return LY_ERR value.
2161 */
2162static LY_ERR
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002163lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, const struct lysp_module *pmod,
2164 const struct lysp_ext_instance *ext)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002165{
2166 LY_ERR ret = LY_SUCCESS;
Michal Vasko8824a6e2024-01-19 12:42:21 +01002167 struct lysc_nodeid *nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002168 struct lysc_augment *aug;
2169 const struct lys_module *mod;
2170
Michal Vasko8824a6e2024-01-19 12:42:21 +01002171 /* compile its target, it was already parsed and fully checked (except for the existence of the nodes) */
2172 ret = lys_precompile_nodeid(ctx->ctx, aug_p->nodeid, &nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002173 LY_CHECK_GOTO(ret, cleanup);
2174
Michal Vasko8824a6e2024-01-19 12:42:21 +01002175 mod = lys_schema_node_get_module(ctx->ctx, nodeid->prefix[0], pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002176 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2177 if (mod != ctx->cur_mod) {
2178 /* augment for another module, ignore */
2179 goto cleanup;
2180 }
2181
2182 /* allocate new compiled augment and store it in the set */
2183 aug = calloc(1, sizeof *aug);
2184 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2185 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
2186
Michal Vasko8824a6e2024-01-19 12:42:21 +01002187 aug->nodeid = nodeid;
2188 nodeid = NULL;
Michal Vasko28fe5f62021-03-03 16:37:39 +01002189 aug->aug_pmod = pmod;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002190 aug->ext = ext;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002191 aug->aug_p = aug_p;
2192
2193cleanup:
Michal Vasko8824a6e2024-01-19 12:42:21 +01002194 lysc_nodeid_free(ctx->ctx, nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002195 return ret;
2196}
2197
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002198/**
2199 * @brief Prepare all top-level augments and extension instance augments to be applied during data nodes compilation.
2200 *
2201 * @param[in] ctx Compile context.
2202 * @param[in] pmod Parsed mod to use.
2203 * @return LY_ERR value.
2204 */
2205static LY_ERR
2206lys_precompile_own_augments_mod(struct lysc_ctx *ctx, const struct lysp_module *pmod)
2207{
2208 LY_ARRAY_COUNT_TYPE u, v;
2209 struct lysp_node_augment *aug_p;
2210
2211 /* module */
2212 LY_LIST_FOR(pmod->augments, aug_p) {
2213 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, NULL));
2214 }
2215
2216 /* parsed extension instances */
2217 LY_ARRAY_FOR(pmod->exts, u) {
2218 aug_p = NULL;
2219 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2220 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
Michal Vaskoa6bab1e2024-09-05 12:24:20 +02002221 aug_p = *(pmod->exts[u].substmts[v].storage_p);
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002222 break;
2223 }
2224 }
2225 if (!aug_p) {
2226 continue;
2227 }
2228
2229 LY_CHECK_RET(lys_precompile_own_augment(ctx, aug_p, pmod, &pmod->exts[u]));
2230 }
2231
2232 return LY_SUCCESS;
2233}
2234
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002235LY_ERR
2236lys_precompile_own_augments(struct lysc_ctx *ctx)
2237{
Radek Krejci2a9fc652021-01-22 17:44:34 +01002238 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002239 const struct lys_module *aug_mod;
2240 const struct lysp_module *submod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002241
2242 LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002243 aug_mod = ctx->cur_mod->augmented_by[u];
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002244
2245 /* collect all module augments */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002246 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, aug_mod->parsed));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002247
2248 /* collect all submodules augments */
2249 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002250 submod = (struct lysp_module *)aug_mod->parsed->includes[v].submodule;
2251
2252 LY_CHECK_RET(lys_precompile_own_augments_mod(ctx, submod));
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002253 }
2254 }
2255
2256 return LY_SUCCESS;
2257}
2258
2259/**
2260 * @brief Prepare a deviation to be applied during data nodes compilation.
2261 *
2262 * @param[in] ctx Compile context.
2263 * @param[in] dev_p Parsed deviation to be applied.
2264 * @param[in] pmod Both current and prefix module for @p dev_p.
2265 * @return LY_ERR value.
2266 */
2267static LY_ERR
2268lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod)
2269{
2270 LY_ERR ret = LY_SUCCESS;
2271 struct lysc_deviation *dev = NULL;
Michal Vasko8824a6e2024-01-19 12:42:21 +01002272 struct lysc_nodeid *nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002273 struct lysp_deviation **new_dev;
2274 const struct lys_module *mod;
2275 const struct lysp_module **new_dev_pmod;
2276 uint32_t i;
2277
2278 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
Michal Vasko8824a6e2024-01-19 12:42:21 +01002279 ret = lys_precompile_nodeid(ctx->ctx, dev_p->nodeid, &nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002280 LY_CHECK_GOTO(ret, cleanup);
2281
Michal Vasko8824a6e2024-01-19 12:42:21 +01002282 mod = lys_schema_node_get_module(ctx->ctx, nodeid->prefix[0], pmod);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002283 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
2284 if (mod != ctx->cur_mod) {
2285 /* deviation for another module, ignore */
2286 goto cleanup;
2287 }
2288
2289 /* try to find the node in already compiled deviations */
2290 for (i = 0; i < ctx->devs.count; ++i) {
Michal Vasko8824a6e2024-01-19 12:42:21 +01002291 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 +02002292 ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) {
2293 dev = ctx->devs.objs[i];
2294 break;
2295 }
2296 }
2297
2298 if (!dev) {
2299 /* allocate new compiled deviation */
2300 dev = calloc(1, sizeof *dev);
2301 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
2302 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
2303
Michal Vasko8824a6e2024-01-19 12:42:21 +01002304 dev->nodeid = nodeid;
2305 nodeid = NULL;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002306 }
2307
2308 /* add new parsed deviation structure */
2309 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
2310 *new_dev = dev_p;
2311 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup);
2312 *new_dev_pmod = pmod;
2313
2314cleanup:
Michal Vasko8824a6e2024-01-19 12:42:21 +01002315 lysc_nodeid_free(ctx->ctx, nodeid);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002316 return ret;
2317}
2318
2319LY_ERR
2320lys_precompile_own_deviations(struct lysc_ctx *ctx)
2321{
2322 LY_ARRAY_COUNT_TYPE u, v, w;
Michal Vaskoe8220db2021-06-02 15:39:05 +02002323 struct lys_module *orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002324 const struct lys_module *dev_mod;
2325 struct lysc_deviation *dev;
2326 struct lysp_deviate *d;
2327 int not_supported;
2328 uint32_t i;
2329
2330 LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) {
2331 dev_mod = ctx->cur_mod->deviated_by[u];
2332
2333 /* compile all module deviations */
2334 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
2335 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed));
2336 }
2337
2338 /* compile all submodules deviations */
2339 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
2340 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
2341 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w],
2342 (struct lysp_module *)dev_mod->parsed->includes[v].submodule));
2343 }
2344 }
2345 }
2346
2347 /* set not-supported flags for all the deviations */
2348 for (i = 0; i < ctx->devs.count; ++i) {
2349 dev = ctx->devs.objs[i];
2350 not_supported = 0;
2351
2352 LY_ARRAY_FOR(dev->devs, u) {
2353 LY_LIST_FOR(dev->devs[u]->deviates, d) {
2354 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
2355 not_supported = 1;
2356 break;
2357 }
2358 }
2359 if (not_supported) {
2360 break;
2361 }
2362 }
2363 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
Michal Vaskoe8220db2021-06-02 15:39:05 +02002364 orig_cur_mod = ctx->cur_mod;
2365 ctx->cur_mod = dev->dev_pmods[u]->mod;
2366 lysc_update_path(ctx, NULL, "{deviation}");
Michal Vasko8824a6e2024-01-19 12:42:21 +01002367 lysc_update_path(ctx, NULL, dev->nodeid->str);
Radek Krejci2efc45b2020-12-22 16:25:44 +01002368 LOGVAL(ctx->ctx, LYVE_SEMANTICS,
Michal Vasko8824a6e2024-01-19 12:42:21 +01002369 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->str);
Michal Vaskoe8220db2021-06-02 15:39:05 +02002370 lysc_update_path(ctx, NULL, NULL);
2371 lysc_update_path(ctx, NULL, NULL);
2372 ctx->cur_mod = orig_cur_mod;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002373 return LY_EVALID;
2374 }
2375
2376 dev->not_supported = not_supported;
2377 }
2378
2379 return LY_SUCCESS;
2380}
2381
2382/**
2383 * @brief Add a module reference into an array, checks for duplicities.
2384 *
2385 * @param[in] ctx Compile context.
2386 * @param[in] mod Module reference to add.
2387 * @param[in,out] mod_array Module sized array to add to.
2388 * @return LY_ERR value.
2389 */
2390static LY_ERR
2391lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
2392{
2393 LY_ARRAY_COUNT_TYPE u;
2394 struct lys_module **new_mod;
2395
2396 LY_ARRAY_FOR(*mod_array, u) {
2397 if ((*mod_array)[u] == mod) {
2398 /* already there */
2399 return LY_EEXIST;
2400 }
2401 }
2402
2403 /* add the new module ref */
2404 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
2405 *new_mod = mod;
2406
2407 return LY_SUCCESS;
2408}
2409
Michal Vasko1ccbf542021-04-19 11:35:00 +02002410/**
2411 * @brief Check whether all modules in a set are implemented.
2412 *
2413 * @param[in] mod_set Module set to check.
2414 * @return Whether all modules are implemented or not.
2415 */
2416static ly_bool
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002417lys_precompile_mod_set_is_all_implemented(const struct ly_set *mod_set)
Michal Vasko1ccbf542021-04-19 11:35:00 +02002418{
2419 uint32_t i;
2420 const struct lys_module *mod;
2421
2422 for (i = 0; i < mod_set->count; ++i) {
2423 mod = mod_set->objs[i];
2424 if (!mod->implemented) {
2425 return 0;
2426 }
2427 }
2428
2429 return 1;
2430}
2431
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002432/**
2433 * @brief Add references to target modules of top-level augments, deviations, and augments in extension instances
2434 * in a module and all its submodules.
2435 *
2436 * @param[in] pmod Module to process.
2437 * @param[in,out] mod_set Module set to add referenced modules into.
2438 * @return LY_SUCCESS on success.
2439 * @return LY_ERR on error.
2440 */
2441static LY_ERR
2442lys_precompile_mod_augments_deviations(struct lysp_module *pmod, struct ly_set *mod_set)
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002443{
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002444 LY_ERR ret = LY_SUCCESS;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002445 LY_ARRAY_COUNT_TYPE u, v;
Michal Vaskoc636ea42022-09-16 10:20:31 +02002446 struct lysc_ctx ctx;
Michal Vasko65333882021-06-10 14:12:16 +02002447 struct lys_module *m;
Radek Krejci2a9fc652021-01-22 17:44:34 +01002448 struct lysp_node_augment *aug;
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002449 struct ly_set set = {0};
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002450
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002451 LYSC_CTX_INIT_PMOD(ctx, pmod, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002452
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002453 LY_LIST_FOR(pmod->augments, aug) {
Michal Vasko1ccbf542021-04-19 11:35:00 +02002454 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002455 lysc_update_path(&ctx, NULL, "{augment}");
2456 lysc_update_path(&ctx, NULL, aug->nodeid);
2457 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2458 lysc_update_path(&ctx, NULL, NULL);
2459 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002460 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002461
Michal Vasko1ccbf542021-04-19 11:35:00 +02002462 /* add this module into the target module augmented_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002463 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002464 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002465 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002466 }
Michal Vasko1ccbf542021-04-19 11:35:00 +02002467 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002468 }
2469
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002470 LY_ARRAY_FOR(pmod->deviations, u) {
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002471 /* get target module */
Michal Vasko65333882021-06-10 14:12:16 +02002472 lysc_update_path(&ctx, NULL, "{deviation}");
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002473 lysc_update_path(&ctx, NULL, pmod->deviations[u].nodeid);
2474 ret = lys_nodeid_mod_check(&ctx, pmod->deviations[u].nodeid, 1, &set, NULL, &m);
Michal Vasko65333882021-06-10 14:12:16 +02002475 lysc_update_path(&ctx, NULL, NULL);
2476 lysc_update_path(&ctx, NULL, NULL);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002477 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002478
Michal Vasko1ccbf542021-04-19 11:35:00 +02002479 /* add this module into the target module deviated_by, if not there and implemented */
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002480 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->deviated_by) != LY_EEXIST) ||
Michal Vaskoffe7dfe2021-06-15 11:58:38 +02002481 !lys_precompile_mod_set_is_all_implemented(&set)) {
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002482 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1ccbf542021-04-19 11:35:00 +02002483 }
2484 ly_set_erase(&set, NULL);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002485 }
2486
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002487 LY_ARRAY_FOR(pmod->exts, u) {
2488 aug = NULL;
2489 LY_ARRAY_FOR(pmod->exts[u].substmts, v) {
2490 if (pmod->exts[u].substmts[v].stmt == LY_STMT_AUGMENT) {
Michal Vaskoa6bab1e2024-09-05 12:24:20 +02002491 aug = *(pmod->exts[u].substmts[v].storage_p);
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002492 break;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002493 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002494 }
2495 if (!aug) {
2496 continue;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002497 }
2498
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002499 /* get target module */
2500 lysc_update_path(&ctx, NULL, "{ext-augment}");
2501 lysc_update_path(&ctx, NULL, aug->nodeid);
2502 ret = lys_nodeid_mod_check(&ctx, aug->nodeid, 1, &set, NULL, &m);
2503 lysc_update_path(&ctx, NULL, NULL);
2504 lysc_update_path(&ctx, NULL, NULL);
2505 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002506
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002507 /* add this module into the target module augmented_by, if not there and implemented */
2508 if ((lys_array_add_mod_ref(&ctx, pmod->mod, &m->augmented_by) != LY_EEXIST) ||
2509 !lys_precompile_mod_set_is_all_implemented(&set)) {
2510 LY_CHECK_GOTO(ret = ly_set_merge(mod_set, &set, 0, NULL), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002511 }
Michal Vaskoa0ba01e2022-10-19 13:26:57 +02002512 ly_set_erase(&set, NULL);
2513 }
2514
2515cleanup:
2516 ly_set_erase(&set, NULL);
2517 return ret;
2518}
2519
2520LY_ERR
2521lys_precompile_augments_deviations(struct lys_module *mod, struct lys_glob_unres *unres)
2522{
2523 LY_ERR ret = LY_SUCCESS, r;
2524 LY_ARRAY_COUNT_TYPE u;
2525 struct lys_module *m;
2526 struct lysp_module *submod;
2527 const char **imp_f, *all_f[] = {"*", NULL};
2528 uint32_t i;
2529 struct ly_set mod_set = {0};
2530
2531 /* module */
2532 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(mod->parsed, &mod_set), cleanup);
2533
2534 /* submodules */
2535 LY_ARRAY_FOR(mod->parsed->includes, u) {
2536 submod = (struct lysp_module *)mod->parsed->includes[u].submodule;
2537 LY_CHECK_GOTO(ret = lys_precompile_mod_augments_deviations(submod, &mod_set), cleanup);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002538 }
2539
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002540 for (i = 0; i < mod_set.count; ++i) {
2541 m = mod_set.objs[i];
Michal Vasko1ccbf542021-04-19 11:35:00 +02002542
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002543 if (m == mod) {
2544 /* will be applied normally later */
2545 continue;
2546 }
2547
2548 /* we do not actually need the target modules compiled with out amends, they just need to be implemented
2549 * not compiled yet and marked for compilation */
2550
2551 if (!m->implemented) {
2552 /* implement the target module */
Michal Vaskoc56d6372021-10-19 12:29:00 +02002553 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
2554 r = lys_implement(m, imp_f, unres);
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002555 if (r == LY_ERECOMPILE) {
2556 /* implement all the modules right away to save possible later recompilation */
2557 ret = r;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002558 continue;
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002559 } else if (r) {
2560 /* error */
2561 ret = r;
Michal Vasko65333882021-06-10 14:12:16 +02002562 goto cleanup;
Michal Vasko1ccbf542021-04-19 11:35:00 +02002563 }
Michal Vaskoa9f807e2021-06-15 12:07:16 +02002564 } else if (m->compiled) {
2565 /* target module was already compiled without our amends (augment/deviation), we need to recompile it */
2566 m->to_compile = 1;
2567 ret = LY_ERECOMPILE;
2568 continue;
2569 }
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002570 }
2571
Michal Vasko1ccbf542021-04-19 11:35:00 +02002572cleanup:
Michal Vasko1ccbf542021-04-19 11:35:00 +02002573 ly_set_erase(&mod_set, NULL);
2574 return ret;
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002575}
2576
2577void
2578lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
2579{
2580 uint32_t i;
2581 LY_ARRAY_COUNT_TYPE u, count;
2582 struct lys_module *m;
2583
2584 for (i = 0; i < ctx->list.count; ++i) {
2585 m = ctx->list.objs[i];
2586
2587 if (m->augmented_by) {
2588 count = LY_ARRAY_COUNT(m->augmented_by);
2589 for (u = 0; u < count; ++u) {
2590 if (m->augmented_by[u] == mod) {
2591 /* keep the order */
2592 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002593 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u - 1) * sizeof *m->augmented_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002594 }
2595 LY_ARRAY_DECREMENT(m->augmented_by);
2596 break;
2597 }
2598 }
2599 if (!LY_ARRAY_COUNT(m->augmented_by)) {
2600 LY_ARRAY_FREE(m->augmented_by);
2601 m->augmented_by = NULL;
2602 }
2603 }
2604
2605 if (m->deviated_by) {
2606 count = LY_ARRAY_COUNT(m->deviated_by);
2607 for (u = 0; u < count; ++u) {
2608 if (m->deviated_by[u] == mod) {
2609 /* keep the order */
2610 if (u < count - 1) {
Michal Vasko69bd24a2021-06-29 08:12:06 +02002611 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u - 1) * sizeof *m->deviated_by);
Michal Vasko1a7a7bd2020-10-16 14:39:15 +02002612 }
2613 LY_ARRAY_DECREMENT(m->deviated_by);
2614 break;
2615 }
2616 }
2617 if (!LY_ARRAY_COUNT(m->deviated_by)) {
2618 LY_ARRAY_FREE(m->deviated_by);
2619 m->deviated_by = NULL;
2620 }
2621 }
2622 }
2623}