blob: 5c897bfba64079816df9f559d5d1bcee6c5b98bd [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
Radek Krejcica376bd2020-06-11 16:04:06 +020030#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020031#include "compat.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020032#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020033#include "dict.h"
Radek Krejci47fab892020-11-05 17:02:41 +010034#include "in.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020035#include "in_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010036#include "log.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 Vaskoc0c64ae2022-10-06 10:15:23 +020040#include "plugins_internal.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020041#include "schema_compile.h"
Michal Vaskof4258e12021-06-15 12:11:42 +020042#include "schema_compile_amend.h"
Michal Vasko7b1ad1a2020-11-02 15:41:27 +010043#include "schema_features.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020044#include "set.h"
45#include "tree.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010046#include "tree_edit.h"
Michal Vaskoc636ea42022-09-16 10:20:31 +020047#include "tree_schema_free.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020048#include "tree_schema_internal.h"
49#include "xpath.h"
Radek Krejci3f5e3db2018-10-11 15:57:47 +020050
Radek Krejcieccf6602021-02-05 19:42:54 +010051const char * const ly_devmod_list[] = {
52 [LYS_DEV_NOT_SUPPORTED] = "not-supported",
53 [LYS_DEV_ADD] = "add",
54 [LYS_DEV_DELETE] = "delete",
55 [LYS_DEV_REPLACE] = "replace",
56};
57
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010058LIBYANG_API_DEF LY_ERR
Michal Vaskof1ab44f2020-10-22 08:58:32 +020059lysc_tree_dfs_full(const struct lysc_node *root, lysc_dfs_clb dfs_clb, void *data)
60{
Michal Vasko1d972ca2020-11-03 17:16:56 +010061 struct lysc_node *elem, *elem2;
Radek Krejci2a9fc652021-01-22 17:44:34 +010062 const struct lysc_node_action *action;
63 const struct lysc_node_notif *notif;
Michal Vaskof1ab44f2020-10-22 08:58:32 +020064
65 LY_CHECK_ARG_RET(NULL, root, dfs_clb, LY_EINVAL);
66
67 LYSC_TREE_DFS_BEGIN(root, elem) {
68 /* schema node */
69 LY_CHECK_RET(dfs_clb(elem, data, &LYSC_TREE_DFS_continue));
70
Radek Krejci2a9fc652021-01-22 17:44:34 +010071 LY_LIST_FOR(lysc_node_actions(elem), action) {
72 LYSC_TREE_DFS_BEGIN(action, elem2) {
Michal Vaskof1ab44f2020-10-22 08:58:32 +020073 /* action subtree */
74 LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
75
Radek Krejci2a9fc652021-01-22 17:44:34 +010076 LYSC_TREE_DFS_END(action, elem2);
Michal Vaskof1ab44f2020-10-22 08:58:32 +020077 }
78 }
79
Radek Krejci2a9fc652021-01-22 17:44:34 +010080 LY_LIST_FOR(lysc_node_notifs(elem), notif) {
81 LYSC_TREE_DFS_BEGIN(notif, elem2) {
Michal Vaskof1ab44f2020-10-22 08:58:32 +020082 /* notification subtree */
83 LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
84
Radek Krejci2a9fc652021-01-22 17:44:34 +010085 LYSC_TREE_DFS_END(notif, elem2);
Michal Vaskof1ab44f2020-10-22 08:58:32 +020086 }
87 }
88
89 LYSC_TREE_DFS_END(root, elem);
90 }
91
92 return LY_SUCCESS;
93}
94
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010095LIBYANG_API_DEF LY_ERR
Michal Vaskof1ab44f2020-10-22 08:58:32 +020096lysc_module_dfs_full(const struct lys_module *mod, lysc_dfs_clb dfs_clb, void *data)
97{
Michal Vasko2336cf52020-11-03 17:18:15 +010098 const struct lysc_node *root;
Michal Vaskof1ab44f2020-10-22 08:58:32 +020099
100 LY_CHECK_ARG_RET(NULL, mod, mod->compiled, dfs_clb, LY_EINVAL);
101
102 /* schema nodes */
Michal Vasko2336cf52020-11-03 17:18:15 +0100103 LY_LIST_FOR(mod->compiled->data, root) {
104 LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
105 }
Michal Vaskof1ab44f2020-10-22 08:58:32 +0200106
107 /* RPCs */
Radek Krejci2a9fc652021-01-22 17:44:34 +0100108 LY_LIST_FOR((const struct lysc_node *)mod->compiled->rpcs, root) {
109 LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
Michal Vaskof1ab44f2020-10-22 08:58:32 +0200110 }
111
112 /* notifications */
Radek Krejci2a9fc652021-01-22 17:44:34 +0100113 LY_LIST_FOR((const struct lysc_node *)mod->compiled->notifs, root) {
114 LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
Michal Vaskof1ab44f2020-10-22 08:58:32 +0200115 }
116
117 return LY_SUCCESS;
118}
119
Radek Krejcib93bd412020-11-02 13:23:11 +0100120static void
121lys_getnext_into_case(const struct lysc_node_case *first_case, const struct lysc_node **last, const struct lysc_node **next)
122{
Radek Krejcic5b54a02020-11-05 17:13:18 +0100123 for ( ; first_case; first_case = (const struct lysc_node_case *)first_case->next) {
Radek Krejcib93bd412020-11-02 13:23:11 +0100124 if (first_case->child) {
125 /* there is something to return */
126 (*next) = first_case->child;
127 return;
128 }
129 }
130
131 /* no children in choice's cases, so go to the choice's sibling instead of into it */
132 (*last) = (*next);
133 (*next) = (*next)->next;
134}
135
Radek Krejci035dacf2021-02-12 18:25:53 +0100136/**
137 * @brief Generic getnext function for ::lys_getnext() and ::lys_getnext_ext().
138 *
139 * Gets next schema tree (sibling) node element that can be instantiated in a data tree. Returned node can
140 * be from an augment. If the @p ext is provided, the function is locked inside the schema tree defined in the
141 * extension instance.
142 *
Michal Vasko193dacd2022-10-13 08:43:05 +0200143 * ::lys_getnext_() is supposed to be called sequentially. In the first call, the @p last parameter is usually NULL
144 * and function starts returning i) the first @p parent's child or ii) the first top level element specified in the
145 * given extension (if provided) or iii) the first top level element of the @p module.
146 * Consequent calls suppose to provide the previously returned node as the @p last parameter and still the same
147 * @p parent and @p module parameters.
Radek Krejci035dacf2021-02-12 18:25:53 +0100148 *
149 * 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 +0200150 * 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 +0100151 * all the schema nodes are iteratively returned.
152 *
153 * @param[in] last Previously returned schema tree node, or NULL in case of the first call.
154 * @param[in] parent Parent of the subtree where the function starts processing.
Michal Vasko193dacd2022-10-13 08:43:05 +0200155 * @param[in] module In case of iterating on top level elements, the @p parent is NULL and
Radek Krejci035dacf2021-02-12 18:25:53 +0100156 * module must be specified.
157 * @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 +0200158 * 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 +0100159 * @param[in] options [ORed options](@ref sgetnextflags).
160 * @return Next schema tree node that can be instantiated in a data tree, NULL in case there is no such element.
161 */
162static const struct lysc_node *
163lys_getnext_(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module,
164 const struct lysc_ext_instance *ext, uint32_t options)
Radek Krejcia3045382018-11-22 14:30:31 +0100165{
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100166 const struct lysc_node *next = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200167 ly_bool action_flag = 0, notif_flag = 0;
Radek Krejcia3045382018-11-22 14:30:31 +0100168
Radek Krejci035dacf2021-02-12 18:25:53 +0100169 LY_CHECK_ARG_RET(NULL, parent || module || ext, NULL);
Radek Krejcia3045382018-11-22 14:30:31 +0100170
Radek Krejcid5a2b9d2019-04-12 10:39:30 +0200171next:
Radek Krejcia3045382018-11-22 14:30:31 +0100172 if (!last) {
173 /* first call */
174
175 /* get know where to start */
176 if (parent) {
177 /* schema subtree */
Michal Vasko544e58a2021-01-28 14:33:41 +0100178 next = last = lysc_node_child(parent);
Radek Krejcia3045382018-11-22 14:30:31 +0100179 } else {
180 /* top level data */
Radek Krejci035dacf2021-02-12 18:25:53 +0100181 if (ext) {
Michal Vaskofbd037c2022-11-08 10:34:20 +0100182 lyplg_ext_get_storage(ext, LY_STMT_DATA_NODE_MASK, sizeof last, (const void **)&last);
Michal Vasko193dacd2022-10-13 08:43:05 +0200183 next = last;
Radek Krejci035dacf2021-02-12 18:25:53 +0100184 } else {
185 next = last = module->data;
186 }
Radek Krejcia3045382018-11-22 14:30:31 +0100187 }
188 if (!next) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100189 /* try to get action or notification */
190 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100191 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100192 /* test if the next can be returned */
193 goto check;
194
Michal Vasko1bf09392020-03-27 12:38:10 +0100195 } else if (last->nodetype & (LYS_RPC | LYS_ACTION)) {
Radek Krejci05b774b2019-02-25 13:26:18 +0100196 action_flag = 1;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100197 next = last->next;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100198 } else if (last->nodetype == LYS_NOTIF) {
Radek Krejci05b774b2019-02-25 13:26:18 +0100199 action_flag = notif_flag = 1;
Radek Krejci2a9fc652021-01-22 17:44:34 +0100200 next = last->next;
Michal Vasko20424b42020-08-31 12:29:38 +0200201 } else {
202 next = last->next;
Radek Krejcia3045382018-11-22 14:30:31 +0100203 }
204
Radek Krejcia3045382018-11-22 14:30:31 +0100205repeat:
206 if (!next) {
Radek Krejcia9026eb2018-12-12 16:04:47 +0100207 /* possibly go back to parent */
Michal Vasko69730152020-10-09 16:30:07 +0200208 if (last && (last->parent != parent)) {
Radek Krejcia9026eb2018-12-12 16:04:47 +0100209 last = last->parent;
Radek Krejcid5a2b9d2019-04-12 10:39:30 +0200210 goto next;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100211 } else if (!action_flag) {
212 action_flag = 1;
Radek Krejci035dacf2021-02-12 18:25:53 +0100213 if (ext) {
Michal Vaskofbd037c2022-11-08 10:34:20 +0100214 lyplg_ext_get_storage(ext, LY_STMT_OP_MASK, sizeof next, (const void **)&next);
Radek Krejci035dacf2021-02-12 18:25:53 +0100215 } else if (parent) {
216 next = (struct lysc_node *)lysc_node_actions(parent);
217 } else {
218 next = (struct lysc_node *)module->rpcs;
219 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100220 } else if (!notif_flag) {
221 notif_flag = 1;
Radek Krejci035dacf2021-02-12 18:25:53 +0100222 if (ext) {
Michal Vaskofbd037c2022-11-08 10:34:20 +0100223 lyplg_ext_get_storage(ext, LY_STMT_NOTIFICATION, sizeof next, (const void **)&next);
Radek Krejci035dacf2021-02-12 18:25:53 +0100224 } else if (parent) {
225 next = (struct lysc_node *)lysc_node_notifs(parent);
226 } else {
227 next = (struct lysc_node *)module->notifs;
228 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100229 } else {
230 return NULL;
Radek Krejcia9026eb2018-12-12 16:04:47 +0100231 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100232 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100233 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100234check:
Radek Krejcia3045382018-11-22 14:30:31 +0100235 switch (next->nodetype) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100236 case LYS_RPC:
Radek Krejcia3045382018-11-22 14:30:31 +0100237 case LYS_ACTION:
238 case LYS_NOTIF:
239 case LYS_LEAF:
240 case LYS_ANYXML:
241 case LYS_ANYDATA:
242 case LYS_LIST:
243 case LYS_LEAFLIST:
244 break;
Michal Vasko20424b42020-08-31 12:29:38 +0200245 case LYS_CASE:
246 if (options & LYS_GETNEXT_WITHCASE) {
247 break;
248 } else {
249 /* go into */
Radek Krejcib93bd412020-11-02 13:23:11 +0100250 lys_getnext_into_case((const struct lysc_node_case *)next, &last, &next);
Michal Vasko20424b42020-08-31 12:29:38 +0200251 }
252 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100253 case LYS_CONTAINER:
Michal Vasko14ed9cd2021-01-28 14:16:25 +0100254 if (!(next->flags & LYS_PRESENCE) && (options & LYS_GETNEXT_INTONPCONT)) {
Michal Vasko544e58a2021-01-28 14:33:41 +0100255 if (lysc_node_child(next)) {
Radek Krejcia3045382018-11-22 14:30:31 +0100256 /* go into */
Michal Vasko544e58a2021-01-28 14:33:41 +0100257 next = lysc_node_child(next);
Radek Krejcia3045382018-11-22 14:30:31 +0100258 } else {
Radek Krejcib93bd412020-11-02 13:23:11 +0100259 last = next;
Radek Krejcia3045382018-11-22 14:30:31 +0100260 next = next->next;
261 }
262 goto repeat;
263 }
264 break;
265 case LYS_CHOICE:
266 if (options & LYS_GETNEXT_WITHCHOICE) {
Michal Vasko20424b42020-08-31 12:29:38 +0200267 break;
Michal Vasko544e58a2021-01-28 14:33:41 +0100268 } else if ((options & LYS_GETNEXT_NOCHOICE) || !lysc_node_child(next)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100269 next = next->next;
270 } else {
Radek Krejcia9026eb2018-12-12 16:04:47 +0100271 if (options & LYS_GETNEXT_WITHCASE) {
Michal Vasko544e58a2021-01-28 14:33:41 +0100272 next = lysc_node_child(next);
Radek Krejcia9026eb2018-12-12 16:04:47 +0100273 } else {
Radek Krejcib93bd412020-11-02 13:23:11 +0100274 /* go into */
275 lys_getnext_into_case(((struct lysc_node_choice *)next)->cases, &last, &next);
Radek Krejcia9026eb2018-12-12 16:04:47 +0100276 }
Radek Krejcia3045382018-11-22 14:30:31 +0100277 }
278 goto repeat;
Michal Vasko544e58a2021-01-28 14:33:41 +0100279 case LYS_INPUT:
280 if (options & LYS_GETNEXT_OUTPUT) {
281 /* skip */
282 next = next->next;
283 } else {
284 /* go into */
285 next = lysc_node_child(next);
286 }
287 goto repeat;
288 case LYS_OUTPUT:
289 if (!(options & LYS_GETNEXT_OUTPUT)) {
290 /* skip */
291 next = next->next;
292 } else {
293 /* go into */
294 next = lysc_node_child(next);
295 }
296 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100297 default:
298 /* we should not be here */
Radek Krejci035dacf2021-02-12 18:25:53 +0100299 LOGINT(module ? module->mod->ctx : parent ? parent->module->ctx : ext->module->ctx);
Radek Krejcia3045382018-11-22 14:30:31 +0100300 return NULL;
301 }
302
Radek Krejcia3045382018-11-22 14:30:31 +0100303 return next;
304}
305
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100306LIBYANG_API_DEF const struct lysc_node *
Radek Krejci035dacf2021-02-12 18:25:53 +0100307lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, uint32_t options)
308{
309 return lys_getnext_(last, parent, module, NULL, options);
310}
311
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100312LIBYANG_API_DEF const struct lysc_node *
Radek Krejci035dacf2021-02-12 18:25:53 +0100313lys_getnext_ext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_ext_instance *ext, uint32_t options)
314{
315 return lys_getnext_(last, parent, NULL, ext, options);
316}
317
Radek Krejcif16e2542021-02-17 15:39:23 +0100318const struct lysc_node *
Radek Krejciba05eab2021-03-10 13:19:29 +0100319lysc_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 +0100320 uint16_t nodetype, uint32_t options)
321{
322 const struct lysc_node *node = NULL;
323
324 LY_CHECK_ARG_RET(NULL, ext, name, NULL);
325 if (!nodetype) {
326 nodetype = LYS_NODETYPE_MASK;
327 }
328
329 if (module && (module != ext->module)) {
330 return NULL;
331 }
332
333 while ((node = lys_getnext_ext(node, NULL, ext, options))) {
334 if (!(node->nodetype & nodetype)) {
335 continue;
336 }
337
338 if (name_len) {
339 if (!ly_strncmp(node->name, name, name_len)) {
340 return node;
341 }
342 } else {
343 if (!strcmp(node->name, name)) {
344 return node;
345 }
346 }
347 }
348 return NULL;
349}
350
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100351LIBYANG_API_DEF const struct lysc_node *
Michal Vaskoe444f752020-02-10 12:20:06 +0100352lys_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 +0200353 uint16_t nodetype, uint32_t options)
Radek Krejcia3045382018-11-22 14:30:31 +0100354{
355 const struct lysc_node *node = NULL;
356
357 LY_CHECK_ARG_RET(NULL, module, name, NULL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100358 LY_CHECK_CTX_EQUAL_RET(parent ? parent->module->ctx : NULL, module->ctx, NULL);
Radek Krejcia3045382018-11-22 14:30:31 +0100359 if (!nodetype) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100360 nodetype = LYS_NODETYPE_MASK;
Radek Krejcia3045382018-11-22 14:30:31 +0100361 }
362
363 while ((node = lys_getnext(node, parent, module->compiled, options))) {
364 if (!(node->nodetype & nodetype)) {
365 continue;
366 }
367 if (node->module != module) {
368 continue;
369 }
370
371 if (name_len) {
Radek Krejci7f9b6512019-09-18 13:11:09 +0200372 if (!ly_strncmp(node->name, name, name_len)) {
Radek Krejcia3045382018-11-22 14:30:31 +0100373 return node;
374 }
375 } else {
376 if (!strcmp(node->name, name)) {
377 return node;
378 }
379 }
380 }
Michal Vaskoddd76592022-01-17 13:34:48 +0100381
Radek Krejcia3045382018-11-22 14:30:31 +0100382 return NULL;
383}
384
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100385LIBYANG_API_DEF LY_ERR
Michal Vasko26512682021-01-11 11:35:40 +0100386lys_find_xpath_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *xpath, uint32_t options,
387 struct ly_set **set)
Michal Vasko519fd602020-05-26 12:17:39 +0200388{
389 LY_ERR ret = LY_SUCCESS;
390 struct lyxp_set xp_set;
Radek Krejcif03a9e22020-09-18 20:09:31 +0200391 struct lyxp_expr *exp = NULL;
Michal Vasko519fd602020-05-26 12:17:39 +0200392 uint32_t i;
393
Michal Vasko26512682021-01-11 11:35:40 +0100394 LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100395 LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
Michal Vasko519fd602020-05-26 12:17:39 +0200396 if (!(options & LYXP_SCNODE_ALL)) {
Michal Vasko4ad69e72021-10-26 16:25:55 +0200397 options |= LYXP_SCNODE;
Michal Vasko519fd602020-05-26 12:17:39 +0200398 }
Michal Vasko26512682021-01-11 11:35:40 +0100399 if (!ctx) {
400 ctx = ctx_node->module->ctx;
401 }
Michal Vasko519fd602020-05-26 12:17:39 +0200402
403 memset(&xp_set, 0, sizeof xp_set);
404
405 /* compile expression */
Michal Vasko26512682021-01-11 11:35:40 +0100406 ret = lyxp_expr_parse(ctx, xpath, 0, 1, &exp);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200407 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200408
409 /* atomize expression */
Michal Vaskoa3e92bc2022-07-29 14:56:23 +0200410 ret = lyxp_atomize(ctx, exp, NULL, LY_VALUE_JSON, NULL, ctx_node, ctx_node, &xp_set, options);
Michal Vasko519fd602020-05-26 12:17:39 +0200411 LY_CHECK_GOTO(ret, cleanup);
412
413 /* allocate return set */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200414 ret = ly_set_new(set);
415 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200416
417 /* transform into ly_set */
418 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
Michal Vasko26512682021-01-11 11:35:40 +0100419 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200420 (*set)->size = xp_set.used;
421
422 for (i = 0; i < xp_set.used; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +0200423 if (xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200424 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200425 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200426 }
427 }
428
429cleanup:
430 lyxp_set_free_content(&xp_set);
Michal Vasko26512682021-01-11 11:35:40 +0100431 lyxp_expr_free(ctx, exp);
Michal Vasko519fd602020-05-26 12:17:39 +0200432 return ret;
433}
434
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100435LIBYANG_API_DEF LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +0200436lys_find_expr_atoms(const struct lysc_node *ctx_node, const struct lys_module *cur_mod, const struct lyxp_expr *expr,
437 const struct lysc_prefix *prefixes, uint32_t options, struct ly_set **set)
438{
439 LY_ERR ret = LY_SUCCESS;
440 struct lyxp_set xp_set = {0};
441 uint32_t i;
442
443 LY_CHECK_ARG_RET(NULL, cur_mod, expr, prefixes, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100444 LY_CHECK_CTX_EQUAL_RET(ctx_node ? ctx_node->module->ctx : NULL, cur_mod->ctx, LY_EINVAL);
Michal Vasko40308e72020-10-20 16:38:40 +0200445 if (!(options & LYXP_SCNODE_ALL)) {
446 options = LYXP_SCNODE;
447 }
448
449 /* atomize expression */
Michal Vaskoa3e92bc2022-07-29 14:56:23 +0200450 ret = lyxp_atomize(cur_mod->ctx, expr, cur_mod, LY_VALUE_SCHEMA_RESOLVED, (void *)prefixes, ctx_node, ctx_node,
451 &xp_set, options);
Michal Vasko40308e72020-10-20 16:38:40 +0200452 LY_CHECK_GOTO(ret, cleanup);
453
454 /* allocate return set */
455 ret = ly_set_new(set);
456 LY_CHECK_GOTO(ret, cleanup);
457
458 /* transform into ly_set */
459 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
460 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(cur_mod->ctx); ret = LY_EMEM, cleanup);
461 (*set)->size = xp_set.used;
462
463 for (i = 0; i < xp_set.used; ++i) {
Michal Vasko1a09b212021-05-06 13:00:10 +0200464 if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx >= LYXP_SET_SCNODE_ATOM_NODE)) {
465 assert((xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_NODE) ||
466 (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_VAL) ||
Michal Vaskod97959c2020-12-10 12:18:28 +0100467 (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX));
Michal Vasko40308e72020-10-20 16:38:40 +0200468 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
469 LY_CHECK_GOTO(ret, cleanup);
470 }
471 }
472
473cleanup:
474 lyxp_set_free_content(&xp_set);
475 if (ret) {
476 ly_set_free(*set, NULL);
477 *set = NULL;
478 }
479 return ret;
480}
481
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100482LIBYANG_API_DEF LY_ERR
Michal Vasko26512682021-01-11 11:35:40 +0100483lys_find_xpath(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *xpath, uint32_t options,
484 struct ly_set **set)
Michal Vasko072de482020-08-05 13:27:21 +0200485{
486 LY_ERR ret = LY_SUCCESS;
Michal Vasko40308e72020-10-20 16:38:40 +0200487 struct lyxp_set xp_set = {0};
Radek Krejcif03a9e22020-09-18 20:09:31 +0200488 struct lyxp_expr *exp = NULL;
Michal Vasko072de482020-08-05 13:27:21 +0200489 uint32_t i;
490
Michal Vasko26512682021-01-11 11:35:40 +0100491 LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100492 LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
Michal Vasko072de482020-08-05 13:27:21 +0200493 if (!(options & LYXP_SCNODE_ALL)) {
494 options = LYXP_SCNODE;
495 }
Michal Vasko26512682021-01-11 11:35:40 +0100496 if (!ctx) {
497 ctx = ctx_node->module->ctx;
498 }
Michal Vasko072de482020-08-05 13:27:21 +0200499
Michal Vasko072de482020-08-05 13:27:21 +0200500 /* compile expression */
Michal Vasko26512682021-01-11 11:35:40 +0100501 ret = lyxp_expr_parse(ctx, xpath, 0, 1, &exp);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200502 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200503
504 /* atomize expression */
Michal Vaskoa3e92bc2022-07-29 14:56:23 +0200505 ret = lyxp_atomize(ctx, exp, NULL, LY_VALUE_JSON, NULL, ctx_node, ctx_node, &xp_set, options);
Michal Vasko072de482020-08-05 13:27:21 +0200506 LY_CHECK_GOTO(ret, cleanup);
507
508 /* allocate return set */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200509 ret = ly_set_new(set);
510 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200511
512 /* transform into ly_set */
513 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
Michal Vasko26512682021-01-11 11:35:40 +0100514 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200515 (*set)->size = xp_set.used;
516
517 for (i = 0; i < xp_set.used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100518 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 +0200519 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200520 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200521 }
522 }
523
524cleanup:
525 lyxp_set_free_content(&xp_set);
Michal Vasko26512682021-01-11 11:35:40 +0100526 lyxp_expr_free(ctx, exp);
Michal Vaskoae159662020-10-21 11:57:24 +0200527 if (ret) {
Michal Vasko40308e72020-10-20 16:38:40 +0200528 ly_set_free(*set, NULL);
529 *set = NULL;
530 }
Michal Vasko072de482020-08-05 13:27:21 +0200531 return ret;
532}
533
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100534LIBYANG_API_DEF LY_ERR
Radek Krejcibc5644c2020-10-27 14:53:17 +0100535lys_find_lypath_atoms(const struct ly_path *path, struct ly_set **set)
536{
537 LY_ERR ret = LY_SUCCESS;
538 LY_ARRAY_COUNT_TYPE u, v;
539
540 LY_CHECK_ARG_RET(NULL, path, set, LY_EINVAL);
541
542 /* allocate return set */
543 LY_CHECK_RET(ly_set_new(set));
544
545 LY_ARRAY_FOR(path, u) {
546 /* add nodes from the path */
547 LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].node, 0, NULL), cleanup);
548 if (path[u].pred_type == LY_PATH_PREDTYPE_LIST) {
549 LY_ARRAY_FOR(path[u].predicates, v) {
550 /* add all the keys in a predicate */
551 LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].predicates[v].key, 0, NULL), cleanup);
552 }
553 }
554 }
555
556cleanup:
557 if (ret) {
558 ly_set_free(*set, NULL);
559 *set = NULL;
560 }
561 return ret;
562}
563
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100564LIBYANG_API_DEF LY_ERR
Radek Krejcibc5644c2020-10-27 14:53:17 +0100565lys_find_path_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *path, ly_bool output,
566 struct ly_set **set)
567{
568 LY_ERR ret = LY_SUCCESS;
569 uint8_t oper;
570 struct lyxp_expr *expr = NULL;
571 struct ly_path *p = NULL;
572
573 LY_CHECK_ARG_RET(ctx, ctx || ctx_node, path, set, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100574 LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100575
576 if (!ctx) {
577 ctx = ctx_node->module->ctx;
578 }
579
580 /* parse */
581 ret = lyxp_expr_parse(ctx, path, strlen(path), 0, &expr);
582 LY_CHECK_GOTO(ret, cleanup);
583
584 /* compile */
585 oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
Michal Vasko0884d212021-10-14 09:21:46 +0200586 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 +0100587 LY_CHECK_GOTO(ret, cleanup);
588
589 /* resolve */
590 ret = lys_find_lypath_atoms(p, set);
591
592cleanup:
593 ly_path_free(ctx, p);
594 lyxp_expr_free(ctx, expr);
595 return ret;
596}
597
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100598LIBYANG_API_DEF const struct lysc_node *
Radek Krejcibc5644c2020-10-27 14:53:17 +0100599lys_find_path(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *path, ly_bool output)
600{
601 const struct lysc_node *snode = NULL;
602 struct lyxp_expr *exp = NULL;
603 struct ly_path *p = NULL;
604 LY_ERR ret;
605 uint8_t oper;
606
607 LY_CHECK_ARG_RET(ctx, ctx || ctx_node, NULL);
Michal Vasko892f5bf2021-11-24 10:41:05 +0100608 LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, NULL);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100609
610 if (!ctx) {
611 ctx = ctx_node->module->ctx;
612 }
613
614 /* parse */
615 ret = lyxp_expr_parse(ctx, path, strlen(path), 0, &exp);
616 LY_CHECK_GOTO(ret, cleanup);
617
618 /* compile */
619 oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
Michal Vasko0884d212021-10-14 09:21:46 +0200620 ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, oper, LY_PATH_TARGET_MANY, 0, LY_VALUE_JSON, NULL, &p);
Radek Krejcibc5644c2020-10-27 14:53:17 +0100621 LY_CHECK_GOTO(ret, cleanup);
622
623 /* get last node */
624 snode = p[LY_ARRAY_COUNT(p) - 1].node;
625
626cleanup:
627 ly_path_free(ctx, p);
628 lyxp_expr_free(ctx, exp);
629 return snode;
630}
631
Michal Vasko14654712020-02-06 08:35:21 +0100632char *
633lysc_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 +0200634 size_t buflen)
Radek Krejci327de162019-06-14 12:52:07 +0200635{
Michal Vaskobde22b62022-03-22 15:32:56 +0100636 const struct lysc_node *iter, *par, *key;
Radek Krejci327de162019-06-14 12:52:07 +0200637 char *path = NULL;
638 int len = 0;
Michal Vaskobde22b62022-03-22 15:32:56 +0100639 ly_bool skip_schema;
Radek Krejci327de162019-06-14 12:52:07 +0200640
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200641 if (buffer) {
642 LY_CHECK_ARG_RET(node->module->ctx, buflen > 1, NULL);
Michal Vasko770d3fc2021-01-26 09:14:35 +0100643 buffer[0] = '\0';
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200644 }
645
Michal Vaskobde22b62022-03-22 15:32:56 +0100646 if ((pathtype == LYSC_PATH_DATA) || (pathtype == LYSC_PATH_DATA_PATTERN)) {
647 /* skip schema-only nodes */
648 skip_schema = 1;
649 } else {
650 skip_schema = 0;
651 }
Radek Krejci327de162019-06-14 12:52:07 +0200652
Michal Vaskobde22b62022-03-22 15:32:56 +0100653 for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
654 char *s;
655 const char *slash;
Michal Vasko65de0402020-08-03 16:34:19 +0200656
Michal Vaskobde22b62022-03-22 15:32:56 +0100657 if (skip_schema && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT))) {
658 /* schema-only node */
659 continue;
660 }
Michal Vasko87dd1342021-08-23 16:17:55 +0200661
Michal Vaskobde22b62022-03-22 15:32:56 +0100662 if ((pathtype == LYSC_PATH_DATA_PATTERN) && (iter->nodetype == LYS_LIST)) {
663 key = NULL;
664 while ((key = lys_getnext(key, iter, NULL, 0)) && lysc_is_key(key)) {
665 s = buffer ? strdup(buffer) : path;
Michal Vasko87dd1342021-08-23 16:17:55 +0200666
Michal Vaskobde22b62022-03-22 15:32:56 +0100667 /* print key predicate */
Radek Krejci1c0c3442019-07-23 16:08:47 +0200668 if (buffer) {
Michal Vaskobde22b62022-03-22 15:32:56 +0100669 len = snprintf(buffer, buflen, "[%s='%%s']%s", key->name, s ? s : "");
Radek Krejci1c0c3442019-07-23 16:08:47 +0200670 } else {
Michal Vaskobde22b62022-03-22 15:32:56 +0100671 len = asprintf(&path, "[%s='%%s']%s", key->name, s ? s : "");
Radek Krejci1c0c3442019-07-23 16:08:47 +0200672 }
Michal Vaskobde22b62022-03-22 15:32:56 +0100673 free(s);
Michal Vasko28d03812022-03-24 15:26:11 +0100674
675 if (buffer && (buflen <= (size_t)len)) {
676 /* not enough space in buffer */
677 break;
678 }
Radek Krejci1c0c3442019-07-23 16:08:47 +0200679 }
Radek Krejci327de162019-06-14 12:52:07 +0200680 }
681
Michal Vaskobde22b62022-03-22 15:32:56 +0100682 s = buffer ? strdup(buffer) : path;
683 if (parent && (iter->parent == parent)) {
684 slash = "";
685 } else {
686 slash = "/";
687 }
688
689 if (skip_schema) {
690 par = lysc_data_parent(iter);
691 } else {
692 par = iter->parent;
693 }
694
695 if (!par || (par->module != iter->module)) {
696 /* print prefix */
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200697 if (buffer) {
Michal Vaskobde22b62022-03-22 15:32:56 +0100698 len = snprintf(buffer, buflen, "%s%s:%s%s", slash, iter->module->name, iter->name, s ? s : "");
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200699 } else {
Michal Vaskobde22b62022-03-22 15:32:56 +0100700 len = asprintf(&path, "%s%s:%s%s", slash, iter->module->name, iter->name, s ? s : "");
701 }
702 } else {
703 /* prefix is the same as in parent */
704 if (buffer) {
705 len = snprintf(buffer, buflen, "%s%s%s", slash, iter->name, s ? s : "");
706 } else {
707 len = asprintf(&path, "%s%s%s", slash, iter->name, s ? s : "");
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200708 }
Radek Krejci327de162019-06-14 12:52:07 +0200709 }
Michal Vaskobde22b62022-03-22 15:32:56 +0100710 free(s);
711
712 if (buffer && (buflen <= (size_t)len)) {
713 /* not enough space in buffer */
714 break;
715 }
716 }
717
718 if (len < 0) {
719 free(path);
720 path = NULL;
721 } else if (len == 0) {
722 if (buffer) {
723 strcpy(buffer, "/");
724 } else {
725 path = strdup("/");
726 }
Radek Krejci327de162019-06-14 12:52:07 +0200727 }
728
Radek Krejci1c0c3442019-07-23 16:08:47 +0200729 if (buffer) {
730 return buffer;
731 } else {
732 return path;
733 }
Radek Krejci327de162019-06-14 12:52:07 +0200734}
735
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100736LIBYANG_API_DEF char *
Michal Vasko14654712020-02-06 08:35:21 +0100737lysc_path(const struct lysc_node *node, LYSC_PATH_TYPE pathtype, char *buffer, size_t buflen)
738{
739 return lysc_path_until(node, NULL, pathtype, buffer, buflen);
740}
741
Michal Vasko405cc9e2020-12-01 12:01:27 +0100742LY_ERR
Michal Vasko65333882021-06-10 14:12:16 +0200743_lys_set_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
Michal Vasko405cc9e2020-12-01 12:01:27 +0100744{
745 LY_ERR ret = LY_SUCCESS, r;
aPiecek6b3d5422021-07-30 15:55:43 +0200746 struct lys_module *mod_iter;
Michal Vaskoc56d6372021-10-19 12:29:00 +0200747 const char **imp_f, *all_f[] = {"*", NULL};
Michal Vasko65333882021-06-10 14:12:16 +0200748 uint32_t i;
Michal Vasko916aefb2020-11-02 15:43:16 +0100749
Michal Vasko405cc9e2020-12-01 12:01:27 +0100750 if (mod->implemented) {
751 /* mod is already implemented, set the features */
752 r = lys_set_features(mod->parsed, features);
753 if (r == LY_EEXIST) {
754 /* no changes */
755 return LY_SUCCESS;
Michal Vasko7213ac52021-06-15 11:52:13 +0200756 } else if (!r) {
757 /* mark the module as changed */
Michal Vasko01db7de2021-04-16 12:23:30 +0200758 mod->to_compile = 1;
Michal Vasko01db7de2021-04-16 12:23:30 +0200759 }
Michal Vasko7213ac52021-06-15 11:52:13 +0200760
761 return r;
Michal Vasko89b5c072020-10-06 13:52:44 +0200762 }
Michal Vasko08c8b272020-11-24 18:11:30 +0100763
Michal Vasko7213ac52021-06-15 11:52:13 +0200764 /* implement, ignore recompilation because it must always take place later */
765 r = lys_implement(mod, features, unres);
766 LY_CHECK_ERR_GOTO(r && (r != LY_ERECOMPILE), ret = r, cleanup);
Michal Vasko65333882021-06-10 14:12:16 +0200767
768 if (mod->ctx->flags & LY_CTX_ALL_IMPLEMENTED) {
769 /* implement all the imports as well */
770 for (i = 0; i < unres->creating.count; ++i) {
771 mod = unres->creating.objs[i];
772 if (mod->implemented) {
773 continue;
774 }
775
Michal Vaskoc56d6372021-10-19 12:29:00 +0200776 imp_f = (mod->ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
777 r = lys_implement(mod, imp_f, unres);
Michal Vasko7213ac52021-06-15 11:52:13 +0200778 LY_CHECK_ERR_GOTO(r && (r != LY_ERECOMPILE), ret = r, cleanup);
Michal Vasko65333882021-06-10 14:12:16 +0200779 }
780 }
781
aPiecek6b3d5422021-07-30 15:55:43 +0200782 /* Try to find module with LYS_MOD_IMPORTED_REV flag. */
783 i = 0;
784 while ((mod_iter = ly_ctx_get_module_iter(mod->ctx, &i))) {
Michal Vaskoe8b085b2021-09-02 08:20:08 +0200785 if (!strcmp(mod_iter->name, mod->name) && (mod_iter != mod) && (mod_iter->latest_revision & LYS_MOD_IMPORTED_REV)) {
786 LOGVRB("Implemented module \"%s@%s\" was not and will not be imported if the revision-date is missing"
787 " in the import statement. Instead, the revision \"%s\" is imported.", mod->name, mod->revision,
788 mod_iter->revision);
aPiecek6b3d5422021-07-30 15:55:43 +0200789 break;
790 }
791 }
792
Michal Vasko65333882021-06-10 14:12:16 +0200793cleanup:
794 return ret;
795}
796
Michal Vaskof4258e12021-06-15 12:11:42 +0200797/**
Michal Vasko7ee5be22021-06-16 17:03:34 +0200798 * @brief Check whether it may be needed to (re)compile a module from a particular dependency set
799 * and if so, add it into its dep set.
800 *
801 * Dependency set includes all modules that need to be (re)compiled in case any of the module(s)
802 * in the dep set are (re)compiled.
803 *
804 * The reason for recompilation is possible disabled nodes and updating
805 * leafref targets to point to the newly compiled modules. Using the import relation, the
806 * dependency is reflexive because of possible foreign augments and deviations, which are compiled
807 * during the target module compilation.
808 *
809 * - every module must belong to exactly one dep set
810 * - implement flag must be ignored because it can be changed during dep set compilation
Michal Vaskof4258e12021-06-15 12:11:42 +0200811 *
812 * @param[in] mod Module to process.
813 * @param[in,out] ctx_set Set with all not-yet-processed modules.
814 * @param[in,out] dep_set Current dependency set to update.
Michal Vasko775fbd02021-07-28 08:25:29 +0200815 * @param[in] aux_set Set of traversed non-compiled modules, should be empty on first call.
Michal Vaskof4258e12021-06-15 12:11:42 +0200816 * @return LY_ERR value.
817 */
818static LY_ERR
Michal Vasko775fbd02021-07-28 08:25:29 +0200819lys_unres_dep_sets_create_mod_r(struct lys_module *mod, struct ly_set *ctx_set, struct ly_set *dep_set,
820 struct ly_set *aux_set)
Michal Vaskof4258e12021-06-15 12:11:42 +0200821{
822 struct lys_module *mod2;
823 struct lysp_import *imports;
824 uint32_t i;
825 LY_ARRAY_COUNT_TYPE u, v;
826 ly_bool found;
827
Michal Vasko0bccbf12021-11-22 09:59:57 +0100828 if (LYS_IS_SINGLE_DEP_SET(mod)) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200829 /* is already in a separate dep set */
Michal Vasko87cfdba2022-02-22 14:13:45 +0100830 if (!lys_has_dep_mods(mod)) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200831 /* break the dep set here, no modules depend on this one */
Michal Vasko7ee5be22021-06-16 17:03:34 +0200832 return LY_SUCCESS;
833 }
Michal Vasko775fbd02021-07-28 08:25:29 +0200834
835 if (ly_set_contains(aux_set, mod, NULL)) {
836 /* it was traversed */
837 return LY_SUCCESS;
838 }
839
840 /* add a new auxiliary module */
841 LY_CHECK_RET(ly_set_add(aux_set, mod, 1, NULL));
Michal Vasko7ee5be22021-06-16 17:03:34 +0200842 } else {
Michal Vasko709f9a52021-07-21 10:51:59 +0200843 if (!ly_set_contains(ctx_set, mod, &i)) {
844 /* it was already processed */
845 return LY_SUCCESS;
846 }
847
848 /* remove it from the set, we are processing it now */
849 ly_set_rm_index(ctx_set, i, NULL);
850
Michal Vasko7ee5be22021-06-16 17:03:34 +0200851 /* add a new dependent module into the dep set */
852 LY_CHECK_RET(ly_set_add(dep_set, mod, 1, NULL));
Michal Vaskof4258e12021-06-15 12:11:42 +0200853 }
854
855 /* process imports of the module and submodules */
856 imports = mod->parsed->imports;
857 LY_ARRAY_FOR(imports, u) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200858 mod2 = imports[u].module;
Michal Vasko775fbd02021-07-28 08:25:29 +0200859 LY_CHECK_RET(lys_unres_dep_sets_create_mod_r(mod2, ctx_set, dep_set, aux_set));
Michal Vaskof4258e12021-06-15 12:11:42 +0200860 }
861 LY_ARRAY_FOR(mod->parsed->includes, v) {
862 imports = mod->parsed->includes[v].submodule->imports;
863 LY_ARRAY_FOR(imports, u) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200864 mod2 = imports[u].module;
Michal Vasko87cfdba2022-02-22 14:13:45 +0100865 if (LYS_IS_SINGLE_DEP_SET(mod2) && !lys_has_dep_mods(mod2)) {
866 /* break the dep set here, no modules depend on this one */
867 continue;
Michal Vasko709f9a52021-07-21 10:51:59 +0200868 }
869
Michal Vasko775fbd02021-07-28 08:25:29 +0200870 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 +0200871 }
872 }
873
874 /* process modules and submodules importing this module */
Michal Vasko7ee5be22021-06-16 17:03:34 +0200875 for (i = 0; i < mod->ctx->list.count; ++i) {
876 mod2 = mod->ctx->list.objs[i];
Michal Vaskof4258e12021-06-15 12:11:42 +0200877 found = 0;
878
879 imports = mod2->parsed->imports;
880 LY_ARRAY_FOR(imports, u) {
881 if (imports[u].module == mod) {
882 found = 1;
883 break;
884 }
885 }
886
887 if (!found) {
888 LY_ARRAY_FOR(mod2->parsed->includes, v) {
889 imports = mod2->parsed->includes[v].submodule->imports;
890 LY_ARRAY_FOR(imports, u) {
891 if (imports[u].module == mod) {
892 found = 1;
893 break;
894 }
895 }
896
897 if (found) {
898 break;
899 }
900 }
901 }
902
903 if (found) {
Michal Vasko775fbd02021-07-28 08:25:29 +0200904 LY_CHECK_RET(lys_unres_dep_sets_create_mod_r(mod2, ctx_set, dep_set, aux_set));
Michal Vaskof4258e12021-06-15 12:11:42 +0200905 }
906 }
907
908 return LY_SUCCESS;
909}
910
Michal Vasko709f9a52021-07-21 10:51:59 +0200911/**
912 * @brief Add all simple modules (that have nothing to (re)compile) into separate dep sets.
913 *
914 * @param[in,out] ctx_set Set with all not-yet-processed modules.
915 * @param[in,out] main_set Set of dependency module sets.
916 * @return LY_ERR value.
917 */
918static LY_ERR
919lys_unres_dep_sets_create_single(struct ly_set *ctx_set, struct ly_set *main_set)
920{
921 LY_ERR ret = LY_SUCCESS;
922 struct lys_module *m;
923 uint32_t i = 0;
924 struct ly_set *dep_set = NULL;
925
926 while (i < ctx_set->count) {
927 m = ctx_set->objs[i];
Michal Vasko0bccbf12021-11-22 09:59:57 +0100928 if (LYS_IS_SINGLE_DEP_SET(m)) {
Michal Vasko709f9a52021-07-21 10:51:59 +0200929 /* remove it from the set, we are processing it now */
930 ly_set_rm_index(ctx_set, i, NULL);
931
932 /* this module can be in a separate dep set (but there still may be modules importing this one
933 * that depend on imports of this one in case it defines groupings) */
934 LY_CHECK_GOTO(ret = ly_set_new(&dep_set), cleanup);
935 LY_CHECK_GOTO(ret = ly_set_add(dep_set, m, 1, NULL), cleanup);
936 LY_CHECK_GOTO(ret = ly_set_add(main_set, dep_set, 1, NULL), cleanup);
937 dep_set = NULL;
938 } else {
939 ++i;
940 }
941 }
942
943cleanup:
944 ly_set_free(dep_set, NULL);
945 return ret;
946}
947
Michal Vaskof4258e12021-06-15 12:11:42 +0200948LY_ERR
Michal Vasko50bc09a2021-06-17 17:31:56 +0200949lys_unres_dep_sets_create(struct ly_ctx *ctx, struct ly_set *main_set, struct lys_module *mod)
Michal Vaskof4258e12021-06-15 12:11:42 +0200950{
951 LY_ERR ret = LY_SUCCESS;
952 struct lys_module *m;
Michal Vasko775fbd02021-07-28 08:25:29 +0200953 struct ly_set *dep_set = NULL, *ctx_set = NULL, aux_set = {0};
Michal Vaskof4258e12021-06-15 12:11:42 +0200954 uint32_t i;
Michal Vasko7ee5be22021-06-16 17:03:34 +0200955 ly_bool found;
Michal Vaskof4258e12021-06-15 12:11:42 +0200956
Michal Vasko22b26222021-07-30 11:16:47 +0200957 assert(!main_set->count);
958
Michal Vaskof4258e12021-06-15 12:11:42 +0200959 /* start with a duplicate set of modules that we will remove from */
960 LY_CHECK_GOTO(ret = ly_set_dup(&ctx->list, NULL, &ctx_set), cleanup);
961
Michal Vasko709f9a52021-07-21 10:51:59 +0200962 /* first create all dep sets with single modules */
963 LY_CHECK_GOTO(ret = lys_unres_dep_sets_create_single(ctx_set, main_set), cleanup);
964
965 if (mod && !ly_set_contains(ctx_set, mod, NULL)) {
966 /* dep set for this module has already been created, nothing else to do */
967 goto cleanup;
968 }
969
Michal Vaskof4258e12021-06-15 12:11:42 +0200970 while (ctx_set->count) {
971 /* create new dep set */
972 LY_CHECK_GOTO(ret = ly_set_new(&dep_set), cleanup);
973
974 if (mod) {
975 /* use the module create a dep set with the rest of its dependent modules */
Michal Vasko775fbd02021-07-28 08:25:29 +0200976 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 +0200977 } else {
978 /* use first ctx mod to create a dep set with the rest of its dependent modules */
Michal Vasko775fbd02021-07-28 08:25:29 +0200979 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 +0200980 }
Michal Vasko775fbd02021-07-28 08:25:29 +0200981 ly_set_erase(&aux_set, NULL);
Michal Vasko7ee5be22021-06-16 17:03:34 +0200982 assert(dep_set->count);
Michal Vaskof4258e12021-06-15 12:11:42 +0200983
984 /* check whether there is any module that will be (re)compiled */
Michal Vasko7ee5be22021-06-16 17:03:34 +0200985 found = 0;
Michal Vaskof4258e12021-06-15 12:11:42 +0200986 for (i = 0; i < dep_set->count; ++i) {
987 m = dep_set->objs[i];
988 if (m->to_compile) {
Michal Vasko7ee5be22021-06-16 17:03:34 +0200989 found = 1;
Michal Vaskof4258e12021-06-15 12:11:42 +0200990 break;
991 }
992 }
993
Michal Vasko7ee5be22021-06-16 17:03:34 +0200994 if (found) {
Michal Vaskof4258e12021-06-15 12:11:42 +0200995 /* if there is, all the implemented modules need to be recompiled */
996 for (i = 0; i < dep_set->count; ++i) {
997 m = dep_set->objs[i];
998 if (m->implemented) {
999 m->to_compile = 1;
1000 }
1001 }
1002 }
1003
Michal Vasko7ee5be22021-06-16 17:03:34 +02001004 /* add the dep set into main set */
1005 LY_CHECK_GOTO(ret = ly_set_add(main_set, dep_set, 1, NULL), cleanup);
Michal Vaskof4258e12021-06-15 12:11:42 +02001006 dep_set = NULL;
1007
1008 if (mod) {
1009 /* we need dep set only for this module */
1010 break;
1011 }
1012 }
1013
Michal Vaskoe558f792021-07-28 08:20:15 +02001014#ifndef NDEBUG
1015 LOGDBG(LY_LDGDEPSETS, "dep sets created (%" PRIu32 "):", main_set->count);
1016 for (i = 0; i < main_set->count; ++i) {
1017 struct ly_set *iter_set = main_set->objs[i];
1018
1019 LOGDBG(LY_LDGDEPSETS, "dep set #%" PRIu32 ":", i);
1020 for (uint32_t j = 0; j < iter_set->count; ++j) {
1021 m = iter_set->objs[j];
1022 LOGDBG(LY_LDGDEPSETS, "\t%s", m->name);
1023 }
1024 }
1025#endif
1026
Michal Vaskof4258e12021-06-15 12:11:42 +02001027cleanup:
Michal Vaskobd65c2e2021-06-16 11:49:45 +02001028 assert(ret || main_set->objs);
Michal Vasko775fbd02021-07-28 08:25:29 +02001029 ly_set_erase(&aux_set, NULL);
Michal Vaskof4258e12021-06-15 12:11:42 +02001030 ly_set_free(dep_set, NULL);
1031 ly_set_free(ctx_set, NULL);
1032 return ret;
1033}
1034
1035void
1036lys_unres_glob_revert(struct ly_ctx *ctx, struct lys_glob_unres *unres)
1037{
Michal Vaskod4a6d042022-12-08 08:34:29 +01001038 uint32_t i, j, idx, temp_lo = 0;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001039 struct lysf_ctx fctx = {.ctx = ctx};
Michal Vaskof4258e12021-06-15 12:11:42 +02001040 struct ly_set *dep_set;
Michal Vaskof4258e12021-06-15 12:11:42 +02001041 LY_ERR ret;
1042
1043 for (i = 0; i < unres->implementing.count; ++i) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001044 fctx.mod = unres->implementing.objs[i];
1045 assert(fctx.mod->implemented);
Michal Vaskof4258e12021-06-15 12:11:42 +02001046
1047 /* make the module correctly non-implemented again */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001048 fctx.mod->implemented = 0;
1049 lys_precompile_augments_deviations_revert(ctx, fctx.mod);
1050 lysc_module_free(&fctx, fctx.mod->compiled);
1051 fctx.mod->compiled = NULL;
Michal Vaskof4258e12021-06-15 12:11:42 +02001052
1053 /* should not be made implemented */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001054 fctx.mod->to_compile = 0;
Michal Vaskof4258e12021-06-15 12:11:42 +02001055 }
1056
1057 for (i = 0; i < unres->creating.count; ++i) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001058 fctx.mod = unres->creating.objs[i];
Michal Vaskof4258e12021-06-15 12:11:42 +02001059
Michal Vaskod297f2a2021-06-16 11:51:28 +02001060 /* remove the module from the context */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001061 ly_set_rm(&ctx->list, fctx.mod, NULL);
Michal Vaskof4258e12021-06-15 12:11:42 +02001062
Michal Vasko22b26222021-07-30 11:16:47 +02001063 /* remove it also from dep sets */
Michal Vasko7ee5be22021-06-16 17:03:34 +02001064 for (j = 0; j < unres->dep_sets.count; ++j) {
1065 dep_set = unres->dep_sets.objs[j];
Michal Vaskoc636ea42022-09-16 10:20:31 +02001066 if (ly_set_contains(dep_set, fctx.mod, &idx)) {
Michal Vasko7ee5be22021-06-16 17:03:34 +02001067 ly_set_rm_index(dep_set, idx, NULL);
1068 break;
Michal Vaskof4258e12021-06-15 12:11:42 +02001069 }
Michal Vaskof4258e12021-06-15 12:11:42 +02001070 }
Michal Vaskod297f2a2021-06-16 11:51:28 +02001071
1072 /* free the module */
Michal Vaskoc636ea42022-09-16 10:20:31 +02001073 lys_module_free(&fctx, fctx.mod, 1);
Michal Vaskof4258e12021-06-15 12:11:42 +02001074 }
1075
Michal Vaskoc636ea42022-09-16 10:20:31 +02001076 /* remove the extensions as well */
1077 lysf_ctx_erase(&fctx);
1078
Michal Vaskof4258e12021-06-15 12:11:42 +02001079 if (unres->implementing.count) {
1080 /* recompile previous context because some implemented modules are no longer implemented,
1081 * we can reuse the current to_compile flags */
Michal Vaskod4a6d042022-12-08 08:34:29 +01001082 ly_temp_log_options(&temp_lo);
Michal Vasko22b26222021-07-30 11:16:47 +02001083 ret = lys_compile_depset_all(ctx, &ctx->unres);
Michal Vaskod4a6d042022-12-08 08:34:29 +01001084 ly_temp_log_options(NULL);
Michal Vaskof4258e12021-06-15 12:11:42 +02001085 if (ret) {
1086 LOGINT(ctx);
1087 }
1088 }
1089}
1090
1091void
1092lys_unres_glob_erase(struct lys_glob_unres *unres)
1093{
1094 uint32_t i;
1095
1096 for (i = 0; i < unres->dep_sets.count; ++i) {
1097 ly_set_free(unres->dep_sets.objs[i], NULL);
1098 }
1099 ly_set_erase(&unres->dep_sets, NULL);
1100 ly_set_erase(&unres->implementing, NULL);
1101 ly_set_erase(&unres->creating, NULL);
1102
Michal Vaskoc130e162021-10-19 11:30:00 +02001103 assert(!unres->ds_unres.whens.count);
1104 assert(!unres->ds_unres.musts.count);
Michal Vaskof4258e12021-06-15 12:11:42 +02001105 assert(!unres->ds_unres.leafrefs.count);
aPiecekc6526b42021-07-12 15:21:39 +02001106 assert(!unres->ds_unres.disabled_leafrefs.count);
Michal Vaskof4258e12021-06-15 12:11:42 +02001107 assert(!unres->ds_unres.dflts.count);
1108 assert(!unres->ds_unres.disabled.count);
1109}
1110
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001111LIBYANG_API_DEF LY_ERR
Michal Vasko65333882021-06-10 14:12:16 +02001112lys_set_implemented(struct lys_module *mod, const char **features)
1113{
1114 LY_ERR ret = LY_SUCCESS;
Michal Vasko22b26222021-07-30 11:16:47 +02001115 struct lys_glob_unres *unres = &mod->ctx->unres;
Michal Vasko65333882021-06-10 14:12:16 +02001116
1117 LY_CHECK_ARG_RET(NULL, mod, LY_EINVAL);
1118
1119 /* implement */
Michal Vasko22b26222021-07-30 11:16:47 +02001120 ret = _lys_set_implemented(mod, features, unres);
Michal Vasko65333882021-06-10 14:12:16 +02001121 LY_CHECK_GOTO(ret, cleanup);
1122
Michal Vaskof4258e12021-06-15 12:11:42 +02001123 if (!(mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE)) {
1124 /* create dep set for the module and mark all the modules that will be (re)compiled */
Michal Vasko22b26222021-07-30 11:16:47 +02001125 LY_CHECK_GOTO(ret = lys_unres_dep_sets_create(mod->ctx, &unres->dep_sets, mod), cleanup);
Michal Vaskof4258e12021-06-15 12:11:42 +02001126
Michal Vasko709f9a52021-07-21 10:51:59 +02001127 /* (re)compile the whole dep set (other dep sets will have no modules marked for compilation) */
Michal Vasko22b26222021-07-30 11:16:47 +02001128 LY_CHECK_GOTO(ret = lys_compile_depset_all(mod->ctx, unres), cleanup);
1129
1130 /* unres resolved */
1131 lys_unres_glob_erase(unres);
Michal Vaskof4258e12021-06-15 12:11:42 +02001132 }
1133
Michal Vasko65333882021-06-10 14:12:16 +02001134cleanup:
Michal Vasko405cc9e2020-12-01 12:01:27 +01001135 if (ret) {
Michal Vasko22b26222021-07-30 11:16:47 +02001136 lys_unres_glob_revert(mod->ctx, unres);
1137 lys_unres_glob_erase(unres);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001138 }
Michal Vasko89b5c072020-10-06 13:52:44 +02001139 return ret;
Radek Krejci77a8bcd2019-09-11 11:20:02 +02001140}
1141
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001142/**
1143 * @brief Resolve (find) all imported and included modules.
1144 *
1145 * @param[in] pctx Parser context.
1146 * @param[in] pmod Parsed module to resolve.
1147 * @param[out] new_mods Set with all the newly loaded modules.
1148 * @return LY_ERR value.
1149 */
Michal Vasko7c8439f2020-08-05 13:25:19 +02001150static LY_ERR
Michal Vaskod0625d72022-10-06 15:02:50 +02001151lysp_resolve_import_include(struct lysp_ctx *pctx, struct lysp_module *pmod, struct ly_set *new_mods)
Michal Vasko7c8439f2020-08-05 13:25:19 +02001152{
1153 struct lysp_import *imp;
Michal Vasko7c8439f2020-08-05 13:25:19 +02001154 LY_ARRAY_COUNT_TYPE u, v;
1155
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001156 pmod->parsing = 1;
1157 LY_ARRAY_FOR(pmod->imports, u) {
1158 imp = &pmod->imports[u];
Michal Vasko7c8439f2020-08-05 13:25:19 +02001159 if (!imp->module) {
aPiecekc3e26142021-06-22 14:25:49 +02001160 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 +02001161
1162 if (!imp->rev[0]) {
1163 /* This module must be selected for the next similar
1164 * import without revision-date to avoid incorrect
1165 * derived identities in the ::lys_module.identities.
1166 */
1167 imp->module->latest_revision |= LYS_MOD_IMPORTED_REV;
1168 }
Michal Vasko7c8439f2020-08-05 13:25:19 +02001169 }
1170 /* check for importing the same module twice */
1171 for (v = 0; v < u; ++v) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001172 if (imp->module == pmod->imports[v].module) {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001173 LOGWRN(PARSER_CTX(pctx), "Single revision of the module \"%s\" imported twice.", imp->name);
1174 }
1175 }
1176 }
aPiecekc3e26142021-06-22 14:25:49 +02001177 LY_CHECK_RET(lysp_load_submodules(pctx, pmod, new_mods));
Radek Krejci771928a2021-01-19 13:42:36 +01001178
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001179 pmod->parsing = 0;
Michal Vasko7c8439f2020-08-05 13:25:19 +02001180
1181 return LY_SUCCESS;
1182}
1183
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001184/**
Michal Vasko193dacd2022-10-13 08:43:05 +02001185 * @brief Generate path of the given paresed node.
1186 *
1187 * @param[in] node Schema path of this node will be generated.
1188 * @param[in] parent Build relative path only until this parent is found. If NULL, the full absolute path is printed.
1189 * @return NULL in case of memory allocation error, path of the node otherwise.
1190 * In case the @p buffer is NULL, the returned string is dynamically allocated and caller is responsible to free it.
1191 */
1192static char *
1193lysp_path_until(const struct lysp_node *node, const struct lysp_node *parent, const struct lysp_module *pmod)
1194{
1195 const struct lysp_node *iter, *par;
1196 char *path = NULL, *s;
1197 const char *slash;
1198 int len = 0;
1199
1200 for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
1201 if (parent && (iter->parent == parent)) {
1202 slash = "";
1203 } else {
1204 slash = "/";
1205 }
1206
1207 s = path;
1208 par = iter->parent;
1209 if (!par) {
1210 /* print prefix */
1211 len = asprintf(&path, "%s%s:%s%s", slash, pmod->mod->name, iter->name, s ? s : "");
1212 } else {
1213 /* prefix is the same as in parent */
1214 len = asprintf(&path, "%s%s%s", slash, iter->name, s ? s : "");
1215 }
1216 free(s);
1217 }
1218
1219 if (len < 0) {
1220 free(path);
1221 path = NULL;
1222 } else if (len == 0) {
1223 path = strdup("/");
1224 }
1225
1226 return path;
1227}
1228
1229/**
1230 * @brief Build log path for a parsed extension instance.
1231 *
1232 * @param[in] pcxt Parse context.
1233 * @param[in] ext Parsed extension instance.
1234 * @param[out] path Generated path.
1235 * @return LY_ERR value.
1236 */
1237static LY_ERR
1238lysp_resolve_ext_instance_log_path(const struct lysp_ctx *pctx, const struct lysp_ext_instance *ext, char **path)
1239{
1240 char *buf = NULL;
1241 uint32_t used = 0, size = 0;
1242
1243 if (ext->parent_stmt & LY_STMT_NODE_MASK) {
1244 /* parsed node path */
1245 buf = lysp_path_until(ext->parent, NULL, PARSER_CUR_PMOD(pctx));
1246 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1247 size = used = strlen(buf);
1248
1249 /* slash */
1250 size += 1;
1251 buf = realloc(buf, size + 1);
1252 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1253 used += sprintf(buf + used, "/");
1254 } else {
1255 /* module */
1256 size += 1 + strlen(PARSER_CUR_PMOD(pctx)->mod->name) + 1;
1257 buf = realloc(buf, size + 1);
1258 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1259 used += sprintf(buf + used, "/%s:", PARSER_CUR_PMOD(pctx)->mod->name);
1260 }
1261
1262 /* extension name */
1263 size += 12 + strlen(ext->name) + 2;
1264 buf = realloc(buf, size + 1);
1265 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1266 used += sprintf(buf + used, "{extension='%s'}", ext->name);
1267
1268 /* extension argument */
1269 if (ext->argument) {
1270 size += 1 + strlen(ext->argument);
1271 buf = realloc(buf, size + 1);
1272 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(pctx)), LY_EMEM);
1273 used += sprintf(buf + used, "/%s", ext->argument);
1274 }
1275
1276 *path = buf;
1277 return LY_SUCCESS;
1278}
1279
1280/**
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001281 * @brief Resolve (find) all extension instance records and finish their parsing.
1282 *
1283 * @param[in] pctx Parse context with all the parsed extension instances.
1284 * @return LY_ERR value.
1285 */
1286static LY_ERR
Michal Vaskod0625d72022-10-06 15:02:50 +02001287lysp_resolve_ext_instance_records(struct lysp_ctx *pctx)
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001288{
Michal Vasko193dacd2022-10-13 08:43:05 +02001289 LY_ERR r;
1290 struct lysf_ctx fctx = {.ctx = PARSER_CTX(pctx)};
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001291 struct lysp_ext_instance *exts, *ext;
1292 const struct lys_module *mod;
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001293 uint32_t i;
1294 LY_ARRAY_COUNT_TYPE u;
Michal Vasko193dacd2022-10-13 08:43:05 +02001295 char *path = NULL;
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001296
Michal Vasko193dacd2022-10-13 08:43:05 +02001297 /* first finish parsing all extension instances ... */
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001298 for (i = 0; i < pctx->ext_inst.count; ++i) {
1299 exts = pctx->ext_inst.objs[i];
1300 LY_ARRAY_FOR(exts, u) {
1301 ext = &exts[u];
1302
Michal Vasko193dacd2022-10-13 08:43:05 +02001303 /* find the extension definition */
1304 LY_CHECK_RET(lysp_ext_find_definition(PARSER_CTX(pctx), ext, &mod, &ext->def));
1305
1306 /* resolve the argument, if needed */
1307 LY_CHECK_RET(lysp_ext_instance_resolve_argument(PARSER_CTX(pctx), ext));
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001308
1309 /* find the extension record, if any */
Michal Vasko193dacd2022-10-13 08:43:05 +02001310 ext->record = lyplg_ext_record_find(mod->name, mod->revision, ext->def->name);
1311 }
1312 }
1313
1314 /* ... then call the parse callback */
1315 for (i = 0; i < pctx->ext_inst.count; ++i) {
1316 exts = pctx->ext_inst.objs[i];
1317 u = 0;
1318 while (u < LY_ARRAY_COUNT(exts)) {
1319 ext = &exts[u];
1320 if (!ext->record || !ext->record->plugin.parse) {
1321 goto next_iter;
1322 }
1323
1324 /* set up log path */
1325 if ((r = lysp_resolve_ext_instance_log_path(pctx, ext, &path))) {
1326 return r;
1327 }
Michal Vaskof8ebf132022-11-21 14:06:48 +01001328 LOG_LOCSET(NULL, NULL, path, NULL);
Michal Vasko193dacd2022-10-13 08:43:05 +02001329
1330 /* parse */
1331 r = ext->record->plugin.parse(pctx, ext);
1332
1333 LOG_LOCBACK(0, 0, 1, 0);
1334 free(path);
1335
1336 if (r == LY_ENOT) {
1337 /* instance should be ignored, remove it */
1338 lysp_ext_instance_free(&fctx, ext);
1339 LY_ARRAY_DECREMENT(exts);
1340 if (u < LY_ARRAY_COUNT(exts)) {
1341 /* replace by the last item */
1342 *ext = exts[LY_ARRAY_COUNT(exts)];
1343 } /* else if there are no more items, leave the empty array, we are not able to free it */
1344 continue;
1345 } else if (r) {
1346 /* error */
1347 return r;
1348 }
1349
1350next_iter:
1351 ++u;
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001352 }
1353 }
1354
1355 return LY_SUCCESS;
1356}
1357
Michal Vasko3a41dff2020-07-15 14:30:28 +02001358LY_ERR
Michal Vaskod0625d72022-10-06 15:02:50 +02001359lys_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 +02001360 LY_ERR (*custom_check)(const struct ly_ctx *, struct lysp_module *, struct lysp_submodule *, void *),
aPiecekc3e26142021-06-22 14:25:49 +02001361 void *check_data, struct ly_set *new_mods, struct lysp_submodule **submodule)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001362{
Michal Vasko3a41dff2020-07-15 14:30:28 +02001363 LY_ERR ret;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001364 struct lysp_submodule *submod = NULL, *latest_sp;
Michal Vaskod0625d72022-10-06 15:02:50 +02001365 struct lysp_yang_ctx *yangctx = NULL;
1366 struct lysp_yin_ctx *yinctx = NULL;
1367 struct lysp_ctx *pctx;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001368 struct lysf_ctx fctx = {.ctx = ctx};
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001369
Michal Vasko3a41dff2020-07-15 14:30:28 +02001370 LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001371
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001372 switch (format) {
1373 case LYS_IN_YIN:
Michal Vasko63f3d842020-07-08 10:10:14 +02001374 ret = yin_parse_submodule(&yinctx, ctx, main_ctx, in, &submod);
Michal Vaskod0625d72022-10-06 15:02:50 +02001375 pctx = (struct lysp_ctx *)yinctx;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001376 break;
1377 case LYS_IN_YANG:
Michal Vasko63f3d842020-07-08 10:10:14 +02001378 ret = yang_parse_submodule(&yangctx, ctx, main_ctx, in, &submod);
Michal Vaskod0625d72022-10-06 15:02:50 +02001379 pctx = (struct lysp_ctx *)yangctx;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001380 break;
1381 default:
David Sedlák4f2f5ba2019-08-15 13:18:48 +02001382 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
Radek Krejci82fa8d42020-07-11 22:00:59 +02001383 ret = LY_EINVAL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001384 break;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001385 }
Radek Krejcif6923e82020-07-02 16:36:53 +02001386 LY_CHECK_GOTO(ret, error);
Radek Krejcif027df72020-09-15 13:00:28 +02001387 assert(submod);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001388
1389 /* make sure that the newest revision is at position 0 */
1390 lysp_sort_revisions(submod->revs);
1391
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001392 /* decide the latest revision */
Michal Vasko8dc31992021-02-22 10:30:47 +01001393 latest_sp = (struct lysp_submodule *)ly_ctx_get_submodule2_latest(submod->mod, submod->name);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001394 if (latest_sp) {
1395 if (submod->revs) {
1396 if (!latest_sp->revs) {
1397 /* latest has no revision, so mod is anyway newer */
1398 submod->latest_revision = latest_sp->latest_revision;
Radek Krejcib3289d62019-09-18 12:21:39 +02001399 /* the latest_sp is zeroed later when the new module is being inserted into the context */
1400 } else if (strcmp(submod->revs[0].date, latest_sp->revs[0].date) > 0) {
1401 submod->latest_revision = latest_sp->latest_revision;
1402 /* the latest_sp is zeroed later when the new module is being inserted into the context */
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001403 } else {
Radek Krejcib3289d62019-09-18 12:21:39 +02001404 latest_sp = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001405 }
Radek Krejcib3289d62019-09-18 12:21:39 +02001406 } else {
1407 latest_sp = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001408 }
1409 } else {
1410 submod->latest_revision = 1;
1411 }
1412
Radek Krejcib3289d62019-09-18 12:21:39 +02001413 if (custom_check) {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001414 LY_CHECK_GOTO(ret = custom_check(ctx, NULL, submod, check_data), error);
Radek Krejcib3289d62019-09-18 12:21:39 +02001415 }
1416
1417 if (latest_sp) {
1418 latest_sp->latest_revision = 0;
1419 }
1420
Michal Vasko7a0b0762020-09-02 16:37:01 +02001421 lys_parser_fill_filepath(ctx, in, &submod->filepath);
1422
Michal Vasko7c8439f2020-08-05 13:25:19 +02001423 /* resolve imports and includes */
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001424 LY_CHECK_GOTO(ret = lysp_resolve_import_include(pctx, (struct lysp_module *)submod, new_mods), error);
1425
David Sedlák1b623122019-08-05 15:27:49 +02001426 if (format == LYS_IN_YANG) {
Michal Vaskod0625d72022-10-06 15:02:50 +02001427 lysp_yang_ctx_free(yangctx);
David Sedlák1b623122019-08-05 15:27:49 +02001428 } else {
Michal Vaskod0625d72022-10-06 15:02:50 +02001429 lysp_yin_ctx_free(yinctx);
David Sedlák1b623122019-08-05 15:27:49 +02001430 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02001431 *submodule = submod;
1432 return LY_SUCCESS;
David Sedlák1b623122019-08-05 15:27:49 +02001433
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001434error:
Radek Krejcic64661b2020-08-15 15:42:26 +02001435 if (!submod || !submod->name) {
1436 LOGERR(ctx, ret, "Parsing submodule failed.");
1437 } else {
1438 LOGERR(ctx, ret, "Parsing submodule \"%s\" failed.", submod->name);
1439 }
Michal Vaskoc636ea42022-09-16 10:20:31 +02001440 lysp_module_free(&fctx, (struct lysp_module *)submod);
David Sedlák1b623122019-08-05 15:27:49 +02001441 if (format == LYS_IN_YANG) {
Michal Vaskod0625d72022-10-06 15:02:50 +02001442 lysp_yang_ctx_free(yangctx);
David Sedlák1b623122019-08-05 15:27:49 +02001443 } else {
Michal Vaskod0625d72022-10-06 15:02:50 +02001444 lysp_yin_ctx_free(yinctx);
David Sedlák1b623122019-08-05 15:27:49 +02001445 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02001446 return ret;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001447}
1448
Michal Vasko45b521c2020-11-04 17:14:39 +01001449/**
1450 * @brief Add ietf-netconf metadata to the parsed module. Operation, filter, and select are added.
1451 *
Michal Vasko193dacd2022-10-13 08:43:05 +02001452 * @param[in] pctx Parse context.
Michal Vasko45b521c2020-11-04 17:14:39 +01001453 * @param[in] mod Parsed module to add to.
1454 * @return LY_SUCCESS on success.
1455 * @return LY_ERR on error.
1456 */
1457static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +02001458lysp_add_internal_ietf_netconf(struct lysp_ctx *pctx, struct lysp_module *mod)
Michal Vasko45b521c2020-11-04 17:14:39 +01001459{
Michal Vasko193dacd2022-10-13 08:43:05 +02001460 struct lysp_ext_instance *extp;
Michal Vasko45b521c2020-11-04 17:14:39 +01001461 struct lysp_stmt *stmt;
1462 struct lysp_import *imp;
1463
1464 /*
1465 * 1) edit-config's operation
1466 */
Michal Vasko193dacd2022-10-13 08:43:05 +02001467 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
1468 LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
1469 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
1470 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "operation", 0, &extp->argument));
1471 extp->format = LY_VALUE_SCHEMA;
1472 extp->prefix_data = mod;
1473 extp->parent = mod;
1474 extp->parent_stmt = LY_STMT_MODULE;
1475 extp->flags = LYS_INTERNAL;
Michal Vasko45b521c2020-11-04 17:14:39 +01001476
Michal Vasko193dacd2022-10-13 08:43:05 +02001477 extp->child = stmt = calloc(1, sizeof *extp->child);
Michal Vasko45b521c2020-11-04 17:14:39 +01001478 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1479 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1480 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001481 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001482 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001483 stmt->kw = LY_STMT_TYPE;
1484
1485 stmt->child = calloc(1, sizeof *stmt->child);
1486 stmt = stmt->child;
1487 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1488 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1489 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "merge", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001490 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001491 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001492 stmt->kw = LY_STMT_ENUM;
1493
1494 stmt->next = calloc(1, sizeof *stmt->child);
1495 stmt = stmt->next;
1496 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1497 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1498 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "replace", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001499 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001500 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001501 stmt->kw = LY_STMT_ENUM;
1502
1503 stmt->next = calloc(1, sizeof *stmt->child);
1504 stmt = stmt->next;
1505 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1506 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1507 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "create", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001508 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001509 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001510 stmt->kw = LY_STMT_ENUM;
1511
1512 stmt->next = calloc(1, sizeof *stmt->child);
1513 stmt = stmt->next;
1514 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1515 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1516 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "delete", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001517 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001518 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001519 stmt->kw = LY_STMT_ENUM;
1520
1521 stmt->next = calloc(1, sizeof *stmt->child);
1522 stmt = stmt->next;
1523 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1524 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1525 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "remove", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001526 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001527 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001528 stmt->kw = LY_STMT_ENUM;
1529
1530 /*
1531 * 2) filter's type
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, "type", 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, "subtree", 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, "xpath", 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 /* if-feature for enum allowed only for YANG 1.1 modules */
1570 if (mod->version >= LYS_VERSION_1_1) {
1571 stmt->child = calloc(1, sizeof *stmt->child);
1572 stmt = stmt->child;
1573 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1574 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "if-feature", 0, &stmt->stmt));
1575 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001576 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001577 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001578 stmt->kw = LY_STMT_IF_FEATURE;
1579 }
1580
1581 /*
1582 * 3) filter's select
1583 */
Michal Vasko193dacd2022-10-13 08:43:05 +02001584 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
1585 LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
1586 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
1587 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "select", 0, &extp->argument));
1588 extp->format = LY_VALUE_SCHEMA;
1589 extp->prefix_data = mod;
1590 extp->parent = mod;
1591 extp->parent_stmt = LY_STMT_MODULE;
1592 extp->flags = LYS_INTERNAL;
Michal Vasko45b521c2020-11-04 17:14:39 +01001593
Michal Vasko193dacd2022-10-13 08:43:05 +02001594 extp->child = stmt = calloc(1, sizeof *extp->child);
Michal Vasko45b521c2020-11-04 17:14:39 +01001595 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1596 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1597 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_:xpath1.0", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001598 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001599 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001600 stmt->kw = LY_STMT_TYPE;
1601
Michal Vasko193dacd2022-10-13 08:43:05 +02001602 if (LY_ARRAY_COUNT(mod->exts) == 3) {
1603 /* first extension instances */
Michal Vaskoc8806c82022-12-06 10:31:24 +01001604 assert(pctx->main_ctx == pctx);
Michal Vasko193dacd2022-10-13 08:43:05 +02001605 LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
1606 }
1607
Michal Vasko45b521c2020-11-04 17:14:39 +01001608 /* create new imports for the used prefixes */
1609 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
Michal Vasko45b521c2020-11-04 17:14:39 +01001610 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
1611 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
1612 imp->flags = LYS_INTERNAL;
1613
1614 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
Michal Vasko45b521c2020-11-04 17:14:39 +01001615 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-types", 0, &imp->name));
1616 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_", 0, &imp->prefix));
1617 imp->flags = LYS_INTERNAL;
1618
1619 return LY_SUCCESS;
1620}
1621
1622/**
1623 * @brief Add ietf-netconf-with-defaults "default" metadata to the parsed module.
1624 *
Michal Vasko193dacd2022-10-13 08:43:05 +02001625 * @param[in] pctx Parse context.
Michal Vasko45b521c2020-11-04 17:14:39 +01001626 * @param[in] mod Parsed module to add to.
1627 * @return LY_SUCCESS on success.
1628 * @return LY_ERR on error.
1629 */
1630static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +02001631lysp_add_internal_ietf_netconf_with_defaults(struct lysp_ctx *pctx, struct lysp_module *mod)
Michal Vasko45b521c2020-11-04 17:14:39 +01001632{
Michal Vasko193dacd2022-10-13 08:43:05 +02001633 struct lysp_ext_instance *extp;
Michal Vasko45b521c2020-11-04 17:14:39 +01001634 struct lysp_stmt *stmt;
1635 struct lysp_import *imp;
1636
1637 /* add new extension instance */
Michal Vasko193dacd2022-10-13 08:43:05 +02001638 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
Michal Vasko45b521c2020-11-04 17:14:39 +01001639
1640 /* fill in the extension instance fields */
Michal Vasko193dacd2022-10-13 08:43:05 +02001641 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
1642 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "default", 0, &extp->argument));
1643 extp->format = LY_VALUE_SCHEMA;
1644 extp->prefix_data = mod;
1645 extp->parent = mod;
1646 extp->parent_stmt = LY_STMT_MODULE;
1647 extp->flags = LYS_INTERNAL;
Michal Vasko45b521c2020-11-04 17:14:39 +01001648
Michal Vasko193dacd2022-10-13 08:43:05 +02001649 extp->child = stmt = calloc(1, sizeof *extp->child);
Michal Vasko45b521c2020-11-04 17:14:39 +01001650 LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1651 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1652 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "boolean", 0, &stmt->arg));
Radek Krejci8df109d2021-04-23 12:19:08 +02001653 stmt->format = LY_VALUE_SCHEMA;
Michal Vaskofc2cd072021-02-24 13:17:17 +01001654 stmt->prefix_data = mod;
Michal Vasko45b521c2020-11-04 17:14:39 +01001655 stmt->kw = LY_STMT_TYPE;
1656
Michal Vasko193dacd2022-10-13 08:43:05 +02001657 if (LY_ARRAY_COUNT(mod->exts) == 1) {
1658 /* first extension instance */
Michal Vaskoc8806c82022-12-06 10:31:24 +01001659 assert(pctx->main_ctx == pctx);
Michal Vasko193dacd2022-10-13 08:43:05 +02001660 LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
1661 }
1662
Michal Vasko45b521c2020-11-04 17:14:39 +01001663 /* create new import for the used prefix */
1664 LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
Michal Vasko45b521c2020-11-04 17:14:39 +01001665 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
1666 LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
1667 imp->flags = LYS_INTERNAL;
1668
1669 return LY_SUCCESS;
1670}
1671
Michal Vasko3a41dff2020-07-15 14:30:28 +02001672LY_ERR
Michal Vasko4e205e82021-06-08 14:01:47 +02001673lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
Radek Krejci1deb5be2020-08-26 16:43:36 +02001674 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 +02001675 void *check_data, struct ly_set *new_mods, struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02001676{
Michal Vaskoa9309bb2021-07-09 09:31:55 +02001677 struct lys_module *mod = NULL, *latest, *mod_dup = NULL;
Michal Vasko3a41dff2020-07-15 14:30:28 +02001678 LY_ERR ret;
Michal Vaskod0625d72022-10-06 15:02:50 +02001679 struct lysp_yang_ctx *yangctx = NULL;
1680 struct lysp_yin_ctx *yinctx = NULL;
1681 struct lysp_ctx *pctx = NULL;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001682 struct lysf_ctx fctx = {.ctx = ctx};
Michal Vasko7a0b0762020-09-02 16:37:01 +02001683 char *filename, *rev, *dot;
1684 size_t len;
Radek Krejcic64661b2020-08-15 15:42:26 +02001685 ly_bool module_created = 0;
Radek Krejci86d106e2018-10-18 09:53:19 +02001686
Michal Vaskodd992582021-06-10 14:34:57 +02001687 assert(ctx && in && new_mods);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001688
Michal Vasko7a0b0762020-09-02 16:37:01 +02001689 if (module) {
1690 *module = NULL;
1691 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001692
1693 mod = calloc(1, sizeof *mod);
Michal Vasko3a41dff2020-07-15 14:30:28 +02001694 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), LY_EMEM);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001695 mod->ctx = ctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001696
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001697 /* parse */
Radek Krejci86d106e2018-10-18 09:53:19 +02001698 switch (format) {
1699 case LYS_IN_YIN:
aPiecekc3e26142021-06-22 14:25:49 +02001700 ret = yin_parse_module(&yinctx, in, mod);
Michal Vaskod0625d72022-10-06 15:02:50 +02001701 pctx = (struct lysp_ctx *)yinctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001702 break;
1703 case LYS_IN_YANG:
aPiecekc3e26142021-06-22 14:25:49 +02001704 ret = yang_parse_module(&yangctx, in, mod);
Michal Vaskod0625d72022-10-06 15:02:50 +02001705 pctx = (struct lysp_ctx *)yangctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001706 break;
1707 default:
1708 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
Michal Vasko3a41dff2020-07-15 14:30:28 +02001709 ret = LY_EINVAL;
Radek Krejci86d106e2018-10-18 09:53:19 +02001710 break;
1711 }
Radek Krejcic64661b2020-08-15 15:42:26 +02001712 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001713
1714 /* make sure that the newest revision is at position 0 */
1715 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci0af46292019-01-11 16:02:31 +01001716 if (mod->parsed->revs) {
Radek Krejcic64661b2020-08-15 15:42:26 +02001717 LY_CHECK_GOTO(ret = lydict_insert(ctx, mod->parsed->revs[0].date, 0, &mod->revision), cleanup);
Radek Krejci0af46292019-01-11 16:02:31 +01001718 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001719
Radek Krejcib3289d62019-09-18 12:21:39 +02001720 /* decide the latest revision */
Michal Vaskoa51ef072021-07-02 10:40:30 +02001721 latest = ly_ctx_get_module_latest(ctx, mod->name);
Radek Krejcib3289d62019-09-18 12:21:39 +02001722 if (latest) {
1723 if (mod->revision) {
1724 if (!latest->revision) {
1725 /* latest has no revision, so mod is anyway newer */
aPiecek8ca21bd2021-07-26 14:31:01 +02001726 mod->latest_revision = latest->latest_revision & (LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
Radek Krejcib3289d62019-09-18 12:21:39 +02001727 /* the latest is zeroed later when the new module is being inserted into the context */
1728 } else if (strcmp(mod->revision, latest->revision) > 0) {
aPiecek8ca21bd2021-07-26 14:31:01 +02001729 mod->latest_revision = latest->latest_revision & (LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
Radek Krejcib3289d62019-09-18 12:21:39 +02001730 /* the latest is zeroed later when the new module is being inserted into the context */
1731 } else {
1732 latest = NULL;
1733 }
1734 } else {
1735 latest = NULL;
1736 }
1737 } else {
aPiecek8ca21bd2021-07-26 14:31:01 +02001738 mod->latest_revision = LYS_MOD_LATEST_REV;
Radek Krejcib3289d62019-09-18 12:21:39 +02001739 }
1740
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001741 if (custom_check) {
Radek Krejcic64661b2020-08-15 15:42:26 +02001742 LY_CHECK_GOTO(ret = custom_check(ctx, mod->parsed, NULL, check_data), cleanup);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001743 }
1744
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001745 /* check whether it is not already in the context in the same revision */
Michal Vaskoa51ef072021-07-02 10:40:30 +02001746 mod_dup = ly_ctx_get_module(ctx, mod->name, mod->revision);
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001747 if (mod_dup) {
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001748 /* nothing to do */
1749 LOGVRB("Module \"%s@%s\" is already present in the context.", mod_dup->name,
1750 mod_dup->revision ? mod_dup->revision : "<none>");
Radek Krejcic64661b2020-08-15 15:42:26 +02001751 goto cleanup;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001752 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001753
Michal Vaskob24145d2022-07-13 18:34:39 +02001754 /* check whether there is not a namespace collision */
1755 mod_dup = ly_ctx_get_module_latest_ns(ctx, mod->ns);
1756 if (mod_dup && (mod_dup->revision == mod->revision)) {
1757 LOGERR(ctx, LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\".",
1758 mod_dup->name, mod->name, mod->ns);
1759 ret = LY_EINVAL;
1760 goto cleanup;
1761 }
1762
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001763 switch (in->type) {
1764 case LY_IN_FILEPATH:
1765 /* check that name and revision match filename */
1766 filename = strrchr(in->method.fpath.filepath, '/');
1767 if (!filename) {
1768 filename = in->method.fpath.filepath;
1769 } else {
1770 filename++;
1771 }
1772 rev = strchr(filename, '@');
1773 dot = strrchr(filename, '.');
1774
1775 /* name */
1776 len = strlen(mod->name);
1777 if (strncmp(filename, mod->name, len) ||
Michal Vasko69730152020-10-09 16:30:07 +02001778 ((rev && (rev != &filename[len])) || (!rev && (dot != &filename[len])))) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001779 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
1780 }
1781 if (rev) {
1782 len = dot - ++rev;
Radek Krejcif13b87b2020-12-01 22:02:17 +01001783 if (!mod->parsed->revs || (len != LY_REV_SIZE - 1) || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001784 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Michal Vasko69730152020-10-09 16:30:07 +02001785 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001786 }
1787 }
1788
1789 break;
1790 case LY_IN_FD:
1791 case LY_IN_FILE:
1792 case LY_IN_MEMORY:
1793 /* nothing special to do */
1794 break;
Michal Vasko7a0b0762020-09-02 16:37:01 +02001795 case LY_IN_ERROR:
1796 LOGINT(ctx);
1797 ret = LY_EINT;
Radek Krejcic64661b2020-08-15 15:42:26 +02001798 goto cleanup;
Radek Krejci096235c2019-01-11 11:12:19 +01001799 }
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001800 lys_parser_fill_filepath(ctx, in, &mod->filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001801
Michal Vasko7a0b0762020-09-02 16:37:01 +02001802 if (latest) {
aPiecek8ca21bd2021-07-26 14:31:01 +02001803 latest->latest_revision &= ~(LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001804 }
1805
Michal Vasko45b521c2020-11-04 17:14:39 +01001806 /* add internal data in case specific modules were parsed */
1807 if (!strcmp(mod->name, "ietf-netconf")) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001808 LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf(pctx, mod->parsed), cleanup);
Michal Vasko45b521c2020-11-04 17:14:39 +01001809 } else if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
Michal Vasko193dacd2022-10-13 08:43:05 +02001810 LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf_with_defaults(pctx, mod->parsed), cleanup);
Michal Vasko45b521c2020-11-04 17:14:39 +01001811 }
1812
Michal Vasko405cc9e2020-12-01 12:01:27 +01001813 /* add the module into newly created module set, will also be freed from there on any error */
Radek Krejcic64661b2020-08-15 15:42:26 +02001814 LY_CHECK_GOTO(ret = ly_set_add(new_mods, mod, 1, NULL), cleanup);
1815 module_created = 1;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001816
Michal Vasko7a0b0762020-09-02 16:37:01 +02001817 /* add into context */
Radek Krejci3d92e442020-10-12 12:48:13 +02001818 ret = ly_set_add(&ctx->list, mod, 1, NULL);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001819 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko794ab4b2021-03-31 09:42:19 +02001820 ctx->change_count++;
Michal Vasko7a0b0762020-09-02 16:37:01 +02001821
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001822 /* resolve includes and all imports */
Michal Vaskoc0c64ae2022-10-06 10:15:23 +02001823 LY_CHECK_GOTO(ret = lysp_resolve_import_include(pctx, mod->parsed, new_mods), cleanup);
1824
1825 /* resolve extension instance plugin records */
1826 LY_CHECK_GOTO(ret = lysp_resolve_ext_instance_records(pctx), cleanup);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001827
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001828 /* check name collisions */
Michal Vasko405cc9e2020-12-01 12:01:27 +01001829 LY_CHECK_GOTO(ret = lysp_check_dup_typedefs(pctx, mod->parsed), cleanup);
aPiecek63e080d2021-06-29 13:53:28 +02001830 LY_CHECK_GOTO(ret = lysp_check_dup_groupings(pctx, mod->parsed), cleanup);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001831 LY_CHECK_GOTO(ret = lysp_check_dup_features(pctx, mod->parsed), cleanup);
1832 LY_CHECK_GOTO(ret = lysp_check_dup_identities(pctx, mod->parsed), cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001833
1834 /* compile features */
Michal Vasko405cc9e2020-12-01 12:01:27 +01001835 LY_CHECK_GOTO(ret = lys_compile_feature_iffeatures(mod->parsed), cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001836
aPiecek6b3d5422021-07-30 15:55:43 +02001837 /* compile identities */
1838 LY_CHECK_GOTO(ret = lys_compile_identities(mod), cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001839
Radek Krejcic64661b2020-08-15 15:42:26 +02001840cleanup:
Michal Vaskobe04af42021-07-16 10:48:43 +02001841 if (ret && (ret != LY_EEXIST)) {
Radek Krejcic64661b2020-08-15 15:42:26 +02001842 if (mod && mod->name) {
1843 /* there are cases when path is not available for parsing error, so this additional
1844 * message tries to add information about the module where the error occurred */
1845 struct ly_err_item *e = ly_err_last(ctx);
Michal Vasko26bbb272022-08-02 14:54:33 +02001846
Radek Krejcic64661b2020-08-15 15:42:26 +02001847 if (e && (!e->path || !strncmp(e->path, "Line ", ly_strlen_const("Line ")))) {
1848 LOGERR(ctx, ret, "Parsing module \"%s\" failed.", mod->name);
1849 }
1850 }
1851 }
1852 if (!module_created) {
Michal Vaskoc636ea42022-09-16 10:20:31 +02001853 fctx.mod = mod;
1854 lys_module_free(&fctx, mod, 0);
1855 lysf_ctx_erase(&fctx);
1856
Michal Vasko0e02e8e2021-02-26 15:01:55 +01001857 mod = mod_dup;
1858 }
Michal Vasko8a69a1b2020-12-03 14:19:02 +01001859
Michal Vasko7a0b0762020-09-02 16:37:01 +02001860 if (format == LYS_IN_YANG) {
Michal Vaskod0625d72022-10-06 15:02:50 +02001861 lysp_yang_ctx_free(yangctx);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001862 } else {
Michal Vaskod0625d72022-10-06 15:02:50 +02001863 lysp_yin_ctx_free(yinctx);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001864 }
1865
Michal Vasko405cc9e2020-12-01 12:01:27 +01001866 if (!ret && module) {
1867 *module = mod;
1868 }
Michal Vasko7a0b0762020-09-02 16:37:01 +02001869 return ret;
1870}
1871
Radek Krejci545b4872020-11-15 10:15:12 +01001872static LYS_INFORMAT
1873lys_parse_get_format(const struct ly_in *in, LYS_INFORMAT format)
1874{
1875 if (!format && (in->type == LY_IN_FILEPATH)) {
1876 /* unknown format - try to detect it from filename's suffix */
1877 const char *path = in->method.fpath.filepath;
1878 size_t len = strlen(path);
1879
1880 /* ignore trailing whitespaces */
1881 for ( ; len > 0 && isspace(path[len - 1]); len--) {}
1882
Radek Krejcif13b87b2020-12-01 22:02:17 +01001883 if ((len >= LY_YANG_SUFFIX_LEN + 1) &&
1884 !strncmp(&path[len - LY_YANG_SUFFIX_LEN], LY_YANG_SUFFIX, LY_YANG_SUFFIX_LEN)) {
Radek Krejci545b4872020-11-15 10:15:12 +01001885 format = LYS_IN_YANG;
Radek Krejcif13b87b2020-12-01 22:02:17 +01001886 } else if ((len >= LY_YIN_SUFFIX_LEN + 1) &&
1887 !strncmp(&path[len - LY_YIN_SUFFIX_LEN], LY_YIN_SUFFIX, LY_YIN_SUFFIX_LEN)) {
Radek Krejci545b4872020-11-15 10:15:12 +01001888 format = LYS_IN_YIN;
1889 } /* else still unknown */
1890 }
1891
1892 return format;
1893}
1894
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001895LIBYANG_API_DEF LY_ERR
Michal Vasko4de7d072021-07-09 09:13:18 +02001896lys_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 +02001897{
Michal Vasko65333882021-06-10 14:12:16 +02001898 LY_ERR ret = LY_SUCCESS;
Michal Vasko4e205e82021-06-08 14:01:47 +02001899 struct lys_module *mod;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001900
Michal Vasko7a0b0762020-09-02 16:37:01 +02001901 if (module) {
1902 *module = NULL;
1903 }
Radek Krejci545b4872020-11-15 10:15:12 +01001904 LY_CHECK_ARG_RET(NULL, ctx, in, LY_EINVAL);
1905
1906 format = lys_parse_get_format(in, format);
1907 LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001908
1909 /* remember input position */
1910 in->func_start = in->current;
1911
Michal Vasko4e205e82021-06-08 14:01:47 +02001912 /* parse */
Michal Vasko22b26222021-07-30 11:16:47 +02001913 ret = lys_parse_in(ctx, in, format, NULL, NULL, &ctx->unres.creating, &mod);
Michal Vasko4e205e82021-06-08 14:01:47 +02001914 LY_CHECK_GOTO(ret, cleanup);
1915
1916 /* implement */
Michal Vasko22b26222021-07-30 11:16:47 +02001917 ret = _lys_set_implemented(mod, features, &ctx->unres);
Michal Vasko405cc9e2020-12-01 12:01:27 +01001918 LY_CHECK_GOTO(ret, cleanup);
1919
Michal Vaskof4258e12021-06-15 12:11:42 +02001920 if (!(ctx->flags & LY_CTX_EXPLICIT_COMPILE)) {
1921 /* create dep set for the module and mark all the modules that will be (re)compiled */
Michal Vasko22b26222021-07-30 11:16:47 +02001922 LY_CHECK_GOTO(ret = lys_unres_dep_sets_create(ctx, &ctx->unres.dep_sets, mod), cleanup);
Michal Vaskof4258e12021-06-15 12:11:42 +02001923
Michal Vasko709f9a52021-07-21 10:51:59 +02001924 /* (re)compile the whole dep set (other dep sets will have no modules marked for compilation) */
Michal Vasko22b26222021-07-30 11:16:47 +02001925 LY_CHECK_GOTO(ret = lys_compile_depset_all(ctx, &ctx->unres), cleanup);
1926
1927 /* unres resolved */
1928 lys_unres_glob_erase(&ctx->unres);
Michal Vaskof4258e12021-06-15 12:11:42 +02001929 }
1930
Michal Vasko405cc9e2020-12-01 12:01:27 +01001931cleanup:
1932 if (ret) {
Michal Vasko22b26222021-07-30 11:16:47 +02001933 lys_unres_glob_revert(ctx, &ctx->unres);
1934 lys_unres_glob_erase(&ctx->unres);
Michal Vasko87f1cf02021-06-08 14:02:47 +02001935 } else if (module) {
1936 *module = mod;
Michal Vasko405cc9e2020-12-01 12:01:27 +01001937 }
Michal Vasko405cc9e2020-12-01 12:01:27 +01001938 return ret;
Radek Krejci86d106e2018-10-18 09:53:19 +02001939}
1940
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001941LIBYANG_API_DEF LY_ERR
Michal Vasko4de7d072021-07-09 09:13:18 +02001942lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02001943{
Radek Krejci0f969882020-08-21 16:56:47 +02001944 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001945 struct ly_in *in = NULL;
Radek Krejci86d106e2018-10-18 09:53:19 +02001946
Michal Vasko3a41dff2020-07-15 14:30:28 +02001947 LY_CHECK_ARG_RET(ctx, data, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejci65639b92018-11-27 10:51:37 +01001948
Michal Vasko3a41dff2020-07-15 14:30:28 +02001949 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 +02001950
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001951 ret = lys_parse(ctx, in, format, NULL, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001952 ly_in_free(in, 0);
Radek Krejci86d106e2018-10-18 09:53:19 +02001953
Michal Vasko3a41dff2020-07-15 14:30:28 +02001954 return ret;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001955}
1956
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001957LIBYANG_API_DEF LY_ERR
Michal Vasko4de7d072021-07-09 09:13:18 +02001958lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02001959{
Radek Krejci0f969882020-08-21 16:56:47 +02001960 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001961 struct ly_in *in = NULL;
Radek Krejci86d106e2018-10-18 09:53:19 +02001962
Michal Vasko3a41dff2020-07-15 14:30:28 +02001963 LY_CHECK_ARG_RET(ctx, fd > -1, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001964
Michal Vasko3a41dff2020-07-15 14:30:28 +02001965 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 +02001966
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001967 ret = lys_parse(ctx, in, format, NULL, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001968 ly_in_free(in, 0);
Radek Krejci86d106e2018-10-18 09:53:19 +02001969
Michal Vasko3a41dff2020-07-15 14:30:28 +02001970 return ret;
Radek Krejci86d106e2018-10-18 09:53:19 +02001971}
1972
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001973LIBYANG_API_DEF LY_ERR
Michal Vasko4de7d072021-07-09 09:13:18 +02001974lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, struct lys_module **module)
Radek Krejcid33273d2018-10-25 14:55:52 +02001975{
Radek Krejci0f969882020-08-21 16:56:47 +02001976 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001977 struct ly_in *in = NULL;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001978
Michal Vasko3a41dff2020-07-15 14:30:28 +02001979 LY_CHECK_ARG_RET(ctx, path, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001980
Michal Vasko3a41dff2020-07-15 14:30:28 +02001981 LY_CHECK_ERR_RET(ret = ly_in_new_filepath(path, 0, &in),
Michal Vasko69730152020-10-09 16:30:07 +02001982 LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", path), ret);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001983
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001984 ret = lys_parse(ctx, in, format, NULL, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001985 ly_in_free(in, 0);
1986
Michal Vasko3a41dff2020-07-15 14:30:28 +02001987 return ret;
Radek Krejcid33273d2018-10-25 14:55:52 +02001988}
1989
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001990LIBYANG_API_DEF LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001991lys_search_localfile(const char * const *searchpaths, ly_bool cwd, const char *name, const char *revision,
Radek Krejci0f969882020-08-21 16:56:47 +02001992 char **localfile, LYS_INFORMAT *format)
Radek Krejcid33273d2018-10-25 14:55:52 +02001993{
Radek Krejci1deb5be2020-08-26 16:43:36 +02001994 LY_ERR ret = LY_EMEM;
Radek Krejcid33273d2018-10-25 14:55:52 +02001995 size_t len, flen, match_len = 0, dir_len;
Radek Krejci857189e2020-09-01 13:26:36 +02001996 ly_bool implicit_cwd = 0;
Radek Krejcid33273d2018-10-25 14:55:52 +02001997 char *wd, *wn = NULL;
1998 DIR *dir = NULL;
1999 struct dirent *file;
2000 char *match_name = NULL;
2001 LYS_INFORMAT format_aux, match_format = 0;
2002 struct ly_set *dirs;
2003 struct stat st;
2004
2005 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
2006
2007 /* start to fill the dir fifo with the context's search path (if set)
2008 * and the current working directory */
Radek Krejciba03a5a2020-08-27 14:40:41 +02002009 LY_CHECK_RET(ly_set_new(&dirs));
Radek Krejcid33273d2018-10-25 14:55:52 +02002010
2011 len = strlen(name);
2012 if (cwd) {
2013 wd = get_current_dir_name();
2014 if (!wd) {
2015 LOGMEM(NULL);
2016 goto cleanup;
2017 } else {
2018 /* add implicit current working directory (./) to be searched,
2019 * this directory is not searched recursively */
Radek Krejciba03a5a2020-08-27 14:40:41 +02002020 ret = ly_set_add(dirs, wd, 0, NULL);
2021 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcid33273d2018-10-25 14:55:52 +02002022 implicit_cwd = 1;
2023 }
2024 }
2025 if (searchpaths) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02002026 for (uint64_t i = 0; searchpaths[i]; i++) {
Radek Krejcid33273d2018-10-25 14:55:52 +02002027 /* check for duplicities with the implicit current working directory */
2028 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
2029 implicit_cwd = 0;
2030 continue;
2031 }
2032 wd = strdup(searchpaths[i]);
2033 if (!wd) {
2034 LOGMEM(NULL);
2035 goto cleanup;
Radek Krejciba03a5a2020-08-27 14:40:41 +02002036 } else {
2037 ret = ly_set_add(dirs, wd, 0, NULL);
2038 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcid33273d2018-10-25 14:55:52 +02002039 }
2040 }
2041 }
2042 wd = NULL;
2043
2044 /* start searching */
2045 while (dirs->count) {
2046 free(wd);
2047 free(wn); wn = NULL;
2048
2049 dirs->count--;
2050 wd = (char *)dirs->objs[dirs->count];
2051 dirs->objs[dirs->count] = NULL;
Radek Krejcieeee95c2021-01-19 10:57:22 +01002052 LOGVRB("Searching for \"%s\" in \"%s\".", name, wd);
Radek Krejcid33273d2018-10-25 14:55:52 +02002053
2054 if (dir) {
2055 closedir(dir);
2056 }
2057 dir = opendir(wd);
2058 dir_len = strlen(wd);
2059 if (!dir) {
2060 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
2061 } else {
2062 while ((file = readdir(dir))) {
2063 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
2064 /* skip . and .. */
2065 continue;
2066 }
2067 free(wn);
2068 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
2069 LOGMEM(NULL);
2070 goto cleanup;
2071 }
2072 if (stat(wn, &st) == -1) {
2073 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
Michal Vasko69730152020-10-09 16:30:07 +02002074 file->d_name, wd, strerror(errno));
Radek Krejcid33273d2018-10-25 14:55:52 +02002075 continue;
2076 }
2077 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
2078 /* we have another subdirectory in searchpath to explore,
2079 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
Radek Krejciba03a5a2020-08-27 14:40:41 +02002080 ret = ly_set_add(dirs, wn, 0, NULL);
2081 LY_CHECK_GOTO(ret, cleanup);
2082
Radek Krejcid33273d2018-10-25 14:55:52 +02002083 /* continue with the next item in current directory */
2084 wn = NULL;
2085 continue;
2086 } else if (!S_ISREG(st.st_mode)) {
2087 /* not a regular file (note that we see the target of symlinks instead of symlinks */
2088 continue;
2089 }
2090
2091 /* here we know that the item is a file which can contain a module */
2092 if (strncmp(name, file->d_name, len) ||
Michal Vasko69730152020-10-09 16:30:07 +02002093 ((file->d_name[len] != '.') && (file->d_name[len] != '@'))) {
Radek Krejcid33273d2018-10-25 14:55:52 +02002094 /* different filename than the module we search for */
2095 continue;
2096 }
2097
2098 /* get type according to filename suffix */
2099 flen = strlen(file->d_name);
Radek Krejcif13b87b2020-12-01 22:02:17 +01002100 if ((flen >= LY_YANG_SUFFIX_LEN + 1) &&
2101 !strcmp(&file->d_name[flen - LY_YANG_SUFFIX_LEN], LY_YANG_SUFFIX)) {
Radek Krejcid33273d2018-10-25 14:55:52 +02002102 format_aux = LYS_IN_YANG;
Radek Krejcif13b87b2020-12-01 22:02:17 +01002103 } else if ((flen >= LY_YIN_SUFFIX_LEN + 1) &&
2104 !strcmp(&file->d_name[flen - LY_YIN_SUFFIX_LEN], LY_YIN_SUFFIX)) {
Radek Krejci01a937f2020-11-15 10:14:12 +01002105 format_aux = LYS_IN_YIN;
Radek Krejcid33273d2018-10-25 14:55:52 +02002106 } else {
2107 /* not supportde suffix/file format */
2108 continue;
2109 }
2110
2111 if (revision) {
2112 /* we look for the specific revision, try to get it from the filename */
2113 if (file->d_name[len] == '@') {
2114 /* check revision from the filename */
2115 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
2116 /* another revision */
2117 continue;
2118 } else {
2119 /* exact revision */
2120 free(match_name);
2121 match_name = wn;
2122 wn = NULL;
2123 match_len = dir_len + 1 + len;
2124 match_format = format_aux;
2125 goto success;
2126 }
2127 } else {
2128 /* continue trying to find exact revision match, use this only if not found */
2129 free(match_name);
2130 match_name = wn;
2131 wn = NULL;
Michal Vasko44f3d2c2020-08-24 09:49:38 +02002132 match_len = dir_len + 1 + len;
Radek Krejcid33273d2018-10-25 14:55:52 +02002133 match_format = format_aux;
2134 continue;
2135 }
2136 } else {
2137 /* remember the revision and try to find the newest one */
2138 if (match_name) {
Michal Vasko69730152020-10-09 16:30:07 +02002139 if ((file->d_name[len] != '@') ||
Radek Krejcif13b87b2020-12-01 22:02:17 +01002140 lysp_check_date(NULL, &file->d_name[len + 1],
2141 flen - ((format_aux == LYS_IN_YANG) ? LY_YANG_SUFFIX_LEN : LY_YIN_SUFFIX_LEN) - len - 1, NULL)) {
Radek Krejcid33273d2018-10-25 14:55:52 +02002142 continue;
Michal Vasko69730152020-10-09 16:30:07 +02002143 } else if ((match_name[match_len] == '@') &&
Radek Krejcid33273d2018-10-25 14:55:52 +02002144 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
2145 continue;
2146 }
2147 free(match_name);
2148 }
2149
2150 match_name = wn;
2151 wn = NULL;
2152 match_len = dir_len + 1 + len;
2153 match_format = format_aux;
2154 continue;
2155 }
2156 }
2157 }
2158 }
2159
2160success:
2161 (*localfile) = match_name;
2162 match_name = NULL;
2163 if (format) {
2164 (*format) = match_format;
2165 }
Radek Krejci1deb5be2020-08-26 16:43:36 +02002166 ret = LY_SUCCESS;
Radek Krejcid33273d2018-10-25 14:55:52 +02002167
2168cleanup:
2169 free(wn);
2170 free(wd);
2171 if (dir) {
2172 closedir(dir);
2173 }
2174 free(match_name);
2175 ly_set_free(dirs, free);
2176
2177 return ret;
2178}