blob: d7ac8d88dcf75b96c3691f0d528b01d81619db4c [file] [log] [blame]
Radek Krejci3f5e3db2018-10-11 15:57:47 +02001/**
2 * @file tree_schema.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema tree implementation
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Radek Krejcib7db73a2018-10-24 14:18:40 +020014
Christian Hopps32874e12021-05-01 09:43:54 -040015#define _GNU_SOURCE /* asprintf, strdup */
Radek Krejci535ea9f2020-05-29 16:01:05 +020016
Radek Krejcica376bd2020-06-11 16:04:06 +020017#include "tree_schema.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020018
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include <assert.h>
Radek Krejci545b4872020-11-15 10:15:12 +010020#include <ctype.h>
Radek Krejcid33273d2018-10-25 14:55:52 +020021#include <dirent.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020022#include <errno.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include <stdint.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020024#include <stdio.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include <stdlib.h>
26#include <string.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020027#include <sys/stat.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020028#include <unistd.h>
Radek Krejci3f5e3db2018-10-11 15:57:47 +020029
Michal Vasko5aa44c02020-06-29 11:47:02 +020030#include "compat.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020031#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032#include "dict.h"
Radek Krejci47fab892020-11-05 17:02:41 +010033#include "in.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020034#include "in_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010035#include "log.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010036#include "ly_common.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020037#include "parser_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020038#include "parser_schema.h"
Michal Vasko40308e72020-10-20 16:38:40 +020039#include "path.h"
Michal Vaskoe482bb92023-02-01 11:41:41 +010040#include "plugins_exts.h"
Michal Vaskoc0c64ae2022-10-06 10:15:23 +020041#include "plugins_internal.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020042#include "schema_compile.h"
Michal Vaskof4258e12021-06-15 12:11:42 +020043#include "schema_compile_amend.h"
Michal Vasko7b1ad1a2020-11-02 15:41:27 +010044#include "schema_features.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020045#include "set.h"
46#include "tree.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010047#include "tree_edit.h"
Michal Vaskoc636ea42022-09-16 10:20:31 +020048#include "tree_schema_free.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020049#include "tree_schema_internal.h"
50#include "xpath.h"
Radek Krejci3f5e3db2018-10-11 15:57:47 +020051
Radek Krejcieccf6602021-02-05 19:42:54 +010052const char * const ly_devmod_list[] = {
53 [LYS_DEV_NOT_SUPPORTED] = "not-supported",
54 [LYS_DEV_ADD] = "add",
55 [LYS_DEV_DELETE] = "delete",
56 [LYS_DEV_REPLACE] = "replace",
57};
58
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010059LIBYANG_API_DEF LY_ERR
Michal Vaskof1ab44f2020-10-22 08:58:32 +020060lysc_tree_dfs_full(const struct lysc_node *root, lysc_dfs_clb dfs_clb, void *data)
61{
Michal Vasko1d972ca2020-11-03 17:16:56 +010062 struct lysc_node *elem, *elem2;
Radek Krejci2a9fc652021-01-22 17:44:34 +010063 const struct lysc_node_action *action;
64 const struct lysc_node_notif *notif;
Michal Vaskof1ab44f2020-10-22 08:58:32 +020065
66 LY_CHECK_ARG_RET(NULL, root, dfs_clb, LY_EINVAL);
67
68 LYSC_TREE_DFS_BEGIN(root, elem) {
69 /* schema node */
70 LY_CHECK_RET(dfs_clb(elem, data, &LYSC_TREE_DFS_continue));
71
Radek Krejci2a9fc652021-01-22 17:44:34 +010072 LY_LIST_FOR(lysc_node_actions(elem), action) {
73 LYSC_TREE_DFS_BEGIN(action, elem2) {
Michal Vaskof1ab44f2020-10-22 08:58:32 +020074 /* action subtree */
75 LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
76
Radek Krejci2a9fc652021-01-22 17:44:34 +010077 LYSC_TREE_DFS_END(action, elem2);
Michal Vaskof1ab44f2020-10-22 08:58:32 +020078 }
79 }
80
Radek Krejci2a9fc652021-01-22 17:44:34 +010081 LY_LIST_FOR(lysc_node_notifs(elem), notif) {
82 LYSC_TREE_DFS_BEGIN(notif, elem2) {
Michal Vaskof1ab44f2020-10-22 08:58:32 +020083 /* notification subtree */
84 LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
85
Radek Krejci2a9fc652021-01-22 17:44:34 +010086 LYSC_TREE_DFS_END(notif, elem2);
Michal Vaskof1ab44f2020-10-22 08:58:32 +020087 }
88 }
89
90 LYSC_TREE_DFS_END(root, elem);
91 }
92
93 return LY_SUCCESS;
94}
95
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010096LIBYANG_API_DEF LY_ERR
Michal Vaskof1ab44f2020-10-22 08:58:32 +020097lysc_module_dfs_full(const struct lys_module *mod, lysc_dfs_clb dfs_clb, void *data)
98{
Michal Vasko2336cf52020-11-03 17:18:15 +010099 const struct lysc_node *root;
Michal Vaskof1ab44f2020-10-22 08:58:32 +0200100
101 LY_CHECK_ARG_RET(NULL, mod, mod->compiled, dfs_clb, LY_EINVAL);
102
103 /* schema nodes */
Michal Vasko2336cf52020-11-03 17:18:15 +0100104 LY_LIST_FOR(mod->compiled->data, root) {
105 LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
106 }
Michal Vaskof1ab44f2020-10-22 08:58:32 +0200107
108 /* RPCs */
Radek Krejci2a9fc652021-01-22 17:44:34 +0100109 LY_LIST_FOR((const struct lysc_node *)mod->compiled->rpcs, root) {
110 LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
Michal Vaskof1ab44f2020-10-22 08:58:32 +0200111 }
112
113 /* notifications */
Radek Krejci2a9fc652021-01-22 17:44:34 +0100114 LY_LIST_FOR((const struct lysc_node *)mod->compiled->notifs, root) {
115 LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
Michal Vaskof1ab44f2020-10-22 08:58:32 +0200116 }
117
118 return LY_SUCCESS;
119}
120
Radek Krejcib93bd412020-11-02 13:23:11 +0100121static void
122lys_getnext_into_case(const struct lysc_node_case *first_case, const struct lysc_node **last, const struct lysc_node **next)
123{
Radek Krejcic5b54a02020-11-05 17:13:18 +0100124 for ( ; first_case; first_case = (const struct lysc_node_case *)first_case->next) {
Radek Krejcib93bd412020-11-02 13:23:11 +0100125 if (first_case->child) {
126 /* there is something to return */
127 (*next) = first_case->child;
128 return;
129 }
130 }
131
132 /* no children in choice's cases, so go to the choice's sibling instead of into it */
133 (*last) = (*next);
134 (*next) = (*next)->next;
135}
136
Radek Krejci035dacf2021-02-12 18:25:53 +0100137/**
138 * @brief Generic getnext function for ::lys_getnext() and ::lys_getnext_ext().
139 *
140 * Gets next schema tree (sibling) node element that can be instantiated in a data tree. Returned node can
141 * be from an augment. If the @p ext is provided, the function is locked inside the schema tree defined in the
142 * extension instance.
143 *
Michal Vasko193dacd2022-10-13 08:43:05 +0200144 * ::lys_getnext_() is supposed to be called sequentially. In the first call, the @p last parameter is usually NULL
145 * and function starts returning i) the first @p parent's child or ii) the first top level element specified in the
146 * given extension (if provided) or iii) the first top level element of the @p module.
147 * Consequent calls suppose to provide the previously returned node as the @p last parameter and still the same
148 * @p parent and @p module parameters.
Radek Krejci035dacf2021-02-12 18:25:53 +0100149 *
150 * Without options, the function is used to traverse only the schema nodes that can be paired with corresponding
Michal Vasko193dacd2022-10-13 08:43:05 +0200151 * data nodes in a data tree. By setting some @p options the behavior can be modified to the extent that
Radek Krejci035dacf2021-02-12 18:25:53 +0100152 * all the schema nodes are iteratively returned.
153 *
154 * @param[in] last Previously returned schema tree node, or NULL in case of the first call.
155 * @param[in] parent Parent of the subtree where the function starts processing.
Michal Vasko193dacd2022-10-13 08:43:05 +0200156 * @param[in] module In case of iterating on top level elements, the @p parent is NULL and
Radek Krejci035dacf2021-02-12 18:25:53 +0100157 * module must be specified.
158 * @param[in] ext The extension instance to provide a separate schema tree. To consider the top level elements in the tree,
Michal Vasko193dacd2022-10-13 08:43:05 +0200159 * the @p parent must be NULL. Anyway, at least one of @p parent, @p module and @p ext parameters must be specified.
Radek Krejci035dacf2021-02-12 18:25:53 +0100160 * @param[in] options [ORed options](@ref sgetnextflags).
161 * @return Next schema tree node that can be instantiated in a data tree, NULL in case there is no such element.
162 */
163static const struct lysc_node *
164lys_getnext_(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module,
165 const struct lysc_ext_instance *ext, uint32_t options)
Radek Krejcia3045382018-11-22 14:30:31 +0100166{
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100167 const struct lysc_node *next = NULL;
Michal Vaskoe482bb92023-02-01 11:41:41 +0100168 ly_bool action_flag = 0, notif_flag = 0, sm_flag = options & LYS_GETNEXT_WITHSCHEMAMOUNT ? 0 : 1;
169 LY_ARRAY_COUNT_TYPE u;
170 struct ly_ctx *sm_ctx = NULL;
171 const struct lys_module *mod;
172 uint32_t idx;
Radek Krejcia3045382018-11-22 14:30:31 +0100173
Radek Krejci035dacf2021-02-12 18:25:53 +0100174 LY_CHECK_ARG_RET(NULL, parent || module || ext, NULL);
Radek Krejcia3045382018-11-22 14:30:31 +0100175
Radek Krejcid5a2b9d2019-04-12 10:39:30 +0200176next:
Radek Krejcia3045382018-11-22 14:30:31 +0100177 if (!last) {
178 /* first call */
179
Michal Vaskoe482bb92023-02-01 11:41:41 +0100180 /* learn where to start */
Radek Krejcia3045382018-11-22 14:30:31 +0100181 if (parent) {
182 /* schema subtree */
Michal Vasko544e58a2021-01-28 14:33:41 +0100183 next = last = lysc_node_child(parent);
Radek Krejcia3045382018-11-22 14:30:31 +0100184 } else {
185 /* top level data */
Radek Krejci035dacf2021-02-12 18:25:53 +0100186 if (ext) {
Michal Vaskofbd037c2022-11-08 10:34:20 +0100187 lyplg_ext_get_storage(ext, LY_STMT_DATA_NODE_MASK, sizeof last, (const void **)&last);
Michal Vasko193dacd2022-10-13 08:43:05 +0200188 next = last;
Radek Krejci035dacf2021-02-12 18:25:53 +0100189 } else {
190 next = last = module->data;
191 }
Radek Krejcia3045382018-11-22 14:30:31 +0100192 }
193 if (!next) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100194 /* try to get action or notification */
195 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100196 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100197 /* test if the next can be returned */
198 goto check;
199
Michal Vasko1bf09392020-03-27 12:38:10 +0100200 } else if (last->nodetype & (LYS_RPC | LYS_ACTION)) {
Radek Krejci05b774b2019-02-25 13:26:18 +0100201 action_flag = 1;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100202 next = last->next;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100203 } else if (last->nodetype == LYS_NOTIF) {
Radek Krejci05b774b2019-02-25 13:26:18 +0100204 action_flag = notif_flag = 1;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100205 next = last->next;
Michal Vasko20424b42020-08-31 12:29:38 +0200206 } else {
207 next = last->next;
Radek Krejcia3045382018-11-22 14:30:31 +0100208 }
209
Radek Krejcia3045382018-11-22 14:30:31 +0100210repeat:
211 if (!next) {
Michal Vaskoe482bb92023-02-01 11:41:41 +0100212 if (last && !sm_flag && parent && (last->module->ctx != parent->module->ctx)) {
213 sm_flag = 1;
214
215 /* find the module of last */
216 sm_ctx = last->module->ctx;
217 idx = 0;
218 while ((mod = ly_ctx_get_module_iter(sm_ctx, &idx))) {
219 if (mod == last->module) {
220 break;
221 }
222 }
223 assert(mod);
224
225 /* get node from the next mounted module */
226 while (!next && (mod = ly_ctx_get_module_iter(sm_ctx, &idx))) {
227 if (!mod->implemented) {
228 continue;
229 }
230
231 next = lys_getnext(NULL, NULL, mod->compiled, options & ~LYS_GETNEXT_WITHSCHEMAMOUNT);
232 }
233 } else if (last && (last->parent != parent)) {
234 /* go back to parent */
Radek Krejcia9026eb2018-12-12 16:04:47 +0100235 last = last->parent;
Radek Krejcid5a2b9d2019-04-12 10:39:30 +0200236 goto next;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100237 } else if (!action_flag) {
238 action_flag = 1;
Radek Krejci035dacf2021-02-12 18:25:53 +0100239 if (ext) {
Michal Vaskofbd037c2022-11-08 10:34:20 +0100240 lyplg_ext_get_storage(ext, LY_STMT_OP_MASK, sizeof next, (const void **)&next);
Radek Krejci035dacf2021-02-12 18:25:53 +0100241 } else if (parent) {
242 next = (struct lysc_node *)lysc_node_actions(parent);
243 } else {
244 next = (struct lysc_node *)module->rpcs;
245 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100246 } else if (!notif_flag) {
247 notif_flag = 1;
Radek Krejci035dacf2021-02-12 18:25:53 +0100248 if (ext) {
Michal Vaskofbd037c2022-11-08 10:34:20 +0100249 lyplg_ext_get_storage(ext, LY_STMT_NOTIFICATION, sizeof next, (const void **)&next);
Radek Krejci035dacf2021-02-12 18:25:53 +0100250 } else if (parent) {
251 next = (struct lysc_node *)lysc_node_notifs(parent);
252 } else {
253 next = (struct lysc_node *)module->notifs;
254 }
Michal Vaskoe482bb92023-02-01 11:41:41 +0100255 } else if (!sm_flag) {
256 sm_flag = 1;
257 if (parent) {
258 LY_ARRAY_FOR(parent->exts, u) {
259 if (!strcmp(parent->exts[u].def->name, "mount-point") &&
260 !strcmp(parent->exts[u].def->module->name, "ietf-yang-schema-mount")) {
261 lyplg_ext_schema_mount_create_context(&parent->exts[u], &sm_ctx);
262 if (sm_ctx) {
263 /* some usable context created */
264 break;
265 }
266 }
267 }
268 if (sm_ctx) {
269 /* get the first node from the first usable module */
270 idx = 0;
271 while (!next && (mod = ly_ctx_get_module_iter(sm_ctx, &idx))) {
272 if (!mod->implemented) {
273 continue;
274 }
275
276 next = lys_getnext(NULL, NULL, mod->compiled, options & ~LYS_GETNEXT_WITHSCHEMAMOUNT);
277 }
278 if (!next) {
279 /* no nodes found */
280 ly_ctx_destroy(sm_ctx);
281 }
282 }
283 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100284 } else {
285 return NULL;
Radek Krejcia9026eb2018-12-12 16:04:47 +0100286 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100287 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100288 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100289check:
Radek Krejcia3045382018-11-22 14:30:31 +0100290 switch (next->nodetype) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100291 case LYS_RPC:
Radek Krejcia3045382018-11-22 14:30:31 +0100292 case LYS_ACTION:
293 case LYS_NOTIF:
294 case LYS_LEAF:
295 case LYS_ANYXML:
296 case LYS_ANYDATA:
297 case LYS_LIST:
298 case LYS_LEAFLIST:
299 break;
Michal Vasko20424b42020-08-31 12:29:38 +0200300 case LYS_CASE:
301 if (options & LYS_GETNEXT_WITHCASE) {
302 break;
303 } else {
304 /* go into */
Radek Krejcib93bd412020-11-02 13:23:11 +0100305 lys_getnext_into_case((const struct lysc_node_case *)next, &last, &next);
Michal Vasko20424b42020-08-31 12:29:38 +0200306 }
307 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100308 case LYS_CONTAINER:
Michal Vasko14ed9cd2021-01-28 14:16:25 +0100309 if (!(next->flags & LYS_PRESENCE) && (options & LYS_GETNEXT_INTONPCONT)) {
Michal Vasko544e58a2021-01-28 14:33:41 +0100310 if (lysc_node_child(next)) {
Radek Krejcia3045382018-11-22 14:30:31 +0100311 /* go into */
Michal Vasko544e58a2021-01-28 14:33:41 +0100312 next = lysc_node_child(next);
Radek Krejcia3045382018-11-22 14:30:31 +0100313 } else {
Radek Krejcib93bd412020-11-02 13:23:11 +0100314 last = next;
Radek Krejcia3045382018-11-22 14:30:31 +0100315 next = next->next;
316 }
317 goto repeat;
318 }
319 break;
320 case LYS_CHOICE:
321 if (options & LYS_GETNEXT_WITHCHOICE) {
Michal Vasko20424b42020-08-31 12:29:38 +0200322 break;
Michal Vasko544e58a2021-01-28 14:33:41 +0100323 } else if ((options & LYS_GETNEXT_NOCHOICE) || !lysc_node_child(next)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100324 next = next->next;
325 } else {
Radek Krejcia9026eb2018-12-12 16:04:47 +0100326 if (options & LYS_GETNEXT_WITHCASE) {
Michal Vasko544e58a2021-01-28 14:33:41 +0100327 next = lysc_node_child(next);
Radek Krejcia9026eb2018-12-12 16:04:47 +0100328 } else {
Radek Krejcib93bd412020-11-02 13:23:11 +0100329 /* go into */
330 lys_getnext_into_case(((struct lysc_node_choice *)next)->cases, &last, &next);
Radek Krejcia9026eb2018-12-12 16:04:47 +0100331 }
Radek Krejcia3045382018-11-22 14:30:31 +0100332 }
333 goto repeat;
Michal Vasko544e58a2021-01-28 14:33:41 +0100334 case LYS_INPUT:
335 if (options & LYS_GETNEXT_OUTPUT) {
336 /* skip */
337 next = next->next;
338 } else {
339 /* go into */
340 next = lysc_node_child(next);
341 }
342 goto repeat;
343 case LYS_OUTPUT:
344 if (!(options & LYS_GETNEXT_OUTPUT)) {
345 /* skip */
346 next = next->next;
347 } else {
348 /* go into */
349 next = lysc_node_child(next);
350 }
351 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100352 default:
353 /* we should not be here */
Radek Krejci035dacf2021-02-12 18:25:53 +0100354 LOGINT(module ? module->mod->ctx : parent ? parent->module->ctx : ext->module->ctx);
Radek Krejcia3045382018-11-22 14:30:31 +0100355 return NULL;
356 }
357
Radek Krejcia3045382018-11-22 14:30:31 +0100358 return next;
359}
360
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100361LIBYANG_API_DEF const struct lysc_node *
Radek Krejci035dacf2021-02-12 18:25:53 +0100362lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, uint32_t options)
363{
364 return lys_getnext_(last, parent, module, NULL, options);
365}
366
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100367LIBYANG_API_DEF const struct lysc_node *
Radek Krejci035dacf2021-02-12 18:25:53 +0100368lys_getnext_ext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_ext_instance *ext, uint32_t options)
369{
370 return lys_getnext_(last, parent, NULL, ext, options);
371}
372
Radek Krejcif16e2542021-02-17 15:39:23 +0100373const struct lysc_node *
Radek Krejciba05eab2021-03-10 13:19:29 +0100374lysc_ext_find_node(const struct lysc_ext_instance *ext, const struct lys_module *module, const char *name, size_t name_len,
Radek Krejcif16e2542021-02-17 15:39:23 +0100375 uint16_t nodetype, uint32_t options)
376{
377 const struct lysc_node *node = NULL;
378
379 LY_CHECK_ARG_RET(NULL, ext, name, NULL);
380 if (!nodetype) {
381 nodetype = LYS_NODETYPE_MASK;
382 }
383
384 if (module && (module != ext->module)) {
385 return NULL;
386 }
387
388 while ((node = lys_getnext_ext(node, NULL, ext, options))) {
389 if (!(node->nodetype & nodetype)) {
390 continue;
391 }
392
393 if (name_len) {
394 if (!ly_strncmp(node->name, name, name_len)) {
395 return node;
396 }
397 } else {
398 if (!strcmp(node->name, name)) {
399 return node;
400 }
401 }
402 }
403 return NULL;
404}
405
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100406LIBYANG_API_DEF const struct lysc_node *
Michal Vaskoe444f752020-02-10 12:20:06 +0100407lys_find_child(const struct lysc_node *parent, const struct lys_module *module, const char *name, size_t name_len,
Radek Krejci1deb5be2020-08-26 16:43:36 +0200408 uint16_t nodetype, uint32_t options)
Radek Krejcia3045382018-11-22 14:30:31 +0100409{
410 const struct lysc_node *node = NULL;
411
412 LY_CHECK_ARG_RET(NULL, module, name, NULL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100413 LY_CHECK_CTX_EQUAL_RET(parent ? parent->module->ctx : NULL, module->ctx, NULL);
Radek Krejcia3045382018-11-22 14:30:31 +0100414 if (!nodetype) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100415 nodetype = LYS_NODETYPE_MASK;
Radek Krejcia3045382018-11-22 14:30:31 +0100416 }
417
418 while ((node = lys_getnext(node, parent, module->compiled, options))) {
419 if (!(node->nodetype & nodetype)) {
420 continue;
421 }
422 if (node->module != module) {
423 continue;
424 }
425
426 if (name_len) {
Radek Krejci7f9b6512019-09-18 13:11:09 +0200427 if (!ly_strncmp(node->name, name, name_len)) {
Radek Krejcia3045382018-11-22 14:30:31 +0100428 return node;
429 }
430 } else {
431 if (!strcmp(node->name, name)) {
432 return node;
433 }
434 }
435 }
Michal Vaskoddd76592022-01-17 13:34:48 +0100436
Radek Krejcia3045382018-11-22 14:30:31 +0100437 return NULL;
438}
439
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100440LIBYANG_API_DEF LY_ERR
Michal Vasko26512682021-01-11 11:35:40 +0100441lys_find_xpath_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *xpath, uint32_t options,
442 struct ly_set **set)
Michal Vasko519fd602020-05-26 12:17:39 +0200443{
444 LY_ERR ret = LY_SUCCESS;
Michal Vasko0b1d0762023-07-10 10:11:22 +0200445 struct lyxp_set xp_set = {0};
Radek Krejcif03a9e22020-09-18 20:09:31 +0200446 struct lyxp_expr *exp = NULL;
Michal Vasko519fd602020-05-26 12:17:39 +0200447 uint32_t i;
448
Michal Vasko26512682021-01-11 11:35:40 +0100449 LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100450 LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
Michal Vasko519fd602020-05-26 12:17:39 +0200451 if (!(options & LYXP_SCNODE_ALL)) {
Michal Vasko4ad69e72021-10-26 16:25:55 +0200452 options |= LYXP_SCNODE;
Michal Vasko519fd602020-05-26 12:17:39 +0200453 }
Michal Vasko26512682021-01-11 11:35:40 +0100454 if (!ctx) {
455 ctx = ctx_node->module->ctx;
456 }
Michal Vasko519fd602020-05-26 12:17:39 +0200457
Michal Vasko0b1d0762023-07-10 10:11:22 +0200458 /* allocate return set */
459 ret = ly_set_new(set);
460 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200461
462 /* compile expression */
Michal Vasko26512682021-01-11 11:35:40 +0100463 ret = lyxp_expr_parse(ctx, xpath, 0, 1, &exp);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200464 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200465
466 /* atomize expression */
Michal Vaskoa3e92bc2022-07-29 14:56:23 +0200467 ret = lyxp_atomize(ctx, exp, NULL, LY_VALUE_JSON, NULL, ctx_node, ctx_node, &xp_set, options);
Michal Vasko519fd602020-05-26 12:17:39 +0200468 LY_CHECK_GOTO(ret, cleanup);
469
Michal Vasko519fd602020-05-26 12:17:39 +0200470 /* transform into ly_set */
471 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
Michal Vasko26512682021-01-11 11:35:40 +0100472 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200473 (*set)->size = xp_set.used;
474
475 for (i = 0; i < xp_set.used; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +0200476 if (xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200477 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200478 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200479 }
480 }
481
482cleanup:
483 lyxp_set_free_content(&xp_set);
Michal Vasko26512682021-01-11 11:35:40 +0100484 lyxp_expr_free(ctx, exp);
Michal Vasko519fd602020-05-26 12:17:39 +0200485 return ret;
486}
487
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100488LIBYANG_API_DEF LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +0200489lys_find_expr_atoms(const struct lysc_node *ctx_node, const struct lys_module *cur_mod, const struct lyxp_expr *expr,
490 const struct lysc_prefix *prefixes, uint32_t options, struct ly_set **set)
491{
492 LY_ERR ret = LY_SUCCESS;
493 struct lyxp_set xp_set = {0};
494 uint32_t i;
495
496 LY_CHECK_ARG_RET(NULL, cur_mod, expr, prefixes, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100497 LY_CHECK_CTX_EQUAL_RET(ctx_node ? ctx_node->module->ctx : NULL, cur_mod->ctx, LY_EINVAL);
Michal Vasko40308e72020-10-20 16:38:40 +0200498 if (!(options & LYXP_SCNODE_ALL)) {
499 options = LYXP_SCNODE;
500 }
501
Michal Vasko0b1d0762023-07-10 10:11:22 +0200502 /* allocate return set */
503 ret = ly_set_new(set);
504 LY_CHECK_GOTO(ret, cleanup);
505
Michal Vasko40308e72020-10-20 16:38:40 +0200506 /* atomize expression */
Michal Vaskoa3e92bc2022-07-29 14:56:23 +0200507 ret = lyxp_atomize(cur_mod->ctx, expr, cur_mod, LY_VALUE_SCHEMA_RESOLVED, (void *)prefixes, ctx_node, ctx_node,
508 &xp_set, options);
Michal Vasko40308e72020-10-20 16:38:40 +0200509 LY_CHECK_GOTO(ret, cleanup);
510
Michal Vasko40308e72020-10-20 16:38:40 +0200511 /* transform into ly_set */
512 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
513 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(cur_mod->ctx); ret = LY_EMEM, cleanup);
514 (*set)->size = xp_set.used;
515
516 for (i = 0; i < xp_set.used; ++i) {
Michal Vasko1a09b212021-05-06 13:00:10 +0200517 if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx >= LYXP_SET_SCNODE_ATOM_NODE)) {
518 assert((xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_NODE) ||
519 (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_VAL) ||
Michal Vaskod97959c2020-12-10 12:18:28 +0100520 (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX));
Michal Vasko40308e72020-10-20 16:38:40 +0200521 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
522 LY_CHECK_GOTO(ret, cleanup);
523 }
524 }
525
526cleanup:
527 lyxp_set_free_content(&xp_set);
528 if (ret) {
529 ly_set_free(*set, NULL);
530 *set = NULL;
531 }
532 return ret;
533}
534
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100535LIBYANG_API_DEF LY_ERR
Michal Vasko26512682021-01-11 11:35:40 +0100536lys_find_xpath(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *xpath, uint32_t options,
537 struct ly_set **set)
Michal Vasko072de482020-08-05 13:27:21 +0200538{
539 LY_ERR ret = LY_SUCCESS;
Michal Vasko40308e72020-10-20 16:38:40 +0200540 struct lyxp_set xp_set = {0};
Radek Krejcif03a9e22020-09-18 20:09:31 +0200541 struct lyxp_expr *exp = NULL;
Michal Vasko072de482020-08-05 13:27:21 +0200542 uint32_t i;
543
Michal Vasko26512682021-01-11 11:35:40 +0100544 LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100545 LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
Michal Vasko072de482020-08-05 13:27:21 +0200546 if (!(options & LYXP_SCNODE_ALL)) {
547 options = LYXP_SCNODE;
548 }
Michal Vasko26512682021-01-11 11:35:40 +0100549 if (!ctx) {
550 ctx = ctx_node->module->ctx;
551 }
Michal Vasko072de482020-08-05 13:27:21 +0200552
Michal Vasko0b1d0762023-07-10 10:11:22 +0200553 /* allocate return set */
554 ret = ly_set_new(set);
555 LY_CHECK_GOTO(ret, cleanup);
556
Michal Vasko072de482020-08-05 13:27:21 +0200557 /* compile expression */
Michal Vasko26512682021-01-11 11:35:40 +0100558 ret = lyxp_expr_parse(ctx, xpath, 0, 1, &exp);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200559 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200560
561 /* atomize expression */
Michal Vaskoa3e92bc2022-07-29 14:56:23 +0200562 ret = lyxp_atomize(ctx, exp, NULL, LY_VALUE_JSON, NULL, ctx_node, ctx_node, &xp_set, options);
Michal Vasko072de482020-08-05 13:27:21 +0200563 LY_CHECK_GOTO(ret, cleanup);
564
Michal Vasko072de482020-08-05 13:27:21 +0200565 /* transform into ly_set */
566 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
Michal Vasko26512682021-01-11 11:35:40 +0100567 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200568 (*set)->size = xp_set.used;
569
570 for (i = 0; i < xp_set.used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100571 if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200572 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200573 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200574 }
575 }
576
577cleanup:
578 lyxp_set_free_content(&xp_set);
Michal Vasko26512682021-01-11 11:35:40 +0100579 lyxp_expr_free(ctx, exp);
Michal Vaskoae159662020-10-21 11:57:24 +0200580 if (ret) {
Michal Vasko40308e72020-10-20 16:38:40 +0200581 ly_set_free(*set, NULL);
582 *set = NULL;
583 }
Michal Vasko072de482020-08-05 13:27:21 +0200584 return ret;
585}
586
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100587LIBYANG_API_DEF LY_ERR
Radek Krejcibc5644c2020-10-27 14:53:17 +0100588lys_find_lypath_atoms(const struct ly_path *path, struct ly_set **set)
589{
590 LY_ERR ret = LY_SUCCESS;
591 LY_ARRAY_COUNT_TYPE u, v;
592
593 LY_CHECK_ARG_RET(NULL, path, set, LY_EINVAL);
594
595 /* allocate return set */
596 LY_CHECK_RET(ly_set_new(set));
597
598 LY_ARRAY_FOR(path, u) {
599 /* add nodes from the path */
600 LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].node, 0, NULL), cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100601 LY_ARRAY_FOR(path[u].predicates, v) {
602 if ((path[u].predicates[v].type == LY_PATH_PREDTYPE_LIST) || (path[u].predicates[v].type == LY_PATH_PREDTYPE_LIST_VAR)) {
Radek Krejcibc5644c2020-10-27 14:53:17 +0100603 /* add all the keys in a predicate */
604 LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].predicates[v].key, 0, NULL), cleanup);
605 }
606 }
607 }
608
609cleanup:
610 if (ret) {
611 ly_set_free(*set, NULL);
612 *set = NULL;
613 }
614 return ret;
615}
616
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100617LIBYANG_API_DEF LY_ERR
Radek Krejcibc5644c2020-10-27 14:53:17 +0100618lys_find_path_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *path, ly_bool output,
619 struct ly_set **set)
620{
621 LY_ERR ret = LY_SUCCESS;
622 uint8_t oper;
623 struct lyxp_expr *expr = NULL;
624 struct ly_path *p = NULL;
625
626 LY_CHECK_ARG_RET(ctx, ctx || ctx_node, path, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100627 LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100628
629 if (!ctx) {
630 ctx = ctx_node->module->ctx;
631 }
632
633 /* parse */
Michal Vasko4f7c53d2023-04-17 08:45:53 +0200634 ret = ly_path_parse(ctx, ctx_node, path, strlen(path), 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
635 LY_PATH_PRED_SIMPLE, &expr);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100636 LY_CHECK_GOTO(ret, cleanup);
637
638 /* compile */
639 oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
Michal Vasko0884d212021-10-14 09:21:46 +0200640 ret = ly_path_compile(ctx, NULL, ctx_node, NULL, expr, oper, LY_PATH_TARGET_MANY, 0, LY_VALUE_JSON, NULL, &p);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100641 LY_CHECK_GOTO(ret, cleanup);
642
643 /* resolve */
644 ret = lys_find_lypath_atoms(p, set);
645
646cleanup:
647 ly_path_free(ctx, p);
648 lyxp_expr_free(ctx, expr);
649 return ret;
650}
651
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100652LIBYANG_API_DEF const struct lysc_node *
Radek Krejcibc5644c2020-10-27 14:53:17 +0100653lys_find_path(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *path, ly_bool output)
654{
655 const struct lysc_node *snode = NULL;
Michal Vasko4f7c53d2023-04-17 08:45:53 +0200656 struct lyxp_expr *expr = NULL;
Radek Krejcibc5644c2020-10-27 14:53:17 +0100657 struct ly_path *p = NULL;
658 LY_ERR ret;
659 uint8_t oper;
660
661 LY_CHECK_ARG_RET(ctx, ctx || ctx_node, NULL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100662 LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, NULL);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100663
664 if (!ctx) {
665 ctx = ctx_node->module->ctx;
666 }
667
668 /* parse */
Michal Vasko4f7c53d2023-04-17 08:45:53 +0200669 ret = ly_path_parse(ctx, ctx_node, path, strlen(path), 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
670 LY_PATH_PRED_SIMPLE, &expr);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100671 LY_CHECK_GOTO(ret, cleanup);
672
673 /* compile */
674 oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
Michal Vasko4f7c53d2023-04-17 08:45:53 +0200675 ret = ly_path_compile(ctx, NULL, ctx_node, NULL, expr, oper, LY_PATH_TARGET_MANY, 0, LY_VALUE_JSON, NULL, &p);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100676 LY_CHECK_GOTO(ret, cleanup);
677
678 /* get last node */
679 snode = p[LY_ARRAY_COUNT(p) - 1].node;
680
681cleanup:
682 ly_path_free(ctx, p);
Michal Vasko4f7c53d2023-04-17 08:45:53 +0200683 lyxp_expr_free(ctx, expr);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100684 return snode;
685}
686
Michal Vasko14654712020-02-06 08:35:21 +0100687char *
688lysc_path_until(const struct lysc_node *node, const struct lysc_node *parent, LYSC_PATH_TYPE pathtype, char *buffer,
Radek Krejci0f969882020-08-21 16:56:47 +0200689 size_t buflen)
Radek Krejci327de162019-06-14 12:52:07 +0200690{
Michal Vaskobde22b62022-03-22 15:32:56 +0100691 const struct lysc_node *iter, *par, *key;
Radek Krejci327de162019-06-14 12:52:07 +0200692 char *path = NULL;
693 int len = 0;
Michal Vaskobde22b62022-03-22 15:32:56 +0100694 ly_bool skip_schema;
Radek Krejci327de162019-06-14 12:52:07 +0200695
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200696 if (buffer) {
697 LY_CHECK_ARG_RET(node->module->ctx, buflen > 1, NULL);
Michal Vasko770d3fc2021-01-26 09:14:35 +0100698 buffer[0] = '\0';
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200699 }
700
Michal Vaskobde22b62022-03-22 15:32:56 +0100701 if ((pathtype == LYSC_PATH_DATA) || (pathtype == LYSC_PATH_DATA_PATTERN)) {
702 /* skip schema-only nodes */
703 skip_schema = 1;
704 } else {
705 skip_schema = 0;
706 }
Radek Krejci327de162019-06-14 12:52:07 +0200707
Michal Vaskobde22b62022-03-22 15:32:56 +0100708 for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
709 char *s;
710 const char *slash;
Michal Vasko65de0402020-08-03 16:34:19 +0200711
Michal Vaskobde22b62022-03-22 15:32:56 +0100712 if (skip_schema && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT))) {
713 /* schema-only node */
714 continue;
715 }
Michal Vasko87dd1342021-08-23 16:17:55 +0200716
Michal Vaskobde22b62022-03-22 15:32:56 +0100717 if ((pathtype == LYSC_PATH_DATA_PATTERN) && (iter->nodetype == LYS_LIST)) {
Alexandre Snarskii669345c2024-05-24 15:56:36 +0300718 char *predicates = NULL;
719
Michal Vaskobde22b62022-03-22 15:32:56 +0100720 key = NULL;
721 while ((key = lys_getnext(key, iter, NULL, 0)) && lysc_is_key(key)) {
Alexandre Snarskii669345c2024-05-24 15:56:36 +0300722 s = predicates;
Michal Vasko87dd1342021-08-23 16:17:55 +0200723
Michal Vaskobde22b62022-03-22 15:32:56 +0100724 /* print key predicate */
Michal Vaskoeea767a2024-05-24 15:11:47 +0200725 if (asprintf(&predicates, "%s[%s='%%s']", s ? s : "", key->name) == -1) {
Alexandre Snarskii669345c2024-05-24 15:56:36 +0300726 free(s);
Michal Vaskoeea767a2024-05-24 15:11:47 +0200727 free(path);
728 return NULL;
Radek Krejci1c0c3442019-07-23 16:08:47 +0200729 }
Michal Vaskoeea767a2024-05-24 15:11:47 +0200730 free(s);
Alexandre Snarskii669345c2024-05-24 15:56:36 +0300731 }
732 s = buffer ? strdup(buffer) : path;
733 if (buffer) {
734 len = snprintf(buffer, buflen, "%s%s", predicates ? predicates : "", s ? s : "");
735 } else {
736 len = asprintf(&path, "%s%s", predicates ? predicates : "", s ? s : "");
737 }
Michal Vaskoeea767a2024-05-24 15:11:47 +0200738 free(predicates);
Alexandre Snarskii669345c2024-05-24 15:56:36 +0300739 free(s);
Michal Vasko28d03812022-03-24 15:26:11 +0100740
Alexandre Snarskii669345c2024-05-24 15:56:36 +0300741 if (buffer && (buflen <= (size_t)len)) {
742 /* not enough space in buffer */
743 break;
Radek Krejci1c0c3442019-07-23 16:08:47 +0200744 }
Radek Krejci327de162019-06-14 12:52:07 +0200745 }
746
Michal Vaskobde22b62022-03-22 15:32:56 +0100747 s = buffer ? strdup(buffer) : path;
748 if (parent && (iter->parent == parent)) {
749 slash = "";
750 } else {
751 slash = "/";
752 }
753
754 if (skip_schema) {
755 par = lysc_data_parent(iter);
756 } else {
757 par = iter->parent;
758 }
759
760 if (!par || (par->module != iter->module)) {
761 /* print prefix */
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200762 if (buffer) {
Michal Vaskobde22b62022-03-22 15:32:56 +0100763 len = snprintf(buffer, buflen, "%s%s:%s%s", slash, iter->module->name, iter->name, s ? s : "");
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200764 } else {
Michal Vaskobde22b62022-03-22 15:32:56 +0100765 len = asprintf(&path, "%s%s:%s%s", slash, iter->module->name, iter->name, s ? s : "");
766 }
767 } else {
768 /* prefix is the same as in parent */
769 if (buffer) {
770 len = snprintf(buffer, buflen, "%s%s%s", slash, iter->name, s ? s : "");
771 } else {
772 len = asprintf(&path, "%s%s%s", slash, iter->name, s ? s : "");
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200773 }
Radek Krejci327de162019-06-14 12:52:07 +0200774 }
Michal Vaskobde22b62022-03-22 15:32:56 +0100775 free(s);
776
777 if (buffer && (buflen <= (size_t)len)) {
778 /* not enough space in buffer */
779 break;
780 }
781 }
782
783 if (len < 0) {
784 free(path);
785 path = NULL;
786 } else if (len == 0) {
787 if (buffer) {
788 strcpy(buffer, "/");
789 } else {
790 path = strdup("/");
791 }
Radek Krejci327de162019-06-14 12:52:07 +0200792 }
793
Radek Krejci1c0c3442019-07-23 16:08:47 +0200794 if (buffer) {
795 return buffer;
796 } else {
797 return path;
798 }
Radek Krejci327de162019-06-14 12:52:07 +0200799}
800
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100801LIBYANG_API_DEF char *
Michal Vasko14654712020-02-06 08:35:21 +0100802lysc_path(const struct lysc_node *node, LYSC_PATH_TYPE pathtype, char *buffer, size_t buflen)
803{
804 return lysc_path_until(node, NULL, pathtype, buffer, buflen);
805}
806
Michal Vasko405cc9e2020-12-01 12:01:27 +0100807LY_ERR
Michal Vasko65333882021-06-10 14:12:16 +0200808_lys_set_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
Michal Vasko405cc9e2020-12-01 12:01:27 +0100809{
810 LY_ERR ret = LY_SUCCESS, r;
aPiecek6b3d5422021-07-30 15:55:43 +0200811 struct lys_module *mod_iter;
Michal Vaskoc56d6372021-10-19 12:29:00 +0200812 const char **imp_f, *all_f[] = {"*", NULL};
Michal Vasko65333882021-06-10 14:12:16 +0200813 uint32_t i;
Michal Vasko916aefb2020-11-02 15:43:16 +0100814
Michal Vasko405cc9e2020-12-01 12:01:27 +0100815 if (mod->implemented) {
816 /* mod is already implemented, set the features */
817 r = lys_set_features(mod->parsed, features);
818 if (r == LY_EEXIST) {
819 /* no changes */
820 return LY_SUCCESS;
Michal Vasko7213ac52021-06-15 11:52:13 +0200821 } else if (!r) {
822 /* mark the module as changed */
Michal Vasko01db7de2021-04-16 12:23:30 +0200823 mod->to_compile = 1;
Michal Vasko01db7de2021-04-16 12:23:30 +0200824 }
Michal Vasko7213ac52021-06-15 11:52:13 +0200825
826 return r;
Michal Vasko89b5c072020-10-06 13:52:44 +0200827 }
Michal Vasko08c8b272020-11-24 18:11:30 +0100828
Michal Vasko7213ac52021-06-15 11:52:13 +0200829 /* implement, ignore recompilation because it must always take place later */
830 r = lys_implement(mod, features, unres);
831 LY_CHECK_ERR_GOTO(r && (r != LY_ERECOMPILE), ret = r, cleanup);
Michal Vasko65333882021-06-10 14:12:16 +0200832
833 if (mod->ctx->flags & LY_CTX_ALL_IMPLEMENTED) {
834 /* implement all the imports as well */
835 for (i = 0; i < unres->creating.count; ++i) {
836 mod = unres->creating.objs[i];
837 if (mod->implemented) {
838 continue;
839 }
840
Michal Vaskoc56d6372021-10-19 12:29:00 +0200841 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
842 r = lys_implement(mod, imp_f, unres);
Michal Vasko7213ac52021-06-15 11:52:13 +0200843 LY_CHECK_ERR_GOTO(r && (r != LY_ERECOMPILE), ret = r, cleanup);
Michal Vasko65333882021-06-10 14:12:16 +0200844 }
845 }
846
aPiecek6b3d5422021-07-30 15:55:43 +0200847 /* Try to find module with LYS_MOD_IMPORTED_REV flag. */
848 i = 0;
849 while ((mod_iter = ly_ctx_get_module_iter(mod->ctx, &i))) {
Michal Vaskoe8b085b2021-09-02 08:20:08 +0200850 if (!strcmp(mod_iter->name, mod->name) && (mod_iter != mod) && (mod_iter->latest_revision & LYS_MOD_IMPORTED_REV)) {
851 LOGVRB("Implemented module \"%s@%s\" was not and will not be imported if the revision-date is missing"
852 " in the import statement. Instead, the revision \"%s\" is imported.", mod->name, mod->revision,
853 mod_iter->revision);
aPiecek6b3d5422021-07-30 15:55:43 +0200854 break;
855 }
856 }
857
Michal Vasko65333882021-06-10 14:12:16 +0200858cleanup:
859 return ret;
860}
861
Michal Vaskof4258e12021-06-15 12:11:42 +0200862/**
Michal Vasko7ee5be22021-06-16 17:03:34 +0200863 * @brief Check whether it may be needed to (re)compile a module from a particular dependency set
864 * and if so, add it into its dep set.
865 *
866 * Dependency set includes all modules that need to be (re)compiled in case any of the module(s)
867 * in the dep set are (re)compiled.
868 *
869 * The reason for recompilation is possible disabled nodes and updating
870 * leafref targets to point to the newly compiled modules. Using the import relation, the
871 * dependency is reflexive because of possible foreign augments and deviations, which are compiled
872 * during the target module compilation.
873 *
874 * - every module must belong to exactly one dep set
875 * - implement flag must be ignored because it can be changed during dep set compilation
Michal Vaskof4258e12021-06-15 12:11:42 +0200876 *
877 * @param[in] mod Module to process.
878 * @param[in,out] ctx_set Set with all not-yet-processed modules.
879 * @param[in,out] dep_set Current dependency set to update.
Michal Vasko775fbd02021-07-28 08:25:29 +0200880 * @param[in] aux_set Set of traversed non-compiled modules, should be empty on first call.
Michal Vaskof4258e12021-06-15 12:11:42 +0200881 * @return LY_ERR value.
882 */
883static LY_ERR
Michal Vasko775fbd02021-07-28 08:25:29 +0200884lys_unres_dep_sets_create_mod_r(struct lys_module *mod, struct ly_set *ctx_set, struct ly_set *dep_set,
885 struct ly_set *aux_set)
Michal Vaskof4258e12021-06-15 12:11:42 +0200886{
887 struct lys_module *mod2;
888 struct lysp_import *imports;
889 uint32_t i;
890 LY_ARRAY_COUNT_TYPE u, v;
891 ly_bool found;
892
Michal Vasko0bccbf12021-11-22 09:59:57 +0100893 if (LYS_IS_SINGLE_DEP_SET(mod)) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200894 /* is already in a separate dep set */
Michal Vasko87cfdba2022-02-22 14:13:45 +0100895 if (!lys_has_dep_mods(mod)) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200896 /* break the dep set here, no modules depend on this one */
Michal Vasko7ee5be22021-06-16 17:03:34 +0200897 return LY_SUCCESS;
898 }
Michal Vasko775fbd02021-07-28 08:25:29 +0200899
900 if (ly_set_contains(aux_set, mod, NULL)) {
901 /* it was traversed */
902 return LY_SUCCESS;
903 }
904
905 /* add a new auxiliary module */
906 LY_CHECK_RET(ly_set_add(aux_set, mod, 1, NULL));
Michal Vasko7ee5be22021-06-16 17:03:34 +0200907 } else {
Michal Vasko709f9a52021-07-21 10:51:59 +0200908 if (!ly_set_contains(ctx_set, mod, &i)) {
909 /* it was already processed */
910 return LY_SUCCESS;
911 }
912
913 /* remove it from the set, we are processing it now */
914 ly_set_rm_index(ctx_set, i, NULL);
915
Michal Vasko7ee5be22021-06-16 17:03:34 +0200916 /* add a new dependent module into the dep set */
917 LY_CHECK_RET(ly_set_add(dep_set, mod, 1, NULL));
Michal Vaskof4258e12021-06-15 12:11:42 +0200918 }
919
920 /* process imports of the module and submodules */
921 imports = mod->parsed->imports;
922 LY_ARRAY_FOR(imports, u) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200923 mod2 = imports[u].module;
Michal Vasko775fbd02021-07-28 08:25:29 +0200924 LY_CHECK_RET(lys_unres_dep_sets_create_mod_r(mod2, ctx_set, dep_set, aux_set));
Michal Vaskof4258e12021-06-15 12:11:42 +0200925 }
926 LY_ARRAY_FOR(mod->parsed->includes, v) {
927 imports = mod->parsed->includes[v].submodule->imports;
928 LY_ARRAY_FOR(imports, u) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200929 mod2 = imports[u].module;
Michal Vasko87cfdba2022-02-22 14:13:45 +0100930 if (LYS_IS_SINGLE_DEP_SET(mod2) && !lys_has_dep_mods(mod2)) {
931 /* break the dep set here, no modules depend on this one */
932 continue;
Michal Vasko709f9a52021-07-21 10:51:59 +0200933 }
934
Michal Vasko775fbd02021-07-28 08:25:29 +0200935 LY_CHECK_RET(lys_unres_dep_sets_create_mod_r(imports[u].module, ctx_set, dep_set, aux_set));
Michal Vaskof4258e12021-06-15 12:11:42 +0200936 }
937 }
938
939 /* process modules and submodules importing this module */
Michal Vasko7ee5be22021-06-16 17:03:34 +0200940 for (i = 0; i < mod->ctx->list.count; ++i) {
941 mod2 = mod->ctx->list.objs[i];
Michal Vaskof4258e12021-06-15 12:11:42 +0200942 found = 0;
943
944 imports = mod2->parsed->imports;
945 LY_ARRAY_FOR(imports, u) {
946 if (imports[u].module == mod) {
947 found = 1;
948 break;
949 }
950 }
951
952 if (!found) {
953 LY_ARRAY_FOR(mod2->parsed->includes, v) {
954 imports = mod2->parsed->includes[v].submodule->imports;
955 LY_ARRAY_FOR(imports, u) {
956 if (imports[u].module == mod) {
957 found = 1;
958 break;
959 }
960 }
961
962 if (found) {
963 break;
964 }
965 }
966 }
967
968 if (found) {
Michal Vasko775fbd02021-07-28 08:25:29 +0200969 LY_CHECK_RET(lys_unres_dep_sets_create_mod_r(mod2, ctx_set, dep_set, aux_set));
Michal Vaskof4258e12021-06-15 12:11:42 +0200970 }
971 }
972
973 return LY_SUCCESS;
974}
975
Michal Vasko709f9a52021-07-21 10:51:59 +0200976/**
977 * @brief Add all simple modules (that have nothing to (re)compile) into separate dep sets.
978 *
979 * @param[in,out] ctx_set Set with all not-yet-processed modules.
980 * @param[in,out] main_set Set of dependency module sets.
981 * @return LY_ERR value.
982 */
983static LY_ERR
984lys_unres_dep_sets_create_single(struct ly_set *ctx_set, struct ly_set *main_set)
985{
986 LY_ERR ret = LY_SUCCESS;
987 struct lys_module *m;
988 uint32_t i = 0;
989 struct ly_set *dep_set = NULL;
990
991 while (i < ctx_set->count) {
992 m = ctx_set->objs[i];
Michal Vasko0bccbf12021-11-22 09:59:57 +0100993 if (LYS_IS_SINGLE_DEP_SET(m)) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200994 /* remove it from the set, we are processing it now */
995 ly_set_rm_index(ctx_set, i, NULL);
996
997 /* this module can be in a separate dep set (but there still may be modules importing this one
998 * that depend on imports of this one in case it defines groupings) */
999 LY_CHECK_GOTO(ret = ly_set_new(&dep_set), cleanup);
1000 LY_CHECK_GOTO(ret = ly_set_add(dep_set, m, 1, NULL), cleanup);
1001 LY_CHECK_GOTO(ret = ly_set_add(main_set, dep_set, 1, NULL), cleanup);
1002 dep_set = NULL;
1003 } else {
1004 ++i;
1005 }
1006 }
1007
1008cleanup:
1009 ly_set_free(dep_set, NULL);
1010 return ret;
1011}
1012
Michal Vaskof4258e12021-06-15 12:11:42 +02001013LY_ERR
Michal Vasko50bc09a2021-06-17 17:31:56 +02001014lys_unres_dep_sets_create(struct ly_ctx *ctx, struct ly_set *main_set, struct lys_module *mod)
Michal Vaskof4258e12021-06-15 12:11:42 +02001015{
1016 LY_ERR ret = LY_SUCCESS;
1017 struct lys_module *m;
Michal Vasko775fbd02021-07-28 08:25:29 +02001018 struct ly_set *dep_set = NULL, *ctx_set = NULL, aux_set = {0};
Michal Vaskof4258e12021-06-15 12:11:42 +02001019 uint32_t i;
Michal Vasko7ee5be22021-06-16 17:03:34 +02001020 ly_bool found;
Michal Vaskof4258e12021-06-15 12:11:42 +02001021
Michal Vasko22b26222021-07-30 11:16:47 +02001022 assert(!main_set->count);
1023
Michal Vaskof4258e12021-06-15 12:11:42 +02001024 /* start with a duplicate set of modules that we will remove from */
1025 LY_CHECK_GOTO(ret = ly_set_dup(&ctx->list, NULL, &ctx_set), cleanup);
1026
Michal Vasko709f9a52021-07-21 10:51:59 +02001027 /* first create all dep sets with single modules */
1028 LY_CHECK_GOTO(ret = lys_unres_dep_sets_create_single(ctx_set, main_set), cleanup);
1029
1030 if (mod && !ly_set_contains(ctx_set, mod, NULL)) {
1031 /* dep set for this module has already been created, nothing else to do */
1032 goto cleanup;
1033 }
1034
Michal Vaskof4258e12021-06-15 12:11:42 +02001035 while (ctx_set->count) {
1036 /* create new dep set */
1037 LY_CHECK_GOTO(ret = ly_set_new(&dep_set), cleanup);
1038
1039 if (mod) {
1040 /* use the module create a dep set with the rest of its dependent modules */
Michal Vasko775fbd02021-07-28 08:25:29 +02001041 LY_CHECK_GOTO(ret = lys_unres_dep_sets_create_mod_r(mod, ctx_set, dep_set, &aux_set), cleanup);
Michal Vaskof4258e12021-06-15 12:11:42 +02001042 } else {
1043 /* use first ctx mod to create a dep set with the rest of its dependent modules */
Michal Vasko775fbd02021-07-28 08:25:29 +02001044 LY_CHECK_GOTO(ret = lys_unres_dep_sets_create_mod_r(ctx_set->objs[0], ctx_set, dep_set, &aux_set), cleanup);
Michal Vaskof4258e12021-06-15 12:11:42 +02001045 }
Michal Vasko775fbd02021-07-28 08:25:29 +02001046 ly_set_erase(&aux_set, NULL);
Michal Vasko7ee5be22021-06-16 17:03:34 +02001047 assert(dep_set->count);
Michal Vaskof4258e12021-06-15 12:11:42 +02001048
1049 /* check whether there is any module that will be (re)compiled */
Michal Vasko7ee5be22021-06-16 17:03:34 +02001050 found = 0;
Michal Vaskof4258e12021-06-15 12:11:42 +02001051 for (i = 0; i < dep_set->count; ++i) {
1052 m = dep_set->objs[i];
1053 if (m->to_compile) {
Michal Vasko7ee5be22021-06-16 17:03:34 +02001054 found = 1;
Michal Vaskof4258e12021-06-15 12:11:42 +02001055 break;
1056 }
1057 }
1058
Michal Vasko7ee5be22021-06-16 17:03:34 +02001059 if (found) {
Michal Vaskof4258e12021-06-15 12:11:42 +02001060 /* if there is, all the implemented modules need to be recompiled */
1061 for (i = 0; i < dep_set->count; ++i) {
1062 m = dep_set->objs[i];
1063 if (m->implemented) {
1064 m->to_compile = 1;
1065 }
1066 }
1067 }
1068
Michal Vasko7ee5be22021-06-16 17:03:34 +02001069 /* add the dep set into main set */
1070 LY_CHECK_GOTO(ret = ly_set_add(main_set, dep_set, 1, NULL), cleanup);
Michal Vaskof4258e12021-06-15 12:11:42 +02001071 dep_set = NULL;
1072
1073 if (mod) {
1074 /* we need dep set only for this module */
1075 break;
1076 }
1077 }
1078
Michal Vaskoe558f792021-07-28 08:20:15 +02001079#ifndef NDEBUG
1080 LOGDBG(LY_LDGDEPSETS, "dep sets created (%" PRIu32 "):", main_set->count);
1081 for (i = 0; i < main_set->count; ++i) {
1082 struct ly_set *iter_set = main_set->objs[i];
1083
1084 LOGDBG(LY_LDGDEPSETS, "dep set #%" PRIu32 ":", i);
1085 for (uint32_t j = 0; j < iter_set->count; ++j) {
1086 m = iter_set->objs[j];
1087 LOGDBG(LY_LDGDEPSETS, "\t%s", m->name);
1088 }
1089 }
1090#endif
1091
Michal Vaskof4258e12021-06-15 12:11:42 +02001092cleanup:
Michal Vaskobd65c2e2021-06-16 11:49:45 +02001093 assert(ret || main_set->objs);
Michal Vasko775fbd02021-07-28 08:25:29 +02001094 ly_set_erase(&aux_set, NULL);
Michal Vaskof4258e12021-06-15 12:11:42 +02001095 ly_set_free(dep_set, NULL);
1096 ly_set_free(ctx_set, NULL);
1097 return ret;
1098}
1099
1100void
1101lys_unres_glob_revert(struct ly_ctx *ctx, struct lys_glob_unres *unres)
1102{
Michal Vasko59004e32024-01-30 16:09:54 +01001103 uint32_t i, j, idx, *prev_lo, temp_lo = 0;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001104 struct lysf_ctx fctx = {.ctx = ctx};
Michal Vaskof4258e12021-06-15 12:11:42 +02001105 struct ly_set *dep_set;
Michal Vaskof4258e12021-06-15 12:11:42 +02001106 LY_ERR ret;
1107
1108 for (i = 0; i < unres->implementing.count; ++i) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001109 fctx.mod = unres->implementing.objs[i];
1110 assert(fctx.mod->implemented);
Michal Vaskof4258e12021-06-15 12:11:42 +02001111
1112 /* make the module correctly non-implemented again */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001113 fctx.mod->implemented = 0;
1114 lys_precompile_augments_deviations_revert(ctx, fctx.mod);
1115 lysc_module_free(&fctx, fctx.mod->compiled);
1116 fctx.mod->compiled = NULL;
Michal Vaskof4258e12021-06-15 12:11:42 +02001117
1118 /* should not be made implemented */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001119 fctx.mod->to_compile = 0;
Michal Vaskof4258e12021-06-15 12:11:42 +02001120 }
1121
1122 for (i = 0; i < unres->creating.count; ++i) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001123 fctx.mod = unres->creating.objs[i];
Michal Vaskof4258e12021-06-15 12:11:42 +02001124
Michal Vaskod297f2a2021-06-16 11:51:28 +02001125 /* remove the module from the context */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001126 ly_set_rm(&ctx->list, fctx.mod, NULL);
Michal Vaskof4258e12021-06-15 12:11:42 +02001127
Michal Vasko22b26222021-07-30 11:16:47 +02001128 /* remove it also from dep sets */
Michal Vasko7ee5be22021-06-16 17:03:34 +02001129 for (j = 0; j < unres->dep_sets.count; ++j) {
1130 dep_set = unres->dep_sets.objs[j];
Michal Vaskoc636ea42022-09-16 10:20:31 +02001131 if (ly_set_contains(dep_set, fctx.mod, &idx)) {
Michal Vasko7ee5be22021-06-16 17:03:34 +02001132 ly_set_rm_index(dep_set, idx, NULL);
1133 break;
Michal Vaskof4258e12021-06-15 12:11:42 +02001134 }
Michal Vaskof4258e12021-06-15 12:11:42 +02001135 }
Michal Vaskod297f2a2021-06-16 11:51:28 +02001136
1137 /* free the module */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001138 lys_module_free(&fctx, fctx.mod, 1);
Michal Vaskof4258e12021-06-15 12:11:42 +02001139 }
1140
Michal Vaskoc636ea42022-09-16 10:20:31 +02001141 /* remove the extensions as well */
1142 lysf_ctx_erase(&fctx);
1143
Michal Vaskof4258e12021-06-15 12:11:42 +02001144 if (unres->implementing.count) {
1145 /* recompile previous context because some implemented modules are no longer implemented,
1146 * we can reuse the current to_compile flags */
Michal Vasko59004e32024-01-30 16:09:54 +01001147 prev_lo = ly_temp_log_options(&temp_lo);
Michal Vasko22b26222021-07-30 11:16:47 +02001148 ret = lys_compile_depset_all(ctx, &ctx->unres);
Michal Vasko59004e32024-01-30 16:09:54 +01001149 ly_temp_log_options(prev_lo);
Michal Vaskof4258e12021-06-15 12:11:42 +02001150 if (ret) {
1151 LOGINT(ctx);
1152 }
1153 }
1154}
1155
1156void
1157lys_unres_glob_erase(struct lys_glob_unres *unres)
1158{
1159 uint32_t i;
1160
1161 for (i = 0; i < unres->dep_sets.count; ++i) {
1162 ly_set_free(unres->dep_sets.objs[i], NULL);
1163 }
1164 ly_set_erase(&unres->dep_sets, NULL);
1165 ly_set_erase(&unres->implementing, NULL);
1166 ly_set_erase(&unres->creating, NULL);
1167
Michal Vaskoc130e162021-10-19 11:30:00 +02001168 assert(!unres->ds_unres.whens.count);
1169 assert(!unres->ds_unres.musts.count);
Michal Vaskof4258e12021-06-15 12:11:42 +02001170 assert(!unres->ds_unres.leafrefs.count);
aPiecekc6526b42021-07-12 15:21:39 +02001171 assert(!unres->ds_unres.disabled_leafrefs.count);
Michal Vaskof4258e12021-06-15 12:11:42 +02001172 assert(!unres->ds_unres.dflts.count);
1173 assert(!unres->ds_unres.disabled.count);
1174}
1175
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001176LIBYANG_API_DEF LY_ERR
Michal Vasko65333882021-06-10 14:12:16 +02001177lys_set_implemented(struct lys_module *mod, const char **features)
1178{
1179 LY_ERR ret = LY_SUCCESS;
Michal Vasko22b26222021-07-30 11:16:47 +02001180 struct lys_glob_unres *unres = &mod->ctx->unres;
Michal Vasko65333882021-06-10 14:12:16 +02001181
1182 LY_CHECK_ARG_RET(NULL, mod, LY_EINVAL);
1183
1184 /* implement */
Michal Vasko22b26222021-07-30 11:16:47 +02001185 ret = _lys_set_implemented(mod, features, unres);
Michal Vasko65333882021-06-10 14:12:16 +02001186 LY_CHECK_GOTO(ret, cleanup);
1187
Michal Vaskof4258e12021-06-15 12:11:42 +02001188 if (!(mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE)) {
1189 /* create dep set for the module and mark all the modules that will be (re)compiled */
Michal Vasko22b26222021-07-30 11:16:47 +02001190 LY_CHECK_GOTO(ret = lys_unres_dep_sets_create(mod->ctx, &unres->dep_sets, mod), cleanup);
Michal Vaskof4258e12021-06-15 12:11:42 +02001191
Michal Vasko709f9a52021-07-21 10:51:59 +02001192 /* (re)compile the whole dep set (other dep sets will have no modules marked for compilation) */
Michal Vasko22b26222021-07-30 11:16:47 +02001193 LY_CHECK_GOTO(ret = lys_compile_depset_all(mod->ctx, unres), cleanup);
1194
1195 /* unres resolved */
1196 lys_unres_glob_erase(unres);
Michal Vaskof4258e12021-06-15 12:11:42 +02001197 }
1198
Michal Vasko65333882021-06-10 14:12:16 +02001199cleanup:
Michal Vasko405cc9e2020-12-01 12:01:27 +01001200 if (ret) {
Michal Vasko22b26222021-07-30 11:16:47 +02001201 lys_unres_glob_revert(mod->ctx, unres);
1202 lys_unres_glob_erase(unres);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001203 }
Michal Vasko89b5c072020-10-06 13:52:44 +02001204 return ret;
Radek Krejci77a8bcd2019-09-11 11:20:02 +02001205}
1206
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001207/**
1208 * @brief Resolve (find) all imported and included modules.
1209 *
1210 * @param[in] pctx Parser context.
1211 * @param[in] pmod Parsed module to resolve.
1212 * @param[out] new_mods Set with all the newly loaded modules.
1213 * @return LY_ERR value.
1214 */
Michal Vasko7c8439f2020-08-05 13:25:19 +02001215static LY_ERR
Michal Vaskod0625d72022-10-06 15:02:50 +02001216lysp_resolve_import_include(struct lysp_ctx *pctx, struct lysp_module *pmod, struct ly_set *new_mods)
Michal Vasko7c8439f2020-08-05 13:25:19 +02001217{
1218 struct lysp_import *imp;
Michal Vasko7c8439f2020-08-05 13:25:19 +02001219 LY_ARRAY_COUNT_TYPE u, v;
1220
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001221 pmod->parsing = 1;
1222 LY_ARRAY_FOR(pmod->imports, u) {
1223 imp = &pmod->imports[u];
Michal Vasko7c8439f2020-08-05 13:25:19 +02001224 if (!imp->module) {
aPiecekc3e26142021-06-22 14:25:49 +02001225 LY_CHECK_RET(lys_parse_load(PARSER_CTX(pctx), imp->name, imp->rev[0] ? imp->rev : NULL, new_mods, &imp->module));
aPiecekd4911ee2021-07-30 07:40:24 +02001226
1227 if (!imp->rev[0]) {
1228 /* This module must be selected for the next similar
1229 * import without revision-date to avoid incorrect
1230 * derived identities in the ::lys_module.identities.
1231 */
1232 imp->module->latest_revision |= LYS_MOD_IMPORTED_REV;
1233 }
Michal Vasko7c8439f2020-08-05 13:25:19 +02001234 }
1235 /* check for importing the same module twice */
1236 for (v = 0; v < u; ++v) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001237 if (imp->module == pmod->imports[v].module) {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001238 LOGWRN(PARSER_CTX(pctx), "Single revision of the module \"%s\" imported twice.", imp->name);
1239 }
1240 }
1241 }
aPiecekc3e26142021-06-22 14:25:49 +02001242 LY_CHECK_RET(lysp_load_submodules(pctx, pmod, new_mods));
Radek Krejci771928a2021-01-19 13:42:36 +01001243
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001244 pmod->parsing = 0;
Michal Vasko7c8439f2020-08-05 13:25:19 +02001245
1246 return LY_SUCCESS;
1247}
1248
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001249/**
Michal Vasko193dacd2022-10-13 08:43:05 +02001250 * @brief Generate path of the given paresed node.
1251 *
1252 * @param[in] node Schema path of this node will be generated.
1253 * @param[in] parent Build relative path only until this parent is found. If NULL, the full absolute path is printed.
1254 * @return NULL in case of memory allocation error, path of the node otherwise.
1255 * In case the @p buffer is NULL, the returned string is dynamically allocated and caller is responsible to free it.
1256 */
1257static char *
1258lysp_path_until(const struct lysp_node *node, const struct lysp_node *parent, const struct lysp_module *pmod)
1259{
1260 const struct lysp_node *iter, *par;
1261 char *path = NULL, *s;
1262 const char *slash;
1263 int len = 0;
1264
1265 for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
1266 if (parent && (iter->parent == parent)) {
1267 slash = "";
1268 } else {
1269 slash = "/";
1270 }
1271
1272 s = path;
1273 par = iter->parent;
1274 if (!par) {
1275 /* print prefix */
1276 len = asprintf(&path, "%s%s:%s%s", slash, pmod->mod->name, iter->name, s ? s : "");
1277 } else {
1278 /* prefix is the same as in parent */
1279 len = asprintf(&path, "%s%s%s", slash, iter->name, s ? s : "");
1280 }
1281 free(s);
1282 }
1283
1284 if (len < 0) {
1285 free(path);
1286 path = NULL;
1287 } else if (len == 0) {
1288 path = strdup("/");
1289 }
1290
1291 return path;
1292}
1293
1294/**
1295 * @brief Build log path for a parsed extension instance.
1296 *
1297 * @param[in] pcxt Parse context.
1298 * @param[in] ext Parsed extension instance.
1299 * @param[out] path Generated path.
1300 * @return LY_ERR value.
1301 */
1302static LY_ERR
1303lysp_resolve_ext_instance_log_path(const struct lysp_ctx *pctx, const struct lysp_ext_instance *ext, char **path)
1304{
1305 char *buf = NULL;
1306 uint32_t used = 0, size = 0;
1307
1308 if (ext->parent_stmt & LY_STMT_NODE_MASK) {
1309 /* parsed node path */
1310 buf = lysp_path_until(ext->parent, NULL, PARSER_CUR_PMOD(pctx));
1311 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1312 size = used = strlen(buf);
1313
1314 /* slash */
1315 size += 1;
1316 buf = realloc(buf, size + 1);
1317 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1318 used += sprintf(buf + used, "/");
1319 } else {
1320 /* module */
1321 size += 1 + strlen(PARSER_CUR_PMOD(pctx)->mod->name) + 1;
1322 buf = realloc(buf, size + 1);
1323 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1324 used += sprintf(buf + used, "/%s:", PARSER_CUR_PMOD(pctx)->mod->name);
1325 }
1326
1327 /* extension name */
1328 size += 12 + strlen(ext->name) + 2;
1329 buf = realloc(buf, size + 1);
1330 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1331 used += sprintf(buf + used, "{extension='%s'}", ext->name);
1332
1333 /* extension argument */
1334 if (ext->argument) {
1335 size += 1 + strlen(ext->argument);
1336 buf = realloc(buf, size + 1);
1337 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1338 used += sprintf(buf + used, "/%s", ext->argument);
1339 }
1340
1341 *path = buf;
1342 return LY_SUCCESS;
1343}
1344
1345/**
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001346 * @brief Resolve (find) all extension instance records and finish their parsing.
1347 *
1348 * @param[in] pctx Parse context with all the parsed extension instances.
1349 * @return LY_ERR value.
1350 */
1351static LY_ERR
Michal Vaskod0625d72022-10-06 15:02:50 +02001352lysp_resolve_ext_instance_records(struct lysp_ctx *pctx)
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001353{
Michal Vasko193dacd2022-10-13 08:43:05 +02001354 LY_ERR r;
1355 struct lysf_ctx fctx = {.ctx = PARSER_CTX(pctx)};
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001356 struct lysp_ext_instance *exts, *ext;
1357 const struct lys_module *mod;
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001358 uint32_t i;
1359 LY_ARRAY_COUNT_TYPE u;
Michal Vasko193dacd2022-10-13 08:43:05 +02001360 char *path = NULL;
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001361
Michal Vasko193dacd2022-10-13 08:43:05 +02001362 /* first finish parsing all extension instances ... */
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001363 for (i = 0; i < pctx->ext_inst.count; ++i) {
1364 exts = pctx->ext_inst.objs[i];
1365 LY_ARRAY_FOR(exts, u) {
1366 ext = &exts[u];
1367
Michal Vasko193dacd2022-10-13 08:43:05 +02001368 /* find the extension definition */
1369 LY_CHECK_RET(lysp_ext_find_definition(PARSER_CTX(pctx), ext, &mod, &ext->def));
1370
1371 /* resolve the argument, if needed */
1372 LY_CHECK_RET(lysp_ext_instance_resolve_argument(PARSER_CTX(pctx), ext));
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001373
1374 /* find the extension record, if any */
stewegf7aeeae2024-04-02 13:15:52 +02001375 ext->record = lyplg_ext_record_find(mod->ctx, mod->name, mod->revision, ext->def->name);
Michal Vasko193dacd2022-10-13 08:43:05 +02001376 }
1377 }
1378
1379 /* ... then call the parse callback */
1380 for (i = 0; i < pctx->ext_inst.count; ++i) {
1381 exts = pctx->ext_inst.objs[i];
1382 u = 0;
1383 while (u < LY_ARRAY_COUNT(exts)) {
1384 ext = &exts[u];
1385 if (!ext->record || !ext->record->plugin.parse) {
1386 goto next_iter;
1387 }
1388
1389 /* set up log path */
1390 if ((r = lysp_resolve_ext_instance_log_path(pctx, ext, &path))) {
1391 return r;
1392 }
Michal Vasko7a266772024-01-23 11:02:38 +01001393 ly_log_location(NULL, NULL, path, NULL);
Michal Vasko193dacd2022-10-13 08:43:05 +02001394
1395 /* parse */
1396 r = ext->record->plugin.parse(pctx, ext);
1397
Michal Vasko7a266772024-01-23 11:02:38 +01001398 ly_log_location_revert(0, 0, 1, 0);
Michal Vasko193dacd2022-10-13 08:43:05 +02001399 free(path);
1400
1401 if (r == LY_ENOT) {
1402 /* instance should be ignored, remove it */
1403 lysp_ext_instance_free(&fctx, ext);
1404 LY_ARRAY_DECREMENT(exts);
1405 if (u < LY_ARRAY_COUNT(exts)) {
1406 /* replace by the last item */
1407 *ext = exts[LY_ARRAY_COUNT(exts)];
1408 } /* else if there are no more items, leave the empty array, we are not able to free it */
1409 continue;
1410 } else if (r) {
1411 /* error */
1412 return r;
1413 }
1414
1415next_iter:
1416 ++u;
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001417 }
1418 }
1419
1420 return LY_SUCCESS;
1421}
1422
Michal Vasko3a41dff2020-07-15 14:30:28 +02001423LY_ERR
Michal Vaskod0625d72022-10-06 15:02:50 +02001424lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, struct lysp_ctx *main_ctx,
Michal Vasko22df3f02020-08-24 13:29:22 +02001425 LY_ERR (*custom_check)(const struct ly_ctx *, struct lysp_module *, struct lysp_submodule *, void *),
aPiecekc3e26142021-06-22 14:25:49 +02001426 void *check_data, struct ly_set *new_mods, struct lysp_submodule **submodule)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001427{
Michal Vasko3a41dff2020-07-15 14:30:28 +02001428 LY_ERR ret;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001429 struct lysp_submodule *submod = NULL, *latest_sp;
Michal Vaskod0625d72022-10-06 15:02:50 +02001430 struct lysp_yang_ctx *yangctx = NULL;
1431 struct lysp_yin_ctx *yinctx = NULL;
1432 struct lysp_ctx *pctx;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001433 struct lysf_ctx fctx = {.ctx = ctx};
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001434
Michal Vasko3a41dff2020-07-15 14:30:28 +02001435 LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001436
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001437 switch (format) {
1438 case LYS_IN_YIN:
Michal Vasko63f3d842020-07-08 10:10:14 +02001439 ret = yin_parse_submodule(&yinctx, ctx, main_ctx, in, &submod);
Michal Vaskod0625d72022-10-06 15:02:50 +02001440 pctx = (struct lysp_ctx *)yinctx;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001441 break;
1442 case LYS_IN_YANG:
Michal Vasko63f3d842020-07-08 10:10:14 +02001443 ret = yang_parse_submodule(&yangctx, ctx, main_ctx, in, &submod);
Michal Vaskod0625d72022-10-06 15:02:50 +02001444 pctx = (struct lysp_ctx *)yangctx;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001445 break;
1446 default:
David Sedlák4f2f5ba2019-08-15 13:18:48 +02001447 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
Radek Krejci82fa8d42020-07-11 22:00:59 +02001448 ret = LY_EINVAL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001449 break;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001450 }
Radek Krejcif6923e82020-07-02 16:36:53 +02001451 LY_CHECK_GOTO(ret, error);
Radek Krejcif027df72020-09-15 13:00:28 +02001452 assert(submod);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001453
1454 /* make sure that the newest revision is at position 0 */
1455 lysp_sort_revisions(submod->revs);
1456
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001457 /* decide the latest revision */
Michal Vasko8dc31992021-02-22 10:30:47 +01001458 latest_sp = (struct lysp_submodule *)ly_ctx_get_submodule2_latest(submod->mod, submod->name);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001459 if (latest_sp) {
1460 if (submod->revs) {
1461 if (!latest_sp->revs) {
1462 /* latest has no revision, so mod is anyway newer */
1463 submod->latest_revision = latest_sp->latest_revision;
Radek Krejcib3289d62019-09-18 12:21:39 +02001464 /* the latest_sp is zeroed later when the new module is being inserted into the context */
1465 } else if (strcmp(submod->revs[0].date, latest_sp->revs[0].date) > 0) {
1466 submod->latest_revision = latest_sp->latest_revision;
1467 /* the latest_sp is zeroed later when the new module is being inserted into the context */
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001468 } else {
Radek Krejcib3289d62019-09-18 12:21:39 +02001469 latest_sp = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001470 }
Radek Krejcib3289d62019-09-18 12:21:39 +02001471 } else {
1472 latest_sp = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001473 }
1474 } else {
1475 submod->latest_revision = 1;
1476 }
1477
Radek Krejcib3289d62019-09-18 12:21:39 +02001478 if (custom_check) {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001479 LY_CHECK_GOTO(ret = custom_check(ctx, NULL, submod, check_data), error);
Radek Krejcib3289d62019-09-18 12:21:39 +02001480 }
1481
1482 if (latest_sp) {
1483 latest_sp->latest_revision = 0;
1484 }
1485
Michal Vasko7a0b0762020-09-02 16:37:01 +02001486 lys_parser_fill_filepath(ctx, in, &submod->filepath);
1487
Michal Vasko7c8439f2020-08-05 13:25:19 +02001488 /* resolve imports and includes */
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001489 LY_CHECK_GOTO(ret = lysp_resolve_import_include(pctx, (struct lysp_module *)submod, new_mods), error);
1490
David Sedlák1b623122019-08-05 15:27:49 +02001491 if (format == LYS_IN_YANG) {
Michal Vaskod0625d72022-10-06 15:02:50 +02001492 lysp_yang_ctx_free(yangctx);
David Sedlák1b623122019-08-05 15:27:49 +02001493 } else {
Michal Vaskod0625d72022-10-06 15:02:50 +02001494 lysp_yin_ctx_free(yinctx);
David Sedlák1b623122019-08-05 15:27:49 +02001495 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02001496 *submodule = submod;
1497 return LY_SUCCESS;
David Sedlák1b623122019-08-05 15:27:49 +02001498
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001499error:
Radek Krejcic64661b2020-08-15 15:42:26 +02001500 if (!submod || !submod->name) {
1501 LOGERR(ctx, ret, "Parsing submodule failed.");
1502 } else {
1503 LOGERR(ctx, ret, "Parsing submodule \"%s\" failed.", submod->name);
1504 }
Michal Vaskoc636ea42022-09-16 10:20:31 +02001505 lysp_module_free(&fctx, (struct lysp_module *)submod);
David Sedlák1b623122019-08-05 15:27:49 +02001506 if (format == LYS_IN_YANG) {
Michal Vaskod0625d72022-10-06 15:02:50 +02001507 lysp_yang_ctx_free(yangctx);
David Sedlák1b623122019-08-05 15:27:49 +02001508 } else {
Michal Vaskod0625d72022-10-06 15:02:50 +02001509 lysp_yin_ctx_free(yinctx);
David Sedlák1b623122019-08-05 15:27:49 +02001510 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02001511 return ret;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001512}
1513
Michal Vasko45b521c2020-11-04 17:14:39 +01001514/**
1515 * @brief Add ietf-netconf metadata to the parsed module. Operation, filter, and select are added.
1516 *
Michal Vasko193dacd2022-10-13 08:43:05 +02001517 * @param[in] pctx Parse context.
Michal Vasko45b521c2020-11-04 17:14:39 +01001518 * @param[in] mod Parsed module to add to.
1519 * @return LY_SUCCESS on success.
1520 * @return LY_ERR on error.
1521 */
1522static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +02001523lysp_add_internal_ietf_netconf(struct lysp_ctx *pctx, struct lysp_module *mod)
Michal Vasko45b521c2020-11-04 17:14:39 +01001524{
Michal Vasko125b07c2023-04-28 09:07:14 +02001525 struct lysp_ext_instance *extp, *prev_exts = mod->exts;
Michal Vasko45b521c2020-11-04 17:14:39 +01001526 struct lysp_stmt *stmt;
1527 struct lysp_import *imp;
Michal Vasko125b07c2023-04-28 09:07:14 +02001528 uint32_t idx;
Michal Vasko45b521c2020-11-04 17:14:39 +01001529
1530 /*
1531 * 1) edit-config's operation
1532 */
Michal Vasko193dacd2022-10-13 08:43:05 +02001533 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
1534 LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
1535 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
1536 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "operation", 0, &extp->argument));
1537 extp->format = LY_VALUE_SCHEMA;
1538 extp->prefix_data = mod;
1539 extp->parent = mod;
1540 extp->parent_stmt = LY_STMT_MODULE;
1541 extp->flags = LYS_INTERNAL;
Michal Vasko45b521c2020-11-04 17:14:39 +01001542
Michal Vasko193dacd2022-10-13 08:43:05 +02001543 extp->child = stmt = calloc(1, sizeof *extp->child);
Michal Vasko45b521c2020-11-04 17:14:39 +01001544 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1545 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1546 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001547 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001548 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001549 stmt->kw = LY_STMT_TYPE;
1550
1551 stmt->child = calloc(1, sizeof *stmt->child);
1552 stmt = stmt->child;
1553 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1554 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1555 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "merge", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001556 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001557 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001558 stmt->kw = LY_STMT_ENUM;
1559
1560 stmt->next = calloc(1, sizeof *stmt->child);
1561 stmt = stmt->next;
1562 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1563 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1564 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "replace", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001565 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001566 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001567 stmt->kw = LY_STMT_ENUM;
1568
1569 stmt->next = calloc(1, sizeof *stmt->child);
1570 stmt = stmt->next;
1571 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1572 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1573 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "create", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001574 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001575 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001576 stmt->kw = LY_STMT_ENUM;
1577
1578 stmt->next = calloc(1, sizeof *stmt->child);
1579 stmt = stmt->next;
1580 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1581 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1582 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "delete", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001583 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001584 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001585 stmt->kw = LY_STMT_ENUM;
1586
1587 stmt->next = calloc(1, sizeof *stmt->child);
1588 stmt = stmt->next;
1589 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1590 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1591 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "remove", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001592 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001593 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001594 stmt->kw = LY_STMT_ENUM;
1595
1596 /*
1597 * 2) filter's type
1598 */
Michal Vasko193dacd2022-10-13 08:43:05 +02001599 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
1600 LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
1601 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
1602 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &extp->argument));
1603 extp->format = LY_VALUE_SCHEMA;
1604 extp->prefix_data = mod;
1605 extp->parent = mod;
1606 extp->parent_stmt = LY_STMT_MODULE;
1607 extp->flags = LYS_INTERNAL;
Michal Vasko45b521c2020-11-04 17:14:39 +01001608
Michal Vasko193dacd2022-10-13 08:43:05 +02001609 extp->child = stmt = calloc(1, sizeof *extp->child);
Michal Vasko45b521c2020-11-04 17:14:39 +01001610 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1611 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1612 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001613 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001614 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001615 stmt->kw = LY_STMT_TYPE;
1616
1617 stmt->child = calloc(1, sizeof *stmt->child);
1618 stmt = stmt->child;
1619 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1620 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1621 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "subtree", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001622 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001623 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001624 stmt->kw = LY_STMT_ENUM;
1625
1626 stmt->next = calloc(1, sizeof *stmt->child);
1627 stmt = stmt->next;
1628 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1629 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1630 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001631 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001632 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001633 stmt->kw = LY_STMT_ENUM;
1634
1635 /* if-feature for enum allowed only for YANG 1.1 modules */
1636 if (mod->version >= LYS_VERSION_1_1) {
1637 stmt->child = calloc(1, sizeof *stmt->child);
1638 stmt = stmt->child;
1639 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1640 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "if-feature", 0, &stmt->stmt));
1641 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001642 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001643 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001644 stmt->kw = LY_STMT_IF_FEATURE;
1645 }
1646
1647 /*
1648 * 3) filter's select
1649 */
Michal Vasko193dacd2022-10-13 08:43:05 +02001650 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
1651 LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
1652 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
1653 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "select", 0, &extp->argument));
1654 extp->format = LY_VALUE_SCHEMA;
1655 extp->prefix_data = mod;
1656 extp->parent = mod;
1657 extp->parent_stmt = LY_STMT_MODULE;
1658 extp->flags = LYS_INTERNAL;
Michal Vasko45b521c2020-11-04 17:14:39 +01001659
Michal Vasko193dacd2022-10-13 08:43:05 +02001660 extp->child = stmt = calloc(1, sizeof *extp->child);
Michal Vasko45b521c2020-11-04 17:14:39 +01001661 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1662 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1663 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_:xpath1.0", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001664 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001665 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001666 stmt->kw = LY_STMT_TYPE;
1667
Michal Vasko125b07c2023-04-28 09:07:14 +02001668 if (!prev_exts) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001669 /* first extension instances */
Michal Vaskoc8806c82022-12-06 10:31:24 +01001670 assert(pctx->main_ctx == pctx);
Michal Vasko193dacd2022-10-13 08:43:05 +02001671 LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
Michal Vasko125b07c2023-04-28 09:07:14 +02001672 } else {
1673 /* replace previously stored extension instances */
1674 if (!ly_set_contains(&pctx->ext_inst, prev_exts, &idx)) {
1675 LOGINT_RET(mod->mod->ctx);
1676 }
1677 pctx->ext_inst.objs[idx] = mod->exts;
Michal Vasko193dacd2022-10-13 08:43:05 +02001678 }
1679
Michal Vasko45b521c2020-11-04 17:14:39 +01001680 /* create new imports for the used prefixes */
1681 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
Michal Vasko45b521c2020-11-04 17:14:39 +01001682 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
1683 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
1684 imp->flags = LYS_INTERNAL;
1685
1686 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
Michal Vasko45b521c2020-11-04 17:14:39 +01001687 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-types", 0, &imp->name));
1688 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_", 0, &imp->prefix));
1689 imp->flags = LYS_INTERNAL;
1690
1691 return LY_SUCCESS;
1692}
1693
1694/**
1695 * @brief Add ietf-netconf-with-defaults "default" metadata to the parsed module.
1696 *
Michal Vasko193dacd2022-10-13 08:43:05 +02001697 * @param[in] pctx Parse context.
Michal Vasko45b521c2020-11-04 17:14:39 +01001698 * @param[in] mod Parsed module to add to.
1699 * @return LY_SUCCESS on success.
1700 * @return LY_ERR on error.
1701 */
1702static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +02001703lysp_add_internal_ietf_netconf_with_defaults(struct lysp_ctx *pctx, struct lysp_module *mod)
Michal Vasko45b521c2020-11-04 17:14:39 +01001704{
Michal Vasko125b07c2023-04-28 09:07:14 +02001705 struct lysp_ext_instance *extp, *prev_exts = mod->exts;
Michal Vasko45b521c2020-11-04 17:14:39 +01001706 struct lysp_stmt *stmt;
1707 struct lysp_import *imp;
Michal Vasko125b07c2023-04-28 09:07:14 +02001708 uint32_t idx;
Michal Vasko45b521c2020-11-04 17:14:39 +01001709
1710 /* add new extension instance */
Michal Vasko193dacd2022-10-13 08:43:05 +02001711 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
Michal Vasko45b521c2020-11-04 17:14:39 +01001712
1713 /* fill in the extension instance fields */
Michal Vasko193dacd2022-10-13 08:43:05 +02001714 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
1715 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "default", 0, &extp->argument));
1716 extp->format = LY_VALUE_SCHEMA;
1717 extp->prefix_data = mod;
1718 extp->parent = mod;
1719 extp->parent_stmt = LY_STMT_MODULE;
1720 extp->flags = LYS_INTERNAL;
Michal Vasko45b521c2020-11-04 17:14:39 +01001721
Michal Vasko193dacd2022-10-13 08:43:05 +02001722 extp->child = stmt = calloc(1, sizeof *extp->child);
Michal Vasko45b521c2020-11-04 17:14:39 +01001723 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1724 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1725 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "boolean", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001726 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001727 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001728 stmt->kw = LY_STMT_TYPE;
1729
Michal Vasko125b07c2023-04-28 09:07:14 +02001730 if (!prev_exts) {
1731 /* first extension instances */
Michal Vaskoc8806c82022-12-06 10:31:24 +01001732 assert(pctx->main_ctx == pctx);
Michal Vasko193dacd2022-10-13 08:43:05 +02001733 LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
Michal Vasko125b07c2023-04-28 09:07:14 +02001734 } else {
1735 /* replace previously stored extension instances */
1736 if (!ly_set_contains(&pctx->ext_inst, prev_exts, &idx)) {
1737 LOGINT_RET(mod->mod->ctx);
1738 }
1739 pctx->ext_inst.objs[idx] = mod->exts;
Michal Vasko193dacd2022-10-13 08:43:05 +02001740 }
1741
Michal Vasko45b521c2020-11-04 17:14:39 +01001742 /* create new import for the used prefix */
1743 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
Michal Vasko45b521c2020-11-04 17:14:39 +01001744 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
1745 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
1746 imp->flags = LYS_INTERNAL;
1747
1748 return LY_SUCCESS;
1749}
1750
aPiecek6cf1d162023-11-08 16:07:00 +01001751/**
1752 * @brief Define a new internal 'lyds_tree' value for metadata.
1753 *
1754 * The 'lyds_tree' is a data type containing a reference to a binary search tree
1755 * by which the data nodes are ordered.
1756 *
1757 * @param[in] pctx Parse context.
1758 * @param[in] mod Parsed module to add to.
1759 * @return LY_SUCCESS on success.
1760 * @return LY_ERR on error.
1761 */
1762static LY_ERR
1763lysp_add_internal_yang(struct lysp_ctx *pctx, struct lysp_module *mod)
1764{
1765 struct lysp_ext_instance *extp, *prev_exts = mod->exts;
1766 struct lysp_stmt *stmt;
1767 struct lysp_tpdf *tpdf;
1768 uint32_t idx;
1769
1770 /* add new typedef */
1771 LY_ARRAY_NEW_RET(PARSER_CTX(pctx), mod->typedefs, tpdf, LY_EMEM);
1772 LY_CHECK_RET(lydict_insert(PARSER_CTX(pctx), "lyds_tree", 0, &tpdf->name));
1773 LY_CHECK_RET(lydict_insert(PARSER_CTX(pctx), "uint64", 0, &tpdf->type.name));
1774 tpdf->type.pmod = mod;
1775
1776 /* add new extension instance */
1777 LY_ARRAY_NEW_RET(PARSER_CTX(pctx), mod->exts, extp, LY_EMEM);
1778
1779 /* fill in the extension instance fields */
1780 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md:annotation", 0, &extp->name));
1781 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "lyds_tree", 0, &extp->argument));
1782 extp->format = LY_VALUE_SCHEMA;
1783 extp->prefix_data = mod;
1784 extp->parent = mod;
1785 extp->parent_stmt = LY_STMT_MODULE;
1786 extp->flags = LYS_INTERNAL;
1787
1788 /* prepare for metadata plugin */
1789 extp->child = stmt = calloc(1, sizeof *extp->child);
1790 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1791 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1792 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "lyds_tree", 0, &stmt->arg));
1793 stmt->format = LY_VALUE_SCHEMA;
1794 stmt->prefix_data = mod;
1795 stmt->kw = LY_STMT_TYPE;
1796
1797 if (!prev_exts) {
1798 /* first extension instances */
1799 assert(pctx->main_ctx == pctx);
1800 LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
1801 } else {
1802 /* replace previously stored extension instances */
1803 if (!ly_set_contains(&pctx->ext_inst, prev_exts, &idx)) {
1804 LOGINT_RET(mod->mod->ctx);
1805 }
1806 pctx->ext_inst.objs[idx] = mod->exts;
1807 }
1808
1809 return LY_SUCCESS;
1810}
1811
Michal Vasko3a41dff2020-07-15 14:30:28 +02001812LY_ERR
Michal Vasko4e205e82021-06-08 14:01:47 +02001813lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
Radek Krejci1deb5be2020-08-26 16:43:36 +02001814 LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
Michal Vaskodd992582021-06-10 14:34:57 +02001815 void *check_data, struct ly_set *new_mods, struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02001816{
Michal Vaskoa9309bb2021-07-09 09:31:55 +02001817 struct lys_module *mod = NULL, *latest, *mod_dup = NULL;
Michal Vasko3a41dff2020-07-15 14:30:28 +02001818 LY_ERR ret;
Michal Vaskod0625d72022-10-06 15:02:50 +02001819 struct lysp_yang_ctx *yangctx = NULL;
1820 struct lysp_yin_ctx *yinctx = NULL;
1821 struct lysp_ctx *pctx = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001822 struct lysf_ctx fctx = {.ctx = ctx};
Radek Krejcic64661b2020-08-15 15:42:26 +02001823 ly_bool module_created = 0;
Radek Krejci86d106e2018-10-18 09:53:19 +02001824
Michal Vaskodd992582021-06-10 14:34:57 +02001825 assert(ctx && in && new_mods);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001826
Michal Vasko7a0b0762020-09-02 16:37:01 +02001827 if (module) {
1828 *module = NULL;
1829 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001830
1831 mod = calloc(1, sizeof *mod);
Michal Vasko3a41dff2020-07-15 14:30:28 +02001832 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), LY_EMEM);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001833 mod->ctx = ctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001834
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001835 /* parse */
Radek Krejci86d106e2018-10-18 09:53:19 +02001836 switch (format) {
1837 case LYS_IN_YIN:
aPiecekc3e26142021-06-22 14:25:49 +02001838 ret = yin_parse_module(&yinctx, in, mod);
Michal Vaskod0625d72022-10-06 15:02:50 +02001839 pctx = (struct lysp_ctx *)yinctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001840 break;
1841 case LYS_IN_YANG:
aPiecekc3e26142021-06-22 14:25:49 +02001842 ret = yang_parse_module(&yangctx, in, mod);
Michal Vaskod0625d72022-10-06 15:02:50 +02001843 pctx = (struct lysp_ctx *)yangctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001844 break;
1845 default:
1846 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
Michal Vasko3a41dff2020-07-15 14:30:28 +02001847 ret = LY_EINVAL;
Radek Krejci86d106e2018-10-18 09:53:19 +02001848 break;
1849 }
Radek Krejcic64661b2020-08-15 15:42:26 +02001850 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001851
1852 /* make sure that the newest revision is at position 0 */
1853 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci0af46292019-01-11 16:02:31 +01001854 if (mod->parsed->revs) {
Radek Krejcic64661b2020-08-15 15:42:26 +02001855 LY_CHECK_GOTO(ret = lydict_insert(ctx, mod->parsed->revs[0].date, 0, &mod->revision), cleanup);
Radek Krejci0af46292019-01-11 16:02:31 +01001856 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001857
Radek Krejcib3289d62019-09-18 12:21:39 +02001858 /* decide the latest revision */
Michal Vaskoa51ef072021-07-02 10:40:30 +02001859 latest = ly_ctx_get_module_latest(ctx, mod->name);
Radek Krejcib3289d62019-09-18 12:21:39 +02001860 if (latest) {
1861 if (mod->revision) {
1862 if (!latest->revision) {
1863 /* latest has no revision, so mod is anyway newer */
aPiecek8ca21bd2021-07-26 14:31:01 +02001864 mod->latest_revision = latest->latest_revision & (LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
Radek Krejcib3289d62019-09-18 12:21:39 +02001865 /* the latest is zeroed later when the new module is being inserted into the context */
1866 } else if (strcmp(mod->revision, latest->revision) > 0) {
aPiecek8ca21bd2021-07-26 14:31:01 +02001867 mod->latest_revision = latest->latest_revision & (LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
Radek Krejcib3289d62019-09-18 12:21:39 +02001868 /* the latest is zeroed later when the new module is being inserted into the context */
1869 } else {
1870 latest = NULL;
1871 }
1872 } else {
1873 latest = NULL;
1874 }
1875 } else {
aPiecek8ca21bd2021-07-26 14:31:01 +02001876 mod->latest_revision = LYS_MOD_LATEST_REV;
Radek Krejcib3289d62019-09-18 12:21:39 +02001877 }
1878
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001879 if (custom_check) {
Radek Krejcic64661b2020-08-15 15:42:26 +02001880 LY_CHECK_GOTO(ret = custom_check(ctx, mod->parsed, NULL, check_data), cleanup);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001881 }
1882
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001883 /* check whether it is not already in the context in the same revision */
Michal Vaskoa51ef072021-07-02 10:40:30 +02001884 mod_dup = ly_ctx_get_module(ctx, mod->name, mod->revision);
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001885 if (mod_dup) {
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001886 /* nothing to do */
1887 LOGVRB("Module \"%s@%s\" is already present in the context.", mod_dup->name,
1888 mod_dup->revision ? mod_dup->revision : "<none>");
Radek Krejcic64661b2020-08-15 15:42:26 +02001889 goto cleanup;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001890 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001891
Michal Vaskob24145d2022-07-13 18:34:39 +02001892 /* check whether there is not a namespace collision */
1893 mod_dup = ly_ctx_get_module_latest_ns(ctx, mod->ns);
1894 if (mod_dup && (mod_dup->revision == mod->revision)) {
1895 LOGERR(ctx, LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\".",
1896 mod_dup->name, mod->name, mod->ns);
1897 ret = LY_EINVAL;
1898 goto cleanup;
1899 }
1900
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001901 switch (in->type) {
1902 case LY_IN_FILEPATH:
Jan Kundrát026737b2023-09-05 13:03:30 +02001903 ly_check_module_filename(ctx, mod->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL, in->method.fpath.filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001904 break;
1905 case LY_IN_FD:
1906 case LY_IN_FILE:
1907 case LY_IN_MEMORY:
1908 /* nothing special to do */
1909 break;
Michal Vasko7a0b0762020-09-02 16:37:01 +02001910 case LY_IN_ERROR:
1911 LOGINT(ctx);
1912 ret = LY_EINT;
Radek Krejcic64661b2020-08-15 15:42:26 +02001913 goto cleanup;
Radek Krejci096235c2019-01-11 11:12:19 +01001914 }
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001915 lys_parser_fill_filepath(ctx, in, &mod->filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001916
Michal Vasko7a0b0762020-09-02 16:37:01 +02001917 if (latest) {
aPiecek8ca21bd2021-07-26 14:31:01 +02001918 latest->latest_revision &= ~(LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001919 }
1920
Michal Vasko45b521c2020-11-04 17:14:39 +01001921 /* add internal data in case specific modules were parsed */
1922 if (!strcmp(mod->name, "ietf-netconf")) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001923 LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf(pctx, mod->parsed), cleanup);
Michal Vasko45b521c2020-11-04 17:14:39 +01001924 } else if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001925 LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf_with_defaults(pctx, mod->parsed), cleanup);
aPiecek6cf1d162023-11-08 16:07:00 +01001926 } else if (!strcmp(mod->name, "yang")) {
1927 LY_CHECK_GOTO(ret = lysp_add_internal_yang(pctx, mod->parsed), cleanup);
Michal Vasko45b521c2020-11-04 17:14:39 +01001928 }
1929
Michal Vasko405cc9e2020-12-01 12:01:27 +01001930 /* add the module into newly created module set, will also be freed from there on any error */
Radek Krejcic64661b2020-08-15 15:42:26 +02001931 LY_CHECK_GOTO(ret = ly_set_add(new_mods, mod, 1, NULL), cleanup);
1932 module_created = 1;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001933
Michal Vasko7a0b0762020-09-02 16:37:01 +02001934 /* add into context */
Radek Krejci3d92e442020-10-12 12:48:13 +02001935 ret = ly_set_add(&ctx->list, mod, 1, NULL);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001936 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko794ab4b2021-03-31 09:42:19 +02001937 ctx->change_count++;
Michal Vasko7a0b0762020-09-02 16:37:01 +02001938
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001939 /* resolve includes and all imports */
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001940 LY_CHECK_GOTO(ret = lysp_resolve_import_include(pctx, mod->parsed, new_mods), cleanup);
1941
1942 /* resolve extension instance plugin records */
1943 LY_CHECK_GOTO(ret = lysp_resolve_ext_instance_records(pctx), cleanup);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001944
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001945 /* check name collisions */
Michal Vasko405cc9e2020-12-01 12:01:27 +01001946 LY_CHECK_GOTO(ret = lysp_check_dup_typedefs(pctx, mod->parsed), cleanup);
aPiecek63e080d2021-06-29 13:53:28 +02001947 LY_CHECK_GOTO(ret = lysp_check_dup_groupings(pctx, mod->parsed), cleanup);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001948 LY_CHECK_GOTO(ret = lysp_check_dup_features(pctx, mod->parsed), cleanup);
1949 LY_CHECK_GOTO(ret = lysp_check_dup_identities(pctx, mod->parsed), cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001950
1951 /* compile features */
Michal Vasko405cc9e2020-12-01 12:01:27 +01001952 LY_CHECK_GOTO(ret = lys_compile_feature_iffeatures(mod->parsed), cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001953
aPiecek6b3d5422021-07-30 15:55:43 +02001954 /* compile identities */
1955 LY_CHECK_GOTO(ret = lys_compile_identities(mod), cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001956
Radek Krejcic64661b2020-08-15 15:42:26 +02001957cleanup:
Michal Vaskobe04af42021-07-16 10:48:43 +02001958 if (ret && (ret != LY_EEXIST)) {
Radek Krejcic64661b2020-08-15 15:42:26 +02001959 if (mod && mod->name) {
1960 /* there are cases when path is not available for parsing error, so this additional
1961 * message tries to add information about the module where the error occurred */
Michal Vasko7a266772024-01-23 11:02:38 +01001962 const struct ly_err_item *e = ly_err_last(ctx);
Michal Vasko26bbb272022-08-02 14:54:33 +02001963
Michal Vasko7a266772024-01-23 11:02:38 +01001964 if (e && (!e->schema_path || e->line)) {
Michal Vasko56318fe2024-04-05 08:43:40 +02001965 LOGERR(ctx, LY_EOTHER, "Parsing module \"%s\" failed.", mod->name);
Radek Krejcic64661b2020-08-15 15:42:26 +02001966 }
1967 }
1968 }
1969 if (!module_created) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001970 fctx.mod = mod;
1971 lys_module_free(&fctx, mod, 0);
1972 lysf_ctx_erase(&fctx);
1973
Michal Vasko0e02e8e2021-02-26 15:01:55 +01001974 mod = mod_dup;
1975 }
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001976
Michal Vasko7a0b0762020-09-02 16:37:01 +02001977 if (format == LYS_IN_YANG) {
Michal Vaskod0625d72022-10-06 15:02:50 +02001978 lysp_yang_ctx_free(yangctx);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001979 } else {
Michal Vaskod0625d72022-10-06 15:02:50 +02001980 lysp_yin_ctx_free(yinctx);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001981 }
1982
Michal Vasko405cc9e2020-12-01 12:01:27 +01001983 if (!ret && module) {
1984 *module = mod;
1985 }
Michal Vasko7a0b0762020-09-02 16:37:01 +02001986 return ret;
1987}
1988
Radek Krejci545b4872020-11-15 10:15:12 +01001989static LYS_INFORMAT
1990lys_parse_get_format(const struct ly_in *in, LYS_INFORMAT format)
1991{
1992 if (!format && (in->type == LY_IN_FILEPATH)) {
1993 /* unknown format - try to detect it from filename's suffix */
1994 const char *path = in->method.fpath.filepath;
1995 size_t len = strlen(path);
1996
1997 /* ignore trailing whitespaces */
1998 for ( ; len > 0 && isspace(path[len - 1]); len--) {}
1999
Radek Krejcif13b87b2020-12-01 22:02:17 +01002000 if ((len >= LY_YANG_SUFFIX_LEN + 1) &&
2001 !strncmp(&path[len - LY_YANG_SUFFIX_LEN], LY_YANG_SUFFIX, LY_YANG_SUFFIX_LEN)) {
Radek Krejci545b4872020-11-15 10:15:12 +01002002 format = LYS_IN_YANG;
Radek Krejcif13b87b2020-12-01 22:02:17 +01002003 } else if ((len >= LY_YIN_SUFFIX_LEN + 1) &&
2004 !strncmp(&path[len - LY_YIN_SUFFIX_LEN], LY_YIN_SUFFIX, LY_YIN_SUFFIX_LEN)) {
Radek Krejci545b4872020-11-15 10:15:12 +01002005 format = LYS_IN_YIN;
2006 } /* else still unknown */
2007 }
2008
2009 return format;
2010}
2011
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002012LIBYANG_API_DEF LY_ERR
Michal Vasko4de7d072021-07-09 09:13:18 +02002013lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const char **features, struct lys_module **module)
Michal Vasko7a0b0762020-09-02 16:37:01 +02002014{
Michal Vasko65333882021-06-10 14:12:16 +02002015 LY_ERR ret = LY_SUCCESS;
Michal Vasko4e205e82021-06-08 14:01:47 +02002016 struct lys_module *mod;
Michal Vasko405cc9e2020-12-01 12:01:27 +01002017
Michal Vasko7a0b0762020-09-02 16:37:01 +02002018 if (module) {
2019 *module = NULL;
2020 }
Radek Krejci545b4872020-11-15 10:15:12 +01002021 LY_CHECK_ARG_RET(NULL, ctx, in, LY_EINVAL);
2022
2023 format = lys_parse_get_format(in, format);
2024 LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
Michal Vasko7a0b0762020-09-02 16:37:01 +02002025
2026 /* remember input position */
2027 in->func_start = in->current;
2028
Michal Vasko4e205e82021-06-08 14:01:47 +02002029 /* parse */
Michal Vasko22b26222021-07-30 11:16:47 +02002030 ret = lys_parse_in(ctx, in, format, NULL, NULL, &ctx->unres.creating, &mod);
Michal Vasko4e205e82021-06-08 14:01:47 +02002031 LY_CHECK_GOTO(ret, cleanup);
2032
2033 /* implement */
Michal Vasko22b26222021-07-30 11:16:47 +02002034 ret = _lys_set_implemented(mod, features, &ctx->unres);
Michal Vasko405cc9e2020-12-01 12:01:27 +01002035 LY_CHECK_GOTO(ret, cleanup);
2036
Michal Vaskof4258e12021-06-15 12:11:42 +02002037 if (!(ctx->flags & LY_CTX_EXPLICIT_COMPILE)) {
2038 /* create dep set for the module and mark all the modules that will be (re)compiled */
Michal Vasko22b26222021-07-30 11:16:47 +02002039 LY_CHECK_GOTO(ret = lys_unres_dep_sets_create(ctx, &ctx->unres.dep_sets, mod), cleanup);
Michal Vaskof4258e12021-06-15 12:11:42 +02002040
Michal Vasko709f9a52021-07-21 10:51:59 +02002041 /* (re)compile the whole dep set (other dep sets will have no modules marked for compilation) */
Michal Vasko22b26222021-07-30 11:16:47 +02002042 LY_CHECK_GOTO(ret = lys_compile_depset_all(ctx, &ctx->unres), cleanup);
2043
2044 /* unres resolved */
2045 lys_unres_glob_erase(&ctx->unres);
Michal Vaskof4258e12021-06-15 12:11:42 +02002046 }
2047
Michal Vasko405cc9e2020-12-01 12:01:27 +01002048cleanup:
2049 if (ret) {
Michal Vasko22b26222021-07-30 11:16:47 +02002050 lys_unres_glob_revert(ctx, &ctx->unres);
2051 lys_unres_glob_erase(&ctx->unres);
Michal Vasko87f1cf02021-06-08 14:02:47 +02002052 } else if (module) {
2053 *module = mod;
Michal Vasko405cc9e2020-12-01 12:01:27 +01002054 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01002055 return ret;
Radek Krejci86d106e2018-10-18 09:53:19 +02002056}
2057
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002058LIBYANG_API_DEF LY_ERR
Michal Vasko4de7d072021-07-09 09:13:18 +02002059lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02002060{
Radek Krejci0f969882020-08-21 16:56:47 +02002061 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002062 struct ly_in *in = NULL;
Radek Krejci86d106e2018-10-18 09:53:19 +02002063
Michal Vasko3a41dff2020-07-15 14:30:28 +02002064 LY_CHECK_ARG_RET(ctx, data, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejci65639b92018-11-27 10:51:37 +01002065
Michal Vasko3a41dff2020-07-15 14:30:28 +02002066 LY_CHECK_ERR_RET(ret = ly_in_new_memory(data, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
Radek Krejci86d106e2018-10-18 09:53:19 +02002067
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002068 ret = lys_parse(ctx, in, format, NULL, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002069 ly_in_free(in, 0);
Radek Krejci86d106e2018-10-18 09:53:19 +02002070
Michal Vasko3a41dff2020-07-15 14:30:28 +02002071 return ret;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01002072}
2073
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002074LIBYANG_API_DEF LY_ERR
Michal Vasko4de7d072021-07-09 09:13:18 +02002075lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02002076{
Radek Krejci0f969882020-08-21 16:56:47 +02002077 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002078 struct ly_in *in = NULL;
Radek Krejci86d106e2018-10-18 09:53:19 +02002079
Michal Vasko3a41dff2020-07-15 14:30:28 +02002080 LY_CHECK_ARG_RET(ctx, fd > -1, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejci86d106e2018-10-18 09:53:19 +02002081
Michal Vasko3a41dff2020-07-15 14:30:28 +02002082 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
Radek Krejci86d106e2018-10-18 09:53:19 +02002083
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002084 ret = lys_parse(ctx, in, format, NULL, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002085 ly_in_free(in, 0);
Radek Krejci86d106e2018-10-18 09:53:19 +02002086
Michal Vasko3a41dff2020-07-15 14:30:28 +02002087 return ret;
Radek Krejci86d106e2018-10-18 09:53:19 +02002088}
2089
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002090LIBYANG_API_DEF LY_ERR
Michal Vasko4de7d072021-07-09 09:13:18 +02002091lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, struct lys_module **module)
Radek Krejcid33273d2018-10-25 14:55:52 +02002092{
Radek Krejci0f969882020-08-21 16:56:47 +02002093 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002094 struct ly_in *in = NULL;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002095
Michal Vasko3a41dff2020-07-15 14:30:28 +02002096 LY_CHECK_ARG_RET(ctx, path, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002097
Michal Vasko3a41dff2020-07-15 14:30:28 +02002098 LY_CHECK_ERR_RET(ret = ly_in_new_filepath(path, 0, &in),
Michal Vasko69730152020-10-09 16:30:07 +02002099 LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", path), ret);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002100
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01002101 ret = lys_parse(ctx, in, format, NULL, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02002102 ly_in_free(in, 0);
2103
Michal Vasko3a41dff2020-07-15 14:30:28 +02002104 return ret;
Radek Krejcid33273d2018-10-25 14:55:52 +02002105}
2106
Michal Vasko9c49d882024-01-23 11:34:56 +01002107/**
2108 * @brief Check file type of a file.
2109 *
2110 * @param[in] file Dirent file to check.
2111 * @param[in] wd Working directory.
2112 * @param[in,out] dirs Set with searched directories to add to.
2113 * @param[in] implicit_cwd Whether implicit CWD is used.
2114 * @param[out] skip Whether to skip this file.
2115 * @return LY_ERR value.
2116 */
2117static LY_ERR
2118lys_search_localfile_file_type(const struct dirent *file, const char *wd, struct ly_set *dirs, ly_bool implicit_cwd,
2119 ly_bool *skip)
2120{
2121 LY_ERR rc = LY_SUCCESS;
2122 char *str = NULL;
2123 ly_bool is_dir = 0, is_reg = 0;
2124 struct stat st;
2125
2126 *skip = 0;
2127
Michal Vaskoc3509222024-05-21 15:42:16 +02002128 if ((file->d_type == DT_UNKNOWN) || (file->d_type == DT_LNK)) {
2129 /* FS does not support this field or its a symbolic link, need to call stat */
Michal Vasko9c49d882024-01-23 11:34:56 +01002130 if (asprintf(&str, "%s/%s", wd, file->d_name) == -1) {
2131 LOGMEM(NULL);
2132 rc = LY_EMEM;
2133 goto cleanup;
2134 }
2135 if (stat(str, &st)) {
2136 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
2137 file->d_name, wd, strerror(errno));
2138 } else if (S_ISDIR(st.st_mode)) {
2139 /* stat - dir */
2140 is_dir = 1;
2141 } else if (S_ISREG(st.st_mode)) {
2142 /* stat - file */
2143 is_reg = 1;
2144 }
2145 } else if (file->d_type == DT_DIR) {
2146 /* dirent - dir */
2147 is_dir = 1;
2148 } else if (file->d_type == DT_REG) {
2149 /* dirent - file */
2150 is_reg = 1;
2151 }
2152
2153 if (is_dir && (dirs->count || !implicit_cwd)) {
2154 /* we have another subdirectory in searchpath to explore,
2155 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
2156 if (!str && (asprintf(&str, "%s/%s", wd, file->d_name) == -1)) {
2157 LOGMEM(NULL);
2158 rc = LY_EMEM;
2159 goto cleanup;
2160 }
2161 if ((rc = ly_set_add(dirs, str, 0, NULL))) {
2162 goto cleanup;
2163 }
2164 str = NULL;
2165
2166 /* continue with the next item in current directory */
2167 *skip = 1;
2168 } else if (!is_reg) {
2169 /* not a regular file (note that we see the target of symlinks instead of symlinks */
2170 *skip = 1;
2171 }
2172
2173cleanup:
2174 free(str);
2175 return rc;
2176}
2177
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002178LIBYANG_API_DEF LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02002179lys_search_localfile(const char * const *searchpaths, ly_bool cwd, const char *name, const char *revision,
Radek Krejci0f969882020-08-21 16:56:47 +02002180 char **localfile, LYS_INFORMAT *format)
Radek Krejcid33273d2018-10-25 14:55:52 +02002181{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002182 LY_ERR ret = LY_EMEM;
Radek Krejcid33273d2018-10-25 14:55:52 +02002183 size_t len, flen, match_len = 0, dir_len;
Michal Vasko9c49d882024-01-23 11:34:56 +01002184 ly_bool implicit_cwd = 0, skip;
2185 char *wd;
Radek Krejcid33273d2018-10-25 14:55:52 +02002186 DIR *dir = NULL;
2187 struct dirent *file;
2188 char *match_name = NULL;
2189 LYS_INFORMAT format_aux, match_format = 0;
2190 struct ly_set *dirs;
Radek Krejcid33273d2018-10-25 14:55:52 +02002191
2192 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
2193
2194 /* start to fill the dir fifo with the context's search path (if set)
2195 * and the current working directory */
Radek Krejciba03a5a2020-08-27 14:40:41 +02002196 LY_CHECK_RET(ly_set_new(&dirs));
Radek Krejcid33273d2018-10-25 14:55:52 +02002197
2198 len = strlen(name);
2199 if (cwd) {
2200 wd = get_current_dir_name();
2201 if (!wd) {
2202 LOGMEM(NULL);
2203 goto cleanup;
2204 } else {
2205 /* add implicit current working directory (./) to be searched,
2206 * this directory is not searched recursively */
Radek Krejciba03a5a2020-08-27 14:40:41 +02002207 ret = ly_set_add(dirs, wd, 0, NULL);
2208 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcid33273d2018-10-25 14:55:52 +02002209 implicit_cwd = 1;
2210 }
2211 }
2212 if (searchpaths) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02002213 for (uint64_t i = 0; searchpaths[i]; i++) {
Radek Krejcid33273d2018-10-25 14:55:52 +02002214 /* check for duplicities with the implicit current working directory */
2215 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
2216 implicit_cwd = 0;
2217 continue;
2218 }
2219 wd = strdup(searchpaths[i]);
2220 if (!wd) {
2221 LOGMEM(NULL);
2222 goto cleanup;
Radek Krejciba03a5a2020-08-27 14:40:41 +02002223 } else {
2224 ret = ly_set_add(dirs, wd, 0, NULL);
2225 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcid33273d2018-10-25 14:55:52 +02002226 }
2227 }
2228 }
2229 wd = NULL;
2230
2231 /* start searching */
2232 while (dirs->count) {
2233 free(wd);
Radek Krejcid33273d2018-10-25 14:55:52 +02002234
2235 dirs->count--;
2236 wd = (char *)dirs->objs[dirs->count];
2237 dirs->objs[dirs->count] = NULL;
Radek Krejcieeee95c2021-01-19 10:57:22 +01002238 LOGVRB("Searching for \"%s\" in \"%s\".", name, wd);
Radek Krejcid33273d2018-10-25 14:55:52 +02002239
2240 if (dir) {
2241 closedir(dir);
2242 }
2243 dir = opendir(wd);
2244 dir_len = strlen(wd);
2245 if (!dir) {
2246 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
Michal Vaskob89abc02024-01-19 09:36:13 +01002247 continue;
2248 }
2249
2250 /* search the directory */
2251 while ((file = readdir(dir))) {
2252 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
2253 /* skip . and .. */
2254 continue;
2255 }
2256
Michal Vasko9c49d882024-01-23 11:34:56 +01002257 /* check whether file type is */
2258 if ((ret = lys_search_localfile_file_type(file, wd, dirs, implicit_cwd, &skip))) {
2259 goto cleanup;
Michal Vaskob89abc02024-01-19 09:36:13 +01002260 }
Radek Krejcid33273d2018-10-25 14:55:52 +02002261
Michal Vaskob89abc02024-01-19 09:36:13 +01002262 /* here we know that the item is a file which can contain a module */
2263 if (strncmp(name, file->d_name, len) || ((file->d_name[len] != '.') && (file->d_name[len] != '@'))) {
2264 /* different filename than the module we search for */
2265 continue;
2266 }
Radek Krejcid33273d2018-10-25 14:55:52 +02002267
Michal Vaskob89abc02024-01-19 09:36:13 +01002268 /* get type according to filename suffix */
2269 flen = strlen(file->d_name);
2270 if ((flen >= LY_YANG_SUFFIX_LEN + 1) && !strcmp(&file->d_name[flen - LY_YANG_SUFFIX_LEN], LY_YANG_SUFFIX)) {
2271 format_aux = LYS_IN_YANG;
2272 } else if ((flen >= LY_YIN_SUFFIX_LEN + 1) && !strcmp(&file->d_name[flen - LY_YIN_SUFFIX_LEN], LY_YIN_SUFFIX)) {
2273 format_aux = LYS_IN_YIN;
2274 } else {
2275 /* not supported suffix/file format */
2276 continue;
2277 }
2278
2279 if (revision) {
2280 /* we look for the specific revision, try to get it from the filename */
2281 if (file->d_name[len] == '@') {
2282 /* check revision from the filename */
2283 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
2284 /* another revision */
2285 continue;
Radek Krejcid33273d2018-10-25 14:55:52 +02002286 } else {
Michal Vaskob89abc02024-01-19 09:36:13 +01002287 /* exact revision */
Radek Krejcid33273d2018-10-25 14:55:52 +02002288 free(match_name);
Michal Vaskob89abc02024-01-19 09:36:13 +01002289 if (asprintf(&match_name, "%s/%s", wd, file->d_name) == -1) {
2290 LOGMEM(NULL);
2291 goto cleanup;
2292 }
Michal Vasko44f3d2c2020-08-24 09:49:38 +02002293 match_len = dir_len + 1 + len;
Radek Krejcid33273d2018-10-25 14:55:52 +02002294 match_format = format_aux;
Michal Vaskob89abc02024-01-19 09:36:13 +01002295 goto success;
Radek Krejcid33273d2018-10-25 14:55:52 +02002296 }
2297 } else {
Michal Vaskob89abc02024-01-19 09:36:13 +01002298 /* continue trying to find exact revision match, use this only if not found */
2299 free(match_name);
2300 if (asprintf(&match_name, "%s/%s", wd, file->d_name) == -1) {
2301 LOGMEM(NULL);
2302 goto cleanup;
Radek Krejcid33273d2018-10-25 14:55:52 +02002303 }
Radek Krejcid33273d2018-10-25 14:55:52 +02002304 match_len = dir_len + 1 + len;
2305 match_format = format_aux;
2306 continue;
2307 }
Michal Vaskob89abc02024-01-19 09:36:13 +01002308 } else {
2309 /* remember the revision and try to find the newest one */
2310 if (match_name) {
2311 if ((file->d_name[len] != '@') ||
2312 lysp_check_date(NULL, &file->d_name[len + 1],
2313 flen - ((format_aux == LYS_IN_YANG) ? LY_YANG_SUFFIX_LEN : LY_YIN_SUFFIX_LEN) - len - 1, NULL)) {
2314 continue;
2315 } else if ((match_name[match_len] == '@') &&
2316 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
2317 continue;
2318 }
2319 free(match_name);
2320 }
2321
2322 if (asprintf(&match_name, "%s/%s", wd, file->d_name) == -1) {
2323 LOGMEM(NULL);
2324 goto cleanup;
2325 }
2326 match_len = dir_len + 1 + len;
2327 match_format = format_aux;
2328 continue;
Radek Krejcid33273d2018-10-25 14:55:52 +02002329 }
2330 }
2331 }
2332
2333success:
2334 (*localfile) = match_name;
2335 match_name = NULL;
2336 if (format) {
2337 (*format) = match_format;
2338 }
Radek Krejci1deb5be2020-08-26 16:43:36 +02002339 ret = LY_SUCCESS;
Radek Krejcid33273d2018-10-25 14:55:52 +02002340
2341cleanup:
Radek Krejcid33273d2018-10-25 14:55:52 +02002342 free(wd);
2343 if (dir) {
2344 closedir(dir);
2345 }
2346 free(match_name);
2347 ly_set_free(dirs, free);
2348
2349 return ret;
2350}