blob: 3876762693fefc1c05981609f979fd4a01edc5f2 [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
Michal Vasko7a266772024-01-23 11:02:38 +010059 if (cur_node) {
60 LOG_LOCSET(cur_node, NULL);
61 }
Radek Krejci2efc45b2020-12-22 16:25:44 +010062
Michal Vasko004d3152020-06-11 19:59:22 +020063 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020064 /* '[' */
65
Michal Vasko69730152020-10-09 16:30:07 +020066 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
67 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020068 ret = ly_set_new(&set);
69 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020070
71 do {
72 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020073 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020074
75 /* check prefix based on the options */
76 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
77 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Michal Vasko21eaa392024-02-20 15:48:42 +010078 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", (int)exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020079 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020080 goto token_error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020081 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
Michal Vasko21eaa392024-02-20 15:48:42 +010082 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", (int)exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020083 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020084 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020085 }
86 if (!name) {
87 name = exp->expr + exp->tok_pos[*tok_idx];
88 name_len = exp->tok_len[*tok_idx];
89 } else {
90 ++name;
91 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
92 }
93
94 /* check whether it was not already specified */
95 for (i = 0; i < set->count; ++i) {
96 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +020097 if (!strncmp(set->objs[i], name, name_len) &&
98 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +010099 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200100 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200101 }
102 }
103
104 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200105 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200106 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200107
108 /* NameTest */
109 ++(*tok_idx);
110
111 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200112 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200113
Michal Vaskob01983e2023-04-24 10:43:13 +0200114 /* fill repeat */
115 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
116 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
117 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
118
Michal Vasko90189962023-02-28 12:10:34 +0100119 /* Literal, Number, or VariableReference */
120 if (lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_LITERAL) &&
121 lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER) &&
122 lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_VARREF)) {
123 /* error */
124 lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL);
125 goto token_error;
126 }
Michal Vasko004d3152020-06-11 19:59:22 +0200127
128 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200129 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200130
Radek Krejci0f969882020-08-21 16:56:47 +0200131 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200132 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
133
Michal Vasko004d3152020-06-11 19:59:22 +0200134 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200135 /* '.' */
136
Michal Vasko004d3152020-06-11 19:59:22 +0200137 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200138 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200139
Michal Vaskob01983e2023-04-24 10:43:13 +0200140 /* fill repeat */
141 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
142 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
143 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
144
Michal Vasko4911eeb2021-06-28 11:23:05 +0200145 /* Literal or Number */
146 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 +0200147
148 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200149 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200150
Michal Vasko004d3152020-06-11 19:59:22 +0200151 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200152 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200153
Michal Vasko2261dfa2022-09-29 12:29:20 +0200154 /* check for index 0 */
155 if (!atoi(exp->expr + exp->tok_pos[*tok_idx - 1])) {
156 LOGVAL(ctx, LYVE_XPATH, "Invalid positional predicate \"%.*s\".", (int)exp->tok_len[*tok_idx - 1],
157 exp->expr + exp->tok_pos[*tok_idx - 1]);
158 goto token_error;
159 }
160
Michal Vasko004d3152020-06-11 19:59:22 +0200161 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200162 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200163
164 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
165 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200166 ret = ly_set_new(&set);
167 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200168
169 do {
170 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200171 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200172
173 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
174 if (!name) {
175 name = exp->expr + exp->tok_pos[*tok_idx];
176 name_len = exp->tok_len[*tok_idx];
177 } else {
178 ++name;
179 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
180 }
181
182 /* check whether it was not already specified */
183 for (i = 0; i < set->count; ++i) {
184 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +0200185 if (!strncmp(set->objs[i], name, name_len) &&
186 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +0100187 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200188 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200189 }
190 }
191
192 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200193 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200194 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200195
196 /* NameTest */
197 ++(*tok_idx);
198
199 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200200 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200201
Michal Vaskob01983e2023-04-24 10:43:13 +0200202 /* fill repeat */
203 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
204 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
205 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
206
Michal Vasko004d3152020-06-11 19:59:22 +0200207 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200208 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100209 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
210 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100211 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko21eaa392024-02-20 15:48:42 +0100212 (int)exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200213 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200214 }
215 ++(*tok_idx);
216
217 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200218 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200219
220 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200221 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200222
223 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200224 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200225
226 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200227 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200228 do {
229 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200230 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200231 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
232
233 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200234 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200235
236 /* '/' */
237 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
238 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200239 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200240 }
241
242 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200243 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200244
Radek Krejci0f969882020-08-21 16:56:47 +0200245 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200246 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
247
Michal Vasko3c19b492022-09-05 08:48:10 +0200248 } else if (lyxp_check_token(ctx, exp, *tok_idx, 0)) {
249 /* unexpected EOF */
250 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200251 } else {
Michal Vasko3c19b492022-09-05 08:48:10 +0200252 /* invalid token */
Michal Vasko49fec8e2022-05-24 10:28:33 +0200253 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 +0200254 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200255 }
256 }
257
Radek Krejciba03a5a2020-08-27 14:40:41 +0200258cleanup:
Michal Vasko7a266772024-01-23 11:02:38 +0100259 LOG_LOCBACK(cur_node ? 1 : 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200260 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200261 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200262
Radek Krejciba03a5a2020-08-27 14:40:41 +0200263token_error:
Michal Vasko7a266772024-01-23 11:02:38 +0100264 LOG_LOCBACK(cur_node ? 1 : 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200265 ly_set_free(set, NULL);
266 return LY_EVALID;
267}
268
stewegd8e2fc92023-05-31 09:52:56 +0200269/**
270 * @brief Parse deref XPath function and perform all additional checks.
271 *
272 * @param[in] ctx libyang context.
273 * @param[in] ctx_node Optional context node, used for logging.
274 * @param[in] exp Parsed path.
275 * @param[in,out] tok_idx Index in @p exp, is adjusted.
276 * @return LY_ERR value.
277 */
278static LY_ERR
279ly_path_parse_deref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lyxp_expr *exp,
280 uint32_t *tok_idx)
281{
282 size_t arg_len;
283 uint32_t begin_token, end_token;
284 struct lyxp_expr *arg_expr = NULL;
285
286 /* mandatory FunctionName */
287 LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_FUNCNAME), LY_EVALID);
288 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "deref", 5)) {
289 LOGVAL(ctx, LYVE_XPATH, "Unexpected XPath function \"%.*s\" in path, expected \"deref(...)\"",
Michal Vasko21eaa392024-02-20 15:48:42 +0100290 (int)exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
stewegd8e2fc92023-05-31 09:52:56 +0200291 return LY_EVALID;
292 }
293
294 /* mandatory '(' */
295 LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), LY_EVALID);
296 begin_token = *tok_idx;
297
298 /* count tokens till ')' */
299 while (lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_PAR2) && *tok_idx < exp->used) {
300 /* emebedded functions are not allowed */
301 if (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_FUNCNAME)) {
302 LOGVAL(ctx, LYVE_XPATH, "Embedded function XPath function inside deref function within the path"
303 "is not allowed");
304 return LY_EVALID;
305 }
306
307 (*tok_idx)++;
308 }
309
310 /* mandatory ')' */
311 LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), LY_EVALID);
312 end_token = *tok_idx - 1;
313
314 /* parse the path of deref argument */
315 arg_len = exp->tok_pos[end_token] - exp->tok_pos[begin_token];
316 LY_CHECK_RET(ly_path_parse(ctx, ctx_node, &exp->expr[exp->tok_pos[begin_token]], arg_len, 1,
317 LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &arg_expr), LY_EVALID);
318 lyxp_expr_free(ctx, arg_expr);
319
320 return LY_SUCCESS;
321}
322
Michal Vasko004d3152020-06-11 19:59:22 +0200323LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200324ly_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 +0100325 ly_bool lref, uint16_t begin, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200326{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200327 LY_ERR ret = LY_SUCCESS;
328 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200329 uint32_t tok_idx, cur_len;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200330 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko32ca49b2023-02-17 15:11:35 +0100331 ly_bool is_abs;
Michal Vasko004d3152020-06-11 19:59:22 +0200332
333 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
Michal Vasko69730152020-10-09 16:30:07 +0200334 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
Michal Vasko32ca49b2023-02-17 15:11:35 +0100335 (prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200336 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
337
Michal Vasko7a266772024-01-23 11:02:38 +0100338 if (ctx_node) {
339 LOG_LOCSET(ctx_node, NULL);
340 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100341
Michal Vaskob01983e2023-04-24 10:43:13 +0200342 /* parse as a generic XPath expression, reparse is performed manually */
343 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200344 tok_idx = 0;
345
Michal Vaskob01983e2023-04-24 10:43:13 +0200346 /* alloc empty repeat (only '=', filled manually) */
347 exp->repeat = calloc(exp->size, sizeof *exp->repeat);
348 LY_CHECK_ERR_GOTO(!exp->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
349
Michal Vasko004d3152020-06-11 19:59:22 +0200350 if (begin == LY_PATH_BEGIN_EITHER) {
351 /* is the path relative? */
352 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200353 /* relative path check specific to leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200354 if (lref) {
stewegd8e2fc92023-05-31 09:52:56 +0200355 /* optional function 'deref..' */
356 if ((ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_EXTENDED) &&
357 !lyxp_check_token(NULL, exp, tok_idx, LYXP_TOKEN_FUNCNAME)) {
358 LY_CHECK_ERR_GOTO(ly_path_parse_deref(ctx, ctx_node, exp, &tok_idx), ret = LY_EVALID, error);
359
360 /* '/' */
361 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID,
362 error);
363 }
364
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200365 /* mandatory '..' */
366 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
367
368 do {
369 /* '/' */
stewegd8e2fc92023-05-31 09:52:56 +0200370 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID,
371 error);
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200372
373 /* optional '..' */
374 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200375 }
Michal Vasko32ca49b2023-02-17 15:11:35 +0100376
377 is_abs = 0;
378 } else {
379 is_abs = 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200380 }
381 } else {
382 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200383 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 +0100384
385 is_abs = 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200386 }
387
388 do {
389 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200390 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 +0200391
392 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200393 cur_node = exp->expr + exp->tok_pos[tok_idx];
394 cur_len = exp->tok_len[tok_idx];
395 if (prefix == LY_PATH_PREFIX_MANDATORY) {
396 if (!strnstr(cur_node, ":", cur_len)) {
Michal Vasko21eaa392024-02-20 15:48:42 +0100397 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", (int)cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200398 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200399 goto error;
400 }
Michal Vasko32ca49b2023-02-17 15:11:35 +0100401 } else if ((prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) {
402 if (!prev_prefix && is_abs) {
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200403 /* the first node must have a prefix */
404 if (!strnstr(cur_node, ":", cur_len)) {
Michal Vasko21eaa392024-02-20 15:48:42 +0100405 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", (int)cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200406 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200407 goto error;
408 }
409
410 /* remember the first prefix */
411 prev_prefix = cur_node;
Michal Vasko32ca49b2023-02-17 15:11:35 +0100412 } else if (prev_prefix && (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) {
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200413 /* the prefix must be different, if any */
414 ptr = strnstr(cur_node, ":", cur_len);
415 if (ptr) {
416 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Michal Vasko21eaa392024-02-20 15:48:42 +0100417 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", (int)cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200418 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200419 goto error;
420 }
421
422 /* remember this next prefix */
423 prev_prefix = cur_node;
424 }
425 }
Michal Vasko004d3152020-06-11 19:59:22 +0200426 }
427
428 ++tok_idx;
429
430 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200431 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200432
Radek Krejci0f969882020-08-21 16:56:47 +0200433 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200434 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
435
436 /* trailing token check */
437 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100438 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 +0200439 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200440 goto error;
441 }
442
443 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100444
Michal Vasko7a266772024-01-23 11:02:38 +0100445 LOG_LOCBACK(ctx_node ? 1 : 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200446 return LY_SUCCESS;
447
448error:
449 lyxp_expr_free(ctx, exp);
Michal Vasko7a266772024-01-23 11:02:38 +0100450 LOG_LOCBACK(ctx_node ? 1 : 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200451 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200452}
453
454LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200455ly_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 +0100456 size_t path_len, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200457{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200458 LY_ERR ret = LY_SUCCESS;
459 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200460 uint32_t tok_idx;
Michal Vasko004d3152020-06-11 19:59:22 +0200461
462 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
463 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
464
Michal Vasko7a266772024-01-23 11:02:38 +0100465 if (cur_node) {
466 LOG_LOCSET(cur_node, NULL);
467 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100468
Michal Vaskob01983e2023-04-24 10:43:13 +0200469 /* parse as a generic XPath expression, reparse is performed manually */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200470 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200471 tok_idx = 0;
472
Michal Vaskob01983e2023-04-24 10:43:13 +0200473 /* alloc empty repeat (only '=', filled manually) */
474 exp->repeat = calloc(exp->size, sizeof *exp->repeat);
475 LY_CHECK_ERR_GOTO(!exp->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
476
Radek Krejcif03a9e22020-09-18 20:09:31 +0200477 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200478
479 /* trailing token check */
480 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100481 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200482 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200483 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200484 goto error;
485 }
486
487 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100488
Michal Vasko7a266772024-01-23 11:02:38 +0100489 LOG_LOCBACK(cur_node ? 1 : 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200490 return LY_SUCCESS;
491
492error:
493 lyxp_expr_free(ctx, exp);
Michal Vasko7a266772024-01-23 11:02:38 +0100494 LOG_LOCBACK(cur_node ? 1 : 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200495 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200496}
497
498/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200499 * @brief Parse NameTest and get the corresponding schema node.
Michal Vasko004d3152020-06-11 19:59:22 +0200500 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200501 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200502 * @param[in] cur_node Optional current (original context) node.
Radek Krejci84d7fd72021-07-14 18:32:21 +0200503 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
504 * and ::LY_VALUE_SCHEMA_RESOLVED.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200505 * @param[in] prev_ctx_node Previous context node.
Michal Vasko004d3152020-06-11 19:59:22 +0200506 * @param[in] expr Parsed path.
507 * @param[in] tok_idx Index in @p expr.
Michal Vasko004d3152020-06-11 19:59:22 +0200508 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200509 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko8cc3f662022-03-29 11:25:51 +0200510 * @param[in] top_ext Optional top-level extension to use for searching the schema node.
511 * @param[in] getnext_opts Options to be used for ::lys_getnext() calls.
512 * @param[out] snode Resolved schema node.
513 * @param[out] ext Optional extension instance of @p snode, if any.
Michal Vasko004d3152020-06-11 19:59:22 +0200514 * @return LY_ERR value.
515 */
516static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200517ly_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 +0200518 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 +0200519 void *prefix_data, const struct lysc_ext_instance *top_ext, uint32_t getnext_opts, const struct lysc_node **snode,
520 struct lysc_ext_instance **ext)
Michal Vasko004d3152020-06-11 19:59:22 +0200521{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100522 LY_ERR ret;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200523 const struct lys_module *mod = NULL;
524 struct lysc_ext_instance *e = NULL;
525 const char *pref, *name;
526 size_t len, name_len;
Michal Vasko004d3152020-06-11 19:59:22 +0200527
528 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
529
Michal Vasko8cc3f662022-03-29 11:25:51 +0200530 *snode = NULL;
531 if (ext) {
532 *ext = NULL;
533 }
534
Michal Vasko004d3152020-06-11 19:59:22 +0200535 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200536 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
537 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
538 pref = expr->expr + expr->tok_pos[tok_idx];
539 } else {
540 len = 0;
541 }
Michal Vasko004d3152020-06-11 19:59:22 +0200542
Michal Vasko8cc3f662022-03-29 11:25:51 +0200543 /* set name */
544 if (pref) {
545 name = pref + len + 1;
546 name_len = expr->tok_len[tok_idx] - len - 1;
547 } else {
548 name = expr->expr + expr->tok_pos[tok_idx];
549 name_len = expr->tok_len[tok_idx];
550 }
551
552 /* find node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200553 if (pref) {
Michal Vasko7a266772024-01-23 11:02:38 +0100554 if (cur_node) {
555 LOG_LOCSET(cur_node, NULL);
556 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100557
Michal Vasko35b29622022-07-22 14:12:56 +0200558 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 +0200559 if ((!mod || !mod->implemented) && prev_ctx_node) {
560 /* check for nested ext data */
561 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
562 if (!ret) {
563 goto success;
564 } else if (ret != LY_ENOT) {
565 goto error;
566 }
567 }
568
569 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100570 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100571 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200572 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100573 goto error;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200574 } else if (!mod->implemented) {
575 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
Michal Vaskoed725d72021-06-23 12:03:45 +0200576 ret = LY_EVALID;
577 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200578 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100579
Michal Vasko7a266772024-01-23 11:02:38 +0100580 LOG_LOCBACK(cur_node ? 1 : 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200581 } else {
582 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200583 case LY_VALUE_SCHEMA:
584 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200585 if (!cur_mod) {
586 LOGINT_RET(ctx);
587 }
588 /* use current module */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200589 mod = cur_mod;
Michal Vasko004d3152020-06-11 19:59:22 +0200590 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200591 case LY_VALUE_JSON:
Michal Vasko79228af2021-08-26 14:44:28 +0200592 case LY_VALUE_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200593 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200594 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200595 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200596 /* inherit module of the previous node */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200597 mod = prev_ctx_node->module;
Michal Vasko004d3152020-06-11 19:59:22 +0200598 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200599 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200600 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +0100601 case LY_VALUE_STR_NS:
Radek Krejcif9943642021-04-26 10:18:21 +0200602 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200603 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200604 }
605 }
606
Michal Vasko8cc3f662022-03-29 11:25:51 +0200607 /* find schema node */
608 if (!prev_ctx_node && top_ext) {
609 *snode = lysc_ext_find_node(top_ext, mod, name, name_len, 0, getnext_opts);
Michal Vasko004d3152020-06-11 19:59:22 +0200610 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200611 *snode = lys_find_child(prev_ctx_node, mod, name, name_len, 0, getnext_opts);
612 if (!(*snode) && prev_ctx_node) {
613 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
614 LY_CHECK_RET(ret && (ret != LY_ENOT), ret);
615 }
616 }
617 if (!(*snode)) {
618 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
619 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200620 }
621
Michal Vasko8cc3f662022-03-29 11:25:51 +0200622success:
623 if (ext) {
624 *ext = e;
625 }
Michal Vasko004d3152020-06-11 19:59:22 +0200626 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100627
628error:
Michal Vasko7a266772024-01-23 11:02:38 +0100629 LOG_LOCBACK(cur_node ? 1 : 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200630 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200631}
632
633LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200634ly_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 +0200635 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 +0100636 void *prefix_data, struct ly_path_predicate **predicates)
Michal Vasko004d3152020-06-11 19:59:22 +0200637{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100638 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200639 struct ly_path_predicate *p;
640 const struct lysc_node *key;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200641 const char *val;
642 size_t val_len, key_count;
Michal Vasko004d3152020-06-11 19:59:22 +0200643
Michal Vasko00cbf532020-06-15 13:58:47 +0200644 assert(ctx && ctx_node);
645
Michal Vasko7a266772024-01-23 11:02:38 +0100646 if (cur_node) {
647 LOG_LOCSET(cur_node, NULL);
648 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100649
Michal Vasko90189962023-02-28 12:10:34 +0100650 *predicates = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200651
Michal Vasko004d3152020-06-11 19:59:22 +0200652 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200653 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100654 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200655 }
656
657 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
658 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100659 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200660 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100661 ret = LY_EVALID;
662 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200663 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100664 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200665 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100666 ret = LY_EVALID;
667 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200668 }
669
670 do {
671 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200672 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
673 NULL, 0, &key, NULL));
674 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100675 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
676 key->name);
677 ret = LY_EVALID;
678 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200679 }
680 ++(*tok_idx);
681
Michal Vasko90189962023-02-28 12:10:34 +0100682 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100683 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200684 p->key = key;
685
686 /* '=' */
687 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
688 ++(*tok_idx);
689
Michal Vasko90189962023-02-28 12:10:34 +0100690 /* Literal, Number, or VariableReference */
691 if (expr->tokens[*tok_idx] == LYXP_TOKEN_VARREF) {
692 /* store the variable name */
693 p->variable = strndup(expr->expr + expr->tok_pos[*tok_idx], expr->tok_len[*tok_idx]);
694 LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); ret = LY_EMEM, cleanup);
695
696 p->type = LY_PATH_PREDTYPE_LIST_VAR;
697 ++(*tok_idx);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200698 } else {
Michal Vasko90189962023-02-28 12:10:34 +0100699 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
700 /* skip quotes */
701 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
702 val_len = expr->tok_len[*tok_idx] - 2;
703 } else {
704 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
705 val = expr->expr + expr->tok_pos[*tok_idx];
706 val_len = expr->tok_len[*tok_idx];
707 }
708
709 /* store the value */
Michal Vasko8108afa2024-02-27 09:16:33 +0100710 LOG_LOCSET(key, NULL);
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +0200711 ret = lyd_value_store(ctx_node->module->ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, 0,
stewegd4cde642024-02-21 08:34:16 +0100712 NULL, format, prefix_data, LYD_HINT_DATA, key, NULL);
Michal Vasko8108afa2024-02-27 09:16:33 +0100713 LOG_LOCBACK(1, 0);
Michal Vasko90189962023-02-28 12:10:34 +0100714 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
715
716 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
717 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
718
719 p->type = LY_PATH_PREDTYPE_LIST;
720 ++(*tok_idx);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200721 }
722
Michal Vasko004d3152020-06-11 19:59:22 +0200723 /* ']' */
724 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
725 ++(*tok_idx);
726
727 /* another predicate follows? */
728 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
729
730 /* check that all keys were set */
731 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100732 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200733 ++key_count;
734 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200735 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200736 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100737 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200738 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +0200739 ly_path_predicates_free(ctx_node->module->ctx, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200740 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100741 ret = LY_EVALID;
742 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200743 }
744
745 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
746 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100747 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200748 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100749 ret = LY_EVALID;
750 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200751 }
752 ++(*tok_idx);
753
754 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100755 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100756 p->type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko004d3152020-06-11 19:59:22 +0200757
758 /* '=' */
759 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
760 ++(*tok_idx);
761
Michal Vasko4911eeb2021-06-28 11:23:05 +0200762 /* Literal or Number */
763 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
764 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
765 /* skip quotes */
766 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
767 val_len = expr->tok_len[*tok_idx] - 2;
768 } else {
769 val = expr->expr + expr->tok_pos[*tok_idx];
770 val_len = expr->tok_len[*tok_idx];
771 }
772
Michal Vasko004d3152020-06-11 19:59:22 +0200773 /* store the value */
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +0200774 LOG_LOCSET(ctx_node, NULL);
775 ret = lyd_value_store(ctx_node->module->ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, 0,
stewegd4cde642024-02-21 08:34:16 +0100776 NULL, format, prefix_data, LYD_HINT_DATA, ctx_node, NULL);
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +0200777 LOG_LOCBACK(1, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200778 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200779 ++(*tok_idx);
780
Michal Vaskoae875662020-10-21 10:33:17 +0200781 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200782 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200783
Michal Vasko004d3152020-06-11 19:59:22 +0200784 /* ']' */
785 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
786 ++(*tok_idx);
787 } else {
788 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
789 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100790 ret = LY_EVALID;
791 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200792 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100793 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200794 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100795 ret = LY_EVALID;
796 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200797 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100798 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200799 }
Michal Vasko004d3152020-06-11 19:59:22 +0200800
801 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100802 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100803 p->type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko004d3152020-06-11 19:59:22 +0200804
805 /* syntax was already checked */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200806 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200807 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200808
809 /* ']' */
810 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
811 ++(*tok_idx);
812 }
813
Radek Krejci2efc45b2020-12-22 16:25:44 +0100814cleanup:
Michal Vasko7a266772024-01-23 11:02:38 +0100815 LOG_LOCBACK(cur_node ? 1 : 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100816 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200817}
818
819/**
820 * @brief Compile leafref predicate. Actually, it is only checked.
821 *
822 * @param[in] ctx_node Context node, node for which the predicate is defined.
823 * @param[in] cur_node Current (original context) node.
824 * @param[in] expr Parsed path.
825 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200826 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200827 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200828 * @return LY_ERR value.
829 */
830static LY_ERR
831ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vaskodd528af2022-08-08 14:35:07 +0200832 const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200833{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100834 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200835 const struct lysc_node *key, *node, *node2;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100836 struct ly_ctx *ctx = cur_node->module->ctx;
837
Michal Vasko004d3152020-06-11 19:59:22 +0200838 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200839 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100840 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200841 }
842
843 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100844 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200845 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100846 ret = LY_EVALID;
847 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200848 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100849 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200850 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100851 ret = LY_EVALID;
852 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200853 }
854
855 do {
856 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200857 ret = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
858 NULL, 0, &key, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100859 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200860 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100861 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200862 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100863 ret = LY_EVALID;
864 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200865 }
866 ++(*tok_idx);
867
868 /* we are not actually compiling, throw the key away */
869 (void)key;
870
871 /* '=' */
872 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
873 ++(*tok_idx);
874
875 /* FuncName */
876 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
877 ++(*tok_idx);
878
879 /* evaluating from the "current()" node */
880 node = cur_node;
881
882 /* '(' */
883 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
884 ++(*tok_idx);
885
886 /* ')' */
887 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
888 ++(*tok_idx);
889
890 do {
891 /* '/' */
892 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
893 ++(*tok_idx);
894
895 /* go to parent */
896 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100897 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
898 ret = LY_EVALID;
899 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200900 }
901 node = lysc_data_parent(node);
902
903 /* '..' */
904 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
905 ++(*tok_idx);
906 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
907
908 do {
909 /* '/' */
910 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
911 ++(*tok_idx);
912
913 /* NameTest */
914 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200915 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
916 prefix_data, NULL, 0, &node2, NULL));
Michal Vasko004d3152020-06-11 19:59:22 +0200917 node = node2;
918 ++(*tok_idx);
919 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
920
921 /* check the last target node */
922 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100923 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200924 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100925 ret = LY_EVALID;
926 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200927 }
928
929 /* we are not actually compiling, throw the rightside node away */
930 (void)node;
931
932 /* ']' */
933 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
934 ++(*tok_idx);
935
Radek Krejci0f969882020-08-21 16:56:47 +0200936 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200937 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
938
Radek Krejci2efc45b2020-12-22 16:25:44 +0100939cleanup:
Michal Vasko8cc3f662022-03-29 11:25:51 +0200940 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200941}
942
Michal Vaskoed725d72021-06-23 12:03:45 +0200943/**
stewegd8e2fc92023-05-31 09:52:56 +0200944 * @brief Duplicate ly_path_predicate structure.
945 *
946 * @param[in] ctx libyang context.
947 * @param[in] pred The array of path predicates.
948 * @param[out] dup Duplicated predicates.
949 * @return LY_ERR value.
950 */
951static LY_ERR
952ly_path_dup_predicates(const struct ly_ctx *ctx, const struct ly_path_predicate *pred, struct ly_path_predicate **dup)
953{
954 LY_ARRAY_COUNT_TYPE u;
955
956 if (!pred) {
957 return LY_SUCCESS;
958 }
959
960 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(pred), LY_EMEM);
961 LY_ARRAY_FOR(pred, u) {
962 LY_ARRAY_INCREMENT(*dup);
963 (*dup)[u].type = pred->type;
964
Michal Vasko5339b4f2023-09-29 14:38:08 +0200965 switch (pred[u].type) {
stewegd8e2fc92023-05-31 09:52:56 +0200966 case LY_PATH_PREDTYPE_POSITION:
967 /* position-predicate */
Michal Vasko5339b4f2023-09-29 14:38:08 +0200968 (*dup)[u].position = pred[u].position;
stewegd8e2fc92023-05-31 09:52:56 +0200969 break;
970 case LY_PATH_PREDTYPE_LIST:
971 case LY_PATH_PREDTYPE_LEAFLIST:
972 /* key-predicate or leaf-list-predicate */
Michal Vasko5339b4f2023-09-29 14:38:08 +0200973 (*dup)[u].key = pred[u].key;
974 pred[u].value.realtype->plugin->duplicate(ctx, &pred[u].value, &(*dup)[u].value);
975 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred[u].value.realtype)->refcount);
stewegd8e2fc92023-05-31 09:52:56 +0200976 break;
977 case LY_PATH_PREDTYPE_LIST_VAR:
978 /* key-predicate with a variable */
Michal Vasko5339b4f2023-09-29 14:38:08 +0200979 (*dup)[u].key = pred[u].key;
980 (*dup)[u].variable = strdup(pred[u].variable);
stewegd8e2fc92023-05-31 09:52:56 +0200981 break;
982 }
983 }
984
985 return LY_SUCCESS;
986}
987
988/**
989 * @brief Appends path elements from source to destination array
990 *
991 * @param[in] ctx libyang context.
992 * @param[in] src The source path
993 * @param[in,out] dst The destination path
994 * @return LY_ERR value.
995 */
996static LY_ERR
997ly_path_append(const struct ly_ctx *ctx, const struct ly_path *src, struct ly_path **dst)
998{
999 LY_ERR ret = LY_SUCCESS;
1000 LY_ARRAY_COUNT_TYPE u;
1001 struct ly_path *p;
1002
1003 if (!src) {
1004 return LY_SUCCESS;
1005 }
1006
1007 LY_ARRAY_CREATE_RET(ctx, *dst, LY_ARRAY_COUNT(src), LY_EMEM);
1008 LY_ARRAY_FOR(src, u) {
Michal Vasko696915b2023-05-31 10:12:11 +02001009 LY_ARRAY_NEW_GOTO(ctx, *dst, p, ret, cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001010 p->node = src[u].node;
1011 p->ext = src[u].ext;
Michal Vasko696915b2023-05-31 10:12:11 +02001012 LY_CHECK_GOTO(ret = ly_path_dup_predicates(ctx, src[u].predicates, &p->predicates), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001013 }
1014
Michal Vasko696915b2023-05-31 10:12:11 +02001015cleanup:
1016 return ret;
stewegd8e2fc92023-05-31 09:52:56 +02001017}
1018
1019/**
1020 * @brief Compile deref XPath function into ly_path structure.
1021 *
1022 * @param[in] ctx libyang context.
1023 * @param[in] ctx_node Optional context node, mandatory of @p lref.
1024 * @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find
1025 * the top-level node inside the extension instance instead of a module. Note that this is the case not only if
1026 * the @p ctx_node is NULL, but also if the relative path starting in @p ctx_node reaches the document root
1027 * via double dots.
1028 * @param[in] expr Parsed path.
1029 * @param[in] oper Oper option (@ref path_oper_options).
1030 * @param[in] target Target option (@ref path_target_options).
1031 * @param[in] format Format of the path.
1032 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
1033 * @param[in,out] tok_idx Index in @p exp, is adjusted.
1034 * @param[out] path Compiled path.
1035 * @return LY_ERR value.
1036 */
1037static LY_ERR
1038ly_path_compile_deref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
1039 const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint16_t oper, uint16_t target,
1040 LY_VALUE_FORMAT format, void *prefix_data, uint32_t *tok_idx, struct ly_path **path)
1041{
1042 LY_ERR ret = LY_SUCCESS;
1043 struct lyxp_expr expr2;
1044 struct ly_path *path2 = NULL;
1045 const struct lysc_node *node2;
1046 const struct lysc_node_leaf *deref_leaf_node;
1047 const struct lysc_type_leafref *lref;
1048 uint32_t begin_token;
1049
Michal Vasko696915b2023-05-31 10:12:11 +02001050 *path = NULL;
1051
stewegd8e2fc92023-05-31 09:52:56 +02001052 /* properly parsed path must always starts with 'deref' and '(' */
1053 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_FUNCNAME));
1054 assert(!strncmp(&expr->expr[expr->tok_pos[*tok_idx]], "deref", 5));
1055 (*tok_idx)++;
1056 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR1));
1057 (*tok_idx)++;
1058 begin_token = *tok_idx;
1059
1060 /* emebedded functions were already identified count tokens till ')' */
1061 while (lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2) && (*tok_idx < expr->used)) {
1062 (*tok_idx)++;
1063 }
1064
1065 /* properly parsed path must have ')' within the tokens */
1066 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2));
1067
1068 /* prepare expr representing just deref arg */
1069 expr2.tokens = &expr->tokens[begin_token];
1070 expr2.tok_pos = &expr->tok_pos[begin_token];
1071 expr2.tok_len = &expr->tok_len[begin_token];
1072 expr2.repeat = &expr->repeat[begin_token];
1073 expr2.used = *tok_idx - begin_token;
1074 expr2.size = expr->size - begin_token;
1075 expr2.expr = expr->expr;
1076
1077 /* compile just deref arg, append it to the path and find dereferenced lref for next operations */
Michal Vasko696915b2023-05-31 10:12:11 +02001078 LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, ctx_node, top_ext, &expr2, oper, target, format, prefix_data,
1079 &path2), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001080 node2 = path2[LY_ARRAY_COUNT(path2) - 1].node;
steweg1ac8b412023-10-31 13:25:33 +01001081 if ((node2->nodetype != LYS_LEAF) && (node2->nodetype != LYS_LEAFLIST)) {
1082 LOGVAL(ctx, LYVE_XPATH, "The deref function target node \"%s\" is not leaf nor leaflist", node2->name);
1083 ret = LY_EVALID;
1084 goto cleanup;
1085 }
stewegd8e2fc92023-05-31 09:52:56 +02001086 deref_leaf_node = (const struct lysc_node_leaf *)node2;
steweg1ac8b412023-10-31 13:25:33 +01001087 if (deref_leaf_node->type->basetype != LY_TYPE_LEAFREF) {
1088 LOGVAL(ctx, LYVE_XPATH, "The deref function target node \"%s\" is not leafref", node2->name);
1089 ret = LY_EVALID;
1090 goto cleanup;
1091 }
stewegd8e2fc92023-05-31 09:52:56 +02001092 lref = (const struct lysc_type_leafref *)deref_leaf_node->type;
Michal Vasko696915b2023-05-31 10:12:11 +02001093 LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup);
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +02001094 ly_path_free(path2);
stewegd8e2fc92023-05-31 09:52:56 +02001095 path2 = NULL;
1096
1097 /* compile dereferenced leafref expression and append it to the path */
Michal Vasko696915b2023-05-31 10:12:11 +02001098 LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, node2, top_ext, lref->path, oper, target, format, prefix_data,
1099 &path2), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001100 node2 = path2[LY_ARRAY_COUNT(path2) - 1].node;
Michal Vasko696915b2023-05-31 10:12:11 +02001101 LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup);
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +02001102 ly_path_free(path2);
stewegd8e2fc92023-05-31 09:52:56 +02001103 path2 = NULL;
1104
1105 /* properly parsed path must always continue with ')' and '/' */
1106 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2));
1107 (*tok_idx)++;
1108 assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_OPER_PATH));
1109 (*tok_idx)++;
1110
1111 /* prepare expr representing rest of the path after deref */
1112 expr2.tokens = &expr->tokens[*tok_idx];
1113 expr2.tok_pos = &expr->tok_pos[*tok_idx];
1114 expr2.tok_len = &expr->tok_len[*tok_idx];
1115 expr2.repeat = &expr->repeat[*tok_idx];
1116 expr2.used = expr->used - *tok_idx;
1117 expr2.size = expr->size - *tok_idx;
1118 expr2.expr = expr->expr;
1119
1120 /* compile rest of the path and append it to the path */
Michal Vasko696915b2023-05-31 10:12:11 +02001121 LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, node2, top_ext, &expr2, oper, target, format, prefix_data, &path2),
1122 cleanup);
1123 LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup);
stewegd8e2fc92023-05-31 09:52:56 +02001124
1125cleanup:
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +02001126 ly_path_free(path2);
stewegd8e2fc92023-05-31 09:52:56 +02001127 if (ret) {
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +02001128 ly_path_free(*path);
stewegd8e2fc92023-05-31 09:52:56 +02001129 *path = NULL;
1130 }
Michal Vasko696915b2023-05-31 10:12:11 +02001131 return ret;
stewegd8e2fc92023-05-31 09:52:56 +02001132}
1133
1134/**
Michal Vaskoed725d72021-06-23 12:03:45 +02001135 * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
1136 *
1137 * @param[in] ctx libyang context.
1138 * @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 +02001139 * without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
Michal Vaskoed725d72021-06-23 12:03:45 +02001140 * @param[in] ctx_node Optional context node, mandatory of @p lref.
Michal Vasko8cc3f662022-03-29 11:25:51 +02001141 * @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 +02001142 * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
1143 * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
1144 * @param[in] expr Parsed path.
1145 * @param[in] lref Whether leafref is being compiled or not.
1146 * @param[in] oper Oper option (@ref path_oper_options).
1147 * @param[in] target Target option (@ref path_target_options).
Michal Vasko0884d212021-10-14 09:21:46 +02001148 * @param[in] limit_access_tree Whether to limit accessible tree as described in
1149 * [XPath context](https://datatracker.ietf.org/doc/html/rfc7950#section-6.4.1).
Michal Vaskoed725d72021-06-23 12:03:45 +02001150 * @param[in] format Format of the path.
1151 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vaskoed725d72021-06-23 12:03:45 +02001152 * @param[out] path Compiled path.
1153 * @return LY_ERECOMPILE, only if @p lref.
1154 * @return LY_ERR value.
1155 */
1156static LY_ERR
1157_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 +01001158 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 +02001159 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +02001160{
1161 LY_ERR ret = LY_SUCCESS;
Michal Vaskodd528af2022-08-08 14:35:07 +02001162 uint32_t tok_idx = 0, getnext_opts;
Michal Vasko6b26e742020-07-17 15:02:10 +02001163 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +02001164 struct ly_path *p = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +02001165 struct lysc_ext_instance *ext = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001166
Michal Vasko00cbf532020-06-15 13:58:47 +02001167 assert(ctx);
Michal Vaskoed725d72021-06-23 12:03:45 +02001168 assert(!lref || ctx_node);
Michal Vasko00cbf532020-06-15 13:58:47 +02001169 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
1170 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +02001171
Michal Vasko0884d212021-10-14 09:21:46 +02001172 if (!limit_access_tree) {
1173 op = NULL;
1174 } else {
1175 /* find operation, if we are in any */
1176 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
1177 }
Michal Vasko6b26e742020-07-17 15:02:10 +02001178
Radek Krejci2efc45b2020-12-22 16:25:44 +01001179 *path = NULL;
1180
Michal Vasko6b26e742020-07-17 15:02:10 +02001181 /* remember original context node */
1182 cur_node = ctx_node;
Michal Vasko7a266772024-01-23 11:02:38 +01001183 if (cur_node) {
1184 LOG_LOCSET(cur_node, NULL);
1185 }
Michal Vasko004d3152020-06-11 19:59:22 +02001186
Michal Vasko00cbf532020-06-15 13:58:47 +02001187 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001188 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +02001189 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01001190 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +02001191 }
1192
stewegd8e2fc92023-05-31 09:52:56 +02001193 if (lref && (ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_EXTENDED) &&
1194 (expr->tokens[tok_idx] == LYXP_TOKEN_FUNCNAME)) {
1195 /* deref function */
1196 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 +02001197 goto cleanup;
1198 } else if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
Michal Vasko004d3152020-06-11 19:59:22 +02001199 /* absolute path */
1200 ctx_node = NULL;
1201
1202 ++tok_idx;
1203 } else {
1204 /* relative path */
Michal Vasko80239792021-11-02 11:48:32 +01001205 if (!ctx_node) {
1206 LOGVAL(ctx, LYVE_XPATH, "No initial schema parent for a relative path.");
1207 ret = LY_EVALID;
1208 goto cleanup;
1209 }
1210
1211 /* go up the parents for leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +02001212 while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
Michal Vasko004d3152020-06-11 19:59:22 +02001213 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001214 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +01001215 ret = LY_EVALID;
1216 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +02001217 }
1218
1219 /* get parent */
1220 ctx_node = lysc_data_parent(ctx_node);
1221
1222 ++tok_idx;
1223
1224 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
1225 ++tok_idx;
1226 }
Michal Vasko004d3152020-06-11 19:59:22 +02001227 }
1228
1229 do {
Michal Vasko00cbf532020-06-15 13:58:47 +02001230 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskoed725d72021-06-23 12:03:45 +02001231 if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001232 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +02001233 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +01001234 ret = LY_EVALID;
1235 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +02001236 }
1237
Michal Vasko14424ba2020-12-09 18:09:51 +01001238 /* NameTest */
1239 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
1240
Michal Vasko8cc3f662022-03-29 11:25:51 +02001241 /* get schema node */
1242 LY_CHECK_GOTO(ret = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
1243 top_ext, getnext_opts, &node2, &ext), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02001244 ++tok_idx;
Michal Vasko8cc3f662022-03-29 11:25:51 +02001245 if ((op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
1246 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
Radek Krejci8de005f2020-06-25 17:02:07 +02001247 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02001248 goto cleanup;
1249 }
1250 ctx_node = node2;
1251
1252 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +02001253 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02001254 p->node = ctx_node;
Michal Vasko8cc3f662022-03-29 11:25:51 +02001255 p->ext = ext;
Michal Vasko004d3152020-06-11 19:59:22 +02001256
1257 /* compile any predicates */
Michal Vaskoed725d72021-06-23 12:03:45 +02001258 if (lref) {
Michal Vasko24fc4d12021-07-12 14:41:20 +02001259 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +02001260 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +02001261 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 +01001262 &p->predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001263 }
1264 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02001265 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
1266
Michal Vasko14424ba2020-12-09 18:09:51 +01001267 /* check leftover tokens */
1268 if (tok_idx < expr->used) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02001269 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 +01001270 ret = LY_EVALID;
1271 goto cleanup;
1272 }
1273
Michal Vasko00cbf532020-06-15 13:58:47 +02001274 /* check last compiled node */
Michal Vaskoed725d72021-06-23 12:03:45 +02001275 if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001276 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +02001277 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +01001278 ret = LY_EVALID;
1279 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +02001280 }
1281
Michal Vasko004d3152020-06-11 19:59:22 +02001282cleanup:
1283 if (ret) {
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +02001284 ly_path_free(*path);
Michal Vasko004d3152020-06-11 19:59:22 +02001285 *path = NULL;
1286 }
Michal Vasko7a266772024-01-23 11:02:38 +01001287 LOG_LOCBACK(cur_node ? 1 : 0, 0);
Michal Vasko8cc3f662022-03-29 11:25:51 +02001288 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +02001289}
1290
1291LY_ERR
Michal Vaskoed725d72021-06-23 12:03:45 +02001292ly_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 +01001293 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 +02001294 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +02001295{
Michal Vasko8cc3f662022-03-29 11:25:51 +02001296 return _ly_path_compile(ctx, cur_mod, ctx_node, top_ext, expr, 0, oper, target, limit_access_tree, format,
1297 prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +02001298}
1299
1300LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +02001301ly_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 +01001302 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 +02001303 struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +02001304{
Michal Vasko8cc3f662022-03-29 11:25:51 +02001305 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 +02001306}
1307
1308LY_ERR
Michal Vasko90189962023-02-28 12:10:34 +01001309ly_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 +02001310 ly_bool with_opaq, LY_ARRAY_COUNT_TYPE *path_idx, struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +02001311{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001312 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoe43e21f2022-06-07 12:26:36 +02001313 struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +02001314 uint64_t pos;
1315
1316 assert(path && start);
1317
1318 if (lysc_data_parent(path[0].node)) {
1319 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001320 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001321 } else {
1322 /* absolute path, start from the first top-level sibling */
1323 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +01001324 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001325 }
1326 while (start->prev->next) {
1327 start = start->prev;
1328 }
1329 }
1330
1331 LY_ARRAY_FOR(path, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001332 if (path[u].predicates) {
1333 switch (path[u].predicates[0].type) {
1334 case LY_PATH_PREDTYPE_POSITION:
1335 /* we cannot use hashes and want an instance on a specific position */
1336 pos = 1;
1337 node = NULL;
1338 LYD_LIST_FOR_INST(start, path[u].node, elem) {
1339 if (pos == path[u].predicates[0].position) {
1340 node = elem;
1341 break;
1342 }
1343 ++pos;
Michal Vasko004d3152020-06-11 19:59:22 +02001344 }
Michal Vasko90189962023-02-28 12:10:34 +01001345 break;
1346 case LY_PATH_PREDTYPE_LEAFLIST:
1347 /* we will use hashes to find one leaf-list instance */
1348 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
1349 lyd_find_sibling_first(start, target, &node);
1350 lyd_free_tree(target);
1351 break;
1352 case LY_PATH_PREDTYPE_LIST_VAR:
1353 case LY_PATH_PREDTYPE_LIST:
1354 /* we will use hashes to find one list instance */
stewegd4cde642024-02-21 08:34:16 +01001355 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, 1, &target));
Michal Vasko90189962023-02-28 12:10:34 +01001356 lyd_find_sibling_first(start, target, &node);
1357 lyd_free_tree(target);
1358 break;
Michal Vasko004d3152020-06-11 19:59:22 +02001359 }
Michal Vasko90189962023-02-28 12:10:34 +01001360 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02001361 /* we will use hashes to find one any/container/leaf instance */
Michal Vasko838829d2023-10-09 16:06:43 +02001362 if (lyd_find_sibling_val(start, path[u].node, NULL, 0, &node) && with_opaq) {
1363 if (!lyd_find_sibling_opaq_next(start, path[u].node->name, &node) &&
1364 (lyd_node_module(node) != path[u].node->module)) {
1365 /* non-matching opaque node */
1366 node = NULL;
1367 }
1368 }
Michal Vasko004d3152020-06-11 19:59:22 +02001369 }
1370
1371 if (!node) {
1372 /* no matching nodes */
1373 break;
1374 }
1375
Michal Vasko00cbf532020-06-15 13:58:47 +02001376 /* rememeber previous node */
1377 prev_node = node;
1378
Michal Vasko004d3152020-06-11 19:59:22 +02001379 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001380 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +02001381 }
1382
Michal Vasko004d3152020-06-11 19:59:22 +02001383 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001384 /* we have found the full path */
1385 if (path_idx) {
1386 *path_idx = u;
1387 }
1388 if (match) {
1389 *match = node;
1390 }
Michal Vasko004d3152020-06-11 19:59:22 +02001391 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +02001392
1393 } else if (prev_node) {
1394 /* we have found only some partial match */
1395 if (path_idx) {
1396 *path_idx = u - 1;
1397 }
1398 if (match) {
1399 *match = prev_node;
1400 }
1401 return LY_EINCOMPLETE;
1402 }
1403
1404 /* we have not found any nodes */
1405 if (path_idx) {
1406 *path_idx = 0;
1407 }
1408 if (match) {
1409 *match = NULL;
1410 }
1411 return LY_ENOTFOUND;
1412}
1413
1414LY_ERR
Michal Vasko90189962023-02-28 12:10:34 +01001415ly_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 +02001416{
1417 LY_ERR ret;
1418 struct lyd_node *m;
1419
Michal Vasko838829d2023-10-09 16:06:43 +02001420 ret = ly_path_eval_partial(path, start, vars, 0, NULL, &m);
Michal Vasko00cbf532020-06-15 13:58:47 +02001421
1422 if (ret == LY_SUCCESS) {
1423 /* last node was found */
1424 if (match) {
1425 *match = m;
1426 }
1427 return LY_SUCCESS;
1428 }
1429
1430 /* not a full match */
1431 if (match) {
1432 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001433 }
1434 return LY_ENOTFOUND;
1435}
1436
1437LY_ERR
1438ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1439{
stewegd8e2fc92023-05-31 09:52:56 +02001440 LY_ERR ret = LY_SUCCESS;
1441 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001442
1443 if (!path) {
1444 return LY_SUCCESS;
1445 }
1446
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001447 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001448 LY_ARRAY_FOR(path, u) {
1449 LY_ARRAY_INCREMENT(*dup);
1450 (*dup)[u].node = path[u].node;
stewegd8e2fc92023-05-31 09:52:56 +02001451 (*dup)[u].ext = path[u].ext;
1452 LY_CHECK_RET(ret = ly_path_dup_predicates(ctx, path[u].predicates, &(*dup)[u].predicates), ret);
Michal Vasko004d3152020-06-11 19:59:22 +02001453 }
1454
1455 return LY_SUCCESS;
1456}
1457
1458void
Michal Vasko90189962023-02-28 12:10:34 +01001459ly_path_predicates_free(const struct ly_ctx *ctx, struct ly_path_predicate *predicates)
Michal Vasko004d3152020-06-11 19:59:22 +02001460{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001461 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001462 struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
Michal Vasko004d3152020-06-11 19:59:22 +02001463
1464 if (!predicates) {
1465 return;
1466 }
1467
1468 LY_ARRAY_FOR(predicates, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001469 switch (predicates[u].type) {
Michal Vasko004d3152020-06-11 19:59:22 +02001470 case LY_PATH_PREDTYPE_POSITION:
Michal Vasko004d3152020-06-11 19:59:22 +02001471 /* nothing to free */
1472 break;
1473 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001474 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001475 if (predicates[u].value.realtype) {
1476 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
Michal Vaskoc636ea42022-09-16 10:20:31 +02001477 lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype);
Michal Vaskoae875662020-10-21 10:33:17 +02001478 }
Michal Vasko004d3152020-06-11 19:59:22 +02001479 break;
Michal Vasko90189962023-02-28 12:10:34 +01001480 case LY_PATH_PREDTYPE_LIST_VAR:
1481 free(predicates[u].variable);
1482 break;
Michal Vasko004d3152020-06-11 19:59:22 +02001483 }
1484 }
1485 LY_ARRAY_FREE(predicates);
1486}
1487
1488void
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +02001489ly_path_free(struct ly_path *path)
Michal Vasko004d3152020-06-11 19:59:22 +02001490{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001491 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001492
Michal Vasko55b84812021-05-11 09:23:58 +02001493 if (!path) {
1494 return;
1495 }
1496
Michal Vasko004d3152020-06-11 19:59:22 +02001497 LY_ARRAY_FOR(path, u) {
Ondrej Kusnirikffeedfd2024-08-15 10:14:11 +02001498 ly_path_predicates_free(path[u].node->module->ctx, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001499 }
1500 LY_ARRAY_FREE(path);
1501}