blob: 2ef2fbd5fb2c15c1809621f03cc9994e17b560e4 [file] [log] [blame]
Michal Vasko004d3152020-06-11 19:59:22 +02001/**
2 * @file path.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief Path functions
5 *
Michal Vasko90189962023-02-28 12:10:34 +01006 * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
Michal Vasko004d3152020-06-11 19:59:22 +02007 *
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 */
Michal Vasko90189962023-02-28 12:10:34 +010014
15#define _GNU_SOURCE
16
Michal Vasko004d3152020-06-11 19:59:22 +020017#include "path.h"
18
19#include <assert.h>
Michal Vasko004d3152020-06-11 19:59:22 +020020#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020021#include <string.h>
Michal Vasko004d3152020-06-11 19:59:22 +020022
Michal Vasko5aa44c02020-06-29 11:47:02 +020023#include "compat.h"
Michal Vasko004d3152020-06-11 19:59:22 +020024#include "log.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010025#include "ly_common.h"
Michal Vasko004d3152020-06-11 19:59:22 +020026#include "plugins_types.h"
Michal Vasko40c158c2021-04-28 17:01:03 +020027#include "schema_compile.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020028#include "set.h"
Michal Vasko4c583e82020-07-17 12:16:14 +020029#include "tree.h"
Michal Vasko004d3152020-06-11 19:59:22 +020030#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010031#include "tree_edit.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020032#include "tree_schema.h"
Michal Vasko004d3152020-06-11 19:59:22 +020033#include "tree_schema_internal.h"
34#include "xpath.h"
35
Radek Krejcic0c66412020-08-21 13:53:50 +020036#define LOGVAL_P(CTX, CUR_NODE, CODE, ...) ly_vlog(CTX, (CUR_NODE) ? LY_VLOG_LYSC : LY_VLOG_NONE, CUR_NODE, CODE, ##__VA_ARGS__)
Michal Vasko6b26e742020-07-17 15:02:10 +020037
Michal Vasko004d3152020-06-11 19:59:22 +020038/**
39 * @brief Check predicate syntax.
40 *
41 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +020042 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +020043 * @param[in] exp Parsed predicate.
44 * @param[in,out] tok_idx Index in @p exp, is adjusted.
45 * @param[in] prefix Prefix option.
46 * @param[in] pred Predicate option.
47 * @return LY_ERR value.
48 */
49static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +020050ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lyxp_expr *exp,
Michal Vasko32ca49b2023-02-17 15:11:35 +010051 uint32_t *tok_idx, uint16_t prefix, uint16_t pred)
Michal Vasko004d3152020-06-11 19:59:22 +020052{
Radek Krejciba03a5a2020-08-27 14:40:41 +020053 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +020054 struct ly_set *set = NULL;
55 uint32_t i;
56 const char *name;
57 size_t name_len;
58
Radek Krejciddace2c2021-01-08 11:30:56 +010059 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +010060
Michal Vasko004d3152020-06-11 19:59:22 +020061 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020062 /* '[' */
63
Michal Vasko69730152020-10-09 16:30:07 +020064 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
65 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020066 ret = ly_set_new(&set);
67 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020068
69 do {
70 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020071 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020072
73 /* check prefix based on the options */
74 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
75 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Michal Vasko21eaa392024-02-20 15:48:42 +010076 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", (int)exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020077 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020078 goto token_error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020079 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
Michal Vasko21eaa392024-02-20 15:48:42 +010080 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", (int)exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020081 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020082 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020083 }
84 if (!name) {
85 name = exp->expr + exp->tok_pos[*tok_idx];
86 name_len = exp->tok_len[*tok_idx];
87 } else {
88 ++name;
89 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
90 }
91
92 /* check whether it was not already specified */
93 for (i = 0; i < set->count; ++i) {
94 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +020095 if (!strncmp(set->objs[i], name, name_len) &&
96 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +010097 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +020098 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020099 }
100 }
101
102 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200103 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200104 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200105
106 /* NameTest */
107 ++(*tok_idx);
108
109 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200110 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200111
Michal Vaskob01983e2023-04-24 10:43:13 +0200112 /* fill repeat */
113 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
114 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
115 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
116
Michal Vasko90189962023-02-28 12:10:34 +0100117 /* Literal, Number, or VariableReference */
118 if (lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_LITERAL) &&
119 lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER) &&
120 lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_VARREF)) {
121 /* error */
122 lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL);
123 goto token_error;
124 }
Michal Vasko004d3152020-06-11 19:59:22 +0200125
126 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200127 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200128
Radek Krejci0f969882020-08-21 16:56:47 +0200129 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200130 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
131
Michal Vasko004d3152020-06-11 19:59:22 +0200132 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200133 /* '.' */
134
Michal Vasko004d3152020-06-11 19:59:22 +0200135 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200136 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200137
Michal Vaskob01983e2023-04-24 10:43:13 +0200138 /* fill repeat */
139 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
140 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
141 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
142
Michal Vasko4911eeb2021-06-28 11:23:05 +0200143 /* Literal or Number */
144 LY_CHECK_GOTO(lyxp_next_token2(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL, LYXP_TOKEN_NUMBER), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200145
146 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200147 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200148
Michal Vasko004d3152020-06-11 19:59:22 +0200149 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200150 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200151
Michal Vasko2261dfa2022-09-29 12:29:20 +0200152 /* check for index 0 */
153 if (!atoi(exp->expr + exp->tok_pos[*tok_idx - 1])) {
154 LOGVAL(ctx, LYVE_XPATH, "Invalid positional predicate \"%.*s\".", (int)exp->tok_len[*tok_idx - 1],
155 exp->expr + exp->tok_pos[*tok_idx - 1]);
156 goto token_error;
157 }
158
Michal Vasko004d3152020-06-11 19:59:22 +0200159 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200160 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200161
162 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
163 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200164 ret = ly_set_new(&set);
165 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200166
167 do {
168 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200169 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200170
171 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
172 if (!name) {
173 name = exp->expr + exp->tok_pos[*tok_idx];
174 name_len = exp->tok_len[*tok_idx];
175 } else {
176 ++name;
177 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
178 }
179
180 /* check whether it was not already specified */
181 for (i = 0; i < set->count; ++i) {
182 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +0200183 if (!strncmp(set->objs[i], name, name_len) &&
184 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +0100185 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200186 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200187 }
188 }
189
190 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200191 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200192 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200193
194 /* NameTest */
195 ++(*tok_idx);
196
197 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200198 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200199
Michal Vaskob01983e2023-04-24 10:43:13 +0200200 /* fill repeat */
201 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
202 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
203 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
204
Michal Vasko004d3152020-06-11 19:59:22 +0200205 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200206 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100207 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
208 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100209 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko21eaa392024-02-20 15:48:42 +0100210 (int)exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200211 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200212 }
213 ++(*tok_idx);
214
215 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200216 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200217
218 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200219 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200220
221 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200222 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200223
224 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200225 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200226 do {
227 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200228 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200229 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
230
231 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200232 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200233
234 /* '/' */
235 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
236 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200237 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200238 }
239
240 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200241 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200242
Radek Krejci0f969882020-08-21 16:56:47 +0200243 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200244 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
245
Michal Vasko3c19b492022-09-05 08:48:10 +0200246 } else if (lyxp_check_token(ctx, exp, *tok_idx, 0)) {
247 /* unexpected EOF */
248 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200249 } else {
Michal Vasko3c19b492022-09-05 08:48:10 +0200250 /* invalid token */
Michal Vasko49fec8e2022-05-24 10:28:33 +0200251 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(exp->tokens[*tok_idx]), exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200252 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200253 }
254 }
255
Radek Krejciba03a5a2020-08-27 14:40:41 +0200256cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100257 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200258 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200259 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200260
Radek Krejciba03a5a2020-08-27 14:40:41 +0200261token_error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100262 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200263 ly_set_free(set, NULL);
264 return LY_EVALID;
265}
266
stewegd8e2fc92023-05-31 09:52:56 +0200267/**
268 * @brief Parse deref XPath function and perform all additional checks.
269 *
270 * @param[in] ctx libyang context.
271 * @param[in] ctx_node Optional context node, used for logging.
272 * @param[in] exp Parsed path.
273 * @param[in,out] tok_idx Index in @p exp, is adjusted.
274 * @return LY_ERR value.
275 */
276static LY_ERR
277ly_path_parse_deref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lyxp_expr *exp,
278 uint32_t *tok_idx)
279{
280 size_t arg_len;
281 uint32_t begin_token, end_token;
282 struct lyxp_expr *arg_expr = NULL;
283
284 /* mandatory FunctionName */
285 LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_FUNCNAME), LY_EVALID);
286 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "deref", 5)) {
287 LOGVAL(ctx, LYVE_XPATH, "Unexpected XPath function \"%.*s\" in path, expected \"deref(...)\"",
Michal Vasko21eaa392024-02-20 15:48:42 +0100288 (int)exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
stewegd8e2fc92023-05-31 09:52:56 +0200289 return LY_EVALID;
290 }
291
292 /* mandatory '(' */
293 LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), LY_EVALID);
294 begin_token = *tok_idx;
295
296 /* count tokens till ')' */
297 while (lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_PAR2) && *tok_idx < exp->used) {
298 /* emebedded functions are not allowed */
299 if (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_FUNCNAME)) {
300 LOGVAL(ctx, LYVE_XPATH, "Embedded function XPath function inside deref function within the path"
301 "is not allowed");
302 return LY_EVALID;
303 }
304
305 (*tok_idx)++;
306 }
307
308 /* mandatory ')' */
309 LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), LY_EVALID);
310 end_token = *tok_idx - 1;
311
312 /* parse the path of deref argument */
313 arg_len = exp->tok_pos[end_token] - exp->tok_pos[begin_token];
314 LY_CHECK_RET(ly_path_parse(ctx, ctx_node, &exp->expr[exp->tok_pos[begin_token]], arg_len, 1,
315 LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &arg_expr), LY_EVALID);
316 lyxp_expr_free(ctx, arg_expr);
317
318 return LY_SUCCESS;
319}
320
Michal Vasko004d3152020-06-11 19:59:22 +0200321LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200322ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
Michal Vasko32ca49b2023-02-17 15:11:35 +0100323 ly_bool lref, uint16_t begin, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200324{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200325 LY_ERR ret = LY_SUCCESS;
326 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200327 uint32_t tok_idx, cur_len;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200328 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko32ca49b2023-02-17 15:11:35 +0100329 ly_bool is_abs;
Michal Vasko004d3152020-06-11 19:59:22 +0200330
331 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
Michal Vasko69730152020-10-09 16:30:07 +0200332 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
Michal Vasko32ca49b2023-02-17 15:11:35 +0100333 (prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200334 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
335
Radek Krejciddace2c2021-01-08 11:30:56 +0100336 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100337
Michal Vaskob01983e2023-04-24 10:43:13 +0200338 /* parse as a generic XPath expression, reparse is performed manually */
339 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200340 tok_idx = 0;
341
Michal Vaskob01983e2023-04-24 10:43:13 +0200342 /* alloc empty repeat (only '=', filled manually) */
343 exp->repeat = calloc(exp->size, sizeof *exp->repeat);
344 LY_CHECK_ERR_GOTO(!exp->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
345
Michal Vasko004d3152020-06-11 19:59:22 +0200346 if (begin == LY_PATH_BEGIN_EITHER) {
347 /* is the path relative? */
348 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200349 /* relative path check specific to leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200350 if (lref) {
stewegd8e2fc92023-05-31 09:52:56 +0200351 /* optional function 'deref..' */
352 if ((ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_EXTENDED) &&
353 !lyxp_check_token(NULL, exp, tok_idx, LYXP_TOKEN_FUNCNAME)) {
354 LY_CHECK_ERR_GOTO(ly_path_parse_deref(ctx, ctx_node, exp, &tok_idx), ret = LY_EVALID, error);
355
356 /* '/' */
357 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID,
358 error);
359 }
360
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200361 /* mandatory '..' */
362 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
363
364 do {
365 /* '/' */
stewegd8e2fc92023-05-31 09:52:56 +0200366 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID,
367 error);
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200368
369 /* optional '..' */
370 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200371 }
Michal Vasko32ca49b2023-02-17 15:11:35 +0100372
373 is_abs = 0;
374 } else {
375 is_abs = 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200376 }
377 } else {
378 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200379 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
Michal Vasko32ca49b2023-02-17 15:11:35 +0100380
381 is_abs = 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200382 }
383
384 do {
385 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200386 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, error);
Michal Vasko004d3152020-06-11 19:59:22 +0200387
388 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200389 cur_node = exp->expr + exp->tok_pos[tok_idx];
390 cur_len = exp->tok_len[tok_idx];
391 if (prefix == LY_PATH_PREFIX_MANDATORY) {
392 if (!strnstr(cur_node, ":", cur_len)) {
Michal Vasko21eaa392024-02-20 15:48:42 +0100393 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", (int)cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200394 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200395 goto error;
396 }
Michal Vasko32ca49b2023-02-17 15:11:35 +0100397 } else if ((prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) {
398 if (!prev_prefix && is_abs) {
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200399 /* the first node must have a prefix */
400 if (!strnstr(cur_node, ":", cur_len)) {
Michal Vasko21eaa392024-02-20 15:48:42 +0100401 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", (int)cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200402 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200403 goto error;
404 }
405
406 /* remember the first prefix */
407 prev_prefix = cur_node;
Michal Vasko32ca49b2023-02-17 15:11:35 +0100408 } else if (prev_prefix && (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) {
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200409 /* the prefix must be different, if any */
410 ptr = strnstr(cur_node, ":", cur_len);
411 if (ptr) {
412 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Michal Vasko21eaa392024-02-20 15:48:42 +0100413 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", (int)cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200414 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200415 goto error;
416 }
417
418 /* remember this next prefix */
419 prev_prefix = cur_node;
420 }
421 }
Michal Vasko004d3152020-06-11 19:59:22 +0200422 }
423
424 ++tok_idx;
425
426 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200427 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200428
Radek Krejci0f969882020-08-21 16:56:47 +0200429 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200430 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
431
432 /* trailing token check */
433 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100434 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.", exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200435 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200436 goto error;
437 }
438
439 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100440
Radek Krejciddace2c2021-01-08 11:30:56 +0100441 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200442 return LY_SUCCESS;
443
444error:
445 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100446 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200447 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200448}
449
450LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200451ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
Michal Vasko32ca49b2023-02-17 15:11:35 +0100452 size_t path_len, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200453{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200454 LY_ERR ret = LY_SUCCESS;
455 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200456 uint32_t tok_idx;
Michal Vasko004d3152020-06-11 19:59:22 +0200457
458 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
459 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
460
Radek Krejciddace2c2021-01-08 11:30:56 +0100461 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100462
Michal Vaskob01983e2023-04-24 10:43:13 +0200463 /* parse as a generic XPath expression, reparse is performed manually */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200464 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200465 tok_idx = 0;
466
Michal Vaskob01983e2023-04-24 10:43:13 +0200467 /* alloc empty repeat (only '=', filled manually) */
468 exp->repeat = calloc(exp->size, sizeof *exp->repeat);
469 LY_CHECK_ERR_GOTO(!exp->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
470
Radek Krejcif03a9e22020-09-18 20:09:31 +0200471 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200472
473 /* trailing token check */
474 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100475 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200476 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200477 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200478 goto error;
479 }
480
481 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100482
Radek Krejciddace2c2021-01-08 11:30:56 +0100483 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200484 return LY_SUCCESS;
485
486error:
487 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100488 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200489 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200490}
491
492/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200493 * @brief Parse NameTest and get the corresponding schema node.
Michal Vasko004d3152020-06-11 19:59:22 +0200494 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200495 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200496 * @param[in] cur_node Optional current (original context) node.
Radek Krejci84d7fd72021-07-14 18:32:21 +0200497 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
498 * and ::LY_VALUE_SCHEMA_RESOLVED.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200499 * @param[in] prev_ctx_node Previous context node.
Michal Vasko004d3152020-06-11 19:59:22 +0200500 * @param[in] expr Parsed path.
501 * @param[in] tok_idx Index in @p expr.
Michal Vasko004d3152020-06-11 19:59:22 +0200502 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200503 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko8cc3f662022-03-29 11:25:51 +0200504 * @param[in] top_ext Optional top-level extension to use for searching the schema node.
505 * @param[in] getnext_opts Options to be used for ::lys_getnext() calls.
506 * @param[out] snode Resolved schema node.
507 * @param[out] ext Optional extension instance of @p snode, if any.
Michal Vasko004d3152020-06-11 19:59:22 +0200508 * @return LY_ERR value.
509 */
510static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200511ly_path_compile_snode(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vaskodd528af2022-08-08 14:35:07 +0200512 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint32_t tok_idx, LY_VALUE_FORMAT format,
Michal Vasko8cc3f662022-03-29 11:25:51 +0200513 void *prefix_data, const struct lysc_ext_instance *top_ext, uint32_t getnext_opts, const struct lysc_node **snode,
514 struct lysc_ext_instance **ext)
Michal Vasko004d3152020-06-11 19:59:22 +0200515{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100516 LY_ERR ret;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200517 const struct lys_module *mod = NULL;
518 struct lysc_ext_instance *e = NULL;
519 const char *pref, *name;
520 size_t len, name_len;
Michal Vasko004d3152020-06-11 19:59:22 +0200521
522 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
523
Michal Vasko8cc3f662022-03-29 11:25:51 +0200524 *snode = NULL;
525 if (ext) {
526 *ext = NULL;
527 }
528
Michal Vasko004d3152020-06-11 19:59:22 +0200529 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200530 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
531 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
532 pref = expr->expr + expr->tok_pos[tok_idx];
533 } else {
534 len = 0;
535 }
Michal Vasko004d3152020-06-11 19:59:22 +0200536
Michal Vasko8cc3f662022-03-29 11:25:51 +0200537 /* set name */
538 if (pref) {
539 name = pref + len + 1;
540 name_len = expr->tok_len[tok_idx] - len - 1;
541 } else {
542 name = expr->expr + expr->tok_pos[tok_idx];
543 name_len = expr->tok_len[tok_idx];
544 }
545
546 /* find node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200547 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100548 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100549
Michal Vasko35b29622022-07-22 14:12:56 +0200550 mod = ly_resolve_prefix(prev_ctx_node ? prev_ctx_node->module->ctx : ctx, pref, len, format, prefix_data);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200551 if ((!mod || !mod->implemented) && prev_ctx_node) {
552 /* check for nested ext data */
553 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
554 if (!ret) {
555 goto success;
556 } else if (ret != LY_ENOT) {
557 goto error;
558 }
559 }
560
561 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100562 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100563 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200564 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100565 goto error;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200566 } else if (!mod->implemented) {
567 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
Michal Vaskoed725d72021-06-23 12:03:45 +0200568 ret = LY_EVALID;
569 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200570 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100571
Radek Krejciddace2c2021-01-08 11:30:56 +0100572 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200573 } else {
574 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200575 case LY_VALUE_SCHEMA:
576 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200577 if (!cur_mod) {
578 LOGINT_RET(ctx);
579 }
580 /* use current module */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200581 mod = cur_mod;
Michal Vasko004d3152020-06-11 19:59:22 +0200582 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200583 case LY_VALUE_JSON:
Michal Vasko79228af2021-08-26 14:44:28 +0200584 case LY_VALUE_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200585 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200586 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200587 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200588 /* inherit module of the previous node */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200589 mod = prev_ctx_node->module;
Michal Vasko004d3152020-06-11 19:59:22 +0200590 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200591 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200592 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +0100593 case LY_VALUE_STR_NS:
Radek Krejcif9943642021-04-26 10:18:21 +0200594 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200595 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200596 }
597 }
598
Michal Vasko8cc3f662022-03-29 11:25:51 +0200599 /* find schema node */
600 if (!prev_ctx_node && top_ext) {
601 *snode = lysc_ext_find_node(top_ext, mod, name, name_len, 0, getnext_opts);
Michal Vasko004d3152020-06-11 19:59:22 +0200602 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200603 *snode = lys_find_child(prev_ctx_node, mod, name, name_len, 0, getnext_opts);
604 if (!(*snode) && prev_ctx_node) {
605 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
606 LY_CHECK_RET(ret && (ret != LY_ENOT), ret);
607 }
608 }
609 if (!(*snode)) {
610 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
611 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200612 }
613
Michal Vasko8cc3f662022-03-29 11:25:51 +0200614success:
615 if (ext) {
616 *ext = e;
617 }
Michal Vasko004d3152020-06-11 19:59:22 +0200618 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100619
620error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100621 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200622 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200623}
624
625LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200626ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vaskodd528af2022-08-08 14:35:07 +0200627 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format,
Michal Vasko90189962023-02-28 12:10:34 +0100628 void *prefix_data, struct ly_path_predicate **predicates)
Michal Vasko004d3152020-06-11 19:59:22 +0200629{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100630 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200631 struct ly_path_predicate *p;
632 const struct lysc_node *key;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200633 const char *val;
634 size_t val_len, key_count;
Michal Vasko004d3152020-06-11 19:59:22 +0200635
Michal Vasko00cbf532020-06-15 13:58:47 +0200636 assert(ctx && ctx_node);
637
Radek Krejciddace2c2021-01-08 11:30:56 +0100638 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100639
Michal Vasko90189962023-02-28 12:10:34 +0100640 *predicates = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200641
Michal Vasko004d3152020-06-11 19:59:22 +0200642 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200643 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100644 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200645 }
646
647 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
648 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100649 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200650 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100651 ret = LY_EVALID;
652 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200653 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100654 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200655 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100656 ret = LY_EVALID;
657 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200658 }
659
660 do {
661 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200662 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
663 NULL, 0, &key, NULL));
664 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100665 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
666 key->name);
667 ret = LY_EVALID;
668 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200669 }
670 ++(*tok_idx);
671
Michal Vasko90189962023-02-28 12:10:34 +0100672 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100673 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200674 p->key = key;
675
676 /* '=' */
677 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
678 ++(*tok_idx);
679
Michal Vasko90189962023-02-28 12:10:34 +0100680 /* Literal, Number, or VariableReference */
681 if (expr->tokens[*tok_idx] == LYXP_TOKEN_VARREF) {
682 /* store the variable name */
683 p->variable = strndup(expr->expr + expr->tok_pos[*tok_idx], expr->tok_len[*tok_idx]);
684 LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); ret = LY_EMEM, cleanup);
685
686 p->type = LY_PATH_PREDTYPE_LIST_VAR;
687 ++(*tok_idx);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200688 } else {
Michal Vasko90189962023-02-28 12:10:34 +0100689 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
690 /* skip quotes */
691 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
692 val_len = expr->tok_len[*tok_idx] - 2;
693 } else {
694 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
695 val = expr->expr + expr->tok_pos[*tok_idx];
696 val_len = expr->tok_len[*tok_idx];
697 }
698
699 /* store the value */
700 LOG_LOCSET(key, NULL, NULL, NULL);
Michal Vasko989cdb42023-10-06 15:32:37 +0200701 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, NULL,
702 format, prefix_data, LYD_HINT_DATA, key, NULL);
Michal Vasko90189962023-02-28 12:10:34 +0100703 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
704 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
705
706 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
707 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
708
709 p->type = LY_PATH_PREDTYPE_LIST;
710 ++(*tok_idx);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200711 }
712
Michal Vasko004d3152020-06-11 19:59:22 +0200713 /* ']' */
714 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
715 ++(*tok_idx);
716
717 /* another predicate follows? */
718 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
719
720 /* check that all keys were set */
721 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100722 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200723 ++key_count;
724 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200725 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200726 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100727 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200728 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko90189962023-02-28 12:10:34 +0100729 ly_path_predicates_free(ctx, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200730 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100731 ret = LY_EVALID;
732 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200733 }
734
735 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
736 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100737 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200738 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100739 ret = LY_EVALID;
740 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200741 }
742 ++(*tok_idx);
743
744 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100745 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100746 p->type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko004d3152020-06-11 19:59:22 +0200747
748 /* '=' */
749 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
750 ++(*tok_idx);
751
Michal Vasko4911eeb2021-06-28 11:23:05 +0200752 /* Literal or Number */
753 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
754 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
755 /* skip quotes */
756 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
757 val_len = expr->tok_len[*tok_idx] - 2;
758 } else {
759 val = expr->expr + expr->tok_pos[*tok_idx];
760 val_len = expr->tok_len[*tok_idx];
761 }
762
Michal Vasko004d3152020-06-11 19:59:22 +0200763 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100764 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Michal Vasko989cdb42023-10-06 15:32:37 +0200765 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, NULL,
766 format, prefix_data, LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100767 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200768 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200769 ++(*tok_idx);
770
Michal Vaskoae875662020-10-21 10:33:17 +0200771 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200772 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200773
Michal Vasko004d3152020-06-11 19:59:22 +0200774 /* ']' */
775 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
776 ++(*tok_idx);
777 } else {
778 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
779 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100780 ret = LY_EVALID;
781 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200782 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100783 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200784 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100785 ret = LY_EVALID;
786 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200787 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100788 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200789 }
Michal Vasko004d3152020-06-11 19:59:22 +0200790
791 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100792 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100793 p->type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko004d3152020-06-11 19:59:22 +0200794
795 /* syntax was already checked */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200796 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200797 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200798
799 /* ']' */
800 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
801 ++(*tok_idx);
802 }
803
Radek Krejci2efc45b2020-12-22 16:25:44 +0100804cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100805 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100806 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200807}
808
809/**
810 * @brief Compile leafref predicate. Actually, it is only checked.
811 *
812 * @param[in] ctx_node Context node, node for which the predicate is defined.
813 * @param[in] cur_node Current (original context) node.
814 * @param[in] expr Parsed path.
815 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200816 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200817 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200818 * @return LY_ERR value.
819 */
820static LY_ERR
821ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vaskodd528af2022-08-08 14:35:07 +0200822 const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200823{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100824 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200825 const struct lysc_node *key, *node, *node2;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100826 struct ly_ctx *ctx = cur_node->module->ctx;
827
Michal Vasko004d3152020-06-11 19:59:22 +0200828 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200829 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100830 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200831 }
832
833 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100834 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200835 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100836 ret = LY_EVALID;
837 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200838 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100839 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200840 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100841 ret = LY_EVALID;
842 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200843 }
844
845 do {
846 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200847 ret = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
848 NULL, 0, &key, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100849 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200850 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100851 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200852 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100853 ret = LY_EVALID;
854 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200855 }
856 ++(*tok_idx);
857
858 /* we are not actually compiling, throw the key away */
859 (void)key;
860
861 /* '=' */
862 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
863 ++(*tok_idx);
864
865 /* FuncName */
866 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
867 ++(*tok_idx);
868
869 /* evaluating from the "current()" node */
870 node = cur_node;
871
872 /* '(' */
873 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
874 ++(*tok_idx);
875
876 /* ')' */
877 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
878 ++(*tok_idx);
879
880 do {
881 /* '/' */
882 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
883 ++(*tok_idx);
884
885 /* go to parent */
886 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100887 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
888 ret = LY_EVALID;
889 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200890 }
891 node = lysc_data_parent(node);
892
893 /* '..' */
894 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
895 ++(*tok_idx);
896 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
897
898 do {
899 /* '/' */
900 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
901 ++(*tok_idx);
902
903 /* NameTest */
904 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200905 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
906 prefix_data, NULL, 0, &node2, NULL));
Michal Vasko004d3152020-06-11 19:59:22 +0200907 node = node2;
908 ++(*tok_idx);
909 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
910
911 /* check the last target node */
912 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100913 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200914 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100915 ret = LY_EVALID;
916 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200917 }
918
919 /* we are not actually compiling, throw the rightside node away */
920 (void)node;
921
922 /* ']' */
923 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
924 ++(*tok_idx);
925
Radek Krejci0f969882020-08-21 16:56:47 +0200926 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200927 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
928
Radek Krejci2efc45b2020-12-22 16:25:44 +0100929cleanup:
Michal Vasko8cc3f662022-03-29 11:25:51 +0200930 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200931}
932
Michal Vaskoed725d72021-06-23 12:03:45 +0200933/**
stewegd8e2fc92023-05-31 09:52:56 +0200934 * @brief Duplicate ly_path_predicate structure.
935 *
936 * @param[in] ctx libyang context.
937 * @param[in] pred The array of path predicates.
938 * @param[out] dup Duplicated predicates.
939 * @return LY_ERR value.
940 */
941static LY_ERR
942ly_path_dup_predicates(const struct ly_ctx *ctx, const struct ly_path_predicate *pred, struct ly_path_predicate **dup)
943{
944 LY_ARRAY_COUNT_TYPE u;
945
946 if (!pred) {
947 return LY_SUCCESS;
948 }
949
950 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(pred), LY_EMEM);
951 LY_ARRAY_FOR(pred, u) {
952 LY_ARRAY_INCREMENT(*dup);
953 (*dup)[u].type = pred->type;
954
Michal Vasko5339b4f2023-09-29 14:38:08 +0200955 switch (pred[u].type) {
stewegd8e2fc92023-05-31 09:52:56 +0200956 case LY_PATH_PREDTYPE_POSITION:
957 /* position-predicate */
Michal Vasko5339b4f2023-09-29 14:38:08 +0200958 (*dup)[u].position = pred[u].position;
stewegd8e2fc92023-05-31 09:52:56 +0200959 break;
960 case LY_PATH_PREDTYPE_LIST:
961 case LY_PATH_PREDTYPE_LEAFLIST:
962 /* key-predicate or leaf-list-predicate */
Michal Vasko5339b4f2023-09-29 14:38:08 +0200963 (*dup)[u].key = pred[u].key;
964 pred[u].value.realtype->plugin->duplicate(ctx, &pred[u].value, &(*dup)[u].value);
965 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred[u].value.realtype)->refcount);
stewegd8e2fc92023-05-31 09:52:56 +0200966 break;
967 case LY_PATH_PREDTYPE_LIST_VAR:
968 /* key-predicate with a variable */
Michal Vasko5339b4f2023-09-29 14:38:08 +0200969 (*dup)[u].key = pred[u].key;
970 (*dup)[u].variable = strdup(pred[u].variable);
stewegd8e2fc92023-05-31 09:52:56 +0200971 break;
972 }
973 }
974
975 return LY_SUCCESS;
976}
977
978/**
979 * @brief Appends path elements from source to destination array
980 *
981 * @param[in] ctx libyang context.
982 * @param[in] src The source path
983 * @param[in,out] dst The destination path
984 * @return LY_ERR value.
985 */
986static LY_ERR
987ly_path_append(const struct ly_ctx *ctx, const struct ly_path *src, struct ly_path **dst)
988{
989 LY_ERR ret = LY_SUCCESS;
990 LY_ARRAY_COUNT_TYPE u;
991 struct ly_path *p;
992
993 if (!src) {
994 return LY_SUCCESS;
995 }
996
997 LY_ARRAY_CREATE_RET(ctx, *dst, LY_ARRAY_COUNT(src), LY_EMEM);
998 LY_ARRAY_FOR(src, u) {
Michal Vasko696915b2023-05-31 10:12:11 +0200999 LY_ARRAY_NEW_GOTO(ctx, *dst, p, ret, cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001000 p->node = src[u].node;
1001 p->ext = src[u].ext;
Michal Vasko696915b2023-05-31 10:12:11 +02001002 LY_CHECK_GOTO(ret = ly_path_dup_predicates(ctx, src[u].predicates, &p->predicates), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001003 }
1004
Michal Vasko696915b2023-05-31 10:12:11 +02001005cleanup:
1006 return ret;
stewegd8e2fc92023-05-31 09:52:56 +02001007}
1008
1009/**
1010 * @brief Compile deref XPath function into ly_path structure.
1011 *
1012 * @param[in] ctx libyang context.
1013 * @param[in] ctx_node Optional context node, mandatory of @p lref.
1014 * @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find
1015 * the top-level node inside the extension instance instead of a module. Note that this is the case not only if
1016 * the @p ctx_node is NULL, but also if the relative path starting in @p ctx_node reaches the document root
1017 * via double dots.
1018 * @param[in] expr Parsed path.
1019 * @param[in] oper Oper option (@ref path_oper_options).
1020 * @param[in] target Target option (@ref path_target_options).
1021 * @param[in] format Format of the path.
1022 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
1023 * @param[in,out] tok_idx Index in @p exp, is adjusted.
1024 * @param[out] path Compiled path.
1025 * @return LY_ERR value.
1026 */
1027static LY_ERR
1028ly_path_compile_deref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
1029 const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint16_t oper, uint16_t target,
1030 LY_VALUE_FORMAT format, void *prefix_data, uint32_t *tok_idx, struct ly_path **path)
1031{
1032 LY_ERR ret = LY_SUCCESS;
1033 struct lyxp_expr expr2;
1034 struct ly_path *path2 = NULL;
1035 const struct lysc_node *node2;
1036 const struct lysc_node_leaf *deref_leaf_node;
1037 const struct lysc_type_leafref *lref;
1038 uint32_t begin_token;
1039
Michal Vasko696915b2023-05-31 10:12:11 +02001040 *path = NULL;
1041
stewegd8e2fc92023-05-31 09:52:56 +02001042 /* properly parsed path must always starts with 'deref' and '(' */
1043 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_FUNCNAME));
1044 assert(!strncmp(&expr->expr[expr->tok_pos[*tok_idx]], "deref", 5));
1045 (*tok_idx)++;
1046 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR1));
1047 (*tok_idx)++;
1048 begin_token = *tok_idx;
1049
1050 /* emebedded functions were already identified count tokens till ')' */
1051 while (lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2) && (*tok_idx < expr->used)) {
1052 (*tok_idx)++;
1053 }
1054
1055 /* properly parsed path must have ')' within the tokens */
1056 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2));
1057
1058 /* prepare expr representing just deref arg */
1059 expr2.tokens = &expr->tokens[begin_token];
1060 expr2.tok_pos = &expr->tok_pos[begin_token];
1061 expr2.tok_len = &expr->tok_len[begin_token];
1062 expr2.repeat = &expr->repeat[begin_token];
1063 expr2.used = *tok_idx - begin_token;
1064 expr2.size = expr->size - begin_token;
1065 expr2.expr = expr->expr;
1066
1067 /* compile just deref arg, append it to the path and find dereferenced lref for next operations */
Michal Vasko696915b2023-05-31 10:12:11 +02001068 LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, ctx_node, top_ext, &expr2, oper, target, format, prefix_data,
1069 &path2), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001070 node2 = path2[LY_ARRAY_COUNT(path2) - 1].node;
steweg1ac8b412023-10-31 13:25:33 +01001071 if ((node2->nodetype != LYS_LEAF) && (node2->nodetype != LYS_LEAFLIST)) {
1072 LOGVAL(ctx, LYVE_XPATH, "The deref function target node \"%s\" is not leaf nor leaflist", node2->name);
1073 ret = LY_EVALID;
1074 goto cleanup;
1075 }
stewegd8e2fc92023-05-31 09:52:56 +02001076 deref_leaf_node = (const struct lysc_node_leaf *)node2;
steweg1ac8b412023-10-31 13:25:33 +01001077 if (deref_leaf_node->type->basetype != LY_TYPE_LEAFREF) {
1078 LOGVAL(ctx, LYVE_XPATH, "The deref function target node \"%s\" is not leafref", node2->name);
1079 ret = LY_EVALID;
1080 goto cleanup;
1081 }
stewegd8e2fc92023-05-31 09:52:56 +02001082 lref = (const struct lysc_type_leafref *)deref_leaf_node->type;
Michal Vasko696915b2023-05-31 10:12:11 +02001083 LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001084 ly_path_free(ctx, path2);
1085 path2 = NULL;
1086
1087 /* compile dereferenced leafref expression and append it to the path */
Michal Vasko696915b2023-05-31 10:12:11 +02001088 LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, node2, top_ext, lref->path, oper, target, format, prefix_data,
1089 &path2), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001090 node2 = path2[LY_ARRAY_COUNT(path2) - 1].node;
Michal Vasko696915b2023-05-31 10:12:11 +02001091 LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001092 ly_path_free(ctx, path2);
1093 path2 = NULL;
1094
1095 /* properly parsed path must always continue with ')' and '/' */
1096 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2));
1097 (*tok_idx)++;
1098 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_OPER_PATH));
1099 (*tok_idx)++;
1100
1101 /* prepare expr representing rest of the path after deref */
1102 expr2.tokens = &expr->tokens[*tok_idx];
1103 expr2.tok_pos = &expr->tok_pos[*tok_idx];
1104 expr2.tok_len = &expr->tok_len[*tok_idx];
1105 expr2.repeat = &expr->repeat[*tok_idx];
1106 expr2.used = expr->used - *tok_idx;
1107 expr2.size = expr->size - *tok_idx;
1108 expr2.expr = expr->expr;
1109
1110 /* compile rest of the path and append it to the path */
Michal Vasko696915b2023-05-31 10:12:11 +02001111 LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, node2, top_ext, &expr2, oper, target, format, prefix_data, &path2),
1112 cleanup);
1113 LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001114
1115cleanup:
1116 ly_path_free(ctx, path2);
1117 if (ret) {
1118 ly_path_free(ctx, *path);
1119 *path = NULL;
1120 }
Michal Vasko696915b2023-05-31 10:12:11 +02001121 return ret;
stewegd8e2fc92023-05-31 09:52:56 +02001122}
1123
1124/**
Michal Vaskoed725d72021-06-23 12:03:45 +02001125 * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
1126 *
1127 * @param[in] ctx libyang context.
1128 * @param[in] cur_mod Current module of the path (where it was "instantiated"), ignored of @p lref. Used for nodes
Radek Krejci84d7fd72021-07-14 18:32:21 +02001129 * without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
Michal Vaskoed725d72021-06-23 12:03:45 +02001130 * @param[in] ctx_node Optional context node, mandatory of @p lref.
Michal Vasko8cc3f662022-03-29 11:25:51 +02001131 * @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find the top-level
Michal Vaskoed725d72021-06-23 12:03:45 +02001132 * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
1133 * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
1134 * @param[in] expr Parsed path.
1135 * @param[in] lref Whether leafref is being compiled or not.
1136 * @param[in] oper Oper option (@ref path_oper_options).
1137 * @param[in] target Target option (@ref path_target_options).
Michal Vasko0884d212021-10-14 09:21:46 +02001138 * @param[in] limit_access_tree Whether to limit accessible tree as described in
1139 * [XPath context](https://datatracker.ietf.org/doc/html/rfc7950#section-6.4.1).
Michal Vaskoed725d72021-06-23 12:03:45 +02001140 * @param[in] format Format of the path.
1141 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vaskoed725d72021-06-23 12:03:45 +02001142 * @param[out] path Compiled path.
1143 * @return LY_ERECOMPILE, only if @p lref.
1144 * @return LY_ERR value.
1145 */
1146static LY_ERR
1147_ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Michal Vasko32ca49b2023-02-17 15:11:35 +01001148 const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, ly_bool lref, uint16_t oper, uint16_t target,
Michal Vasko0884d212021-10-14 09:21:46 +02001149 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +02001150{
1151 LY_ERR ret = LY_SUCCESS;
Michal Vaskodd528af2022-08-08 14:35:07 +02001152 uint32_t tok_idx = 0, getnext_opts;
Michal Vasko6b26e742020-07-17 15:02:10 +02001153 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +02001154 struct ly_path *p = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +02001155 struct lysc_ext_instance *ext = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001156
Michal Vasko00cbf532020-06-15 13:58:47 +02001157 assert(ctx);
Michal Vaskoed725d72021-06-23 12:03:45 +02001158 assert(!lref || ctx_node);
Michal Vasko00cbf532020-06-15 13:58:47 +02001159 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
1160 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +02001161
Michal Vasko0884d212021-10-14 09:21:46 +02001162 if (!limit_access_tree) {
1163 op = NULL;
1164 } else {
1165 /* find operation, if we are in any */
1166 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
1167 }
Michal Vasko6b26e742020-07-17 15:02:10 +02001168
Radek Krejci2efc45b2020-12-22 16:25:44 +01001169 *path = NULL;
1170
Michal Vasko6b26e742020-07-17 15:02:10 +02001171 /* remember original context node */
1172 cur_node = ctx_node;
Michal Vasko62225e22022-08-05 10:06:50 +02001173 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02001174
Michal Vasko00cbf532020-06-15 13:58:47 +02001175 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001176 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +02001177 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001178 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +02001179 }
1180
stewegd8e2fc92023-05-31 09:52:56 +02001181 if (lref && (ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_EXTENDED) &&
1182 (expr->tokens[tok_idx] == LYXP_TOKEN_FUNCNAME)) {
1183 /* deref function */
1184 ret = ly_path_compile_deref(ctx, ctx_node, top_ext, expr, oper, target, format, prefix_data, &tok_idx, path);
stewegd8e2fc92023-05-31 09:52:56 +02001185 goto cleanup;
1186 } else if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
Michal Vasko004d3152020-06-11 19:59:22 +02001187 /* absolute path */
1188 ctx_node = NULL;
1189
1190 ++tok_idx;
1191 } else {
1192 /* relative path */
Michal Vasko80239792021-11-02 11:48:32 +01001193 if (!ctx_node) {
1194 LOGVAL(ctx, LYVE_XPATH, "No initial schema parent for a relative path.");
1195 ret = LY_EVALID;
1196 goto cleanup;
1197 }
1198
1199 /* go up the parents for leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +02001200 while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
Michal Vasko004d3152020-06-11 19:59:22 +02001201 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001202 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +01001203 ret = LY_EVALID;
1204 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +02001205 }
1206
1207 /* get parent */
1208 ctx_node = lysc_data_parent(ctx_node);
1209
1210 ++tok_idx;
1211
1212 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
1213 ++tok_idx;
1214 }
Michal Vasko004d3152020-06-11 19:59:22 +02001215 }
1216
1217 do {
Michal Vasko00cbf532020-06-15 13:58:47 +02001218 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskoed725d72021-06-23 12:03:45 +02001219 if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001220 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +02001221 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +01001222 ret = LY_EVALID;
1223 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +02001224 }
1225
Michal Vasko14424ba2020-12-09 18:09:51 +01001226 /* NameTest */
1227 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
1228
Michal Vasko8cc3f662022-03-29 11:25:51 +02001229 /* get schema node */
1230 LY_CHECK_GOTO(ret = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
1231 top_ext, getnext_opts, &node2, &ext), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02001232 ++tok_idx;
Michal Vasko8cc3f662022-03-29 11:25:51 +02001233 if ((op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
1234 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
Radek Krejci8de005f2020-06-25 17:02:07 +02001235 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02001236 goto cleanup;
1237 }
1238 ctx_node = node2;
1239
1240 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +02001241 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02001242 p->node = ctx_node;
Michal Vasko8cc3f662022-03-29 11:25:51 +02001243 p->ext = ext;
Michal Vasko004d3152020-06-11 19:59:22 +02001244
1245 /* compile any predicates */
Michal Vaskoed725d72021-06-23 12:03:45 +02001246 if (lref) {
Michal Vasko24fc4d12021-07-12 14:41:20 +02001247 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +02001248 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +02001249 ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
Michal Vasko90189962023-02-28 12:10:34 +01001250 &p->predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001251 }
1252 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02001253 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
1254
Michal Vasko14424ba2020-12-09 18:09:51 +01001255 /* check leftover tokens */
1256 if (tok_idx < expr->used) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02001257 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(expr->tokens[tok_idx]), &expr->expr[expr->tok_pos[tok_idx]]);
Michal Vasko14424ba2020-12-09 18:09:51 +01001258 ret = LY_EVALID;
1259 goto cleanup;
1260 }
1261
Michal Vasko00cbf532020-06-15 13:58:47 +02001262 /* check last compiled node */
Michal Vaskoed725d72021-06-23 12:03:45 +02001263 if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001264 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +02001265 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +01001266 ret = LY_EVALID;
1267 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +02001268 }
1269
Michal Vasko004d3152020-06-11 19:59:22 +02001270cleanup:
1271 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001272 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +02001273 *path = NULL;
1274 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001275 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko8cc3f662022-03-29 11:25:51 +02001276 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +02001277}
1278
1279LY_ERR
Michal Vaskoed725d72021-06-23 12:03:45 +02001280ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Michal Vasko32ca49b2023-02-17 15:11:35 +01001281 const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint16_t oper, uint16_t target,
Michal Vasko0884d212021-10-14 09:21:46 +02001282 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +02001283{
Michal Vasko8cc3f662022-03-29 11:25:51 +02001284 return _ly_path_compile(ctx, cur_mod, ctx_node, top_ext, expr, 0, oper, target, limit_access_tree, format,
1285 prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +02001286}
1287
1288LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +02001289ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *top_ext,
Michal Vasko32ca49b2023-02-17 15:11:35 +01001290 const struct lyxp_expr *expr, uint16_t oper, uint16_t target, LY_VALUE_FORMAT format, void *prefix_data,
Michal Vasko24fc4d12021-07-12 14:41:20 +02001291 struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +02001292{
Michal Vasko8cc3f662022-03-29 11:25:51 +02001293 return _ly_path_compile(ctx, ctx_node->module, ctx_node, top_ext, expr, 1, oper, target, 1, format, prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +02001294}
1295
1296LY_ERR
Michal Vasko90189962023-02-28 12:10:34 +01001297ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars,
Michal Vasko838829d2023-10-09 16:06:43 +02001298 ly_bool with_opaq, LY_ARRAY_COUNT_TYPE *path_idx, struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +02001299{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001300 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoe43e21f2022-06-07 12:26:36 +02001301 struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +02001302 uint64_t pos;
1303
1304 assert(path && start);
1305
1306 if (lysc_data_parent(path[0].node)) {
1307 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001308 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001309 } else {
1310 /* absolute path, start from the first top-level sibling */
1311 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +01001312 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001313 }
1314 while (start->prev->next) {
1315 start = start->prev;
1316 }
1317 }
1318
1319 LY_ARRAY_FOR(path, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001320 if (path[u].predicates) {
1321 switch (path[u].predicates[0].type) {
1322 case LY_PATH_PREDTYPE_POSITION:
1323 /* we cannot use hashes and want an instance on a specific position */
1324 pos = 1;
1325 node = NULL;
1326 LYD_LIST_FOR_INST(start, path[u].node, elem) {
1327 if (pos == path[u].predicates[0].position) {
1328 node = elem;
1329 break;
1330 }
1331 ++pos;
Michal Vasko004d3152020-06-11 19:59:22 +02001332 }
Michal Vasko90189962023-02-28 12:10:34 +01001333 break;
1334 case LY_PATH_PREDTYPE_LEAFLIST:
1335 /* we will use hashes to find one leaf-list instance */
1336 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
1337 lyd_find_sibling_first(start, target, &node);
1338 lyd_free_tree(target);
1339 break;
1340 case LY_PATH_PREDTYPE_LIST_VAR:
1341 case LY_PATH_PREDTYPE_LIST:
1342 /* we will use hashes to find one list instance */
1343 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, &target));
1344 lyd_find_sibling_first(start, target, &node);
1345 lyd_free_tree(target);
1346 break;
Michal Vasko004d3152020-06-11 19:59:22 +02001347 }
Michal Vasko90189962023-02-28 12:10:34 +01001348 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02001349 /* we will use hashes to find one any/container/leaf instance */
Michal Vasko838829d2023-10-09 16:06:43 +02001350 if (lyd_find_sibling_val(start, path[u].node, NULL, 0, &node) && with_opaq) {
1351 if (!lyd_find_sibling_opaq_next(start, path[u].node->name, &node) &&
1352 (lyd_node_module(node) != path[u].node->module)) {
1353 /* non-matching opaque node */
1354 node = NULL;
1355 }
1356 }
Michal Vasko004d3152020-06-11 19:59:22 +02001357 }
1358
1359 if (!node) {
1360 /* no matching nodes */
1361 break;
1362 }
1363
Michal Vasko00cbf532020-06-15 13:58:47 +02001364 /* rememeber previous node */
1365 prev_node = node;
1366
Michal Vasko004d3152020-06-11 19:59:22 +02001367 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001368 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +02001369 }
1370
Michal Vasko004d3152020-06-11 19:59:22 +02001371 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001372 /* we have found the full path */
1373 if (path_idx) {
1374 *path_idx = u;
1375 }
1376 if (match) {
1377 *match = node;
1378 }
Michal Vasko004d3152020-06-11 19:59:22 +02001379 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +02001380
1381 } else if (prev_node) {
1382 /* we have found only some partial match */
1383 if (path_idx) {
1384 *path_idx = u - 1;
1385 }
1386 if (match) {
1387 *match = prev_node;
1388 }
1389 return LY_EINCOMPLETE;
1390 }
1391
1392 /* we have not found any nodes */
1393 if (path_idx) {
1394 *path_idx = 0;
1395 }
1396 if (match) {
1397 *match = NULL;
1398 }
1399 return LY_ENOTFOUND;
1400}
1401
1402LY_ERR
Michal Vasko90189962023-02-28 12:10:34 +01001403ly_path_eval(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars, struct lyd_node **match)
Michal Vasko00cbf532020-06-15 13:58:47 +02001404{
1405 LY_ERR ret;
1406 struct lyd_node *m;
1407
Michal Vasko838829d2023-10-09 16:06:43 +02001408 ret = ly_path_eval_partial(path, start, vars, 0, NULL, &m);
Michal Vasko00cbf532020-06-15 13:58:47 +02001409
1410 if (ret == LY_SUCCESS) {
1411 /* last node was found */
1412 if (match) {
1413 *match = m;
1414 }
1415 return LY_SUCCESS;
1416 }
1417
1418 /* not a full match */
1419 if (match) {
1420 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001421 }
1422 return LY_ENOTFOUND;
1423}
1424
1425LY_ERR
1426ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1427{
stewegd8e2fc92023-05-31 09:52:56 +02001428 LY_ERR ret = LY_SUCCESS;
1429 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001430
1431 if (!path) {
1432 return LY_SUCCESS;
1433 }
1434
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001435 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001436 LY_ARRAY_FOR(path, u) {
1437 LY_ARRAY_INCREMENT(*dup);
1438 (*dup)[u].node = path[u].node;
stewegd8e2fc92023-05-31 09:52:56 +02001439 (*dup)[u].ext = path[u].ext;
1440 LY_CHECK_RET(ret = ly_path_dup_predicates(ctx, path[u].predicates, &(*dup)[u].predicates), ret);
Michal Vasko004d3152020-06-11 19:59:22 +02001441 }
1442
1443 return LY_SUCCESS;
1444}
1445
1446void
Michal Vasko90189962023-02-28 12:10:34 +01001447ly_path_predicates_free(const struct ly_ctx *ctx, struct ly_path_predicate *predicates)
Michal Vasko004d3152020-06-11 19:59:22 +02001448{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001449 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001450 struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
Michal Vasko004d3152020-06-11 19:59:22 +02001451
1452 if (!predicates) {
1453 return;
1454 }
1455
1456 LY_ARRAY_FOR(predicates, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001457 switch (predicates[u].type) {
Michal Vasko004d3152020-06-11 19:59:22 +02001458 case LY_PATH_PREDTYPE_POSITION:
Michal Vasko004d3152020-06-11 19:59:22 +02001459 /* nothing to free */
1460 break;
1461 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001462 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001463 if (predicates[u].value.realtype) {
1464 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
Michal Vaskoc636ea42022-09-16 10:20:31 +02001465 lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype);
Michal Vaskoae875662020-10-21 10:33:17 +02001466 }
Michal Vasko004d3152020-06-11 19:59:22 +02001467 break;
Michal Vasko90189962023-02-28 12:10:34 +01001468 case LY_PATH_PREDTYPE_LIST_VAR:
1469 free(predicates[u].variable);
1470 break;
Michal Vasko004d3152020-06-11 19:59:22 +02001471 }
1472 }
1473 LY_ARRAY_FREE(predicates);
1474}
1475
1476void
1477ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1478{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001479 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001480
Michal Vasko55b84812021-05-11 09:23:58 +02001481 if (!path) {
1482 return;
1483 }
1484
Michal Vasko004d3152020-06-11 19:59:22 +02001485 LY_ARRAY_FOR(path, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001486 ly_path_predicates_free(ctx, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001487 }
1488 LY_ARRAY_FREE(path);
1489}